⚖️判定ロジックと精度の記録
確定した判定の仕組み + 暫定の精度(Wilson 95%CI)+ 精度改善の議論の作業台。実FPRは実機テストでこれから。
判定ロジック(確定している仕組み)と、その精度(暫定・信頼区間つき)を 1 か所に記録するページ。精度を良くするための議論の作業台として使う。精度の数字はすべて暫定・Wilson 95% 信頼区間つき。点推定で断言しない。 実 FPR(まっとうな電話をどれだけ誤ブロックするか)は Chris→Hide の実機テスト(n≥20)で測定する — これから。 いまある数字は半合成 gold set 上の値であり、実運用の保証ではない。
種類①: 判定の仕組み(確定)
設計は 2 段階判定: まずルール層(決定的・速い)、次に LLM 層(文脈を読む)。
本線(champion)は rules 層のみ。LLM 層は実装(classify_call / 実測プローブ)は存在するが 本線ではない(棚上げ中)。昇格するときは verdict port 内部の差し替えで行い、 呼び出し側は変わらない設計になっている。
ルール層 — チェッカーの固定実行順(順序そのものが仕様)
- ブロックリスト照合 — 一致 → 即 blocked(allowlist より先)
- ホワイトリスト照合 — 一致 → 即 direct_transfer
- 営業時間チェック — 時間外 → after_hours
- 認証キーワード — 一致 → transferred(score=0.0。判定には利用者発話のみ使用)
- キーワードスコア — 重み high=0.3 / medium=0.15 / low=0.05 を加算(client 別上書き可)
- 開幕フロア(opener floor) — 権威フレームなりすまし検知で score に 0.6 を OR 合成(max)。単独では切断せず grey 帯へ引き上げ
- カテゴリ判定 — SpamCategory(DB)のキーワード一致 → allowed_sales / form_guided
- 閾値判定 — score ≥ 0.8 → form_guided / ≤ 0.3 → transferred / 中間 → grey_transferred
閾値(確定値の正は SSoT — ここは写し)
| 名前 | 値 | 意味 | 出典 |
|---|---|---|---|
block_threshold | 0.8(既定) | これ以上で form_guided(遮断系)。EngineConfig で client 別上書き可 | backend/engine/scorer.py |
grey_threshold | 0.3(既定) | これ以下で transferred(取次)。中間は grey_transferred(人へ) | backend/engine/scorer.py |
opener floor | 0.6 | 開幕なりすましの下駄。安全弁 0.8 未満なので単独では切断しない設計 | backend/engine/opener_floor.py |
AEGIS_TERMINATE_MIN_SCORE | 0.8 | 切断安全弁。スコア由来の遮断(form_guided)はこの値以上のときだけ should_terminate=true | SSoT / backend/config.py |
確定値(0.8 / 0.3 / 0.6 / 安全弁 0.8)は SSoT と整合。変えるときは先に SSoT。
LLM 層 — classify_call の分類(5 値)
existing_contact— 既存の取引先・知人new_business— 新規の商談・問い合わせsales_pitch— 営業・勧誘support_request— サポート依頼unknown— 上記に当てはまらない・判断不能
verdict port — 分類脳の唯一の入口(契約の要点)
- 判定を求める全経路(transcript-tick / transcript-final / bridge の classify)は verdict_port.evaluate() を呼ぶ。champion が rules か llm かは port 内部の関心事で、呼び出し側からは不可視。
- 正は常に action。should_terminate / should_transfer はその投影(導出値)で、port の外で独自計算しない(二重化の禁止)。
- 遮断系 action = form_guided / after_hours / blocked。取次系 = transferred / direct_transfer / grey_transferred / allowed_sales。
- L1 決定的ゲート由来(after_hours / blocked)は無条件で should_terminate=true。スコア由来(form_guided)は spam_score ≥ 0.8(安全弁)のときのみ true。
- フェイルオープン: 空 transcript → pending、内部例外 → error。いずれも導出 bool は false(人へ倒す側)。
- 判定源の名札は call_logs.score_source('rules' / 'llm' / NULL)。どちらの脳が出した値かを後から追跡できる。
種類②: 精度・eval(暫定・信頼区間つき)
測っているもの(gold set の現状)
- gold set: v3(42 件 = spam 21 / not_spam 21) — feat/eval-gold-v01 ブランチ(未マージ)。main の gold_set.json は骨格 2 件のみ
- provenance: public 10(千葉県警文字起こし等)/ synthetic-grounded 20 / synthetic 12。real は 0 件
- プローブ: 42 件全件に llm_observed(gpt-realtime GA の実測プローブ、commit da55690)
測定値(詐欺見逃し対策 A/B・暫定)
| 指標 | before | after(案A) | 注意 |
|---|---|---|---|
| 詐欺(特殊詐欺 10 件)の見逃し | 7/10 | 3/10 [10.8%, 60.3%] | n=10 なので区間は非常に広い。傾向の把握まで |
| FNR 全体(迷惑の見逃し率) | 33.3% [17.2%, 54.6%] | 14.3% [5.0%, 34.6%] | n=21(spam 側)。区間が重なるため「改善傾向」以上は言えない |
| FPR(まっとうな電話の誤ブロック率) | 0.0% [0.0%, 15.5%] | 0.0% [0.0%, 15.5%](維持) | n=21(not_spam 側)。0 件でも上限 15.5% — 「FPR ゼロ」とは言えない |
上の表は LLM 層(棚上げ中)の実測プローブ(llm_observed)を閾値 0.8 で block/pass 化した値。 本線 rules 層の実運用値ではない。しかも測定元は未マージのブランチ(feat/eval-gold-v01)。 n が小さく区間が重なるため、言えるのは「改善傾向」まで。
FPR 規律(eval 設計 D4 / D5)
- FNR / FPR は必ず Wilson 95% 信頼区間つきで報告し、受入判定は区間の上限 / 下限で行う(点推定で断言しない)。
- gold 各件は provenance(real / public / synthetic-grounded / synthetic)を持ち、全体と real-only の両方で報告する(半合成への過適合検知)。現状 real は 0 件なので real-only は測定不能。
- 実 FPR は Chris→Hide の実機テスト(n≥20)で測定する。これから。今ある数字は半合成 gold 上の暫定値。
改善の議論の作業台
精度を良くするために、いま開いている論点。議論が動いたらこのページ(src/data/detection.ts)を更新する。
🧠 LLM 層の champion 昇格をいつ・何を根拠に判断するか
- 現状の champion は rules 層。昇格は verdict port 内部の差し替えで行える設計(呼び出し側の改修不要)。
- 昇格判断の材料 = gold での rules vs llm の区間比較 + 実機テストの実測。区間が重なるうちは昇格しない。
🕵️ 詐欺見逃し対策: 案A(fraud enum)と案B(unknown 帯 0.6)の選定
- 両案とも見逃しは 7/10 → 3/10(暫定)。ただし案A は詐欺 6 件のスコアが 0.95–0.99 へ動き大マージン、案B は 0.6–0.7 に張り付き薄氷。
- 案A 優勢だが未マージ(feat/eval-gold-v01)。マージ判断の前に実機テストの結果を待つか、が論点。
📞 real provenance の獲得(gold の最大の穴)
- gold 42 件に real は 0 件。半合成への過適合はいま検知できない。
- Chris→Hide 実機テスト(n≥20)の通話を、PII マスクの上で real provenance として gold へ昇格させる動線(gold_candidates キュー)が用意済み。
📏 rules 層自体の gold 実測を記録に残す
- eval_scorer.py --source rules で本線 rules 層を同じ gold 42 件で測れるが、その数字はまだこのページに記録していない。
- llm 層との比較を区間つきで並べるのが次の一歩(champion 昇格判断の土台になる)。
🏷️ ラベル待ちキューの消化(PII マスク必須)
- 実文字起こしのラベル待ちキュー(git 非追跡・PII の可能性あり)が手元にある。promote 前に個人情報のマスクが必須(キュー自身にもその旨を明記済み)。
- ラベル付けの人手(誰が・どの基準で)が未定。gold_category の付け方は taxonomy と揃える。
数字・論点は src/data/detection.ts に集約してある。新しい測定値は必ず「gold の版 × 測定対象(rules / llm)×
commit」を紐づけ、Wilson 95%CI つきで追記する。実機テストの結果が出たら、暫定値と入れ替えるのではなく
並記する(半合成 gold との乖離そのものが情報)。