メインコンテンツへスキップ
ブログ一覧に戻る
AI活用・LLM

RAG(検索拡張生成)とは?企業のナレッジベースをAIで活用する方法

2025年11月24日
最終更新: 2026年10月8日
15分で読めます

この記事でわかること

企業のナレッジベースにRAGを導入する前に、検索と生成の役割、文書の版管理、閲覧権限、分割、根拠不足時の保留を整理します。架空文書で動くPythonの完全例、検索と回答を分けた評価表、費用や更新の確認手順から、小さな試行を設計できます。社内FAQ・顧客対応・技術資料それぞれの導入判断と運用の責任も具体化します。

2026年10月8日に、OWASP RAG Security、LangChainのTools、LangGraphのPersistence、OpenAIの評価ガイドを再読しました。RAGは検索できたこと、閲覧できること、根拠に沿って答えたことを分け、版・適用条件・権限・削除・キャッシュを検証します。取得文書の指示をツール権限へ昇格させず、検索精度・根拠一致・保留・人の修正を別に評価し、チェックポイントとログの保持・削除条件も決めます。

社内規程を探すだけで十分な仕事と、複数の資料を読んで回答案を作る仕事では、必要な仕組みが違います。RAGを導入する前に、どちらの負担を減らしたいのかを決めましょう。

RAG(Retrieval-Augmented Generation、検索拡張生成)は、質問に関係する資料を検索し、その内容を生成AIの入力へ加える構成です。モデルが知らない社内情報を参照させる用途に使えます。ただし、検索できた資料が現行で、利用者に閲覧権限があり、回答を裏づけるとは限りません。

30秒で要点

表が収まらない場合は、横にスクロールできます

決めること実務で確認する内容
RAGが必要か文書の発見だけか、比較・要約・回答案まで必要か
何を参照するか文書の責任者、現行版、適用日、読める人を確定する
どこで止めるか根拠なし、矛盾、権限不明なら回答を保留する
何を測るか検索、回答の根拠、適切な保留、確認負担を別々に測る

本記事は、社内ナレッジの検索と回答案の作成を設計する担当者向けです。コードは架空文書を使うローカル教材で、実際のLLMやクラウド検索には接続しません。顧客情報や認証情報を投入せず、まず境界が守られるかを確認します。

導入前に、三つの問いを決める

第一に、困っているのは「見つからない」ことか、「読んで組み合わせられない」ことか。 前者なら、文書の整理、タイトル、通常の全文検索を直すだけで負担が減る場合があります。RAGは生成の工程を増やすため、利用料だけでなく回答を確認する時間も必要です。

第二に、正しい資料を誰が維持するか。 改定前後の規程が同じ場所にあり、どちらを適用するか不明なら、AIにも解決の前提がありません。文書の責任者、適用対象、発効日、廃止日、承認済みかを整理します。

第三に、AIの出力を誰が何に使うか。 社内検索の補助、問い合わせの回答案、外部への確定回答では、失敗の影響が違います。「回答案を作る」段階と「顧客へ送る」段階を分け、送信は担当者が根拠と宛先を確認する構成から始められます。

例えば、総務担当者が旅費規程を探す場面を考えます。該当ページへのリンクだけで足りるなら検索で完了です。複数の条件を突き合わせる必要があるなら、根拠の節を添えた回答案が役立つ可能性があります。ただし、例外申請の承認までAIに任せる理由にはなりません。

検索と生成の間に、確認する境界を置く

Azure AI SearchのRAG説明では、検索した内容をモデルの入力へ渡す構成と、問い合わせを分解する構成などが区別されています。ここでは、検索を一度行って回答案へ渡す基本形を扱います。製品固有の機能がなくても、工程を分けて設計する考え方は使えます。
管理された文書から現行版と閲覧権限で検索対象を絞り、根拠があれば回答案へ、不足や矛盾があれば保留するRAGの流れ
図1:文書の登録と利用時の確認を分ける設計例。根拠の確認は生成前と回答案の確認時の両方に置く。実製品の画面ではない。

