InfoWok
AI Agents from Scratch in Python · 05Beginner

From Scratch to LangGraph: When to Stop Hand-Building Agents

From scratch to LangGraph: the four walls that tell you when to use LangGraph instead of a hand-built Python agent loop — and when plain Python is still the right call.

SK
Sukhveer Kaur
Published June 20, 2026
5 min read
Part 5 banner reading Scratch to LangGraph showing a hand-built Python while loop turning into a LangGraph StateGraph for AI agentsAI Agents from Scratch in Python · Part 05
SCRATCH TO LANGGRAPH
On this page +
🧰 New here? Set up your environment first · ~5 min
  1. Install Python 3.11+ — confirm with python3 --version.
  2. Create and activate a virtual environment: python3 -m venv .venv then source .venv/bin/activate (Windows: .venv\Scripts\activate). venv, pip & uv primer →
  3. Install the packages this tutorial lists: pip install -U pip <packages>.
  4. Put your LLM API key in a .env file and never commit it. API key + .env primer →

Full walkthrough → Environment Setup primer

Series: AI Agents from Scratch in Python This is Part 5, the finale. So far: Part 1 made an LLM call, Part 2 added tools, Part 3 wrapped them in the agent loop, and Part 4 gave it memory. Now we answer the question that started this series in reverse: when to use LangGraph instead of the loop you just hand-built.

You don’t need a framework to build an AI agent — you’ve now built one without one. The move from scratch to LangGraph isn’t about whether your code works. It already does. It’s about four problems that push you toward a framework sooner or later. Pretending they won’t just wastes your afternoon. So this post draws a clear line: here is when LangGraph earns its place, and when plain Python is still the better call.

I’ll say the unpopular part first. For a single agent that runs once and exits, your hand-built loop is better than LangGraph — fewer moving parts, nothing to learn, easy to read. Frameworks start paying off at the second or third feature, not the first.

🟢 Beginner⏱️ 12 min readStack: Concepts + LangGraph — no setup needed to follow
Before you start
  • You’ve built the scratch agent through Part 4 (or just want to know when a framework is worth it)
  • You can read a while loop and a dict-based dispatch table — see Part 3
🎯 Key takeaways
  • You already built the hard part. LangGraph is your loop, tools, state, and routing — with durability bolted on.
  • Four walls trigger the switch: complex branching, persistence across runs, automatic retries, and tracing.
  • Plain Python still wins for simple, single-shot agents — reach for the framework when the walls actually appear, not before.

What Hand-Built Agents Are Bad At#

Your scratch agent is great at exactly one thing: being small enough to understand. The trouble starts when it has to be reliable, and four weaknesses show up in roughly this order.

State gets messy. In Part 3, control flow lived in a while loop and a few variables. Add three tools, a retry path, and a “should I stop?” check, and that loop becomes a tangle of flags you have to hold in your head.

There are no retries. When a tool call fails or the model returns junk, your try/except is the whole safety net. Real agents need to retry a step, fall back, or route around the failure — and you’d hand-write every bit of that.

Branching doesn’t scale. A dispatch table (the dict that maps a tool name to a function) handles a handful of paths. Once the model needs to choose between many sub-flows, hand-rolled routing gets fragile fast.

Nothing persists, and nothing is visible. Close the program and the agent forgets everything (you saw this in Part 4). And when a ten-step run goes wrong, print() is a poor way to find which step broke.

I felt all four at once on a small research agent. It worked in the demo. Then I added a second tool, a retry, and a “stop when done” rule — and the loop grew three new flags I had to track by hand. Each fix was easy alone; together they turned 30 clean lines into a knot. That knot is the real signal. It isn’t that your code is bad — it’s that you’re now maintaining plumbing a framework already ships.

🔑 Key point

None of these are reasons your scratch agent is wrong. They are the bill that comes due when an agent moves from a demo to something people depend on.

Your Scratch Agent, Mapped Onto LangGraph#

Here is the reassuring part: LangGraph doesn’t replace what you learned — it formalizes it. Every piece you hand-built has a direct equivalent, so reading a LangGraph graph feels familiar, not foreign.

The mapping is almost one-to-one:

What you hand-builtLangGraph equivalentWhat you gain
while True: loopStateGraph (nodes + edges)a structure that scales without rewrites
if/else + dispatch tableconditional edgesrouting that stays readable as paths grow
messages = [...] listtyped graph Stateone shared, validated state object
try/except + manual retriesbuilt-in retry / error handlingreliability you configure, not code
forgets on exitcheckpointerpause, resume, and survive a restart
print() debuggingtracing (LangSmith)a timeline of every step in a run

Read that table top to bottom and you’ve read the whole value proposition. A framework is not magic; it is the parts you already built, made durable. That is why building from scratch first was worth it — you can now look at any node and edge and know precisely what it stands for.

The Decision Rule: When Plain Python Still Wins#

