Inspect 自 定义 评 分 器: Score、 未 评 分 样本 和 评 分 模型
英国 AI Security Institute 的 Inspect 文档:自定义评分器接收 TaskState 和 Target,返回 Score。说明 value 的 C/I/P/N、返回 None 与 Score.unscored() 的差别,以及用 grader 角色调用模型。附 close_enough、includes 和 model_graded_qa 的代码。

本文目录
自定义评分器
概述
自定义评分器是这样的函数:接收 TaskState 和 Target,产出一个 Score。评分器(scorer)负责给模型输出打分。TaskState 是当前样本的任务状态,里面有输入和模型输出。Target 是样本的标准答案。Score 是一次打分的结果。
async def score(state: TaskState, target: Target):
# Compare state / model output with target
# to yield a score
return Score(value=...)先说明核心对象 Score 和 Value,再给出几个自定义评分器的例子,把做法说具体。
示例
这个评分器从模型输出里取出最后一个数。当它落在 target 的相对容差之内时,把样本判为正确。它用 @scorer 登记指标,从 state 读取模型输出,与 target.text 比较,并返回带 answer 和 explanation 的 Score。指标(metric)是对许多样本的分数做汇总,例如正确率。
import re
from inspect_ai import Task, task
from inspect_ai.dataset import Sample
from inspect_ai.scorer import (
CORRECT,
INCORRECT,
Score,
Target,
accuracy,
scorer,
stderr,
)
from inspect_ai.solver import TaskState, generate
@scorer(metrics=[accuracy(), stderr()])
def close_enough(rel_tol: float = 0.01):
async def score(state: TaskState, target: Target) -> Score:
numbers = re.findall(
r"-?\d+(?:\.\d+)?", state.output.completion
)
if not numbers:
return Score(
value=INCORRECT,
explanation="No number found in output."
)
answer = numbers[-1]
expected = float(target.text)
correct = abs(float(answer) - expected) <= rel_tol * abs(expected)
return Score(
value=CORRECT if correct else INCORRECT,
answer=answer,
explanation=state.output.completion,
)
return score
@task
def arithmetic():
return Task(
dataset=[
Sample(
input="What is 18 * 7?",
target="126"
),
],
solver=generate(),
scorer=close_enough(),
)下面各节说明这个例子用到的部件。
Score
Score 的组成部分包括:
| 字段 | 类型 | 说明 |
|---|---|---|
value | Value | 赋给样本的分值(例如 "C" 或 "I",或一个原始数值)。 |
answer | str | 从模型输出中抽出、用来比较的文本(可选)。 |
explanation | str | 分数的说明,例如完整模型输出或评分模型的输出(可选)。 |
reason | ScoreReason | str` |
metadata | dict[str,Any] | 要写入日志文件的、关于这次分数的额外元数据(可选)。 |
例如,下面这些都是合法的 Score 对象:
Score(value="C")
Score(value="I")
Score(value=0.6)
Score(
value="C" if extracted == target.text else "I",
answer=extracted,
explanation=state.output.completion
)Score.value 可以是你的指标知道如何解释的任何 Value。内置的正确性评分器使用常量 CORRECT("C")、INCORRECT("I")、PARTIAL("P")和 NOANSWER("N")。指标如 accuracy() 默认使用的 value_to_float() 转换器,把这些值分别映射为 1.0、0.0、0.5 和 0.0。它也转换数值、数字字符串,以及常见的布尔字符串,例如 "yes" / "no" 和 "true" / "false"。
你可以返回其他字符串,但汇总指标需要一个能理解它们的转换器。例如:
from inspect_ai.scorer import accuracy, value_to_float
accuracy(
to_float=value_to_float(correct="pass", incorrect="fail")
)如果你是从一次补全内部抽取答案(例如用正则找文本,或看补全的开头或结尾),应尽量在 Score 里始终返回 answer。查看评测日志时,这会让打分细节容易理解得多。
未评分样本
当样本不在该评分器的范围内时,返回 None。例如,混合数据集里的代码测试评分器,可以对作文题返回 None。这样不会产生分数条目,也不会增加 unscored_samples。
当本来预期要给出判断、但没能得到时,使用 Score.unscored(),例如评分器的裁决无法解析:
return Score.unscored(
reason="grader_failed",
answer=extracted,
explanation="Grader did not return a parseable verdict.",
)这会创建一条值为 NaN 的分数,并保留所给的 reason、answer 和 explanation。指标会排除这个值。覆盖计数在 epoch 归约之后计算:默认的均值归约器忽略未评分的 epoch,其他归约器可以不同地处理它们。见 Interpreting coverage。
可选的 reason 接受标准的 ScoreReason 标签或自定义字符串。用 reason 描述结局,用 explanation 放上理解它所需要的细节。
对错误答案,或没有遵守任务要求格式的情况,返回一条已评分的裁决。对执行失败或非法的评分器输入,抛出异常,以便 Inspect 应用本次运行的错误处理设置。这些结局如何影响结果,见 Scoring Policy。
分值
Value 是主要标量类型,以及这些类型的 list 或 dict 的联合:
Value = Union[
str | int | float | bool,
Sequence[str | int | float | bool],
Mapping[str, str | int | float | bool],
]绝大多数评分器会使用 str(例如用 "C" 和 "I" 表示正确/不正确)或 float(其他类型是为了更复杂的情形)。要记住:评分器里使用的任何 Value 类型,都必须被该评分器声明的指标所支持(下文还会谈到)。
接下来看两个内置评分器的源码,作为实现自己的评分器的起点。如果正在写自定义评分器,也应阅读 Scoring Workflow,其中有优化开发过程的提示。
评分器里的模型
实现评分器时,常常要用到模型。最好的做法是用模型角色指定评分模型,让它们在运行时再选定。默认情况下,模型评分器查找名为 "grader" 的模型角色:
grader_model = get_model(role="grader")也可以用 get_model() 取得当前被评测的模型,或其他模型接口。例如:
# use the model being evaluated for grading
grader_model = get_model()
# use another model for grading
grader_model = get_model("google/gemini-2.5-pro")用 get_model() 的 config 参数覆盖默认生成选项:
grader_model = get_model(
"google/gemini-2.5-pro",
config = GenerateConfig(
temperature = 0.0
)
)示例:Includes
下面是内置 includes() 评分器的源码:
@scorer(metrics=[accuracy(), stderr()]) # <1>
def includes(ignore_case: bool = True):
async def score(state: TaskState, target: Target): # <2>
# check for correct
answer = state.output.completion
target = target.text # <3>
if ignore_case:
correct = answer.lower().rfind(target.lower()) != -1
else:
correct = answer.rfind(target) != -1
# return score
return Score(
value = CORRECT if correct else INCORRECT, # <4>
answer=answer # <5>
)
return score- 函数使用
@scorer装饰器,并登记两个供该评分器使用的指标。 score函数声明为async。这样它就能参加 Inspect 为昂贵的模型生成调用所做的优化调度(这个评分器不调用模型,但其他评分器会)。- 使用
Target上的text属性。这是一个方便属性,用来从Target取出简单文本值(因为目标在技术上可以是字符串列表)。 - 分值使用特殊常量
CORRECT和INCORRECT。accuracy()、stderr()和bootstrap_stderr()知道如何把这些常量转换成浮点值(分别是 1.0 和 0.0)。 - 把完整的模型补全作为分数的 answer(
answer可选,但强烈建议提供,评测开发时经常要回看它)。
示例:模型评分
下面是 model_graded_qa() 评分器代码的一个有所简化的版本:
@scorer(metrics=[accuracy(), stderr()])
def model_graded_qa(
template: str = DEFAULT_MODEL_GRADED_QA_TEMPLATE,
instructions: str = DEFAULT_MODEL_GRADED_QA_INSTRUCTIONS,
grade_pattern: str = DEFAULT_GRADE_PATTERN,
model: str | Model | None = None,
) -> Scorer:
# resolve grading template and instructions,
# (as they could be file paths or URLs)
template = resource(template)
instructions = resource(instructions)
# resolve model
grader_model = get_model(model)
async def score(state: TaskState, target: Target) -> Score:
# format the model grading template
score_prompt = template.format(
question=state.input_text,
answer=state.output.completion,
criterion=target.text,
instructions=instructions,
)
# query the model for the score
result = await grader_model.generate(score_prompt)
# extract the grade
match = re.search(grade_pattern, result.completion)
if match:
return Score(
value=match.group(1),
answer=match.group(0),
explanation=result.completion,
)
else:
return Score.unscored(
reason="grader_failed",
explanation="Grade not found in model output: "
+ f"{result.completion}",
)
return score如果分数无法解析,这个评分器会记一条未评分结果,并把评分模型的输出当作 explanation。如何选择分数结局,见 未评分样本。
注意对 model_grader.generate() 的调用使用了 await。这一点很关键,才能让评分器正确参加生成工作的调度。
还要注意,我们用 TaskState 的 input_text 属性取得原始用户输入的字符串版本,再代进评分模板。使用 input_text 有两个好处:(1)它保证覆盖数据集里的原始输入(而不是 messages 里被改写过的提示);(2)它把输入归一成字符串(输入本来也可能是消息列表)。
内置评分器的全部定制选项,见 Model Grading。
UK AI Security Institute,Custom Scorers,文档页无单独发布日期(检索于 2026-10-04),https://inspect.aisi.org.uk/custom-scorers.html ,MIT License(Copyright (c) 2024 UK AI Security Institute)
觉得有用,转给同事
微信扫码
用微信扫一扫,在手机上打开后即可转发。