跳转至

第 21 章 Agent Harness:运行时、状态与权限

开场问题:同一个模型装进两个 Coding Agent,为什么一个能连续工作几个小时,另一个十分钟后就忘记目标、重复调用工具?差异往往不在模型,而在 Harness。

21.1 Harness 到底是什么

Agent 是第 20 章的“观察—决策—行动”闭环;Agent Harness 是承载并约束这个闭环的运行外壳。它至少负责:

  • 把模型输出解析成动作并执行。
  • 管理工具注册、选择、参数验证与权限。
  • 保存任务状态、文件和中间产物。
  • 在上下文变长时压缩、淘汰和重新注入信息。
  • 处理错误、重试、暂停、恢复和人工审批。
  • 调度子 Agent,并合并结果。
  • 记录完整轨迹、成本和可观测信息。

模型只负责预测“下一步做什么”。长任务能否可靠完成,很大程度取决于 Harness 是否把正确的信息留在上下文、把危险动作挡在外面、把工具错误变成模型可理解的观察。

它不是一个新模型架构,也不只是几行 ReAct prompt。可以把它理解为 Agent 的操作系统:向上给模型稳定接口,向下管理工具、状态、资源与权限。

21.2 不要混淆三种 Harness

三个相似名字解决不同问题:

  • Agent Harness:线上运行 Agent 的控制循环,本章主题。
  • Evaluation Harness:第 14 章的实验协议,用同一套任务、解析和指标公平评测模型。
  • Environment Harness:包裹训练/评测环境,动态调整任务、观察和反馈,但保留底层验证器。它属于第 22 章的前沿方向。

Evaluation Harness 可以启动 Agent Harness 去完成任务;Environment Harness 可以为 Agent 提供变化后的训练环境。三者可以组合,但不是同义词。

21.3 控制循环不能全交给模型

一个典型循环是:

  1. 从持久状态恢复任务。
  2. 根据当前阶段选择需要的工具定义。
  3. 组装受预算约束的上下文。
  4. 调用模型得到文本、工具调用或结束信号。
  5. 校验动作与权限。
  6. 执行并把结果转成结构化观察。
  7. 更新状态、预算和轨迹。
  8. 判断成功、失败、等待审批或继续。

步骤 2、3、5、7、8 必须有确定性代码参与。若连“是否已经成功”和“还有多少预算”都让模型用自然语言自行判断,系统会重复工作、越权或永不结束。

21.4 上下文管理是 Harness 的核心能力

长任务会产生大量工具输出、代码 diff、网页和子 Agent 报告,全部塞回上下文最终一定溢出。Harness 要区分:

  • 始终保留:用户目标、硬约束、权限和验收条件。
  • 结构化状态:待办、已完成项、文件路径、提交 ID、测试状态。
  • 按需取回:长文档、旧日志、网页内容。
  • 可以丢弃:重复输出、已被后续结果取代的中间尝试。

Compaction 不是把历史随便总结成一段话。摘要必须保存未完成承诺、失败原因和外部资源引用;事实性产物仍放在文件或数据库中,需要时重新读取。上下文是工作内存,不是唯一存储。

21.5 工具发现与按需加载

工具增到几百个后,把所有 schema 放进 prompt 会浪费 token,也降低选择准确率。现代 Harness 先让模型搜索工具目录,只把相关工具定义加载到当前上下文。

还可以让 Harness 直接用代码编排简单的数据流:并行调用多个搜索工具、过滤结果、做确定性聚合,只把精炼结果交回模型。这样既省上下文,也减少模型在机械搬运数据上出错。

原则是:能由确定性程序完成的编排,不要消耗一次模型推理。

21.6 持久任务、暂停与恢复

真正的 Agent 任务可能持续数小时或数天,会等待 CI、人工审批或外部事件。Harness 不能依赖一个常驻 Python 进程和内存中的消息数组。

每一步完成后保存:

  • 当前状态和待办。
  • 模型与 prompt 版本。
  • 已用预算。
  • 工具调用及幂等键。
  • 环境快照或外部资源版本。
  • 下一次恢复所需的最小上下文。

恢复时要避免重复执行已有副作用。持久化、幂等性和事件驱动状态机,比“再给模型一个更强 prompt”更能决定长任务可靠性。

21.7 子 Agent:上下文隔离比角色扮演更重要

子 Agent 的主要价值不是让多个模型扮演“研究员、评论家”,而是:

  • 并行处理真正独立的子任务。
  • 给每个子任务独立、干净的上下文。
  • 防止主线程被大量搜索细节污染。
  • 让不同子任务使用不同模型、工具和预算。

父 Agent 必须给出明确的输入、交付物和终止条件。子 Agent 返回的应是结论和证据引用,而不是完整思考历史。共享同一份可写状态时还要处理冲突,不能假设多个 Agent 自然会协调。

