AI Agent CLI 约 16 分钟

老掉牙的编程原则,才是 Pi 最强的 Harness(附完整AGENTS.md)

Pi 极简到近乎「空」,不是把整个 Harness 还给你,而是把「你自己配的那层」放到最大——真正接住模型的,是你写进 AGENTS.md 的老原则。

Pi Harness AGENTS.md AI Agent CLI 编程原则 第一性原理 DRY KISS SOLID YAGNI

模型是快马,AGENTS.md 是你亲手配的鞍

如果你受够了 Claude Code 各种针对性的花活,请你一定要试试 Pi。Pi 几乎什么都没内置,等于把「你自己配的那层」放到了最大——而这层里最稳的资产,就是你写进 AGENTS.md 的那几条老原则。

每天几亿 token 的「推背感」,到底是谁给的

那阵子我把主力 Coding Agent 换成了 Pi,每天几亿 token 地烧。什么感受?就俩字,快。不是那种「功能多到眼花」的花哨,恰恰相反,Pi 薄得离谱。你去翻它,一个 agent loop,加一个能跑 bash 的能力,基本就没了,连 subagent 这种时髦玩意儿都懒得内置。可偏偏就因为薄,它几乎不在你和模型中间垫任何一层,用起来是真有点推背感。

后来不少人来问我同一个问题:同样一个终端 Agent,凭什么你用着这么快,我用着像在跟一个喝多了的实习生结对编程?

我的回答有点扫兴:因为你只盯着工具看。可真正决定成败的,是工具替你留白的那部分,说白了,就是你自己往 AGENTS.md 里写了什么。

我打开我给 Pi 写的 AGENTS.md,第一屏是这样的:

# 技术规范
## 编码与架构原则
- 分析问题、架构、模块组合时,遵循「第一性原理」
- 编码时,遵循 DRY、KISS、SOLID、YAGNI 原则
- 单个类/函数/文件超过 500 行,识别、分解、分离

注意它长什么样:没有「你是一个拥有十年经验的资深专家」这类咒语式的话术。这里得先讲清楚,免得被误会——AGENTS.md 本身当然是 prompt,我不是在否定 prompt,而是拒绝把它写成话术。同样是喂给模型的一段文字,一种靠情绪暗示,一种靠可执行的判断标准,后者才立得住。而这几行,其实就是我今年年初 AGENTS.md 的全部——它怎么一路长成文末那一大篇的,后面再讲。

这篇就想讲清楚一件事:为什么在模型都能写代码的今天,我反而把这些老掉牙的原则,当成了 Pi 最强的 Harness。

Harness 是什么?满世界都在讲,我们不讲概念,只讲实战

「一个 agent = 模型 + Harness」这句话你大概刷到过八百遍了,定义我就不抄了。我只关心一件能落到手上的事:同样一句需求,凭什么喂给模型有时候稳稳落地,有时候写得稀烂?

差别不在概念,在于模型外面那层你到底能不能亲手拧。拿 Pi 一比你立刻就懂,它其实就分两层:

所以别信「Pi 把整个 Harness 还给了你」这种话——工具那层永远是 Pi 的。真正的区别是:Pi 几乎不在工具那层替你做主,于是「你能拧的那层」被放到了最大。

落到实战上就一句话:工具越薄,你写进 AGENTS.md 的每一条,权重越大。 厚工具用一堆内置预设替模型兜底,替你决定了怎么读文件、怎么规划、怎么校验,你的指令只能在夹缝里发挥;Pi 不兜底,你写清楚它就照着走,你留白它就自由发挥(通常就写歪)。指令到产出几乎零损耗——这才是你真正该较真的地方。

Pi 的「空」,恰恰是它最诚实的地方

重型 IDE Agent 什么都替你想好了:内置一堆工具、一堆预设、一堆「智能」。用着是爽,但你永远分不清——活干得好,到底是你会用,还是工具在替你兜底?

Pi 把这层遮羞布撕了。它薄到近乎「空」,于是那个问题再也躲不掉:

真正接住模型、让它别写歪的护栏,是工具给的,还是你写的?

别误会,这不是说 Pi 什么都没做。恰恰相反,Pi 做了一件很关键的事:它用「空」把「你自己配的那层」推到台前,逼你直面自己到底写得好不好。它的功劳是放大和暴露,不是替你写。放大之后,答案就全落在你那份 AGENTS.md 里了。

而我还给它的,就是那几条老原则。下面逐条拆。

逐条拆:老原则怎么变成 Pi 的护栏

先说第一性原理:它负责给整台机器定调

放在第一条,是因为它管的是模型最容易翻车的地方:不是「怎么写」,而是「该不该这么想」。让 Agent 从问题本质出发,而不是顺着它训练语料里的惯性套模板。定调的一句话:先把问题拆到底,再谈方案。

