CAR Bench Challenge 技术方案

背景

CAR-bench:车载语音 Agent 基准。

  • CAR-bench 简介
  • Challenge 最终排行榜
  • 技术报告原文

  • 254 个任务、58 个工具、19 条车载策略
  • 用户、环境、工具调用:评测器控制
  • 每题独立运行 3 次;Pass³ 要求 3 次全过
  • 一次错误调用、一次漏读前置状态、一次不合规回复:该 trial 归零

三类任务:

类型 额外困难 正确行为
Base 多轮工具操作、策略级联 先读状态,再按顺序执行
Hallucination 工具、参数或返回字段被移除 承认能力缺失;不盲调、不编造、不承诺完成
Disambiguation 用户没有给全取值 能内部消解则内部消解;需要时读取偏好;不猜

这个基准测的不是“偶尔能不能做成”,而是“能不能每次都守住边界”。

我的方案:Ground, then Act

模型:DeepSeek V4 Flash;官方隐藏集 Pass³ 53.3%,$0.0055 per trial,打败 GPT-5.6 Sol baseline 中成本最低方案 (其他队伍方案成本的 1~3%)。

目标:不靠更大的模型;在工具调用前,把高确定性的错误拦在 harness 中。

其他过半队伍的方案也是做 guardrail, 就不赘述.

结构

用户消息 + 工具
        ↓
ReAct 模型提出调用
        ↓
schema / 偏好 / policy 三道门
        ↓
放行原调用 | 扣留、反馈、重提议 | 诚实拒答
  • Owned prompt:能力缺失时承认,不强行完成
  • Schema gate:参数必须符合实际工具接口
  • 偏好判别器:对用户未明说的写入值,区分“有依据”与“猜测”;猜测则先读 get_user_preferences
  • Policy gate:确定性检查策略、顺序和级联后的预测状态
  • Unknown disclosure:返回字段未知时,强制在下一句说明
  • 至多 3 次重提议:仍失败则无工具诚实说明;绝不把已拦截的调用再放出去

关键原则:

  • 策略、schema、状态约束:代码
  • 语义边界:小范围 LLM 判别
  • 被拦截的调用:只存在于内部上下文,绝不 dispatch
  • 跨轮状态:仅从已执行调用和真实工具结果重放

效果与成本

公共训练集,同一 DeepSeek V4 Flash、不开推理:

配置 Pass³ Base Hallucination Disambiguation
官方 baseline 47.7% 66% 42% 35%
三门 harness 60.4% 66% 67% 48%
  • 总体:+12.7pp
  • Hallucination:+25pp;核心收益
  • Disambiguation:+13pp
  • 着重优化这两类任务的原因是最终评分算三类任务 macro-avg, 先优化分数低的任务性价比高
  • Base:持平;守卫没有牺牲常规任务
  • 延迟:12.4s → 13.2s1.06×
  • 成本:约 $0.0011 / trial;提示缓存命中 94.7%
  • 开启高推理:训练集 68.3%,隐藏测试 62.0%;成本约 $0.0042 / trial

创新点不在“又加了一个 prompt”,而在把失败会造成不可逆扣分的动作,改成:

提出 → 可验证 → 放行
       └→ 不可验证 / 不合规 → 不执行

得失

有效:

  • 缺失参数、未知结果字段:从盲调/沉默变为诚实披露
  • 偏好相关写入:从猜值变为先读偏好
  • 级联策略:从“调用过工具”升级为“预测后的状态满足约束”

仍然困难:

  • 被删的导航编辑工具:评测期望承认缺失,静默绕路也可能失败
  • 消歧中的“该内部判断还是该问用户”:纯规则很难完整覆盖
  • 个别题目的参考解存在合理解释空间

冠军方案:TRACE

冠军:Darwin Agent;GPT-5.6 Sol,隐藏集 Pass³ 70.0%,$0.27 per trial。

核心不是运行时叠更多 guardrail,而是离线从评测轨迹中蒸馏一组可检索技能,再在每一轮按对话状态注入相关技能。

  • 冠军:单次成功 70.0%Pass@3 83.3%Pass³ 70.0%
  • 我的方案:单次成功 66.7%Pass@3 83.3%Pass³ 53.3%
  • 不是“冠军有更多偶发成功”;两者至少成功一次的题数相同
  • 冠军优势:consistency 更强, 无法判断是否为模型本身强度所致

