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-deepseek | OpenAI Embeddingモデルを提供 |
| langchain-chroma | ChromaベクトルデータベースのLangChain統合 |
| chromadb | Chromaベクトルデータベース(軽量で初心者向け) |
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]}")
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 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)}件のドキュメントをベクトルストアに追加しました")
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}")
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]}...")
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]}...")