mcpField
O
opik-test

opik-test

github.com/comet-ml测试与质量856 次安装6 周前更新
代码仓库

关于 opik-test

opik-test 可将 Opik 跟踪记录中的失败转为经过验证的测试套件条目,供跟踪回归的团队使用。它把记录的输入和可判定断言存入 Opik,不修改应用代码。

主要功能

  1. 01从 Opik 跟踪记录提取案例
  2. 02编写二元且针对失败的断言
  3. 03创建或复用项目测试套件
  4. 04按跟踪 ID 检查重复项
  5. 05读回条目以验证存储
  6. 06不修改应用代码

适用场景

  1. 01将跟踪记录中的失败转为回归案例
  2. 02根据失败描述创建测试
  3. 03避免重复录入同一跟踪记录

MCP 相关

该技能可使用 Opik 托管 MCP 的写入工具操作套件和条目,也可使用 Opik SDK;MCP 并非必需。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/comet-ml/opik-skills --skill opik-test

安装后在 Claude Code 中输入/opik-test确认已加载。

详细介绍

测试 — 将失败案例捕获为可重复检查

完成定义: Opik 中存在一个测试套件条目,可重现该故障 — 其 data 包含失败输入(以及已知时的预期输出),并且有一到两个二元断言,这些断言在错误轨迹上会失败,在正确轨迹上会通过。该条目位于一个限定到项目的命名套件中,已通过读取确认,并已准备好由 /opik-compare 运行。如果无法捕获案例,请在遇到第一个真正的阻碍时停止,并且只返回一个后续步骤。编写 pytest 文件或用文字描述测试都不算成功。

操作:从真实轨迹数据中提取案例,编写可由评判者判定为是或否的断言,将其存储在 /opik-compare 能找到的位置 — 不修改任何应用代码。 此技能会写入 Opik,不会写入代码仓库。

输入

入口可以是 /opik-test <trace-id>(捕获该轨迹)、/opik-test <describe the failure>(查找轨迹,或仅根据描述捕获),或在 /opik-explain 之后立即运行 /opik-test(捕获它刚刚解释的轨迹)。推断其余信息;将以下内容视为可选覆盖项:

  • 套件名称(默认:<project>-regressions) · 项目(默认:轨迹所属项目,否则使用已配置的项目) · 预期输出(默认:无 — 断言中包含预期) · 执行策略(默认:套件的策略;仅针对间歇性故障使用 runs_per_item: 3, pass_threshold: 2)。

仅在遇到真正无法推断的阻碍时提问(参见阻碍)。

激活 — 唯一允许的工作范围

1. 确定案例
  • 轨迹 ID(UUID 格式):该轨迹就是案例。
  • 描述(“退款回复不正确”“它编造了配送时间”):在项目中使用 search_traces 查找匹配的轨迹(错误、低分或自由文本匹配),并选取最合适的一条。如果没有匹配项,则仅根据描述捕获 — 将用户输入和预期作为条目内容。
  • 确认 Opik 可访问:如果 ~/.opik.config 存在或设置了 OPIK_API_KEY,则使用它。否则 → 阻碍(“运行 opik configure,然后重新运行”)。
2. 读取轨迹(优先使用 SDK)
import opik
client = opik.Opik()

tid = "<trace_id>"
trace = client.get_trace_content(tid)       # TracePublic: .input, .output, .project_id — NOT .project_name (accessing it raises)
project = client.rest_client.projects.get_project_by_id(trace.project_id).name
spans = client.search_spans(project_name=project, trace_id=tid)   # root span (no parent_span_id) names the entrypoint the compare skill will call
# Pass project_name: without it search_spans looks in the configured default project and returns nothing.

准确提取轨迹记录的输入(根 span / 轨迹 input)、实际输出(出错之处)以及根 span 名称(入口点)。MCP 已连接时,read('trace', id) 是等效方式 — 方便但非必需。

3. 编写断言

断言是简单的英文陈述,大模型评判者会根据条目的 data 和候选输出给出通过/失败判断。规则:

  1. 每条断言只针对一种失败模式。 说明正确的输出会做什么,不要罗列多项质量标准。
  2. 在错误轨迹上本应失败。 对照刚才读取的实际输出进行检查;如果该断言会通过,那它就是错误的断言。
  3. 仅根据输出即可判定(若存在 expected_output,也可依据它)。不要使用“有帮助”之类的标准,也不要用李克特量表。
  4. 最多两条:一条正向预期;仅当错误输出具体做了某件错误的事时,再加一条负向断言(“不得声称……”)。优先采用正向表述:较小的评判模型可能会误读否定句(观察到的情况:“不得承诺 24 小时内退款”在某个明确承诺了这一点的输出上被判定为真)。如果负向要求很重要,就将其融入正向表述(“说明需要 5–7 个工作日,而不是 24 小时”)。

如果正确答案是确定的,应优先采用确定性检查,而不是评判者:也将它放入 data.expected_output,这样 /opik-compare 就能用启发式指标对其评分。

4. 保存用例(创建或追加)

套件命名:<project>-regressions,除非用户指定了名称。复用现有套件;同一项目绝不创建第二个套件。

suite = client.get_or_create_test_suite(
    name="<project>-regressions",
    project_name=project,
    tags=["regression"],
)

