Hands-On 7 min read Updated Sep 8, 2026

Retrieval & RAG

A model only knows what it was trained on and whatever you put directly in the prompt. Retrieval-augmented generation - RAG - is how you bridge that gap: instead of retraining anything, you search your own documents for the relevant bits and hand those to the model alongside the question. LangChain's retrieval pieces exist specifically to make that pipeline manageable.

The five stages, in order

Every RAG setup, however fancy it eventually gets, is built from the same five stages:

Load read the files Split chunk it up Embed text to vectors Store vector database Retrieve at query time

The first four stages happen once, up front, when you index your documents. Retrieve happens on every query.

Load - a document loader turns your source files (PDFs, web pages, database rows, whatever) into LangChain Document objects. Split - a text splitter cuts each document into smaller chunks, because embedding an entire 40-page PDF as one unit loses too much precision for retrieval to work well. Embed - an embedding model converts each chunk into a vector: a list of numbers positioned so that chunks with similar meaning end up close together in that space. Store - a vector store keeps those vectors somewhere you can search efficiently by similarity. Retrieve - given a new question, a retriever embeds the question the same way and returns whichever stored chunks are closest to it.

Building the pipeline

The first four stages run once, when you index your documents:

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

# Document loaders now live in their own dedicated packages too - check
# the integrations page for whichever file type or source you're loading
# (PDF, CSV, a specific SaaS tool, etc.) for the current, maintained import
# rather than assuming it's still bundled in one place.
docs = load_documents("handbook.pdf")
chunks = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100).split_documents(docs)

vectorstore = Chroma.from_documents(chunks, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

Then, at query time, the retriever plugs straight into an LCEL chain alongside your prompt and model:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableParallel, RunnablePassthrough

prompt = ChatPromptTemplate.from_template(
    "Answer using only this context:\n{context}\n\nQuestion: {question}"
)

rag_chain = (
    RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
    | prompt
    | model
    | StrOutputParser()
)

answer = rag_chain.invoke("What's our policy on remote work?")

RunnableParallel runs the retriever and passes the original question through side by side, so the prompt template gets both the retrieved context and the question it needs to answer, in one step.

A detail worth getting right early: always use the same embedding model for indexing your documents and for embedding queries at search time. Switching embedding models later means every chunk has to be re-embedded and re-indexed - the vectors from two different models aren't comparable.

A current, practical note on which packages to use

Document loaders, embeddings, and vector store integrations used to mostly live in one large langchain-community package. That package was archived in mid-2026 and is no longer maintained - integrations have moved to dedicated packages like langchain-openai, langchain-chroma, or langchain-pinecone, each maintained separately. If a tutorial you're following imports a loader or vector store from langchain_community, it's worth checking that provider's current integrations page for its actual maintained package before you build on it.

Where this fits with LangGraph: a retriever built this way is just another Runnable - which means it drops straight into a LangGraph node exactly the way any other LangChain piece does, the moment your RAG app needs to loop, re-search, or decide whether it retrieved enough to answer.
Share this guide

Was this guide helpful?

Thanks for the feedback!

Want more hands-on AI builds like this?

APA Mastery runs live, practical sessions on working with modern AI tools - not just theory.

See What's On →
← PreviousPrompts, Models & Output Parsers