先に用語を整理します
この分野は言葉が混同されやすいので、先に整理しておきます。とくに GGUF は「学習させるための形式」ではありません。推論用にモデルを格納するファイル形式です。
| 用語 | 意味 |
|---|---|
| LoRA | モデルの一部パラメータだけを追加学習する手法 |
| ファインチューニング | モデルの重みを目的に合わせて調整すること |
| RAG | 外部文書を検索し、回答時にプロンプトへ渡して参照させる仕組み。モデルの重みは更新しない |
| GGUF | 主に llama.cpp 系で使う、推論用モデルの格納フォーマット |
| 量子化 | 精度を下げてメモリ使用量と計算量を削減すること |
実際の流れは FP16 / BF16 などの元モデルに LoRA で追加学習 → マージ → GGUF へ変換・量子化 です。GGUFファイルそのものを学習させるわけではありません。
:root { –primary: #1a1a2e; –secondary: #16213e; –accent: #0f3460; –highlight: #e94560; –text: #eee; –text-muted: #aab; –bg: #0f0f1a; –card-bg: #1a1a2e; –border: #2a2a4a; –gradient-1: #667eea; –gradient-2: #764ba2; } .rag-guide * { margin: 0; padding: 0; box-sizing: border-box; } .rag-guide { font-family: ‘Segoe UI’, ‘Hiragino Sans’, ‘Noto Sans JP’, sans-serif; background: var(–bg); color: var(–text); line-height: 1.8; } .rag-guide .container { max-width: 1100px; margin: 0 auto; padding: 0 24px; } /* Hero */ .rag-guide .hero { text-align: center; padding: 80px 24px 60px; background: linear-gradient(135deg, var(–primary), var(–accent)); border-bottom: 2px solid var(–border); } .rag-guide .hero h1 { font-size: 2.4rem; background: linear-gradient(135deg, var(–gradient-1), var(–gradient-2)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 16px; } .rag-guide .hero p { color: var(–text-muted); font-size: 1.1rem; max-width: 700px; margin: 0 auto; } /* Section */ .rag-guide section { padding: 60px 0; border-bottom: 1px solid var(–border); } .rag-guide section:last-child { border-bottom: none; } .rag-guide h2 { font-size: 1.8rem; margin-bottom: 24px; color: var(–gradient-1); display: flex; align-items: center; gap: 12px; } .rag-guide h2 .num { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, var(–gradient-1), var(–gradient-2)); color: #fff; font-size: 1.1rem; flex-shrink: 0; } .rag-guide h3 { font-size: 1.3rem; margin: 32px 0 16px; color: #ccd; } .rag-guide p, .rag-guide li { color: var(–text-muted); margin-bottom: 12px; } .rag-guide ul, .rag-guide ol { padding-left: 24px; margin-bottom: 20px; } .rag-guide li { margin-bottom: 8px; } /* SVG Container */ .rag-guide .diagram { background: var(–card-bg); border: 1px solid var(–border); border-radius: 12px; padding: 24px; margin: 32px 0; overflow-x: auto; } .rag-guide .diagram svg { display: block; margin: 0 auto; } /* Card */ .rag-guide .card { background: var(–card-bg); border: 1px solid var(–border); border-radius: 12px; padding: 24px; margin: 20px 0; } /* Tech stack badges */ .rag-guide .tech-stack { display: flex; flex-wrap: wrap; gap: 12px; margin: 20px 0; } .rag-guide .badge { display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; border-radius: 8px; background: var(–secondary); border: 1px solid var(–border); font-size: 0.9rem; color: var(–text); } .rag-guide .badge .dot { width: 10px; height: 10px; border-radius: 50%; } /* Code block */ .rag-guide .code-block { background: #0d0d18; border: 1px solid var(–border); border-radius: 8px; padding: 20px; margin: 16px 0; font-family: ‘Fira Code’, ‘SF Mono’, monospace; font-size: 0.85rem; color: #a8d8a8; overflow-x: auto; white-space: pre; line-height: 1.6; } /* Table */ .rag-guide table { width: 100%; border-collapse: collapse; margin: 20px 0; } .rag-guide th, .rag-guide td { padding: 12px 16px; text-align: left; border: 1px solid var(–border); color: var(–text-muted); } .rag-guide th { background: var(–secondary); color: var(–text); font-weight: 600; } .rag-guide tr:hover { background: rgba(102, 126, 234, 0.05); } .rag-guide .note { background: rgba(102, 126, 234, 0.1); border-left: 4px solid var(–gradient-1); padding: 16px 20px; border-radius: 0 8px 8px 0; margin: 20px 0; } .rag-guide .note strong { color: var(–gradient-1); } .rag-guide .warning { background: rgba(233, 69, 96, 0.1); border-left: 4px solid var(–highlight); padding: 16px 20px; border-radius: 0 8px 8px 0; margin: 20px 0; } .rag-guide .warning strong { color: var(–highlight); } .rag-guide a { color: var(–gradient-1); text-decoration: none; } .rag-guide a:hover { text-decoration: underline; } /* Footer */ .rag-guide footer { text-align: center; padding: 40px 24px; color: var(–text-muted); font-size: 0.85rem; border-top: 1px solid var(–border); } /* ==================== Responsive ==================== */ /* Tablet */ @media (max-width: 768px) { .rag-guide .hero { padding: 60px 16px 40px; } .rag-guide .hero h1 { font-size: 1.8rem; } .rag-guide .hero p { font-size: 1rem; } .rag-guide .hero p br { display: none; } .rag-guide .container { padding: 0 16px; } .rag-guide section { padding: 40px 0; } .rag-guide h2 { font-size: 1.4rem; } .rag-guide h3 { font-size: 1.1rem; margin: 24px 0 12px; } .rag-guide .diagram { padding: 16px; margin: 20px 0; } .rag-guide .diagram svg { min-width: 600px; } .rag-guide table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; } .rag-guide th, .rag-guide td { padding: 10px 12px; font-size: 0.85rem; white-space: nowrap; } .rag-guide .code-block { padding: 16px; font-size: 0.78rem; } .rag-guide .card { padding: 16px; } .rag-guide .tech-stack { gap: 8px; } .rag-guide .badge { padding: 6px 12px; font-size: 0.8rem; } } /* Mobile */ @media (max-width: 480px) { .rag-guide .hero { padding: 40px 12px 30px; } .rag-guide .hero h1 { font-size: 1.4rem; } .rag-guide .hero p { font-size: 0.9rem; } .rag-guide .container { padding: 0 12px; } .rag-guide section { padding: 30px 0; } .rag-guide h2 { font-size: 1.2rem; gap: 8px; } .rag-guide h2 .num { width: 32px; height: 32px; font-size: 0.9rem; } .rag-guide h3 { font-size: 1rem; margin: 20px 0 10px; } .rag-guide .diagram { padding: 12px; margin: 16px 0; border-radius: 8px; } .rag-guide .card { padding: 14px; border-radius: 8px; } .rag-guide .code-block { padding: 12px; font-size: 0.75rem; border-radius: 6px; } .rag-guide .note, .rag-guide .warning { padding: 12px 14px; font-size: 0.9rem; } .rag-guide .tech-stack { gap: 6px; } .rag-guide .badge { padding: 5px 10px; font-size: 0.75rem; } .rag-guide footer { padding: 30px 12px; font-size: 0.8rem; } }RAGシステム構築 完全ガイド
H2O LLM Studio でファインチューニングしたモデルを Ollama + Open WebUI で動かし、
独自ナレッジベースによる RAG を実現するまでの全工程
全体アーキテクチャ
本システムは大きく4つのレイヤーで構成されています。ユーザーからの質問が各コンポーネントを経由し、ナレッジベースの情報を加味した回答を生成するまでの全体像を示します。
1H2O LLM Studioでモデルをファインチューニング
H2O LLM Studioは、コードを一行も書かずにLLMをファインチューニングできるGUIツールです。 社内データやドメイン固有のデータを使い、ベースモデルを自社用途に特化させます。
1-1. Datasetの準備とアップロード
H2O LLM Studioが期待するデータセット形式は、CSV/TSVで以下のカラムを含む構成です:
| カラム名 | 説明 | 例 |
|---|---|---|
instruction | モデルへの指示(システムプロンプト的役割) | 「以下の質問に日本語で答えてください」 |
input | ユーザーの入力・質問 | 「RAGとは何ですか?」 |
output | 期待される応答 | 「RAGは Retrieval-Augmented Generation の略で…」 |
1-2. Experimentの作成と設定
データセットをアップロードしたら、次にExperiment(訓練実験)を作成します。ここが最も設定項目が多く、理解が必要なステップです。
主要な設定項目の解説
| カテゴリ | 設定項目 | 説明 |
|---|---|---|
| Dataset | Prompt Column | 入力(質問)が含まれるカラム名を指定 |
| Answer Column | 出力(回答)が含まれるカラム名を指定 | |
| LLM Backbone | Base Model | ファインチューニングのベースとなるモデル(Llama, Mistral等) |
| LoRA | メモリ効率の良い学習手法。フル学習よりGPUメモリが少なくて済む | |
| Max Length | 入力トークンの最大長。長いほどメモリを消費 | |
| Training | Learning Rate | 学習率。大きすぎると発散、小さすぎると収束しない |
| Epochs | データセット全体を何回繰り返し学習するか | |
| Batch Size | 一度に処理するサンプル数。GPUメモリに依存 |
1-3. 訓練の実行とモデルのエクスポート
Experimentを開始すると、H2O LLM Studioがトレーニングを自動的に実行します。完了後、モデルをエクスポートします。
2Ollamaにモデルを登録する
GGUFファイルをOllamaに登録し、APIサーバーとして利用可能にします。「モデル工場」でH2Oのexperimentを選択し、Ollamaモデル名を入力するステップです。
3ドキュメント処理パイプライン(Tika / Docling)
RAGで利用するナレッジベースのドキュメントを、LLMが理解できるテキスト形式に変換します。PDF、Word、Excel、PowerPointなど多様な形式に対応するため、TikaとDoclingを活用します。
Tika vs Docling の使い分け
| 特徴 | Apache Tika | Docling |
|---|---|---|
| 対応形式 | 1000+形式(汎用的) | PDF中心(高精度) |
| テーブル抽出 | 基本的なサポート | 構造を保持した高精度抽出 |
| OCR | Tesseract連携 | 内蔵OCRエンジン |
| レイアウト認識 | 限定的 | 高精度なレイアウト解析 |
| 実装言語 | Java (REST API提供) | Python |
| 推奨ユースケース | 多様なファイル形式を一括処理 | PDFの高精度テキスト抽出 |
4Qdrant ベクトルデータベース
ドキュメントから抽出・分割されたテキストチャンクをベクトル化して保存し、類似検索を可能にするのがQdrantの役割です。RAGの「Retrieval」部分の中核を担います。
5Open WebUI でRAGチャットを構築
すべてのコンポーネントを統合するフロントエンドがOpen WebUIです。ナレッジベースの作成、ファイルのアップロード、モデルの設定をGUIで行えます。
5-1. ナレッジベースの作成
5-2. Open WebUI のセットアップ手順
設定手順まとめ
- ナレッジベース作成: 管理画面 → ワークスペース → ナレッジベース → 「New Knowledge」をクリック。名前と説明を入力して作成。
- ファイルアップロード: 作成したナレッジベースの編集画面を開き、RAGに使いたいドキュメント(PDF, DOCX等)をドラッグ&ドロップまたはファイル選択でアップロード。自動的にチャンク分割・ベクトル化される。
- モデル作成: ワークスペース → モデル → 「New Model」。Ollamaで登録したモデル名を指定し、先ほど作成したナレッジベースを紐付ける。
- チャット開始: チャット画面でモデルを選択して質問すると、自動的にRAG検索が行われ、関連ドキュメントの情報を加味した回答が生成される。
6全体データフロー
最後に、ユーザーが質問を入力してから回答が生成されるまでの全体的なデータの流れを確認しましょう。
7技術スタック一覧
| 技術 | 役割 | 公式ドキュメント |
|---|---|---|
| H2O LLM Studio | GUIベースのLLMファインチューニングツール。コード不要でLoRA等の学習が可能 | docs.h2o.ai |
| llama.cpp | C++実装の高速LLM推論エンジン。GGUF形式のモデルを効率的に実行。量子化もサポート | GitHub |
| Ollama | LLMのローカル実行環境。llama.cppをラップし、REST APIを提供。モデル管理を簡素化 | docs.ollama.com |
| Open WebUI | チャット型WebインターフェースRAG機能内蔵。ナレッジベース管理、モデル切替をGUIで提供 | docs.openwebui.com |
| Apache Tika | 汎用ドキュメントパーサー。1000+のファイル形式からテキスト・メタデータを抽出 | tika.apache.org |
| Docling | PDF特化の高精度ドキュメントパーサー。テーブル構造やレイアウトを保持した抽出が可能 | docling-project.github.io |
| Qdrant | 高性能ベクトルデータベース。コサイン類似度等による高速な近似最近傍検索を提供 | qdrant.tech |