AI coding

Enumerating What an Agent Sends to a Check

Antonio Evans8 min read

A single rectangular envelope labeled 'Agent Check Prompt' split into colored horizontal bands like a stacked bar chart.
Key points

Key points

  1. 1A check's prompt is assembled from separate sources: system instructions, tool schemas and descriptions, retrieved documents, conversation history, few-shot examples, the user message, and serialization framing, and each one should be counted on its own.
  2. 2Local text tokenizers miss the tokens a real request adds for message roles, tool schemas, and conversation boundaries, so the only reliable count comes from serializing the exact payload the model receives.
  3. 3Token counts differ from provider to provider for identical text, so a segment's token count is specific to the tokenizer and model you measure against.
  4. 4Once each segment has its own count, multiplying by the input price per token turns an undifferentiated bill into a per-source cost share you can act on.

Why aggregate counts hide the problem

A total input token count per call answers one question only: how big was the request. It cannot tell you whether the growth came from a longer tool description, an oversized retrieval result, or a few-shot block that crept in during a prompt revision. Teams running agents often see input spend climb and reach for a cheaper model, when the real cause is one segment that grows on every call.

Braintrust's guide to tracking token usage makes this distinction explicit: prompt bloat usually arrives through small template changes that accumulate, such as an added few-shot example or a longer tool description, and finding it requires breaking out prompt and completion tokens per call and tracking them across prompt versions rather than watching a monthly total 1. Mintive's monitoring write-up reaches the same conclusion from a cost angle: per-agent cost attribution is what surfaces retrieval faults, oversized context, and retry loops that drive unnecessary spend, while aggregate dashboards leave the CFO's question unanswered 2.

The productivity argument is indirect but real. Google's DORA research on test automation notes that fast, reliable automated test suites give developers feedback in under ten minutes and drive both stability and reduced deployment pain, which is why an agent check that runs on every pull request deserves the same cost discipline as the CI minutes it consumes 3.

List every source before you count anything

Attribution fails when the inventory is incomplete. Before you touch a tokenizer, write down every input that reaches the check's prompt. For a typical agent that reviews a change against acceptance criteria, the list looks like this:

SourceWhat it containsTypical behaviorWhere it is assembled
System instructionsRole, rules, output format, refusal policyFixed per prompt versionPrompt template
Tool schemasTool names, parameters, JSON Schema, descriptionsFixed, but grows when tools are addedTool registry passed with the request
Tool descriptionsNatural-language explanation per toolEdited often, rarely measuredSame registry
Retrieved documentsCode, specs, ticket text pulled by a retrieverVaries wildly per callRetrieval step
Conversation historyPrior messages and tool resultsGrows with every turnMessage array
Few-shot examplesInput and output pairs showing the target formatFixed but easy to bloatPrompt template
User inputThe ticket, diff, or question under reviewVaries per callRequest
Serialization overheadRole tags, separators, message boundariesHidden from local tokenizationProvider request framing

The two rows that surprise people are tool schemas and serialization overhead. Tool definitions are sent on every call when tools are enabled, so a generous set of tools can dwarf the user message. Serialization overhead is invisible because it never appears in your strings: OpenAI's own documentation states that its input token counting endpoint includes formatting tokens used for request structure, such as message roles and boundaries, and that these tokens might not appear in the text you tokenize locally 4. An older community thread on counting chat tokens documents the same effect, where a single user message in chat mode consumed roughly 422 more tokens than the same text in completion mode 5.

A practical rule: any input the model reads but you did not type into a single variable belongs in the inventory. That includes anything the framework inserts.

Capture the exact serialized payload

Counting segments from your source variables gives you estimates. Counting the payload the provider actually receives gives you the truth. The way to get it is to log the request body at the boundary where it leaves your process, not to reconstruct it later from template variables.

import json, hashlib, time

def log_request(model: str, payload: dict) -> dict:
    body = json.dumps(payload, sort_keys=True, separators=(",", ":"))
    record = {
        "ts": time.time(),
        "model": model,
        "sha256": hashlib.sha256(body.encode()).hexdigest(),
        "bytes": len(body.encode()),
        "payload": payload,
    }
    # write to your trace store, one record per call
    return record

