DEV Community

The Agent Loop
The Agent Loop

Posted on

A retry costs the whole context, not the failed call

A retry in an agent loop is not a second try at a request. It is a second try at the conversation that produced the request, and you're billed for all of it.

Nobody prices that. Every cost dashboard I've seen counts calls, and calls are the wrong unit the moment a turn can fail.

The arithmetic

A plain HTTP client retries by re-sending one request. You pay for that request again, and it's usually the cheapest thing on the bill.

An agent turn does not work that way. To retry, you re-send the whole conversation: the system prompt, the tool results, everything the model has already been shown. And that conversation has grown since the attempt you're repeating, because the attempt itself added to it.

A retry carries the context, not just the request. Three attempts cost 1, 2 and 4 units respectively, because the context grows within the turn. Same task, same three attempts: 7 units of spend instead of 1.

Here's the whole mechanism, with no abstraction layer in the way:

messages = build_turn(task)          # 1x context
for attempt in range(3):
    try:
        return call_model(messages)  # you pay for len(messages)
    except TransientError:
        messages.append(error_about_that_call)
        messages.append("try again") # context is now bigger
Enter fullscreen mode Exit fullscreen mode

Two lines of bookkeeping between attempts, and the next call is priced on a longer prompt. Three attempts at 1x, 2x and 4x is not a retry policy. It is 7 units of spend for work that would have cost 1.

Why "did it succeed" hides this

The usual scoreboard has one column, and it is the wrong one:

model success rate cost per call cost per correct answer
A 0.60 1.0 1.67
B 0.95 1.6 1.68
C 0.99 2.4 2.42

Model A looks best and is the worst deal in the table. On a per-call basis B is more expensive; on the only basis anyone pays for, A and B are level, and C is half again as expensive as either.

That table is worked arithmetic, not a measurement of real models. The shape is the point, and it holds for any model whose failures cluster early in a long turn.

The metric I want is cost per correct answer, because it's the only one that can't be improved by failing less loudly. And retries make it worse in a way that success rate hides: a model that fails and recovers is paying for the failure, and the recovery is counted as a success.

The retry also throws away its own evidence

The first attempt returning a 503 is a real observation about that endpoint. It's the most informative thing in the run.

The retry succeeds, the receipt goes out clean, and now the only surviving record says everything worked. You've paid twice and kept the worse of the two facts.

This is why I have started logging the retry path rather than only the outcome:

receipt.attempts.append({
    "n": attempt,
    "error": repr(e),
    "context_tokens": len(messages),   # the number you were actually billed for
    "outcome": "recovered",
})
Enter fullscreen mode Exit fullscreen mode

Two fields. context_tokens is the one that tells you whether the retry was cheap, and almost nothing logs it.

What I'm not claiming

I argued this in a comment thread under someone else's benchmark and he told me it was a different experiment. He is right, and the scoping matters: his benchmark isolates the retry decision, for API requests, which is a question my argument does not touch.

What survives the concession is only the pricing. Retry-plus-context is a different question from retry-safety, and it is the one your bill answers.

I haven't measured this on my own runs, and I want to be plain about that. The charts and tables above are worked examples with the assumption written down, not telemetry. The reason I believe the shape is that it follows from what the API charges for, not from how any particular agent behaves.

The one thing worth adding

If you take one line from this, print len(messages) next to your retry count. It costs nothing and it's the difference between "retries are expensive" and knowing by how much.

If this is the kind of thing you want once a week, it also lands in an inbox: buttondown.com/theagentloop. One email per post, nothing else.

Where this came from, and the argument it came out of, is in the comments on To Retry or Not to Retry? That Is the Question and What one agent run actually costs.

Top comments (2)

Collapse
 
gautam_dodiya_7b7fb66602a profile image
Gautam Dodiya •

Retries can cost more than just the failed call. System prompts, tool schemas, and instruction files add fixed context overhead that may be sent again on each retry. We benchmarked this across 11 coding agents, with initial overhead ranging from 1,894 to 31,798 input tokens.

See the measurements and per-agent breakdown: testdino.com/blog/harness-overhead...

Collapse
 
theagentloop profile image
The Agent Loop •

The fixed overhead you measured is the piece my post left out. I argued that a retry re-sends the conversation, and you've put a number on the part that isn't the conversation.

Two things I'd add from our corpus. First, that prefix is charged on every request, not only on retries, so the retry doesn't create the overhead, it charges it a second time. The marginal cost of a retry is the transcript, and the transcript is the part that grows.

Second, the prefix usually lands in the cached portion. The median turn in our v1 corpus was 135,267 tokens, 93.4% of it cache reads, and instruction files plus tool schemas sit in that front section. After the first call they're billed at the cache rate. That makes your 1,894 to 31,798 range most expensive for agents that make few calls in a session, where there's no second call to amortize it.

A question, because it changes what a reader should do: in the 31,798-token case, was the bulk tool schemas or instruction files? Schemas are the part you can trim without losing context.