简介:当 Agent 在同一类任务上反复失败时,问题往往不在模型本身,而在它外层的执行策略没有被单独设计和切换。本文从“生成文档但格式错误”“更新系统但未真正写入”两类典型问题出发,对比统一策略、独立策略与继承式策略三种 Harness 组织方式,重点分析它们在代码复用、任务适配、维护成本和效果评估上的差异,帮助开发者判断何时应拆分执行规则、如何复用已有逻辑,以及依据什么标准切换策略。
在 Agent 应用开发中,一个常见现象是:模型能力看起来足够,但在某一类任务上却持续失败。例如,让它生成一个 Word 文档,它最终只把纯文本保存成了 .docx 后缀;让它更新业务系统,它完成了一轮查询后便结束流程,没有真正执行写入操作。
这两种失败都不属于“模型不知道答案”,而属于“模型外层执行程序没有做对事情”。前者的本质是文件后端选择错误,后者的本质是缺少对写操作是否真正发生的验证。更值得关注的是,这类问题往往不是随机出现,而是集中在某一类任务上重复出现。
因此,问题可以转化为:能否把某类任务需要的执行规则单独抽出来,并在合适的场景下自动启用?
这引出了 Agent 开发中一个关键但容易被忽视的对象——Harness。
Harness 可以理解为包裹在大模型外部的执行控制程序。它并不改变模型权重,而是参与决定以下事项:
换句话说,模型负责“理解和生成”,而 Harness 负责“执行和管理”。在很多 Agent 失败案例中,模型输出并没有问题,问题出在 Harness 没有针对任务特点做相应控制。
为了处理“同类任务反复失败”,通常有三种做法:
三者的关系可以用下图式的结构表示:
统一策略:所有任务 -> 同一个 Harness独立策略:任务A -> Harness A任务B -> Harness B任务C -> Harness C继承式策略:基础 Harness├── 子类 Harness A:覆盖写入检查├── 子类 Harness B:覆盖文件后端└── 子类 Harness C:增加预算耗尽前保存产物
继承式策略的核心思想与经典面向对象设计相似:父类提供默认行为,子类只覆盖需要调整的部分,必要时通过类似 super() 的机制复用父类逻辑后再补充新检查。
无论采用哪种组织方式,它们都有一些共同基础:
这些共同点说明,Harness 的改进不是模型层的优化,而是工程控制层的优化。它更接近“流程修复”,而不是“能力提升”。
统一策略的复用程度最高,因为只有一套代码。但它无法表达“不同任务需要不同规则”的差异,所有调整都只能全局生效。
独立策略几乎没有复用。每个 Harness 各自维护完整流程,一旦公共逻辑发生变化,例如提示词模板调整或上下文管理方式改变,需要同步修改所有副本。
继承式策略在复用与差异之间取得平衡。基础逻辑保留在父类,子类只覆盖差异部分。例如:
class BaseHarness:def execute(self, task):result = self.run_agent(task)return resultclass WriteCheckHarness(BaseHarness):def execute(self, task):result = super().execute(task)self.verify_write_occurred(task)return result
上述示意代码中,WriteCheckHarness 复用了父类的主执行逻辑,只额外增加了写入验证。它不会重复实现整套 Agent 流程。
统一策略难以适应差异明显的任务。例如“生成文档”和“更新业务系统”对工具调用、中间检查、结束条件的要求差异很大,如果共用一套逻辑,很容易顾此失彼。
独立策略可以为每个任务精细调整,但任务数量增加后,维护成本迅速上升。当两个任务只需要细微差异时,维护两套几乎相同的完整 Harness 很不经济。
继承式策略允许按需覆盖。两个业务领域完全不同的任务,如果都卡在“查到了信息但没有写入”,可以复用同一个写入检查子类;两个应用场景不同的任务,如果都需要在资源耗尽前保存中间产物,也可以继承同一个保存逻辑。分组依据不是业务领域,而是失败机制。
统一策略维护成本最低,但任何改动都可能影响所有任务,风险集中。
独立策略维护成本最高。随着任务类型增加,重复代码不断膨胀,公共缺陷的修复需要多处同步。
继承式策略的维护成本介于两者之间。公共逻辑的修改只需在父类完成,专项逻辑的调整只影响对应子类。不过,继承层级过深也可能带来理解成本,需要合理控制继承关系。
这是一个容易被忽视但非常关键的差异。
如果同一批任务既用来反复修改 Harness,又用来证明修改有效,就很容易出现“过拟合”:策略只是记住了特定题目的答案,而不是真正获得了通用执行能力。
更可靠的做法是把任务分成两个不重叠的集合:
三种组织方式都需要这种评估分离,但统一策略和独立策略由于结构简单,开发者更容易忽略这一点。继承式策略在实现时通常需要更明确地记录“某个子类是为哪类失败机制设计”,这反过来也促使评估过程更规范。
| 维度 | 统一策略 | 独立策略 | 继承式策略 |
|---|---|---|---|
| 代码复用 | 最高,但无法表达差异 | 最低,大量重复 | 较高,公共逻辑在父类共享 |
| 任务适配 | 弱,只能全局调整 | 强,但每个任务需完整实现 | 较强,按需覆盖差异部分 |
| 维护成本 | 低,但改动风险集中 | 高,多处同步成本大 | 中等,公共改动集中,专项改动局部 |
| 扩展方式 | 修改唯一 Harness | 新增一套完整 Harness | 新增子类或覆盖方法 |
| 失败机制分组能力 | 弱,难以区分不同失败原因 | 可以实现,但结构不清晰 | 清晰,可按失败机制归类 |
| 评估规范性 | 容易混用任务集 | 容易混用任务集 | 更易区分发现集与验证集 |
| 适用团队规模 | 小规模、任务差异小的场景 | 任务类型少且差异很大的场景 | 任务类型多、需要持续演进的场景 |
当任务类型比较接近、执行流程高度一致时,统一策略足够。例如,一组主要做文本摘要和分类的 Agent,工具集相似,结束条件相同,失败模式也趋同。此时引入复杂继承结构反而增加不必要成本。
当任务类型很少但差异极大,且每个任务都需要完全不同的执行流程时,独立策略更直观。例如一个任务是文件格式转换,另一个任务是长流程业务审批,两者的 Harness 几乎无法共享任何逻辑,强行抽象反而僵硬。
当任务类型较多,但失败机制可以归纳成少数几类时,继承式策略优势最大。例如:
这些专项规则可以分别写成子类,由路由逻辑根据任务特征选择启用。改进过的规则可以继续继承,暂时用不上的规则不必强加给所有任务。
选型时不应抽象地追求“哪种更好”,而应结合以下条件判断:
一个容易忽略的点是:选择继承式策略并不意味着要启动多个 Agent 实例。被选中的子类本身就是一个完整的 Harness,父类只提供代码复用。 在一次任务执行中,只有被选中的子类实例运行,继承树上的节点不会各自跑一轮任务。
如果从统一策略或独立策略迁移到继承式策略,需要关注以下几点:
Agent 在同类任务上反复失败,往往不是模型能力不足,而是外层执行策略没有针对任务特点进行区分。统一策略、独立策略和继承式策略分别代表了“不加区分”“完全区分”和“有继承地按需区分”三种路线。
三者的核心差异不在于模型层,而在于执行规则的复用方式、适配粒度、维护成本和评估可靠性。统一策略简单但容易全局受限;独立策略灵活但重复成本高;继承式策略在复用和差异之间取得平衡,更适合任务类型多、失败机制可归纳、需要长期演进的 Agent 工作流。
选型的关键不是追求结构上的“先进”,而是回答三个问题:要改什么、能否复用、凭什么切换。 只有把失败机制拆解清楚,才能把 Harness 改进从“打补丁”变成一套可持续积累的执行策略体系。