LangChain vs LlamaIndex for RAG Pipelines

The same RAG pipeline built in LangChain and in LlamaIndex, a side-by-side list of their prebuilt components, and which framework fits each common use case.

On this page 8 sections
  1. 01How each framework thinks about RAG
  2. 02The example pipeline
  3. 03Prebuilt components compared
  4. 04Advanced retrieval techniques out of the box
  5. 05Head-to-head comparison
  6. 06Which to choose for each use case
  7. 07Using both together
  8. 08Mistakes to avoid with either framework

LangChain and LlamaIndex can both build a production RAG pipeline. They start from different places. LlamaIndex is a data framework: its best parts are about getting documents in, split well and retrieved accurately. LangChain is an orchestration framework: its best parts are about chaining models, tools and steps, and with LangGraph, running agents that keep state.

So the short answer is:

  • If the hard part of your project is retrieval quality over messy documents, start with LlamaIndex.
  • If the hard part is what happens around retrieval (tools, multi-step logic, approvals, an agent that does more than answer questions), start with LangChain and LangGraph.
  • If both are hard, use both. They work well together.

The rest of this guide shows why, with the same pipeline built in each, a component-by-component comparison and a recommendation for each common use case.

How each framework thinks about RAG

A RAG pipeline has two halves:

  1. Ingestion: load documents, parse them, split them into chunks, embed the chunks and store them in a vector database.
  2. Query: take a question, retrieve the relevant chunks, optionally rerank them, and have a model write an answer from them with sources.

LlamaIndex is built around this pipeline. Its core objects are the stages themselves: readers, node parsers, indexes, retrievers, postprocessors, response synthesizers and query engines. Defaults are chosen for you, so a working pipeline takes a few lines, and each stage can be swapped out when the defaults stop being good enough.

LangChain gives you the building blocks (loaders, splitters, embeddings, vector stores, retrievers) as interchangeable integrations, and leaves the shape of the pipeline to you. Since LangChain 1.0, the recommended way to put RAG in front of users is an agent built with create_agent, with retrieval exposed as a tool. Agents run on LangGraph, which handles state, memory, streaming and human-in-the-loop steps.

The example pipeline

An internal assistant that answers employee questions from a folder of HR handbook files, and cites the file each answer came from.

Built in LlamaIndex

Python
from llama_index.core import Settings, SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.postprocessor import SentenceTransformerRerank
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI

Settings.llm = OpenAI(model="gpt-5-mini")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")

# Ingestion: load, split, embed and index
documents = SimpleDirectoryReader("./handbook", recursive=True).load_data()
index = VectorStoreIndex.from_documents(
    documents,
    transformations=[SentenceSplitter(chunk_size=512, chunk_overlap=64)],
)
index.storage_context.persist("./storage")  # or pass a vector store such as Qdrant or pgvector

# Query: retrieve 10 candidates, rerank to the best 3, then answer
query_engine = index.as_query_engine(
    similarity_top_k=10,
    node_postprocessors=[
        SentenceTransformerRerank(model="cross-encoder/ms-marco-MiniLM-L-6-v2", top_n=3),
    ],
)

response = query_engine.query("How many days of parental leave do we offer?")
print(response)
for node in response.source_nodes:
    print(node.metadata["file_name"], round(node.score, 2))

Reranking, source tracking and the answer prompt are all built in. To make it a multi-turn chat, swap as_query_engine() for as_chat_engine(chat_mode="condense_plus_context").

Built in LangChain

Python
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_chroma import Chroma
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Ingestion: load, split, embed and store
docs = DirectoryLoader("./handbook", glob="**/*.md", loader_cls=TextLoader).load()
chunks = RecursiveCharacterTextSplitter(chunk_size=1500, chunk_overlap=200).split_documents(docs)
vector_store = Chroma.from_documents(
    chunks,
    OpenAIEmbeddings(model="text-embedding-3-small"),
    persist_directory="./chroma",
)

# Query: retrieval is a tool the agent decides when to call
@tool(response_format="content_and_artifact")
def search_handbook(query: str):
    """Search the employee handbook for policies and procedures."""
    results = vector_store.similarity_search(query, k=4)
    text = "\n\n".join(f"Source: {doc.metadata['source']}\n{doc.page_content}" for doc in results)
    return text, results

agent = create_agent(
    model="openai:gpt-5-mini",
    tools=[search_handbook],
    system_prompt=(
        "You answer questions about the employee handbook. Always search it first "
        "and cite the source file. If the handbook doesn't cover it, say so."
    ),
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "How many days of parental leave do we offer?"}]}
)
print(result["messages"][-1].content)

There is a bit more code, but the shape is different in a useful way: the agent can call search_handbook more than once, rephrase its query, or skip retrieval for "hello". Adding a second tool, such as get_leave_balance(employee_id), is one more function in the tools list. If you want retrieval to always run exactly once, a two-step chain (retrieve, then prompt the model) is simpler and cheaper than an agent.

