# 测试 API 参考 > 自动从 pixie 源代码文档字符串生成。 > 请勿手动编辑——请运行 `uv run python scripts/generate_skill_docs.py`。 pixie.evals —— LLM 应用程序的评估框架。 公开 API: - `Evaluation` —— 单次评估器运行的结果数据类 - `Evaluator` —— 评估可调用对象的协议 - `evaluate` —— 针对一个可评估对象运行一个评估器 - `run_and_evaluate` —— 评估来自 MemoryTraceHandler 的跨度 - `assert_pass` —— 带通过/失败条件的批量评估 - `assert_dataset_pass` —— 加载数据集并运行 assert_pass - `EvalAssertionError` —— 当 assert_pass 失败时抛出 - `capture_traces` —— 用于内存中追踪捕获的上下文管理器 - `MemoryTraceHandler` —— 收集跨度的 InstrumentationHandler - `ScoreThreshold` —— 可配置的通过标准 - `last_llm_call` / `root` —— 追踪到可评估对象的辅助函数 - `DatasetEntryResult` —— 单个数据集条目的评估结果 - `DatasetScorecard` —— 带非统一评估器的按数据集评分卡 - `generate_dataset_scorecard_html` —— 将评分卡渲染为 HTML - `save_dataset_scorecard` —— 将评分卡 HTML 写入磁盘 预置评估器(autoevals 适配器): - `AutoevalsAdapter` —— 任意 autoevals `Scorer` 的通用包装器 - `LevenshteinMatch` —— 编辑距离字符串相似度 - `ExactMatch` —— 精确值比较 - `NumericDiff` —— 归一化数值差异 - `JSONDiff` —— 结构化 JSON 比较 - `ValidJSON` —— JSON 语法 / Schema 验证 - `ListContains` —— 列表重叠 - `EmbeddingSimilarity` —— 嵌入余弦相似度 - `Factuality` —— LLM 事实准确性检查 - `ClosedQA` —— 闭卷问答评估 - `Battle` —— 两两对比 - `Humor` —— 幽默检测 - `Security` —— 安全漏洞检查 - `Sql` —— SQL 等价性 - `Summary` —— 摘要质量 - `Translation` —— 翻译质量 - `Possible` —— 可行性检查 - `Moderation` —— 内容审核 - `ContextRelevancy` —— RAGAS 上下文相关性 - `Faithfulness` —— RAGAS 忠实度 - `AnswerRelevancy` —— RAGAS 答案相关性 - `AnswerCorrectness` —— RAGAS 答案正确性 ## 数据集 JSON 格式 数据集是一个 JSON 对象,包含以下顶层字段: ```json { "name": "customer-faq", "runnable": "pixie_qa/run_app.py:AppRunnable", "evaluators": ["Factuality"], "entries": [ { "input_data": { "question": "Hello" }, "description": "Basic greeting", "eval_input": [{ "name": "input", "value": "Hello" }], "expectation": "A friendly greeting that offers to help", "evaluators": ["...", "ClosedQA"] } ] } ``` ### 条目结构 所有字段均在每个条目上作为顶层字段(扁平结构——无嵌套): ``` entry: ├── input_data (必需)—— Runnable.run() 的参数 ├── eval_input (可选)—— {"name": ..., "value": ...} 对象的列表(默认:[]) ├── description (必需)——测试用例的人类可读标签 ├── expectation (可选)——用于基于比较的评估器的参考值 ├── eval_metadata (可选)——用于自定义评估器的额外逐条目数据 └── evaluators (可选)——此条目的评估器名称 ``` ### 字段参考 - `runnable`(必需):驱动评估期间应用的 `Runnable` 子类的 `filepath:ClassName` 引用。 - `evaluators`(数据集级别,可选):默认评估器名称——应用于每个未声明自己的 `evaluators` 的条目。 - `entries[].input_data`(必需):作为 Pydantic 模型传递给 `Runnable.run()` 的关键字参数。键必须与 `run(args: T)` 中使用的 Pydantic 模型的字段匹配。 - `entries[].description`(必需):测试用例的人类可读标签。 - `entries[].eval_input`(可选,默认 `[]`):`{"name": ..., "value": ...}` 对象的列表。用于填充包装输入注册表——应用中的 `wrap(purpose="input")` 调用返回按 `name` 键控的注册表值。运行器在构建 `Evaluable` 时会自动前置 `input_data`。 - `entries[].expectation`(可选):针对基于比较的评估器的简洁预期描述。应描述正确输出的样子,**而不是**逐字复制输出。对追踪使用 `pixie format` 以查看实际输出形状,然后编写更短的描述。 - `entries[].eval_metadata`(可选):用于自定义评估器的额外逐条目数据——例如,预期的工具名称、布尔标志、阈值。在评估器中通过 `evaluable.eval_metadata` 访问。 - `entries[].evaluators`(可选):行级别的评估器覆盖。规则: - 省略 → 条目继承数据集级别的 `evaluators`。 - `["...", "ClosedQA"]` → 数据集默认值 **加上** ClosedQA。 - `["OnlyThis"]`(无 `"..."`)→ **仅** OnlyThis,不包含默认值。 ## 评估器名称解析 在数据集 JSON 中,评估器名称按如下方式解析: - **内置名称**(裸名称,如 `"Factuality"`、`"ExactMatch"`)会自动解析为 `pixie.{Name}`。 - **自定义评估器**使用 `filepath:callable_name` 格式(例如 `"pixie_qa/evaluators.py:my_evaluator"`)。 - 自定义评估器引用指向模块级别的可调用对象——类(自动实例化)、工厂函数(如果零参数则调用)、评估器函数(按原样使用)或预实例化的可调用对象(例如 `create_llm_evaluator` 的结果——按原样使用)。 ## CLI 命令 | 命令 | 描述 | | ------------------------------------------- | ----------------------------- | | `pixie test [path] [-v] [--no-open]` | 对数据集文件运行评估测试 | | `pixie dataset create ` | 创建一个新的空数据集 | | `pixie dataset list` | 列出所有数据集 | | `pixie dataset save [--select MODE]` | 将跨度保存到数据集中 | | `pixie dataset validate [path]` | 验证数据集 JSON 文件 | | `pixie analyze ` | 生成分析和建议 | --- ## 类型 ### `Evaluable` ```python class Evaluable(TestCase): eval_output: list[NamedData] # wrap(purpose="output") + wrap(purpose="state") 值 # 继承自 TestCase: # eval_input: list[NamedData] # 来自数据集条目中的 eval_input # expectation: JsonValue | _Unset # 来自数据集条目中的 expectation # eval_metadata: dict[str, JsonValue] | None # 来自数据集条目中的 eval_metadata # description: str | None ``` 评估器的数据载体。使用实际输出扩展 `TestCase`。 - `eval_input` —— 从条目的 `eval_input` 字段加上 `input_data`(由运行器前置)填充的 `list[NamedData]`。始终至少包含一个条目。 - `eval_output` —— 包含运行期间捕获的所有 `wrap(purpose="output")` 和 `wrap(purpose="state")` 值的 `list[NamedData]`。每个条目都有 `.name`(str)和 `.value`(JsonValue)。使用 `_get_output(evaluable, "name")` 按名称查找。 - `eval_metadata` —— 来自条目 `eval_metadata` 字段的 `dict[str, JsonValue] | None` - `expected_output` —— 来自数据集的预期文本(如果未提供则为 `UNSET`) 属性: eval_input:命名输入数据项(来自数据集 + 运行器前置的 input_data)。始终非空。 eval_output:命名输出数据项(来自运行期间的 wrap 调用)。 每个条目都有 `.name`(str)和 `.value`(JsonValue)。 包含所有 `wrap(purpose="output")` 和 `wrap(purpose="state")` 值。 eval_metadata:补充元数据(不存在时为 `None`)。 expected_output:用于评估的预期/参考输出。 默认为 `UNSET`(未提供)。可被显式 设置为 `None`,表示"没有预期输出"。 ### 测试时 `wrap()` 如何映射到 `Evaluable` 字段 当 `pixie test` 运行数据集条目时,应用中的 `wrap()` 调用会填充评估器接收的 `Evaluable`: | 应用代码中的 `wrap()` 调用 | Evaluable 字段 | 类型 | 在评估器中的访问方式 | | --------------------------------------------- | --------------- | ----------------- | --------------------------------------------------------- | | `wrap(data, purpose="input", name="X")` | `eval_input` | `list[NamedData]` | 从数据集条目的 `eval_input` 预填充 | | `wrap(data, purpose="output", name="X")` | `eval_output` | `list[NamedData]` | `_get_output(evaluable, "X")` —— 参见下面的辅助函数 | | `wrap(data, purpose="state", name="X")` | `eval_output` | `list[NamedData]` | `_get_output(evaluable, "X")` —— 与输出相同的列表 | | (来自数据集条目 `expectation`) | `expected_output` | `str \| None` | `evaluable.expected_output` | | (来自数据集条目 `eval_metadata`) | `eval_metadata` | `dict \| None` | `evaluable.eval_metadata` | **关键理解**:`purpose="output"` 和 `purpose="state"` 的 wrap 值最终都作为 `NamedData` 条目进入 `eval_output`。没有单独的 `captured_output` 或 `captured_state` 字典。使用下面的辅助函数按 wrap 名称查找值: ```python def _get_output(evaluable: Evaluable, name: str) -> Any: """Look up a wrap value by name from eval_output.""" for item in evaluable.eval_output: if item.name == name: return item.value return None ``` **`eval_metadata`** 用于向评估器传递额外的逐条目数据,这些数据既不是输入数据也不是输出——例如,预期的工具名称、布尔标志、阈值。定义为条目的顶层字段,通过 `evaluable.eval_metadata` 访问。 **完整的自定义评估器示例**(工具调用检查 + 数据集条目): ```python from pixie import Evaluation, Evaluable def _get_output(evaluable: Evaluable, name: str) -> Any: """Look up a wrap value by name from eval_output.""" for item in evaluable.eval_output: if item.name == name: return item.value return None def tool_call_check(evaluable: Evaluable, *, trace=None) -> Evaluation: expected = evaluable.eval_metadata.get("expected_tool") if evaluable.eval_metadata else None actual = _get_output(evaluable, "function_called") if expected is None: return Evaluation(score=1.0, reasoning="No expected_tool specified") match = str(actual) == str(expected) return Evaluation( score=1.0 if match else 0.0, reasoning=f"Expected {expected}, got {actual}", ) ``` 对应的数据集条目: ```json { "input_data": { "user_message": "I want to end this call" }, "description": "User requests call end after failed verification", "eval_input": [{ "name": "user_input", "value": "I want to end this call" }], "expectation": "Agent should call endCall tool", "eval_metadata": { "expected_tool": "endCall", "expected_call_ended": true }, "evaluators": ["...", "pixie_qa/evaluators.py:tool_call_check"] } ``` ### `Evaluation` ```python Evaluation(score: 'float', reasoning: 'str', details: 'dict[str, Any]' = ) -> None ``` 单个评估器应用于单个测试用例的结果。 属性: score:介于 0.0 和 1.0 之间的评估分数。 reasoning:人类可读的解释(必需)。 details:任意的 JSON 可序列化元数据。 ### `ScoreThreshold` ```python ScoreThreshold(threshold: 'float' = 0.5, pct: 'float' = 1.0) -> None ``` 通过标准:在所有评估器上,_pct_ 比例的输入必须得分 >= _threshold_。 属性: threshold:单次评估必须达到的最低分数。 pct:必须通过的测试用例输入比例(0.0–1.0)。 ## 评估函数 ### `pixie.run_and_evaluate` ```python pixie.run_and_evaluate(evaluator: 'Callable[..., Any]', runnable: 'Callable[..., Any]', eval_input: 'Any', *, expected_output: 'Any' = , from_trace: 'Callable[[list[ObservationNode]], Evaluable] | None' = None) -> 'Evaluation' ``` 在捕获追踪的同时运行 _runnable(eval_input)_,然后进行评估。 结合了 `_run_and_capture` 和 `evaluate` 的便捷包装器。 runnable 仅被调用一次。 参数: evaluator:评估器可调用对象(同步或异步)。 runnable:要测试的应用函数。 eval_input:传递给 _runnable_ 的单个输入。 expected_output:合并到 evaluable 中的可选预期值。 from_trace:用于从追踪树中选择特定跨度进行评估的可选可调用对象。 返回: `Evaluation` 结果。 抛出: ValueError:如果执行期间未捕获到任何跨度。 ### `pixie.assert_pass` ```python pixie.assert_pass(runnable: 'Callable[..., Any]', eval_inputs: 'list[Any]', evaluators: 'list[Callable[..., Any]]', *, evaluables: 'list[Evaluable] | None' = None, pass_criteria: 'Callable[[list[list[Evaluation]]], tuple[bool, str]] | None' = None, from_trace: 'Callable[[list[ObservationNode]], Evaluable] | None' = None) -> 'None' ``` 在多个输入上对 runnable 运行评估器。 对于每个输入,通过 `_run_and_capture` 运行一次 runnable, 然后通过 `asyncio.gather` 并发地使用每个评估器进行评估。 结果矩阵的形状为 `[eval_inputs][evaluators]`。 如果未满足通过标准,则抛出携带该矩阵的 :class:`EvalAssertionError`。 当提供了 `evaluables` 时,行为取决于每个条目是否已填充了 `eval_output`: - **eval_output 为 None** —— 通过 `run_and_evaluate` 调用 `runnable` 以从追踪生成输出,并且来自 evaluable 的 `expected_output` 会合并到结果中。 - **eval_output 不为 None** —— 直接使用该 evaluable(该条目不调用 runnable)。 参数: runnable:要测试的应用函数。 eval_inputs:输入列表,每个都传递给 _runnable_。 evaluators:评估器可调用对象列表。 evaluables:可选的 `Evaluable` 项列表,每个输入对应一个。 当提供时,它们的 `expected_output` 会被转发到 `run_and_evaluate`。必须与 _eval_inputs_ 具有相同的长度。 pass_criteria:接收结果矩阵,返回 `(passed, message)`。默认为 `ScoreThreshold()`。 from_trace:可选的跨度选择器,转发到 `run_and_evaluate`。 抛出: EvalAssertionError:当未满足通过标准时。 ValueError:当 _evaluables_ 长度与 _eval_inputs_ 不匹配时。 ### `pixie.assert_dataset_pass` ```python pixie.assert_dataset_pass(runnable: 'Callable[..., Any]', dataset_name: 'str', evaluators: 'list[Callable[..., Any]]', *, dataset_dir: 'str | None' = None, pass_criteria: 'Callable[[list[list[Evaluation]]], tuple[bool, str]] | None' = None, from_trace: 'Callable[[list[ObservationNode]], Evaluable] | None' = None) -> 'None' ``` 按名称加载数据集,然后对其条目运行 `assert_pass`。 这是一个便捷包装器,它: 1. 从 `DatasetStore` 加载数据集。 2. 从每个条目中提取 `eval_input` 作为 runnable 输入。 3. 使用完整的 `Evaluable` 项(它们携带 `expected_output`) 作为评估对象。 4. 委托给 `assert_pass`。 参数: runnable:要测试的应用函数。 dataset_name:要加载的数据集的名称。 evaluators:评估器可调用对象列表。 dataset_dir:数据集存储的覆盖目录。 当为 `None` 时,从 `PixieConfig.dataset_dir` 读取。 pass_criteria:接收结果矩阵,返回 `(passed, message)`。 from_trace:可选的跨度选择器,转发到 `assert_pass`。 抛出: FileNotFoundError:如果不存在名为 _dataset_name_ 的数据集。 EvalAssertionError:当未满足通过标准时。 ## 追踪辅助函数 ### `pixie.last_llm_call` ```python pixie.last_llm_call(trace: 'list[ObservationNode]') -> 'Evaluable' ``` 在追踪树中找到具有最新 `ended_at` 的 `LLMSpan`。 参数: trace:追踪树(根 `ObservationNode` 实例的列表)。 返回: 包装最近结束的 `LLMSpan` 的 `Evaluable`。 抛出: ValueError:如果追踪中不存在 `LLMSpan`。 ### `pixie.root` ```python pixie.root(trace: 'list[ObservationNode]') -> 'Evaluable' ``` 将第一个根节点的跨度作为 `Evaluable` 返回。 参数: trace:追踪树(根 `ObservationNode` 实例的列表)。 返回: 包装第一个根节点跨度的 `Evaluable`。 抛出: ValueError:如果追踪为空。 ### `pixie.capture_traces` ```python pixie.capture_traces() -> 'Generator[MemoryTraceHandler, None, None]' ``` 安装 `MemoryTraceHandler` 并返回它的上下文管理器。 调用 `init()`(如果已初始化则为空操作),然后通过 `add_handler()` 注册该处理器。退出时,处理器被移除,交付队列被刷新,以便所有跨度在 `handler.spans` 上可用。