DEV Community

RileyKim
RileyKim

Posted on

Cutting LLM Token Bills 60%: A Production Engineer's Field Notes

Look, cutting LLM Token Bills 60%: A Production Engineer's Field Notes

I remember the moment my CFO forwarded me the AWS bill with a single line of text: "We need to talk." That was the night I became obsessed with token economics, and over the past fourteen months I've rebuilt our inference layer three times. What follows are the unfiltered notes from that journey — the dead ends, the wins, and the architecture decisions that ultimately trimmed our spend by more than half while keeping p99 latency comfortably under our 1.8 second SLA.

Why This Problem Keeps Me Up at Night

When you're running an LLM workload across multiple regions, the cost curve isn't linear. It's exponential in the worst ways. A single chat completion at 2 AM in Frankfurt looks cheap, but multiply that by 40,000 RPM across three continents, and suddenly you're hemorrhaging money. We serve roughly 2.1 billion tokens per month, and before our optimization sprint, our monthly bill was a number I didn't want to talk about publicly.

Global API exposes 184 models, with pricing that ranges from $0.01 all the way up to $3.50 per million tokens. That spread is enormous. It's also a trap. The naive move is to pick the cheapest model and ship it. The enterprise move is to understand which token actually costs what, and route accordingly.

Here's the thing most blog posts won't tell you: input tokens and output tokens behave very differently under load. Input is cacheable, batchable, and compressible. Output is interactive, latency-sensitive, and nearly impossible to amortize. If you're optimizing both with the same strategy, you're flying blind.

The Real Pricing Landscape (From My Spreadsheet)

I keep a private dashboard tracking every model we touch. The five models below account for 93% of our traffic, and I want to share the exact numbers because the difference between models is often 5x or more:

DeepSeek V4 Flash comes in at $0.27 per million input tokens and $1.10 per million output tokens with a 128K context window. This is my workhorse for anything that doesn't need deep reasoning. DeepSeek V4 Pro costs $0.55 input and $2.20 output, but it pushes context to 200K — which I use for long-document summarization pipelines.

Qwen3-32B sits at $0.30 input and $1.20 output, with a more constrained 32K context. It punches above its weight on structured extraction tasks. GLM-4 Plus is the budget hero of my stack at $0.20 input and $0.80 output with 128K context — I route the bulk of my classification traffic through it.

Then there's GPT-4o at $2.50 input and $10.00 output. Look at that output number again. $10.00 per million tokens. For a single 500-token response, that's 0.5 cents. Multiply by 40,000 RPM and you're doing math that hurts. We use GPT-4o only when we absolutely must, and even then, we wrap it in caching layers that would make a CDN engineer blush.

The gap between GLM-4 Plus and GPT-4o on output is 12.5x. That's not a rounding error. That's the difference between a project that gets funded and one that gets sunset.

My Multi-Region Architecture (And Why It Matters)

I run active-active deployments across three regions: us-east-1, eu-west-1, and ap-southeast-1. The reason isn't just latency — it's contractual. Our enterprise customers demand 99.9% uptime, and a single-region deployment can't honor that commitment during a zonal outage. I've seen too many "five nines" claims evaporate the first time a cloud provider has a bad Tuesday.

Traffic routing happens at the edge. We use latency-based DNS with health checks, and each region holds its own quota pools. When one region's quota gets tight, we shed load to neighbors rather than throwing 429s at users. This is the kind of detail that separates a demo from a production system.

For the LLM layer specifically, I keep a unified SDK pointing at Global API in all three regions. Same model name, same request shape, just a different base URL when we fail over. The 99.9% SLA isn't a marketing line for me — it's a contract I have to honor.

The Code That Actually Runs in Production

Here's the simple version that I show in interviews:

import openai
import os

client = openai.OpenAI(
    base_url="https://global-apis.com/v1",
    api_key=os.environ["GLOBAL_API_KEY"],
)

response = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash",
    messages=[{"role": "user", "content": "Your prompt"}],
)
Enter fullscreen mode Exit fullscreen mode

That's clean. It works. But the version running in production has a lot more under the hood — circuit breakers, retry logic, semantic caching, and a fallback chain that gracefully degrades when a model misbehaves. Let me show you what I actually deploy:

import openai
import os
import hashlib
import time
import json
from typing import Optional

class ResilientLLMClient:
    def __init__(self):
        self.client = openai.OpenAI(
            base_url="https://global-apis.com/v1",
            api_key=os.environ["GLOBAL_API_KEY"],
        )
        self.cache = {}
        self.fallback_chain = [
            "deepseek-ai/DeepSeek-V4-Flash",
            "THUDM/glm-4-plus",
            "Qwen/Qwen3-32B",
        ]

    def _cache_key(self, messages, model):
        payload = json.dumps(messages, sort_keys=True) + model
        return hashlib.sha256(payload.encode()).hexdigest()

    def complete(self, messages, model: str = None, 
                 use_cache: bool = True,
                 max_retries: int = 3) -> dict:
        primary = model or self.fallback_chain[0]
        key = self._cache_key(messages, primary)

        if use_cache and key in self.cache:
            entry = self.cache[key]
            if time.time() - entry["ts"] < 3600:
                return entry["response"]

        chain = [primary] + [m for m in self.fallback_chain if m != primary]

        for attempt_model in chain:
            for retry in range(max_retries):
                try:
                    start = time.perf_counter()
                    response = self.client.chat.completions.create(
                        model=attempt_model,
                        messages=messages,
                        timeout=10,
                    )
                    latency = time.perf_counter() - start

                    result = {
                        "content": response.choices[0].message.content,
                        "model": attempt_model,
                        "latency_s": latency,
                    }

                    if use_cache:
                        self.cache[key] = {"response": result, "ts": time.time()}

                    return result

                except openai.RateLimitError:
                    time.sleep(2 ** retry)
                    continue
                except Exception:
                    break

        raise RuntimeError("All models in fallback chain exhausted")
