news 2026/10/2 19:38:40

Harness架构实战:一个人九个月20万行代码的工业级Agent工程之道

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Harness架构实战:一个人九个月20万行代码的工业级Agent工程之道

1. 先搞清楚这个项目到底在造什么

一个人、九个月、20万行代码、每月40亿+ token的消耗量——这几个数字摆在一起,任何一个写过代码的人都会先愣一下。20万行代码如果按常规业务系统来算,大概是一个十人团队干一年半的产出;而每月40亿token的调用量,意味着这套系统几乎每时每刻都在和模型对话,不是那种"用户点一下才调一次"的轻量应用,而是一个持续运转、自主决策的Agent系统。

这个项目的核心关键词是Harness架构。如果你最近在Agent开发圈子里泡过,应该对这个词不陌生——它指的是一种"把模型当作被约束的执行单元,用外部框架去驱动、校验、纠偏"的工程范式。和早期那种"给模型一个prompt让它自己跑"的裸奔式Agent不同,Harness强调的是框架层对模型行为的强约束:模型负责生成,框架负责判断、重试、回滚、记录、编排。模型是发动机,Harness是底盘、变速箱和刹车。

那这套东西到底解决什么问题?简单说,就是让AI Agent从"玩具"变成"能干活的工具"。裸奔式Agent最大的毛病是:跑三步就开始飘,上下文一长就忘事,遇到工具调用失败就卡死,产出质量全凭运气。而Harness架构要做的,是把这些不确定性用工程手段兜住——用状态机管理流程、用校验器卡住输出、用重试机制处理失败、用持久化存储对抗上下文丢失。

这个项目适合谁来参考?三类人:一是正在做Agent产品但被稳定性折磨的开发者;二是想理解"工业级Agent"和"Demo级Agent"差距在哪的技术负责人;三是对Harness工程之道感兴趣、想看看真实项目里这套理念怎么落地的人。下面我会从架构设计、token消耗的真相、Markdown与Obsidian的集成、以及踩过的坑这几个角度,把这个项目拆开讲。

2. Harness架构的核心:把模型关进笼子里干活

2.1 为什么裸奔式Agent一定会崩

先说一个我自己的观察:几乎所有Agent项目在Demo阶段都很惊艳,一到真实场景就拉胯。原因不复杂——Demo阶段的输入是精心设计的,模型只要走对一次就行;真实场景的输入是脏的、长的、带歧义的,模型走错一步,后面全盘皆输。

裸奔式Agent的典型结构是:一个system prompt + 一堆工具定义 + 一个while循环。模型输出工具调用,框架执行,把结果塞回上下文,再让模型继续。这个结构在3-5步的短任务里能跑,一旦任务超过10步,问题就来了:

  • 上下文爆炸:每一步的工具返回都塞进历史,几千token的任务很快变成几万token,模型开始"忘记"最早的目标。
  • 错误累积:第3步调用失败,模型可能在第4步基于错误结果继续推理,越走越偏。
  • 状态丢失:进程一重启,整个任务状态归零,用户得从头再来。
  • 无法审计:出了错你根本不知道是哪一步、哪个决策导致的,只能看一堆日志猜。

Harness架构的本质,就是针对这四个问题各下一刀。

2.2 Harness的四层结构拆解

这个项目里,Harness被拆成了四层,我按自己的理解重新梳理一下:

第一层是编排层(Orchestration)。这一层管的是"任务怎么走"。它不关心模型说什么,只关心当前处于哪个状态、下一步该触发什么动作。实现上通常是一个显式的状态机,每个状态对应一个明确的输入输出契约。比如"解析需求"状态只接受用户原始输入,输出必须是结构化的任务列表;"执行子任务"状态接受单个任务,输出必须是执行结果或失败原因。状态之间的转移由代码控制,不由模型自由发挥。

第二层是约束层(Constraint)。这一层管的是"模型能说什么"。每个状态对模型的输出格式都有硬性要求,比如必须是合法JSON、必须包含特定字段、字段值必须在枚举范围内。模型输出后,框架先校验,不合格就打回重试,重试N次还不行就降级或报错。这一层是Harness和裸奔式Agent最大的区别——模型没有"随便说"的自由。

