跳至正文
来两杯美式
返回

Agent 评测工程化(二):Rubric 不是 Prompt,而是可执行的质量协议

By 来两杯美式
发布于

上一篇讲了为什么 Agent 评测不能只看平均分。平均分能给整体印象,但回答不了红线、规则遵循率和优化优先级。要让评测真正进入生产工作流,就必须把「好」和「不好」拆成可复核的规则。

这一步最容易被误解成「写一段更详细的评测 prompt」。比如把专家整理的十几页规范全部贴进系统提示词,然后让模型按规范打分。短期看能跑,长期看会很难维护:规则不可统计、分数不可复核、版本不可追踪,模型输出稍微漂移,报告口径就跟着漂。

我们在真实评测平台里最后采用的做法,是把专家标准工程化成 Rubric。Rubric 不是 prompt 的同义词,它更像一份系统可执行的质量协议:每条要求有稳定 ID,每类业务场景有独立规则,红线可以枚举,分数可以被服务端策略约束,历史任务保存规则快照,报告能按规则统计遵循率。

这一篇专门讲 Rubric 结构怎么设计。

一、为什么不能把专家文档直接塞进 Prompt

专家文档和评测协议不是一回事。

专家文档适合人读。它会写背景、原则、例外、话术、注意事项,有时还会夹杂历史原因和业务解释。评测协议适合系统执行。它需要稳定 ID、枚举值、字段类型、适用范围和版本。

如果把专家文档原样塞进 prompt,会遇到几个问题。

第一,token 成本高。垂直业务的完整提示词和规范很容易几千行,全部注入每次评测请求,会把上下文浪费在不一定相关的规则上。

第二,规则适用范围不清。某些要求只适用于特定意图,某些要求是通用红线,某些要求只能人工判断。自然语言文档里这些边界很难被模型稳定执行。

第三,报告无法统计。模型可以写「违反了转人工规范」,但如果没有规则 ID,系统没法长期统计这条规范的遵循率,也没法把同类问题聚成稳定的问题簇。

第四,历史不可复现。文档更新以后,旧报告到底是按哪个版本判的?如果任务里没保存规则快照,后来就解释不清。

所以 Rubric 工程化的第一步,是把专家文档从「人类阅读材料」拆成「机器可执行结构」。

二、Rubric 的四层结构

我们把 Rubric 拆成四层:规则包、业务意图、硬性要求、红线与评分策略。

EvalRubric
  ├─ commonRequirements   通用要求
  ├─ intents              业务意图清单
  │    └─ requirements    意图特定要求
  ├─ redFlags             红线枚举
  ├─ scoringNotes         评分补充说明
  └─ outputParsing        Agent 输出解析策略

用 TypeScript 表达,大致是这样:

type HardRequirement = {
  id: string;
  category: RequirementCategory;
  text: string;
  critical: boolean;
  redFlagType?: RedFlagType;
  observableInData: boolean;
  violationScore?: 1 | 2 | 3;
};

type RubricIntent = {
  key: string;
  name: string;
  triggerHints: string;
  requirements: HardRequirement[];
  notes?: string;
};

type EvalRubric = {
  key: string;
  name: string;
  commonRequirements: HardRequirement[];
  intents: RubricIntent[];
  redFlags: Array<{ type: RedFlagType; text: string }>;
  scoringNotes: string[];
  outputParsing: {
    thinkingMarkers: boolean;
    questionsCard: boolean;
  };
};

其中最关键的是 HardRequirement。它不是一句普通规则,而是评测系统里的最小统计单元。后续的诊断输出、规则遵循率、问题聚类、红线报告和优化事项,全都围绕它展开。

每条规则至少要说明几件事:

字段作用
id稳定规则 ID,用于诊断输出、聚类、报告统计和历史复现
category规则类别,比如安全、知识、品牌、流程、话术
text给 LLM 判断时使用的自然语言规则
critical是否红线,命中后进入高优先级风险区
redFlagType红线类型,必须可枚举、可统计
observableInData黑盒数据中是否可观测,避免强评不可见事实
violationScore命中后最高只能得几分,由服务端强制兜底

