无头工具的工作原理
从高层次看,无头工具将工具模式与仅在浏览器端运行的实现分离开来。- 在智能体上注册一个仅包含模式(schema-only)的工具定义。
- 使用
.implement(...)在前端实现匹配的工具。 - 将这些实现传递给
useStream({ tools: [...] })。 - 当智能体发出匹配的工具调用时,客户端运行它并使用工具结果恢复被中断的运行。
在智能体上注册工具
Playground 定义了一小组遵循相同模式的客户端工具:智能体暴露一个工具模式,前端负责实际执行。 在共享的tools.ts 文件中定义一次工具,并从智能体和前端使用该文件。
实现浏览器行为
将仅限客户端的行为放在一个单独的模块中,并使用.implement(...) 将其附加。真实的 Playground 包含了一个更完整的 IndexedDB 存储,具有搜索、列表、过期和删除操作。以下示例在更高层次上展示了相同的结构:
impl.ts
将实现连接到 useStream
将已实现的工具传递给 useStream。当智能体发出匹配的工具调用时,该钩子会运行客户端实现并为您恢复运行。
智能体状态可以从智能体定义中推断出来:
内联渲染工具活动
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.

