1. 先搞清楚这个项目到底在做什么
一个人,九个月,二十万行代码,每个月消耗四十亿以上的 token,最终交付一个基于 Harness 架构的应用。这组数字第一次看到的时候,我的反应和大多数人一样——先怀疑,再好奇,最后是那种"这到底是怎么堆出来的"的困惑。二十万行代码放在传统软件工程里,一个成熟团队干九个月也就这个量级,而这里只有一个人。四十亿 token 的月消耗量,按主流大模型的计费口径折算,哪怕走的是最便宜的批量通道,每个月的账单也是四位数美元起步,如果用的是高价位模型,五位数都打不住。
所以这个项目的核心看点根本不是"一个人写了多少代码",而是这个人把 AI Agent 当成了一个可编排、可复用、可观测的工程系统来用,而不是当成一个聊天框。Harness 这个词在这里不是某个具体产品的名字,它指的是一整套"驾驭层"——把模型、工具、上下文、记忆、校验、回滚这些环节串成一条稳定的流水线,让 Agent 在受控的轨道上跑,而不是每次对话都从零开始即兴发挥。
我把它拆成三个层次来理解。最底层是模型调用层,负责和 Claude Code、DeepSeek 这类能力对接,处理 token 预算、重试、限流。中间层是Harness 编排层,也就是这个项目的灵魂,管的是任务分解、上下文注入、工具路由、结果校验。最上层是知识与应用层,用 Markdown 作为统一的中间表示,把 Obsidian 当成本地知识库和项目管理台账,让 Agent 产出的内容能沉淀下来、能被检索、能被下一轮任务复用。
这套东西解决的是什么问题?说白了就是AI 写代码"不可控"的问题。你让一个 Agent 直接改一个十万行的仓库,它大概率会改崩,因为它没有全局视野,也没有自我校验机制。Harness 架构要做的就是给 Agent 装上"护栏"和"仪表盘":护栏保证它不跑偏,仪表盘让你随时知道它跑到哪了、烧了多少钱、哪一步出了问题。
适合谁来参考?三类人。第一类是独立开发者,想用 AI 把个人产能放大到小团队的水平。第二类是AI Agent 方向的工程师,正在做 Agent 框架、工具调用、上下文管理这些事。第三类是重度知识工作者,比如做研究、写长文档、管理复杂项目的人,Obsidian 加 Markdown 加 Agent 这套组合对他们同样适用。哪怕你完全不写代码,理解这套"驾驭"思路,也能把 AI 用得更稳。
下面我按实际搭建的顺序,把这套 Harness 架构从设计思路到落地细节完整拆一遍。里面有些是我自己踩过的坑,有些是基于这个项目量级反推出来的合理工程实践,我会明确标注哪些是推测、哪些是通用做法。
2. Harness 架构的整体设计与选型逻辑
2.1 为什么是 Harness,而不是直接裸用 Agent
裸用 Agent 的典型场景是这样的:打开 Claude Code 或者某个 Agent 工具,输入一句"帮我实现这个功能",然后等它吐代码。小任务没问题,一旦任务跨多个文件、涉及重构、需要保持架构一致性,问题就来了。Agent 会遗忘早期约定,会重复造轮子,会在某个文件里用 A 方案、另一个文件里用 B 方案,最后你得到一堆能跑但没法维护的代码。
Harness 的本质是把"一次性对话"变成"可重复执行的流水线"。它做的事情包括:把大任务拆成有依赖关系的小任务;给每个小任务准备刚好够用的上下文,而不是把整个仓库塞进去;在 Agent 产出后自动跑校验(编译、测试、lint);校验失败就把错误信息回灌给 Agent 让它重试;重试超过阈值就停下来等人介入。
这个项目九个月能堆出二十万行,靠的就是这条流水线的吞吐量。人不需要盯着每一步,只需要在关键节点做决策。四十亿 token 的月消耗,反过来印证了这条流水线一直在满负荷运转——token 不是被浪费在闲聊上,而是被消耗在大量的生成、校验、重试循环里。
2.2 技术选型背后的取舍
选 Claude Code 作为主力 Agent 执行器,逻辑很直接:它在代码理解和多文件编辑上的稳定性,目前是同类工具里比较靠前的。但它的订阅访问有组织策略限制,很多人会遇到"your organization has disabled claude subscription access"这类提示,所以项目里大概率做了多模型兜底——主力用 Claude Code,备用接 DeepSeek 或者本地模型(比如通过 LM Studio 暴露的接口)。这样做的代价是要抽象一层统一的模型调用接口,好处是任何一家出问题都不至于让整条流水线停摆。
用 Markdown 作为统一中间表示,是个被很多人低估的决定。Markdown 的好处是人和机器都能读。Agent 产出的任务清单、设计决策、变更记录,全部写成 Markdown 文件,人可以直接在 Obsidian 里看,Agent 下一轮也能直接读回来当上下文。相比 JSON 或数据库,Markdown 的容错性高得多——格式稍微乱一点不影响理解,而 JSON 少个逗号就全废。
Obsidian 在这里扮演的是本地知识库加项目管理台账的双重角色。它的双向链接能把"任务—文件—决策—问题"串成一张网,Dataview 插件可以基于 frontmatter 自动生成任务看板。把 Zotero 的笔记导入 Obsidian 也是常见操作,做研究类项目时,文献笔记和代码任务放在同一个库里,Agent 检索上下文时能一并拿到。
2.3 目录结构设计
一个能撑住二十万行代码的 Harness 项目,目录结构必须清晰到 Agent 能靠路径就判断出文件用途。我推测的结构大致是这样:
project/ ├── harness/ # 驾驭层核心 │ ├── orchestrator/ # 任务编排 │ ├── context/ # 上下文构建 │ ├── validators/ # 校验器 │ └── adapters/ # 模型适配器 ├── tasks/ # 任务定义(Markdown) │ ├── backlog/ │ ├── active/ │ └── done/ ├── knowledge/ # Obsidian 知识库 │ ├── decisions/ # 架构决策记录 │ ├── notes/ # 研究笔记 │ └── templates/ ├── src/ # 实际代码 └── logs/ # 运行日志与 token 统计关键点是任务用 Markdown 定义,每个任务文件带 frontmatter,写明依赖、预估复杂度、涉及文件、验收标准。编排器读这些文件决定执行顺序,执行完把状态从 active 移到 done。这套东西看起来朴素,但它让"项目进度"变成了文件系统状态,人和 Agent 用的是同一份真相。
提示:任务文件一定要写"验收标准",而且要写成可自动校验的形式。比如"函数 X 对输入 Y 返回 Z"比"实现功能 X"有用一百倍,因为前者能直接转成测试用例。
3. 核心细节解析与实操要点
3.1 上下文构建:token 花在哪,怎么省
四十亿 token 一个月,平均到每天是一亿三千万左右。这个量级下,上下文构建策略直接决定成本。如果每个任务都把整个仓库塞进 prompt,token 消耗会爆炸,而且模型注意力会被稀释,效果反而更差。
合理的做法是分层检索。第一层是任务文件本身,包含任务描述和验收标准。第二层是任务显式声明的相关文件,Agent 自己判断需要哪些。第三层是知识库检索,用关键词或向量相似度从 Obsidian 库里捞出相关的决策记录和历史笔记。第四层才是必要的全局信息,比如项目约定、代码风格规范,这部分可以做成固定前缀缓存起来。
Claude Code 这类工具支持 prompt caching,固定不变的前缀部分缓存后,重复调用时这部分 token 按更低价计费。把项目规范、常用工具定义、代码风格约定放进缓存前缀,能省下相当可观的开销。我实测下来,一个稳定的前缀缓存能让整体成本降三到四成。
3.2 Markdown 作为中间表示的实操细节
Markdown 用起来爽,但有几个坑必须提前处理。换行是最经典的:标准 Markdown 里单个换行不产生新段落,要空一行才行。Agent 生成的内容经常忘记这点,导致渲染出来挤成一团。解决办法是在 Harness 里加一个后处理步骤,统一规范化换行。
表格转换也是高频需求。Agent 经常产出 Markdown 表格,但你要把它导进 Excel 或者数据库时就得转换。项目里大概率有个转换脚本,把 Markdown 表格解析成 CSV 或直接写库。反过来,从数据生成 Markdown 表格也是常见操作,尤其是生成任务看板的时候。
数学公式要小心。Markdown 本身不认数学符号,得靠插件(比如 Obsidian 的 MathJax 支持)。如果 Agent 产出的内容里有公式,要确保用$...$或$$...$$包裹,否则渲染出来就是一堆乱码。做技术文档时这个问题特别突出。
frontmatter是 Markdown 文件承载结构化数据的关键。每个任务文件顶部的 YAML 块里写清楚 id、status、deps、files、estimate 这些字段,Dataview 就能自动生成各种视图。这是把 Obsidian 变成项目管理台账的核心技巧。
3.3 校验器设计:让 Agent 自己发现错误
Harness 架构里最值钱的部分不是生成,是校验。Agent 生成代码后,自动跑这几类检查:
- 语法与编译检查:语言自带的编译器或解析器,最快最便宜。
- 静态分析:lint、类型检查,能抓出大量低级错误。
- 单元测试:针对任务验收标准生成的测试,这是最关键的。
- 集成测试:跨模块的检查,频率可以低一些。
- 一致性检查:对比项目规范,比如命名风格、目录约定。
校验失败时,把具体的错误信息(不是笼统的"失败了")回灌给 Agent,让它针对性修复。这里有个技巧:错误信息要截断到关键部分,不要把几千行堆栈全塞回去,否则又浪费 token 又干扰判断。
注意:校验器本身也要有超时和资源限制。我见过测试跑飞了把机器拖垮的情况,尤其是 Agent 生成的测试里带了死循环或者无限递归。
3.4 重试与熔断机制
Agent 不是万能的,有些任务它反复试都做不对。这时候必须有熔断:同一个任务重试超过 N 次(我一般设 3 次),就标记为 blocked,写清楚失败原因,等人介入。没有熔断的流水线会陷入"生成—失败—重试—再失败"的死循环,token 烧得飞快还不出活。
重试时还要变换策略。第一次失败可能是上下文不够,第二次就补充相关文件;第二次还失败可能是任务拆得不够细,第三次就尝试自动拆分。每次重试都带上前一次的失败信息,让 Agent 知道"这条路走不通"。
4. 实操过程与核心环节实现
4.1 环境搭建与工具链配置
先把基础环境搭起来。核心工具是 Claude Code,安装方式按官方文档走,装完后要配置好模型访问。如果遇到订阅访问限制,就切到备用方案——通过 LM Studio 起一个本地模型服务,或者接 DeepSeek 的接口。Harness 的适配器层要能同时对接这几家,配置写成文件,切换时改配置不改代码。
Obsidian 这边,装好之后重点配几个插件:Dataview 做动态视图,Templater 做任务模板,还有 Markdown 相关的格式化插件。把知识库目录和项目目录放在同一个 vault 里,这样 Agent 读写文件和你在 Obsidian 里看的是同一份。
VSCode 里配好 Claude Code 的集成,方便在编辑器里直接触发任务。如果用的是其他编辑器,至少要保证能方便地查看和编辑 Markdown 任务文件。
4.2 任务定义与编排流程
一个完整的任务生命周期是这样的:
- 写任务文件:在
tasks/backlog/下新建 Markdown,填好 frontmatter 和正文。正文里写清楚目标、验收标准、涉及文件、参考知识库条目。 - 编排器扫描:定时或手动触发,扫描 backlog,按依赖关系排序,把可执行的任务移到 active。
- 构建上下文:对每个 active 任务,按分层策略组装 prompt。
- 调用 Agent:通过适配器发给模型,记录 token 消耗。
- 执行产出:Agent 返回的代码或文档写入对应位置。
- 跑校验:依次执行语法、静态、测试检查。
- 处理结果:通过就移到 done 并更新知识库;失败就回灌错误重试;超限就标记 blocked。
- 记录日志:token 消耗、耗时、重试次数全部落盘,方便后续分析。
这套流程跑顺了之后,你每天的工作就变成:早上看 blocked 列表处理卡住的任务,白天写新任务文件,晚上看 token 报表。真正的手工编码量大幅下降,更多精力花在定义问题和验收结果上。
4.3 token 消耗的监控与优化
四十亿 token 一个月,必须监控。日志里要记录每次调用的输入 token、输出 token、缓存命中情况、耗时、任务 id。基于这些数据做几个报表:
| 指标 | 用途 | 优化方向 |
|---|---|---|
| 单任务平均 token | 发现异常任务 | 拆分过大的任务 |
| 缓存命中率 | 评估前缀缓存效果 | 扩大稳定前缀 |
| 重试率 | 评估任务质量 | 改进任务描述 |
| 输出/输入比 | 判断是否上下文过载 | 精简上下文 |
| 单任务耗时 | 发现性能瓶颈 | 并行化 |
我自己的经验是,重试率是最值得盯的指标。重试率高的任务类型,往往说明任务描述方式有问题,改描述比改代码收益大得多。另外,输出 token 通常比输入贵,如果发现某个任务输出特别多,可能是 Agent 在啰嗦,可以在 prompt 里加"只输出代码,不要解释"这类约束。
4.4 知识库的沉淀与复用
九个月下来,知识库里积累的决策记录和笔记,本身就是巨大的资产。关键是让 Agent 能检索到。做法是给每个知识库文件打好标签和 frontmatter,检索时按标签过滤加关键词匹配。规模大了之后可以上向量检索,但小规模下关键词加标签就够了,别过度工程。
一个实用技巧:每次任务完成后,让 Agent 自动生成一条变更摘要写进知识库,包含改了什么、为什么改、有什么坑。下次遇到相关任务时,这条摘要就是最好的上下文。这相当于给项目建了一个自动维护的"记忆"。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
| 问题现象 | 可能原因 | 排查与解决 |
|---|---|---|
| Agent 反复改同一个文件改不对 | 上下文缺失或任务描述模糊 | 补充相关文件,细化验收标准 |
| token 消耗突然飙升 | 某任务陷入重试循环 | 检查熔断是否生效,看日志找异常任务 |
| 生成的 Markdown 渲染错乱 | 换行或公式格式问题 | 加后处理规范化步骤 |
| 插件加载失败 | 版本不兼容或配置错误 | 检查插件版本,看控制台报错 |
| 本地模型响应慢 | 硬件资源不足 | 降低并发,或换更小的模型 |
| 任务依赖死锁 | 依赖关系成环 | 编排器加环检测 |
| 校验误报 | 测试本身有问题 | 人工复核测试用例 |
| 知识库检索不到相关内容 | 标签或关键词缺失 | 补 frontmatter,统一标签体系 |
5.2 几个踩过的坑
坑一:任务拆得太粗。一开始我总想一个任务搞定一个功能模块,结果 Agent 每次都做一半就崩。后来改成"一个任务只改一个文件的一个函数",成功率立刻上去了。任务粒度是 Harness 架构里最需要反复调参的东西。
坑二:忽略缓存前缀的稳定性。有段时间我老改项目规范文件,导致缓存频繁失效,成本居高不下。后来把规范文件冻结,只在版本升级时改,缓存命中率稳定在八成以上。
坑三:校验器太严。早期我把 lint 规则开到最严,Agent 生成的代码十有八九过不了,全卡在格式问题上。后来把格式类检查降级为警告,只把逻辑和测试作为硬性门槛,吞吐量明显提升。
坑四:没有及时清理 blocked 任务。blocked 列表堆了几十个之后,整个看板就没法看了。现在养成习惯,每天固定时间处理 blocked,要么修任务描述重试,要么直接关掉。
5.3 并发与稳定性
Agent 任务天然适合并发,但并发不是越高越好。模型接口有速率限制,本地模型有显存限制,文件系统有写入冲突。我的做法是按资源类型分别限流:模型调用限制并发数,文件写入加锁,校验任务排队执行。这样虽然单任务延迟没降,但整体吞吐稳定,不会因为某个环节过载导致全线崩溃。
还有一个容易被忽略的点:Agent 沙盒的更新。有些工具会提示"显示更新 agent 沙盒",这通常意味着执行环境有变化,要确认新环境里依赖是否齐全,否则任务会莫名其妙失败。
6. 这套架构还能怎么扩展
跑通基础流程之后,有几个方向值得继续投入。一是多 Agent 协作,让一个 Agent 负责写、一个负责审,互相挑刺,质量能再上一个台阶。二是自动化任务生成,从代码的 TODO 注释、issue 列表、知识库里的待办自动生成任务文件,减少手工录入。三是跨项目复用,把 Harness 层抽成独立工具,换个项目直接接上,知识库也可以按领域拆分复用。
我个人在实际操作中的体会是,这套东西的价值不在某个单点技术,而在把 AI 的能力约束在一条可观测、可回滚、可积累的轨道上。二十万行代码和四十亿 token 只是结果,真正难的是那条轨道本身。轨道修好了,产出是自然发生的;轨道没修好,烧再多 token 也是一地鸡毛。最后分享一个小技巧:每周花半小时看一遍 token 报表和 blocked 列表,比任何优化都管用,因为问题往往就藏在那几个反复出现的任务类型里。