返回 AICAP-180
B10 · Day 96p95/cost 测量 + 成本级联 + tau2-bench

tau2-bench 概念 (M2, 2026-03)

B1→B18 的能力曲线在 B10 进入「把模型/agent 当作可测量系统」的工程化阶段。

阶段: B10 · p95/cost 测量 + 成本级联 + tau2-bench(Day 91-100) 标签: #tau2-bench #agent-eval #dual-control #passk

今日导引(由浅入深)

B1→B18 的能力曲线在 B10 进入「把模型/agent 当作可测量系统」的工程化阶段。 B7-B9 我们建了 eval gate、红队、部署韧性;Day 91-93 把延迟/吞吐/$/query 拆成 p95/p99 + 单位成本;Day 94-95 用 cascade 把成本换质量。 昨天(Day 95)锁的是单轮任务上的「省 $% vs pass 掉幅」曲线。 但单轮 eval 测不出真实对话 agent 的稳定性——多轮里 user 会追问、会改主意、工具会改环境状态。 今天切到 tau2-bench:双控制(dual-control)多轮 agent 评测 + pass^k 稳定性口径。 这是 M2(评测能力支柱)从「单次问答打分」升级到「多轮任务稳定通过」的关键一跳。 今天的最小可判定产出:一个 bench/tau2/ retail 单域脚手架 + 1 条可 commit 的完整 transcript(需 key 跑通)。

1. 机理精读

定义。 tau2-bench(τ²-bench,论文 2026-03)是 tau-bench 的第二代。 核心创新是 dual-control(双控制):在一次评测里,user 模拟器被测 agent 都能调用工具去读写同一个共享的环境状态(environment state)。 这与第一代 tau-bench 的 single-control 不同——v1 里只有 agent 改环境,user 仅在对话层发话。 双控制更贴近真实场景:客户自己也会去后台改资料、取消订单,agent 必须在一个被对方也能改动的世界里完成任务。

为什么这样设计。 真实客服/调查类任务里,「正确答案」不是一句话,而是最终环境状态是否对:订单是否真的退了、余额是否对、合规标记是否写入。 如果只让 agent 单方面操作环境,评测就退化成「agent 自说自话」,测不出它能否在对方也施加副作用的情况下保持目标一致性。 双控制把 user 也变成一个会调工具的 actor,逼出 agent 的鲁棒性——它得处理「我刚说要退货,但 user 自己又把订单改了」这类竞争性状态变更。 换句话说,dual-control 把评测从「对话质量」推进到「在可被对方改动的世界里把事办成」。

pass^k 的引入。 tau2-bench 同时把稳定性口径从 pass^1 提升到 pass^k。 pass^k 指:同一任务用相同配置独立跑 k 次,k 次全部通过才记一次稳定通过。 这是对「不一致性」的直接惩罚——一个 pass^1=0.8 但 pass^3 只有 0.4 的 agent,意味着它通过靠的是采样运气而非可靠能力。 对生产部署,pass^k 比 pass^1 更有决策价值,因为用户不会容忍「同一个问题三次里有一次翻车」。 (pass^k 的具体测量留到 Day 98 做,今天只确立概念。)

关键权衡。 双控制让评测更真实,但代价是环境实现复杂度不确定性来源增多。 user 模拟器本身是个 LLM,它的行为也有方差,于是评测里既有 agent 的方差也有 user 的方差。 这正是要用 pass^k 而非单跑的原因——只有重复采样才能把这两层方差暴露出来。 另一个权衡是成本:dual-control + 多轮 + k 次重复,token 消耗是单轮 eval 的数倍。 所以本项目先从 retail 单域起步(只一个工具集),把脚手架跑通再谈规模扩展。

与相邻概念的边界。 tau2-bench ≠ 我们已有的 src/agent/eval/tasks.ts(那是单轮、确定性 codeCheck + LLM-judge 的 ~30 题集,测的是 AML/agent 单点失败模式)。 tau2 测的是多轮 + 环境状态 + pass^k,两者互补。 tasks.ts 答「这个模型单点会不会犯错」;tau2 答「这个 agent 在多轮可改世界里能不能稳定办成事」。 今天只搭 retail 单域脚手架,不替换 tasks.ts——两套口径并存,分别回答不同问题。

单域起步的理由。 tau2-bench 官方含 retail/airline/telecom 多域,每域工具集与状态机不同。 本项目先做 retail 单域,是因为多域会让脚手架复杂度与 token 成本同时爆炸,而单域已足以验证 dual-control + pass^k 的全链路。 等单域脚手架 + 验证函数 + pass^k 聚合都跑通、口径对齐,再谈扩域才有意义。 这与 B10 整体「先把可测量管线打通、再谈规模」的节奏一致——脚手架优先于覆盖度。

2. 推导 / 手算 / 代码走读

tau2 脚手架(bench/tau2/)目前未建——bench/ 目录在仓库里不存在(Glob 验证:no files found)。 seed 也诚实标注 "tau2-bench scaffold NOT built (gated)"。 所以今天不是对现有代码走读,而是按仓库已有风格设计脚手架。可复用的真实代码风格如下:

  • 工具注册沿用 src/agent/mcp/toolRegistry.ts 的形状McpToolRegistry.register(spec, handler)(toolRegistry.ts:151)声明 name / description / inputSchema(JSON-Schema 子集)
  • 校验是注册表的一等公民call(name, args)(toolRegistry.ts:183)先用 validate()(toolRegistry.ts:112)按 schema 校验入参,失败抛 McpCallError(RPC.INVALID_PARAMS, ...)(toolRegistry.ts:187)再进 handler。
  • retail 工具集:退货 returnOrder、查单 getOrder、改单 modifyOrder 等,用这一注册/校验/调用三段式,保证 in-process、纯函数式、可单测。
  • 校验先于副作用:handler 永远拿到的是已校验入参——这正好是 dual-control 里需要的「工具是受控入口」语义,user 与 agent 都只能经由受校验的工具改环境。
  • 环境状态:tau2 需要一个可被 user 与 agent 共同读写的 state 对象(如 { orders: {...}, balances: {...} })。脚手架把它做成 in-process 可变结构,每次工具调用是对它的确定性 transform。
  • transcript:一条 transcript = [user 模拟轮, agent 轮, 工具调用, 环境快照, ...] 的有序记录,今天用 deepseek-v4-flash 跑通 1 条并落盘 commit。
  • 同源 runner:模型调用走 provider-agnostic runner(默认 deepseek),与 Day 91-95 同源,保证 token/$ 口径一致——这是 Day 99 三表能拼到一起的前提。

