适配器是什么

这一页说明适配器做什么、不做什么,以及接一个后端时各方要写什么。

结论

  • 适配器只做协议翻译:把输入编成协议规定的请求内容,把后端的响应解析成界面能显示的消息。
  • 请求由接入方发。每项能力写一个函数,函数里决定请求发到哪、带什么凭据、用哪个模型或应用。
  • 函数决定可用能力;入口还受组件是否挂载、features 配置和当前轮次状态约束。停止已派发的运行需要后端提供 abort 能力。
  • 运行时在浏览器内存中保留消息;SDK 不把会话和历史写入浏览器持久存储。页面重建后的历史来自 history。

各方管什么

职责划分ChatKit 提供界面与 Core显示消息排队、停止一轮的状态与结论ChatKit 提供适配器按协议编请求内容解析流、历史、会话记轮次编号、事件编号接入方写能力函数请求发到哪带什么凭据模型、应用名、用户后端团队后端执行对话存会话与历史按约定的格式返回命令事实请求内容响应传输事件实线:发出虚线:返回
能力函数与代理负责地址、鉴权和部署参数;适配器不提供凭据防泄露保证。
角色谁写管什么不管什么
界面与 CoreChatKit显示消息、排队、停止、一轮的状态与结论协议、请求
适配器ChatKit按协议编请求内容;解析流、历史、会话;记轮次编号和事件编号地址、凭据、部署参数;存储;重试
能力函数接入方请求发到哪、带什么凭据;补上模型名、应用名这类部署参数;格式转换解析协议
后端后端团队执行对话;存会话与历史;按后端约定返回界面

最小的接入

下面展示只提供 run 的接入。示例使用浏览器环境变量中的开发凭据;生产环境应改用自己的代理,长期服务密钥保留在服务端:

adapter.ts
import { createOpenAiAdapter } from '@volcengine/chatkit/adapters/openai';

// 直连模型服务,只用于本地开发:密钥从本机的环境变量读,不要提交、不要上线
const BASE = 'https://llm.example.com/v1';
const KEY = import.meta.env.VITE_LLM_KEY;
const MODEL = 'your-model-id';

