ブログに戻る
コラム

RAGとは?検索して渡す仕組みと、実装に必要な5つの部品

FastMetal

RAG(Retrieval-Augmented Generation/検索拡張生成)とは、質問に答える直前に関連する資料を検索して、それをプロンプトに入れてからモデルに答えさせる仕組みです。

ポイントは、モデルに何かを覚えさせるわけではないという点です。モデルは毎回まっさらな状態で、渡された資料を読んで答えます。だから資料を差し替えれば答えも変わり、モデルを再学習する必要はありません。

なぜ必要か

LLMは学習した範囲のことしか知りません。具体的には次の3つが問題になります。

  • 社内のデータを知らない — 自社の仕様書、議事録、問い合わせ履歴は学習データに入っていません
  • 最新の情報を知らない — 学習が終わった後の出来事は答えられません
  • 知らないことを、知らないと言わないハルシネーションが起きます

RAGはこの3つを同時に解きます。手元の資料を渡すので社内データに答えられ、資料を更新すれば最新になり、「資料に書いてあることだけ答えて」と指示できるので作り話が減ります。

ファインチューニングとの違い

よく比較されますが、目的が違います。

RAGファインチューニング
何を変えるか渡す資料モデルの重み
向くもの知識・事実を与える口調・形式・振る舞いを教える
更新資料を差し替えるだけ再学習が必要
出典の提示できるできない

「うちのデータに答えさせたい」の答えはほぼRAGです。 ファインチューニングは「常に敬語のJSONで返させたい」のような、振る舞いの型を教えたいときのものです。

5つの部品

RAGは1つの技術ではなく、5つの部品の組み合わせです。どれが弱くても全体が効きません。

1. チャンク分割

長い文書をそのまま扱うことはできないので、検索できる単位に切ります。

ここが品質をいちばん左右します。 細かく切りすぎると文脈が失われ(「これ」「同社」が何を指すか分からなくなる)、大きく切りすぎると無関係な部分まで一緒に渡すことになります。実務では数百〜千数百字を目安に、見出しや段落の切れ目で切り、前後を少し重ねる(オーバーラップ)のが定石です。

2. 埋め込み(Embedding)

各チャンクを数値のベクトルに変換します。意味が近い文章ほどベクトルが近くなるので、「言葉は違うが意味は同じ」文書を拾えます。キーワード一致では拾えないものが拾えるのが、この部品の価値です。

詳しくはEmbeddingとはにまとめました。

3. ベクトルの保存と検索

ベクトルを保存し、質問のベクトルに近いものを取り出します。PostgreSQLの拡張(pgvector)でも、専用のベクトルデータベースでも構いません。最初はpgvectorで十分なことがほとんどです。すでにPostgreSQLを運用しているなら、増える運用対象がゼロで済みます。

4. 再ランク(リランキング)

検索で拾った20〜50件を、質問との関連度で並べ替えて上位数件に絞ります。省略されがちですが、入れると効果が大きい部品です。ベクトル検索は「だいたい近い」ものを返すので、その中の本当に関連する数件を選び直す工程が効きます。

5. 生成

絞り込んだ資料をプロンプトに入れて、モデルに答えさせます。ここがLLM APIの出番です。

生成の部分を実装する

5番目だけならすぐ書けます。検索結果が手元にある前提のコードです。

from openai import OpenAI

client = OpenAI(api_key="<FASTMETAL_API_KEY>", base_url="https://api.fastmetal.ai/v1")

def answer(question: str, chunks: list[str]) -> str:
    context = "\n\n---\n\n".join(f"[資料{i+1}]\n{c}" for i, c in enumerate(chunks))
    resp = client.chat.completions.create(
        model="anthropic-claude-haiku-4-5",
        max_tokens=800,
        messages=[
            {
                "role": "system",
                "content": (
                    "以下の資料だけを根拠に日本語で答えてください。"
                    "資料に書かれていないことは『資料からは判断できません』と答えること。"
                    "回答の末尾に、使った資料の番号を必ず挙げること。"
                ),
            },
            {"role": "user", "content": f"{context}\n\n質問: {question}"},
        ],
    )
    return resp.choices[0].message.content

