Configure token counting and enforcement¶
Overview¶
When you route AI inference requests through F5 BIG-IP Next for Kubernetes (BNK), you can track how many tokens each user consumes and set limits to control usage. Token counting and enforcement lets you:
Count input and output tokens per user, per model, and across all inference requests.
Identify users by API key ID or source IP address.
Set rate limits to cap token usage within a time window.
Limit concurrent active sessions per user.
Report usage data through High Speed Logging (HSL) to external metering and billing tools such as OpenMeter.
Token counting operates at the gateway level. You configure this feature through infrastructure annotations on the Gateway custom resource (CR), the same way you configure AI semantic caching.
Before you begin¶
BNK installed with Gateway API custom resources available in your cluster.
Access to modify Gateway API resource manifests in your Kubernetes cluster.
The distributed Shared State Manager (dSSM) pod deployed in your cluster for multi-pod environments.
A logging pool configured, if you plan to use HSL reporting.
How token counting works¶
The request and response flow helps you plan your rate limit strategy and troubleshoot issues.
User identification¶
The system identifies users based on the user_id_source configuration, which supports these modes:
IP address (
ip): The system uses the client IP address directly as the user identity.Header (
header): The system uses the raw value of the request header specified byuser_id_headeras the user identity. If the header is missing or empty andfallback_to_ipis set totrue, the system uses the client IP address as a fallback.API key (
api_key): The system extracts the user identity from the request header specified byuser_id_header. Ifuser_id_headeris set toAuthorization, the system parses the bearer token from theAuthorization: Bearer <token>header. For all other headers (for example,x-api-key), the system uses the raw header value directly. If the resolved value is empty andfallback_to_ipis set totrue, the system uses the client IP address as a fallback.
Note
If the user identity is empty and fallback_to_ip is set to false, the system rejects the request with the 401 user_identity_missing error.
Request path¶
The client sends an inference request to the BNK virtual server.
The system extracts the API key ID, the client IP address, and the raw value of the configured request header. If no API key is found, the system falls back to the client source IP address when
fallback_to_ipis set totrue.The system queries the dSSM pod for the user’s current token count.
When the user exceeds their rate limit and the action is set to
drop, the system returns a429 Too Many Requestsresponse. When the action is set tolog_only, the system logs the request and allows it.When the user is within their limit, the system forwards the request to the backend large language model (LLM).
Response path for non-streaming requests¶
The system parses the JSON response to extract
usage.prompt_tokens,usage.completion_tokens, andusage.total_tokens.The system updates the dSSM pod with the new token counts: the user total, the user-model count, and the global counters.
The system generates an HSL log entry with the usage data.
The system returns the response to the client.
Response path for streaming requests¶
The system processes Server-Sent Events (SSE) chunks and accumulates the content.
The system extracts the final token count from the terminal chunk using the
finish_reasonattribute (for example,stop,length,content_filter,tool_calls, orfunction_call). The system then checks whetherusage.prompt_tokensandusage.completion_tokensare configured. If the usage object is not configured, the system uses the estimate.After the stream completes, the system updates the dSSM pod and generates an HSL log entry.
Rate limiting policies¶
You can apply rate limits at different levels:
Per user: Sets a single token limit that applies to all of a user’s requests, regardless of model.
Per model: Sets token limits based on the model used, regardless of user.
Per user, per model: Sets different token limits for different models for each user. Use wildcard patterns to match model names (for example,
gpt-4*).Global: Sets a single token limit shared across all users.
Enforcement actions¶
When a user exceeds their token limit, the system takes the action you configure:
drop: Returns a429 Too Many Requestsresponse and rejects the request.log_only: Logs the violation but allows the request to proceed.
Concurrent session limiting¶
You can set a maximum number of active sessions per user. This limit prevents a single user from consuming too many gateway resources at once.
Configure basic token counting¶
To monitor token usage without enforcing limits:
Open your Gateway CR manifest.
Add the
k8s.f5.com/ai-token-countingannotation underspec.infrastructure.annotations.Set these parameters:
Set
token_countingtoenabled.Set
user_id_sourcetoapi_key.Set
user_id_headerto the header that contains the API key (for example,Authorization).Set
fallback_to_iptotrueto fall back to the source IP address when no key is found.Set
hsl_publisherto the name of your logging pool.
Apply the manifest to your cluster.
Example:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: llm-gateway
namespace: nim
spec:
gatewayClassName: f5-gateway-class
listeners:
- name: http
protocol: HTTP
port: 8000
infrastructure:
annotations:
k8s.f5.com/ai-token-counting: |
token_counting=enabled,
user_id_source=api_key,
user_id_header=Authorization,
fallback_to_ip=true,
hsl_publisher=hsl-logging-pool
This configuration turns on token counting for all inference requests, including streaming, non-streaming, and batch requests. It also sends usage data to the hsl-logging-pool logging pool.
Configure token counting with per-user rate limiting¶
To enforce a single token limit for each user across all models:
Open your Gateway CR manifest.
Set
enforcementtoenabled.Set
rate_limit_policytoper_user.Set
rate_limit_tokens,rate_limit_window, andrate_limit_actionto the values you want.Apply the manifest to your cluster.
Example:
infrastructure:
annotations:
k8s.f5.com/ai-token-counting: |
token_counting=enabled,
user_id_source=api_key,
user_id_header=x-api-key,
enforcement=enabled,
rate_limit_policy=per_user,
rate_limit_tokens=100000,
rate_limit_window=3600,
rate_limit_action=drop
Configure token counting with per-model rate limiting¶
To enforce different token limits for different models, use the per_user_per_model policy with the rate_limits array:
Open your Gateway CR manifest.
Set
enforcementtoenabled.Set
rate_limit_policytoper_user_per_model.Define per-model limits in the
rate_limitsarray.Apply the manifest to your cluster.
Example:
infrastructure:
annotations:
k8s.f5.com/ai-token-counting: |
token_counting=enabled,
user_id_source=api_key,
enforcement=enabled,
rate_limit_policy=per_user_per_model,
rate_limits=[
{"model":"gpt-4*","tokens":10000,"window":3600},
{"model":"gpt-3.5*","tokens":100000,"window":3600},
{"model":"*","tokens":500000,"window":86400}
],
concurrent_sessions_limit=5,
rate_limit_action=drop,
hsl_publisher=usage-logging-pool
This configuration does the following:
Limits requests to models matching
gpt-4*to 10,000 tokens per hour.Limits requests to models matching
gpt-3.5*to 100,000 tokens per hour.Sets a default limit of 500,000 tokens per day for all other models.
Limits each user to five concurrent active sessions.
Returns a
429 Too Many Requestsresponse when any limit is exceeded.Sends usage data to the
usage-logging-poollogging pool.
Use wildcard patterns in the model field to match model name prefixes. The * entry acts as a default for any model that doesn’t match a more specific rule.
Annotation parameters reference¶
Use these parameters in the k8s.f5.com/ai-token-counting annotation to customize token counting and enforcement for your environment.
Token counting parameters¶
Parameter |
Default |
Description |
|---|---|---|
|
|
Required. Set to |
User identification parameters¶
Parameter |
Default |
Description |
|---|---|---|
|
|
Optional. Choose how the system identifies users. Set to |
|
|
Optional. Set to the name of the request header that contains the API key, for example, |
|
|
Optional. Set to |
Enforcement parameters¶
Parameter |
Default |
Description |
|---|---|---|
|
|
Optional. Set to |
|
None |
Required when |
|
None |
Optional. Set the total number of tokens allowed in the rate limit window. |
|
None |
Optional. Set the maximum number of input tokens allowed in the rate limit window. |
|
None |
Optional. Set the maximum number of output tokens allowed in the rate limit window. |
|
3600 |
Optional. Set the time window for rate limiting, in seconds. |
|
None |
Required when |
|
None |
Optional. Set the maximum number of concurrent active sessions per user. Set to 0 for no limit. |
|
None |
Optional. Choose the action the system takes when a limit is exceeded. Set to |
|
86400 |
Optional. Set the entry idle timeout for the non-rate-limit state, in seconds. |
|
86400 |
Optional. Set the absolute lifetime for the non-rate-limit state, in seconds. |
Logging and estimation parameters¶
Parameter |
Default |
Description |
|---|---|---|
|
None |
Optional. Set to the pool object ID created by the |
|
|
Optional. Choose where the system gets token counts. Set to |
|
4.0 |
Optional. Set the number of characters per token used for estimation. |
When token_source is set to estimate, the system estimates token counts based on character length. The estimation logic splits text by character class and applies a different token ratio to each class:
ASCII and English characters use the
token_estimate_ratiovalue. The default is 4.0 characters per token.Non-ASCII and UTF characters use a tighter ratio, about half the characters per token of ASCII. The same string length produces a higher token count.
Whitespace acts as a separator, and the system handles it independently.
After the system calculates the initial estimate, the gateway applies a 25% discount to both the estimated prompt and completion token counts. The final value is about 75% of the raw estimate. The system applies this estimation logic to both non-streaming and streaming requests whenever it uses the estimation path or a fallback is required.