资讯动态

一个人九个月二十万行代码:Harness架构与Agent开发实战

发布时间:2026/9/30 13:46:05 来源:尧图企业网站定制
1. 一个人九个月二十万行代码这件事到底在说什么先把数字摊开来看。一个人九个月二十万行代码每个月消耗四十亿以上的 token。这几个数字放在一起任何一个写过代码的人都会先愣一下。九个月按二百七十天算平均每天要产出七百多行有效代码同时还要消耗掉一个中型团队都未必用得完的模型调用量。这不是在写一个脚本或者一个小工具这是在用一个人的力量撑起一套完整应用的工程体量。这个应用的核心架构叫Harness。如果你最近在关注 Agent 开发这个方向应该对这个词不陌生。Harness 本质上是一套围绕 AI Agent 运行的编排与执行框架它负责把模型的推理能力、工具调用能力、上下文管理能力串成一条可运行的链路。你可以把它理解成 Agent 的“骨架加神经系统”——模型是大脑Harness 是让大脑能指挥手脚、能记住事情、能在出错时自我修正的那套机制。那二十万行代码到底花在哪了不是花在写业务逻辑上而是花在让 Agent 真正可靠地跑起来这件事上。上下文怎么裁剪、工具调用失败了怎么重试、多轮对话的状态怎么持久化、Markdown 文档怎么解析成结构化数据、Obsidian 的本地库怎么和 Agent 的记忆打通、Claude Code 这类编码 Agent 怎么被调度进整个流程——每一个问题单独拎出来都不算大但当你把它们全部塞进一个系统里代码量就会像滚雪球一样涨起来。这篇文章适合谁看如果你正在做 Agent 相关的项目或者你正在用 Claude Code、Obsidian 这类工具搭建自己的知识工作流再或者你只是好奇“一个人到底能不能扛起一个完整应用”那这篇内容应该能给你不少参考。我会把 Harness 架构的设计思路、Markdown 与 Obsidian 的集成细节、Agent 执行链路的搭建方式、以及那四十亿 token 到底烧在了哪些环节一层一层拆开讲。里面有不少是我自己踩过坑之后才想明白的东西也有一些是常规文档里不会写的实操经验。2. Harness 架构的整体设计与思路拆解2.1 为什么是 Harness而不是直接调模型很多人做 Agent 项目第一反应是直接调模型 API写个循环把工具塞进去就完事了。刚开始确实能跑但跑到第三天你就会发现问题全冒出来了。模型忘了之前说过什么工具调用参数格式错了没人管同一个任务重复执行了三遍上下文越来越长最后直接把 token 撑爆。这些问题的根源在于你缺了一层专门负责编排和兜底的架构而 Harness 就是干这个的。Harness 的核心价值在于把“模型该干什么”和“系统该怎么保证它干成”这两件事分开。模型只负责推理和决策Harness 负责执行、重试、状态管理、上下文压缩、错误恢复。这样做的直接好处是你换模型的时候不用重写整个系统你加新工具的时候不用改核心逻辑你发现某个环节不稳定的时候可以单独加固那一层。我自己的体会是Harness 架构最值得投入的地方是状态机设计。Agent 执行一个任务本质上是在多个状态之间流转理解意图、规划步骤、调用工具、检查结果、决定是否继续。如果这些状态没有被显式地建模那整个系统就是一团浆糊出了问题你根本不知道是哪一步断的。把状态机画清楚每个状态的进入条件、退出条件、失败处理都定义好后面调试的时候你会感谢自己。2.2 二十万行代码的分布逻辑二十万行听起来吓人但拆开看其实很合理。按照我自己的项目经验一个完整的 Harness 应用代码大致会分布在这么几个模块里。模块大致占比核心职责上下文管理20%对话历史裁剪、摘要生成、token 预算控制工具调度层25%工具注册、参数校验、调用重试、结果解析状态持久化15%会话状态存储、断点恢复、多任务隔离Markdown 解析12%文档结构化、表格转换、语法树构建Obsidian 集成10%本地库读写、双向链接解析、插件通信Agent 编排18%多 Agent 协作、任务分发、结果聚合你看真正跟“业务”相关的代码可能连百分之十都不到剩下百分之九十全是在解决可靠性和可维护性的问题。这也是为什么一个人九个月能写出二十万行——因为大部分代码是在跟边界情况作斗争而边界情况是无穷无尽的。2.3 为什么选择 Markdown 和 Obsidian 作为核心载体这个选择其实非常聪明。Markdown 是当下最适合 AI 处理的文本格式没有之一。它的语法足够简单模型能稳定生成它的结构足够清晰解析起来不会像 HTML 那样嵌套到让人崩溃它的表格、代码块、列表这些元素天然就适合承载结构化信息。你在做 Agent 的时候如果让模型输出 JSON它经常会漏括号或者多逗号但让它输出 Markdown稳定性会高很多。Obsidian 则是本地知识库这个场景里最合适的选择。它基于纯文本文件所有笔记都是 Markdown这意味着 Agent 可以直接读写文件系统不需要通过任何 API 中间层。它的双向链接机制让笔记之间形成了图谱结构Agent 在做检索和推理的时候可以顺着链接找到相关上下文。再加上 Obsidian 有丰富的插件生态你可以通过插件把 Agent 的能力嵌入到日常的笔记工作流里。把 Markdown 和 Obsidian 组合起来你得到的是一个对 AI 友好、对人也友好的知识工作环境。Agent 在里面读写内容你在里面整理思路两边用的是同一套文件不需要同步不需要转换。这个设计决策直接决定了后面很多实现细节的走向。3. 核心细节解析与实操要点3.1 上下文管理四十亿 token 到底怎么烧的每个月四十亿 token这个数字乍看很夸张但如果你理解了 Agent 的工作方式就会发现它其实烧得很有道理。一个 Agent 执行任务不是一次调用就完事的。它要读上下文、做规划、调工具、看结果、再规划、再调工具一个稍微复杂点的任务来回十几轮是很正常的。每一轮都要把之前的对话历史重新塞进模型这就是 token 消耗的大头。我实测下来的经验是上下文裁剪策略直接决定了你的 token 账单。如果你不做任何裁剪把全部历史都塞进去那 token 消耗会随着对话轮次指数级增长。我的做法是三层裁剪第一层是滑动窗口只保留最近 N 轮完整对话第二层是摘要压缩把更早的对话用模型总结成一段简短摘要第三层是结构化提取把关键信息比如用户偏好、任务目标、已完成的步骤抽出来存成独立的状态对象不占用对话历史的 token。具体参数上我一般把滑动窗口设在 10 到 15 轮摘要压缩的触发阈值设在窗口满了之后摘要长度控制在 500 token 以内。结构化提取则是每轮都做但只提取增量信息。这样一套组合拳下来token 消耗能压到不做裁剪时的三分之一左右。注意摘要压缩本身也要消耗 token所以不要每轮都做摘要而是等窗口满了再触发。另外摘要的质量很关键如果摘要丢掉了关键信息Agent 后面就会做出错误决策。我的做法是让模型在摘要时保留“任务目标、已完成步骤、待解决问题”这三个字段其他内容可以压缩。3.2 工具调度层的重试与降级机制工具调用是 Agent 最容易出问题的环节。模型生成的参数格式不对、工具执行超时、返回结果解析失败这些情况几乎每天都会遇到。如果没有一套完善的重试和降级机制你的 Agent 会在各种奇怪的地方卡死。我的做法是把工具调用分成三个层次来处理。第一层是参数校验在真正调用工具之前先用一个轻量的校验函数检查参数是否符合预期格式不符合就直接返回错误让模型重新生成不浪费一次工具调用。第二层是执行重试工具执行失败时根据错误类型决定是否重试。网络超时这类临时错误重试三次每次间隔递增参数错误这类逻辑错误不重试直接把错误信息返回给模型让它修正。第三层是降级处理如果某个工具连续失败就切换到备用方案比如用另一个工具替代或者直接告诉模型“这个工具暂时不可用请用其他方式完成任务”。这套机制写起来代码量不小但它能把 Agent 的成功率从百分之六十多拉到百分之九十以上。那二十万行代码里有相当一部分就是花在这些看似琐碎的容错逻辑上。3.3 Markdown 解析的坑与技巧Markdown 看起来简单但真正写一个健壮的解析器坑非常多。最常见的问题是换行处理。Markdown 里一个换行和两个换行含义完全不同一个换行是软换行渲染时可能被合并成一行两个换行才是新段落。模型生成内容的时候经常搞混导致解析出来的结构跟预期不一致。我的处理方式是在解析之前先做一轮规范化把连续三个以上的换行统一成两个把行尾的空格去掉把制表符统一成四个空格。这一步能解决百分之八十的格式问题。然后是表格解析Markdown 表格的对齐方式、单元格内换行、转义字符这些都要单独处理。我写了一个专门的表格解析模块能把 Markdown 表格转成二维数组也能反向把二维数组转回 Markdown 表格这样在跟 Excel 或者其他表格工具做数据交换的时候就方便很多。还有一个容易被忽略的点是数学符号。Markdown 里的数学公式用美元符号包裹但模型有时候会生成不完整的公式或者把美元符号用在非数学场景。我的做法是在解析时先识别数学块单独处理避免跟普通文本混淆。3.4 Obsidian 集成的关键细节Obsidian 的库本质上就是一个文件夹里面全是 Markdown 文件。Agent 要跟它集成核心就是文件读写和链接解析。但这里面有几个细节需要注意。第一是文件锁。Obsidian 本身在运行的时候会监控文件变化如果 Agent 同时写入文件可能会触发冲突。我的做法是 Agent 写入之前先检查文件是否被占用写入时用原子操作写完再通知 Obsidian 刷新。第二是双向链接解析。Obsidian 的[[链接]]语法需要被解析成实际的图谱关系我在 Agent 里维护了一个链接索引每次文件变化时增量更新这样 Agent 在检索的时候可以顺着链接找到相关笔记。第三是插件通信。如果你想让 Agent 的能力通过 Obsidian 插件暴露出来就需要了解 Obsidian 的插件 API这部分文档不算特别完善很多细节要靠读源码和实际测试。提示Obsidian 的库如果很大几千个文件以上全量扫描会很慢。建议用增量索引的方式只处理变化的文件。另外文件名的编码问题也要注意中文文件名在某些系统上会有兼容性问题建议统一用英文或者拼音命名。4. 实操过程与核心环节实现4.1 从零搭建 Harness 的步骤拆解搭建一个 Harness 应用我建议按这个顺序来不要跳步。第一步是定义状态机。把你的 Agent 要完成的任务拆成状态画出状态转移图。比如一个文档处理 Agent状态可能是接收任务、读取文档、解析结构、生成摘要、写入结果、完成。每个状态定义清楚输入是什么、输出是什么、失败怎么办。这一步不需要写代码用纸笔或者白板画清楚就行但它决定了后面所有代码的结构。第二步是实现上下文管理器。这是 Harness 的地基。先实现最简单的滑动窗口能跑通之后再加摘要压缩和结构化提取。上下文管理器的接口要设计好对外只暴露“添加消息”和“获取上下文”两个方法内部怎么裁剪是它自己的事。第三步是实现工具调度层。先注册一两个简单的工具把调用、重试、降级这条链路跑通。工具的定义用统一的接口每个工具声明自己的名称、参数 schema、执行函数。调度层负责根据模型输出的工具调用请求找到对应工具并执行。第四步是接入模型。把上下文管理器和工具调度层串起来形成一个完整的 Agent 循环。这个循环的逻辑是获取上下文、调用模型、解析模型输出、如果有工具调用就执行、把结果加回上下文、继续循环直到模型输出最终答案。第五步是持久化。把会话状态存到磁盘或者数据库支持断点恢复。这一步很多人会拖到最后才做但我的建议是尽早做因为调试的时候你会需要反复回放某个会话。第六步是集成 Markdown 和 Obsidian。在前面五步都稳定之后再把文档解析和知识库读写加进来。这时候你的 Harness 已经是一个可靠的执行框架了加新能力只是往上面挂模块。4.2 关键参数的计算与选择在 Harness 里有几个参数需要你根据实际情况仔细调。上下文窗口大小。这个取决于你用的模型。假设模型支持 128K token 的上下文你不能把 128K 全用满因为输出也要占空间。我的经验是输入控制在 80K 以内留 48K 给输出和工具返回结果。然后在 80K 里面再按前面说的三层裁剪策略分配。重试次数和间隔。工具调用的重试我一般设三次间隔用指数退避第一次等 1 秒第二次等 2 秒第三次等 4 秒。这个参数不能设太大否则一个任务卡住会拖很久也不能设太小否则临时故障还没恢复就重试完了。摘要触发阈值。滑动窗口满了之后触发摘要窗口大小我设的是 12 轮。也就是说当对话超过 12 轮时把最早的 6 轮压缩成一段摘要保留最近 6 轮完整对话。这个比例可以根据任务复杂度调整任务越复杂保留的完整对话应该越多。并发任务数。如果你的 Harness 要同时处理多个任务需要控制并发数。我一般设 3 到 5 个并发再多的话上下文管理会变得很复杂而且模型 API 也可能有限流。4.3 一次完整的 Agent 执行记录我拿一个实际的任务来演示。任务是读取 Obsidian 库里的一篇笔记提取其中的待办事项生成一个汇总表格写回库里的另一个文件。Agent 接收任务后进入“理解意图”状态。模型分析任务输出一个规划第一步读取源文件第二步解析待办事项第三步生成表格第四步写入目标文件。进入“执行工具”状态。Harness 调用文件读取工具传入源文件路径。工具返回文件内容是一段 Markdown 文本。Harness 把结果加入上下文。模型看到文件内容后输出工具调用请求调用 Markdown 解析工具提取待办事项。Harness 执行解析返回一个列表里面有五条待办事项。模型接着输出调用表格生成工具把这五条待办事项转成 Markdown 表格。Harness 执行返回表格文本。模型最后输出调用文件写入工具把表格写入目标文件。Harness 执行返回成功。模型输出最终答案任务完成共提取五条待办事项。整个过程中Harness 在背后做了这些事每次工具调用前校验参数调用失败时重试把每次的工具结果加入上下文并做裁剪记录每一步的状态以便断点恢复。这些动作用户看不到但它们是任务能顺利完成的关键。5. 常见问题与排查技巧实录5.1 Agent 执行中断的典型原因Agent 跑到一半突然停了这是最常见的问题。根据我的排查经验原因大致分布如下。问题现象可能原因排查方法模型输出为空上下文超长被截断检查 token 计数看是否超过模型限制工具调用报错参数格式不符合 schema打印模型原始输出检查参数结构循环执行同一工具模型陷入死循环设置最大循环次数超过就强制退出结果不符合预期上下文丢失关键信息检查摘要压缩是否丢掉了重要内容执行速度极慢上下文太大导致推理变慢优化裁剪策略减少无效上下文我遇到最多的是上下文超长导致的截断。模型在上下文被截断后会丢失之前的对话历史然后就开始胡言乱语。解决办法是在每次调用模型之前先算一下 token 数如果接近限制就主动触发裁剪而不是等模型报错。5.2 Markdown 解析失败的排查思路Markdown 解析出问题通常表现为表格错位、代码块没闭合、链接解析错误。我的排查步骤是这样的。先看原始文本确认 Markdown 语法本身有没有问题。模型生成的 Markdown 经常有细微的语法错误比如表格分隔行少了一个竖线或者代码块的反引号数量不对。然后看解析器的规范化步骤有没有正确处理有时候是规范化把有用的格式给改坏了。最后看解析器的实现特别是嵌套结构的处理比如列表里面套代码块表格里面套链接这些复杂情况容易出 bug。提示建议在解析器里加一个调试模式把解析过程中的中间结果打印出来这样出问题的时候能快速定位是哪一步错了。5.3 Obsidian 集成的常见坑Obsidian 集成最常遇到的问题有三个。第一是文件路径问题Obsidian 库的路径可能包含空格或者特殊字符在代码里处理的时候要小心转义。第二是文件编码问题虽然 Obsidian 默认用 UTF-8但如果你从其他来源导入的文件用了别的编码读出来就是乱码。第三是插件冲突如果你同时装了多个修改文件内容的插件它们之间可能会打架导致 Agent 写入的内容被覆盖或者修改。我的建议是Agent 操作 Obsidian 库的时候尽量用最简单的文件读写不要依赖插件的功能。如果必须用插件先在测试库里验证确认稳定之后再上生产库。另外定期备份库文件这个习惯能救命。5.4 成本控制的实操技巧四十亿 token 一个月成本不是小数目。控制成本的核心思路是减少无效调用。什么叫无效调用就是模型明明可以直接回答你却让它调了一圈工具或者上下文里塞了大量无关信息模型要花很多 token 去处理这些噪音。我的做法是在 Harness 里加一个预判层。对于简单任务预判层直接判断不需要调工具让模型直接回答。对于复杂任务预判层先做一个粗略的规划估算需要多少轮工具调用如果超过阈值就提醒用户任务可能很复杂。另外定期分析 token 消耗的分布看看哪些环节消耗最多针对性地优化。我分析下来上下文重复传输占了消耗的百分之六十以上优化裁剪策略之后整体成本降了将近一半。6. 这套架构还能怎么扩展Harness 架构搭好之后扩展性其实很强。你可以往里面加新的工具比如接入搜索引擎、接入数据库、接入其他 AI 服务。你也可以加新的 Agent让多个 Agent 协作完成复杂任务。你还可以把 Harness 的能力通过 API 暴露出去让其他应用调用。我自己下一步想尝试的是把 Harness 和代码生成结合起来。用 Claude Code 这类工具做代码生成Harness 负责调度和验证生成完的代码自动跑测试测试不通过就回退重来。这个方向如果跑通对开发效率的提升会非常明显。另外一个小技巧是把 Harness 的执行日志结构化存储然后用另一个 Agent 去分析这些日志找出常见的失败模式和优化点。这相当于让 Agent 自己优化自己虽然听起来有点绕但实际效果不错。我试过用这种方式发现了好几个之前没注意到的性能瓶颈。最后再分享一个我在实际使用中的体会不要追求一次把 Harness 设计得完美。我一开始花了很多时间在设计上结果写出来的代码跟实际需求差很远。后来改成先跑通最小闭环然后根据实际遇到的问题逐步迭代效率反而高很多。那二十万行代码不是一次写出来的是九个月里一天一天长出来的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