关于 build-a-scorer
面向构建 MLflow 生成式 AI 评估的技能,引导用户先定义可观察的质量标准,再实现小型评分器套件。强调按标准选择成本较低且可靠的检查,并通过对话确认需求。
主要功能
- 01引导定义原子质量标准
- 02限制为小型评分器套件
- 03优先采用低成本检查
- 04检查数据与追踪可观测性
- 05区分规则与用户结果
- 06先讨论标准再写实现
适用场景
- 01为 AI 应用设计首版评估套件
- 02把模糊质量目标转成可检查标准
- 03根据可用追踪选择评估方式
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mlflow/ skills --skill build-a-scorer安装后在 Claude Code 中输入/build-a-scorer确认已加载。
附带文件references/judge-alignment.md
详细介绍
build-a-scorer
帮助用户从零开始,交付评估原型。首轮不必做到 100% 正确——先构建一套稳定、易懂的评分器套件,让他们能够运行、检查并迭代。
你的首要任务是理解,而用户才是判断什么算错误的专家。不要从“我该用哪个 MLflow 评分器?”开始。
首要目标:
充分了解应用,以便定义一小组原子化、持久的质量标准,然后用成本最低且可靠的评分器逐一实现。
原则
- 先做原型。 立即交付一个实用的 v1。明确标出 v2 升级项。
- 套件要精简。 使用 3-5 个高信号评分器,严格限制数量。每增加一个,就要淘汰一个较弱的评分器。
- 一个评分器,一个标准。 如果一个标准里有“并且”,就把它拆开。不要使用“总体质量”评判器。
- 采用成本最低且可靠的实现。 代码/规则优于内置检查,内置检查优于手写 LLM 评判器。参见阶段 4——这是最常被跳过的规则,而跳过它会在规模扩大后付出真金白银的代价。MLflow 已经提供的评判器,绝不要自己手写。
- 覆盖结果,而不只是规则。 仅包含策略检查的套件只能告诉你 Agent 是否遵守了规则,却无法说明用户是否成功。每个套件都必须至少有一项检查,用来判断用户是否得到了想要的结果。参见阶段 3。
- 采用二元输出。 优先使用
bool;对于 LLM 评判器,使用"yes"/"no"——其他字符串会在计算指标时被静默丢弃(阶段 4)。除非有校准方案,否则避免使用0.0-1.0;通过率比浮点数平均值更便于调试。 - Trace 是可选的。 如果存在,就检查它们;否则使用数据集 +
predict_fn。除非某项标准确实需要执行内部信息,否则不要让用户因追踪功能而停滞。 - 稍后再对齐。 把每个初版 LLM 评判器都视为草稿。提醒用户,等 Trace 和人工标签到位后再进行对齐。
- 先沟通,再写代码。 对话是厘清对错的地方。大段代码会终止对话——用户会停止阅读,开始照着实现。在对话中穿插小片段没问题;完整实现应放在最终回复中,并在用户确认标准之后再提供。
事实依据:检查,不要凭记忆
MLflow 的评分器接口会变化。推荐评分器之前,先查看已安装的接口。如果项目没有使用 uv 管理,请去掉 uv run 前缀:
uv run python -c "
from mlflow.genai.scorers import get_all_scorers
import mlflow.genai.scorers as s
for sc in get_all_scorers():
req = getattr(sc, 'required_columns', set())
print(f'{type(sc).__name__:32} requires={sorted(req)} session={getattr(sc, \"is_session_level_scorer\", False)}')
print(sorted(n for n in dir(s) if n[0].isupper()))
"
get_all_scorers()返回可以使用默认值实例化的内置评分器。需要构造函数参数的评分器(Guidelines、RegexMatch、ResponseLength)可能只会出现在导出的名称中。.required_columns是准确的数据契约。请使用它,绝不要猜测。- LLM 评判器:
from mlflow.genai.judges import make_judge。代码评分器:from mlflow.genai.scorers import scorer。
如果无法导入 MLflow,请如实说明,继续从基本原理出发,并指出名称和必需列仍需核实。
面向用户的语言
先使用产品语言(质量检查、评判器、代码检查、内置检查),再使用 API 语言(评分器、make_judge、@scorer、required_columns)。每项建议都按以下格式表述:
Quality check: <plain-English name> Layer: <rule | outcome>
Criterion: <one sentence, one thing only>
Implementation: <code check | built-in | LLM judge>
Why not cheaper: <for LLM judges — the code check AND built-in you rejected, and why>
Output: <bool, or "yes"/"no"> Data needed: <inputs/outputs/expectations/trace/session>
工作流程
阶段 0:确定方向
清楚说明双方的约定:
我们会构建一套小型 v1 评分器套件,它可以立即运行、捕捉反复出现的失败,并为后续迭代提供稳定基础。它还不会完美。
阶段 1:了解用户对对错的看法
你的工作是制定标准,而不是设计架构——了解用户认为什么是好与坏,而不是他们的产品规格。
最多先问 3 个问题,再展示草稿。 用户纠正错误的草稿,远比回答访谈问题容易。
依次询问以下问题,每次只问一个:
- 这个应用是做什么的?
- 你最不希望发布的失败是什么?
- 不确定或缺少信息时,它应该怎么做?
然后停止提问并起草。将“好的回答”之类含糊的答案转化为明确、可观察的标准,并展示给用户修正——不要再通过提问把工作推回给用户。
以下内容不在讨论范围内;这些是用户的工作,不是评判者的工作:
- 业务逻辑中每个步骤需要哪些必填字段。
- 应用如何在不同分支或状态之间做出选择。
- 内部架构、门槛、阈值或槽位分类体系。
如果你发现自己连续第二次询问应用内部细节,就停止提问并起草。
应避免的真实失败案例: 了解到“信息不完整时不应预订”后,又追问四个问题,确认哪些字段算完整。第一句话已经足够。
阶段 2:检查哪些内容可观察
用户对草稿做出回应后,确认评判者实际上能看到哪些证据。只有可检查的标准才算有效。集中检查一次即可,不要进行访谈。
如果存在追踪记录,检查一两个:确认 inputs、outputs、expectations、跨度类型、工具调用,以及任务是单轮还是会话级别。
RETRIEVER 与 TOOL 的陷阱: RetrievalGroundedness、RetrievalRelevance 和
RetrievalSufficiency 需要 RETRIEVER 跨度,否则会直接报错。通过 TOOL 埋点记录的 web_search 或数据库查询不符合要求。
对于“以工具输出为依据”的标准,应使用代码评分器封装评判器,而不是传入 {{ trace }}。 @scorer 可以获取 trace,因此可使用 trace.search_spans() 提取证据跨度,并仅将该跨度和声明传给评判器。{{ trace }} 会序列化每个跨度,让模型自行找出正确的跨度——成本更高,而且存在多个跨度时,跨度选择会变得不确定。只有当标准涉及整个追踪记录(例如工具调用顺序、重试),且没有可提取的单一跨度时,才使用 {{ trace }}。
如果不存在追踪记录,请使用 inputs,以及可选的 outputs/expectations,调用
mlflow.genai.evaluate(data=..., predict_fn=..., scorers=[...]),并将仅依赖追踪记录的改进标记为未来工作。
阶段 3:将示例提炼为原子化标准——覆盖两个层面
将示例归类为重复出现的失败模式。保留可能反复出现的标准;将偶发问题单独存放。
为每项标准命名,例如 answers_user_question、does_not_invent_facts、
refuses_out_of_scope_requests——每项只对应一种行为。
覆盖两个层面。仅涵盖第一层的评测套件,是这项技能最常见的失败。
- 规则层——Agent 是否在本轮行为不当? 违反策略、事实错误、漏掉升级处理、做出禁止的声明。这类问题易于命名、易于检查,也是用户明确表达担忧的所在。
- 结果层——用户是否得到了他们想要的? 任务完成、放弃、沮丧、不得不重复说明。这类问题更难命名,也是产品存在的理由。
Agent 即使通过了所有规则检查,仍可能毫无用处。直接询问:“对用户来说,成功是什么样的——他们来这里是为了做什么,我们如何判断他们做到了?”
结果检查通常成本低廉,而非高昂——不要假设它们需要 LLM 评判:
task_completed——轨迹中是否包含目标工具调用(预订、申请、下单)?用代码检查。- 无需数据要求的会话级内置评估器:
UserFrustration、ConversationCompleteness、KnowledgeRetention。通过.required_columns验证。 had_to_repeat——用户是否在多轮对话中重述了同一请求?用代码检查对话。
不要用可检查的代理指标取代重要的结果。 像
promotion_disclosed(“是否提到了促销标记?”)这样的检查看似严谨,但衡量的是文本中是否出现相关内容,而非租车者是否获得了最优惠的价格,或是否觉得服务到位。代理指标可以用作规则检查,但不能替代结果层。如果用户的真实目标模糊不清,就明确说明,并将一个低成本代理指标与一项诚实的结果检查配对,而不是假装代理指标已涵盖一切。
结果检查也要保持原子化。“满足客户期望”捆绑了找到所需内容、未被误导以及没有感到沮丧;一旦失败,你就无从得知原因。应拆分检查。
阶段 4:将每项标准分配给成本最低且可靠的实现方式
在请用户确认评测套件之前完成此步骤,这样他们批准的才是实际成本。
Can code check it deterministically (or filter most cases)?
yes -> code check
no -> Is there a built-in for this standard concept, and do we have its required data?
yes -> built-in
no -> LLM judge
检查点——每个手写的 LLM 评判器都必须有一个 why not cheaper 单元格,列出代码检查和你排除的内置评估器。 不能写在消息其他位置的正文中:必须写在阶段 6 表格的单元格里。如果无法填写,说明该检查分类有误。只有在你确实查阅过后,“没有内置评估器能覆盖此项”才算合理。
先检查评估器目录,再手动实现。 当 MLflow 可导入时,运行上方的内省命令;不可导入时,以下评估器已随当前版本提供——依赖它们之前,请确认名称和 required_columns,但不要假装目录是空的:
| 内置评估器 | 所需内容 | 适用场景 |
|---|---|---|
Guidelines(guidelines=...) | 输入、输出 | “响应是否遵循了这项明确说明的策略”——最常被忽视的内置评估器 |
Correctness | 输入、输出 | 答案是否符合预期 |
RelevanceToQuery | 输入、输出 | 响应是否回答了问题 |
Safety / PIIDetection | 输入、输出 / 输出 | 有害内容;PII 泄露 |
RegexMatch(pattern=...) / ResponseLength(...) | 输出 | 模式和长度规则 |
Completeness / Fluency / Summarization | 输入、输出 | 覆盖度;可读性;摘要质量 |
ToolCallCorrectness / ToolCallEfficiency | 轨迹 | 工具是否正确,是否存在冗余调用 |
Retrieval{Groundedness,Relevance,Sufficiency} | 输入、轨迹 | 仅适用于 RETRIEVER 跨度——见阶段 2 |
UserFrustration、ConversationCompleteness、KnowledgeRetention、ConversationalSafety、ConversationalRoleAdherence | 无(会话级) | 多轮结果与对话质量 |
| 内置评估器比空白提示词更适合作为起点,但不能取代你的标准。 | ||
内置评估器是采用 MLflow 通用指令的 LLM 评判器,因此“内置”不代表它适用于你的产品;之所以优先考虑它们,是因为其脚手架和数据契约都已过测试。由此带来两点:Guidelines 始终适用,因为它采用的是你的策略文本。此外,校准并不局限于内置评估器或定制评估器——align() 属于 Judge,因此可以像 make_judge 一样,根据你的标签校准单轮内置评估器;但会话级评估器(UserFrustration、ConversationCompleteness、KnowledgeRetention)会引发 NotImplementedError,只能遵循 MLflow 的定义。对于重要且有争议的标准,请手动编写评估准则,以便进行校准。 |
如果你的标准确实不同,不用内置评估器也合理;但不看一眼就跳过则不合理。
默认选择:
- 格式、JSON 结构、必填字段、正则表达式/链接、长度、精确值、延迟、PII 模式、特定短语或关键词:代码检查。
- 相关性、正确性、安全性、依据充分性、检索质量、工具调用质量、流畅度、会话级对话质量:如果数据契约相符,使用内置评估器。
- 领域语气、策略遵循情况、特定任务的正确性、与来源的释义匹配、细致的拒绝质量:LLM 评判器。
对于多阶段 Agent,应将每项已商定的标准映射到可观察该标准的已埋点阶段。使用代码检查,将明确预期的工具调用与跟踪记录进行比较;只有当选择取决于语义意图时,才使用评判器。应根据跨度测量阶段延迟,而不是使用评判器。仅当某项标准需要可复用的配置或状态时,才使用基于类的评分器。
优先采用混合方案,而非纯评判器。 大多数“语义”检查都有成本低廉的确定性前置环节:关键词或短语扫描可以近乎零成本地捕捉明显情况,并只将模棱两可的情况交给模型。只要某项标准提及具体承诺、类别或触发话题,就应采用这种方式,例如“是否承诺退款”“用户是否提出账单争议”。检测触发条件通常用代码即可;评判回复则可能需要模型。
如果用户想用 LLM 评判器统计字数或验证 JSON、用正则表达式判断语气、只用一个“总体表现良好”评分器,或在没有校准理由的情况下使用浮点数,请提出异议。
输出类型——只有 bool、数值和 "yes"/"no" 会被聚合。 任何其他值都会被 _cast_assessment_value_to_float 静默转换为 None,并且不会出现在 results.metrics 中,也不会报错:"pass"、"fail"、"correct"、"not_applicable" 都会消失。已根据 mlflow/genai/scorers/aggregation.py 验证;CategoricalRating 只接受 yes/no/unknown。
- 通过/失败优先使用
bool。 - LLM 评判器必须返回字符串时,使用
"yes"/"no"。 - 用
Feedback(value=True, rationale="not applicable: ...")表示“不适用”,或者跳过该行;不要使用"not_applicable"字符串,否则它会从指标中消失。 - 补充细节写在
rationale中,而不是value中。
Phase 5:与领域专家一起打磨每项标准
这是价值最高的阶段——把大部分对话时间花在这里。 用户最清楚什么算错。你的任务是找出每项标准的边界:合理的人可能会对同一种行为是否可接受得出不同判断的地方。
提出方案,而不是盘问。 把候选判定摆到用户面前,让他们裁定:
对于“不会因受保护类别而引导用户”——以下三种情况我会判定为不合格:[...]。这个情况我会判定为合格,因为租客先问了:[...]。这个情况我不确定:[...]。你会如何界定?
与开放式提问相比,这种方式每轮能获得多得多的有效信息,而且只需用户作出判断,而不是编写规范。
探查方式,每种都附上你自己的建议答案:
- 近似反例。“这个情况你会判定为不合格吗?它几乎相同,只是 [X]?”
- 合理例外。“有没有这种行为实际上是正确的情况?”
- 严重程度区分。“这两种情况里,有一种是不可逾越的红线,另一种只是小问题吗?”
- 不适用。“标准不适用时,检查结果应该怎么写?”
当用户已纠正或确认至少一个建议判定、两个人会对同一个示例作出相同标注,而且你清楚“不适用”是什么情况时,这项标准就算完成。
简短片段在这里会有帮助——一种输出形式、一份包含三个项目的关键词列表。无需提供完整实现。
Phase 6:实现前先确认
把整套检查项重述为一张表格,每项检查占一行,并为每行填写以下列: 名称 | 层级(规则/结果)| 实现方式 | 为什么不能用更简单的方式 | 输出。空白单元格代表设计缺陷,而不是格式选择——没有“为什么不能用更简单的方式”的 LLM 评审无法路由,而缺少结果层级检查项的套件则不完整。然后请用户确认或修改,并等待回复。
这是我准备构建的套件。在我编写之前,有什么要添加、删除或改写的吗?
在这里严格控制检查项数量。 如果超过 5 项,不要让用户自行删减——说明你会删掉哪些以及原因,然后让用户决定是否否决。添加一项标准意味着替换一项较弱的标准,而不是不断扩充列表。包含 9 项检查的 v1 只是检查清单,而检查清单无法得到验证。
不要在请求确认的同一轮中编写完整实现。如果有任何变更,请重新确认变更项。
Phase 7:交付实现
仅在确认之后交付。用一条整合后的最终消息交付,而不是把代码分散在多轮对话中。
- 代码检查项:提供可运行的代码,包括导入语句、畸形输入防护,以及可运行的
mlflow.genai.evaluate(...)调用。 - 内置检查项:说明
.required_columns中的数据契约。如果缺少数据,则重新路由或标记为未来升级项。 - LLM 评审:提供针对其领域定制的实际
instructions字符串,包含模板变量({{ inputs }}、{{ outputs }}、{{ expectations }}、{{ trace }}、{{ conversation }})、bool或"yes"/"no"输出,以及按用户所述用量估算的成本。始终补充:“一旦有了轨迹和人工标签,就应校准此评审,并验证其一致性,然后再依赖它进行监控。”
评审模型。 明确设置 model=,并从中档模型开始——anthropic:/claude-sonnet-4-6、openai:/gpt-4.1,或你所用服务商的同档模型。如果评审在明确案例上与人工标签不一致,就升级模型;只有在带标签样本上测量过一致性后,才降级模型。切勿为节省少量费用而降低红线评审(安全、法律)的模型等级——代码预筛选已经控制了其处理量。URI 格式和键名以 agent-evaluation/references/scorers.md 为准。
第 8 阶段:说明验证计划,然后移交
确定如何评估测试套件,然后停止。运行评估是 agent-evaluation 的工作,本技能不得重复执行。
优先使用用户已有的标签。 在提议任何人手动标注新数据集之前,先询问已有记录的过往失败案例有哪些——支持工单、投诉、事件报告、点踩反馈、退款、升级处理记录。基于真实的已知失败案例进行回测,胜过合成标签,而且无需任何制作成本。只有在不存在此类历史记录时,才提议手动标注。
对于每个 LLM 评审器,说明其对齐计划:将对齐哪些标签,以及第一个版本属于草案。谨慎对齐语气或风格等主观维度——对齐可能导致过拟合。指出无法对齐的地方:会话级内置评审器会引发 NotImplementedError。
最后确认测试套件、实现方案、暂缓到 v2 的想法、仅基于追踪数据的改进,以及验证计划。
然后移交——不要亲自运行评估。
agent-evaluation——注册评分器、发现/创建数据集、试运行、完整评估、结果分析和迭代。注册很重要:未注册的内联评分器不会出现在mlflow scorers list中,也无法重复使用。instrumenting-with-mlflow-tracing——处理第 2 阶段发现的追踪缺口,例如某项查找被标记为TOOL,但某项评估标准需要RETRIEVER。
范围界定。 本技能决定测量什么以及如何实现。
agent-evaluation决定如何运行评估以及如何解读结果。如果你发现自己正在准备数据集、注册评分器或解读评估输出,就已经超出本技能的范围——应移交处理。
关于领域专家标签、Review App 标注会话或 MemAlign,请阅读 references/judge-alignment.md。运行由此产生的评估仍是 agent-evaluation 的工作。
反模式
- 从评分器目录着手,而不是从用户的应用和失败案例出发。
- 在用户同意明确的评估标准之前就编写代码。如果用户想先讨论,就先讨论。
- 在对话中途贴出大段代码;这会终止逐步明确需求的讨论。
- 发布一套全由 LLM 评审器组成的测试套件,却不说明每项评审为何不能用代码检查或内置评审器实现——这是本技能最常见、代价最高的失误。
- 手写
make_judge来实现 MLflow 已提供的功能。策略遵循使用Guidelines;模式规则使用RegexMatch;多轮对话质量有会话级内置评审器。 - 只发布规则/策略检查,却不衡量用户是否成功。Agent 可能通过所有合规检查,却仍让每位使用者失望。
- 用可检查的代理指标替代重要结果(用
promotion_disclosed代替“租客获得了当时最优惠的交易”),并把结果层面视为已覆盖。 - 有更便宜的实现方案时,仅用抽样来回应成本异议。
- 还没询问用户已有的标签,就提议重新手动标注。
- 连续提问超过 3 个,却不展示草案。
- 为了编写评审器而询问内部关卡或状态机。
- 只检查最终状态,却忽略失败其实发生在对话上游。
- 明明使用数据集/
predict_fn原型就能奏效,却仍因追踪数据而阻塞。 - 把多个评估标准合并到一个评分器中,或只给无法推广的一次性示例打分。
- 默认使用
0.0-1.0分数;编写带有未定义占位符的代码。 - 在仅含 TOOL 的追踪数据上使用
RetrievalGroundedness。