SQL検索とRAGを組み合わせた業務データ活用PoC:8週間で検証した設計と評価ポイント
はじめに
社内データを生成AIで活用する場合、PDFやマニュアルをベクトル検索するだけでは対応できないケースがあります。
例えば、次のような質問です。
今月の実績と計画の差異を示し、過去の報告資料を参考に原因を説明してください。
この質問に答えるには、2種類の処理が必要です。
- 計画値と実績値をデータベースから正確に取得する
- 過去の報告資料から関連する説明や背景を検索する
数値をベクトル検索だけで扱うと、正確な集計や条件指定が難しくなります。一方、SQLだけでは、文書に記載された背景や説明を取得できません。
そこで、BAP Solution Japanが支援した日本企業向けPoCでは、構造化データにはSQL検索、社内文書にはRAG検索を使用し、両方の結果を統合して回答を生成する構成を採用しました。
本記事では、8週間のPoCで検証したアーキテクチャ、処理フロー、評価ポイントを、公開可能な範囲で紹介します。
本記事では顧客情報と業務データを匿名化し、システム構成を一部簡略化しています。
対象となった業務課題
対象は、企業の計数管理に関する業務です。
従来は、担当者が複数のExcelや社内資料から数値を収集し、形式を整えた上で集計していました。
集計後も、次の作業が必要でした。
- 実績と計画の差異を確認する
- 過去データから変化の原因を調査する
- 関連する報告資料を探す
- 改善案を検討する
- 経営報告資料の下書きを作成する
データ収集と資料検索に時間がかかるため、担当者が分析や改善策の検討に使える時間が限られていました。
今回のPoCでは、過去の数値と社内資料を生成AIが参照し、差異分析と説明文の作成を支援できるか検証しました。
PoCの目標
技術面では、次の項目を確認しました。
- 質問に応じてSQL検索とRAG検索を使い分けられるか
- 過去の数値を正しく取得できるか
- 質問に関連する文書を検索できるか
- SQLとRAGの結果を同じコンテキストに統合できるか
- 回答の根拠を追跡できるか
業務面では、AIが生成した説明に合理性があるか、経営報告資料の下書きとして利用できるかを評価しました。
生成結果をそのまま経営判断に使用するのではなく、担当者が根拠を確認し、必要に応じて修正する運用を前提としています。
使用した技術
| 領域 | 技術 |
|---|---|
| AI基盤 | Amazon Bedrock |
| LLM | Claude Sonnet 4.5 |
| データベース | PostgreSQL |
| ベクトル検索 | pgvector |
| バックエンド | Python、FastAPI、Uvicorn、Gunicorn |
| フロントエンド | React、TypeScript |
| 構造化データ | Excelから取り込んだ計数データ |
| 非構造化データ | Office文書などの社内資料 |
LLMやデータベースは、PoCの要件と顧客環境に基づいて選定しました。
別のプロジェクトでは、データ量、セキュリティ条件、既存クラウド、応答速度、運用コストによって適切な構成が変わります。
システム構成
以下の位置に、SQL検索とRAG検索の統合を示す図を挿入します。
[構成図を挿入]
Structured Data ── SQL Search ──┐
├── Context Assembly ── LLM ── Response
Internal Documents ─ RAG Search ┘
システムは、大きく4つの領域に分けました。
- データソース
- データ取り込み
- SQL・RAGによる情報取得
- コンテキスト統合と回答生成
データソース
構造化データ
計画、実績、差異など、正確な値や集計が必要なデータはPostgreSQLで管理しました。
元データにはExcelが含まれますが、質問ごとにExcelファイルを直接読み込むのではなく、形式を検証した上でデータベースへ登録します。
これにより、期間、部門、項目などの条件を指定した検索や集計をSQLで実行できます。
ナレッジデータ
背景説明、業務ルール、過去の報告内容などは、Office文書を中心とした非構造化データとして扱いました。
文書は解析後、検索に適した単位へ分割し、Embeddingとメタデータをpgvectorへ保存しました。
メタデータには、必要に応じて次の情報を保持します。
- 文書名
- 文書の種類
- 対象期間
- 部門
- 更新日時
- 参照権限
- 元文書内の位置
回答に参照元を表示するには、ベクトルだけでなく、元文書へ戻れる情報を保持する必要があります。
データ取り込み
構造化データの取り込み
Excelなどの構造化データは、次の流れで処理しました。
- ファイルを読み込む
- 必須項目とデータ型を検証する
- 不正なレコードを検出する
- PostgreSQLへ登録する
- 登録結果をログへ記録する
PoCであっても、列の欠損、日付形式の違い、数値と文字列の混在などを考慮する必要があります。
生成AI以前に、データを安全に登録できることが重要です。
文書データの取り込み
文書データは、次の流れで処理しました。
- 文書からテキストを抽出する
- 見出しや段落を考慮して分割する
- メタデータを付与する
- Embeddingを生成する
- pgvectorへ保存する
チャンクを細かくしすぎると前後関係が失われます。一方、大きすぎると不要な情報までLLMへ渡されます。
そのため、文字数だけで機械的に分割せず、文書構造と実際の質問を確認しながら調整しました。
Intent Router
ユーザーの質問を受け取ると、Intent Routerが必要な処理を判定します。
今回の構成では、主に次のパターンを想定しました。
| 質問の種類 | 使用する処理 |
|---|---|
| 数値の取得・集計 | SQL検索 |
| 規程・説明・過去資料の検索 | RAG検索 |
| 数値と説明の両方が必要 | SQL検索+RAG検索 |
| 対象外または根拠不足 | 回答を制限 |
概念的には、次のような処理です。
def handle_question(question: str):
intent = route_intent(question)
if intent == "structured_data":
sql_result = execute_sql(question)
return generate_answer(
question=question,
structured_context=sql_result
)
if intent == "knowledge_search":
documents = retrieve_documents(question)
return generate_answer(
question=question,
document_context=documents
)
if intent == "hybrid":
sql_result = execute_sql(question)
documents = retrieve_documents(question)
return generate_answer(
question=question,
structured_context=sql_result,
document_context=documents
)
return create_out_of_scope_response()
このコードは実際のプロジェクトコードではなく、処理の考え方を示す簡略化した例です。
SQL検索
売上、計画、実績などの数値に関する質問では、SQL ToolがPostgreSQLから必要なデータを取得します。
例えば、次のような質問です。
2026年4月の実績と計画の差異を部門別に表示してください。
この場合、文書をベクトル検索するよりも、対象期間や部門を条件にSQLを実行する方が適しています。
ただし、Text-to-SQLを利用する場合は、LLMが生成したSQLを無条件で実行してはいけません。
最低限、次の対策が必要です。
- 参照専用のDBユーザーを使用する
- 実行可能なSQLをSELECTに限定する
- 対象スキーマとテーブルを制限する
- タイムアウトと取得件数の上限を設ける
- 実行前にSQLを検証する
- 実行したSQLと結果を記録する
- 個人情報や機密列へのアクセスを制御する
PoCでも、本番導入を想定した安全性を確認しておくと、後の設計変更を減らせます。
RAG検索
過去の説明資料や業務ルールを参照する質問では、RAG Toolが関連文書を取得します。
基本的な処理は次のとおりです。
- ユーザーの質問をEmbeddingへ変換する
- pgvectorで類似文書を検索する
- 必要に応じてメタデータで絞り込む
- 上位のチャンクを取得する
- 出典情報とともにLLMへ渡す
単純なベクトル類似度だけで期待した文書を取得できない場合は、キーワード検索との併用、質問の書き換え、リランキングなどを検討します。
検索品質を確認するときは、最終回答だけでなく、取得したチャンクも確認します。
SQLとRAGの結果を統合する
今回のPoCで重要だったのは、SQLとRAGを別々に動かすことではなく、両方の結果を1つの回答へ統合することでした。
例えば、次の質問を考えます。
計画と実績の差異を示し、過去の報告資料を参考に原因を説明してください。
処理フローは次のようになります。
- PostgreSQLから計画値と実績値を取得する
- 差異を計算する
- 対象期間や項目に関連する過去資料を検索する
- SQL結果と文書検索結果をコンテキストへまとめる
- Claude Sonnet 4.5へ渡す
- 数値、説明、参照元を含む回答を生成する
プロンプトでは、構造化データと文書を明確に分離して渡します。
You are an assistant that supports business performance analysis.
Rules:
- Use the numerical values only from STRUCTURED DATA.
- Use DOCUMENT CONTEXT only for explanations and background.
- Do not create missing numbers.
- If evidence is insufficient, state that the cause cannot be determined.
- Cite the source document used in the explanation.
[STRUCTURED DATA]
{sql_result}
[DOCUMENT CONTEXT]
{retrieved_documents}
[QUESTION]
{user_question}
数値と文書の役割を明示することで、文書内の古い数値を現在値として使用するなどの混同を減らせます。
8週間の進め方
今回のPoCは、合計8週間で実施しました。
前半:要件とデータの理解
最初に、対象業務、データ構造、質問例、期待する回答を確認しました。
特に時間をかけたのは、次の点です。
- 各データ項目の意味
- Excelとデータベースの対応関係
- 実際の担当者が使用する質問
- 説明に必要な文書
- 人が確認すべき出力
中盤:機能開発とフィードバック
SQL検索、RAG検索、回答生成を機能単位で開発しました。
完成後にまとめて確認するのではなく、開発途中から実データでテストし、フィードバックを反映しました。
後半:改善と引き渡し
後半では、回答方法、検索条件、プロンプト、エラー処理を調整しました。
最後に、PoC環境と必要なドキュメントを整備し、計画したスケジュール内で成果物を引き渡しました。
評価方法
PoCでは、「AIが回答したか」だけでなく、検索と回答生成を分けて評価しました。
Retrievalの評価
- 正しい数値を取得できたか
- 質問に関連する文書を取得できたか
- 必要な文書が上位に含まれているか
- 古い文書や対象外文書を取得していないか
- ユーザーの権限に合ったデータだけを取得しているか
Generationの評価
- SQL結果の数値を正しく使用しているか
- 文書にない原因を追加していないか
- 説明内容に業務上の合理性があるか
- 根拠となる文書を示しているか
- 情報不足の場合に回答を控えられるか
- 担当者が修正しやすい形式になっているか
回答が間違っている場合は、次のように原因を分類しました。
| エラー | 主な確認箇所 |
|---|---|
| 必要な文書を取得できない | Chunking、Embedding、検索条件 |
| 正しい文書を取得したが回答が誤る | Prompt、LLM、コンテキスト構成 |
| 数値が誤っている | SQL生成、計算、データ型 |
| 古い情報を使用する | メタデータ、更新処理、検索フィルター |
| 根拠のない説明を追加する | Grounding指示、回答制御 |
| 権限外の情報を取得する | 認証、検索フィルター、DB権限 |
この切り分けを行わないと、すべての問題をプロンプト調整だけで解決しようとしてしまいます。
PoCで得られた結果
確認済みの結果は次のとおりです。
- 8週間のPoCを計画どおりに完了
- 構造化データと社内文書を統合
- SQL検索とRAG検索を組み合わせた回答基盤を構築
- 回答の参照元を追跡できる構成を実装
- 経営報告資料の下書きを想定した業務検証を実施
- 顧客から肯定的なフィードバックを獲得
- PoC環境と関連ドキュメントを引き渡し
本記事では、確認されていない精度や工数削減率を記載していません。
PoCで分かったこと
1. 数値データを無理にベクトル検索へ寄せない
合計、差分、期間指定などが必要なデータは、SQLで取得する方が正確です。
RAGは万能なデータアクセス方式ではありません。データの性質に応じて検索手段を分ける必要があります。
2. 最終回答だけを評価しない
回答が正しくても、偶然正しい場合があります。
どのSQLを実行し、どの文書を取得し、どの情報を根拠に回答したかを確認できる設計が必要です。
3. 評価用の質問を先に作る
代表的な質問と期待回答がない状態では、改善の基準が定まりません。
開発開始前に、実際の利用者から質問例を収集しておくことが重要です。
4. Human in the Loopを前提にする
今回の用途では、生成結果を最終的な経営判断として使用せず、報告資料の下書きとして利用する設計にしました。
誤回答の影響が大きい業務では、人による確認と承認を業務フローへ組み込みます。
5. PoCでも運用を考える
本番環境では、データ更新、権限管理、ログ、コスト監視、障害対応が必要です。
PoCの段階から本番化に必要な項目を整理しておくと、検証後の作り直しを減らせます。
本番化で追加検討する項目
今回のようなシステムを本番化する場合は、少なくとも次の項目を検討します。
- IDプロバイダーとの認証連携
- ユーザー・部署単位のアクセス制御
- SQL実行権限の制限
- 文書の追加・更新・削除の反映
- プロンプトと回答のログ管理
- 個人情報・機密情報のマスキング
- 回答品質の継続評価
- モデル変更時の回帰テスト
- トークンとインフラ費用の監視
- 障害検知と復旧手順
- 監査ログ
- データ保持期間
PoCで高い回答品質が得られても、これらがなければ企業の業務システムとして継続運用することは難しくなります。
まとめ
今回のPoCでは、Excelなどの構造化データをSQLで検索し、社内文書をRAGで検索する構成を採用しました。
主なポイントは次のとおりです。
- データの種類に応じてSQLとRAGを使い分ける
- Intent Routerで質問を適切な処理へ振り分ける
- SQLとRAGの結果を共通コンテキストへ統合する
- RetrievalとGenerationを分けて評価する
- 回答だけでなく、SQLと参照文書を追跡できるようにする
- 重要な業務では人による確認を前提にする
RAGを導入する場合、最初から大規模なシステムを構築する必要はありません。
対象業務、データ、質問を限定し、技術的な実現可能性と業務上の効果をPoCで確認する方法が現実的です。
BAP Solution Japanについて
BAP Solution Japanは、日本企業向けにAI・業務システム・クラウド・オフショア開発を提供しています。
生成AI領域では、RAG、AIエージェント、文書処理、既存システムへのLLM組み込みなどを対象に、ユースケースの整理、PoC、本番開発、運用改善を支援しています。
開発プロジェクトでは、日本法人のPM・BrSEが顧客との要件整理と日本語コミュニケーションを担当し、ベトナムの開発拠点に在籍するAI、バックエンド、フロントエンド、インフラ、QAの各エンジニアが実装を担当します。
今回紹介したPoCのように、社内文書を検索するRAGだけでなく、Excelやデータベースなどの構造化データ、既存業務システムを組み合わせたAI活用にも取り組んでいます。
BAPのAI開発・RAG構築に関する情報は、公式サイトでも紹介しています。
参考資料
- Design and develop a RAG solution - Microsoft Learn
- Amazon Novaを使用したRAGシステムの構築 - AWS
- pgvector - GitHub
本記事は、BAP Solution Japanが支援した日本企業向けPoCについて、公開可能な技術情報を基にまとめたものです。
