A thing that surprised me profiling an LLM agent loop: the biggest single token line item, before the user even types anything, was the tool/function schema block. A dozen tools with verbose JSON-Schema parameter descriptions was ~4–6k tokens re-sent on every turn, because the tool list is part of the system context and isn’t cached the same way across a multi-turn loop unless you set it up deliberately.

Three things that measurably cut it, in order of impact:

  1. Trim parameter descriptions to one line. Long per-field prose in schemas is the easy win — the model rarely needs a paragraph to know what path means. This alone dropped one agent’s per-turn overhead ~30%.
  2. Defer rarely-used tools. Instead of loading all 20 tool schemas up front, expose a small core set plus a search_tools call that returns the full schema on demand. Most turns only touch 2–3 tools.
  3. Order for prompt caching. Keep the static block (system prompt + tool schemas) as a stable prefix so the provider’s prefix cache actually hits; anything that changes per turn goes at the end.

Curious how others measure this — do you track tokens-per-turn broken down by (system / tools / history / user), or just watch the total bill? The per-segment breakdown is what made the tool-schema cost obvious; the aggregate number hid it.