Two fields do the heavy lifting here. The payload is what you will segment later, and the hash lets you deduplicate: if the system instructions and the tool registry are unchanged between calls, their hash is unchanged too, and you can count them once and reuse the number. That matters for prompt caching, where keeping reusable prefixes stable is how cache hit rates improve and input costs fall, with savings that depend on the provider and workload 2.

Where a provider exposes an input token counting endpoint, use it on the assembled request rather than on the individual strings. OpenAI documents that the endpoint accepts the same input format as the request, including messages, files, tools, and conversations, and returns the exact count the model will receive 4. The general API guidance is blunter: a plain text token count does not necessarily include all tokens in an API request, because message structure, tools, schemas, images, and files all affect the full input count 6.

Tokenize each segment with the same tokenizer

Now split the logged payload into labeled segments and count each one independently. The discipline that matters is using the same tokenizer and encoding for every segment and for the whole, so the parts reconcile with the total.

import tiktoken

enc = tiktoken.encoding_for_model("gpt-6-astra")  # use the encoding for your target model

def count(segment_text: str) -> int:
    return len(enc.encode(segment_text))

segments = {
    "system": system_instructions,
    "tools": json.dumps(tool_registry),
    "few_shot": few_shot_block,
    "history": json.dumps(conversation_history),
    "retrieved": "\n\n".join(doc["text"] for doc in retrieved_docs),
    "user": user_message,
}

counts = {name: count(text) for name, text in segments.items()}
serialized_total = request["usage"]["input_tokens"]  # from the provider response
overhead = serialized_total - sum(counts.values())
counts["serialization_overhead"] = overhead

The overhead line is the insight most teams never compute. It is the difference between the sum of your segments and what the provider billed, and it absorbs role tags, separators, and any structure the provider adds. If overhead is large and roughly constant per call, it is a fixed frame cost; if it scales with the number of messages or tools, it points at framing, not content.

One warning: do not mix tokenizers. Firecrawl's analysis of tokenization across providers reports that the same text can produce up to 2.65 times more tokens on one model than another, and that Gemini is cheapest on plain text but 46 percent dearer than OpenAI on tool definitions 7. Tool schemas are exactly the segment most sensitive to this, because they are dense JSON, and the same report notes that code and JSON tokenize far less tidily than prose 7. Count tool schemas with the target model's tokenizer every time.

For quick sanity checks, a general-purpose tokenizer tool can show how a sample string splits into tokens, though its counts apply to the model family it names, not to every provider 8. And keep prose conversions out of billing: a tokens-to-words calculator is useful for planning a prompt budget, not for estimating an invoice, since English prose runs roughly 1.3 to 1.5 tokens per word depending on the tokenizer 9.

Turn counts into a cost table

Counting is only half the job. The other half is multiplying and presenting in a shape a team can act on. Take the input price per token for the model in use, multiply each segment, and add a share column. A worked example makes the decision rule concrete.

Assume a model priced at 2 US dollars per million input tokens, and a check that runs 100,000 times a month. The per-segment counts come from the logged payload, not from estimates.

SegmentTokens per callShare of inputMonthly tokensMonthly input cost
System instructions9005.0%90,000,000$180
Tool schemas and descriptions5,40030.0%540,000,000$1,080
Few-shot examples1,80010.0%180,000,000$360
Conversation history3,60020.0%360,000,000$720
Retrieved documents4,50025.0%450,000,000$900
User input9005.0%90,000,000$180
Serialization overhead9005.0%90,000,000$180
Total18,000100%1,800,000,000$3,600

Read the table as a set of decisions. Tool schemas at 30 percent are the largest single line, so trimming unused tools or tightening descriptions buys more than anything else. Retrieved documents at 25 percent suggest a retrieval cap or a reranker that keeps fewer chunks. Conversation history at 20 percent suggests truncation or summarization after a fixed number of turns. System instructions and user input together are 10 percent, so rewriting the prose there is wasted effort at this scale.

Glean's token efficiency guide argues for exactly this framing, tying spend to the task it served and the model that processed it rather than reporting raw consumption 10. The same source notes that output tokens cost several times more than input tokens across major providers, which is why this table covers input only: a complete cost model needs a second table for output, but input is where the attribution problem lives. A general LLM cost estimation walkthrough is a useful companion for building that second table, since it works from token usage through to total spend 11.