方案上其实和我类似都是用个 meta agent 去分析 trace 改进 harness. 不过 Darwin Agent 六个人一整个团队, 加上之前做过类似的 HarnessX, 方法可能更成熟一些. 叫 Darwin 应该是因为这套范式通常叫自进化 agent.

机制

冠军提交的技术报告:TRACE。源码尚未公开;以下是报告明确写出的流程。

离线:多轮评测轨迹 → 初始化 skill bank → 反复对比改写
在线:当前对话 + skill 描述索引 → 自选少量 skill → 注入正文 → 工具动作

两个角色:

  • Actor:运行时的普通 tool agent;选 skill、对话、调用工具
  • Curator:离线读评测轨迹;创建、改写、拆分 skill

每条 skill 有两部分:

字段 放什么 运行时作用
描述 一行说明;触发短语、适用操作 常驻 prompt;组成轻量索引
正文 工具规则、决策准则、常见失败、流程 选中后才注入当前回合 prompt

关键不是“把所有经验写进一个长 prompt”,而是让每条 skill 足够窄、可被当前回合重新选中。

1. 冷启动 skill bank

先在训练集上对每题运行多轮。Curator 对同题的成功与失败轨迹做 task-level 蒸馏;再连续抽象:

同一 task 的多条轨迹
        ↓ 去掉偶发路径,保留成功行为 + 常见错误
task skill
        ↓ 合并同一 task type,移除 task 专属细节
type skill
        ↓ 跨 type 按底层操作合并
operation skill
        ↓ 拆开过宽 skill
初始 skill bank
  • task-level:记录某一任务怎样成功、怎样失败
  • type-level:只保留同类任务共有的行为
  • operation-level:把表面目标不同、底层操作相同的经验合并
  • decomposition:大而模糊的 skill 拆成单一能力;提高检索精度

报告没有公开实际 skill 文本或数量;能确认的是它们以 Markdown SKILL.md 保存。

2. 进化:按“实际命中的 skill”归因

每一轮先用当前 skill bank 跑评测,再根据轨迹更新 skill bank。

步骤 实际做法 要解决的问题
Skill-aware grouping 按轨迹各回合真正选中的 skill 分组 不把失败笼统归给整个 agent
Runtime-faithful reconstruction 重建 Actor 当时能看到的上下文;把离线特权信息单独标注 不把答案或不可见环境信息写进 skill
Contrastive refinement 对同一 skill 的成功 / 失败轨迹做对比,直接改写该 skill 让规则同时包含“该做什么”和“为何会错”
Split / discover skill 太宽就拆;无 skill 命中的重复模式则新增 skill 控制粒度,补齐覆盖空洞

重建时,共享的基础 prompt、工具列表只写一次;每道题只附相对 baseline 的 capability changes。离线分析能看到奖励、期望动作等诊断信息,但 skill 只能依赖 Actor 运行时可见的内容。

3. 部署:逐回合自选择,而不是常驻全文

常驻:所有 skill 的描述
        ↓ Actor 根据当前对话自选相关 skill
选中:对应正文注入 prompt
        ↓ Actor 产生本回合动作
下一回合:丢弃本回合正文;重新从描述索引选择
  • 不需要额外 retriever;报告中的选择器就是 Actor 自己
  • 每回合可选多个 skill;选中正文不跨回合累积
  • 对话从“明确请求”变成“发现能力缺失 / 需要消歧”时,下一回合可切换 skill
  • 代价:skill bank 变大后,LLM 自选描述的检索可能扩展性变差

4. 两条防过拟合约束

  • operation-level organization:技能写“怎样执行一类操作”,不写某个 task 的答案
  • de-hardcoding:禁止 task id、环境专属取值、记忆答案;只保留可迁移的工具与决策原则

这解释了为何同一 skill bank 在 GPT-5.5 轨迹上进化后,还能原样放到 GLM-5.2 上评测。

5. 报告的实验边界

  • skill bank:先用训练集冷启动,再用测试集轨迹扩展覆盖
  • 结果:训练与测试合并后的完整 CAR-bench 自测
  • 模型:GPT-5.5 medium 上进化 skill bank;原样迁移到 GLM-5.2 high
  • 因而 94.5% Pass³ / 84.8% Pass³ 说明方法很强,但不是严格 held-out 泛化估计 (过拟合嫌疑)
  • 官方隐藏榜的冠军配置:GPT-5.6 Sol,Pass³ 70.0%;与上述自测不能直接横比

