Warning: Token count mismatch — prompt tokens (4500) + completion tokens (1200) = 5700, but API reports total_tokens=5800
ID: llm/token-count-mismatch-streaming
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| tiktoken==0.7.0 | active | — | — | — |
| openai==1.30.0 | active | — | — | — |
| python==3.11 | active | — | — | — |
Root Cause
The tiktoken tokenizer counts tokens differently than the OpenAI API's internal tokenizer, especially for multi-byte characters, special tokens, or streaming overhead tokens like role markers and stop sequences.
generic中文
tiktoken分词器对Token的计数方式与OpenAI API内部分词器不同,尤其是在多字节字符、特殊Token或流式传输的额外Token(如角色标记和停止序列)方面存在差异。
Official Documentation
https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktokenWorkarounds
-
95% success Use the API's reported `total_tokens` as the source of truth for billing and truncation, and only use tiktoken for approximate pre-flight checks: `response = client.chat.completions.create(model='gpt-4', messages=messages, stream=True); total_tokens = response.usage.total_tokens if hasattr(response, 'usage') else None`
Use the API's reported `total_tokens` as the source of truth for billing and truncation, and only use tiktoken for approximate pre-flight checks: `response = client.chat.completions.create(model='gpt-4', messages=messages, stream=True); total_tokens = response.usage.total_tokens if hasattr(response, 'usage') else None`
-
80% success Implement a buffer of 10% when using tiktoken to estimate context window usage: `max_tokens_allowed = int(model_max_tokens * 0.9) - tiktoken_count(prompt)`
Implement a buffer of 10% when using tiktoken to estimate context window usage: `max_tokens_allowed = int(model_max_tokens * 0.9) - tiktoken_count(prompt)`
中文步骤
Use the API's reported `total_tokens` as the source of truth for billing and truncation, and only use tiktoken for approximate pre-flight checks: `response = client.chat.completions.create(model='gpt-4', messages=messages, stream=True); total_tokens = response.usage.total_tokens if hasattr(response, 'usage') else None`
Implement a buffer of 10% when using tiktoken to estimate context window usage: `max_tokens_allowed = int(model_max_tokens * 0.9) - tiktoken_count(prompt)`
Dead Ends
Common approaches that don't work:
-
90% fail
The discrepancy is inherent because the API uses a different tokenization pipeline that includes service-side tokens (e.g., role markers, stop sequences) not counted by tiktoken.
-
70% fail
The mismatch varies with prompt structure and completion length; a fixed fudge factor is unreliable and may cause budget overruns or early truncation.
-
50% fail
While this avoids the mismatch warning, it doesn't fix the root cause; the token count reported by the API still uses its internal tokenizer, and the mismatch persists in non-streaming mode too.