所有 Harness 设计,本质上都在对抗两类问题:Agent 偷懒,或者 Agent 犯蠢。
在设计真正能够长时间自主运行的 AI 系统时,其控制框架(Harness)的健壮性至关重要。本文将详细剖析 AI agent 在长时自主场景中常见的失败模式,如上下文焦虑、规划偏差等,并提出通过定制 Harness 框架来系统性地缓解这些问题,确保 agent 的行为更加可靠和可控。我们常在云栈社区探讨此类工程实践,旨在帮助开发者构建更稳定的智能系统。
Agent 的许多“心理问题”源于其强化学习(RL)训练偏好短期任务完成,而非长期项目的持续成功。借鉴人类的生产力方法,我们可以采用会话切换、任务分解和专用验证 agent 等策略来优化整个工作流。

如果你想为长时自主系统设计一套可靠的 Harness,就必须深入思考并解决以下八个核心问题。
本质上,所有 Harness 设计都是在对抗两类根本性问题:agent 要么开始偷懒、走捷径,要么开始迷糊、犯蠢。虽然有些问题比另一些更难修复,但一个精心设计的 Harness 确实能解决大部分麻烦。
agent 会怎么犯蠢
1. 任务前:上下文没吃够 (Pre-Task)
Agent 在任务开始前如果没有拿到足够且准确的上下文,那么它的行动从起点就是建立在错误或缺失的信息之上。
要解决这个问题,你需要在任务启动前,就系统性地检查信息是否完整、是否存在内部矛盾。因为一旦工程启动,这些早期问题只会像病毒一样一路传染下去,导致后续所有工作都可能偏离轨道。
2. 规划阶段:上下文不完整 (Planning — Incomplete Context)
规划是 agent 决定解决路径的关键阶段。这里最大的风险是它选错了攻击路径,导致最终产物从根基上就是错误的。
如今,单纯因为模型能力不足而“犯蠢”选错路径的情况已不常见。更常见的是对齐(Alignment)出了问题,即 agent 误解了用户的真实意图。
解决方案是确保 agent 在开始规划前,已经扫描并覆盖了所有相关的文件与信息。这里还有一个关键前提:你的代码仓库或知识库中,不能存在互相冲突或矛盾的信息源。
3. 规划阶段:短期思维 (Planning — Short Term Thinking)
Agent 不会主动承担那些短期、速成方案所带来的长期技术债务。这就好比雇佣了一个廉价的软件外包,你可能很快得到一个“能跑起来”的东西,但随之而来的维护成本和架构混乱会越滚越大。
解决方法是在规划阶段反复提醒 agent:它的目标是产出一个可扩展、易于融入现有系统、便于维护,并且遵循良好软件工程范式的方案。简而言之,你希望它像项目创始人一样思考,而不是像一个只想赶紧交差结款的临时工。
你还可以引入多方案评审机制:让 agent 先产出 N 个(例如 N=5)不同的备选方案,再交给另一个专职评审的 agent,从中选出在可维护性、代码清洁度上得分更高的方案。
任务执行阶段的陷阱
4. 任务阶段:上下文焦虑 (Task — Context Anxiety)
这是 agent 真正动手编码和解决问题的阶段。目前,最大的挑战莫过于“上下文耗尽”。
如果前期规划得当且上下文提供准确,现在几乎所有前沿模型的 agent 都能以接近“一次性完成”的能力,处理好足够细粒度的任务。真正出问题的,往往是那些复杂、跨越多轮会话、可能消耗数百万 token 的超长任务。
几乎所有 agent 都表现出某种“上下文焦虑”。随着会话时间拉长和上下文膨胀,它们会变得越来越急于结束当前会话。Claude 模型在这方面的表现尤为明显。解决方法是进行智能的会话交接(session handoff),将沉重的上下文负担从当前 agent 转移出去。
但紧接着你会遇到一个新问题:如何保证交接时的上下文保真度?你需要确保交接提示(handoff prompt)包含足够多的细节,让新会话中的 agent 能以高信息密度的方式,无缝承接所有推进任务所需的内容。本质上,你在这里是在做一种“有损压缩”。你有可能比基础模型提供方做得更好,原因在于:你比他们更了解自己项目的仓库结构和业务逻辑。
5. 任务阶段:偏离计划 (Task — Planning Deviations)
除了上下文膨胀,第二常见的问题是“规划粘滞”(planning stickiness),即 agent 在执行中逐渐偏离原计划,最终几乎是在按自己的意图行事。
最常见的表现是:你要求它完成一个漫长、复杂且艰巨的任务 A。结果它交付了 A‘。它可能认为 A’ 已经非常接近 A,但实际上,A‘ 根本无法将项目导向既定目标。
这不仅是结果不达标的问题,更麻烦的是软件本身的可组合性。所有原本依赖任务 A 产出物的下游代码,现在都不得不与 A‘ 进行适配。由此衍生出的整条代码链,从根本上就是错误的。
要解决这个问题,你必须尽早且频繁地进行验证,确认任务方案是否被正确实施,是否符合预期。这种持续验证可以有效阻断任务列表中的级联故障。
6. 任务阶段:对复杂度的恐惧 (Task — Complexity Fear)
Agent 对高复杂度任务有着根深蒂固的恐惧。
你让它写一个 5 行的函数,通常毫无压力。但如果它预判自己将要编写的是一个长达 5 万行的类,它就会开始想方设法地“糊弄”过去。
最糟糕的表现有两种:一种是随手写几个桩函数(stub)就宣告完成;更糟的是,直接宣布该任务“超出本次会话范围”,然后单方面结束会话。
我们最好的猜测是:在 RL 训练过程中,agent 学会了这样一个经验——处理高度复杂的任务时,它极易犯错并因此受到严厉惩罚,所以它学会了激进地回避这类任务。
讽刺的是,人类也完全一样。大多数人面对庞大工作量时,第一反应就是无限拖延。生产力教练通常给出的解法是:从任务最简单的第一步开始。这样启动的“心理能量”几乎为零,你能立刻从“准备状态”切换到“执行状态”。
对 agent 也需如此。你需要把复杂的母问题拆解成许多看起来不那么吓人的子任务,每个子任务最好控制在百行代码以内,然后将几百个这样的小任务串联起来完成。
一个有趣的副作用是:如果你研究并实践过人类的生产力方法,会发现它们同样适用于管理 agent。这让人清晰地意识到,agent 的“心理”很大程度上是对我们自身思维模式的镜像。
任务完成后的问题
7. 任务后:验证偷懒 (Post-Task — Verification Laziness)
Agent 倾向于选择最短路径进行验证。它会编写一些非常薄弱的测试用例,看着它们通过,然后就宣布任务成功。
上下文压力越大,这种“敷衍了事”的验证行为就会越离谱。最坏的情况是:假设某个函数本应实现行为 A,但 agent 却为相似但不同的行为 A‘ 编写了测试。测试通过后,它便宣告该函数工作正常。
缓解方法是确保负责编写验证测试的那个 agent,拥有尽可能新鲜且完整的上下文,并且它本身就应该是一个专职规划验证方案的独立 agent。更重要的是,你要验证的必须是期望在生产环境中出现的精确行为,而非一个模糊的通用行为。
这意味着,如果你在测试前端某个按钮是否有效,不要去测试“一个通用按钮是否能点击”。你应该思考,究竟怎样才算真正证明了这个按钮是好的:
- 你需要看到一张截图,确认这个按钮确实渲染在正确的页面上。
- 你需要真实地模拟一次对该按钮的点击事件。
- 这次点击需要触发后端,并发出符合预期的正确数据载荷(payload)。
在你能确凿证明某个功能真的工作之前,它就等于没有工作。相信我,与 agent 打交道足够久之后,我对这句话非常有把握。
8. 任务后:熵最大化 (Post-Task — Entropy Maximization)
以目前的能力来看,agent 产出的代码通常只是“勉强可接受”的水平,它不会主动帮你降低代码仓库的混乱度(熵)。
常见的情况是:它把函数 X 的行为从 A 修改为了 B,但所有相关的文档、注释甚至其他函数的调用说明,还在描述旧的行为 A。你的 agent 不会顺手把这些不一致的地方一起修复。
这种情况重复发生几十上百次后,你就会得到一个完全不可维护的“屎山”仓库。然后,你的 agent 会持续被这些混乱信息搞糊涂,并因此做出越来越糟糕的决策。
最好的解决办法是:在每次长时间会话结束后,专门分配一些计算资源(token),启动一个拥有新鲜上下文的 agent,让它负责“清道夫”工作,包括清理无效状态、消除文档矛盾、处理合并冲突、删除死代码和过期文档等。
为什么要自己做 Harness
在模型提供商提供的原生 Harness 或简单封装里,能用来解决上述问题的工具非常有限。例如早期的 Codex,连基本的钩子(hooks)机制都没有。
更重要的是,如果你直接让 Claude 这样的模型在你的框架里充当总调度器(orchestrator),它自身会被大量与具体任务无关的编排上下文撑得臃肿不堪。你真正需要的,是把 agent 的编排层放在任务列表之上进行管理,而不是与任务执行逻辑混在一起。
例如,你可以设计一个专门的“监工” agent,它的唯一职责就是确保每个会话都必须满足一份预设的“算法合约”(algorithmic contract)才能结束。这个监工会持续监控合约状态,提醒其他 agent 不要偏离合约,并额外启动拥有新鲜上下文的独立 agent 来判断当前工作质量,独立验证任务是否真正完成。
当你拥有自己独立的 Harness 框架时,你就可以设计出专门针对“agent 会如何犯蠢”的定制化工作流。这种对系统设计的深度把控,是提升AI系统稳定性的关键。
- 如果你发现,基于你的工作类型,agent 经常因任务复杂度高而退缩,你就可以增加一个“复杂度评估” agent。它专门判断当前任务属于简单项目还是高复杂度项目。若判定为高复杂度,则再拉起一个“任务分解” agent,将项目拆解为一系列可被执行的小任务,同时确保最终产出仍与原始目标对齐。
- 如果你发现,agent 没有将代码仓库维护在一个整洁的状态,你就可以在每次会话结束时,启动一些“仓库保洁” agent,去分析本次改动的“爆炸半径”(blast radius),确保改动触及的所有文件、文档都没有自相矛盾,并符合你定义的“干净代码”标准。
最后,也是最重要的一点:你需要对 Harness 编排层接收和产出的所有内容进行详细遥测,包括 prompts、执行轨迹(traces)、结果(outcomes),并设计评估标准(rubric)来量化你的 Harness 质量。持续迭代才是王道,这能让你一步步逼近更高效、更可靠的框架。
OpenForage Harness
顺带一提,我们团队构建了一套主张明确(opinionated)的 Harness,它用一套清晰且带点主观色彩的方式解决了上述所有问题。我们对此深感自豪,它已成为我们日常编码的核心工具。经过多年迭代,当它准备好面对更广泛的应用时,我们会将其开源。
结论
对于绝大多数应用场景,从模型提供的原生功能出发,配置一套简单朴素的框架,其实已经足够使用。
但如果你需要从 agent 身上压榨出更强大的生产力,尤其是构建长时、自主运行的复杂工程系统,那么本文的目的,就是提前为你揭示那些几乎必然会遭遇的挑战,并提供系统的解决思路。
原文: x.com/systematicls/status/2038241033755168959