Guides

What Is a State Machine: Deterministic Control for Multi Step Agent Flows

States, transitions, and guards with a worked transition table, plus how the pattern bounds multi-step agent flows and how to check the path an agent took.

· Updated
· 14 min read
state-machine finite-state-machine agent-orchestration langgraph agent-evaluation determinism
Editorial cover on a black blueprint grid reading WHAT IS A STATE MACHINE over the line DETERMINISTIC CONTROL FOR MULTI STEP AGENT FLOWS, with a thin line diagram of four circled states named idle, collecting, verifying and refunding joined by labelled arrows, one rejected transition drawn as a dashed line, and a row showing current state, event and next state.
Table of Contents

An agent handling a refund calls the payment API before it has finished verifying the customer’s identity. Nothing crashed. The model simply had every tool available at every step, and picked one early.

That is not a prompting problem. It is a control problem. The agent was allowed to make a move that should never have been legal from where it stood.

A state machine is the oldest fix in computer science for exactly this. It says: here are the states, here are the moves out of each one, and everything else is rejected. This post covers what that model is, how it works, how it compares to prompt chains and free-form loops, whether LangGraph counts as one, and how to check that an agent actually followed the path you designed.

Key takeaways

  • A state machine holds one state at a time and only moves through transitions you defined in advance.
  • The bounded set of reachable states is the whole point: you can enumerate what the system is allowed to do before it runs.
  • Small per-step error rates compound fast across a chain, which is arithmetic, not a study finding.
  • Scoping tools to the current state stops a class of bugs that no amount of prompt wording reliably prevents.
  • Checking that an agent reached the right answer is not the same as checking it took the right path.

What Is a State Machine?

A state machine is a model of behavior in which a system occupies exactly one state at any moment and changes state only through defined transitions. It is a way of describing what a system can do, not just what it happens to do.

The value comes from what it forbids. If a transition is not written down, it cannot happen. That turns “what could this system possibly do?” from a guess into a list you can read.

States, Transitions, and Events

Three pieces do most of the work. A state is a named condition the system rests in, like awaiting_payment. An event is something that arrives from outside, like coin_inserted. A transition is the rule connecting them.

Two more pieces show up in any serious design. A guard is a condition attached to a transition that must be true for it to fire. An action is the side effect that runs when the transition fires, such as writing a record or calling a tool.

Put together, the rule reads: in state S, on event E, if guard G holds, run action A and move to state T. Everything the system does fits that sentence. Nothing else is permitted.

Finite vs. Infinite State Machines

A finite state machine has a countable, fixed set of states. A traffic light has three. A refund workflow might have eight. You can list them on paper, which is why the model is so easy to reason about and test.

Infinite state machines allow state to include unbounded data, like a counter that never stops growing or a stack of arbitrary depth. They are strictly more expressive. They are also much harder to verify, because you can no longer enumerate every situation.

Most agent orchestration sits between the two. The control flow is finite and drawable, while the data carried along with it, such as conversation history, is not. Keeping those two layers separate is what makes the design tractable.

How a Finite State Machine Works

A finite state machine runs as a loop. Read the current state, read the incoming event, look up the transition, apply it. If no transition matches, the event is rejected and the state does not change.

That rejection behavior matters more than it first appears. A system with no defined move for an event does nothing rather than something improvised. Undefined input produces a refusal, not a surprise.

Thin line blueprint diagram on a black grid titled how a finite state machine runs one transition, showing five circled states in a row named idle, collecting, verifying, refunding and closed, joined by arrows labelled request received, details complete, identity confirmed and refund issued, a guard label reading identity verified equals true, a dashed arrow from collecting to refunding crossed out and captioned no transition defined event rejected state unchanged, and a four column transition table below listing current state, event, guard and next state with a final greyed row where refund issued from collecting resolves to rejected.

A Deterministic Transition Table, Worked Through

