renue

ARTICLE

社内ドキュメント検索AIエージェント実装ガイド【2026年版】— Agentic RAG×マルチ環境対応×ファイルパス解決の本番アーキテクチャ

公開日: 2026/4/6

社内ドキュメント検索AIエージェントとは、仕様書・マニュアル・社内Wikiなど散在するドキュメントに対して自然言語で質問し、AIが関連情報を検索・要約して回答するシステムである。2026年現在、従来の「1回検索して1回生成する」RAGから、AIエージェントが検索結果を評価して再検索を繰り返す「Agentic RAG」へと進化している。本記事では、renueの社内ナレッジ検索プロダクトの実装知見をもとに、本番品質の社内ドキュメント検索AIを構築するための設計パターンを解説する。

社内ドキュメント検索AIが本番運用で直面する5つの課題

課題内容
1. ファイルパス解決DBに相対パス、実ファイルは環境ごとに異なる場所
2. 環境差異ローカル/Azure/AWSで異なるストレージ形態
3. 大規模ドキュメント1ファイルが80,000文字を超えるとトークン制限に当たる
4. マルチフォーマットPDF/Word(.doc/.docx)/Excel/画像混在
5. 精度と速度のトレードオフAgentic RAGは精度高いが検索コストが大きい

本番品質に必要な6レイヤー

レイヤー1: Agentic RAGの設計

従来のRAGは「クエリ→ベクトル検索→コンテキストに追加→LLM回答」の1パス構成だった。Agentic RAGは以下のループを回す。

  1. ユーザーの質問を受け取る
  2. 検索クエリを生成(LLM)
  3. ドキュメントを検索(ベクトル検索 or メタデータ検索)
  4. 検索結果を評価(LLM) → 不十分なら再検索
  5. 十分な情報が集まったら回答生成

Agentic RAGのメリット

  • 質問が曖昧でも自動的に検索クエリを最適化
  • 1回の検索で情報が不足しても追加検索する
  • 複数のデータソース(ベクトルDB/メタデータDB/外部API)を組み合わせられる
  • 検索結果の品質評価ができる

レイヤー2: ファイルパス解決の設計

本番運用で最も厄介なのは「DBに保存されているファイルパスと、実ファイルの置き場所が異なる」問題である。これを解決する`PathResolver`パターンを実装する。

PathResolverの設計

class PathResolver:
    def __init__(self):
        self.local_base_path = os.getenv("LOCAL_FILE_BASE_PATH")
        self.azure_base_path = os.getenv("AZURE_FILE_BASE_PATH")
        self.use_azure = os.getenv("USE_AZURE_FILES") == "true"

    # DB保存の相対パスを実ファイルの絶対パスに変換
    def resolve_file_path(self, relative_path):
        base = self.azure_base_path if self.use_azure else self.local_base_path
        return os.path.join(base, relative_path)

環境変数による切替

# ローカル環境(.env.local)
LOCAL_FILE_BASE_PATH=/Users/dev/Box/project_documents
USE_AZURE_FILES=false

# Azure環境(.env.azure)
AZURE_FILE_BASE_PATH=/mnt/azure-files/project
USE_AZURE_FILES=true

同じコードがローカル開発環境とAzure本番環境の両方で動作する。DB内の相対パスは環境非依存で保持される。

レイヤー3: Azure Files / Azure Blob Storageの選択

Azure環境では2つの選択肢がある。それぞれ特性が異なる。

Azure Files(SMB/NFSマウント)

  • App Serviceにファイル共有としてマウント可能
  • 既存のローカルファイル操作コードをそのまま使える
  • 設定: Azure Portal → App Service → 構成 → パスマッピング → 新しいAzure Storageマウント
  • デメリット: 大容量ファイルの読み取りがやや遅い

Azure Blob Storage(API経由)

  • より高速・安価・スケーラブル
  • 接続文字列とコンテナー名で管理
  • アプリケーションコードでBlob APIを呼び出す必要がある
  • 大容量・大量ファイル向け

選択基準

