LangChain vs LangGraph: Roles, Users, and When to Reach for Each
What LangChain owns and what LangGraph owns: chains versus durable graphs, who each library is really for, and an operational checklist for picking one.
This article is published in English.
This walkthrough rebuilds an operable path for: LangChain and LangGraph Explained: What They Are, Who Uses Them, and How to Build AI Agents with Them. Focus on contracts, checks, and code you can drop into a repo without guessing intent. For Overview, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph.
llm = ChatOpenAI()
if (userAskedForFlights()) {
callFlightApi();
}
if (resultsAvailable()) {
summarizeResults();
}
User Question
↓
Reason
↓
Search Tool
↓
Analyze Result
↓
Answer
User Request
|
+---- Search
|
+---- Database
|
+---- Human Approval
|
v
Continue
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4o"
)
def get_weather(city):
return weather_api(city)
tools = [get_weather]
Need weather information
weather = get_weather("Bangalore")
{
"temperature": 34,
"condition": "Sunny"
}
The current temperature in Bangalore is 34°C and the weather is sunny.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4o"
)
response = llm.invoke(
"Explain microservices in simple terms."
)
print(response.content)
User Request
|
v
Analyze Request
|
+---- Search Agent
|
+---- Database Agent
|
+---- Human Review
|
v
Generate Final Response
from langgraph.graph import StateGraph
builder = StateGraph(AgentState)
builder.add_node("search", search_node)
builder.add_node("answer", answer_node)
builder.set_entry_point("search")
builder.add_edge("search", "answer")
graph = builder.compile()
class AgentState(TypedDict):
question: str
search_result: str
answer: str
Example:
{
"question": "What is LangGraph?",
"search_result": "",
"answer": ""
}
def search_node(state):
...
builder.add_node("search", search_node)
builder.add_node("answer", answer_node)
builder.add_edge(
"search",
"answer"
)
builder.set_entry_point("search")
graph = builder.compile()
State
│
▼
┌─────────────┐
│ Search │ ← Node
└─────────────┘
│
│ ← Edge
▼
┌─────────────┐
│ Answer │ ← Node
└─────────────┘
│
▼
Updated State
A Message from AI Mind
For A Message from AI Mind, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
Operational checklist
For Operational checklist, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments.
Checkpoint after expensive model calls so a retry does not re-bill the same work.
Keep graph state flat and typed. Nested blobs hide which node wrote which field and break resume after interrupts.
Write a short runbook: how to rotate keys, how to drain the queue, how to roll back the last change.
Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.
Before promoting the stack, freeze versions, capture a golden transcript for the critical path, and confirm rollback steps. Shared environments need rate limits, tenancy checks, and a clear owner for secret rotation. Prefer boring reliability over clever one-off demos.
For hardening note 0, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph.
Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
For hardening note 1, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.
Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
For hardening note 2, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments.
Checkpoint after expensive model calls so a retry does not re-bill the same work.
For hardening note 3, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish.
Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.