Vercel AI SDK Agents: Complete 2026 Implementation Guide
The AI Agent Revolution with Vercel AI SDK
Artificial intelligence agents are transforming how users interact with applications, moving beyond simple chatbots to sophisticated systems that can query databases, execute complex workflows, and interact with your application's core functionality. Vercel AI SDK has emerged as the dominant TypeScript toolkit for building these intelligent systems, with over 20 million monthly downloads and adoption by teams ranging from startups to Fortune 500 companies.
Real impact: "Thomson Reuters used the AI SDK to build CoCounsel, their AI assistant for attorneys, accountants, and audit teams, with just 3 developers in 2 months. Now serving 1,300 accounting firms, they're migrating their entire codebase to the AI SDK, deprecating thousands of lines of code across 10 providers and consolidating into one composable, scalable system."
This comprehensive guide covers everything you need to build production-ready AI agents with Vercel AI SDK 6, from basic tool calling to sophisticated database integration that lets agents query your job board, e-commerce platform, or any other data-driven application.
Understanding Vercel AI SDK and AI Agents
What is Vercel AI SDK?
Vercel AI SDK is a free, open-source TypeScript toolkit designed specifically for building AI-powered applications and agents. Unlike provider-specific SDKs, it provides a unified API that works across 25+ AI providers including OpenAI, Anthropic, Google, AWS Bedrock, Azure OpenAI, xAI Grok, and Mistral.
Core SDK Components:
AI SDK Core:
Unified API for generating text and structured outputs
Built-in tool calling and agent orchestration
Multi-step workflow automation
Provider-agnostic model switching
AI SDK UI:
Framework-agnostic hooks for React, Vue, Svelte, and Angular
Streaming response handling with minimal code
Type-safe UI components that auto-sync with agent logic
Generative UI support for dynamic component rendering
AI SDK Agents (SDK 6):
Reusable agent abstractions across application contexts
Production-ready ToolLoopAgent implementation
Human-in-the-loop approval workflows
End-to-end TypeScript type safety
What are AI Agents?
AI agents are autonomous systems that observe their environment, make decisions based on large language models (LLMs), and take actions to achieve specific goals. Unlike simple chatbots that respond to predefined inputs, agents can:
Autonomous Decision Making:
Analyze user requests to determine required actions
Choose appropriate tools from available options
Execute multi-step workflows without human intervention
Adapt behavior based on tool execution results
Tool Integration and Execution:
Query databases to retrieve relevant information
Call external APIs for real-time data
Execute business logic and workflows
Interact with file systems and cloud services
Context Management:
Maintain conversation history across interactions
Track tool call results for informed decision-making
Build understanding through iterative tool usage
Generate final responses synthesizing all collected information
Industry insight: Clay used Vercel AI SDK to build Claygent, their AI web research agent that scrapes public data, connects to first-party sources via MCP servers, and helps sales teams find accounts with custom insights at massive scale.
Vercel AI SDK 6: Revolutionary Agent Features
Agent Abstraction Layer
AI SDK 6 introduces a fundamental shift in how developers build agents by providing a reusable agent abstraction that works everywhere—chat UIs, background jobs, API endpoints, or standalone scripts.
Before AI SDK 6 (Repetitive Configuration):
javascript
// Chat route
const chatResult = await streamText({
model: openai('gpt-4'),
system: 'You are a helpful assistant',
tools: { weather, database, email },
messages,
});
// Background job route
const jobResult = await generateText({
model: openai('gpt-4'),
system: 'You are a helpful assistant',
tools: { weather, database, email },
prompt: jobPrompt,
});
// API endpoint route
const apiResult = await generateText({
model: openai('gpt-4'),
system: 'You are a helpful assistant',
tools: { weather, database, email },
prompt: apiRequest,
});After AI SDK 6 (Define Once, Use Everywhere):
javascript
// Define agent once in agents/assistant.ts
import { ToolLoopAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
import { weatherTool, databaseTool, emailTool } from './tools';
export const assistant = new ToolLoopAgent({
model: openai('gpt-4'),
system: 'You are a helpful assistant',
tools: {
weather: weatherTool,
database: databaseTool,
email: emailTool,
},
});
// Use in chat route
const chatResult = await assistant.stream({ messages });
// Use in background job
const jobResult = await assistant.generate({ prompt: jobPrompt });
// Use in API endpoint
const apiResult = await assistant.generate({ prompt: apiRequest });ToolLoopAgent: Production-Ready Implementation
The ToolLoopAgent class provides an out-of-the-box implementation that handles the complete agent execution cycle:
Automatic Tool Loop Orchestration:
javascript
const agent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4'),
system: 'You are a data analyst assistant',
tools: {
queryDatabase: databaseQueryTool,
generateChart: chartGenerationTool,
sendReport: emailReportTool,
},
stopWhen: stepCountIs(20), // Maximum 20 steps
});
// Agent automatically:
// 1. Receives user request
// 2. Decides which tool to call
// 3. Executes tool and receives result
// 4. Adds result to conversation history
// 5. Generates new request based on updated context
// 6. Repeats until completion or max steps reached
const result = await agent.generate({
prompt: 'Analyze last month sales and email report to leadership'
});Tool Execution Approval System
AI SDK 6 introduces human-in-the-loop approval for sensitive operations, ensuring agents never execute critical actions without human oversight:
Implementing Tool Approval:
javascript
import { tool } from 'ai';
import { z } from 'zod';
const deleteRecordTool = tool({
description: 'Delete a database record permanently',
parameters: z.object({
table: z.string().describe('Database table name'),
id: z.string().describe('Record ID to delete'),
}),
needsApproval: true, // Requires human approval
execute: async ({ table, id }) => {
// Only executes after approval
await database.deleteRecord(table, id);
return { success: true, deleted: id };
},
});
// Agent pauses for approval before deletion
const result = await agent.generate({
prompt: 'Delete customer record ID 12345',
});
// User approves via UI, then agent continuesConditional Approval Based on Parameters:
javascript
const transferFundsTool = tool({
description: 'Transfer funds between accounts',
parameters: z.object({
from: z.string(),
to: z.string(),
amount: z.number(),
}),
needsApproval: async ({ amount }) => {
// Only large transfers require approval
return amount > 1000;
},
execute: async ({ from, to, amount }) => {
await bankingService.transfer(from, to, amount);
return { success: true, amount };
},
});Building Database-Integrated Agents: Job Board Example
Real-World Use Case: Job Search Agent
Let's build exactly what you described—an AI agent for a job board that can query your database and respond to natural language requests like "list me 100 Java jobs posted recently."
Complete Job Board Agent Implementation:
Step 1: Define Database Query Tool
javascript
// lib/tools/database.js
import { tool } from 'ai';
import { z } from 'zod';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export const jobSearchTool = tool({
description: `Search for job listings in the database.
Use this when users ask about jobs, positions, or career opportunities.
You can filter by job title, skills, location, salary, and posting date.`,
parameters: z.object({
query: z.string().optional().describe('Job title or keywords to search'),
skills: z.array(z.string()).optional().describe('Required skills (e.g., "Java", "Python")'),
location: z.string().optional().describe('Job location'),
minSalary: z.number().optional().describe('Minimum salary requirement'),
maxSalary: z.number().optional().describe('Maximum salary requirement'),
postedAfter: z.string().optional().describe('ISO date string for jobs posted after this date'),
limit: z.number().default(100).describe('Maximum number of results to return'),
}),
execute: async ({ query, skills, location, minSalary, maxSalary, postedAfter, limit }) => {
try {
// Build dynamic query based on parameters
const whereClause = {};
if (query) {
whereClause.OR = [
{ title: { contains: query, mode: 'insensitive' } },
{ description: { contains: query, mode: 'insensitive' } },
];
}
if (skills && skills.length > 0) {
whereClause.skills = {
hasSome: skills,
};
}
if (location) {
whereClause.location = {
contains: location,
mode: 'insensitive',
};
}
if (minSalary || maxSalary) {
whereClause.salary = {};
if (minSalary) whereClause.salary.gte = minSalary;
if (maxSalary) whereClause.salary.lte = maxSalary;
}
if (postedAfter) {
whereClause.postedAt = {
gte: new Date(postedAfter),
};
}
// Execute database query
const jobs = await prisma.job.findMany({
where: whereClause,
take: limit,
orderBy: {
postedAt: 'desc',
},
select: {
id: true,
title: true,
company: true,
location: true,
salary: true,
skills: true,
description: true,
postedAt: true,
applicants: true,
},
});
// Return formatted results
return {
count: jobs.length,
jobs: jobs.map(job => ({
id: job.id,
title: job.title,
company: job.company,
location: job.location,
salary: `$${job.salary.toLocaleString()}/year`,
skills: job.skills.join(', '),
posted: new Date(job.postedAt).toLocaleDateString(),
applicants: job.applicants,
description: job.description.substring(0, 200) + '...',
})),
};
} catch (error) {
console.error('Database query error:', error);
return {
error: 'Failed to search jobs. Please try again.',
};
}
},
});Step 2: Create Additional Job-Related Tools
javascript
// lib/tools/job-details.js
export const getJobDetailsTool = tool({
description: 'Get complete details for a specific job listing by ID',
parameters: z.object({
jobId: z.string().describe('The unique job ID'),
}),
execute: async ({ jobId }) => {
const job = await prisma.job.findUnique({
where: { id: jobId },
include: {
company: {
select: {
name: true,
description: true,
website: true,
size: true,
},
},
},
});
if (!job) {
return { error: 'Job not found' };
}
return {
job: {
id: job.id,
title: job.title,
description: job.description,
requirements: job.requirements,
salary: job.salary,
location: job.location,
type: job.type, // Full-time, part-time, contract
remote: job.remote,
skills: job.skills,
postedAt: job.postedAt,
company: job.company,
},
};
},
});
export const applyToJobTool = tool({
description: 'Submit job application for the current user',
parameters: z.object({
jobId: z.string().describe('The job ID to apply to'),
coverLetter: z.string().optional().describe('Optional cover letter'),
}),
needsApproval: true, // User must approve application submission
execute: async ({ jobId, coverLetter }, context) => {
// Get user from context (passed via call options)
const userId = context.userId;
const application = await prisma.jobApplication.create({
data: {
jobId,
userId,
coverLetter,
status: 'submitted',
submittedAt: new Date(),
},
});
return {
success: true,
applicationId: application.id,
message: 'Application submitted successfully',
};
},
});
export const getApplicationStatusTool = tool({
description: 'Check status of user job applications',
parameters: z.object({
applicationId: z.string().optional().describe('Specific application ID to check'),
}),
execute: async ({ applicationId }, context) => {
const userId = context.userId;
const whereClause = { userId };
if (applicationId) {
whereClause.id = applicationId;
}
const applications = await prisma.jobApplication.findMany({
where: whereClause,
include: {
job: {
select: {
title: true,
company: true,
},
},
},
orderBy: {
submittedAt: 'desc',
},
});
return {
applications: applications.map(app => ({
id: app.id,
job: app.job.title,
company: app.job.company,
status: app.status,
submittedAt: app.submittedAt,
lastUpdated: app.updatedAt,
})),
};
},
});Step 3: Create Job Board Agent
javascript
// agents/job-board-agent.ts
import { ToolLoopAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
import {
jobSearchTool,
getJobDetailsTool,
applyToJobTool,
getApplicationStatusTool
} from '../lib/tools';
export const jobBoardAgent = new ToolLoopAgent({
model: openai('gpt-4-turbo'),
system: `You are an intelligent job board assistant that helps users find and apply for jobs.
Your capabilities:
- Search for jobs based on various criteria (title, skills, location, salary, posting date)
- Retrieve detailed information about specific job listings
- Help users apply to jobs (requires approval)
- Check application status
When searching for jobs:
- Extract relevant criteria from user requests
- Use appropriate date filters for "recent" jobs (last 30 days)
- Suggest related searches if results are limited
- Highlight key details like salary, location, and required skills
Be conversational and helpful. Format job listings clearly with:
- Job title and company
- Location and salary
- Key required skills
- How long ago it was posted
- Number of applicants (to gauge competition)
Always ask clarifying questions if the user's request is ambiguous.`,
tools: {
searchJobs: jobSearchTool,
getJobDetails: getJobDetailsTool,
applyToJob: applyToJobTool,
checkApplications: getApplicationStatusTool,
},
stopWhen: stepCountIs(10),
});Step 4: Create API Route
javascript
// app/api/chat/route.ts
import { jobBoardAgent } from '@/agents/job-board-agent';
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth'; // Your authentication system
export const runtime = 'edge';
export const maxDuration = 60;
export async function POST(req: Request) {
try {
// Authenticate user
const session = await auth();
if (!session?.user) {
return new NextResponse('Unauthorized', { status: 401 });
}
const { messages } = await req.json();
// Stream agent response with user context
const stream = await jobBoardAgent.stream({
messages,
// Pass user context to tools via call options
callOptions: {
userId: session.user.id,
userEmail: session.user.email,
},
});
return stream.toDataStreamResponse();
} catch (error) {
console.error('Agent error:', error);
return new NextResponse('Internal Server Error', { status: 500 });
}
}Step 5: Create Chat UI
jsx
// app/chat/page.tsx
'use client';
import { useChat } from 'ai/react';
export default function JobBoardChat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: '/api/chat',
onError: (error) => {
console.error('Chat error:', error);
},
});
return (
<div className="flex flex-col h-screen max-w-4xl mx-auto p-4">
<div className="flex-1 overflow-y-auto space-y-4 mb-4">
{messages.map((message) => (
<div
key={message.id}
className={`flex ${
message.role === 'user' ? 'justify-end' : 'justify-start'
}`}
>
<div
className={`max-w-xl rounded-lg px-4 py-2 ${
message.role === 'user'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-900'
}`}
>
<p className="whitespace-pre-wrap">{message.content}</p>
{/* Display tool calls */}
{message.toolInvocations?.map((tool, index) => (
<div key={index} className="mt-2 p-2 bg-opacity-20 bg-black rounded">
<p className="text-xs font-mono">
🔧 {tool.toolName}
</p>
{tool.state === 'result' && (
<pre className="text-xs mt-1 overflow-x-auto">
{JSON.stringify(tool.result, null, 2)}
</pre>
)}
</div>
))}
</div>
</div>
))}
{isLoading && (
<div className="flex justify-start">
<div className="bg-gray-100 rounded-lg px-4 py-2">
<div className="flex space-x-2">
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" />
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-100" />
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-200" />
</div>
</div>
</div>
)}
</div>
<form onSubmit={handleSubmit} className="flex gap-2">
<input
value={input}
onChange={handleInputChange}
placeholder="Ask about jobs... (e.g., 'Find 100 Java jobs posted recently')"
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
Send
</button>
</form>
</div>
);
}Example Interactions
User Request: "List me 100 Java jobs posted recently"
Agent Process:
Agent receives request and analyzes intent
Calls
searchJobstool with parameters:query: "Java"
limit: 100
postedAfter: (30 days ago)
Receives database results
Formats and presents jobs to user
Agent Response:
I found 87 Java jobs posted in the last 30 days. Here are the results:
1. Senior Java Developer - TechCorp
📍 San Francisco, CA | 💰 $150,000/year
📋 Required: Java, Spring Boot, Microservices, AWS
📅 Posted 2 days ago | 👥 23 applicants
2. Java Backend Engineer - StartupXYZ
📍 Remote | 💰 $130,000/year
📋 Required: Java, PostgreSQL, Docker, Kubernetes
📅 Posted 3 days ago | 👥 15 applicants
3. Full Stack Java Developer - Enterprise Inc
📍 New York, NY | 💰 $140,000/year
📋 Required: Java, React, MongoDB, Jenkins
📅 Posted 5 days ago | 👥 31 applicants
[... continues for all 87 jobs ...]
Would you like me to:
- Filter by location or salary range?
- Show more details about any specific job?
- Help you apply to any of these positions?Follow-up: "Show me remote jobs over $140k"
Agent Process:
Calls
searchJobstool with refined parameters:query: "Java"
location: "Remote"
minSalary: 140000
postedAfter: (30 days ago)
limit: 100
Returns filtered results
This demonstrates a fully functional agent with actual system access—exactly what you asked for!
Advanced Tool Calling Patterns
Multi-Step Tool Orchestration
Agents can chain multiple tool calls to accomplish complex tasks:
javascript
const dataAnalystAgent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4'),
system: 'You are a data analyst that creates comprehensive reports',
tools: {
queryDatabase: databaseQueryTool,
calculateMetrics: metricsCalculationTool,
generateChart: chartGenerationTool,
sendEmail: emailTool,
},
stopWhen: stepCountIs(15),
});
// User: "Analyze last quarter sales and send report to CEO"
// Agent automatically:
// 1. Calls queryDatabase for Q4 sales data
// 2. Calls calculateMetrics to compute growth rates
// 3. Calls generateChart to create visualizations
// 4. Calls sendEmail with complete report
const result = await dataAnalystAgent.generate({
prompt: 'Analyze last quarter sales and send report to ceo@company.com'
});Dynamic Tool Selection
Tools can be enabled/disabled based on runtime conditions:
javascript
const customerServiceAgent = new ToolLoopAgent({
model: openai('gpt-4'),
system: 'You are a customer service agent',
tools: {
searchOrders: orderSearchTool,
processRefund: refundTool,
escalateToHuman: escalationTool,
},
activeTools: ({ messages }) => {
// Only allow refunds for authenticated users
const isAuthenticated = checkUserAuth(messages);
return isAuthenticated
? ['searchOrders', 'processRefund', 'escalateToHuman']
: ['searchOrders', 'escalateToHuman'];
},
});Tool Result Validation and Repair
AI SDK 6 supports automatic tool call repair when validation fails:
javascript
const bookingTool = tool({
description: 'Book a hotel room',
parameters: z.object({
checkIn: z.string().refine(
(date) => new Date(date) > new Date(),
{ message: 'Check-in date must be in the future' }
),
checkOut: z.string(),
guests: z.number().min(1).max(10),
}),
execute: async ({ checkIn, checkOut, guests }) => {
// Booking logic
},
experimental_repairToolCall: async ({ toolCall, error }) => {
// Attempt to fix invalid tool calls
if (error.message.includes('future')) {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return {
...toolCall,
args: {
...toolCall.args,
checkIn: tomorrow.toISOString(),
},
};
}
},
});Model Context Protocol (MCP) Integration
What is MCP?
Model Context Protocol is an open standard introduced by Anthropic in November 2024 that standardizes how AI applications connect to external tools and data sources. Instead of building custom integrations for each combination of AI model and data source, MCP provides a single protocol that works universally.
MCP Solves the M×N Integration Problem:
Before MCP: Need M×N integrations (each model × each data source)
With MCP: Need M+N integrations (each model + each data source)
Connecting to MCP Servers
Vercel AI SDK 6 includes native MCP support through the @ai-sdk/mcp package:
javascript
import { createMCPClient } from '@ai-sdk/mcp';
// Connect to remote MCP server
const mcpClient = createMCPClient({
transport: {
type: 'http',
url: 'https://api.example.com/mcp',
headers: {
'Authorization': `Bearer ${process.env.MCP_API_KEY}`,
},
},
});
// List available tools from MCP server
const availableTools = await mcpClient.listTools();
// Use MCP tools in your agent
const agent = new ToolLoopAgent({
model: openai('gpt-4'),
tools: {
// Include MCP tools alongside native tools
...mcpClient.tools(),
// Your custom tools
customTool: myCustomTool,
},
});OAuth Authentication for MCP
AI SDK 6 handles OAuth complexity automatically:
javascript
const mcpClient = createMCPClient({
transport: {
type: 'http',
url: 'https://salesforce-mcp.example.com/sse',
auth: {
type: 'oauth',
clientId: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
tokenUrl: 'https://login.salesforce.com/services/oauth2/token',
refreshUrl: 'https://login.salesforce.com/services/oauth2/token',
},
},
});
// SDK automatically handles:
// - PKCE challenges
// - Token refresh
// - Dynamic client registration
// - Retry logic when tokens expireMCP Resources and Prompts
MCP servers can expose data through resources and reusable prompt templates:
javascript
// List available resources from MCP server
const resources = await mcpClient.listResources();
// Fetch specific resource
const customerData = await mcpClient.readResource({
uri: 'customers://database/recent-purchases',
});
// List available prompt templates
const prompts = await mcpClient.listPrompts();
// Get prompt with arguments
const salesPrompt = await mcpClient.getPrompt({
name: 'analyze-sales',
arguments: {
period: 'Q4-2025',
region: 'North America',
},
});E-commerce Chatbot: Complete Implementation
Architecture Overview
Building a production-ready e-commerce agent that queries products, processes orders, and handles customer support:
javascript
// lib/tools/ecommerce-tools.ts
import { tool } from 'ai';
import { z } from 'zod';
import { prisma } from '@/lib/database';
export const searchProductsTool = tool({
description: 'Search products in the store catalog',
parameters: z.object({
query: z.string().optional(),
category: z.string().optional(),
minPrice: z.number().optional(),
maxPrice: z.number().optional(),
inStock: z.boolean().default(true),
limit: z.number().default(20),
}),
execute: async ({ query, category, minPrice, maxPrice, inStock, limit }) => {
const products = await prisma.product.findMany({
where: {
AND: [
query ? {
OR: [
{ name: { contains: query, mode: 'insensitive' } },
{ description: { contains: query, mode: 'insensitive' } },
],
} : {},
category ? { category } : {},
minPrice ? { price: { gte: minPrice } } : {},
maxPrice ? { price: { lte: maxPrice } } : {},
inStock ? { stock: { gt: 0 } } : {},
],
},
take: limit,
select: {
id: true,
name: true,
price: true,
stock: true,
imageUrl: true,
category: true,
rating: true,
reviews: true,
},
});
return {
products: products.map(p => ({
id: p.id,
name: p.name,
price: `$${p.price.toFixed(2)}`,
stock: p.stock,
category: p.category,
rating: `${p.rating}/5 (${p.reviews} reviews)`,
})),
total: products.length,
};
},
});
export const getOrderStatusTool = tool({
description: 'Check order status for a customer',
parameters: z.object({
orderId: z.string().optional(),
email: z.string().email().optional(),
}),
execute: async ({ orderId, email }) => {
const orders = await prisma.order.findMany({
where: {
OR: [
orderId ? { id: orderId } : {},
email ? { customerEmail: email } : {},
],
},
include: {
items: {
include: {
product: true,
},
},
},
orderBy: {
createdAt: 'desc',
},
});
return {
orders: orders.map(order => ({
id: order.id,
status: order.status,
total: `$${order.total.toFixed(2)}`,
items: order.items.length,
createdAt: order.createdAt,
estimatedDelivery: order.estimatedDelivery,
})),
};
},
});
export const addToCartTool = tool({
description: 'Add product to shopping cart',
parameters: z.object({
productId: z.string(),
quantity: z.number().min(1).default(1),
}),
execute: async ({ productId, quantity }, context) => {
const sessionId = context.sessionId;
const cartItem = await prisma.cartItem.upsert({
where: {
sessionId_productId: {
sessionId,
productId,
},
},
create: {
sessionId,
productId,
quantity,
},
update: {
quantity: {
increment: quantity,
},
},
include: {
product: true,
},
});
return {
success: true,
item: {
product: cartItem.product.name,
quantity: cartItem.quantity,
price: `$${(cartItem.product.price * cartItem.quantity).toFixed(2)}`,
},
};
},
});
export const processPaymentTool = tool({
description: 'Process customer payment and create order',
parameters: z.object({
paymentMethod: z.enum(['credit_card', 'paypal', 'apple_pay']),
shippingAddress: z.object({
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.string(),
}),
}),
needsApproval: true, // Always require confirmation for payments
execute: async ({ paymentMethod, shippingAddress }, context) => {
const sessionId = context.sessionId;
// Get cart items
const cartItems = await prisma.cartItem.findMany({
where: { sessionId },
include: { product: true },
});
if (cartItems.length === 0) {
return { error: 'Cart is empty' };
}
// Calculate total
const total = cartItems.reduce(
(sum, item) => sum + (item.product.price * item.quantity),
0
);
// Process payment (integrate with payment provider)
const paymentResult = await paymentService.processPayment({
amount: total,
method: paymentMethod,
});
if (!paymentResult.success) {
return { error: 'Payment failed' };
}
// Create order
const order = await prisma.order.create({
data: {
customerId: context.userId,
total,
status: 'processing',
paymentMethod,
shippingAddress: JSON.stringify(shippingAddress),
items: {
create: cartItems.map(item => ({
productId: item.productId,
quantity: item.quantity,
price: item.product.price,
})),
},
},
});
// Clear cart
await prisma.cartItem.deleteMany({
where: { sessionId },
});
return {
success: true,
orderId: order.id,
total: `$${total.toFixed(2)}`,
estimatedDelivery: '3-5 business days',
};
},
});E-commerce Agent Configuration
javascript
// agents/ecommerce-agent.ts
import { ToolLoopAgent } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import {
searchProductsTool,
getOrderStatusTool,
addToCartTool,
processPaymentTool,
} from '../lib/tools/ecommerce-tools';
export const ecommerceAgent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4'),
system: `You are ShopBot, a friendly and helpful e-commerce assistant.
Your capabilities:
- Search and recommend products based on customer preferences
- Check order status and shipping information
- Add items to cart and process orders
- Answer questions about products, policies, and shipping
Guidelines:
- Be conversational and enthusiastic about products
- Always confirm before adding items to cart
- Clearly explain pricing, shipping times, and policies
- Suggest related products when relevant
- If payment is required, explain the process before proceeding
When showing products:
- Display price, availability, and ratings
- Highlight key features
- Mention if items are low in stock
- Suggest alternatives if items are out of stock`,
tools: {
searchProducts: searchProductsTool,
checkOrder: getOrderStatusTool,
addToCart: addToCartTool,
processPayment: processPaymentTool,
},
stopWhen: stepCountIs(12),
});Deploying AI Agents on Vercel
Fluid Compute for AI Agents
Vercel's Fluid Compute platform is specifically designed for AI agent workloads:
Fluid Compute Advantages:
Minimized Cold Starts:
Agents respond faster with reduced initialization time
Critical for real-time user interactions
Maintains performance during traffic spikes
Background Task Execution:
Long-running agent workflows continue after responding to users
Perfect for multi-step research or data processing
No timeout interruptions for complex operations
Extended Function Durations:
Default maximum: 60-800 seconds (plan dependent)
Configurable via
maxDurationparameterIdeal for agents that need extended processing time
Concurrent Workload Support:
Handles multiple agent requests simultaneously
No typical serverless timeout constraints
Scales automatically with demand
Production Deployment Configuration
javascript
// app/api/agent/route.ts
import { jobBoardAgent } from '@/agents/job-board-agent';
export const runtime = 'edge'; // Use Edge Runtime
export const maxDuration = 300; // 5 minutes maximum duration
export async function POST(req: Request) {
const { messages, userId } = await req.json();
try {
// Stream agent responses
const stream = await jobBoardAgent.stream({
messages,
callOptions: {
userId,
timestamp: new Date().toISOString(),
},
});
return stream.toDataStreamResponse({
headers: {
'X-Agent-Version': '1.0',
'X-Max-Steps': '20',
},
});
} catch (error) {
return new Response(
JSON.stringify({ error: 'Agent execution failed' }),
{ status: 500 }
);
}
}Environment Configuration
bash
# .env.local
# AI Provider Keys
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_GENERATIVE_AI_API_KEY=...
# Database
DATABASE_URL=postgresql://...
# Vercel AI Gateway (optional - unified model access)
AI_GATEWAY_KEY=...
# Application
NEXTAUTH_SECRET=...
NEXTAUTH_URL=https://yourdomain.comPerformance Monitoring
javascript
// Monitor agent performance with built-in telemetry
const result = await agent.generate({
prompt: userRequest,
experimental_telemetry: {
isEnabled: true,
functionId: 'job-search-agent',
metadata: {
userId: session.user.id,
requestType: 'job-search',
},
},
});
// Access telemetry data
console.log({
duration: result.usage.totalTokens,
steps: result.steps.length,
toolCalls: result.steps.filter(s => s.toolCalls.length > 0).length,
finishReason: result.finishReason,
});AI SDK vs. Other Frameworks: Comprehensive Comparison
Vercel AI SDK vs. LangChain
Bundle Size Comparison:
Vercel AI SDK: ~50 kB gzipped
LangChain JS: 101.2 kB gzipped
OpenAI SDK: 34.3 kB gzipped (minimal abstraction)
Developer Experience:
Vercel AI SDK Advantages:
Clean, functional API design
Native streaming support with React hooks
Edge runtime compatible
Type-safe tool calling out of the box
Simpler implementation (20 lines vs 100+ for same functionality)
LangChain Advantages:
More comprehensive agent frameworks
Extensive RAG (Retrieval Augmented Generation) tooling
Larger ecosystem of pre-built chains
More complex workflow orchestration
Code Comparison - Simple Chat:
javascript
// Vercel AI SDK (concise)
import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
const result = await generateText({
model: anthropic('claude-3-5-sonnet-latest'),
system: "You are Amy, a friendly assistant",
prompt: "What's your name?",
});
console.log(result.text);
// LangChain (more verbose)
import { ChatAnthropic } from '@langchain/anthropic';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
const ai = new ChatAnthropic({
model: 'claude-3-5-sonnet-latest',
temperature: 0,
});
const messages = [
new SystemMessage("You are Amy, a friendly assistant"),
new HumanMessage("What's your name?"),
];
const response = await ai.invoke(messages);
console.log(response.content);When to Choose Each:
Choose Vercel AI SDK when:
Building Next.js/React applications
Need edge deployment capability
Want streaming-first architecture
Prioritize developer experience and minimal boilerplate
Building customer-facing chat interfaces
Choose LangChain when:
Building complex RAG systems
Need extensive chain composition
Want pre-built agent templates
Working outside web frameworks (Python, standalone scripts)
Require advanced prompt management
Provider Flexibility
Vercel AI SDK Supported Providers (25+):
Major LLM Providers:
OpenAI (GPT-4, GPT-4 Turbo, GPT-3.5)
Anthropic (Claude 3.5 Sonnet, Claude 3 Opus)
Google (Gemini Pro, Gemini Ultra, PaLM)
xAI (Grok)
Mistral AI
Cohere
Enterprise Providers:
AWS Bedrock
Azure OpenAI
Vertex AI
Together AI
Audio/Speech Providers:
ElevenLabs (text-to-speech)
LMNT (voice synthesis)
Deepgram (transcription)
AssemblyAI (transcription)
Switching providers:
javascript
// Switch models with single line change
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
import { google } from '@ai-sdk/google';
// OpenAI
const result1 = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
// Anthropic - just change the model
const result2 = await generateText({
model: anthropic('claude-sonnet-4'),
prompt: 'Hello',
});
// Google - same interface
const result3 = await generateText({
model: google('gemini-pro'),
prompt: 'Hello',
});Cost Analysis and Pricing Considerations
Vercel Platform Pricing for AI Workloads
Hobby Plan (Free):
Personal and non-commercial use only
60-second function duration limit
Sufficient for demos and prototypes
Not suitable for production AI agents (conversations typically exceed 60s)
Pro Plan ($20/user/month):
Production-ready for moderate AI usage
Includes compute quotas (varies by plan)
Usage-based billing for overages
Cost drivers for AI agents:
Function execution time (billed per millisecond)
Data transfer (egress charges)
Concurrent request handling
Enterprise Plan (Custom pricing):
Custom compute limits
Dedicated support
SLA guarantees
Better for high-volume AI applications
AI Agent Cost Calculation Example
Typical AI Agent Request Costs:
Streaming chat response (30-second duration):
- Function execution: 30 seconds × memory usage
- Model API cost: $0.002 - $0.01 per request (varies by provider)
- Data transfer: ~50KB response = minimal cost
Monthly estimate for 10,000 requests:
- Vercel compute: ~$50-150 (depends on execution time)
- LLM API costs: $20-100 (OpenAI) or $15-75 (Anthropic)
- Total: $70-250/month for 10K interactionsCost Optimization Strategies:
Use Cheaper Models for Simple Tasks:
javascript
const agent = new ToolLoopAgent({
model: ({ messages }) => {
// Use cheaper model for simple queries
if (messages.length < 5) {
return openai('gpt-3.5-turbo'); // $0.0005 per 1K tokens
}
// Use powerful model for complex conversations
return openai('gpt-4-turbo'); // $0.01 per 1K tokens
},
tools: { ... },
});Implement Response Caching:
javascript
import { kv } from '@vercel/kv';
async function getCachedResponse(query: string) {
const cacheKey = `agent:${hash(query)}`;
const cached = await kv.get(cacheKey);
if (cached) {
return cached;
}
const result = await agent.generate({ prompt: query });
await kv.set(cacheKey, result.text, { ex: 3600 }); // Cache 1 hour
return result.text;
}Limit Maximum Steps:
javascript
const agent = new ToolLoopAgent({
model: openai('gpt-4'),
tools: { ... },
stopWhen: stepCountIs(5), // Prevent expensive infinite loops
});LLM Provider Costs Comparison (Feb 2026)
OpenAI Pricing:
GPT-4 Turbo: $0.01 / 1K input tokens, $0.03 / 1K output
GPT-3.5 Turbo: $0.0005 / 1K input, $0.0015 / 1K output
Anthropic Pricing:
Claude Sonnet 4: $0.003 / 1K input, $0.015 / 1K output
Claude Haiku 4: $0.00025 / 1K input, $0.00125 / 1K output
Google Pricing:
Gemini 1.5 Pro: $0.00125 / 1K input, $0.005 / 1K output
Gemini 1.5 Flash: $0.000075 / 1K input, $0.0003 / 1K output
Cost-Effective Strategy: Use cheaper models (Haiku, Flash, GPT-3.5) for initial tool calling and routing, reserve expensive models (GPT-4, Opus) for final response generation.
Advanced Agent Patterns and Best Practices
Structured Output with Tool Calling
Generate typed responses while using tools:
javascript
import { generateObject, Output } from 'ai';
import { z } from 'zod';
const result = await generateObject({
model: openai('gpt-4'),
tools: {
searchJobs: jobSearchTool,
},
output: Output.object({
summary: z.string().describe('Brief summary of job search results'),
topJobs: z.array(z.object({
title: z.string(),
company: z.string(),
matchScore: z.number().min(0).max(100),
reasoning: z.string(),
})).max(5),
recommendations: z.array(z.string()),
}),
prompt: 'Find top 5 Java jobs for senior developer with 8 years experience',
stopWhen: stepCountIs(10),
});
// Fully typed result
const { summary, topJobs, recommendations } = result.object;Agent DevTools for Debugging
AI SDK 6 includes built-in DevTools for inspecting agent behavior:
javascript
import { experimental_devtools as devtools } from 'ai';
const result = await generateText({
model: openai('gpt-4'),
tools: { database: dbTool },
prompt: 'Analyze user engagement',
experimental_devtools: devtools({
// Enable detailed logging
enabled: true,
// Custom trace handler
onTrace: (trace) => {
console.log({
duration: trace.duration,
steps: trace.steps.length,
tokens: trace.usage.totalTokens,
toolCalls: trace.steps.flatMap(s => s.toolCalls),
});
},
}),
});
// DevTools provides:
// - Output content and tool calls
// - Token usage and timing
// - Raw provider request/response dataMulti-Agent Orchestration
Coordinate multiple specialized agents:
javascript
const researchAgent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4'),
system: 'You are a research specialist',
tools: { webSearch, documentRetrieval },
});
const analysisAgent = new ToolLoopAgent({
model: openai('gpt-4'),
system: 'You are a data analyst',
tools: { calculateMetrics, generateChart },
});
const reportingAgent = new ToolLoopAgent({
model: google('gemini-pro'),
system: 'You are a report writer',
tools: { formatReport, sendEmail },
});
async function orchestrateAgents(userQuery: string) {
// Step 1: Research
const research = await researchAgent.generate({
prompt: userQuery,
});
// Step 2: Analyze research findings
const analysis = await analysisAgent.generate({
prompt: `Analyze this research: ${research.text}`,
});
// Step 3: Create and send report
const report = await reportingAgent.generate({
prompt: `Create report from analysis: ${analysis.text}`,
});
return report.text;
}Error Handling and Resilience
Implement robust error handling:
javascript
const resilientAgent = new ToolLoopAgent({
model: openai('gpt-4'),
tools: {
database: tool({
description: 'Query database',
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => {
try {
const result = await db.query(query);
return { success: true, data: result };
} catch (error) {
// Return error info for agent to handle
return {
success: false,
error: error.message,
suggestion: 'Try rephrasing the query or check data availability',
};
}
},
}),
},
onStepFinish: (step) => {
// Log each step for debugging
console.log(`Step ${step.stepType}:`, {
toolCalls: step.toolCalls.length,
finishReason: step.finishReason,
});
},
});
// Wrap in try-catch
try {
const result = await resilientAgent.generate({
prompt: userQuery,
maxRetries: 3, // Retry on failure
});
} catch (error) {
// Handle agent failures gracefully
console.error('Agent failed:', error);
return 'I encountered an error. Please try again.';
}Security and Safety Considerations
Input Validation and Sanitization
Always validate user inputs before tool execution:
javascript
const secureDatabaseTool = tool({
description: 'Execute database query',
parameters: z.object({
table: z.enum(['users', 'products', 'orders']), // Whitelist tables
operation: z.enum(['SELECT', 'COUNT', 'SUM']), // Whitelist operations
filters: z.object({
id: z.string().uuid().optional(),
email: z.string().email().optional(),
}),
}),
execute: async ({ table, operation, filters }) => {
// Sanitize inputs
const safeTable = sanitizeTableName(table);
const safeFilters = Object.entries(filters)
.filter(([_, value]) => value !== undefined)
.map(([key, value]) => `${key} = $${value}`);
// Use parameterized queries
const query = buildParameterizedQuery(safeTable, operation, safeFilters);
return await db.query(query);
},
});Rate Limiting and Abuse Prevention
javascript
import { Ratelimit } from '@upstash/ratelimit';
import { kv } from '@vercel/kv';
const ratelimit = new Ratelimit({
redis: kv,
limiter: Ratelimit.slidingWindow(10, '1 m'), // 10 requests per minute
});
export async function POST(req: Request) {
const userId = await getUserId(req);
const { success } = await ratelimit.limit(userId);
if (!success) {
return new Response('Too many requests', { status: 429 });
}
// Continue with agent execution
const result = await agent.generate({ ... });
return result.toDataStreamResponse();
}Data Privacy and Compliance
javascript
const privacyAwareAgent = new ToolLoopAgent({
model: openai('gpt-4'),
system: `You are a customer service agent.
CRITICAL PRIVACY RULES:
- Never share customer passwords or credit card numbers
- Redact sensitive information (SSN, payment details) in responses
- Only access data for authenticated user
- Log all data access for audit trails`,
tools: {
getCustomerData: tool({
description: 'Retrieve customer information',
parameters: z.object({
customerId: z.string(),
fields: z.array(z.enum([
'name', 'email', 'address', 'order_history'
// No 'password', 'payment_info', etc.
])),
}),
execute: async ({ customerId, fields }, context) => {
// Verify user authorization
if (context.userId !== customerId) {
throw new Error('Unauthorized access');
}
// Fetch only requested fields
const data = await db.customer.findUnique({
where: { id: customerId },
select: Object.fromEntries(
fields.map(f => [f, true])
),
});
// Log data access
await auditLog.create({
userId: context.userId,
action: 'data_access',
fields,
timestamp: new Date(),
});
return data;
},
}),
},
});Real-World Success Stories
Thomson Reuters CoCounsel
Challenge: Build AI assistant for attorneys, accountants, and audit teams across multiple document types and legal workflows.
Solution: Used Vercel AI SDK with 3 developers in 2 months.
Results:
Serving 1,300 accounting firms
Migrating entire codebase to AI SDK
Deprecating thousands of lines of code across 10 providers
Consolidated into one composable, scalable system
Key Implementation:
Multi-provider support for resilience
Complex document analysis workflows
Enterprise-grade security compliance
Seamless integration with existing systems
Clay Claygent
Challenge: Build AI web research agent for sales teams to find and qualify accounts.
Solution: Leveraged Vercel AI SDK's agentic capabilities and MCP integration.
Results:
Massive-scale deployment
Integration with first-party data sources
Custom, targeted prospect insights
Automated sourcing and qualification
Implementation Highlights:
Web scraping with intelligent data extraction
MCP server connections for proprietary data
Multi-step research workflows
TypeScript-first architecture for reliability
E-commerce Conversion Optimization
Challenge: SaaS company's static landing pages converting poorly from organic traffic.
Solution: AI-powered product recommendation agent with database integration.
Results:
340% increase in organic conversion rates
25% improvement in average session duration
60% reduction in page loading time
Double-digit growth in trial signups from search traffic
Technical Implementation:
Real-time inventory checking
Personalized product recommendations
Cart abandonment recovery
Dynamic pricing suggestions
Migration from AI SDK 5 to SDK 6
Automated Migration
Vercel provides automated migration tooling:
bash
# Run automated codemod
npx @ai-sdk/codemod v6
# Reviews and updates:
# - Agent configuration patterns
# - Tool definition syntax
# - Import statements
# - Type definitionsKey Breaking Changes
Agent Class to Interface:
javascript
// AI SDK 5
import { Agent } from 'ai';
const agent = new Agent({ ... });
// AI SDK 6
import { ToolLoopAgent } from 'ai';
const agent = new ToolLoopAgent({ ... });Tool Definition Updates:
javascript
// AI SDK 5
import { tool } from 'ai';
const myTool = tool({
parameters: z.object({ ... }),
execute: async (params) => { ... },
});
// AI SDK 6 (same syntax, enhanced features)
const myTool = tool({
description: 'Clear description for model',
parameters: z.object({ ... }),
execute: async (params, context) => { ... }, // Context added
needsApproval: false, // New option
experimental_toToolResultContent: (result) => { ... }, // New option
});Future of AI Agents and Vercel SDK
Emerging Patterns
Durable Workflows: Vercel's Workflow DevKit introduces persistent agent execution:
javascript
import { use } from '@vercel/workflow';
async function durableAgentWorkflow() {
// Survives crashes and restarts
const research = await use('research', () =>
researchAgent.generate({ prompt: 'Market analysis' })
);
// Checkpoint - workflow can resume from here
const analysis = await use('analysis', () =>
analysisAgent.generate({ prompt: research.text })
);
// Final step
return await use('report', () =>
reportAgent.generate({ prompt: analysis.text })
);
}Multi-Modal Agents: Expanding beyond text to images, audio, and video:
javascript
const multiModalAgent = new ToolLoopAgent({
model: openai('gpt-4-vision'),
tools: {
analyzeImage: tool({
description: 'Analyze uploaded image',
parameters: z.object({
imageUrl: z.string(),
}),
execute: async ({ imageUrl }) => {
const analysis = await vision.analyze(imageUrl);
return analysis;
},
}),
generateAudio: tool({
description: 'Generate spoken response',
parameters: z.object({
text: z.string(),
}),
execute: async ({ text }) => {
const audioUrl = await tts.generate(text);
return { audioUrl };
},
}),
},
});Industry Adoption Trends
Enterprise AI Integration:
67% of Fortune 500 companies exploring AI agents
Internal tools automation primary use case
Compliance and security top concerns
ROI demonstrated within 3-6 months
Developer Ecosystem Growth:
20M+ monthly npm downloads (Vercel AI SDK)
25+ official provider integrations
Growing marketplace of pre-built agents
Active community contributions
Getting Started: Your First AI Agent
Quick Start Checklist
✅ Set Up Development Environment
Install Node.js 18+ and npm/yarn
Create Next.js 14+ application
Install Vercel AI SDK:
npm install aiChoose and configure AI provider
✅ Define Agent Purpose
Identify specific use case (chatbot, data query, automation)
List required tools and data sources
Determine authentication requirements
Plan conversation flow
✅ Implement Basic Agent
Create tool definitions with Zod schemas
Build ToolLoopAgent with system prompt
Set up API routes for agent endpoints
Add UI components for interaction
✅ Test and Iterate
Test with realistic user queries
Monitor tool call accuracy
Refine system prompts
Add error handling
✅ Deploy to Production
Configure environment variables
Set up monitoring and logging
Implement rate limiting
Enable production optimizations
Minimal Working Example
javascript
// 1. Install dependencies
// npm install ai @ai-sdk/openai zod
// 2. Create tool
import { tool } from 'ai';
import { z } from 'zod';
const greetingTool = tool({
description: 'Greet user by name',
parameters: z.object({
name: z.string(),
}),
execute: async ({ name }) => {
return `Hello, ${name}! Welcome to our service.`;
},
});
// 3. Create agent
import { ToolLoopAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
const agent = new ToolLoopAgent({
model: openai('gpt-4'),
system: 'You are a friendly assistant',
tools: { greeting: greetingTool },
});
// 4. Use agent
const result = await agent.generate({
prompt: 'Greet me, my name is Alex',
});
console.log(result.text);
// Agent calls greetingTool and responds with personalized greetingEssential Resources and Documentation
Official Documentation
Vercel AI SDK Documentation:
Main docs: https://ai-sdk.dev/docs
Agent building: https://ai-sdk.dev/docs/agents
Tool calling: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
MCP integration: https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools
Vercel Platform:
AI agents guide: https://vercel.com/docs/agents
Fluid Compute: https://vercel.com/docs/functions/fluid-compute
Deployment: https://vercel.com/docs/deployments
Community Resources
GitHub Repository:
Source code: https://github.com/vercel/ai
Example templates: https://github.com/vercel/ai/tree/main/examples
Issue tracking: https://github.com/vercel/ai/issues
Learning Platforms:
Vercel Academy: https://vercel.com/academy/ai-sdk
YouTube tutorials: Official Vercel channel
Community Discord: Active developer community
Code Templates
Starter Templates:
Next.js chatbot: https://vercel.com/templates/next.js/nextjs-ai-chatbot
Multi-step agents: https://ai-sdk.dev/examples/next-app/agent/multi-step-call
Database integration: https://ai-sdk.dev/examples/database-agent
E-commerce assistant: Custom template in documentation
Ready to Build Production AI Agents?
Building AI agents that integrate with your application's core functionality transforms user experiences from passive consumption to active collaboration. Vercel AI SDK 6 provides the production-ready infrastructure, type safety, and developer experience needed to ship sophisticated agents quickly and confidently.
Essential Implementation Checklist:
✅ Agent Foundation - ToolLoopAgent with clear system prompts and tool definitions
✅ Database Integration - Secure, validated tool calling with Prisma/PostgreSQL
✅ Type Safety - End-to-end TypeScript types from tools to UI components
✅ Human Oversight - Tool approval workflows for sensitive operations
✅ Error Handling - Robust error recovery and user-friendly fallbacks
✅ Performance Monitoring - DevTools integration and telemetry tracking
✅ Production Deployment - Fluid Compute on Vercel with proper resource limits
The future of application development is agentic—where users describe what they want and intelligent systems execute complex workflows autonomously. Start building with Vercel AI SDK today and transform your applications from tools users operate to assistants that work for them.
Build your first agent, connect it to your database, and discover how AI can revolutionize your user experience within hours, not months.