基本情報

エレベーターピッチ

  • これは何?  : 起案を読んで「過去に似た決定をした既存 ADR」を最大 5 件自動で想起し、本文や審査の参照リストに添える proactive な想起 actor。
  • だれのため? : 起案者(自分が知らない過去 ADR を参照できる)と、後段の整合性チェック・並列レビュー(citation を読んで重複・前提・矛盾・補完を精査できる)。
  • なにが起きる?: 関連 ADR の top-5 を citation として後段へ渡すだけ。判定や差戻しは絶対にしない。embedding 失敗時は空配列で safe degrade。
  • 譲れない一線 : rejected は絶対に立てない。候補集合の所属検査と逐語照合で hallucination を必ず除去する。
  • だから    : 過去 ADR の重複・前提・矛盾・補完の見落としが、起案者の記憶と検索努力に依存せず入口で機械的に拾われる。

1. 役割と位置づけ

起案者は自分が知らない過去 ADR を参照できない。本ノードは triage 通過直後に既存 ADR から関連のあるものを top-5 まで自動で挙げ、下流の整合性チェック・並列レビューに citation として渡す。

  • 解決する課題: 過去 ADR の重複・前提・矛盾・補完の見落とし。起案者の記憶と検索努力に依存していた想起を、入口で機械的に強制する。
  • 設計思想: proactive な想起 actor。判定や棄却は行わず、後段の consistency / parallel_review が citation を読んで精査する。rejected は絶対に立てない
  • 二段構成 (ADR-0142 / ADR-0157 と同型): embedding で top-N 候補を事前絞り込み → LLM が top-5 citation を抽出 → コードが逐語照合 + 候補所属検査で hallucination を除去。
  • 由来: RQ-107 Must-have #1 R9 Recaller。

2. フロー図

flowchart LR
    T[triage] -->|needsAdr=true| R[recall_pre_gate]
    R -->|RECALL_ENABLED=false| ABC1[abc_screen
citations=空] R -->|候補 0 件 / embedding 失敗| ABC2[abc_screen
citations=空] R -->|LLM 抽出 + 逐語照合| ABC3[abc_screen
citations=top-5]

どの分岐でも次は abc_screen。差戻しはしない。


3. トリガー条件

エントリポイント起動グラフ説明
POST /draftbuildGraphWithWebhooktriage 通過 (needsAdr=true) 直後に実行
POST /chat/runbuildGraphwebhook を除く full pipeline

スキップ条件:

  • env RECALL_ENABLED='false' で素通し (recallCitations=[] を返す)。
  • 起案テキストが空 (applicantInput.trim() === '') ならスキップ。
  • Vectorize / embedding 失敗時は safe degrade で空配列。
  • 候補集合が 0 件のときは LLM を呼ばず空配列。

再実行ガードは入っていない (citation は安全に再計算可能・state は単純上書き)。


4. 入力 (State)

State フィールド必須用途
titlestring任意起案タイトル
contextstring任意背景・目的
optionsstring任意検討した代替案

入力は buildRecallQueryText({ title, context, options }) で 1 本のテキストに組み立てる。Phase a SSoT の applicant_input 形式に合わせる。

外部入力:

  • Vectorize binding (embedding 検索) — 環境変数経由
  • KV (プロンプト本文 + LLM パラメータ) — loadPrompt / loadLlmParams

5. 処理ロジック

0. RECALL_ENABLED='false' なら recallCitations=[] で素通し
1. applicantInput = buildRecallQueryText(state)
   - 空文字なら recall_pre_gate_skipped ログ + 空配列で終了
2. embedQueryText(env, applicantInput) で起案文を embedding 化
3. queryRecallCandidates(env, vec, RECALL_TOP_N=20) で Vectorize 上位 20 件を絞り込み
   - embedding / Vectorize が throw した場合は safe degrade で空配列
   - 候補 0 件なら recall_pre_gate_no_candidates ログ + 空配列で終了
4. プロンプト (recall-pre-gate) と LLM パラメータを KV から取得
5. claude-opus (MODELS.consistency) を temperature 0 / seed 42 で 1 call
   - user content: 【applicant_input】 + 【candidate_adrs】 (候補 20 件の整形)
   - 期待出力: { citations: [{ adr_id, relevance, relevance_reason }] } 0〜5 件
6. safeParseLlmJson でフォールバック付き parse
7. filterValidCitations() がコードで検証
   ① adr_id が候補集合に含まれているか (hallucinated id を除去)
   ② 重複除去
   ③ relevance_reason の逐語照合 (NFKC + 空白畳み)
      - 起案本文 OR 候補集合の summary のいずれかに含まれていれば valid
   ④ relevance が enum (high / med / low) でなければ 'low' へ正規化
   ⑤ 先頭 5 件で打ち切り (schema maxItems=5)
8. state.recallCitations へ verified を上書き

正規化の方針: NFKC + 空白畳み (全角/半角・合成/分解を吸収する方向)。ADR-0142 / ADR-0157 と方針統一・#safe 寄り。詳しい正規化は normalizeForCitationMatch() にある。

二段照合 (本文 OR summary): relevance_reason は起案本文に書かれた語と、候補 ADR の summary に書かれた語のどちらでも valid とする。proactive 想起者の役割上、起案者が書いていない概念でも summary 側にあれば拾える。


6. LLM 設定

