LangChain vs LlamaIndex vs Claude Agent SDK: How to Choose
LangChain, LlamaIndex, and the Claude Agent SDK all help you build applications where a model calls tools, but they start from different centres of gravity. LangChain gives you a configurable agent harness (create_agent) on top of a graph-and-state runtime, with middleware for retries, human approval, and summarisation, across many model providers. LlamaIndex starts from your data: loaders, chunking, indexes, and query engines, with agents built on top. The Claude Agent SDK packages Claude Code's own agent loop, with working file, shell, and search tools, permissions, and hooks, for Claude models.
This guide compares them by what each is built around, shows a current minimal agent in each (from each project's documentation), and covers trade-offs, failure modes, and a common hybrid. Framework APIs move fast, so treat the code as a starting point and check the linked docs for your version. For the Agent SDK in depth, see Claude Agent SDK Quickstart; for retrieval itself, see RAG Evaluation: Retrieval vs Answer Quality.
What each one is built around
LangChain is a general framework for LLM applications. Its current agent entry point is create_agent, which takes a model (a "provider:model" string or a model object), tools (plain Python callables work), and a system prompt, and returns an agent you invoke with messages. Customisation goes through middleware: prebuilt pieces include model and tool retries, PII handling, human-in-the-loop approval, and summarisation. Conversation state persists through a checkpointer and a thread_id. Its strengths are provider portability and explicit control over the steps an agent takes.
LlamaIndex is built for connecting models to data. Its core objects are readers (load documents from files and services), indexes such as VectorStoreIndex (chunk, embed, store), and query engines (retrieve and synthesise an answer). Agents such as FunctionAgent sit on top and can use a query engine as one of their tools. Its strengths are ingestion and retrieval: the part of RAG where most quality problems live.
The Claude Agent SDK exposes the loop behind Claude Code. You call query() with a prompt and options, and Claude reads files, runs commands, edits code, and calls MCP tools until the task is done, while you stream messages. Built-in tools already work, and Claude Code's permission rules, permission modes, hooks, and MCP support carry over. Its strength is agents that act on a codebase or system; its constraint is that it runs Claude models (directly or through Bedrock, Google Cloud, or Foundry).
Quick reference
- All three can call tools and keep conversation state; the differences are in defaults, ecosystems, and which problem gets first-class support.
- LangChain's broader ecosystem includes LangGraph for explicit graphs and LangSmith for tracing and deployment.
- The Agent SDK is not the plain Messages API: the tools are implemented for you, which is the main reason to use it.
Remember this
LangChain centres on a configurable, portable agent harness; LlamaIndex on data and retrieval; the Agent SDK on an agent that already knows how to act.
A minimal agent in each
LangChain (Python):
1from langchain.agents import create_agent2 3def get_weather(city: str) -> str:4 """Get the current weather for a city."""5 return f"It is sunny in {city}."6 7agent = create_agent(8 model="anthropic:<model>",9 tools=[get_weather],10 system_prompt="You are a concise assistant.",11)12result = agent.invoke({"messages": [{"role": "user", "content": "Weather in Oslo?"}]})LlamaIndex (Python), with retrieval as a tool:
1from llama_index.core import VectorStoreIndex, SimpleDirectoryReader2from llama_index.core.agent.workflow import FunctionAgent3from llama_index.llms.openai import OpenAI4 5documents = SimpleDirectoryReader("data").load_data()6query_engine = VectorStoreIndex.from_documents(documents).as_query_engine()7 8async def search_documents(query: str) -> str:9 """Answer questions about the documents in ./data."""10 return str(await query_engine.aquery(query))11 12agent = FunctionAgent(tools=[search_documents], llm=OpenAI(model="gpt-4o-mini"),13 system_prompt="Answer from the documents and cite them.")Claude Agent SDK (TypeScript):
1import { query } from "@anthropic-ai/claude-agent-sdk";2 3for await (const message of query({4 prompt: "Find the failing test in this repo and fix it.",5 options: { allowedTools: ["Read", "Grep", "Edit", "Bash"], permissionMode: "acceptEdits" },6})) {7 if (message.type === "result") console.log(message.subtype);8}Note what each example has to provide. The LangChain and LlamaIndex agents only know the tools you write; the Agent SDK agent can already read, search, edit, and run commands, which is powerful and also the reason it needs tighter permissions.
Quick reference
- The docstrings in the Python examples become tool descriptions; write them for the model, including when not to use the tool.
- LlamaIndex agents are asynchronous; run them inside an event loop.
- Give the Agent SDK only the tools a task needs;
Bashwith auto-approved edits has the reach of a shell session.
Remember this
LangChain and LlamaIndex agents use the tools you define; the Agent SDK starts with real file and shell tools you must restrict.
Trade-offs and failure modes
Each has a characteristic way of going wrong. With LangChain, it is distance from the model call: several layers between your code and the request make it harder to see the exact prompt and tool definitions, so tracing (for example with LangSmith) stops being optional. With LlamaIndex, it is retrieval quality: the agent answers confidently from the wrong chunks, and the fix is in chunking, metadata, and re-ranking, measured separately from the final answer. With the Agent SDK, it is reach: an agent that can edit files and run commands will do so, so permission rules, sandboxing, and a narrow tool list are part of the design, not an afterthought.
Version churn affects all three. LangChain's agent API changed substantially with create_agent; LlamaIndex moved agents to a workflow-based design; the Agent SDK tracks Claude Code releases. Pin versions and read the changelog before upgrading.
| LangChain | LlamaIndex | Claude Agent SDK | |
|---|---|---|---|
| Built around | Agent harness, middleware, state | Ingestion, indexes, query engines | Claude Code's agent loop and tools |
| Model choice | Many providers | Many providers | Claude (direct or via cloud providers) |
| Built-in tools | You define them | Query engines as tools | Read, Edit, Bash, Grep, WebSearch, MCP |
| Control and safety | Middleware, human-in-the-loop | Your code around the agent | Permission rules, modes, hooks |
| Typical failure | Abstraction layers hide what was sent | Retrieval returns the wrong chunks | An over-permissioned agent does too much |
| Avoid when | A single model call would do | There is no corpus to retrieve from | You need non-Claude models |
Quick reference
- If one model call with a structured output solves the task, none of these frameworks is needed.
- Evaluate retrieval and agent behaviour separately; a good agent cannot fix a bad index.
- Whichever framework you choose, keep tool functions plain and framework-free so they can move.
Remember this
Pick by your hardest problem: control and portability, retrieval quality, or acting on real systems, and plan for that framework's typical failure.
A common hybrid: retrieval behind one tool
Many systems combine them at a clean boundary. LlamaIndex owns ingestion and the index; the agent, built with whichever framework fits, sees retrieval as a single tool:
1# retrieval.py - LlamaIndex only2from llama_index.core import VectorStoreIndex, SimpleDirectoryReader3_engine = VectorStoreIndex.from_documents(SimpleDirectoryReader("docs").load_data()).as_query_engine()4 5async def search_docs(query: str) -> str:6 """Search the internal docs. Use for product or policy questions; not for code."""7 response = await _engine.aquery(query)8 return str(response)That function can be registered as a LangChain tool, a LlamaIndex agent tool, or, wrapped in an MCP server, a tool for the Claude Agent SDK and Claude Code. The boundary keeps responsibilities separate: retrieval can be evaluated and tuned on its own (did the right passages come back?), while agent behaviour is evaluated end to end (did it search when it should, and use the answer correctly?).
Keep the tool's output short and cited. Long retrieved passages fill the agent's context, and uncited answers make it impossible to tell retrieval errors from reasoning errors.
Quick reference
- Exposing retrieval through MCP lets several hosts share one index without each embedding a framework.
- Put access control in the retrieval layer: filter by the user's permissions before results reach the model.
- Return document IDs with each passage so answers can be checked.
Remember this
Let LlamaIndex own the index, expose it as one well-described tool, and let the agent framework own decisions and permissions.
Hands-on: one task, three frameworks
Use a folder of 20 internal documents and one question set of ten questions, half answerable from the documents.
- Build the LlamaIndex index and a
search_docsfunction; check that the top results contain the answer for each answerable question. - Register
search_docswith a LangChaincreate_agentagent and run the ten questions. - Wrap
search_docsin a small MCP server, give it to the Claude Agent SDK withallowedToolslimited to that tool, and run the same questions. - For each run, record correct answers, unnecessary searches, and confident answers to unanswerable questions.
- Read one full trace from each framework and note how easy it was to see the exact prompt and tool calls.
Pass criterion: retrieval is measured separately from answers, all three agents share one retrieval function, and you can state which framework you would ship and why, based on the numbers you recorded.
Quick reference
- If all three fail the same questions, the problem is retrieval, not the framework.
- Keep model and prompt constant across frameworks so the comparison is about the framework.
- Save the question set; it becomes your regression suite for upgrades.
Remember this
Compare frameworks on your own task with shared retrieval; the numbers will decide faster than feature lists.
Key takeaway
LangChain, LlamaIndex, and the Claude Agent SDK overlap, but each is built around a different hard problem. LangChain's create_agent gives a portable, configurable harness with middleware and checkpointed state; LlamaIndex gives loaders, indexes, and query engines for retrieval, with agents on top; the Claude Agent SDK gives Claude Code's loop with working file, shell, and MCP tools and Claude Code's permission model. Choose by where your difficulty is, and plan for each one's typical failure: hidden prompts, wrong chunks, or an over-permissioned agent.
Often the best answer is a hybrid with a clean boundary: retrieval behind one well-described tool, and an agent framework that owns decisions and permissions. For the permission side of agents that act, see Claude Code Permissions; for reliable typed outputs from any of them, see LLM Structured Outputs.
Practice (90 min): run the five-step comparison above on your own documents.
References
- LangChain docs: Agents (create_agent) — checked Oct 17, 2026
- LlamaIndex docs: Starter tutorial — checked Oct 17, 2026
- Claude Agent SDK docs: Overview — checked Oct 17, 2026
Shoaib Hossain
Author, Core Concept LearningRelated Articles
Explore this topic