Take a refund agent with five states: idle, collecting, verifying, refunding, closed. A run starts in idle. The event request_received moves it to collecting, and no other event does anything at all from idle.

In collecting the agent gathers order details. The event details_complete moves it to verifying. The interesting case is what happens if the model tries to issue a refund here: there is no refund_issued transition out of collecting, so the move is rejected.

verifying carries a guard. The transition to refunding fires on identity_confirmed only if identity_verified == true. That single line is the difference between the bug in the opening paragraph and a system that cannot commit it.

Core Components at a Glance

Here is the same vocabulary mapped onto agent orchestration, which is where most readers will actually apply it.

ComponentPlain-English definitionAgent-orchestration example
StateA named condition the system is in right now, one at a timeverifying_identity — the agent is confirming who it is talking to
TransitionA defined move from one state to anotherverifying_identity → issuing_refund
EventThe input that triggers a transitionTool returns identity_match: true
Guard conditionA test that must pass for the transition to fireRefund amount is under the auto-approval limit
ActionThe side effect performed during the transitionCall the payments API and write an audit record

Vending Machines, Traffic Lights, Elevators

The textbook examples earn their place. A vending machine sits in idle, accumulates credit as coins arrive, and only dispenses when credit meets the price. Pressing the button with no credit does nothing, because that transition does not exist.

A traffic light cycles through a fixed sequence on timer events, and there is no input that makes two directions green at once. An elevator holds a floor and a direction, and a call button changes a queue rather than teleporting the car.

None of these are simple because the problem is simple. They are simple because the designers constrained the reachable states until the behavior fit on one page.

State Machines vs. Prompt Chaining vs. Free-Form Agent Loops

Three patterns dominate multi-step agent work. A prompt chain runs a fixed sequence of model calls, each feeding the next. A free-form loop hands the model a toolset and lets it decide what to do until it declares itself done.

A state machine sits between them. The sequence is not fixed, but the legal moves at each point are. The model chooses within a boundary rather than choosing the boundary.

Why Prompt Chains Degrade Across Steps

Run the arithmetic on a chain where each step is right 95% of the time and errors carry forward. Ten steps gives 0.95 raised to the tenth power, about 0.599, so roughly 60% of runs finish clean. Twenty steps gives about 0.358, roughly 36%.

That calculation is illustrative, not an empirical finding, and it is worth saying plainly. Real steps are not independent and real accuracy is not uniform. Some errors cancel, others amplify.

The point survives the simplification anyway. A per-step rate that looks excellent in isolation stops looking excellent once you multiply it by itself ten times. Nothing in a plain chain interrupts that multiplication.

Audit Traceability and Boundedness

A state machine gives you two guarantees a loop does not. Boundedness means the set of reachable states is known before the system runs, so “could the agent ever do X?” is answerable by reading the definition. Traceability means every run reduces to a sequence of named states.

That second property is what makes review practical. A free-form loop produces a transcript you have to interpret. A state machine produces a path, and comparing a path against an expected path is a mechanical check.

Error containment follows from both. When a transition is rejected, the failure surfaces at the boundary instead of travelling downstream disguised as a normal result. We wrote about how easily those disguised results slip past monitoring in the failures your agent harness never reports.

PatternPredictabilityError containmentAuditabilityBest use case
State machineHigh — reachable states are enumerable up frontStrong — undefined transitions are rejected at the boundaryStrong — every run is a named state pathRegulated or irreversible workflows: refunds, onboarding, provisioning
Prompt chainingMedium — the sequence is fixed but each output is notWeak — a bad output is passed forward as inputMedium — you get a transcript, not a pathLinear content transformation where steps are cheap to redo
Free-form agent loopLow — the model picks the next action each turnWeak — recovery depends entirely on the model noticingWeak — behavior must be reconstructed from the transcriptOpen-ended research and exploration where the path is unknown

Thin line blueprint comparison on a black grid titled where the error stops, showing the same five step agent flow run three ways. The prompt chaining track is five boxes in a line with an error entering at step two and every later box shaded to show the error carried forward. The free-form agent loop track is one box labelled model plus all tools with arrows curving back on itself, a note reading retries same call four times and four empty squares marked no progress. The state machine track is five circled states where the error enters at state two and a dashed transition is stopped by a solid bar captioned transition rejected, error stops here.

Why Do Multi-Step AI Agents Need Deterministic Control?

Because the failure that matters is rarely a wrong answer. It is a correct-looking answer produced by an illegal sequence of actions, in a workflow where some of those actions cannot be undone.

Refunds move money. Provisioning creates accounts. Emails reach customers. For that class of work, a system that is right most of the time and unbounded the rest of the time is not usable, regardless of how good the average looks.

Scoping Tools to the Current State

The most practical benefit is narrow. Instead of exposing the full toolset on every turn, expose only the tools that are valid in the current state. The refund tool simply is not in the model’s list until the agent reaches refunding.

This removes an entire failure class by construction rather than by instruction. You are not asking the model to remember a rule under pressure. The wrong action is unavailable, so no amount of confused reasoning can select it.

It also shrinks the decision the model has to make. Choosing among three relevant tools is a much easier problem than choosing among thirty, and a trace makes that gap visible: watch for a wrong-tool selection getting caught by a rejected transition before it ever reaches the final answer.

LangGraph as a Practical Implementation

Teams rarely hand-roll this. LangGraph is one of the most widely used ways the pattern reaches production in Python, and it describes itself as a “low-level orchestration framework for building stateful agents” (github.com/langchain-ai/langgraph, as of August 2026).

The mapping is direct. You declare a state schema, write nodes that update it, and connect them with edges that decide where control goes next. We covered the framework itself in more depth in what LangGraph is and when to use it.

Is LangGraph a State Machine?

It implements the pattern rather than being a textbook finite state machine, and the distinction is worth holding onto. The core vocabulary lines up almost exactly. What LangGraph adds is what takes it past the classical model.

Where LangGraph Follows the Pattern and Where It Extends It

LangGraph’s documentation defines nodes as “functions that encode the logic of your agents” which “receive the current state as input, perform some computation or side-effect, and return an updated state,” and edges as “functions that determine which Node to execute next based on the current state” (docs.langchain.com). Nodes behave like states with attached actions. Edges behave like transitions.

Conditional edges are the guard equivalent. The docs describe add_conditional_edges as the method to use when you want to “optionally route to one or more edges (or optionally terminate).” That is a transition whose target depends on a runtime test.

The extensions are where it departs. Reducers control how each key in the state is updated, so state is a merged object rather than a single label. Cycles are first-class: the docs note you can “create complex, looping workflows that evolve the state over time.”

Persistence goes further than either. The project’s README describes durable execution that lets agents “persist through failures and can run for extended periods, automatically resuming from exactly where they left off,” which no classical FSM specifies.

AspectClassical finite state machineLangGraph
StateOne label from a finite setA user-defined schema object, updated per key by reducers
TransitionA table entry: state + event → stateAn edge function that returns the next node
Conditional routingGuard on a transitionadd_conditional_edges on a runtime test
CyclesOrdinary, but a repeated state is identical every time it recursFirst-class, and state accumulates across each pass through the loop
PersistenceNot part of the modelCheckpointing and durable execution across failures
VerificationEnumerate all reachable statesHarder — reachable states depend on the state object

When a Plain FSM Is Enough

If your workflow has a handful of states, no long-running pauses, and no need to resume after a crash, a switch statement and an explicit state variable will do. You get the same boundedness with none of the dependency surface.

Reach for a graph framework when you need cycles with sane termination, human-in-the-loop pauses, resumable runs, or parallel branches that merge. The common mistake is picking the framework first and then discovering your flow was five states in a straight line. Draw the diagram before you choose the tool.

Evaluating and Tracing State-Based Agent Flows

Defining the state machine is half the work. The other half is confirming that production runs actually followed it, which output-level testing cannot tell you.

