LangChain RAG

RAG(Retrieval-Augmented Generation、検索拡張生成)は、AIがあなたのプライベートドキュメントに基づいて質問に答えられるようにします。モデルをファインチューニングする必要はなく、ドキュメントをベクトル化して保存するだけで、Agentが関連コンテンツを検索して回答できるようになります。


RAGとは

通常の大規模モデルは、学習データに含まれる内容にしか回答できません。あなたのドキュメントがプライベート(社内文書、個人メモなど)の場合、モデルは「知らない」状態です。RAGはこの問題を解決します:

  • オフライン段階:ドキュメントを小さなチャンクに分割 → Embeddingモデルでベクトルに変換 → ベクトルデータベースに保存
  • オンライン段階:ユーザーが質問 → 質問をベクトルに変換 → ベクトルデータベースで最も類似したコンテンツを検索 → 検索したコンテンツをコンテキストとしてモデルに送信 → モデルは検索内容に基づいて回答

RAGのワークフロー

┌──────────────────────────────────────────────────────┐
│                    离线阶段(索引)                     │
│                                                      │
│  文档 → DocumentLoader → TextSplitter → Embedding     │
│                                           ↓          │
│                                      VectorStore     │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│                    在线阶段(检索)                     │
│                                                      │
│  用户提问 → Embedding → 相似度搜索 → 检索结果          │
│                                          ↓           │
│                      检索结果 + 用户问题 → 模型 → 回答  │
└──────────────────────────────────────────────────────┘


環境準備

RAG関連の依存関係をインストール:

$ pip install langchain-deepseek langchain-chroma chromadb
包用途
langchain-deepseekOpenAI Embeddingモデルを提供
langchain-chromaChromaベクトルデータベースのLangChain統合
chromadbChromaベクトルデータベース(軽量で初心者向け)

Embeddingモデルの初期化

例

from dotenv import load_dotenv
load_dotenv()

from langchain_openai import OpenAIEmbeddings

# OpenAIのテキスト埋め込みモデル
# テキストをベクトル(浮動小数点数の配列)に変換する
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# テスト:テキストをベクトルに変換する
text = "サンプル(初心者向けチュートリアル)はプログラミング学習プラットフォームです"
vector = embeddings.embed_query(text)

print(f"テキスト: {text}")
print(f"ベクトル次元数: {len(vector)}")   # text-embedding-3-small は1536次元
print(f"ベクトルの最初の5つの値: {vector[:5]}")

実行結果:

テキスト: サンプル 是一个编程学习平台
ベクトル次元: 1536
ベクトルの最初の5つの値: [0.0123, -0.0045, 0.0234, -0.0012, 0.0089]

また、OpenAIのキーがない場合は、Alibaba Cloud百炼のEmbeddingサービスを利用できます。.env設定ファイルにAlibaba Cloud百炼のキーを追加する必要があります:

DASHSCOPE_API_KEY="sk-xxx"

設定後のコード:

例

import os
from dotenv import load_dotenv
load_dotenv()

from langchain_openai import OpenAIEmbeddings

# OpenAIのテキスト埋め込みモデル
# テキストをベクトル(浮動小数点数の配列)に変換する

# Alibaba Cloud百炼(DashScope)の通義千問(Qwen)Embeddingサービスを利用する
# 百炼のEmbedding APIはOpenAI APIの仕様と互換性があるため、langchain-openaiをそのまま使用
# のOpenAIEmbeddingsのbase_urlを百炼の互換エンドポイントに指定するだけでOKです。
# 追加でlangchain-community / dashscopeをインストールする必要はありません(このパッケージはメンテナンス停止済み)。
text-embedding-v4は現在推奨されている汎用ベクトルモデルで、デフォルトで1024次元のベクトルを出力します。
#
# 2つの重要なパラメータは必須です:
# - check_embedding_ctx_length=False:OpenAIEmbeddingsはデフォルトでtiktokenを使用し、
# テキストを事前にトークンID配列にエンコードして送信します(OpenAI公式APIはこの形式を認識します)。
# しかし百炼の互換APIは元の文字列のみを受け付けるため、このオプションをオフにしないとエラーになります。
# "contents is neither str nor list of str" というエラーが発生します。
# - chunk_size=10:百炼のEmbedding APIは1回のリクエストで最大10件のテキストしか受け付けません。
# OpenAIEmbeddingsはデフォルトで一度に1000件をまとめて送信するため、ナレッジベースが少し大きくなると上限超過エラーになります。
embeddings = OpenAIEmbeddings(
    model="text-embedding-v4",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    check_embedding_ctx_length=False,
    chunk_size=10,
)
# テスト:テキストをベクトルに変換する
text = "サンプル(初心者向けチュートリアル)はプログラミング学習プラットフォームです"
vector = embeddings.embed_query(text)

print(f"テキスト: {text}")
print(f"ベクトル次元数: {len(vector)}")   # text-embedding-3-small は1536次元
print(f"ベクトルの最初の5つの値: {vector[:5]}")

ベクトルストアの作成

例

from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

# Embeddingモデルを初期化
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# Chromaベクトルストアを作成(データはローカルディレクトリに保存)
vector_store = Chroma(
    collection_name="サンプル_docs",
    embedding_function=embeddings,
    persist_directory="./chroma_db",  # 永続化ディレクトリ
)

# ドキュメントを追加(最も簡単な形式:テキストリスト)
texts = [
    "サンプル(初心者向けチュートリアル)は無料のプログラミング学習サイトで、HTML、CSS、JavaScript、Pythonなどのチュートリアルを提供しています。",
    "Python3基礎チュートリアルは全30章で、ゼロから始める初心者に適しており、環境構築、構文の基礎、オブジェクト指向などの内容が含まれています。",
    "HTML基礎チュートリアルは全25章で、HTMLタグ、フォーム、マルチメディアなどの基礎知識をカバーしています。",
]

# add_textsはテキストを自動的にベクトルに変換して保存します
vector_store.add_texts(texts)

print(f"{len(texts)}件のドキュメントをベクトルストアに追加しました")

セマンティック検索

例

# セマンティック検索——キーワード一致ではなく、意味的な類似度に基づく
results = vector_store.similarity_search(
    "Pythonを学びたいのですが、おすすめのチュートリアルはありますか?",
    k=2,  # 最も類似した2件の結果を返す
)

print("検索結果:")
for i, doc in enumerate(results):
    print(f"\n結果 {i+1}:")
    print(f" 内容: {doc.page_content}")
    print(f" メタデータ: {doc.metadata}")

実行結果:

搜索结果:

結果1:
  内容: Python3 基础教程共 30 章,适合零基础入门...
  メタデータ: {}

結果2:
  内容: サンプル是一个免费的编程学习网站...
  メタデータ: {}

最初の検索結果は2番目の結果よりも関連性が高いことに注意してください。最初の結果には"Python"というキーワードが含まれていますが、それは意味的な類似度ではなく、キーワード一致による並び替えです。これがベクトル検索の強みです。


Retriever(検索器)の作成

RetrieverはVector Storeの標準化されたインターフェースです:

例

# vector_storeからretrieverを作成
retriever = vector_store.as_retriever(
    search_type="similarity",  # 類似度検索
    search_kwargs={"k": 3},    # 上位3件の結果を返す
)

# retrieverを使用
docs = retriever.invoke("Python学習ロードマップ")
for doc in docs:
    print(f"- {doc.page_content[:60]}...")
その他の拡張