Opik Python SDK 的 TestSuiteResult 深入解析:测试套件结果的数据结构、通过判定与报告生成
【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm
导读
opik.TestSuiteResult是 Opik Python SDK 中代表一次测试套件(Test Suite)运行结果的核心对象,由opik.run_tests()返回。本文以该对象的官方 API 文档为骨架,结合仓库源码(test_suite_result.py、suite_result_constructor.py 等)逐层拆解其数据结构、三级通过判定规则、执行策略的影响,以及结构化报告的生成与解析方式。读完本文,你将能读懂测试套件返回结果中的每一个字段,并能在 CI 中基于pass_rate、all_items_passed等属性编写自动化断言。
一、TestSuiteResult 的定位:一次测试套件运行的「成绩单」
在 Opik 的回归测试体系中,Test Suite 是一组预配置的测试用例(item),每个用例可以携带独立的断言(assertions)和执行策略(execution policy)。调用opik.run_tests(test_suite=..., task=...)后,SDK 会依次完成:
- 创建实验(experiment);
- 对每个测试项调用任务函数(task)并收集输出;
- 用 LLM 判官(LLMJudge)对输出执行断言打分;
- 将原始评估结果汇总为
TestSuiteResult并返回。
这条调用链的源码入口在 evaluator.py 的run_tests(),其内部调用__internal_api__run_test_suite__(),最后由 suite_result_constructor.py 的build_suite_result()完成结果装配。
TestSuiteResult的官方 docstring 将其职责概括为:"包含每个测试项在执行策略下的通过/失败状态,以及整个套件的总体通过/失败状态"。也就是说,它是一个聚合视图——向上回答"套件过没过",向下回答"哪个测试项、哪次运行、哪条断言挂了"。
二、TestSuiteResult 核心数据模型
TestSuiteResult定义于 test_suite_result.py,其构造参数如下(正常情况下用户不会直接实例化它,而是由build_suite_result()自动构建):
| 构造参数 | 类型 | 说明 |
|---|---|---|
items_passed | int | 通过(满足执行策略)的测试项数量 |
items_total | int | 参与评估的测试项总数 |
item_results | Dict[str, ItemResult] | 以dataset_item_id为键的逐项结果 |
evaluation_result_ | EvaluationResult | 底层的原始评估结果,用于暴露实验信息 |
suite_name | Optional[str] | 测试套件名称 |
total_time | Optional[float] | 整个评估的总耗时(秒) |
2.1 面向使用者的属性
通过公开属性可以直接读取结果的核心指标:
all_items_passed→bool:是否所有测试项全部通过。其实现是items_passed == items_total,这也是判定"套件整体通过"的唯一定义,同时被写入 JSON 报告中的suite_passed字段。items_passed→int:通过的测试项数量。items_total→int:测试项总数。pass_rate→Optional[float]:通过率,仅在有断言的测试项中计算。源码中先筛出has_assertions == True的项再求比值;若没有任何项带断言,则返回None。这意味着"无断言的测试项既不会拉低通过率,也不计入分母"。item_results→Dict[str, ItemResult]:逐项结果,键为dataset_item_id。suite_name→Optional[str]:套件名称。total_time→Optional[float]:总评估耗时(秒)。
2.2 实验信息透传属性
由于TestSuiteResult内部持有EvaluationResult,它还透传了三个实验相关属性,方便与 Opik 平台联动:
experiment_id→str:本次运行创建的实验 ID;experiment_name→Optional[str]:实验名称(未显式指定时由 SDK 自动生成);experiment_url→Optional[str]:在 Opik 仪表盘中查看该实验的链接。
这三个字段最终都会出现在生成的 JSON 报告中,是连接"本地结果"与"平台可观测数据"的桥梁。
三、ItemResult:单个测试项的细粒度结果
ItemResult是与TestSuiteResult同文件定义的一个@dataclasses.dataclass(test_suite_result.py),描述单个测试项的评估情况:
| 字段 | 类型 | 含义 |
|---|---|---|
dataset_item_id | str | 数据集(测试套件)中该项的 ID |
passed | bool | 该项是否按执行策略通过 |
has_assertions | bool | 该项是否有断言被执行 |
runs_passed | int | 该项通过的运行(run)次数 |
runs_total | int | 该项实际完成的运行总数 |
configured_runs_per_item | int | 执行策略配置的每项运行次数 |
pass_threshold | int | 执行策略要求的最低通过运行次数 |
test_results | List[TestResult] | 每次运行的详细测试结果(按trial_id排序) |
其中configured_runs_per_item与pass_threshold直接来源于执行策略。执行策略在 execution_policy.py 中定义,默认值为:
DEFAULT_EXECUTION_POLICY = { "runs_per_item": 1, "pass_threshold": 1, }即默认每个测试项运行 1 次、通过 1 次即算通过。当需要对抗 LLM 输出的随机性时,可以给某个测试项单独配置{"runs_per_item": 5, "pass_threshold": 4}——多次采样、多数通过才算该用例通过。
四、三级通过判定逻辑(源码级)
整个结果的通过判定是**"运行 → 测试项 → 套件"**的三级递进结构,逻辑集中在 suite_result_constructor.py:
- 一次运行(RUN)通过:该次运行的所有断言分数全部通过。判定函数
is_score_passed()(test_suite_result.py)的规则是:scoring_failed(打分失败)一律视为不通过;否则当分数值等于布尔True或数值1时视为通过。值得注意的是,一个测试项如果没有断言(score_results为空),其运行默认视为通过。 - 一个测试项(ITEM)通过:
runs_passed >= pass_threshold,其中runs_passed统计该测试项下所有通过运行的次数。 - 整个套件(SUITE)通过:
items_passed == items_total,即所有测试项全部通过——套件层面不允许部分通过,这与pass_rate(允许 0~1 之间的小数)形成鲜明对比。
这套逻辑的源码注释同样给出了权威描述:"A RUN passes if all its assertion scores pass (value=True or value=1); An ITEM passes if runs_passed >= pass_threshold; The SUITE passes if all items pass."
五、run_tests 参数速查:与结果对象直接相关的使用面
TestSuiteResult由opik.run_tests()产生,其签名(evaluator.py)中与结果形态最相关的参数如下:
| 参数 | 默认值 | 说明 |
|---|---|---|
test_suite | 必填 | 传入TestSuite(跑最新版本)或TestSuiteVersion(跑指定版本快照) |
task | 必填 | 接收每个测试项data字典的可调用对象;返回dict(须含input/output键)或其他任意值(自动包装为{"output": value}) |
experiment_name/experiment_name_prefix | None | 指定或自动生成实验名称,会体现在result.experiment_name中 |
verbose | 2 | 0=静默,1=汇总,2=详细(影响控制台输出与断言明细) |
worker_threads | 16 | 并行执行任务函数的线程数 |
model | None | 用于执行断言打分的模型名 |
generate_report | True | 是否生成 JSON 报告文件 |
report_output_path | None | 报告文件路径,缺省时写入opik_test_suite_reports/目录 |
scoring_tool_strategy | None | "auto"/"always"/"never",覆盖所有判官的评分工具策略 |
六、结构化报告:to_report_dict 与 JSON 落盘
6.1 报告字典结构
to_report_dict()(test_suite_result.py,to_dict()是其别名)将结果序列化为可供 CI 消费的字典。顶层结构如下:
{ "suite_passed": true, "items_passed": 8, "items_total": 8, "pass_rate": 1.0, "experiment_id": "9f3a...", "suite_name": "Refund Policy Tests", "experiment_name": "test-suite-2025-01-01-00-00-00", "experiment_url": "https://...", "total_time_seconds": 42.13, "generated_at": "2026-09-12T00:00:00+00:00", "items": [ { "dataset_item_id": "...", "passed": true, "runs_passed": 5, "execution_policy": {"runs_per_item": 5, "pass_threshold": 4}, "runs": [ { "trial_id": 0, "passed": true, "input": {...}, "output": "...", "trace_id": "...", "task_execution_time_seconds": 0.812, "scoring_time_seconds": 0.35, "assertions": [ {"name": "Response is polite", "passed": true, "value": true, "scoring_failed": false} ] } ] } ] }报告中对每条断言展开name、passed、value、scoring_failed,并在存在时附带reason与metadata;每次运行附带trace_id、task_execution_time_seconds、scoring_time_seconds,便于回查平台上的完整链路。整体items数组按数据集项分组,与item_results字典一一对应。
6.2 JSON 文件落盘
当generate_report=True时,file_writer.py 会将上述字典写入本地 JSON 文件:未指定report_output_path时默认落在opik_test_suite_reports/目录下,文件名为净化后的实验名加.json后缀(如opik_test_suite_reports/test-suite-2025-01-01-00-00-00.json)。写入时会自动创建父目录,并使用indent=2保证可读性。
6.3 控制台展示
结果同时会在终端以面板形式渲染(displayer.py),展示套件名、Suite result: PASSED/FAILED、Items passed: 8/8、Pass rate: 100.0%、总耗时(HH:MM:SS格式)、平均任务/打分耗时;verbose >= 2时还会按通过率升序逐条列出每个断言的通过率。若实验 URL 或报告路径存在,面板会输出可点击的"View results in Opik dashboard"与"View local detailed report file"链接。
七、实战示例:创建套件、运行并消费结果
结合 test_suite.py 的官方示例,一个完整的"运行 + 结果消费"流程如下:
import opik client = opik.Opik() # 1. 创建测试套件,定义套件级全局断言 suite = client.create_test_suite( name="Refund Policy Tests", description="Regression tests for refund scenarios", global_assertions=[ "Response does not contain hallucinated information", "Response is helpful to the user", ], ) # 2. 插入测试项:可携带项级断言与独立执行策略 suite.insert([ { "data": {"user_input": "How do I get a refund?", "user_tier": "premium"}, "assertions": ["Response is polite"], }, { "data": {"user_input": "Is my account hacked?"}, "assertions": ["Response treats the concern with urgency"], "execution_policy": {"runs_per_item": 5, "pass_threshold": 4}, }, ]) # 3. 运行测试套件,task 接收 data 字典并返回输出 results = opik.run_tests( test_suite=suite, task=my_llm_function, experiment_name="refund-v2-regression", verbose=1, ) # 4. 消费 TestSuiteResult print(results.all_items_passed) # 套件是否整体通过 print(results.items_passed, results.items_total) # 8 8 print(results.pass_rate) # 1.0(仅统计有断言的项) print(results.experiment_url) # 跳转平台查看实验 print(results.total_time) # 总耗时(秒) # 5. 逐项排查:找到失败项及其失败断言 for item_id, item in results.item_results.items(): if not item.passed: print("failed item:", item_id) print("runs:", item.runs_passed, "/", item.runs_total, "threshold:", item.pass_threshold) # 6. 生成结构化报告字典 / 落盘 JSON report = results.to_report_dict() # 或 results.to_dict()在 CI 场景中,常见的做法是直接断言results.all_items_passed或results.pass_rate >= 0.95来决定流水线是否继续,并通过results.experiment_url将失败详情链接回 Opik 仪表盘人工排查。
八、注意事项与最佳实践
- 无断言项不影响 pass_rate:
pass_rate只统计has_assertions=True的测试项,无断言的项不会拉低通过率,但也不会进入分母;套件级all_items_passed则不受此影响。 - 打分失败(scoring_failed)视为不通过:断言打分过程中出现异常时,
is_score_passed直接返回False,保证"无法判定"不会误报为通过。 - 区分三种"通过"粒度:运行通过 ≠ 测试项通过 ≠ 套件通过。配置
runs_per_item > 1时,单次运行失败并不代表测试项失败,只有通过次数低于pass_threshold时该项才判失败。 - 任务函数返回值规范:若返回
dict,必须同时包含"input"与"output"键,否则validate_task_result()(test_suite.py)会抛出ValueError;返回其他类型则自动包装为{"output": result}。 - 报告的
generated_at使用 UTC 时间戳:跨时区团队比对报告时注意时区转换。
相关文件索引
- 类定义与报告序列化:test_suite_result.py
- 结果构建与三级判定逻辑:suite_result_constructor.py
- 执行策略类型与默认值:execution_policy.py
- 运行入口
run_tests:evaluator.py - 控制台展示:displayer.py
- JSON 报告落盘:file_writer.py
- 套件 API 与任务校验:test_suite.py
【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考