“ChatGPT 开启无限 token”——你是不是也刷到过这种标题?点进去要么是付费课,要么是让你装一个来路不明的脚本。我在真实项目里拿 ChatGPT 干翻译、写代码、啃文档已经两三年,可以负责任地告诉你:不存在一个开关能让你一次塞进无限文本,也不存在一个脚本能让输出永不停。但存在一套方法论,能让你在官方规则内获得接近“无限”的体验。这篇文章不卖关子,只讲我玩明白 token 之后沉淀下来的实操思路。它适合重度使用 ChatGPT 做翻译、写代码、读文档、做知识管理的人,也适合那些开发时对着“token exchange failed”一脸懵的人。今天把两种 token——计费 token 和身份 token——一次说透。
1. 从“开关不存在”开始:token 到底是什么,上限卡在哪
先把我这两三年最重要的结论放这里:想要接近无限,靠三件事——人肉管理上下文、工程化分批处理、把身份报错和计费问题分开看待。这三件事听起来一点不酷,但每一条都能实打实帮你省下几百上千块,还能让你少熬几个深夜。
1.1 一个 token 是多少字:别再凭感觉估上下文
token 是模型处理文本的最小单位,既不是“一个字”,也不是“一个词”。像英文这种拼音文字,它按子词切分,一个常见单词可能是一个 token,也可能被切成两三个;中文则是按字或按词表切分,一个汉字大约占 1 到 2 个 token。所以中文用户经常觉得“怎么这么快就用完了”,因为我们的文本在 token 消耗上天然不占便宜。
换算成日常经验:1000 个 token 大约能对应 750 个英文单词,或者 500 到 800 个汉字。我自己的粗算方式是,中文字数直接乘 1.5,英文单词数乘 1.3,得到的就是大概的 token 数。举几个例子:
- 一页 A4 英文文档,大约 600 词,粗算 800 token 上下;
- 一份 10 万字的报告,按中文字乘 1.5 就是 15 万 token;
- 一个 1080p 屏幕能显示的中文网页,大约是 3000 到 5000 字,相当于 4500 到 7500 token。
为什么要先算这个?因为后面所有“无限 token”的方案,都建立在“知道自己一顿能吃多少”的基础上。你连自己发给模型的文本大概多少 token 都没数,那任何优化策略都是空谈。
1.2 网页版、API、命令行:三种场景的上限差异
很多人被“上下文窗口 128k”这种参数绕晕了,其实不同使用场景,限制的呈现方式完全不一样。
| 使用场景 | token 上限的表现 | 用户能控制什么 |
|---|---|---|
| 网页版 ChatGPT | 系统背后有隐藏的上下文管理策略,聊天过长会变慢、答非所问,或提示开启新对话 | 新开会话、清理历史、手动让模型总结 |
| API | 必须显式传参,上下文窗口包含输入和输出,超限直接报错 | 选择模型、设置输出上限、裁剪历史、分批发送 |
| 桌面客户端 / Codex CLI | 受本地配置文件和模型能力共同影响,配置损坏也能引发一连串登录失败 | 修复配置文件、升级客户端、退出重登 |
网页版是“悄悄截断型”,API 是“硬性报错型”,命令行工具则是“配置文件背锅型”。很多人只在网页版里点点点,以为上下文窗口就是那个输入框往上滚的长度,这其实是误解。真实情况是:每次请求,模型都要把历史对话重新处理一遍,这个词叫“重新读一遍”,而不是像数据库一样把记忆一直存着。
1.3 为什么“长上下文”不等于“无限”
现在不少模型都宣传百万级上下文,听起来好像几十万字塞进去没问题。确实,窗口变大了,但你要想清楚三件事:
第一,上下文越长,模型处理时要注意的东西越多,速度和成本一起涨。底层有个叫 KV Cache 的注意力缓存,长度和上下文成正比,上下文翻一倍,显存占用、算力开销都会明显上升。你实际用起来的感觉就是:新开一个短对话,回答很快;塞了几万字之后,每回复一个字都像在等火车。
第二,学术界很早就发现一个现象,模型对长上下文中间部分的信息召回率明显下降,专业说法叫“中间丢失”。意思是:开头和结尾的内容它记得比较牢,中间塞进去的细节很容易被忘掉。你把整个项目历史堆在上下文里,结果最关键的约定可能正好处在“被遗忘区”。
第三,输出长度仍然是有限制的,上下文窗口是输入加输出总共的大小。你以为窗口很大就能让它一口气写本书?输出上限照样卡着你。
所以“长上下文”只是在特定场景下有用的一个租用选项,不是“无限”的通行证。理解了这一点,才能真正接受后面这些方法论。
2. 别把整个历史背在身上:滚动摘要与滑动窗口的对话瘦身法
大部分人对 token 不够用的感知,来自同一个场景:跟 ChatGPT 聊了很久,越聊越卡,越聊回答越弱,最后它开始重复前面说过的话。这不是模型变笨了,是你的上下文里堆了太多垃圾。
2.1 上下文一旦膨胀,质量和钱包一起报警
有一次我在一个项目里连续修改同一个工具脚本,前后聊了大概五六十轮。到后面每问一句,响应时间翻倍,而且回答里开始出现前面已经废弃的方案。原因就是每次提问,模型都得把几十轮历史一起“读完”再回答,那些已经否定的旧方案照样占着位置,干扰判断。
费用也是一样。API 计费按 token 算,输入和输出都花钱。上下文越长,每提一个问题要重新计算的输入 token 就越多。同样的问题,放在刚才新开的对话里提问和放在一个已经积累了五万字历史的对话里提问,花费可能差出几十倍。
所以对话瘦身不是“洁癖”,是实打实省时间和省钱。核心原则只有一条:上下文窗口是你这一轮的工作内存,不是长期硬盘。工作内存应该只放现在要用到的东西。
2.2 滚动摘要法:让模型帮你压缩记忆
我最推荐的操作,是每隔几轮就让模型自己输出一份结构化摘要,然后用摘要开启新一轮对话,老对话直接归档。这比你自己复制粘贴省力得多,模型参与提炼,相当于用一种“自我提炼”的方式把关键信息留在新会话里。
具体步骤很简单:
- 每聊 5 到 10 轮,让它输出一份进度摘要;
- 摘要有固定结构:当前目标、已完成事项、待办事项、用户偏好;
- 把摘要复制进新对话,并让它基于摘要继续工作;
- 如果新对话又变得很长,重复这个过程,做“摘要的摘要”。
我实际用的提示词大概是这样的:
请基于我们刚才的整段对话,生成一份结构化进度摘要,包含:1)当前目标;2)已完成事项(列出可保留的结论、文件名、代码模块);3)待办事项;4)我在表达偏好时的特殊要求。控制在 400 token 以内,用列表输出,不要复述过程细节。
注意“控制在 400 token 以内”这个约束一定要给。你不给,模型很容易给你写个 1500 token 的“摘要”,那摘要本身就失去了压缩意义。滚动摘要的本质,是用一块很小的固定开销,换取永远用不满的窗口。只要摘要质量合格,你可以这样“滚动”几十上百轮。
2.3 滑动窗口与归档习惯:旧内容有序退场
摘要适合“长期项目”,滑动窗口则适合“即时任务”。所谓滑动窗口,就是只保留最近若干轮完整内容,更早的只留摘要或者直接丢弃。
我自己处理长对话的标准是:保留最近 10 到 20 轮完整细节,再往前的全部交给摘要。因为近期的内容包含当前正在处理的代码、具体的报错、刚刚确认过的决策,这些丢失了会很痛苦;而更早的内容大多是上下文铺垫,摘要足够。
同时要养成一个“归档”动作:完成一个阶段目标后,主动新开对话,并在新对话第一句写明项目背景,比如:
我们在做一个小程序后端,用 Python FastAPI,已完成用户登录模块。当前目标是给订单接口加上分页。上次结论:使用 offset/limit 方式。请继续。
这不叫“重新开始”,这叫把上下文里最值钱的东西提取出来,装进新对话。窗口还是那个窗口,桌子还是那张桌子,但你主动决定了桌面上摆什么。定期清理掉已经确认没问题的代码块、已经执行的命令、已经否定的方案,让模型轻装上阵,质量自然回升。
3. 大文档硬啃不动?分块、向量检索和队列化处理
聊天对话再长,也还有个尽头。真正让人头疼的是塞文档:一本几十万字的书、一份全量日志、一套游戏 Mod 的全部文本。这时候哪怕窗口有 128k 甚至更大,你也不能硬塞。
3.1 分块与向量检索:查资料而不是背整本书
把一本 30 万字的书直接丢给 ChatGPT,让它写书评,听起来很爽,实操基本等于自杀。先不说 token 费爆炸,光是 30 万字塞进去,模型对中间内容的召回质量就已经很差了。正确做法是:不背整本书,只翻需要的页。
流程分三步。第一,把文档按章节或者语义完整的小节拆成一块块,每块控制在 500 到 1500 token。拆的时候注意别从一句话中间硬切,尽量保持语义完整。第二,把每个块做向量化,也就是 embedding,存储到一个可以按相似度检索的地方。第三,用户提问时,把问题也转成向量,从库里捞最相关的 3 到 5 个块,只把这些块放进上下文让模型回答。
这个过程现在有专门的说法叫 RAG,但它背后的道理跟人查资料一模一样:你不会为了回答“黛玉是什么性格”把整本《红楼梦》背下来,而是先定位到相关章节再细读。模型也一样,给它喂它需要的材料,效果远远好过把整个文档库扔进上下文。
我贴一段思路示意,不绑定具体框架,核心逻辑就是这样:
# 伪代码示意:分块 + 检索 + 问答 chunks = split_text(document, chunk_size=1000) vectors = [embed(chunk) for chunk in chunks] hits = top_k(embed(user_question), vectors, k=5) context = "\n".join(hits) response = chat_with(context + "\n" + user_question)这套做法几乎可以应对所有“文档太长”的问题:长篇报告、合同全集、小说设定、游戏文本库,都能这样处理。你不需要真的搭一套复杂系统,哪怕是用 Python 脚本把文本切块、再用向量库内存暴力检索,都能收获巨大。
3.2 队列化批处理:断点续跑比一把梭靠谱
另一个高频场景是批量任务:一次翻译 5000 条游戏 Mod 文本、批量生成产品描述、给几十篇长文做摘要。很多人习惯把这些内容拼接成一个大 prompt 发过去,结果不是超窗口就是中途失败,然后从头再来。
我的方案是把它改造成队列化任务:
- 把任务拆成独立小条目,每一条单独请求;
- 维护一个任务状态表,记录每条是 pending、running、done 还是 failed;
- 失败的处理两条逻辑:短期失败重试 2 到 3 次,连续失败跳过并记录,不要中断整批;
- 每完成一条立刻把结果写盘落库,不要攒到最后再一次写。
这个习惯是我踩坑踩出来的。最早做批量翻译时,我写了个一把梭的脚本,把 800 条文本一次性丢进去,跑到第 600 条网络抖了一下,全部作废,前功尽弃。后来改成“先写落盘,再标记完成”的顺序,无论中间断多少次都能从断点继续,再也没慌过。
任务拆分前最好先粗算一下总量。比如 5000 条文本,平均每条 50 token,输入打底就是 25 万 token,加上输出和重试,整个任务可能吞掉三四十万 token。分批跑,每批 50 条,成本和进度都更可控。
3.3 外部记忆:让代码记住,别全塞给模型
还有一个长期项目场景,比如用一个长期会话维护知识库、追踪连载小说世界观、记录一个持续半年项目的所有决策。这种场景天然会越积越多,靠摘要有时候也不够,因为你需要模型在回答时随时能引用具体的“事实”。
解决办法是外部记忆。把所有事实性信息放进文件或数据库,模型每次只负责处理当前这个小片段,需要事实时由代码检索出来再喂给它。举例来说,我维护一个project_notes.md,里面记着端口号、模块结构、已经踩过的坑。新开对话时只贴相关章节,而不是把整个文件粘进去。
理解方式很简单:模型的上下文是工作内存,文件系统和数据库才是长期记忆。工作内存再大也是有限的,但长期记忆的容量由你的存储决定,本质上可以无限。
4. 登录十次挂八次:身份 token 与那些 token 报错
前面讲的是计费意义上的 token,也就是模型处理文本的单位。但热搜词里还有一堆报错这种东西:“token exchange failed”“failed to refresh token”“JWT 实现 token 续签”。这些词里的 token 完全是另一个东西——身份凭证。不把这个区别讲清楚,你会在排障时走很多弯路。
4.1 同名不同物:认证 token 和计费 token 是两回事
登录 ChatGPT 或者调用 API 时,服务端会发给你一串身份令牌,用来证明“你是你”。一般分两把钥匙:一把短期有效的叫 access token,有效期可能只有几小时;一把长期有效的叫 refresh token,用来在短期钥匙过期后重新换取新钥匙。这个“换钥匙”的动作,业界就叫 token 续签,英文常见说法是 token refresh。
而“token exchange failed”这种报错,说的就是换新钥匙的过程失败了。它跟你上下文用了多少 token、聊天多长、有没有充会员,一点关系都没有。我见过有人看到“failed to refresh token”慌得不行,以为是自己的用量超标,其实只是登录态过期了。
4.2 三类高频认证报错的排查链路
我把搜索热词里出现频率最高的三类登录类报错整理成了排查表,下次遇到可以直接对着查:
| 报错关键词 | 含义 | 常见原因 | 处理建议 |
|---|---|---|---|
| token exchange failed: token endpoint returned status 403 forbidden: country, region, or territory not supported | 服务端按归属地策略拒绝了这次令牌交换 | 账号注册地或当前网络出口不在服务商支持列表内 | 查看官方支持地区,在符合服务条款的环境下使用 |
| failed to refresh token: 400 bad request invalid refresh_token | refresh token 内容为空或已失效 | 本地保存的登录态损坏、过期、被服务端吊销 | 退出登录,清理本地凭据缓存,重新走完整登录流程 |
| sign-in could not be completed token exchange failed: error sending request | 令牌交换请求根本没被成功发出或响应 | 网络不通、公司内网网关拦截、服务端临时故障 | 检查网络连通性,确认相关域名能否访问,重试或错峰登录 |
第一类报错是最容易让人产生“有没有办法绕一下”的冲动。我的建议是别在合规边缘试探,按照服务商条款使用,能省掉非常多后续麻烦。如果是浏览器访问,可以试试无痕窗口排除扩展插件干扰;如果是客户端,退出重登通常就能解决第二类问题。
4.3 config.toml 与 codex CLI:本地配置怎么引发 token 失败
热搜词里还有两条很有代表性:“ChatGPT 无法加载 config.toml”“请修复 config.toml: model”。这属于命令行工具或桌面客户端的本地配置文件问题,跟账号本身没太大关系。
config.toml 通常记录着模型名、认证信息、一些本地运行参数。报错“无法加载 config.toml”,常见原因是配置结构不匹配、模型名字在当前客户端版本里不存在、或者文件本身损坏了。还有一种情况是换了新模型版本之后,旧配置里写的模型名已经失效,客户端加载时直接报错。
处理链路很简单:先备份原文件,再重置为默认配置,重新登录一次,然后确认配置里的模型名在当前版本下是否支持。如果是类似 model not supported 的报错,更直接的办法是升级客户端到最新版,再换成稳定可用的模型名。别一上来就满世界找“配置文件修复工具”,大多数情况就是版本兼容问题。
我提醒一点:这种本地认证失败的报错机制,和网页登录本质是一回事。很多命令行工具会在本地缓存 refresh token,它失效了,所有命令都会莫名失败,表现就是“一会儿能用一会儿不能用”。
4.4 JWT 续签机制:为什么报错总让你退出重登
JWT 是现在最常见的身份令牌实现方式。一个 JWT 长这样:header.payload.signature,三段分别装类型与签名算法、具体数据、防篡改签名。它最大的特点是无状态,服务器不保存令牌记录,只靠签名验证内容合法。这也意味着一个 JWT 一旦签发,短期内无法轻易“收回”,所以 access token 的有效期必须做短。
于是就有了 refresh token 机制。访问令牌快过期时,客户端拿着 refresh token 去换新令牌;刷新接口返回新的 access token。如果 refresh token 本身过期、被吊销、或者代码里传了空字符串,服务器就返回 400 错误。这也是为什么很多官方报错信息最后都跟一句“log out and sign in again”——它是在告诉你:本地那枚长期凭证已经没用了,必须重新走一遍完整登录流程拿新的一对令牌。
理解了 JWT 这套机制,你以后再到开发群里看到“token exchange failed”,第一反应就应该是“检查登录态”,而不是“我是不是干了什么坏事”。这套原理不是 ChatGPT 专属,任何用 JWT 做登录的网站和工具都适用。
5. token 就是钱:用量体检、上下文缓存与预算熔断
前面几章都在讲怎么让对话更“长”,这一章反过来聊一个更现实的问题:token 是计费单位,每一个 token 都是钱。网上那些“无限 token”的帖子,恰恰最爱回避成本问题。
5.1 不同模型的 token 单价差距比想象的大
同一个问题,用不同模型处理,费用能差出一个量级。旗舰级推理模型贵,通用模型中等,轻量模型很便宜。我见过不少团队拿最贵的旗舰模型跑文本分类、关键词抽取这种简单活,纯属浪费。
我的选型习惯是看任务复杂度,选最便宜的够用模型。
| 模型档位 | 典型用途 | 相对成本 |
|---|---|---|
| 旗舰推理型 | 复杂推理、长文深析、架构设计 | 高 |
| 通用型 | 日常对话、翻译、中等代码任务 | 中 |
| 轻量型 | 分类、抽取、简单改写、格式整理 | 低 |
具体价格每个季度都可能变,以官方定价页为准,但“输出 token 比输入 token 贵”这一点是稳定的,大约贵出数倍。所以写 prompt 时尽量引导模型简答,也是省钱手段。
还有一点很重要:大规模跑任务之前,先拿小批量试跑。花几块钱估算整批任务的 token 消耗,再决定用什么模型,比一上来就跑全量再收账单要理智得多。
5.2 缓存命中:把重复内容变成打折 token
很多主流 API 支持提示词缓存(Prompt Caching),如果连续多次请求的开头部分是相同的,这部分内容会被缓存,再次计算时费用大幅下降,平台不同折扣不同,有些能省下一个很大的比例。
怎么利用这个机制?把不变的内容放到最前面。系统提示词、项目背景、超长的说明文档、固定的工具定义,放在 prompt 开头固定不动;变化的内容,例如用户问题、当前查询参数,放在后面。这样每次请求的前缀都一致,缓存命中率就会很高。
有一个细节必须注意:缓存要求前缀逐字节一致。你不能在固定前缀里动态插入一个时间戳,或者每次重新生成一遍系统提示词。我以前做批量任务时,因为项目描述里加了个动态日期,缓存一直没命中,账单还特别难看,后来去掉动态字段才好转。
5.3 用量体检与熔断:在账单爆炸之前叫停
成本意识不能靠感性,要靠数据。API 控制台里通常都有用量报表和预算告警,一定要设置。个人开发者也别嫌麻烦,设个月度预算上限和告警阈值,超过就通知你。
代码层面,用 token 计数库提前估算文本长度,是有效的手段。以 Python 生态为例,tiktoken 可以把文本编码成 token 序列,数一下长度就知道大概要花多少钱:
import tiktoken enc = tiktoken.get_encoding("o200k_base") text = "你要估算的文本内容" token_count = len(enc.encode(text)) print(token_count)我的习惯是在批处理脚本里加一道熔断:每批次预算上限设为比如 100 万 token,一旦接近这个值,自动切到更便宜的轻量模型继续跑,或者直接暂停等人工确认。这样即便某个环节失控,损失也在一个可以接受的范围内,而不是月底收到一张看得人血压升高的账单。
6. 我用了半年的“伪无限”工作流:两个会话各司其职
方法论讲了一大堆,最后分享一个我实际在跑的完整工作流。这套组合不是知识库级别的复杂系统,但它几乎覆盖了我日常 90% 的“想要无限 token”的需求,你甚至可以照抄。
6.1 主会话养文档,临时会话跑杂活
我会同时开两个会话。主会话专门服务长期项目,只讨论这个项目的核心内容:目标、当前文件、下一步计划。临时会话则处理一切杂活:翻译一句英文、写个一次性脚本、回答一个临时疑问。临时会话用完就丢,哪怕聊得再长也不心疼;主会话保持精简,从来不塞杂七杂八的问题。
这样做最大的好处是,主会话的上下文质量一直很高。因为长期项目的信息密度集中,滚动摘要做起来也简单;而那些临时任务如果不单独开,它们的存在会稀释主会话的注意力,让模型对核心问题的响应质量下降。
6.2 同步结论而不是同步全文
主会话总会慢慢长大。我定期做一次“结论同步”:让模型输出项目当前状态摘要,然后新开一个主会话,把摘要作为开场。注意,同步的是结论,不是全文。代码完整内容留在文件里,模型只需要知道文件路径和核心接口就够了,没必要把几百行代码反复贴在上下文里。
同步结论的习惯我还用在了跨模型切换上。今天用一个模型,明天用另一个,只需要把摘要贴给新模型,它就能很快进入状态。你不必跟上下文窗口较劲,而是通过控制输入信息的密度来管理窗口。
6.3 每周压缩一次知识库
每周五我会把这周所有主会话的摘要归拢起来,交给一个轻量模型做“摘要的摘要”,生成一份周报,内容包括本周完成、关键技术决定、遗留问题、下一步计划。日积月累,这份周报就成了一个小型个人知识库。
下次遇到类似问题,我先翻周报,而不是去翻聊天记录。聊天记录太长了,而且夹杂大量无效信息;周报是提炼过的,命中率高得多。这种“人肉 RAG”虽然原始,但对个人项目管理完全够用。
6.4 什么时候真的需要更大窗口
当然,更长上下文不是没有价值。一次分析整份长代码库的结构、直接审查一份上百页的合同、把一本书作为整体讨论主题这种任务,确实需要大窗口。但它的价值在于“租用更大的内存”,让你少拆几次,不是让你无限制地往里面堆东西。该做摘要的时候还是得做摘要,该归档的还是得归档。
前几天还有朋友问我,现在是不是已经“开启无限 token”了。我说我没有开任何开关,只是把该压缩的压缩、该归档的归档、该用代码记的用代码记。无限是策略问题,不是开关问题。你把这套思路跑顺之后,会发现上下文窗口的数字其实没那么重要。