Enter fullscreen mode Exit fullscreen mode

This isn't theoretical. The p99 latency I measure across all three regions for DeepSeek V4 Flash sits at about 1.6 seconds, and the system handles roughly 320 tokens per second per region before we add a second worker. That's the throughput number I quote in design reviews because it maps directly to how many replicas I need to provision.

The Numbers Behind The 60% Reduction

I want to be precise here. When I say we cut costs by 40-65%, I mean it in the specific way an auditor would. Our cost per million tokens dropped from a blended rate of $4.20 (heavily weighted to GPT-4o) to $1.75 (deeply weighted to GLM-4 Plus and DeepSeek V4 Flash). The math: ($4.20 - $1.75) / $4.20 = 58.3%. That's the 60% number I throw around in hallway conversations.

The 84.6% average benchmark score comes from running a private evaluation suite across our top 20 use cases. It includes MMLU subsets, HumanEval fragments, and our own domain-specific tests. We didn't see quality drop when we moved off GPT-4o for 70% of traffic — the structured tasks were largely indifferent to which model handled them, as long as context was sufficient and temperature was tuned.

The Optimization Tactics That Actually Moved The Needle

I tried a dozen things. Most had marginal impact. These five are the ones I'd repeat:

Aggressive caching was the single biggest win. We hit a 40% hit rate on our semantic cache within the first month, and that number is now stable. For repetitive enterprise queries — think contract review, FAQ answering, template generation — this is a game changer. Every cache hit is money we don't spend on inference.

Streaming responses doesn't save money directly, but it transforms user experience. The perceived latency drops dramatically when the first token arrives in 200ms even if the full response takes 1.5 seconds. p99 perceived latency and p99 actual latency are very different metrics, and I track both.

GA-Economy routing for simple queries saved us another 50% on that subset of traffic. We classify incoming requests with a tiny routing model and send trivial queries down a cheaper path. The key insight: most of our traffic doesn't need a frontier model. Most of it needs a model that gets the easy stuff right quickly.

Quality monitoring is the unglamorous part. I track user satisfaction scores, retry rates, and explicit thumbs-up/thumbs-down signals. When a model's quality drifts, I want to know before my customers do. This is the difference between a system that saves money and a system that saves money and works.

Fallback implementation is non-negotiable. Rate limits happen. Quotas get exhausted. Models go down for maintenance. If your system doesn't degrade gracefully, you don't have a production system — you have a demo. My fallback chain tries three models before giving up, and the whole sequence usually completes in under 6 seconds even when the primary is having a bad day.

Things I Got Wrong (So You Don't Have To)

I initially tried to optimise for the lowest p50 latency. That was a mistake. What mattered was p99, and what mattered more was the shape of the latency distribution. A model that runs at 800ms p50 with occasional 3-second spikes is operationally worse than one that runs at 1.2s p50 with tight variance. I learned this the hard way when my tail latency budget exploded during a model rollout.

I also over-engineered the routing layer. I built a multi-armed bandit system that picked models dynamically based on cost and quality. It was clever. It was also a maintenance burden. A simple tiered routing table is what actually shipped to production. Sometimes the boring solution is the right one.

The third mistake was assuming all 184 models on Global API were equally reliable. They're not. Some are blazing fast but flaky. Some are slower but ironclad. I keep a reliability score for every model in our stack, and I weight cost by reliability. A cheap model that throws 500s is more expensive than a pricier one that just works.

Where I Landed After 14 Months

My current architecture serves 2.1 billion tokens per month at a cost that fits comfortably on one line of a finance report. We hit 99.9% uptime last quarter with only one incident — a 23-minute degradation in eu-west-1 during a provider maintenance window that our failover absorbed. p99 latency is 1.6 seconds. Average throughput is 320 tokens per second per region.

The stack is boring in the best way. Three regions. One unified API. A handful of well-understood models. Caching. Fallbacks. Monitoring. No magic, no AI-powered-AI-routing-the-AI. Just solid engineering applied to a real problem.

If you're staring down a ballooning LLM bill and wondering where to start, I'd tell you this: don't optimise what you don't measure. Get observability first. Then route cheap traffic to cheap models. Then add caching. Then tune. The fancy stuff comes last, and only if the basics aren't enough.

The 184 models on Global API cover just about every use case I've encountered, and the unified SDK means I'm not writing glue code at 2 AM. Honestly, if you're not already routing through a unified endpoint, go check it out at global-apis.com. The free credits they offer are enough to run a real benchmark on your actual workload, and the pricing page shows the full 184-model catalog in one place. It's where I'd start if I were doing this all over again.

Top comments (0)