ファインチューニング vs RAG:本番LLMでどちらのアプローチを使うべきか

ファインチューニング vs RAG:本番LLMでどちらのアプローチを使うべきか

「社内ドキュメントを学習させたら、幻覚が増えた」——こんな報告を受けたことはないだろうか。

GPT-4やClaude、Geminiといったベースモデルがそのままでは使えない場面に直面したとき、エンジニアが最初に検討するのがファインチューニングとRAG(Retrieval-Augmented Generation)だ。正直、この二択を誤ったプロジェクトを何度も見てきた。コストと工数が無駄になるだけならまだしも、本番環境で深刻な品質問題を引き起こしてから気づくケースが多い。

この記事ではファインチューニング vs RAGそれぞれの仕組みと向き不向きを整理し、判断に必要な具体的な指標と実装パターンを示す。


ファインチューニングとは何か

ファインチューニングは、事前学習済みモデルの重みを追加データで更新し、特定のタスクや文体・ドメインに最適化する手法だ。

仕組み

ベースモデルが持つ汎用的な表現能力を土台に、用意したデータセットで勾配を計算してパラメータを更新する。全パラメータを更新するFull Fine-tuningのほか、計算コストを抑えた手法として以下が広く使われている。

  • LoRA(Low-Rank Adaptation): 重み行列の低ランク近似を学習し、変更するパラメータ数を1〜10%程度に削減する
  • QLoRA: LoRAに量子化を組み合わせ、一般的なGPU(24GB VRAM)でも70Bクラスのモデルを学習できる
  • Prefix Tuning / P-Tuning: 入力に仮想トークンを付加し、モデル本体の重みは固定する
# LoRAを使ったファインチューニングの基本構成(HuggingFace + PEFT)
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType

model_id = "meta-llama/Llama-3-8b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
base_model = AutoModelForCausalLM.from_pretrained(model_id, load_in_4bit=True)

lora_config = LoraConfig(
    r=16,                    # ランク(低いほど軽量、高いほど表現力)
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    task_type=TaskType.CAUSAL_LM,
)

model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters()
# trainable params: 4,194,304 || all params: 8,033,669,120 || trainable%: 0.052

LoRAのランク(r)の選択は地味に悩む。私の経験では、まずr=16で試して、タスクが複雑ならr=64まで上げる、という進め方が無難だった。

ファインチューニングが向いているケース

  • 出力の形式や文体を固定したい: 特定のJSONスキーマで常に応答させる、敬語体を維持する、など
  • 特定タスクに特化した精度が必要: 医療文書の構造化、法的文書の分類など
  • レイテンシを最小化したい: コンテキストを大量に渡す必要がなくなるため推論が速くなる
  • 機密データをクラウドに送れない: オンプレで完結させる場合、小さなモデルをチューニングする方が現実的

RAGとは何か

RAG(Retrieval-Augmented Generation)は、モデルのパラメータは変えずに、推論時に外部知識を動的に取得してプロンプトに注入する手法だ。

仕組み

ユーザーの質問
    ↓
[Retriever] ベクトル検索 or BM25 で関連ドキュメントを取得
    ↓
[Augment]  取得したチャンクをプロンプトに挿入
    ↓
[Generate] LLMが文脈を踏まえて回答生成

実装の中核はベクトルストアへのインデックス構築と、クエリとの類似度計算だ。

# LangChainを使ったシンプルなRAGパイプライン
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# ドキュメントのロードとチャンク分割
loader = DirectoryLoader("./docs", glob="**/*.md")
documents = loader.load()

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64,
)
chunks = splitter.split_documents(documents)

# ベクトルストアの構築
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=OpenAIEmbeddings(),
    persist_directory="./chroma_db",
)

# RAGチェーンの構築
qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o", temperature=0),
    retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
    return_source_documents=True,
)

result = qa_chain.invoke({"query": "返品ポリシーを教えてください"})
print(result["result"])
print([doc.metadata["source"] for doc in result["source_documents"]])

