- An agent is a while loop around a chat completion. Send the messages and the tool list, read the reply, run any tool it asked for, append the result, repeat until you decide to stop.
- The model never runs anything. It emits a request; your code executes it and hands back the output. Every security property of the system lives on your side of that line.
- The stop condition is where homegrown agents fail, and one condition is not enough. You need a step ceiling, a repetition detector and a token budget, because each catches a failure the others miss.
- Anthropic's own guidance argues against building one at all until simpler things fall short, because agents trade latency and cost for capability and can compound their own errors.
- The pattern has a paper behind it. ReAct interleaves reasoning with actions and reported a 34 percent absolute improvement over imitation and reinforcement learning baselines on ALFWorld.
- Keep the tool count small. OpenAI's guidance suggests fewer than 20 available at the start of a turn, and every definition you add is billed on every request.
Most tutorials on this subject are advertisements. They import a framework in line three, and by the end you have a working demo and no idea which part was the agent. That matters, because the framework decision is the one you are trying to make, and you cannot make it while the framework is doing the explaining.
So here is one agent with nothing underneath it. The loop is written out in the order it executes, the stop condition gets the attention it deserves rather than a passing mention, and at the end there is a plain table of what a framework would actually add so the decision becomes obvious instead of fashionable.
What is an agent, precisely?
A loop that keeps calling a model until the model stops asking for things. That is the whole idea, and the useful definition comes from Anthropic's engineering guidance on effective agents, which draws the line at who controls the path.
A workflow orchestrates models and tools through code paths you wrote in advance. You know the steps. An agent lets the model direct its own process and choose its own tool use across as many turns as it takes. You do not know the steps, and that is the point: the guidance says agents suit open ended problems where the required number of steps cannot be predicted.
The distinction is worth holding onto because most things people call agents are workflows, and workflows are better. They are cheaper, they are debuggable, and they fail in ways you can enumerate. If you can draw your process as a flowchart, write the flowchart. The same guidance is direct about this: start with simple prompts, evaluate them properly, and add agentic machinery only when the simpler thing has actually fallen short.
The loop, one turn at a time
Five steps, and OpenAI's function calling documentation lists them in the same order every implementation converges on.
One. Send the state. Your request carries the full message list so far plus the schema of every tool the model may call. There is no hidden memory. Whatever you do not send, the model does not know, which is why an agent's cost grows on every turn even when nothing interesting happens.
Two. Read the reply. It contains either a final answer or one or more tool calls, each with a name and arguments. Branching on this is the entire control flow of the loop. If it is an answer, you are done; if it is a call, you continue.
Three. Run the tool. Your code executes the function with the arguments the model supplied. This is the sentence people skim and should not: the model produced a request, and your program decided to honour it. Validate the arguments here the way you would validate a form submitted by a stranger, because in the security sense that is exactly what this is.
Four. Append the result. The output goes back into the message list as a tool result, so on the next turn the model sees what happened. Errors go back too, as text. A tool that raises and kills the loop teaches the model nothing; a tool that returns no customer found with that email lets it try something else.
Five. Check the stop condition. Then loop, or exit. Most tutorials write this as a for loop with ten iterations and move on, which is why the next section is longer than this one.
Why does the stop condition matter more than the rest?
Because everything above it is mechanical, and this is the only place where a homegrown agent quietly costs you money. There are three distinct failures and a single condition catches only one.
The runaway. The model keeps calling tools and never concludes. A hard ceiling on turns fixes it. Pick a number, make it visible in your logs, and treat hitting it as an incident rather than as a normal outcome, because a loop that regularly reaches its ceiling is a loop whose task was never achievable.
The oscillation. Two tools call each other in effect, or the model repeats the same call with the same arguments, gets the same answer, and tries again. The step ceiling catches this eventually and expensively. A repetition detector catches it on the second occurrence: hash the tool name plus its arguments, keep a set, and break when a hash repeats. That is about four lines and it is the highest value four lines in the whole file.
The budget overrun. Neither of the above triggers, the loop concludes correctly, and it cost eleven times what you expected because the message list grew on every turn. Track the tokens you have spent inside the loop and stop on a threshold. This one surprises people because the run succeeds, so nothing alerts, and the arithmetic underneath is the same compounding one we set out in why the bill comes in bigger than the estimate.
Anthropic's guidance names the underlying risk plainly: autonomy brings higher costs and the potential for compounding errors, which is why sandboxed testing and guardrails belong in the first version rather than the third.
Where do the tools come from?
You write them, and they are ordinary functions. The interesting part is the description, because that text is the only thing the model uses to decide whether to call you.
The OpenAI guidance offers a test worth stealing: the pass the intern test. If a competent new colleague could not work out how to use the function from the name, the parameter descriptions and the system prompt alone, the model will not either. It also gives three rules that each remove a class of bug. Use enums and structured objects so invalid states cannot be expressed. Do not make the model fill in arguments you already know, such as the current user id. And combine functions that are always called in sequence into one operation, because two calls means two chances to get the order wrong.
On quantity, the suggestion is fewer than twenty tools available at the start of a turn, described as a soft limit rather than a hard one. Two reasons back it. Choice quality degrades as the list grows, and every definition is sent on every request, so a large catalogue is a fixed tax on each turn of the loop.
If your tools need to reach systems outside your own code, that is what the Model Context Protocol standardises, and building one is a short exercise: our walkthrough of a first MCP server from nothing to working covers it end to end.
Does the reasoning trace do anything?
Yes, and there is evidence rather than folklore behind it. The ReAct paper, published in 2022 and presented at ICLR 2023, set out the pattern of interleaving reasoning traces with actions rather than emitting actions alone.
The numbers it reported are the reason the pattern stuck. On ALFWorld, an interactive decision making benchmark, interleaving beat imitation and reinforcement learning baselines by 34 percentage points of absolute success rate, using one or two in context examples and no specialised training. On WebShop the improvement was 10 points. On knowledge tasks the authors described the reasoning trace as reducing hallucination and error propagation, because a wrong step becomes visible in the trajectory instead of silently poisoning the next one.
The practical version for your loop: let the model say what it is doing before it does it, and keep those statements in the message list. It costs tokens and it buys you a debuggable transcript, which on the day something goes wrong is the difference between reading the reasoning and guessing at it.
How do you keep the message list from eating the budget?
By deciding, deliberately, what the model needs to still be able to see on turn nine. Left alone, the list only grows, and since you resend all of it every turn, cost rises roughly with the square of the number of turns rather than linearly.
Three techniques, in increasing order of effort.
Truncate tool results after they are used. Once the model has read a large query result and acted on it, the full text is rarely needed again. Replace it in the list with a one line summary and a note that it was truncated. This is safe far more often than people expect, and it is the single largest saving available.
Summarise the middle. When the list passes a threshold, collapse the oldest turns into a short paragraph of established facts and decisions, keeping the system message and the most recent exchanges intact. The risk is losing a detail that mattered, so summarise into a fixed structure, facts established and decisions taken, rather than into free prose.
Keep state outside the conversation. The most durable fix is to stop using the message list as your database. If the agent has gathered five facts, hold them in a structure your code owns and render them into the prompt each turn in a compact form. This also makes the run inspectable, since you can print the state rather than reading a transcript, and it is the boundary described in our note on what an orchestration layer has to own.
All three of these are decisions about your application, not about the model, which is the recurring theme of building one of these yourself. The clever part is not the prompt. It is knowing which information deserves to survive to the next turn.
What would a framework actually give you?
Now the comparison is answerable, because you have written each piece and know what it cost.
| Concern | Yours to build | What a framework typically supplies |
|---|---|---|
| The loop itself | About 40 lines | The same loop, with a class name |
| Stop conditions | Ceiling, repeat detector, token budget | Usually a step limit only, so you still add the rest |
| Tool schemas | Written by hand or from type hints | Generated from your function signatures, a real saving |
| Retries and timeouts | Your own wrapper around the client | Built in, configured rather than written |
| Tracing and replay | Logging you design | The strongest argument for adopting one |
| Multi agent handoff | Genuinely fiddly | Solved, if you actually need it |
Read the table honestly and the decision follows. If you are building one agent with four tools, the framework buys you schema generation and tracing, and charges you a dependency plus an abstraction between you and the API. If you are building six agents that hand work to each other, it buys you the hard parts. We took that comparison further in whether you need an agent framework or just the loop, and the conclusion has not moved.
Which of the five workflow patterns fits before you reach for an agent?
Anthropic's guidance lists five, and four of them will solve a problem you were about to hand to a loop. Reading them as a menu is a faster way to make the build decision than arguing about definitions.
Prompt chaining is sequential calls where each one consumes the previous output. Use it when the task decomposes cleanly and you know the order. Drafting then editing then formatting is a chain, not an agent.
Routing classifies the input and sends it to specialised handling. A support inbox where refunds, shipping questions and technical faults each need different treatment is a routing problem, and building it as a routing step gives you three simple prompts instead of one overloaded one.
Parallelisation splits work into independent pieces or runs the same task several times and votes on the result. Useful when the pieces genuinely do not depend on each other, and the voting variant is a cheap accuracy improvement on judgement calls.
Orchestrator workers has a central model delegating subtasks whose shape is not known in advance. This is the closest of the four to an agent, and the difference is that the orchestrator owns the decomposition while the workers stay narrow.
Evaluator optimiser loops a generator against a critic. It is the right shape whenever you can state what good looks like more easily than you can produce it, which describes most writing and much code.
Only when none of these fit does the open ended loop earn its cost. The test is whether you can predict the number of steps. If you can, one of the five patterns above is cheaper, faster and far easier to debug at three in the morning.
What breaks first in production?
Not the model. Three other things, in roughly this order.
Tool output size. Someone runs a query that returns four hundred rows and the whole result lands in the message list, where it stays for the rest of the run and is resent on every subsequent turn. Cap the output of every tool at the boundary and say in the description that it is capped.
Partial failure. The third of five tool calls fails, the loop continues, and the final answer confidently describes a state that never existed. The model has no way to distinguish a tool that returned nothing from a tool that failed unless your result text says so. Make failure explicit in the words you return.
Silent drift. Nothing errors and quality falls, usually because a tool description was edited or a model version moved. This is the argument for keeping a fixed set of test tasks you rerun on any change, which is the practice described in checking whether a change actually helped. Without it you are relying on someone noticing, and nobody notices.
If the agent you have in mind is one that operates a commerce system rather than a general assistant, MaShop already exposes those operations over a documented interface. The MaShop MCP page lists what is available, which is usually cheaper than rebuilding the same catalogue of tools.
Build this one first
Two tools, a hard ceiling of six turns, a repetition break and a printed transcript. Pick a task you can verify by eye, such as looking something up and writing a short summary of it.
Run it twenty times and read every transcript. You will find that the model calls one tool far more than you expected, that one description is ambiguous in a way you could not see when you wrote it, and that at least one run did something you did not anticipate. Those three discoveries are the actual output of the exercise. The working agent is a side effect.
Then, and only then, decide about a framework. You will be choosing based on what you know it costs to do without one, which is a different and much better position than choosing based on which one had the clearest documentation.