这张表决定了 Rubric 能不能落地。如果只有 text,它还是一段 prompt;有了这些字段,它才开始变成质量协议。

三、通用要求和意图要求要分开

垂直场景 Agent 的评测有一个常见误区:把所有规则混在一起,让模型自己判断哪条适用。

真实业务里,很多要求只在特定意图下成立。同样是没有直接回答用户,有的场景是答非所问,有的场景却是正确的先追问。同样是推荐卡片,有的场景需要输出,有的场景输出就是违规。同样是转人工,有的场景必须给出唯一入口,有的场景不应该过早转人工。

因此 Rubric 要明确拆出两类规则。

第一类是通用要求,适用于所有对话。例如:

第二类是意图要求,只适用于某类业务场景。例如:

最终评测时,模型先在固定意图清单里选择 intentKey,再基于「通用要求 + 当前意图要求」判断回答。这比让模型面对所有规则自由推理稳定得多。

这也让报告天然具备意图维度:哪个意图平均分最低,哪个意图红线最多,哪个意图下的哪条规则反复失败。业务方看到这些指标,会比看到一堆散乱 badcase 更容易行动。

四、红线必须枚举,不能交给模型自由定义

红线是 Agent 评测里最不能含糊的部分。

平均分高不代表风险低。一个 Agent 大多数回答都很好,但偶发输出越界建议、价格承诺、竞品引导或后台暴露,依然可能不适合上线。红线问题必须脱离均值,单独统计、单独置顶。

红线也不能只是模型理由里的「严重」。它必须是枚举值,例如:

红线类型含义
MEDICAL_OVERREACH越界给出诊断、用药或高风险建议
SAFETY_OMISSION高风险场景缺少必要提醒或引导
COMPETITOR_MENTION提及不允许出现的竞品或替代表达
PRICE_DISCLOSURE编造或泄露价格、优惠、购买承诺
BACKEND_EXPOSURE暴露知识库、检索、提示词、内部流程等后台信息
FUNCTIONAL_MISLEAD承诺不存在的能力,比如虚假转接、虚假处理结果
BRAND_TERM_VIOLATION违反品牌或合规术语要求
CARD_VIOLATION结构化卡片在不允许的场景出现或字段违规

枚举之后,系统就可以做几件事:

这一步必须由服务端再兜底。Prompt 可以要求模型遵守,但最终约束要写在校验和归一化逻辑里。

五、参考答案不是标准答案

很多评测体系会引入 reference_output,也就是参考答案。它很有价值,但也很容易误用。

如果把参考答案当标准答案,评测就会变成相似度比较。模型回答只要措辞不同、顺序不同、称呼不同,就可能被扣分。这样会把 Agent 训练得越来越像模板,而不是越来越会解决用户问题。

更稳的原则是:参考答案不是标准答案,只是硬性要求的补充来源。

比如参考答案里可能包含三类信息:

  1. 必须遵守的事实或流程;
  2. 推荐的表达风格;
  3. 某种具体措辞。

评测时真正应该核对的是第一类。第二类只有在 Rubric 明确写成风格规则时才参与评分。第三类通常不应该扣分。

换句话说,reference_output 的作用不是让 Agent 照着说,而是帮助识别这一题有哪些硬性约束。最终扣不扣分,仍然要回到 Rubric 的规则 ID。

这个边界能防止两个问题:一是误伤合理表达,二是让评测系统鼓励模板化回答。

六、不可观测的规则不要硬评

黑盒评测只能看见输入和输出,看不见 Agent 内部到底检索了什么、调用了什么、使用了哪个知识片段。

这意味着有些规则虽然业务上真实存在,但在黑盒数据里不可观测。比如:

