Integrating Large Language Models (LLMs) like OpenAI’s ChatGPT, Google Gemini, and Anthropic Claude into web applications has unlocked a new class of user experiences, ranging from chatbots that feel like friends. AI writing tools that help you think. Tools that summarise, translate, or generate things in seconds.
But as exciting as it sounds, here’s the thing no one tells you…
Getting an AI model into your app is not that easy.
LLM integration is complex, provider-specific, and fraught with edge cases.
Whether you're using OpenAI, Google Gemini, Anthropic Claude, or Hugging Face, you often end up writing different boilerplate code, tweaking payloads, handling custom error structures, and managing streaming behaviours. That’s a lot of repetitive, non-creative work for developers.
The problem with direct integration
Let’s say you want to build a chatbot or AI assistant into your site. Sounds simple, right?
Well… not quite.
You’ll quickly run into problems like:
- Different APIs for each provider
- Manual handling of streaming with Server-Sent Events (SSE)
- Payload structuring that varies per model
- Token usage tracking and completion management
- Edge case issues with long prompts or slow responses
And if you ever want to switch from one model to another, you will probably need to rewrite half your app and make your codebase harder to maintain.
What does the AI SDK by Vercel solve?
The AI SDK solves these headaches by offering a standard interface for working with AI models. It acts as a middleware layer that abstracts away provider-specific quirks and lets you focus on building features.
It does all the hard stuff behind the scenes so you can focus on the fun part: building cool AI features.
Without the SDK:
// You call the raw API
const res = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
Authorisation: 'Bearer your-api-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Tell me a joke' }],
}),
});
const data = await res.json();
With AI SDK (React):
const { messages, input, handleInputChange, handleSubmit } = useChat();
const { messages, input, handleInputChange, handleSubmit } = useChat();
That’s it! No boilerplate, no streaming management, no token juggling.
Provider-agnostic interface
Instead of writing separate logic for OpenAI, Gemini, or Claude, the SDK provides unified hooks like:
- useChat() – for conversational UIs (chatbots)
const { messages, input, handleInputChange, handleSubmit } = useChat();
- useCompletion() – for autocomplete or generating content
const { completion, input, handleInputChange, handleSubmit } = useCompletion();
- StreamingTextResponse() – Live Responses, Token-by-Token
People love it when AI responds live, like ChatGPT does. The SDK handles this for you. You don’t have to know what SSE (Server-Sent Events) are — it just streams the answer in real time, automatically:
return new StreamingTextResponse(OpenAIStream(response));
Handles Tools (Function Calling)
The Vercel AI SDK's function tool calls allow you to define and register arbitrary "tools" (user-defined async functions with parameter schemas) that the LLM can call during chat or text generation. This enables models not only to generate text but also to trigger executable functions and react to their outputs, supporting advanced workflows like agents, chatbots with plugins, and more.
Core Concepts
- Tool: An object with a description, parameter validation schema (using Zod or JSON schema), and an execute async function that gets called with the arguments when the LLM triggers a tool call.
- Tool Call: When the model issues a structured command to invoke a tool with arguments.
- Tool Result: The return value of your function, which can be given back to the model for further processing or summarisation.
- Multi-Step Tool Calls: By configuring the maxSteps option, the AI can trigger multiple tool calls in a session, chaining results as needed
Just define them like this:
import { generateText, tool } from 'ai'; // ai = Vercel AI SDK
import { z } from 'zod';
const getWeather = tool({
description: 'Get the weather in a location',
parameters: z.object({
location: z.string().describe('City name'),
}),
// This function is called when the model wants to use the tool:
execute: async ({ location }) => {
// You could call a real weather API here
return { location, temperature: 25 };
},
});
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'What is the weather in Berlin?',
tools: { getWeather }, // tools made available to the assistant
// Optional: enable multi-step tool reasoning
maxSteps: 3,
});
- The model can decide when to use a tool based on its description and parameter schema.
- Results are included as part of the reply, and you can handle them in your app.
Upload Files and Ask Questions About Them
Imagine you upload a PDF, and the AI can answer questions about it.
You can do that too:
const { handleUpload } = useChat({
onUpload: async (files) => {
await uploadToVectorDB(files); // Or your own file system
},
});
Expanded Steps
- UI for File Upload
<input type="file" multiple onChange={(e) => handleUpload(e.target.files)} />
- onUpload Handler
- Calls your backend API to process and store vectors
- Q&A Flow
- User enters a question in your chat UI
- Backend: retrieves relevant file snippets from the vector DB
- Passes context + question to your LLM via AI SDK, streaming the answer
This is how apps like ChatPDF and AI Notebooks work.
Built-in streaming
The SDK supports Server-Sent Events (SSE) out of the box, so you get real-time token-by-token updates for a snappy user experience, without having to handle the stream manually.
Plug and play with UI
The hooks are designed for React, Next.js, SvelteKit, and even Nuxt, which means you can bind AI behaviour directly to your frontend components.
Secure by default
The AI SDK promotes using API routes or server functions to call the model, ensuring your API keys and prompt logic are not exposed to the client.
Use Cases made easy
Here’s where the AI SDK shines: