Academy

The agent that acts (and when not to)

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 team 3 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 in three checked stepsA customer asks to cancel their last order. The row is found: order 3381, placed 12 Jun. The refund window is checked: 7 days since purchase, inside the 14-day window, so it is allowed. The change is sent to billing, which confirms that order 3381 is cancelled.customer: “cancel my last order”look up the roworders: #3381, placed 12 Juncheck the refund window7 days since purchase, window 14allowedsend the change to billingcancel_order(3381)billing confirms: order #3381 cancelled
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, corrected and retriedThe model calls lookup_order with id “last” and gets an error: id must be a number. It reads the error, fixes the id to 3381 and calls again. The billing database returns the row for order 3381, placed 12 Jun.the modeldecides thenext callfixes the idcall 1: “last”id must be a numbercall 2: 3381lookup_orderbilling databaseplaced 12 Junrow found
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.

A guessed id cancels the wrong orderA customer asks to cancel their last order, which is order 3381. The model writes cancel_order with order_id 3831, an id it composed from memory. Billing accepts any integer and cancels order 3831, which belongs to another customer. Order 3381 stays active.customer: “cancel my last order”the model’s callcancel_order(order_id = 3831id composed from memorybillingorder #3381, yoursorder #3831, not yourscancelled: wrong orderbilling accepts any integer it is given
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.

Three rungs and when each one fitsA table of three rungs, top to bottom: several agents, a single agent, and a code workflow at the bottom, where you start. A code workflow fits fixed steps with no model call. A single agent fits a free-text request where one agent picks the tool within one scope. Several agents fit billing, returns and claims, which each need their own rules and tools.runguse it whenseveral agentsone scope eachbilling, returns, claimseach needs its own rulessingle agentone model, one scopethe request is free textthe agent picks the toolcode workflowno model callthe steps are fixed:check the window, then cancelstart here
Start with a code workflow and climb a rung only when the one below breaks on a real requirement.