HarnessX on τ²-bench

因为冠军方案没开源, 但是 darwin agent 团队有个开源的 HarnessX, 以及 car-bench 本身也是模仿 tau-bench 的, 所以看下这块代码.

相关源码:

以下按 bf5f199(2026-07-29)源码核对。

TRACE 产出的是 skill bank;HarnessX 的 meta-harness 产出的是下一版 harness

Meta-agent:一个有严格交付契约的简单 loop

是 HarnessX 自己的单 agent loop,默认模型为 Claude Opus 4.6 + extended thinking。

读本轮任务说明、历史 memo、轨迹
        ↓
找跨任务模式;写 candidate 假设
        ↓
写下一版 config / processor / prompt
        ↓
自检 + 记录 journal
        ↓
外层 runner 真实评测;保留或回退

没有 planner / executor 多角色编排。复杂性在输入、输出、验证、跨轮记忆的文件契约

  • 只写本轮 output_dir 与 journal;不能改框架源码
  • 必须写出可加载的 config.yaml;无改动也要复制旧 config
  • 每个非空改动先写 Candidate C-NNN:失败模式、受影响任务、为什么选这个 lever、不选相邻 lever 的理由、收益/回归/成本预测
  • runner 回填上一轮的 accepted / reverted 与逐题归因;下一轮不应重试已失败的同一假设

它实际读到的 prompt

不是一份巨型 prompt;由一份角色说明、每轮文件和按需 skill 组成。

内容
SOUL.md 身份:从轨迹交付新 HarnessConfig;七步 loop;Pareto 规则;硬约束
TASK.md 本轮 config、轨迹目录、输出目录、预算、路径
memo_path + CONTEXT.md 过往假设、接受/回退结果、lever scoreboard
analyze skill 用 failure / capability-gap / success 三种 lens 读轨迹;在 configuration / control / action / instruction 四种 lever 中选修复方式
tau2-playbook τ² 特有失败模式、已有可用 processor、策略与 tool 约束
reference skill YAML schema、hook 表、MultiHookProcessor / Jinja 的编写方式
validate skill canonicalize、dry-fire、hook contract、literal scan
journal skill 跨轮记录格式;下一轮的唯一持久记忆

SOUL.md 的核心要求:

  • 修 harness deficiency;不把 model capability gap 伪装成 prompt 补丁
  • passing trace 和 failing trace 同样重要;修失败时要保护已成功模式
  • 目标是全局净收益;单题收益但有回归风险,默认不做
  • 禁止把任务 id、答案、环境专属常量塞进产物

SOUL.md:不是“帮我调参”,而是一套决策规程

阶段 SOUL 强制行为
读历史 先看 memo、已接受/回退假设与 lever scoreboard;跳过已证伪方案
读轨迹 先扫 frontmatter;某模式占主导时,再读代表性对话正文
写候选 每个改动写 Candidate C-NNN;附收益、回归风险、成本变化与 rollback trigger
写产物 config.yaml 必须存在;可写 processor、tool、template
自检 canonicalize;写了代码再 dry-fire / contract check;literal scan 只告警
留记忆 journal 追加本轮假设;外层评测填 accepted / reverted / 逐题归因

先判断:

  • Harness deficiency:动态信息缺失、重复的危险动作、工具结果难用 → 可以改 harness
  • Model capability gap:缺领域知识、某类推理能力不足 → 记录后跳过;不能靠塞题目知识假装修好

两道刹车:保护成功模式;预先声明回退条件。

analyze skill:把 trace 变成可证伪的改动

输入:每题一份 Markdown 轨迹。

  • frontmatter:eval_passed、reward、退出原因、步骤数、工具/错误计数、成本
  • body:决定性回合真正看到了什么、调用了什么、为何失败
  • eval_* 是正确性真值;LLM judge 只用于解释失败形状

两个轴给候选定位:

选项 作用
Lens failure / capability gap / success 不只修失败;成功轨迹也可锁定或迁移
Lever configuration / control / action / instruction 调参数、写 hook、加 tool、改提示

