RAG(Retrieval-Augmented Generation)は、大規模言語モデルに外部知識を効果的に組み合わせる手法として注目されています。本記事では、実務で使えるRAGの実装パターンと、検索精度を左右するチャンク分割のベストプラクティスを具体例とともに解説します。適切な設計により、より正確で関連性の高い回答を生成できるシステムを構築しましょう。
RAGの基本アーキテクチャと実装パターン
シンプルRAGパターン
最も基本的なRAG実装では、以下の流れでデータを処理します:
- 文書をチャンクに分割
- 各チャンクをベクトル化してデータベースに保存
- クエリに対してベクトル検索を実行
- 検索結果をコンテキストとしてLLMに入力
async def simple_rag(query: str, k: int = 3):
# ベクトル検索
query_embedding = embed_text(query)
similar_chunks = vector_db.search(query_embedding, k=k)
# コンテキスト構築
context = "\n".join([chunk.text for chunk in similar_chunks])
# LLM生成
prompt = f"Context: {context}\n\nQuestion: {query}\nAnswer:"
return llm.generate(prompt)
ハイブリッド検索パターン
セマンティック検索とキーワード検索を組み合わせることで、より高精度な検索が可能になります:
def hybrid_search(query: str, alpha: float = 0.7):
# セマンティック検索
semantic_results = vector_db.search(query, k=10)
# キーワード検索
keyword_results = elasticsearch.search(query, k=10)
# スコア統合
combined_scores = {}
for result in semantic_results:
combined_scores[result.id] = alpha * result.score
for result in keyword_results:
if result.id in combined_scores:
combined_scores[result.id] += (1-alpha) * result.score
else:
combined_scores[result.id] = (1-alpha) * result.score
return get_top_k_results(combined_scores)
チャンク分割のベストプラクティス
文書タイプ別分割戦略
技術文書・マニュアル
- セクション単位での分割(500-800トークン)
- コードブロックは完結性を保持
- 見出し階層を活用したメタデータ付与
def split_technical_doc(text: str):
# 見出しベースでの分割
sections = split_by_headers(text)
chunks = []
for section in sections:
if len(section.tokens) > 800:
# 長いセクションはパラグラフ単位で再分割
sub_chunks = split_by_paragraph(section, max_tokens=600)
chunks.extend(sub_chunks)
else:
chunks.append(section)
return chunks
FAQ・Q&Aデータ
- 1つの質問と回答をペアで保持
- 関連する質問をグループ化
- 質問バリエーションを含める
重複排除とオーバーラップ戦略
連続するチャンク間で情報が分断されることを防ぐため、適切なオーバーラップを設定します:
def create_overlapping_chunks(text: str, chunk_size: int = 500, overlap: int = 50):
chunks = []
start = 0
while start < len(text):
end = min(start + chunk_size, len(text))
# 文境界で調整
if end < len(text):
last_period = text.rfind('.', start, end)
if last_period > start + chunk_size * 0.8:
end = last_period + 1
chunks.append({
'text': text[start:end],
'start_pos': start,
'end_pos': end
})
start = end - overlap
return chunks
検索精度向上のための実装テクニック
メタデータ活用
チャンクにメタデータを付与することで、フィルタリング機能を強化できます:
chunk_metadata = {
'document_type': 'technical_manual',
'section': 'installation',
'level': 'beginner',
'last_updated': '2024-01-15',
'tags': ['setup', 'configuration', 'troubleshooting']
}
クエリ拡張
ユーザーのクエリを拡張して、より関連性の高い結果を取得します:
例:「エラーが出る」→「エラー, 問題, 障害, トラブル, 解決」
パフォーマンス最適化
インデックス最適化
- 適切なベクトル次元数の選択(384, 768, 1536次元等)
- 階層的クラスタリング(HNSW等)の活用
- 定期的なインデックス再構築
キャッシュ戦略
頻繁にアクセスされるクエリの結果をキャッシュすることで、レスポンス時間を大幅に改善できます。
まとめ
効果的なRAG実装には、データの性質に応じた適切なチャンク分割戦略が不可欠です。シンプルなパターンから始めて、ハイブリッド検索やメタデータ活用など、段階的に機能を拡張していくことをお勧めします。実際の運用では、継続的なクエリ分析と改善により、システムの精度を向上させていくことが重要です。