vercel-ai-sdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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钩子和服务器工具,用于构建支持工具调用、文件附件和多步推理的流式聊天界面。

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);
  }
});

// Send a message
sendMessage({ text: 'Hello', metadata: { createdAt: Date.now() } });

// Send with files
sendMessage({
  text: 'Analyze this',
  files: fileList // FileList or FileUIPart[]
});

ChatStatus States

ChatStatus状态

The
status
field indicates the current state of the chat:
  • ready
    : Chat is idle and ready to accept new messages
  • submitted
    : Message sent to API, awaiting response stream start
  • streaming
    : Response actively streaming from the API
  • error
    : An error occurred during the request
status
字段表示聊天的当前状态:
  • ready
    :聊天处于空闲状态,可接受新消息
  • submitted
    :消息已发送至API,等待响应流开始
  • streaming
    :响应正从API流式传输中
  • error
    :请求过程中发生错误

Message Structure

消息结构

Messages use the
UIMessage
type with a parts-based structure:
typescript
interface UIMessage {
  id: string;
  role: 'system' | 'user' | 'assistant';
  metadata?: unknown;
  parts: Array<UIMessagePart>; // text, file, tool-*, reasoning, etc.
}
Part types include:
  • text
    : Text content with optional streaming state
  • file
    : File attachments (images, documents)
  • tool-{toolName}
    : Tool invocations with state machine
  • reasoning
    : AI reasoning traces
  • data-{typeName}
    : Custom data parts
消息采用
UIMessage
类型,基于部件的结构:
typescript
interface UIMessage {
  id: string;
  role: 'system' | 'user' | 'assistant';
  metadata?: unknown;
  parts: Array<UIMessagePart>; // text, file, tool-*, reasoning, etc.
}
部件类型包括:
  • text
    :带可选流式状态的文本内容
  • file
    :文件附件(图片、文档)
  • tool-{toolName}
    :带状态机的工具调用
  • reasoning
    :AI推理轨迹
  • 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 }) => {
    // Save to database
  }
});

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);
  }
});

// Clear error and reset to ready state
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();

// Regenerate last assistant message
await regenerate();

// Regenerate specific message
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
// Throttle UI updates to reduce re-renders
const chat = useChat({
  experimental_throttle: 100 // Update max once per 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
  // Automatically resend when all tool calls have outputs
});

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 }, // Metadata type
  UIDataTypes,
  InferUITools<typeof tools> // Tool types
>;

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:
  1. input-streaming
    : Tool input streaming (optional)
  2. input-available
    : Tool input complete
  3. approval-requested
    : Waiting for user approval (optional)
  4. approval-responded
    : User approved/denied (optional)
  5. output-available
    : Tool execution complete
  6. output-error
    : Tool execution failed
  7. output-denied
    : User denied approval
工具部件会经历以下状态:
  1. input-streaming
    :工具输入流式传输(可选)
  2. input-available
    :工具输入完成
  3. approval-requested
    :等待用户批准(可选)
  4. approval-responded
    :用户已批准/拒绝(可选)
  5. output-available
    :工具执行完成
  6. output-error
    :工具执行失败
  7. output-denied
    :用户拒绝批准

Streaming Protocol

流式传输协议

The SDK uses Server-Sent Events (SSE) with UIMessageChunk types:
  • text-start
    ,
    text-delta
    ,
    text-end
  • tool-input-available
    ,
    tool-output-available
  • reasoning-start
    ,
    reasoning-delta
    ,
    reasoning-end
  • start
    ,
    finish
    ,
    abort
SDK使用Server-Sent Events (SSE)和UIMessageChunk类型:
  • text-start
    ,
    text-delta
    ,
    text-end
  • tool-input-available
    ,
    tool-output-available
  • reasoning-start
    ,
    reasoning-delta
    ,
    reasoning-end
  • start
    ,
    finish
    ,
    abort

Client vs Server Tools

客户端与服务器端工具

Server-side tools have an
execute
function and run on the API route.
Client-side tools omit
execute
and are handled via
onToolCall
and
addToolOutput
.
服务器端工具包含
execute
函数,在API路由上运行。
客户端工具省略
execute
函数,通过
onToolCall
addToolOutput
处理。

Best Practices

最佳实践

  1. Always handle the
    error
    state and provide user feedback
  2. Use
    experimental_throttle
    for high-frequency updates
  3. Implement proper loading states based on
    status
  4. Type your messages with custom metadata and tools
  5. Use
    sendAutomaticallyWhen
    for multi-turn tool workflows
  6. Handle all tool states in the UI for better UX
  7. Use
    stop()
    to allow users to cancel long-running requests
  8. Validate messages with
    validateUIMessages
    on the server
  1. 始终处理
    error
    状态并向用户提供反馈
  2. 对于高频更新,使用
    experimental_throttle
  3. 根据
    status
    实现合适的加载状态
  4. 为消息添加自定义元数据和工具的类型定义
  5. 对于多轮工具工作流,使用
    sendAutomaticallyWhen
  6. 在UI中处理所有工具状态以提升用户体验
  7. 使用
    stop()
    允许用户取消长时间运行的请求
  8. 在服务器端使用
    validateUIMessages
    验证消息