候选至少覆盖两个任务;还要通过反事实检查:

  • corrective:这个修复早存在,失败题会过吗?
  • preservative-lock:去掉成功习惯,已通过题会挂吗?
  • preservative-transfer:把成功习惯施加到失败题,能在关键回合解锁吗?

analyze 的实际工作单元

它不输出“失败原因总结”;输出可交给下一步实现的 candidates.md

## Candidate C-001
[lens: failure | lever: control | intent: corrective]

- Tasks affected: task-011, task-042, task-108
- Signal: 三题均在同一 tool 输出后失败;`tool_error_counts = 0`
- Verified: 正文显示 tool 已取到数据,但输出格式无法被 agent 使用
- Why Control not Action: 信息已返回;缺的是后处理,不是再发明一个 fetch tool
- Retroactive check: 有解析后的结果,关键回合可继续
- expected_global_gain / regression_risk / cost_shift / rollback_trigger

因此它在强迫 meta-agent 回答四个常被跳过的问题:

问题 防止什么
为什么是这个 lever,不是相邻 lever? 用 prompt 逃避真正的工具/控制缺口
是否有至少两个不同输入的任务? 为单题 hardcode
轨迹正文是否支持根因? 只看计数和 reward 的事后猜测
改动先前存在时真能改变关键回合吗? 修下游症状,不修上游原因

典型判别:

轨迹证据 analyze 倾向的 lever
budget_exceeded,但最后几步仍在有效推进 Configuration:提高 CostGuard 上限
tool 返回二进制/重定向页面,agent 无法消费 Control:on_after_tool 规范化结果
已有数据和推理正确,只是输出格式被 judge 判错 Instruction:加明确输出规则
三题都缺同一种、现有工具无法取得的信息 Action:新增窄工具
成功题都先列计划,失败题直接工具乱撞 Instruction / Control:把计划习惯锁定或迁移

刻意限制:capability gap 不等于 prompt 问题。现有工具没有某能力时,增加一句“请仔细思考”不算修复。

tau2-playbook:把抽象 loop 接到具体 benchmark

它不是答案库;是 τ² 的任务模型与 failure map:

  • reward = DB 状态 × action checks × NL assertion;任一为零,全题零
  • 标准节奏:读状态 → 诊断 → 用户确认 → 写工具 → 收尾
  • retail:订单状态决定 modify / exchange;退货不能换支付方式
  • airline:basic-economy 不可改;必须取得用户与 reservation id
  • telecom:用户侧开关要先指导用户操作、等确认、再读取状态
轨迹形状 首选修改
首轮就写、未读状态 上调 PhaseAwareToolFilter.read_only_steps
同一调用反复循环 调整 / 加入 loop detection
工具输出类型或参数不稳 parse retry、type correction、tool-failure guard
策略顺序错 SystemAppendProcessor 追加 domain guidance / 决策树
telecom 状态满足某条件 启用 PolicyHintProcessor 注入 remediation hint
每回合都漏相关策略 on_before_model IRMA processor

Playbook 的完整技术清单

已在 harness_config.yaml 接入:

技术 作用 可调项
Phase-aware tool gate 强制先读后写 read_only_steps
Loop detection 阻断重复 tool call / confirmation loop 阈值
Parse retry 模型输出不符合工具格式时重试 重试次数
Tool-call correction 修正 bool / int / float 等常见类型错配 启用 / 规则
Tool-failure guard 连续工具错误后尽早停止 错误上限
Token budget 上下文超窗时截断 上下文比例
SystemAppendProcessor 原始 τ² policy 后追加领域指导 guidance 文件
PolicyHintProcessor telecom 条件命中时注入正向提示 按域启用
Extended Thinking 任务 agent 增加推理 token thinking budget
StopGuard 确认消息中移除过早 ###STOP### --stop-guard

Playbook 建议 meta-agent 视轨迹新增:

技术 对应产物 适用迹象
Policy → decision tree guidance_<domain>.md 反复错过政策分支或顺序
IRMA input reformulation on_before_model processor 规则已在 prompt,却未在当前回合激活
Plan-confirm-execute plan guidance + 写前 gate 不可逆写、幻觉 ID、漏确认
Trust-score revision on_after_model processor 输出偶发不可信、可局部重写
Dependency-aware reordering guidance / planner control 用户给的顺序违反策略前置条件
Case-specific guard on_before_tool processor 同一状态—动词错配跨任务复发

后半是候选库,不等于每轮都会启用;其论文中的 lift 引用也不是 HarnessX 自身的端到端 ablation。

tau2-playbook 如何指导一次真实诊断

它给每份轨迹一个 domain-specific 检查顺序:

领域 先看什么 常见“看似合理、实际零分”
Retail order status、产品/支付限制、是否已经确认 对 delivered order 调 modify_pending…;退货时换支付方式;只处理用户多请求的一半
Airline cabin、reservation / user id、用户隐藏约束 修改 basic-economy;猜 ID;没问清 EWR vs JFK 这类约束
Telecom issue hierarchy、用户侧还是 agent 侧操作、确认后的状态 agent 直接“打开”用户手机设置;未等确认就继续;未 re-read 结果

它要求从 τ² evaluator 的三块结果反推,而不是只看最终 reward=0

evaluator 信号 应检查的根因 常见配置方向
db_match=false 写工具、参数、执行顺序、过早停止 phase gate、policy guidance、on_before_tool guard
action check 缺失 / 多余 漏确认、重复写、选错工具 loop guard、顺序提醒、状态—工具映射
nl_assertion 失败,DB 正确 过度承诺、遗漏解释、编造限制 system append guidance / response-side control

它也区分两种性质不同的修复:

  • Harness 问题:前两步就写、循环、类型错误、确认消息被 ###STOP### 吃掉。可由 gate、retry、StopGuard 修。
  • 策略表达问题:模型读到完整 policy 仍没在当前回合激活正确分支。可用 SystemAppendProcessor 把规则压成触发条件 → 检查 → 动作的 guidance。

IRMA 是更动态的一层:不永久增加整份 prompt;每次 on_before_model 从当前轨迹中挑相关 policy、候选工具和顺序提醒,插到该回合上下文。它适合“规则存在但经常没被激活”,不适合“工具本身不存在”。

它到底改什么

不改:任务 Agent 的模型权重;τ² 的环境、评测器、原始工具和原始系统策略。

它改的是 HarnessConfig一份声明“这个 Agent loop 装哪些部件、按什么参数运行”的 YAML

配置面 真实改动 τ² 例子
Processor 列表 添加、删除、排序、传 constructor 参数 LoopDetectionProcessorParseRetryProcessorToolCallCorrectionLayer
既有 processor 参数 改现有组件的阈值 / 预算 / 行为 read_only_steps: 2 → 3;token 或 cost guard 阈值
自定义 control YAML 用绝对 file://...py::Class 引入新 MultiHookProcessor on_before_model 插入 policy reminder;on_before_tool 阻止状态不匹配的写操作
Prompt builder TemplateSystemPromptBuilder 指向新 .j2;或用 overlay processor 普通 benchmark 可替换 template;τ² 只能在保留原策略 prompt 的前提下追加 guidance
Tool registry 增删 builtin / custom @tool 真正缺少某一类能力时才加;不是默认方案
运行槽位 tracer、workspace、sandbox 等声明配置 记录 trajectory,供下一轮读取

τ² 的特殊点:系统 prompt 由 benchmark 注入,NullSystemPromptBuilder 会原样通过。直接换成 Jinja template 会丢掉完整 policy 与工具说明。因此 prompt 改动通常是:

原 τ² system prompt
        +
domain guidance Markdown
        ↓
SystemAppendProcessor 在 on_task_start 合并
        ↓
每轮模型调用看到合并后的 prompt

一个最小的自定义 processor 接入形状:

processors:
  - _target_: file:///abs/output/processors/irma.py::IrmaProcessor
    max_hint_chars: 600

IrmaProcessor 是一个 MultiHookProcessor 子类;它实现 on_before_model / on_before_tool / on_after_tool 等 hook,把 event 原样放行、替换字段,或在明确规则下拦截。YAML kwargs 直接传给它的 __init__

τ² 的 hardened baseline 本身已有:

  • 前两步只暴露 read tool 的 phase-aware filter
  • loop detection、工具调用解析重试、参数类型纠正、连续工具失败保护
  • StopGuard:用户在确认语中夹带 ###STOP### 时,移除过早停止标记;避免写操作尚未执行就结束

meta-harness 的输入与产物

R0:基线 config 跑 τ² 任务
    ↓
