langchain-rag

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

Más skills de langchain-ai

langgraph-docs
langchain-ai
Accede a la documentación de LangGraph para construir agentes con estado y flujos de trabajo multiagente. Obtiene la documentación oficial de LangGraph en Python que cubre máquinas de estado, diseño de agentes basado en grafos y patrones de intervención humana. Prioriza la documentación relevante según el tipo de consulta: guías de implementación para preguntas de procedimiento, páginas conceptuales para teoría, tutoriales para ejemplos completos y referencias de API para detalles técnicos. Selecciona automáticamente de 2 a 4 URL de documentación más relevantes y recupera su contenido para responder...
official
langgraph-human-in-the-loop
langchain-ai
Pausar la ejecución del grafo para revisión, aprobación o validación humana, luego reanudar con su entrada. Requiere tres componentes: un checkpointer (InMemorySaver o PostgresSaver), un ID de hilo en la configuración y cargas de interrupción serializables en JSON. interrupt(value) pausa y expone datos; Command(resume=value) reanuda y devuelve ese valor al nodo pausado. Todo el código antes de interrupt() se re-ejecuta al reanudar, por lo que los efectos secundarios deben ser idempotentes (usar upsert, no insert). Soporta flujos de aprobación,...
official
web-research
langchain-ai
Usa esta habilidad para solicitudes relacionadas con investigación web; proporciona un enfoque estructurado para realizar investigaciones web exhaustivas.
official
langchain-oss-primer
langchain-ai
SIEMPRE EMPIEZA AQUÍ para cualquier proyecto de construcción de agentes LangChain, Deep Agents o LangGraph. Punto de partida requerido antes de elegir otras habilidades o escribir cualquier…
official
skill-creator
langchain-ai
Guía para crear habilidades efectivas que extiendan las capacidades del agente con conocimientos especializados, flujos de trabajo o integraciones de herramientas. Usa esta habilidad cuando el usuario…
official
social-media
langchain-ai
Redacta publicaciones para redes sociales específicas de cada plataforma, con contenido respaldado por investigación e imágenes complementarias generadas. Admite publicaciones de LinkedIn (1.300 caracteres con tono profesional) e hilos de Twitter/X (280 caracteres por tuit con formato 1/🧵). Requiere delegar la investigación a un subagente antes de redactar, y luego leer los hallazgos para garantizar precisión y relevancia. Genera automáticamente imágenes llamativas para redes sociales usando la herramienta generate_social_image con composiciones audaces y de alto contraste optimizadas para tamaños pequeños...
official
deep-agents-memory
langchain-ai
Backends de memoria y archivos conectables para Deep Agents con opciones de enrutamiento efímero, persistente e híbrido. Cuatro tipos de backend: StateBackend (efímero, con ámbito de hilo), StoreBackend (persistente entre sesiones), FilesystemBackend (acceso real a disco para desarrollo local) y CompositeBackend (enruta diferentes rutas a diferentes backends). FilesystemMiddleware proporciona seis herramientas de operación de archivos: ls, read_file, write_file, edit_file, glob, grep. CompositeBackend utiliza coincidencia de prefijo más largo para enrutar...
official
deep-agents-orchestration
langchain-ai
Orquestrar subagentes, planificar tareas de múltiples pasos y requerir aprobación humana para operaciones sensibles. Delegar trabajo a subagentes especializados mediante la herramienta de tareas; los subagentes personalizados admiten conjuntos de herramientas aislados y mensajes del sistema, mientras que el subagente "de propósito general" predeterminado hereda la configuración del agente principal. Planificar y rastrear flujos de trabajo complejos con write_todos, organizando tareas en estados pendientes, en curso y completados; requiere un thread_id para la persistencia entre invocaciones. Implementar...
official