RAGが向いているケース

  • 知識が頻繁に更新される: 製品マニュアル、社内規定、ニュース記事など
  • 情報ソースの根拠を示す必要がある: 出典付きで回答させたい場合
  • データ量が膨大: 数十万件のドキュメントをモデルに「記憶」させるのは非現実的
  • ドメインが広い: 複数分野にまたがる知識ベースへのQ&A

ファインチューニング vs RAG:5つの判断軸

ファインチューニング vs RAGを選ぶとき、以下の5軸で整理すると意思決定がしやすい。

1. 知識の更新頻度

更新頻度推奨手法
日次〜週次RAG
月次以下どちらでも可
固定(変わらない)ファインチューニング

ファインチューニングは学習済みの知識をパラメータに焼き込む。情報が変わるたびに再学習が必要になり、継続的な更新コストがかかる。RAGならインデックスを更新するだけで済む。

2. 求めているのは「知識」か「振る舞い」か

これが一番大事な問いだ——そしてここを混同しているチームが多い。

  • 振る舞いを変えたい(出力形式、文体、タスク特化の推論パターン)→ ファインチューニング
  • 知識を与えたい(社内情報、最新情報、専門ドメイン知識)→ RAG

「GPT-4に医療の知識を持たせたい」という要求の場合、RAGで医療文献をインデックスする方が、ファインチューニングよりも圧倒的に安く・速く・更新しやすい。一方、「常に構造化されたJSONで返してほしい」という要求はプロンプトでも対応できるが、安定性を高めるにはファインチューニングが有効だ。個人的には、要件定義の段階でこの二軸を分けて考えるだけで、多くの議論がスッキリする印象がある。

3. コスト構造

ファインチューニングのコスト
– 初期:学習コスト(GPU時間)+データ収集・アノテーション費用
– 継続:モデルホスティング費用(API利用と比べて固定費が高い傾向)
– 更新時:再学習コスト

RAGのコスト
– 初期:ベクトルストア構築+埋め込みAPI費用
– 継続:検索+LLM推論(コンテキストが長くなるため1リクエストあたりのトークン数が増加)
– 更新時:差分インデックス更新(比較的安価)

リクエスト数が少なく知識が固定的なら、ファインチューニングして小さなモデルを使う方が長期的に安くなることがある。逆にリクエスト数が多く知識が変動するならRAGの方がオペレーションコストを抑えやすい。

4. レイテンシ要件

RAGは検索ステップが加わるため、単純な推論よりもレイテンシが増える。ベクトル検索自体は高速(数十ms)だが、チャンク数が増えるとリランク処理や複数回の検索(HyDE、Multi-queryなど)でさらに増加する。

厳格なレイテンシ要件(100ms以下など)がある場合、ファインチューニングした小型モデルの方が有利になりやすい。

5. ハルシネーションの許容度

RAGは「取得したドキュメントに基づいて回答する」という構造上、知識に関するハルシネーションを抑制しやすい。一方でファインチューニングされたモデルは、学習データにない情報を自信を持って生成することがある——冒頭の「幻覚が増えた」報告はだいたいこのパターンだ。

根拠を求められる用途(法律、医療、金融)では、RAGによる出典付き回答の方がリスク管理上も合理的だ。


実際の判断フロー

現場で使える簡易チェックリストを示す。

Q1: 回答に最新・社内情報が必要か?
    YES → RAG を検討

Q2: 知識は毎週以上の頻度で変わるか?
    YES → RAG ほぼ確定

Q3: 求めているのは文体・形式・タスク特化の改善か?
    YES → ファインチューニングを検討

Q4: まずプロンプトエンジニアリングで解決できないか?
    NO(できない)→ ファインチューニングを検討

Q5: ハルシネーションが許されないユースケースか?
    YES → RAG(出典付き)を強く推奨

