claimcheck-rules / python /deploy.md
NagaYu's picture
Add the Python reference implementation (Gradio UI + REST API) for self-hosting
0675e3e verified
|
Raw
History Blame Contribute Delete
15.6 kB
# ClaimCheck デプロイ手順
Hugging Face Spaces の無料枠(CPU basic)に、コピペで配置するための手順です。
所要時間は 5〜10 分。GPU も課金設定も不要です。
---
## 1. Space を新規作成する
<https://huggingface.co/new-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` の上限に当たりました。打ち切った事実は必ず出力に残ります。上限を上げるか、入力を短くしてください |