第三层是记忆层(Memory)。这一层管的是"什么该记住"。不是所有历史都值得塞回上下文,Harness会做主动的记忆管理:把已完成子任务的详细过程压缩成摘要,只保留结论;把关键决策点单独存成结构化记录;把工具调用的原始返回存到外部存储,需要时再按需检索。这样上下文长度就能控制在可控范围内,而不是线性膨胀。

第四层是执行层(Execution)。这一层管的是"工具怎么调"。包括工具注册、参数校验、超时控制、失败重试、结果归一化。工具调用失败不是简单地把错误信息塞回给模型,而是先判断失败类型:网络超时可以自动重试,参数错误要返回明确的修正提示,权限问题直接终止任务。这些判断逻辑都在框架层,不依赖模型自己"想明白"。

2.3 状态机设计里最容易踩的坑

状态机听起来简单,实际设计时坑很多。我踩过最深的一个是状态粒度过细。一开始我把每个小动作都设成一个状态,结果状态图变成了蜘蛛网,转移条件复杂到没法维护,而且模型在每个状态之间切换时都要重新理解上下文,token消耗反而更高。

后来调整成"粗粒度状态 + 状态内子步骤"的结构:状态数量控制在10个以内,每个状态内部允许模型做多步推理,但状态的进入和退出有严格契约。这样既保证了流程可控,又给了模型足够的发挥空间。

另一个坑是状态转移的触发条件。如果完全由模型决定"我完成了,可以进入下一状态",那模型很容易过早宣布完成。正确做法是让框架来判断:比如"执行子任务"状态的退出条件是"所有子任务都有明确的成功或失败标记",这个判断由代码做,模型只负责产出结果。

3. 每月40亿token到底烧在哪了

3.1 token消耗的构成拆解

40亿token一个月,平均每天1.3亿,按24小时算每秒1500token左右。这个量级听起来吓人,但拆开看就合理了。我根据这类系统的常见消耗结构估算一下:

消耗项占比估算说明
系统提示词15%-20%每次调用都要带,长系统提示词是隐形杀手
历史上下文30%-40%多轮对话累积,是最大的变量
工具返回结果20%-25%文件内容、搜索结果、API返回
模型生成15%-20%实际输出的token
重试与校验5%-10%格式不合格打回重试的额外消耗

看到没,真正"有用"的模型生成只占15%-20%,剩下80%都是上下文和框架开销。这就是Harness架构必须解决的核心成本问题——不是让模型少说话,而是让框架少塞东西。

3.2 上下文压缩的三种实战策略

这个项目里用了三种压缩策略,我按效果从高到低排:

第一种是摘要替换。当一个子任务完成后,把整个过程(可能几千token)压缩成一段200字以内的结论,原始过程存到外部。这样历史上下文里只留结论,需要细节时再检索。实测这一招能砍掉40%左右的历史token。

第二种是结构化裁剪。工具返回的原始结果往往包含大量冗余(比如一个JSON里只有两个字段有用),框架在塞回上下文前先做字段提取,只保留相关部分。这一招对文件读取类工具效果特别明显,一个1000行的文件读进来,可能只需要其中50行。

第三种是滑动窗口 + 关键锚点。不是简单丢弃最早的历史,而是保留"关键决策点"(比如用户的核心需求、已经确认的方案),丢弃中间的探索过程。实现上需要给每条消息打标记,标记为"锚点"的永不丢弃,其他的按窗口滑动。

提示:压缩策略一定要可配置、可回滚。我一开始把压缩做得太激进,结果模型丢失了关键上下文,产出质量断崖式下跌。后来改成"压缩后如果校验不通过,自动回退到未压缩版本重试",稳定性才上来。

3.3 系统提示词的瘦身经验

系统提示词是每次调用都要带的固定开销,一个5000token的系统提示词,调用100万次就是50亿token。这个项目里系统提示词被压到了1500token以内,做法是:

  • 把"通用行为规范"和"当前任务指令"分离,通用部分尽量短,任务部分动态注入。
  • 用结构化格式(JSON schema)代替自然语言描述工具,模型理解成本更低,token也更少。
  • 把示例从系统提示词里挪到few-shot消息里,只在需要时注入。

