Harness架构实战:一个人九个月如何用Agent工程化产出20万行代码
1. 先搞清楚一个人九个月20万行到底意味着什么先把数字摊开看。九个月按每月22个工作日算大概198个工作日。20万行代码平摊下来每天要产出1000行左右的有效代码。这个量级如果靠手敲别说质量光是打字速度都撑不住。所以这个项目从第一天起核心命题就不是怎么写代码而是怎么让机器写代码人来当架构师和验收员。每个月烧掉40亿 token这个数字更值得琢磨。40亿token是什么概念按主流大模型的中文处理能力1个token大约对应0.7到1.5个汉字40亿token粗略折算就是几十亿字的处理量。一个人一个月读不完这么多字但一个Agent系统可以。这说明整个项目的运转模式是人负责定义结构、约束边界、验收结果Agent负责填充实现、批量重构、重复劳动。这就是Harness架构应用的核心价值所在。Harness这个词在工程语境里本意是挽具、约束装置放到AI应用开发里它指的是一套把大模型能力约束在可控轨道上运行的工程框架。你可以把它理解成给一匹力大无穷但方向感很差的马套上缰绳和车架——马负责出力缰绳负责方向车架负责把力转化成可用的位移。这个项目适合谁来参考三类人最该看一是独立开发者想用有限的人力撬动大产出二是团队里的技术负责人在评估Agent工程到底能不能落地三是已经用过Claude Code、Obsidian这套工具链但始终停留在玩具阶段、没跑通规模化生产的人。如果你只是想知道Harness是什么概念看完第一节就够了如果你想复现这套打法后面每一节都得细看。我先把结论摆在这20万行代码不是靠勤奋堆出来的是靠一套约束反馈复用的工程闭环滚出来的。下面拆开讲。2. Harness架构的本质给Agent套上可验证的轨道2.1 为什么裸用大模型写不出20万行很多人第一次用Claude Code或者类似的Agent工具兴奋点在于它能自己写文件、自己跑命令。但真拿它做一个上万行的项目很快就会撞墙。原因不复杂上下文会漂移。Agent聊到第50轮早就忘了第3轮定下的命名规范。它没有全局观。你让它改一个函数它不知道这个函数被另外17个文件引用。它不会自我怀疑。写错了它也很自信除非你给它一个能证伪的机制。重复劳动没有沉淀。同样的CRUD逻辑它每次都要重新推理一遍token全烧在这上面。40亿token一个月如果全花在重复推理上那就是纯浪费。Harness架构要解决的就是这个问题把需要推理的部分和可以固化的部分分开。能固化的写成模板、规则、脚本只有真正需要判断的地方才交给模型。2.2 Harness的三层结构我在实际搭建时把整个系统分成三层这个分层直接决定了后面代码怎么组织层级职责由谁执行典型产物约束层定义规范、目录结构、命名、接口契约人规则文件、schema、lint配置执行层按约束生成/修改代码、跑测试、批量重构Agent代码文件、迁移脚本验证层检查产物是否符合约束、测试是否通过脚本Agent测试报告、diff审查记录关键洞察是约束层和验证层必须是确定性的deterministic只有执行层允许概率性。很多人搞反了让模型去判断这个命名合不合规结果每次判断结果都不一样整个系统就没法收敛。举个具体例子。项目里所有数据模型都要求有created_at和updated_at字段命名必须是下划线风格。这条规则不写在提示词里让模型记住而是写成一个校验脚本Agent每次生成完模型文件脚本自动跑一遍不符合就报错打回。模型只负责生成不负责记住规则。这一条改动直接把我项目里因为命名不一致导致的返工率降了大半。2.3 约束层怎么写才不僵化约束写太死Agent就没有发挥空间遇到边界情况直接卡住写太松又回到裸用模型的老路。我的经验是约束只锁接口和结构不锁实现。比如一个数据导出模块我锁的是输入必须是某个schema定义的对象数组输出必须是符合特定格式的文件函数签名固定。至于内部是用流式写还是先攒内存再写用哪个库交给Agent判断。这样既保证了模块之间能拼装又给了Agent优化空间。提示约束层文件建议用Markdown写而不是JSON或YAML。原因是Markdown既能被人读又能被Agent当上下文吃进去还能直接嵌代码示例。这也是为什么热词里Markdown和Harness总是绑在一起出现。3. 20万行代码的目录骨架是怎么长出来的3.1 先定骨架再让Agent填肉一个人做20万行最忌讳的是边写边想结构。结构一旦中途大改前面Agent生成的所有代码都得重来token全打水漂。所以项目启动的第一周我几乎没让Agent写业务代码全花在设计目录骨架上。骨架的核心原则是按变化频率分层而不是按功能类型分层。传统MVC按功能分但在这个项目里变化最频繁的是业务规则最稳定的是基础设施。所以我的分层是core/最稳定工具函数、类型定义、常量。几乎不动。adapters/中等稳定对接外部系统的适配层。偶尔改。domain/变化频繁业务逻辑。天天改。flows/编排层把domain串起来。改得也勤。这样分层的好处是Agent在改domain/的时候几乎不会碰到core/减少了跨层误伤。而且每一层的约束可以单独定义core/的约束最严domain/的约束最松。3.2 目录即提示词这是Harness架构里我觉得最巧妙的一点目录结构本身就是给Agent的提示词。当Agent看到domain/order/下面全是订单相关的文件它自然知道新文件该放哪、该叫什么。你不需要在提示词里反复强调订单相关代码放订单目录。我甚至把每个目录下的README.md当成该模块的局部约束文件。Agent在动这个目录之前会先读这个README里面写清楚这个模块的职责边界、依赖了谁、被谁依赖。这比全局提示词精准得多也省token——不用每次都把整个项目的规范塞进上下文。3.3 骨架定完后的第一次压力测试骨架搭好后我做的第一件事不是写业务而是让Agent故意做一个跨层改动看它会不会乱。比如让它给所有domain模块加一个统一的日志埋点。结果第一次它把日志代码直接写进了每个业务函数里污染了domain层。这个测试暴露了问题约束层没有定义横切关注点该怎么处理。于是我补了一条规则所有日志、监控、鉴权这类横切逻辑必须通过adapters/层的装饰器或中间件实现禁止直接写进domain。补完规则再测一次Agent就乖乖去adapters层加装饰器了。注意这种故意压力测试非常值得做。它花不了多少token但能在项目早期暴露约束漏洞。等20万行写完再发现约束有问题返工成本是天文数字。4. 每月40亿token都烧在哪了怎么烧得值4.1 token消耗的四个大头我把一个月的token账单拆开看大致分布是这样的消耗类型占比是否值得代码生成约45%值得这是主要产出上下文重读约25%部分浪费可优化测试与验证约20%非常值得省了人工review试错与返工约10%可通过约束降低最该砍的是上下文重读。Agent每轮对话都要把之前的文件重新读一遍如果项目大这个开销会爆炸。我的优化手段是给每个模块维护一个摘要文件Agent读摘要而不是读全文。摘要由Agent自己在上次改动后生成人抽查。这样上下文体积能压到原来的三分之一左右。4.2 让token花在可复用的地方40亿token如果每次都是全新推理那就是纯消耗。但如果把推理结果沉淀成模板下次直接复用token就变成了投资。具体做法每当Agent完成一类重复性任务比如给一个实体生成完整的CRUD接口我就让它把这次的过程抽象成一个模板文件放到templates/目录。下次遇到同类任务直接调用模板Agent只需要填参数不需要重新推理整个流程。这个机制跑起来之后项目后期的token消耗明显下降因为大量重复劳动已经被模板吃掉了。前期token烧得多是正常的关键是看它有没有转化成可复用的资产。4.3 一个反直觉的省钱技巧很多人以为省钱就是少让Agent干活。我的经验恰恰相反在验证环节要舍得烧token在生成环节要抠。为什么因为生成错了后面要花十倍token去修。而验证环节多花token能提前拦住错误。我甚至专门写了一个对抗性审查流程让一个Agent生成代码再让另一个Agent专门挑刺两个Agent互相博弈。这个流程token消耗不小但它拦下来的bug如果流到后期修复成本高得多。5. 工具链怎么搭Claude Code、Obsidian和Markdown的分工5.1 三个工具各管一段热词里反复出现Claude Code、Obsidian、Markdown这三个在我的工作流里分工非常明确Claude Code执行层主力。负责实际读写代码文件、跑命令、跑测试。它的优势是能直接操作文件系统不是只会在聊天框里输出文本。Obsidian约束层和知识层。所有规则、模板、模块摘要、决策记录都放在Obsidian库里用双链关联。Agent需要哪部分约束就喂哪部分。Markdown通用载体。约束文件、模板、摘要、决策记录全是Markdown。它既是人读的文档也是Agent吃的上下文一份内容两用。这个分工的关键在于Obsidian不只是笔记工具它是约束层的存储介质。我用双链把规则和用到这条规则的模块关联起来改规则的时候能立刻看到影响范围。5.2 为什么不用数据库存约束有人会问约束为什么不用数据库或者配置中心存答案是Agent读Markdown的准确率远高于读结构化配置。大模型对自然语言的理解天然强于对JSON嵌套结构的理解。而且Markdown能写为什么这么约束的解释Agent理解了原因遇到边界情况时判断更准。5.3 把决策记录也喂给Agent项目里每个重要决策我都会在Obsidian里写一条决策记录背景是什么、考虑了哪些方案、为什么选这个、什么情况下要重新评估。这些记录平时看着像文档但关键时刻能救命。比如有一次Agent想重构一个模块用了和当初决策相反的方向。我把当初的决策记录喂给它它立刻明白了约束的来龙去脉调整了方案。没有决策记录的Agent就像一个不知道历史的人容易重复踩坑。6. 踩过的坑那些让项目差点翻车的时刻6.1 上下文污染导致的集体失忆项目进行到第三个月出现过一次严重问题Agent开始生成风格完全不一致的代码命名一会儿驼峰一会儿下划线注释一会儿中文一会儿英文。排查后发现是因为某个模块的摘要文件被错误地覆盖了Agent读到了错误的规范然后这个错误通过模板扩散到了其他模块。修复方案是给摘要文件加版本号和校验和Agent读之前先校验。这个坑让我意识到约束层的文件也需要版本管理不能随便改。6.2 模板过度泛化有一段时间我沉迷于抽象模板想把所有CRUD都用一个超级模板覆盖。结果模板越来越复杂参数越来越多Agent填参数时经常填错反而比不用模板还慢。教训是模板要窄而深不要宽而浅。一个模板只解决一类具体问题宁可多几个模板也不要一个万能模板。后来我把那个超级模板拆成了七个专用模板效率立刻回来了。6.3 验证脚本本身有bug最危险的一次是验证脚本自己写错了导致一批不符合规范的代码被放行。等发现的时候已经生成了几千行有问题的代码。这件事之后我定了个规矩验证脚本本身也要被验证。每次改验证脚本先用一批已知合格和已知不合格的样本跑一遍确认脚本判断正确才能投入使用。6.4 排查链路长什么样遇到Agent产出异常时我的排查顺序是固定的先看约束文件有没有被改过版本号、校验和。再看Agent读到的上下文是不是最新的摘要有没有过期。然后看模板有没有被误用参数对不对。最后才怀疑模型本身。这个顺序很重要因为大部分问题出在前三步而不是模型能力。很多人一遇到问题就换模型、调提示词其实方向错了。7. 一个人怎么扛住20万行的维护7.1 把理解成本转移给系统一个人维护20万行靠脑子记是不可能的。我的做法是把所有需要记住的东西都外化成文件模块职责写在README依赖关系写在摘要决策写在决策记录规范写在约束文件。人不需要记住只需要知道去哪查。Agent也一样它不需要记住整个项目只需要在动某个模块时读到那个模块的局部约束就够了。这就是为什么局部约束比全局提示词更省token也更准。7.2 定期做架构体检每两周我会让Agent做一次全项目扫描检查有没有违反分层原则的地方、有没有循环依赖、有没有孤儿文件。这个体检报告会生成一份Markdown我花半小时过一遍。这个习惯帮我提前发现了好几次架构腐化。架构腐化是渐进的等你看出来的时候往往已经晚了。定期体检相当于给项目做体检早发现早处理。7.3 人只做三件事到项目后期我的角色收敛到三件事定义新约束、验收关键产出、处理Agent搞不定的边界情况。其余全部交给系统。这不是偷懒而是把人的稀缺判断力用在最需要的地方。8. 如果你也想复现从哪一步开始别一上来就想搞20万行。我的建议是从一个两千行左右的小项目开始把Harness的三层结构跑通约束层写清楚执行层让Agent干活验证层自动检查。跑通之后再逐步放大规模。第一个月重点不是产出多少代码而是把约束层和验证层打磨到可靠。这两层稳了后面放大规模就是水到渠成的事。这两层不稳规模越大越乱。关于token预算前期可以宽松一点允许Agent试错因为你在积累模板和约束。等模板库建起来单位产出的token消耗会自然下降。我个人的体会是前三个月的token投入本质是在建资产不是在建代码。资产建好了代码是自然长出来的。最后分享一个我一直在用的小技巧每次Agent完成一个大任务后让它自己写一段这次任务的经验总结存进Obsidian。这些总结积累起来就是一套只属于你这个项目的、活的工程手册。下次遇到类似任务先让Agent读这些总结它的表现会明显更稳。这比任何通用教程都管用因为它是从你自己的项目里长出来的。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →