langchain-rag

작성자: langchain-ai

INVOKE THIS SKILL when building ANY retrieval-augmented generation (RAG) system. Covers document loaders, RecursiveCharacterTextSplitter, embeddings (OpenAI),…

npx skills add https://github.com/langchain-ai/langchain-skills --skill langchain-rag
Retrieval Augmented Generation (RAG) enhances LLM responses by fetching relevant context from external knowledge sources.

Pipeline:

  1. Index: Load → Split → Embed → Store
  2. Retrieve: Query → Embed → Search → Return docs
  3. Generate: Docs + Query → LLM → Response

Key Components:

  • Document Loaders: Ingest data from files, web, databases
  • Text Splitters: Break documents into chunks
  • Embeddings: Convert text to vectors
  • Vector Stores: Store and search embeddings
Vector StoreUse CasePersistence
InMemoryTestingMemory only
FAISSLocal, high performanceDisk
ChromaDevelopmentDisk
PineconeProduction, managedCloud

Complete RAG Pipeline

End-to-end RAG pipeline: load documents, split into chunks, embed, store, retrieve, and generate a response.
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document

# 1. 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},
])
End-to-end RAG pipeline: load documents, split into chunks, embed, store, retrieve, and generate a response.
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 },
]);

Document Loaders

Load a PDF file and extract each page as a separate document.
from langchain_community.document_loaders import PyPDFLoader

loader = PyPDFLoader("./document.pdf")
docs = loader.load()
print(f"Loaded {len(docs)} pages")
Load a PDF file and extract each page as a separate document.
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`);
Fetch and parse content from a web URL into a document.
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://docs.langchain.com")
docs = loader.load()
Fetch and parse content from a web URL into a document using Cheerio.
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";

const loader = new CheerioWebBaseLoader("https://docs.langchain.com");
const docs = await loader.load();
Load all text files from a directory using a glob pattern.
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()

Text Splitting

Split documents into chunks using RecursiveCharacterTextSplitter with configurable size and overlap.
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)

Vector Stores

Create a persistent Chroma vector store and reload it from disk.
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = 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",
)
Create a Chroma vector store connected to a running Chroma server.
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" }
);
Create a FAISS vector store, save it to disk, and reload it.
from langchain_community.vectorstores import FAISS

vectorstore = FAISS.from_documents(splits, embeddings)
vectorstore.save_local("./faiss_index")

# Only load FAISS indexes that you created and fully control.
# The Python FAISS loader uses pickle-backed metadata, so never load
# downloaded, shared, or otherwise untrusted index directories.
loaded = FAISS.load_local(
    "./faiss_index",
    embeddings,
    allow_dangerous_deserialization=True,
)
Create a FAISS vector store, save it to disk, and reload it.
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);

Retrieval

Perform similarity search and retrieve results with relevance scores.
# 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}")
Perform similarity search and retrieve results with relevance scores.
// 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}`);
}
Use MMR (Maximal Marginal Relevance) to balance relevance and diversity in search results.
# MMR balances relevance and diversity
retriever = vectorstore.as_retriever(
    search_type="mmr",
    search_kwargs={"fetch_k": 20, "lambda_mult": 0.5, "k": 5},
)
Add metadata to documents and filter search results by metadata properties.
# 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
)
Create an agent that uses RAG as a tool for answering questions.
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?"}]
})
Create an agent that uses RAG as a tool for answering questions.
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?" }],
});
### What You CAN Configure
  • Chunk size/overlap
  • Embedding model
  • Number of results (k)
  • Metadata filters
  • Search algorithms: Similarity, MMR

What You CANNOT Configure

  • Embedding dimensions (per model)
  • Mix embeddings from different models in same store
Chunk size 500-1500 is typically good.
# 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)
Chunk size 500-1500 is typically good.
// WRONG: Too small or too large
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 50 });

// CORRECT
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });
Use overlap (10-20% of chunk size) to maintain context at boundaries.
# 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)
Use persistent vector store instead of in-memory to avoid data loss.
# WRONG: InMemory - lost on restart
vectorstore = InMemoryVectorStore.from_documents(docs, embeddings)

# CORRECT
vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./chroma_db")
Use persistent vector store instead of in-memory to avoid data loss.
// WRONG: Memory - lost on restart
const vectorstore = await MemoryVectorStore.fromDocuments(docs, embeddings);

// CORRECT
const vectorstore = await Chroma.fromDocuments(docs, embeddings, { collectionName: "my-collection" });
Use the same embedding model for indexing and querying.
# 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
Use the same embedding model for indexing and querying.
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const vectorstore = await Chroma.fromDocuments(docs, embeddings);
const retriever = vectorstore.asRetriever();  // Uses same embeddings
Only opt in to FAISS deserialization for trusted local indexes. Python FAISS indexes include pickle-backed metadata, and untrusted pickle files can execute arbitrary code during loading.
# WRONG: Loading a downloaded, shared, cloud-hosted, or third-party-controlled
# FAISS index with dangerous deserialization enabled.
loaded_store = FAISS.load_local(
    "./untrusted_faiss_index",
    embeddings,
    allow_dangerous_deserialization=True,
)

# CORRECT: Only opt in when the index directory was created by you and has
# remained under your control.
loaded_store = FAISS.load_local(
    "./faiss_index",
    embeddings,
    allow_dangerous_deserialization=True,
)

If you cannot guarantee the provenance of a persisted index, do not load it with allow_dangerous_deserialization=True. Rebuild the index from trusted source documents or use a vector store/backend that does not require pickle deserialization for untrusted files.

Ensure embedding dimensions match the vector store index dimensions.
# 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

langchain-ai의 다른 스킬

langgraph-docs
langchain-ai
LangGraph 문서에 접근하여 상태 기반 에이전트 및 멀티 에이전트 워크플로우를 구축합니다. 공식 LangGraph Python 문서를 가져오며, 상태 머신, 그래프 기반 에이전트 설계, 인간 개입 패턴을 다룹니다. 쿼리 유형에 따라 관련 문서를 우선시합니다: 방법 질문에는 구현 가이드, 이론에는 개념 페이지, 종단 간 예제에는 튜토리얼, 기술 세부 사항에는 API 참조를 제공합니다. 자동으로 가장 관련성 높은 2~4개의 문서 URL을 선택하고 해당 콘텐츠를 검색하여 답변합니다...
official
langgraph-human-in-the-loop
langchain-ai
그래프 실행을 일시 중지하여 사람의 검토, 승인 또는 검증을 받은 후, 입력을 받아 다시 실행합니다. 세 가지 구성 요소가 필요합니다: 체크포인터(InMemorySaver 또는 PostgresSaver), config의 스레드 ID, JSON 직렬화 가능한 인터럽트 페이로드. interrupt(value)는 데이터를 일시 중지하고 표시하며, Command(resume=value)는 다시 시작하여 일시 중지된 노드에 해당 값을 반환합니다. interrupt() 이전의 모든 코드는 다시 시작 시 재실행되므로, 부작용은 멱등성을 가져야 합니다(insert 대신 upsert 사용). 승인 워크플로우를 지원합니다,...
official
web-research
langchain-ai
웹 리서치와 관련된 요청에 이 스킬을 사용하세요. 포괄적인 웹 리서치를 수행하기 위한 체계적인 접근 방식을 제공합니다.
official
langchain-oss-primer
langchain-ai
LangChain, Deep Agents 또는 LangGraph 에이전트 구축 프로젝트를 시작할 때는 항상 여기서 시작하세요. 다른 스킬을 선택하거나 코드를 작성하기 전에 반드시 거쳐야 하는 시작점입니다.
official
skill-creator
langchain-ai
에이전트의 기능을 확장하기 위한 효과적인 스킬을 만드는 가이드로, 특화된 지식, 워크플로우 또는 도구 통합을 포함합니다. 사용자가...
official
social-media
langchain-ai
플랫폼별 소셜 미디어 게시물을 초안 작성하며, 연구 기반 콘텐츠와 함께 생성된 보조 이미지를 제공합니다. 링크드인 게시물(1,300자, 전문적인 어조)과 트위터/X 스레드(트윗당 280자, 1/🧵 형식)를 지원합니다. 작성 전에 하위 에이전트에 연구를 위임한 후, 결과를 읽어 정확성과 관련성을 확인해야 합니다. generate_social_image 도구를 사용하여 자동으로 눈에 띄는 소셜 이미지를 생성하며, 작은 화면에 최적화된 대담하고 대비가 높은 구성을 사용합니다.
official
deep-agents-memory
langchain-ai
Deep Agents를 위한 플러그형 메모리 및 파일 백엔드로, 임시, 영구 및 하이브리드 라우팅 옵션을 제공합니다. 네 가지 백엔드 유형: StateBackend(스레드 범위, 임시), StoreBackend(세션 간 영구), FilesystemBackend(로컬 개발을 위한 실제 디스크 액세스), CompositeBackend(다른 경로를 다른 백엔드로 라우팅). FilesystemMiddleware는 ls, read_file, write_file, edit_file, glob, grep의 여섯 가지 파일 작업 도구를 제공합니다. CompositeBackend는 최장 접두사 일치를 사용하여 라우팅합니다...
official
deep-agents-orchestration
langchain-ai
서브 에이전트를 조율하고, 다단계 작업을 계획하며, 민감한 작업에 대해 인간의 승인을 요구합니다. task 도구를 통해 전문화된 서브 에이전트에 작업을 위임합니다. 맞춤형 서브 에이전트는 격리된 도구 세트와 시스템 프롬프트를 지원하며, 기본 "범용" 서브 에이전트는 메인 에이전트 구성을 상속받습니다. write_todos를 사용하여 복잡한 워크플로우를 계획 및 추적하고, 보류 중, 진행 중, 완료 상태로 작업을 구성합니다. 호출 간 지속성을 위해 thread_id가 필요합니다. 구현...
official