You can build a tool-using agent now. This final post covers the three patterns that separate a demo from a product: persistence (memory that survives), human-in-the-loop (approval before risky actions), and multi-agent (a team of specialists). All three are built into LangGraph.
1. Persistence โ memory that survives restarts
Add a checkpointer when you compile, and LangGraph saves the state after every step. Give each conversation a thread_id and it remembers โ even across separate program runs.
from langgraph.checkpoint.memory import MemorySaver
agent = builder.compile(checkpointer=MemorySaver())
cfg = {"configurable": {"thread_id": "student-42"}}
agent.invoke({"messages": [{"role": "user", "content": "I am in CSE, 6th sem."}]}, cfg)
# later โ same thread_id, no need to resend history:
out = agent.invoke({"messages": [{"role": "user", "content": "Which sem am I in?"}]}, cfg)
print(out["messages"][-1].content) # "6th semester" โ rememberedMemorySaver keeps state in RAM (fine for learning). Swap it for SqliteSaver or PostgresSaver and the memory survives a crash or deploy. This is the modern replacement for the manual message lists from the memory post.
2. Human-in-the-loop โ approve before acting
Some actions (send an email, delete data, spend money) should never run without a human OK. Tell LangGraph to pause before a node; the graph stops, you inspect, then resume.
agent = builder.compile(checkpointer=MemorySaver(), interrupt_before=["tools"])
cfg = {"configurable": {"thread_id": "u1"}}
agent.invoke({"messages": [{"role": "user", "content": "Email my results to admin."}]}, cfg)
# graph paused right before running the tool. Check what it wants to do:
state = agent.get_state(cfg)
print(state.next) # ('tools',) <- waiting for approval
# approve by resuming with no new input:
agent.invoke(None, cfg) # now the tool runsBecause the state is checkpointed, "pause and wait for a human" can mean seconds or days โ the run resumes exactly where it stopped. That's only possible thanks to persistence.
3. Multi-agent โ a team of specialists
One agent with 20 tools gets confused. The fix: several focused agents plus a supervisor that routes each request to the right one โ a "research" agent, a "math" agent, a "writing" agent.
from langgraph.prebuilt import create_react_agent research = create_react_agent(model, tools=[web_search], name="researcher") maths = create_react_agent(model, tools=[cgpa_to_percentage, gpa_needed], name="math") # a supervisor node reads the request and returns the next agent name; # conditional edges route to that agent, then back to the supervisor. # (langgraph-supervisor packages this pattern in a few lines.)
Each agent is a graph; the supervisor is a graph of graphs. Same nodes-and-edges idea from post 8, one level up. Keep each agent's toolset small and its job clear โ that's what makes multi-agent reliable.
Seeing and shipping it
- Debug visually with LangSmith or by printing
agent.get_state(cfg)after each step. - Cap loops with a recursion limit so a stuck agent can't run forever.
- Deploy the compiled graph behind a web API โ it's just an object with
.invoke().
You've gone A to Z
From a 6-line "hello LLM" to persistent, human-supervised, multi-agent systems. The whole journey, in order: what LangChain is โ core concepts โ chains โ memory โ RAG โ tools & agents โ LangGraph โ first graph โ ReAct agent โ advanced. Build something and put it on GitHub โ a working agent is the portfolio piece that gets interviews. Keep learning in our free AI course.
โ All Articles