无头工具的工作原理
从高层次看,无头工具将工具模式与仅在浏览器端运行的实现分离开来。- 在智能体上注册一个工具,该工具立即调用
interrupt()以将执行推迟到前端。 - 在前端的定义中映射相同的工具名称和参数字段。
- 使用
.implement(...)在前端实现匹配的工具,并将它们传递给useStream({ tools: [...] })。 - 当智能体调用一个匹配的工具时,客户端处理该操作并使用工具结果恢复被中断的运行。
在智能体上注册工具
Playground 定义了一小组遵循相同模式的客户端工具:智能体暴露一个工具模式,前端负责实际执行。 在服务器上定义常规工具,这些工具立即调用interrupt(),然后在前端的 tools.ts 文件中映射相同的工具名称和参数字段。
agent.py
tools.ts
实现浏览器行为
将仅限客户端的行为放在一个单独的模块中,并使用.implement(...) 将其附加。真实的 Playground 包含了一个更完整的 IndexedDB 存储,具有搜索、列表、过期和删除操作。以下示例在更高层次上展示了相同的结构:
impl.ts
将实现连接到 useStream
将已实现的工具传递给 useStream。当智能体发出匹配的工具调用时,该钩子会运行客户端实现并为您恢复运行。
定义一个匹配您智能体状态模式的 TypeScript 接口,并将其作为类型参数传递给 useStream,以便类型安全地访问状态值:
types.ts
内联渲染工具活动
Playground 将每个记忆或地理位置操作渲染为独立的卡片,并在输入框附近保留一个小型记忆统计面板。关键步骤是将stream.toolCalls 中的每个条目映射回触发它的 AI 消息:
用例
当工作依赖于仅存在于客户端的 API 或数据时,使用无头工具:- 在 IndexedDB 或
localStorage中的本地记忆 - 设备 API,如地理位置、剪贴板、摄像头或文件选择器
- 画布、音频或其他仅限浏览器的渲染原语
- 应保留在用户设备上的隐私敏感数据
- 需要直接访问内存中前端状态的 UI 操作
最佳实践
- 保持工具小巧且类型化。优先使用多个窄范围的工具,而不是一个通用的“运行任意浏览器代码”工具。
- 返回 JSON 可序列化的结果。不要尝试返回 DOM 节点、文件句柄或其他不可序列化的浏览器对象。
- 共享定义,分离实现。智能体和客户端应就工具名称和模式达成一致,但只有客户端应加载浏览器 API。
- 在 UI 中呈现工具状态。使用
stream.toolCalls和onTool来显示待处理、成功和错误状态。 - 在需要时添加审查。对于敏感的客户端操作,将此模式与 人在环中 结合使用。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

