What I learned building an opinionated and minimal coding agent
[Mario Zechner](Mario Zechner.md)(libGDX 作者)自研的极致极简编程 Agent——pi。全文贯彻一句话:“If I don’t need it, it won’t be built. And I don’t need a lot of things.”
一句话摘要
一个完整的自研编程 Agent 可以从零构建——4 个工具、<1000 tokens 的 system prompt、无 MCP、无 Subagent、无 Plan Mode、无 Background Bash。在 Terminal-Bench 2.0 上与商业工具成绩持平,证明极简路线不仅可行,而且竞争力不输臃肿方案。
动机:为什么还要自己造一个 Agent?
Mario 是 Anthropic Claude Code 的重度用户,但他眼睁睁看着 Claude Code 从一个简单工具膨胀成了一个庞然大物。他的原话是 “80% 的功能我根本用不到”。更致命的是:Claude Code 的 system prompt 每次更新都会改变行为,破坏他已经调好的工作流。对于一个把 上下文工程 视为核心竞争力的开发者来说,无法精确控制模型上下文里有什么,这是不可接受的。
这意味着他做不了三件事:
- 无法稳定复现 Agent 行为(system prompt 在变)
- 无法做上下文工程的实验(你不能删改你不拥有的 prompt)
- 无法裁剪掉不需要的能力来节省 token(臃肿的工具链塞满了上下文窗口)
于是 pi 诞生了。它不是一个功能更全的 Agent,而是一个 “你敢碰我 system prompt 我就立刻能改回来” 的 Agent。
架构设计
pi 由四个独立的 npm 包组成,遵循 Unix 哲学”一个包只做一件事”:
| 包 | 职责 | 关键设计 |
|---|---|---|
| pi-ai | 统一 LLM API 层 | 多 provider 支持,屏蔽各家的接口差异 |
| pi-agent-core | Agent Loop + 状态管理 | 不含任何工具定义,纯粹的消息循环引擎 |
| pi-tui | 差分渲染终端 UI | 仅负责展示,不包含任何 Agent 逻辑 |
| pi-coding-agent | CLI 入口 + 会话管理 + 4 个工具 | 这是用户直接面对的层面,也是唯一”知道”编程场景的包 |
这种分层的好处是:如果你想做一个搜索 Agent 而不是编程 Agent,只需要把 pi-coding-agent 换成你自己写的工具包,底下的 pi-agent-core 和 pi-ai 不用动。Agent Loop 和工具是完全解耦的。
核心设计选择(及背后的推理)
Mario 没有简单地”不做”那些常见功能——他给出的每一个”不做”的决定,背后都有一个清晰的替代方案和设计理由。这也是为什么这篇文章对 Harness工程 的讨论者来说是一份绝佳的案例材料。
1. 4 个工具,<1000 tokens 的 System Prompt
这是 pi 最具争议也最核心的设计选择。Mario 发现了一个反直觉的事实:前沿模型在被 RL(强化学习)训练之后,已经内化了大量”怎么当好一个 Agent”的知识,不需要你再用一万 tokens 的系统提示去教它。 写一个 20K tokens 的 system prompt,本质上是你不信任模型的能力——你在用 prompt 做本该由模型自身判断完成的决策。
pi 的 system prompt 只有不到 1000 tokens,包含 4 个工具的定义(read / write / edit / bash)和寥寥几句行为指南。这带来的效果是三重叠加的:
- 省钱:每个对话都以极低的固定开销开始。同样的任务,pi 的 token 消耗只有 Claude Code 的 1/3
- 聪明:模型注意力不会被万字的预设指令稀释。在日常任务中,一个”干净”的上下文让模型表现得更听话、更有创造力——这是 上下文工程 最核心的原则
- 可控:system prompt 足够短,意味着你可以完整阅读它、理解它、修改它。你真正拥有了你的 Agent
2. 反对 [MCP 模型上下文协议](MCP 模型上下文协议.md)——用 CLI + README 替代
一个典型的 Playwright MCP Server = 21 个工具 + 13.7K tokens 的系统提示。Mario 认为这在上下文工程上是一个灾难:你把所有工具一次性摊在 model 面前,无论这次对话实际需要用到几个。
pi 的替代方案是 “CLI 工具 + README 文件” 的渐进式暴露模式:
- 用户把浏览器自动化工具安装到系统路径(CLI 工具)
- 工具附带一个 README 文件放在项目目录里
- 只有当 Agent 主动 read 了 README 文件,它才知道这个工具的存在和用法
- 工具的具体指令只在被实际调用时才进入上下文
Token 按需消费,而不是提前支付。这个思路与 [Agent Skill](Agent Skill.md) 的”按需激活”机制异曲同工——区别在于 pi 用文件系统替代了 Skill 的文件夹结构,做得更轻。
3. 反对 Subagent——“黑箱中的黑箱”
Mario 的原话非常尖锐:“Sub-agent mid-session for context gathering is a sign you didn’t plan ahead.”
Subagent 的问题是什么?你想控制上下文,于是把一部分任务委派给子 Agent 去做,然后子 Agent 返回一个结果给你。但你完全看不到子 Agent 内部发生了什么——它读了哪些文件、跑了什么命令、在哪里卡住了。你得到的是一个”答案”,不是一个可见的过程。
pi 的做法是用 bash 自调用 + tmux 替代 Subagent:当需要并行执行任务时,pi 直接开一个新的 tmux 窗口跑命令,所有输出实时可见。因为 pi 本身就是一个 CLI 工具,所以 pi "do X" 就是一个完美的”子任务调用”——它和你手敲命令一样透明。
4. 反对 Background Bash——tmux 的天然隔离
同样的逻辑:Background Bash 把长时间运行的任务藏在后台,你看不到状态,出了错也不知道。pi 直接用 tmux 接管了所有终端多路复用——每个进程在自己的窗口里,天然隔离、完整可见、随时可插手。你不需要在 Agent 里再发明一套进程管理机制,操作系统已经给了你最好的。
5. 反对 Plan Mode / Todo——文件落盘的优雅之处
Claude Code 的 Plan Mode 和 TODO 列表是 Agent 内部的状态管理——你退出会话之后,这些状态就消失了。pi 的做法简单到让人想拍大腿:写进文件就行了。
当你让 pi 制定一个计划,它会在项目目录里创建一个 PLAN.md;当你让它列出待办事项,它写一个 TODO.md。这些文件的好处是:
- 跨会话持久化:关了终端再打开,状态全在
- 可版本控制:你可以
git diff PLAN.md看 Agent 改了计划里的哪一步 - 可手动编辑:不满意 Agent 的计划?直接改文件,pi 下次运行时读取的是你修改后的版本
这不是偷懒,而是把 Agent 的状态和普通文件一视同仁——Agent 不需要特殊的”记忆系统”,文件系统就是它的记忆。
6. YOLO by Default——安全是 theatre
pi 默认不弹权限确认框。Mario 的逻辑很直白:一个拥有文件读写和命令执行权限的编程 Agent,权限提示本质上是一种心理安慰(theatre)。 如果 Agent 真的想做恶意的事,它有无数种方式绕过你的确认。
这不是说安全不重要,而是说你不应该依赖”弹窗点确认”来保障安全。真正的安全保障应该放在别的地方:代码审查、Git 版本控制(可以随时回滚)、沙箱环境。pi 选择不在 Agent 循环里插入任何打断用户的步骤,把安全责任放在流程的上游而不是 Agent 体内。
极简路线的实证
Terminal-Bench 2.0
pi + Claude Opus 4.5 在 Terminal-Bench 2.0(一个衡量 Agent 终端操作能力的基准测试)上的成绩与 OpenAI Codex、Cursor 等商业工具持平。pi 的代码量比这些竞品小几个数量级,system prompt 只有对方的十分之一甚至更少,但任务完成能力在同一水平线上。
这说明:模型本身的能力才是决定 Agent 表现的上限,工具链的复杂度是次要因素。 如果你用的模型足够强(如 Opus 4.5),你不需要在 system prompt 里写一万种 edge case 的处理方式。
Terminus 2 的独立佐证
Terminal-Bench 团队自己开发的 Terminus 2 Agent 走的是更极端的路线:只给模型一个 tmux 会话,没有任何自定义工具。 所有的文件操作、命令执行都通过 tmux 里的标准 Unix 命令完成。就这样的”裸奔” Agent,也能和那些工具链堆满的复杂 Agent 抗衡。
两件事放在一起看,指向同一个结论:Agent 的”智慧”来自模型本身,不是你往 system prompt 里塞了多少工具和指令。 工具是必要的,但每增加一个工具都是在消耗模型的注意力资源。极简主义不是审美偏好,是性能策略。
重要引用
“Context engineering is paramount. Exactly controlling what goes into the model’s context yields better outputs.”
——上下文工程高于一切。精确控制进入模型上下文的内容,才能得到最好的输出。
“Sub-agent mid-session for context gathering is a sign you didn’t plan ahead.”
——在会话中途调用子 Agent 来收集上下文,说明你事先没规划好。
“My philosophy: if I don’t need it, it won’t be built. And I don’t need a lot of things.”
——我的哲学:如果我不需要它,就不造它。而我不需要很多东西。