这里有个反直觉的点:系统提示词不是越长越好。我做过对比测试,同一个任务,3000token的系统提示词和1500token的,成功率只差2个百分点,但token成本差一倍。那2个百分点完全可以通过重试机制补回来。

4. Markdown、Obsidian与Agent的集成实战

4.1 为什么选Markdown作为中间格式

这个项目的产出大量以Markdown形式落地,原因很实际:Markdown是人和模型都能高效读写的格式。模型生成Markdown的准确率远高于生成HTML或富文本,人阅读Markdown也不需要额外工具。而且Markdown天然适合做版本控制,每次产出都能diff。

但Markdown有个坑:换行和空格的语义在不同解析器里不一致。比如两个空格加换行在有些解析器里是软换行,有些是硬换行;表格的对齐语法各家实现也有差异。项目里的做法是定义一套内部Markdown规范,生成时严格遵守,解析时用统一的解析器,避免"生成的和解析的对不上"。

4.2 Obsidian作为知识沉淀层的价值

Obsidian在这个项目里扮演的是"长期记忆外部存储"的角色。Agent产出的所有结构化笔记、决策记录、任务总结,都以Markdown文件形式存进Obsidian库。这样做有几个好处:

  • 双向链接:Obsidian的[[链接]]语法让笔记之间能建立关联,Agent可以通过链接关系做知识检索,比纯向量检索更精准。
  • 本地优先:所有数据在本地,不依赖外部服务,隐私和可控性都好。
  • 插件生态:Dataview插件能把笔记当数据库查询,Agent可以用它做结构化检索。

实际集成时,Agent通过文件系统直接读写Obsidian库的Markdown文件,不需要走Obsidian的API。写入时注意保持frontmatter格式规范,这样Dataview才能正确索引。

4.3 从Zotero到Obsidian的笔记流转

热词里出现了"如何将zotero的笔记导入obsidian",这其实是这类知识管理Agent的常见需求。Zotero的笔记导出成Markdown后,格式往往很乱——引用标记、多余空行、不规范的标题层级。项目里的处理流程是:

  1. Zotero导出为Markdown(用Better BibTeX插件)。
  2. Agent读取原始Markdown,做格式清洗:统一标题层级、移除冗余引用标记、规范化列表缩进。
  3. 按主题分类,写入Obsidian对应文件夹,并自动生成双向链接。
  4. 用Dataview生成索引页,方便后续检索。

这个流程的关键是清洗规则要可配置,因为不同人的Zotero笔记格式差异很大,硬编码规则很快就会失效。

5. 九个月20万行代码的工程真相

5.1 代码量为什么这么大

20万行代码,如果全是业务逻辑,那确实夸张。但Agent项目的代码构成很特殊:

  • 框架层:状态机、校验器、重试机制、记忆管理,这部分大概占30%。
  • 工具层:每个工具的定义、参数校验、结果处理,工具越多代码越多,占25%。
  • 提示词与配置:如果把提示词模板、配置schema都算进去,占15%。
  • 测试:Agent系统的测试极其繁琐,要模拟各种模型输出、各种失败场景,占20%。
  • 胶水代码:各种格式转换、适配器、工具函数,占10%。

真正"核心逻辑"可能就几万行,剩下都是让系统稳定运转的必要开销。这也是为什么一个人九个月能写出20万行——大量代码是模式化的、可复制的,不是每行都需要深度思考。

5.2 一个人做Agent项目的节奏控制

一个人干九个月,最大的挑战不是技术,是节奏。我的经验是分三个阶段:

前三个月做骨架。不要急着接模型,先把状态机、校验器、记忆管理这些框架层的东西搭起来,用mock模型跑通流程。这个阶段产出慢,但决定了后面能不能规模化。

中间三个月做工具和集成。把需要的工具一个个接进来,每接一个就写测试、跑通端到端。这个阶段最容易失控——工具是无限的,必须有明确的优先级,只做当前任务真正需要的。

后三个月做优化和打磨。压缩上下文、优化提示词、处理边界情况、补测试。这个阶段的产出最不明显,但对最终质量影响最大。

