Files
2026-07-13 21:35:56 +08:00

340 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试 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 <name>` | 创建一个新的空数据集 |
| `pixie dataset list` | 列出所有数据集 |
| `pixie dataset save <name> [--select MODE]` | 将跨度保存到数据集中 |
| `pixie dataset validate [path]` | 验证数据集 JSON 文件 |
| `pixie analyze <test_run_id>` | 生成分析和建议 |
---
## 类型
### `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]' = <factory>) -> 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' = <object object at 0x7788c2ad5c80>, 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` 上可用。