An agent can reach a correct final answer through a path you never intended: skipping a verification state, looping four times where once was expected, or calling a tool that happened to be reachable through an edge you forgot to constrain. The answer looks fine. The behavior is not.

Verifying the Path, Not Just the Answer

Path-level checking means asserting on the sequence of states and tool calls, not only the final string. Did the run pass through verifying before refunding? Did it use the number of steps the design implies? Did each tool call match the state it was made from?

These are cheap assertions that catch expensive bugs. They also catch regressions that output scoring misses entirely, because a refactor can change routing without changing the answer on your test cases. Our guide to LLM evaluation metrics covers how path checks sit alongside output scoring.

Catching Stuck Loops Before They Reach a User

Cycles are useful and cycles are where agents get stuck. A retry loop with a condition the model never satisfies will spin, burning tokens, until a step cap ends it or a user gives up.

The signal is repetition without progress: the same state re-entered, the same tool called with near-identical arguments, no change in the underlying task status. Detecting that in traces, before it becomes a support ticket, is a monitoring job rather than a design one.

Future AGI

Future AGI sits on the evaluation and observability side of this. It scores and traces the execution path of a state-based or graph-based agent. It does not define your state machine or orchestrate transitions — that stays in your code or your graph framework.

Four evaluators map onto path checking directly. Trajectory Match compares an agent’s actual action sequence against an expected one, and Step Count validates the number of steps in a run against an exact count or a range. Task Completion assesses whether the response did what was asked, and Tool Call Accuracy scores function invocations on name and arguments against what was expected.

Two conversation-level evaluators cover the loop problem. Customer Agent: Loop Detection flags an agent stuck asking the same question or circling back during a conversation. Customer Agent: Context Retention checks whether the agent retains and applies context from earlier in the conversation instead of re-asking for it.

Beyond the built-ins, LLM-as-judge lets you define custom evals for rules specific to your own state graph.

The tracing side supplies the data those checks run on. Observe records a trace as “the step-by-step record of the model calls, tool calls, and retrievals behind one response,” and sessions let you “follow a full conversation, or one customer across sessions” (docs.futureagi.com/docs/observe). A span is one step inside that trace: a single model call, tool call, retrieval, agent step, or evaluator run.

The tracing is OpenTelemetry-native across a wide range of agent frameworks (github.com/future-agi/future-agi).

Put together, that is the loop: your graph decides what the agent may do, the trace records what it did, and the evaluators tell you whether the two matched.

Conclusion

A state machine trades flexibility for predictability. In a demo that trade looks like a cost, because the flexible version handles more inputs and needs less design work up front.

In production the trade inverts. Bounded behavior, rejected illegal moves, and a run that reduces to a named path are worth more than the extra cases a free-form loop can improvise its way through.

Start by drawing the states. Then scope the tools to each one, so the wrong action is unavailable rather than merely discouraged. Then check the path, not just the answer, because an agent that arrives at the right destination through the wrong route will eventually arrive at the wrong one.

Frequently Asked Questions

What is a state machine in simple terms?

A model where a system sits in exactly one state at a time and moves between states only through transitions defined in advance for specific events.

What is the difference between a state machine and a state diagram?

The state machine is the logic itself: the states and transition rules. A state diagram is the drawing of that logic, with states as nodes and transitions as arrows.

What is a finite state machine used for?

Anywhere behavior must stay predictable and bounded: traffic lights, vending machines, network protocols, parsers, UI flows, and increasingly the orchestration layer around multi-step AI agents.

Why use a state machine instead of prompt chaining for AI agents?

A state machine limits which tools and transitions are legal at each step, so errors are contained. A prompt chain passes every error forward with nothing to stop it.

Is LangGraph a state machine?

LangGraph applies the pattern. Its docs define nodes as functions that update state and edges as functions that pick the next node, then add loops, conditional routing, and checkpointed persistence.
Related Articles
View all