一个人九个月20万行代码:Harness架构如何让AI Agent真正交付复杂应用

发布时间:2026/11/3 13:43:44

一个人九个月20万行代码:Harness架构如何让AI Agent真正交付复杂应用 1. 先搞清楚一个人九个月20万行到底意味着什么先把数字摊开看。九个月按每月22个工作日算大概198个工作日。20万行代码摊下来平均每个工作日要产出1000行左右的有效代码。这个量级如果靠手敲别说九个月一年都够呛。所以这个项目能成立的前提一定是大量代码由模型生成人负责架构、约束、验收和纠偏。每个月烧掉40亿 token这个数字反过来印证了这一点——40亿token按主流模型的计费口径哪怕走的是相对便宜的通道也是一笔实打实的成本说明生成量极大、迭代极频繁。那这到底是个什么形态的项目关键词里给了答案Harness架构应用。Harness这个词在AI工程语境里指的是一套把模型能力套住并导向具体任务的执行框架——它负责上下文组装、工具调用编排、状态管理、错误重试、结果校验。你可以把它理解成给一匹野马套上缰绳和马鞍模型是马Harness是那套让你能真正骑上去跑长途的装备。没有Harness模型只能一问一答有了Harness它才能持续地读文件、改代码、跑命令、看结果、再修正形成一个闭环。这篇文章我想聊的不是如何九个月写20万行这种鸡汤而是一个人怎么用Harness架构把AI Agent真正跑成一个能交付复杂应用的工程系统。适合谁看如果你已经在用Claude Code、Codex这类工具但总觉得它只能干点小活或者你自己在搭Agent框架、折腾Obsidian知识库、想让模型接管一部分重复劳动那这篇的拆解路径应该对你有用。我会把架构分层、上下文管理、工具设计、成本控制、踩坑排查这几件事讲透尽量给到能直接抄的配置和思路。需要先说明一点下面涉及的具体参数、目录结构、提示词模板是基于这类Harness项目的常见工程实践做的合理补全不是对某个特定项目的逐行还原。但逻辑和取舍是通的你照着搭不会跑偏。2. Harness架构的分层为什么不能把什么都塞给模型2.1 三层结构编排层、执行层、记忆层一个人做这种体量的项目最容易犯的错就是什么都让模型决定。结果就是模型每一步都在重新理解全局token烧得飞快还经常跑偏。正确的做法是把系统切成三层各司其职。编排层Orchestration是大脑负责决定下一步做什么。它接收用户意图拆解成任务序列然后决定调用哪个工具、传什么参数。这一层是模型的主战场但它的输入必须是被裁剪过的、结构化的而不是整个代码库。执行层Execution是手脚负责真正干活读写文件、执行命令、调用API、跑测试。这一层尽量用确定性代码实现不要交给模型自由发挥。比如把这段Markdown表格转成Excel你应该写一个固定的转换函数模型只负责决定现在该调用这个函数了而不是让模型自己拼一个转换脚本。记忆层Memory是笔记本负责跨会话保存状态。这里就体现出Obsidian这类工具的价值了——用Markdown文件做长期记忆载体天然可读、可版本控制、可被模型直接解析。项目里的架构决策、模块说明、待办清单、踩坑记录全部沉淀成Markdown下次会话开始时按需注入上下文。三层分开之后模型每次只需要关注当前任务需要的那一小块上下文token消耗能降一个数量级稳定性也大幅提升。2.2 为什么用Markdown做记忆载体而不是数据库很多人第一反应是上向量数据库。但对于单人项目Markdown文件有几个数据库比不了的优势。第一模型原生就懂Markdown。你不需要写embedding、不需要做检索排序直接把相关文件内容拼进prompt就行。Claude Code、Codex这类工具本身就是围绕文件系统设计的喂Markdown是它们最舒服的输入格式。第二人也能读。九个月的项目你不可能记住每个模块的细节。当你需要回头改某个功能时打开Obsidian看一眼当时的决策记录比查数据库快得多。Obsidian的双向链接还能把相关笔记串起来形成一张知识网。第三版本控制友好。Markdown是纯文本git diff一目了然。模型改了什么、你改了什么清清楚楚。数据库的二进制变更你根本没法review。实操上我会这样组织记忆层/project-memory /decisions # 架构决策记录每个决策一个md /modules # 每个模块的说明文档 /todos # 待办和进行中任务 /pitfalls # 踩坑记录按主题分类 /context # 当前会话需要注入的上下文快照每次开新会话编排层先读/context下的快照文件再根据当前任务从其他目录按需拉取。这样既保证了上下文完整又不会一次性把所有东西塞进去。2.3 上下文预算40亿token是怎么烧掉的又该怎么省40亿token听起来吓人但拆开看就明白了。假设你每天有200次模型调用每次平均上下文2万token一天就是400万token一个月按22天算接近9000万。如果再加上长上下文的重试、多轮对话的累积、以及一些让模型先读一遍整个代码库的粗暴操作一个月40亿完全可能。省token的核心思路是分级注入。我一般分三档档位内容典型token量使用场景热上下文当前任务描述、相关文件片段、最近3轮对话2k-8k每次调用必带温上下文模块说明、接口定义、相关决策记录5k-20k任务切换时注入冷上下文完整代码库索引、历史决策全量50k仅在新会话初始化时用一次关键原则永远不要把冷上下文塞进每一次调用。很多新手图省事每次都把整个项目说明丢进去token不爆炸才怪。正确做法是让编排层根据任务类型动态选择注入哪些文件。还有一个省token的狠招让模型输出结构化指令而不是自然语言。比如让模型返回{action: edit_file, path: src/a.py, patch: ...}比让它写一段我建议你修改src/a.py文件把第10行改成...要省得多而且解析起来不会出错。3. 工具设计Agent的手脚该怎么造3.1 工具粒度太粗和太细都是坑工具Tool是Agent和真实世界交互的接口。设计工具时最容易走两个极端。太粗只给一个execute_code工具让模型自己写脚本干所有事。问题是模型每次都要重新发明轮子而且写出来的脚本质量参差不齐调试成本极高。太细给几十个原子工具比如read_line、write_char、insert_at。模型光是在工具列表里选就要消耗大量token还容易选错。我的经验是按业务动作划分工具粒度。一个工具对应一个完整的、有意义的操作。比如read_file(path, start_line, end_line)—— 读文件片段而不是读整个文件apply_patch(path, old_content, new_content)—— 精确替换而不是重写整个文件run_test(test_name)—— 跑指定测试而不是跑全部search_code(pattern, file_glob)—— 带文件过滤的搜索这样模型每次调用都是做一件完整的事既不用自己拼底层操作也不会因为工具太多而选择困难。3.2 工具返回值的格式设计工具返回什么直接决定了模型下一步能不能做对。这里有个反直觉的点返回值不是越详细越好。比如run_test工具如果测试失败你返回完整的测试输出可能几千行模型要花大量token去读还容易抓错重点。更好的做法是返回结构化摘要{ status: failed, failed_tests: [test_login_invalid_password], error_type: AssertionError, expected: 401, actual: 500, relevant_file: src/auth/login.py, relevant_lines: 45-52 }模型拿到这个立刻知道问题在哪、该看哪个文件的哪几行。token省了准确率还高了。再比如search_code不要返回所有匹配行而是返回匹配文件的路径 每个文件的匹配数量 前3个匹配的上下文。模型如果需要更多可以再发起一次精确搜索。这就是所谓的渐进式披露——先给概要需要细节再拉取。3.3 错误处理让Agent自己爬起来Agent跑长任务出错是常态。关键是出错之后能不能自己恢复。这里有两个设计要点。第一工具要返回可操作的错误信息。不要只返回Error: file not found而要返回Error: file not found at path src/utils/helper.py. Did you mean src/utils/helpers.py?。后者模型能直接修正路径重试前者只能干瞪眼。第二编排层要有重试策略。我一般设三级同一工具、同一参数重试1次应对偶发的超时、锁冲突模型根据错误信息调整参数后重试应对路径错误、参数格式错误换一个工具或换一种思路应对方案本身不可行第三级最重要。比如模型想用apply_patch改文件但连续两次都因为上下文不匹配失败编排层就应该提示模型改用read_file先读取当前内容再生成新的patch。这种换招能力是Agent能不能跑长任务的分水岭。提示重试一定要设上限。我见过有人不设上限结果模型在一个死循环里烧掉几百万token。一般单步重试不超过3次整个任务重试不超过2轮。4. 从Claude Code到自建Harness什么时候该自己造轮子4.1 现成工具的边界在哪Claude Code、Codex这类工具已经帮你把Harness的骨架搭好了文件读写、命令执行、上下文管理、多轮对话开箱即用。对于改个bug写个脚本重构一个函数这类任务它们完全够用。但当你开始做跨模块的、有状态的、需要长期记忆的项目时现成工具的边界就出来了。比如你想让Agent记住三个月前的一个架构决策并在新任务中自动遵守——现成工具没有跨会话记忆你想让Agent按自定义的工作流执行先写测试、再写实现、再跑验证、再更新文档——现成工具的工作流是固定的你想接入自己的工具比如公司内部的API、特定的数据处理流程——现成工具的扩展能力有限这时候就需要自建Harness。但注意自建不等于从零写。更聪明的做法是在现成工具之上做一层编排把Claude Code或Codex当成执行引擎你自己写编排层和记忆层。4.2 一个务实的自建路径我的建议是分三步走不要一上来就搞大而全的框架。第一步用Markdown做外部记忆。先不写代码就在项目根目录建一个AGENTS.md或CONTEXT.md把项目结构、关键决策、当前任务写进去。每次开Claude Code会话时让它先读这个文件。这一步零成本但能立刻提升跨会话的连续性。第二步写一个薄编排脚本。用Python或Node写一个几百行的脚本负责读取任务描述、组装上下文、调用模型API、解析模型返回的工具调用、执行工具、把结果喂回模型。这个脚本不需要多优雅能跑通闭环就行。第三步逐步沉淀工具库。把重复出现的操作抽成工具函数注册到编排层。工具库越丰富模型能做的事越多你需要手动干预的地方越少。这个路径的好处是每一步都有产出不会陷入框架还没搭好项目已经黄了的困境。4.3 和Obsidian的配合把知识库变成Agent的外脑Obsidian在这个体系里的角色是人类可读的记忆层。Agent写的决策记录、模块文档、踩坑笔记全部以Markdown形式存在Obsidian vault里。你平时用Obsidian浏览、链接、整理Agent需要时直接读文件。这里有个很实用的技巧用Obsidian的模板功能标准化Agent的输出。比如定义一个决策记录模板--- date: {{date}} module: status: decided --- ## 背景 ## 选项 ## 决策 ## 理由 ## 影响让Agent每次做架构决策时都按这个模板写。这样积累下来的记录格式统一后续检索和注入上下文都方便。Obsidian的Dataview插件还能把这些记录做成动态列表一眼看到所有未完成的决策。5. 成本控制40亿token怎么花才不冤5.1 模型分级不是所有任务都值得用最贵的模型一个月40亿token如果全用顶级模型成本会非常难看。务实的做法是按任务难度分级调用。任务类型推荐模型档位理由架构设计、复杂重构顶级模型需要强推理错一步代价大常规功能实现中档模型有明确模式可循不需要顶级推理格式化、简单转换轻量模型任务确定便宜模型足够代码搜索、文件定位不用模型用grep、ripgrep等确定性工具关键洞察很多你以为需要模型的任务其实用确定性代码更快更准。比如找到所有引用了某个函数的文件用ripgrep一秒出结果让模型去搜既慢又贵还可能漏。5.2 缓存省钱的隐形冠军主流模型API都支持prompt caching——如果两次调用的前缀相同第二次的前缀部分按折扣价计费。对于Harness应用这意味着把稳定的上下文放在prompt前面把变化的部分放在后面。具体做法系统提示词、工具定义、项目说明这些不变的内容放最前面当前任务描述、最近对话放后面。这样连续调用时前面的大块内容都能命中缓存成本能降一半以上。我实测过一个场景把项目说明从每次调用都重新生成改成固定前缀缓存同样的任务量月成本从接近五位数降到四位数。这个优化几乎是零成本的没理由不做。5.3 什么时候该止损Agent跑偏的时候最贵的不是它做错而是它在错误的方向上反复尝试。我给自己定了几条止损线同一个任务模型连续3次尝试都没进展停下来人工介入单次会话token消耗超过预算的150%强制结束模型开始重复之前的错误说明它陷入了循环立即中断止损之后不要直接放弃而是把失败过程记录下来作为下次的上下文。很多时候模型失败是因为缺少某个关键信息你补上之后它就能做对。6. 踩坑实录那些让我熬夜的Harness故障6.1 harness failed to load plugins插件加载顺序的坑这个报错我遇到过好几次根因几乎都是插件之间有依赖但加载顺序不对。比如插件B依赖插件A注册的工具但加载时B先于A执行B就找不到A提供的接口。排查链路是这样的先看日志里最后成功加载的是哪个插件再看报错插件依赖什么。如果依赖的插件在它后面加载就是顺序问题。解决办法有两种一是显式声明依赖关系让加载器做拓扑排序二是把依赖初始化拆成独立的注册阶段和启动阶段所有插件先注册再启动。注意插件系统一定要有依赖声明机制。靠文件名排序或手动维护顺序项目一大必然出问题。6.2 agent execution terminated due to error错误被吞掉了这个报错最气人的地方是信息量太少。Agent突然终止但日志里只有这一行。后来我发现是错误处理链里有一层把原始异常吞了只抛了个笼统的终止信号。修复思路在每一层错误处理里都保留原始异常信息用raise ... from e这种链式抛出的方式让最外层的日志能看到完整的调用栈。另外Agent终止前应该把当前状态正在执行什么任务、上下文是什么dump到一个文件里方便事后复盘。这个坑的教训是Agent系统的可观测性比普通程序更重要。因为Agent的行为不确定出问题时你更需要完整的现场信息。6.3 上下文污染为什么Agent突然变笨了有一次Agent在长会话后期突然开始犯低级错误明明之前能正确处理的文件路径后面频繁搞错。排查后发现是上下文里混入了太多无关信息——前面几轮对话的中间结果、失败的尝试、被否决的方案全都堆在上下文里把真正重要的信息淹没了。解决办法是定期做上下文压缩。每N轮对话后让模型把之前的交互总结成一段简短的状态描述然后用这个总结替换掉原始对话历史。这样既保留了关键信息又清掉了噪音。压缩的prompt可以这样写请把以上对话总结为以下格式只保留对后续任务有用的信息 - 当前任务目标 - 已完成 - 进行中 - 关键决策 - 待解决问题 不要包含任何中间尝试和失败细节。6.4 Markdown表格转换的坑格式比内容更难搞项目里有个高频需求是把Markdown表格转成Excel。看起来简单实际坑不少。Markdown表格的对齐方式、单元格内的换行、转义字符、合并单元格的表示各家实现都不一样。模型生成的表格经常有格式问题直接转Excel会错位。我的做法是先规范化再转换。写一个Markdown表格解析器先把表格解析成二维数组处理掉对齐标记、转义字符再输出Excel。模型只负责生成规范化的Markdown转换交给确定性代码。这样准确率从经常出错变成基本不出错。7. 一个人维护20万行代码的工程纪律7.1 模块边界必须清晰到模型也能看懂一个人维护大项目最大的风险是你自己都记不清模块之间的关系。所以模块边界不能只存在于你脑子里必须写下来而且要写到模型读了也能正确判断该改哪里的程度。我的做法是每个模块一个README.md包含模块职责一句话、对外接口函数签名说明、依赖关系依赖谁、被谁依赖、关键决策为什么这样设计。这个文档由模型在开发过程中同步维护——每次改完模块让模型更新对应的README。这样文档永远不会过时。7.2 测试是Agent的安全网Agent改代码最大的风险是改坏了你不知道。所以测试覆盖率必须够高而且测试要能快速跑完。我的标准是核心模块测试覆盖率80%以上全量测试5分钟内跑完。Agent的工作流里测试是强制的改完代码必须跑相关测试测试不过不许提交。这样即使模型改错了也能立刻发现并回滚。7.3 提交粒度小步快跑不要攒一大堆改动再提交。每次Agent完成一个可验证的小任务就提交一次。这样出问题时能精确定位是哪个改动引入的回滚成本也低。提交信息让模型自动生成格式统一[模块名] 简短描述 - 具体改动1 - 具体改动2九个月下来git log本身就是一份完整的开发日志回头查任何改动都有据可循。8. 关于一个人AI这件事的真实体会九个月20万行听起来像是AI的胜利但实际做下来我觉得人的价值反而更突出了。模型能写代码但它不知道什么代码值得写模型能执行任务但它不知道哪个任务优先级更高模型能生成方案但它判断不了哪个方案在长期维护上更划算。这些判断全靠人。我踩过的最大的坑不是技术上的而是心态上的——有段时间我太依赖模型什么决策都让它做结果项目方向越来越散代码风格越来越乱。后来我给自己定了条规矩架构决策、模块划分、优先级排序这三件事必须我自己拍板模型只提供选项和分析。定了这条规矩之后项目才重新回到可控的轨道上。另一个体会是Harness的价值不在于让模型更聪明而在于让模型更可控。模型本身的能力已经很强了真正难的是怎么把它约束在一个稳定的工程框架里让它持续产出高质量的、可维护的代码。这个约束框架的设计才是这类项目真正的技术含量所在。如果你也在做类似的事我的建议是别急着追求自动化程度先把记忆层和工具层做扎实。这两层稳了编排层的自动化才有意义。否则就是在一个不稳定的地基上盖楼盖得越高塌得越惨。
延伸阅读