export const adapter = createOpenAiAdapter({
  run: ({ body }) =>
    fetch(`${BASE}/chat/completions`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${KEY}` },
      // 请求内容里没有模型名,在这里补
      body: JSON.stringify({ model: MODEL, ...body }),
    }),
});
chat.tsx
import { Chatkit, useChatRuntime } from '@volcengine/chatkit';
import '@volcengine/chatkit/styles.css';

import { adapter } from './openai-minimal';

// 只有一个对话、没有会话列表时用 useChatRuntime
export function Chat() {
  const runtime = useChatRuntime({ sessionId: 'default', adapter });
  return runtime ? <Chatkit runtime={runtime} /> : null;
}

联网适配器使用相同的能力名称,协议请求体、历史格式和错误回调仍有差异。DSH、Codex、OpenCode、Hermes Dashboard 的适配器自带连接(createDshConnection 等),能力函数不用接入方写,地址与鉴权经连接的选项给出:

后端创建函数入口页面
ADKcreateAdkAdapter@volcengine/chatkit/adapters/adkADK
A2AcreateA2aAdapter@volcengine/chatkit/adapters/a2aA2A
OpenAI 兼容接口createOpenAiAdapter@volcengine/chatkit/adapters/openaiOpenAI 兼容接口
HermescreateHermesAdapter@volcengine/chatkit/adapters/hermesHermes
DSHcreateDshAdapter@volcengine/chatkit/adapters/dshDSH
Codex app-servercreateCodexAdapter@volcengine/chatkit/adapters/codexCodex
OpenCode servercreateOpenCodeAdapter@volcengine/chatkit/adapters/opencodeOpenCode
Hermes DashboardcreateHermesGatewayAdapter@volcengine/chatkit/adapters/hermes-gatewayHermes Dashboard
别的协议createAdapter@volcengine/chatkit/core写一个新的适配器

本地开发和演示可以使用内置的 Mock 适配器(入口 @volcengine/chatkit/adapters/mock),它不连接后端、按脚本回放对话,不用于生产环境,见 Mock 适配器。

一次发送的过程

一次发送的过程界面Core适配器run 函数接入方写后端用户点发送发起一轮会话编号、轮次编号、输入调用 run编号、请求内容发请求补上地址、凭据、部署参数响应:事件流返回 Response / 事件序列逐个事件翻译成事实正文、工具调用、结论界面更新
图示未配置 subscribe:run 返回 Response 或异步事件序列;独立订阅的输出另走会话通道。
步骤谁做做什么
1Core生成这一轮的轮次编号,把输入交给适配器
2适配器按协议编好请求内容 body,调用接入方的 run
3run 函数补上地址、凭据、部署参数,发出请求,返回协议流(Response 或异步事件序列);配置 subscribe 时仅返回受理 Response
4适配器读响应里的流,逐个事件翻译成统一数据:正文、工具调用、这一轮的结论
5Core更新这一轮的状态,界面跟着更新

能力函数的共同点

四个联网适配器和 createAdapter 的能力函数有以下共同约定(Mock 适配器不发请求,选项另见其页面):

规则说明
收到一个请求对象参数按能力而定;history 没有 body;回调不接收 signal
返回后端的响应流式能力支持 Response 或异步事件序列,其余返回 Response;适配器解析协议内容
body 是对象仅有 body 的能力适用;body 尚未序列化,发送 JSON 时由接入方序列化
返回流必须支持资源清理停止通过后端 abort 确认;释放运行时取消 reader 或调用 iterator.return()
失败的两种表示函数抛错,或者返回非成功状态码。通常都表示调用失败;取消、协议专用处理与错误出口见各协议页,不能统一当作远端执行失败
每次调用都是一次新的请求适配器不缓存返回值。凭据会过期时在函数里每次现取

每个函数收到什么、要返回什么,见能力一览和各协议的页面。

为什么地址、鉴权、部署参数不在适配器里

原因说明
每个部署都不一样地址怎么排、凭据放请求头还是 Cookie、要不要带租户,各家不同。做成选项永远列不全
长期服务密钥留在服务端能力函数和代理负责鉴权。前端环境变量、请求体、响应和错误日志仍可能暴露凭据,适配器不提供防泄露保证
同一件事只有一种写法想改请求的任何部分,都在能力函数里改。不用去查有没有对应的选项
适配器可以保持不变后端的地址、网关、鉴权方式变了,只改能力函数。协议没变,适配器不用动

适配器的创建选项因此很少:

类别选项必填作用
能力run是发起一轮
能力subscribe、abort、resume、steer、regenerate、edit、history否给了就是支持
业务字段transformInput否调整输入怎么放进请求内容
业务字段transformOutput否把默认内容与业务字段转换为内容变更
其他messages否替换适配器自己产生的错误文字
其他onError否错误上报

个别适配器另有少数和协议行为有关的选项,见各自的页面。

适配器实例

规则说明
按后端配置复用实例同一配置的实例可服务多个会话;list/create 等会话管理调用不带 sessionId
引用要稳定建在模块级,或者用 useMemo 包住。每次渲染都新建会让运行时反复重建,正在进行的流被掐断
没给 run 立即报错创建函数在没给 run 时直接抛错,不会等到第一次发送

接下来看什么

想知道页面
每项能力对应界面上的什么能力一览
后端要配合做什么后端约定
具体协议怎么接ADK、A2A、OpenAI 兼容接口、Hermes;Hermes Dashboard、DSH、Codex、OpenCode;字段细节见各自的协议参考
会话列表和历史从哪来会话与历史从哪来
后端的格式和约定不一样后端不符合约定时
上线前要检查什么、出了问题怎么查上线前检查

独立接收与新协议

后端把发送和接收分开,或需要接收其他端触发的回答时,使用 run + subscribe。新协议使用 createAdapter,能力函数的名字保持一致。