Jul 16, 2026 - 13 min read
Building Agentic Applications: Workflow, Agent, or Something Between?
A decision guide to deterministic workflows, tool-using agents, and bounded agentic workflows—and why most production systems need less autonomy than expected.
I've watched more teams over-build an agent than under-build one. The instinct makes sense — agent architectures are the interesting part of the field right now, and there's a real temptation to reach for one because it's the more sophisticated-sounding answer, not because the task actually needs it. The result is usually a system that's harder to test, harder to secure, and harder to explain when something goes wrong, solving a problem that a deterministic script would have handled in an afternoon with none of that risk.
So the framing I want to push on first: autonomy is a design variable, not a destination. You're not choosing whether to "build an agent." You're choosing how much of the decision-making about what happens next you delegate to a model at runtime, versus how much you decide yourself at design time. That's a dial, not a switch, and most production systems should sit closer to the deterministic end of it than the marketing around agents would suggest.
Four points on the same dial, not four different technologies
- A workflow follows predefined transitions. The next step is a function of the current step, full stop — no model is involved in deciding what happens next, even if a model is involved in doing the work at a given step.
- An AI-assisted workflow uses a model inside known steps — extracting structured data from a document, summarizing a ticket, classifying an intent — but the sequence of steps is still fixed by your code. The model does a job; it doesn't decide what job comes next.
- An agent chooses the next action and the next tool based on current state, at runtime, without a predetermined path. The model is doing real planning, not just execution.
- An agentic workflow is the honest middle ground most production systems should actually target: real autonomy, but bounded by a graph of allowed transitions, explicit budgets, policies, and human checkpoints at the moments that matter. The model still chooses — but it chooses from a constrained menu, inside a shape you defined.
These aren't four different architectures competing for the same job. They're four points on one continuum, and the skill being exercised is picking the point that matches the actual shape of the problem — not defaulting to the most autonomous option because it's the most interesting one to build.
Match autonomy to uncertainty and risk
The variable that should actually drive this choice is uncertainty in the task, not sophistication of the tool. Ask: can I enumerate the paths this task might need to take, economically, ahead of time? If yes — even if there are a lot of them — a workflow (possibly AI-assisted at individual steps) is almost always the better answer, because every path you can enumerate is a path you can test deterministically, secure explicitly, and reason about without needing to observe a model's live behavior to know what it's capable of doing.
Reach for real agent autonomy specifically when the number of viable paths is not economical to enumerate — when the right sequence of actions genuinely depends on what's discovered mid-task in a way your design-time self couldn't have anticipated. Debugging an unfamiliar system, researching an open-ended question, handling a support case where the right next step depends entirely on what the last tool call returned — these have real path uncertainty that a fixed workflow would either fail to cover or become combinatorially unmanageable trying to.
Higher autonomy is not a free upgrade — it's a direct trade against predictability, and that trade has to be paid for at every later stage of the system. More autonomy means a larger evaluation surface (you're no longer testing a fixed set of paths, you're testing a distribution of possible paths), higher and less predictable latency and cost (a model that gets to decide how many tool calls to make can decide to make a lot of them), and materially larger security exposure (every tool you hand to an autonomous planner is a capability an adversarial input might be able to redirect). None of that is a reason to avoid agents. It's a reason to make sure the task's actual uncertainty justifies paying that cost, rather than defaulting to it.
Choose the least autonomy that solves the task
This is worth stating as a design principle, not just a recommendation: use deterministic code for anything governed by known rules, a workflow for repeatable multi-step processes even if some steps need a model, and reach for agent autonomy only when the path genuinely cannot be enumerated economically. Every rung up that ladder should be a deliberate decision made because the rung below it demonstrably couldn't handle the task's real uncertainty — not a default reached for because agents are more capable in the abstract. Capability isn't the constraint most systems run into. Predictability is.
When you do build with tool-using autonomy — whether a full agent or a bounded agentic workflow — a few disciplines separate a system you can operate confidently from one that's a live incident waiting for the right adversarial input:
- Give tools narrow schemas, scoped credentials, idempotency, and explicit side-effect labels. A tool with a broad, loosely-typed interface and broad credentials is a bigger blast radius no matter how good your prompt is — the model doesn't need to be manipulated into doing something dangerous if the tool already had the permissions to do it accidentally. Idempotency matters here for the same reason it mattered in Part A and B of the RAG series: retries and re-planning happen, and a non-idempotent tool call under retry is silent duplicate side effects, not a clean error.
- Separate planning from execution, and require explicit approval before irreversible actions. The moment a plan is generated, that's a checkpoint — a place a human, or at minimum a policy check, can look at the proposed sequence before any of it runs against a real system with real consequences. An agent that plans and executes in the same breath has no such checkpoint, which is fine for read-only exploration and much less fine for anything that sends an email, moves money, or deletes data.
- Persist state and make every step replayable and observable. If a run fails, stops, or does something surprising three tool calls in, you need to be able to reconstruct exactly what state the agent believed it was in and what it decided to do about it — the same discipline as the request trace from the RAG series, applied to a multi-step plan instead of a single retrieval.
Design the stop conditions first, not last
The failure mode that's specific to autonomous systems — and doesn't really have an equivalent in a fixed workflow — is the run that doesn't know when to stop. A workflow terminates because its graph terminates; an agent terminates because you told it, explicitly and in advance, what termination looks like. If you haven't defined that, you haven't built a bounded system, you've built one that happens to stop eventually, for reasons you'll have to reconstruct after the fact.
Define, before the system runs a single real task: maximum steps (an upper bound on how much planning and tool-calling one task can consume, independent of whether it's "making progress"), time and token budgets (both, because a system can blow through one without the other), retry policy (how many attempts, with what backoff, and — critically — what counts as the same failure happening again versus genuine new progress), duplicate-action protection (has this tool already been called with these arguments in this run, and should it be called again), success criteria (what does "done" actually mean, stated concretely enough that the system — or a human reviewing the trace — can check it, not left as an implicit judgment call), escalation (the explicit path to a human when the system can't make progress or the task crosses a risk threshold it wasn't built to handle alone), and safe termination (what state does the system leave things in when it stops — mid-transaction is not a safe place to stop, and "safe to stop here" needs to be a property you designed for, not an accident of where the budget ran out).
Evaluate full trajectories, not just final prose. This is the single biggest blind spot I see in how teams test agentic systems: they check whether the final answer looks good and stop there, which tells you nothing about whether the path to that answer was efficient, safe, or would generalize to a slightly different situation. A trajectory that took an unnecessary destructive action and then recovered, arriving at a correct-looking final answer, is not a system that worked — it's a system that got lucky once, in a test you happened to be watching. Evaluate the sequence of decisions, not just where it ended up, and do it against simulated failures and adversarial tool outputs deliberately — a tool that returns malformed data, a tool that times out, a tool result that contains an embedded instruction trying to redirect the plan — because those are exactly the situations where the gap between "looks fine in the demo" and "fine in production" actually shows up.
The through-line, if there's one thing to take from this: an agentic system's autonomy is not the feature. Its boundedness is — the fact that you can say precisely what it's allowed to do, how far it can go before something stops it, and what happened, step by step, on the run that didn't go as expected. Build that first. The autonomy is easy to add on top of a bounded system. It's much harder to retrofit boundaries onto a system that's already been given the run of the place.