🚀 Vercel AI SDK 使用指南:自定义传输层 (Transport)

5 阅读4分钟

在构建 AI Chat 应用时,我们通常使用 useChat hook 来快速实现对话功能。默认情况下,它会向 /api/chat 发送标准的 HTTP POST 请求。

但在实际的企业级开发中,我们往往面临更复杂的需求:

  • 鉴权 (Authentication) :需要在请求头中携带动态的 Token。
  • 自定义后端 (Custom Backend) :API 路径不是 /api/chat,或者需要透传额外的上下文信息(如 Session ID、用户偏好)。
  • 非 HTTP 协议:需要通过 WebSocket 通信,或者在服务端/本地环境中直接调用 Agent(无需网络请求)。

Vercel AI SDK 的 Transport(传输层) 系统正是为了解决这些问题而设计的。它允许你完全控制消息的发送方式和响应的处理逻辑。

本文将带你深入了解如何配置和自定义 Transport。


1. 默认行为 (Default Transport)

首先,回顾一下最基础的用法。当你仅仅调用 useChat() 时,SDK 内部会自动创建一个 DefaultChatTransport 实例。

TypeScript

import { useChat } from '@ai-sdk/react';

// 默认行为:向 /api/chat 发送 HTTP POST 请求
const { messages, sendMessage } = useChat();

这实际上等同于显式配置了默认传输层:

TypeScript

import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai'; // 注意这里是从 'ai' 核心库导入

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
  }),
});

2. 自定义请求配置 (Custom Configuration)

最常见的需求是修改 API 地址或添加静态请求头。

修改 API 路径与添加静态 Header

TypeScript

import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    // 指向自定义的后端路由
    api: '/api/v1/custom-chat',
    
    // 添加静态请求头
    headers: {
      'Authorization': 'Bearer my-static-token',
      'X-App-Version': '1.0.0',
    },
    
    // 配置 fetch 的 credentials 选项(如需要发送 Cookie)
    credentials: 'include',
  }),
});

3. 动态配置 (Dynamic Configuration)

在现代 Web 应用中,Token 往往是动态变化的,或者我们需要根据当前用户的状态传递不同的参数。DefaultChatTransport 允许你传入函数来动态生成配置。

这对于处理 JWT Token 刷新或传递实时上下文非常有用。

TypeScript

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
    
    // 动态生成 Headers
    headers: () => ({
      'Authorization': `Bearer ${localStorage.getItem('token')}`, // 每次请求都会获取最新的 Token
      'X-Team-ID': getCurrentTeamId(),
    }),
    
    // 动态生成 Body 里的额外字段
    body: () => ({
      theme: 'dark',
      userLocation: 'CN',
      timestamp: Date.now(),
    }),
  }),
});

4. 请求转换 (Request Transformation)

有时候,我们需要在请求发送前的最后一刻修改请求体(Body),例如为了节省 Token,只发送最近的 10 条消息,或者添加特定的追踪 ID。

这时可以使用 prepareSendMessagesRequest 回调。

TypeScript

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
    
    // 在发送前拦截并修改请求
    prepareSendMessagesRequest: ({ id, messages, trigger, messageId }) => {
      return {
        headers: {
          'X-Conversation-ID': id,
        },
        body: {
          // 只发送最近的 10 条消息,避免上下文超长
          messages: messages.slice(-10), 
          // 透传触发源
          trigger,
          // 当前消息 ID
          messageId, 
        },
      };
    },
  }),
});

5. 服务端/本地 Agent 直连 (Direct Agent Transport)

这是 Vercel AI SDK 一个非常强大的功能。如果你是在 服务端渲染 (SSR)测试环境,或者是开发 Electron/Tauri 这种本地应用,你可能并不希望发起一个 HTTP 网络请求,而是希望直接调用本地的 Agent 逻辑。

DirectChatTransport 允许 UI 直接与 Agent 通信,跳过 HTTP 层。

注意:这通常用于服务端组件或本地环境,因为如果在纯客户端使用,你需要确保 Agent 的逻辑(包括 API Key)是安全的或在服务端上下文中执行。

TypeScript

import { useChat } from '@ai-sdk/react';
import { DirectChatTransport, ToolLoopAgent } from 'ai';
// 假设你已经定义了一些工具
import { weatherTool } from './tools'; 

// 1. 初始化 Agent
const agent = new ToolLoopAgent({
  model: 'anthropic/claude-sonnet-4.5', // 你可以替换为任何兼容的模型
  instructions: '你是一个乐于助人的助手。',
  tools: {
    weather: weatherTool,
  },
});

// 2. 在 useChat 中使用直连传输层
const { messages, sendMessage } = useChat({
  transport: new DirectChatTransport({ 
    agent,
    // 可选:配置是否向客户端发送推理过程或来源
    sendReasoning: true,
    sendSources: true
  }),
});

工作原理

  1. DirectChatTransport 接收 UI 消息。
  2. 使用 convertToModelMessages 将其转换为模型可理解的格式。
  3. 直接调用 Agent 的 stream() 方法(在同一进程内)。
  4. 通过 toUIMessageStream() 将结果流式传回给 UI。

总结

Vercel AI SDK 的 Transport 设计采用了极具扩展性的策略:

  • 简单的 HTTP 请求:使用默认配置即可。
  • 复杂的鉴权/上下文:使用 headersbody 的动态函数配置。
  • 精细的控制:使用 prepareSendMessagesRequest 裁剪或转换数据。
  • 非 HTTP 环境:使用 DirectChatTransport 实现进程内直连。

掌握这些配置,你就可以轻松应对各种复杂的企业级集成场景,无论是对接私有网关还是构建本地 AI 应用。