ファインチューニング 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で管理、振る舞いはモデルに学習させる」という役割分担が明確にできる点が、このアーキテクチャの強みだ。
段階的なアプローチ
いきなりファインチューニングに投資するより、以下の順序で試すことを勧める。
- プロンプトエンジニアリング(数時間〜数日)
- RAG(数日〜2週間)
- ファインチューニング(数週間〜)
多くのケースでは、ステップ1か2で十分な品質に到達する。ファインチューニングが真に必要になるのは、プロンプトやRAGでは解決できないタスク特化の品質問題が明確になってからだ。
実装時の落とし穴
RAGでよくある失敗
チャンク分割の粗さ
固定サイズ(例:512トークン)で機械的に分割すると、文脈が途切れた不完全なチャンクが検索される。セクション境界や段落単位での分割を基本とし、オーバーラップを適切に設定する。
埋め込みモデルとLLMのミスマッチ
検索に使う埋め込みモデルが日本語に弱い場合、関連ドキュメントを正しく取得できない。日本語であればintfloat/multilingual-e5-largeやcl-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のアーキテクチャ設計について、具体的なケースがあれば気軽にコメントしてほしい。