011-2-ToolCalling
心智模型
工具调用的前端渲染,核心是将 Agent 执行动作的“黑盒”过程,可视化为结构化的 UI 卡片。其运转逻辑是一个生命周期驱动的状态机:
- 数据统一:后端 Agent 的工具调用和结果,被
useStreamHook 统一封装为toolCalls数组。数组中每个对象都遵循pending -> completed/error的明确生命周期。 - 消息关联:通过
call.id,将每个工具调用对象与触发它的 AI 消息关联起来,确保卡片渲染在正确的对话位置。 - UI 映射:根据工具调用对象的
call.name(工具名) 和state(生命周期状态),在组件中通过switch/case或条件判断,来精准选择渲染加载、错误、成功或特定工具的专属卡片。
关键实践提示
- 【核心】必须处理所有状态:在为工具调用设计 UI 时,务必覆盖
pending(加载)、completed(成功)和error(失败)三种状态。绝不能让用户看到空白的卡片,这是提供良好体验的底线。 - 【安全/健壮性】安全解析结果:工具执行的结果通常是字符串,使用
JSON.parse()解析时必须包裹在try/catch中,并提供解析失败时的回退(fallback)UI,防止因非预期数据格式导致组件崩溃。 - 【类型安全】利用类型系统:如果你的工具是用 Zod 等库定义了 Schema,应使用
ToolCallFromTool等工具类型来推导参数类型。这能在编译时为args提供类型安全,Schema 变更时立刻暴露错误。 - 【架构】提供通用回退:不需要为每个工具都创建专属卡片。对所有未知或不重要的工具名,渲染一个通用的、可折叠的 JSON 卡片即可,保证系统不会因未处理 工具名而报错。
- 【UX】加载态展示上下文:在执行
pending状态的加载卡片时,应明确展示工具名称和参数。这能既时告诉用户“Agent 正在做什么”,使其感知系统状态。 - 【UX】处理并发调用:Agent 可能同时调用多个工具。代码应能处理
toolCalls数组中同时存在多个pending状态项,使它们各自独立解析和更新,互不干扰。 - 【UX】更新模式:工具调用是原地更新的,它在
toolCalls数组中始终是同一个对象(通过id标识),只是其state属性会从pending变为completed或error。前端组件据此进行状态的平滑过渡。
总结自检
- 性能相关:文档未提及特定的性能瓶颈,主要是UI组件的渲染开销,常规做法即可。
- 安全相关:已包含对工具调用结果字符串进行安全解析的最佳实践,强调了
try/catch的必要性,并将其列入关键提示。 - 技术细节:已覆盖
ToolCallWithResult接口结构、call.id如何与消息关联、三种核心状态的处理、并发调用处理以及类型安全的工具参数推导方法,篇幅匹配原文重点。