前置阅读:建议先阅读 Vercel AI SDK 指南 了解基础概念。
关键概念:Vercel AI SDK 3.0+ 将核心拆分为
ai(通用接口)、@ai-sdk/provider(提供商协议)和@ai-sdk/react(前端 Hooks),实现了模型无关的 AI 应用开发。
核心架构与包结构
┌─────────────────┐ │ @ai-sdk/react │ ← useChat / useCompletion / useObject (前端 Hooks) ├─────────────────┤ │ ai │ ← streamText / generateObject / embed (核心运行时) ├─────────────────┤ │ @ai-sdk/openai │ ← OpenAI 提供商适配 │ @ai-sdk/anthropic│ ← Anthropic 适配 │ @ai-sdk/google │ ← Google Gemini 适配 │ @ai-sdk/mistral │ ← Mistral 适配 │ ... │ └─────────────────┘包 职责 典型使用场景 ai通用 AI 运行时 Server Action / API Route 中调用 @ai-sdk/openaiOpenAI 提供商 gpt-4o/gpt-4o-mini模型@ai-sdk/reactReact Hooks 前端流式 UI 组件 @ai-sdk/svelteSvelte 支持 SvelteKit 项目 npm install ai @ai-sdk/openai @ai-sdk/react zodAI SDK 3.0+ 的演进与 Breaking Changes
Vercel AI SDK 经历了从 2.x 到 3.x 的重大架构重构,核心目标是解耦模型提供商与运行时逻辑,使代码具备更强的可移植性。
3.x 相比 2.x 的关键变化:
- 包拆分:旧版所有功能集中在
ai包中,3.x 将 provider 相关逻辑拆分到独立的@ai-sdk/*命名空间,安装体积减小约 40%。 - Provider 协议标准化:引入
@ai-sdk/provider规范,任何第三方模型都能通过实现LanguageModelV1接口接入 AI SDK,无需等待官方适配。 - 新版 React Hooks:
useChat/useCompletion的返回值和事件流在 3.1+ 中重新设计,支持更细粒度的toolInvocations状态追踪,废弃了旧版的experimental_前缀 API。 - RSC(React Server Components)深度集成:
ai/rsc子路径提供createStreamableValue/useStreamableValue,使 Server Action 流式传输不再需要ReadableStream的手动封装。
迁移指南(2.x → 3.x):
// ❌ 2.x 写法 import { OpenAIStream, StreamingTextResponse } from 'ai'; const stream = OpenAIStream(response); return new StreamingTextResponse(stream); // ✅ 3.x 写法 import { streamText } from 'ai'; import { openai } from '@ai-sdk/openai'; const result = streamText({ model: openai('gpt-4o'), prompt: '...' }); return result.toDataStreamResponse();Core API 全景:
ai包提供六大核心函数,覆盖 90% 的 LLM 交互场景:API 模式 输出 适用场景 generateText同步 字符串 短文本、确定性回复 streamText流式 字符串流 Chat UI、长文本生成 generateObject同步 Zod 对象 类型安全的结构化数据 streamObject流式 部分对象流 渐进式表单/卡片渲染 embed同步 向量数组 单条文本 Embedding embedMany批量 向量数组 文档集批量向量化 - 包拆分:旧版所有功能集中在
类型安全的结构化输出(generateObject)
相比 JSON 模式,
generateObject提供编译期类型安全 + 运行时校验:// app/api/analyze/route.ts import { openai } from "@ai-sdk/openai"; import { generateObject } from "ai"; import { z } from "zod"; const AnalysisSchema = z.object({ sentiment: z.enum(["positive", "neutral", "negative"]), confidence: z.number().min(0).max(1), keyTopics: z.array(z.string()).max(5), actionItems: z.array(z.object({ priority: z.enum(["high", "medium", "low"]), description: z.string(), })).max(3), }); export type AnalysisResult = z.infer<typeof AnalysisSchema>; export async function POST(req: Request) { const { text } = await req.json(); const { object } = await generateObject({ model: openai("gpt-4o-mini"), schema: AnalysisSchema, prompt: `Analyze the following text and return structured insights:\n\n${text}`, // 自动重试策略:如果解析失败,最多重试 3 次 maxRetries: 3, }); return Response.json(object); // 类型为 AnalysisResult }前端 Hook 版本(
useObject):// app/components/Analyzer.tsx "use client"; import { useObject } from "@ai-sdk/react"; export function Analyzer() { const { object, submit, isLoading } = useObject({ api: "/api/analyze", schema: AnalysisSchema, }); return ( <div> <button onClick={() => submit("Our Q3 revenue grew 45% QoQ...")}> Analyze </button> {isLoading && <span>Processing...</span>} {object && ( <div> <p>Sentiment: {object.sentiment} ({object.confidence})</p> <ul>{object.keyTopics?.map(t => <li key={t}>{t}</li>)}</ul> </div> )} </div> ); }复杂 Schema 与嵌套类型处理
真实业务场景中,AI 生成的数据结构远比基础平面对象复杂。
generateObject与streamObject对 zod 高级类型的支持,让深嵌套、联合类型、数组结构的输出同样具备类型安全。嵌套对象与数组验证:
const ProductCatalogSchema = z.object({ category: z.string(), products: z.array(z.object({ id: z.string().uuid(), name: z.string().min(1).max(100), price: z.number().positive(), tags: z.array(z.string()).min(1).max(5), metadata: z.record(z.string(), z.union([z.string(), z.number()])), })).min(1).max(20), }); const { object } = await generateObject({ model: openai('gpt-4o'), schema: ProductCatalogSchema, prompt: 'Generate a catalog of 3 fictional AI-powered developer tools...', }); // object.products[0].metadata 的类型为 Record<string, string | number>联合类型(z.union)与 discriminated union:当输出可能是多种形态之一时,使用
z.discriminatedUnion让模型通过type字段自动路由:const EventSchema = z.discriminatedUnion('type', [ z.object({ type: z.literal('click'), elementId: z.string(), timestamp: z.number() }), z.object({ type: z.literal('scroll'), scrollTop: z.number(), timestamp: z.number() }), z.object({ type: z.literal('input'), fieldName: z.string(), value: z.string(), timestamp: z.number() }), ]); const { object: event } = await generateObject({ model: openai('gpt-4o-mini'), schema: EventSchema, prompt: 'Generate a user interaction event for an e-commerce checkout page.', }); // TypeScript 自动推断 event.type 为 'click' | 'scroll' | 'input'生成失败重试与降级策略:复杂 Schema 的解析失败率高于简单对象,可结合
maxRetries与备用模型实现自动降级:async function generateWithFallback<T>(schema: z.ZodSchema<T>, prompt: string): Promise<T> { const models = [openai('gpt-4o'), anthropic('claude-3-5-sonnet-20241022')]; for (const model of models) { try { const { object } = await generateObject({ model, schema, prompt, maxRetries: 2 }); return object; } catch (err) { console.warn(`Schema generation failed with ${model.modelId}:`, err); } } throw new Error('All models failed to generate valid schema.'); }流式对象生成(streamObject)与部分解析:
streamObject允许在对象未完全生成时开始渲染,配合useObjectHook 实现实时填充 React 表单:// app/api/stream-form/route.ts import { streamObject } from 'ai'; export async function POST(req: Request) { const { description } = await req.json(); const result = streamObject({ model: openai('gpt-4o-mini'), schema: z.object({ title: z.string(), description: z.string(), priority: z.enum(['low', 'medium', 'high']), tags: z.array(z.string()), }), prompt: `Generate a task form from: ${description}`, }); return result.toTextStreamResponse(); }// app/components/TaskForm.tsx 'use client'; import { useObject } from '@ai-sdk/react'; export function TaskForm() { const { object, submit, isLoading } = useObject({ api: '/api/stream-form', schema: z.object({ title: z.string(), description: z.string(), priority: z.enum(['low','medium','high']), tags: z.array(z.string()) }), }); return ( <form> <input value={object?.title ?? ''} onChange={() => {}} placeholder="Title" /> <textarea value={object?.description ?? ''} onChange={() => {}} placeholder="Description" /> <select value={object?.priority ?? 'medium'}> <option value="low">Low</option> <option value="medium">Medium</option> <option value="high">High</option> </select> <div>{object?.tags?.map(t => <span key={t} className="tag">{t}</span>)}</div> <button type="button" onClick={() => submit('Create a high-priority bug fix task for login page')}>AI 填充</button> </form> ); }流式对象的核心优势在于首字节时间(约 200-400ms)即可渲染第一个字段,用户无需等待整段 JSON 完成。
流式工具调用(streamText + tools)
核心优势:工具执行状态实时流回前端,无需等待完整响应:
// app/api/chat/route.ts import { streamText, tool } from "ai"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; const weatherTool = tool({ description: "Get current weather for a location", parameters: z.object({ city: z.string().describe("City name in English"), unit: z.enum(["celsius", "fahrenheit"]).default("celsius"), }), execute: async ({ city, unit }) => { // 实际调用天气 API const res = await fetch( `https://api.weather.example.com/v1/current?city=${city}&unit=${unit}` ); return res.json(); }, }); const calculatorTool = tool({ description: "Perform calculations", parameters: z.object({ expression: z.string().describe("Math expression, e.g. '15 * 23'"), }), execute: async ({ expression }) => { // 安全评估:限制为数学表达式 const safeExpr = expression.replace(/[^0-9+\-*/().\s]/g, ""); return { result: Function(""return ${safeExpr}`)() }; }, }); export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: openai("gpt-4o"), messages, tools: { weather: weatherTool, calculator: calculatorTool }, maxSteps: 5, // 允许模型自主执行最多 5 轮工具调用 }); return result.toDataStreamResponse(); }前端消费流式工具状态:
// app/components/Chat.tsx "use client"; import { useChat } from "@ai-sdk/react"; export function Chat() { const { messages, input, handleInputChange, handleSubmit, toolInvocations } = useChat({ api: "/api/chat", }); return ( <div> {messages.map(m => ( <div key={m.id}> <strong>{m.role}:</strong> {m.content} {m.toolInvocations?.map(tool => ( <div key={tool.toolCallId} className="tool-call"> <span>🔧 Calling {tool.toolName}...</span> {tool.state === "result" && ( <pre>{JSON.stringify(tool.result, null, 2)}</pre> )} </div> ))} </div> ))} <form onSubmit={handleSubmit}> <input value={input} onChange={handleInputChange} placeholder="Ask about weather or math..." /> </form> </div> ); }多步 Agent 与自主工具调用
AI SDK 3.0+ 的
maxSteps参数不仅仅是限制轮数,它实际上驱动了一个隐式的 Agent 循环:模型决定调用工具 → 工具执行返回结果 → 结果追加到消息历史 → 模型再次推理 → 直到得出最终答案或达到最大步数。Agent 循环原理:
const result = streamText({ model: openai('gpt-4o'), messages: history, tools: { search: searchTool, calculate: calcTool }, maxSteps: 10, // 每一步之间的回调,可用于状态追踪 onStepFinish: async ({ text, toolCalls, toolResults, finishReason, usage }) => { console.log(`Step finished: ${finishReason}, tokens: ${usage?.totalTokens}`); }, });在循环中,AI SDK 自动维护
messages上下文。工具调用的结果通过toolResults重新注入到对话中,使模型具备"看到"工具返回并继续思考的能力。状态机模式实现多步任务:对于需要严格阶段控制的复杂任务(如:数据查询 → 计算聚合 → 生成报告),可在外层封装状态机:
type AgentState = 'idle' | 'querying' | 'calculating' | 'summarizing' | 'done'; interface AgentContext { state: AgentState; data: Record<string, unknown>; history: CoreMessage[]; } async function runMultiStepAgent(goal: string): Promise<string> { const ctx: AgentContext = { state: 'idle', data: {}, history: [{ role: 'user', content: goal }] }; while (ctx.state !== 'done' && ctx.history.length < 20) { const result = await generateText({ model: openai('gpt-4o'), messages: ctx.history, tools: { queryDatabase: tool({ description: 'Query the sales database', parameters: z.object({ sql: z.string() }), execute: async ({ sql }) => { /* ... */ }, }), calculate: tool({ description: 'Perform aggregation', parameters: z.object({ expression: z.string() }), execute: async ({ expression }) => { /* ... */ }, }), summarize: tool({ description: 'Generate final report', parameters: z.object({ findings: z.string() }), execute: async ({ findings }) => { ctx.state = 'done'; return findings; }, }), }, maxSteps: 5, }); ctx.history.push({ role: 'assistant', content: result.text }); // 根据工具调用结果更新状态 if (result.toolCalls.some(t => t.toolName === 'queryDatabase')) ctx.state = 'querying'; if (result.toolCalls.some(t => t.toolName === 'calculate')) ctx.state = 'calculating'; if (result.toolCalls.some(t => t.toolName === 'summarize')) ctx.state = 'done'; } return ctx.history[ctx.history.length - 1].content as string; }与 LangChain Agent 模式对比:
维度 Vercel AI SDK Agent LangChain Agent 运行时 Edge / Node.js / Browser 主要 Node.js 流式支持 原生 streamText实时流需额外封装 CallbackHandler状态管理 轻量,自定义状态机 内置 AgentExecutor,较重工具定义 zod schema + tool()函数StructuredTool类集成成本 低,直接绑定 Next.js 中等,需配置 Chain 和 Memory 社区生态 Vercel / Next.js 生态 更广泛的第三方集成 对于以 Next.js 为技术栈、追求流式 UI 体验的项目,AI SDK 的原生 Agent 模式在延迟和开发效率上具有显著优势。
多模型路由与故障回退
// lib/ai-router.ts import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; import { google } from "@ai-sdk/google"; import { LanguageModel } from "ai"; type ModelTier = "fast" | "balanced" | "quality"; type TaskType = "chat" | "code" | "analysis" | "creative"; const MODEL_REGISTRY: Record<ModelTier, Record<TaskType, LanguageModel[]>> = { fast: { chat: [openai("gpt-4o-mini"), google("gemini-1.5-flash")], code: [openai("gpt-4o-mini")], analysis: [google("gemini-1.5-flash")], creative: [openai("gpt-4o-mini")], }, balanced: { chat: [openai("gpt-4o"), anthropic("claude-3-5-sonnet-20241022")], code: [anthropic("claude-3-5-sonnet-20241022"), openai("gpt-4o")], analysis: [openai("gpt-4o")], creative: [anthropic("claude-3-5-sonnet-20241022")], }, quality: { chat: [anthropic("claude-3-opus-20240229"), openai("gpt-4o")], code: [anthropic("claude-3-opus-20240229")], analysis: [openai("gpt-4o")], creative: [anthropic("claude-3-opus-20240229")], }, }; export class ModelRouter { async routeWithFallback( tier: ModelTier, task: TaskType, promptFn: (model: LanguageModel) => Promise<any> ): Promise<{ result: any; model: string; attempts: number }> { const candidates = MODEL_REGISTRY[tier][task]; let lastError: Error | null = null; for (let i = 0; i < candidates.length; i++) { try { const result = await promptFn(candidates[i]); return { result, model: candidates[i].modelId, attempts: i + 1, }; } catch (err) { lastError = err as Error; console.warn(`Model ${candidates[i].modelId} failed:`, err.message); // 指数退避 await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000)); } } throw new Error( `All ${candidates.length} models failed. Last error: ${lastError?.message}` ); } } // 使用示例:Route 并自动降级 const router = new ModelRouter(); const { result, model, attempts } = await router.routeWithFallback( "balanced", "code", async (model) => { const { text } = await generateText({ model, prompt: "Explain async/await in Python" }); return text; } ); console.log(`Used ${model} after ${attempts} attempt(s)`);成本优化与 Token 预算管理
在生产环境中,LLM 调用成本是仅次于模型质量的考量因素。不同模型的 Token 定价差异可达 30 倍以上,合理的成本控制策略直接影响项目的可持续性。
主流模型 Token 定价对比(每百万 Token / 2025):
模型 Input (USD) Output (USD) 上下文长度 gpt-4o-mini $0.15 $0.60 128K gemini-1.5-flash $0.075 $0.30 1M gpt-4o $2.50 $10.00 128K claude-3-5-sonnet $3.00 $15.00 200K claude-3-opus $15.00 $75.00 200K 以上数据表明,简单任务使用 gpt-4o-mini 比 claude-3-opus 便宜约 125 倍。
请求前 Token 预估:使用
js-tiktoken在服务端预估 Prompt Token 数量,据此动态选择模型:import { encoding_for_model } from 'tiktoken'; function estimateTokens(text: string, model: string): number { const enc = encoding_for_model(model as any); const tokens = enc.encode(text); enc.free(); return tokens.length; } function selectModel(prompt: string, complexity: 'low' | 'medium' | 'high'): LanguageModel { const tokenCount = estimateTokens(prompt, 'gpt-4o'); if (tokenCount > 16000 || complexity === 'high') return openai('gpt-4o'); if (tokenCount > 4000 || complexity === 'medium') return anthropic('claude-3-5-sonnet-20241022'); return openai('gpt-4o-mini'); }月度预算上限实现:结合 Redis 或内存存储实现硬限制与软告警:
import { kv } from '@vercel/kv'; const MONTHLY_BUDGET_USD = 500; const SOFT_ALERT_THRESHOLD = 0.8; async function checkBudget(costCents: number): Promise<{ allowed: boolean; alert?: string }> { const key = `ai:cost:${new Date().toISOString().slice(0, 7)}`; // YYYY-MM const currentCents = await kv.incrby(key, costCents); await kv.expire(key, 60 * 60 * 24 * 40); // 40 days TTL const currentUsd = currentCents / 100; if (currentUsd > MONTHLY_BUDGET_USD) { return { allowed: false, alert: `Budget exceeded: $${currentUsd.toFixed(2)} / $${MONTHLY_BUDGET_USD}` }; } if (currentUsd > MONTHLY_BUDGET_USD * SOFT_ALERT_THRESHOLD) { return { allowed: true, alert: `Budget warning: $${currentUsd.toFixed(2)} / $${MONTHLY_BUDGET_USD}` }; } return { allowed: true }; }动态模型选择策略:基于任务特征进行模型路由,在质量与成本之间取得平衡。常见规则包括:分类/提取用轻量模型、代码/复杂推理用 sonnet、创意/长文本用 opus 或 gpt-4o。建议配合 A/B 测试持续校准各任务的质量门槛值。
Server Action 集成(Next.js App Router)
无需 API Route,直接在 Server Action 中调用 AI SDK:
// app/actions/generate.ts "use server"; import { generateText, streamText } from "ai"; import { openai } from "@ai-sdk/openai"; import { createStreamableValue } from "ai/rsc"; // 同步生成 export async function generateSummary(content: string) { const { text } = await generateText({ model: openai("gpt-4o-mini"), prompt: `Summarize in 3 bullet points:\n${content}`, }); return text; } // 流式生成(Server Component 流式传输) export async function streamSummary(content: string) { const stream = createStreamableValue(""); (async () => { const { textStream } = await streamText({ model: openai("gpt-4o-mini"), prompt: `Summarize:\n${content}`, }); for await (const delta of textStream) { stream.update(delta); } stream.done(); })(); return stream.value; }// app/components/Summary.tsx import { useStreamableValue } from "ai/rsc"; import { streamSummary } from "@/app/actions/generate"; export async function SummaryCard({ content }: { content: string }) { const stream = await streamSummary(content); return <StreamingContent stream={stream} />; } "use client"; function StreamingContent({ stream }: { stream: any }) { const [text] = useStreamableValue(stream); return <div className="whitespace-pre-wrap">{text}</div>; }Vercel KV / Edge Config 与 AI SDK 的缓存策略
LLM 调用成本高昂且速度受限,对常见查询启用缓存是最立竿见影的优化手段。Vercel KV(基于 Redis)与 Edge Config 是部署在边缘的缓存基础设施,天然适配 AI SDK 的流式响应。
缓存键设计:缓存键应当精确标识请求的"语义等价性",同时包含影响输出的参数:
import { createHash } from 'crypto'; function createCacheKey(prompt: string, model: string, temperature: number): string { const hash = createHash('sha256').update(prompt).digest('hex').slice(0, 16); return `ai:cache:${model}:${temperature}:${hash}`; }实现 LLM 响应缓存层:
import { kv } from '@vercel/kv'; import { generateText, streamText } from 'ai'; async function cachedGenerateText( model: LanguageModel, prompt: string, options?: { ttl?: number; temperature?: number } ) { const key = createCacheKey(prompt, model.modelId, options?.temperature ?? 0.7); const cached = await kv.get<string>(key); if (cached) { console.log('Cache hit for', model.modelId); return { text: cached, fromCache: true }; } const { text } = await generateText({ model, prompt, temperature: options?.temperature }); await kv.set(key, text, { ex: options?.ttl ?? 3600 * 24 }); // 默认 24h TTL return { text, fromCache: false }; }差异化 TTL 策略:根据查询类型设置不同的缓存有效期,在命中率与响应新鲜度之间取得平衡:
const TTL_STRATEGY: Record<string, number> = { 'faq': 3600 * 24 * 7, // FAQ 类:7 天 'code-example': 3600 * 24, // 代码示例:1 天 'creative': 3600, // 创意内容:1 小时 'news-summary': 1800, // 新闻摘要:30 分钟 }; function determineTTL(prompt: string): number { if (prompt.includes('write') || prompt.includes('create')) return TTL_STRATEGY.creative; if (prompt.includes('news') || prompt.includes('latest')) return TTL_STRATEGY['news-summary']; if (prompt.includes('how to') || prompt.includes('example')) return TTL_STRATEGY['code-example']; return TTL_STRATEGY.faq; }边缘缓存减少 API 调用成本:将高频查询的缓存预热到 Edge Config(只读、极低延迟),KV 用于动态缓存。配合 Next.js 的
revalidate机制,可实现近乎零延迟的 AI 响应。RAG 集成实战
RAG(Retrieval-Augmented Generation,检索增强生成)是构建知识库问答系统的标准架构。使用 AI SDK 与向量数据库,可高效实现文档 Embedding、语义检索与生成的完整闭环。
文档分块与 Embedding 生成:长文档需要先切分为语义连贯的段落,每段控制在 512-1024 Token 之间,overlap 约 10% 保证上下文连续性:
import { embedMany } from 'ai'; import { openai } from '@ai-sdk/openai'; interface DocumentChunk { id: string; content: string; metadata: { source: string; page?: number; title: string }; } async function embedChunks(chunks: DocumentChunk[]) { const { embeddings } = await embedMany({ model: openai.embedding('text-embedding-3-small'), values: chunks.map(c => c.content), }); return chunks.map((chunk, i) => ({ ...chunk, embedding: embeddings[i] })); }Supabase Vector 存储与检索:Supabase 内置
pgvector扩展,是托管型向量存储的轻量选择:import { createClient } from '@supabase/supabase-js'; const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!); // 存储文档块 async function storeEmbeddings(chunks: DocumentChunk[]) { const embedded = await embedChunks(chunks); await supabase.from('documents').insert(embedded.map(c => ({ content: c.content, embedding: c.embedding, source: c.metadata.source, }))); } // 语义检索 async function retrieveRelevant(query: string, topK: number = 5) { const { embedding } = await embed({ model: openai.embedding('text-embedding-3-small'), value: query, }); const { data } = await supabase.rpc('match_documents', { query_embedding: embedding, match_threshold: 0.7, match_count: topK, }); return data ?? []; }检索-生成一体化实现:将检索到的上下文注入 Prompt,配合
generateText生成带引用来源的回复:async function ragGenerate(query: string): Promise<{ answer: string; sources: string[] }> { const docs = await retrieveRelevant(query, 5); const context = docs.map((d, i) => `[${i + 1}] ${d.content}`).join('\n\n'); const { text } = await generateText({ model: openai('gpt-4o'), system: 'You are a helpful assistant. Answer based on the provided context. Cite sources using [1], [2] format.', prompt: `Context:\n${context}\n\nQuery: ${query}`, }); const sources = [...new Set(docs.map(d => d.source))]; return { answer: text, sources }; }引用来源追踪:前端展示时,将
[1]、[2]等引用标记渲染为可点击的文献链接,提升答案可信度。对引用的来源进行去重,按相关性排序展示,避免来源列表过于冗长。性能基准与最佳实践
模式 首字节延迟 (TTFB) 总延迟 适用场景 generateText800-1500ms 完整后返回 短回答、结构化输出 streamText200-500ms 流式持续 长文本生成、Chat UI generateObject1000-2000ms 完整后返回 需要类型安全的 API streamObject300-600ms 流式持续 结构化数据的渐进渲染 不同 Provider 延迟对比(基于相同 Prompt、TTFB):
Provider gpt-4o-mini gpt-4o claude-3-5-sonnet gemini-1.5-flash 首字节时间 120-250ms 200-400ms 250-450ms 150-300ms Token 吞吐 快 中 中 快 稳定性 高 高 高 中 Gemini Flash 在首字节时间上略优于 gpt-4o-mini,但在复杂推理任务的稳定性方面稍逊。对于要求低延迟的边缘部署场景,优先选择 Flash Mini 系列。
流式输出首字节时间(Time to First Token)优化:影响 TTFB 的核心因素包括模型加载时间、网络往返延迟和 Prompt Token 数量。实践上可以采取以下措施降低首字节延迟:启用 Vercel Edge Runtime 就近调用、使用 prompt caching 减少重复处理、压缩 system prompt 避免冗余 Token、合理设置
maxTokens避免超时等待。关键优化:
// 启用响应式流式传输 const result = streamText({ model: openai("gpt-4o-mini"), prompt: "...", // 将长文本分块发送,减少前端等待 experimental_streamData: true, // 限制最大 Token,控制成本和延迟 maxTokens: 2048, // 温度控制:确定任务用 0,创意任务用 0.7+ temperature: 0.3, });FAQ
Q1: AI SDK 是否有免费额度限制?
AI SDK 本身是开源免费的,没有使用限制。但实际调用的模型 API(OpenAI、Anthropic 等)按 Token 收费。OpenAI 新注册用户有 $5 额度,Anthropic 提供少量免费试用。建议在开发阶段使用 gpt-4o-mini 降低成本。Q2: 流式输出中如何处理错误?
streamText的流在服务端抛出异常时,前端useChat会自动捕获并通过error状态暴露。建议在 API Route 中包装 try-catch,将错误转换为 JSON 错误帧;前端通过onError回调展示友好提示,并允许用户重试。Q3: 工具调用如何设置超时控制?
在tool()的execute函数内部使用Promise.race或AbortSignal实现超时。推荐方式为传入AbortSignal到 fetch 调用中,并在服务端设置全局的serverActionTimeout:execute: async ({ city }, { signal }) => { const res = await fetch(url, { signal }); // 超时由 outer 的 AbortController 控制 }Q4: v0 与 AI SDK 的关系是什么?
v0 是 Vercel 的 AI 生成式 UI 构建工具,底层复用了 AI SDK 的streamObject和streamText能力。你可以将 v0 视为 AI SDK 的一个消费者应用。v0 生成的组件代码同样可以使用 AI SDK 增加交互式 AI 功能,两者属于同一技术栈的不同层级。Q5:
generateObject支持非 zod 的 schema 库吗?
AI SDK 3.x 主要原生支持 zod。对于 valibot 或 JSON Schema,可以通过jsonSchema辅助函数转换后再传入。官方路线图显示未来可能扩展更多 schema 库的原生支持。Q6:
streamObject能否配合 React Server Components 使用?
可以。在 Server Component 中使用streamObject,通过createStreamableValue包装结果流,客户端使用useStreamableValue消费。这种方式避免了客户端 JavaScript 的水合开销,适合首屏渲染性能敏感的场景。延伸阅读:
- Vercel AI SDK 指南 — AI SDK 基础概念与 Vercel 平台原生集成
- Vercel Edge Functions 深度指南 — 流式响应的网络层优化
- LLM API 基础调用指南 — 底层 API 调用与 Token 经济学
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。