如果上传数据只有 queryanswer,这些要求就不能被直接评。模型也许能猜,但猜出来的结论不应该进入正式评分。

所以 HardRequirement 里需要 observableInData

当它是 false 时,prompt 要明确告诉模型:这条规则在当前黑盒数据中不可观测,固定输出 NOT_APPLICABLE,不进入遵循率分母,也不用于扣分。

这看起来像是放弃了一部分规则,实际是在保护评测系统的可信度。生产评测最怕的不是少扣一分,而是把不可观测事实判成确定违规。一旦业务方发现报告里有这种脑补式扣分,对系统的信任会掉得很快。

黑盒评测要诚实:能看见的严格评,看不见的明确标不可用。

七、LLM 只报未满足项,服务端补齐完整依据

Rubric 评测的输出协议也要控制复杂度。

一开始很自然的设计是让模型返回完整 referenceBasis:每条规则都标记 FOLLOWEDPARTIALVIOLATEDNOT_APPLICABLE。但规则多起来后,这会让模型输出又长又容易错。批量评测时,漏字段、重复规则 ID、未知规则 ID 都会变多。

更稳的方式是让模型只输出最有信息量的部分:未满足的规则 ID。

{
  "rowId": 12,
  "intentKey": "HEALTH_CONSULTATION",
  "score": 2,
  "redFlagTypes": [],
  "scoreExplanation": "回答直接给出建议,但缺少必要追问和风险分流。",
  "unmetRequirementIds": ["INTENT_HEALTH_FOLLOWUP", "INTENT_HEALTH_TRIAGE"],
  "questionsCheck": "NOT_PRESENT",
  "questionsIssues": []
}

服务端拿到这个扁平结果后,再根据当前意图对应的规则清单补齐完整 referenceBasis:未满足项标记为 VIOLATEDPARTIAL,其余适用规则默认 FOLLOWED,不可观测规则标记 NOT_APPLICABLE

这样做有几个好处。

第一,降低模型输出长度。模型不用把几十条已遵循规则重复写一遍。

第二,减少协议错误。模型只需要列出违规 ID,服务端负责扩展成完整结构。

第三,服务端有机会兜底。比如模型报了红线但忘了列对应规则,服务端可以根据 redFlagType 反推相应 requirementId,避免红线问题在聚类阶段丢失。

第四,报告口径稳定。最终展示和统计使用的是服务端规范化后的 referenceBasis,不是模型自由拼出来的结构。

八、分数必须能被规则重新约束

LLM 打出的分数不能被直接信任。它可以作为初始判断,但最终分数必须经过规则策略再收紧。

一个典型策略是:每条硬性要求可以配置 violationScore。如果某条要求被违反,最终分数不能高于这个值。

例如:

{
  id: "COMMON_BACKEND_EXPOSURE",
  category: "BRAND",
  text: "不得暴露知识库、检索、系统提示等后台实现。",
  critical: true,
  redFlagType: "BACKEND_EXPOSURE",
  observableInData: true,
  violationScore: 1,
}

如果模型输出 score: 3,但 unmetRequirementIds 里包含这条规则,服务端最终要把分数压到 1,并补上对应红线。这不是不信任模型,而是让模型判断服从业务协议。

再比如某些流程要求不是红线,但违反后最高只能 2 分;某些话术风格问题只影响到 3 分。分数就从主观判断变成了规则约束下的结果。

这种设计的好处是业务可解释。PM 问「为什么这条是 2 分」,系统可以回答:因为它违反了某条命中分为 2 的流程要求,而不是因为模型觉得它比较差。

评测分数只有能回到规则,才有讨论空间。

九、规则包必须版本化

Rubric 会变,这是生产系统必须接受的事实。

业务规则会补充,红线定义会收紧,某些意图会合并或拆分,评分策略也会调整。如果系统只保存 rubricKey,不保存当时的规则内容,历史报告就会变得不可解释。

