SuperAPI AI 工具集

ai-core/chat-experience

智能体与模型

查看项目

更新于 10-16 09:41

技能介绍

Chat Experience 技能建立在 ai-core 之上,需先阅读 ai-core 以了解关键规则。本技能围绕如何使用 TanStack AI 搭建端到端聊天应用展开。

一、用途与整体结构 该技能的目标是端到端的聊天实现,涵盖服务端聊天接口与客户端聊天组件两部分。服务端通过 chat() 创建流,并通过 toServerSentEventsResponse() 输出 SSE 响应;客户端通过 useChat hook 配合 fetchServerSentEvents() 建立连接、收发消息。

二、最小聊天应用 服务端(TanStack Start 的 API Route):在 src/routes/api.chat.ts 中导入 createFileRoute、chat、toServerSentEventsResponse 以及 openaiText。在 server.handlers.POST 中读取请求体的 messages,创建 AbortController,调用 chat({ adapter: openaiText('gpt-5.5'), messages, systemPrompts: ['You are a helpful assistant.'], abortController }),再返回 toServerSentEventsResponse(stream, { abortController })。 客户端(React 组件):在 src/routes/index.tsx 中导入 useState、useChat、fetchServerSentEvents 以及 UIMessage 类型。使用 useChat({ connection: fetchServerSentEvents('/api/chat') }) 获得 messages、sendMessage、isLoading、error、stop。通过 input 与 handleSubmit 发送输入内容,遍历 messages.parts 渲染 text 类型内容,并处理错误显示与发送/停止按钮。Vue/Solid/Svelte/Preact 具有相同模式,只是 hook 导入不同(如从 '@tanstack/ai-solid' 导入 useChat)。

三、核心模式

  1. 使用 SSE 的流式聊天:服务端返回流式 SSE Response,客户端自动解析。示例中使用 anthropicText('claude-opus-5'),并可设置 modelOptions(如 temperature、max_tokens,其中 max_tokens 为 Anthropic 原生键)。如需可恢复的 SSE 响应(断线或刷新后重连而无需重新调用 provider),可传入 delivery-durability 适配器:toServerSentEventsResponse(stream, { durability: { adapter: memoryStream(request) } })(memoryStream 来自 @tanstack/ai,进程本地,用于开发/测试)或来自 @tanstack/ai-durable-stream 的 durableStream(request, { server })(Durable Streams 协议,生产环境)。每个 SSE 事件带有适配器拥有的不透明 id;fetchServerSentEvents 会自动以 Last-Event-ID 重连,并暴露 joinRun(runId) 从头重放一次运行。客户端 useChat 支持 body 字段(会与 messages 一同合并进 POST 请求体)、onFinish、onError,以及 status 字段('ready' | 'submitted' | 'streaming' | 'error')。
  2. 渲染思考/推理内容:具有扩展思考的模型(Claude、Gemini)会在 message.parts 中产生 ThinkingPart。示例 MessageRenderer 根据 part.type 分别渲染 thinking(使用 details/pre 展示,通过后续是否存在 text 判断是否完成)、text、tool-call。服务端通过适配器的 modelOptions 开启思考,例如 Gemini 的 thinkingConfig: { includeThoughts: true, thinkingLevel: 'HIGH' }(Gemini 3.x;Gemini 2.x 使用 thinkingBudget)。
  3. 发送多模态内容(图片):使用 sendMessage 传入 MultimodalContent 对象而非纯字符串。可传 data 类型的 base64 图片或 url 类型图片源。接收消息中的 image 部分可渲染,若 source.type 为 file 则返回 null(provider 文件句柄是不透明 id,浏览器无法加载)。跨轮次复用的媒体可先通过 provider Files 适配器(openaiFiles()、anthropicFiles()、geminiFiles()、grokFiles()、falFiles())上传一次,再用 fileSourceFromHandle(handle) 构造 { type: 'file' } 源发送。该 source 为 { type: 'file', value, provider }:不透明句柄和签发它的适配器。不同 provider(或完全不支持 Files API 的 provider)会在发送任何请求前以清晰错误拒绝。该 source 会跨越聊天传输,浏览器可直接放入 sendMessage 内容。fileSourceFromHandle 需从浏览器安全的 @tanstack/ai/client 入口导入。
  4. 发送音频消息(浏览器录音):使用 @tanstack/ai-react 的 useAudioRecorder(或在 Svelte 中为 createAudioRecorder)在浏览器中采集音频。解析后的 AudioRecording 包含可直接放入 sendMessage 的 part。recording.part 为 { type: 'audio', source: { type: 'data', value: base64, mimeType } },返回录音机原生格式(audio/webm 或 audio/mp4),无转码。
  5. HTTP 流格式(SSE 的替代):使用 toHttpResponse + fetchHttpStream 传输换行分隔 JSON 而非 SSE。服务端返回 toHttpResponse(stream, { abortController }),客户端使用 fetchHttpStream('/api/chat')。唯一区别是替换 toServerSentEventsResponse / fetchServerSentEvents 为 toHttpResponse / fetchHttpStream,其余保持一致。可恢复性同理:向 toHttpResponse 传入相同 durability 适配器,每条 NDJSON 行变为 { id, chunk } 信封;fetchHttpStream 自动以 Last-Event-ID 重连、去重重放前缀,并暴露 joinRun(runId)。XHR 适配器(xhrServerSentEvents / xhrHttpStream)同样可恢复。
  6. 通过 chat({ mcp }) 进行 MCP 工具发现:传入 mcp 让 chat() 为一个或多个 MCP 客户端负责发现与生命周期。createMCPClient 会优先尝试 spec 2026-07-28,若服务器不支持则使用 2025 initialize 握手。mcp 属性包含 clients(一个或多个 MCPClient / MCPClients 实例)、connection('close' 默认,运行结束时关闭各客户端;'keep-alive' 则 chat() 从不关闭客户端,由调用方管理生命周期)、lazyTools(转发给 tools({ lazy: true }),按需发送工具 schema)、onDiscoveryError(抛出/重新抛出以快速失败整个调用;正常返回则跳过该来源继续;省略则重新抛出即快速失败)。选择 mcp 还是 tools 展开:当希望自动管理发现与生命周期且不需要完全类型化的输入/输出 schema 时用 chat({ mcp: { clients: [...] } });当需要完全类型化的 MCP 工具与 Zod 输入/输出校验时用 tools: [...await client.tools([toolDefinition(...)])]。

