Most of what gets sold as AI agent architecture is a while loop with a language model in the middle. That is not an insult. It is the honest starting point, and once you accept it the whole topic gets a lot less mystical. An agent reads some state, asks a model what to do next, runs that action, feeds the result back in, and repeats until it decides it is done or you cut it off. Everything else is plumbing around that core, and the quality of the plumbing is what separates a demo from something you can leave running.
The loop is the whole thing
Strip away the frameworks and an agent is a control loop. You give the model a goal, a description of the tools it can call, and the current context. It returns either a tool call or a final answer. If it returns a tool call, you execute it, append the output, and go around again. The reason this feels harder than it sounds is that the model is non-deterministic and the world it acts on is messy, so your loop has to survive bad calls, repeated calls, and calls that half work.
I keep the loop dumb on purpose. The model decides what to do. My code decides whether it is allowed to, runs it safely, and records what happened. Mixing those two jobs is how you end up with an agent that is impossible to debug, because you can no longer tell whether a failure came from the model reasoning poorly or from your orchestration dropping a result on the floor.
Tools are the actual product
An agent is only as capable as the tools you hand it, and tool design is where I spend most of my time. A good tool has a narrow job, a clear name, and arguments the model can fill without guessing. A bad tool is a kitchen-sink endpoint with ten optional parameters and a description that assumes the reader already knows your codebase. The model will misuse the second kind constantly, and you will blame the model.
A few habits that have held up for me:
- Write tool descriptions for a smart stranger, not for yourself. The model has none of your context.
- Return errors as plain text the model can read and act on, not stack traces or raw HTTP codes.
- Make tools idempotent where you can, because the agent will call them twice.
- Validate arguments before executing, and send violations back as a normal result so the model can correct course.
Memory is mostly context management
People hear agent memory and picture something grand. In practice it is the unglamorous work of deciding what goes into the context window on each turn and what gets left out. The window is finite and every token costs money and attention, so you cannot just append everything forever. You summarize old turns, you keep a running scratchpad of decisions, you store facts somewhere retrievable and pull them in only when relevant.
The mistake I see most is treating memory as a database problem when it is really a relevance problem. You do not need the agent to remember everything. You need it to have the right five things in front of it at the moment it makes a decision. Get that selection wrong and a model with a huge window still acts confused, because the signal is buried under stale junk it dragged along from twenty steps ago.
Planning, and why I stay skeptical of it
There is a lot of literature on giving agents explicit planning steps, where the model writes out a plan and then executes it. Sometimes this helps. Often it produces a confident plan that falls apart on contact with the first real tool result, and then the agent stubbornly follows the dead plan anyway. I lean toward short horizons. Let the model take one good step, observe the result, and decide again. Replanning every turn is cheaper than recovering from a wrong plan it committed to early.
For genuinely long tasks I split the work into smaller agents with tight scopes rather than one agent trying to hold the entire problem in its head. A focused agent that does one job and reports back is easier to test, constrain, and reason about when something goes sideways at 2am.
The failure modes nobody warns you about
The first time you ship an agent you learn that loops do not always end. The model gets stuck calling the same tool with slightly different arguments, convinced the next try will work. You need hard limits: a max step count, a budget cap, and detection for repeated identical actions. Without them a single confused run can burn real money and produce nothing.
The second thing you learn is that agents fail quietly. A traditional program crashes and you get a stack trace. An agent calmly produces a plausible wrong answer and reports success. That is why observability matters more here than almost anywhere else. Log every step, every tool call, every model decision. When something goes wrong, and it will, the trace is the only way to see where the reasoning broke instead of guessing.
Build the boring parts first
If you take one thing from this, make it this: the interesting part of an agent is the model, but the part that decides whether it works in production is everything around the model. Tight tools, careful context, hard limits, and traces you can read. Get those right and a fairly ordinary model becomes genuinely useful. Skip them and the smartest model on the market will still embarrass you in front of real users.
Building something where this matters?
I am open to senior full-stack, Web3, or AI engineering roles, fully remote and any timezone. If the hard part of your product is fighting you, that is the work I like.
Get in touch →