注意:千万不要在框架没搭好之前就大量接工具。我早期犯过这个错,接了十几个工具后发现状态机设计有问题,全部推倒重来,浪费了一个多月。

5.3 并发与稳定性:Agent怎么扛住真实流量

热词里有"ai agent 怎么扛并发",这是Agent从Demo走向生产必须过的坎。这个项目里的做法是:

  • 无状态化:Agent的每个任务状态都存在外部存储(数据库或文件),进程本身无状态,可以水平扩展。
  • 任务队列:所有任务进队列,worker从队列取任务执行,避免请求直接打到模型。
  • 限流与降级:模型调用有速率限制,超限时任务排队而不是失败;模型服务不可用时降级到备用模型或返回明确错误。
  • 幂等设计:每个任务有唯一ID,重复提交不会重复执行,这对重试场景很重要。

实测下来,这套结构在单机4个worker的情况下,能稳定处理每秒几十个任务,瓶颈主要在模型API的速率限制上,不在框架本身。

6. 那些文档里不会写的踩坑记录

6.1 模型输出格式的"薛定谔稳定性"

你以为定义了JSON schema模型就会乖乖输出JSON?太天真了。实测下来,即使schema写得很清楚,模型仍有5%-10%的概率输出格式不对——多一个逗号、少一个引号、字段名拼错、该是数组的给了对象。这些错误在Demo阶段可能一次都遇不到,一到生产就集中爆发。

项目里的应对是三层校验:第一层用正则做快速格式检查,第二层用JSON parser做结构校验,第三层用schema validator做语义校验。任何一层不过就打回重试,重试时把具体的错误信息告诉模型("你的输出第3行缺少闭合引号"),比笼统说"格式错误"有效得多。

6.2 工具调用的超时与重试陷阱

工具调用失败是常态,但盲目重试是灾难。我踩过的坑:一个文件写入工具因为路径问题失败,框架自动重试了5次,每次都失败,5次重试消耗的token比正常执行还多,而且最后任务还是失败了。

正确的做法是按失败类型决定策略:

失败类型处理策略
网络超时自动重试2-3次,指数退避
参数错误不重试,返回明确修正提示给模型
权限问题不重试,直接终止任务并报告
资源不存在重试1次,仍失败则让模型换方案
模型格式错误重试,附带具体错误信息

这个策略表是项目里最值钱的东西之一,它把"重试"从一个盲目动作变成了有判断的决策。

6.3 上下文丢失导致的"失忆"问题

Agent跑长任务时最诡异的现象是:前面明明确认过的需求,跑到后面模型突然"忘了",开始按自己的理解瞎干。这不是模型的问题,是上下文管理的问题——压缩策略把关键信息压没了,或者滑动窗口把锚点滑出去了。

解决办法是显式锚点机制:用户的核心需求、已确认的关键决策、不可违背的约束,这些信息打上"永久锚点"标记,任何压缩策略都不能动它们。实现上就是在消息结构里加一个is_anchor字段,压缩时先过滤出锚点消息,永远保留。

6.4 提示词版本管理的血泪史

提示词改了,效果变差了,想回滚——结果发现没存旧版本。这种事我干过不止一次。后来强制要求:所有提示词必须进版本控制,每次修改都要记录改了什么、为什么改、改前改后的效果对比。提示词文件用Markdown写,带frontmatter记录版本信息,这样diff起来也方便。

7. 从这套架构里能复用的经验

7.1 什么场景适合上Harness

不是所有Agent项目都需要Harness。如果你的任务步骤少于5步、失败率可以接受、不需要审计,那裸奔式Agent就够了,上Harness是过度工程。但如果你满足以下任意两条,就该考虑Harness:

  • 任务步骤超过10步,且步骤之间有依赖。
  • 失败成本高,不能接受"跑一半崩了"。
  • 需要审计和回溯,要能说清楚每一步发生了什么。
  • 需要长期运行,进程重启后任务要能恢复。
  • 有多个模型或多个工具需要编排。

7.2 最小可行Harness的搭建顺序