ファイル数が1,000件以下、サイズが100MB以下程度ならAzure Files。それ以上の規模、または大量の読み取りが発生する場合はBlob Storageを選択する。renueの実装では両方に対応できるよう、`PathResolver`を抽象化している。

レイヤー4: マルチフォーマット対応

社内ドキュメントは多様なフォーマットで存在する。それぞれに対応するパーサーが必要。

フォーマット推奨ライブラリ備考
PDFPyMuPDF (pymupdf)表/画像も扱える
Word (.docx)python-docx標準的な.docx
Word (.doc)antiword古い.doc用、別途brew install必要
Excel (.xlsx)openpyxl / pandasセル単位の抽出
画像(OCR必要)Azure Computer Vision / Gemini Vision図面・スキャンPDF
PowerPointpython-pptxスライド単位の抽出

`.doc`対応の罠

古い`.doc`ファイル(Word 97-2003)は`python-docx`で読めない。`antiword`を別途インストールする必要があり、Macなら`brew install antiword`、Linuxなら`apt-get install antiword`が必要。Dockerイメージにも含める必要があるため、Dockerfileに明示的に記載する。

レイヤー5: トークン制限とマルチエージェント分割

1つのドキュメントが80,000文字を超えると、LLMのコンテキスト制限に当たる。これを回避するには、処理を複数のエージェントに分割する。

マルチエージェント分割パターン

  • 検索エージェント: クエリから関連ドキュメントを特定する
  • 要約エージェント: 長いドキュメントをチャンク単位で要約する
  • 統合エージェント: 複数の要約を統合して最終回答を生成する
  • 評価エージェント: 回答の品質をチェックし、不十分なら再検索を指示する

各エージェントは独立した状態管理を持ち、互いにメッセージを受け渡す。OpenAI Agents SDKや Google ADK, LangGraphなどのフレームワークでこのパターンを実装できる。

レイヤー6: メタデータDBの設計

ベクトル検索だけでは「このドキュメントはどのフォルダにあるか」「いつ更新されたか」などの属性情報を活かせない。メタデータDB(PostgreSQL等)と組み合わせるハイブリッド検索が効果的である。

推奨スキーマ

CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    file_path TEXT NOT NULL,  -- DB内相対パス
    file_name TEXT NOT NULL,
    file_type VARCHAR(20),  -- pdf/doc/docx/xlsx
    folder_path TEXT,  -- 部署別/プロジェクト別の階層
    document_type VARCHAR(50),  -- 仕様書/マニュアル/報告書/議事録
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    metadata JSONB,  -- 自由な追加属性
    embedding VECTOR(1536)  -- pgvector拡張
);

ハイブリッド検索のクエリ例

  • 「資材部の仕様書で2024年以降の文書」→ folder_path + document_type + updated_at で絞り込み
  • 「〇〇工事に関する書類」→ ベクトル検索で関連度順
  • 「先月更新された仕様書」→ updated_at + document_type で絞り込み

PostgreSQLなら`pgvector`拡張でベクトル検索を同じDBで実装できるため、システム構成がシンプルになる。

LLMプロバイダーの切替対応

本番運用では、LLMプロバイダーを固定せず切替可能にしておく。OpenAI、Anthropic Claude、Google Gemini、Azure OpenAIなどを環境変数で切り替えられる設計が望ましい。

# 環境変数
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=...
LLM_PROVIDER=anthropic  # openai / anthropic / azure

プロバイダー切替をコード1行で済ませるには、抽象化レイヤー(`LLMClient`)を実装する。

ドキュメント更新検知の仕組み

ドキュメントが更新された際に、ベクトルDBのインデックスを再構築する必要がある。以下のパターンが一般的。

定期バッチ方式

夜間バッチで全ドキュメントをスキャンし、`updated_at`が変わったものだけを再インデックス化する。シンプルだが更新反映に時間がかかる。

ファイル監視方式

ファイルシステムの変更イベントを監視し、リアルタイムで再インデックス化する。Linuxなら`inotify`、Azure Filesなら`Event Grid`を使う。

