ARTICLE DETAIL

资讯详情

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

AI辅助编程实战:Harness架构如何支撑九个月二十万行代码

AI辅助编程实战:Harness架构如何支撑九个月二十万行代码 1. 一个人九个月二十万行代码背后的工程逻辑先把数字摊开看。九个月按每月有效工作日22天算不到200个工作日。20万行代码平均每个工作日要产出1000行以上。如果算上调试、重构、写文档、处理线上问题的时间实际有效编码时间可能只有一半那日均产出就是2000行量级。这个数字放在传统软件工程里是不可思议的但在AI辅助编程的语境下它变得可以理解——前提是你把“写代码”这件事的定义彻底改掉。我最初看到这个项目描述时的第一反应不是“厉害”而是“这到底是怎么做到的”。因为我自己也试过用AI工具辅助开发深知其中的坑上下文丢失、代码风格漂移、重复劳动、调试困难。一个人能撑起20万行代码的体量核心不在于他打字有多快而在于他构建了一套让AI能够持续、稳定、高质量输出的工程体系。这套体系的关键词就是Harness。Harness这个词在软件工程里原本指的是测试 harness即一套自动化测试框架。但在这个项目的语境下它的含义被扩展了它是一层包裹在AI Agent外面的控制结构负责管理上下文、调度任务、校验输出、维护状态。你可以把它理解成AI的“操作系统”——Agent是CPUHarness是内核加驱动加文件系统。为什么需要这层东西因为裸用Claude Code或者任何AI编程工具你面对的是一个“失忆的天才”。它每次对话都从零开始不知道你昨天写了什么不知道你的代码规范不知道哪些模块已经完成。你得像哄小孩一样反复交代背景效率极低。Harness要解决的就是这个问题让AI拥有持久记忆、明确边界和可验证的输出标准。这个项目的另一个关键数字是每月40亿 token。按Claude的定价粗略估算这是一笔不小的开销。但更值得关注的是这个数字背后的信息它说明系统在持续、高频地调用模型而不是偶尔用一下。40亿token意味着大量的上下文注入、代码生成、自我校验和迭代修改。这已经不是“辅助编程”了而是“AI主导编程人做架构和审核”。适合谁来参考这套东西我认为有三类人一是独立开发者想用AI放大自己的产出二是小团队的技术负责人想搭建AI辅助开发的工程规范三是对Agent架构感兴趣的技术人想理解Harness这层抽象到底该怎么设计。如果你只是偶尔用AI写个脚本这篇文章可能偏重了但如果你想系统性地把AI纳入开发流程下面的内容应该对你有用。2. Harness架构的核心设计思路拆解2.1 为什么不是直接用Agent而要加一层Harness很多人第一次接触Agent概念时会觉得Agent本身就是智能的给它一个目标它就能自己干活。实际用下来你会发现裸Agent有三个致命问题。第一个问题是上下文窗口的硬限制。不管模型宣称支持多少token的上下文实际使用中你会发现当上下文超过一定长度后模型对早期信息的注意力会显著下降。你把整个项目的代码库塞进去它反而什么都记不住。Harness的做法是分层管理上下文当前任务相关的代码全文注入间接依赖的代码只注入接口签名无关代码完全不注入。这需要Harness维护一个代码索引和依赖图。第二个问题是输出不可控。Agent可能会写出能运行但风格诡异的代码可能会引入你不想要的依赖可能会在你不注意的时候删掉关键逻辑。Harness通过预设的lint规则、类型检查、单元测试来约束输出。每次Agent生成代码后Harness自动运行校验不通过就打回去重写。第三个问题是状态丢失。Agent没有持久记忆今天写的代码明天就忘了。Harness需要维护一个项目状态文件记录哪些模块已完成、哪些接口已定义、哪些测试已通过。每次启动新任务时Harness把相关状态注入给Agent。提示Harness和Agent的关系类似于Kubernetes和容器的关系。Agent是干活的单元Harness是调度和治理层。没有HarnessAgent就是一堆散兵游勇有了Harness它们才能协同作战。2.2 上下文管理的具体策略这个项目在上下文管理上采用了一种我称之为“三层注入”的策略。第一层是全局约束层。这部分内容每次对话都会注入包括代码规范、项目结构约定、命名规则、错误处理模式等。这部分内容不长大概几百token但它是保证代码风格一致性的关键。没有这一层Agent写出来的代码会像十个人拼凑的。第二层是任务相关层。根据当前任务涉及的文件和模块动态注入相关代码。这里的关键是“相关”的判定。Harness维护了一个基于import关系的依赖图当任务涉及某个文件时它会把该文件、该文件直接依赖的文件、以及依赖该文件的文件都注入进来。但注入的不是全文而是接口定义和关键实现片段。第三层是历史上下文层。这部分记录最近几次对话的摘要让Agent知道自己刚才做了什么。摘要由Harness自动生成不是简单截断而是提取关键决策和变更点。这三层加起来每次注入的上下文控制在模型窗口的30%到50%之间留出足够空间给模型生成输出。这个比例是我实测下来比较稳的太低模型信息不足太高模型注意力分散。2.3 任务分解与调度机制一个人管理20万行代码不可能事无巨细都自己来。这个项目的做法是把开发任务分解成“原子任务”每个原子任务对应一个可独立验证的代码变更。原子任务的粒度怎么定经验法则是一个原子任务应该能在一次Agent对话中完成且完成后可以通过一个明确的测试来验证。比如“实现用户登录接口”太大了应该拆成“定义登录请求的数据结构”、“实现密码哈希函数”、“实现token生成逻辑”、“编写登录接口的单元测试”等。Harness维护一个任务队列按依赖关系排序。没有前置依赖的任务可以并行调度给多个Agent实例。这里有个坑并行任务如果涉及同一文件的修改会产生冲突。Harness的解决方案是文件级锁——一个文件同时只能被一个任务修改。任务完成后Harness自动运行该任务关联的测试。测试通过则标记完成更新项目状态测试不通过则把错误信息注入上下文让Agent重试。重试超过三次的任务会被挂起等待人工介入。2.4 为什么选择Markdown作为中间格式这个项目大量使用Markdown作为Agent输入输出的中间格式这个选择值得展开说。Agent之间的通信、任务描述、状态记录如果都用自然语言会有歧义。如果都用JSON可读性太差人没法快速审查。Markdown是一个很好的折中结构化的标题和列表让机器容易解析自然语言的段落让人容易理解。具体来说任务描述用Markdown模板## 任务实现密码哈希函数 ### 输入 - 明文密码字符串 ### 输出 - 哈希后的字符串 ### 约束 - 使用bcrypt算法 - cost factor 设为 12 - 不允许明文日志 ### 验收标准 - 单元测试覆盖正常和异常输入 - 相同密码每次哈希结果不同这种格式Agent解析起来很准人审查起来也快。项目状态也用Markdown维护每个模块一个文件记录接口、依赖、完成度、已知问题。Obsidian这类工具可以直接打开这些文件形成知识图谱方便人纵览全局。3. 核心细节解析与实操要点3.1 项目目录结构的设计Harness架构对目录结构有硬性要求因为Agent需要根据路径来判断文件的角色。这个项目采用的是一种“按职责分层、按功能分模块”的结构project/ ├── specs/ # 任务描述和验收标准 ├── src/ │ ├── core/ # 核心业务逻辑 │ ├── adapters/ # 外部依赖适配层 │ ├── utils/ # 纯工具函数 │ └── types/ # 类型定义 ├── tests/ │ ├── unit/ # 单元测试 │ └── integration/ # 集成测试 ├── docs/ # 自动生成的文档 └── .harness/ # Harness配置和状态 ├── context/ # 上下文模板 ├── state/ # 项目状态 └── logs/ # 操作日志这个结构的关键在于specs/和.harness/两个目录。specs/存放所有任务的Markdown描述是人和Agent的共同语言。.harness/存放Harness自身的配置和状态是系统的“大脑”。注意不要让Agent随意创建新目录。每次Agent想新建文件时Harness会检查路径是否符合预设规则。不符合规则的路径会被拒绝并提示Agent使用正确的路径。这个约束看似死板但它是保持项目结构清晰的关键。3.2 代码生成的质量控制Agent生成的代码不能直接合并。这个项目设置了三道质量关卡。第一道是语法和类型检查。每次生成后立即运行不通过直接打回。这一步能过滤掉大部分低级错误。第二道是lint检查。项目预设了一套ESLint规则包括命名规范、导入顺序、函数长度限制等。Agent生成的代码必须通过所有规则。这里有个技巧把lint规则写成自然语言描述也注入到上下文里让Agent在生成时就尽量遵守减少返工。第三道是单元测试。每个原子任务都必须附带测试测试不通过不算完成。测试覆盖率有下限要求核心模块要求80%以上。这三道关卡都是自动运行的人只需要在最后审查通过的代码。实测下来经过这三道关卡后人工审查的时间可以减少70%以上。3.3 上下文注入的模板设计上下文模板是Harness的核心资产。这个项目维护了十几种模板对应不同类型的任务。比如“新建模块”模板、“修改接口”模板、“修复bug”模板、“重构”模板。以“修改接口”模板为例## 当前任务 {task_description} ## 相关接口定义 {interface_definitions} ## 调用方代码 {caller_snippets} ## 约束 - 保持向后兼容 - 更新所有调用方 - 更新相关测试 ## 项目规范 {coding_standards}模板的设计原则是只注入必要信息不注入完整文件。接口定义只给签名和注释调用方代码只给调用片段。这样既保证了Agent有足够信息又不会撑爆上下文。3.4 Token消耗的优化策略每月40亿token听起来很多但如果分摊到每个任务其实需要精细控制。这个项目采用了几个优化策略。第一个策略是缓存。相同的上下文前缀如果多次使用可以利用模型的prompt caching功能。Claude和GPT都支持这个特性能显著降低重复上下文的成本。Harness会把全局约束层和项目规范层做成固定前缀享受缓存优惠。第二个策略是分级模型。不是所有任务都需要最强的模型。简单的代码格式化、注释生成用便宜的小模型复杂的架构设计、算法实现用大模型。Harness根据任务类型自动选择模型。第三个策略是输出限制。Agent生成代码时Harness会设置max_tokens上限防止Agent啰嗦。同时要求Agent只输出代码和必要的注释不要输出解释性文字。这三个策略加起来能把token消耗降低40%到60%。我实测过同样的任务量优化前后差距非常明显。4. 实操过程与核心环节实现4.1 从零搭建Harness的步骤如果你现在想复现这套东西我建议按以下顺序来。第一步先不要写Harness代码。先用最原始的方式手动和Claude Code对话完成一个小项目。这个过程中记录下你每次需要重复交代的背景信息、每次遇到的Agent犯错模式、每次需要人工干预的环节。这些记录就是你Harness的需求文档。第二步设计项目状态文件。用Markdown写一个state.md记录项目结构、模块列表、接口定义、完成度。这个文件一开始手动维护后来让Agent帮你更新。第三步写第一个自动化脚本。最简单的Harness就是一个shell脚本它读取任务描述拼接上下文调用模型API把输出写入文件然后运行测试。这个脚本可能只有几十行但它已经具备了Harness的核心功能。第四步逐步增加功能。加入lint检查、加入测试运行、加入重试逻辑、加入任务队列。每增加一个功能都要问自己这个功能解决了我实际遇到的什么问题如果没遇到就先不加。第五步把Harness本身也纳入Agent的管理。让Agent帮你写Harness的代码你只做架构设计和代码审查。这是实现“一个人20万行”的关键——Harness自己也在进化。4.2 一个完整任务的执行流程我拿“实现用户注册接口”这个任务来演示完整流程。首先人在specs/目录下创建一个Markdown文件描述任务## 任务实现用户注册接口 ### 输入 - email: string - password: string ### 输出 - 成功用户ID - 失败错误码和错误信息 ### 约束 - email 需要验证格式 - password 最少8位包含字母和数字 - 密码不能明文存储 - 需要防止重复注册 ### 验收标准 - 单元测试覆盖所有错误分支 - 集成测试验证数据库写入然后Harness读取这个文件识别任务类型为“新建接口”选择对应模板注入相关上下文。上下文包括现有的用户模型定义、数据库连接模块的接口、错误处理规范、密码哈希工具的接口。Harness调用模型模型生成代码。生成的代码包括路由定义、请求验证、业务逻辑、数据库操作、错误处理。Harness把代码写入src/对应位置。接着Harness自动运行lint和测试。假设测试失败错误是“重复注册未处理”。Harness把错误信息注入上下文让模型重试。模型补充了重复检查逻辑再次生成。这次测试通过。最后Harness更新state.md标记该接口已完成记录接口签名和依赖关系。整个过程人只做了两件事写任务描述、审查最终代码。4.3 处理Agent的“幻觉”和错误Agent会犯错这是常态。关键是如何让错误可发现、可恢复。最常见的错误是“幻觉API”——Agent调用了一个不存在的函数或方法。这种错误通常会被类型检查或lint捕获。Harness的做法是在上下文里注入所有可用API的签名列表让Agent只能从列表中选择。如果Agent调用了列表外的APIHarness会拒绝并提示。第二种错误是“过度设计”——Agent实现了一个简单功能却引入了复杂的抽象层。这种错误lint捕获不了需要人工审查。Harness的应对策略是在约束里明确写“不要引入新的抽象层”、“使用项目已有的模式”。同时在代码审查阶段人重点关注新增的抽象。第三种错误是“测试造假”——Agent写的测试没有真正验证功能只是让测试通过。这种错误最隐蔽。Harness的应对是要求测试必须包含“负面用例”即验证错误情况的测试。同时定期人工抽查测试质量。提示不要指望Agent一次做对。把Agent当成一个速度快但经验不足的初级工程师你的任务是给它清晰的指令和严格的验收标准。4.4 用Obsidian管理项目知识这个项目用Obsidian来管理所有的Markdown文件包括任务描述、项目状态、接口文档、决策记录。Obsidian的双向链接功能让这些文件形成了一个知识网络。具体用法是每个模块一个笔记笔记里用[[链接]]引用相关的接口、依赖、测试。Obsidian会自动生成关系图你可以直观地看到模块之间的依赖关系。当你要修改某个接口时打开该接口的笔记就能看到所有引用它的地方。这个做法还有一个好处Agent生成的文档可以直接被Obsidian索引。你让Agent为每个模块生成文档文档里的链接自动生效。人和Agent共享同一套知识库沟通成本大幅降低。4.5 并发任务的调度实现当项目变大后串行执行任务会成为瓶颈。这个项目实现了一个简单的并发调度器。调度器的核心是一个任务队列和一组worker。每个worker是一个独立的Agent会话拥有独立的上下文。调度器从队列中取出没有依赖冲突的任务分配给空闲worker。冲突检测基于文件锁。每个任务在执行前会声明它要修改的文件列表。调度器检查这些文件是否被其他正在执行的任务锁定。如果有冲突任务等待如果没有任务开始执行并锁定文件。这个调度器用Python写核心逻辑不到200行。但它让任务吞吐量提升了3倍以上。不过要注意并发度不是越高越好。实测下来同时运行3到5个worker比较合适再多的话上下文切换和冲突等待的开销会抵消并行收益。5. 常见问题与排查技巧实录5.1 Agent输出格式错乱的排查问题表现Agent生成的代码中混入了Markdown标记、解释性文字、或者格式不符合预期。排查思路首先检查上下文模板是否明确要求了输出格式。如果模板里只说“生成代码”Agent可能会自由发挥。要在模板里明确写“只输出代码不要输出任何解释”。其次检查是否有示例。在上下文里给一个正确输出的示例Agent会模仿。示例比文字描述有效得多。最后检查max_tokens设置。如果max_tokens太小Agent的输出可能被截断导致格式不完整。5.2 上下文超限的应急处理问题表现任务复杂时注入的上下文超过了模型窗口导致调用失败。应急处理Harness应该有一个降级策略。当上下文超限时按优先级裁剪。优先级从高到低当前任务描述、直接依赖的接口定义、项目规范、历史上下文。裁剪到窗口的80%为止。长期方案是优化任务分解把大任务拆小。如果一个任务的上下文总是超限说明任务粒度太粗。5.3 测试通过但功能不对的情况问题表现Agent写的代码通过了所有测试但实际运行时功能不对。原因通常是测试本身有问题。Agent可能写了“假测试”——测试逻辑和实现逻辑一致但都错了。排查方法人工审查测试用例特别是边界条件和错误处理。要求Agent为每个测试用例写一句注释说明这个测试验证什么。如果注释说不清楚测试大概率有问题。预防措施在任务描述里明确要求“测试必须包含至少一个负面用例”。负面用例是验证错误情况的比正面用例更难造假。5.4 常见问题速查表问题现象可能原因排查方向解决方案Agent输出格式错乱模板未明确格式要求检查上下文模板添加格式要求和示例上下文超限任务粒度过大检查任务描述复杂度拆分任务或启用裁剪策略测试通过但功能不对测试造假审查测试用例质量要求负面用例和注释Agent重复犯错错误信息未注入检查重试逻辑把错误信息加入上下文并发任务冲突文件锁失效检查锁的实现修复锁逻辑或降低并发度Token消耗过高上下文冗余分析token分布启用缓存、分级模型、输出限制Agent调用不存在的API上下文缺少API列表检查API注入注入完整API签名列表代码风格不一致全局约束未注入检查约束层确保每次对话都注入规范5.5 几个踩过的坑第一个坑是过度依赖Agent的自我评估。早期我让Agent自己判断任务是否完成结果它总是说“完成了”但实际上测试都没跑。后来改成必须通过自动化测试才算完成问题解决。第二个坑是上下文注入太多。一开始我想给Agent尽可能多的信息结果它反而抓不住重点。后来学会做减法只注入必要信息效果反而更好。第三个坑是忽略日志。Harness运行过程中会产生大量日志一开始我没在意。后来排查问题时发现日志里记录了每次调用的上下文和输出是排查问题的金矿。现在我会定期分析日志找出Agent的常见错误模式针对性地优化上下文模板。第四个坑是任务描述太模糊。比如“优化性能”这种描述Agent完全不知道从何下手。后来改成“把getUserList函数的响应时间从200ms降到50ms以内”Agent就能给出具体方案。任务描述越具体Agent表现越好。5.6 性能优化的几个实用技巧第一个技巧是预热缓存。在开始一批任务前先发一个只包含全局约束的请求让模型缓存这部分内容。后续请求都带上这个前缀能享受缓存折扣。第二个技巧是批量提交。把多个小任务合并成一个请求让Agent一次性生成多个文件的代码。这样能减少请求次数降低开销。但要注意批量任务之间不能有依赖冲突。第三个技巧是结果复用。如果两个任务需要相似的代码让Agent先生成一个然后第二个任务基于第一个修改。这样比从头生成更省token。第四个技巧是定期清理。项目状态文件和上下文模板会随着时间膨胀。定期清理过时的内容保持精简。我一般每周清理一次把已完成的模块从活跃状态移到归档状态。5.7 关于Harness和Agent区别的理解很多人问Harness和Agent到底有什么区别。我的理解是Agent是“做什么”的Harness是“怎么做”的。Agent负责理解任务、生成代码、解决问题。它是智能的但也是不可控的。Harness负责给Agent提供信息、约束Agent的行为、验证Agent的输出。它是死板的但也是可靠的。一个好的系统需要两者配合。Agent提供灵活性和创造力Harness提供稳定性和可重复性。没有AgentHarness只是一堆空架子没有HarnessAgent只是一个不可靠的天才。这个项目能一个人做到20万行核心就在于把Harness这层做厚了。Agent可以换模型可以升级但Harness积累的上下文模板、任务描述、验收标准、项目状态是真正的资产。这些东西让AI的能力可以被持续、稳定地调用而不是每次都要重新调教。我在实际使用中发现Harness的投入产出比在项目初期不明显甚至会觉得是负担。但当项目超过一定规模后没有Harness的系统会迅速崩溃——上下文混乱、代码风格分裂、任务无法追踪。这时候Harness的价值就体现出来了。所以我的建议是哪怕项目还小也尽早开始积累Harness资产哪怕只是一个简单的状态文件和几个上下文模板。这些积累会在项目变大后救你的命。
返回列表