One detail that catches people moving between the two: LlamaIndex's SentenceSplitter measures chunks in tokens, LangChain's RecursiveCharacterTextSplitter measures in characters unless you build it with from_tiktoken_encoder. That's why the chunk sizes above differ.

Prebuilt components compared

Pipeline stageLlamaIndexLangChain
Loading documentsSimpleDirectoryReader handles PDFs, Word, Markdown and more out of the box, plus hundreds of readers on LlamaHubHundreds of document loaders in langchain-community and partner packages (PDF, web, Notion, Google Drive, S3 and so on)
Parsing complex filesLlamaParse (paid, via LlamaCloud) for tables, charts and scanned PDFs; MarkdownElementNodeParser for tablesIntegrations such as Unstructured, Docling and PyMuPDF; no first-party parser
ChunkingSentenceSplitter, TokenTextSplitter, SemanticSplitterNodeParser, MarkdownNodeParser, HierarchicalNodeParser, SentenceWindowNodeParserRecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter, HTMLHeaderTextSplitter, code-aware splitters, token splitters
Ingestion pipelineIngestionPipeline with caching and a docstore that skips unchanged documents on re-runsThe indexing API with a record manager to skip duplicates and remove deleted documents
Embeddings and vector storesIntegrations for all major providers and databasesIntegrations for all major providers and databases
Index typesVector, summary, keyword and property graph indexesVector stores only; graph RAG through separate integrations
RetrieversVector, BM25, QueryFusionRetriever (hybrid and multi-query), AutoMergingRetriever, RecursiveRetriever, router retrieverVector store retriever, BM25, EnsembleRetriever (hybrid), MultiQueryRetriever, ParentDocumentRetriever, SelfQueryRetriever, MultiVectorRetriever
Reranking and filteringNode postprocessors: cross-encoder, Cohere and LLM rerankers, similarity cutoff, metadata replacement for sentence windowsContextualCompressionRetriever with Cohere, cross-encoder or LLM-based compressors
Answer generationResponse synthesizers (compact, refine, tree_summarize), CitationQueryEnginePrompt templates and chat models you compose yourself, or the agent's final answer
Multi-source questionsRouterQueryEngine, SubQuestionQueryEngine, SQL and pandas query enginesAgent with several retrieval tools, SQL toolkit
Chat and memoryChat engines with built-in condensing of follow-up questions, memory modulesLangGraph checkpointers for conversation state, long-term memory stores
Agents and orchestrationFunctionAgent, AgentWorkflow, event-driven Workflowscreate_agent on LangGraph, with middleware, human-in-the-loop interrupts and durable execution
EvaluationBuilt-in faithfulness, relevancy, correctness and retriever (hit rate, MRR) evaluatorsLangSmith datasets and evaluators (commercial, with a free tier), or open tools such as Ragas
TracingOne-line integrations with Arize Phoenix, Langfuse and othersLangSmith, plus Langfuse and other integrations
Managed platformLlamaCloud: hosted parsing, ingestion and retrievalLangSmith: tracing, evaluation and agent deployment

Note that in LangChain 1.0, several older chains and retriever helpers moved to the langchain-classic package. They still work, but newer tutorials build the same things with agents and plain functions, so check the date on any example you copy.

Advanced retrieval techniques out of the box

These are the techniques that usually separate a demo from a system people trust. Both frameworks cover most of them. The difference is how much you write yourself.

TechniqueWhat it fixesLlamaIndexLangChain
Hybrid search (keyword + vector)Missed exact terms such as product codes and namesQueryFusionRetriever over vector and BM25 retrievers, or the vector database's own hybrid modeEnsembleRetriever over vector and BM25 retrievers, or the database's hybrid mode
RerankingRight chunk retrieved but ranked too lowOne postprocessorCompression retriever wrapper
Small-to-big retrievalSmall chunks match well but lack contextSentenceWindowNodeParser, AutoMergingRetrieverParentDocumentRetriever
Multi-query / query rewritingVague or badly worded questionsQueryFusionRetriever with num_queries, HyDE transformMultiQueryRetriever, or let the agent rephrase
Metadata filteringAnswers from the wrong department, year or customerMetadata filters on retrievers, auto-retrievalFilters on the vector store, SelfQueryRetriever
Questions that span documents"Compare our 2025 and 2026 policies"SubQuestionQueryEngineAn agent calling the search tool once per document
Tables in PDFsNumbers lost or scrambled in chunkingLlamaParse plus recursive retrieval over table summariesMultiVectorRetriever with table summaries, built yourself
Knowledge graphsQuestions about relationships between entitiesPropertyGraphIndexGraph database integrations, more assembly required

