Retrieval & RAG Bridge

This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

This page was written against langchain 1.4.3, langchain-core 1.6.5, langchain-classic 1.0.8 and langgraph 1.2.12 on Python 3.12, as verified on 2026-09-29. The running example is DocsAssistant, backed by the pgvector store built in Integrating with LangChain with Ollama’s nomic-embed-text embeddings and llama3.1:8b chat model. Ollama was not available while the snippets were checked, so every output shown here was produced against the real packages with a scripted fake chat model and a small in-memory stub (a keyword-based embedding class over InMemoryVectorStore) in place of pgvector; no output comes from a live model.

This is a bridge page, deliberately short. The vector-store, splitter, retriever and RAG-chain surface of LangChain already has a canonical home in the Vector Databases & RAG section and is linked here rather than repeated. What this page adds is the LangChain-side view: how the building blocks map onto the framework’s packages, which RAG architecture to reach for, and how retrieval plugs into the agents described in Agents with create_agent.

The building blocks

Retrieval in LangChain is a pipeline of interchangeable parts. The official Retrieval page lists five: document loaders, text splitters, embedding models, vector stores and retrievers. Each is an interface with many provider implementations, so any of them can be swapped without touching the rest of the application.

flowchart LR subgraph indexing[Indexing, offline] SRC([Sources]) --> LD[Document loaders] LD --> SP[Text splitters] SP --> EM1[Embeddings] EM1 --> VS[(Vector store)] end subgraph querying[Querying, at run time] Q([Question]) --> EM2[Embeddings] EM2 --> VS VS --> RT[Retriever] RT --> USE[Chain, tool or middleware] USE --> LLM[Chat model] LLM --> ANS([Answer]) end
Figure 1. The LangChain retrieval building blocks and where each lives

Loaders, splitters, embeddings and vector stores return or consume Document objects from langchain-core; splitters ship in the separate langchain-text-splitters package; provider integrations such as langchain-ollama or langchain-postgres sit beside them (see Ecosystem & Packages). The retrieval techniques that v0 kept in langchain.retrievers moved to langchain-classic in 1.x. Nothing in the diagram is specific to agents: the last box, where retrieved text meets the model, is the design decision the rest of this page is about.

The table sends each block to the section that documents it in depth.

Table 1. Where each block is documented
Block Canonical page Anchor

Embeddings

Integrating with LangChain

langchain-embeddings

Vector stores

Integrating with LangChain

langchain-vector-stores

Splitters

Integrating with LangChain

langchain-splitters

Retrievers

Integrating with LangChain

langchain-retrievers

RAG chain

Integrating with LangChain

langchain-rag-chain

Agentic RAG and memory

Integrating with LangChain

langchain-agentic-rag

LangChain4j equivalents

Integrating with LangChain

langchain4j

Chunking choices are in Document Ingestion & Chunking, search strategies in Retrieval Strategies and Hybrid Search & Re-ranking, and the vector databases themselves in PostgreSQL & pgvector, Qdrant RAG Integration Patterns (which uses langchain-qdrant) and Neo4j Vector Search & GenAI.

Choosing an architecture

The official page names three RAG architectures. They differ in who decides to retrieve.

Table 2. The three RAG architectures in LangChain
Architecture How it is built Trade-off

Two-step RAG

Retrieval always runs before generation. In LangChain 1.x, a chain (see LCEL & Runnables) or an agent whose middleware injects the retrieved text.

Predictable latency and cost, at most one retrieval; cannot skip retrieval or retry it.

Agentic RAG

The model gets a retrieval tool and decides when, and how often, to call it (create_agent plus tools).

Flexible, handles follow-ups and multi-hop questions; variable latency, and the model may skip retrieval.

Hybrid RAG

Adds query rewriting, retrieval grading and answer validation around retrieval, usually as a LangGraph graph (see LangGraph Workflows).

Most control over quality; most moving parts.

The concepts behind the agentic and hybrid variants (grading, rewriting, self-correction) are in Agentic RAG and in Workflow Patterns. The next two sections show the two agent-side patterns in LangChain 1.x. Both use the stand-in store described in the lead paragraph.

The stand-in store used by the snippets
from langchain_core.documents import Document
from langchain_core.embeddings import Embeddings
from langchain_core.vectorstores import InMemoryVectorStore

VOCAB = ["hnsw", "ef_search", "recall", "latency", "cosine", "operator", "distance"]


class KeywordEmbeddings(Embeddings):
    """Stand-in for nomic-embed-text: one dimension per keyword."""

    def embed_documents(self, texts):
        return [[float(w in t.lower()) for w in VOCAB] for t in texts]

    def embed_query(self, text):
        return self.embed_documents([text])[0]


