Vercel AI SDK reference notes

Vercel AI SDK reference notes

What is the Vercel AI SDK?

The Vercel AI SDK is an open-source JavaScript library that provides a unified interface for working with different LLM (Large Language Model) providers. It handles the communication between your application and various AI models, making it easy to switch between providers without rewriting your code.

The SDK is completely free and open-source. You can use it in any JavaScript environment → you don't need to use Vercel's hosting or pay them anything.

Core Components

The SDK has three main packages:

  • Core (package name: ai) → For backend code (Node.js, Bun, Deno)

  • AI SDK UI → Frontend components and hooks (framework-agnostic)

  • AI SDK RSC → React Server Components integration

Basic Usage

Installation

npm install ai

For specific providers, install their packages:

npm install @ai-sdk/anthropic
npm install @ai-sdk/openai

Generate Text

The simplest way to get text from an LLM:

import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";

const model = anthropic("claude-3-5-haiku-latest");

const response = await generateText({
  model,
  prompt: "What is the chemical formula for water?",
});

console.log(response.text); // "The chemical formula for water is H2O."

Stream Text

For a better user experience, stream the response as it's generated:

import { streamText } from "ai";

const { textStream } = await streamText({
  model,
  prompt: "What is the color of the sun?",
});

// Stream to UI
for await (const text of textStream) {
  // Add text to your UI as it arrives
  process.stdout.write(text);
}

// Or get the final text when complete
const finalText = await textStream;

System Prompts

Guide the model's behavior with system prompts:

const { text } = await generateText({
  model,
  prompt: "Summarize this article...",
  system: "You are a text summarizer. Be concise. Return only the summary."
});

You can also use messages format:

const { text } = await generateText({
  model,
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Hello, who are you?" }
  ]
});

Model Switching

Easily switch between different models:

import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
import { generateText, type LanguageModel } from "ai";

// Function that works with any model
async function askQuestion(prompt: string, model: LanguageModel) {
  const { text } = await generateText({ model, prompt });
  return text;
}

// Use with different providers
const openaiResponse = await askQuestion("Tell me a joke", openai("gpt-4o"));
const anthropicResponse = await askQuestion("Tell me a joke", anthropic("claude-3-opus"));

Chat History

Manage conversations with message history:

// Messages array structure
const messages = [
  { role: "system", content: "You are a friendly assistant." },
  { role: "user", content: "Hello, who are you?" },
  { role: "assistant", content: "Hi there! I'm Claude, your AI assistant. How can I help you today?" },
  { role: "user", content: "What can you do?" }
];

// Pass to model
const { response } = await generateText({
  model,
  messages
});

// Add new messages from response
const updatedMessages = [...messages, ...response.messages];

Advanced Features

Structured Outputs

Get structured data instead of free-form text:

import { generateObject } from "ai";
import { z } from "zod";

const schema = z.object({
  recipe: z.object({
    name: z.string().describe("The title of the recipe"),
    ingredients: z.array(
      z.object({
        name: z.string(),
        amount: z.string(),
      })
    ).describe("The ingredients needed for the recipe"),
    steps: z.array(z.string()).describe("The steps to make the recipe")
  })
});

const { object } = await generateObject({
  model,
  schema,
  prompt: "How to make chocolate cake?",
  schemaName: "Recipe"
});

console.log(object.recipe.name); // "Chocolate Cake"

Stream Structured Outputs

Stream objects as they're being generated:

import { streamObject } from "ai";

const result = await streamObject({
  model,
  schema,
  prompt: "How to make pancakes?"
});

// Stream partial objects
for await (const obj of result.partialObjectStream) {
  // Update UI with partial object
  updateUI(obj);
}

// Get final object
const finalObject = await result.object;

Enums

Classify text into predefined categories:

import { generateObject } from "ai";

const sentiment = await generateObject({
  model,
  output: "enum",
  enum: ["positive", "negative", "neutral"],
  prompt: "I love this product!",
  system: "Classify the sentiment of the text."
});

console.log(sentiment.object); // "positive"

Arrays

Generate arrays of structured data:

import { generateObject } from "ai";

const { object: users } = await generateObject({
  model,
  output: "array",
  schema: z.object({
    name: z.string(),
    age: z.number(),
    email: z.string().email()
  }),
  prompt: "Generate 5 fake users."
});

console.log(users); // Array of 5 user objects

Working with Images

Process and describe images:

import { generateText } from "ai";
import { readFileSync } from "fs";

// From local file
const imageData = readFileSync("./image.jpg");
const description = await generateText({
  model,
  system: "Describe this image concisely.",
  messages: [{
    role: "user",
    content: [{ type: "image", image: imageData }]
  }]
});

// From URL
const urlDescription = await generateText({
  model,
  system: "Describe this image concisely.",
  messages: [{
    role: "user",
    // new URL is required
    content: [{ type: "image", image: new URL("https://example.com/image.jpg") }]
  }]
});

Working with PDFs

Extract structured data from PDFs:

import { generateObject } from "ai";
import { readFileSync } from "fs";

const { object } = await generateObject({
  model,
  schema: z.object({
    invoiceNumber: z.string(),
    total: z.number(),
    currency: z.string(),
    // Other fields...
  }),
  messages: [{
    role: "user",
    content: [{
      type: "file",
      data: readFileSync("./invoice.pdf"),
      mimeType: "application/pdf"
    }]
  }]
});

Embeddings

Create embeddings for semantic search:

import { embedMany, embed, cosineSimilarity } from "ai";
import { openai } from "@ai-sdk/openai";

const embeddingModel = openai.embedding("text-embedding-3-small");

// Create embeddings for multiple items
const { embeddings } = await embedMany({
  model: embeddingModel,
  values: ["Dog", "Cat", "Car", "Bike"]
});

// Create embedding for search term
const searchTerm = await embed({
  model: embeddingModel,
  value: "Canine"
});

// Find similar items
const similarities = embeddings.map((embedding, index) => ({
  value: values[index],
  similarity: cosineSimilarity(embedding, searchTerm.embedding)
}));

const sortedResults = similarities.sort((a, b) => b.similarity - a.similarity);

Tool Calling

Allow the model to call functions:

import { generateText, tool } from "ai";
import { z } from "zod";

// Define a tool
const getWeatherTool = tool({
  description: "Get the current weather in a city",
  parameters: z.object({
    city: z.string().describe("The city to get weather for")
  }),
  execute: async ({ city }) => {
    // Call a weather API
    return `The weather in ${city} is 25°C and sunny.`;
  }
});

// Use the tool
const { text, steps } = await generateText({
  model,
  prompt: "What's the weather in London?",
  tools: {
    getWeather: getWeatherTool
  }
});

// See tool calls
console.log(steps[0].toolCalls);

Building Agents

Create agents that can use tools in a reasoning loop:

import { streamText, tool } from "ai";

const { textStream } = await streamText({
  model,
  prompt: "What's the weather in London and Paris?",
  tools: {
    getWeather: getWeatherTool
  },
  maxSteps: 3  // Allow multiple tool-calling steps
});

// Display the streaming result
for await (const text of textStream) {
  process.stdout.write(text);
}

The maxSteps parameter determines how many reasoning steps the model can take. The model may stop earlier if it decides it has completed the task.