Webhook方式

ドキュメント管理システム(SharePoint、Box等)のWebhookを利用する。最もリアルタイム性が高い。

Streamlitでの実装上の注意点

社内向けの簡易UIはStreamlitで構築するケースが多い。ただし以下の制約に注意が必要。

ファイル名の重複禁止

Streamlitはファイル名からURLパスを生成するため、同じファイル名は使えない。`34_問い合わせ対応_マルチエージェント版.py`のように番号プレフィックスで一意化する。

Expanderのネスト不可

`st.expander`の中に`st.expander`を入れることはできない。代わりにマークダウンヘッダーや`st.divider()`を使う。

セッション状態の管理

マルチエージェントの状態を`st.session_state`で管理する。エージェント間のメッセージ履歴もセッション状態に保持することで、再読み込み時の状態維持ができる。

renueの実装事例 — 社内ナレッジ検索の本番運用

renueは「Self-DX First」の方針のもと、自社・クライアント向けに社内ドキュメント検索AIの実装知見を蓄積している。社内12業務を553のAIツールで自動化済み(2026年1月時点)であり、ドキュメント検索AIもその一部である(全て公開情報)。

公開されている技術的特徴

  • バックエンド: Python + FastAPI or Streamlit
  • データベース: PostgreSQL + pgvector
  • LLMプロバイダー: OpenAI / Anthropic Claude 切替対応
  • ファイルストレージ: ローカル / Azure Files / Azure Blob Storage 切替対応
  • マルチエージェント: 検索・要約・統合・評価の分業
  • フォーマット: PDF / Word (.doc/.docx) / Excel 対応
  • デプロイ: Azure App Service + Docker

導入時のよくある失敗パターン

  • ファイルパスをハードコード: 本番環境で動かない
  • 単一の長大プロンプトで実装: トークン制限で失敗
  • ベクトル検索のみに依存: メタデータ検索と組み合わせないと精度が出ない
  • .doc対応を忘れる: 古い仕様書が読めない
  • LLMプロバイダーを固定: API障害時に動かなくなる
  • 更新検知の仕組みがない: 古い情報を返し続ける
  • エラーの客観的事実を記録しない: 再現・デバッグができない

業界別の活用パターン

業界主な活用ドキュメント
製造業設計仕様書、工程手順書、品質管理マニュアル
金融商品説明書、規程類、稟議書、コンプライアンス資料
法務契約書、判例、法令、規則
医療診療プロトコル、薬剤情報、症例報告
建設設計図、施工要領、安全管理規程
電力・インフラ運用マニュアル、保守手順、仕様書(購入/工事/委託)

よくある質問

Agentic RAGと従来のRAGの違いは?

従来のRAGは「1回検索して1回生成」の固定フロー。Agentic RAGはAIエージェントが検索結果を評価し、不十分なら別クエリで再検索する。精度は上がるが、LLM呼び出し回数が増えるためコストも上がる。

PostgreSQLとVector DB(Pinecone等)、どちらを選ぶべき?

文書数が100万件以下ならPostgreSQL+pgvectorで十分。構成がシンプルで運用が楽。1,000万件を超える規模、または極めて低レイテンシが必要な場合は専用Vector DBを検討する。

日本語PDFの抽出精度は?

PyMuPDFで概ね90%以上の精度で抽出できる。ただし、スキャンPDFや図表が多いPDFはOCRが必要になる。Azure Computer VisionまたはGemini Visionを使うと、高精度な日本語OCRが可能。

ローカルとAzureの切替はどうやる?

環境変数`USE_AZURE_FILES`と`PathResolver`クラスで切替可能にする。コードレベルでは`if`分岐を最小化し、環境変数読み込みだけで自動切替できる設計にする。

社員が使わない問題はどう解決する?

「検索しても出てこない」体験が1〜2回続くと使われなくなる。導入初期は検索精度を徹底的にチューニングし、FAQやよくある検索クエリを別途準備しておく。Slack等の既存ワークフローに統合すると利用率が上がる。