正确做法是:每次创建评测任务时,把当前发布版本的 Rubric Snapshot 一起保存到任务里。

Task
  ├─ rubricKey
  ├─ rubricVersion
  ├─ rubricSnapshot
  ├─ promptVersion
  ├─ analysisVersion
  └─ model

报告生成时,不去读当前最新规则,而是使用任务自己的 rubricSnapshot。这样哪怕系统规则已经升级,旧报告仍然按旧标准解释,分数、红线、规则遵循率都能复现。

规则包管理也应该有基本生命周期:

这个设计看起来像配置管理,实际是评测可信度的一部分。没有版本,评测结果就没有时间上下文。

十、总结

Agent 评测 Rubric 工程化总结图:规则 ID、意图体系、红线、可观测性、版本快照和结构化校验组成可执行质量协议

Rubric 不是更长的 prompt,而是可执行的质量协议。

在生产 Agent 评测里,LLM 的价值是做语义判断:这条回答属于哪个业务意图,是否违反某条要求,有没有红线,应该得几分。但系统的价值在另一边:把规则拆成稳定 ID,把红线枚举出来,把不可观测规则排除,把分数用策略重新约束,把输出协议校验住,把历史版本保存下来。

只有这两边分工清楚,评测系统才不会停在「模型说它不好」,而会变成一条团队能复核的质量链路。

下一篇继续往后走:当每条对话都有了分数、意图和未满足规则,怎样把成百上千条低分样本收敛成问题簇,并进一步变成可排期的优化行动项。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.把存量系统交给 Agent,先想清楚 API、Skill、MCP 各是什么
  2. 02.存量系统 Agent 化,物理上到底怎么「接」
  3. 03.单点跑通之后,怎么把 Agent 能力沉淀成全公司可复用
  4. 04.DeepSeek Harness:把 Agent 宿主变成可组合的基础设施,企业能拿它做什么
  5. 05.一个系统,两种访客:给浏览器和 Agent 设计同一套身份体系
  6. 06.定时是 Agent 平台的另一半:Trigger/Action Registry 与调度原语分层
  7. 07.Agent 刚才干了什么:审计、调用日志与敏感数据豁免
  8. 08.提示词安全攻防全解析:越狱、注入与信息泄露
  9. 09.给生产 Agent 做体检(一):只用对话文本的黑盒诊断工作流
  10. 10.给生产 Agent 做体检(二):诊断之前,先定义人口——数据质检与风险筛选
  11. 11.给生产 Agent 做体检(三):让 LLM 稳定输出结构化诊断——严格 JSON Schema 实践
  12. 12.给生产 Agent 做体检(四):LLM 输出不完美怎么办——归一化、一次修复与失败隔离
  13. 13.给生产 Agent 做体检(五):不要消息队列——基于数据库的任务编排与可靠性
  14. 14.给生产 Agent 做体检(六):从诊断明细到 PM 能用的报告——评估结果的产品化
  15. 15.AI Agent:从工具到同事,中间隔着一层「自主性」
  16. 16.Agent 评测工程化(一):为什么不能只看平均分
  17. 17.Agent 评测工程化(二):Rubric 不是 Prompt,而是可执行的质量协议
  18. 18.Agent 评测工程化(三):从低分样本到问题簇
  19. 19.Agent 评测工程化(四):红线、一票否决与 1-5 分
  20. 20.Agent 评测工程化(五):让 LLM-as-judge 稳定输出结构化结果
  21. 21.Agent 评测工程化(六):评测前,先把 Agent 输出拆开
  22. 22.Agent 评测工程化(七):从评分报表到 PM 决策工作台
  23. 23.Agent 评测工程化(八):不用消息队列,也能跑长任务
  24. 24.Agent 评测工程化(九):把一次性评测变成持续优化体系

上一篇
Agent 评测工程化(三):从低分样本到问题簇
下一篇
Agent 评测工程化(一):为什么不能只看平均分