Skill v1.0.1
currentLLM-judged scan95/100+2 new
version: "1.0.1" name: langchain-rag description: "INVOKE THIS SKILL when building ANY retrieval-augmented generation (RAG) system. Covers document loaders, RecursiveCharacterTextSplitter, embeddings (OpenAI), and vector stores (Chroma, FAISS, Pinecone)."
<overview> Retrieval Augmented Generation (RAG) enhances LLM responses by fetching relevant context from external knowledge sources.
Pipeline:
- Index: Load → Split → Embed → Store
- Retrieve: Query → Embed → Search → Return docs
- 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
</overview>
<vectorstore-selection>
| Vector Store | Use Case | Persistence | |
|---|---|---|---|
| InMemory | Testing | Memory only | |
| FAISS | Local, high performance | Disk | |
| Chroma | Development | Disk | |
| Pinecone | Production, managed | Cloud |
</vectorstore-selection>
Complete RAG Pipeline
<ex-basic-rag-setup> <python> End-to-end RAG pipeline: load documents, split into chunks, embed, store, retrieve, and generate a response.
from langchain_openai import ChatOpenAI, OpenAIEmbeddingsfrom langchain_community.vectorstores import InMemoryVectorStorefrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_core.documents import Document# 1. Load documentsdocs = [Document(page_content="LangChain is a framework for LLM apps.", metadata={}),Document(page_content="RAG = Retrieval Augmented Generation.", metadata={}),]# 2. Split documentssplitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)splits = splitter.split_documents(docs)# 3. Create embeddings and storeembeddings = OpenAIEmbeddings(model="text-embedding-3-small")vectorstore = InMemoryVectorStore.from_documents(splits, embeddings)# 4. Create retrieverretriever = vectorstore.as_retriever(search_kwargs={"k": 4})# 5. Use in RAGmodel = 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> 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 documentsconst docs = [new Document({ pageContent: "LangChain is a framework for LLM apps.", metadata: {} }),new Document({ pageContent: "RAG = Retrieval Augmented Generation.", metadata: {} }),];// 2. Split documentsconst splitter = new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 50 });const splits = await splitter.splitDocuments(docs);// 3. Create embeddings and storeconst embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });const vectorstore = await MemoryVectorStore.fromDocuments(splits, embeddings);// 4. Create retrieverconst retriever = vectorstore.asRetriever({ k: 4 });// 5. Use in RAGconst 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 },]);
</typescript> </ex-basic-rag-setup>
Document Loaders
<ex-loading-pdf> <python> Load a PDF file and extract each page as a separate document.
from langchain_community.document_loaders import PyPDFLoaderloader = PyPDFLoader("./document.pdf")docs = loader.load()print(f"Loaded {len(docs)} pages")
</python> <typescript> 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`);
</typescript> </ex-loading-pdf>
<ex-loading-web-pages> <python> Fetch and parse content from a web URL into a document.
from langchain_community.document_loaders import WebBaseLoaderloader = WebBaseLoader("https://docs.langchain.com")docs = loader.load()
</python> <typescript> 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();
</typescript> </ex-loading-web-pages>
<ex-loading-directory> <python> Load all text files from a directory using a glob pattern.
from langchain_community.document_loaders import DirectoryLoader, TextLoader# Load all text files from directoryloader = DirectoryLoader("path/to/documents",glob="**/*.txt", # Pattern for files to loadloader_cls=TextLoader)docs = loader.load()
</python> </ex-loading-directory>
Text Splitting
<ex-text-splitting> <python> Split documents into chunks using RecursiveCharacterTextSplitter with configurable size and overlap.
from langchain_text_splitters import RecursiveCharacterTextSplittersplitter = RecursiveCharacterTextSplitter(chunk_size=1000, # Characters per chunkchunk_overlap=200, # Overlap for context continuityseparators=["\n\n", "\n", " ", ""], # Split hierarchy)splits = splitter.split_documents(docs)
</python> </ex-text-splitting>
Vector Stores
<ex-chroma-vectorstore> <python> Create a persistent Chroma vector store and reload it from disk.
from langchain_chroma import Chromafrom langchain_openai import OpenAIEmbeddingsvectorstore = Chroma.from_documents(documents=splits,embedding=OpenAIEmbeddings(),persist_directory="./chroma_db",collection_name="my-collection",)# Load existingvectorstore = Chroma(persist_directory="./chroma_db",embedding_function=OpenAIEmbeddings(),collection_name="my-collection",)
</python> <typescript> 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" });
</typescript> </ex-chroma-vectorstore>
<ex-faiss-vectorstore> <python> Create a FAISS vector store, save it to disk, and reload it.
from langchain_community.vectorstores import FAISSvectorstore = 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,)
</python> <typescript> 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);
</typescript> </ex-faiss-vectorstore>
Retrieval
<ex-similarity-search> <python> Perform similarity search and retrieve results with relevance scores.
# Basic searchresults = vectorstore.similarity_search(query, k=5)# With scoresresults_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> Perform similarity search and retrieve results with relevance scores.
// Basic searchconst results = await vectorstore.similaritySearch(query, 5);// With scoresconst resultsWithScore = await vectorstore.similaritySearchWithScore(query, 5);for (const [doc, score] of resultsWithScore) {console.log(`Score: ${score}, Content: ${doc.pageContent}`);}
</typescript> </ex-similarity-search>
<ex-mmr-search> <python> Use MMR (Maximal Marginal Relevance) to balance relevance and diversity in search results.
# MMR balances relevance and diversityretriever = vectorstore.as_retriever(search_type="mmr",search_kwargs={"fetch_k": 20, "lambda_mult": 0.5, "k": 5},)
</python> </ex-mmr-search>
<ex-metadata-filtering> <python> Add metadata to documents and filter search results by metadata properties.
# Add metadata when creating documentsdocs = [Document(page_content="Python programming guide",metadata={"language": "python", "topic": "programming"}),]# Search with filterresults = vectorstore.similarity_search("programming",k=5,filter={"language": "python"} # Only Python docs)
</python> </ex-metadata-filtering>
<ex-rag-with-agent> <python> Create an agent that uses RAG as a tool for answering questions.
from langchain.agents import create_agentfrom langchain.tools import tool@tooldef 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?"}]})
</python> <typescript> 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?" }],});
</typescript> </ex-rag-with-agent>
<boundaries>
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
</boundaries>
<fix-chunk-size> <python> 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)# CORRECTsplitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
</python> <typescript> Chunk size 500-1500 is typically good.
// WRONG: Too small or too largeconst splitter = new RecursiveCharacterTextSplitter({ chunkSize: 50 });// CORRECTconst splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });
</typescript> </fix-chunk-size>
<fix-chunk-overlap> <python> Use overlap (10-20% of chunk size) to maintain context at boundaries.
# WRONG: No overlap - context breaks at boundariessplitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)# CORRECT: 10-20% overlapsplitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
</python> </fix-chunk-overlap>
<fix-persist-vectorstore> <python> Use persistent vector store instead of in-memory to avoid data loss.
# WRONG: InMemory - lost on restartvectorstore = InMemoryVectorStore.from_documents(docs, embeddings)# CORRECTvectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./chroma_db")
</python> <typescript> Use persistent vector store instead of in-memory to avoid data loss.
// WRONG: Memory - lost on restartconst vectorstore = await MemoryVectorStore.fromDocuments(docs, embeddings);// CORRECTconst vectorstore = await Chroma.fromDocuments(docs, embeddings, { collectionName: "my-collection" });
</typescript> </fix-persist-vectorstore>
<fix-consistent-embeddings> <python> 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 modelembeddings = OpenAIEmbeddings(model="text-embedding-3-small")vectorstore = Chroma.from_documents(docs, embeddings)retriever = vectorstore.as_retriever() # Uses same embeddings
</python> <typescript> 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
</typescript> </fix-consistent-embeddings>
<fix-faiss-deserialization> <python> 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. </python> </fix-faiss-deserialization>
<fix-dimension-mismatch> <python> Ensure embedding dimensions match the vector store index dimensions.
# WRONG: Index has 1536 dimensions but using 512-dim embeddingspc.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 dimensionsembeddings = OpenAIEmbeddings() # Default 1536
</python> </fix-dimension-mismatch>