mcpField
O
opik-test

opik-test

github.com/comet-mlテスト・品質856 回インストール6 週間前に更新
リポジトリ

opik-test について

opik-test は、Opik のトレースで確認した失敗を、検証済みのテストスイート項目に変換するスキルです。回帰を追跡するチーム向けに、記録された入力と判定可能なアサーションを Opik に保存し、アプリケーションコードは変更しません。

主な機能

  1. 01Opik のトレースからケースを抽出
  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を入力して読み込まれたか確認します。

詳細

Test — 失敗ケースを再現可能なチェックとして記録する

完了の定義: Opik にテストスイートの項目が 1 つ存在し、失敗を再現します。その data には失敗した入力(既知の場合は期待される出力も)が含まれ、正しいトレースなら通過し、問題のあるトレースでは失敗する二値アサーションが 1 つまたは 2 つ設定されています。この項目はプロジェクトを対象とした名前付きスイートに含まれ、読み戻して内容を確認済みで、/opik-compare を実行する準備が整っています。ケースを記録できない場合は、実際に発生した最初のブロッカーで停止し、次のステップをちょうど 1 つ返してください。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 を使用します)。

推測できない実際のブロッカーがある場合に限り質問してください(Blockers を参照)。

有効化 — 対象範囲内の作業はこれだけです

1. ケースを特定する
  • トレース ID(UUID 形式):そのトレースがケースです。
  • 説明(「返金の回答が間違っている」「配送時間を幻覚した」):プロジェクトに対して search_traces を実行し、一致するトレース(エラー、低スコア、またはフリーテキストの一致)を検索して、最も適切なものを選びます。一致するものがなければ、説明だけから記録します — ユーザーの入力と期待値を項目にします。
  • Opik に接続できることを確認します。~/.opik.config が存在するか、OPIK_API_KEY が設定されていれば、それを使用します。どちらもない場合 → Blocker(「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.

トレースに記録された入力(ルートスパン/トレースの input)、実際の出力(問題が起きた内容)、およびルートスパン名(エントリーポイント)を取得します。MCP が接続されている場合は、read('trace', id) も同等の方法です — 便利ですが、必須ではありません。

3. アサーションを書く

アサーションは、項目の data と候補の出力から LLM 判定者が合否を判断する、平易な英語の文です。ルール:

  1. 1 つのアサーションにつき、失敗モードは 1 つ。 品質の羅列ではなく、正しい出力が何をするかを述べます。
  2. 問題のあるトレースなら失敗すること。 直前に読み取った実際の出力と照らし合わせます。合格してしまうなら、そのアサーションは適切ではありません。
  3. 出力だけで判定できること(expected_output がある場合はそれも含む)。「役に立つ」などの表現や、リッカート尺度は使いません。
  4. 最大 2 つまで: 肯定的な期待値を 1 つと、問題のある出力が具体的に誤ったことを述べている場合に限り、否定的なアサーションを 1 つ(「…と主張しない」)。否定形より肯定形を優先してください。小規模な判定モデルは否定文を誤読します(実例:「24 時間以内に返金すると約束しない」というアサーションが、そのとおりに約束していた出力に対して真と判定されました)。否定が重要なら、肯定形に含めてください(「24 時間ではなく、5~7 営業日と伝えている」)。

正解が厳密に決まっている場合は、判定者より決定的なチェックを優先してください。data.expected_output にも設定すれば、/opik-compare でヒューリスティック指標を使ってスコアリングできます。

4. ケースを保存する(作成または追加)

スイート名は、ユーザーが指定しない限り<project>-regressionsにします。既存のスイートを再利用し、同じプロジェクト用に2つ目のスイートを作成しないでください。

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キーを使うことで、同じトレースに対して2回目の/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. 報告する

スイート、項目、アサーション、および次のステップを1つ返します(出力を参照)。自然な次のステップは、「修正後に/opik-compare <suite>を実行する」です。このスキルはキャプチャを行います。スイートの実行は行いません(それは/opik-compareの役割です)。また、コードは変更しません。

ブロッカー

最初に見つかったブロッカーで停止し、次のステップを1つだけ返します。

  • 「opik configureを実行してから、/opik-test <trace-id>を再実行してください。」
  • 「プロジェクト<name>に<id>のトレースが見つかりません。IDとプロジェクトを確認するか、失敗の内容を説明してください。そこからキャプチャします。」
  • 「トレースに記録済みの入力がありません。入力と期待される動作を渡してください。そこからキャプチャします。」
  • 「ここでどの動作が誤っていますか?出力がどうあるべきかを教えてください。アサーションを作成します。」

出力

ユーザー向け:短いメッセージで、スイート名とバージョン、項目(入力は1行、アサーションは原文のまま)、項目が新規か既存か、および次のステップを1つ示します。JSONやpytestファイルにはしません。

内部形式(構成/評価用)では、次の形式を1つ使います。

  • status:captured | exists | blocked
  • suite:name、project、version
  • item:id、source_trace_id、input(保存された値)、assertions(リスト)、expected_output(設定されている場合)、entrypoint
  • source:sdk | mcp
  • next_step:1つだけ(通常は「修正後に/opik-compare <suite>を実行する」)

不変条件:capturedとexistsには、空でないassertionsリストとsuiteを含むitemを持たせます。各アサーションでは、1つの失敗モードを指定します。existsは、重複排除処理によってトレースがすでにキャプチャ済みだと判定され、何も挿入されていないことを意味します。blockedにはnext_stepを1つだけ含めます。どの経路でもコードベースは変更されません。

例

説明済みのトレースから。 /opik-explainで、retrieveツールが何も返さず、回答が24時間以内の返金を約束していることが判明しました。/opik-test 019fd8a7-…:入力 = "what is your refund window?"、ルートスパン = answer。アサーション:「回答に返金処理には5~7営業日かかると記載されている」「回答で24時間以内の返金を約束していない」。スイート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。一致するトレースがないため、ユーザーの入力と期待が項目になります。入力 = 説明されたプロンプト、アサーション = 「回答は法律上の助言を断り、専門家への相談を促している」。→ captured(source_trace_idなし)。

ブロック — 設定なし。 ~/.opik.configもOPIK_API_KEYもありません。→ blocked:「opik configureを実行してから再実行してください。」(コードには触れません。)

アンチパターン

スイート項目ではなく pytest/vitest ファイルを書くこと(/opik-compare が実行し、UI に表示するのはスイートです)。全体的なアサーション(「レスポンスは良好です」「レスポンスは正確で役に立ちます」)。失敗したトレースでもパスしていたはずのアサーション。1 つの失敗に対して 5 つのアサーションを設けること。トレースごとに新しいスイートを作ること。入力をそのまま保存せず、言い換えること。ここでスイートを実行すること(それは /opik-compare の役割です)。アプリケーションコードを編集すること。副次的にバグを修正すること。

参考資料

テストスイートとデータセットの詳細は、これと同じ場所にインストールされている 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/ を使用してください。

コメント