从阶段二内置工具和自定义工具实践进入 Pi 源码,理解 built-in tools、schema、执行结果、错误包装、tool diff 和 tool output streaming。
Pi 的 Tool System 分成两层:coding-agent 层负责定义具体工具,agent-core 层负责按统一协议执行工具。低层 loop 不知道某个命令如何启动,也不知道编辑工具如何算 diff;它只知道如何校验参数、调用工具、接收 update、包装错误和生成 tool result message。
为什么工具的业务细节不应该散落在 agent loop 里?
- 工具定义层描述 name、description、schema、execute 和可选渲染信息。
- 包装层把 SDK 工具变成 core 能执行的统一工具。
- 执行层处理参数校验、before/after hook、并行或串行策略。
- 结果层把成功、失败和 partial update 都转成模型可读消息。
源码推演(省略版)
Section titled “源码推演(省略版)”下面不是完整源码,而是把本课主线压缩成可以在文档里直接阅读的关键形状。读者即使不打开本地源码,也应该能看出运行时如何组织职责。
async function executePreparedTool(call: ToolCall) { const tool = tools.find(call.name); const args = validate(tool.parameters, call.arguments);
try { const result = await tool.execute(args, { onUpdate: emitToolUpdate }); return toolResult(call.id, { ok: true, result }); } catch (error) { return toolResult(call.id, { ok: false, error: summarize(error) }); }}- 这段省略版源码展示了工具系统的公共协议。
- 具体工具可以有自己的实现细节,但错误和结果必须统一包装,否则模型无法继续推理。
- 如果要增加命令风险评分,应该先决定它属于工具结果、before hook 策略,还是审计事件。
为命令风险评分设计字段位置:放在工具结果、before hook 决策,还是 trace 事件里,并说明理由。
- 能说明工具定义、包装、执行和结果四层。
- 能解释为什么错误也要变成 tool result。
- 能判断 tool diff 为什么属于具体工具而不是通用 loop 概念。
- 实践题:基于本课的省略版源码,补出一个最小实现草图,要求写清输入、输出、副作用和错误处理。
- 思考题:本课机制如果只靠 prompt 约束,而不放进 harness 或 runtime,会出现什么工程风险?