Recommended resources
The freely available resources this lesson will direct you to.
- Design ChatGPT Like a Senior Engineer: 800M Users, One Primary Databasewww.youtube.com
- How To Build an API with Python (LLM Integration, FastAPI, Ollama & More)www.youtube.com
- How to Implement LLM Rate Limiting - OneUptimeoneuptime.com
- Rate limiting – agentgateway | Agent Connectivity Solvedagentgateway.dev
Welcome to the next lesson in our journey to master the LLM system layer. In our previous session, we built a robust, scalable backend that can automatically adjust the number of worker pods based on the real-time demand for inference. This ensures we always have enough capacity to handle the workload. However, with great power comes the need for great control. An open, infinitely scalable endpoint is a recipe for unpredictable costs and potential abuse.
This is where rate limiting comes in. Today, we'll move from managing capacity to managing access. You will learn how to implement token-aware rate limiting to manage endpoint usage based on generation load, not just request count. This is a critical skill for any LLM Ops engineer, as it's fundamental to building secure, fair, and economically viable AI services. We'll start with the "why" and then dive into a practical implementation using Python and FastAPI.
1. Beyond Request Counting: The Need for Token-Aware Limits
In traditional web services, rate limiting is often as simple as counting requests per second per user. If a user exceeds 10 requests per second, you block them. With your background in SRE, you've likely configured and managed such systems. However, this model breaks down for LLMs.
Why? Because not all requests are created equal. One user might ask, "What is the capital of France?", while another submits a 10,000-word document and asks for a summary. Both are single requests, but their computational cost is vastly different. The cost of an LLM call is directly proportional to the number of tokens processed (both in the prompt and the generated completion), not the number of API calls.
This is why we need to think in terms of tokens as our primary unit of consumption.

This image illustrates that the number of tokens is not directly proportional to the number of characters. A Spanish phrase might have more characters than its English equivalent but use more tokens, and a long German number can be a single word but many tokens. This highlights why tokens, not characters or requests, are the true measure of LLM work.
To understand how this concept fits into a large-scale system architecture like ChatGPT, let's watch a brief segment from a system design discussion.
Design ChatGPT Like a Senior Engineer: 800M Users, One Primary Database
The video "Design ChatGPT Like a Senior Engineer" by Hayk Simonyan provides a high-level architectural overview.
Watch these two short clips to see why token limiting is a first-class citizen in LLM system design: Requests vs. Tokens: The speaker explains the necessity of limiting both requests (to prevent spam) and tokens (to manage cost and compute). Justification for Token Limits: This part provides a clear example of why request-only limiting is insufficient. A single, large request can consume more resources than many small ones, making token limits essential for controlling infrastructure costs.
The key takeaway is that a robust LLM rate-limiting strategy must be two-dimensional, controlling both the frequency of requests and the volume of tokens.
2. The Token Bucket Algorithm
To implement rate limiting, we need an algorithm to track usage over time. One of the most common and intuitive algorithms is the Token Bucket. Given your experience with distributed systems, you may have encountered this before in contexts like network traffic shaping or API gateways.
Here’s how it works:
- A "bucket" has a predefined capacity (e.g., 100,000 tokens).
- The bucket is refilled with "tokens" at a constant rate (e.g., 1,000 tokens per second).
- Each incoming request "consumes" a number of tokens from the bucket equal to its size (e.g., the number of LLM tokens it will use).
- If the bucket has enough tokens, the request is allowed, and the tokens are removed.
- If the bucket is empty, the request is rejected or queued.

