ADR 0015: リレーション抽出 — model-derived / unverified の出典マーカーを持つオプトインスロット
build_relation_graph の傍らに RelationExtractor Protocol スロットを追加する。デフォルトはバイト単位で同一のまま維持され、LLM が抽出したエッジには model-derived + unverified が刻印され、SecurityGate によるスクリーニングを経て、決して暗黙に信頼されることはない。
ステータス: accepted · 日付: 2026-07-13
不変の記録。ドリフト追跡の対象外(
coversなし)。編集せず、置き換え(supersede)で対応すること。
0002 のプロダクト方針の一部。 0005(実験的機能はデフォルトパスから隔離する)と 0010(決定論的セキュリティゲート)による制約を受ける。 rag-spine 0.9.0 で出荷済み。
背景
構造的リレーショングラフ(build_relation_graph)は完全に決定論的で、引用可能である。
すべてのエッジは、制御された次元 — プロファイル設定、ファクト、あるいはチャンク — から導出される。しかし、有用なリレーションの中には、ナラティブなテキストの中にしか存在しないものがあり(例:「A は B と提携している」)、それに到達できるのは LLM のみである。LLM は非決定論的であり、捏造の可能性もある。私たちはこの能力を、モデルが主張するエッジが制御・検証済みのファクトを装うことを許さず、かつバイト単位で同一のデフォルトパスに一切手を触れることなく、手に入れたい。
鍵となる洞察は ADR 0010 と同じ形をしている。すなわち、モデルが抽出したリレーションは 有用だが信頼できない。それは信頼できないものとしてラベル付けされなければならず、2 つのハードな保証 — RESTRICTED の隔離と競合他社への回答拒否 — は、モデルが何を返そうとも、この新しい入力パス上でも決定論的に成立しなければならない。
決定
RelationExtractor Protocol スロット(src/ragspine/graph/extractor.py)を追加し、
build_relation_graph(..., relation_extractor=None) から利用できるようにする。
- デフォルトは
None→ ベースグラフは従来とバイト単位で同一(追加エッジなし)。 - デフォルトの extractor(利用を望む場合)は
DeterministicRelationExtractor:ルールベースの同一ドキュメント内エンティティ共起(co_occurs_with)で、LLM を一切使わず、決定論的であり、クリーンなリネージを持つ(ドキュメントソースのみ、モデルマーカーなし)— ベースの doc→entitymentionsエッジとは真に別物である。 LLMRelationExtractorはオプトイン([llm]extra の背後)であり、ナラティブグラフ抽出器のデグレード規律を踏襲する。これが出力するすべてのエッジにはderived=model-derived+verified=unverifiedが刻印される(決して暗黙に信頼されない)。そのリネージはチャンク(呼び出し元)から刻印され、モデルの自己申告からは決して刻印されない。RESTRICTED チャンクは決して LLM に到達しない。そしてすべてのリレーションの両エンドポイントが決定論的なSecurityGateによってスクリーニングされる — 競合他社/外部のエンドポイントであればそのエッジは破棄される。ProviderErrorや不正な JSON の場合は何も出力しない形にデグレードし、max_relationsによって上限が設けられる。- 選択方法は
make_narrative_graphを踏襲する:make_relation_extractor(spec, *, provider, profile)/RAGSPINE_RELATION_EXTRACTOR(none→None;deterministic/rule/cooccurrence;llm/on→ provider がない場合は正直にNoneへデグレード)。
原則:能力はデフォルトパスの傍らに置き、その内側には決して置かない。モデルが主張するエッジはラベル付けとスクリーニングの対象であり、決して暗黙に採用されない。
検討した代替案(却下)
- LLM エッジを、制御されたエッジと同じクリーンなリネージでマテリアライズする。 却下 — 捏造されたリレーションが検証済みファクトとして読めてしまい、出典追跡の不変量が破られる。
- 抽出されたエッジに対する
SecurityGateを省略する(ベースグラフのノード隔離を信頼する)。却下 — モデルはノードとして一度も存在しない競合他社の名前を挙げることができ、競合他社のリレーションを密輸できてしまう。代わりに抽出時点でスクリーニングする。 - 抽出をデフォルトの
build_relation_graphに無条件で組み込む。 却下 — バイト単位で同一のデフォルトが破られ、制御されたパスの上に非決定論的なステップが置かれてしまう。
帰結
- リレーショングラフはオプトインのナラティブリレーション能力を獲得しつつ、デフォルトパスはバイト単位で同一のまま維持され、モデル由来のすべてのエッジは自己ラベル付けされ、監査可能である。
- 2 つのハードな保証(RESTRICTED の隔離、競合他社への回答拒否)は、この新しい抽出入力パス上でも成立するようになり、モデルへの信頼ではなく決定論的に強制される。
- 新しい成果物:
RelationExtractorProtocol、決定論的なデフォルト実装と LLM 実装、ファクトリ/環境変数セレクタ、そして各エッジのメタデータに書き込まれる出典マーカー定数 (derived=model-derived、verified=unverified)。
ADR 0014: サービスとしての Dify ワークフロー(analyze / compile / run)と三層安全実行
既存の ragspine サービスを、信頼度が段階的に高まる 3 つの Dify エンドポイントで拡張する — analyze と compile は常時有効、run はデフォルト無効で、静的 import ゲート、制限付きインプロセスサンドボックス、(Linux では)サブプロセス隔離の背後に置く。プロバイダは常にサーバー側で決定される。
ADR 0016 — 検索プロダクト化の設定
メタデータフィルタリング、マルチインデックスルーティング、親子プリセット、エコノミーモード。すべての検索不変条件を保持したまま。