🙌

RAGを構築してもうまくいかない時にまず調べること:それはチャンク戦略だ!

に公開

こんにちは。D2Cのデータサイエンティスト(AIエンジニア)の須田です。

「どのテーブルを使えばいいかわからない…」
社内データ活用の現場でよく聞くそんな声に応えるため、
自然言語で質問するだけで、社内データベースから必要な情報を探し、SQLまで生成してくれるAIツール「Kibidango」を開発・リリースしました。

機能の詳細については以下の記事をご覧ください👇
▶︎ 社内データ活用を加速する“Kibidango”の新機能!テーブルレコメンド×SQL生成で検索体験を革新

本記事ではRAG(Retrieval Augmented Generation)を活用する中で得た学びをお伝えします。


Kibidangoの課題と目標

初期のKibidangoは「テーブルを選んで自然言語で質問し、SQLを生成する」形式でした。
しかし実際に運用してみると「そもそもどのテーブルを選べば良いかわからない」「詳しい人に質問が集中してしまう」といった声があがってきました。

社内のデータ構造は複雑で、新しく入った人がキャッチアップするにも時間がかかります。
そこで「自然言語で、目的に合ったテーブルをレコメンドしてくれる機能があれば、業務の効率化に繋がるはず」と考え、開発に踏み切りました。


Kibidangoのアーキテクチャ

ここで一度、Kibidangoの構成を簡単に図にまとめてみました。

Kibidangoアーキテクチャ図

この構成では、ユーザーがUI(たとえばStreamlit)から自然言語で質問を入力すると、そのリクエストはAmazon ECS上のアプリを通じてClaude 3 Sonnetへ送られます。
Claudeは、OpenSearch上にインデックスされたテーブル情報をベースにレコメンド処理を行い、最終的にユーザーへ「このテーブルが良さそうです」と返します。

図の青い部分が今回新たに設計・追加された領域で、社内のS3バケットやOpenSearchと連携している点がポイントです。


試したこと

まずは既存のDDL(データ定義)を活用してできることを試しました。

  • DDLに簡単なテーブル要約を追加
  • タグ情報(用途やドメイン)を付加
  • データレイクのカタログの情報を整形して取り込み
  • LLMプロンプトを工夫して回答精度を上げる工夫

ただし、これらだけでは思うような結果は得られませんでした。
つまり「データが多ければ良い」という単純な話ではなかったのです。


ハルシネーションには2つ種類がある

1. LLM自体の問題

「ナレッジベースからの検索はうまくいっているが、LLMが適切な回答を生成できていない」というケースです。
この場合は、RAGの「生成」部分に問題がある可能性があります。

考えられる要因

  • LLMの精度が不十分
    • モデルがそもそも対象ドメインの知識に弱い、複雑な構文理解が苦手など
  • プロンプトテンプレートが最適化されていない
    • 情報がうまく渡せていない、出力形式の指示が曖昧、意図が伝わりにくい など
  • 検索で得たチャンクが多すぎてLLMが混乱している
    • 入力トークンが多くなりすぎて、文脈理解が難しくなっている可能性も

2. LLMにくわせる前、データベースから取得できていない問題

これは、RAGの「検索」部分でうまく情報が取り出せていないケースです。
つまり、ユーザーの質問に対して適切な情報がナレッジベースから引っ張れていない状態です。
原因の一つとしてよくあるのが、「チャンク戦略がうまく設計されていない」という問題です。

チャンクとは?

RAG(Retrieval Augmented Generation)では、元となるテキストデータをそのまま一括で使うのではなく、小さな意味のまとまり=「チャンク(chunk)」に分割して、ベクトル検索用のインデックスとして保存します。

このチャンクには以下のような目的があります:

  • 検索の精度を高める
    → 小さい単位で意味が通るようにすることで、似た文脈がマッチしやすくなる

  • 回答生成時の文脈を維持する
    → 必要な情報が文ごとに残っていれば、ハルシネーションを減らせる

  • しかし、このチャンクの切り方が不適切だと以下のような問題が起きます:

    • 文の途中で切れてしまい意味が伝わらない
    • テーブル名と説明が別チャンクに入り、結びつかない
    • カラム情報や用途がばらばらになり、検索対象にならない

