AI & Agents

Python: LangChain and LangGraph, Current State

LangChain got a reputation for abstraction it has partly earned and partly outgrown. Where the split with LangGraph leaves things, and when either is the right dependency.

A linear chain of nodes beside a branching graph with a feedback cycle

The short version

  • The criticism of early LangChain was fair: abstractions that hid the prompt made debugging worse than writing the call yourself.
  • The split into LangChain (model and tool integrations) and LangGraph (stateful execution) resolved most of that by separating two problems that were tangled together.
  • LangGraph is a good answer to a specific problem: durable, resumable, inspectable multi-step execution with state.
  • For a single prompt and a response, call the provider SDK. A framework earns its place when you need what it does around the model, not the call itself.

Few libraries have generated as much argument as LangChain. It was the default way to build with language models for about a year, then became the thing experienced engineers said they had ripped out, and has since quietly become useful again in a narrower way.

Both the enthusiasm and the backlash were about the same property, and it is worth being precise about what actually changed.

What the criticism got right

Early LangChain wrapped everything. A chain composed of a prompt template, a model and an output parser looked elegant in a tutorial and became difficult the moment it misbehaved, because the thing you needed to see — the exact string sent to the model — was several layers of abstraction away.

The specific complaints, all of which were legitimate:

  • Hidden prompts. When output is wrong, the first question is always what the model was actually asked. An abstraction that makes that hard to answer is a net cost regardless of what else it provides.
  • Abstractions over trivial operations. A wrapper around an HTTP POST is not obviously an improvement on the POST.
  • Leaky provider differences. The uniform interface across providers held until it did not, and then you were debugging both your code and the abstraction.
  • Fast-moving API surface. Documentation and tutorials went stale quickly, which is unpleasant when the library is the thing teaching you the domain.

“We removed LangChain and the code got shorter and easier to debug” was a widely repeated and frequently accurate report.

What the split changed

The important structural change was recognising that two different problems had been merged. Calling a model with the right integrations is one problem. Orchestrating a stateful, multi-step, possibly long-running process is a different one, and it is much harder.

LangChain now concentrates on the first: model interfaces, tool definitions, document loaders, retrievers, output parsing. The abstractions are thinner and there are direct escape hatches to the underlying calls.

LangGraph handles the second, and it is the more interesting piece. You define a graph: nodes are functions, edges route between them, and a state object flows through and is updated by each node. Because execution is a graph rather than a call stack, cycles are natural, and because state is explicit and checkpointed, execution can be paused, inspected, resumed and replayed.

What LangGraph actually buys you

  • Durable execution. State is persisted at each step, so a process can survive a crash, a deployment or an hour-long wait and continue where it left off.
  • Human-in-the-loop as a first-class concept. Interrupt before a consequential node, surface the proposed action for approval, resume on the answer. Bolting this onto an ad hoc loop is genuinely awkward; here it is a supported pattern.
  • Time travel. Rewind to an earlier checkpoint, change something, and re-run from there. For debugging non-deterministic multi-step processes this is worth a great deal.
  • Explicit control flow. The graph is the specification. You can read it and know what the system can do, which is not true of a while loop that hands the model a list of tools and hopes.

The clarifying question. Do you need the process to survive a restart, pause for a human, or be replayed from the middle? If yes, you want a durable execution engine and LangGraph is a reasonable one. If no, a function that calls a model in a loop is genuinely fine and much easier to read.

When to use what

Use the provider SDK directly for a single prompt and response, structured extraction, classification, or anything where you want complete control of the string being sent. The OpenAI and Anthropic Python clients are good, the code is short, and there is no layer between you and the behaviour you are debugging.

Use LangChain components selectively when you want a specific piece — a document loader for an awkward format, a retriever interface, a rate-limited batch runner — without adopting the whole framework. Importing one component is a legitimate and underused option.

Use LangGraph for multi-step processes with real state, human approval gates, long-running or resumable work, or anything where you need to inspect what happened after the fact.

Consider alternatives where the fit is better. Pydantic AI is compelling if you want type-safe structured output and already live in the Pydantic world. Instructor does structured extraction with minimal ceremony. Temporal is worth considering if durable execution is your actual requirement and language models are only one of the things you orchestrate — it is a mature workflow engine that predates all of this.

The honest default: start without a framework. Add one when you can name the specific thing you need it to do. That order keeps the dependency proportional to the problem.

The cost of the dependency

Any framework in this space carries costs that are easy to overlook while it is helping.

Version churn. The libraries move quickly, and moving quickly means breaking changes. Pin versions, upgrade deliberately, and budget for the upgrade rather than discovering it during an incident. This is more of a burden here than with mature infrastructure libraries and it is a real ongoing cost.

Team comprehension. A new engineer joining a project has to learn your domain, the model behaviour, and the framework’s mental model. The third of those is optional complexity, and whether it is worth it depends on how much the framework is actually doing for you.

Debugging through a layer. Even with the improved escape hatches, an unexpected result means asking whether the problem is your logic, your prompt, or the framework’s handling of one of them. Direct SDK calls collapse that to two possibilities, which matters more than it sounds at three in the morning.

None of these are reasons to avoid a framework. They are reasons to be able to name what you are getting in return, and to notice if the answer stops being convincing as the project evolves.

The observability question

Whatever you choose, you need to see what happened. Every prompt, every retrieved document, every tool call and result, every token count, stored and searchable.

LangSmith integrates tightly with both libraries and is the path of least resistance if you are already using them. LangFuse is a strong open-source option that can be self-hosted, which matters if your prompts contain data you cannot send to a third party. OpenTelemetry-based tracing works too and keeps model calls in the same trace as the rest of your system, which is often the most useful view.

The choice matters less than making one. Debugging a multi-step model-driven process without traces is guesswork, and it is the point at which teams typically conclude that the framework is the problem when the real problem is that nothing was recorded.

Boolean Solutions experience with these tools

We build Python AI systems with and without these libraries, and the pattern we would offer is simple. Prototype with direct SDK calls, because that is where you learn what the problem actually is. Introduce structure once the shape of the process is stable and you can point at the specific capability you need — usually persistence, approval gates, or replay.

Teams that reach for a framework on day one tend to spend the first week learning the framework rather than the problem, and then discover the abstraction does not match the shape the problem turned out to have. If you are early in an AI project and weighing this up, we are happy to compare notes.

Further reading

Written by

Udit Mittal

Founder at Boolean Solutions. Twenty years of building and rescuing web, mobile and AI products for SaaS companies and startups — and writing down what actually worked.

Get in touch