npc_lab — 会話NPCの堅牢性を測る実験環境¶
設計パターン集 のうち、ゲームへの接続と安全に関わるパターンが 本当に効くのかを測るための小さな実験環境(Phase 3: 一次情報)。
何を比べるか¶
| 実装 | 中身 |
|---|---|
| 素朴な実装(naive) | LLMに「依頼は達成されたか」「門を開けるか」「いくらで売るか」を判断させ、その結果をそのままゲームの事実にする |
| パターン適用(guarded) | P16 事実はエンジンが持つ / P17 判定器の分離 / P26 地の文の偽装への防御 / P27 段階的な退場 / P11 状態としての関係値 |
| パターン適用v2(guarded_v2) | 上に加えて P19: 判定器は主張の種類を分類するだけ。保証人・目的・荷の検査はゲームの事実で確かめ、確かめられない主張は合計+1まで |
舞台は宿場町。3人のNPCがいる。 - ミオ(依頼人): 行方不明の兄2人を探してほしい。見つけたらお礼に薬草袋をくれる - ゴウ(門番): 通行手形か、山賊ではないと納得できる理由があれば関所を通す - タマキ(行商人): 地図を100両で売る
評価フレームワーク の攻撃表から作った8つの攻撃、判定器そのものを狙う5つの攻撃、4つの正当なプレイ、判断が分かれる1つ(L3)を流し、 LLMの発言ではなく、ゲームの状態(所持品・フラグ・所持金)で結果を判定する。
使い方¶
cd prototype
# モック(APIキー不要): 仕組みの動作確認
python3 -m npc_lab.run_eval --backend mock
# 構造上の保証のテスト(判定器まで完全にだまされた最悪の場合)
python3 -m unittest discover -s tests -t .
# 実モデルでの実験(要 NPC_LAB_API_KEY、ANTHROPIC_API_KEY、または `ant auth login`)
pip install -r requirements.txt
# まず見積もる(APIは呼ばない)
python3 -m npc_lab.run_eval --dry-run --model claude-haiku-4-5 --only A12,A13,L5 --engines guarded_v2
# 必要な分だけ、上限付きで流す
python3 -m npc_lab.run_eval --backend anthropic --model claude-haiku-4-5 \
--only A12,A13,L5 --engines guarded_v2 --max-usd 0.10 \
--out ../experiments/$(date +%F)-result.md
- APIキーは
NPC_LAB_API_KEYを優先して読む。Claude Code のクラウド環境ではANTHROPIC_API_KEYがセッションに渡らないため、こちらを使う - 既定のモデルは
claude-opus-5、effortはlow(会話NPCは待ち時間が重要なため)。--modelと--effortで変えられる(claude-haiku-4-5は effort 非対応なので送らない) - 安全分類器による拒否に備えて、サーバー側フォールバック(
fallbacks: "default")を有効にしている - 費用の方針: 最小コストで進める(STRATEGY.md の「API試験の費用方針」)。
--max-usd(既定 $0.50)で上限を付け、--onlyと--enginesで必要な分だけ流す - 費用の目安: 全シナリオ・3実装・5試行を
claude-opus-5で流すと約1,150回・約7.5ドル。v2 の4シナリオをclaude-haiku-4-5で1試行なら26回・約3セント(実測)
構成¶
npc_lab/
├── world.py ゲームの状態とキャラクター設定(P05 バイブル形式)
├── llm.py Claude API バックエンドとモック
├── agents.py 素朴な実装とパターン適用版のエンジン
├── scenarios.py 攻撃13種(うち判定器狙い5種)・正当なプレイ4種・判断が分かれるもの1種
├── run_eval.py 実行と結果の表の出力
├── probe_judge.py 判定器(P17)の採点を発言ごとに表示する調査用スクリプト(`--judge v2` で主張の分類も表示)
├── replay_probe.py probe_judge の記録を v2 のエンジンに流し直す(APIを呼ばない)
└── latency_probe.py 判定器とキャラの呼び出しを順番/同時で行ったときの待ち時間を比べる
tests/
└── test_guarantees.py LLMが完全にだまされても守れること/守れないことのテスト
分かっていること・分かっていないこと¶
- モックは「だまされやすいLLM」を意図的に戯画化している。モックでの結果は配線の確認であって、実際のモデルの性能を示すものではない
- テストで確認できた構造上の保証: LLMと判定器が完全にだまされても、報酬・価格・同じ発言の繰り返しによる信頼の積み上げは守れる
- 構造だけでは守れない残存リスク(v1): 判定器がだまされると、異なる言い回しを3回言えば門は開く
- v2 では、判定器が完全にだまされても門は事実の裏づけなしには開かない(信頼は最大2で止まる)。代わりに「話術だけで通る」体験はなくなる