Why the Vercel AI SDK?
Every AI provider has a different streaming API, tool call format, and error shape. The Vercel AI SDK abstracts all of that into one consistent interface that works with OpenAI, Anthropic, Google, Mistral, Ollama, and dozens of others — and it integrates directly with React via hooks.
Streaming Text
// app/api/chat/route.ts
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await streamText({
model: openai("gpt-4o"),
messages,
onFinish({ usage, finishReason }) {
// cost tracking
console.log("Tokens used:", usage.totalTokens);
},
});
return result.toDataStreamResponse();
}
// components/Chat.tsx
"use client";
import { useChat } from "ai/react";
export function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
return (
<div>
{messages.map(m => (
<div key={m.id}><strong>{m.role}:</strong> {m.content}</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={isLoading} />
<button type="submit">Send</button>
</form>
</div>
);
}
Tool Calls
Tools let the model call functions during generation. The SDK handles the tool call → result → continue loop:
import { streamText, tool } from "ai";
import { z } from "zod";
const result = await streamText({
model: openai("gpt-4o"),
tools: {
getWeather: tool({
description: "Get current weather for a city",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => {
const data = await fetchWeather(city);
return { temperature: data.temp, condition: data.condition };
},
}),
},
prompt: "What is the weather in Tokyo?",
maxSteps: 3, // allow model to use tool then continue
});
Structured Output With generateObject()
When you need structured data instead of free text:
import { generateObject } from "ai";
import { z } from "zod";
const { object } = await generateObject({
model: openai("gpt-4o"),
schema: z.object({
tasks: z.array(z.object({
title: z.string(),
priority: z.enum(["low", "medium", "high"]),
estimatedHours: z.number(),
})),
}),
prompt: "Break down building a REST API into tasks",
});
// object.tasks is fully typed Task[]
Multi-Step Agents
Set maxSteps to let the model take multiple tool calls in a chain:
const result = await streamText({
model: anthropic("claude-3-5-sonnet-20241022"),
tools: {
searchWeb: tool({ /* ... */ }),
readPage: tool({ /* ... */ }),
writeFile: tool({ /* ... */ }),
},
system: "You are a research agent. Search for information and write a summary.",
prompt: "Research the current state of WebAssembly and write a 500-word summary.",
maxSteps: 10, // agent can take up to 10 tool calls
});
// Stream each step as it happens
for await (const delta of result.fullStream) {
if (delta.type === "tool-call") {
console.log("Tool called:", delta.toolName);
}
if (delta.type === "text-delta") {
process.stdout.write(delta.textDelta);
}
}
Switching Providers
The SDK's provider abstraction means switching models is one line:
import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
import { google } from "@ai-sdk/google";
import { ollama } from "ollama-ai-provider"; // community
// Just swap the model — everything else stays the same
const model = openai("gpt-4o"); // OpenAI
const model = anthropic("claude-3-5-sonnet-20241022"); // Anthropic
const model = google("gemini-1.5-pro"); // Google
const model = ollama("llama3.2"); // Local via Ollama
References: Vercel AI SDK · GitHub · docs