第 03 章:补齐四大工具 read/write/edit
上一章的 agent 只会用 bash——理论上这已经够了(cat、sed 什么都能干)。但实践中,给模型专用的 read/write/edit 工具效果好得多。这一章把 pi 的默认四件套补齐,并解决一个 agent 的隐形杀手:工具输出把上下文撑爆。
为什么是这四个工具
pi 默认只给模型 read、write、edit、bash 四个工具(createCodingTools,MIT 许可),理由有三:
- 模型在训练数据里已经见过大量同构的工具 schema,拿来就会用,不需要在系统提示词里再教一遍。
edit的"精确文本替换"比"全量重写"省 token 且更不易错——改一行和重写一个 500 行文件,出错概率天差地别。- 其余一切交给
bash。pi 还有grep/find/ls三个只读工具,但默认禁用,只在你显式--tools read,grep,find,ls(只读模式)时才启用。
四件套的语义分工(pi 系统提示词里的 guideline 也是这么写的):
edit 的精确匹配哲学
edit 是四件套里最值得细看的。它的失败模式被刻意设计成可操作的错误文本:
oldText找不到 → "oldText not found … Read the file first" —— 提示模型先去读;oldText匹配到多处 → "matches N locations … Provide more context" —— 提示模型带上更多上下文。
模型读到这些错误会自我修复:先 read 拿到精确内容,再用更大的上下文块重试。错误信息是写给模型看的指令,这是工具设计里最容易被忽视的一点。pi 的 edit.ts 同样如此,只是多了 diff 生成等给 UI 用的附加信息。
mini-pi 用的是"一次一处替换"的形式(简单、好讲)。pi 当前版本的 edit 工具接受 edits: [{oldText, newText}, …],一次调用完成多处互不重曡的替换(旧的单替换形式仍被兼容、内部归一化为 edits[])——改多处可以少一次往返,又比全量重写省 token。等你的 agent 稳定后,这是值得借鉴的下一步。
上下文防爆:输出截断
cat 一个 10 万行的日志、grep 命中 5000 行……任何一次工具调用都可能把上下文窗口打穿。pi 的对策是 truncate.ts:2000 行 / 50KB 双上限,先到先截,绝不返回半行,并在输出尾部告诉模型"被截了、一共多少、怎么拿剩下的"。
三个新工具
在 TOOL_DEFS 里补上三个定义(描述对照 pi;pi 当前的描述还会带上截断行为说明,mini-pi 从简),并把 executeTool 的 switch 补全:
验收
在空目录里试这个任务,它会驱动 write → read → edit 的完整链路:
你会看到模型 write 创建文件,bash 执行 npx tsx hello.ts,如需修改则用 edit 精确替换——四个工具各司其职。
本章要点
- 四件套的价值不在能力(
bash全能),而在引导模型用更省 token、更少出错的方式工作。 edit的多匹配报错、"先读后改"的错误文案,都是写给模型的指令。- 2000 行/50KB 截断是上下文预算的保险丝,截断说明要告诉模型"怎么拿到剩下的"。
- pi 的真实实现还做了更多:给 UI 的 diff(
edit-diff.ts)、写操作串行化(file-mutation-queue.ts)、图片读取等,详见源码导读:工具实现。
下一章:第 04 章:流式输出与中断。