1:1 mentoring with Big Tech AI engineers
Back to blog
By AgenticPrep Team10 min read

LangChain vs LlamaIndex vs LangGraph — Which One, and When

Three names, two of them from the same company, and a choice most teams make by vibes. They are not three answers to one question — they are three different layers of the same stack.

langchainllamaindexlanggraphframeworks

Three names, two of them from the same company, and a choice most teams make by vibes. They are not three answers to one question — they are three different layers of the same stack.

Every few weeks someone opens the discussion the same way: “are we going LangChain or LlamaIndex? What about LangGraph?” The comparison feels natural because the names look alike and the READMEs overlap. It is still the wrong comparison, and it produces a predictable outcome — a codebase that adopted one of them for a job it does not do, wrapped in glue that exists to work around the mismatch.

Sort them by the job they own and the choice mostly makes itself.

THE REFRAME

LangChain is an integration layer. LlamaIndex is a data layer. LangGraph is a control layer. Asking which is best is like asking whether requests, SQLAlchemy or Celery is the best Python library — the answer depends entirely on which part of the program you are looking at, and a real system usually has all three parts.

The three jobs, drawn as a stack

Three layers, not three products — and you can adopt any one alone
HIGHER LAYER = MORE OF YOUR CONTROL FLOW LIVES IN THE FRAMEWORK CONTROL FLOW what runs next · what state survives a crash LangGraph DATA & RETRIEVAL parse · chunk · index · get the right passage into the window LlamaIndex INTEGRATIONS & GLUE one interface over many models, stores and tools LangChain THE MODEL CALL messages · tools · streaming · retries provider SDK nothing forces you to take a layer you do not need — the bottom one alone ships a lot of production software

The stack is also the honest version of “do I need a framework at all?” The bottom layer is not a fallback for toy projects. A great deal of shipped LLM software is a provider SDK, a database and some ordinary code.

What each one is actually best at

LangChain — breadth of integrations, composed

Its core value is that a hundred model providers, vector stores, loaders and tools present roughly the same interface, and that you can compose them into a pipeline. That matters most when the set of components is unsettled: you are still choosing a model, evaluating two vector stores, or building something that has to run against whatever a customer already owns. It matters least when you have made those choices and they are not changing.

LlamaIndex — documents into an answerable index

Its center of gravity is everything between a messy corpus and a good retrieval result: connectors, parsing, node/chunk construction, index types, retrievers, postprocessors, query engines. If your hard problem is 40,000 PDFs with tables in them, this is the library whose defaults were chosen by people staring at that exact problem. See document processing and chunking for what it is doing on your behalf.

LangGraph — state and control flow you can inspect

A typed state object, nodes that transform it, and edges that decide what may run next — plus checkpointing, so a run can be resumed, replayed or paused for a human. It is the layer you reach for when the interesting part is not any single call but the branching, retrying and gating between calls. The mental model is graph engineering; the framework is one implementation of it.

THE NAME COLLISION

LangGraph comes from the LangChain team and builds on langchain-core, which is why people assume adopting one means adopting both. You can run a graph whose nodes call a provider SDK directly and never touch a LangChain chain, retriever or agent. Conversely, plenty of LangChain codebases have no graph in them at all. Treat them as separable, because they are.

The decision tree

Three questions, asked about the part of the system that is actually hard. Not the demo — the part that will still be difficult in six months.

Ask what the hard part is — the framework falls out of the answer
Is the hard part what runs next? YES LangGraph branches, cycles, checkpoints NO Is the hard part the documents? YES LlamaIndex parse, index, retrieve NO Do you need many swappable pieces? YES LangChain one interface, many backends NO No framework the provider SDK is enough answer for the part that is hard in month six, not the part that is fiddly in week one

Side by side

LANGCHAINLLAMAINDEXLANGGRAPH
Job it ownsIntegrations and compositionCorpus → retrievable indexControl flow and state
Core abstractionComposable components in a pipelineIndex, retriever, query engineTyped state, nodes, edges
What you writeWiring between componentsIngestion and retrieval configNode functions and routing functions
State between stepsThreaded through the pipelinePer query, largely statelessOne explicit object, checkpointed
Resume after a crashBuild it yourselfBuild it yourselfBuilt in — replay from the last node
Pause for a humanBuild it yourselfBuild it yourselfFirst-class interrupt
Strongest whenThe components are still changingThe documents are messy and plentifulThe path branches, loops or needs a gate
Overkill whenOne model, one store, one pathYour “corpus” is one table or APIThe flow is a straight line
If you rip it outYou rewrite the wiringYou rebuild ingestion and re-indexYour graph shape survives; the API does not

The bottom row is worth more than the rest of the table. Two of these frameworks own code; LlamaIndex also owns data you have already paid to process, which is the more expensive kind of commitment.

THE OVERLAP CAVEAT

Each has grown into the others’ territory — LlamaIndex ships an event-driven workflow engine, LangChain ships retrievers, LangGraph examples do plenty of retrieval. The overlap is real, and it is not where any of them is strongest. Choose on the center of gravity, not on the feature matrix; the feature matrix is where a project ends up using the third-best implementation of everything.

Three scenarios, worked

1 · “Chat over 40,000 internal PDFs”

