Token Tracking in Production
Per-token prices dropped 280× since 2022. Production bills went up.
The gap is not the model. It is the workflow.
The Production Reality
Agentic systems consume more tokens than chat.
- Gartner: 5–30× more tokens than equivalent chatbot asks
- Stanford: coding agents up to 1,000× more than chat completions
- Production audit: 366K input tokens per average request across 10-turn conversations
Same task. Same outcome. Opus 4.7 used 2.9× more output tokens than 4.6.
Tokenizer changes can raise bills 35% overnight without touching the rate card.
Counting tokens is not enough. You need to know where they go.
What To Track Beyond Counts
A counter tells you how much you spent. It does not tell you why.
Track these instead:
Tokens per completed task One user action may trigger five LLM calls. Measure the full chain, not each call in isolation.
Quality gate metrics How many requests never reached the model because relevance was too low? Those are your cheapest wins.
Context utilization Models reason better with free context. Production systems often fill the window and pay for history they no longer use.
Call chain patterns Five sequential calls at 250 tokens each beats one call at 1,250 tokens. Consolidated designs win on latency and cost.
Quality Gates
Most savings come from calls you do not make.
pub const QualityGate = struct {
relevance_floor: f64 = 0.005,
max_context_files: usize = 6,
max_output_tokens: usize = 500,
pub fn shouldCallLLM(self: QualityGate, score: f64) bool {
return score >= self.relevance_floor;
}
};
Usage:
const gate = QualityGate{};
if (!gate.shouldCallLLM(combined_score)) {
tracker.recordSkipped(.below_relevance_floor);
return;
}
const context = selectTopN(ranked_results, gate.max_context_files);
try llm.review(context, gate.max_output_tokens);
A relevance floor of 0.005 skips roughly 57% of review requests in real codebases. Weak signal, weak answer, full price.
Search-First Pipeline
Put inference at the end of deterministic work.
Stage 1: Vector search (~$0.0002)
Stage 2: BM25 reranking (~$0.0001)
Stage 3: Static analysis (~$0.0001)
Stage 4: Quality gate (free)
Stage 5: Single LLM call (~$0.03, only if gate passes)
Stages 1–4 cost $0.0004 combined. They decide what is relevant, rank it, resolve symbols, and check whether an LLM call is worth making.
pub const PipelineStage = struct {
source_char_budget: usize = 600,
output_token_budget: usize = 200,
pub fn trimContext(self: PipelineStage, context: []const u8) []const u8 {
return if (context.len > self.source_char_budget)
context[0..self.source_char_budget]
else
context;
}
};
Input caps matter more than output caps. Production overspend lives on the input side.
Consolidated Design
The naive multi-call chain:
1. Classify intent → ~150 tokens
2. Plan subsystems → ~250 tokens
3. Query subsystem A → ~300 tokens
4. Query subsystem B → ~300 tokens
5. Synthesize answer → ~250 tokens
Total: ~1,250 tokens, 5 calls
The consolidated version:
1. Classify intent → ~80 tokens (tight tagger)
2. Fan-out to subsystems → 0 tokens (deterministic map)
3. Synthesize answer → ~200 tokens
Total: ~280 tokens, 2 calls
The classifier returns a tag from a fixed vocabulary. Each tag maps to downstream calls in plain code. No LLM in the routing step.
pub const IntentRouter = struct {
pub fn route(intent_tag: []const u8) []const Subsystem {
if (std.mem.eql(u8, intent_tag, "revenue.query.ytd"))
return &.{ .crm, .analytics };
if (std.mem.eql(u8, intent_tag, "account.lookup.contact"))
return &.{ .crm };
return &.{};
}
};
Use the model to classify. Use code to route.
Task-Level Tracking
Extend basic counters to capture the full picture:
pub const TaskMetrics = struct {
llm_calls: u64,
skipped_calls: u64,
input_tokens: u64,
output_tokens: u64,
deterministic_cost_usd: f64,
llm_cost_usd: f64,
pub fn costPerTask(self: TaskMetrics) f64 {
return self.deterministic_cost_usd + self.llm_cost_usd;
}
pub fn skipRate(self: TaskMetrics) f64 {
const total = self.llm_calls + self.skipped_calls;
if (total == 0) return 0;
return @as(f64, @floatFromInt(self.skipped_calls)) / @as(f64, @floatFromInt(total));
}
};
Record one TaskMetrics per user action. That is where architectural problems become visible.
Real Economics
| Approach | Cost per operation | LLM calls per 1K ops |
|---|---|---|
| Direct “send everything to the model” | ~$0.030 | 1,000 |
| Search-first with quality gates | ~$0.0034 | ~430 |
| Consolidated routing (5 calls → 2) | ~$0.004 | ~200 |
Routable structured queries: $0.274 per multi-turn Sonnet conversation vs $0.0009 via deterministic retrieval. A 300:1 ratio on the slice that does not need full reasoning.
Model choice is a 2–5× lever. Architecture is closer to 10×.
Production Patterns
Treat inference as the expensive final step. Search, regex, and switch statements are cheap. Reserve the model for judgment over unstructured input.
Use LLMs to code solutions, not to solve problems. A model that writes a 50-line classifier costs tokens once. A model that acts as the classifier costs tokens on every request forever.
Set ROI targets per call. “AI-assisted code review” is too coarse. “Review 6 files with relevance > 0.005, return 500 words” is measurable.
Enforce budgets in code, not in prompts. Per-source character limits. Per-call token caps. Quality gates before every inference step.
Instrumentation Matters
Track to find architectural problems, not just to report costs.
Quality gates save 90%+ of unnecessary calls. Consolidated designs cut token chains by 4×. Input trimming stops the slow drift that tokenizer changes hide.
Build the counter first. Then build the pipeline that makes most calls unnecessary.
That is where production token economics actually change.
Implementation
Count tokens before you call the API.
zig-ai-tokenizer — BPE token counting and cost estimation in Zig.
git clone https://github.com/Stdubic/zig-ai-tokenizer.git
cd zig-ai-tokenizer
./scripts/fetch-vocab.sh
zig build
./zig-out/bin/zig-ai-tokenizer count "hello world"
# 2 tokens
Cursor Integration
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"zig-ai-tokenizer": {
"command": "python3",
"args": ["mcp/server.py"],
"cwd": "/path/to/zig-ai-tokenizer"
}
}
}
Reload Cursor. Then ask:
Use count_tokens on: "Write a Python Fibonacci function"
Use estimate_cost with gpt4 and 500 output tokens
Two MCP tools: count_tokens and estimate_cost.
Full setup: github.com/Stdubic/zig-ai-tokenizer/docs/cursor-setup.md