使用Node.js调用OpenAI API时token计数与实际不符的问题排查
问题:用tiktoken计算token数远低于实际,触发OpenAI上下文超限错误
我用Node.js通过OpenAI API调用gpt-3.5-turbo,提交messages数组作为上下文:
const completion = await this.openai.chat.completions.create({ messages: messages, model: 'gpt-3.5-turbo' });
提交前用自己实现的TokenCounter类,通过tiktoken统计token数:
import {get_encoding, encoding_for_model} from 'tiktoken'; class TokenCounter{ constructor(){ this.enc = get_encoding('cl100k_base'); } countFromUserMessages(userMessages){ const initialValue = 0; const result = userMessages.reduce((accumulator,currentValue) => { const messageTokenCount = this.enc.encode(currentValue.content).length; return accumulator + messageTokenCount; },initialValue); return result; } } export default TokenCounter;
我认为只统计content的token数就足够,但提交计算为2097token的消息数组后,OpenAI返回超限错误:
This model's maximum context length is 4097 tokens. However, your messages resulted in 4337 tokens. Please reduce the length of the messages.
消息数组包含历史对话(用户+助手回复,每条助手回复100-300token),还有限制响应长度的系统消息:
{ role: 'system', content: 'Your response must be 2000 characters or less.' }
原因分析
- 忽略了Chat消息的结构开销:OpenAI的Chat Completions API处理消息时,每个消息不仅包含
content,还会添加role字段对应的token,以及<|start|>、<|end|>这类特殊分隔符token,这些都会占用上下文token数。你的代码只统计了content的token,完全没算这些结构开销,导致计数严重偏低。 - 编码方式的选择不够严谨:虽然gpt-3.5-turbo确实使用
cl100k_base编码,但直接固定编码不如用encoding_for_model('gpt-3.5-turbo')获取对应模型的编码,避免后续模型更新编码规则时出现偏差。 - 字符数限制不等于token数限制:系统消息里的2000字符限制,和token数没有直接的1:1对应关系(比如中文单字通常对应1-2个token),但这不是当前超限的直接原因。
修正后的TokenCounter实现
import { encoding_for_model } from 'tiktoken'; class TokenCounter{ constructor(){ // 根据模型自动获取对应编码 this.enc = encoding_for_model('gpt-3.5-turbo'); } countFromUserMessages(userMessages){ let totalTokens = 0; // 遍历所有消息,计算每个消息的完整token数(包含role、分隔符) for (const msg of userMessages) { const fullMessage = `<|start|>${msg.role}\n${msg.content}<|end|>`; totalTokens += this.enc.encode(fullMessage).length; } // 添加Chat模型所需的额外结束token(官方计算规则要求) totalTokens += 3; return totalTokens; } } export default TokenCounter;
这个实现会完整统计OpenAI实际计算的所有token,包括消息结构开销,计算结果会和API返回的token数一致。
内容的提问来源于stack exchange,提问作者sigil
相关产品推荐
相关产品推荐