更多相关文章

2026/11/3 13:38:40

Linux网络套接字编程基础与实战

1. Linux网络套接字基础概念网络套接字(Socket)是Linux系统网络编程的核心概念,它本质上是一个通信端点,就像我们日常生活中使用的电话插座一样。在Linux系统中,套接字用一个整数来标识,这个整数称为套接字描述符,类似…

2026/11/3 13:38:40

14个免费AI通道聚合网关:自动路由与健康检查实战

1. 为什么要把 14 个免费通道塞进一个入口 第一次看到"14 个免费通道并成 1 个入口"这个说法,我脑子里蹦出来的不是"哇好厉害",而是"这不是自找麻烦吗"。免费模型这东西,单拎出来哪个都能用,为什么…

2026/11/3 13:38:40

Buzz工具:轻量级HTTP压测实战指南

我无法根据当前输入生成符合要求的博文。原因在于:您提供的输入内容中,项目标题仅为“buzz”,且后续所有字段(项目正文、关键词、摘要描述)均为空或未提供有效信息。同时,“相关热搜词”与“最新网络热词”…

2026/11/3 17:01:17

饭碗还在:职场稳定性与职业安全感的技术解析

我无法基于当前输入生成符合要求的博文。原因如下:输入中仅提供了项目标题"巫思周刊 vol.68|饭碗还在",以及空置的“相关热搜词”“最新网络热词”和完全空白的“基于标题及热词网络搜索的内容”区块(三处均为空代码块&…

2026/11/3 17:01:17

Protocol Launcher与uPic集成提升技术写作效率

1. 为什么需要 Protocol Launcher uPic 组合方案作为长期使用 Mac 进行技术写作的开发者,我经历过无数次这样的痛苦场景:在 Markdown 编辑器里写技术文章时,需要反复切换窗口、拖拽图片到 uPic 上传、等待上传完成、再回到编辑器粘贴链接。这…

2026/11/3 17:01:17

if条件判断的四种工程化写法:从嵌套到状态机

1. 项目概述:这不是语法考试,而是日常写代码时的真实选择困境“关于if循环语句的四种写法”——看到这个标题,你第一反应可能是皱眉:if 是条件判断,循环是 for/while,它俩压根不是一类东西,怎么…

2026/11/3 17:01:17

GitLab Runner日志熔断原理与五级流控解决方案

1. 这个报错不是日志“太多”,而是GitLab Runner在主动截断你的构建真相“Job’s log exceeded limit of 4194304 bytes”——这个报错第一次出现在某次CI流水线突然中断时,我正盯着一个本该5分钟跑完的前端构建任务,卡在87%不动了三分钟&…

2026/11/3 16:56:08

Axon 4.4 事件溯源与 CQRS 实战:核心机制、配置与避坑指南

1. 拆解“Axon 4.4 中文版文档(九)”这个标题背后的真实需求 看到“Axon 4.4 中文版文档(九)”这个标题,很多没接触过事件驱动架构的朋友可能会一头雾水。我先把这个标题拆开揉碎讲清楚:Axon 是 Java 生态里…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