Pydantic Evals 评估器(Evaluator)完全指南:从确定性断言到 LLM 裁判与实验级报告评估
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
Pydantic Evals 是 Pydantic AI 生态中的 AI 系统评估框架,而 Evaluator(评估器)是其核心:它们分析任务输出并产出分数(score)、标签(label)或通过/失败(pass/fail)断言。本文以 Evaluators Overview 为主干,结合pydantic_evals仓库源码,系统讲解三类评估器的选型、评估结果类型、组合与 case 级评估、同步/异步实现、EvaluatorContext上下文、错误处理以及实验级的报告评估器。读完本文,你将掌握如何为 LLM 调用、Agent 工具调用轨迹乃至多智能体应用搭建分层、可维护、可扩展的评估套件。
评估器的本质:一个接收上下文、产出结果的函数
在深入选型之前,先明确"评估器"在代码层面的抽象。Pydantic Evals 中所有评估器(包括报告评估器)都继承自共享的序列化基类BaseEvaluator,而普通评估器则继承自Evaluator(见 evaluator.py):
@dataclass(repr=False) class Evaluator(BaseEvaluator, Generic[InputsT, OutputT, MetadataT]): """Base class for all evaluators. Subclasses must implement the `evaluate` method. Note it can be defined with either `def` or `async def`.""" @abstractmethod def evaluate( self, ctx: EvaluatorContext[InputsT, OutputT, MetadataT] ) -> EvaluatorOutput | Awaitable[EvaluatorOutput]: ...关键事实如下:
- 唯一的抽象方法是
evaluate:它接收一个EvaluatorContext,返回EvaluatorOutput。子类只需实现它,同步def或异步async def均可; EvaluatorOutput是三种输出类型的联合(evaluator.py):
EvaluationScalar = bool | int | Annotated[float, Field(allow_inf_nan=False)] | str EvaluatorOutput = EvaluationScalar | EvaluationReason | Mapping[str, EvaluationScalar | EvaluationReason]bool作为断言,int/有限float作为分数,str作为标签——这与下文"评估结果类型"一节严格对应;- 序列化是内置的:
BaseEvaluator.as_spec()(evaluators/_base.py)会把评估器序列化为EvaluatorSpec(名称 + 参数),默认丢弃等于默认值的字段,使评估配置可写入 dataset 文件并跨环境复现; - 可选的版本标签:覆写
get_evaluator_version可给评估器打版本号(如'v2'),供在线评估(online evaluation)面板过滤掉旧版本结果而无需删除历史数据行。
此外,Evaluator提供evaluate_sync与evaluate_async两个辅助方法(evaluator.py),它们统一处理同步/异步实现:遇到协程就run_until_complete或await,因此你写的评估器无论同步还是异步,调用方都能以任意方式调用。
三类评估器选型:确定性检查、LLM 裁判、自定义逻辑
确定性检查(Deterministic Checks):快而可靠
当你可以写出精确规则时,优先使用确定性评估器。它们以微秒到毫秒级执行、结果可复现、零成本、极易调试。内置清单及典型用途如下表(全部实现在 common.py 与 agentic.py 中,完整参考见 Native Evaluators):
| 评估器 | 用途 | 示例 |
|---|---|---|
EqualsExpected | 输出与expected_output完全相等 | 结构化数据、分类任务 |
Equals | 输出等于指定值 | 检查哨兵值(sentinel) |
Contains | 子串 / 元素 / 键值对包含检查 | 必含关键词、PII 检测 |
IsInstance | 类型校验 | 输出格式验证 |
MaxDuration | 执行时长阈值 | SLA 合规 |
HasMatchingSpan | 行为验证 | 工具调用、代码路径 |
ToolCorrectness | 必需工具覆盖 | 实际调用工具名的多重集合 |
TrajectoryMatch | 工具调用序列质量 | 与期望轨迹的 F1 |
ArgumentCorrectness | 工具参数检查 | 退款单order_id、搜索 query |
MaxToolCalls | 预算纪律 | 工具调用预算 |
MaxModelRequests | 预算纪律 | 模型请求预算 |
适用场景:
- 格式验证(JSON 结构、类型检查);
- 必含/必不含内容检查(必须包含 X、不得包含 Y);
- 性能要求(延迟、token 数);
- 行为检查(调用了哪些工具、执行了哪些代码路径)。
从源码看,Contains的语义远比"子串匹配"丰富(common.py):对字符串检查子串、对 list/tuple 检查元素、对 dict 和 PydanticBaseModel/dataclass 检查键值对是否全部存在;case_sensitive仅当 value 与 output 都是字符串时生效。EqualsExpected有个值得注意的细节:当expected_output为None时它返回空字典{}跳过比较(common.py),因此若要断言"输出确实为 None",应改用Equals(value=None)。
LLM-as-a-Judge:灵活而有洞察力
当评估需要理解与判断时(事实准确性、相关性、语气风格、完整性、指令遵循、RAG 质量等),使用LLMJudge:
from pydantic_evals import Case, Dataset from pydantic_evals.evaluators import LLMJudge dataset = Dataset( name='llm_judge_example', cases=[Case(inputs='What is 2+2?', expected_output='4')], evaluators=[ LLMJudge( rubric='Response is factually accurate based on the input', include_input=True, ) ], )LLMJudge的关键参数与默认值(common.py):
rubric(必填):判定标准描述;model:裁判模型,默认为'openai:gpt-5.2',可通过set_default_judge_model全局覆盖;支持任意 Pydantic AIModel、KnownModelName或模型 ID 字符串;include_input/include_expected_output:是否把任务输入 / 期望输出一并交给裁判;model_settings:透传ModelSettings(如温度、max tokens);score/assertion:配置评分输出与断言输出的名称与是否附带理由,二者可同时启用(OutputConfig)。
底层实现(llm_as_a_judge.py)值得了解:LLMJudge 内部用 Pydantic AIAgent构建了 4 个专用裁判 agent(judge_output、judge_input_output、judge_output_expected、judge_input_output_expected),system prompt 中给出 JSON 输出结构{reason, pass, score}与正反示例,output_type=GradingOutput保证结构化输出;GradingOutput包含reason(1~2 句简洁裁决理由)、pass(布尔)与score(浮点)。因此一次LLMJudge调用既能产出断言也能产出分数,且理由字段可沉淀到报告中供人工审计。
优点:能评估主观质量(有用性、语气、创造力)、理解自然语言、可遵循复杂 rubric、跨领域灵活。缺点:每次评估需数秒、有调用成本、结果非确定性、可能存在偏见。适用场景:事实准确性、相关性与有用性、语气与风格、完整性、指令遵循、RAG 质量(groundedness、引用准确度)。
若需与业界广泛使用的方法对齐(G-Eval、Ragas 的 RAG 指标、GEMBA),见 Standard Quality Metrics:包括 G-Eval 风格的GEval评估器(提供criteria、evaluation_steps、score_range,默认(1, 5),实现为让模型先产出推理痕迹再给出区间内整数分,并校验min < max与至少一个步骤)以及可直接复制修改的LLMJudgerubric。若要与外部框架的精确上游实现对接,见 Third-Party Integrations。
自定义评估器:领域专属逻辑
框架未提供的逻辑,尤其是领域专属规则,可自行实现。自定义评估器只需继承Evaluator并实现evaluate:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class ValidSQL(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> bool: try: import sqlparse sqlparse.parse(ctx.output) return True except Exception: return False适用场景:
- 领域专属校验(SQL 语法、正则模式、业务规则);
- 外部 API 调用(运行生成代码、查询数据库);
- 复杂计算(precision/recall、BLEU 分数);
- 集成检查(API 调用是否成功)。
注意:Evaluator使用_StrictABCMeta元类(evaluators/_base.py),继承时若未实现抽象方法会在类定义阶段直接抛出TypeError,比标准 ABC 更早暴露遗漏。完整自定义指南见 Custom Evaluators。
评估结果类型:断言、分数、标签与多结果
评估器本质上返回三种标量结果(EvaluationScalar的精确定义见 evaluator.py),也可以返回EvaluationReason(标量 + 可选理由)或多结果映射。报告中的详细返回类型说明见 Custom Evaluator Return Types。
1. 断言(Assertions,bool)
通过/失败检查,在报告中显示为 ✔ 或 ✗:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class HasKeyword(Evaluator): keyword: str def evaluate(self, ctx: EvaluatorContext) -> bool: return self.keyword in ctx.output用于:二元检查、质量门禁(quality gates)、合规要求。
2. 分数(Scores,int 或 float)
数值型指标:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class ConfidenceScore(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> float: # Analyze and return score return 0.87 # 87% confidence用于:质量指标、排序、A/B 测试、回归跟踪。(源码层面float被限制为有限值:Annotated[float, Field(allow_inf_nan=False)]。)
3. 标签(Labels,str)
分类型结果:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class SentimentClassifier(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> str: if 'error' in ctx.output.lower(): return 'error' elif 'success' in ctx.output.lower(): return 'success' return 'neutral'用于:分类、错误归类、质量分桶。
多结果:一次评估产出多项
单个评估器可返回映射,键名即各评估项在报告中的名称:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class ComprehensiveCheck(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> dict[str, bool | float | str]: return { 'valid_format': self._check_format(ctx.output), # bool 'quality_score': self._score_quality(ctx.output), # float 'category': self._classify(ctx.output), # str } def _check_format(self, output: str) -> bool: return True def _score_quality(self, output: str) -> float: return 0.85 def _classify(self, output: str) -> str: return 'good'此外,EvaluationReason可给任何标量附带一句解释性reason(evaluator.py),报告会展示这些理由——内置的Contains、IsInstance、TrajectoryMatch等评估器失败时都会附带可读的失败原因文本,方便定位问题。
组合评估器:构建分层评估套件
将快速确定性检查与慢速 LLM 判断分层组合,是性价比最高的评估策略——先用廉价检查拦截绝大多数问题,再让 LLM 处理需要理解力的部分:
from pydantic_evals import Case, Dataset from pydantic_evals.evaluators import ( Contains, IsInstance, LLMJudge, MaxDuration, ) dataset = Dataset( name='layered_evaluation', cases=[Case(inputs='test', expected_output='result')], evaluators=[ # Fast deterministic checks first IsInstance(type_name='str'), Contains(value='required_field'), MaxDuration(seconds=2.0), # Slower LLM checks after LLMJudge( rubric='Response is accurate and helpful', include_input=True, ), ], )Dataset会按列表顺序执行这些评估器;在 Dataset 的evaluate/evaluate_sync流程中,所有 case 执行完毕后统一汇总各评估器的EvaluationResult与EvaluatorFailure到EvaluationReport。内置的DEFAULT_EVALUATORS元组(common.py)列出了全部 13 种可用内置评估器,可作为了解生态的索引。
Case-specific 评估器:为单个用例定制标准
case 级评估器是构建综合评估套件最强大的特性之一:你可以把评估器挂到单个Case对象上,让它只针对该 case 运行:
from pydantic_evals import Case, Dataset from pydantic_evals.evaluators import IsInstance, LLMJudge dataset = Dataset( name='case_specific_evaluators', cases=[ Case( name='greeting_response', inputs='Say hello', evaluators=[ # This evaluator only runs for this case LLMJudge( rubric='Response is warm and friendly, uses casual tone', include_input=True, ), ], ), Case( name='formal_response', inputs='Write a business email', evaluators=[ # Different requirements for this case LLMJudge( rubric='Response is professional and formal, uses business language', include_input=True, ), ], ), ], evaluators=[ # This runs for ALL cases IsInstance(type_name='str'), ], )为什么 case 级评估器很重要
case 级评估器解决了"一刀切评估"的根本问题:如果你能用单个评估 rubric 完美刻画所有 case 的需求,那不如把这个 rubric 直接写进 agent 的系统提示词。(当然,若生产环境用便宜模型、评测用更贵模型,这一论点相对弱化;但多数情况下生产环境应尽量用好模型。)case 级评估的价值来自其中的细微差别:
- 不同 case 需求不同:客服回复需要共情,技术 API 回复需要精确;
- 避免"囚徒管监狱"(inmates running the asylum):若 LLMJudge 的 rubric 通用到适用于一切场景,你的 agent 本就应当遵守它;
- 捕获细微的黄金行为:每个 case 可以精确指定该场景下"好"长什么样。
用 case 级 LLMJudge 构建黄金数据集(Golden Dataset)
一个特别强大的模式是:用 case 级LLMJudge快速构建全面、可维护的评估套件——不必准备精确的expected_output,只需描述你关心的行为:
from pydantic_evals import Case, Dataset from pydantic_evals.evaluators import LLMJudge dataset = Dataset( name='golden_dataset', cases=[ Case( name='handle_refund_request', inputs={'query': 'I want my money back', 'order_id': '12345'}, evaluators=[ LLMJudge( rubric=""" Response should: 1. Acknowledge the refund request empathetically 2. Ask for the reason for the refund 3. Mention our 30-day refund policy 4. NOT process the refund immediately (needs manager approval) """, include_input=True, ), ], ), Case( name='handle_shipping_question', inputs={'query': 'Where is my order?', 'order_id': '12345'}, evaluators=[ LLMJudge( rubric=""" Response should: 1. Confirm the order number 2. Provide tracking information 3. Give estimated delivery date 4. Be brief and factual (not overly apologetic) """, include_input=True, ), ], ), Case( name='handle_angry_customer', inputs={'query': 'This is completely unacceptable!', 'order_id': '12345'}, evaluators=[ LLMJudge( rubric=""" Response should: 1. Prioritize de-escalation with empathy 2. Avoid being defensive 3. Offer concrete next steps 4. Use phrases like "I understand" and "Let me help" """, include_input=True, ), ], ), ], )这种做法的收益:
- 快速构建全面测试套件:只需按 case 描述期望行为;
- 易于维护:需求变化时更新 rubric,无需重新生成输出;
- 自然覆盖边界情况:发现新边界时直接新增带专属要求的 case;
- 沉淀领域知识:每条 rubric 都记录该场景"好"的定义。
LLM 评估器擅长理解细微需求并评估符合度,这让它成为在不引入脆弱性的前提下实现全面评估覆盖的实用途径。该模式在仓库测试中同样被大量使用(见 test_agentic_evaluators.py、test_evaluator_common.py)。
同步 vs 异步:框架自动处理
评估器可以是同步的也可以是异步的:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext @dataclass class SyncEvaluator(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> bool: return True async def some_async_operation() -> bool: return True @dataclass class AsyncEvaluator(Evaluator): async def evaluate(self, ctx: EvaluatorContext) -> bool: result = await some_async_operation() return resultPydantic Evals 对两者自动处理(evaluate_sync/evaluate_async统一适配,见 evaluator.py)。需要异步的场景:发起 API 调用、执行数据库查询、进行 I/O 操作、调用 LLM(如LLMJudge,其evaluate本身就是async def)。
EvaluationContext:评估器的唯一输入
所有评估器都会收到一个EvaluatorContext,其字段如下:
ctx.inputs— 任务输入;ctx.output— 任务输出(待评估对象);ctx.expected_output— 期望输出(若提供);ctx.metadata— case 元数据(若提供);ctx.duration— 任务执行时长(秒);ctx.span_tree— OpenTelemetry span 树(配置了 Logfire 时可用;未配置或 TracerProvider 不兼容时,访问该属性会抛出SpanTreeRecordingError);ctx.metrics— 自定义指标字典,可在任务执行中通过pydantic_evals.dataset.increment_eval_metric写入;ctx.attributes— 自定义属性字典,可在任务执行中通过pydantic_evals.dataset.set_eval_attribute写入。
正是span_tree、metrics、attributes这些字段让 agentic 评估器(ToolCorrectness、TrajectoryMatch等)得以读取工具调用轨迹,也让评估器拥有完整上下文做出明智判断。
错误处理:EvaluatorFailure
若评估器抛出异常,它会被捕获为EvaluatorFailure:
from dataclasses import dataclass from pydantic_evals.evaluators import Evaluator, EvaluatorContext def risky_operation(output: str) -> bool: # This might raise an exception if 'error' in output: raise ValueError('Found error in output') return True @dataclass class RiskyEvaluator(Evaluator): def evaluate(self, ctx: EvaluatorContext) -> bool: # If this raises an exception, it will be captured result = risky_operation(ctx.output) return result失败会出现在report.cases[i].evaluator_failures中,包含:
- 评估器名称(
name); - 错误消息(
error_message); - 完整堆栈(
error_stacktrace); - 评估器 spec(
source)与可选的版本标签、异常类型类名(error_type,会以error.type属性体现在 OTel 事件上)。
可结合重试配置处理瞬时失败,参见 Retry Strategies。
报告评估器(Report Evaluators):实验级统计
以上所有评估器都是每个 case 运行一次。报告评估器则不同:它们在所有 case 评估完成后,对整个实验运行一次,分析全部结果集合。适用场景包括:
- 混淆矩阵(Confusion Matrix)— 可视化跨类别的分类准确率;
- Precision-Recall 曲线— 用 AUC 分数评估排序质量;
- 标量指标— 整体准确率、F1、BLEU 或任意单一数值;
- 汇总表— 按类别分解、错误类别汇总。
from pydantic_evals import Case, Dataset from pydantic_evals.evaluators import ConfusionMatrixEvaluator dataset = Dataset( name='report_evaluator_example', cases=[ Case(inputs='meow', expected_output='cat'), Case(inputs='woof', expected_output='dog'), ], report_evaluators=[ ConfusionMatrixEvaluator( predicted_from='output', expected_from='expected_output', ), ], )执行顺序为:Cases executed → Case evaluators run → Report evaluators run → Final report。报告评估器的结果以analyses形式存放在报告中,配置 Logfire 时会作为结构化属性附加到实验 span 上供可视化。
内置报告评估器除ConfusionMatrixEvaluator外,还有PrecisionRecallEvaluator、ROCAUCEvaluator、KolmogorovSmirnovEvaluator(report_common.py)。ConfusionMatrixEvaluator的关键参数(report-evaluators.md):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
predicted_from | 'expected_output' \| 'output' \| 'metadata' \| 'labels' | 'output' | 预测值来源 |
predicted_key | str \| None | None | 使用metadata/labels时取值键 |
expected_from | 'expected_output' \| 'output' \| 'metadata' \| 'labels' | 'expected_output' | 期望/真值来源 |
expected_key | str \| None | None | 使用metadata/labels时取值键 |
title | str | 'Confusion Matrix' | 报告中的标题 |
这些分类指标评估器内部会从case.scores(case 级评估器产出的分数)或case.metrics中提取分数,从expected_output、assertions或labels中提取正例标记,因此可以与 case 级评估器无缝协作——例如用 case 级LLMJudge产出分数,再用实验级ROCAUCEvaluator汇总评估排序质量。完整指南见 Report Evaluators。
下一步
- Native Evaluators — 全部内置评估器的完整参考(参数、返回类型、用例);
- LLM Judge — LLM-as-a-Judge 深度讲解;
- Standard Quality Metrics — G-Eval 及常见 RAG / 翻译指标的 LLM 裁判 rubric;
- Third-Party Integrations — 包装 Ragas、DeepEval 等指标库;
- Custom Evaluators — 编写自定义评估逻辑;
- Report Evaluators — 实验级分析;
- Span-Based Evaluation — 基于 OpenTelemetry span 的评估;
- Agentic Evaluators — 面向 agent 的轨迹、工具正确性、参数与步数预算检查。
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考