チャンク戦略の例

  • テーブル単位でチャンク化する
  • カラム単位でチャンク化する
  • 説明文とテーブル名を1セットにしてチャンク化する
    など、目的やデータ構造に応じたチャンクの工夫が、RAGの精度に直結します。

今回採用しているAWS Bedrockでは以下のチャンク戦略がデフォルトで設定されていました。

デフォルトの300トークン単位で切ると文脈が破壊される
テーブルごと/カラムごと/1行ごと に分けるなど、工夫が必要

チャンク関連の話はこちらのブログがとても参考になりました。

このように、「ハルシネーション」の原因が検索段階にある場合には、まずチャンクの粒度や構造を見直すのが効果的です。LLMが悪いのではなく、「そもそも必要な情報にたどり着けていない」ことがよくあるため、まずは「生成が悪いのか、検索が悪いのか?」を切り分けることが何よりも重要です。
そのためには以下のようなアプローチを取ることができます。(AWSのKnowladge baseを利用していることを前提としています)


チャンク戦略の確認方法(RAGの構造を調べる)

1. aws bedrock-agent-runtime retrieve コマンドでナレッジベースの検索結果を確認

AWSのコンソールからCloudShellを開き、以下のコマンドを実行します。

aws bedrock-agent-runtime retrieve   --knowledge-base-id <ナレッジベースのID>   --retrieval-query '{"text": "デモグラデータを集計したい時はどのテーブルを使えば良い?"}'   --retrieval-configuration '{"vectorSearchConfiguration": {"numberOfResults": 3}}'

次のようなアウトプットが出てくるはずです。
scoreから--retrieval-query '{"text": "デモグラデータを集計したい時はどのテーブルを使えば良い?"}'との検索一致度がわかります。

