Fragrachとは
Fragrach v0.1.0というRust製ライブラリを公開しました。
https://github.com/hachiware-labs/fragrach
Fragrachは、企業文書のように内容や効力が変化し続ける文書群を対象に、どの文書を回答の根拠として採用すべきかを扱うためのKnowledge Compilerです。文書を検索へ投入する前に解析し、有効時点・適用範囲・承認状態・権威・版の優先関係・例外・文書間のRelation・原文Evidenceなどを、Knowledge Buildとしてコンパイルします。
……と書くと最初からこういう仕組みを狙っていたように見えますが、実際の出発点はもっと素朴でした。
どうすればRAGの精度をもっと上げられるのか。
GraphRAGを調べ、Sparse RetrievalやDense Retrieval、Hybrid RAGを評価していくうちに、問題の見え方が少しずつ変わっていき、最終的にこう考えるようになりました。
必要な文書を検索できることと、その中から回答に使うべき文書を選べることは、別の問題ではないか。
この記事では、Fragrachがこの形にたどり着くまでの経緯を書きます。
なお用語を先に整理しておくと、タイトルのRecallは「必要な文書を検索候補に入れられた割合」、この記事でいう「RAGの精度」は「最終的に正しい回答ができたか」という回答側のAccuracyを指しています。この二つが別物である、というのがこの記事の主題です。
最初はGraphRAGを調べていた
RAGの精度改善というテーマで最初に気になったのがGraphRAGでした。
通常のRAGは文書をchunkに分割し、BM25などの語彙ベース検索(Sparse Retrieval)やEmbeddingによるベクトル検索(Dense Retrieval)で関連文書を取得します。GraphRAGはそこにEntityやRelationといった構造を加え、単純な類似検索では扱いにくい関係を検索や回答に利用します。
直感的にはかなり強そうです。実際、multi-hop reasoning、複数文書にまたがる関係の探索、temporal / comparison question、文書群全体のglobal summarizationといった問題では、Graphを使う意味が明確にあります。「GraphRAGを使えば通常のRAGよりかなり高い精度が出るのではないか」と期待して調査を始めました。
ところが、調べてみると状況はそこまで単純ではありませんでした。GraphRAGには明確な得意領域がある一方で、通常RAGを安定して上回るとは限らないのです。
例えば、RAGと複数のGraphRAG実装を統一条件で比較した系統的評価(Han et al., "RAG vs. GraphRAG: A Systematic Evaluation and Key Insights")では、質問タイプによって勝者が入れ替わることが報告されています。single-hopのNQでは通常RAGが最も強く、multi-hopやtemporalな質問ではGraphRAG系が勝ちます。
| 手法(Llama 3.1-8B) NQ<br>(single-hop, F1) MultiHop-RAG<br>(Overall Acc.) 同・Temporal<br>(Acc.) | |||
|---|---|---|---|
| 通常RAG(Dense) | 64.78 | 67.02 | 30.70 |
| KG-GraphRAG(Triplets) | 34.28 | 41.24 | 18.70 |
| Community-GraphRAG(Local) | 63.01 | 69.01 | 50.60 |
| HippoRAG2 | 61.03 | 70.27 | 49.91 |
Temporalな質問ではGraphの効果が大きい(30.70 → 50.60)一方、single-hopでは通常RAGを超えられず、KGだけを検索対象にする構成に至っては大幅に劣化しています。「Graphを足せば全体が良くなる」わけではないことが、数字にはっきり出ています。
さらに、Graphの構築・維持コストも無視できません。同じ評価から、MultiHop-RAGデータセットでの構築時間と検索時間を引用します。
| 手法 Index構築時間 検索時間 | ||
|---|---|---|
| 通常RAG | 135秒 | 1,724秒 |
| KG-GraphRAG | 7,702秒(約57倍) | 14,434秒 |
| Community-GraphRAG | 5,560秒(約41倍) | 1,249秒 |
構築コストはRAGの数十倍で、しかもGraph構築に使うLLMの性能によって最終精度が変わる(同評価ではGPT-4o-mini構築で71.17、GPT-4o構築で75.08)ことも報告されています。文書が更新され続ける企業コーパスでは、このGraph再構築コストを払い続けることになります。
つまり近年の研究は、「Graphを追加すればRAG全般が良くなるか」という段階を過ぎて、どの種類の質問に、どの構造を使うと効果があるのかを切り分ける段階に入っているように見えました。実際、上記の評価でもRAGだけが正解した質問とGraphRAGだけが正解した質問がそれぞれ1割以上存在し、両者は優劣ではなく補完関係にあると結論づけられています。
このとき調べた内容はリポジトリにも残しています。
Sparse Retrievalはまだかなり強かった
GraphRAGと並行して、通常のRetrievalも改めて評価しました。ここで少し意外だったのは、Dense Retrievalだけに寄せればよいわけでもなかったことです。
企業文書には、規程番号、製品名、型番、部品番号、条項番号、日付、数値、固有の専門用語が大量に登場します。こうした情報に対しては、意味検索よりもBM25のような語彙一致のほうが圧倒的に確実です。一方で「故障したときの対応」と「異常発生時の復旧手順」のように、意味は近いが表現が異なるケースではDense Retrievalが効きます。
つまりSparseとDenseは強みが違い、実際にFragrach内の評価でも、質問や文書領域によって勝者が入れ替わりました。どちらかが常に勝つことはありません。
そうなると有力なのは、SparseとDenseを組み合わせ、必要に応じてrerankerで整えるHybrid RAGです。Fragrachでは最初から新しいRetrieverを作るのではなく、まず強いHybrid RAGをbaselineとして固めることにしました。
Hybrid RAGは必要文書を取れる。それでも回答は間違える
Hybrid RAGを使うと、必要な文書はかなり高い確率で検索候補に入るようになりました。ここまでは期待どおりです。
ところが、回答はまだ間違えます。
失敗ケースを一つずつ見ていくと、不思議なことが起きていました。Retriever自体は失敗していないのです。
例えば、ある規程について質問すると、検索結果には現行版と失効した旧版の両方が入ってきます。同じ規程の新旧版なので、どちらも同じ主題を扱っており、SparseでもDenseでも両方が高い関連度を持つのは当然です。Retrieverから見れば、これはむしろ良い検索結果です。しかし現在の規則を聞いているなら、回答に使ってよいのは現行版だけです。
別のケースでは、承認済みの正式文書と、次期改訂案のdraftが両方取得されます。どちらも質問には関連していますが、未承認のdraftを現在の規則として使ってはいけません。さらに、一般規則と、特定製品や設備だけに適用される例外が同時に取れるケースもあります。この場合、質問の対象によっては例外側を優先しなければなりません。
失敗ケースに共通していたのは、どれも検索の失敗ではなく、「関連している文書」と「回答の根拠として採用すべき文書」が別物だったことです。
Recall 100%でも、RAGは間違える
ここがFragrachの方向を決めた一番大きな転換点でした。
Recallは「必要な文書を検索候補に入れられたか」を測ります。しかし必要な文書が候補に入っていても、旧版・draft・別scopeの規則・競合文書が一緒に入っていれば、その中からどれを使うかの判断は回答モデルに丸投げされます。
極端な例で考えてみます。検索上位4文書が次のようだったとします。
- 承認済みの基本規則
- 今回だけ適用される例外
- 失効した旧版
- 未承認の次期改訂案
必要な文書が1と2なら、Recall@4は100%で、検索としては完璧です。それでも回答モデルが3や4を根拠に採用すれば、最終回答は間違います。
Recall 100%でも、RAGは間違える。
これは検索性能の問題ではなく、検索後の判断の問題です。
そして重要なのは、この問題が偶然や運用ミスで起きているのではなく、企業文書というコーパスの性質そのものから必然的に生まれているという点です。
Wikipediaのスナップショットや教科書のように、内容が固定されたコーパスなら、「関連している文書」はほぼそのまま「使ってよい文書」です。似た内容の文書が複数ヒットしても、どれを使っても大きくは間違えません。多くのRAGベンチマークが暗黙に置いているのも、この静的なコーパスの世界です。
しかし企業文書は違います。規程は改訂され、旧版は失効し、draftは承認を待ち、例外は期限付きで発行され、決定は実施されて記録が残る。**コーパス自体が生きて変化し続けています。**私はこれをLiving Corpusと呼んでいます。
Living Corpusでは、同じ主題を扱う「正しかった文書」と「今正しい文書」と「これから正しくなるかもしれない文書」が、必然的に同じ検索空間へ蓄積されていきます。旧版を消せばいいという話でもありません。「2024年時点の規則ではどうだったか」という質問には旧版こそが正解であり、監査やトレーサビリティの観点からも過去の文書は保持され続けます。つまり、紛らわしい文書が候補に混ざるのは検索のバグではなく、Living Corpusの仕様なのです。
そして文書が増え、改訂が重なるほど、この「関連はしているが採用してはいけない文書」は単調に増え続けます。運用を続けるほどRAGの回答が劣化していくとしたら、原因の一つはここにあります。静的なコーパスを前提としたRAGの設計だけでは、この構造に対応できません。Recallをいくら上げても解決しないのは、そもそも測っている問題が違うからです。
RetrievalとAdoptionを分けて考える
そこで、問題を二つに分けることにしました。
Retrieval — Which documents are relevant? 質問に関連する文書を見つける問題。Sparse / Dense / Hybrid Retrievalとrerankerが担当する、従来どおりの領域です。
Adoption — Which documents should be used? 取得した文書の中から、最終回答の根拠としてどれを採用するかを判断する問題です。具体的には、
- 旧版と現行版のどちらを使うか
- 正式文書と草案をどう区別するか
- 一般規則と個別例外のどちらが優先するか
- 提案された変更は承認されたのか
- 決定は実際に実施されたのか
- 実施記録を規則そのものとして扱ってよいか
- 質問時点でその文書は有効だったか
- 対象部門や製品へ適用できるか
といった判断です。これらはsimilarityでは決まりません。
ここからFragrachは、「新しいRetrieverを作る」のではなく、**「Retrieverが取得した文書の採否を判断可能にする」**方向へ進みました。
では、Knowledge Graphを作れば解けるのか
文書の採否を判断するには、文書同士の関係が必要です。
Policy v2
supersedes
Policy v1
この関係が分かれば、現在の規則について答えるときにv1を採用すべきでないと判断できます。同様に、
Exception A
exception_to
General Policy
があれば、質問のscopeが一致するときだけ例外を優先できます。
ここで再びGraphの考え方が出てきます。ただしFragrachは、汎用的なKnowledge Graphを作る方向には進みませんでした。人物・組織・製品・概念・イベントを可能な限りEntity化して大量のRelationで結ぶ必要はなく、必要なのは回答時の文書採否を変えるRelationだけだと考えたからです。
そこで、扱うRelationを次のように絞りました。
-
supersedes:旧版を置き換える -
amends:特定部分を変更する -
proposes_change_to:変更を提案するが、まだ効力を持たない -
applies_to:特定対象へ適用される -
exception_to:一般規則に対する限定的な例外 -
conflicts_with:解決していない矛盾 -
approves:提案などを承認する -
implements_decision:決定を実装する -
records_execution_of:実施された事実を記録する -
order_of_precedence:優先順位を示す -
derived_from:正本と派生文書を結ぶ
Relationは、増やしても混ぜてもいけない
Relationを絞ったあとにも、GraphRAGを調べたときと似た罠が二つありました。
一つ目は、Relationごとに意味が違うという点です。例えばrecords_execution_ofは「この作業が実際に実施された」ことのEvidenceにはなりますが、その実施記録が「今後も守るべき規則」になるわけではありません。exception_toも、質問の対象や期間が一致しなければ一般規則を上書きしません。だからFragrachでは、すべてのRelationを単一のGraph距離やscoreへ潰さず、RelationはRelationの意味を保ったまま扱うことにしました。ここは設計上かなり意識した部分です。
二つ目は、構造化したRelationをそのままLLMへ渡すべきではないという点です。文書間Relationをきれいに構造化できても、それを全部回答モデルに渡して「このGraphを見て、今回どの文書を使うか判断してください」とすれば、最終判断をまたLLMに戻すことになります。Relationが増えるほどcontextも膨らみます。
そこでFragrachでは、Relationをさらに回答上の役割へ縮約することにしました。それがDecision Packetです。質問やUsage Intentに対して、文書を4つの役割に整理します。
-
governing:回答を支配する文書 -
verifier:承認や実施などを裏付ける文書 -
contender:競合していて、まだ解決できない文書 -
excluded:旧版、draft、scope外など、今回は採用しない文書
情報の流れはこうなります。
原文文書
↓
必要最小限のRelation
↓
文書の採否判断
↓
governing / verifier / contender / excluded
Graphを回答時に探索させるのではなく、回答前に済ませられる判断は、できるだけ先にコンパイルしておくという考え方です。
FragrachはKnowledge Compilerになった
こうしてFragrachは、新しいRetrieverではなくなりました。役割分担を一言でいうと、
Hybrid RAGは関連する文書を見つける。Fragrachは、その中で採用・確認・競合・除外すべき文書を示す。
Fragrachは原文文書から、Evidence、Claim、文書Profile、authority、approval state、scope、valid time、version、Relation、conflict、Decision PacketをKnowledge Buildへコンパイルします。そのKnowledge Buildを、既存のSparse / Dense / Hybrid RAGから利用します。
Fragrach自体はVector DBでも、検索サーバーでも、Chat UIでも、回答生成器でもありません。RAGの前段で文書群を処理し、後段のRAGが判断しやすい形へ変換するKnowledge Compilerです。
この問題に取り組んでいるのは、Fragrachだけではない
公開にあたって改めて調べると、同じ問題領域に取り組む研究がこの1年ほどで急速に増えていることが分かりました。「Recall 100%でも間違える」という問題認識は、Fragrachの独創ではありません。
例えばVersionRAG(2025年10月)は、バージョン進化する技術文書を対象に、版の系列・内容の境界・版間の変更を階層グラフとして明示的にモデル化するframeworkです。バージョン依存の質問において、既存手法のAccuracyが58〜64%に留まる一方で90%を達成したと報告されており、「意味的に似ているが時点が違う文書に惑わされる」という、この記事で書いてきた失敗と同じ現象を扱っています。
またControlling Authority Retrieval(2026年)は、後の文書が先の文書を形式的に無効化する領域——判例が後の判決で覆される、医薬品承認がリコールで失効する、脆弱性開示がパッチで無効になる——を「controlling authority retrieval」という問題群として定式化し、意味的関連度に基づく標準的な検索がこの問題に構造的に失敗することを示しています。Fragrachのsupersedesが扱っているのと、ほぼ同じ問題です。
さらに遡れば、法律情報学のcitator(Shepard'sやKeyCite)は、「この判例はまだ有効か、覆されていないか」を人手とシステムで数十年前からフラグ付けしてきました。「関連していることと、根拠として使えることは別」という洞察自体は、法律の世界では古典なのです。
同時期に複数の研究が独立に同じ壁へぶつかっているのは、この問題が本物である証拠だと受け止めています。その上で、Fragrachのアプローチが先行研究と違うのは次の3点です。
**1. 採否を決める軸を、一つの体系として扱う。**VersionRAGはバージョン軸、Controlling Authority Retrievalはsupersession軸に特化しています。しかし実際の企業文書では、版・承認状態・scope・例外・実施記録・権威・優先順位が同時に絡みます。「最新版だがdraft」「承認済みだがscope外」「有効だが例外に上書きされる」といった組み合わせを判断するには、これらを個別の問題としてではなく、Adoptionという一つの問題の複数の軸として扱う必要があります。
**2. Relationを回答時に渡すのではなく、役割へコンパイルする。**先行研究の多くは、構造を検索時・回答時に参照します。Fragrachは、Relationの評価をgoverning / verifier / contender / excludedという4つの役割へ事前に縮約し、回答時の判断を最小化します。
**3. パイプラインではなく、コンパイラとして切り出す。**先行研究は新しいRAGパイプラインとして提案されていますが、Fragrachは特定のRetrieverやVector DBに縛られないKnowledge Buildという成果物を生成する独立したツールです。既存のSparse / Dense / Hybrid構成を置き換えずに、その前段へ挿入できます。
VersionQAでの評価
自作コーパスだけでは説得力に限界があるため、VersionRAGが公開しているベンチマークVersionQAのバージョン依存60問で、Fragrachを評価しました。
| Condition Accuracy Evidence Unit Recall 完全根拠付き正答率 | |||
|---|---|---|---|
| Raw Ruri Hybrid(baseline) | 58.3%(35/60) | — | — |
| Fragrach Query-relative Packet | 100%(53/53) | 100% | 100% |
baselineの58.3%は、VersionRAG論文が報告するnaive RAGの58%とほぼ一致しており、評価セットアップが原論文の条件を再現できていることの傍証になっています。その上でFragrach構成は、評価可能な53問すべてに、完全な根拠付きで正答しました。VersionRAG自身の報告値である90%を上回る結果です。
ただし、この数字にも留保があります。60問中7問は、ベンチマークのGold回答が配布文書の内容と矛盾していた(文書に基づく限りGoldが正解にならない)ことを確認したため、評価から除外しています。除外した各問と矛盾の内容は評価ドキュメントに記載しています。Goldが誤っている問題ではbaseline側の正誤判定も意味を持たないため、厳密な比較は同じ53問同士で行うべきですが、参考値として、除外7問をすべてFragrachの不正解として数えた最も保守的な場合でも53/60 = 88.3%です。また53問で失敗ゼロという結果から統計的に言えるのは「真のAccuracyがおよそ94%以上」までであり、規模の小さいベンチマークであることに変わりはありません。それでも、自作ではない外部ベンチマークで、先行研究の報告値と同水準以上の結果が出たことは、方向性の裏付けとして意味があると考えています。
候補集合を変えなくても、「正しい根拠の採用」は改善した
現在のFragrach Soft Rerank v1は、Hybrid Retrievalが取得した上位20文書をそのまま使います。候補の追加も削除もせず、Decision Packetのroleに応じて提示順だけを調整します。
500文書の評価コーパスから作成した125問での結果です。
| Condition Recall@20 Accuracy DVAA | |||
|---|---|---|---|
| Hybrid | 97.07% | 55.20% | 0.6689 |
| Hybrid + Fragrach Soft Rerank v1 | 97.07% | 56.00% | 0.7281 |
Recall@20が変わっていないのは、同じ候補集合を使っているからです。
この結果で見てほしいのは、AccuracyよりもDVAAです。
Accuracyは「最終回答が正解だったか」しか見ません。しかし企業文書QAでは、たまたま正解した回答が存在します。旧版を根拠にしたが結論は現行版と同じだった、draftを引いたが該当箇所は承認済み部分と一致していた、といったケースです。これらはAccuracy上は正解ですが、根拠の選び方は間違っており、文書が次に改訂された瞬間に不正解へ変わります。運が良かっただけの正解は、Living Corpusでは時限爆弾です。
DVAAは、文書の時点・scope・承認状態・権威・Relationを考慮し、回答が適切なEvidenceを採用できたかを測ります。Fragrachが解こうとしているのはAdoptionの問題なので、効果を測るべき指標はこちらです。そのDVAAは0.6689 → 0.7281へ改善しました。Accuracyも55.20% → 56.00%と悪化はしていませんが、125問中1問の差であり、こちらは効果を主張できる規模ではありません。
また、未見の100文書シリーズから作成した200問の実運用ホールドアウトでは、Fragrachのメタデータを利用した構成でAccuracy 98.50%、fully grounded answer rate(正答かつ、時点・scope・承認・発行者・文書関係まで妥当なEvidenceで裏付けられた回答の割合)96.00%に達しました。ベースラインのDense単体では、Accuracyが78.50%ある一方でfully groundedは0%です。つまり8割近く正解していても、根拠の妥当性まで求めると一問も残らない。「正解しているのに根拠が正しくない」という問題が実際に大量に起きていることを示す結果でもあります。
**とはいえ、これらの評価にはまだ大きな留保が必要です。**評価に使ったコーパスも質問も自作であり、DVAAも本プロジェクトで定義した指標です。「自分で定義した物差しで自分を測っている」構図であることは自覚しています。問題数も125問・200問と少なく、統計的に頑健と言える規模ではありません。自作コーパスでの好成績は、コーパス生成時の前提とメタデータ抽出の前提が噛み合っているだけの可能性も否定できません。ここに書いた数字は「この方向に効果がありそうだ」という開発中の手応えとして読んでいただき、効果の実証は、第三者のベンチマークや実在の企業文書での評価を待つ必要があると考えています。
Fragrachは、Retrieverが見つけられなかった文書を魔法のように発見するわけではありません。すでに取得できた文書の中から、今回の回答で何を採用すべきかを扱います。
評価の詳細はこちらに公開しています。
GraphRAGを調べて分かったのは、「Graphが不要」ではない
振り返ると、GraphRAGを調べたことはこのプロジェクトにとってかなり重要でした。ただし得た結論は「GraphRAGは役に立たない」ではなく、Graphをどこに使うべきなのかという問いへの置き換えです。
multi-hopやglobal summarizationのように、Graphそのものの探索に価値がある問題は確かにあります。一方で、企業文書QAで最後まで残っていた問題が「どちらが現行版か」「この例外は今回の対象に適用されるか」「このdraftは承認済みか」「この実施記録は規則なのか、実施の証拠なのか」なら、巨大なKnowledge Graphは必要ありません。
**回答の採否に必要なRelationだけを構造化し、回答前に判断できるところまでコンパイルする。**Fragrachはその方向へ進みました。
v0.1.0を公開しました
Fragrachはまだv0.1.0です。Rust製のCLIとして実装しており、生成したKnowledge Buildは既存RAGへexportできます。実装だけでなく、RAG技術の調査、要件分析、評価方法、開発中の評価結果、設計資料もできるだけGitHubに残しています。
https://github.com/hachiware-labs/fragrach
今回は機能そのものより「なぜこの仕組みを作ることになったのか」を書きました。次回はもう少し内部に入り、なぜ汎用Knowledge Graphではなく文書採否に必要なRelationだけを扱うことにしたのか、そしてそれをどのようにgoverning / verifier / contender / excludedへコンパイルしているのかを書く予定です。
Fragrachを作るまでを一文でまとめるなら、こうなります。
Recallを改善する方法を探していたら、Recallの先に別の問題が残っていた。
必要な文書を見つけること。その文書を、今回の回答の根拠として採用してよいか判断すること。Fragrachは、この二つを分けて考えるところから始まりました。

