LangChain vs LangGraph: when you need chains and when you need a graph
LangGraph does not compete with LangChain, it sits underneath. We cover when a chain or create_agent is enough, when you need a stateful graph, with code on one model.
5 min · · development · агенты
The "langchain vs langgraph" question looks like a choice between two libraries, but it is really a choice of abstraction level. The LangChain documentation says it directly: LangGraph is a low-level orchestration runtime, and LangChain agents are built on top of it. Below we explain the difference in plain terms, show minimal code at each level with one model through a gateway and count what a graph with a loop costs.
LangChain vs LangGraph: what differs
LangChain provides components (models, prompts, parsers, tools) and a ready agent, create_agent: a minimal configurable harness around the loop "the model thinks, calls a tool, gets the result". You describe the model, the tools and the system prompt, and the loop is already written.
LangGraph is a runtime where you describe the graph yourself: nodes (functions), edges between them and shared state. The documentation lists its strengths: mixing fixed steps and model-driven steps in one graph, persisting state and resuming after a failure, human intervention at any point, streaming, memory. LangGraph can also be used without LangChain.
The recommendation in the LangChain documentation boils down to this: take create_agent for a customizable agent, and take LangGraph for complex cases where deterministic steps are combined with agentic ones.
| Task | What to take |
|---|---|
| Prompt, model, response parsing in order | A chain of components |
| The model calls tools in a loop | create_agent |
| Branches and returns by condition | LangGraph |
| State between steps and persistence after a failure | LangGraph with a checkpointer |
| A pause and human confirmation | LangGraph |
| A long process that may be interrupted | LangGraph |
Setup
You need a fetch_... key from the dashboard and the address https://api.zukko.pro/v1. Install: pip install langchain langchain-openai langgraph. Connection and the request format are described in the Python reference. The shared part for the examples:
from langchain_openai import ChatOpenAI
writer = ChatOpenAI(
model="claude-sonnet-5-5",
base_url="https://api.zukko.pro/v1",
api_key="fetch_your_key",
)Level 1: a chain
If the steps go in order and there are no branches, you do not need a graph:
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[("system", "Answer briefly."), ("user", "{question}")]
)
chain = prompt | writer | StrOutputParser()
print(chain.invoke({"question": "What is prompt caching?"}))The | operator glues components into a pipeline. This is the cheapest option by request count: one model call.
Level 2: an agent with a tool
When the model itself decides which function to call and how many times, take create_agent:
from langchain.agents import create_agent
PRICES = {"claude-sonnet-5-5": (0.4, 2.0), "gpt-6.1-sol": (0.27, 1.32)}
def get_price(model: str) -> str:
"""Return the model's input and output price in dollars per 1M tokens."""
pin, pout = PRICES[model]
return f"input {pin}, output {pout}"
agent = create_agent(model=writer, tools=[get_price], system_prompt="You are a pricing assistant.")
result = agent.invoke({"messages": [{"role": "user", "content": "What is the output price of gpt-6.1-sol?"}]})
print(result["messages"][-1].content)For an agent it matters that the model supports tool calling. Check it on the chosen model with one test request. The loop is hidden here: you do not control how many times the model calls a tool, apart from the system prompt and key limits.
Level 3: a graph with state
Now a task with control: write a text, check it with a second model and, if the check fails, rewrite it, but no more than three attempts. This is an explicit loop with a condition, and a graph describes it conveniently.
from typing import TypedDict
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import END, START, StateGraph
checker = ChatOpenAI(
model="deepseek-v4.1-flash",
base_url="https://api.zukko.pro/v1",
api_key="fetch_your_key",
temperature=0,
)
class State(TypedDict):What happens here. State is a shared dictionary that every node reads and partly updates. The write and check nodes are ordinary functions. A plain edge leads from write to check, and a conditional edge after check decides whether to finish or go back. The InMemorySaver checkpointer stores state per thread_id, so a run can be inspected or continued, and in production it is replaced by storage on disk or in a database. One saving detail: the checking node uses a cheap model, and a graph lets you pick a model per step.
Pitfalls
- The address. In both classes
base_urlends with/v1, because this is an OpenAI-compatible client. Without the suffix requests go to a path that does not exist and return 404. - A loop costs money. Every pass through the graph makes new requests. That is why the router has an attempt counter and the key has a daily dollar spend limit; when it runs out the gateway returns 429
key_daily_limit_reached. More: how to limit a key's spend. Also look in the LangGraph documentation for therecursion_limitparameter, which bounds the number of execution steps. - Claude cache. In the OpenAI format (and ChatOpenAI works exactly that way by default) all Claude input is billed at the input price. If you have a long repeating context, see the cache calculation in the article on cache reads and writes.
What the loop costs
Prices as of October 18, 2026, per 1M tokens. One pass through the graph: write on claude-sonnet-5-5 (input 0.4, output 2) with 300 input and 150 output tokens; check on deepseek-v4.1-flash (input 0.013, output 0.038) with 250 input and 5 output tokens.
- write: 300 × 0.4 + 150 × 2 = 120 + 300 = 420 micro-dollars.
- check: 250 × 0.013 + 5 × 0.038 = 3.25 + 0.19 = 3.44 micro-dollars.
- A pass: 423.44 micro-dollars. Worst case, three passes: 3 × 423.44 = 1,270.32, about $0.0013 per document, about $1.27 per 1,000 documents.
If the same claude-sonnet-5-5 did the checking, check would cost 250 × 0.4 + 5 × 2 = 110 micro-dollars and a pass 530. Most of the cost is in the generation node, so a cheap checker saves little but does no harm: whether such a model is good enough for checking is decided by a test on your texts. Prices and the model list: GET https://api.zukko.pro/v1/models. Payment: SBP (the payment page adds an 8.5% fee on top), cryptocurrency or MasterCard. Basic LangChain connection: LangChain: pointing it at our base_url.
FAQ
Does LangGraph need LangChain?
No. The LangGraph documentation says directly that it can be used without LangChain, but LangChain components are convenient for models and tools.
Are chains obsolete?
For linear tasks they remain the simplest option. In the current documentation the main entry point for agents is create_agent.
What is Deep Agents?
Per the documentation, it is a more ready-made agent with automatic context compression, a virtual filesystem and subagent spawning, built on LangChain agents. You take it when you want more ready-made behavior out of the box.
Do I need LangSmith?
It is optional. It is a separate service for tracing and evaluation that you connect if you want. To begin, logs and the "Usage" section of the Zukko dashboard are enough.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- Prompt Injection: What It Is and How to Protect a Bot and an AgentHow prompt injection works through user input and third-party documents, and which measures limit the damage: data isolation, tool permissions, key limits.
- Claude Code YOLO: Permission Modes and Working Without PromptsClaude Code has no mode literally called YOLO, but it has several permission modes and flexible rules. How to stop clicking Yes without losing files.
- Claude Code: a checklist of best practices for daily workHabits that make working with Claude Code predictable: a short CLAUDE.md, a plan before edits, small tasks, checking results and keeping spend under control.
- An MCP server in Java: a minimal example with one toolWe write a minimal MCP server in Java with one tool, register it in Claude Code, and learn to find the cause when the agent doesn't see it.