langchain-rag について
langchain-ragは、LangChainで検索拡張生成のワークフローを構築する開発者向けのスキルです。ドキュメントの読み込み、分割、ベクトルストア、検索、生成と設定上の注意点を扱います。
主な機能
- 01ファイル、Web、データベースから読み込み
- 02ドキュメント分割と埋め込み生成
- 03ベクトルストアで保存・検索
- 04類似度検索とMMR検索
- 05検索コンテキストから回答生成
活用シーン
- 01エンドツーエンドのRAGパイプライン構築
- 02PDFやWebページからのコンテンツ抽出
- 03メタデータによる検索結果の絞り込み
- 04ドキュメント検索をエージェントに接続
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ langchain-ai/ skills-benchmarks --skill langchain-ragインストール後、Claude Code で/langchain-ragを入力して読み込まれたか確認します。
詳細
パイプライン:
- インデックス作成:読み込み → 分割 → 埋め込み → 保存
- 検索:クエリ → 埋め込み → 検索 → ドキュメントを返す
- 生成:ドキュメント + クエリ → LLM → 応答
主なコンポーネント:
- ドキュメントローダー:ファイル、ウェブ、データベースからデータを取り込む
- テキスト分割器:ドキュメントをチャンクに分割する
- 埋め込み:テキストをベクトルに変換する
- ベクトルストア:埋め込みを保存し、検索する
| ベクトルストア | 用途 | 永続化 |
|---|---|---|
| InMemory | テスト | メモリのみ |
| FAISS | ローカル、高性能 | ディスク |
| Chroma | 開発 | ディスク |
| Pinecone | 本番環境、マネージド | クラウド |
RAG パイプライン全体
ドキュメントの読み込み、チャンクへの分割、埋め込み、保存、検索、応答の生成を行う、エンドツーエンドの RAG パイプラインです。 ```python from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_community.vectorstores import InMemoryVectorStore from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_core.documents import Document1. Load documents
docs = [ Document(page_content="LangChain is a framework for LLM apps.", metadata={}), Document(page_content="RAG = Retrieval Augmented Generation.", metadata={}), ]
2. Split documents
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50) splits = splitter.split_documents(docs)
3. Create embeddings and store
embeddings = OpenAIEmbeddings(model="text-embedding-3-small") vectorstore = InMemoryVectorStore.from_documents(splits, embeddings)
4. Create retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
5. Use in RAG
model = ChatOpenAI(model="gpt-4.1") query = "What is RAG?" relevant_docs = retriever.invoke(query)
context = "\n\n".join([doc.page_content for doc in relevant_docs]) response = model.invoke([ {"role": "system", "content": f"Use this context:\n\n{context}"}, {"role": "user", "content": query}, ])
</python>
<typescript>
ドキュメントの読み込み、チャンクへの分割、埋め込み、保存、検索、応答の生成を行う、エンドツーエンドの RAG パイプラインです。
```typescript
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";
// 1. Load documents
const docs = [
new Document({ pageContent: "LangChain is a framework for LLM apps.", metadata: {} }),
new Document({ pageContent: "RAG = Retrieval Augmented Generation.", metadata: {} }),
];
// 2. Split documents
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 50 });
const splits = await splitter.splitDocuments(docs);
// 3. Create embeddings and store
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const vectorstore = await MemoryVectorStore.fromDocuments(splits, embeddings);
// 4. Create retriever
const retriever = vectorstore.asRetriever({ k: 4 });
// 5. Use in RAG
const model = new ChatOpenAI({ model: "gpt-4.1" });
const query = "What is RAG?";
const relevantDocs = await retriever.invoke(query);
const context = relevantDocs.map(doc => doc.pageContent).join("\n\n");
const response = await model.invoke([
{ role: "system", content: `Use this context:\n\n${context}` },
{ role: "user", content: query },
]);
ドキュメントローダー
PDF ファイルを読み込み、各ページを個別のドキュメントとして抽出します。 ```python from langchain_community.document_loaders import PyPDFLoaderloader = PyPDFLoader("./document.pdf") docs = loader.load() print(f"Loaded {len(docs)} pages")
</python>
<typescript>
PDF ファイルを読み込み、各ページを個別のドキュメントとして抽出します。
```typescript
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
const loader = new PDFLoader("./document.pdf");
const docs = await loader.load();
console.log(`Loaded ${docs.length} pages`);
ウェブ URL からコンテンツを取得して解析し、ドキュメントにします。
```python
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.langchain.com") docs = loader.load()
</python>
<typescript>
Cheerio を使用してウェブ URL からコンテンツを取得して解析し、ドキュメントにします。
```typescript
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
const loader = new CheerioWebBaseLoader("https://docs.langchain.com");
const docs = await loader.load();
glob パターンを使用して、ディレクトリ内のすべてのテキストファイルを読み込みます。
```python
from langchain_community.document_loaders import DirectoryLoader, TextLoader
Load all text files from directory
loader = DirectoryLoader( "path/to/documents", glob="**/*.txt", # Pattern for files to load loader_cls=TextLoader ) docs = loader.load()
</python>
</ex-loading-directory>
---
## テキスト分割
<ex-text-splitting>
<python>
設定可能なサイズとオーバーラップを指定し、RecursiveCharacterTextSplitter を使用してドキュメントをチャンクに分割します。
```python
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Characters per chunk
chunk_overlap=200, # Overlap for context continuity
separators=["\n\n", "\n", " ", ""], # Split hierarchy
)
splits = splitter.split_documents(docs)
ベクトルストア
永続化された Chroma ベクトルストアを作成し、ディスクから再読み込みします。 ```python from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddingsvectorstore = Chroma.from_documents( documents=splits, embedding=OpenAIEmbeddings(), persist_directory="./chroma_db", collection_name="my-collection", )
Load existing
vectorstore = Chroma( persist_directory="./chroma_db", embedding_function=OpenAIEmbeddings(), collection_name="my-collection", )
</python>
<typescript>
稼働中の Chroma サーバーに接続された Chroma ベクトルストアを作成します。
```typescript
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
const vectorstore = await Chroma.fromDocuments(
splits,
new OpenAIEmbeddings(),
{ collectionName: "my-collection", url: "http://localhost:8000" }
);
FAISS ベクトルストアを作成してディスクに保存し、再読み込みします。
```python
from langchain_community.vectorstores import FAISS
vectorstore = FAISS.from_documents(splits, embeddings) vectorstore.save_local("./faiss_index")
Load (requires allow_dangerous_deserialization)
loaded = FAISS.load_local( "./faiss_index", embeddings, allow_dangerous_deserialization=True )
</python>
<typescript>
FAISS ベクトルストアを作成してディスクに保存し、再読み込みします。
```typescript
import { FaissStore } from "@langchain/community/vectorstores/faiss";
const vectorstore = await FaissStore.fromDocuments(splits, embeddings);
await vectorstore.save("./faiss_index");
const loaded = await FaissStore.load("./faiss_index", embeddings);
検索
類似度検索を実行し、関連度スコアとともに結果を取得します。 ```python # Basic search results = vectorstore.similarity_search(query, k=5)With scores
results_with_score = vectorstore.similarity_search_with_score(query, k=5) for doc, score in results_with_score: print(f"Score: {score}, Content: {doc.page_content}")
</python>
<typescript>
類似度検索を実行し、関連度スコアとともに結果を取得します。
```typescript
// Basic search
const results = await vectorstore.similaritySearch(query, 5);
// With scores
const resultsWithScore = await vectorstore.similaritySearchWithScore(query, 5);
for (const [doc, score] of resultsWithScore) {
console.log(`Score: ${score}, Content: ${doc.pageContent}`);
}
MMR(最大限界関連性)を使用して、検索結果の関連性と多様性のバランスを取ります。
```python
# MMR balances relevance and diversity
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"fetch_k": 20, "lambda_mult": 0.5, "k": 5},
)
```
ドキュメントにメタデータを追加し、メタデータのプロパティで検索結果を絞り込みます。
```python
# Add metadata when creating documents
docs = [
Document(
page_content="Python programming guide",
metadata={"language": "python", "topic": "programming"}
),
]
Search with filter
results = vectorstore.similarity_search( "programming", k=5, filter={"language": "python"} # Only Python docs )
</python>
</ex-metadata-filtering>
<ex-rag-with-agent>
<python>
質問に回答するためのツールとして RAG を使用するエージェントを作成します。
```python
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def search_docs(query: str) -> str:
"""Search documentation for relevant information."""
docs = retriever.invoke(query)
return "\n\n".join([d.page_content for d in docs])
agent = create_agent(
model="gpt-4.1",
tools=[search_docs],
)
result = agent.invoke({
"messages": [{"role": "user", "content": "How do I create an agent?"}]
})
質問に回答するためのツールとして RAG を使用するエージェントを作成します。
```typescript
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const searchDocs = tool( async (input) => { const docs = await retriever.invoke(input.query); return docs.map(d => d.pageContent).join("\n\n"); }, { name: "search_docs", description: "Search documentation for relevant information.", schema: z.object({ query: z.string() }), } );
const agent = createAgent({ model: "gpt-4.1", tools: [searchDocs], });
const result = await agent.invoke({ messages: [{ role: "user", content: "How do I create an agent?" }], });
</typescript>
</ex-rag-with-agent>
<boundaries>
### 設定できる項目
- チャンクサイズ/オーバーラップ
- 埋め込みモデル
- 結果数(k)
- メタデータフィルター
- 検索アルゴリズム:類似度、MMR
### 設定できない項目
- モデルごとの埋め込み次元数
- 同じストア内で異なるモデルの埋め込みを混在させること
</boundaries>
<fix-chunk-size>
<python>
チャンクサイズは 500~1500 が一般的に適切です。
```python
# WRONG: Too small (loses context) or too large (hits limits)
splitter = RecursiveCharacterTextSplitter(chunk_size=50)
splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
# CORRECT
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
チャンクサイズは 500~1500 が一般的に適切です。
```typescript
// WRONG: Too small or too large
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 50 });
// CORRECT const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });
</typescript>
</fix-chunk-size>
<fix-chunk-overlap>
<python>
境界でコンテキストを維持するため、チャンクサイズの 10~20%のオーバーラップを設定してください。
```python
# WRONG: No overlap - context breaks at boundaries
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
# CORRECT: 10-20% overlap
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
データ損失を防ぐため、メモリ内ではなく永続化されるベクトルストアを使用してください。
```python
# WRONG: InMemory - lost on restart
vectorstore = InMemoryVectorStore.from_documents(docs, embeddings)
CORRECT
vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./chroma_db")
</python>
<typescript>
データ損失を防ぐため、メモリ内ではなく永続化されるベクトルストアを使用してください。
```typescript
// WRONG: Memory - lost on restart
const vectorstore = await MemoryVectorStore.fromDocuments(docs, embeddings);
// CORRECT
const vectorstore = await Chroma.fromDocuments(docs, embeddings, { collectionName: "my-collection" });
インデックス作成とクエリには同じ埋め込みモデルを使用してください。
```python
# WRONG: Different embeddings for index and query - incompatible!
vectorstore = Chroma.from_documents(docs, OpenAIEmbeddings(model="text-embedding-3-small"))
retriever = vectorstore.as_retriever(embeddings=OpenAIEmbeddings(model="text-embedding-3-large"))
CORRECT: Same model
embeddings = OpenAIEmbeddings(model="text-embedding-3-small") vectorstore = Chroma.from_documents(docs, embeddings) retriever = vectorstore.as_retriever() # Uses same embeddings
</python>
<typescript>
インデックス作成とクエリには同じ埋め込みモデルを使用してください。
```typescript
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const vectorstore = await Chroma.fromDocuments(docs, embeddings);
const retriever = vectorstore.asRetriever(); // Uses same embeddings
FAISS インデックスの読み込み時に、デシリアライズを明示的に許可してください。
```python
# WRONG: Will raise error
loaded_store = FAISS.load_local("./faiss_index", embeddings)
CORRECT
loaded_store = FAISS.load_local("./faiss_index", embeddings, allow_dangerous_deserialization=True)
</python>
</fix-faiss-deserialization>
<fix-dimension-mismatch>
<python>
埋め込み次元数がベクトルストアのインデックス次元数と一致していることを確認してください。
```python
# WRONG: Index has 1536 dimensions but using 512-dim embeddings
pc.create_index(name="idx", dimension=1536, metric="cosine")
vectorstore = PineconeVectorStore.from_documents(
docs, OpenAIEmbeddings(model="text-embedding-3-small", dimensions=512), index=pc.Index("idx")
) # Error: dimension mismatch!
# CORRECT: Match dimensions
embeddings = OpenAIEmbeddings() # Default 1536