DEV Community

Jangwook Kim
Jangwook Kim

Posted on • Originally published at effloow.com

Web-Search Agents Waste Tokens: We Measured How Much

Picture a support assistant that looks things up for your team. A customer asks about a shipping delay, and the assistant runs three web searches, reads the results, and answers. Useful. Now it asks a follow-up question in the same conversation, then another. Each new step still carries every word of those earlier search results along with it, and you pay for all of it again on every turn.

That is the quiet tax on any AI feature that browses the web. The reading isn't the expensive part. Carrying what it read is.

This article puts a number on that tax. We ran a small, recorded check on a live model API to see how much a browsing agent's bill grows when it keeps raw search results in memory instead of trimming them to citations. Then we walk through the controls two major providers shipped in mid-2026 to stop the bleeding, and how to tell whether they belong in your own product.

Why a browsing agent gets expensive on the second step

Large language models charge by the token, roughly a token per three-quarters of a word. There are input tokens (everything you send the model) and output tokens (everything it writes back). When a model runs a web search, the page content it pulls back becomes part of the conversation. On the next step, that content is sent to the model again as input, so you are billed for it again.

Anthropic says this plainly in its own web-search documentation: "Web search results retrieved throughout a conversation are counted as input tokens, in search iterations executed during a single turn and in subsequent conversation turns." In other words, a result the agent read on step one is still on the invoice at step five.

For a one-shot lookup this barely matters. For an agent that searches, reads, reasons, and searches again across a dozen steps, the raw text of those early searches rides along the whole way. The bill keeps climbing after the agent has already pulled the one fact it needed. That is context bloat. On long-running tasks it shows up as slower responses and a fatter token bill.

What we built and ran

We could not call the hosted web-search tools directly from our bounded lab harness, so we measured the mechanism underneath them. We sent the same follow-up question to a real model twice. The only difference was what the model still had to carry from an earlier search step.

  • Baseline run: three full search-result blocks (verbose, placeholder text sized like real scraped pages) stayed in the context, the way they would if the agent echoed everything forward.
  • Trimmed run: the same three results, reduced to one-line citations (title plus link), the way a trimming control would leave them.

The follow-up question was identical: pick which of the three sources an analyst would trust most, in one sentence. We read the exact input-token count each provider returned in its usage report. The run used OpenAI's Responses API on the gpt-5.5-2026-04-23 model. Every prompt, request ID, and usage figure is saved in our public lab note.

What actually happened

Carrying the full results tripled the input bill for a single follow-up step.

What the agent carried forward Input tokens billed Answer it reached
Three full search results (baseline) 701 "C" — the standards source
Three citations only (trimmed) 236 "C" — same conclusion

The trimmed context cost 236 input tokens against 701 for the full one. That is 465 fewer tokens, about a two-thirds cut (66.3% lower), on one step. Put another way, the bloated version billed three times (3.0x) the input of the trimmed version for the same question.

Here's the part that matters for trust: the trimmed run still landed on the same answer. Dropping the raw text and keeping the citations didn't break the reasoning in this small test. The agent picked the same source and gave the same reason.

Now scale it up. One step saved a few hundred tokens. An agent that runs ten or twenty steps, each dragging those same early results forward, pays the penalty every single time. The waste grows with the length of the task, which is exactly where browsing agents are supposed to earn their keep. Our write-ups on where agents burn budget and trimming reasoning tokens show the same pattern from other angles. The cost is rarely the one big call. It's the accumulation.

Can this survive your workflow?

The question for a business reader isn't "is this interesting" but "does this show up in something I run." A few real cases where carried search results quietly inflate cost and latency:

  • Support triage that browses. An assistant that checks your help center, status page, and a shipping carrier before replying keeps all three around for the rest of the ticket. Multiply by ticket volume.
  • Research and monitoring agents. A competitive-tracking or news-summary agent that searches repeatedly across many turns is the worst case: long tasks, many results, all retained.
  • Internal automations that verify facts. A workflow that looks up a policy, a price, or a spec before writing a record carries that lookup through every downstream step.
  • Anything you plan to run at scale. A 3x input difference on browsing steps is the gap between a pilot that looks cheap and a rollout that does not.

If your agent searches once and stops, this is noise. If it searches, reasons, and searches again, this is a line item.

The controls providers shipped to fix it

Both major API providers now give you a switch for this. They work differently, and the names matter when you brief an engineer.

Control Provider What it does in plain terms What it touches
response_inclusion: "excluded" Claude (web_search_20260318+) Drops search results the agent already consumed in code, so they are not echoed back in the reply Output tokens
Dynamic filtering (default on web_search_20260209+) Claude Filters results in a sandbox before they reach the model, so only relevant text enters context Input / context tokens
return_token_budget OpenAI (hosted web_search) Caps how much search-result content the tool returns per run; set "unlimited" only for deep research Returned content size

