An LLM answers questions; an agent takes action. Knowing when to hand over control — and when to hold it back — decides whether the system stays stable.
The Felesh team3 min
You have a prompt and context, and your LLM answers accurately. Then a user asks, “cancel my last order.” The system hits a wall. To do this, the software must look up a database row, evaluate a date against a refund policy, and issue a state-changing request to a billing API. That is more than retrieving text — it requires taking a sequence of steps. This is the boundary where you cross from text generation into agent territory.
Cancelling takes three checked steps: find the row, test it against the refund window, then send the change to billing.
An agent does not just output a response; it runs a process. It is an LLM wrapped in a control loop, given a goal and a set of tools. Crucially, it decides which tool to call, when to call it, and what to do with the result. If a lookup returns an error, the agent reads the exception, corrects its request, and tries again. It drives itself.
A failed call is data: the model reads the error, fixes its own argument, and the retry finds the row.
But autonomy introduces entropy. The moment an LLM decides what to do next, you add a failure mode. Hallucinated function arguments and runaway loops become real production risks.
The model composed an order id from memory, and billing accepted it: one valid call cancelled someone else’s order.
You reach for an agent only when the system genuinely must direct itself. If a process is linear and predictable, write a plain code workflow. If a task requires real-time decisions, start with a single, well-scoped agent bound to a strict domain. The progression from deterministic code to a single agent to a coordinated set of agents is a ladder of fit, not of better — you move up only when the rigidity of the previous stage breaks under your requirements.
Start with a code workflow and climb a rung only when the one below breaks on a real requirement.