14.2 工具执行运行时

生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~900k tokens,输出 ~85k tokens(本章合计)


上一节我们了解了工具是如何定义、组装和过滤的。本节深入工具从被 LLM 调用到返回结果的完整生命周期。


14.2.1 工具调用生命周期

完整调用链路

当 LLM 决定调用一个工具时,调用会经过以下步骤:

LLM 输出 tool_use → pi-agent-core 解析 → 工具分发

                                    ┌─────────┴─────────┐
                                    │  before_tool_call  │ ← 插件钩子(可拦截/修改)
                                    └─────────┬─────────┘

                                        ┌─────┴─────┐
                                        │ 工具执行   │ ← abort signal 守卫
                                        └─────┬─────┘

                                    ┌─────────┴─────────┐
                                    │  after_tool_call   │ ← 插件钩子(通知)
                                    └─────────┬─────────┘

                                    ┌─────────┴─────────┐
                                    │ 结果格式化 + 持久化 │
                                    └─────────┬─────────┘

                                    ┌─────────┴─────────┐
                                    │ tool_result_persist │ ← 插件钩子(可修改结果)
                                    └─────────┬─────────┘

                                      返回给 LLM

before_tool_call 钩子包装

每个工具在创建后都会被 wrapToolWithBeforeToolCallHook() 包装,注入钩子调用逻辑:

runBeforeToolCallHook() 的内部逻辑:

Abort Signal 守卫

工具还会被 wrapToolWithAbortSignal() 包装,支持会话中断时取消长时间运行的工具:

包装顺序

工具的包装遵循从内到外的顺序:

createOpenClawCodingTools() 中可以清楚看到这个链:


14.2.2 工具结果格式化

AgentToolResult 结构

工具执行后返回 AgentToolResult,其核心结构:

content 是发送给 LLM 的内容块数组,支持文本和图片两种类型。details 是结构化的执行详情,不发送给 LLM,但可以用于日志和调试。

JSON 结果模式

大多数工具使用 jsonResult() 返回结构化数据:

图片结果模式

browserimagecanvas 等视觉工具使用 imageResult() 返回图片:

图片结果会经过 sanitizeToolResultImages() 处理,确保图片不会超过 LLM 的上下文限制。

工具结果持久化钩子

在工具结果写入会话转录之前,会触发 tool_result_persist 钩子(回顾 13.2.3 节),允许插件修改持久化的内容。典型应用场景:

  • 精简大型结果:移除工具结果中的冗余数据,减少上下文占用

  • 脱敏处理:在持久化前移除敏感信息

  • 补充元数据:添加时间戳或标签


14.2.3 错误处理与重试策略

工具级错误处理

工具执行中的异常会被 pi-agent-core 捕获,转换为工具错误结果返回给 LLM:

LLM 看到错误结果后,通常会:

  1. 分析错误原因

  2. 修正参数后重试

  3. 如果多次失败则放弃并告知用户

钩子错误隔离

before_tool_call 钩子的错误不会阻止工具执行——钩子被设计为"尽力而为":

超时控制

exec 工具(命令执行)有独立的超时配置:

工具执行还受到会话级 AbortSignal 的控制——当用户发送 /stop 命令或会话超时时,所有正在运行的工具都会收到中断信号。


本节小结

  1. 工具调用经过四层处理before_tool_call 钩子拦截/修改 → 工具执行 → after_tool_call 通知 → tool_result_persist 持久化控制。

  2. 工具被三层包装器链式包装:Schema 归一化 → 钩子注入 → Abort Signal 守卫,保证了兼容性、可扩展性和可中断性。

  3. 工具结果支持文本和图片两种格式jsonResult()imageResult() 分别用于结构化数据和视觉内容。图片结果会经过 sanitize 处理。

  4. 错误处理遵循"优雅降级"原则:钩子失败不阻止执行,工具异常被转为错误结果让 LLM 自行修正,会话中断通过 AbortSignal 传播。

Last updated