两种用法

chatkit 有两种用法:多个会话的完整应用用 useChatSessions,嵌在页面里的单个对话用 useChatRuntime。两者用同一个适配器、同一个 <Chatkit>。

用法hook交给 <Chatkit> 的 prop适合
完整应用useChatSessionssessions独立的对话产品:会话列表、新建、切换
单个对话useChatRuntimeruntime嵌在业务页面里的助手:工单页、文档页的侧边栏

sessions 与 runtime 二选一。

完整应用:useChatSessions

app.tsx
import { Chatkit, SessionList, type SessionListProps, useChatSessions } from '@volcengine/chatkit';
import '@volcengine/chatkit/styles.css';

// 适配器怎么建见「接入后端」
import { adapter } from './adk-proxy';

export function App({
  sessions: items,
  activeSessionId,
  onSelect,
}: Pick<SessionListProps, 'sessions' | 'activeSessionId' | 'onSelect'>) {
  const sessions = useChatSessions({ activeSessionId, adapter });
  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      <SessionList sessions={items} activeSessionId={activeSessionId} onSelect={onSelect} style={{ width: 260 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <Chatkit sessions={sessions} />
      </div>
    </div>
  );
}
  • 聊天区和会话列表是两个组件:<Chatkit> 只显示聊天区,SessionList 是会话列表,聊天区接收运行时,会话列表接收外部数组与回调。列表放在哪里由页面的布局决定,见会话列表。

  • 一个适配器服务所有会话:同一组会话共用一个稳定的适配器实例。

  • 切换会话不打断回答:会话第一次打开时才建运行时,在 hook 存续期间保留,显式 actions.release(id) 时释放。页面内切换后,原会话继续接收回答;切回来显示已收到的内容。

  • 打开会话时先取历史:会话第一次打开时取一次历史;历史提供活动轮次及有效事件游标、适配器又给了 resume 时,尝试续接。

  • 先创建再发送:应用调用业务创建接口,取得真实 ID 后更新 activeSessionId;也可 await actions.open(id) 后向返回的 runtime 发送。

  • 列表外部受控:目录查询、分页、改名、删除、fork 都由应用实现;不提供某个操作回调时隐藏对应按钮。

参数说明
adapter适配器实例,必须是稳定引用
activeSessionId持续受控的当前会话 ID,可直接来自路由;未提供时 runtime 为空
onError取历史、连接或续接失败等错误的出口;不写时交给 <Chatkit> / <ChatkitProvider> 的 onError
eventAttributes给事件补充的属性,见事件
stallThresholdMs运行中多久没有新数据算卡住,默认 60 秒;0 关掉

单个对话:useChatRuntime

ticket-assistant.tsx
import { Chatkit, useChatRuntime } from '@volcengine/chatkit';
import '@volcengine/chatkit/styles.css';

import { adapter } from './adk-proxy';

export function TicketAssistant({ ticketId }: { ticketId: string }) {
  const runtime = useChatRuntime({ sessionId: `ticket-${ticketId}`, adapter });
  return runtime ? <Chatkit runtime={runtime} /> : null;
}
  • sessionId 必填,由业务方决定(工单号、文档 id)。换了 sessionId 就换了对话。
  • 首次挂载、sessionId 为空,以及切换 sessionId 或适配器时,运行时可能为 undefined,所以渲染前要判断。
  • useChatRuntime 只管一个对话。SessionList 是独立的受控组件,也能用来切换它的 sessionId,但每次切换都会释放旧运行时、重新取历史,旧会话不在后台继续接收;需要多会话切换时用 useChatSessions。
  • 其余参数与 useChatSessions 相同。两者修改 stallThresholdMs 都会重建运行时,建议在挂载时确定。

对话界面被销毁重建时

运行时跟着这两个 hook 所在的组件:组件卸载时运行时释放。适配器给了 history 时,再次打开同一 sessionId 会查询后端已保存的内容; 没给时对话会清空,要保留就把 hook 写在不会卸载的上层组件里,或者隐藏而不是移除对话界面。 写法见会话与历史从哪来。

两种用法的差别

功能完整应用单个对话
会话列表 SessionList:切换、新建、改名、删除由应用数组与回调控制,切换后原会话在后台继续接收一般不用;用它切换 sessionId 时旧运行时被释放
重新生成、编辑后重发给了对应的函数时显示同左
附件、赞踩、@ 与 /、语音、划词追问同右照常
插槽、渲染器、onSend、事件同右照常

在聊天区之外用内置组件和 hooks

想把附件按钮放进页面头部,或者在侧边栏里操作输入框时,用 <ChatkitProvider> 把页面包起来。里面的 <Chatkit /> 可以不写任何 props:

<ChatkitProvider sessions={sessions} settings={settings}>
  <PageHeader /> {/* 里面可以用 useCurrentSession、useComposer */}
  <SessionList sessions={items} activeSessionId={activeSessionId} onSelect={setActiveSessionId} />
  <Chatkit />
</ChatkitProvider>

见调整内置功能与 Hook 参考。