21.8 权限、审批与策略引擎

Harness 才是真正的执行边界。每个工具应声明:

  • 读还是写。
  • 可访问的资源范围。
  • 是否有外部副作用。
  • 是否可自动重试。
  • 是否需要人工批准。

模型不能通过在参数里写“用户已经批准”绕过策略。审批结果应来自独立通道,并绑定具体动作摘要;动作发生变化后要重新审批。

21.9 可观测性:记录语义事件

除了模型延迟和 token,Harness 还应记录:

  • 每轮选择了什么动作,为什么进入下一状态。
  • 哪些上下文被加入、压缩或丢弃。
  • 工具发现和选择结果。
  • 重试原因和错误分类。
  • 子 Agent 的派发、取消和合并。
  • 权限拒绝和人工审批。

只有这些语义事件,才能判断失败源于模型、上下文、工具还是控制逻辑。

21.10 Agent 评测的单位是完整轨迹

保存每一步:

  • 当时可见的消息和状态。
  • 模型原始输出。
  • 解析出的动作。
  • 工具输入、输出、耗时和错误。
  • 环境状态变化。
  • token 和费用。
  • 最终验证结果。

只有最终答案无法分析失败,也无法把成功轨迹回流训练。

21.11 环境必须可重置

编程 Agent 要固定仓库 commit、依赖和测试;浏览器 Agent 要固定网站快照或模拟后端;操作系统任务要在容器/虚拟机中恢复初始状态。

每次运行前重置,每次结束清理副作用。否则前一个 Agent 的修改会让后一个任务变简单或变难。

21.12 成功判定必须独立

编程任务以隐藏测试通过和改动范围为准,不以“Agent 说已修复”为准;客服任务看真实订单状态和政策遵循;研究任务检查引用和结论是否被来源支持。

公开测试可给 Agent 反馈,隐藏测试只用于最终验收,防止它针对测试投机。

21.13 消融:找出提升来自哪里

至少做:

  • 同模型,换新旧 prompt。
  • 同模型,换新旧工具。
  • 同系统,换模型。
  • 固定步数/预算后比较。
  • 去掉记忆、规划、反思模块分别测试。

如果不固定预算,允许新系统多跑三倍步骤得到的成功率提升不能归因于“更聪明”。

21.14 轨迹怎样回流训练

失败轨迹先分类。工具 schema 错修工具;环境返回不清修接口;模型决策错才进入训练。

成功轨迹也不能原样全收:可能包含多余搜索、偶然试错、泄露测试信息。应压缩成高质量示范,保留关键决策和必要观察;也可以构造 chosen/rejected 轨迹对,训练模型偏好更短、更可靠的路径。

对可验证任务,可把最终环境结果作为 RLVR reward;步骤级工具成功可作为过程信号。但要防止 Agent 通过修改测试、绕过权限等方式 hacking 环境。

21.15 模型与 Harness 的共同进化

模型升级后,旧 prompt 的过度解释可能成为负担;模型工具调用更强后,手写纠错逻辑可能反而干扰。因此每次换基座都要重新做系统消融,不能永久继承所有 scaffold。

判断一项脚手架是否还需要:去掉它后质量是否下降、成本是否改善、失败类型是否变化。能由新模型稳定完成的逻辑应逐渐删掉,保持系统简单。

21.16 从离线任务到线上闭环

上线顺序:

  1. 离线固定环境大量回放。
  2. shadow 模式,只观察会怎么做,不真正执行副作用。
  3. 低权限 canary,小流量执行。
  4. 扩大权限与流量,同时保留人工接管。

线上收集的不只是成功/失败,还包括用户中断、人工修正、重试路径和成本。这些形成下一轮失败样本库。

核心问答

Q:Agent 与 Agent Harness 一句话怎么区分? Agent 是利用观察选择动作的策略;Harness 是让这个策略能够长期、安全、可恢复地运行的控制系统。

Q:Harness 最重要的能力是什么? 不是某个花哨规划算法,而是上下文管理、工具与权限、持久状态、错误恢复和完整轨迹。

Q:Agent benchmark 为什么比普通问答难复现? 结果依赖环境状态、工具版本、Harness、预算和多步随机性;任何一项变化都可能改变分数。

Q:成功轨迹能直接拿去 SFT 吗? 不应直接拿。成功可能靠大量无效试错或利用漏洞,需要清洗和压缩成可取的策略。

Q:怎样证明提升来自模型而非更多预算? 固定工具、prompt、步数、token 和时间预算做消融,只替换模型。

Q:模型变强后旧 scaffold 怎么办? 重新消融。没有持续贡献的规划、纠错和提示应删除,避免历史补丁永久堆积。