一个 dual-control 回合的状态推演(手写示意,便于理解为什么需要双控制):

  1. 初始 env:orders={A: {status:'shipped'}}balances={u: 0}
  2. user 轮:客户说「我要退订单 A」(对话层意图)。
  3. agent 轮:调 returnOrder(A) → env 变 orders.A.status='returned'balances.u += refund
  4. user 副作用轮(dual-control 关键):user 模拟器自己modifyOrder(A, addr=...),企图在退货后改地址。
  5. agent 必须识别「A 已 returned,改地址无意义/应拒」——这一步是 single-control 永远测不到的鲁棒性。
  6. 终态由验证函数(Day 97)断言:orders.A.status==='returned' 且未被错误回滚。

3. 今日实战

可执行步骤(指向真实路径):

  1. 新建 bench/tau2/ 目录与 retail 单域骨架:bench/tau2/env.ts(共享环境状态 + 工具集,沿用 src/agent/mcp/toolRegistry.ts 的 register/validate/call 三段式)。
  2. 写 1 个 user 模拟 prompt(描述一个退货/查单场景的客户人设、目标与可调工具)。
  3. 用 provider-agnostic runner(默认 deepseek、模型 deepseek-v4-flash)驱动 agent 与该 user 模拟跑通 1 条完整多轮 transcript。
  4. 把 transcript 序列化为 bench/tau2/transcripts/retail-001.jsongit commit
  5. 工具集与环境 transform 用单测断言(纯函数部分,不需 key)先测通,再接模型——确定性部分先绿,gated 部分后跑。

4. 今日实测 / 产出

  • tau2-bench scaffold = 待跑(需 key 跑);当前 REPO REALITY 标注 tau2-bench scaffold NOT built (gated)(Glob 确认 bench/ 不存在)。
  • 本日产出 = tau2 retail 脚手架 + 1 条 committed transcript 文件(需 key 跑通)。
  • 可立即落地(不需 key)的部分 = 工具集/环境 transform 的纯函数实现 + 其断言单测;模型驱动的真实 transcript 仍 gated。

诚信底线:不把「待建/待跑」升级成「已完成」。脚手架尚未建、transcript 尚未跑出,状态如实保留为 gated。

5. 常见误区 / 陷阱

  • 把 tau2 当 tasks.ts 的替代品:它是多轮 + 环境 + pass^k 的补充,不替换单轮 eval;两套口径分别回答不同问题。
  • 用旧 tau-bench(v1 单控制) 当主线:v1 只有 agent 改环境,测不出 dual-control 下的鲁棒性;2026-03 后的双控制 + pass^k 才是新口径。
  • 只跑 1 次就下结论:单条 transcript 只能验证脚手架打通,不能当能力数字——稳定性要靠 pass^k(Day 98)。
  • user 模拟器方差被忽略:user 也是 LLM,它的行为方差会混进结果;不重复采样就分不清是 agent 弱还是 user 模拟抖动。
  • 把工具调用顺序当评判依据:dual-control 下应判最终环境状态而非动作顺序,否则 user 的合法副作用会被误判为 agent 失败。

6. 学习资源(每条带 YYYY-MM)

  • tau2-bench 论文(dual-control + pass^k 多轮 agent 评测),2026-03。
  • tau-bench(v1, single-control)原始工作,作为对照基线,2024(演进史用途)。
  • 本仓 src/agent/mcp/toolRegistry.ts(MCP 工具注册/校验/调用教学装置,工具集风格来源),2026-06。
  • 本仓 src/agent/eval/tasks.ts(单轮确定性 codeCheck + LLM-judge 题集,与 tau2 互补对照),2026-06。
  • Anthropic "Demystifying evals"(评测方法论,pass^k/HITL 视角),2026-01。

SOTA检查 (2026-06 更新)

  • 当前主流:tau2-bench(2026-03)是当前 agent 多轮评测主线,双控制 + pass^k 仍 SOTA
  • 是否仍 SOTA:是。dual-control 把「在可改世界里办成事」做成可测量口径,2026 上半年无更主流替代。
  • 过时黑名单:旧 tau-bench(v1 单控制) 不得当主线;旧 deepseek-chat/-reasoner id(2026-07-24 退役)不得用于跑 transcript,统一 deepseek-v4-flash / deepseek-v4-pro
  • 下次复查点:tau2-bench 域扩展(airline/telecom 等)与排行榜状态执行当周重验;模型价格/平台 GA 随周波动须查。

衔接

  • 昨天:Day 95 — 级联省钱 vs 质量权衡(M6),单轮上的 $-vs-pass 曲线。
  • 今天:多轮 dual-control 评测 tau2-bench 概念 + retail 单域脚手架(1 条 transcript,需 key)。
  • 明天:Day 97 — held-out 任务设计(M2),用开发期不可见的任务 + 确定性验证函数防过拟合。