# Introduction
Large language model (LLM) apps get slow and expensive faster than you’d expect. In a prototype, things look fine. A few users, one model call, a short prompt, and response times you don’t think twice about. Production is a different story. Traffic spikes and requests pile up in a queue. Conversations get longer. Retrieval-augmented generation (RAG) pipelines add big chunks of context to every prompt. Agents call several tools instead of one. And those generous output limits you set early on quietly push up both latency and cost. The surprising part is that the fix usually isn’t a better model or more graphics processing units (GPUs). Most of the gains come from cutting work you didn’t need to do in the first place: fewer tokens, fewer calls, a smaller model for the easy tasks, real cache reuse, and less time stuck in a queue. This guide covers 12 practical ways to cut LLM latency and inference cost in production. So, let’s get started:
# 1. Measuring the Right Latency Metrics First
Before optimizing anything, understand where time is going.
End-to-end latency is useful, but it does not explain the cause of a slow response. A production LLM system should track at least:
- Queue time: How long a request waits before processing begins.
- Time to first token (TTFT): How long it takes before the user sees the first streamed response token.
- Inter-token latency: How quickly the model generates each following token.
- End-to-end latency: The total duration from request to completed response.
- Input and output token counts: The main drivers of inference cost.
- Cache hit rate: How often prompt, retrieval, or response caches avoid repeated work.
- Tool and retrieval latency: Time spent outside the model itself.
- P50, P95, and P99 latency: Tail latency often matters more than the average.
For example, a high TTFT may point to long prompts, slow retrieval, or queueing. Slow inter-token latency may indicate an oversized model, overloaded GPU, poor batching configuration, or memory pressure.
Without these measurements, teams often optimize the wrong bottleneck.
# 2. Reducing Output Tokens Aggressively
Generated output tokens are often the clearest source of both latency and cost.
A model must generate each completion token sequentially. A response that is twice as long can take roughly twice as long to generate and cost significantly more.
Start with these changes:
- Set realistic
max_tokensor maximum completion limits. - Ask for concise answers when users do not need long explanations.
- Use stop sequences where appropriate.
- Avoid asking the model to restate the user’s question.
- Use compact JSON schemas and shorter field names.
- Remove unnecessary summaries, disclaimers, and repeated context from outputs.
- Separate “brief answer” and “detailed explanation” modes in the product UI.
For example, an internal support assistant may only need a three-bullet answer and a source link. It does not need a 700-word explanation by default.
A simple rule is: do not pay for tokens the user will not read.
# 3. Routing Requests to the Smallest Capable Model
Not every task needs the largest or most expensive model.
Many production workloads are repetitive and structured:
- Sentiment analysis
- Data extraction
- Content moderation
- Query rewriting
- FAQ answers
- Structured JSON generation
- Basic summarization
These tasks can often run on a smaller model with acceptable quality, lower cost, and faster responses.
A useful pattern is model routing:
- Send simple requests to a small, low-cost model.
- Evaluate the confidence, complexity, or output quality.
- Escalate difficult requests to a stronger model only when needed.
You can route based on factors such as prompt length, task type, user tier, model confidence, retrieval quality, or a lightweight classifier.
This approach avoids making your most capable model the default answer to every request.
# 4. Reducing the Number of LLM Calls
A common production mistake is building workflows with too many sequential model calls.
For example, an agent may:
- Classify the user request.
- Rewrite the request.
- Retrieve documents.
- Summarize retrieved documents.
- Generate an answer.
- Critique the answer.
- Rewrite the answer.
Each call adds latency, cost, failure points, and operational complexity.
Look for steps that can be combined. A single well-designed prompt with structured output may replace two or three model calls.
Also identify steps that do not need an LLM at all. Use deterministic code for:
- Date formatting
- Field validation
- Simple routing rules
- Permission checks
- Calculations
- UI labels
- Known templates
- Database lookups
For independent tasks, run them in parallel. Retrieval, classification, and background enrichment often do not need to wait for each other.
# 5. Designing Prompts for Prefix Caching
Prompt caching is one of the most effective ways to reduce cost and time for repeated long prompts.
Most LLM systems have stable content that appears in every request:
- System instructions
- Safety policies
- Tool definitions
- Few-shot examples
- Product documentation
- Long reference material
- Static context for a workflow
Place this reusable content at the beginning of the prompt.
Put changing content later:
- User requests
- Conversation state
- Current timestamps
- Retrieved passages
- Tool outputs
- User-specific data
- Dynamic IDs
This ordering matters because changing content early in the prompt can invalidate the reusable prefix.
A well-structured prompt can turn a long repeated context into a cache hit instead of paying to process it from scratch for every request.
# 6. Adding Multiple Cache Layers
Prompt caching is useful, but it should not be the only cache in your system.
A production LLM application can benefit from several cache layers:
// Exact Response Cache
Store responses for identical requests.
This works well for stable questions such as:
- “What are your pricing plans?”
- “How do I reset my password?”
- “What is your refund policy?”
Use versioning and time-to-live (TTL) values so outdated answers are not served indefinitely.
// Semantic Cache
A semantic cache can reuse an answer when a new request is highly similar to a previous one.
For example:
- “How do I change my email address?”
- “Can I update the email on my account?”
These may share the same answer even though the wording differs.
Semantic caching is useful for support, internal knowledge bases, and repeated information requests. However, it needs strict similarity thresholds, tenant isolation, content versioning, and evaluation checks.
// Retrieval Cache
Cache embeddings, search results, reranking results, and document chunks for repeated queries.
// Tool Result Cache
Many agent tools produce deterministic or slowly changing data. Cache outputs from APIs, database queries, product lookups, and web retrieval where freshness requirements allow.
The goal is simple: do not repeatedly ask the model to process information your system already knows.
# 7. Controlling Your Retrieval-Augmented Generation Context Budget
RAG can improve accuracy, but it can also become a major source of latency and cost.
A typical failure pattern looks like this:
- Retrieve too many documents.
- Add full passages without reranking.
- Include duplicate chunks.
- Keep all conversation history.
- Add raw tool outputs and HTML.
- Send everything to the model “just in case.”
The result is a large prompt that is expensive to process, slower to generate from, and often less accurate because the model must search through irrelevant information.
Use a context budget instead.
- Retrieve fewer documents.
- Rerank before sending content to the model.
- Deduplicate overlapping chunks.
- Remove navigation text, boilerplate, and HTML.
- Use concise summaries for older conversation turns.
- Include only the tool output needed for the current decision.
- Set separate token budgets for system instructions, retrieved context, chat history, and output.
More context is not always better context.
# 8. Moving Non-Interactive Work to Batch Processing
Not every LLM task needs an immediate response.
Tasks such as these should usually run asynchronously:
- Data labeling
- Evaluation runs
- Bulk summarization
- Report generation
- Knowledge-base processing
- Nightly workflows
- Large-scale extraction
Batch processing can reduce costs and protect interactive user traffic from background workloads.
Keep real-time systems focused on requests that affect users directly. Send offline jobs to lower-priority queues, batch APIs, or scheduled workers.
This separation improves the experience for users while making infrastructure usage more predictable.
# 9. Tuning Batching for Latency, Not Only Throughput
Batching helps GPUs process multiple requests efficiently. However, larger batches are not automatically better.
Aggressive batching can improve throughput while increasing queue time and harming TTFT. A system may look efficient from a GPU utilization perspective while users experience slow responses.
Tune batching against user-facing service-level objectives:
- Maximum acceptable queue time
- P95 and P99 TTFT
- Inter-token latency
- Concurrent request volume
- Average prompt and output length
- Priority of interactive versus background work
For self-hosted models, continuous batching or in-flight batching is often valuable because completed requests can leave the batch while new requests enter.
The goal is not maximum GPU utilization. The goal is the best user experience within an acceptable cost envelope.
# 10. Managing Key-Value Cache and Context Length Carefully
Long-context workloads can consume GPU memory quickly.
The key-value (KV) cache stores information needed for token generation. As context windows and concurrent requests grow, KV cache memory becomes a major infrastructure constraint.
This can lead to:
- Memory pressure
- Request preemption
- Cache eviction
- Slowdowns
- Reduced concurrency
- Out-of-memory failures
To manage this, set realistic limits for:
- Maximum context length
- Maximum output length
- Concurrent requests
- Per-user conversation memory
- Number of retrieved chunks
- Tool output size
Paged KV cache systems, KV cache quantization, and memory-aware scheduling can help, but they should be validated against your actual workload.
Do not expose a massive context window simply because the model supports one. Most applications do not need to use the maximum limit on every request.
# 11. Benchmarking Serving Optimizations on Real Traffic
Self-hosted LLM serving stacks offer many performance features:
- Quantization
- Speculative decoding
- Tensor and pipeline parallelism
- Prefix caching
- Chunked prefill
- Prefill/decode disaggregation
- Flash attention and continuous batching
These can improve performance, but they are not universal wins.
For example, speculative decoding may improve throughput for one workload while adding overhead or reducing cache efficiency for another. Tensor parallelism may help large models fit across GPUs but introduce communication overhead. Quantization can reduce memory use while affecting quality or speed differently across hardware.
Benchmark every change using representative production traffic:
- Real prompt lengths
- Real output lengths
- Real concurrency
- Real cache-hit rates
- Real retrieval behavior
- Real P95 and P99 latency targets
Do not rely only on isolated benchmark numbers or tokens-per-second claims.
# 12. Adding Admission Control and Graceful Degradation
Traffic spikes can turn a normally fast LLM system into a slow and expensive one.
A production application should know what to do when capacity is limited.
Useful controls include:
- Per-user rate limits
- Request size limits
- Maximum output limits
- Priority queues
- Concurrency and retry limits
- Backpressure for overloaded services
- Fallback to a smaller model
- Temporary reduction in response detail
- Delayed processing for non-critical requests
For example, during high load, a product may:
- Disable optional agent steps.
- Reduce the maximum output length.
- Route lower-priority users to a smaller model.
- Delay background enrichment.
- Return a concise answer instead of a long report.
Graceful degradation is better than allowing every request to queue until the entire experience becomes unusable.
# Final Thoughts
The most effective LLM optimization strategy is not simply using a faster model or adding more GPUs.
It is designing the system so the model does less unnecessary work.
Reduce output tokens. Avoid repeated calls. Reuse cached prefixes and responses. Control context size. Route simple tasks to smaller models. Separate batch jobs from user-facing traffic. Tune infrastructure against P95 and P99 latency, not just GPU utilization.
When these fundamentals are in place, you can often make an LLM application faster, cheaper, and more reliable without sacrificing the quality users care about.
Kanwal Mehreen is a machine learning engineer and a technical writer with a profound passion for data science and the intersection of AI with medicine. She co-authored the ebook “Maximizing Productivity with ChatGPT”. As a Google Generation Scholar 2022 for APAC, she champions diversity and academic excellence. She’s also recognized as a Teradata Diversity in Tech Scholar, Mitacs Globalink Research Scholar, and Harvard WeCode Scholar. Kanwal is an ardent advocate for change, having founded FEMCodes to empower women in STEM fields.
