On this page
Adding an AI chat box is easy; shipping an AI feature that behaves predictably is harder. The application still needs authentication, request limits, useful loading states, reliable persistence and a clear definition of success. The Vercel AI SDK helps connect model providers to application code, but it does not remove those product responsibilities.
Start with a narrow feature such as rewriting a selected paragraph. That gives you a bounded input, an output users can inspect and an obvious recovery path. Build the complete interaction before expanding into autonomous workflows or long conversations.
Define the feature contract before choosing a model
Write down the input contract: which fields the server accepts, their maximum sizes and whether documents can contain private information. Treat every browser request as untrusted, including requests originating from your own interface. Authenticate the user and establish their workspace permissions before calling a provider.
Define an output contract separately. A rewrite tool might return revised text plus a short explanation, while a classification feature might require one category from an approved list. Those interfaces need different validation and rendering strategies. Avoid building a universal chat endpoint when the product only needs a constrained transformation.
Use the word counter to compare instruction drafts and sample user inputs, then trim repeated requirements. Word counts help editorial review, but they are not token counts; use provider usage reporting for actual consumption. Record a maximum output budget and explain what the interface should do when a response is incomplete.
Choose a representative success example and a difficult failure example. These become the first cases in your AI evaluation workflow, rather than informal examples that disappear after the demo.
Keep provider calls behind a server boundary
The SDK offers shared interfaces for generation, streaming and provider integration. Check the official AI SDK documentation for the installed release because imports, message shapes and streaming helpers can change. Pin dependencies and review migration notes before upgrading a working endpoint.
Keep provider credentials exclusively on the server. Do not place secret keys in public environment variables, browser bundles or client configuration. The browser should call your authenticated application endpoint, which then decides whether the request is permitted and which provider settings apply.
Use a small application adapter around the SDK. Its responsibilities should include selecting an approved model, applying request deadlines and recording sanitised usage information. Do not hide every provider difference behind abstractions that promise identical behaviour: supported modalities, safety controls and tool semantics can vary.
A useful implementation brief is explicit about boundaries:
Build POST /api/rewrite as an authenticated server endpoint.
Accept text and an approved tone identifier, not arbitrary model settings.
Validate length and workspace quota before generation.
Return a request ID and stream text through the SDK response helper.
Never log the submitted text or expose provider credentials.Treat this as a specification for review, not a complete implementation. Framework-specific session verification and stream handling still need real code and tests.
Make streaming a designed interaction
Streaming improves perceived responsiveness by showing useful output before generation finishes. It does not necessarily reduce total processing time. Follow the SDK's streaming guidance rather than assuming a buffered response becomes live simply because the client reads it incrementally.
Design distinct states for connecting, receiving content, finishing and failing. If an error occurs after text has arrived, preserve the partial result and label it incomplete. An empty response should not look like a successful blank rewrite. Offer retry and cancellation without discarding the user's original input.
Implement cancellation propagation from browser to application server and, where supported, to the provider request. Confirm actual behaviour through testing: closing a component does not automatically prove that upstream work stopped. Set server deadlines even when the browser never sends a cancellation signal.
For accessibility, avoid announcing every streamed token through a live region. Announce a concise status and make the completed result discoverable. The W3C status message guidance provides useful criteria for communicating asynchronous changes without forcing focus movement. Test keyboard navigation during generation as well as after completion.
Validate structured output and tool access
Use schema validation when generated data will drive interface state or business logic. A parseable object is not automatically valid for your application. Check field types, permitted values, relationships between fields and whether referenced resources belong to the current user.
For example, a generated project identifier must be checked against workspace access rules before loading a project. Never treat a model-selected identifier as proof of authorisation. Keep these checks in normal application code so they remain effective regardless of prompt wording.
Adding tools creates a separate permission boundary. Define narrow tools with constrained arguments, explicit timeouts and predictable errors. A read-only search tool should not share credentials with a write-capable administration service. Require confirmation before consequential changes and recheck permissions when the action executes.
Content returned by a search result or document remains untrusted even when your own tool retrieved it. It may contain instructions attempting to redirect the model. Apply the boundaries described in prompt injection defence, particularly when retrieved content can influence later tool calls.
Ship with budgets, evidence and recovery
Set request budgets for input size, output size, tool calls, elapsed time and concurrent requests. A simple rate limit alone cannot contain a single expensive workflow. Apply limits per user and workspace where appropriate, and decide whether exhausted quotas produce a retry time or a different product path.
Record operational telemetry without recording sensitive prompts by default. Useful fields include request identifier, feature version, model configuration, timing, usage and outcome category. Separate validation errors, provider throttling, deadline failures and user cancellations so dashboards describe actionable problems rather than one generic error count.
Roll out to a small group with a non-AI fallback or a clear manual workflow. Review examples of accepted and rejected output, not just response speed. A fast rewrite that changes the meaning is still a failed feature. Keep the prompt and evaluation set under version control alongside the application adapter.
Before expanding scope, rehearse a provider outage and a client disconnect. Confirm that retries do not duplicate stored results or repeat side effects. Add bounded retries only for suitable transient failures, respecting provider guidance and your total deadline. Reliability comes from these explicit decisions, not from the presence of an SDK.
Key takeaways
- Define bounded input and output contracts before integrating generation.
- Keep credentials, quotas and permission checks on the server.
- Design streaming states, cancellation and accessible status updates together.
- Validate generated structures and authorise every tool action independently.
- Release against evaluations, operational budgets and tested recovery paths.
Reach designers & developers at work
Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.
Become a sponsor