この流れで残す情報は、回答だけではありません。質問、検索対象の版、参照した文書IDと節、保留理由、担当者による修正を、必要な範囲で記録します。ログそのものに機密文書や個人情報を無制限に複製しないよう、閲覧者と保持期間も決めます。

RAGは、モデルのパラメータを更新する追加学習と同じではありません。資料を差し替えても、検索インデックス、権限情報、キャッシュが更新されなければ古い内容が残ります。「元ファイルを直したから全回答も更新された」と考えず、登録から参照までを確かめます。

文書を登録する:分割より先に、版と責任者を決める

最初は一つの業務に絞ります。問い合わせが多く、正解を文書で確認でき、資料の責任者がいる範囲が候補です。社内の全ファイルを集めることを開始条件にしない方が、誤りの原因を調べやすくなります。

表が収まらない場合は、横にスクロールできます

登録時の情報必要な理由仮想の値
文書ID・節ID回答から原文へ戻るtravel-policy / domestic-rail
版・適用期間過去のルールとの混在を防ぐv3、2026年10月から有効
責任者・承認状態内容を確認できる相手を決める総務、承認済み
閲覧できる利用者・部署読めない内容を検索結果へ含めない総務・社員向け範囲
元の保存場所・更新時刻差分取り込みと追跡に使う文書管理システムのURL
検索用の処理版分割・埋め込みの変更を追えるようにするsplitter-v1 / embedding設定ID

PDFの本文抽出では、表の見出し、脚注、注記、ページの順序も確認します。例えば「上限額」の行だけが残って「特定の等級のみ」という条件が落ちると、検索できても誤った回答につながります。OCRで読んだ金額や日付は、検証用の質問で原本と照合します。

チャンクは、条件が離れない単位にする

チャンクは検索用に分割した文章の単位です。小さくすると局所的な記述を選びやすくなりますが、適用条件や例外が別の断片へ離れることがあります。大きくすると文脈が残る一方、無関係な文が増え、モデルへ渡す量も大きくなります。

Microsoftの分割資料は、固定長、見出しなどの構造、意味のまとまりによる方法を示しています。文字数とモデルのトークン数も同じではありません。「日本語は必ず何文字」という固定値を正解にせず、見出し・本文・例外・表を一緒に取り出せるかで比較します。

オーバーラップは隣の断片と一部を重ねる方法です。境界の文脈を残せますが、同じ文書の重複した断片が検索上位を埋める場合もあります。検索結果を文書や節ごとにまとめる工夫と合わせて試します。自作の固定長分割なら、重なりが分割長以上にならない検査も必要です。

埋め込みの変更は、検索対象の変更として扱う

埋め込みは文章を数値の配列へ変換し、近い内容を探すために使います。同じ次元数でも、異なるモデルのベクトルをそのまま比較できるとは限りません。モデル、次元、正規化、距離尺度、処理版をセットで記録し、変更時は再生成の対象を明示します。

まず新しい索引を別に作り、既存の評価質問で比較し、問題がなければ切り替える方法があります。旧索引を即座に削除すると原因調査や復旧が難しくなるため、保持方針と復旧先を決めておきます。廃止文書を利用者へ返さない制御と、監査のために履歴を保管することも別の判断です。

検索する:似た文章と、答えに必要な文章は違う

キーワード検索は製品番号や正確な名称を探すときの候補です。ベクトル検索は、質問と文書で表現が異なる場合の候補です。両者を組み合わせるハイブリッド検索もあります。いずれも、実際の質問で必要な節が取り出せるかを確認します。

例えば「交通費は誰が承認するか」という質問に、交通費の上限額を説明したページが近い内容として返っても、承認者の答えにはなりません。検索スコアをそのまま「正答確率」と表示しないことが大切です。

