ワークフロー(処理の流れ)のトレース(記録)を体系的に確認して、評価器を構築する前に問題が起きやすいパターンを特定します。 次のような場合に使用: 評価プロジェクトを開始するとき、処理の仕組みに大きな変更を加えた後、または本番環境の品質が低下したとき
Systematically review workflow traces to identify failure modes before building evaluators. Use when starting an eval project, after significant pipeline changes, or when production quality drops.
エバリュエーターを作成する前に、実際のワークフロートレースを確認し、ワークフローがどのように失敗するかを分類します。 エラー分析なしに構築されたエバリュエーターは、ワークフローが実際に壊れる具体的な原因ではなく、「これは良いか?」といった汎用的な品質を対象にしてしまいます。 このスキルでは、その分析プロセスを順を追って説明します。
ワークフローの実行記録を 50〜100 件集めます。トレース数が多いほど、失敗カテゴリの信頼性が高まります。
直近のワークフロー実行を一覧表示し、トレースを取得します:
# ワークフローの最近の実行を一覧表示する
npx output workflow runs list <workflowName>
# 特定のトレースを JSON 形式で取得する
npx output workflow debug <workflowId> --json
本番環境のトレースをデータセット YAML ファイルに直接ダウンロードします:
# 最新のトレースを最大 20 件ダウンロードしてデータセットファイルとして保存する
npx output workflow dataset generate <workflowName> --download --limit 20
このコマンドにより、実際の実行記録から取得した input および last_output フィールドが入力済みの YAML ファイルが tests/datasets/ 配下に作成されます。
本番トレースが少ない場合は、シナリオのインプットからトレースを生成します:
# シナリオファイルからデータセットを生成する
npx output workflow dataset generate <workflowName> basic --name basic_trace
# インライン JSON から生成する
npx output workflow dataset generate <workflowName> --input '{"topic": "AI safety"}' --name ai_safety_trace
50 件以上のトレースが得られるまで十分なインプットを実行してください。 量よりも多様性を優先し、重要と思われる軸に沿ってインプットを変化させましょう。
各トレースを 1 件ずつ確認します。それぞれのトレースについて、以下の項目を記録してください:
| フィールド | 記入内容 |
|---|---|
| トレース ID | ワークフロー実行の ID |
| 判定 | Pass または Fail(この段階では二択のみ — "partial" は不可) |
| 根本原因 | Fail の場合: 具体的に何がどのように失敗したか |
| 備考 | 驚いた点や記憶しておく価値があること |
確認内容を記録するファイルを作成します。シンプルなマークダウン表で十分です:
# エラー分析: <workflow_name>
# 日付: YYYY-MM-DD
# 確認済みトレース: 0 / 50
| # | トレース ID | 判定 | 根本原因 | 備考 |
|---|------------|------|----------|------|
| 1 | abc-123 | Fail | 存在しない URL をハルシネーションした | 技術的なトピックで頻発 |
| 2 | def-456 | Pass | — | 出力はクリーン |
| 3 | ghi-789 | Fail | "フォーマルなトーン" の要件を無視した | インプットに矛盾するシグナルがあった |
JSON トレースを開き、以下を確認します:
失敗カテゴリに名前をつける前に、少なくとも 30 件のトレースを確認してください。 早まった分類は、実在しないパターンを見出したり、実在するパターンを見落としたりする原因になります。 この段階では、観察したことをそのまま記録するだけにとどめましょう。
30 件以上確認するとパターンが見えてきます。 表面的な症状ではなく、根本原因に基づいて失敗を 5〜10 のカテゴリに分類してください。
ブログ生成ワークフローで 60 件のトレースを確認した結果:
| カテゴリ | 件数 | 割合 | 例 |
|---|---|---|---|
| ハルシネーション URL | 8 | 13% | 存在しないページへのリンクを生成 |
| トーン不一致 | 6 | 10% | フォーマルを要求したのにカジュアルなトーンになった |
| トピックの逸脱 | 5 | 8% | 「AI」についてのブログが無関係な ML の歴史に流れた |
| セクションの欠落 | 4 | 7% | 明示的に要求した「まとめ」をスキップした |
| 文字数不足 | 3 | 5% | 500 字以上を要求したのに 200 字未満 |
| 失敗合計 | 26 | 43% | |
| Pass | 34 | 57% |
エバリュエーターが検証に使用できるよう、データセット YAML ファイルに ground_truth ラベルを追加します。
各失敗カテゴリは、今後作成するエバリュエーターの名前に対応します。
name: ai_safety_trace
input:
topic: "AI safety"
tone: "formal"
min_length: 500
last_output:
output:
title: "Understanding AI Safety"
blog_post: "AI safety is super important and stuff..."
executionTimeMs: 3200
date: '2026-03-25T00:00:00.000Z'
ground_truth:
# グローバルな ground truth(すべてのエバリュエーターから参照可能)
human_verdict: fail
failure_categories:
- tone_mismatch
notes: "フォーマルなトーンを要求したにもかかわらずカジュアルな表現が使われた"
# エバリュエーターごとの ground truth
evals:
check_tone:
expected_tone: formal
verdict: fail
check_length:
min_length: 500
verdict: pass
check_hallucinated_urls:
verdict: pass
ground_truth.evals.<evaluator_name> フィールドは、verify() で使用するエバリュエーター名に直接対応します。
各エバリュエーターは、context.ground_truth を通じてトップレベルの ground_truth とマージされた形で、自身の ground_truth を受け取ります。
すべてのデータセットにすべてのカテゴリのラベルを付ける必要はありません。 以下の優先順位で進めましょう:
human_verdict(pass/fail)をラベリングするすべての失敗カテゴリにエバリュエーターが必要なわけではありません。 以下のデシジョンツリーで判断してください:
この失敗は、修正可能なプロンプト/ツールのギャップが原因か?
├─ YES → まずプロンプトを修正するか、不足しているツールを追加する
│ 修正後にエラー分析を再実施する
└─ NO → この失敗は再発する可能性があり、継続的なモニタリングが必要か?
├─ YES → エバリュエーターを構築する
│ 決定論的なコードでチェックできるか?
│ ├─ YES → Verdict.* ヘルパーを使用する
│ │ (contains, matches, gte など)
│ └─ NO → LLM ジャッジプロンプトを使って
│ judgeVerdict() を使用する
└─ NO → ドキュメントに記録して先に進む(まれなエッジケース)
最も失敗率が高いカテゴリから順にエバリュエーターを構築してください。 13% の失敗は、2% の失敗より重要です。
主観的に思える失敗にも、客観的な代替手段がある場合が多くあります:
| 失敗 | 一見… | 実際には…でチェックできる |
|---|---|---|
| 「文字数不足」 | 主観的 | Verdict.gte(output.length, threshold) |
| 「セクションの欠落」 | LLM が必要 | Verdict.contains(output, "## Conclusion") |
| 「ハルシネーション URL」 | LLM が必要 | 正規表現で URL を抽出し、HTTP HEAD で検証 |
| 「フォーマット誤り」 | LLM が必要 | Verdict.matches(output, expectedPattern) |
LLM ジャッジは、トーン・関連性・忠実性・一貫性など、真に主観的な基準のためにとっておきましょう。
失敗カテゴリと計画中のエバリュエーターを対応付けるマッピングドキュメントを作成します:
# エバリュエーター計画: blog_generator
| カテゴリ | 割合 | エバリュエータータイプ | エバリュエーター名 | 重要度 |
|----------|------|----------------------|-------------------|--------|
| ハルシネーション URL | 13% | コード(URL 抽出 + HTTP チェック) | check_urls | required |
| トーン不一致 | 10% | LLM ジャッジ | check_tone | required |
| トピックの逸脱 | 8% | LLM ジャッジ | check_topic | required |
| セクションの欠落 | 7% | コード(文字列の contains) | check_sections | required |
| 文字数不足 | 5% | コード(文字数チェック) | check_length | informational |
これが実装のロードマップになります。
判定をブロックすべき失敗カテゴリには criticality: 'required' を、あると望ましいチェックには 'informational' を使用してください。
Review real workflow traces and categorize how your workflow fails before writing any evaluators. Evaluators built without error analysis target generic qualities ("is this good?") instead of the specific ways your workflow actually breaks. This skill walks you through the process.
Gather 50-100 representative workflow executions. More traces = more reliable failure categories.
List recent workflow executions and pull their traces:
# List recent runs for a workflow
npx output workflow runs list <workflowName>
# Pull a specific trace as JSON
npx output workflow debug <workflowId> --json
Download production traces directly into dataset YAML files:
# Download up to 20 recent traces as dataset files
npx output workflow dataset generate <workflowName> --download --limit 20
This creates YAML files in tests/datasets/ with the input and last_output fields populated from real executions.
If production traces are sparse, generate traces from scenario inputs:
# Generate a dataset from a scenario file
npx output workflow dataset generate <workflowName> basic --name basic_trace
# Generate from inline JSON
npx output workflow dataset generate <workflowName> --input '{"topic": "AI safety"}' --name ai_safety_trace
Run enough inputs to get 50+ traces. Prioritize diversity over volume — vary inputs across the dimensions you expect to matter.
Review each trace one at a time. For each trace, record:
| Field | What to write |
|---|---|
| Trace ID | The workflow execution ID |
| Verdict | Pass or Fail (binary — no "partial" at this stage) |
| Root cause | If Fail: what specifically went wrong and why |
| Notes | Anything surprising or worth remembering |
Create a file to track your reviews. A simple markdown table works:
# Error Analysis: <workflow_name>
# Date: YYYY-MM-DD
# Traces reviewed: 0 / 50
| # | Trace ID | Verdict | Root Cause | Notes |
|---|----------|---------|------------|-------|
| 1 | abc-123 | Fail | Hallucinated a URL that doesn't exist | Common with technical topics |
| 2 | def-456 | Pass | — | Clean output |
| 3 | ghi-789 | Fail | Ignored the "formal tone" requirement | Input had conflicting signals |
Open the JSON trace and examine:
Review at least 30 traces before naming any failure categories. Premature categorization causes you to see patterns that aren't there and miss patterns that are. Just record what you observe.
After reviewing 30+ traces, patterns will emerge. Group your failures into 5-10 categories based on root cause, not surface symptoms.
For a blog generation workflow after reviewing 60 traces:
| Category | Count | Rate | Example |
|---|---|---|---|
| Hallucinated URLs | 8 | 13% | Invented links to non-existent pages |
| Tone mismatch | 6 | 10% | Casual tone when formal was requested |
| Off-topic drift | 5 | 8% | Blog about "AI" drifted to unrelated ML history |
| Missing sections | 4 | 7% | Skipped "conclusion" when explicitly requested |
| Too short | 3 | 5% | Under 200 words when 500+ requested |
| Total failures | 26 | 43% | |
| Passes | 34 | 57% |
Add ground_truth labels to your dataset YAML files so evaluators can validate against them. Each failure category maps to a future evaluator name.
name: ai_safety_trace
input:
topic: "AI safety"
tone: "formal"
min_length: 500
last_output:
output:
title: "Understanding AI Safety"
blog_post: "AI safety is super important and stuff..."
executionTimeMs: 3200
date: '2026-03-25T00:00:00.000Z'
ground_truth:
# Global ground truth (available to all evaluators)
human_verdict: fail
failure_categories:
- tone_mismatch
notes: "Used casual language despite formal tone request"
# Per-evaluator ground truth
evals:
check_tone:
expected_tone: formal
verdict: fail
check_length:
min_length: 500
verdict: pass
check_hallucinated_urls:
verdict: pass
The ground_truth.evals.<evaluator_name> fields map directly to the evaluator names you'll use in verify(). Each evaluator receives its own ground truth merged with the top-level ground truth via context.ground_truth.
You don't need to label every dataset for every category. Focus on:
human_verdict (pass/fail)Not every failure category needs an evaluator. Use this decision tree:
Is this failure caused by a fixable prompt/tool gap?
├─ YES → Fix the prompt or add the missing tool first
│ Re-run error analysis after the fix
└─ NO → Will this failure recur and need ongoing monitoring?
├─ YES → Build an evaluator
│ Can it be checked with deterministic code?
│ ├─ YES → Use Verdict.* helpers (contains, matches, gte, etc.)
│ └─ NO → Use judgeVerdict() with an LLM judge prompt
└─ NO → Document it and move on (rare edge case)
Build evaluators for the highest-rate failure categories first. A failure at 13% matters more than one at 2%.
Many failures that seem subjective have objective proxies:
| Failure | Seems like... | But you can check with... |
|---|---|---|
| "Too short" | Subjective | Verdict.gte(output.length, threshold) |
| "Missing section" | Needs LLM | Verdict.contains(output, "## Conclusion") |
| "Hallucinated URLs" | Needs LLM | Extract URLs with regex, verify with HTTP HEAD |
| "Wrong format" | Needs LLM | Verdict.matches(output, expectedPattern) |
Reserve LLM judges for genuinely subjective criteria: tone, relevance, faithfulness, coherence.
Create a mapping document that connects your failure categories to planned evaluators:
# Evaluator Plan: blog_generator
| Category | Rate | Evaluator Type | Evaluator Name | Criticality |
|----------|------|----------------|----------------|-------------|
| Hallucinated URLs | 13% | Code (URL extraction + HTTP check) | check_urls | required |
| Tone mismatch | 10% | LLM judge | check_tone | required |
| Off-topic drift | 8% | LLM judge | check_topic | required |
| Missing sections | 7% | Code (string contains) | check_sections | required |
| Too short | 5% | Code (length check) | check_length | informational |
This becomes your implementation roadmap. Use criticality: 'required' for failure categories that should block a passing verdict. Use 'informational' for nice-to-have checks.
output-dev-eval-testing to implement each evaluator with verify() and wire them into evalWorkflow()output-eval-judge-prompt to write effective .prompt filesoutput-eval-dataset-design to generate diverse test casesVerdict.contains() worksoutput-dev-eval-testing — Implement evaluators with verify(), Verdict, and evalWorkflow()output-eval-judge-prompt — Design LLM judge prompts for subjective failure modesoutput-eval-dataset-design — Generate diverse datasets when real traces are sparseoutput-eval-validate-judge — Validate LLM judges against human labelsoutput-eval-audit — Audit an existing eval suite for trustworthinessoutput-workflow-trace — Retrieve and analyze workflow execution traces原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。