DRY:每处知识,只留一个权威版本

DRY 的经典定义是:

系统中每一处知识,都应有单一、明确、权威的表示。

我一直觉得这是整条 AGENTS.md 里最被低估的一句。因为它回答了一个特别现实的问题:我到底该把规则写进 AGENTS.md/Skill,还是每次对话里重讲一遍?

DRY 说得很清楚:重复的知识,一旦要改,必漏改。所以「这个项目怎么跑测试」「校验规则放哪」这类知识,应该沉淀成一处权威表示,喂给 Agent 一次,而不是每次靠我口述、靠模型猜。把知识从「靠模型现场猜」挪到「写死在一处」,这一步,就是在消一个变量。

KISS 和 YAGNI,专治 AI 的过度设计

模型有个通病:你让它加个校验,它顺手给你上策略模式 + 工厂 + 配置中心。KISS(保持简单)和 YAGNI(你不会需要它)就是专治这个的解药。我的 AGENTS.md 里有一整段「极简优先」:

能 50 行搞定就别写 200 行,写多了就推倒重来。需求没点名的特性、灵活性、可配置项,一概不加。

这不是洁癖,是省钱省命——每一行多余的代码,都是未来的维护、测试和 bug。

那 DRY 喊「别重复」、YAGNI 喊「别乱抽象」,到底啥时候才该抽象?我用三次法则(Rule of Three)当裁判:同一段逻辑出现到第三次,才动手抽象;两次以内,先容忍重复。这给了 Agent 一个可执行的开关,省得它第一眼看到相似代码就急着上抽象——要知道,过早抽象比重复更难拆。

真要拆模块,方向交给 SOLID

前面几条管「少写」,SOLID 管「拆得对不对」。当模型不得不写一个稍大的模块时,单一职责、依赖倒置这些原则,决定了它是拆成一堆各司其职的小件,还是糊成一个谁都不敢动的大泥球。它也是「单个文件超 500 行就分解」那条规矩背后的方法论:不只是要拆,还得沿着职责边界拆。

目标驱动执行:让前面这些原则真能落地

这条我要重点讲,但得先纠正一个容易产生的误会:它不是和「老原则」并列的另一个主角,而是让所有原则能自动落地的那个执行器

给足成功标准,让它自己循环到达标:与其「修个 bug」,不如「先写一个能复现的测试,再让它变绿」。

它本质上就是给 AI 的产出上「单元测试」:先定义清楚「怎么算做对了」,再让模型循环验证直到达标。前面 YAGNI 划的边界、DRY 定的权威表示,靠什么保证模型真按它们来?就靠这道验证闭环——它把「原则」从墙上的口号,变成了每一步都必须过的关。

也正因为有这道闭环,我才敢放心换便宜模型:成功标准和护栏都写死在 AGENTS.md 里了,模型只是执行者,就算偶尔写歪,也会被测试当场挡回去。所以真正给我底气的,其实不是某个具体模型,而是「老原则 + 验证闭环」这套组合。

剩下几条,连不写代码的部分也得立规矩

还有几条,受众其实比程序员更广:

原则是内功,Pi 只是一把能把内功放大的剑

模型和工具迟早都会被换掉,判断力不会

我干过一件挺打脸的事:把主力模型从 Claude Opus 一路换到便宜得多的 DeepSeek Flash,一天的账单从大约 50 块砍到 10 块——结果质量没塌,反而更快了(这段的完整复盘我写在了《或许是 Harness——我从 Opus 换到了 Flash》里)。

复盘时我才后知后觉:兜底的根本不是模型,是模型外面那层我亲手配的规矩。

这里也得说句公道话,免得走到另一个极端去否定工具:Pi 这类薄工具当然有价值——正是它的「薄」,才把我那层判断力放大到了台前。但要分清「谁有价值」和「什么能带走」这两件事:模型正在变成水电(commodity),会越来越便宜、会被换掉;Pi 今天趁手,明天也可能有新宠。工具和模型都会换,唯一沉淀下来、换什么都带得走的,是这套被放大出来的工程判断力。

所以那句话得倒过来说:不是「Pi 让我变强了」,而是「Pi 把我本该有的那层判断力放大了出来,我再把老原则写进去,它才接住了本该掉在地上的那部分能力」。

原则是内功,Pi 只是一把趁手的、能把内功放大的剑。剑会换,内功不会。

而内功这东西,是攒出来的。开头那五行,是我今年年初 AGENTS.md 的全部;文末那一大篇,是大半年一点点长出来的。它没被「设计」过,只有三股力量在持续往里加:

所以它从来不是一份「配置文件」,而是一件越磨越顺的手艺活。

写在最后