{
    "retrievalResults": [
        {
            "content": {
                "text": "検索結果の内容",
                "type": "TEXT"
            },
            "location": {
                "s3Location": {
                    "uri": "xxx"
                },
                "type": "xx"
            },
            "metadata": {
                "xxx": "xxx"
            },
            "score": 0.xxx
        }

2. OpenSearchの中身を確認する

OpenSearchを開き、[Serverless]ボタン→[Dashboard] ボタン → 指定のダッシュボードをクリック→左上サイドバーから[Dev Tools]ボタンをクリック。(自分が作成したダッシュボードしか表示されないことがあるため権限に注意)


上記画面になったら次のコマンドを入力し実行します。

GET bedrock-knowledge-base-default-index/_search
{
  "_source": ["AMAZON_BEDROCK_TEXT"],
  "query": { "match_all": {} }
}

以下のようなアウトプットが出てくるはずです。(ベクトルDBに入れている内容によってアウトプットの中身も変わります)

### エントリ 1 ###
{   "xxx": "xxx",   "xxx": "xxx",   "xxx": [     "xxx",     "AdMaster",     "xxx",     "xxx",     "xx",     "xxx"]}

チャンク戦略について確認した後に考えられるアプローチ

チャンクの切り方や内容を確認した結果、「必要な情報がきちんと含まれていない」あるいは「含まれていても上位に出てこない」などの課題が見つかった場合、次にとるべきアプローチはいくつかあります。

1. チャンクの再構成(切り方の見直し)

  • カラム単位では細かすぎる/文脈が失われている → テーブル単位や意味のまとまり単位で再構成
  • 逆にテーブル単位では大きすぎる/検索精度が低下している → セマンティックチャンクや、説明文・用途文単位に分割
  • チャンク内に含める情報の順序・フォーマットを揃える → LLMにとって読みやすい構造に変える(例:見出し付き、ラベル統一)

2. メタ情報の拡充

  • descriptionやcommentが短い/抽象的すぎる → 用途や具体的な利用例、業務での使われ方を補足
  • タグやドメイン、部門情報などを付与 → 質問の意図とのマッチング精度を高める
  • ナレッジベースの内容にFAQ・サンプル質問と回答を追加 → LLMが意図を汲み取りやすくなる

LLMに問題があると特定された場合のアプローチ

RAGの構成上、検索結果(チャンク)は適切に取得できているのに、最終的な出力がおかしい/ハルシネーションが多いというケースでは、LLM自体の課題が疑われます。以下のような改善策を検討するのが効果的です。

1. プロンプトテンプレートの見直し

  • 出力形式が曖昧/自由すぎる
     → 表形式や箇条書きなど、出力構造を明確に指定
  • 条件分岐が不足している
     → 「該当するテーブルがなければこのように答えてください」など、想定外出力を防ぐ設計を強化
  • 説明文が長すぎ/複雑すぎ
     → prompt内のシステムメッセージや指示を簡潔にして、意図が伝わりやすい内容に改善

2. モデルの変更・アップグレード

  • Claude 3.5 → Claude 3.7 など、より最新・高性能なモデルを利用することで精度が大きく改善するケースあり
  • タスクごとに異なるモデルを使い分ける
     → 例:検索タイプの判定に軽量モデル、最終回答生成に高精度モデルを使う構成

Kibidangoで実際に取り組んだ工夫

1. 答えてほしい内容について整理をすること

チームで話し合った結果、まずはどんな質問に答えられたらよいか?を明確にするために考えれる質問の分類と優先順位づけ、想定質問を考えることを行いました。

▼ 実際に作った表

質問のタイプ 特徴 解決アプローチ
テーブルの詳細を知る スキーマ情報が明示的に含まれている DDLの整備
テーブルの用途を知る 説明文が整備されていればヒットしやすい descriptionの強化
関連するテーブルを知る JOIN可能かどうか判断できれば対応可能 リネージ情報の追加・補完
データの取得方法を知る サンプルクエリがあれば提案しやすい クエリ例をナレッジベースに追加
ID変換方法を知る 明示的ルールがないと難しい 対応表の整備・プロンプト制御で補完

→解決アプローチ的にDDLの整備とdescriptionの強化が一番手をつけやすそうということからテーブルの詳細を知ったり、用途を知る質問に答えられるようにしようとスコープを絞りました。
テーブルの詳細については既存の機能で聞ける内容でもあったため、テーブル用途を知ることをメインとして以下の想定質問を考えました。

  • 2024年12月中にxxxをした人を分析できるテーブルを教えて
  • xxxのxxxユーザーを抽出したいです。

この質問は実際にステークホルダーからどういう質問に答えてくれたら嬉しいか?を伺い、決定しました。

2. 想定質問に合わせたデータを用意する

社内のステークホルダーにこういう質問ができる機能を作りたい。と相談したところ
用途ごとに整備されたテーブル情報を社内の熟知者から提供いただくことになりました。
そのテーブル情報をナレッジベースに投入したところ、レコメンドの精度が劇的に改善しました。
もしいただいていなかったら、自分達で作成していたと思います。本当にありがとうございます!

まとめ:RAG活用のコツとKibidangoで得た学び

Kibidangoの開発を通じて、RAG(Retrieval Augmented Generation)を本番運用レベルまで持っていくには「設計・検証・整備」の地道な積み重ねが不可欠だと実感しました。

特に、以下の3つの視点はとても重要です:

1. 「検索」と「生成」の問題を切り分けて改善

  • aws bedrock-agent-runtime retrieveやOpenSearchの中身を確認し、取得できていないのか、生成が間違っているのかを切り分ける
  • LLMのプロンプト設計やモデル選定も合わせて検証する

2. “どの質問に答えられるようにしたいか?”の明確化

  • 質問のタイプを整理し、AIに得意なパターンから対応していく
  • スコープを広げすぎず、まずは用途に絞ってデータ整備を進める

3. 必要に応じてチャンク戦略を“データ構造に合わせて設計する”

  • ただ分割するのではなく、文脈がつながるように構造を考慮
  • テーブル・カラム単位か、用途単位かなど、最適な粒度を見つける

本記事が、RAGを活用した社内システムの構築や改善に挑戦する方にとって、少しでも参考になれば嬉しいです。

D2C m-tech

Discussion