Harness 是什么
先给结论
模型负责生成候选决策,Agent 负责围绕目标循环调用模型和工具,Harness 负责把这套循环变成一个可运行、可约束、可恢复、可评测的系统。
如果只有一个聊天窗口,模型可能会给出一段看起来合理的代码;如果有 Harness,系统还会负责:
- 收集仓库规则和任务上下文;
- 选择并限制可用工具;
- 保存会话和执行轨迹;
- 在修改后运行格式化、测试和安全检查;
- 把失败结果反馈给 Agent;
- 在高风险操作前暂停并等待批准。
Tool Calling、MCP、Agent 与 Harness 的边界
这四个概念处在不同层次,不应因为共同出现于一个项目就混为一谈:
| 层次 | 解决的问题 | 不负责什么 |
|---|---|---|
| Tool Calling | 模型如何用结构化参数提出调用工具的候选动作 | 不直接执行工具,也不授予权限 |
| MCP | Host 如何用标准协议发现和连接外部工具、资源与提示 | 不决定任务目标、业务授权和停止条件 |
| Agent | 如何围绕目标维护状态并循环决策、执行、观察和停止 | 不天然提供沙箱、CI 和团队治理 |
| Harness | 如何为 Agent 提供仓库上下文、工具执行、权限、审批、验证、轨迹和恢复 | 不替模型做业务推理,也不替业务系统鉴权 |
例如,模型可以通过 Tool Calling 提出 run_tests,Harness 校验仓库与命令权限后,既可以调用本地函数,也可以通过 MCP Client 连接远程测试服务;Agent 再根据测试结果决定修复还是停止。这里 MCP 不是 Agent 的同义词,Tool Calling 也不等于工具已经执行。
本页只说明 Harness 的工程职责。Agent 的状态循环由 Agent 运行机制总览统一解释,三者协议关系见 Tool Calling、MCP 与 Agent 的关系,避免在 Harness 专栏重复定义。
五个核心部件
Model
Model 处理语言、代码和结构化输出。它不天然知道仓库约定,也不应该直接拥有所有系统权限。
Agent
Agent 是目标、状态、模型和工具组成的循环。它会根据当前上下文决定下一步是继续分析、调用工具、修改文件,还是结束任务。
Harness
Harness 是 Agent 的运行时。它提供上下文构建、工具注册、权限、状态、重试、日志、审批、评测和恢复机制。
Tool
Tool 是一个有明确输入和输出的动作,例如读取文件、搜索符号、运行测试或创建 Pull Request。工具的描述应足够精确,输入应做 schema 校验。
Feedback
Feedback 是执行结果,不是模型的自我评价。编译错误、测试失败、代码审查意见和用户确认都可以成为下一轮上下文。
一次代码任务如何运行
用户:为订单接口增加幂等键支持
1. Harness 读取仓库规则、相关文件和测试命令
2. Agent 规划:定位接口、数据模型、迁移和测试
3. Harness 只开放读取、编辑和测试工具
4. Agent 修改代码
5. Hook 执行格式化和单元测试
6. 测试失败 -> 错误摘要回到 Agent
7. 测试通过 -> Reviewer Subagent 检查风险
8. Harness 输出 diff、测试结果和未决事项最小伪代码
for state := NewTaskState(goal); !state.Done(); {
context := BuildContext(state, repositoryRules, recentOutputs)
decision := model.Decide(context, availableTools)
if decision.NeedsApproval() {
approval := guardrail.Request(decision)
if !approval.Allowed {
state.Stop("operation rejected")
break
}
}
result := executor.Call(decision.Tool, decision.Input)
state.Append(decision, result)
if verifier.HasBlockingFailure(result) {
state.AddFeedback(verifier.Summarize(result))
}
}Harness 设计的四个边界
把规则放在上下文,把门禁放在 Hook
“请记得运行测试”适合写入规则;“未通过测试不能结束”应由 Hook 或 Runner 强制执行。前者依赖模型遵循,后者是确定性约束。
把事实放在工具结果,不放在提示词猜测
仓库状态、测试结果、权限和当前分支都应从工具或运行时获取。不要把可能过期的状态硬编码进系统提示。
把高风险动作拆成可审查步骤
删除文件、写生产数据、发布镜像和推送代码应有清晰的预览、审批和审计记录。
把长任务拆成可恢复阶段
规划、实现、验证和审查各自保存状态。单次上下文耗尽时,可以从阶段检查点继续,而不是从头再来。
接入真实仓库时的最小权限
不要以“Agent 需要自主工作”为理由默认开放整个磁盘、网络和 Shell。一次仓库任务至少要明确:
- 工作区:固定仓库根目录,解析真实路径后拒绝越界和符号链接逃逸。
- 上下文:加载用户目标、仓库规则、相关代码和测试入口,不把整个仓库一次性塞进上下文。
- 工具 allowlist:按阶段开放读取、搜索、局部编辑和指定测试;推送、部署、密钥读取默认不可用。
- 审批点:删除、外部写入、安装依赖、扩大修改范围和不可逆操作先展示影响再确认。
- 回归证据:保存基线、变更 diff、命令、退出码和测试摘要,不能用模型的“应该通过”代替执行结果。
权限由 Harness 和下游系统共同执行:从模型上下文隐藏工具不是授权,用户批准某次操作也不是永久授权。真实仓库的完整接入流程见主流 Coding Agent 对比。
常见误区
| 误区 | 后果 | 改进 |
|---|---|---|
| 把所有仓库内容塞进上下文 | 成本高、重点丢失 | 按任务检索和分层加载 |
| 给 Agent 一个万能 Shell | 越权和破坏风险 | 工具白名单、参数校验、沙箱 |
| 只看最终代码,不存轨迹 | 无法复盘和评测 | 记录决策、工具调用和验证结果 |
| 只用提示词约束测试 | 模型可能跳过 | 用 Hook/CI 做硬门禁 |
| 只追求一次成功 | 版本升级后回归 | 建立任务集和持续评测 |
练习
- 为一个 Go HTTP 接口画出 Context、Model、Tool、Verifier 的调用链。
- 列出 Java 服务中三个应该只读、三个需要审批的工具。
- 设计一个“测试失败后最多自动修复两次”的状态机。