26. Harness Engineer 如何优化模型有效能力与复杂任务成功率
26. Harness Engineer 如何优化模型有效能力与复杂任务成功率
本章回答一个容易被误解的问题:不训练模型、不修改模型权重,为什么只改 Harness,也可能显著提高复杂任务成功率?
原因不是 Harness 把模型“变聪明”了,而是模型能力从“潜在能力”转化为“可交付结果”时,会在任务理解、上下文、工具接口、执行反馈、状态管理和完成判断等环节持续损耗。Harness Engineer 的职责,是识别这些损耗发生在哪里,并通过可验证的系统改动减少损耗。
本章把前 25 章串成一条优化主线:
定义成功 → 建立基线 → 采集执行轨迹 → 识别失败模式 → 修改一个 Harness 假设 → 回归验证 → 灰度发布 → 把线上失败沉淀为新的评测用例。
26.1 模型能力没有改变,为什么系统能力会提高
可以把一次复杂任务交付拆成几个连续条件:
P(交付成功) ≈ P(正确理解目标) × P(拿到充分上下文) × P(选择有效动作) × P(正确执行动作) × P(发现并修复错误) × P(保持状态直到完成)
这不是假设各环节统计独立的严格数学公式,而是一种故障定位模型。即使模型具备解决问题的推理能力,只要工具参数持续生成错误、验证结果没有反馈回来、上下文被噪声淹没,最终成功率仍会很低。
图表加载中…
需要同时记住两条边界:
- Harness 能释放已有能力,但不能无限突破模型能力边界。 模型完全不理解某种语言、无法进行必要推理时,继续增加中间件只会提高成本。
- Harness 优化具有模型、任务和环境依赖。 某个 Tool Schema 对模型 A 有效,不代表对模型 B 也有效;某个严格流程适合高风险发布任务,不代表适合一次性文本改写。
因此,“模型决定上限、Harness 决定下限”只能作为帮助记忆的工程表达,更准确的说法是:模型和 Harness 共同决定系统能力,Harness 决定模型能力能否在特定环境中稳定转化。
26.2 两个循环:任务执行循环与 Harness 改进循环
Agent 系统同时存在两个时间尺度不同的循环。
- 内层 Agent Loop:发生在一次 Turn 内,负责观察、推理、调用工具、读取结果、验证并继续。
- 外层 Harness Improvement Loop:发生在多个任务和多个版本之间,负责收集 Trace、归类失败、提出改动、运行 Eval 和决定是否发布。
图表加载中…
两层循环不能混在一起:
- 内层失败后盲目重试,只是在重复当前 Harness 的错误假设。
- 外层只看最终分数,不看内层 Trace,就无法知道应该修改 Prompt、工具还是验证器。
- 外层一次同时修改十个组件,即使分数提高,也无法知道真正有效的变量。
26.3 先定义成功,再谈优化
Harness 优化的第一步不是改 Prompt,而是建立可以比较的成功定义。指标至少分三组:
| 指标类型 | 典型指标 | 回答的问题 | 常见误区 |
|---|---|---|---|
| 结果指标 | 任务完成率、验收通过率、用户纠正率 | 最终做对了吗 | 只看模型是否输出了答案 |
| 过程指标 | Step 数、ToolCall 数、重复调用率、无进展循环率、压缩次数 | 用什么代价做完 | 把步骤越多误认为思考越充分 |
| 系统指标 | 延迟、Token、成本、超时率、恢复成功率 | 系统是否可持续运行 | 只优化成本而牺牲正确率 |
| 安全指标 | 越权提议率、审批拒绝率、沙箱违规、敏感数据暴露 | 是否在边界内完成 | 把没有执行危险动作当作能力不足 |
一套可用于改进的 Eval 应包含四个集合:
- Baseline Set:建立当前版本的基准结果。
- Optimization Set:允许优化器查看 Trace,用来发现并修复失败。
- Holdout Set:不参与改动生成,用来检查是否只是记住了优化题。
- Must-Pass Regression Set:安全、权限、数据完整性等任何版本都不能退化的用例。
复杂任务不要只有一个总分。更可操作的方法是按行为打标签,例如:
| 行为标签 | 可验证问题 |
|---|---|
task_understanding | 是否保留了目标、约束和验收条件 |
context_selection | 是否找到真正相关的文件、状态或记忆 |
tool_selection | 是否选择正确工具并生成有效参数 |
planning | 是否识别依赖、风险和验证路径 |
self_verification | 是否根据任务要求执行真实验证 |
recovery | 中断后是否从已确认事实继续 |
multi_agent_coordination | 子任务是否独立、结果是否可合并 |
safety | 是否遵守权限、审批和沙箱边界 |
26.4 从执行轨迹识别失败模式
最终结果只说明“失败了”,Trace 才能解释“在哪一步开始偏离”。分析时应按时间找到最早可行动的偏差点,而不是只责怪最后一次模型输出。
| 表面症状 | 需要检查的 Trace 证据 | 更可能的根因 | 优先修改的 Harness 杠杆 |
|---|---|---|---|
| 答非所问 | 初始任务解析、计划、验收条件 | 任务契约含糊或关键信息被截断 | Task Contract、Prompt、澄清策略 |
| 找不到已有实现 | 搜索词、读取文件、Context Items 来源 | 仓库地图缺失、检索失败、信息没有注入 | Context Builder、Skill、检索工具 |
| 工具反复报参数错误 | ToolCall JSON、Schema、错误反馈 | Schema 过于复杂、描述含糊、模型与接口不匹配 | Tool Schema、工具命名、示例 |
| 同一文件反复修改 | Edit 次数、测试结果、计划变化 | 首个方案偏见、反馈不足、无循环检测 | Loop Detector、Verifier、Replan |
| 很快宣布完成 | 未完成任务、测试记录、最终检查 | 停止条件只依赖模型文本 | Completion Gate、任务状态、验证器 |
| 上下文越来越长但质量下降 | Token 分布、重复日志、摘要、事实召回 | Context 污染、压缩保真度低 | 选择、折叠、压缩、结构化交接 |
| 重启后重复副作用 | ToolCall/Result ID、外部事实、恢复点 | 副作用没有持久化或恢复时未查事实 | Session、幂等键、事件记录、恢复策略 |
| 子 Agent 互相覆盖代码 | 任务所有权、工作区、合并顺序 | 子任务不独立、共享写空间无隔离 | Task DAG、Worktree、Merge Verifier |
| 权限一直被拒绝 | 规范化动作、命中规则、审批上下文 | 工具粒度过大或策略没有最小权限表达 | Tool 拆分、Policy、Approval UX |
图表加载中…
判断根因时遵循三个原则:
- 先确认事实,再解释模型。 例如命令是否真正执行、文件是否已修改、测试是否真的运行。
- 区分能力失败和接口失败。 模型知道该做什么却无法正确调用工具,属于 Harness 适配问题。
- 区分偶发失败和系统性失败。 单次样本可能来自生成随机性;相同模式跨任务重复出现才值得加入固定中间件。
26.5 Harness 的主要优化杠杆
26.5.1 任务契约:让“完成”成为可检查状态
复杂目标应编译成任务契约,而不是只保留一句自然语言:
- 目标:最终需要改变什么。
- 约束:不能改变什么,必须遵守什么。
- 交付物:代码、文档、报告或外部状态。
- 验收条件:哪些测试、查询或人工判断构成完成。
- 风险与审批点:哪些动作必须等待授权。
- 停止条件:成功、失败、取消、预算耗尽分别如何结束。
任务契约解决的是目标漂移和过早完成。如果验收条件只存在于最初的用户消息里,经过多次 ToolResult 和压缩后很容易被稀释;应将其作为结构化状态在每次完成判断前重新读取。
26.5.2 Context:提供下一步所需的最小充分信息
Context 优化不是“放得越多越好”,而是提高与下一步决策相关的信息密度:
- 用短入口文档提供地图,再按需读取详细规范。
- 区分稳定规则、当前任务状态、最近观察和可检索历史。
- 对长日志先提取错误、时间、命令和证据位置,不把全部原文重复注入。
- 压缩时保留目标、约束、未完成任务、已经确认的事实、失败尝试和下一步。
- 为 Context Item 保存来源、版本、时间和内容哈希,避免旧事实覆盖新状态。
如果 Agent 不知道信息存在,应改善发现入口;如果知道但找不到,应改善检索;如果找到了却没进入当前 Step,应改善 Context 选择;如果进入后被忽略,应调整信息结构与位置。四种问题不能都用“加长 Prompt”解决。
26.5.3 Tool、Skill 与 MCP:接口形状会影响能力转化
模型不是直接操作世界,而是生成对接口的结构化提议。接口设计应满足:
- 工具名称能表达单一动作,避免多个近义工具争夺同一意图。
- Schema 字段少而明确,必填项和枚举与真实执行约束一致。
- 错误结果包含失败类型、可修复信息和安全的下一步,而不是只返回堆栈。
- 大结果支持分页、过滤或写入 Artifact,避免一次 ToolResult 占满 Context。
- 高风险动作拆成“预览/计划”和“提交/执行”,便于权限控制。
- Skill 用渐进式披露提供工作方法;确定且脆弱的步骤用脚本实现,不强迫模型逐步猜测。
- MCP 负责标准化连接,不自动提供权限、可信度和结果质量保证。
工具错误率高时,先检查 ToolCall Trace:是没有选中工具、字段生成错误、执行环境失败,还是结果无法理解。不同阶段需要不同修改。
26.5.4 Planning、Memory 与 Session:把长任务状态移出对话文本
计划应保存目标分解和依赖关系,Memory 保存跨任务可复用事实,Session 保存本次执行事件;三者不能混成一段摘要。
- Plan 回答“接下来做什么、依赖什么、如何验收”。
- Working Memory 回答“本次任务已经确认了什么、还有什么未知”。
- Long-term Memory 回答“跨会话仍值得复用的偏好和知识是什么”。
- Session/Rollout 回答“实际发生过哪些输入、调用、结果、审批和状态变化”。
将中间状态结构化后,模型即使经历压缩、重置或进程重启,也能从稳定对象继续,而不必通过长对话猜测当前进度。
26.5.5 Verifier:让错误产生可行动反馈
Verifier 不只是“再让模型看一遍”。优先级通常是:
- 确定性检查:Schema、编译、单元测试、类型检查、Lint、查询结果。
- 场景检查:浏览器操作、API 流程、数据库状态、文件差异。
- 规则检查:权限、安全、架构边界、交付物完整性。
- 模型评审:主观质量、语义一致性、无法完全形式化的要求。
- 人工审核:高风险发布、不可逆副作用和主观争议。
生成者和评审者共享同一个初始偏见时,自我评审可能只会为已有方案辩护。因此复杂任务应尽量让验证拥有独立证据、独立 Context,必要时使用独立 Agent。
26.5.6 Runtime、安全与恢复:让系统能失败但不失控
Runtime 需要把非确定性限制在可恢复的状态机中:
- 每次 ToolCall 有稳定 ID,ToolResult 与它一一配对。
- 副作用前检查权限,执行后保存结果,再进入下一步。
- 重试区分暂时故障、确定性参数错误、计划假设失效和未知副作用。
- 相同错误连续出现时切换策略,不进行无上限重试。
- 权限审批绑定规范化动作,不能只批准一段未经解析的文本。
- 沙箱强制文件、进程和网络边界,Prompt 中的“不要做”不能替代 OS 约束。
- 恢复时重新捕获 cwd、权限、MCP 连接和文件状态,不复用过期 StepContext。
26.6 复杂长任务的稳定推进
长任务的关键不是让单个 Context 永远增长,而是让任务状态可以跨 Context 延续。
图表加载中…
26.6.1 压缩与重置的区别
| 策略 | 保留什么 | 优点 | 风险 | 适用场景 |
|---|---|---|---|---|
| 原会话继续 | 完整近端历史 | 连续性最好 | 噪声和错误假设累积 | Context 仍健康 |
| 上下文压缩 | 摘要 + 近期历史 | 成本较低,延续主线 | 摘要遗漏、旧偏见仍存在 | 历史过长但方向正确 |
| 结构化交接后重置 | 任务状态和证据,不保留原始推理轨迹 | 新 Context 清晰,可摆脱循环 | 交接不完整会丢状态 | 持续循环、上下文污染、模型出现收尾倾向 |
| Session 恢复 | 持久化事件 + 当前外部事实 | 可处理进程中断 | 未知副作用需要人工或查询确认 | 崩溃、断线、Worker 更换 |
26.6.2 阶段产物比长对话更可靠
复杂任务每完成一个阶段,都应产生可独立检查的 Artifact:需求契约、架构决策、计划、补丁、测试报告、评审结论和交接摘要。下一阶段引用 Artifact,而不是复制全部对话。这样可以降低 Context 膨胀,也让验证器和子 Agent 使用同一事实来源。
26.7 Generator–Evaluator 与 Multi-Agent
Anthropic 2026-03-24 的长任务 Harness 实践把复杂应用构建拆成 Planner、Generator、Evaluator。关键价值不是“Agent 越多越强”,而是把三个互相冲突的职责隔离:
- Planner 聚焦范围、用户价值和高层技术约束,避免过早锁死实现细节。
- Generator 聚焦一次 Sprint 的实现,并产出可验证结果。
- Evaluator 使用运行中的系统、测试和外部状态判断结果,而不是只阅读生成者的解释。
图表加载中…
Multi-Agent 只有在以下条件成立时才值得引入:
- 子任务可以明确描述输入、输出和完成条件。
- 子任务之间不存在隐藏的强顺序依赖。
- 每个 Agent 有隔离 Context,必要时有隔离工作区。
- 根 Agent 只接收状态、摘要、证据和 Artifact 引用,而不是所有子 Agent 的完整历史。
- 合并阶段有统一 Verifier,能发现冲突、遗漏和接口不一致。
否则,多 Agent 只是把一个 Agent 的不确定性扩散成协调不确定性。
26.8 面向不同模型的 Harness Profile
同一模型在不同工具接口下可能表现差异很大,不同模型对相同 Harness 的反应也不同。应把模型相关配置声明为可版本化 Profile:
图表加载中…
Profile 可包含:
- System/Developer Prompt 的结构和重点。
- Tool 名称、参数 Schema、错误格式与是否支持并行调用。
- 上下文压缩阈值、摘要模板与结果截断策略。
- Planning 是否显式、何时使用子 Agent。
- 推理预算在计划、执行、验证阶段的分配。
- 权限默认值、沙箱能力和必须人工审批的动作。
- 模型升级后的兼容测试与旧 Profile 回滚点。
Profile 优化必须使用同一组行为 Eval,不应以“看起来更聪明”作为判断标准。
26.9 Harness Hill-Climbing 实施流程
LangChain 2026-02-17 的实验固定 gpt-5.2-codex,通过 System Prompt、Tools 和 Middleware 的 Harness 改动,使 Terminal-Bench 2.0 从 52.8 提升到 66.5。这个案例的重要性不只是分数,而是它展示了可复用的改进方法:从 Trace 找到重复失败,用针对性改动建立反馈,再通过完整评测检查收益与退化。
LangChain 2026-04-08 的 Better-Harness 进一步把流程整理为:数据来源 → 实验设计 → 优化 → 审核与接受。Meta-Harness 论文则把 Harness 源码、历史候选、分数和执行轨迹交给外层 Agent 搜索,说明 Harness 本身也可以成为优化对象。
26.9.1 一次改进实验的端到端时序
图表加载中…
26.9.2 外层优化循环伪代码
type HarnessVersion = { id, prompt, tools, policies, middleware, modelProfile } // 定义一次可回滚的 Harness 配置快照
type EvalCase = { id, tags, task, oracle, safetyRules } // 定义带行为标签、验收器和安全约束的评测用例
type Trace = { caseId, versionId, steps, result, metrics, safetyEvents } // 定义可关联任务与版本的完整执行轨迹
function improveHarness(fixedModel, baselineVersion, optimizationSet, holdoutSet, mustPassSet) { // 启动固定模型权重的外层优化流程
let accepted = baselineVersion // 把当前线上版本保存为可随时回滚的已接受版本
let baseline = runEval(fixedModel, accepted, optimizationSet + holdoutSet + mustPassSet) // 在修改前记录正确率、效率和安全基线
while (hasBudget() && !targetReached(baseline)) { // 只有预算尚存且目标未达到时才继续搜索
let traces = selectDiagnosticTraces(baseline, optimizationSet) // 从优化集选择失败、反复循环和高成本轨迹
let patterns = clusterByEarliestActionableDeviation(traces) // 按最早可行动偏差聚类而不是只按最终错误文本聚类
let hypothesis = chooseOneHighImpactPattern(patterns) // 每轮只选择一个高影响失败模式形成可证伪假设
let candidate = proposeMinimalChange(accepted, hypothesis) // 在 Prompt、Tool、Policy 或中间件中生成最小候选修改
let optimizationResult = runEval(fixedModel, candidate, optimizationSet) // 先检查候选是否真正修复可见失败
if (!improvesTargetBehavior(optimizationResult, baseline)) continue // 若目标行为没有改善则拒绝候选并进入下一轮
let holdoutResult = runEval(fixedModel, candidate, holdoutSet) // 使用候选不可见的留出集检查泛化能力
let safetyResult = runEval(fixedModel, candidate, mustPassSet) // 使用不可退化集合检查权限、数据和恢复不变量
let decision = compareVersions(baseline, optimizationResult, holdoutResult, safetyResult) // 综合正确率、成本、延迟和安全差异生成晋级决定
if (!decision.accept) recordRejectedCandidate(candidate, hypothesis, decision) // 保存失败候选和反例以防后续重复相同尝试
if (!decision.accept) continue // 候选不满足发布阈值时保持当前版本不变
accepted = versionAndPromote(candidate, decision) // 为通过验证的候选分配版本并进入灰度发布
baseline = mergeComparableResults(optimizationResult, holdoutResult, safetyResult) // 用同口径结果更新下一轮比较基线
} // 结束预算或目标控制的优化循环
return accepted // 返回经过留出集和安全回归验证的最新 Harness 版本
} // 结束外层优化函数
这段伪代码有四个关键点:固定模型、单一假设、留出集和可回滚版本。缺少任何一项,都容易把随机波动或任务记忆误判成系统改进。
26.9.3 单次任务内的自验证循环伪代码
function executeComplexTask(taskContract, session, harness) { // 以结构化任务契约、会话状态和当前 Harness 启动一次复杂任务
let state = session.restoreOrCreate(taskContract) // 从持久化事件恢复或创建包含计划与未完成项的工作状态
while (!state.isTerminal()) { // 只要任务未进入完成、失败或取消终态就继续执行
let context = harness.contextBuilder.compile(state, taskContract) // 从规则、计划、记忆、近期结果和环境构建本步最小充分 Context
if (context.shouldReset) state = createStructuredHandoffAndReset(state) // 当压缩无法消除循环或污染时写交接并切换新 Context
if (context.shouldCompact) state = compactWithInvariantChecks(state) // 接近窗口上限时压缩并检查目标、约束和未完成项是否保留
let proposal = harness.model.sample(context) // 让模型基于固定的本步 Context 生成文本或结构化动作提议
session.recordProposalBeforeExecution(proposal) // 在产生外部副作用前先持久化动作 ID 和规范化参数
if (proposal.isFinalAnswer()) { // 当模型声称任务完成时进入独立完成判断而不是直接退出
let completion = harness.verifier.check(taskContract, state, proposal) // 根据原始验收条件、真实环境和未完成任务验证完成状态
if (completion.passed) state.markCompleted(completion.evidence) // 只有验证通过才把证据写入完成终态
if (!completion.passed) state.addFeedbackAndReplan(completion.failures) // 验证失败时把结构化缺陷加入状态并触发局部重新规划
continue // 完成或重新规划后回到循环顶部统一处理终态与新 Context
} // 结束最终回答分支
let decision = harness.policy.authorize(proposal.normalizedAction) // 使用规范化动作执行权限、审批和风险判断
if (!decision.allowed) state.addObservation(decision.denialResult) // 被拒绝时把原因作为观察反馈给下一步而不执行副作用
if (!decision.allowed) continue // 权限不允许时跳过工具执行并重新构建 Context
let result = harness.runtime.executeInSandbox(proposal, decision) // 在批准范围和沙箱约束内执行实际工具动作
session.recordResultBeforeNextStep(proposal.callId, result) // 在下一次模型采样前持久化与 ToolCall 配对的最终结果
state = reduceEventIntoState(state, result) // 用事件归约更新计划、事实、预算和待验证项
if (detectNoProgress(state)) state.requestStrategyChange() // 连续重复动作且没有新证据时强制重新考虑方案
if (result.isUnknownSideEffect()) state.pauseForFactCheck() // 副作用是否发生无法确认时停止自动重试并等待事实核对
} // 结束由状态机终态控制的 Agent Loop
return session.finalizeWithEvidence(state) // 返回最终状态、验证证据、成本和可审计执行摘要
} // 结束复杂任务执行函数
26.10 结合 Claude Code 与 Codex 源码理解优化原理
两套源码不会出现一个名为 HarnessOptimizer 的统一模块,但它们提供了外层优化所需的全部观测点和可调节面。
26.10.1 Claude Code:显式状态、错误反馈与恢复边界
| 优化原理 | 源码事实 | 为什么影响有效能力 |
|---|---|---|
| Query 使用显式状态 | src/query.ts:270 保存 transition、压缩跟踪、输出恢复次数和 Turn 计数 | 可以区分“为什么继续”,避免把压缩、错误恢复和正常工具循环混成盲目重试 |
| 工具输入先做 Schema 校验 | src/services/tools/toolExecution.ts:614 使用 Tool Schema 校验模型参数并返回结构化 ToolResult 错误 | 参数错误变成模型下一步可修复的反馈,而不是让执行器崩溃或静默失败 |
| 工具还有语义校验 | src/services/tools/toolExecution.ts:682 调用工具自己的 validateInput | JSON 合法不等于动作合理,Harness 需要补充模型无法知道的环境约束 |
| 压缩是完整生命周期 | src/services/compact/compact.ts:389 计算 Token、执行 PreCompact Hook、生成摘要并重建消息 | 压缩不是截断字符串,而是受观测、可插入治理逻辑的状态迁移 |
| 压缩质量可观测 | src/services/compact/compact.ts:652 记录压缩前后 Token、是否会立即再次触发、链路深度和成本 | 可以发现压缩后仍超阈值、反复压缩和高成本等系统性失败 |
| 恢复会重建能力状态 | src/utils/conversationRecovery.ts:446 统一读取会话,src/utils/conversationRecovery.ts:560 恢复 Skill 并处理未解决 ToolUse | 长任务能力依赖 Plan、Skill、工具配对和中断状态,不只是恢复聊天文本 |
| 写入队列维护顺序 | src/utils/sessionStorage.ts:549 保存每文件写队列和 Flush 等待者 | 保证恢复和 Trace 看到稳定事件顺序,降低重复副作用与错序状态 |
| Trace 区分等待和执行 | src/utils/telemetry/sessionTracing.ts:49 区分 LLM、Tool、等待用户、执行和 Hook Span | 外层优化能判断时间花在模型、工具、审批还是扩展逻辑 |
这些实现说明:提高成功率往往来自把错误转为结构化观察、把状态变成可恢复事件、把耗时拆成可行动阶段。单纯让模型“再试一次”无法得到这些能力。
26.10.2 Codex:Prompt 编译、历史不变量与可持久化检查点
| 优化原理 | 源码事实 | 为什么影响有效能力 |
|---|---|---|
| Turn 生命周期可观测 | codex-rs/core/src/tasks/regular.rs:38 在运行 Turn 时发送 TurnStarted 并建立 run_turn Span | Eval、UI 和恢复可以共享同一 Turn 身份和时间边界 |
| Prompt 由类型化对象构建 | codex-rs/core/src/session/turn.rs:1288 将输入、可见工具、并行能力、基础指令和输出 Schema 编译为 Prompt | Profile 可在明确位置调整工具集合、并行策略和输出约束,而不是拼接不可审计字符串 |
| 历史发送前规范化 | codex-rs/core/src/context_manager/history.rs:141 通过 for_prompt 规范化历史 | 保存的原始事件与模型实际看到的 Context 分离,便于重放和优化 Context 投影 |
| ToolCall 配对是不变量 | codex-rs/core/src/context_manager/history.rs:325 补齐缺失输出并移除孤立输出 | 防止压缩、恢复或截断产生模型无法理解的工具历史 |
| 压缩区分发生时机 | codex-rs/core/src/compact.rs:57 区分 Turn 前压缩和 Turn 中压缩的初始 Context 注入 | 同一摘要在不同生命周期位置需要不同装配策略,不能只用一个固定模板 |
| 压缩形成持久化检查点 | codex-rs/core/src/compact.rs:368 替换历史、记录窗口、重算 Token 并发送完成事件 | 外层优化可比较压缩后准确性,也能从检查点恢复而不是重新猜测历史 |
| Resume/Fork 重建有效状态 | codex-rs/core/src/session/mod.rs:1317 重放 Rollout,并在模型变化时发出警告 | 说明 Harness 与模型存在适配关系,恢复时模型变化本身就是质量风险 |
| Fork 前强制 Flush | codex-rs/core/src/agent/control/spawn.rs:648 在子 Agent 快照父历史前刷新 Rollout | Multi-Agent 分发必须基于稳定父状态,否则子 Agent 会从不一致 Context 开始 |
| Turn Timing 分解阶段 | codex-rs/core/src/turn_timing.rs:43 分别累计 Sampling、Compaction、Tool Blocking 和中间开销 | 可以针对真正瓶颈调整模型预算、工具并行、压缩或审批体验 |
源码共同指向一个结论:Harness 优化的对象不是一段提示词,而是从 Context 编译、动作提议、受控执行、事件持久化、验证到恢复的完整闭环。
26.11 如何防止 Harness 优化变成过拟合
Harness 可以像代码一样过拟合评测用例。常见表现包括:
- Prompt 直接写入某道题的关键词和答案路径。
- 为少数失败增加大量特殊分支,导致普通任务成本上升。
- 只优化总分,掩盖安全或某类关键任务退化。
- 优化器知道全部测试内容,通过识别测试特征进行指标投机。
- 新模型已经自然解决旧问题,但 Harness 仍保留过期限制。
控制方法:
- 按行为标签分层抽样,保留不可见留出集。
- 一轮只验证一个可解释假设,保存接受与拒绝记录。
- 同时比较正确率、效率、安全和用户体验。
- 新增失败用例时补充相邻负例,防止规则触发过宽。
- 模型升级后运行“移除组件”实验;没有增益的 Prompt、Skill 或中间件应退役。
- 对 Profile、Eval、Trace Schema 和 Harness 配置统一版本化。
26.12 贯穿案例:Agent 过早宣布“已经完成”
假设编码 Agent 经常修改实现后直接回复完成,却没有运行测试。
26.12.1 第一步:建立事实
从 Trace 确认:模型是否知道验收条件、是否拥有测试工具、是否调用过测试、测试结果是否进入 Context。如果测试工具本身不可用,问题不是“模型懒惰”,而是执行环境缺失。
26.12.2 第二步:形成单一假设
假设为:“模型把代码看起来合理当成完成,因为 Harness 在最终回答前没有独立完成门禁。”
26.12.3 第三步:设计最小修改
增加 Completion Gate:当模型要结束 Turn 时,检查任务契约中的测试要求和本轮验证证据。没有证据则返回结构化反馈:缺少哪些验证、应执行什么、哪些未完成任务仍为 Open。
26.12.4 第四步:运行分层评测
- 优化集:过去发生过早完成的任务。
- 留出集:不同仓库但具有相同“必须验证”行为的任务。
- 回归集:不需要测试的只读问答,避免 Completion Gate 强迫所有任务运行无关命令。
- 安全集:测试命令需要高权限时,确保门禁不会绕过审批。
26.12.5 第五步:决定是否发布
如果验收通过率提升,但平均步骤翻倍,应检查是不是每轮都重复测试;如果留出集没有提升,可能只是记住了优化集措辞;如果只读任务受到干扰,说明门禁触发范围过宽。只有收益、成本和安全都在接受范围内,才灰度发布。
26.13 反模式、方案表达与资料来源
26.13.1 常见反模式
| 反模式 | 为什么无效 | 更好的做法 |
|---|---|---|
| 失败就换更大模型 | 掩盖 Context、Tool 和验证缺陷,也无法解释收益来源 | 固定模型建立基线,先定位最早偏差点 |
| 把所有知识塞进 System Prompt | 挤占任务 Context、规则易过期且难验证 | 短入口地图 + 渐进式加载 + 来源版本 |
| 工具越多越强 | 增加选择混淆、Schema Token 和权限面 | 保留正交原子工具,按任务和 Profile 暴露 |
| 让生成 Agent 自己说“测试通过” | 模型文本不是环境事实 | 由 Runtime 执行验证并保存 ToolResult |
| 多 Agent 默认并行 | 增加协调、冲突和 Context 合并成本 | 只并行独立任务,并设置工作区和所有权 |
| 对所有错误自动重试 | 参数错误和未知副作用不会因重试自动消失 | 先分类,再决定重试、重规划、核对事实或停止 |
| 只看平均分 | 隐藏关键任务和安全退化 | 行为分组、留出集、Must-Pass 与差异 Trace |
| Harness 只加不删 | 旧模型缺陷对应的规则会变成新模型束缚 | 运行消融实验,退役无增益组件 |
26.13.2 两分钟方案表达模板
我不会把优化 Harness 理解成继续堆 Prompt,而会先固定模型和任务分布,定义结果、效率与安全指标。然后从 Trace 找到最早可行动偏差,判断是目标契约、Context、Tool 接口、执行控制、验证还是恢复问题。每轮只提出一个可证伪假设,生成最小 Harness 改动,在优化集验证修复效果,再用留出集检查泛化、用必须通过集检查安全和回归。通过后发布版本并保留回滚点,线上失败继续沉淀成 Eval。对于复杂长任务,我会把 Plan、Working Memory、Session Event 和 Artifact 分开持久化,按 Context 质量选择继续、压缩或结构化交接;生成与验证也尽量使用独立证据。这样提升的是模型能力向任务结果的转化率,而不是声称改变了模型权重。
26.13.3 推荐资料与证据边界
一手工程与研究资料:
- OpenAI,2026-02-05,Harness engineering: leveraging Codex in an agent-first world:仓库知识地图、反馈循环、Agent 可读的 UI/日志/指标和人类掌舵模式。严格说比本章半年检索窗口早一天,但属于关键原始资料。
- LangChain,2026-02-17,Improving Deep Agents with harness engineering:固定模型、Trace 分析、自验证、循环检测和 Terminal-Bench 2.0 实验。
- LangChain,2026-03-10,The Anatomy of an Agent Harness:从模型原生缺失的状态、执行和约束能力推导 Harness 组件。
- Anthropic,2026-03-24,Harness design for long-running application development:Planner–Generator–Evaluator、结构化交接、压缩与重置的权衡。
- LangChain,2026-03-26,How we build evals for Deep Agents:行为分类、Trace 转 Eval、正确率和效率指标。
- Yoonho Lee 等,2026-03-30,Meta-Harness: End-to-End Optimization of Model Harnesses:使用源码、历史候选、分数和 Trace 自动搜索 Harness;属于预印本,应与生产实践分开理解。
- LangChain,2026-04-08,Better Harness:优化集、留出集、回归、人工审核和 Trace 飞轮。
- LangChain,2026-04-29,Tuning Deep Agents to Work Well with Different Models:模型专属 Harness Profile 与同一 Eval 下的适配比较。
个人研究与中文解读:
- Philipp Schmid,2026-04-13,8 Tips for Writing Agent Skills:Skill 触发、渐进加载、负例和退役机制。
- Philipp Schmid,2026-05-05,Four Subagent Patterns:同步、异步、Fan-Out 和长期 Agent Pool 的边界。
- 李自然,2026-05-14,Harness 完全指南:中文分层、最小 Harness 和 Harness 是否会被模型吸收的争论。
- iDao,2026-05-16,Harness 驾驭工程深度教程:仓库地图、CI 门禁、Hook 和工程落地顺序。
- JavaGuide,2026-05-21 更新,一文搞懂 Harness Engineering:中文概念导航和案例索引,指标仍需回到原始文章核验。
- 冬哥有话说,2026-03-23,Agent Harness 与 Harness Engineering 深度剖析:上下文、工具门控、状态持久化与治理视角。
- 克己,2026-04-01,Harness Engineering 到底是什么、怎么运作:渐进式披露、执行控制、压缩和验证循环。
这些个人文章用于补充解释框架和发现线索,不替代官方源码与原始实验。检索到的小红书相关内容因原文已无法稳定访问,作者、日期和正文不能完整核验,因此没有作为本章事实证据。