llm-chat-sdks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLLM Chat SDKs — Claude API & Vercel AI SDK
LLM 聊天 SDK — Claude API 与 Vercel AI SDK
Two complementary surfaces:
| SDK | When |
|---|---|
| Claude API / Anthropic SDK | Backend Python/Node calling Claude directly. Prompt caching, thinking, tool use, batch, files, citations, Managed Agents, migrating between Claude versions (4.5 → 4.6 → 4.7). |
| Vercel AI SDK | Frontend React/Next.js chat UI. |
Pick by where the code runs. Most real apps need both — Claude API on the server, Vercel AI SDK on the client.
两个互补的适用场景:
| SDK | 适用场景 |
|---|---|
| Claude API / Anthropic SDK | 后端通过 Python/Node 直接调用 Claude。支持提示缓存、思维过程、工具调用、批量处理、文件处理、引用、托管 Agents、Claude 版本迁移(4.5 → 4.6 → 4.7)。 |
| Vercel AI SDK | 前端 React/Next.js 聊天界面。支持 |
根据代码运行环境选择。大多数实际应用需要同时使用两者——后端用 Claude API,客户端用 Vercel AI SDK。
Claude API / Anthropic SDK
Claude API / Anthropic SDK
Vercel AI SDK
Vercel AI SDK
Vercel AI SDK
Vercel AI SDK
The Vercel AI SDK provides React hooks and server utilities for building streaming chat interfaces with support for tool calls, file attachments, and multi-step reasoning.
Vercel AI SDK 提供 React Hooks 和服务端工具,用于构建支持工具调用、文件附件和多步推理的流式聊天界面。
Quick Reference
快速参考
Basic useChat Setup
基础 useChat 配置
typescript
import { useChat } from '@ai-sdk/react';
const { messages, status, sendMessage, stop, regenerate } = useChat({
id: 'chat-id',
messages: initialMessages,
onFinish: ({ message, messages, isAbort, isError }) => {
console.log('Chat finished');
},
onError: (error) => {
console.error('Chat error:', error);
}
});
// Send a message
sendMessage({ text: 'Hello', metadata: { createdAt: Date.now() } });
// Send with files
sendMessage({
text: 'Analyze this',
files: fileList // FileList or FileUIPart[]
});typescript
import { useChat } from '@ai-sdk/react';
const { messages, status, sendMessage, stop, regenerate } = useChat({
id: 'chat-id',
messages: initialMessages,
onFinish: ({ message, messages, isAbort, isError }) => {
console.log('Chat finished');
},
onError: (error) => {
console.error('Chat error:', error);
}
});
// 发送消息
sendMessage({ text: 'Hello', metadata: { createdAt: Date.now() } });
// 附带文件发送
sendMessage({
text: 'Analyze this',
files: fileList // FileList 或 FileUIPart[]
});ChatStatus States
ChatStatus 状态
The field indicates the current state of the chat:
status- : Chat is idle and ready to accept new messages
ready - : Message sent to API, awaiting response stream start
submitted - : Response actively streaming from the API
streaming - : An error occurred during the request
error
status- : 聊天处于空闲状态,可接受新消息
ready - : 消息已发送至 API,等待响应流启动
submitted - : API 正在主动流式返回响应
streaming - : 请求过程中发生错误
error
Message Structure
消息结构
Messages use the type with a parts-based structure:
UIMessagetypescript
interface UIMessage {
id: string;
role: 'system' | 'user' | 'assistant';
metadata?: unknown;
parts: Array<UIMessagePart>; // text, file, tool-*, reasoning, etc.
}Part types include:
- : Text content with optional streaming state
text - : File attachments (images, documents)
file - : Tool invocations with state machine
tool-{toolName} - : AI reasoning traces
reasoning - : Custom data parts
data-{typeName}
消息采用 类型,基于部件的结构:
UIMessagetypescript
interface UIMessage {
id: string;
role: 'system' | 'user' | 'assistant';
metadata?: unknown;
parts: Array<UIMessagePart>; // 文本、文件、tool-*、推理等
}部件类型包括:
- : 带有可选流式状态的文本内容
text - : 文件附件(图片、文档)
file - : 带有状态机的工具调用
tool-{toolName} - : AI 推理轨迹
reasoning - : 自定义数据部件
data-{typeName}
Server-Side Streaming
服务端流式传输
typescript
import { streamText } from 'ai';
import { convertToModelMessages } from 'ai';
const result = streamText({
model: openai('gpt-4'),
messages: convertToModelMessages(uiMessages),
tools: {
getWeather: tool({
description: 'Get weather',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
return { temperature: 72, weather: 'sunny' };
}
})
}
});
return result.toUIMessageStreamResponse({
originalMessages: uiMessages,
onFinish: ({ messages }) => {
// Save to database
}
});typescript
import { streamText } from 'ai';
import { convertToModelMessages } from 'ai';
const result = streamText({
model: openai('gpt-4'),
messages: convertToModelMessages(uiMessages),
tools: {
getWeather: tool({
description: 'Get weather',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
return { temperature: 72, weather: 'sunny' };
}
})
}
});
return result.toUIMessageStreamResponse({
originalMessages: uiMessages,
onFinish: ({ messages }) => {
// 保存至数据库
}
});Tool Handling Patterns
工具处理模式
Client-Side Tool Execution:
typescript
const { addToolOutput } = useChat({
onToolCall: async ({ toolCall }) => {
if (toolCall.toolName === 'getLocation') {
addToolOutput({
tool: 'getLocation',
toolCallId: toolCall.toolCallId,
output: 'San Francisco'
});
}
}
});Rendering Tool States:
typescript
{message.parts.map(part => {
if (part.type === 'tool-getWeather') {
switch (part.state) {
case 'input-streaming':
return <pre>{JSON.stringify(part.input, null, 2)}</pre>;
case 'input-available':
return <div>Getting weather for {part.input.city}...</div>;
case 'output-available':
return <div>Weather: {part.output.weather}</div>;
case 'output-error':
return <div>Error: {part.errorText}</div>;
}
}
})}客户端工具执行:
typescript
const { addToolOutput } = useChat({
onToolCall: async ({ toolCall }) => {
if (toolCall.toolName === 'getLocation') {
addToolOutput({
tool: 'getLocation',
toolCallId: toolCall.toolCallId,
output: 'San Francisco'
});
}
}
});渲染工具状态:
typescript
{message.parts.map(part => {
if (part.type === 'tool-getWeather') {
switch (part.state) {
case 'input-streaming':
return <pre>{JSON.stringify(part.input, null, 2)}</pre>;
case 'input-available':
return <div>Getting weather for {part.input.city}...</div>;
case 'output-available':
return <div>Weather: {part.output.weather}</div>;
case 'output-error':
return <div>Error: {part.errorText}</div>;
}
}
})}Reference Files
参考文档
Detailed documentation on specific aspects:
- use-chat.md: Complete useChat API reference
- messages.md: UIMessage structure and part types
- streaming.md: Server-side streaming implementation
- tools.md: Tool definition and execution patterns
特定方面的详细文档:
- use-chat.md: 完整的 useChat API 参考
- messages.md: UIMessage 结构和部件类型
- streaming.md: 服务端流式传输实现
- tools.md: 工具定义和执行模式
Common Patterns
常见模式
Error Handling
错误处理
typescript
const { error, clearError } = useChat({
onError: (error) => {
toast.error(error.message);
}
});
// Clear error and reset to ready state
if (error) {
clearError();
}typescript
const { error, clearError } = useChat({
onError: (error) => {
toast.error(error.message);
}
});
// 清除错误并重置为就绪状态
if (error) {
clearError();
}Message Regeneration
消息重新生成
typescript
const { regenerate } = useChat();
// Regenerate last assistant message
await regenerate();
// Regenerate specific message
await regenerate({ messageId: 'msg-123' });typescript
const { regenerate } = useChat();
// 重新生成最后一条助手消息
await regenerate();
// 重新生成特定消息
await regenerate({ messageId: 'msg-123' });Custom Transport
自定义传输
typescript
import { DefaultChatTransport } from 'ai';
const { messages } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat',
prepareSendMessagesRequest: ({ id, messages, trigger, messageId }) => ({
body: {
chatId: id,
lastMessage: messages[messages.length - 1],
trigger,
messageId
}
})
})
});typescript
import { DefaultChatTransport } from 'ai';
const { messages } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat',
prepareSendMessagesRequest: ({ id, messages, trigger, messageId }) => ({
body: {
chatId: id,
lastMessage: messages[messages.length - 1],
trigger,
messageId
}
})
})
});Performance Optimization
性能优化
typescript
// Throttle UI updates to reduce re-renders
const chat = useChat({
experimental_throttle: 100 // Update max once per 100ms
});typescript
// 限制 UI 更新频率以减少重渲染
const chat = useChat({
experimental_throttle: 100 // 每 100ms 最多更新一次
});Automatic Message Sending
自动消息发送
typescript
import { lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
const chat = useChat({
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
// Automatically resend when all tool calls have outputs
});typescript
import { lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
const chat = useChat({
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
// 当所有工具调用都有输出时自动重新发送
});Type Safety
类型安全
The SDK provides full type inference for tools and messages:
typescript
import { InferUITools, UIMessage } from 'ai';
const tools = {
getWeather: tool({
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ weather: 'sunny' })
})
};
type MyMessage = UIMessage<
{ createdAt: number }, // Metadata type
UIDataTypes,
InferUITools<typeof tools> // Tool types
>;
const { messages } = useChat<MyMessage>();SDK 为工具和消息提供完整的类型推断:
typescript
import { InferUITools, UIMessage } from 'ai';
const tools = {
getWeather: tool({
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ weather: 'sunny' })
})
};
type MyMessage = UIMessage<
{ createdAt: number }, // 元数据类型
UIDataTypes,
InferUITools<typeof tools> // 工具类型
>;
const { messages } = useChat<MyMessage>();Key Concepts
核心概念
Parts-Based Architecture
基于部件的架构
Messages use a parts array instead of a single content field. This allows:
- Streaming text while maintaining other parts
- Tool calls with independent state machines
- File attachments and custom data mixed with text
消息使用部件数组而非单一内容字段,这允许:
- 在流式传输文本的同时保留其他部件
- 带有独立状态机的工具调用
- 文件附件和自定义数据与文本混合
Tool State Machine
工具状态机
Tool parts progress through states:
- : Tool input streaming (optional)
input-streaming - : Tool input complete
input-available - : Waiting for user approval (optional)
approval-requested - : User approved/denied (optional)
approval-responded - : Tool execution complete
output-available - : Tool execution failed
output-error - : User denied approval
output-denied
工具部件会经历以下状态:
- : 工具输入流式传输(可选)
input-streaming - : 工具输入完成
input-available - : 等待用户批准(可选)
approval-requested - : 用户已批准/拒绝(可选)
approval-responded - : 工具执行完成
output-available - : 工具执行失败
output-error - : 用户拒绝批准
output-denied
Streaming Protocol
流式传输协议
The SDK uses Server-Sent Events (SSE) with UIMessageChunk types:
- ,
text-start,text-deltatext-end - ,
tool-input-availabletool-output-available - ,
reasoning-start,reasoning-deltareasoning-end - ,
start,finishabort
SDK 使用 Server-Sent Events (SSE) 和 UIMessageChunk 类型:
- ,
text-start,text-deltatext-end - ,
tool-input-availabletool-output-available - ,
reasoning-start,reasoning-deltareasoning-end - ,
start,finishabort
Client vs Server Tools
客户端 vs 服务端工具
Server-side tools have an function and run on the API route.
executeClient-side tools omit and are handled via and .
executeonToolCalladdToolOutput服务端工具包含 函数,在 API 路由上运行。
execute客户端工具省略 ,通过 和 处理。
executeonToolCalladdToolOutputBest Practices
最佳实践
- Always handle the state and provide user feedback
error - Use for high-frequency updates
experimental_throttle - Implement proper loading states based on
status - Type your messages with custom metadata and tools
- Use for multi-turn tool workflows
sendAutomaticallyWhen - Handle all tool states in the UI for better UX
- Use to allow users to cancel long-running requests
stop() - Validate messages with on the server NOTE: claude-api is a plugin-loaded skill (not in local dir). Only vercel-ai-sdk was local.
validateUIMessages
- 始终处理 状态并向用户提供反馈
error - 对高频更新使用
experimental_throttle - 根据 实现合适的加载状态
status - 为消息添加自定义元数据和工具的类型定义
- 对多轮工具工作流使用
sendAutomaticallyWhen - 在 UI 中处理所有工具状态以提升用户体验
- 使用 允许用户取消长时间运行的请求
stop() - 在服务端使用 验证消息 注意:claude-api 是插件加载的技能(不在本地目录)。只有 vercel-ai-sdk 是本地的。
validateUIMessages