One operational note on cost allocation across teams: AWS's community guidance for enterprise token tracking is to treat granular cost allocation as an application-level problem when the managed service does not provide it, which in practice means your own logging and tagging, not the provider dashboard 12.

Keep the decomposition honest over time

A one-off measurement decays. Segment counts drift as prompts are edited, tools are added, and retrieval settings change. Three habits keep the table current.

First, snapshot the segment counts whenever the prompt version changes, and store them with the version identifier. Braintrust recommends tracking prompt and completion tokens across prompt versions precisely because bloat arrives through small edits 1.

Second, alert on the ratio, not the total. A rule such as "retrieved documents exceed 40 percent of input tokens on any call" catches retrieval regressions before they reach the invoice, and it survives a model change that shifts every absolute count.

Third, watch the tail, not the mean. Span-level visibility is what reveals a retrying tool call or an oversized retrieval step sitting deep inside a trace and dominating usage even when the top-level numbers look normal 1. Per-call logs give you the distribution; the mean hides the 1 percent of calls that cost 20 percent of the budget.

There is a second reason to decompose rather than just count: it forces the question of whether each segment earns its tokens. A few-shot block that was added to fix one class of failure and never reviewed is a fixed cost you are paying on every call. The same logic that Berkeley researchers apply to autonomy applies to prompts: be explicit about which parts of the work are owned by the instructions and which are carried by retrieved context, because the failure modes differ 13. Write the reasoning down once, and the next person who edits the prompt knows what each block is for.

If you are running checks across several model families and want one place to compare per-segment costs without managing a key per provider, Quanta Inference exposes text, image, video, audio and embedding models through one OpenAI-compatible API with prepaid pricing in US dollars (https://quantaintelligence.ai/inference). The payload logging approach above works unchanged against it.

FAQ

FAQ

What counts as serialization overhead in a prompt?

It is every token the provider adds that you did not type: message role tags, separators between messages, tool-call framing, and request boundaries. It shows up as the gap between the sum of your segment counts and the input token count the provider reports. OpenAI states that its counting endpoint includes these formatting tokens and that they may not appear in locally tokenized text 4.

Can I just divide characters by four to estimate tokens?

Not for a bill. The four-characters-per-token rule is a rough planning heuristic for English prose, and OpenAI labels it an estimate rather than an exact count 6. It breaks badly on JSON, tool schemas, and code, which are the segments most likely to dominate an agent check.

Why do my segment counts not add up to the billed total?

Usually the provider adds framing tokens you did not count, or your tokenizer differs from the one the model uses, since identical text can vary by up to 2.65 times across providers 7. A third cause is a segment assembled after your logging point, such as a tool result injected by the framework. Reconcile on the serialized payload, not the source variables.

How often should I re-measure the segments?

At every prompt version change, and on a fixed cadence in between, because retrieval settings and tool registries drift without any prompt edit. Prompt bloat accumulates through small changes that never trigger a prompt version bump on their own 1. A monthly snapshot is enough for a stable check; a weekly one is worth it when several people edit the template.

Does the largest segment always deserve the first fix?

Not always. Compare the cost share against the effort and risk of the change. A tool schema taking 30 percent of input is usually the cheapest large win, because unused tools can be removed outright. System instructions at 5 percent are rarely worth rewriting even if they read badly, since the saving is small and the behavior risk is not.

Sources

Sources

  1. How to track LLM token usage (2026): Prompt, completion ...
  2. AI Agent Monitoring: How to Track Token Usage, Costs, and ...
  3. Capabilities: Test automation
  4. Counting tokens | OpenAI API
  5. Counting tokens for chat API calls (gpt-3.5-turbo)
  6. Understanding and counting tokens
  7. AI Tokens: What They Are, How They're Counted, and Why ...
  8. Tokenizer and token counter (GPT, Claude, Gemini, Grok)
  9. Tokens to Words Converter
  10. Key metrics for evaluating token efficiency in AI systems
  11. LLM Cost Estimation Guide: From Token Usage to Total ...
  12. Accurate Method for Calculating Token Consumption for AI Usage Across ...
  13. When Coding Stops Being the Bottleneck - Berkeley RDI
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles