OpenAI API 令牌上下文长度限制
问题描述
当使用 OpenAI API 时,用户尝试使用 text-davinci-003
模型生成文本完成。提示(prompt)包含 1360个令牌,同时将 max_tokens
参数设置为 4000,此时API返回以下错误:
json
{
"message": "This model's maximum context length is 4097 tokens, however you requested 5360 tokens (1360 in your prompt; 4000 for the completion). Please reduce your prompt or completion length.",
"type": "invalid_request_error",
"param": null,
"code": null
}
这个错误的核心在于对 令牌分配机制 和 模型上下文限制 的误解:
- OpenAI模型有固定的最大上下文长度
max_tokens
参数定义了生成完成文本的最大令牌数- 提示+完成的总令牌数不能超过模型限制
- 在示例中:1360(提示)+ 4000(完成)= 5360 > 4097(模型上限)
令牌计数误区
即使在OpenAI Playground中测试显示总令牌约1374个,仍需要保证请求时 prompt令牌数 + max_tokens <= 模型上限
,否则API直接拒绝请求。
解决方案
1. 调整max_tokens参数值
最直接的解决方法是动态计算可用的 max_tokens
:
js
// Node.js 示例
const prompt = "你的长提示内容";
const promptTokens = 1360; // 应实际计算令牌数
// 计算可用令牌空间(保留50令牌作为缓冲)
const availableTokens = 4097 - promptTokens - 50;
const maxTokens = Math.max(availableTokens, 1); // 确保至少为1
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt: prompt,
max_tokens: maxTokens, // 动态设置
temperature: 0.2
});
计算令牌的最佳实践
使用 tiktoken
库精确计算令牌:
bash
npm install tiktoken
js
import { encoding_for_model } from 'tiktoken';
const enc = encoding_for_model('text-davinci-003');
const promptTokens = enc.encode(prompt).length;
2. 升级到支持更大上下文的模型
如应用场景需要更长上下文,可切换到支持更多令牌的更新模型:
模型名称 | 最大上下文长度 | 说明 |
---|---|---|
gpt-4-1106-preview | 128,000 tokens | GPT-4 Turbo (推荐) |
gpt-4-0613 | 8,192 tokens | GPT-4标准 |
gpt-4-32k-0613 | 32,768 tokens | GPT-4长上下文版 |
gpt-3.5-turbo-1106 | 16,385 tokens | GPT-3.5 Turbo最新版 |
gpt-3.5-turbo-16k | 16,385 tokens | GPT-3.5长上下文版 |
text-davinci-003 | 4,097 tokens | 旧模型(不推荐用于长文本) |
使用新模型参考代码:
js
// 使用GPT-4 Turbo
const response = await openai.chat.completions.create({
model: "gpt-4-1106-preview",
messages: [{ role: "user", content: prompt }],
max_tokens: 4096, // 最高可设4096令牌完成
});
3. 优化提示策略
当无法升级模型时,可采用以下文本优化技巧:
压缩提示内容
- 删除冗余描述
- 使用缩写和简写
- 移除无关上下文
分块处理技术
python# Python伪代码 chunks = split_text(prompt, chunk_size=2000) results = [] for chunk in chunks: response = openai.Completion.create( model="text-davinci-003", prompt=chunk, max_tokens=2000 ) results.append(response.choices[0].text) final_result = combine_results(results)
摘要提炼法
js// 首先生成摘要 const summaryPrompt = `生成以下文本的摘要:\n${longText}`; const summary = await generateCompletion(summaryPrompt, 500); // 使用摘要继续后续任务 const finalPrompt = `基于摘要:${summary}\n${question}`; const answer = await generateCompletion(finalPrompt, 1000);
关键原理说明
令牌共享机制
OpenAI模型使用共享令牌池:
┌───────────────┬───────────────┐
│ 提示令牌 │ 完成令牌 │
├───────────────┼───────────────┤
│ Prompt │ max_tokens │
└───────┬───────┴───────┬───────┘
│ │
└───── 模型最大上下文长度 ───┘
如官方文档所述:
不同模型的最大上下文长度不同。如果提示占用4000个令牌,那么完成部分最多只能使用97个令牌。
不同模型的特殊考量
聊天模型(gpt-3.5-turbo/gpt-4)
特殊格式影响
消息格式包含系统/用户/助手角色标记,会使实际令牌计数难以预测:
js// 角色标记增加额外令牌 messages: [ { role: "system", content: "你是有帮助的助手" }, { role: "user", content: prompt } ]
使用官方推荐方法精确计数。
GPT-4 Vision多模态模型
- 图像输入需特殊编码占用显著令牌
- 优先压缩文本提示部分
最佳实践总结
- 始终前置令牌计算:在请求前使用
tiktoken
精确计算 - 使用模型映射表:根据需求选择合适上下文长度的模型
- 动态设置max_tokens:
可用令牌 = 模型上限 - 提示令牌 - 缓冲(50~100)
- 长文本优化:优先考虑模型升级 > 分块处理 > 提示压缩
- 实时监控令牌:在响应中包含使用指标js
console.log(`使用令牌: ${response.usage.total_tokens}`);
未来发展趋势
OpenAI正持续扩大模型上下文窗口(GPT-4 Turbo已支持128K令牌),关注模型更新日志获取最新能力。