ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

一个人九个月20万行代码:Harness架构与AI Agent协作实战

一个人九个月20万行代码:Harness架构与AI Agent协作实战 1. 先搞清楚这个项目到底在做什么一个人九个月20 万行代码每个月消耗 40 亿以上的 token最终交付的是一款基于 Harness 架构的应用。这几个数字摆在一起任何一个写过代码的人都会先愣一下20 万行是什么概念如果按一个熟练工程师每天有效产出 200 到 300 行可维护代码来算20 万行大约需要 700 到 1000 个工作日也就是两到三年。而这里只有九个月还是一个人。答案很明显——绝大部分代码不是手写的而是通过 AI Agent 协作生成的token 消耗量就是最直接的证据。那 Harness 架构又是什么在 AI Agent 开发这个圈子里Harness 指的是一层驾驭框架它不负责模型本身的推理能力而是负责把模型的输出变成可控、可执行、可复现的动作。你可以把它理解成马具——马模型跑得快不快是模型的事但往哪跑、跑多快、什么时候停是马具说了算。一个 Harness 架构应用核心工作就是把大模型的非确定性输出收敛成确定性的工程流程。这个项目解决的痛点非常具体当你用 Claude Code、DeepSeek Harness 这类工具做真实项目时最大的问题不是模型不够聪明而是它太自由了。同一个需求问两遍它给你两套完全不同的目录结构让它改一个函数它顺手把三个不相关的文件也重构了上下文一长它开始忘记前面约定好的规范。Harness 架构要做的就是给这种自由套上轨道。适合谁来参考这篇内容三类人。第一类是想用 AI Agent 做正经项目、但被生成一堆跑不起来的代码折磨过的独立开发者第二类是在团队里推动 AI 辅助开发、需要一套可复制工程规范的技术负责人第三类是对 Agent 框架本身感兴趣、想理解为什么同样是调模型有人能做出产品有人只能做出 demo的工程师。下面我会把这个项目拆开讲清楚它的设计思路、关键实现、踩过的坑以及那些文档里不会写的经验。2. 整体架构设计与思路拆解2.1 为什么是 Harness 而不是直接裸调模型裸调模型的问题做过的人都懂。你写一个 prompt模型返回一段代码你复制粘贴跑一下报错再把错误贴回去让它改。这个循环在玩具项目里能跑通但一旦项目超过几千行就会彻底失控。原因有三个一是模型没有稳定的项目记忆每次对话都是失忆状态二是模型的输出格式不稳定有时候给你完整文件有时候只给 diff有时候还夹带解释文字三是模型不理解你的工程约束比如这个项目禁止用某个库、所有网络请求必须走统一封装。Harness 架构的价值就在于它把这三件事全部外置成工程问题。项目记忆交给文件系统和向量检索输出格式交给结构化协议比如 JSON Schema 或者带标记的 Markdown工程约束交给规则引擎和静态检查。模型只负责它最擅长的事——在给定上下文里生成内容剩下的全部由 Harness 层接管。这个项目选择 Harness 架构本质上是一个取舍牺牲一部分灵活性换取可控性和可复现性。在一个人做 20 万行代码的场景下这个取舍是必须的因为没有人有时间去 review 每一行 AI 生成的代码你只能靠架构去保证质量下限。2.2 20 万行代码是怎么堆出来的很多人看到 20 万行会以为是AI 疯狂输出。实际上恰恰相反这个项目的代码量之所以能到这个规模是因为 Harness 架构强制了模块化和代码复用。举个具体的例子项目里有一个文档解析的能力需要支持 Markdown、docx、PDF 等多种格式。如果裸写可能是每个格式一个独立模块各写各的。但在 Harness 架构下会先抽象出一个统一的文档节点数据结构所有格式的解析器都输出这个结构下游的处理逻辑只认这个结构。这样一来代码量确实上去了但上去的是有价值的抽象层而不是重复的胶水代码。20 万行里我估计大概有 30% 是类型定义和接口约束25% 是各个能力模块的实现20% 是测试和校验逻辑剩下 25% 是配置、文档和工具脚本。这个比例在 AI 协作项目里其实很健康——类型和测试占比高说明架构在起作用。每个月 40 亿 token 的消耗换算下来大概是每天 1.3 亿。这个量级听起来吓人但拆开看就合理了一次完整的生成-校验-修复循环可能要消耗几十万 token一天跑几百次这样的循环量就上去了。关键是要让每一次 token 消耗都产生可复用的资产而不是消耗完就扔掉。2.3 技术选型背后的真实考量项目里出现了几个关键词Markdown、Obsidian、Claude Code、Agent。这几个东西不是随便凑在一起的它们构成了一个完整的工作流。Markdown 是整个项目的通用语言。为什么不用 JSON 或者 YAML 作为 Agent 的输入输出格式因为 Markdown 对人类友好对模型也友好。模型生成 Markdown 的准确率明显高于生成严格 JSON 的准确率而且 Markdown 可以直接被人阅读和编辑。项目里所有的任务描述、规范文档、Agent 之间的通信全部用 Markdown 承载。Obsidian 在这里扮演的是知识库和任务面板的角色。它本质上是一个本地 Markdown 文件管理器但它的双向链接和图谱功能让它非常适合管理 Agent 项目里那些互相引用的规范和任务。你可以把每个 Agent 的职责写成一个 Markdown 文件用链接把它们串起来Obsidian 会自动帮你生成关系图。这比维护一个复杂的配置文件直观得多。Claude Code 是主要的代码生成和执行工具。选它的原因很实际它对文件系统的操作能力比较强能直接读写项目文件而且支持在项目根目录放一个约定文件来定义行为规范。这一点对 Harness 架构至关重要——你需要一个地方来注入你的工程约束。2.4 架构分层把混乱挡在门外这个项目的 Harness 架构大致分成四层从下往上依次是层级职责关键实现模型层纯内容生成Claude Code、DeepSeek 等协议层输入输出格式化Markdown 模板、结构化标记编排层任务拆解与调度Agent 角色定义、任务队列约束层质量校验与拦截静态检查、规则引擎、测试这个分层的核心思想是每一层只信任下一层的输出但都要校验。模型层的输出永远被当作不可信输入必须经过协议层解析、编排层验证、约束层检查才能进入代码库。这套机制听起来繁琐但正是它让一个人能管理 20 万行代码而不崩溃。提示分层不是越多越好。我见过有人把 Harness 拆成七八层结果每层之间的转换开销比生成本身还大。四层是一个比较舒服的平衡点再少就挡不住混乱再多就变成官僚流程。3. 核心细节解析与实操要点3.1 Markdown 作为 Agent 通信协议的细节用 Markdown 做 Agent 通信最大的坑是格式漂移。模型今天用##做二级标题明天可能用**加粗**后天可能直接上表格。如果不做约束下游解析器会疯掉。项目里的做法是定义一套最小 Markdown 子集只允许使用特定的语法元素并且每个元素都有明确的语义。比如一级标题#只用于标识任务名称一个文件只能有一个二级标题##用于标识任务的阶段比如输入、处理、输出代码块必须标注语言未标注语言的代码块会被校验器拒绝表格只用于结构化数据不允许在表格里放长文本这套约束写在一个 Markdown 文件里作为所有 Agent 的宪法。每次 Agent 生成内容后会有一个校验脚本检查它是否违反了这些规则。违反规则的输出会被打回重生成而不是直接进入下一步。这里有个实操心得校验规则要尽量简单、可机械判断。不要写标题要简洁这种模糊规则要写标题不超过 20 个字符。模型对模糊规则的理解每次都不一样但对精确规则的理解是稳定的。3.2 Agent 角色划分与职责边界一个人做 20 万行代码不可能只用一个 Agent。项目里定义了多个 Agent 角色每个角色有明确的职责边界。常见的角色包括规划 Agent负责把一个大需求拆成可执行的小任务输出任务清单实现 Agent负责根据单个任务生成代码校验 Agent负责检查生成的代码是否符合规范、是否能通过测试修复 Agent负责根据校验结果修复问题文档 Agent负责把实现过程整理成文档关键点在于每个 Agent 只能看到自己需要的信息。规划 Agent 不需要看具体代码实现 Agent 不需要看其他任务的实现细节校验 Agent 不需要知道代码是怎么生成的。这种信息隔离有两个好处一是减少 token 消耗二是避免 Agent 之间互相污染。注意Agent 角色不是越多越好。我试过拆成十几个角色结果调度复杂度爆炸光协调它们之间的通信就消耗了大量 token。五个左右的角色是比较合理的再多就要考虑合并。3.3 上下文管理40 亿 token 花在哪了40 亿 token 听起来很多但如果管理不当可能一半都浪费在重复的上下文上。项目里的上下文管理有几个原则第一上下文按需加载。不要把所有文件都塞进 prompt而是根据当前任务只加载相关的文件。这需要一个索引机制能快速找到这个任务需要哪些文件。第二上下文分层。把上下文分成永久层项目规范、核心接口定义和临时层当前任务的具体文件。永久层每次都带临时层按需带。永久层要尽量精简能压缩就压缩。第三上下文定期清理。长对话会导致上下文膨胀模型会开始遗忘早期内容。项目里的做法是每完成一个任务就开一个新的对话只把必要的结论带过去。这里有个计算假设一个任务平均需要 5 万 token 的上下文一天跑 200 个任务就是 1000 万 token。加上生成和校验的开销一天 1.3 亿 token 是合理的。如果上下文管理不当同样的任务可能要 3 倍 token成本直接翻三倍。3.4 与 Obsidian 的集成方式Obsidian 在这个项目里不是可有可无的装饰而是核心的工作台。具体用法是项目根目录下有一个vault文件夹里面是 Obsidian 的知识库。每个 Agent 的职责、每个模块的设计文档、每个任务的执行记录都以 Markdown 文件的形式存在这里。Obsidian 的双向链接让这些文件自动形成关系网。比如你有一个Agent-实现.md文件里面链接到规范-代码风格.md和模块-文档解析.md。当你在 Obsidian 里打开Agent-实现.md你能直接看到它依赖哪些规范、涉及哪些模块。这种可视化对一个人管理大项目特别有用——你不需要记住所有关系Obsidian 帮你记。实操上Obsidian 的模板功能可以大幅提升效率。你可以定义一个任务模板包含任务描述、输入、输出、验收标准等固定字段。每次新建任务直接套模板保证格式统一。3.5 代码校验与质量兜底AI 生成的代码最大的风险是看起来对但实际错。项目里的校验分三层第一层是语法校验用语言自带的 linter 和 formatter比如 Python 的 ruff、JavaScript 的 eslint。这一层能挡住大部分低级错误。第二层是类型校验用类型检查工具比如 mypy、TypeScript 的 tsc。这一层能挡住接口不匹配的问题。第三层是测试校验每个模块都要有对应的测试AI 生成代码后自动跑测试。这一层能挡住逻辑错误。三层校验都通过代码才能进入代码库。任何一层失败都会触发修复 Agent。修复 Agent 会拿到具体的错误信息针对性地修改而不是重新生成整个文件。提示测试用例最好由人写而不是让 AI 生成。AI 生成的测试往往会迁就AI 生成的代码导致测试通过但代码是错的。人写的测试才能真正起到兜底作用。4. 实操过程与核心环节实现4.1 从零搭建 Harness 架构的完整流程如果你也想搭一套类似的架构可以按下面的顺序来。这个顺序是我踩过坑之后总结的不要跳步。第一步定义项目宪法。在项目根目录创建一个CONSTITUTION.md写清楚这个项目的所有硬性约束。包括用什么语言、什么框架、什么代码风格、什么目录结构、什么命名规范。这个文件是所有 Agent 的必读文件每次对话都要带上。第二步搭建目录骨架。不要等 AI 生成先手动把目录结构建好。比如src/、tests/、docs/、agents/、vault/。目录结构本身就是一种约束AI 在生成文件时会倾向于遵循已有结构。第三步定义 Agent 角色。在agents/目录下每个角色一个 Markdown 文件。文件里写清楚这个角色的职责、输入、输出、禁止事项。比如实现 Agent 的禁止事项里要写不允许修改其他模块的文件。第四步写第一个任务模板。在vault/里创建一个任务模板包含任务 ID、描述、输入文件、输出文件、验收标准。之后所有任务都从这个模板复制。第五步跑通一个最小闭环。选一个最简单的功能比如读取一个 Markdown 文件并统计字数完整跑一遍规划、实现、校验、修复的流程。这一步的目的是验证架构能跑通而不是产出有价值的代码。第六步逐步扩大规模。最小闭环跑通后开始加功能。每加一个功能都要走完整流程。不要因为这个功能很简单就跳过校验跳过一次就会有第二次。4.2 关键配置让 Claude Code 遵守规则Claude Code 支持在项目根目录放一个约定文件来定义行为。这个文件是 Harness 架构落地的关键。项目里的配置大致包含这几块# 项目约定 ## 必读文件 - CONSTITUTION.md - docs/architecture.md ## 代码规范 - 所有函数必须有类型注解 - 所有公开函数必须有 docstring - 单文件不超过 500 行 ## 禁止事项 - 不允许引入新的第三方依赖除非在 CONSTITUTION.md 中声明 - 不允许修改 tests/ 目录下的文件 - 不允许删除已有的测试用例 ## 输出格式 - 代码必须放在带语言标注的代码块里 - 修改文件时必须说明修改了哪个文件 - 不允许输出与任务无关的解释这个配置看起来简单但它把工程约束从人的脑子里搬到了文件里模型每次都能读到。实测下来有了这个配置模型违反规范的概率能降低一大半。4.3 任务拆解的粒度控制任务拆解是 Harness 架构里最考验经验的部分。拆得太粗一个任务要生成几百行代码模型容易出错拆得太细任务数量爆炸调度开销超过生成开销。项目里的经验值是一个任务对应 50 到 200 行代码。这个粒度下模型能在一个上下文窗口里完成校验也容易做。超过 200 行就要考虑拆成多个任务少于 50 行就要考虑合并。拆解的时候要按功能边界拆而不是按文件边界拆。比如实现文档解析这个功能可能涉及三个文件但它是一个完整的任务不应该拆成三个。反过来实现文档解析和实现文档导出是两个独立功能应该拆开。4.4 修复循环的设计与终止条件修复循环是 token 消耗的大头也是最容易失控的地方。项目里的修复循环有几个硬性规则第一最多修复三轮。三轮还修不好说明任务本身有问题需要人介入重新拆解而不是继续让 AI 试。第二每轮修复必须带具体的错误信息。不要只说代码有问题要把 linter 的输出、测试的失败信息完整贴进去。错误信息越具体修复越精准。第三修复不允许扩大改动范围。修复 Agent 只能改校验失败的文件不允许顺手改其他文件。这条规则能防止修一个 bug 引入三个 bug。第四修复记录要留档。每次修复的原因和结果都记在任务的 Markdown 文件里。这些记录后来成了排查问题的宝贵资料。4.5 用 Obsidian 管理任务状态任务状态管理用 Obsidian 的标签系统实现。每个任务文件打上标签比如#待规划、#实现中、#待校验、#已完成、#需人工介入。在 Obsidian 里点一下标签就能看到所有处于该状态的任务。这个做法比维护一个数据库简单得多而且和 Markdown 工作流无缝衔接。你不需要额外的工具Obsidian 本身就是任务面板。提示标签命名要统一不要一会儿用#todo一会儿用#待办。项目里所有标签都用中文避免中英文混用导致的检索混乱。5. 常见问题与排查技巧实录5.1 Agent 执行中断的典型原因agent execution terminated due to error 这类报错在长时间运行的项目里几乎每天都会遇到。根据我的经验原因主要有这几类报错类型常见原因排查方向上下文超限单次任务加载文件过多检查上下文加载逻辑精简永久层格式解析失败模型输出不符合约定格式检查校验规则补充格式约束工具调用失败文件路径错误或权限问题检查路径拼接逻辑确认文件存在循环超时修复循环没有终止条件检查修复轮次限制是否生效依赖缺失引用了未安装的库检查依赖声明补充安装步骤排查的时候第一步永远是看完整日志而不是猜。日志里通常有具体的错误位置和错误类型比任何猜测都准。5.2 插件加载失败的排查思路harness failed to load plugins 这个问题通常不是插件本身的问题而是加载顺序或者依赖的问题。排查顺序是先确认插件目录结构是否符合约定。很多加载失败是因为插件放错了位置或者缺少必要的元数据文件。然后检查插件之间的依赖关系如果 A 插件依赖 B 插件但 B 插件加载失败A 也会跟着失败。最后检查版本兼容性插件和主程序的版本不匹配也会导致加载失败。一个实用技巧是先禁用所有插件然后一个一个启用。这样能快速定位是哪个插件的问题。如果禁用所有插件后主程序能正常启动说明问题在插件如果还是启动失败说明问题在主程序本身。5.3 token 消耗失控的预警信号token 消耗失控不是突然发生的而是有预警信号的。这几个信号出现时就要警惕了单个任务的 token 消耗超过平均值的三倍修复循环的轮次明显增加上下文加载的文件数量持续增长同一个任务反复出现在待处理列表里出现这些信号时不要继续跑先停下来分析。通常原因是任务拆解粒度不对或者上下文管理出了问题。花半小时分析比继续烧几小时 token 划算得多。5.4 模型忘记规范的应对方法模型忘记规范是常态不要指望它能记住。应对方法不是反复强调而是把规范变成可机械检查的规则。比如与其在 prompt 里写请遵守代码风格不如在校验脚本里加一条检查缩进是否为 4 空格。前者靠模型自觉后者靠工具强制。另一个方法是缩短上下文。上下文越长模型越容易忘记早期内容。把长任务拆成短任务每个任务只带必要的上下文模型的表现会明显提升。5.5 一个人管理大项目的精力分配九个月做 20 万行代码精力分配是关键。我的经验是30% 时间搭架构和写规范50% 时间处理异常和修复20% 时间做规划和复盘。很多人会把 80% 时间花在让 AI 生成代码上结果异常处理跟不上项目越做越乱。正确的做法是前期多花时间在架构和规范上让 AI 生成的部分尽量不需要人管。架构搭好了后期的异常处理会少很多。注意不要追求全自动。一个人做项目人的判断力是最宝贵的资源。把机械的、重复的工作交给 AI把需要判断的工作留给自己。这个边界划清楚了效率才能上去。6. 从 20 万行代码里提炼的几条硬经验6.1 规范要写在代码之前这个项目最大的教训是规范一定要在写代码之前定好而不是边写边定。前期偷懒省下的规范时间后期会以十倍的代价还回来。因为一旦代码库成型再改规范就意味着大量返工而 AI 返工的成本比人还高——它会把不相关的代码也改乱。具体做法是项目启动前花两三天把目录结构、命名规范、接口约定、测试要求全部写清楚。这两三天看起来没产出但它决定了后面九个月能不能顺利。6.2 测试是 AI 协作的安全网AI 生成的代码你不可能逐行 review。唯一能保证质量的手段就是测试。项目里每个模块都有测试测试覆盖率维持在 70% 以上。这个覆盖率不是给老板看的是给自己兜底的。测试用例要人写而且要写得刁钻一点。AI 生成的代码往往能通过正常路径的测试但在边界条件下会出问题。人写的测试要专门覆盖边界条件比如空输入、超长输入、特殊字符输入。6.3 文档即上下文在 Harness 架构里文档不是给别人看的而是给 AI 看的。你写的每一份设计文档都会成为 AI 生成代码时的上下文。所以文档要写得对 AI 友好——结构清晰、术语统一、避免歧义。反过来AI 生成代码后也要让它生成对应的文档。这些文档又会成为后续任务的上下文。文档和代码形成正循环项目越做越顺。6.4 成本意识要贯穿始终40 亿 token 不是小数目成本意识必须贯穿始终。具体做法包括定期分析 token 消耗分布找出消耗大户优化上下文加载逻辑减少不必要的 token对高频任务做缓存避免重复生成。我个人的体会是token 成本的大头往往不是生成代码而是反复修复。把修复循环控制好成本能降一半。所以与其优化生成不如优化校验——校验做得准修复就少。6.5 人机边界要清晰最后一条也是最重要的一条人机边界要清晰。什么事交给 AI什么事自己做要提前想清楚。我的划分是机械的、可验证的、有明确标准的工作交给 AI需要判断、需要权衡、涉及架构决策的工作自己做。这条边界不是一成不变的随着项目推进可以调整。但一定要有边界不能让 AI 什么都做也不能什么都自己做。边界清晰了人和 AI 才能各司其职项目才能跑起来。这个项目后续还可以往几个方向扩展一是把 Harness 架构抽象成通用框架适配更多类型的项目二是引入更多的校验手段比如性能测试、安全扫描三是把 Agent 之间的协作做得更精细支持更复杂的任务编排。不过这些都是后话先把当前这套跑稳比什么都重要。
返回列表