項目根拠
モデルclaude-opus (MODELS.consistency)候補集合からの意味的選定・cross_validation と同モデルプール
temperature / seed0 / 42同一起案には同一 citation 集合 (KV recall-pre-gate params で上書き可能)
期待出力JSON object { citations: [...] } 0〜5 件output_schema.json で形式強制
Vectorize 絞り込みtop-N = 20LLM に渡す候補を 20 件に絞る
プロンプトKV recall-pre-gate (ADR-0085 lifecycle)フォールバックはノード内 FALLBACK_PROMPT

7. 副作用

なし (state 更新のみ)。

  • Vectorize binding への query 1 回・KV からのプロンプト / params 取得 (loadPrompt / loadLlmParams) は副作用ではないが外部 IO。
  • GitHub API / Webhook / D1 書込には触れない。

構造化ログ:

  • event: 'recall_pre_gate_skipped' — 入力が空
  • event: 'recall_pre_gate_embedding_failed' — embedding / Vectorize 例外
  • event: 'recall_pre_gate_no_candidates' — 候補 0 件
  • event: 'prompt_loaded' — KV / FALLBACK の出所
  • event: 'recall_pre_gate_citations_filtered' — LLM 出力件数 / 残った件数 / dropped 件数

8. 出力 (State)

{
  recallCitations: RecallCitation[],   // 0〜5 件
}

RecallCitation の中身:

interface RecallCitation {
  adr_id: string;             // 'ADR-XXXX' 形式 (pattern ^ADR-\d{4}$)
  relevance: 'high' | 'med' | 'low';
  relevance_reason: string;   // 起案本文 or 候補 summary の逐語引用 1-2 行
}
  • rejectedどの分岐でも絶対に立てない
  • 後段 (consistency / parallel_review) が recallCitations を読んで精査する。
  • 0 件の場合 (env OFF / 入力空 / 候補 0 / embedding 失敗) は空配列を返して通過。

9. 分岐 (次ノード)

graph.ts の edge:

.addConditionalEdges('triage', (s) => s?.needsAdr ? 'recall_pre_gate' : END)
.addEdge('recall_pre_gate', 'abc_screen')
状態次ノード
常にabc_screen

無条件 edge。差戻しを起こさないため addConditionalEdges ではない。


10. エラー時の挙動

失敗パターン挙動影響
embedding / Vectorize 例外recallCitations=[] で safe degrade後段の citation 参照は 0 件として動作
候補 0 件LLM を呼ばず空配列で終了コスト節約
LLM 例外safeParseLlmJson のフォールバック値 { citations: [] } を返す例外伝播せず 0 件で通過
LLM が JSON 以外を返すフォールバック値で 0 件structured error log
LLM が候補集合に無い adr_id を返すfilterValidCitations が除去hallucinated id を弾く
relevance_reason が逐語照合できないfilterValidCitations が捨てる幻覚を citation から隔離

設計方針は fail-safe-skip (どのエラーでも 0 件で通過させる)。proactive 想起の失敗は後段審査の精度を直接落とさない。


11. 既知の弱点・運用注意

  • embedding index 更新の遅延: 新規 ADR が受理されてから Vectorize へ ingest されるまで、その ADR は候補に出てこない。ingest pipeline (PR-2 の Vectorize binding + ADR ingest 経路) の monitoring が要る。
  • top-N=20 の代表性: Vectorize の top-20 に入らない関連 ADR は LLM が見ない。意味の遠い関連 (語彙が違うが論点が同じ) は取りこぼしうる。
  • 逐語照合の faithful but not factual 問題: relevance_reason の文字列実在は保証するが、関連の論理的妥当性は担保しない。後段 (consistency / parallel_review) が精査する前提の役割分担。
  • kill switch の安全側影響: RECALL_ENABLED='false' で素通しても recallCitations=[] になるだけ。下流 gate は state を読まないと挙動が変わらないため、誤動作時の影響が小さい。
  • fail-open のトレードオフ: LLM エラー時に 0 件で通過するため、recall_pre_gate_embedding_failed 等のログが頻発すると想起機能が実質無効化される。週次集計で監視する。
  • コスト累積: claude-opus を毎 run で 1 call 呼ぶ。triage で needsAdr=true を通過した起案のみが対象なので極端には膨らまないが、月次で観測する。

12. テストケース

  • pure helpers の unit test: recall_pre_gate_pure.tsnormalizeForCitationMatch / filterValidCitations を fetch/env/LangChain 非依存で test (vitest pool-workers 安全)。
  • 本体 (recall_pre_gate.ts) の test: LangChain を import するため workerd プールでは起動できない。pure helpers の re-export 経由で間接 test。
  • golden eval: prompt-cicd フローで PR ごと CI ゲート化。citation 件数 / relevance 分布 / 候補不在 adr_id 検出率を追跡。

実行: prompt-cicd フローの一部。詳しくは /Users/ts_kuma/projects/bizlp/doc/prompts/production/recall-pre-gate/ 配下の eval セット。


13. 過去の設計判断ログ

日時変更経緯
2026-06RQ-107 Must-have #1 R9 Recaller の synthesis 採択過去 ADR の重複・前提・矛盾・補完の見落としへの対策
2026-06 (Phase b-1 PR-1)state Annotation recallCitations のみ追加graph 未配線・常時 default [] で安全に投入
2026-06 (Phase b-1 PR-2)Vectorize binding + ADR ingest 経路を整備候補絞り込みの基盤を準備
2026-06-21 (Phase b-1 PR-3)本体 + graph 配線 + RECALL_ENABLED kill switchrecall_pre_gate ノードを triage → abc_screen 間に挿入。migrate-v17 で telemetry 列追加

14. 関連リンク