极简核心:pi 的第一性原理

拆开 pi 之前,先看两组数字:

  • pi 的系统提示词加全部工具定义,合计 不到 1000 token
  • 同一时期,主流 harness 的系统提示词在 数千到上万 token 量级,且每个版本都在变。

这组对比浓缩了 pi 的全部哲学:agent 的能力来自模型本身,harness 的职责是管好上下文、提供恰好的工具,然后别挡路。本篇讲这套哲学最直观的两个体现:极简系统提示词和极简工具集。

问题:harness 都在变胖

作者在构建手记里毫不掩饰他的不满:他用了很久的 Claude Code 变成了"一艘 80% 功能他用不到的宇宙飞船",而且系统提示词和工具每个版本都在变——你的工作流随之被迫改变,模型行为也随之漂移。更糟的是,harness 会往上下文里注入你看不见的东西:隐藏的提示词段落、自动附加的"系统提醒"、后台塞进来的文件摘要。

作者的判断是:上下文工程是 coding agent 的第一要务。模型的输出质量取决于你往上下文里放了什么,精确到 token。一个在你背后偷偷加料的 harness,让你永远无法真正控制上下文。pi 因此反其道而行:核心里能不放的东西一律不放,放了的东西必须摊在你面前。

pi 的系统提示词全文

以下是 pi 默认系统提示词的核心部分(见 packages/coding-agent/src/core/system-prompt.ts,MIT 许可;当前版本还含一段 pi 自身文档的指引,此处省略):

You are an expert coding assistant operating inside pi, a coding agent harness.
You help users by reading files, executing commands, editing code, and writing new files.

Available tools:
- read: Read file contents
- bash: Execute bash commands
- edit: Make surgical edits to files
- write: Create or overwrite files

Guidelines:
- Use bash for file operations like ls, rg, find
- Be concise in your responses
- Show file paths clearly when working with files

然后拼接三块动态内容:<project_context>(分层加载的 AGENTS.md)、技能清单(如果有)、当前工作目录。就这些。

你可能觉得疯狂:模型在它的"原生" harness(比如 Claude Code 之于 Claude)上受过训练,用接近原生的提示词不应该效果最好吗?作者的观察是:前沿模型已经被 RL 训练得"天生理解 coding agent 是什么"——它们见过海量的"读写改跑"轨迹,不需要再用一万 token 教它怎么当 agent。证据:他用这段提示词跑 Terminal-Bench 2.0(Claude Opus 4.5),成绩与各家原生 harness 同处第一梯队;更极端的对照是 Terminus-2——Terminal-Bench 团队自己的极简 agent,只给模型一个 tmux 会话、没有任何文件工具——也稳在榜上。

一个值得注意的实现细节:提示词是按实际启用的工具动态拼装的(buildSystemPromptselectedTools/toolSnippets 参数),"Use bash for file operations" 这条 guideline 只在有 bash 而没有 grep/find/ls 工具时才出现。提示词不在多,而在每一句都对应一个真实的系统状态

四个工具的全部定义

pi 默认只给模型四个工具(见 packages/coding-agent/src/core/tools/):

工具参数语义
readpath, offset?, limit?读文件;文本默认前 2000 行,支持翻页;图片作为附件
writepath, content创建或整体覆盖;自动创建父目录
editpath, edits: [{oldText, newText}, …]精确文本替换,每处 oldText 必须唯一、互不重叠;一次调用可改多处(早期单 oldText/newText 形式仍兼容)
bashcommand, timeout?在 cwd 同步执行 bash,返回 stdout+stderr

工具描述也不是死的,而是随实现演进、如实反映行为:例如 bash 的当前描述写着"输出截取最后 2000 行/50KB,截断时完整输出存入临时文件";read 的描述则写明截断上限和"用 offset 翻页直到读完"。描述即文档,模型靠它规划行为。

为什么够?

  1. 模型本来就会。这些 schema 与各家训练数据里大量的工具定义同构,不需要额外教学。
  2. bash 是万有工具lsgrepfindcurlgittmux……一个 bash 覆盖整个 shell 生态。pi 确实实现了 grep/find/ls 三个只读工具,但默认禁用——它们存在的意义是让你在 --tools read,grep,find,ls 时组成只读模式,而不是日常使用。
  3. 每个工具一个明确的语义分工,互相不重叠。重叠的工具会让模型在选择上犹豫,浪费 token 还增加出错面。对比之下,一些 harness 同时提供 grep/search/find_files 等多个近义工具。

工具的返回值设计同样克制:文本输出统一过 2000 行 / 50KB 双上限截断(tools/truncate.ts),截断时明确告诉模型"被截了、总共多少、怎么拿剩下的"。上下文预算由此有了保险丝。

为什么"少"反而赢

把系统提示词+工具定义控制在 1000 token 内,换来的是:

  • 上下文全归你。没有隐藏注入,你可以逐 token 审计模型看到的一切——这是"上下文工程"能成立的前提。
  • 行为可复现。提示词不随版本漂移,你的工作流不会因为 harness 升级而失效。
  • 跨模型通用。提示词不针对特定模型调教,换模型(甚至 mid-session 换 provider)行为一致。
给造 agent 的你的启示

先假设模型什么都会,只给它最精悍的角色锚定、工具清单和分工约束;把项目级、工作流级的定制移出核心,放到用户可控的文件(AGENTS.md)里。提示词膨胀通常是 harness 作者不自信的表现,而不是模型的需求。

动手验证:实战篇第 05 章会把这套提示词逐句搬进 mini-pi;工具实现细节见源码导读:工具实现。下一篇:pi-ai:统一 LLM 层 →