ハイブリッドアプローチ:両方使うという選択

ファインチューニング vs RAGは二択である必要はない。本番システムでは、両者を組み合わせるケースも多い。

典型的なハイブリッド構成

[ユーザー入力]
    ↓
[RAG] 社内ドキュメントから関連情報を取得
    ↓
[ファインチューニング済みモデル] 
  → 特定の出力形式・トーンで回答生成
    ↓
[出力]

例:カスタマーサポートBot

  • RAGで: 製品FAQ、返品ポリシー、最新の障害情報を動的に取得
  • ファインチューニングで: ブランドのトーン・ボイスを固定、エスカレーション判断のロジックを学習

「知識はRAGで管理、振る舞いはモデルに学習させる」という役割分担が明確にできる点が、このアーキテクチャの強みだ。

段階的なアプローチ

いきなりファインチューニングに投資するより、以下の順序で試すことを勧める。

  1. プロンプトエンジニアリング(数時間〜数日)
  2. RAG(数日〜2週間)
  3. ファインチューニング(数週間〜)

多くのケースでは、ステップ1か2で十分な品質に到達する。ファインチューニングが真に必要になるのは、プロンプトやRAGでは解決できないタスク特化の品質問題が明確になってからだ。


実装時の落とし穴

RAGでよくある失敗

チャンク分割の粗さ
固定サイズ(例:512トークン)で機械的に分割すると、文脈が途切れた不完全なチャンクが検索される。セクション境界や段落単位での分割を基本とし、オーバーラップを適切に設定する。

埋め込みモデルとLLMのミスマッチ
検索に使う埋め込みモデルが日本語に弱い場合、関連ドキュメントを正しく取得できない。日本語であればintfloat/multilingual-e5-largecl-nagoya/sup-simcse-ja-largeなどを評価することを勧める。これ、英語前提で設計されたRAGをそのまま日本語コーパスに当てて「精度が出ない」と悩むケースが思ったより多い。

Re-rankの欠如
ベクトル検索はセマンティックな類似度を捉えるが、キーワードマッチが重要な場合に弱い。BM25とベクトル検索のハイブリッドサーチ+Cross-Encoderによるリランクを組み合わせることで、検索品質が改善するケースが多い。

ファインチューニングでよくある失敗

学習データが少なすぎる
LoRAであっても、タスクの複雑さに応じた十分なデータ量が必要だ。数百件程度では過学習しやすく、汎化が損なわれる。

Catastrophic Forgetting
特定ドメインに特化させすぎると、ベースモデルが持っていた汎用的な能力が劣化する。評価セットにはターゲットタスク以外の汎用的な問いも含めること。

評価指標の設計ミス
Loss値が下がってもビジネス要件を満たさないことはよくある。ファインチューニング前後で、本番に近い評価データセット(人手評価を含む)を用意して差分を測る。正直、ここをサボると後でかなり痛い目を見る。


まとめ

ファインチューニング vs RAGの選択は、技術的な優劣ではなくユースケースの性質によって決まる。

  • 知識の問題(最新情報、社内情報、根拠が必要)→ RAGから始める
  • 振る舞いの問題(形式、文体、タスク特化の推論)→ ファインチューニングを検討
  • どちらか迷ったら→ まずプロンプト、次にRAG、最後にファインチューニングの順で試す

ほとんどの本番ユースケースでは、RAGの方が初期コストが低く、知識の更新にも柔軟に対応できる。ファインチューニングは「RAGやプロンプトでどうしても解決できない問題」が明確になった段階で、初めて本格投資を検討するのが現実的だ。


まず自社のユースケースをこの記事の5つの判断軸に当てはめてみてほしい。RAGのプロトタイプは最短1日で動かせる。迷ったら手を動かすのが最速の答え合わせになる。

ファインチューニングの学習コスト見積もりやRAGのアーキテクチャ設計について、具体的なケースがあれば気軽にコメントしてほしい。

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top