每题 reward + 对话/工具轨迹 + 当前 config
    ↓
Meta-agent(默认 Claude Opus 4.6)读失败模式
    ↓
R1:config.yaml + processors/*.py + templates/*.j2
    ↓
重新评测;回退明显退化的 config
  • 普通多轮:在固定任务集上反复“评测 → 改 config → 评测”
  • badcase loop:后一轮只看前一轮仍失败的任务;产出一串针对残余失败的 config
  • 当前代码的保留线:平均 reward 不得比历史最优低超过 2pp
  • 验证:config canonicalize、合成任务 replay、processor hook contract;并记录证据与变更集

实际常见改动不是重写工具逻辑,而是运行时消息增强(IRMA):

  • “还没有查完所有订单”
  • “先修改地址,再修改商品”
  • “策略未明确禁止时,尝试调用工具,不要编造限制”

它产出的结果

先区分两类数字:

结果 设置 含义
HarnessX adapter Sonnet 4.5 + Extended Thinking;GPT-5.2 user simulator;1 trial telecom 86.0% vs leaderboard 84.9%;airline 74.0% vs 72.0%;retail 71.1% vs 72.4%
meta-harness badcase loop Qwen 3.5 27B;retail 114 题 文档示例:92/114 = 80.7% 起步;22 个失败中修复 18 个;推算 110/114 ≈ 96.5%

96.5% 的具体算法:

C1:全量 114 题 → 92 通过,B1 = 22 失败
C2:只在 B1 上进化 / 评测 → 修复 11,B2 = 11
C3:只在 B2 上进化 / 评测 → 再修复 4,B3 = 7
C4:只在 B3 上进化 / 评测 → 再修复 2,B4 = 5
C6:只在 B4 残余上进化 / 评测 → 再修复 1,B6 = 4
估算:原 92 + 累计修复 18 = 110;110 / 114 = 96.5%
  • C{k}C{k-1} 继续修改;不是给每个 task 单独写 agent
  • 每轮只喂仍失败的 task trace;让 meta-agent 专注 hard residual
  • 最终仍有 4 题未解:79、100、105、112
  • 没有重新运行 114 题验证最后的 C696.5% 假设此前 92 个成功 task 永不回归
  • 文档也明确要求:正式结论前应全量 rerun final config

第二行更接近“meta-harness 进化”的结果,但不能当严格最终榜分:

  • 后续轮只评上一轮失败子集
  • 96.5% 假设已通过的题不回归;文档明确建议最后重跑全量验证
  • 默认 num_trials=1
  • 仓库未提交该实验的逐题运行产物;目前只能复核代码和文档中的汇总/示例

论文中的详细 case analysis

HarnessX 技术报告 的详细个案主要来自 GAIA、ALFWorld、WebShop、τ³-bench;不是 τ² recipe 的实际运行产物。

GAIA / Sonnet 4.6 / Round 10:一次完整的“发现 → 修改 → 验证”

阶段 证据与动作
R9 状态 通过率 74.8%;此前峰值 77.7%,已有回归
Trace 信号 23 个失败中,Wikipedia WebFetch 多次返回 0 字符;两个代表性任务累计 10 次空响应
根因 Wikipedia 新前端使 browser-style fetch 超时或得到空 body;不是模型不知道该查什么
Planner 目标 修复持续存在的 source-access 问题;撤销 R9 中造成回归的 prompt / budget 改动

最终只批准候选 C-R10-02

工具:新增 WikiTextFetch,绕过浏览器,调用 MediaWiki API
提示:查 Wikipedia 时优先用 WikiTextFetch
配置:回到 R8 基线;注册新工具;移除有问题的 budget processor

Critic 不是直接相信代码:

  • API 真实返回文章全文:示例分别为 10,52980,028 字符
  • 长工具结果能经 provider 序列化后完整到达模型上下文
  • 新候选包含“回退 R9”的效果;因此拒绝只回退、不修检索的竞争候选
  • 预注册:预期解锁 5 题、稳定 2 题;至少要观察到一次 WikiTextFetch 调用

结果:

  • 74.8% → 79.6%+4.9pp;该 run 最大单轮提升
  • 预期受影响 7 题中 5 题翻转成功;hit rate 0.71
  • 提升主要发生在 GAIA Level 2 / 3

但它没有把这轮当作“问题解决”:

R10:新工具修复真实检索失败;分数上升
R11:trace 发现少数通过来自 verifier 的格式规律,而非真实检索
R12:加 guard;只有能被第二条检索路径交叉验证时才允许该工具

这个案例展示的重点:HarnessX 不是自动加 prompt。它同时改工具、prompt、config;再用 trace 检查分数提升是否来自真正能力,而不是评分漏洞。

另外三种失败病理

病理 论文案例 发生了什么 后果 / 修正
Reward hacking GAIA R10–R12 新检索工具既修复空响应,也让少数任务利用 verifier 格式通过 R11 trace 发现;R12 要求第二检索源交叉验证
Catastrophic forgetting τ³ Telecom,Sonnet 4.6,R2–R9 连续 5 轮叠加同类 reminder;89.5% → 100% → 94.7%,第 6 条规则使其跌至 80.7% R8–R9 以结构化 edit 替换冲突 rule stack,恢复到 99.1%
Under-exploration ALFWorld,Sonnet 4.6,R4–R7 长期只探索 prompt edit;每轮增益 <1%;预测翻转命中率 80% → 0% 识别 prompt 空间耗尽;但唯一一次 processor edit 也仅命中 1/7,最终停在 94.8%

论文给出的反面结论也重要:每轮 gate 能挡住明显坏改动,却未必能发现多个“单独无害”的 rule 逐步耦合;GAIA 的 variant isolation 是他们针对这种全局遗忘提出的补救。

附录:HarnessX Meta-Agent 原始 SOUL.md

来源:HarnessX@bf5f199

# HarnessX Meta-Agent

You analyze trajectories from a HarnessX agent's last benchmark round
and ship an evolved `HarnessConfig` that should close one or more
capability gaps.

## Loop

Skill-reading is lazy — read each skill the first time you need
its content, not preemptively. The arrows below mark where each
skill becomes relevant.

1. `Read _meta_scratch/TASK.md` — paths, memo, budgets, journal
   context (if prior rounds exist).
2. `Read memo_path` and `_meta_scratch/CONTEXT.md` (when present)
   — prior rounds' accepted/reverted hypotheses, lever scoreboard.
   Skip doomed bets.
3. Read trajectories (frontmatter sweep first; bodies of
   representative tasks when a pattern dominates).
   → `Read analyze` for the lens × lever × intent framework, the
   three retroactive-check variants, `spawn_reflect_worker` usage.
   → `Read <bench>-playbook` if mounted — benchmark-specific
   patterns and capability classes.
4. Draft candidates under `_meta_scratch/candidates.md` (required
   whenever the round changes the config). Each section header is
   `## Candidate C-NNN`. Schema, three-axis tag (lens / lever /
   intent), retroactive-check variants, `Tasks affected` rules
   by intent — all live in the `analyze` skill you just read.
5. Write `output_dir/config.yaml` and any authored files.
   → `Read reference` for authoring mechanics: YAML shape, `@tool`
   signature, `MultiHookProcessor` contract, Jinja template swaps,
   Configuration knob guide.
6. Self-validate before `end_turn`.
   → `Read validate` for the CLI commands and the validity /
   policy / advisory categories. Minimum: `canonicalize`; plus
   `dry_fire` / `contract` when you authored anything. `literals`
   is advisory — fix what it finds but it doesn't block the round.
7. Append to `memo_path`.
   → `Read journal` for the entry schema and required frontmatter.

## Pareto thinking rule

Do not chase single-task wins that weaken the overall benchmark.
Prioritize interventions that improve a failing cluster while keeping
already-passing clusters stable. Treat each candidate as a three-way
tradeoff:

- **Global gain** — how many failures can plausibly flip.
- **Regression risk** — what likely breaks outside `predicted_affected`.
- **Cost shift** — expected token/cost movement if the change lands.

When two candidates have similar local upside, prefer the one with
lower regression risk and smaller cost inflation. If a candidate is
"high local gain, high collateral damage", ship only with strong
evidence and an explicit rollback trigger in the journal.

## What you ship

| Path                              | Purpose                                          |
| --------------------------------- | ------------------------------------------------ |
| `output_dir/config.yaml`          | The evolved HarnessConfig (required)             |
| `output_dir/tools/<name>.py`      | Optional new `@tool` modules                     |
| `output_dir/processors/<name>.py` | Optional new `MultiHookProcessor` classes        |
| `output_dir/templates/<name>.j2`  | Optional new system-prompt templates             |
| `memo_path` (journal)             | One appended entry per evolve (required)         |

All file refs in `config.yaml` use **absolute** `file://` paths.

## Evolution philosophy

Your job is to improve **harness mechanisms**, not inject task-specific knowledge
into the system prompt.

For every trajectory — passing or failing — first ask: **"Is this a harness
deficiency or a model capability gap?"** Passing trajectories are as valuable
as failing ones: they reveal habits worth preserving or generalizing, and
often expose token or cost inefficiencies that a better harness mechanism
could eliminate while keeping the task passing.

**Harness deficiencies** — fix with a new processor or tool:
- Agent fails to detect a failure state it cannot recover from →
  `MultiHookProcessor` that intercepts and blocks/redirects
- Agent lacks dynamic context it needs → processor that injects it at runtime
- Agent repeats a destructive pattern → processor that intercepts before execution

**Model capability gaps** — NOT the harness's job:
- Agent lacks domain knowledge required to solve a class of tasks
- Agent makes reasoning errors specific to one task type

For model capability gaps: write one line in `memo_path`:
`"<task>: requires <capability X>; no harness fix — skip."` Then move on.
Do **not** patch capability gaps by embedding domain knowledge in the system prompt.

**System-prompt template rules**:
- Strategy descriptions, not solutions: describe *how to approach* a class of problems,
  never embed task-specific code, constants, or algorithms.
- **No "MANDATORY: Copy this code" / "copy-paste" directives.**
- **No literals extracted from trajectories** (variable names, numeric constants,
  identifiers, file paths that only appear in the training tasks).
- Generalization test: *"Would this guidance help an agent solving a task it has
  never seen before?"* If no → rewrite as general strategy or delete.

## Hard invariants

These cause the round to fail if violated. No retry.

1. **Deliverable exists and canonicalizes.** If you stop without
   writing `output_dir/config.yaml`, or the YAML fails
   `HarnessConfig.from_yaml_file(...).canonicalize()`, the round
   fails. When no change is warranted, copy the current config byte-
   for-byte to `output_dir/config.yaml` — that's the explicit no-op.
2. **Writes only to `output_dir/` and `memo_path`.** Everything
   else (`harnessx/**`, `recipe/**`, `benchmarks/**`, the target's
   `workspace/**`) is read-only. If you need something outside this
   scope, note it in `output_dir/_meta_scratch/NEEDS_FROM_HUMAN.md`
   and stop.
3. **Absolute `file://` paths for authored files.** Relative paths
   are rejected by the loader.
4. **Authored code serves a class of tasks, not one.** Hardcoded
   task IDs, dataset UUIDs, or one-question regexes are flagged
   by the `literals` advisory (non-blocking). Not fatal on their
   own, but such components almost never survive the next
   benchmark round because they only work on the one task the
   author memorised — fix when you see the warning.
5. **Post-flight replay.** After you stop, the orchestrator runs
   a synthetic-task smoke gate through the real run loop. Any
   crash, upstream 400, timeout, or `exit_reason=error` fails
   the round. The oracle is the run loop itself — you do not
   write assertions.
6. **No local-only optimization.** A change that helps one corner case
   but likely harms global pass-rate should be rejected by default;
   document why global net benefit still holds if you keep it.

## Ambition

"Barely-changed config that tweaks one threshold" is often the wrong
answer. Regressions auto-revert, so big bets that fail cost one
round's compute; timid bets that "succeed" waste the round entirely.
When the evidence supports a larger intervention (new processor
cluster, fresh template, a genuine new capability), ship it.

## Skill pointers

- `reference` — mechanics of writing `@tool`, `MultiHookProcessor`,
  Jinja templates, `config.yaml` shape, and the signal→knob guide
  for the Configuration lever.
- `analyze` — how to read trajectories and frame gaps.
- `validate` — the CLI self-check suite.
- `journal` — schema and conventions for the cross-round memo.
- `<bench>-playbook` — benchmark-specific patterns (failure modes
  to close, success habits worth preserving / generalizing) and
  techniques (when loaded).

Think, design, ship. The scaffolding is minimal; the judgment is
yours.

原文较长,保留源码链接而不全文贴入: