自定义工具是 agent harness 和真实工程系统之间的受控接口。模型只能看到工具名、描述和参数 schema;运行时负责校验参数、执行工具、把结果和错误重新包装成模型可以继续推理的上下文。
什么时候应该写一个专用工具,而不是让模型直接使用通用命令工具?
- 工具名和描述决定模型什么时候会调用它。
- 参数 schema 决定模型能传什么输入。
- execute 决定真实副作用和返回格式。
- 工具结果必须足够结构化,方便模型继续推理和宿主审计。
源码推演(省略版)
Section titled “源码推演(省略版)”下面不是完整源码,而是把本课主线压缩成可以在文档里直接阅读的关键形状。读者即使不打开本地源码,也应该能看出运行时如何组织职责。
const runTests = defineTool({ name: "run_tests", description: "Run the approved project test suite and return a structured summary.", parameters: { suite: enumOf(["unit", "typecheck"]) }, async execute(args) { const result = await approvedRunner.run(args.suite); return { exitCode: result.code, summary: result.summary }; },});- 专用工具把权限收窄到“允许的测试套件”,比开放命令工具更可控。
- 返回结构里保留
exitCode和summary,既能让模型继续推理,也能让 trace 审计。 - 工具不要吞掉错误;失败也应该变成结构化 tool result。
设计一个只允许执行固定检查项的 run_tests 工具,写出参数、返回值和错误策略。
- 能写出工具名、描述、schema 和 execute 的边界。
- 能说明专用工具和通用命令工具的取舍。
- 能设计可审计的工具返回结构。
- 实践题:基于本课的省略版源码,补出一个最小实现草图,要求写清输入、输出、副作用和错误处理。
- 思考题:本课机制如果只靠 prompt 约束,而不放进 harness 或 runtime,会出现什么工程风险?