This diagram illustrates the Token Bucket algorithm. A bucket is continuously refilled with tokens at a fixed rate. Each operation consumes tokens from the bucket. If not enough tokens are available, the operation is denied.
This algorithm naturally allows for bursts of traffic (a user can consume all tokens in the bucket at once) while enforcing an average rate over time (determined by the refill rate). The documentation for AgentGateway, an API gateway for AI, provides a clear configuration example based on this algorithm.
Rate limiting – agentgateway | Agent Connectivity Solved
This documentation page shows how a token bucket algorithm is configured in a real-world system.
Read the section on "Configuration" for local rate limiting. Notice the key parameters: maxTokens: The bucket's capacity. fillInterval and tokensPerFill: The refill rate. type: Explicitly distinguishing between requests and tokens. This declarative configuration shows how the abstract algorithm translates into concrete system parameters.
3. Implementing a Rate Limiter in Python with FastAPI
Now, let's get practical. We'll build a simple API gateway in Python using FastAPI that sits in front of an LLM. We will first implement a basic request-based limiter and then upgrade it to be token-aware.
The following video provides an excellent walkthrough for building the foundational API and adding a simple credit-based (request-based) limiter.
How To Build an API with Python (LLM Integration, FastAPI, Ollama & More)
The video "How To Build an API with Python (LLM Integration, FastAPI, Ollama & More)" by Tech With Tim is a great practical guide. We'll use it to set up our base application.
Follow along with these sections to build the initial API. You can use any local LLM via Ollama as shown, or simply mock the LLM call for now. Basic FastAPI Endpoint: Set up your Python environment and create a simple /generate endpoint that takes a prompt and calls an LLM. Adding API Key Verification: Implement a function to verify an API key passed in the request header. This is the foundation for per-user tracking. Implementing a Credit System: See how to associate a "credit" count with each API key and decrement it on each successful request. This is our request-based rate limiter. Testing the Limiter: Observe how to test the endpoint with a tool like Postman, sending the API key in the headers and seeing the credits deplete until a "401 Unauthorized" error is returned.
After completing these steps, you will have a working API that limits usage based on the number of requests. Now, let's evolve this into a proper token-aware system.
4. From Request Credits to Token Budgets
To upgrade our simple credit system, we need to replace the logic of "subtract 1 credit per request" with a more sophisticated approach that handles tokens. This involves a two-phase process:
- Estimate Before: Before forwarding the request to the LLM, we estimate the maximum number of tokens it could consume (prompt tokens +
max_new_tokens). We check if the user has enough tokens in their bucket for this estimated cost. If not, we reject the request immediately with a429 Too Many Requestserror. - Record After: After the LLM call completes, we get the actual token count from the response (prompt and completion tokens). We then use this precise number to update the user's token bucket. This ensures our accounting is accurate.
The following resource provides a superb, production-ready Python implementation of this logic.
How to Implement LLM Rate Limiting - OneUptime
This article from OneUptime provides a detailed implementation of a token-based rate limiter.
Your task is to integrate this logic into the FastAPI app you just built. Study the LLMRateLimiter Class: Read through the code block in the section "Token-Based Rate Limiter." Pay close attention to: The TokenBucket dataclass, which tracks usage for a single user. The count_tokens method, which uses the tiktoken library to accurately count tokens for a given model. The check_limit method, which performs the "Estimate Before" step. The record_usage method, which performs the "Record After" step. Examine the FastAPI Integration: Now look at the section "FastAPI Integration." This shows how to wire the LLMRateLimiter into a FastAPI endpoint. Notice how check_limit is called before the main logic, and how a 429 HTTPException is raised if the limit is exceeded. The code also shows how record_usage would be called after receiving the LLM response.
Now, modify your FastAPI application:
- Replace the simple credit dictionary with an instance of the
LLMRateLimiterclass. - In your
/generateendpoint, before calling the LLM, calltoken_limiter.check_limit(). You'll need to estimate the tokens first by counting the prompt tokens and adding themax_tokensyou plan to generate. - If the check fails, raise an
HTTPExceptionwith status code 429. - After the LLM call, get the actual
prompt_tokensandcompletion_tokensfrom the response and calltoken_limiter.record_usage()to update the bucket accurately.
This exercise combines your Python and API development skills with the core principles of LLM Ops, resulting in a system that intelligently manages load based on the true cost of generation.
Conclusion
Today you've tackled a crucial aspect of LLM infrastructure: managing usage and cost. You've moved beyond simplistic request counting and implemented a sophisticated, token-aware rate limiting system—the same kind used by major providers like OpenAI.
Key Takeaways:
- Tokens are the Unit of Cost: For LLMs, the number of tokens processed, not the number of requests, is the true measure of computational load and financial cost.
- Dual-Limiting Strategy: A robust system should limit both the number of requests (to prevent simple spam) and the number of tokens (to manage cost).
- The Token Bucket Algorithm: This is a standard and effective algorithm for implementing rate limiting that allows for bursts while maintaining a long-term average rate.
- "Estimate Before, Record After": This two-phase implementation pattern is essential for token-aware limiting. It allows you to reject oversized requests upfront while maintaining accurate accounting based on the final token count.
You now have a system that can both scale dynamically to meet demand (from our last lesson) and apply fine-grained controls to manage that demand. But what happens when things go wrong? What if the model is slow, or fails entirely?
In our next lesson, we will begin our dive into reliability. We will start by answering the question, "What does a 'good' service look like?" by learning how to define and configure Service Level Objectives (SLOs) for latency, availability, and error rate for an LLM serving endpoint.