
1. 先搞清楚Harness架构到底在解决什么问题九个月、一个人、20万行代码、每月40亿token的消耗量——这组数字放在任何一个技术社区里都足够扎眼。但比数字更值得聊的是这套东西背后的架构选择Harness。很多人第一次看到这个词会以为是某个新出的开发框架或者脚手架工具其实不是。Harness在这里指的是一种以“执行编排”为核心的Agent应用架构范式它要解决的核心问题只有一个当大模型的能力已经足够强为什么我们还是没法让它稳定地完成一件复杂的事答案在于单次模型调用和真实任务之间隔着一道巨大的鸿沟。你让模型写一个函数它写得很好你让它改一个跨五个文件的bug它就开始丢三落四。Harness架构的本质就是在模型外面套一层“驾驭系统”——把一个大任务拆成可验证的小步骤每一步都有明确的输入、输出、校验规则和回退策略模型只负责它最擅长的那部分推理和生成剩下的调度、状态管理、错误恢复全部由Harness层接管。这跟传统的Agent框架有本质区别。大多数Agent框架的思路是“给模型一堆工具让它自己决定怎么用”结果就是模型在复杂任务里反复横跳、上下文爆炸、执行到一半忘了自己要干什么。Harness的思路反过来先定义清楚任务的执行图再让模型在图的节点上做局部决策。这就像带团队做项目你不会跟新人说“你去把产品做出来”而是说“你先做竞品调研输出一份对比表我确认后你再画原型图”。Harness就是那个把“竞品调研→确认→原型图”这条链路固化下来的项目管理层。那20万行代码花在哪了花在状态机的健壮性、上下文窗口的精细管理、工具调用的错误恢复、多轮对话的记忆压缩、以及大量针对具体场景的适配逻辑上。40亿token的月消耗量绝大部分不是花在“生成代码”上而是花在“让模型理解当前处于执行图的哪个位置、下一步该做什么、上一步的结果是否可信”这些编排决策上。这个比例很反直觉但做过复杂Agent系统的人都会告诉你编排成本远大于生成成本。2. 为什么Markdown成了Harness架构的隐形基础设施翻一下热词列表Markdown相关的词占了将近三分之一markdown换行、markdown语法、markdown表格转换excel、markdown阅读器、markdown preview enhanced、markdown转word工作流……这不是偶然。在Harness架构里Markdown不只是一个文档格式它是人和Agent之间的契约层。2.1 Markdown作为Agent的中间表示Harness架构的核心是执行图而执行图的每个节点都需要一个“任务描述”。这个描述如果用JSON写人读起来痛苦模型理解起来也容易出错如果用自然语言写又太模糊没法做结构化校验。Markdown恰好卡在中间它有足够的结构标题、列表、表格、代码块让机器解析又有足够的可读性让人快速review。我自己的做法是每个Harness节点的定义都写成这样的Markdown块## 节点代码审查 - 输入上一步生成的diff文件路径 - 输出审查意见列表每条包含行号、严重级别、修改建议 - 校验规则严重级别为error的条目必须给出具体修改代码 - 回退策略如果diff文件不存在跳转到“重新生成”节点这种格式的好处是模型在解析时能准确抓住“输入/输出/校验/回退”四个关键字段而人在review时一眼就能看出这个节点的逻辑是否完整。实测下来用Markdown定义节点比用JSON的出错率低一个数量级因为模型在训练数据里见过海量的Markdown结构对标题层级和列表嵌套的理解非常扎实。2.2 换行和表格这些“小问题”为什么成了大坑热词里“markdown换行”和“markdown表格复制”能上榜说明这是真痛点。在Harness架构里Agent生成的Markdown经常要直接喂给下一个节点做解析这时候换行处理不当就会导致解析失败。比如模型生成一个表格如果单元格内容里有换行符标准Markdown解析器会直接把这个表格拆散。我的处理方案是在Harness层加一个预处理步骤所有进入解析器的Markdown先做一次规范化把表格单元格内的换行替换成br把连续空行压缩成单个空行把行尾空格统一清理掉。这个预处理步骤看起来不起眼但它把整个系统的稳定性提升了一个档次。因为Agent生成的内容是不可控的你没法保证它每次都输出完美的Markdown但你可以保证在解析之前把它“洗干净”。这就像做菜之前先把食材切整齐后面炒起来才顺手。2.3 Obsidian在Harness工作流里的位置Obsidian出现在热词里很有意思。它本身是个知识管理工具但在Harness架构的语境下它扮演的是人类可读的执行日志和知识沉淀层。Agent每完成一个节点就把输入、输出、决策理由写成一个Markdown文件按日期和任务ID组织在Obsidian的vault里。这样你随时可以打开Obsidian沿着双向链接回溯整个任务的执行路径。我试过用数据库存这些日志查询确实快但review体验差太远了。在Obsidian里你可以用graph view一眼看出哪些节点经常失败、哪些节点的输出被后续节点频繁引用、哪些任务走了回退路径。这种可视化洞察是纯数据库给不了的。而且Obsidian的本地Markdown文件天然适合做版本控制配合obsidian-git插件每次Agent执行完自动commit出问题随时回滚。3. 40亿token一个月钱到底烧在了哪些环节这个数字第一次看到会觉得夸张但拆开算就合理了。假设你每天运行200个任务每个任务平均经过15个Harness节点每个节点的上下文窗口平均8000token加上系统提示词、工具定义、历史对话压缩后的摘要单次调用的输入token很容易到15000以上。200×15×15000×30这就已经是13.5亿token了。如果再加上失败重试、多轮校验、上下文压缩时的额外调用40亿完全在合理范围内。3.1 上下文压缩是最大的隐形消耗Harness架构里最耗token的不是生成是上下文管理。当一个任务执行到第10个节点时前面9个节点的完整对话历史可能有几万token直接塞给模型既贵又容易让模型迷失重点。所以必须做压缩把历史对话总结成一段简短的“当前状态摘要”只保留与当前节点相关的信息。这个压缩过程本身就要调用模型。我的做法是用一个专门的“压缩节点”它的提示词是这样的你是一个上下文压缩器。请将以下对话历史压缩成不超过500字的摘要必须保留 1. 已完成节点的输出结论 2. 当前任务的全局状态哪些文件被修改、哪些决策已确认 3. 未解决的待办事项 不要保留中间过程的试错、重复的确认对话、与当前节点无关的讨论。这个压缩节点每次消耗大约3000-5000token但能把后续节点的输入从30000token降到8000token。算总账是划算的但如果你不做压缩或者压缩策略太保守保留太多细节token消耗会指数级上升。3.2 校验和回退的token成本Harness架构的另一个token大户是校验环节。每个节点的输出都要经过校验校验不通过就要回退重做。校验本身可以用规则做比如检查文件是否存在、代码是否能编译但很多语义层面的校验必须用模型。比如“这段代码是否符合项目的命名规范”“这个API调用是否与文档一致”这些只能让模型来判断。我的经验是校验节点的提示词要尽可能短而精确不要让它做开放式判断。比如不要问“这段代码写得好不好”而要问“这段代码是否满足以下三条规则1. 函数名以动词开头 2. 没有超过50行的函数 3. 所有公共方法都有docstring”。前者会让模型输出一大段模棱两可的评价后者只需要它输出“是/否”加具体违规行号。校验提示词越具体token消耗越低结果也越稳定。3.3 哪些token花得值哪些是浪费跑了九个月之后我总结出一个判断标准如果一个token的消耗能减少后续至少两个节点的试错它就值得花。比如在任务开始时花500token让模型生成一个详细的执行计划看起来是额外开销但它能让后续每个节点少走一次弯路整体算下来是省的。反过来如果某个校验节点只是重复确认“文件已存在”这种规则引擎就能判断的事那就是纯浪费。具体来说值得花的token包括任务规划、上下文压缩、语义校验、错误诊断。不值得花的包括重复确认已知状态、让模型做确定性计算、在提示词里塞大量无关的示例。我见过有人在系统提示词里放了20个few-shot示例每个示例500token结果每次调用光系统提示词就10000token。其实对于Harness这种结构化任务3个精准的示例就够了模型对格式的理解能力比我们想象的要强。4. 一个人维护20万行代码的工程实践20万行代码一个人写听起来像天方夜谭但如果这20万里有相当一部分是配置、提示词模板、测试用例和文档那就合理了。真正的核心逻辑可能只有3-5万行剩下的都是围绕核心逻辑的“外围工程”。这部分我想聊聊一个人怎么把这么大的代码库管住。4.1 目录结构就是架构文档我的项目根目录长这样harness/ ├── nodes/ # 每个Harness节点一个目录 │ ├── plan/ │ │ ├── prompt.md │ │ ├── schema.json │ │ ├── validator.py │ │ └── test_cases/ │ ├── execute/ │ └── verify/ ├── flows/ # 执行图定义用YAML描述节点连接 ├── shared/ # 共享工具上下文压缩、token计数、日志 ├── adapters/ # 对接不同模型API的适配层 └── vault/ # Obsidian vault执行日志和知识沉淀这个结构的好处是每个节点的所有相关文件都在一起。你要改“代码审查”节点的提示词直接进nodes/verify/prompt.md不用在多个目录之间跳。而且每个节点目录下的test_cases/里放着这个节点的回归测试用例改完提示词跑一遍测试就知道有没有破坏原有行为。4.2 提示词也要做版本控制和回归测试很多人把提示词当代码写但不做版本控制改完直接上线出了问题都不知道是哪个版本。我的做法是每个提示词文件头部都有一个版本号和变更记录!-- version: 2.3.1 -- !-- changelog: 2.3.1 - 增加对空输入的处理 2.3.0 - 调整输出格式从自由文本改为JSON 2.2.0 - 初始版本 --每次改提示词必须同时更新版本号和changelog并且跑一遍该节点的测试用例。测试用例就是一组输入和期望输出的配对用Python脚本自动跑对比实际输出和期望输出的差异。如果差异在可接受范围内比如只是措辞不同但语义一致就通过如果语义变了就要人工review。这套机制听起来重但它是一个人维护大代码库的唯一办法。你没有团队帮你review只能靠自动化测试来兜底。我踩过的坑是有一次改了一个压缩节点的提示词忘了跑测试结果上线后所有任务的上下文压缩都多保留了30%的内容token消耗直接涨了20%。后来加了CI钩子改提示词必须跑测试才能提交。4.3 用Obsidian做“第二大脑”管理项目知识20万行代码的项目最大的风险不是代码写不出来是你忘了自己三个月前为什么做了某个决策。比如为什么校验节点要用两次模型调用而不是一次为什么上下文压缩的阈值设成8000而不是12000这些决策当时都有理由但三个月后你完全想不起来。我的解决方案是每个重要决策都在Obsidian里写一条笔记格式固定## 决策上下文压缩阈值设为8000token - 日期2024-XX-XX - 背景发现压缩后上下文超过8000时模型开始忽略中间部分的信息 - 备选方案12000token成本更低但准确率下降15% - 最终选择8000token - 验证方式在50个历史任务上回测8000token的节点通过率比12000高22% - 相关文件shared/context_compressor.py这些笔记通过双向链接和代码文件关联起来。当我在代码里看到COMPRESSION_THRESHOLD 8000时旁边就有一个链接指向这条决策笔记。这种“代码-决策”的双向追溯是一个人维护复杂系统的救命稻草。5. 从Claude Code到自建Harness的迁移路径热词里Claude Code出现频率很高很多人是从Claude Code开始接触Agent开发的。Claude Code确实是个很好的起点它把“模型工具执行循环”这套东西封装得很易用。但当你需要更复杂的编排逻辑时就会遇到它的边界。5.1 Claude Code适合什么不适合什么Claude Code适合的场景很明确单文件或小范围的代码修改、问答式的代码理解、简单的重构。它的执行循环是“模型决定调用什么工具→执行→把结果喂回模型→继续”这个循环在任务简单时很高效但任务一复杂就会失控。比如你让它“重构整个项目的错误处理逻辑”它会开始到处改文件改到一半上下文满了它就开始忘事最后给你一个半成品。Harness架构正是为了解决这个“复杂任务失控”问题而生的。它把大任务拆成小节点每个节点有明确的边界和校验模型不需要记住整个任务只需要在当前节点做好局部决策。这就像从“一个人包揽整个项目”变成“流水线作业”每个工位只做一件事做完就传给下一个工位。5.2 迁移的核心工作把执行循环拆成执行图从Claude Code迁移到自建Harness核心工作是把原来那个“模型自主决定下一步”的循环拆解成一张预定义的执行图。具体步骤识别任务类型把你经常用Claude Code做的任务分类比如“bug修复”“功能开发”“代码审查”“文档生成”。为每类任务画执行图以bug修复为例执行图可能是“复现bug→定位根因→生成修复→运行测试→代码审查→提交”。定义每个节点的输入输出复现bug节点的输入是bug描述输出是一个能稳定复现的测试用例定位根因节点的输入是测试用例输出是根因分析报告。实现节点间的状态传递每个节点的输出要结构化存储供后续节点读取。我用的是Markdown文件加YAML frontmatter既能人读也能机读。加校验和回退每个节点执行完后自动校验不通过就回退到上一个节点或触发修复流程。这个迁移过程不是一蹴而就的我的做法是先从最痛的任务开始。哪个任务用Claude Code最经常翻车就先把它Harness化。跑通一个再复制到其他任务。九个月下来我大概Harness化了15类常见任务覆盖了日常开发80%的场景。5.3 模型选择不要绑定单一供应商热词里有deepseek harness、claude code、pi agent等多个模型相关的词这反映了一个现实没有哪个模型在所有任务上都最好。我的Harness架构里有一个adapters层专门做模型适配。每个节点可以指定用哪个模型比如规划节点用推理能力强的代码生成节点用代码训练数据多的校验节点用便宜且快的。这种多模型策略的好处是你可以根据任务特点灵活选择而且当某个模型服务不稳定时可以快速切换到备用模型。代价是adapters层的维护成本每个模型API的输入输出格式、token计数方式、错误码都不一样要写不少适配代码。但相比被单一供应商绑死这个成本是值得的。6. 那些只有踩过才知道的坑6.1 上下文压缩过度导致“失忆”最开始做上下文压缩时我为了省token把压缩比设得很激进结果模型经常在后续节点里问“我们刚才做了什么”。后来我加了一个“关键信息白名单”规定某些信息在任何情况下都不能被压缩掉比如已修改的文件列表、已确认的接口定义、用户的明确指令。这个白名单机制把压缩导致的“失忆”问题降低了90%。6.2 节点粒度过细反而降低效率一开始我把节点拆得很细一个“生成代码”拆成“分析需求→设计接口→写实现→写测试”四个节点。结果发现节点间传递状态的token消耗比生成代码本身还高。后来我合并了一些节点把“设计接口”和“写实现”合成一个节点因为这两个步骤在模型内部是连续推理的强行拆开反而打断了它的思路。节点粒度应该以“模型能否在一次推理中完成”为标准而不是以人类工程步骤为标准。6.3 错误恢复不能只靠重试Harness架构里最复杂的就是错误恢复。模型调用失败、输出格式不对、校验不通过、工具执行超时……每种错误都需要不同的恢复策略。我一开始统一用“重试三次”结果发现有些错误重试一百次也没用比如输入本身就有问题有些错误重试一次就能过比如网络抖动。后来我做了错误分类错误类型恢复策略重试上限网络超时指数退避重试5次输出格式错误追加格式修正提示后重试2次校验不通过回退到上一节点重新生成1次输入缺失触发上游节点补全不重试模型拒绝回答换模型重试2次这个分类表是九个月里逐步完善出来的每遇到一种新错误就加一行。现在它是我Harness架构里最有价值的部分之一。6.4 Obsidian vault的同步冲突用Obsidian做执行日志有个坑Agent写入日志的频率很高如果你同时在Obsidian里手动编辑笔记很容易产生同步冲突。我的解决方案是Agent只写入vault/auto/目录这个目录下的文件不允许手动编辑我自己的笔记写在vault/manual/目录两个目录通过Obsidian的dataview插件做关联展示。这样既保留了自动日志的完整性又不影响手动笔记的灵活性。7. 如果你也想走这条路我的几点实在建议先别急着写代码。花一周时间把你日常工作中最重复、最耗时、最容易出错的任务列出来挑一个最痛的用纸笔画出它的执行图。画图的过程中你会发现自己对任务的理解其实很模糊很多步骤你以为是连续的其实中间有隐藏的决策点。把这些决策点标出来它们就是未来Harness节点的雏形。然后不要一上来就追求全自动。先做“半自动Harness”每个节点执行完后暂停等你确认再继续。这样你能观察到模型在每个节点的真实表现知道哪里容易出错、哪里需要加校验。等某个节点的通过率稳定在95%以上再把它设为自动通过。我的系统跑了三个月才实现全自动前三个月都是半自动模式在积累数据。最后token消耗要监控但不要过度优化。我见过有人为了省token把提示词压缩到极致结果模型理解不了反而要更多轮重试。省token的正确方式是减少无效调用而不是压缩有效信息。一个节点如果一次就能做对哪怕它消耗10000token也比一个消耗2000token但要做五次的节点划算。这套东西说到底核心不是技术是对任务的拆解能力和对模型行为的理解。模型在变强但“让模型稳定完成复杂任务”这件事永远需要一层精心设计的驾驭系统。Harness就是这层系统的一种实现方式它不完美但九个月跑下来它确实让我一个人干出了一个团队的活。