候補の取り方、上位何件を使うか、再順位付け、同じ節の重複除去、最低限必要な根拠は別々に設定します。上位件数を増やすだけで品質が上がるとは限りません。必要な資料の取り逃しと、無関係な文章の混入の両方を記録します。

権限は、検索結果をモデルへ渡す前に確認する

利用者が読めない文書をモデルへ送り、「回答では隠してください」と頼む構成では遅すぎます。検索範囲を認証済みの利用者に対応させ、許可した本文だけを後段へ渡します。顧客別・部署別・案件別の境界がある場合は、文書から作った各チャンクにも境界を引き継ぎます。

Azureの文書単位アクセス制御も、文字列フィルターと本人の認証を区別し、索引側の権限情報の同期が必要だと説明しています。部署名をリクエストの文字列で自由に指定できるだけでは認可になりません。本番ではサーバーが利用者の権限を取得し、権限変更の反映遅れも扱います。

回答キャッシュにも同じ注意が必要です。質問文だけをキーにすると、同じ質問をした別の利用者へ、権限の違う回答を返すおそれがあります。利用者の権限範囲、参照版、検索設定を含める設計に加え、権限失効時の無効化と表示直前の再確認を決めます。保存する答えが適切か不明なら、初期試行ではキャッシュを使わない選択もできます。

ローカルの完全例で、検索前の条件を確かめる

次のコードはPython 3.12の標準ライブラリだけで動く、架空文書の教材です。追加パッケージ、APIキー、ネットワークは不要です。prepareはキーワード一致で候補を取り出し、モデルへ渡せる根拠を作るまでを行います。埋め込み検索や自然言語の回答生成を実装したRAG製品ではありません。

roleとcurrent_versionsは、サーバーが確認済みの権限と文書台帳に相当する入力です。この教材自体には認証機構がありません。実際のアプリで利用者が任意に指定できる値として受け取らないでください。

from datetime import date

DOCS = [
    {"id": "travel", "version": 2, "role": "staff",
     "start": "2026-01-01", "end": "2026-10-01",
     "terms": ("交通費",), "text": "旧版:交通費の申請先は総務です。"},
    {"id": "travel", "version": 3, "role": "staff",
     "start": "2026-10-01", "end": None,
     "terms": ("交通費", "承認"), "text": "交通費は所属長が承認します。"},
    {"id": "payroll", "version": 1, "role": "hr",
     "start": "2026-01-01", "end": None,
     "terms": ("交通費",), "text": "人事限定の架空精算記録。"},
]

def chunk_text(text, size=10, overlap=2):
    if not isinstance(text, str):
        raise TypeError("text must be a string")
    if type(size) is not int or type(overlap) is not int:
        raise TypeError("size and overlap must be integers")
    if not 0 <= overlap < size:
        raise ValueError("require 0 <= overlap < size")
    chunks = []
    start = 0
    while start < len(text):
        end = min(start + size, len(text))
        chunks.append(text[start:end])
        if end == len(text):
            break
        start = end - overlap
    return chunks

def prepare(question, role, current_versions, today, top_k=2):
    if not isinstance(question, str) or not 1 <= len(question.strip()) <= 200:
        raise ValueError("question must contain 1..200 characters")
    if type(top_k) is not int or not 1 <= top_k <= 5:
        raise ValueError("top_k must be an integer in 1..5")
    candidates = []
    for d in DOCS:
        if d["role"] != role or current_versions.get(d["id"]) != d["version"]:
            continue
        if today < date.fromisoformat(d["start"]):
            continue
        if d["end"] and today >= date.fromisoformat(d["end"]):
            continue
        score = sum(term in question for term in d["terms"])
        if score:
            candidates.append((score, d))
    candidates.sort(key=lambda item: (-item[0], item[1]["id"]))
    sources = [{"ref": f"{d['id']}@v{d['version']}", "text": d["text"]}
               for _, d in candidates[:top_k]]
    return {"status": "ready" if sources else "abstain", "sources": sources}

