# ClaimCheck デプロイ手順 Hugging Face Spaces の無料枠(CPU basic)に、コピペで配置するための手順です。 所要時間は 5〜10 分。GPU も課金設定も不要です。 --- ## 1. Space を新規作成する を開き、次のとおり設定します。 | 項目 | 値 | |---|---| | Owner | 自分のユーザー名(または組織) | | Space name | `ClaimCheck`(任意) | | License | `apache-2.0` | | Select the Space SDK | **Gradio** | | Space hardware | **CPU basic · 2 vCPU · 16GB · FREE** | | Visibility | Public / Private どちらでも可 | 「Create Space」を押すと、空のリポジトリができます。 このあと `README.md` を push すると、その先頭の YAML frontmatter が Space 設定を上書きするので、ここでテンプレートを選ぶ必要はありません。 --- ## 2. clone → 4ファイル配置 → push `YOUR_NAME` と `ClaimCheck` を自分のものに置き換えて、まとめて実行します。 Git の認証には、`write` 権限を付けた [アクセストークン](https://huggingface.co/settings/tokens) を使ってください(パスワード欄にトークンを貼ります)。 ```bash git clone https://huggingface.co/spaces/YOUR_NAME/ClaimCheck cd ClaimCheck ``` 作成した 4 ファイル(`app.py` / `requirements.txt` / `README.md` / `deploy.md`)をこのディレクトリにコピーしてから: ```bash git add app.py requirements.txt README.md deploy.md && git commit -m "Add ClaimCheck: LLM answer verification gate" && git push ``` push の直後から Space がビルドを始めます。ログは Space ページの「Logs」タブで見られます。 依存は 3 つだけなので、通常 1〜2 分で `Running` になります。 > **大きなファイルは置かないこと。** モデルもデータセットも同梱しません。検証は全てローカルの決定的処理です。 ### ローカルで先に動かして確認したい場合 ```bash pip install -r requirements.txt && python app.py ``` `http://127.0.0.1:7860` が開きます。Spaces 上と同じ挙動です。 --- ## 3. Secrets に `HF_TOKEN` を設定する(任意) **これは任意です。設定しなくても全機能が動きます。** 設定すると、Enrichment(文脈と応答の関連度を補助スコアとして取得する機能)が有効になります。 ただし無料アカウントの推論クレジットは **月 $0.10 程度** しかないため、これはあくまで飾りです。トークンが無い・期限切れ・レート制限・タイムアウトのいずれでも `None` を返し、**主機能であるローカル検証はそのまま動き続けます**(3回連続で失敗すると自動的に呼び出しを止めます)。 設定する場合: 1. Space ページ → **Settings** → **Variables and secrets** 2. **New secret** を押す 3. Name に `HF_TOKEN`、Value に自分のアクセストークン(`read` 権限で十分) 4. 保存すると Space が自動で再起動します 他の環境変数(`LOG_CAPACITY`, `MAX_TEXT_CHARS`, `PRICE_IN_PER_1K` など)も同じ画面から設定できます。秘密でない値は Secrets ではなく **Variables** で構いません。 価格を入れておくと、Retry タブの節約試算が「トークン数」ではなく「金額」で出ます。 --- ## 4. 動作確認 Space が `Running` になったら、以下を順に確認してください。 初期値がそのまま入っているので、基本的にボタンを押すだけです。 ### 4-1. 文脈に無い数値が赤く出ること **Verify** タブを開くと、Answer と Context に例文が入っています。**Verify** を押します。 応答本文が色分けされ、次のようになれば成功です。 | 箇所 | 期待する色 | 理由 | |---|---|---| | `12,000` `1,800` `3,400人` `2024年3月15日` | 🟩 緑 (supported) | 文脈にそのまま存在する | | `15%` | 🟦 青 (derived) | 文脈の数値から計算できる | | `3,250人` | 🟥 **赤** (contradicted) | 文脈は `3,200人`。近いが違う | | `https://example.com/ir/2025` | 🟥 **赤** (contradicted) | 文脈は `/ir/2024`。捏造リンク | | `7.2%` | 🟧 橙 (unsupported) | 文脈のどこにも無い | 自分で試すなら、Answer の末尾に「解約率は99.9%です。」のように**文脈に無い数値**を足して Verify を押してください。橙または赤になります。 上の表に出ている `grounding_score` と `coverage` は必ず両方見てください。 Answer を「詳細は担当部署にお問い合わせください。」だけに書き換えて Verify すると、`grounding_score` は高いのに `coverage` が 0 になります。**これが「何も検証できていない」状態です。** ### 4-2. 「導出」判定を確認する `15%` が 🟦 青 (derived) になり、Full result の該当 claim の `evidence` に ``` derivable from context: 1,800 / 12,000 * 100 (percentage) = 15 ``` と出ていることを確認します。文脈に `15` という文字列は存在しませんが、`1,800 ÷ 12,000 × 100` で導出できるため `supported` ではなく `derived` になります。 ### 4-3. Retry タブで再試行用の指示文が出ること **Retry** タブに移り、入力欄は**空のまま** 「Build retry instruction」を押します(Verify タブの結果を自動で読みます)。 - 上の欄に、失敗した主張だけを列挙した日本語の指示文が出ます - 下の JSON に `blind_retry_tokens` / `targeted_retry_tokens` / `saved_tokens` / `saved_cost` の試算が出ます > **試算の読み方:** `saved_tokens` は符号付きです。文脈が小さいと、指示文のほうが長くなって**マイナスになることがあります**(`targeted_is_cheaper: false`)。これは不具合ではなく事実で、隠すほうが有害です。実運用の RAG のように文脈が数千トークンあると、はっきりプラスになります。 > また `PRICE_*` を設定していると、出力トークンの単価が入力より高いため、**トークン数はマイナスでも金額はプラス**になることがあります。どちらを基準に判断したかは `comparison_basis` に出ます。 ### 4-4. 実際のエンドポイントを取得する **API Docs** タブに、この Space の実際のパスが表示されます(Gradio のバージョンによってプレフィックスが変わるため、ハードコードせず起動時に検出しています)。 最終的な正解はページ最下部の **「Use via API」** リンクです。ここに `gradio_client` と `curl` の両方のサンプルが出るので、そちらを正としてください。 ```bash # Space ページ最下部の「Use via API」で確認できる形 curl -s -X POST https://YOUR_NAME-claimcheck.hf.space/gradio_api/call/verify \ -H 'Content-Type: application/json' \ -d '{"data": ["営業利益率は15%です。", "営業利益は1,800百万円、売上高は12,000百万円でした。", "", "", "", "", "{}"]}' ``` **Health** タブで `mode` / `uptime` / `events_logged` / `mean_latency_ms` も確認しておくと、後で遅くなったときの比較対象になります。 --- ## 5. 運用の型 ### いきなり `block` から始めないこと これが最も重要です。検証器は**偽陽性で信頼を失います**。一度「またこいつが誤検知した」と思われたら、その後どれだけ精度を上げても使われません。 段階的に締めていきます。 #### 第1段階:観測だけ(1〜2週間) `verdict` は見るが、**何もブロックしない**。ログを貯めることだけが目的です。 ```json { "block_on_critical_safety": true, "block_on_leak": false, "retry_on_contradicted": 9999, "retry_grounding": 0.0, "annotate_grounding": 1.0 } ``` これで安全違反(APIキー等)以外は `annotate` 止まりになります。 `tags_json` に `{"model": "...", "prompt_version": "..."}` を必ず入れてください。Dashboard の比較表がこれで初めて意味を持ちます。 #### 第2段階:Audit で偽陽性を潰す **Audit** タブを毎日見ます。`unsupported` / `contradicted` と判定された主張が一覧に出るので、**実は正しかったものに `false_positive` のチェックを入れて保存**します。 画面に出る **偽陽性率 (`false_positive_rate`)** が判断材料です。型別 (`by_type`) も出るので、どの検証が足を引っ張っているかが分かります。 経験則として、`false_positive_rate` が **0.1 を超えているうちは `retry` に進まない**でください。 #### 第3段階:`retry` を有効にする 偽陽性率が落ち着いたら、まず `contradicted`(最も確度が高い)だけで再試行させます。 ```json { "retry_on_contradicted": 1, "retry_grounding": 0.5 } ``` #### 第4段階:`block` はごく一部だけ `block` は原則として**安全違反(既定で有効)**に限定します。 幻覚検出を理由に `block` するなら、対象を絞ってください(例:金額・日付を含む回答のみ、`contradicted` が 2 件以上のときだけ)。 ### Dashboard の使い方 - **model × prompt_version 比較表** — プロンプトを変えたときに、`grounding_mean` / `coverage_mean` / `contradicted_rate` が改善したのか悪化したのかを見ます。これが無いと「なんとなく良くなった気がする」で終わります。 - **累積節約** — Retry を targeted に切り替えた効果です。 - **検査遅延 p50/p95/max** — ClaimCheck 自体のコスト。数百ms を超え始めたら第6節を見てください。 > **記録はメモリ上にしかありません。** ディスクは非永続で、48時間無操作でスリープします。再起動すると **イベントログも偽陽性の印も全部消えます**。必要な分は Dashboard と Audit の CSV を定期的に落としてください。 --- ## 6. よくある失敗と対処 ### 偽陽性が多い **まず ENTITY を切ってください。** 圧倒的に最大の原因です。 ```json { "enable_entity": false } ``` 一般名詞(`Machine Learning`)、略語の展開(文脈 `World Health Organization` / 応答 `WHO`)、固有名詞らしく見えるだけの語が、片端から `unsupported` になります。 **NUMERIC と DATE から始めてください。** この2つが最も確度が高く、かつ「危険な幻覚は具体的」という前提に最も素直に合致します。 ```json { "enable_numeric": true, "enable_date": true, "enable_entity": false, "enable_quote": false, "enable_url": false } ``` それでも数値で誤検知が出る場合: | 症状 | 対処 | |---|---| | 丸めた数値(`約1,200` → `1200`)で落ちる | これは正常に `supported` になります。ならない場合は `numeric_tolerance` を `0.02` 程度に | | 近い別の数値と勝手に照合される | `contradiction_rel` を `0.25` → `0.10` に下げる(照合窓を狭める) | | 引用が言い換えで `approximate` になる | 仕様どおりです。言い換えを許すなら `approx_ratio` を下げるのではなく、プロンプト側で原文引用を指示してください | ### coverage が低い **応答が抽象的すぎます。** ツール側の問題ではありません。 `verify.unverified_sentences` に、検証できなかった文がそのまま入っています。まずそれを読んでください。「ご検討ください」「一般的には〜と言われています」のような文ばかりなら、そもそも検証できる主張が存在しません。 対処はプロンプト側です。**具体的な根拠提示を求める**よう促します。 ``` 回答には、文脈中の該当する数値・日付・原文の引用を必ず含めてください。 文脈に根拠が無い事項については「文脈に記載がありません」と明記してください。 推測で数値や日付を補わないでください。 ``` これを入れると coverage は目に見えて上がります。同時に、モデルが具体的に書くぶん **検証できる範囲が広がり、幻覚も捕まえやすくなります**。 `coverage` が低いまま `grounding_score` だけ高い状態を「検証済み」と報告しないでください。README の警告のとおり、それは「検証できるものが無かった」という意味です。 ### 検査が遅い 無料枠は 2 vCPU です。典型的な応答なら数ミリ秒、20,000文字の最悪ケースでも 100ms 未満で終わりますが、遅くなったら順に: 1. **`MAX_TEXT_CHARS` を下げる**(例 `20000` → `8000`)。最も効きます。入力は安全に切り詰められ、`warnings` に truncation が記録されます。 2. **ENTITY 検証を無効化する**(`{"enable_entity": false}`)。抽出も照合も減ります。偽陽性対策と一石二鳥です。 3. **導出探索を切る**(`{"enable_derivation": false}`)。文脈中の数値が非常に多いときに効きます。`derive_max_terms` を `2` にするだけでも軽くなります。 3b. **近似照合の予算を絞る**(`{"fuzzy_budget_ms": 80}`)。引用が多い応答で効きます。予算切れは `counts.fuzzy_budget_exhausted` と `notes` に必ず出るので、黙って精度が落ちることはありません。 4. **`MAX_CLAIMS` を下げる**(既定 `1500`)。打ち切った件数は `counts.claims_dropped_by_cap` と `notes` に必ず出るので、黙って減ることはありません。 5. **`UI_CONCURRENCY` を下げる**(既定 `4`)。同時実行で CPU を食い合っている場合。 **Health** タブと Dashboard の遅延表 (p50/p95/max) で、変更の前後を比べてください。 ### その他 | 症状 | 原因と対処 | |---|---| | ビルドが失敗する | `requirements.txt` に余計な依存を足していないか確認。torch / transformers は無料枠に入りません | | 起動が遅い | 初回は依存のインストール分です。2回目以降はキャッシュが効きます | | 数時間後に見に行ったら固まっている | 48時間無操作のスリープです。アクセスすれば起きます(初回は数十秒) | | ログが消えた | 仕様です。非永続ディスク + メモリ上のリングバッファ。CSV で落としてください | | Enrichment が常に `null` | `HF_TOKEN` 未設定、または推論クレジット切れ。**任意機能なので放置して構いません。** Health タブの `enrichment.last_error` に理由が出ます | | `verdict` が全部 `annotate` になる | 検証できる主張が見つかっていません。「coverage が低い」の項を参照 | | 条番号・型番が赤くなりすぎる | 仕様です。識別子は「一致か誤りか」しかなく、`第12条` に対する `第13条` は最も危険な捏造なので `contradicted` にしています。緩めるなら `enable_entity: false` で ENTITY ごと切ってください | | `notes` に「budget ran out」と出る | `fuzzy_budget_ms` / `max_claims` / `derive_budget_ms` の上限に当たりました。打ち切った事実は必ず出力に残ります。上限を上げるか、入力を短くしてください |