Frameworks have a cost too — a dependency to track, an API to learn, and a layer of indirection between you and the model. So the rule I use is simple and a little contrarian: stay on plain Python until you hit a wall you’d otherwise have to build around.

Concretely, keep your scratch agent when:

  • It’s a single agent with a handful of tools that runs and exits.
  • You can still explain the entire control flow in one breath.
  • You don’t need to resume a run or persist state across sessions.
  • You’re prototyping and want zero indirection between you and the model.

Reach for LangGraph the moment you need two or more of these: multi-step branching the model controls, persistence across runs, automatic retries and fallbacks, human-in-the-loop approval gates, or production-grade tracing. One feature is a maybe; two is a yes.

💡 A quick gut check

If you find yourself re-inventing one of the table’s right-hand items — writing your own checkpoint store, your own retry policy, your own trace log — stop. That’s the signal you’ve outgrown scratch code, and the framework already solved it.

Make the Jump: From Scratch to LangGraph#

When the walls do appear, the move is smaller than you’d think. LangGraph reached a stable v1.0 in late 2025, and the prebuilt agent is a single call — your whole Part 3 loop, condensed:

python
# pip install langgraph langchain
from langchain.agents import create_agent
 
def get_weather(city: str) -> str:
    """Return the weather for a city."""
    return f"It's sunny in {city}."
 
agent = create_agent(model="openai:gpt-5.4-mini", tools=[get_weather])
result = agent.invoke({"messages": [{"role": "user", "content": "Weather in Pune?"}]})
print(result["messages"][-1].content)

That one call runs the same Thought → Action → Observation loop you wrote by hand. When you need control over the graph itself, you drop down to StateGraphadd_node, add_edge, and conditional edges — which is the explicit version of your loop and dispatch table. To make it persist, compile with a checkpointer and pass a thread_id:

python
from langgraph.checkpoint.memory import InMemorySaver
# graph = builder.compile(checkpointer=InMemorySaver())
# graph.invoke(state, config={"configurable": {"thread_id": "user-1"}})

That checkpointer is the persistence your scratch loop never had — swap InMemorySaver for SqliteSaver or PostgresSaver and the agent remembers across separate runs. If you want to weigh LangGraph against other frameworks before committing, I compared them in LangGraph vs CrewAI vs AutoGen.

Conclusion#

You started this series unable to call an LLM, and you’re ending it able to read a LangGraph graph and know exactly what every node does — because you built each piece by hand first. That is the whole point of going from scratch to LangGraph in this order: the framework stops being a black box and becomes a set of conveniences you can name. Loop, tools, state, memory, routing — you wrote them all; LangGraph just makes them durable.

So don’t adopt a framework out of FOMO. Adopt it when you hit a wall — branching, persistence, retries, or tracing — and not a moment sooner. The dev who built the loop by hand always makes the better call about when to leave it behind.

Which wall pushed you to a framework first — persistence, branching, or just debugging a long run? Tell me in the comments.

Read next: Build an Agentic AI App in Python (Part 1) — the build series picks up exactly here, taking a LangGraph agent from your laptop to production.

🧭 Where to go from here

Frequently asked questions

When should I move from a from-scratch agent to LangGraph? +
Move when you hit one of four walls — branching that your if/else can no longer track, persistence across sessions, automatic retries, or tracing to debug long runs. Until then, plain Python is simpler and faster to reason about.
Is LangGraph just my agent loop with extra steps? +
Mostly, yes — and that is the point. LangGraph wraps the same loop, tools, state, and routing you built by hand, but adds durable state, retries, persistence, and tracing you would otherwise write yourself. You are not learning a new idea, only a sturdier wrapper.
What is a checkpointer in LangGraph? +
A checkpointer saves a snapshot of the graph's state at each step. Compile your graph with one (InMemorySaver, SqliteSaver, or PostgresSaver) and pass a thread_id, and the agent can pause, resume, and remember across separate runs — the persistence your scratch loop never had.
Do I still need to understand the agent loop if I use LangGraph? +
Yes. LangGraph runs the same Thought to Action to Observation loop under the hood. Having built it by hand in this series is exactly what lets you read a LangGraph graph and know what each node is doing.

References

  1. LangGraph — Graph API overview (docs)
  2. LangGraph — Persistence & checkpointers
  3. LangChain — create_agent reference
Written by
Sukhveer Kaur
Sukhveer KaurSoftware Developer & AI Engineer

Sukhveer is a software developer specialising in AI systems and backend engineering. She has hands-on experience designing agentic AI applications, working with large language model pipelines, autonomous agent frameworks, and cloud-native services in Java and Python. At InfoWok, she bridges the gap between cutting-edge AI research and practical implementation — helping developers understand and apply emerging technologies through clear, experience-backed writing.

Get the next part the day it lands

One email per new part. No digest spam.

Comments