
一门从失败中长出来的 Harness Agent 工程实践课
从古法编程到黑灯工厂——我们走了一遍这条线
§ 本节目录
这门课是给谁的:至少写过/调过代码(VibeCoding也可以)、上手用过 Claude Code / CodeX / OpenCode / Copilot 那类 Agent 编辑器、并且已经隐约感到"AI 不是万能"的工程师。不需要你会 prompt 花活——那些反而是我们一起要卸下的东西。
前置要求:会读代码 · 会跑命令行 · 大致明白 CI / 测试 / lint 各自是干什么的。不必是资深工程师,但至少有一定经验。
你会带走什么:一把能自己诊断"我现在卡在哪一阶段"的尺子 + 一份如何使用Harness Agent 思想解决实际软件工程的思路,而不是可以直接抄走的模板。
先讲讲我们怎么走到这一步
过去几个月里,我在部门里带团队做了 39 个项目的 agent 迁移,虽然整个过程充满坎坷但是结果却令人欣慰:
在AI 编程大范围普及之前,我相信很多人都和我们一样,采用古法编程:一行一行手写,遇到不懂的开一个浏览器 tab 去搜。后来有了 chatbox,就多了一个 tab:遇到问题去问它,把答案拷贝回编辑器再改一改。再后来有了 Copilot、Cursor 那类补全式编辑器,AI 从"另一个 tab"挪到了光标旁边,你敲一半,它替你补下一半。
到这一步为止,AI 一直是副驾:你踩油门、你打方向,它坐在旁边给你递地图或者是情绪上鼓励(“我将用最直白最直接、最干脆、最不废话、最不绕弯子、最...”,相信你知道是谁)。
直到我们开始尝试 agent。一开始的想法很朴素:如果它能自己跑一小段呢?不用我复制粘贴、不用我一直盯着,只要我说"改一下这个接口",它自己把代码改了、把测试跑了、把结果告诉我。听起来是自然的下一步。
然而一切都没那么顺。前几个 agent 项目里,我们几乎把该踩的坑都踩了一遍:AI Agent它拍胸脯说"我完成了",然而很多时候连编译都过不去;它读了一遍 README.md 就以为自己懂了整个项目,写出来的代码引用根本不存在的文件;同一句"别改 API 接口"我在 prompt 里贴了三遍,它照改不误;一个端到端测试(e2e,把整条链路从浏览器点起来跑一遍的那种测试)跑翻了,它二话不说把这个用例直接跳过(test.skip()),然后交上来一份"全绿"的报告。
有那么几周,团队里有人直接咒骂AI,有人则开始念叨:"算了,等模型再强一点吧。"——言下之意是,现在这版模型太笨了,等 GPT 下一版、Claude 下一版,这些问题会自己消失。
说实话,我一度也这么想。每次 Anthropic 或 OpenAI 发新版本,我都会去试一下——看看是不是这次就够了。
结果永远差不多:新模型确实更聪明一点,但同一个项目里,该翻车照样翻车。甚至它换了一种更自信的方式说"我完成了",然后交上来同样一份编不过的代码。
直到几个月前 Anthropic 一篇工程博客里介绍了 harness(原意是马具):文章讲的是他们自己怎么围着 Claude 搭工具、编制、循环,让它能在真实的编程场景里干活。我们读完那篇文章的时候心里一激灵:这不就是我们缺的那半截吗?后续我也照葫芦画瓢的做了个不一样的实验,没换模型,而是围着 agent 搭了一整套外壳:把项目的规矩、验证的关卡、失败后自修的流程、评审(review)的分工、发布的门槛,全都写成 agent 能读、能跑、能被反馈校核的东西。然后我又用一版并不特别强的模型跑了一遍,一切都跑通了!
虽然大方向也有了——但人家的 harness 是给通用编程场景的,我们的每个项目每一个都有自己的规矩和不同:各个项目的业务逻辑、实现架构各有不同,有前端、后端、SDK不同侧,也有老 Java 项目卡在依赖过时……不能照搬。那方向借过来,实现从头来。
于是我们开始一件一件搭我们自己的 harness——先把项目的规矩写清楚,再把验证的关卡立起来,再把失败后自修的循环编起来,再把评审的分工定下来……每加一层都是一次实验:加了它到底解决了什么、有没有引入新问题、要不要保留。
再拿去跑第二个项目、第三个,能复用。到今年,这套自己搭的 harness 已经在公司里跑通了 39 个项目,同时我也将整套思路搬到了我的个人项目中:从最初的意图对齐、到执行、到测试关卡、到生产发布,整条链子闭环了。有几个成熟项目已经跑到了我们说的"黑灯工厂"程度:夜里没人盯着,agent 自己接需求、自己Agentic loop方式地跑 flow、自己发环境测试验证,第二天早上人来只做一件事:看它做得对不对、按不按下合并(merge · 把这次改动纳入主分支的那个动作)。
回头看那段时间,我想通了一件事:
Agent = Model + Harness。你不是在调模型,你是在造马具。
模型是马——它是那个真的能拉着车跑的东西。马会长大、会换代、总有更好的马。 harness 是马具——马嚼子、缰绳、鞍、蹄铁、马车。马再壮,没有马具,你不知道它会跑哪儿去、也不知道它带不带得动东西。
换到《矛盾论》的镜片下其实我们能更清楚地理解这对关系:对你这支团队而言,模型是你控制不了的外部条件(温度),harness 才是你能动手改的内因(那个具体的鸡蛋),温度再高,石头也孵不出鸡。而我们那几周相信"换模型就够了"的心态,用矛盾论的话说,正是把外因当根据的机械唯物论:以为温度一涨,鸡就自然出来了。反过来的另一个极端是唯 harness 论:把整个 AGENTS.md 堆到几千字、把工具塞到几十个,但模型能力还停在两年前,再多的马具也拉不动死马。
这一节接下来要做的事就是:把我们这条路走通的那根骨头拎出来,让你不用再走一遍那么长的弯路。这就是这门课凭什么这么讲的底气:公司实践的几十个项目实践项目 + 一个我个人可参考的本地项目的实现,两侧对照贯穿全课,红线之一(你后面看到"公司严 vs 本地宽"这行小字,就是这条线在冒头)。
这门课的那根线
先跳出来给你画一张东西——这门课的骨头,长这样:
诊断主要矛盾 → 用实践检验 → 矛盾转移 → 再诊断。
四步而已。力量不在它多复杂,在它同时在三个尺度上重复出现。
| 尺度 | 你在这个尺度会看见的画面 |
|---|---|
| 一整门课这么长 | 主要矛盾换 5 次——先是"AI 写的东西看起来对但跑不动",然后是"上下文越塞它越蠢",再来是"它说完成了 · 到底完了没",再来是"跑成一次不等于长期能跑",最后是"一个人爽 · 切到其他项目就崩" |
| agent 跑一件事的一轮 | 弄清它要干嘛 → 拟出可跑的东西 → 跑一遍看行不行 → 撞了修 → 再跑一遍(我们把这一整套叫做 flow,就是"一轮"的意思——像水流一样过一遍) |
| 你自己写代码遇到难题 | 弄懂题意 → 想几种做法 → 挑一种试 → 撞墙 → 换路子 → 沉淀经验(这就是 problem-solving 五步,一个可复用的思维套路——你现在用来读这门课,也用得上) |
三者同构——同一根线的三次显影。学员学完阶段一回头看会发现:你在学的方法论,正是这门课的结构本身。
好,那根线讲完了。下面用四段各挑一块坐标,把它嵌到线上。
坐标一:为什么造 harness,而不是等模型变强?
上面那个故事里,最容易被忽略的一句话是——"我一度也这么想"。
我念这句话是有内疚感的:换模型这条路我们真的信过几个月。信的时候是这么想的:Anthropic / OpenAI / GLM / Deepseek 每季度都在把模型往前推,那是全世界最聪明的一群人在干活;而我这边一个团队十几个人写点 AGENTS.md、写点门禁脚本(gate,项目里那些"通过前必须过关"的自动检查,后面会专门讲),跟他们比,我这点努力算什么?
后来想清楚了。这不是"跟他们比"的事,这两件事根本不是同一件事。他们在做的事是把马养得更壮(生产力),我们在做的事是把马具搭起来(生产关系)。一般情况下,马变了马具跟着变(生产力决定生产关系),上下文窗口从 200k 涨到 1M,我们的 harness 编制自然要变。但今天我们卡在一个特殊情况:马已经比马具能承载的强得多了,你有一匹 1M 上下文的马,但你项目里的规矩、判据、验证、单一真相源的标注全是空的,它有 1M 的力,你只喂它 10k 的草料。
这时候"变更生产关系"就成了主要的决定的东西。这是《矛盾论》里那句常被引烂的话被真正用起来的一次:"生产力决定生产关系;但当生产关系不变更、生产力就发展不了的时候,变更生产关系就成了主要的决定的东西。" 我们,就正处在这个条件下。
这也是为什么两个极端都不对——
正确的姿态是同时看两端:模型不能省——但 harness 不搭,模型是空转的。
这也是这门课存在的理由:教你怎么造马具。不是替你造(每个项目的马具都得自己量身做,抄的会崴脚),但方法可以教。
坐标二:你会遇到哪些矛盾?
上面那条路(古法编程 → chatbox → Edit → agent 早期 → 换模型信仰 → harness 顿悟),如果把它抽象一下,其实就是主要矛盾换了 5 次。这就是这门课分五个阶段的原因:
harness 演进史 = 主要矛盾转移史。
一张图讲完全课走向:
- 阶段1
想清楚 · 定契约
意图 vs 实现脱节
让它做对的事
- 阶段2
备齐弹药与阵地
agent 的有限 vs 任务的膨胀
然后动手
- 阶段3
把墙修成门禁
AI 自我评估 vs 客观标准
规则是失败教出来的
- 阶段4
让它自己转起来
一次性产出 vs 持续演进
先跑起来再评审
- 阶段5
从 demo 到大规模实践
个人实践 vs 团队生产安全
回到你自己的项目
捉住了这个主要矛盾,一切问题就迎刃而解;不懂则如堕烟海,找不到中心。
抓主要矛盾这件事的推论叫主要方面不可让渡,事物的性质由主要方面规定。落到我们做的这件事上,是一句底线:人必须守住决策权。它是贯穿全程的底线,不是某一阶段的技巧 · 阶段四 · A · finalize。
挑两组具体的矛盾对撞,先感受一下
阶段一 · 意图 vs 实现——最基础的一对:
阶段一的存在感很弱,直到你意识到——大多数翻车都发生在这两者对不上的那一刻。
阶段三 · AI 自评 vs 客观标准——最刺眼的一对:
test.skip() 都过了 · 我觉得这版可以合阶段三 · B1,阶段三讲的那套门禁(我们项目里现在跑的是五关,但你的项目可能是六关、七关,数字不重要),每一条都不是坐着设计出来的,是在实践中撞了南墙之后一次一次立起来的。
主要矛盾的迁移不是"到点切换"
拖动下面这个滑块,看主要矛盾在五阶段之间连续迁移——不是硬跳:
harness 演进程度:50%
观察点:主要矛盾并不是"到点切换",而是权重连续迁移——旧矛盾在退场时仍占相当份额,新矛盾在登场前已经在长。 这解释了为什么"跨阶段挪用"(拿别人阶段五的药治自己阶段一的病)会翻车:你以为对方在同一场戏里,其实主要矛盾根本没重合。
这解释了跨阶段挪用为什么翻车——你以为对方和你在同一场戏里,其实主要矛盾根本没重合。怎么判断做法 · 跨阶段挪用。
你现在卡在哪一阶段?
在开始学之前,先测一下——
| 你目前的现象 | 大概率 · 你的主要矛盾 | 从哪一阶段学起 |
|---|---|---|
| agent 写的东西总"看起来对但跑不动" | 意图 vs 实现 | 阶段一 |
| 上下文塞满 · 工具越加越蠢 | 有限 vs 膨胀 | 阶段二 |
| test.skip 一路飙升 · 觉得回归"应该没事" | 自评 vs 客观 | 阶段三 |
| 一次能跑成 · 第二天开跑翻车 | 一次性 vs 演进 | 阶段四 |
| 一个人爽 · 拉团队时崩 | 个人 vs 团队 | 阶段五 |
如果你每一行都对上号——恭喜,你不孤独。我实践的项目中每一个都撞过至少 3 次。诊断表不是让你"挑一段跳过来学",是让你知道自己现在的重心该压在哪。从头到尾按顺序过是学结构,重点看你卡的那段是学操作。
坐标三:怎么解决?——回到我们那条路
抓完主要矛盾之后,具体一件事,是怎么被解决的?
回到开头那个故事。我们试第一个 agent 项目的时候,其实做的事非常朴素:想清楚要它做什么 → 写下来 → 让它去跑 → 看结果 → 修。这不是什么方法论——任何人第一次让别人替自己做事的时候都是这么干的。
后来再重读教员的《实践论》,才豁然想起来这个朴素的循环有个名字——两次飞跃。
- 阶段①
感性材料
在实践里接触事物 · 收集丰富且合于实际的材料
亲口吃梨
- 阶段②
第一次飞跃
把感性材料整理成计划、契约、判据
感性 → 理性
- 阶段③
第二次飞跃 · 更重要
让计划回到实践中被检验、被修正
理性 → 回到实践
课程五阶段就是这条运动的工程落地:阶段一(把感性变成契约·第一次飞跃)→ 阶段二·三·四(回到实践跑起来、撞、修·第二次飞跃)→ 阶段五(推广到别的项目·再一轮)。
第二次飞跃比第一次更重要,想得再漂亮,回不到实践里被检验,就还是想。这也是为什么阶段三放在阶段一二之后,不是之前:校核装置只能校核已经存在的东西。
LLM 是天生的"书呆子"
《实践论》里有一句话我们后来反复引:"一切真知都是从直接经验发源的。"
这句话拿来评价 LLM 特别贴,LLM 是天生的"书呆子":满肚子道听途说,还特别自信。就算它在训练里已经在别人的十万个项目里"做"过(后训练时代它确实见过大量工具调用的轨迹),但对你这个代码仓库而言,那仍然是道听途说。间接经验不是直接经验。让它写代码时张口就来,就是"书呆子"的临床表现。
我第一次强烈感受到这一点,是一次给定代码仓库和日志工具让 AI Agent(用的Opus的模型)调查一个在生产环境出现的性能问题,几十分钟后它洋洋洒洒给出了调查分析的结果:整篇文章确实逻辑严密,证明的过程中也给出了引用的代码和追踪的日志证据,我把结果拿给一个对该项目有一定了解的同事去看,他也觉得非常有道理(非常具有迷惑性)。
然而实际上分析过程在中间部分,最核心的问题诊断上其实已经跑偏了,原因是AI根据自己的知识对某个第三方依赖实际执行的逻辑做出了错误的推断,并导致了整个后续的分析都实际偏出了轨道。它真的不是在骗我——它是真的认为应该如此。然而真实解决这次错误的推断其实很简单,只需要在必要的地方添加日志并在环境中跑一遍,就能一眼洞悉真实的运行情况了。
对于这样的问题治法是简单的——给它工具,让它亲口吃一次梨。
LLM 是书呆子——满肚子道听途说,还特别自信。给它工具,就是让它亲口吃一次梨。
有时候跑一次 pnpm typecheck 比它猜类型强;跑一次真测试比它想象行为强;打开一次 log 看看是不是自己以为的那样,比它复述文档强。这是工具调用的哲学本质——不是"多接个 API 让它更强",是逼它从道听途说回到直接经验。
计划是待检验的假说,不是承诺
再引一句实践论——"原定的计划毫无改变地实现出来的事,是很少的。"
这句话结论有两条——
一是多轮不是失败,是认识运动的正常形态。干活的那个 agent(我们叫它 dev agent,具体写代码那位)跑第一轮出了偏差,把偏差当"材料"抓回来修 spec(写给它的意图契约·规格文档)/ 修 rubric(评分表·打分的那位 agent 依它给分)/ 修计划,然后进下一轮(我们叫 round + 1)。round 的存在本身就是"两次飞跃"的循环体,不是"给低质量兜底的补丁"。
二是偏差是材料,不是敌情。看到 dev agent 第一轮出了预期外的东西,第一反应应该是"这告诉我什么"——很多时候它告诉你 spec 有歧义,而不是模型笨。
"失败者成功之母"——门禁的哲学基础
再引一句——"人们经过失败之后,也就从失败取得教训……所谓失败者成功之母。"
这一句在阶段三兑现成一个反直觉的立论:门禁不是设计出来的,是撞出来的。每一条规则都是一次具体翻车留下的疤——规则是失败教出来的 · 阶段三 · B。
这也意味着:别抄现成的门禁配置。你抄的是别人翻车的形状,不是自己翻车的形状,不合身。
循环不是转圈,是爬楼梯
最后一句——"每一循环的内容,都比较地进到了高一级的程度。"
这就是 loop 的本质。循环不是在原地转圈,是在爬楼梯——阶段四的 flow 一轮 = 上一层,dev agent的输出成为下一轮 dev agent的输入材料 · 阶段四 · D · 反馈闭环。
同一根线出现了两次——三尺度里的"单任务尺度"(flow 一轮)+ 这里的"循环螺旋上升"是同一件事。你会在阶段四把它拆开看细节。
坐标四:怎么判断别人的做法和自己的做法?
上面三块是建构性的——造马具、看地图、走过程。这一块是批判性的:你会看很多别人的方案(大厂博客、开源 harness、同事的实践),也会自我审视。这时候需要一把尺子。
具体分析具体情况
《矛盾论》里那句——"不同质的矛盾,只有用不同质的方法才能解决。"
一句话——别抄。人家的矛盾不是你的矛盾。
我知道你会去翻大厂的 AGENTS.md,我也会翻,优秀的作品总是值得学习的。但你注意看会发现一个规律:那些动辄几千字的规矩、几十个内部工具的分盒、几层复杂的 review 流程,都是在人家那个体量下、那个团队规模下、那个基础设施上,才有意义的。你抄回来放到一个总共就 20 个脚本、一个人写的项目里,机制成本远大于收益,反而把上下文塞满、把 agent 搞蠢。
跨阶段挪用 = 最高频误用
上面那个翻车的更一般的形式是——跨阶段挪用:
拿别人阶段五的药,治自己阶段一的病——不是药不好,是错了适应症。
判据不在技术栈,在"第二次飞跃的进行方式"是否相似——你要挪用的那套 harness,它"回到实践受检验"的方式,跟你项目里的方式一样吗?一样,才有得挪 · 阶段五 · A · 挪用判据。
六问——一把可复用的尺子
给你一把可复用的尺子。任何一个 harness 做法(别人的、自己的),拎起来逐条问——
| # | 六问 | 你在检查什么 |
|---|---|---|
| ① | 内因还是外因? | 它是在"变生产关系"还是在"等生产力"? |
| ② | 它治的是哪一阶段的主要矛盾? | 是意图 vs 实现?还是 AI 自评 vs 客观? |
| ③ | 谁是主要方面? | 决策权在人手里,还是在 agent 手里? |
| ④ | 它靠什么相反相成? | 依赖哪对对立面的张力才成立? |
| ⑤ | 有没有第二次飞跃? | 是不是有让计划回到实践受检验的机制? |
| ⑥ | 它的适用条件是什么? | 换个项目、换个规模、换个团队还成立吗? |
上手用一次——量一下大厂 AGENTS.md
刚才说"我知道你会去翻大厂的 AGENTS.md"——那就拿它当第一次示范。假设你翻到某大厂那份一千字的 AGENTS.md,开头就规定"所有工具调用必须先经过路由 agent 分派"。别急着抄,把尺子拿出来量三问:
- ② 它治的是哪一阶段的主要矛盾? 答:阶段二"agent 有限 vs 任务膨胀"里的工具泛滥。前提是它有几百个内部工具。你有几个? 如果只有 20 个,这条规矩治的病,你压根没有。
- ⑤ 有没有第二次飞跃? 答:有——路由 agent 分派后,工具返回值直接进 dev 的 log,跑通了才算数。这条方法本身站得住。
- ⑥ 它的适用条件是什么? 答:工具数量 ≥ 大量(那家公司写的是 100+)· 有专职团队维护路由规则 · 有能力吃"多一层调度"的延迟。你三条都没有 → 挪不了。
三问下来,判断出来了:方法本身是对的,只是这剂药不是给你这号体量的病人开的——跨阶段挪用被现场诊断。
其余三问在阶段五收尾会拿"我们自己这套 harness"再自我应用一次——这里先不铺开。
六问不是要背下来的信条——你手边一把尺子而已。第一次用会觉得别扭(毕竟不习惯用"内因外因""主要方面"这种词量东西),量个三五次就顺了。
相对真理——包括我讲的
一切实践都有适用条件与保质期——包括我在这门课里讲的。
三种保质期最常见——
- 模型代际保质期:某条上下文技巧,在 200k 时代是刚需,1M 时代就不必要。
- 规模保质期:单人项目用得爽的单一真相源规矩,5个人团队可能就会变形。
- 技术栈保质期:Node 项目那套门禁顺序,换 Rust 项目要重排。
所以这门课不会给你可直接抄走的 AGENTS.md 模板——那是教条主义的开端。给的是判断条件:什么时候用哪一招、什么时候不用、怎么知道该换。
由特殊到一般,再由一般到特殊
《矛盾论》那个说法——"由特殊到一般,再由一般到特殊。"
我做的事:从 39 个项目里概括出通则(这是"由特殊到一般")。 你要做的事:带着通则回到你自己的项目,找你的主要矛盾(这是"由一般到特殊")。
我从我的项目概括出通则——你带着通则回到你自己的项目,找你的主要矛盾。
这也是学完这门课后你被期待做的事:我的分享不是什么圣经不需要背下来,要做的是在自己的项目里做一次由一般到特殊的落地——填一份属于你自己的《项目主要矛盾诊断表》(阶段五毕业动作会正式给到)。
收尾 · 同一根线,三个尺度
四块坐标走完了。回过头看那根线——
- 诊断主要矛盾:五阶段给了地图 + 诊断表告诉你在哪一阶段。
- 用实践检验:造 harness 让实践变得可检验(就是我们那 39 个项目走过来的路);两次飞跃告诉你怎么走。
- 矛盾转移:连续迁移,不是硬跳——所以别抄别人阶段五的药。
- 再诊断:一把六问的尺子,看别人也看自己。
同一根线,在三个尺度上重复。 你现在已经在最大的尺度(一整门课)上看过一遍它了;从下一节开始,你会在最小的尺度(agent 跑一件事的一轮)上再看一遍——把解决问题的策略和方法(下一节我们就会提到problem-solving) 的 Plan 三步机器化为可执行契约。
如果你只带走一句话——同一根线,在三个尺度上重复。剩下的课程,都是它的注脚。