四、托管 MCP 服务器 从 @tanstack/ai-mcp/server 导入 createMCPServer,在 HTTP 路由中调用 server.fetch(request)。使用 toolDefinition 与 Zod 定义工具,并挂载到 GET、POST、DELETE(GET 为 spec 2025 流,DELETE 关闭 spec 2025 会话)。serveMCPStdio(来自 @tanstack/ai-mcp/server/stdio)可在 stdin/stdout 上服务该服务器;日志用 console.error 写,stdout 仅承载协议消息。

五、MCP 输入中断 当 chat() 收到 MCP 输入请求时,运行结果为 interrupt(流以 RUN_FINISHED 结束,outcome 类型为 interrupt)。读取每个 reason 为 mcp_input 的中断,payload 键为 tanstack:interruptPayload。form 表示服务器向用户索要输入,sampling 表示服务器索要模型结果。在 useChat 中 item kind 为通用;对 form 调用 resolveInterrupt 并传入匹配 request.requestedSchema 的对象(createMCPServer 服务器索要 { value: string }),对 sampling 调用 resolveInterrupt 传入回复文本,调用 cancel() 表示拒绝。路由将 parentRunId 与 resume 传给 chat(),工具带着答案再次运行。

六、适用场景与限制 适用于使用 TanStack AI 在多种前端框架中快速搭建带流式输出、思考展示、多模态输入、录音、MCP 工具调用等能力的聊天应用。限制与注意事项包括:需先阅读 ai-core;可恢复流依赖对应的 durability 适配器(memoryStream 仅进程本地,生产需用 durableStream);file 类型图片源无法直接在浏览器加载,需用 provider Files 适配器;跨 provider 的 file source 会被拒绝;MCP 托管需按规范挂载 GET/POST/DELETE,stdio 下 stdout 仅承载协议消息。价格、收费与平台支持等事实暂未提供。