# Your AI agent re-reads its tool list on every step — that's 32% of the bill

> Source: <https://dev.to/altrouter/your-ai-agent-re-reads-its-tool-list-on-every-step-thats-32-of-the-bill-3bmn>
> Published: 2026-10-16 11:00:02+00:00

You give your agent a toolbox: read a file, run the tests, search the web. The model picks a tool, your code runs it, the result goes back, the model picks the next one. It feels like the model *knows* its tools. It doesn't. It forgets them after every reply, and you pay to remind it.

I counted what that reminder costs on a realistic toolbox. Short version: about a third of the bill.

A few words first. A **token** is roughly ¾ of a word; APIs bill per million of them, one price for **input** (what you send) and a higher one for **output** (what the model writes). **Tool calling** is the API feature where you describe functions and the model replies with "call `read_file` with these arguments" instead of plain text. Each function is described with a **JSON Schema** — a JSON object listing the name, a description and the parameters with their types.

Here is one of them, exactly as an OpenAI-compatible API expects it:

```
{"type": "function", "function": {
  "name": "edit_file",
  "description": "Replace an exact string in a file with a new string. The old string must appear exactly once in the file unless replace_all is true. Preserve indentation exactly.",
  "parameters": {"type": "object", "properties": {
    "path": {"type": "string", "description": "Path to the file to edit."},
    "old_string": {"type": "string", "description": "Exact text to find. Must be unique in the file."},
    "new_string": {"type": "string", "description": "Text to replace it with."},
    "replace_all": {"type": "boolean", "description": "Replace every occurrence instead of requiring a unique match."}},
  "required": ["path", "old_string", "new_string"]}}}
```

The API is stateless: nothing is remembered between requests. So the whole `tools` array travels inside the input of **every** request, next to the system prompt and the history. An **agent loop** — the model calls a tool, gets the result, decides the next move — is one request per step. Ten steps, ten copies of the toolbox.

I wrote 18 tools of the kind every coding agent ships with: `read_file`, `write_file`, `edit_file`, `list_directory`, `search_code`, `find_files`, `run_shell`, `run_tests`, three git tools, `web_search`, `fetch_url`, `http_request`, `query_database`, `create_issue`, `send_message`, `ask_user`. Descriptions are ordinary, one or two sentences each. Then I counted them with `tiktoken` and `o200k_base`, the tokenizer behind current GPT models:

``` python
import json, tiktoken          # pip install tiktoken
enc = tiktoken.get_encoding("o200k_base")
tools = json.load(open("tools.json"))   # your "tools" array

total = len(enc.encode(json.dumps(tools)))
print(f"{len(tools)} tools = {total} tokens per request")
for t in tools:
    n = len(enc.encode(json.dumps(t)))
    print(f"  {t['function']['name']:<16} {n}")
```

Result: **2,388 tokens**, 133 per tool on average. The smallest, `git_status` with no parameters, is 54. The biggest, `search_code` with five parameters, is 193. That's for one request — before the user has typed a word.

Now a modest agent run: a 500-token system prompt, a 200-token task, 10 steps, each step adding about 780 tokens of history (a tool call plus its result) and producing 150 output tokens. Prices are GPT-5.6's official ones on 15.10.2026: $2.00 per million input, $12.00 per million output.

| Toolbox | Tool tokens per run | Share of input | Cost per run | Schemas per month* | 
|---|---|---|---|---|
| All 18 tools | 23,880 | 36% | $0.150 | $1,433 | 
| 6 tools the task needs | 9,380 | 18% | $0.121 | $563 | 
| No tools (baseline) | 0 | 0% | $0.102 | $0 | 

*1,000 runs a day, 30 days, input price only.

With the full toolbox, the schemas are **$0.048 of a $0.150 run — 32% of the bill**. Per request, they weigh more than three times the system prompt and the task combined. And it's not a one-off: at 1,000 runs a day that's 716 million tokens a month spent re-describing `send_message` to a model fixing a typo.

Ship the agent only the tools the job needs. A coding fix doesn't need `create_issue`, `send_message` or `query_database`. Cutting to six relevant tools dropped the schema cost from $1,433 to $563 a month — $870 saved without touching a prompt.

Second, trim the descriptions. I kept every tool but cut each description to its first sentence and removed per-parameter descriptions: 2,388 → 1,545 tokens, −35%. Test that the model still picks the right tool afterwards; descriptions are how it decides.

Third, run the script above on your own `tools` array. It takes a minute and turns "it's just some JSON" into a number.

The price per token is the other multiplier. We resell GPT-5.6 at $1.70 per million input against the official $2.00, so the same 716M tokens of schemas cost $1,218 instead of $1,433. That's 15% off a waste you shouldn't be paying for at all — trimming the toolbox comes first.

My count is approximate. Providers don't send your JSON to the model verbatim: they rewrite it into an internal format and add their own instructions, so the real figure is a bit different and differs per vendor — check `usage.prompt_tokens` on a real call with and without tools. Prompt caching changes the money a lot: the tool list sits at the start of every request, which is exactly what caching discounts, so with caching on, the 32% shrinks. I can't show how much on our traffic — our usage records don't split cached tokens out yet. And swapping toolboxes per step breaks that cache, so "send fewer tools" and "cache them" pull against each other.

Count your tools before you count anything else. They're the part of the prompt you wrote once and pay for forever.
