One coffee shop, two libraries: prompts, chains, tools, memory, graphs, checkpoints, interrupts, and the ten questions that decide production
A model call is a pure function: messages in, message out. Everything an application needs beyond that one call is plumbing, and every team was rebuilding the same plumbing by hand.
LangChain standardizes one call: prompts, parsing, tools, memory. LangGraph choreographs many calls: state, branching, persistence, interruption.
prompt | model | parser, plus tools and memory around it. Everything happens inside a single .invoke(); nothing persists once it returns.
Nodes, edges, and state threaded across an entire run: branches, cycles, checkpoints, and interrupts that survive a restart.
Every figure ahead is a photograph of real code running one small coffee shop: a real menu, a real stock room with counts that go down, a real till with a balance that moves, and a barista bot built up from raw calls to a full graph.
The APIs are the easy part. Practitioners converge on the same checklist, and the four in amber are the ones teams skip.
Synthesis: OpenAI, A practical guide to building agents · Anthropic, Building effective agents · Anthropic, Demystifying evals · LangChain persistence & interrupt docs · AutoGen termination docs
Everything in Part 1 is about a single model call and the plumbing around it: what goes in, what comes out, and who remembers.
LangChain composes one call. Prompts, parsers, tools, and memory all live inside a single .invoke().
A message is LangChain’s typed unit of conversation: a role (system, human, ai, or tool) plus content. Chains pass a list of messages, never a bare string.
A prompt template is a function from a dict of inputs to a rendered prompt. It fills variables into a fixed structure and returns a typed ChatPromptValue, ready for a model.
One order, four shapes. LCEL’s | is function composition, and the thing flowing through really changes type at every hop.
The LCEL pipe (|) composes runnables into a pipeline, prompt | model | parser. Every stage answers .invoke / .batch / .stream, so pipes compose uniformly even as the payload’s type changes at each hop.
Structured output binds a schema, an OrderItem or other Pydantic class, to the model call, so the reply parses straight into a typed object instead of prose you’d have to regex apart.
A tool round trip: the model emits a tool_calls request, your code runs the real function (check stock, price an order), and the result goes back into the message list as a tool message for the next model call.
A pipe points one way. A real conversation loops, branches, pauses, and survives a restart. LangGraph’s move is to make your control flow an object: nodes, edges, and state you can draw, checkpoint, and interrupt.
LangChain composes one call; LangGraph choreographs many. The difference is state that persists across turns, not just a longer pipe.
A LangChain pipe (|) runs strictly one direction; there is no way to route back to an earlier stage. The moment a task needs to retry, branch, or loop, it needs a graph, not a longer chain.
State is the schema LangGraph threads through every node, one object every node reads and writes, so the shape of a run is a diagram you can draw, not an implicit transcript.
A reducer is the function attached to a state field that says how updates combine, replace, append, sum, so two nodes touching the same field don’t silently clobber each other.
A conditional edge routes to a different next node based on the current state. The branch, and the back-edge that makes a loop possible, are real, drawable graph edges, not hidden if statements inside a Python loop.
The famous agent loop is small enough to memorize, and LangGraph ships it as a two-node graph you have already built by hand.
A checkpoint is a saved snapshot of a graph’s state after each step, keyed to a thread id. A run can be walked away from and resumed exactly where it left off.
Everything so far was mechanism. What separates a demo from a system is a set of decisions, and four of them are chronically skipped: what counts as success, where state lives, when to stop, and what happens on replay.
Success is a property of the world, not the transcript. A reply that “sounds booked” is not a reservation that exists.
OpenAI, A practical guide to building agents · Anthropic, Demystifying evals for AI agents · LangChain interrupt docs
prompt | model | parser, one fixed path. Right when the task is well-specified and every input takes the same route.
One call classifies the request, then each branch is its own fixed path. Right when inputs split into a few known kinds.
create_agent(model, tools): the model decides how many calls to make and which tools to call, in a loop. Right only when the answer depends on something the code can’t know in advance, like live stock.
interrupt() is called inside a node and pauses the graph right there, handing control to a human. On Command(resume=...) that node runs again from its start with the supplied value, so the graph continues from the checkpoint instead of restarting the whole run.
Resuming a graph with no checkpointer replays every node from the start, side effects included, so Beanline’s till gets charged twice for one latte. A checkpointer makes a resume skip completed steps instead of re-running them.
Maya’s large oat-milk latte, one last time, touching every piece the deck introduced.
| # | The question | Where the deck answered it |
|---|---|---|
| 1 | Need an agent at all? | Do You Need an Agent at All? |
| 2 | What counts as success? | Define Done, Verifiably |
| 3 | What can it see and do? | Tools Are Round Trips |
| 4 | Which decisions stay code? | Graphs Are Data (the price node has no LLM) |
| 5 | Authoritative state? | State and Reducers · Walk Away, Come Back |
| 6 | Simplest graph that works? | Chains Can’t Loop · Do You Need an Agent at All? |
| 7 | Stop, retry, escalate? | Stop, Retry, Escalate |
| 8 | Replay-safe side effects? | Resume Without Double-Charging |
| 9 | Authority and approval? | Approve Before You Act |
| 10 | What does each call buy? | Do You Need an Agent at All? (the call-count scorecard) |
Pydantic AI is a typed single-agent framework: Agent(model, output_type=SomeModel) runs one call and hands back a real, validated instance of that model. One pip install, no graph, no checkpointer.
Instructor patches any OpenAI-compatible client so .create() returns a validated Pydantic object instead of raw JSON text, the smallest possible step from prose to a typed object.
Pick the lightest tool that does the job: raw SDK for one call, Pydantic AI for one typed agent, LangGraph when you need durable multi-step.
One call, hand-parsed JSON, no framework dependency. Right when there is exactly one call and you’re willing to parse the reply yourself.
Agent(model, output_type=Order), one pip install. Right when one call needs a validated typed result and nothing more.
Nodes, edges, a checkpointer. Right when the job is many calls, branching, or must resume without re-running side effects.
Guides OpenAI, A practical guide to building agents · Anthropic, Building effective agents · Anthropic, Demystifying evals for AI agents
LangChain / LangGraph docs LangGraph persistence · Interrupts · LangChain messages, runnables, tools
Also drawn on AutoGen, termination · 12-factor agents
Siblings How Git Works, Visually · How RAG Works, Visually · How Inference & Serving Work, Visually · How Evals & Observability Work, Visually · How Agentic Harnesses Work, Visually
Every figure in this deck: a real run of langchain 1.3 / langgraph 1.2 at Beanline Coffee, regenerable with build/regen_all.py · versions pinned in build/requirements.txt