Opik Python SDK 的 TestSuiteResult 深入解析:测试套件结果的数据结构、通过判定与报告生成
2026/9/13 8:13:55 网站建设 项目流程

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_rateall_items_passed等属性编写自动化断言。

一、TestSuiteResult 的定位:一次测试套件运行的「成绩单」

在 Opik 的回归测试体系中,Test Suite 是一组预配置的测试用例(item),每个用例可以携带独立的断言(assertions)和执行策略(execution policy)。调用opik.run_tests(test_suite=..., task=...)后,SDK 会依次完成:

  1. 创建实验(experiment);
  2. 对每个测试项调用任务函数(task)并收集输出;
  3. 用 LLM 判官(LLMJudge)对输出执行断言打分;
  4. 将原始评估结果汇总为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_passedint通过(满足执行策略)的测试项数量
items_totalint参与评估的测试项总数
item_resultsDict[str, ItemResult]dataset_item_id为键的逐项结果
evaluation_result_EvaluationResult底层的原始评估结果,用于暴露实验信息
suite_nameOptional[str]测试套件名称
total_timeOptional[float]整个评估的总耗时(秒)

2.1 面向使用者的属性

通过公开属性可以直接读取结果的核心指标:

  • all_items_passedbool:是否所有测试项全部通过。其实现是items_passed == items_total,这也是判定"套件整体通过"的唯一定义,同时被写入 JSON 报告中的suite_passed字段。
  • items_passedint:通过的测试项数量。
  • items_totalint:测试项总数。
  • pass_rateOptional[float]:通过率,仅在有断言的测试项中计算。源码中先筛出has_assertions == True的项再求比值;若没有任何项带断言,则返回None。这意味着"无断言的测试项既不会拉低通过率,也不计入分母"。
  • item_resultsDict[str, ItemResult]:逐项结果,键为dataset_item_id
  • suite_nameOptional[str]:套件名称。
  • total_timeOptional[float]:总评估耗时(秒)。

2.2 实验信息透传属性

由于TestSuiteResult内部持有EvaluationResult,它还透传了三个实验相关属性,方便与 Opik 平台联动:

  • experiment_idstr:本次运行创建的实验 ID;
  • experiment_nameOptional[str]:实验名称(未显式指定时由 SDK 自动生成);
  • experiment_urlOptional[str]:在 Opik 仪表盘中查看该实验的链接。

这三个字段最终都会出现在生成的 JSON 报告中,是连接"本地结果"与"平台可观测数据"的桥梁。

三、ItemResult:单个测试项的细粒度结果

ItemResult是与TestSuiteResult同文件定义的一个@dataclasses.dataclass(test_suite_result.py),描述单个测试项的评估情况:

字段类型含义
dataset_item_idstr数据集(测试套件)中该项的 ID
passedbool该项是否按执行策略通过
has_assertionsbool该项是否有断言被执行
runs_passedint该项通过的运行(run)次数
runs_totalint该项实际完成的运行总数
configured_runs_per_itemint执行策略配置的每项运行次数
pass_thresholdint执行策略要求的最低通过运行次数
test_resultsList[TestResult]每次运行的详细测试结果(按trial_id排序)

其中configured_runs_per_itempass_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:

  1. 一次运行(RUN)通过:该次运行的所有断言分数全部通过。判定函数is_score_passed()(test_suite_result.py)的规则是:scoring_failed(打分失败)一律视为不通过;否则当分数值等于布尔True或数值1时视为通过。值得注意的是,一个测试项如果没有断言(score_results为空),其运行默认视为通过。
  2. 一个测试项(ITEM)通过runs_passed >= pass_threshold,其中runs_passed统计该测试项下所有通过运行的次数。
  3. 整个套件(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 参数速查:与结果对象直接相关的使用面

TestSuiteResultopik.run_tests()产生,其签名(evaluator.py)中与结果形态最相关的参数如下:

参数默认值说明
test_suite必填传入TestSuite(跑最新版本)或TestSuiteVersion(跑指定版本快照)
task必填接收每个测试项data字典的可调用对象;返回dict(须含input/output键)或其他任意值(自动包装为{"output": value}
experiment_name/experiment_name_prefixNone指定或自动生成实验名称,会体现在result.experiment_name
verbose20=静默,1=汇总,2=详细(影响控制台输出与断言明细)
worker_threads16并行执行任务函数的线程数
modelNone用于执行断言打分的模型名
generate_reportTrue是否生成 JSON 报告文件
report_output_pathNone报告文件路径,缺省时写入opik_test_suite_reports/目录
scoring_tool_strategyNone"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} ] } ] } ] }

报告中对每条断言展开namepassedvaluescoring_failed,并在存在时附带reasonmetadata;每次运行附带trace_idtask_execution_time_secondsscoring_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/FAILEDItems passed: 8/8Pass 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_passedresults.pass_rate >= 0.95来决定流水线是否继续,并通过results.experiment_url将失败详情链接回 Opik 仪表盘人工排查。

八、注意事项与最佳实践

  • 无断言项不影响 pass_ratepass_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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询