# stand-in for DocsAssistant's pgvector store
vector_store = InMemoryVectorStore(KeywordEmbeddings())
vector_store.add_documents([
    Document(page_content="HNSW ef_search trades recall for latency.",
             metadata={"source_path": "ann-indexes.adoc", "section": "HNSW"}),
    Document(page_content="The <=> operator computes cosine distance.",
             metadata={"source_path": "postgresql-pgvector.adoc", "section": "Operators"}),
])
retriever = vector_store.as_retriever(search_kwargs={"k": 1})

In production, vector_store is the pgvector store from the linked page and retriever comes from the same as_retriever call; nothing below depends on the stub. See LangChain — Vector store integrations.

RAG as a tool

The vector-rag page already shows an agentic-RAG agent with a hand-written @tool that calls the store. The alternative, when the whole tool is just "run this retriever", is create_retriever_tool from langchain_core.tools. It wraps any retriever as a tool with a single query argument, joins the returned documents into the text the model sees, and with response_format="content_and_artifact" keeps the Document objects on the side as the tool message’s artifact (see Tools for how artifacts work), which is what a citation feature needs.

A retriever exposed as a tool and given to create_agent
from langchain.agents import create_agent
from langchain_core.tools import create_retriever_tool

docs_tool = create_retriever_tool(
    retriever,
    name="search_docs",
    description="Search the documentation site. Use it for any question about vector search.",
    response_format="content_and_artifact",
)

agent = create_agent(
    model=model,          # ChatOllama(model="llama3.1:8b") in DocsAssistant
    tools=[docs_tool],
    system_prompt="Answer from search_docs results only.",
)
result = agent.invoke({"messages": [{"role": "user", "content": "What does ef_search control?"}]})

Run against the scripted fake model, which is told to call search_docs once and then answer, the tool’s schema and the resulting message trace are:

Output with the scripted fake model
search_docs {'query': {'description': 'query to look up in retriever', 'title': 'Query', 'type': 'string'}}
HumanMessage | What does ef_search control?
AIMessage |
ToolMessage | HNSW ef_search trades recall for latency.
AIMessage | ef_search trades recall for latency (ann-indexes.adoc).
['ann-indexes.adoc']

The last line is [d.metadata["source_path"] for d in result["messages"][2].artifact]: the model saw only the text, while the application receives the source paths to render as citations. The tool has no filter or page arguments; when retrieval needs metadata filters, pagination or concise-versus-detailed responses, write the tool by hand as described in Tool Design. See LangChain reference: create_retriever_tool and LangChain: Agents.

Two-step RAG with a dynamic prompt

When retrieval should always happen, an agent is not needed to decide anything, but a create_agent graph is still useful for its middleware, memory and streaming. The @dynamic_prompt middleware computes the system prompt from the request just before each model call, so it can run the retriever on the latest user message and place the results in the prompt. The agent then has no tools and makes exactly one model call:

Two-step RAG as middleware
from langchain.agents import create_agent
from langchain.agents.middleware import ModelRequest, dynamic_prompt


@dynamic_prompt
def with_context(request: ModelRequest) -> str:
    question = request.messages[-1].text
    docs = retriever.invoke(question)
    context = "\n\n".join(f"[{d.metadata['source_path']}] {d.page_content}" for d in docs)
    return f"Answer using only this context:\n\n{context}"


rag = create_agent(model=model, tools=[], middleware=[with_context])
out = rag.invoke({"messages": [{"role": "user", "content": "What does ef_search control?"}]})

Capturing the system message the fake model received shows what the middleware built:

System prompt received by the model
Answer using only this context:

[ann-indexes.adoc] HNSW ef_search trades recall for latency.

The retrieved passages never enter the stored conversation, only the model request, so long chats do not accumulate old context. The cost is that the model cannot ask for a second, better-targeted search; that trade-off is the reason to pick the previous pattern instead. See LangChain: Custom middleware and Middleware for the full hook list.

For corpora too large to keep in one context, Deep Agents (see Multi-Agent & Deep Agents) document a variant that retrieves, offloads the chunks to a filesystem backend and delegates their analysis to subagents; see LangChain: RAG with Deep Agents.

Evaluating and going to production

Whether retrieval actually helps is measured, not assumed: Evaluating RAG Systems defines the retrieval and generation metrics, and Evaluation runs them as LangSmith experiments on DocsAssistant. Conversational RAG with follow-up rewriting, citation formatting, serving RAG over an API, and query transformation or text-to-SQL routing are the subject of RAG Systems in Production (see Conversational RAG & Memory, Citations & Grounding, Serving RAG as an API and Query Understanding & Routing); this page stops at the LangChain building blocks. Conversation state for an agent that uses either pattern above comes from Short-Term Memory & Checkpointers, and vector-backed long-term memory from Long-Term Memory & Stores.