如果你想自己搭一套,我建议的顺序是:

  1. 先做状态机:用最简单的内存状态机,把任务流程跑通。
  2. 加校验层:给每个状态的输出定义schema,加校验和重试。
  3. 加持久化:把状态存到外部,支持恢复。
  4. 加记忆管理:实现摘要替换和锚点机制。
  5. 加工具层:按需接工具,每个工具配测试。
  6. 加监控:记录每步的token消耗、耗时、成功率。

这个顺序的好处是每一步都有可运行的产出,不会出现"搭了三个月还跑不起来"的情况。

7.3 成本控制的几个硬指标

最后分享几个我在项目里盯着的成本指标,你可以直接拿去用:

  • 单任务平均token消耗:这是最核心的指标,任何优化都应该让它下降。
  • token消耗/有效产出比:有效产出指最终被采纳的结果,这个比值越低越好。
  • 重试率:重试次数/总调用次数,高于15%说明校验或提示词有问题。
  • 上下文压缩率:压缩后token/压缩前token,太低说明压缩不够,太高说明可能丢信息。
  • 缓存命中率:相同或相似请求的缓存命中比例,这个直接省钱。

我个人在实际操作中的体会是,Harness架构的价值不在于让Agent"更聪明",而在于让Agent"更可控"。模型的能力在涨,但工程上的确定性永远得靠框架来保证。一个人九个月能造出这套东西,靠的不是什么黑科技,就是把每个环节的不确定性一个个用工程手段摁住。这个过程很枯燥,但跑通之后,你会发现自己对Agent的理解和那些只会调API的人完全不在一个层次上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 19:37:43

基于Seed-2.1-pro-0915与Next.js SSE的求职薪资雷达实战

1. 这个求职雷达到底解决了什么问题 求职这件事,最让人抓狂的从来不是“投简历”本身,而是 信息筛选的效率 。我身边不少朋友,包括我自己,都经历过这样的循环:打开招聘平台,输入关键词,翻十几…

作者头像 李华
网站建设 2026/10/2 19:37:37

VMware 虚拟机安装 CentOS 6.5 完整教程:分区、网络配置与避坑指南

简介:这份文档面向需要在虚拟机中搭建CentOS 6.5-x86_64开发或测试环境的运维与测试人员,系统梳理了从操作系统安装到常用组件部署的完整流程。内容涵盖Red Hat 5.6_x64基础系统安装、静态网络配置、VMware虚拟工具安装、mpiag与oracle用户创建&#xff…

作者头像 李华
网站建设 2026/10/2 19:36:31

云边端协同算力架构:从推理引擎到量化部署的实战指南

2024年下半年开始,AI算力圈子里最明显的一个变化,就是大家不再只盯着训练集群的利用率,而是开始拼命追问推理服务的时延、并发和单位成本。我自己的团队过去半年处理的推理请求量,已经比训练任务多了快两个数量级,以前…

作者头像 李华
网站建设 2026/10/2 19:36:10

从零构建AI工程能力:推理服务、显存管理与性能优化实战

1. 这个项目到底在解决什么问题第一次看到 "ai-engineering-from-scratch" 这个标题,我脑子里蹦出来的第一个念头是:又是一个教人调包的教程?但仔细琢磨了一下 "from scratch" 这几个字,我意识到它想做的事情…

作者头像 李华
网站建设 2026/10/2 19:35:58

残差扩散模型赋能MIMO CSI可变率JSCC,性能提升数量级

残差扩散模型赋能MIMO CSI可变率联合信源信道编码,性能实现数量级提升【附python代码】做无线通信系统的人,这几年应该都明显感觉到一个趋势:物理层和AI的边界正在快速融合,尤其是CSI反馈这个方向,简直是被深度学习“卷…

作者头像 李华
网站建设 2026/10/2 19:31:43

GitHub日榜高效阅读指南:从热榜中挖掘高价值技术项目

1. 日榜项目的真实价值:为什么值得每天花十分钟扫一遍很多人对 GitHub 热榜有个误解,觉得那不过是"看个热闹"——今天这个项目涨了几千星,明天那个项目被刷屏,跟自己手头的活儿没什么关系。我刚开始也是这么想的&#x…

作者头像 李华