A few specifics worth pinning down, straight from the docs:

  • Claude's response_inclusion defaults to "full". Setting it to "excluded" only affects results that were consumed by a completed code-execution call in the same turn; results from direct calls, or calls that paused, are always returned in full so they can be sent back next turn. Its stated benefit is reducing output token cost.
  • Claude's dynamic filtering is the input-side lever. From web_search_20260209 on, web search runs inside code execution by default and filters results before they hit the context window. That is what trims the per-turn input load our test simulated.
  • Citations survive either way. Claude's docs note that citation fields (cited_text, title, url) do not count toward token usage at all, so keeping attribution is free.
  • OpenAI's return_token_budget accepts only default or unlimited, applies to the hosted web-search tool on GPT-5-class reasoning models, and the guidance is to keep the default because unlimited "can increase latency and cost."

One thread runs through all three: dumping full search results into the model on every turn is now treated as the wrong default, and each provider hands you a way to stop doing it.

When to use these controls, and when to skip

Use them when:

  • Your agent runs multi-step browsing tasks (research, monitoring, multi-search support).
  • You run at volume, where a 2x-3x input difference on browsing steps changes the unit economics.
  • You keep long conversations alive and searches accumulate.

Skip or hold off when:

  • Your feature does a single search and answers. The overhead is tiny and trimming adds complexity for no real gain.
  • You genuinely need the full raw result downstream (for example, quoting long passages verbatim to the user). Trimming to citations would lose content you actually use.
  • You are still validating answer quality. Turn trimming on in a test lane first and confirm answers hold, as they did in our micro-run, before shipping it.

Limitations, stated plainly

This is one small, synthetic check, not a benchmark. We used three fabricated result blocks, one follow-up question, and one model. We measured the input-token mechanism that these controls target; we did not invoke the actual response_inclusion or return_token_budget parameters, and we did not capture a billed-dollar figure. The 66.3% number is specific to this setup. The real savings on your workload depend on how verbose your results are and how many turns they persist, so treat the percentage as an illustration of direction and scale, not a rate to quote in a budget. The reproduction steps are in the lab note if you want to run your own numbers.

What Effloow added

The provider docs tell you these controls exist. They do not show you the size of the problem they solve on a real API, side by side, with the exact token counts. We ran that comparison, recorded both runs with request IDs, confirmed the trimmed context reached the same answer, and translated the result into what it means for a browsing feature you might ship. That measured before-and-after, plus the source-checked control matrix above, is the part you cannot get from a changelog. For context on why long context matters here at all, see our guide on the 1M-token context window race.

For your engineers

Reproduction and method detail, kept separate from the business summary above.

Harness. scripts/openai-lab-run.py, OpenAI Responses API, model gpt-5.5-2026-04-23. Two prompt files: a "bloated" context with three verbose synthetic web_search_result blocks retained, and a "trimmed" context with only citation lines. Identical follow-up instruction in both.

Measured usage (usage.input_tokens, exact):

  • Baseline (full result blocks): 701 input tokens, output 117 (92 reasoning), request 61565989-c5f0-42cb-9e82-0123722d50e8.
  • Trimmed (citations only, 120-token output cap): 236 input tokens; the small cap was spent entirely on reasoning, so no visible answer.
  • Trimmed parity (400-token output cap): 236 input tokens, answered "C", request 99d3d74b-3f7c-42a5-b2c0-f3c1eebb37e5.
  • Delta: 465 input tokens (66.3% reduction); baseline = 3.0x trimmed input.

Full prompts, SHA-256 hashes, request IDs, and raw usage blocks are in /lab-runs/agentic-web-search-context-control-token-proof-2026.

Provider surfaces to configure (read the current docs before shipping):

  • Claude web search: tool versions web_search_20250305 (basic), web_search_20260209 (dynamic filtering, allowed_callers defaults to ["code_execution_20260120"]), web_search_20260318 (adds response_inclusion). No beta header is documented as required. To search directly without filtering, set allowed_callers: ["direct"].
  • OpenAI hosted web_search: return_token_budget is default or unlimited only, GPT-5-class reasoning models, hosted Responses API tool.

Caveats. Synthetic single-run measurement; not the actual hosted parameters; not a billed-cost or latency figure. response_inclusion reduces output tokens (echoed consumed blocks); dynamic filtering and return_token_budget govern the input/returned side. Re-verify tool version identifiers and defaults against the live docs, since these ship on a fast cadence.

Want this measured on your own agent?

Effloow runs claim-bound token and cost checks on the exact workflow you plan to ship, then documents the before-and-after so your team can decide with real numbers.


See how Proof Studio works →

Sources

Top comments (0)