
一个模型会调用工具,并不等于它已经是可靠的 Agent。
最简单的 Agent 循环并不复杂:把任务交给模型,模型选择工具,系统执行工具,再把结果送回模型。循环持续到模型认为任务已经完成。
Demo 往往能顺利跑起来。进入真实项目后,问题会接连出现:工具超时,文件修改失败,模型重复同一个动作,测试没有通过,运行中断后进度全部丢失。更危险的情况是,模型只是"觉得"完成了,系统就直接把结果交给用户。
Harness 工程处理的是这些模型外部的问题。

右侧才是一套完整 Harness:模型之外还有任务状态、工具执行、结果验证和失败恢复。
Harness 是什么
Harness 可以理解为 Agent 的运行系统。模型负责判断下一步,Harness 负责把判断转换为真实操作,并控制操作的边界。
一套常见的 Harness 会管理:
- 模型与工具之间的执行循环;
- 当前任务和子任务状态;
- 文件、命令行与外部服务;
- 工作记忆和完整事件记录;
- 测试、检查项与结果验证;
- 失败重试和中断恢复;
- 权限、凭证与沙箱隔离。
这些模块不一定都很庞大。一个几十行代码的工具循环也可以算最小 Harness。区别在于,系统是否开始对模型的行动负责。
模型的判断不能直接等于事实
假设 Agent 收到一个任务:修复注册接口的重复提交问题。
模型找到相关代码,增加了一段去重逻辑,然后回答"问题已经修复"。如果系统到这里就结束,所谓完成只是模型的一次文本判断。
更可靠的流程会继续检查:
text
代码是否成功写入?
项目能否编译?
原有测试是否通过?
重复提交测试是否真的补上?
接口行为是否符合需求?
这些问题可以由文件系统、测试框架和验收规则回答,不必依赖模型自评。
Harness 的一条基本原则,是尽可能把"我认为正确"换成"环境证明正确"。代码要用测试验证,文件要检查是否存在,网页操作要读取页面状态,数据写入要查询结果。
一个循环怎样持续工作
Agent 每轮通常经历四个步骤:读取状态、构造上下文、请求模型决策、执行动作。
text
读取任务状态
↓
向模型提供当前上下文
↓
模型选择下一步动作
↓
执行工具并记录结果
↓
回到下一轮
真正麻烦的是循环中的异常情况。
工具可能返回错误,模型也可能给出不存在的参数。Harness 需要把机器错误转换成模型能继续处理的信息,并决定是否允许重试。连续多次调用同一工具时,还要判断这是合理迭代还是陷入死循环。
因此,一个成熟的循环通常会设置最大轮数、重复动作检测、超时和失败类型。达到边界后,系统可以重新规划,或者停下来请求人工处理。
任务状态要放在模型之外
只把进度写在对话历史中并不稳妥。上下文可能被压缩,进程也可能意外退出。
任务列表应当有独立状态,例如:
text
pending 尚未开始
in_progress 正在处理
completed 已通过验收
failed 当前方案失败
每次状态变化都要有依据。Executor 生成了一份文件,只能说明动作已经执行;文件是否符合要求,还需要 Validator 检查。验证通过后,任务才能进入 completed。
状态放在外部还有一个好处:Harness 重启后可以从上次位置继续,而不是让模型凭一段残缺历史猜测已经做过什么。
工具应该为模型设计
人使用命令行时,可以阅读帮助文档,也能根据报错临时调整。模型依赖工具名称、描述和返回值来判断下一步,所以工具接口是否清楚会直接影响执行质量。
一个适合 Agent 的工具通常有明确用途,参数数量有限,返回结果也经过整理。
例如,文件编辑失败时,只返回 error 没有什么帮助。把完整运行栈全部返回,又会浪费上下文。更好的结果是:
text
编辑未应用:目标片段在文件中出现 3 次。
请补充行号范围,或提供更长的匹配内容。
模型知道失败原因,也知道可以怎样修正。
工具之间还要减少重叠。如果 search、find、lookup 和 query 都能查文件,却没有清楚区别,模型会把精力浪费在工具选择上。少而明确的工具集通常更稳定。
miniMaster 的三种角色
miniMaster 把运行过程分成 Planner、Executor 和 Validator 三种职责。
Planner 负责安排任务,Executor 执行,Validator 验收;检查失败后,任务回到执行阶段。
Planner 关注全局。它把用户目标拆成任务,安排顺序,并在执行受阻时调整计划。
Executor 处理当前任务。它读取文件、调用搜索、执行命令,或者修改代码。每次行动的结果都会写入工作记忆。
Validator 根据完成条件检查产出。它不会因为 Executor 声称"已完成"就直接通过,而是寻找测试结果、文件内容或其他证据。
如果 Validator 发现缺项,任务会回到 Executor。相同问题反复出现时,Planner 可以改变方案。
三种职责可以由同一个模型在不同上下文中承担,也可以分给多个模型。重点是执行和验收之间要有边界。
失败后怎样继续
长任务很难一次走通。网络会断,外部接口会限流,生成的代码也可能编译失败。
Harness 需要区分失败类型。
临时网络错误可以等待后重试;参数错误应当把具体原因交给模型修正;权限不足不能靠重复调用解决;测试失败则需要回到代码分析阶段。
重试记录也不能简单丢掉。保留失败动作和错误摘要,可以避免模型再次采用同一方案。记录过长时,可以把旧尝试压缩归档,但原始日志仍应能够查询。
如果运行状态和事件日志已经持久化,即使 Harness 进程崩溃,新实例也能读取历史并继续执行。模型上下文可以重建,任务本身不必从头开始。
权限和沙箱不能交给提示词
在系统提示词里写"不要读取密钥",不能构成真正的安全边界。模型可能受到错误指令或提示注入影响,也可能无意间执行危险命令。
安全限制必须落实在模型之外。
文件工具可以限定允许访问的目录,Shell 命令可以运行在隔离沙箱中,高风险操作可以要求人工确认。访问外部服务时,凭证应由代理层注入,而不是直接暴露给模型或执行环境。
即使模型作出错误决定,底层权限仍然应当阻止它越过边界。
Harness 也需要随模型变化
Harness 经常用于补偿模型当前的弱点,例如频繁提醒目标、强制拆解步骤或定期重置上下文。模型升级后,其中一些机制可能不再有用,甚至妨碍新模型发挥能力。
因此,Harness 不应写成一团无法替换的流程。会话记录、工具执行、模型循环和沙箱最好通过稳定接口连接。底层策略变化时,可以单独替换,不必重写整个系统。
还要用真实任务持续评估。某个重试策略究竟提高了成功率,还是只增加了调用次数,需要从运行轨迹和结果中判断。
哪些任务值得使用 Harness
一次摘要或翻译通常不需要复杂 Harness。重新生成一次的成本很低,过程也不会修改外部环境。
当任务包含连续工具调用、中间状态保存、真实文件修改或明确验收标准时,Harness 才有明显价值。任务运行越久,失败成本越高,对状态、验证和恢复的要求也越高。
可靠的 Agent 并不是从不出错的模型。更现实的设计,是允许模型在局部犯错,同时让系统保留现场、限制风险、提供反馈,并在交付前检查结果。
模型决定下一步往哪里走,Harness 确保它没有在半路停下,也没有把未经验证的结果当成终点。