It’s 9am on a Monday. You’re the hiring manager. Your coffee is still too hot to drink. Staring back at you is a 47-tab browser of LinkedIn profiles, three half-written interview rubrics, and a Slack from HR asking if you’ve “started the loop yet.”
Meanwhile, somewhere in a terminal window, a small Python program is calmly asking a candidate to “describe a time you had to design a system for high availability” — scoring their answer, silently judging their vagueness, and deciding whether to probe harder.
That script doesn’t drink coffee. It doesn’t get distracted. And it absolutely does not care that it’s Monday.
This is what I built in a 30-minute workshop using Python, LangGraph, and Google’s Gemini Flash API. No cloud credits. No machine learning degree. Just a state machine, a couple of tools, and some beautifully petty scoring logic.
Let me show you how it works.
The stack — all free-tier:
Python 3.10+
langgraph: the graph engine
langchain-google-genai: Gemini wrapper
langgraph-checkpoint-sqlite: persistence
Either a free Google AI Studio API key, or a GCP project using Vertex AI with Application Default Credentials (gcloud auth application-default login) — no key pasted anywhere in that second case.
The model: gemini-2.5-flash — fast, cheap, and generally available (not a preview model). Just budget for its free-tier limits: Google AI Studio’s free tier for Flash-class models is rate-limited (currently in the low tens of requests per minute), which is plenty for a workshop but worth knowing before a live demo in front of a room.
The project is a handful of small, single-purpose files — state, tools, nodes, and the graph wiring each live on their own — rather than one monolithic script. No Docker, no cloud infrastructure setup required to run it locally.
Here’s the dirty secret of many of LLM tutorials out there: they build chatbots, not agents.
A chatbot answers questions. An agent does things — and crucially, it remembers what it just did.
A chatbot is like a goldfish with a keyboard: every message is a fresh start. An agent is like a colleague with a notepad: it tracks context, changes strategy based on what it hears, and builds toward a goal.
The technical difference comes down to one concept: state.
LangGraph is the library that makes the “colleague with a notepad” version real. It gives your Python code a proper state machine — one where every node (a Python function) reads state, does its job, and returns only what changed. The rest of the state stays intact.
Before any code, here’s the mental model for the whole application:
Three nodes. Three jobs. One loop.
interviewer_node — the brain. It reads the current state (how many questions asked, what scores have appeared) and builds a fresh system prompt every single turn. Low score on the last answer? The prompt says “probe harder.” Strong answer? It says “advance to something harder.”
tool_node — the hands. When the LLM decides it needs to score an answer, it emits a tool call. LangGraph’s built-in ToolNode intercepts that, runs the Python function, and wraps the result in a message. No manual dispatch code.
score_collector_node — the bookkeeper. After every tool call, this node reads the structured score object the evaluator returned and appends it to the scores list in state. The LLM never touches this list directly. Only this node does. That discipline is what makes the scorecard reliable.
Here’s the moment the app stops feeling like a chatbot and starts feeling like software.
After each answer, an evaluate_answer tool makes a second Gemini call — separate, with temperature set to zero (meaning: fully deterministic, no creative variance). Rather than asking the model to free-write a score and hoping the text comes back in a parseable shape, the call uses structured output:
a Pydantic schema (score, feedback, a probe_deeper flag, an optional missing_concept note)... You get a validated Python object back, not a string to parse and hope about.
That score goes into state["scores"]. The next time interviewer_node runs, it reads the latest score and builds a different system prompt depending on what it finds:
The LLM didn’t decide to probe harder. You decided — in a Python if-else — and injected that decision into the system prompt. That’s the difference between a chatbot and a system. The model is powerful. You are the architect.
The other thing most tutorials gloss over: by default, every LLM conversation is stateless. Kill the terminal, lose everything.
LangGraph solves this with a checkpointer — essentially a key-value store that snapshots the entire state graph after every node execution. The SQLite checkpointer writes to a local .db file. Zero server required.
The magic is in one argument:
graph.compile(checkpointer=checkpointer)And one config dict passed to every invoke call:
config = {”configurable”: {”thread_id”: “candidate-alex-2026”}}Same thread_id next run? LangGraph loads the snapshot and resumes exactly where it left off. The candidate can close their laptop mid-interview, come back the next day, and the AI picks up right where it stopped — as long as the checkpointer is a durable one (SQLite locally, Postgres in production). An in-memory checkpointer, by contrast, only remembers within a single run — kill the process and that memory is gone, restart or not.
At the end of the interview, one function call renders this in the terminal:
It renders a scorecard in the terminal using the rich library: a progress bar per question, plus an overall average.
The scores were never programmed into the display. They accumulated in state["scores"] across the entire conversation, one tool call at a time. The scorecard just reads the list. That’s what proper state management looks like.
Building this interviewer taught me something I didn’t expect: the LLM is the least interesting part.
Gemini Flash is capable enough that getting it to ask good interview questions took about three minutes of prompt writing. The interesting engineering work was everything else:
How state flows between nodes,
how the checkpointer makes conversations durable,
how a score in a Python list changes the character of the next question.
LangGraph didn’t make the AI smarter. It gave the AI a memory, a workflow, and a job description. That’s what turned a chatbot into software.
If that sounds like something worth 90 minutes of your time — the full workshop is available as a step-by-step live-coding session. By the end, you’ll have a working interviewer that adapts, remembers, and judges. Ruthlessly.
All code is in the companion GitHub repo.
I’ve got a couple of great offers: FREE & Discount access to my video courses - available for a limited time, so don’t wait too long!
🤖 The Agentic Engineering Bootcamp
Discount coupon AI_ASSISTED_ENG_15_N🔥 Modern Software Engineering: Architecture, Cloud & Security
Discount coupon RAKIA_SOFT_ENG_14_N🔐 Secure Software Development: Principles, Design, and Gen-AI
FREE coupon RAKIA_SECURE_APPS_13FREE coupon RAKIA_API_DESIGN_13
🐳 Getting Started with Docker & Kubernetes + Hands-On
FREE coupon RAKIA_DOCKER_K8S_13⚡ Master Web Performance: From Novice to Expert
FREE coupon RAKIA_WEB_PERF_14
💡 🧠 I break down the real-world engineering wisdom they don’t teach in tutorials. Join my newsletter or my YouTube channel, where I help working developers and engineers navigate the evolving tech landscape with clarity and confidence.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.