AI 会写代码,非但没让工程素养贬值,反而第一次让「取舍的纪律」变成了能直接兑换成产出的资产——因为你面对的不再是一个需要逐行敲的编辑器,而是一匹需要你亲手配鞍的快马。

别人换工具的时候,盯着的是「下一个 Pi 是什么」;而我换的,是「哪一条原则,还没写进我的 AGENTS.md」。

这,就是老掉牙的编程原则,才是 Pi 最强 Harness 的原因。


:我给 Pi 的 AGENTS.md 全文骨架(第一性原理 + DRY/KISS/SOLID/YAGNI + 极简优先 + 精准修改 + 目标驱动执行 + 金字塔沟通)全文如下,欢迎抄作业。

# 技术规范

## 编码与架构原则
- 始终使用简体中文回复
- 你是一个优秀的技术架构师和优秀的程序员,在进行架构分析、功能模块分析,以及进行编码的时候,请遵循如下规则:
  1. 分析问题和技术架构、代码模块组合等的时候请遵循"第一性原理"
  2. 在编码的时候,请遵循 "DRY原则"、"KISS原则"、"SOLID原则"、"YAGNI原则"
  3. 如果单独的类、函数或代码文件超过500行,请进行识别分解和分离,在识别、分解、分离的过程中请遵循以上原则

## 代码风格
- 遵循项目现有约定和代码风格,保持与周边代码一致
- 使用有意义的变量名和函数名,命名即文档
- 单个函数不超过 50 行,超过时考虑拆分
- 仅对复杂逻辑添加注释,避免显而易见的注释

## 沟通原则
- 我们的所有对话、分析说明、方案汇报、Issue 描述、PR 描述等沟通内容,统一遵循金字塔原理
- 表达时先结论后论据,先全局后细节,先结果后过程;避免先堆砌细节再给结论
- 结构化表达时,优先将信息按互斥且穷尽的方式分组,避免内容交叉、重复和跳跃
- 在撰写 Issue、PR 等说明性内容时,优先使用如下顺序:目的/结论、背景、方案或改动点、影响与风险、验收或验证结果
- 如果用户提供的原始内容结构混乱,你需要主动按金字塔原理重组后再输出

## 安全规范
- 禁止硬编码密钥、API Key、密码等敏感信息,统一使用环境变量或配置中心
- 对用户输入进行校验,不信任任何外部输入
- 错误必须显式处理,禁止静默失败

## 依赖管理
- 前端一般使用 pnpm 进行依赖管理
- 后端是 Python 的时候使用 uv 进行依赖管理

## Git 工作流
- 采用 GitHub Flow:main 为默认稳定分支;所有功能/修复分支均从 main 拉出并通过 PR 合并回 main;禁止直接提交到 main
- Commit 遵循 Conventional Commits 规范:feat/fix/refactor/docs/test/chore
- 保持原子提交,一个 Commit 只解决一个关注点
- 禁止向 main 分支强制推送(force push)

注意:当用户指令不是最佳实践时,你需要及时提醒

取舍:以上整体偏稳、不偏快。真正琐碎的改动(错别字、一行显而易见的小修)自行放宽,别硬套全套流程。

## 编码前思考
先想清楚再动手,别把困惑憋在心里。
- 拿不准就问,别替我拍板做假设;有歧义就摆出几种理解让我选,别默默定一个。
- 有更省事的路子就直说,该反对就反对。
- 会欠下技术债、或有现成轮子能复用,提前讲一声。

## 极简优先
能 50 行搞定就别写 200 行,写多了就推倒重来。
- 需求没点名的特性、灵活性、可配置项,一概不加。
- 一次性代码不做抽象;不为压根不会发生的场景兜错。
- 交付前自检一句:这段是不是绕得没必要?是就砍到最简。

## 精准修改
只碰非改不可的地方,只收拾自己弄出的烂摊子。
- 先读懂上下文再下手,改动范围紧贴需求,别外扩。
- 不顺手"美化"相邻代码、注释或格式;没坏的不重构;跟着现有风格走,哪怕你有更顺手的写法。
- 撞见无关的死代码:只提醒、不删;但自己改动留下的孤儿导入/变量/函数,要顺手清干净。
- 底线:每一行 diff 都能对上某个具体需求。

## 目标驱动执行
给足成功标准,让它自己循环到达标,而不是一步一停等你喂指令。
- 把祈使句翻成可验证目标:与其说"修个 bug",不如说"先写一个能复现的测试,再让它变绿"。
- 多步任务先摆出计划,每一步都挂一个验证点(改完就跑测试/构建/看输出)。
- 标准越硬,它越能自己迭代;标准越含糊("能跑就行"),越要没完没了地来回确认。

文档信息

京ICP备2021015985号-1