The control flow here is three steps long: retrieve, answer, cite. Nothing branches. What is genuinely hard is that a third of the PDFs are scanned, half the useful content is inside tables, and the useful chunk boundary is not the paragraph boundary.

LlamaIndex owns this, and the orchestration stays as plain functions. Reaching for a graph here adds a state schema to a problem that has one path; reaching for LangChain adds an abstraction over a vector store you already chose. Your time goes into parsing, chunking and an eval set — and if you find yourself asking whether to fine-tune instead, that is a different decision entirely: see RAG vs fine-tuning.

2 · “A refund agent that needs approval over $50”

One call decides intent. Some paths need a lookup, some need a policy check, refunds over a threshold must reach a human, and a crash halfway through must not re-issue a refund on retry.

LangGraph owns this. Every requirement in that paragraph is a topology statement, and a topology you can draw is a topology you can audit — “approval cannot be skipped” becomes an edge, not a sentence in a system prompt that usually works. Human-in-the-loop and persistence are the two features doing the load-bearing work here, and both are miserable to rebuild by hand.

3 · “Classify a ticket, summarize it, post it to Slack”

No framework. Three calls in a straight line, one file, no state to persist and nothing to decide. A framework here does not reduce the code much and it does make the stack trace worse.

# The version that needs no framework -- and stays readable in a year.
ticket   = fetch(ticket_id)
category = client.messages.create(model=MODEL, messages=classify_prompt(ticket))
summary  = client.messages.create(model=MODEL, messages=summarize_prompt(ticket))
slack.post(channel=ROUTE[category], text=render(summary))

The honest test: if you can write the whole flow as a numbered list and no number says “go back to step 2” or “wait for a person”, you do not have an orchestration problem yet.

How they combine in a real stack

The common production shape does not pick a winner. It is LlamaIndex owning retrieval, exposed to LangGraph as a single node, with the provider SDK underneath.

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from llama_index.core import VectorStoreIndex

# --- data layer: LlamaIndex owns parsing, indexing and retrieval ---
index     = VectorStoreIndex.from_documents(documents)
retriever = index.as_retriever(similarity_top_k=6)

class State(TypedDict):
    question: str
    chunks: list[str]
    answer: str

# --- and shows up upstairs as exactly one node ---
def retrieve(state: State) -> dict:
    nodes = retriever.retrieve(state["question"])
    return {"chunks": [n.get_content() for n in nodes]}

def enough_evidence(state: State) -> str:
    return "answer" if state["chunks"] else "escalate"

# --- control layer: LangGraph owns what runs next, and durability ---
builder = StateGraph(State)
builder.add_node("retrieve", retrieve)
builder.add_node("answer", answer)
builder.add_node("escalate", escalate)
builder.add_edge(START, "retrieve")
builder.add_conditional_edges("retrieve", enough_evidence, ["answer", "escalate"])
builder.add_edge("answer", END)

graph = builder.compile(checkpointer=saver)

Note what the seam buys you. Swapping the retriever for a plain SQL query changes one function. Adding a reranker changes one function. Neither touches the graph, because the graph never knew how retrieval worked — and that is the property to design for, whichever libraries you end up with.

The abstraction tax

What a framework buys

Integrations you would otherwise write and maintain. Defaults chosen by people who have seen more corpora than you have. Durability, retries and interrupts that are genuinely tedious to build. A vocabulary your next hire may already speak, and examples to copy at 2am.

What it costs

A stack trace that goes through six files you did not write. A prompt you can no longer see without turning on debug logging — which is a real problem, because what is in the window is the thing you most need to inspect. Upgrade work on someone else’s schedule, and an abstraction that has to be fought the first time your requirement is slightly unusual.

The tax is worth paying at the layer where your problem is hard, and not at the layers where it is not. That is why the stack diagram matters more than the comparison table: a system can take LlamaIndex for retrieval, keep its own thirty-line loop, and be entirely coherent.

Five checks before you adopt any of them

  • Can you print the exact prompt that was sent? If it takes a debugger to answer that, you have lost the thing you tune most often.
  • Can you see the state between steps? Anything you cannot log, you cannot debug at 3am.
  • What happens on a crash mid-run? If the answer is “start over”, be sure that is acceptable for side-effecting steps — refunds, emails, writes.
  • How do you test one step alone? A node or component you cannot call from a unit test will not be tested.
  • What is the rip-out cost in month nine? Wiring is cheap to redo. A processed corpus is not.
THE TAKEAWAY

Do not pick a framework; pick a layer. Name the part of the system that is genuinely hard — documents, control flow, or an unsettled set of providers — and adopt only the layer that owns it. Systems that chose this way tend to survive both the framework’s next major version and their own change of mind, because each layer can be replaced without the others noticing.

The shape outlives the framework

Retrieval will still be parse → chunk → embed → search → rerank in five years, whatever imports it. A branch with an approval gate will still be a branch with an approval gate. The libraries around those shapes will be renamed, rewritten, merged and deprecated — two of the three here have already been through at least one API era.

Which is the practical reason to learn the shapes rather than the APIs: graph engineering for control flow, loop engineering for the layer above it, and retrieval for the data layer. Then the framework question stops being a decision and becomes an implementation detail — which is what it always was.

Enjoyed this post? The full curriculum has 74+ sections, system design problems, and AI-reviewed practice runs.

See the full guide