LangGraph launched into general availability on May 14, 2025, giving developers managed infrastructure for stateful, long-running AI agents — a capability that previously required stitching together custom orchestration layers. Most teams still default to single-threaded LLM chains because multi-agent architectures feel overwhelming: state persistence, inter-agent communication, human-in-the-loop checkpoints, and deterministic debugging all at once. This guide walks you through building a production-ready autonomous multi-agent system using only open-source tools, drawing on patterns battle-tested in LangChain's own LangGraph Platform rollout.
Quick Answer: Install langgraph and langchain-core, define a StateGraph with typed state schema, add nodes as async functions that read/write shared state, connect edges with conditional routing, compile with a checkpointer (sqlite or postgres), then invoke with a thread_id for persistence. Wrap in FastAPI for serving and add LangSmith tracing for observability.
Why Multi-Agent Systems Need Graph-Based Orchestration
State Is the Hard Part
Traditional LLM chains pass context linearly — input flows through prompt, model, parser, done. Autonomous agents break this model: they loop, branch, wait for human input, and resume days later. LangGraph solves this by treating state as a first-class citizen. Every node reads and writes a shared TypedDict or Pydantic model. The graph compiler snapshots state at each step, enabling time-travel debugging and exactly-once execution semantics. Without this, you're building custom checkpointing logic that breaks under concurrency.
Deterministic Control Flow Beats Prompt Engineering
Prompt-only agent loops (ReAct, AutoGPT-style) rely on the model to decide "what's next" via text generation. That works for demos; it fails in production when the model hallucinates a tool name or skips a required validation step. LangGraph moves control flow into Python: edges are explicit, conditional routing uses real logic, and you can unit-test every transition. A 2024 LangChain benchmark showed graph-orchestrated agents achieved 94% task completion vs. 67% for prompt-only loops on the same tool set.
Human-in-the-Loop as a Graph Primitive
Real workflows pause for approval — expense reports, code merges, medical decisions. LangGraph's interrupt() function halts execution mid-graph, serializes state, and resumes only after an external signal. The open-source checkpointer (sqlite for dev, postgres for prod) stores the exact node, state, and stack frame. No custom queue or webhook handler required. This pattern powers LangGraph Platform's own review workflows.
Step-by-Step: Build a Research Agent Swarm
1. Scaffold the Project with Minimal Dependencies
pip install langgraph langchain-core langchain-openai sqlite-utils— core graph, state types, OpenAI integration, local persistence.- Create
pyproject.tomlwithpython >= 3.10(required for pattern matching in conditional edges). - Add
.envwithOPENAI_API_KEYand optionalLANGSMITH_API_KEYfor tracing.
This installs ~45 MB total — no heavy frameworks, no managed services. The same stack runs locally and in Kubernetes.
2. Define Typed State Schema
- Create
state.pywith aResearchStateTypedDict:topic: str,queries: list[str],findings: list[dict],report: str | None,iteration: int,max_iterations: int. - Add
config_schemafor runtime params:model_name,temperature,search_tool. - Use
Annotated[list, operator.add]forfindingsso parallel nodes can append safely.
Typed state catches schema drift at compile time. The operator.add reducer merges concurrent writes without race conditions — critical when researcher and critic agents run in parallel.
3. Implement Agent Nodes as Pure Async Functions
planner_node(state, config): calls LLM to decompose topic into 3-5 search queries, returns{"queries": [...], "iteration": 0}.researcher_node(state, config): for each query, invokes Tavily or SerpAPI, extracts snippets, appends tofindingswith source URLs.critic_node(state, config): evaluates findings for gaps, returns{"queries": new_queries}or empty list if satisfied.writer_node(state, config): synthesizes findings into final report, returns{"report": markdown}.
Each node is <100 lines, testable with pytest by passing a mocked state dict. No base classes, no lifecycle hooks.
4. Wire the Graph with Conditional Edges
- Create
StateGraph(ResearchState). - Add nodes:
add_node("planner", planner_node),add_node("researcher", researcher_node),add_node("critic", critic_node),add_node("writer", writer_node). - Set entry point:
set_entry_point("planner"). - Add fixed edges:
add_edge("planner", "researcher"),add_edge("researcher", "critic"). - Add conditional edge from critic:
add_conditional_edges("critic", should_continue, {"continue": "researcher", "write": "writer"})whereshould_continuecheckslen(state["queries"]) > 0 and state["iteration"] < state["max_iterations"]. - Set finish point:
set_finish_point("writer").
5. Compile with Checkpointer and Deploy
- Import
SqliteSaver.from_conn_string("checkpoints.db")for local dev. - Compile:
app = graph.compile(checkpointer=checkpointer). - Invoke:
await app.ainvoke({"topic": "LangGraph multi-agent patterns"}, config={"configurable": {"thread_id": "run-123"}}). - Resume after interrupt:
await app.ainvoke(Command(resume=user_feedback), config={"configurable": {"thread_id": "run-123"}}). - Wrap in FastAPI:
@app.post("/runs")creates thread,@app.post("/runs/{thread_id}/resume")handles human input.
The same compiled graph runs unchanged in Cloud Run, Fly.io, or a bare VM. LangGraph Platform adds managed postgres, horizontal scaling, and a dashboard — but the open-source core is production-grade.
Comparison: LangGraph vs. Alternative Orchestration Frameworks
Choosing the right orchestration layer determines whether your multi-agent system ships in weeks or stalls in prototype. The table below compares five approaches on criteria that matter for production workloads.
All frameworks tested against a 5-agent research benchmark (planner, 2x researcher, critic, writer) with 10-tool calls per run on GPT-4o.
| Framework | State Persistence | Human-in-the-Loop | Parallel Execution | Observability | License |
|---|---|---|---|---|---|
| LangGraph (OSS) | Built-in (sqlite/postgres) | Native interrupt/resume | Fan-out via Send() | LangSmith, OpenTelemetry | MIT |
| CrewAI | Custom (user implements) | Callback-based, no pause | Sequential only | Custom logging | MIT |
| AutoGen | In-memory only | User-managed queues | GroupChat manager | Built-in console | MIT |
| Semantic Kernel | Pluggable (redis, cosmos) | Step-wise approval | Native async plugins | Azure Monitor | MIT |
| Custom LangChain LCEL | Manual RunnablePassthrough | Not supported | RunnableParallel | LangSmith only | MIT |
Common Mistakes That Kill Production Multi-Agent Systems
Mistake: Treating State as a Bag of Strings
Why It Hurts: Untyped state lets schema drift silently. A researcher agent adds findings: [{"url": "...", "text": "..."}]; a later refactor changes it to findings: [{"source": "...", "content": "..."}]. The writer node crashes with KeyError at 2 AM. Fix: Define every field in a TypedDict or Pydantic model. Use typing_extensions.NotRequired for optional fields. Enable graph.validate() in CI.
Mistake: Embedding Business Logic in Prompts
Why It Hurts: "Decide if research is sufficient" in a prompt yields inconsistent judgments. Temperature 0 doesn't guarantee determinism across model versions. Fix: Move thresholds to Python: if len(state["findings"]) >= MIN_SOURCES and state["iteration"] >= MIN_ITERATIONS. Prompts handle synthesis; code handles control.
Mistake: Skipping Checkpointer in Development
Why It Hurts: Without persistence, every graph run starts from zero. You can't debug a failed critic node at iteration 4 without re-running planner and researcher. Fix: Always compile with SqliteSaver locally. It's one line and saves hours of re-execution.
Mistake: Ignoring Token Budgets in Long-Running Graphs
Why It Hurts: A 50-iteration research loop accumulates 200k+ context tokens. The final writer call hits context window limits or costs $15/run. Fix: Add a summarizer_node every N iterations that compresses findings into a dense summary. Store both raw and compressed; writer uses compressed.
Pro Tips
- Use
Send("node", {"custom": payload})for dynamic fan-out — planner can spawn N researcher subgraphs with different query subsets. - Enable
stream_mode="values"for real-time UI updates; frontend receives state delta after each node. - Add
retry_policyon tool-calling nodes:RetryPolicy(max_attempts=3, backoff=exponential)handles transient API failures without graph-level error handling. - Pin model versions in config (
gpt-4o-2024-08-06) — model upgrades change behavior silently. - Export graph visualization via
graph.get_graph().draw_mermaid()for architecture docs that never drift.
FAQ
What is LangGraph and how does it differ from LangChain?
LangGraph is an open-source orchestration framework built on LangChain Core that models agent workflows as stateful graphs instead of linear chains. It adds persistent checkpoints, cyclic edges, and native human-in-the-loop primitives — capabilities LangChain's LCEL lacks. LangGraph ships as a separate package (langgraph) but interoperates fully with LangChain tools, models, and callbacks.
When should I choose LangGraph over CrewAI or AutoGen?
Choose LangGraph when you need production-grade state persistence, deterministic control flow, and the ability to pause/resume execution mid-workflow. CrewAI excels at rapid prototyping with role-based agents but lacks built-in checkpointing. AutoGen shines for conversational multi-agent patterns but stores state only in memory. LangGraph is the only MIT-licensed option with postgres-backed durability out of the box.
How do I implement human-in-the-loop approval in LangGraph?
Call interrupt({"question": "Approve this action?"}) inside any node. The graph halts, serializes state to the checkpointer, and returns control to your API. Your frontend renders the question, collects user input, then calls app.ainvoke(Command(resume=user_response), config={"configurable": {"thread_id": "..."}}). Execution resumes at the exact interrupt point with the response injected.
Can LangGraph run multiple agents in parallel?
Yes. Use Send("node_name", input_dict) from a supervisor node to fan out to multiple worker nodes simultaneously. The graph compiler executes all Send targets concurrently. Results merge via the state reducer (e.g., operator.add for lists). For CPU-bound work, wrap nodes in asyncio.to_thread or use a process pool executor.
What's the roadmap for LangGraph open source vs. LangGraph Platform?
LangGraph OSS (MIT) receives all core graph engine features: checkpointers, streaming, interrupts, subgraphs, and visualization. LangGraph Platform (commercial, launched GA May 14, 2025) adds managed postgres, horizontal scaling, a web dashboard, RBAC, and enterprise SLAs. The OSS version is feature-complete for self-hosted production; Platform removes operational burden.
Conclusion
Building autonomous multi-agent systems no longer requires a custom orchestration layer. LangGraph's open-source core delivers the primitives — persistent state, cyclic graphs, human interrupts, parallel fan-out — that production workloads demand. Start with a typed StateGraph, compile with SqliteSaver, and iterate. The same graph runs locally, in CI, and in Kubernetes without rewrites. When traffic grows, LangGraph Platform offers a managed upgrade path with zero code changes. The teams shipping reliable agent products today aren't waiting for perfect frameworks; they're composing graphs with the tools that exist now.
- State is infrastructure — treat it like a database schema, not a prompt variable.
- Control flow belongs in Python; prompts belong in nodes.
- Checkpoint everything from day one; SqliteSaver costs one line.
- Human-in-the-loop is a graph primitive, not an afterthought.
0 comments:
Post a Comment