最后更新:
ChatGPT 输出长度指南 - 理解 Token 限制与响应大小
BPE 分词器的原理与字数的偏差
ChatGPT 所使用的 GPT 系列模型,通过名为 BPE (Byte Pair Encoding,字节对编码) 的算法把文本切分为 Token。BPE 是一种反复合并训练数据中高频字节序列、从而构建词表 (vocabulary) 的方法。GPT-4o 采用的 o200k_base 分词器拥有约 200,000 个词表条目,相比此前的 cl100k_base (约 100,000 个) 有了大幅扩展。
正是这一机制造成了与字数的偏差。在英语中,"information" 这类常用单词可以收进 1 个 Token;而日语中汉字、平假名、片假名混杂在一起,即使是含义相同的句子,Token 消耗量也相差很大。要理解 ChatGPT 的提示词字数限制,掌握这一机制同样不可或缺。
来看具体的偏差模式。日语的 "东京都涩谷区" 只有 6 个字,但在 o200k_base 中会被切分为 4-5 个 Token;相对地,英语的 "Tokyo Shibuya" 有 13 个字符,却只需大约 3 个 Token。也就是说,日语每个 Token 约合 1-1.5 个字,英语约合 4-5 个字符,效率相差悬殊。这一差距也与字数与字节数的区别相关——在 UTF-8 编码下日语 1 个字要占用 3 个字节,这同样会影响 BPE 的切分效率。
| 示例文本 | 字数 | Token 数 (o200k_base) | 每 Token 字数 |
|---|---|---|---|
| 日语的"人工智能的研究开发" (日文原文为汉字 + 平假名混排) | 9 字 | 5-7 Token | 约 1.3-1.8 字 |
| "artificial intelligence research" | 35 字符 | 4 Token | 约 8.8 字符 |
| "おはようございます" (仅平假名) | 9 字 | 5-9 Token | 约 1.0-1.8 字 |
| "機械学習モデル" (汉字 + 片假名) | 7 字 | 4-5 Token | 约 1.4-1.8 字 |
Python 代码:print("hello") | 14 字符 | 5 Token | 约 2.8 字符 |
值得注意的是,纯平假名的句子比汉字混排的句子 Token 效率更低。平假名在 UTF-8 下 1 个字占 3 个字节,不容易成为 BPE 的合并对象,因此 1 个字往往就接近 1 个 Token。而汉字中高频出现的双字词多半会合并成 1 个 Token,效率相对更高。
各模型的 Token 限制
| 模型 | 上下文窗口 | 最大输出 Token | 约输出词数 |
|---|---|---|---|
| GPT-4o | 128K tokens | 16,384 tokens | ~12,000 words |
| GPT-4 Turbo | 128K tokens | 4,096 tokens | ~3,000 words |
| GPT-3.5 Turbo | 16K tokens | 4,096 tokens | ~3,000 words |
| Claude 3.5 Sonnet | 200K tokens | 8,192 tokens | ~6,000 words |
| Gemini 1.5 Pro | 1M tokens | 8,192 tokens | ~6,000 words |
上下文窗口包含输入和输出 Token。128K 上下文窗口配合 10K Token 的提示词,剩余 118K Token 用于对话,但输出仍受最大输出限制的约束。
下面把各模型的标称规格,与用同一条提示词 ("请就日本的四季用 3,000 字左右详细讲解") 实测得到的输出结果做对比。
| 模型 | 最大输出 Token | 上下文 | 实测输出 Token | 实测日语字数 |
|---|---|---|---|---|
| GPT-4o | 16,384 | 128K | 约 2,800-3,500 | 约 2,000-2,800 字 |
| GPT-4o mini | 16,384 | 128K | 约 2,200-2,800 | 约 1,600-2,200 字 |
| o1 | 32,768 | 200K | 约 3,500-5,000 | 约 2,800-4,000 字 |
| o1-mini | 65,536 | 128K | 约 2,500-3,500 | 约 2,000-2,800 字 |
| GPT-4 Turbo | 4,096 | 128K | 约 2,000-3,000 | 约 1,500-2,400 字 |
| GPT-3.5 Turbo | 4,096 | 16K | 约 1,500-2,500 | 约 1,100-2,000 字 |
从实测数据可以读出几个重要倾向。首先,任何模型都很少把最大输出 Token 数用到上限。GPT-4o 最多可输出 16,384 个 Token,但在普通提示词下通常在 3,000-4,000 个 Token 左右就自然收尾——这是因为模型学到了"作为文章合适的长度"。要让它一直输出到上限,就需要明确的指令。
另外还需注意,o1 系列模型会在内部消耗推理 Token (思考过程),因此相对于显示出来的输出字数,实际的 Token 消耗量会更多。在 API 的 usage 字段中确认时,completion_tokens 有时会大幅超过显示文本的 Token 数。
Token 与字符的换算
| 语言 | 每 Token 字符数 | 每 Token 词数 | 1,000 Token ≈ |
|---|---|---|---|
| 英语 | 约 4 字符 | 约 0.75 词 | 750 词 / 4,000 字符 |
| 西班牙语 / 法语 | 约 3.5 字符 | 约 0.65 词 | 650 词 / 3,500 字符 |
| 日语 | 约 1.5 字符 | 不适用 | 1,500 字符 |
| 中文 | 约 1.5 字符 | 不适用 | 1,500 字符 |
| 代码 (Python) | 约 3 字符 | 不适用 | 3,000 字符 |
日语与英语的输出 Token 效率对比
我们验证了让模型用日语和英语输出相同含义的内容时,Token 消耗量会产生多大差距。提示词统一为"请就以下主题分 5 个要点进行讲解:云计算的优势",分别用日语和英语执行。
| 指标 | 日语输出 | 英语输出 | 效率比 (以英语为基准) |
|---|---|---|---|
| 输出字数 | 约 800 字 | 约 1,500 字符 | - |
| 输出 Token 数 | 约 650 Token | 约 350 Token | 1.86 倍 |
| 信息密度 (字 / Token) | 约 1.2 字 | 约 4.3 字符 | - |
| API 成本 (以 GPT-4o 为基准) | 约 $0.0065 | 约 $0.0035 | 1.86 倍 |
要传达同样的信息量,日语要消耗英语约 1.9 倍的 Token。由于这直接关系到 API 成本,在成本优化至关重要的场合,采用"英文提示词 + 日文输出"的策略 (用英语撰写提示词,仅把输出翻译成日语) 是有效的。不过这种做法存在丢失日语特有语感的风险,因此需要根据用途区别使用。
影响输出长度的 API 参数实验结果
我们用同一条提示词改变 temperature 与 max_tokens,验证了 OpenAI API 的主要参数对输出长度的影响。
| 参数设置 | 平均输出 Token | 标准差 | 输出的特征 |
|---|---|---|---|
| temperature=0.0 | 约 1,850 | ±50 | 每次输出几乎完全相同。字数的可复现性最高 |
| temperature=0.5 | 约 1,900 | ±200 | 变化适度。实用上的平衡较好 |
| temperature=1.0 | 约 2,100 | ±450 | 容易变得冗长,字数波动较大 |
| temperature=1.5 | 约 2,300 | ±700 | 容易出现重复和跑题 |
| max_tokens=500 | 500 (被截断) | ±0 | 在句子中间被切断。日语约 400-600 字 |
| max_tokens=2000 | 约 1,850 | ±200 | 自然结束。多数情况下不会触及上限 |
temperature 越高输出越长的倾向,源于概率分布的扩散。temperature=0 时模型始终选择概率最高的 Token,因此输出简洁而确定。temperature 升高后,低概率的 Token 也更容易被选中,补充说明和换句表达随之增多,输出也就更长。
max_tokens 作为硬性上限发挥作用,一旦达到指定值,即使句子未完也会立刻停止输出。日语中 1 个 Token 相当于 1-2 个字,因此 max_tokens=500 大致可得到 400-600 字的输出。不过由于存在句子中途被切断的风险,更实用的做法是把 Token 数设为目标字数的 1.3-1.5 倍,促使模型自然收尾。
控制输出长度的技巧
下面介绍让 ChatGPT 按指定字数输出的提示词设计技巧。由于大语言模型精确计数字数的能力有限,需要一些额外的设计。
- 不按字数而按"量"来指定:比起"写 500 字","分 3 段来写""分 5 个条目来写"更容易得到接近预期的输出。参考值是 1 段约 100-200 字,条目列表的 1 条约 30-80 字
- 指定字数的区间:不写"恰好 500 字",而是留出幅度写成"在 400-600 字的范围内",生成的文章会更自然
- 具体指定输出形式:像"3 个小标题,每个小标题下 2-3 句说明"这样指定结构,字数就更容易控制
- 使用"简洁""详细"这类关键词:"简洁地用 1 句话"倾向于输出 20-50 字,"请详细说明"则倾向于输出 300-800 字
- 设定 max_tokens 参数 (使用 API 时):OpenAI API 可以用 max_tokens 参数设定输出 Token 数的上限。以日语 500 字为目标时,把 max_tokens 设为 700-1,000
- 明确的字数指令:"写一篇 500 字的摘要"比"写一篇简短的摘要"更有效。模型遵循数字目标的准确度相当高 (±10%)
- 结构约束:"提供恰好 5 个要点,每个 20-30 词"为模型提供了明确的边界
- max_tokens 参数:通过 API 设置以硬性限制输出长度。如果达到限制,响应将在句子中间被截断
- 温度设置:较低的温度 (0.3-0.5) 倾向于产生更简洁的输出;较高的温度 (0.8-1.0) 生成更冗长的响应
- 系统提示词:设置"你是一位简洁的技术写作者。每次回复不超过 200 词"可建立持久的长度约束。
字数控制的实践示例
下面给出具体的提示词示例,以及预期的输出字数。
| 提示词示例 | 预期输出字数 | 精度 |
|---|---|---|
| "用一句话总结" | 20-50 字 | 高 |
| "用 3 行总结" | 60-120 字 | 高 |
| "用 100 字以内说明" | 60-130 字 | 中等 |
| "写 500 字左右" | 300-700 字 | 低 |
| "分 5 个要点列出" | 150-400 字 | 高 (指条目数) |
| "用于 Twitter 发帖,140 字以内" | 80-160 字 | 中等 |
| "3 个小标题,每个 100 字" | 250-400 字 | 中等 |
由于大语言模型精确计数字数的能力较弱,"恰好 500 字"这类严格指定很难实现。原因在于模型是以 Token 为单位生成的,并不会逐个计算每个 Token 相当于几个字。更现实的做法是:输出后用字符计数器确认字数,再根据需要追加"再短一些""再补充 100 字"之类的调整指令。
稳定获得长文输出的提示词技巧
要生成超出输出上限的长文,单纯指示"写长一些"是不够的。把以下技巧组合起来,才能获得稳定的长文输出。
- 链式提示词 (分段生成):像"先写第 1 章""接着写第 2 章"这样,按小节拆分生成。为每个小节指定字数,就能控制整体字数。在 API 中把各次请求的输出拼接起来,构成最终的长文
- 先出大纲法:先生成大纲 (小标题与各小节概要),之后再逐节展开。在大纲阶段就定好整体结构与字数分配,可以生成篇幅均衡的长文
- 上下文承接:输出中途被切断时,把上一次输出末尾的 200-300 字一并放进下一次请求,并指示"请接着下面的内容继续写"。仅说"继续写"会丢失上下文,存在内容重复或前后矛盾的风险
- 强化明确的长度指令:写成"务必写 3,000 字以上,每个小节至少 500 字"这样强调最低字数的形式,可以抑制模型过早结束输出的倾向
- 活用 JSON 结构化输出:在 API 的 response_format 中指定 JSON 模式,让各小节作为 JSON 的字段输出,按小节管理字数就会变得容易。
ChatGPT 输出字数的常见问题与陷阱
下面介绍在 ChatGPT 的字数控制中容易遇到的问题,以及容易被忽视的陷阱。
- 输出中途被切断:在达到输出 Token 上限时发生,会在思路中间停止。在 API 中,用 finish_reason="length" 检测并自动请求续写的机制最为可靠;也可以增加 max_tokens 或要求分部分回复。GPT-4o 最多可输出 16,384 个 Token,而 o1 支持到 32,768 个 Token
- 过度冗长:模型倾向于过度解释。在提示词中使用"请简洁回答"或"跳过前言"即可收敛
- 长度不一致:相同的提示词可能产生长度相差 30-50% 的输出。使用温度 0 可获得更一致的结果
- Token 计数不匹配:用户以词为单位思考,模型以 Token 为单位。始终进行换算——把目标词数乘以 1.33 来估算 Token 数
- 与指定字数偏差很大:由于大语言模型无法精确计数字数,±30% 左右的偏差属于预料之中。改用结构 (段落数、条目数) 来指定,精度会更高。尤其在日语中,Token 与字数的对应关系不稳定,偏差往往比英语更大
- 日语输出比英语短:即使 max_tokens 设置相同,日语输出的字数也只有英语的约 50-60%。要让日语得到与英语相当的字数,需要把 max_tokens 设为 1.8-2.0 倍
- 出现重复:生成长文时有时会重复相同内容。把 frequency_penalty 设为 0.5-1.0 可以抑制,但数值调得过高会损害文章的自然度。在 0.3-0.7 的区间内调整比较实用
- Token 计数的误算:可以用 tiktoken 库 (Python) 或 gpt-tokenizer (JavaScript) 事先计算提示词的 Token 数,但模型升级导致分词器变更时,同一段文本的 Token 数也可能改变。o200k_base 与 cl100k_base 对同一文本的 Token 数最多可能相差约 20%,因此请选择与所用模型对应的分词器
- 上下文窗口的消耗:输入提示词越长,可用于输出的 Token 数就越少。即便是 128K 上下文的模型,发送 100K Token 的提示词后,可用于输出的也只剩下 28K Token。不过输出同时还受 max_output_tokens 上限的约束,因此即使上下文有余量,也无法突破输出上限
Web 界面与 API 的输出限制差异
ChatGPT 的 Web 界面 (chat.openai.com) 与 OpenAI API 在输出限制上的行为并不相同。不了解这一差异,就容易产生"在 Web 界面能输出长文,在 API 里却中途被切断"这样的困惑。
| 项目 | Web 界面 (ChatGPT) | OpenAI API |
|---|---|---|
| 输出 Token 上限 | 取决于模型 (自动设定) | 可用 max_tokens 明确指定 |
| "继续写" | 自动保留对话历史 | 需要自行管理对话历史 |
| 流式输出 | 默认启用 | 需用 stream=true 显式启用 |
| 输出被截断的提示 | 显示 "Continue generating" 按钮 | 通过 finish_reason="length" 判断 |
| 成本管理 | 包含在订阅费用中 | 按 Token 计量付费 |
要在 API 上稳定地取得长文,确认 finish_reason 字段不可或缺。finish_reason 为 "length" 表示输出在 max_tokens 上限处被截断;为 "stop" 则表示模型自然结束了输出。把这一判断自动化,在为 "length" 时自动请求续写,API 也能实现与 Web 界面同等的长文输出。
成本影响
| 模型 | 输入成本 (每百万 Token) | 输出成本 (每百万 Token) | 1,000 词输出成本 |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | ~$0.013 |
| GPT-4 Turbo | $10.00 | $30.00 | ~$0.040 |
| GPT-3.5 Turbo | $0.50 | $1.50 | ~$0.002 |
输出 Token 的成本是输入 Token 的 2-4 倍。控制输出长度直接影响 API 成本,尤其是在大规模使用时。
总结
ChatGPT 的输出以 Token 为单位衡量,1 个 Token 大约等于英文 4 个字符,输出长度基于 BPE 分词器的切分而受到限制。当前模型的输出上限为 4,096 至 16,384 个 Token (约 3,000 至 12,000 个英文单词)。日语每个 Token 约合 1-1.5 个字,要消耗英语 (约 4-5 个字符) 3-4 倍的 Token。要控制字数,用结构 (段落数、条目数) 来指定最为有效;在 API 上把设置调到接近 temperature=0,可以提高输出的稳定性。此外还可以通过明确的字数指令、max_tokens 参数和系统提示词来控制输出长度。理解 Web 界面与 API 的行为差异、按用途选择控制手法,是高效运用 ChatGPT 的关键。确认 ChatGPT 生成文章的字数时,欢迎使用字符计数器验证提示词和输出的长度。