M11 · Rubric 离线评测 + 上下文级飞轮(零 GPU 闭环)#
一句话#
给 Agent 装一把「能自动打分、能定位 bad case、能做回归对照」的尺子(Rubrics as Rewards),再用它把数据飞轮里需要 GPU 的「训练腿」换成零 GPU 的「上下文腿」——评测 → 定位真缺陷 → 改 prompt/工具/机制 → 重跑对照证明改进。
背景:没有评测,所有优化都是赌#
第一版 Agent 全靠 prompt engineering 调:今天搜「出差带啥」返回杂货改一版 prompt,明天搜「礼物」返回情侣款加一条规则,后天模型升级整体抖动重头调。这是打地鼠——修 A 冒 B,永远没有「系统性变好」的时刻。根因不是优化方法不行,是没有评测:不知道哪些 case 修好了、不知道这次改是变好还是变坏、不敢动。
完整的数据飞轮是「线上 → 评测 → SFT → RL → 部署」。本项目无 GPU,砍掉训练腿(SFT/Agentic RL/权重更新),但评测 + 数据生产这半段无需 GPU。关键一招:把飞轮里「更新模型权重」换成「更新上下文」——改 system prompt、改工具实现、沉淀 few-shot。模型不动,改喂给它的东西,方向与 SFT/RL 一致(让行为变好、可控、不被厂商版本牵着走),只是载体从权重换成上下文。
关键决策与取舍#
1. 种子集 = 稳定考卷,不是错题本#
手写 18 条种子集和「从使用中收集」不是二选一,是两种职责:种子集是固定的回归基线(test fixture),必须稳定不变,否则尺子自己在动、无法判断分数涨是改进还是 query 变简单;使用收集是增长的真实分布,用来发现未知 bad case。先有种子集才能冷启动(项目没上线、无流量),且红线场景(超预算、性别误推)真实流量里稀疏,必须人工构造保证覆盖。类比:种子集是考卷,使用收集是错题本——没考卷无法判分,错题本让考卷越出越准。
2. 评测器自身会假阳性:先校准尺子,再改 Agent#
首轮基线均分 32.8、一堆 0 分,但深挖发现大头是尺子歪了,不是 Agent 差。三类 RaR 动态 judge 的系统性假阳性:
- 轨迹未脱敏(最严重):把工具调用轨迹(含 item_id、工具名)喂给 judge,judge 当成「Agent 向用户泄露内部 id」判 P0 信息安全 fail——轨迹是评估内部材料,不是 Agent 给用户的输出。系统性命中所有调了工具的 query。
- 价格红线滥设:judge 给无明确预算的 query 凭空造价格一票否决,还自行折算人民币。
- 闲聊类强加购物规范:给非购物意图设「该调检索工具 / 该出商品卡」P1。
修法:轨迹脱敏 + 标注「内部执行日志,禁止据此判泄露」;加红线纪律(无 budget 不设价格 P0、soft 偏好不升级红线、单位统一 USD);intent 透传,闲聊/拒绝类换细则导向。方法论:看 Rubric 0 分先质疑 judge 再质疑 Agent。 校准后均分回到 52.8,假阳性系统性消除。
3. rubric 缓存:让回归对照可比#
judge 每次重新生成细则有方差,改 Agent 前后的分数变化会分不清是 Agent 变了还是尺子抖了。解法:给细则生成加缓存,同一 query 的细则只生成一次后复用,固定尺子刻度。缓存 key 掺入「细则生成 prompt 的 hash」——prompt 一改 key 即变、缓存自动失效重建(尺子定义没变就复用、变了就重建,二者都正确)。剩余方差只来自 Agent 输出 + judge 打分,比「rubric + 打分双重方差」小得多。
4. 改 Agent 证明改进:prompt 改动机,机制兜行为#
固定尺子后定位到一类真缺陷——「过度澄清 + 口头收尾」:信息足够却调 0 个工具反问用户;走完 item_picker 后输出「精挑完成,现在生成清单🎉」就停、没真调终结工具。两手改:
- prompt 改动机:
<workflow>加「主动性纪律」(信息够就直接检索、别为缩小范围反问),<termination>加「不要用文字宣告代替调用」。 - 机制兜行为:「口头收尾」是顽固的方差缺陷,纯 prompt 压不死(同份 prompt 这次调那次不调)。在 middleware 的 item_picker 出口定点注入收尾提示——紧贴「模型刚看到精选、正要决定下一步」那一刻,注意力远比 system prompt 开头的全局纪律强。这呼应项目一贯的「弱模型职责边界用机制兜、不靠 prompt」(fork 深度闸、检索预算同理)。
5. 产品边界由人定,不由 judge 默认#
judge 默认把「仿品/大牌平替」当合规红线判 fail,但产品定位是用户明确提出即正常需求。这类边界是产品决策,不能让动态 judge 替你拍——明确从评测口径里移除「仿冒 = 红线」,种子集对应 query 改回正常购物意图。
6. few-shot 第三腿:全局静态注入 + 自动蒸馏,以及一个诚实的负结果#
「更新上下文」有三条腿:改 prompt、改工具/机制、沉淀 few-shot。第三条这样落地:
- 全局静态注入,不按 query 分桶:范例放进 system prompt 的
<examples>块,但全局固定一小组(不随 query 变)。这是与 prompt cache 的取舍——按 query/品类分桶虽更精准,却让 system prompt 前缀随每条 query 变化、缓存全失效;项目延迟敏感(实测端到端 ~96% 是解码),宁可牺牲分桶精准换缓存命中。又因 few-shot 全局静态,直接让渲染入口内部默认加载,主 Agent 与 fork 子 Agent 自动带同一份——天然同质、零调用方改动,整组控制在 ~340 token。 - 自动蒸馏闭环:人工种子开头,再写脚本从评测高分轨迹(
is_high_score)自动提炼——读成功轨迹的 query + 工具序列 + 回复摘要,用 judge 蒸馏成精短范式,落单独文件、按场景标签与人工种子去重合并。第三腿至此真正闭环:跑评测 → 高分轨迹 → 蒸馏 → 注入 → 再评测。
诚实的负结果:专门做了 few-shot OFF/ON 对照(唯一变量 few-shot、固定尺子、各跑 3 次取中位数),没测出增量。三个原因都比「few-shot 没用」更值得讲:
- 天花板效应(选条失误):选的对照条(过度澄清 / 口头收尾)早被 prompt 纪律治到满分,few-shot 是同方向的冗余强化,没有提升空间。
- 功能重叠:few-shot 种子教的(别过度澄清、别口头收尾)和 prompt 纪律完全同向;规则已成文,再用 few-shot 重复,边际趋零。它的真正价值在 prompt 覆盖不到的新模式。
- 方差淹没:极模糊 query(「随便推荐点东西」)3 次抽样出现 0/100/90,中位数都压不住——低信噪比条目不该做对照样本。
教训:回归对照要选有分数空间、低方差的条目;新「改上下文」手段要测在「现有手段没覆盖」的场景,否则只是验证冗余。这修正了对飞轮的认知——上下文三条腿不是无脑叠加,功能重叠时边际为零,要挑互补场景投放。负结果本身是评测体系的产出:以前根本不知道某改动有没有用,现在能干净地说「这一改在这些场景无增量」。
飞轮第一次完整闭环(数据)#
固定尺子、各跑 3 次取中位数压方差:
| 缺陷条 | 基线 | 改后中位 | 提升 |
|---|---|---|---|
| 过度澄清(信息够却反问) | 16.7 | 95 | +78 |
| 口头收尾(没真调终结工具) | 10 | 93.3 | +83 |
| 对照组(验无副作用) | 100 | 100 | 0 |
闭环:评测 → 定位真缺陷 → 改 Agent(prompt + 机制)→ 固定尺子重跑 → 中位数证明改进 + 对照组无副作用。这是零 GPU、可重复、有数据背书的一圈飞轮。
踩的坑 / 方法论#
- 单次分数会骗人:有条目改后单次分数反降,实际行为大幅改善(从不检索→全链路检索),只是失败点从「过度澄清」换成「口头收尾」又正好踩中。必须看轨迹 + 多跑取中位数,不能只看分数。
- fork 子 Agent 的 token / 行为不在父 trace 里:算成本、看轨迹都只能看到主 loop,子 Agent 的用量要靠在线观测(Langfuse)兜。
- judge 模型决定结构化输出方式:DashScope/Qwen 兼容端点不支持
tool_choice=required(function_calling 不可用),只能走 json_object 模式——prompt 必须含 json 字样并自带结构说明。 - 飞轮顺带挖出的正交缺陷:硬约束(如「降噪」)在召回/精挑执行不稳、数据集缺某些规格(「三件套」)、judge 偶发解析失败——都是下一圈的输入。
可能的面试追问#
- 没有 GPU,飞轮还转得起来吗? 转得起来——失去的只是「改权重」这一种实现手段,评测体系(命门)、数据生产、迭代闭环全保留,把权重更新换成上下文更新即可。代价是模型基座能力封顶在所选 API。
- Rubric 为什么要动态生成,不用统一模板? 换一条 query(工业螺丝批量采购 vs 送闺蜜伴手礼)红线与维度完全不同,统一模板打分会失真。每条 query 先让强模型生成专属细则再打分,与资深运营人工打标一致性可达 90%+。
- 怎么保证「改 Agent 后分数涨了」是真改进而非方差? 三件套:固定尺子(rubric 缓存)+ 多跑取中位数 + 对照组验无副作用。少一样,结论都不可信。
- 为什么不直接在 system prompt 里写「必须收尾」? 写了——但顽固的、有方差的行为(口头收尾)全局 prompt 压不死。机制在决策点定点注入提示远比开头的全局约束有效,这是「机制兜行为」而非「靠模型自觉」。
- few-shot 没测出增量,白做了吗? 不白做。一是拿到一个干净的负结果本身就是评测体系的价值——以前根本不知道某个改动有没有用,现在能说「这一改在这些场景无增量」并解释为什么(天花板 + 功能重叠 + 方差)。二是 few-shot 的注入位和自动蒸馏机制保留着,等遇到 prompt 治不了的新模式再投放。真正的教训是对照实验设计:新手段必须测在现有手段的盲区,否则只是验证冗余;以及上下文三条腿功能重叠时边际为零,不能假设叠加增益。