ai-sdk-core
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAI SDK Core
AI SDK 核心模块
Backend AI with Vercel AI SDK v5 and v6.
Installation:
bash
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google zod使用Vercel AI SDK v5和v6构建后端AI。
安装步骤:
bash
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google zodAI SDK 6 (Stable - January 2026)
AI SDK 6(稳定版 - 2026年1月)
Status: Stable
Latest: ai@6.0.26 (Jan 2026)
状态: 稳定版
最新版本: ai@6.0.26(2026年1月)
BREAKING: Output API Replaces generateObject/streamObject
重大变更:Output API 替代 generateObject/streamObject
⚠️ CRITICAL: and are DEPRECATED and will be removed in a future version. Use the new Output API instead.
generateObject()streamObject()Before (v5 - DEPRECATED):
typescript
// ❌ DEPRECATED - will be removed
import { generateObject } from 'ai';
const result = await generateObject({
model: openai('gpt-5'),
schema: z.object({ name: z.string(), age: z.number() }),
prompt: 'Generate a person',
});After (v6 - USE THIS):
typescript
// ✅ NEW OUTPUT API
import { generateText, Output } from 'ai';
const result = await generateText({
model: openai('gpt-5'),
output: Output.object({ schema: z.object({ name: z.string(), age: z.number() }) }),
prompt: 'Generate a person',
});
// Access the typed object
console.log(result.object); // { name: "Alice", age: 30 }⚠️ 重要提示: 和 已被弃用,将在后续版本中移除,请使用新的Output API替代。
generateObject()streamObject()之前(v5 - 已弃用):
typescript
// ❌ 已弃用 - 将会被移除
import { generateObject } from 'ai';
const result = await generateObject({
model: openai('gpt-5'),
schema: z.object({ name: z.string(), age: z.number() }),
prompt: 'Generate a person',
});现在(v6 - 推荐使用):
typescript
// ✅ 新的OUTPUT API
import { generateText, Output } from 'ai';
const result = await generateText({
model: openai('gpt-5'),
output: Output.object({ schema: z.object({ name: z.string(), age: z.number() }) }),
prompt: 'Generate a person',
});
// 访问类型化对象
console.log(result.object); // { name: "Alice", age: 30 }Output Types
输出类型
typescript
import { generateText, Output } from 'ai';
// Object with Zod schema
output: Output.object({ schema: myZodSchema })
// Array of typed objects
output: Output.array({ schema: personSchema })
// Enum/choice from options
output: Output.choice({ choices: ['positive', 'negative', 'neutral'] })
// Plain text (explicit)
output: Output.text()
// Unstructured JSON (no schema validation)
output: Output.json()typescript
import { generateText, Output } from 'ai';
// 基于Zod schema的对象
output: Output.object({ schema: myZodSchema })
// 类型化对象数组
output: Output.array({ schema: personSchema })
// 从选项中选择枚举值
output: Output.choice({ choices: ['positive', 'negative', 'neutral'] })
// 纯文本(显式声明)
output: Output.text()
// 无结构JSON(无schema验证)
output: Output.json()Streaming with Output API
结合Output API实现流式输出
typescript
import { streamText, Output } from 'ai';
const result = streamText({
model: openai('gpt-5'),
output: Output.object({ schema: personSchema }),
prompt: 'Generate a person',
});
// Stream partial objects
for await (const partialObject of result.objectStream) {
console.log(partialObject); // { name: "Ali..." } -> { name: "Alice", age: ... }
}
// Get final object
const finalObject = await result.object;typescript
import { streamText, Output } from 'ai';
const result = streamText({
model: openai('gpt-5'),
output: Output.object({ schema: personSchema }),
prompt: 'Generate a person',
});
// 流式获取部分对象
for await (const partialObject of result.objectStream) {
console.log(partialObject); // { name: "Ali..." } -> { name: "Alice", age: ... }
}
// 获取最终完整对象
const finalObject = await result.object;v6 New Features
v6 新特性
1. Agent Abstraction
Unified interface for building agents with class:
ToolLoopAgent- Full control over execution flow, tool loops, and state management
- Replaces manual tool calling orchestration
2. Tool Execution Approval (Human-in-the-Loop)
Use selective approval for better UX. Not every tool call needs approval.
typescript
tools: {
payment: tool({
// Dynamic approval based on input
needsApproval: async ({ amount }) => amount > 1000,
inputSchema: z.object({ amount: z.number() }),
execute: async ({ amount }) => { /* process payment */ },
}),
readFile: tool({
needsApproval: false, // Safe operations don't need approval
inputSchema: z.object({ path: z.string() }),
execute: async ({ path }) => fs.readFile(path),
}),
deleteFile: tool({
needsApproval: true, // Destructive operations always need approval
inputSchema: z.object({ path: z.string() }),
execute: async ({ path }) => fs.unlink(path),
}),
}Best Practices:
- Use dynamic approval for operations where risk depends on parameters (e.g., payment amount)
- Always require approval for destructive operations (delete, modify, purchase)
- Don't require approval for safe read operations
- Add system instruction: "When a tool execution is not approved, do not retry it"
- Implement timeout for approval requests to prevent stuck states
- Store user preferences for repeat actions
Sources:
3. Reranking for RAG
typescript
import { rerank } from 'ai';
const result = await rerank({
model: cohere.reranker('rerank-v3.5'),
query: 'user question',
documents: searchResults,
topK: 5,
});4. MCP Tools (Model Context Protocol)
⚠️ SECURITY WARNING: MCP tools have significant production risks. See security section below.
typescript
import { experimental_createMCPClient } from 'ai';
const mcpClient = await experimental_createMCPClient({
transport: { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem'] },
});
const tools = await mcpClient.tools();
const result = await generateText({
model: openai('gpt-5'),
tools,
prompt: 'List files in the current directory',
});Known Issue: MCP tools may not execute in streaming mode (Vercel Community Discussion). Use instead of for MCP tools.
generateText()streamText()MCP Security Considerations
⚠️ CRITICAL: Dynamic MCP tools in production have security risks:
Risks:
- Tool definitions become part of your agent's prompt
- Can change unexpectedly without warning
- Compromised MCP server can inject malicious prompts
- New tools can escalate user privileges (e.g., adding delete to read-only server)
Solution - Use Static Tool Generation:
typescript
// ❌ RISKY: Dynamic tools change without your control
const mcpClient = await experimental_createMCPClient({ /* ... */ });
const tools = await mcpClient.tools(); // Can change anytime!
// ✅ SAFE: Generate static, versioned tool definitions
// Step 1: Install mcp-to-ai-sdk
npm install -g mcp-to-ai-sdk
// Step 2: Generate static tools (one-time, version controlled)
npx mcp-to-ai-sdk generate stdio 'npx -y @modelcontextprotocol/server-filesystem'
// Step 3: Import static tools
import { tools } from './generated-mcp-tools';
const result = await generateText({
model: openai('gpt-5'),
tools, // Static, reviewed, versioned
prompt: 'Use tools',
});Best Practice: Generate static tools, review them, commit to version control, and only update intentionally.
Source: Vercel Blog: MCP Security
5. Language Model Middleware
typescript
import { wrapLanguageModel, extractReasoningMiddleware } from 'ai';
const wrappedModel = wrapLanguageModel({
model: anthropic('claude-sonnet-4-5-20250929'),
middleware: extractReasoningMiddleware({ tagName: 'think' }),
});
// Reasoning extracted automatically from <think>...</think> tags6. Telemetry (OpenTelemetry)
typescript
const result = await generateText({
model: openai('gpt-5'),
prompt: 'Hello',
experimental_telemetry: {
isEnabled: true,
functionId: 'my-chat-function',
metadata: { userId: '123' },
recordInputs: true,
recordOutputs: true,
},
});Official Docs: https://ai-sdk.dev/docs
1. Agent抽象层
通过类提供构建Agent的统一接口:
ToolLoopAgent- 完全控制执行流程、工具循环和状态管理
- 替代手动编排工具调用的方式
2. 工具执行审批(人机协作)
使用选择性审批提升用户体验,并非所有工具调用都需要审批。
typescript
tools: {
payment: tool({
// 根据输入动态判断是否需要审批
needsApproval: async ({ amount }) => amount > 1000,
inputSchema: z.object({ amount: z.number() }),
execute: async ({ amount }) => { /* 处理支付 */ },
}),
readFile: tool({
needsApproval: false, // 安全的读取操作无需审批
inputSchema: z.object({ path: z.string() }),
execute: async ({ path }) => fs.readFile(path),
}),
deleteFile: tool({
needsApproval: true, // 破坏性操作始终需要审批
inputSchema: z.object({ path: z.string() }),
execute: async ({ path }) => fs.unlink(path),
}),
}最佳实践:
- 对于风险取决于参数的操作(如支付金额),使用动态审批
- 对于破坏性操作(删除、修改、购买),始终要求审批
- 安全的读取操作无需审批
- 添加系统指令:"当工具执行未获审批时,请勿重试"
- 为审批请求设置超时,避免流程卡住
- 存储用户对重复操作的偏好设置
参考来源:
3. RAG重排序
typescript
import { rerank } from 'ai';
const result = await rerank({
model: cohere.reranker('rerank-v3.5'),
query: 'user question',
documents: searchResults,
topK: 5,
});4. MCP工具(模型上下文协议)
⚠️ 安全警告:MCP工具在生产环境中存在重大风险,请查看下方的安全章节。
typescript
import { experimental_createMCPClient } from 'ai';
const mcpClient = await experimental_createMCPClient({
transport: { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem'] },
});
const tools = await mcpClient.tools();
const result = await generateText({
model: openai('gpt-5'),
tools,
prompt: 'List files in the current directory',
});MCP安全注意事项
⚠️ 重要提示:生产环境中使用动态MCP工具存在安全风险:
风险:
- 工具定义会成为Agent提示词的一部分
- 工具定义可能会意外变更,无预警
- 被攻陷的MCP服务器可能注入恶意提示词
- 新增工具可能提升用户权限(例如,为只读服务器添加删除权限)
解决方案 - 使用静态工具生成:
typescript
// ❌ 有风险:动态工具会不受控制地变更
const mcpClient = await experimental_createMCPClient({ /* ... */ });
const tools = await mcpClient.tools(); // 随时可能变更!
// ✅ 安全方案:生成静态、版本化的工具定义
// 步骤1:安装mcp-to-ai-sdk
npm install -g mcp-to-ai-sdk
// 步骤2:生成静态工具(一次性操作,纳入版本控制)
npx mcp-to-ai-sdk generate stdio 'npx -y @modelcontextprotocol/server-filesystem'
// 步骤3:导入静态工具
import { tools } from './generated-mcp-tools';
const result = await generateText({
model: openai('gpt-5'),
tools, // 静态、已审核、版本化
prompt: 'Use tools',
});最佳实践:生成静态工具,进行审核,提交到版本控制系统,仅在必要时更新。
参考来源:Vercel博客:MCP安全
5. 语言模型中间件
typescript
import { wrapLanguageModel, extractReasoningMiddleware } from 'ai';
const wrappedModel = wrapLanguageModel({
model: anthropic('claude-sonnet-4-5-20250929'),
middleware: extractReasoningMiddleware({ tagName: 'think' }),
});
// 自动从<think>...</think>标签中提取推理过程6. 遥测(OpenTelemetry)
typescript
const result = await generateText({
model: openai('gpt-5'),
prompt: 'Hello',
experimental_telemetry: {
isEnabled: true,
functionId: 'my-chat-function',
metadata: { userId: '123' },
recordInputs: true,
recordOutputs: true,
},
});官方文档: https://ai-sdk.dev/docs
Latest AI Models (2025-2026)
最新AI模型(2025-2026)
OpenAI
OpenAI
GPT-5.2 (Dec 2025):
- 400k context window, 128k output tokens
- Enhanced reasoning capabilities
- Available in API platform
GPT-5.1 (Nov 2025):
- Improved speed and efficiency over GPT-5
- "Warmer" and more intelligent responses
GPT-5 (Aug 2025):
- 45% less hallucination than GPT-4o
- State-of-the-art in math, coding, visual perception
o3 Reasoning Models (Dec 2025):
- o3, o3-pro, o3-mini - Advanced reasoning
- o4-mini - Fast reasoning
typescript
import { openai } from '@ai-sdk/openai';
const gpt52 = openai('gpt-5.2');
const gpt51 = openai('gpt-5.1');
const gpt5 = openai('gpt-5');
const o3 = openai('o3');
const o3mini = openai('o3-mini');GPT-5.2(2025年12月):
- 400k上下文窗口,128k输出tokens
- 增强的推理能力
- 已在API平台上线
GPT-5.1(2025年11月):
- 比GPT-5更快、更高效
- 回复更"人性化"且更智能
GPT-5(2025年8月):
- 幻觉率比GPT-4o低45%
- 在数学、编码、视觉感知领域达到最先进水平
o3推理模型(2025年12月):
- o3, o3-pro, o3-mini - 高级推理能力
- o4-mini - 快速推理
typescript
import { openai } from '@ai-sdk/openai';
const gpt52 = openai('gpt-5.2');
const gpt51 = openai('gpt-5.1');
const gpt5 = openai('gpt-5');
const o3 = openai('o3');
const o3mini = openai('o3-mini');Anthropic
Anthropic
Claude 4 Family (May-Oct 2025):
- Opus 4 (May 22): Best for complex reasoning, $15/$75 per million tokens
- Sonnet 4 (May 22): Balanced performance, $3/$15 per million tokens
- Opus 4.1 (Aug 5): Enhanced agentic tasks, real-world coding
- Sonnet 4.5 (Sept 29): Most capable for coding, agents, computer use
- Haiku 4.5 (Oct 15): Small, fast, low-latency model
typescript
import { anthropic } from '@ai-sdk/anthropic';
const sonnet45 = anthropic('claude-sonnet-4-5-20250929'); // Latest
const opus41 = anthropic('claude-opus-4-1-20250805');
const haiku45 = anthropic('claude-haiku-4-5-20251015');Claude 4系列(2025年5-10月):
- Opus 4(5月22日): 最适合复杂推理,每百万tokens费用$15/$75
- Sonnet 4(5月22日): 性能均衡,每百万tokens费用$3/$15
- Opus 4.1(8月5日): 增强Agent任务处理能力,支持实际场景编码
- Sonnet 4.5(9月29日): 最适合编码、Agent、计算机操作的版本
- Haiku 4.5(10月15日): 轻量、快速、低延迟模型
typescript
import { anthropic } from '@ai-sdk/anthropic';
const sonnet45 = anthropic('claude-sonnet-4-5-20250929'); // 最新版本
const opus41 = anthropic('claude-opus-4-1-20250805');
const haiku45 = anthropic('claude-haiku-4-5-20251015');Gemini 2.5 Family (Mar-Sept 2025):
- Pro (March 2025): Most intelligent, #1 on LMArena at launch
- Pro Deep Think (May 2025): Enhanced reasoning mode
- Flash (May 2025): Fast, cost-effective
- Flash-Lite (Sept 2025): Updated efficiency
typescript
import { google } from '@ai-sdk/google';
const pro = google('gemini-2.5-pro');
const flash = google('gemini-2.5-flash');
const lite = google('gemini-2.5-flash-lite');Gemini 2.5系列(2025年3-9月):
- Pro(2025年3月): 最智能,发布时在LMArena排名第一
- Pro Deep Think(2025年5月): 增强推理模式
- Flash(2025年5月): 快速、高性价比
- Flash-Lite(2025年9月): 优化后的高效版本
typescript
import { google } from '@ai-sdk/google';
const pro = google('gemini-2.5-pro');
const flash = google('gemini-2.5-flash');
const lite = google('gemini-2.5-flash-lite');Core Functions
核心功能
Text Generation
文本生成
generateText() - Text completion with tools
streamText() - Real-time streaming
generateText() - 支持工具调用的文本补全
streamText() - 实时流式输出
Structured Output (v6 Output API)
结构化输出(v6 Output API)
Output.object() - Typed objects with Zod schema (replaces generateObject)
Output.array() - Typed arrays
Output.choice() - Enum selection
Output.json() - Unstructured JSON
See "AI SDK 6" section above for usage examples.
Output.object() - 基于Zod schema的类型化对象(替代generateObject)
Output.array() - 类型化数组
Output.choice() - 枚举选择
Output.json() - 无结构JSON
使用示例请查看上方"AI SDK 6"章节。
Multi-Modal Capabilities
多模态能力
Speech Synthesis (Text-to-Speech)
语音合成(文本转语音)
typescript
import { experimental_generateSpeech as generateSpeech } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateSpeech({
model: openai.speech('tts-1-hd'),
voice: 'alloy',
text: 'Hello, how can I help you today?',
});
// result.audio is an ArrayBuffer containing the audio
const audioBuffer = result.audio;Supported Providers:
- OpenAI: tts-1, tts-1-hd, gpt-4o-mini-tts
- ElevenLabs: eleven_multilingual_v2, eleven_turbo_v2
- LMNT, Hume
typescript
import { experimental_generateSpeech as generateSpeech } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateSpeech({
model: openai.speech('tts-1-hd'),
voice: 'alloy',
text: 'Hello, how can I help you today?',
});
// result.audio是包含音频的ArrayBuffer
const audioBuffer = result.audio;支持的提供商:
- OpenAI: tts-1, tts-1-hd, gpt-4o-mini-tts
- ElevenLabs: eleven_multilingual_v2, eleven_turbo_v2
- LMNT, Hume
Transcription (Speech-to-Text)
语音转文字
typescript
import { experimental_transcribe as transcribe } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await transcribe({
model: openai.transcription('whisper-1'),
audio: audioFile, // File, Blob, ArrayBuffer, or URL
});
console.log(result.text); // Transcribed text
console.log(result.segments); // Timestamped segmentsSupported Providers:
- OpenAI: whisper-1
- ElevenLabs, Deepgram, AssemblyAI, Groq, Rev.ai
typescript
import { experimental_transcribe as transcribe } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await transcribe({
model: openai.transcription('whisper-1'),
audio: audioFile, // File, Blob, ArrayBuffer或URL
});
console.log(result.text); // 转录后的文本
console.log(result.segments); // 带时间戳的分段内容支持的提供商:
- OpenAI: whisper-1
- ElevenLabs, Deepgram, AssemblyAI, Groq, Rev.ai
Image Generation
图像生成
typescript
import { generateImage } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateImage({
model: openai.image('dall-e-3'),
prompt: 'A futuristic city at sunset',
size: '1024x1024',
n: 1,
});
// result.images is an array of generated images
const imageUrl = result.images[0].url;
const imageBase64 = result.images[0].base64;Supported Providers:
- OpenAI: dall-e-2, dall-e-3
- Google: imagen-3.0
- Fal AI, Black Forest Labs (Flux), Luma AI, Replicate
typescript
import { generateImage } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateImage({
model: openai.image('dall-e-3'),
prompt: 'A futuristic city at sunset',
size: '1024x1024',
n: 1,
});
// result.images是生成的图像数组
const imageUrl = result.images[0].url;
const imageBase64 = result.images[0].base64;支持的提供商:
- OpenAI: dall-e-2, dall-e-3
- Google: imagen-3.0
- Fal AI, Black Forest Labs (Flux), Luma AI, Replicate
Embeddings
向量嵌入
typescript
import { embed, embedMany, cosineSimilarity } from 'ai';
import { openai } from '@ai-sdk/openai';
// Single embedding
const result = await embed({
model: openai.embedding('text-embedding-3-small'),
value: 'Hello world',
});
console.log(result.embedding); // number[]
// Multiple embeddings (parallel processing)
const results = await embedMany({
model: openai.embedding('text-embedding-3-small'),
values: ['Hello', 'World', 'AI'],
maxParallelCalls: 5, // Parallel processing
});
// Compare similarity
const similarity = cosineSimilarity(
results.embeddings[0],
results.embeddings[1]
);
console.log(`Similarity: ${similarity}`); // 0.0 to 1.0Supported Providers:
- OpenAI: text-embedding-3-small, text-embedding-3-large
- Google: text-embedding-004
- Cohere, Voyage AI, Mistral, Amazon Bedrock
typescript
import { embed, embedMany, cosineSimilarity } from 'ai';
import { openai } from '@ai-sdk/openai';
// 单个文本嵌入
const result = await embed({
model: openai.embedding('text-embedding-3-small'),
value: 'Hello world',
});
console.log(result.embedding); // number[]
// 多个文本嵌入(并行处理)
const results = await embedMany({
model: openai.embedding('text-embedding-3-small'),
values: ['Hello', 'World', 'AI'],
maxParallelCalls: 5, // 并行处理
});
// 计算相似度
const similarity = cosineSimilarity(
results.embeddings[0],
results.embeddings[1]
);
console.log(`Similarity: ${similarity}`); // 0.0到1.0之间支持的提供商:
- OpenAI: text-embedding-3-small, text-embedding-3-large
- Google: text-embedding-004
- Cohere, Voyage AI, Mistral, Amazon Bedrock
Multi-Modal Prompts (Files, Images, PDFs)
多模态提示词(文件、图像、PDF)
typescript
import { generateText } from 'ai';
import { google } from '@ai-sdk/google';
const result = await generateText({
model: google('gemini-2.5-pro'),
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'Summarize this document' },
{ type: 'file', data: pdfBuffer, mimeType: 'application/pdf' },
],
}],
});
// Or with images
const result = await generateText({
model: openai('gpt-5'),
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'What is in this image?' },
{ type: 'image', image: imageBuffer },
],
}],
});See official docs for full API: https://ai-sdk.dev/docs/ai-sdk-core
typescript
import { generateText } from 'ai';
import { google } from '@ai-sdk/google';
const result = await generateText({
model: google('gemini-2.5-pro'),
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'Summarize this document' },
{ type: 'file', data: pdfBuffer, mimeType: 'application/pdf' },
],
}],
});
// 或者结合图像
const result = await generateText({
model: openai('gpt-5'),
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'What is in this image?' },
{ type: 'image', image: imageBuffer },
],
}],
});完整API请查看官方文档:https://ai-sdk.dev/docs/ai-sdk-core
v5 Stream Response Methods
v5 流式响应方法
When returning streaming responses from an API, use the correct method:
| Method | Output Format | Use Case |
|---|---|---|
| Plain text chunks | Simple text streaming |
| SSE with JSON events | Chat UIs (text-start, text-delta, text-end, finish) |
For chat widgets and UIs, always use :
toUIMessageStreamResponse()typescript
const result = streamText({
model: workersai('@cf/qwen/qwen3-30b-a3b-fp8'),
messages,
system: 'You are helpful.',
});
// ✅ For chat UIs - returns SSE with JSON events
return result.toUIMessageStreamResponse({
headers: { 'Access-Control-Allow-Origin': '*' },
});
// ❌ For simple text - returns plain text chunks only
return result.toTextStreamResponse();Note: does NOT exist in AI SDK v5 (common misconception).
toDataStreamResponse()从API返回流式响应时,请使用正确的方法:
| 方法 | 输出格式 | 使用场景 |
|---|---|---|
| 纯文本分片 | 简单文本流式输出 |
| 带JSON事件的SSE | 聊天UI(text-start, text-delta, text-end, finish) |
对于聊天组件和UI,始终使用:
toUIMessageStreamResponse()typescript
const result = streamText({
model: workersai('@cf/qwen/qwen3-30b-a3b-fp8'),
messages,
system: 'You are helpful.',
});
// ✅ 聊天UI使用 - 返回带JSON事件的SSE
return result.toUIMessageStreamResponse({
headers: { 'Access-Control-Allow-Origin': '*' },
});
// ❌ 简单文本使用 - 仅返回纯文本分片
return result.toTextStreamResponse();注意: AI SDK v5中不存在(常见误解)。
toDataStreamResponse()workers-ai-provider Version Compatibility
workers-ai-provider 版本兼容性
IMPORTANT: requires AI SDK v5, NOT v4.
workers-ai-provider@2.xbash
undefined重要提示: 需要AI SDK v5,不支持v4。
workers-ai-provider@2.xbash
undefined✅ Correct - AI SDK v5 with workers-ai-provider v2
✅ 正确搭配 - AI SDK v5 + workers-ai-provider v2
npm install ai@^5.0.0 workers-ai-provider@^2.0.0 zod@^3.25.0
npm install ai@^5.0.0 workers-ai-provider@^2.0.0 zod@^3.25.0
❌ Wrong - AI SDK v4 causes error
❌ 错误搭配 - AI SDK v4会导致错误
npm install ai@^4.0.0 workers-ai-provider@^2.0.0
npm install ai@^4.0.0 workers-ai-provider@^2.0.0
Error: "AI SDK 4 only supports models that implement specification version v1"
错误信息: "AI SDK 4 only supports models that implement specification version v1"
**Zod Version:** AI SDK v5 requires `zod@^3.25.0` or later for `zod/v3` and `zod/v4` exports. Older versions (3.22.x) cause build errors: "Could not resolve zod/v4".
---
**Zod版本:** AI SDK v5需要`zod@^3.25.0`或更高版本,以支持`zod/v3`和`zod/v4`导出。旧版本(3.22.x)会导致构建错误:"Could not resolve zod/v4"。
---Cloudflare Workers Startup Fix
Cloudflare Workers 启动修复
Problem: AI SDK v5 + Zod causes >270ms startup time (exceeds Workers 400ms limit).
Solution:
typescript
// ❌ BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
const workersai = createWorkersAI({ binding: env.AI });
// ✅ GOOD: Lazy initialization inside handler
app.post('/chat', async (c) => {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: c.env.AI });
// ...
});Additional:
- Minimize top-level Zod schemas
- Move complex schemas into route handlers
- Monitor startup time with Wrangler
问题: AI SDK v5 + Zod导致启动时间超过270ms(超过Workers 400ms限制)。
解决方案:
typescript
// ❌ 不良实践:顶层导入会增加启动开销
import { createWorkersAI } from 'workers-ai-provider';
const workersai = createWorkersAI({ binding: env.AI });
// ✅ 良好实践:在处理器内部延迟初始化
app.post('/chat', async (c) => {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: c.env.AI });
// ...
});额外建议:
- 尽量减少顶层Zod schema
- 将复杂schema移到路由处理器内部
- 使用Wrangler监控启动时间
v5 Tool Calling Changes
v5 工具调用变更
Breaking Changes:
- →
parameters(Zod schema)inputSchema - Tool properties: →
args,input→resultoutput - removed (now
ToolExecutionErrorcontent parts)tool-error - parameter removed → Use
maxStepsstopWhen(stepCountIs(n))
New in v5:
- Dynamic tools (add tools at runtime based on context)
- Agent class (multi-step execution with tools)
重大变更:
- →
parameters(Zod schema)inputSchema - 工具属性: →
args,input→resultoutput - 已移除(现在使用
ToolExecutionError内容片段)tool-error - 参数已移除 → 使用
maxStepsstopWhen(stepCountIs(n))
v5 新特性:
- 动态工具(根据上下文在运行时添加工具)
- Agent类(支持多步工具执行)
Critical v4→v5 Migration
关键v4→v5迁移指南
AI SDK v5 introduced extensive breaking changes. If migrating from v4, follow this guide.
AI SDK v5引入了大量重大变更。如果从v4迁移,请遵循本指南。
Breaking Changes Overview
重大变更概述
-
Parameter Renames
- →
maxTokensmaxOutputTokens - →
providerMetadataproviderOptions
-
Tool Definitions
- →
parametersinputSchema - Tool properties: →
args,input→resultoutput
-
Message Types
- →
CoreMessageModelMessage - →
MessageUIMessage - →
convertToCoreMessagesconvertToModelMessages
-
Tool Error Handling
- class removed
ToolExecutionError - Now content parts
tool-error - Enables automated retry
-
Multi-Step Execution
- →
maxStepsstopWhen - Use or
stepCountIs()hasToolCall()
-
Message Structure
- Simple string →
contentarrayparts - Parts: text, file, reasoning, tool-call, tool-result
- Simple
-
Streaming Architecture
- Single chunk → start/delta/end lifecycle
- Unique IDs for concurrent streams
-
Tool Streaming
- Enabled by default
- option removed
toolCallStreaming
-
Package Reorganization
- →
ai/rsc@ai-sdk/rsc - →
ai/react@ai-sdk/react - →
LangChainAdapter@ai-sdk/langchain
-
参数重命名
- →
maxTokensmaxOutputTokens - →
providerMetadataproviderOptions
-
工具定义
- →
parametersinputSchema - 工具属性: →
args,input→resultoutput
-
消息类型
- →
CoreMessageModelMessage - →
MessageUIMessage - →
convertToCoreMessagesconvertToModelMessages
-
工具错误处理
- 类已移除
ToolExecutionError - 现在使用内容片段
tool-error - 支持自动重试
-
多步执行
- →
maxStepsstopWhen - 使用或
stepCountIs()hasToolCall()
-
消息结构
- 简单字符串 →
content数组parts - 片段类型: text, file, reasoning, tool-call, tool-result
- 简单
-
流式架构
- 单一分片 → start/delta/end生命周期
- 为并发流分配唯一ID
-
工具流式输出
- 默认启用
- 选项已移除
toolCallStreaming
-
包结构调整
- →
ai/rsc@ai-sdk/rsc - →
ai/react@ai-sdk/react - →
LangChainAdapter@ai-sdk/langchain
Migration Examples
迁移示例
Before (v4):
typescript
import { generateText } from 'ai';
const result = await generateText({
model: openai.chat('gpt-4-turbo'),
maxTokens: 500,
providerMetadata: { openai: { user: 'user-123' } },
tools: {
weather: {
description: 'Get weather',
parameters: z.object({ location: z.string() }),
execute: async (args) => { /* args.location */ },
},
},
maxSteps: 5,
});After (v5):
typescript
import { generateText, tool, stopWhen, stepCountIs } from 'ai';
const result = await generateText({
model: openai('gpt-4-turbo'),
maxOutputTokens: 500,
providerOptions: { openai: { user: 'user-123' } },
tools: {
weather: tool({
description: 'Get weather',
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }) => { /* input.location */ },
}),
},
stopWhen: stepCountIs(5),
});之前(v4):
typescript
import { generateText } from 'ai';
const result = await generateText({
model: openai.chat('gpt-4-turbo'),
maxTokens: 500,
providerMetadata: { openai: { user: 'user-123' } },
tools: {
weather: {
description: 'Get weather',
parameters: z.object({ location: z.string() }),
execute: async (args) => { /* args.location */ },
},
},
maxSteps: 5,
});现在(v5):
typescript
import { generateText, tool, stopWhen, stepCountIs } from 'ai';
const result = await generateText({
model: openai('gpt-4-turbo'),
maxOutputTokens: 500,
providerOptions: { openai: { user: 'user-123' } },
tools: {
weather: tool({
description: 'Get weather',
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }) => { /* input.location */ },
}),
},
stopWhen: stepCountIs(5),
});Migration Checklist
迁移检查清单
- Update all to
maxTokensmaxOutputTokens - Update to
providerMetadataproviderOptions - Convert tool to
parametersinputSchema - Update tool execute functions: →
argsinput - Replace with
maxStepsstopWhen(stepCountIs(n)) - Update message types: →
CoreMessageModelMessage - Remove handling
ToolExecutionError - Update package imports (→
ai/rsc)@ai-sdk/rsc - Test streaming behavior (architecture changed)
- Update TypeScript types
- 将所有更新为
maxTokensmaxOutputTokens - 将更新为
providerMetadataproviderOptions - 将工具转换为
parametersinputSchema - 更新工具执行函数:→
argsinput - 用替换
stopWhen(stepCountIs(n))maxSteps - 更新消息类型:→
CoreMessageModelMessage - 移除相关处理
ToolExecutionError - 更新包导入路径(→
ai/rsc)@ai-sdk/rsc - 测试流式输出行为(架构已变更)
- 更新TypeScript类型
Automated Migration
自动迁移
AI SDK provides a migration tool:
bash
npx ai migrateThis will update most breaking changes automatically. Review changes carefully.
Official Migration Guide:
https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
AI SDK提供迁移工具:
bash
npx ai migrate该工具会自动修复大部分重大变更。请仔细检查变更内容。
Top 15 Errors & Solutions
15个常见错误及解决方案
1. AI_APICallError
1. AI_APICallError
Cause: API request failed (network, auth, rate limit).
Solution:
typescript
import { AI_APICallError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_APICallError) {
console.error('API call failed:', error.message);
console.error('Status code:', error.statusCode);
console.error('Response:', error.responseBody);
// Check common causes
if (error.statusCode === 401) {
// Invalid API key
} else if (error.statusCode === 429) {
// Rate limit - implement backoff
} else if (error.statusCode >= 500) {
// Provider issue - retry
}
}
}Prevention:
- Validate API keys at startup
- Implement retry logic with exponential backoff
- Monitor rate limits
- Handle network errors gracefully
原因: API请求失败(网络、认证、速率限制)。
解决方案:
typescript
import { AI_APICallError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_APICallError) {
console.error('API调用失败:', error.message);
console.error('状态码:', error.statusCode);
console.error('响应内容:', error.responseBody);
// 检查常见原因
if (error.statusCode === 401) {
// API密钥无效
} else if (error.statusCode === 429) {
// 速率限制 - 实现退避重试
} else if (error.statusCode >= 500) {
// 提供商问题 - 重试
}
}
}预防措施:
- 在启动时验证API密钥
- 实现带指数退避的重试逻辑
- 监控速率限制
- 优雅处理网络错误
2. AI_NoObjectGeneratedError
2. AI_NoObjectGeneratedError
Cause: Model didn't generate valid object matching schema.
Solution:
typescript
import { AI_NoObjectGeneratedError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: z.object({ /* complex schema */ }),
prompt: 'Generate data',
});
} catch (error) {
if (error instanceof AI_NoObjectGeneratedError) {
console.error('No valid object generated');
// Solutions:
// 1. Simplify schema
// 2. Add more context to prompt
// 3. Provide examples in prompt
// 4. Try different model (gpt-5 or claude-sonnet-4-5 for complex objects)
}
}Prevention:
- Start with simple schemas, add complexity incrementally
- Include examples in prompt: "Generate a person like: { name: 'Alice', age: 30 }"
- Use GPT-4 for complex structured output
- Test schemas with sample data first
原因: 模型未生成符合schema的有效对象。
解决方案:
typescript
import { AI_NoObjectGeneratedError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: z.object({ /* 复杂schema */ }),
prompt: 'Generate data',
});
} catch (error) {
if (error instanceof AI_NoObjectGeneratedError) {
console.error('未生成有效对象');
// 解决方案:
// 1. 简化schema
// 2. 在提示词中添加更多上下文
// 3. 在提示词中提供示例
// 4. 尝试不同模型(复杂对象推荐使用gpt-5或claude-sonnet-4-5)
}
}预防措施:
- 从简单schema开始,逐步增加复杂度
- 在提示词中包含示例:"Generate a person like: { name: 'Alice', age: 30 }"
- 复杂结构化输出使用GPT-4
- 先用样本数据测试schema
3. Worker Startup Limit (270ms+)
3. Worker启动超时(270ms+)
Cause: AI SDK v5 + Zod initialization overhead in Cloudflare Workers exceeds startup limits.
Solution:
typescript
// BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
import { complexSchema } from './schemas';
const workersai = createWorkersAI({ binding: env.AI });
// GOOD: Lazy initialization inside handler
export default {
async fetch(request, env) {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: env.AI });
// Use workersai here
}
}Prevention:
- Move AI SDK imports inside route handlers
- Minimize top-level Zod schemas
- Monitor Worker startup time (must be <400ms)
- Use Wrangler's startup time reporting
GitHub Issue: Search for "Workers startup limit" in Vercel AI SDK issues
原因: Cloudflare Workers中AI SDK v5 + Zod的初始化开销超过启动限制。
解决方案:
typescript
// 不良实践:顶层导入会增加启动开销
import { createWorkersAI } from 'workers-ai-provider';
import { complexSchema } from './schemas';
const workersai = createWorkersAI({ binding: env.AI });
// 良好实践:在处理器内部延迟初始化
export default {
async fetch(request, env) {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: env.AI });
// 在此处使用workersai
}
}预防措施:
- 将AI SDK导入移到路由处理器内部
- 尽量减少顶层Zod schema
- 监控Worker启动时间(必须<400ms)
- 使用Wrangler的启动时间报告
4. streamText Fails Silently
4. streamText 静默失败
Cause: Stream errors can be swallowed by .
createDataStreamResponseStatus: ✅ RESOLVED - Fixed in ai@4.1.22 (February 2025)
Solution (Recommended):
typescript
// Use the onError callback (added in v4.1.22)
const stream = streamText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
onError({ error }) {
console.error('Stream error:', error);
// Custom error logging and handling
},
});
// Stream safely
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}Alternative (Manual try-catch):
typescript
// Fallback if not using onError callback
try {
const stream = streamText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
} catch (error) {
console.error('Stream error:', error);
}Prevention:
- Use callback for proper error capture (recommended)
onError - Implement server-side error monitoring
- Test stream error handling explicitly
- Always log on server side in production
GitHub Issue: #4726 (RESOLVED)
原因: 流错误可能被吞噬。
createDataStreamResponse状态: ✅ 已解决 - 在ai@4.1.22版本修复(2025年2月)
解决方案(推荐):
typescript
// 使用onError回调(v4.1.22新增)
const stream = streamText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
onError({ error }) {
console.error('流错误:', error);
// 自定义错误日志和处理
},
});
// 安全处理流
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}替代方案(手动try-catch):
typescript
// 如果不使用onError回调的回退方案
try {
const stream = streamText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
} catch (error) {
console.error('流错误:', error);
}预防措施:
- 使用回调 正确捕获错误(推荐)
onError - 实现服务器端错误监控
- 显式测试流错误处理
- 生产环境中始终在服务器端记录日志
GitHub Issue: #4726(已解决)
5. AI_LoadAPIKeyError
5. AI_LoadAPIKeyError
Cause: Missing or invalid API key.
Solution:
typescript
import { AI_LoadAPIKeyError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_LoadAPIKeyError) {
console.error('API key error:', error.message);
// Check:
// 1. .env file exists and loaded
// 2. Correct env variable name (OPENAI_API_KEY)
// 3. Key format is valid (starts with sk-)
}
}Prevention:
- Validate API keys at application startup
- Use environment variable validation (e.g., zod)
- Provide clear error messages in development
- Document required environment variables
原因: API密钥缺失或无效。
解决方案:
typescript
import { AI_LoadAPIKeyError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_LoadAPIKeyError) {
console.error('API密钥错误:', error.message);
// 检查:
// 1. .env文件存在且已加载
// 2. 环境变量名称正确(OPENAI_API_KEY)
// 3. 密钥格式有效(以sk-开头)
}
}预防措施:
- 在应用启动时验证API密钥
- 使用环境变量验证(如zod)
- 在开发环境中提供清晰的错误提示
- 记录所需的环境变量
6. AI_InvalidArgumentError
6. AI_InvalidArgumentError
Cause: Invalid parameters passed to function.
Solution:
typescript
import { AI_InvalidArgumentError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
maxOutputTokens: -1, // Invalid!
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_InvalidArgumentError) {
console.error('Invalid argument:', error.message);
// Check parameter types and values
}
}Prevention:
- Use TypeScript for type checking
- Validate inputs before calling AI SDK functions
- Read function signatures carefully
- Check official docs for parameter constraints
原因: 传递给函数的参数无效。
解决方案:
typescript
import { AI_InvalidArgumentError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
maxOutputTokens: -1, // 无效参数!
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_InvalidArgumentError) {
console.error('无效参数:', error.message);
// 检查参数类型和值
}
}预防措施:
- 使用TypeScript进行类型检查
- 在调用AI SDK函数前验证输入
- 仔细阅读函数签名
- 查看官方文档了解参数约束
7. AI_NoContentGeneratedError
7. AI_NoContentGeneratedError
Cause: Model generated no content (safety filters, etc.).
Solution:
typescript
import { AI_NoContentGeneratedError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Some prompt',
});
} catch (error) {
if (error instanceof AI_NoContentGeneratedError) {
console.error('No content generated');
// Possible causes:
// 1. Safety filters blocked output
// 2. Prompt triggered content policy
// 3. Model configuration issue
// Handle gracefully:
return { text: 'Unable to generate response. Please try different input.' };
}
}Prevention:
- Sanitize user inputs
- Avoid prompts that may trigger safety filters
- Have fallback messaging
- Log occurrences for analysis
原因: 模型未生成任何内容(如安全过滤等)。
解决方案:
typescript
import { AI_NoContentGeneratedError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Some prompt',
});
} catch (error) {
if (error instanceof AI_NoContentGeneratedError) {
console.error('未生成任何内容');
// 可能原因:
// 1. 安全过滤阻止了输出
// 2. 提示词触发了内容政策
// 3. 模型配置问题
// 优雅处理:
return { text: '无法生成响应,请尝试其他输入。' };
}
}预防措施:
- 清理用户输入
- 避免可能触发安全过滤的提示词
- 提供回退消息
- 记录此类事件以便分析
8. AI_TypeValidationError
8. AI_TypeValidationError
Cause: Zod schema validation failed on generated output.
Solution:
typescript
import { AI_TypeValidationError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: z.object({
age: z.number().min(0).max(120), // Strict validation
}),
prompt: 'Generate person',
});
} catch (error) {
if (error instanceof AI_TypeValidationError) {
console.error('Validation failed:', error.message);
// Solutions:
// 1. Relax schema constraints
// 2. Add more guidance in prompt
// 3. Use .optional() for unreliable fields
}
}Prevention:
- Start with lenient schemas, tighten gradually
- Use for fields that may not always be present
.optional() - Add validation hints in field descriptions
- Test with various prompts
原因: 生成的输出未通过Zod schema验证。
解决方案:
typescript
import { AI_TypeValidationError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: z.object({
age: z.number().min(0).max(120), // 严格验证
}),
prompt: 'Generate person',
});
} catch (error) {
if (error instanceof AI_TypeValidationError) {
console.error('验证失败:', error.message);
// 解决方案:
// 1. 放宽schema约束
// 2. 在提示词中添加更多指导
// 3. 对不可靠字段使用.optional()
}
}预防措施:
- 从宽松的schema开始,逐步收紧
- 对可能不总是存在的字段使用
.optional() - 在字段描述中添加验证提示
- 使用各种提示词进行测试
9. AI_RetryError
9. AI_RetryError
Cause: All retry attempts failed.
Solution:
typescript
import { AI_RetryError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
maxRetries: 3, // Default is 2
});
} catch (error) {
if (error instanceof AI_RetryError) {
console.error('All retries failed');
console.error('Last error:', error.lastError);
// Check root cause:
// - Persistent network issue
// - Provider outage
// - Invalid configuration
}
}Prevention:
- Investigate root cause of failures
- Adjust retry configuration if needed
- Implement circuit breaker pattern for provider outages
- Have fallback providers
原因: 所有重试尝试均失败。
解决方案:
typescript
import { AI_RetryError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
maxRetries: 3, // 默认是2
});
} catch (error) {
if (error instanceof AI_RetryError) {
console.error('所有重试均失败');
console.error('最后一次错误:', error.lastError);
// 检查根本原因:
// - 持续网络问题
// - 提供商服务中断
// - 无效配置
}
}预防措施:
- 调查失败的根本原因
- 如有需要调整重试配置
- 为提供商服务中断实现断路器模式
- 提供备用提供商
10. Rate Limiting Errors
10. 速率限制错误
Cause: Exceeded provider rate limits (RPM/TPM).
Solution:
typescript
// Implement exponential backoff
async function generateWithBackoff(prompt: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await generateText({
model: openai('gpt-4-turbo'),
prompt,
});
} catch (error) {
if (error instanceof AI_APICallError && error.statusCode === 429) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
console.log(`Rate limited, waiting ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Rate limit retries exhausted');
}Prevention:
- Monitor rate limit headers
- Queue requests to stay under limits
- Upgrade provider tier if needed
- Implement request throttling
原因: 超过提供商的速率限制(RPM/TPM)。
解决方案:
typescript
// 实现指数退避
async function generateWithBackoff(prompt: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await generateText({
model: openai('gpt-4-turbo'),
prompt,
});
} catch (error) {
if (error instanceof AI_APICallError && error.statusCode === 429) {
const delay = Math.pow(2, i) * 1000; // 指数退避
console.log(`速率受限,等待${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('速率限制重试次数已耗尽');
}预防措施:
- 监控速率限制头信息
- 对请求进行排队以保持在限制内
- 如有需要升级提供商套餐
- 实现请求限流
11. TypeScript Performance with Zod
11. Zod导致的TypeScript性能问题
Cause: Complex Zod schemas slow down TypeScript type checking.
Solution:
typescript
// Instead of deeply nested schemas at top level:
// const complexSchema = z.object({ /* 100+ fields */ });
// Define inside functions or use type assertions:
function generateData() {
const schema = z.object({ /* complex schema */ });
return generateObject({ model: openai('gpt-4-turbo'), schema, prompt: '...' });
}
// Or use z.lazy() for recursive schemas:
type Category = { name: string; subcategories?: Category[] };
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(CategorySchema).optional(),
})
);Prevention:
- Avoid top-level complex schemas
- Use for recursive types
z.lazy() - Split large schemas into smaller ones
- Use type assertions where appropriate
原因: 复杂的Zod schema会减慢TypeScript类型检查速度。
解决方案:
typescript
// 不要在顶层定义深度嵌套的schema:
// const complexSchema = z.object({ /* 100+字段 */ });
// 在函数内部定义或使用类型断言:
function generateData() {
const schema = z.object({ /* 复杂schema */ });
return generateObject({ model: openai('gpt-4-turbo'), schema, prompt: '...' });
}
// 或者对递归schema使用z.lazy():
type Category = { name: string; subcategories?: Category[] };
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(CategorySchema).optional(),
})
);预防措施:
- 避免在顶层定义复杂schema
- 对递归类型使用
z.lazy() - 将大型schema拆分为较小的schema
- 在适当的地方使用类型断言
12. Invalid JSON Response (Provider-Specific)
12. 无效JSON响应(提供商特定)
Cause: Some models occasionally return invalid JSON.
Solution:
typescript
// Use built-in retry and mode selection
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
mode: 'json', // Force JSON mode (supported by GPT-4)
maxRetries: 3, // Retry on invalid JSON
});
// Or catch and retry manually:
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
});
} catch (error) {
// Retry with different model
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
});
}Prevention:
- Use when available
mode: 'json' - Prefer GPT-4 for structured output
- Implement retry logic
- Validate responses
GitHub Issue: #4302 (Imagen 3.0 Invalid JSON)
原因: 某些模型偶尔会返回无效JSON。
解决方案:
typescript
// 使用内置重试和模式选择
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
mode: 'json', // 强制JSON模式(GPT-4支持)
maxRetries: 3, // 无效JSON时重试
});
// 或者手动捕获并重试:
try {
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
});
} catch (error) {
// 使用不同模型重试
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
});
}预防措施:
- 可用时使用
mode: 'json' - 结构化输出优先使用GPT-4
- 实现重试逻辑
- 验证响应
GitHub Issue: #4302(Imagen 3.0返回无效JSON)
13. Gemini Implicit Caching Fails with Tools
13. Gemini 隐式缓存在使用工具时失效
Error: No error, but higher API costs due to disabled caching
Cause: Google Gemini 3 Flash's cost-saving implicit caching doesn't work when any tools are defined, even if never used.
Source: GitHub Issue #11513
Why It Happens: Gemini API disables caching when tools are present in the request, regardless of whether they're invoked.
Prevention:
typescript
// Conditionally add tools only when needed
const needsTools = await analyzePrompt(userInput);
const result = await generateText({
model: google('gemini-3-flash'),
tools: needsTools ? { weather: weatherTool } : undefined,
prompt: userInput,
});Impact: High - Can significantly increase API costs for repeated context
错误: 无错误提示,但因缓存禁用导致API成本增加
原因: Google Gemini 3 Flash的成本优化隐式缓存功能在定义任何工具时失效,即使工具从未被使用。
来源: GitHub Issue #11513
为什么会发生: Gemini API在请求中存在工具时会禁用缓存,无论工具是否被调用。
预防措施:
typescript
// 仅在需要时有条件地添加工具
const needsTools = await analyzePrompt(userInput);
const result = await generateText({
model: google('gemini-3-flash'),
tools: needsTools ? { weather: weatherTool } : undefined,
prompt: userInput,
});影响: 高 - 会显著增加重复上下文场景下的API成本
14. Anthropic Tool Error Results Cause JSON Parse Crash
14. Anthropic工具错误结果导致JSON解析崩溃
Error:
Cause: Anthropic provider built-in tools (web_fetch, etc.) return error objects that SDK tries to JSON.parse
Source: GitHub Issue #11856
SyntaxError: "[object Object]" is not valid JSONWhy It Happens: When Anthropic built-in tools fail (e.g., url_not_allowed), they return error objects. AI SDK incorrectly tries to parse these as JSON strings.
Prevention:
typescript
try {
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { web_fetch: { type: 'anthropic_defined', name: 'web_fetch' } },
prompt: userPrompt,
});
} catch (error) {
if (error.message.includes('is not valid JSON')) {
// Tool returned error result, handle gracefully
console.error('Tool execution failed - likely blocked URL or permission issue');
// Retry without tool or use custom tool
}
throw error;
}Impact: High - Production crashes when using Anthropic built-in tools
错误:
原因: Anthropic提供商的内置工具(如web_fetch)返回错误对象,SDK尝试将其作为JSON字符串解析。
来源: GitHub Issue #11856
SyntaxError: "[object Object]" is not valid JSON为什么会发生: 当Anthropic内置工具失败时(如url_not_allowed),它们会返回错误对象。AI SDK错误地尝试将这些对象解析为JSON字符串。
预防措施:
typescript
try {
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { web_fetch: { type: 'anthropic_defined', name: 'web_fetch' } },
prompt: userPrompt,
});
} catch (error) {
if (error.message.includes('is not valid JSON')) {
// 工具执行失败 - 可能是URL被阻止或权限问题
console.error('工具执行失败 - 可能是URL被阻止或权限问题');
// 不使用工具重试或使用自定义工具
}
throw error;
}影响: 高 - 使用Anthropic内置工具时会导致生产环境崩溃
15. Tool-Result in Assistant Message (Anthropic)
15. Assistant消息中的Tool-Result(Anthropic)
Error: Anthropic API error - in assistant message not allowed
Cause: Server-executed tools incorrectly place parts in assistant messages
Source: GitHub Issue #11855
tool-resulttool-resultWhy It Happens: When using server-executed tools (tools where runs on server, not sent to model), the AI SDK incorrectly includes parts in the assistant message. Anthropic expects tool-result only in user messages.
executetool-resultPrevention:
typescript
// Workaround: Filter messages before sending
const filteredMessages = messages.map(msg => {
if (msg.role === 'assistant') {
return {
...msg,
content: msg.content.filter(part => part.type !== 'tool-result'),
};
}
return msg;
});
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { database: databaseTool },
messages: filteredMessages,
prompt: 'Get user data',
});Impact: High - Breaks server-executed tool pattern with Anthropic provider
Status: Known issue, PR #11854 submitted
More Errors: https://ai-sdk.dev/docs/reference/ai-sdk-errors (31 total)
错误: Anthropic API错误 - 不允许出现在assistant消息中
原因: 服务器执行的工具错误地将片段放在assistant消息中
来源: GitHub Issue #11855
tool-resulttool-result为什么会发生: 当使用服务器执行的工具(在服务器运行,而非发送给模型的工具)时,AI SDK错误地在assistant消息中包含片段。Anthropic要求tool-result只能出现在user消息中。
executetool-result预防措施:
typescript
// 解决方法: 在发送前过滤消息
const filteredMessages = messages.map(msg => {
if (msg.role === 'assistant') {
return {
...msg,
content: msg.content.filter(part => part.type !== 'tool-result'),
};
}
return msg;
});
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { database: databaseTool },
messages: filteredMessages,
prompt: 'Get user data',
});影响: 高 - 破坏Anthropic提供商的服务器执行工具模式
状态: 已知问题,PR #11854已提交
Known Issues & Limitations
已知问题与限制
useChat Stale Closures with Memoized Options
useChat 与 memoized选项的闭包过时问题
Issue: When using with memoized options (common for performance), the and callbacks have stale closures and don't see updated state variables.
useChatonDataonFinishSource: GitHub Issue #11686
Reproduction:
typescript
const [count, setCount] = useState(0);
const chatOptions = useMemo(() => ({
onFinish: (message) => {
console.log('Count:', count); // ALWAYS 0, never updates!
},
}), []); // Empty deps = stale closure
const { messages, append } = useChat(chatOptions);Workaround 1 - Don't Memoize Callbacks:
typescript
const { messages, append } = useChat({
onFinish: (message) => {
console.log('Count:', count); // Now sees current count
},
});Workaround 2 - Use useRef:
typescript
const countRef = useRef(count);
useEffect(() => { countRef.current = count; }, [count]);
const chatOptions = useMemo(() => ({
onFinish: (message) => {
console.log('Count:', countRef.current); // Always current
},
}), []);问题: 当使用搭配memoized选项(常见于性能优化)时,和回调会有过时闭包,无法看到更新后的状态变量。
useChatonDataonFinish复现:
typescript
const [count, setCount] = useState(0);
const chatOptions = useMemo(() => ({
onFinish: (message) => {
console.log('Count:', count); // 始终为0,从未更新!
},
}), []); // 空依赖 = 过时闭包
const { messages, append } = useChat(chatOptions);解决方法1 - 不要Memoize回调:
typescript
const { messages, append } = useChat({
onFinish: (message) => {
console.log('Count:', count); // 现在可以看到当前count
},
});解决方法2 - 使用useRef:
typescript
const countRef = useRef(count);
useEffect(() => { countRef.current = count; }, [count]);
const chatOptions = useMemo(() => ({
onFinish: (message) => {
console.log('Count:', countRef.current); // 始终为当前值
},
}), []);Stream Resumption Fails on Tab Switch
切换标签页时流恢复失败
Issue: When users switch browser tabs or background the app during an AI stream, the stream does not resume when they return. The connection is lost and does not automatically reconnect.
Source: GitHub Issue #11865
Impact: High - Major UX issue for long-running streams
Workaround 1 - Implement onError Handler:
typescript
const { messages, append, reload } = useChat({
api: '/api/chat',
onError: (error) => {
if (error.message.includes('stream') || error.message.includes('aborted')) {
// Attempt to reload last message
reload();
}
},
});Workaround 2 - Detect Visibility Change:
typescript
useEffect(() => {
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
// Check if stream was interrupted
const lastMessage = messages[messages.length - 1];
if (lastMessage?.role === 'assistant' && !lastMessage.content) {
reload();
}
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, [messages, reload]);Status: Known limitation, no auto-reconnection built-in
问题: 当用户在AI流输出期间切换浏览器标签页或让应用进入后台,返回时流无法恢复。连接会丢失且不会自动重连。
影响: 高 - 对长时间运行的流来说是重大UX问题
解决方法1 - 实现onError处理器:
typescript
const { messages, append, reload } = useChat({
api: '/api/chat',
onError: (error) => {
if (error.message.includes('stream') || error.message.includes('aborted')) {
// 尝试重新加载最后一条消息
reload();
}
},
});解决方法2 - 检测可见性变化:
typescript
useEffect(() => {
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
// 检查流是否被中断
const lastMessage = messages[messages.length - 1];
if (lastMessage?.role === 'assistant' && !lastMessage.content) {
reload();
}
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, [messages, reload]);状态: 已知限制,无内置自动重连功能
When to Use This Skill
何时使用本技能
Use ai-sdk-core when:
当你需要以下场景时使用ai-sdk-core:
- Building backend AI features (server-side text generation)
- Implementing server-side text generation (Node.js, Workers, Next.js)
- Creating structured AI outputs (JSON, forms, data extraction)
- Building AI agents with tools (multi-step workflows)
- Integrating multiple AI providers (OpenAI, Anthropic, Google, Cloudflare)
- Migrating from AI SDK v4 to v5
- Encountering AI SDK errors (AI_APICallError, AI_NoObjectGeneratedError, etc.)
- Using AI in Cloudflare Workers (with workers-ai-provider)
- Using AI in Next.js Server Components/Actions
- Need consistent API across different LLM providers
- 构建后端AI功能(服务器端文本生成)
- 实现服务器端文本生成(Node.js, Workers, Next.js)
- 创建结构化AI输出(JSON、表单、数据提取)
- 构建带工具的AI Agent(多步工作流)
- 集成多个AI提供商(OpenAI, Anthropic, Google, Cloudflare)
- 从AI SDK v4迁移到v5
- 遇到AI SDK错误(AI_APICallError, AI_NoObjectGeneratedError等)
- 在Cloudflare Workers中使用AI(搭配workers-ai-provider)
- 在Next.js Server Components/Actions中使用AI
- 需要在不同LLM提供商间使用一致的API
Don't use this skill when:
不要在以下场景使用本技能:
- Building React chat UIs (use ai-sdk-ui skill instead)
- Need frontend hooks like useChat (use ai-sdk-ui skill instead)
- Need advanced topics like embeddings or image generation (check official docs)
- Building native Cloudflare Workers AI apps without multi-provider (use cloudflare-workers-ai skill instead)
- Need Generative UI / RSC (see https://ai-sdk.dev/docs/ai-sdk-rsc)
- 构建React聊天UI(请使用ai-sdk-ui技能)
- 需要前端hooks如useChat(请使用ai-sdk-ui技能)
- 需要向量嵌入或图像生成等高级主题(请查看官方文档)
- 构建原生Cloudflare Workers AI应用且不需要多提供商支持(请使用cloudflare-workers-ai技能)
- 需要生成式UI / RSC(查看https://ai-sdk.dev/docs/ai-sdk-rsc)
Versions
版本信息
AI SDK:
- Stable: ai@6.0.26 (Jan 2026)
- ⚠️ Skip v6.0.40 - Breaking streaming change (reverted in v6.0.41)
- Legacy v5: ai@5.0.117 (ai-v5 tag)
- Zod 3.x/4.x both supported
Latest Models (2026):
- OpenAI: GPT-5.2, GPT-5.1, GPT-5, o3, o3-mini, o4-mini
- Anthropic: Claude Sonnet 4.5, Opus 4.1, Haiku 4.5
- Google: Gemini 2.5 Pro/Flash/Lite
Check Latest:
bash
npm view ai version
npm view ai dist-tagsAI SDK:
- 稳定版: ai@6.0.26(2026年1月)
- ⚠️ 跳过v6.0.40 - 流式输出重大变更(已在v6.0.41中回滚)
- 旧版v5: ai@5.0.117(ai-v5标签)
- 同时支持Zod 3.x/4.x
2026年最新模型:
- OpenAI: GPT-5.2, GPT-5.1, GPT-5, o3, o3-mini, o4-mini
- Anthropic: Claude Sonnet 4.5, Opus 4.1, Haiku 4.5
- Google: Gemini 2.5 Pro/Flash/Lite
检查最新版本:
bash
npm view ai version
npm view ai dist-tagsOfficial Docs
官方文档
Core:
- AI SDK v6: https://ai-sdk.dev/docs
- AI SDK Core: https://ai-sdk.dev/docs/ai-sdk-core/overview
- Output API: https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data
- v4→v5 Migration: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- All Errors (31): https://ai-sdk.dev/docs/reference/ai-sdk-errors
- Providers (69+): https://ai-sdk.dev/providers/overview
Multi-Modal:
- Speech: https://ai-sdk.dev/docs/ai-sdk-core/speech
- Transcription: https://ai-sdk.dev/docs/ai-sdk-core/transcription
- Image Generation: https://ai-sdk.dev/docs/ai-sdk-core/image-generation
- Embeddings: https://ai-sdk.dev/docs/ai-sdk-core/embeddings
GitHub:
- Repository: https://github.com/vercel/ai
- Issues: https://github.com/vercel/ai/issues
Last Updated: 2026-01-20
Skill Version: 2.1.0
Changes: Added 3 new errors (Gemini caching, Anthropic tool errors, tool-result placement), MCP security guidance, tool approval best practices, React hooks edge cases, stream resumption workarounds
AI SDK: 6.0.26 stable (avoid v6.0.40)
核心文档:
- AI SDK v6: https://ai-sdk.dev/docs
- AI SDK Core: https://ai-sdk.dev/docs/ai-sdk-core/overview
- Output API: https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data
- v4→v5迁移指南: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- 所有错误(31个): https://ai-sdk.dev/docs/reference/ai-sdk-errors
- 提供商(69+): https://ai-sdk.dev/providers/overview
多模态文档:
- 语音: https://ai-sdk.dev/docs/ai-sdk-core/speech
- 语音转文字: https://ai-sdk.dev/docs/ai-sdk-core/transcription
- 图像生成: https://ai-sdk.dev/docs/ai-sdk-core/image-generation
- 向量嵌入: https://ai-sdk.dev/docs/ai-sdk-core/embeddings
GitHub:
最后更新: 2026-01-20
技能版本: 2.1.0
变更内容: 新增3个错误(Gemini缓存、Anthropic工具错误、tool-result放置)、MCP安全指导、工具审批最佳实践、React hooks边缘情况、流恢复解决方法
AI SDK版本: 6.0.26稳定版(避免使用v6.0.40)