In general, LlamaIndex has a named component for each technique, and LangChain gives you the pieces to build it. Neither choice fixes bad source documents: clean parsing and sensible chunking matter more than any retriever on this list.

Head-to-head comparison

LlamaIndexLangChain
Main strengthIngestion and retrieval qualityOrchestration, tools and agents
Time to first working RAGMinutes, with good defaultsA little longer, with more choices to make
Abstraction levelHigher: query engines hide the plumbingLower: you see and control each step
Customizing the middle of the pipelineSubclass or replace a stageRewrite the function
Agents and multi-step workflowsCapable (Workflows, AgentWorkflow)The strongest part of the ecosystem (LangGraph)
Human-in-the-loop and long-running tasksPossible with WorkflowsBuilt into LangGraph (interrupts, checkpoints, resuming)
Built-in RAG evaluationIncluded in the libraryMainly through LangSmith
IntegrationsVery wide, through LlamaHubThe widest of any LLM framework
DebuggingClear for standard pipelines, harder once defaults are deepClear once you trace with LangSmith or Langfuse
Upgrade churnModerateHistorically high, steadier since 1.0
Community and hiringLargeLarger

Which to choose for each use case

Use caseExampleChooseWhy
Document Q&A over a knowledge baseHR handbook assistant, support docs search, internal wiki botLlamaIndexIt's the case LlamaIndex is designed for. Good defaults, built-in citations, reranking in one line
Complex PDFs with tablesFinancial reports, insurance policies, lab resultsLlamaIndexLlamaParse and table-aware retrieval save weeks of custom parsing work
Comparing many documents"How did vendor A's contract terms change from 2024 to 2026?"LlamaIndexSubQuestionQueryEngine splits the question per document and combines the answers
Support agent that also takes actionsAnswers from the help center, then checks order status or opens a ticketLangChainRetrieval is one tool among several, and LangGraph handles the multi-step logic
Workflows with approvalsDraft a contract clause from past contracts, wait for legal review, then file itLangChainLangGraph's interrupts and checkpoints let a run pause for a person and resume later
Research assistantSearches internal docs and the web, reads results, searches again, writes a reportLangChainLooping, tool-heavy agents are where LangGraph is strongest
Quick proof of concept"Can AI answer questions over our 500 policy PDFs?" in a dayLlamaIndexFewest lines to a result you can show, and easy to grow into a real pipeline
Product that already uses LangChainA SaaS app with LangChain agents adding a "chat with your files" featureLangChainOne framework, one tracing setup, one set of upgrades to manage
SQL plus documents"What did our top 5 customers by revenue say in their last support ticket?"EitherLlamaIndex's router and SQL query engines and a LangChain agent with SQL and search tools both work. Pick based on the rest of your stack
Simple, latency-critical searchAutocomplete-style answers on a high-traffic siteNeitherCall the embedding API and the vector database client directly. Fewer layers, lower latency, nothing to upgrade

Using both together

The two frameworks aren't mutually exclusive, and a common production setup uses each for what it does best: LlamaIndex for ingestion and retrieval, LangChain or LangGraph for the agent.

Python
from langchain.agents import create_agent
from langchain.tools import tool

# Built with LlamaIndex as in the first example: parsing, chunking, hybrid search, reranking
query_engine = index.as_query_engine(similarity_top_k=10, node_postprocessors=[reranker])

@tool
def search_policies(question: str) -> str:
    """Answer a question from the company policy documents, with sources."""
    response = query_engine.query(question)
    sources = ", ".join({node.metadata["file_name"] for node in response.source_nodes})
    return f"{response}\n\nSources: {sources}"

agent = create_agent(
    model="openai:gpt-5-mini",
    tools=[search_policies, get_leave_balance, create_hr_ticket],
    system_prompt="You are the HR assistant...",
)

The retrieval layer can be tuned and evaluated on its own, and the agent can change without touching it.

Mistakes to avoid with either framework

  • Choosing the framework before checking the documents. Scanned PDFs, tables and slide decks need a parsing plan first. The framework comes second.
  • Skipping evaluation. Write 30 to 50 real questions with known answers before tuning anything. Without them, every change to chunking or retrieval is a guess.
  • Copying old tutorials. Both frameworks have changed a lot. Check that an example matches the version you've installed.
  • Using an agent where a pipeline will do. If every question needs exactly one retrieval, a fixed pipeline is faster, cheaper and easier to debug than an agent deciding when to search.
  • Over-abstracting a simple system. If you only need embed, search and answer, a hundred lines of plain Python may be the most maintainable option.

For what a RAG system costs to build and run once you've chosen the stack, see how much RAG development costs.

If you're planning a RAG system and aren't sure which way to build it, tell me about your documents and users. The first step of every RAG project I take on is a short evaluation on your real documents, and the framework choice follows from what it shows.