システムプロンプトの3つの指示が、それぞれ実務上の意味を持っています。

  • 「資料だけを根拠に」 — モデルが学習知識で補完するのを抑えます
  • 「判断できませんと答えること」 — 逃げ道を明示的に与えないと、モデルは無理にでも答えを作ります
  • 「資料の番号を挙げること」 — 出典が出ることで、人が検証できるようになります

書き方の考え方はシステムプロンプトとはを参照してください。

FastMetalが担当する範囲

正直に書いておくと、FastMetalが提供するのは5番目の生成だけです。埋め込みモデルは提供していません。

理由はEmbeddingとはに書きましたが、要するにゲートウェイが埋め込みを扱う経済的な理由が薄いためです(世界最大のゲートウェイであるOpenRouterも、396のモデルを扱いながら埋め込みモデルは1つも提供していません)。

現実的な構成はこうなります。

  • 埋め込み — ローカルでOllama、または埋め込み専業のサービス
  • 保存と検索 — pgvector
  • 生成 — FastMetal(円建て・プリペイド)

埋め込みは大量に回すぶん、ローカルで動かすのが合理的な場面が多い部品です。一方で生成は品質が直接効くので、良いモデルを使う価値があります。役割で分けるのが素直です。

つまずきやすい点

チャンクが悪い 検索精度が出ないとき、原因の多くは埋め込みモデルではなくチャンク分割です。まず切り方を疑ってください。

検索結果を無条件に信じている ベクトル検索は必ず何かを返します。「関連する資料がない」という状態も返ってこないので、関連度のしきい値を設けて、下回ったら「該当なし」と答えさせてください。

渡しすぎている 拾った20件を全部渡すと、コンテキストが埋まり、コストも増え、かえって精度が落ちます。再ランクで数件に絞ってください。

評価していない 「なんとなく良くなった気がする」で運用すると、変更が改善なのか改悪なのか分かりません。質問と期待される答えの組を数十件用意して測ってください(Evals入門)。

よくある質問

Q. RAGとファインチューニングはどちらを使うべきですか? 知識や事実を与えたいならRAG、口調や出力形式を教えたいならファインチューニングです。「自社のデータに答えさせたい」の答えはほぼRAGで、資料を差し替えるだけで更新でき、出典も提示できます。

Q. ベクトルデータベースは専用のものが必要ですか? 最初は不要なことがほとんどです。PostgreSQLを使っているならpgvectorで始められ、運用対象が増えません。規模が問題になってから専用のものを検討してください。

Q. RAGを使えばハルシネーションはなくなりますか? 減りますが、なくなりません。資料に書かれていないことを推測して答えることはあります。「資料だけを根拠に」「判断できない場合はそう答える」「出典を挙げる」の3つを指示してください。

Q. ロングコンテキストのモデルがあれば、RAGは不要ですか? 資料が少なければ全部渡す方が簡単です。ただし量が増えるとコストと精度の両面で成立しなくなります。判断基準はRAG vs ロングコンテキストにまとめました。

まとめ

RAGは「答える直前に資料を探して渡す」仕組みで、チャンク分割・埋め込み・保存と検索・再ランク・生成の5部品でできています。品質を落とすのはたいていチャンク分割と再ランクの省略で、埋め込みモデルの選定ではありません。

生成の部分はAPIキーを取れば今日から書けます。埋め込みはローカルや専業サービス、生成はFastMetal——という分担が現実的です。対応モデルはモデルカタログから選べます。

最新のAIモデルを今すぐ試す

最新のAIモデルはFastMetalのAPIキー1つで利用できます。ブラウザですぐに試す、またはOpenAI SDKからそのまま呼び出せます。