AI agents look simple at first.
You take a model, add a prompt, maybe connect a tool, and it works. It feels like you are just making one API call and getting an answer.
That illusion disappears the moment the agent starts doing real work.
In production, an agent is not one call. It is a loop. It may call the model multiple times, retrieve memory, execute tools, retry on failure, and refine its own output.
That is where cost shows up.
Not just in tokens, but in latency, complexity, and system load.
The mental model most people miss
Most tutorials present agents like this:
User → Model → Response
Real systems look more like this:
User → Runtime → Model → Tools → Memory → Validation → Model → Response
And that flow may repeat several times.
Each step adds cost.
Not just money. Time, complexity, and failure risk.
1. Token cost is not just one request
The first hidden cost is tokens.
Developers often assume a single request with a fixed prompt. In reality, an agent may call the model multiple times within one run.
For example:
- One call to decide what to do
- One call after retrieving memory
- One call after tool execution
- One call to generate the final response
Each call includes input tokens and output tokens.
If you also include memory retrieval, the prompt gets larger over time. That increases token usage even further.
A simple way to think about it:
const totalTokenCost =
(numberOfCalls) *
(inputTokens + outputTokens);
The problem is that numberOfCalls is not always predictable. It depends on how the agent behaves.
This is why cost can grow faster than expected.
2. Tool calls are not free
Tool usage is often treated as a free extension of the model. It is not.
Each tool call adds:
Network latency
External API cost
Failure scenarios
Additional model calls after execution
For example, a simple flow might look like:
Model decides → Call tool → Tool responds → Model interprets → Continue
Even if the tool itself is cheap, the surrounding orchestration is not.
In many cases, the cost of using a tool is not the tool itself, but the extra model calls and latency it introduces.
3. Retries multiply everything
Retries are where costs start to compound.
If a tool fails, the agent may retry. If the model returns invalid output, the system may retry. If validation fails, the system may retry again.
Each retry is not just one extra call. It repeats the entire step.
A simple retry loop might look like this:
for (let i = 0; i < 3; i++) {
try {
return await callTool(input);
} catch {
continue;
}
}
Now imagine this happening inside an agent loop.
One failure can lead to:
Multiple tool calls
Multiple model calls
Longer execution time
Retries are necessary, but without limits, they become expensive quickly.
4. Latency grows with each step
Latency is often underestimated.
Each model call takes time. Each tool call adds network delay. Each retry increases total execution time.
Even if each step is fast, the combined latency can be noticeable.
A simple breakdown:
Model call: 500ms to 2s
Tool call: 200ms to 1s
Memory retrieval: 100ms to 300ms
Now combine them across multiple steps.
An agent that feels “instant” in a demo can easily take several seconds in production.
This is not always a problem, but it becomes important for user experience.
5. Memory adds both value and cost
Memory is powerful, but it is not free.
Every time you retrieve memory, you add:
Query cost (vector search or database lookup)
Additional tokens (more context sent to the model)
Complexity in prompt construction
If memory is not filtered carefully, it can:
Increase token usage significantly
Add irrelevant context
Reduce model accuracy
The key is not more memory, but better memory.
Retrieve only what is relevant to the current goal.
6. Reflection and “thinking” steps increase usage
Many modern agent patterns include reflection.
The agent may:
Evaluate its own output
Re-plan its next step
Summarize intermediate results
These patterns improve quality, but they also add more model calls.
For example:
Model → Draft response
Model → Critique response
Model → Refine response
This can double or triple token usage.
Reflection is useful, but it should be used intentionally.
7. Cost is not just money
When people talk about cost, they usually mean API pricing.
In practice, cost also includes:
Latency. Slow agents reduce user experience.
System load. More calls mean more infrastructure usage.
Failure surface. More steps increase the chance of something going wrong.
Debugging complexity. More moving parts make issues harder to trace.
This is why cost should be treated as an architectural concern, not just a billing concern.
A simple way to think about it
If I had to simplify everything into one idea, it would be this:
Each new capability multiplies cost.
More tools → more calls
More memory → more tokens
More retries → more loops
More reasoning → more model usage
Agents do not scale linearly. They scale multiplicatively.
What actually works in practice
In real TypeScript systems, I try to keep things controlled.
Limit the number of steps. Do not let the agent run indefinitely.
Keep prompts small. Only include relevant context.
Use tools intentionally. Do not expose everything.
Set retry limits. Avoid infinite loops.
Track usage. Measure tokens, latency, and failures.
These are not optimizations. They are guardrails.
The real takeaway
AI agents are powerful, but they are not free abstractions.
Every decision you add to the system has a cost. Every layer adds complexity. Every retry multiplies usage.
The goal is not to remove these features. The goal is to use them intentionally.
A simple, controlled agent that solves a specific problem is often more valuable than a complex agent that tries to do everything.
Because in production systems, efficiency and reliability matter more than flexibility.
And understanding the hidden cost is the first step toward building something that actually scales.
Top comments (1)
The retry point is the one that bit us hardest. A failed step doesn't cost one more call — it re-runs the whole sub-loop, memory pulls and tool calls included, so the curve bends up fast. What helped was making "when do we stop retrying" a real rule: a hard budget per unit of work, and when it's blown the run caps and hands back to a human instead of digging a deeper hole.
The memory-tax point is the other sneaky one. Context doesn't just cost tokens once — it costs them every turn after, since it rides along in the window forever. We ended up compressing history as the window fills instead of all at once: summarize the low-value messages first, then actually drop them as pressure climbs, and hard-stop before a request would overflow. Trimming what rides along each turn saved us more than any per-call optimization did.