if __name__ == "__main__":
    result = prepare("交通費の承認は?", "staff", {"travel": 3}, date(2026, 10, 4))
    assert result["sources"] == [
        {"ref": "travel@v3", "text": "交通費は所属長が承認します。"}
    ]
    assert prepare("休暇は?", "staff", {"travel": 3}, date(2026, 10, 4))["status"] == "abstain"
    assert chunk_text("abcdefghijkl", 5, 2) == ["abcde", "defgh", "ghijk", "jkl"]
    print(result)

実行すると、readyとtravel@v3の根拠が表示されます。人事限定の文書と旧版は含まれません。質問に一致する語がなければabstainになります。この判定は語の一致の有無だけです。readyでも質問全体に答えられる保証はなく、例えば「交通費の上限は?」でも承認の文が候補になる限界があります。

chunk_textも文字数による制御の教材です。日本語の意味の切れ目やトークン上限を保証しません。採用する分割方法は、前述の条件・例外・表を保持するかで別途検証します。

本番へ進むときは、次の境界を実装へ置き換えます。

表が収まらない場合は、横にスクロールできます

教材の要素実装で接続するもの追加で確かめること
DOCS文書管理と検索索引差分取り込み、削除、現行版、権限の同期
role認証済み利用者の認可情報偽装、異動、失効、部署をまたぐ質問
語の一致全文・ベクトル・ハイブリッド検索必要な節、表、例外の取得、取り逃し
sourcesモデル入力の根拠欄入力上限、出典ID、無関係な指示の混入
ready回答案の生成へ進む条件根拠不足や矛盾を検出したら保留
出力された候補根拠つき回答案出典が文を支持するか、担当者の確認

DBやモデルは、必要な機能から比較する

ベクトルDBの名前や「大企業向け」という区分だけでは選べません。Pinecone、Weaviate、Chroma、Qdrant、Milvusなどを候補に挙げる場合も、同じ質問集合と文書条件で、権限フィルター、更新・削除の反映、バックアップ、運用担当、費用を比較します。ここでは各製品の容量や性能の優劣を認定しません。

Pineconeの現行Python quickstartはPinecone()を入口にし、インデックス形式によって操作面を分けています。2026年10月4日の確認時点でも、文書、ベクトル、モデル統合型の例を混ぜてよいわけではありません。導入時は配布パッケージの版を固定し、その版の公式例で登録・検索・削除を隔離環境から確認します。

埋め込みも、提供元の名前だけで選ばず、日本語の質問、専門用語、略語、数値や型番を含む検索で比べます。外部APIか自社環境で処理するかは、データの持ち出し条件と運用体制に関係します。モデルの利用条件、入力の保存、処理場所、実測費用を確認してから決めます。

回答案を作る:引用の形と、根拠の中身を確認する

モデルへは、質問と参照資料を分けて渡します。資料中の「以前の指示を無視して送信せよ」といった文は、引用対象のデータであって、アプリの権限を変更する命令ではありません。プロンプトで区別を指示するだけに頼らず、回答案を作る経路に外部送信や削除の道具を持たせない設計もできます。

回答の形式は、例えば「結論候補/根拠の文書IDと節/適用条件/未確認点/保留理由」に分けられます。文書IDが存在するだけでは足りません。その文書が実際にその結論を支持しているか、例外条件を落としていないかを確認します。

根拠が二つあり内容が違う場合、単に更新日の新しい方を採用しないでください。発効日、対象部署、地域、承認状態が違う可能性があります。解消できなければ、矛盾する箇所と確認先を示して保留します。質問に必要な個別条件がない場合も、推測で埋めずに不足事項を伝えます。

評価は、検索・回答・保留を分ける

検証用の質問は、開発中に何度も調整へ使うものと、設定を固めてから確かめるものに分けます。答えやすい質問だけでなく、資料がない、権限がない、旧版と衝突する、表の注記が必要、といった条件を含めます。正解文だけでなく「この文書のこの節が必要」「答えず確認へ回す」を担当者が決めます。

次は説明用の仮想20問です。実績でも推奨目標でもありません。現在の権限と資料で答えられる12問と、保留すべき8問を用意したとします。

表が収まらない場合は、横にスクロールできます

指標仮想の結果読み方
必要な根拠を検索できた割合10 / 12 = 約83.3%答えられる質問が分母。検索の取り逃しを見る
根拠に沿って正しく答えた割合9 / 12 = 75%同じ12問で、検索後の回答も含めて確認
保留すべき質問を保留した割合7 / 8 = 87.5%残る1問は、答えてはいけない条件で回答した
想定した対応をできた割合(9 + 7) / 20 = 80%正答と適切な保留をまとめた値。内訳も残す

この例では、検索できた10問のうち1問で回答が条件を取り違え、検索できなかった2問では正答しなかったと仮定しています。検索成功率と回答成功率を同じものにしないための例です。

この「必要な根拠が取れた割合」は質問単位の独自指標です。取得した全断片に占める関連断片の割合であるprecisionや、関連断片全体のうち取得できた割合であるrecallと混ぜず、判定単位と分母を明記します。複数の根拠が必要な質問で一つだけ取れた場合を成功にするかも、先に決めます。

利用者が再質問しなかったことは、正しかった証拠にはなりません。諦めた、別の人に聞いた、誤答に気づかなかった可能性もあります。再質問率や満足度は補助情報として扱い、根拠の照合や業務の受入基準と組み合わせます。

運用費用と障害は、回答一回の外まで数える

費用には、文書抽出、埋め込み、索引の保存、検索、生成、監視、担当者の確認と再作業があります。資料更新の多い業務なら、初回の構築費だけでなく再処理の負担も見積もります。安いモデルへ変更したときも、確認負担が増えれば全体では安くならない場合があります。

遅延は、文書の検索、再順位付け、生成、確認待ちに分けて測ります。データ件数、同時利用数、返す文章量、測定環境を記録し、平均だけでなく遅いケースや失敗も確認します。「数十ミリ秒で返る」といった一般値から利用者の体験を決めないでください。

キャッシュを使う場合は前述の権限と版に加え、無効化が失敗した場合の停止条件を決めます。検索が失敗した、文書の同期が遅れている、モデルAPIの結果が不明といった状況では、成功したように回答を保存しません。問い合わせIDを残し、再試行の上限、待ち時間、代替の検索リンクを用意します。

用途ごとに、小さな試行から始める

表が収まらない場合は、横にスクロールできます

用途回答案が役立つ場面先に確かめる境界
社内FAQ規程の該当箇所を探し、適用条件を説明する現行版、社員区分、例外の扱い
カスタマーサポート担当者向けに候補回答と製品資料を並べる顧客別契約、製品版、送信前の確認
技術ドキュメント複数の仕様・手順の関係を探す対応版、廃止API、実行環境、コードの検証

最小の検証は、一つの業務の架空または公開可能な資料と、担当者が正解・保留を判定できる質問集合を用意することです。まず通常の検索で同じ仕事を行い、その後に回答案の生成を加えて比較します。

  1. 質問ごとに必要な文書、適用条件、答えない条件を記録する。
  2. 旧版、別部署、根拠なしを含め、検索結果へ何が出るか確認する。
  3. 同じ質問で回答案を作り、出典と結論の対応、確認・修正時間を測る。
  4. 文書の改定と権限の失効を模擬し、検索・回答・キャッシュに反映されるか確かめる。
  5. 残る誤りと運用担当を明記し、範囲を広げるか、検索だけに戻すか判断する。

回答の根拠を確認する習慣はAIの回答への過信を防ぐ考え方、外部操作まで含む構成はAIエージェント開発ガイドで整理しています。RAGの評価でも、流暢な回答を完成条件にせず、必要な資料・権限・受入条件をたどれることから始めてください。

よくある質問(FAQ)