# Dedupe on the source trace before inserting.
existing = suite.get_items(filter_string=f'data.source_trace_id = "{tid}"')
if not existing:
    suite.insert([{
        "data": {
            "input": trace.input,                 # verbatim from the trace
            "source_trace_id": tid,
            # "expected_output": "...",           # only when the correct answer is exact
        },
        "assertions": ["<positive assertion>", "<optional negative assertion>"],
        "description": "Regression from trace <tid>: <one-line failure>. Entrypoint: <root span name>",
    }])

description 中包含入口点(根跨度名称),因为 /opik-compare 需要知道调用哪个函数来运行用例;source_trace_id 键则用于避免在同一条轨迹上再次运行 /opik-test 时重复添加。

连接托管的 MCP 后,write 工具的 test_suite.create 和 test_suite_item.upsert 操作会执行相同的操作——调用 schema("test_suite_item.upsert") 获取确切的信封格式。无论使用哪种传输方式,最终都会写入同一个套件;SDK 路径不需要 MCP。

5. 验证

读回该用例——suite.get_items(filter_string=…) 会返回带有 id 的用例——并记录套件当前的版本(suite.get_current_version_name())。不要只凭插入调用就报告成功。

6. 报告

返回套件、用例、断言以及一个后续步骤(见输出)。自然的后续步骤是“修复完成后运行 /opik-compare <suite>”。此技能负责捕获;它不会运行套件(那是 /opik-compare 的工作),也不会更改代码。

阻塞情况

遇到最早的阻塞情况时停止,并且只返回一个后续步骤:

  • “运行 opik configure,然后重新运行 /opik-test <trace-id>。”
  • “在项目 <name> 中未找到 <id> 对应的轨迹——请确认 ID 和项目,或者描述故障,我会据此捕获用例。”
  • “该轨迹没有记录的输入——请提供输入和预期行为,我会据此捕获用例。”
  • “这里的行为哪里不对?请告诉我输出应该是什么样,我会据此编写断言。”

输出

面向用户:简短的自然语言消息——包含套件名称和版本、用例(输入用一行表示,断言原样呈现)、用例是新建的还是已存在,以及唯一的后续步骤。不是 JSON,也不是 pytest 文件。

底层(用于组合 / 评测)使用以下一种结构:

  • status:captured | exists | blocked
  • suite:name、project、version
  • item:id、source_trace_id、input(存储时的内容)、assertions(列表)、expected_output(如果已设置)、entrypoint
  • source:sdk | mcp
  • next_step:恰好一个(通常为“修复后运行 /opik-compare <suite>”)

不变量:captured 和 exists 都包含带有非空 assertions 列表的 item 和一个 suite;每条断言都指明一种故障模式;exists 表示去重检查发现该轨迹已被捕获,且未插入任何内容;blocked 恰好包含一个 next_step;所有路径都不会更改代码库。

示例

来自已说明的轨迹。 /opik-explain 发现 retrieve 工具未返回任何内容,而回答却声称退款会在 24 小时内到账。/opik-test 019fd8a7-…:输入 =“what is your refund window?”,根跨度 = answer。断言:“Response states refunds take 5-7 business days”和“Response does not promise a refund within 24 hours”。创建套件 support-bot-regressions,插入用例,并读回为 v1。→ captured;后续步骤 = “修复 retrieve() 后运行 /opik-compare support-bot-regressions”。

已捕获。 再次使用同一条轨迹。source_trace_id 筛选条件找到了该用例。→ exists:“已存在于 support-bot-regressions 中(用例 …)——准备好后运行 /opik-compare。”

来自描述,没有轨迹。 /opik-test the bot should refuse to give legal advice。没有匹配的轨迹,因此用户的输入和预期会成为用例内容:输入 = 用户描述的提示词,断言 =“Response declines to give legal advice and points to a professional”。→ captured(未设置 source_trace_id)。

受阻——没有配置。 没有 ~/.opik.config,也没有 OPIK_API_KEY。→ blocked:“运行 opik configure,然后重新运行。”(未触碰代码。)

反模式

编写 pytest/vitest 文件,而不是套件条目(/opik-compare 运行的是套件,界面展示的也是套件);使用宽泛的断言(“响应不错”“响应准确且有帮助”);断言在失败的轨迹上也会通过;一次失败写五个断言;每条轨迹都新建一个套件;改写输入,而不是原样保存;在此处运行套件(那是 /opik-compare 的工作);编辑应用代码;顺带修复 bug。

参考资料

测试套件和数据集的详细信息位于与此技能一同安装的 opik 技能中。请直接阅读文件——路径相对于此文件:../opik/references/evaluation-test-suites.md(套件、条目、断言、执行策略、版本);../opik/references/evaluation-datasets.md(OQL 筛选语法、从轨迹创建数据集);../opik/references/production.md(search_traces)。关于如何编写可由裁判判定的断言,请参阅 ../opik-evaluate/references/write-judge-prompt.md。如果宿主采用了不同的技能目录结构,请找到 opik 技能的 references/ 目录。

如果未安装 opik 技能,请在报告中说明,并使用 https://www.comet.com/docs/opik/,不要凭记忆作答。

评论

支持 Markdown