一百万 Token 的上下文窗口正式开放,这件事在圈子里发酵的速度比我预想的快。但真正让我坐下来的,不是"数字又变大了"这个消息本身,而是它把一整类过去只能靠检索拼凑的工作流,直接推到了"全量喂进去"的临界点。Claude Opus 4.6 和 Sonnet 4.6 这轮升级,表面看是上下文上限的扩容,实际上改变的是成本结构、提示词组织方式和工程分层逻辑——你要还是按"塞几段相关文档"的思路去用它,那这一百万 token 对你来说基本等于白给。这篇东西写给两类人:一类是手上已经有长文档、大代码库、长会话智能体需求,想判断值不值得迁移的;另一类是想搞清楚长上下文到底贵在哪、慢在哪、坑在哪,避免上线后账单和延迟同时失控的。我会把换算、成本、缓存、提示词骨架、踩坑排查都拆开讲,能直接抄的部分我给模板,需要你自己代入的部分我标清楚变量。
1. 一百万 Token 到底意味着什么:先把尺子量清楚
很多人对"100 万 token"没有体感,脑子里只有"很大"两个字。这个模糊认知会直接坑到后面的成本估算和材料切分,所以第一件事是把尺子校准。Token 不是字符,也不是单词,它跟分词器强绑定,同一个中文句子在不同模型下切出来的数量能差出三成。你在做容量规划时如果拿字符数当 token 数用,最后要么浪费一半预算,要么在关键时刻被截断。
1.1 从"字数"到"token"的换算直觉
英文场景相对好估,1 个 token 大致对应 0.75 个英文单词,反过来说 1000 个英文单词大概是 1300 到 1400 个 token。中文场景波动更大,一个汉字通常落在 0.6 到 1.2 个 token 之间,取决于分词器对中文词表的覆盖程度和文本里中英混排的比例。技术文档里夹着大量英文术语、代码片段、标识符,实际 token 密度会比纯中文散文高一截。
我把常用的几类材料做了一张粗略对照表,数字是量级估计,你做预算时按自己实际分词结果再修正一遍:
| 材料类型 | 计量单位 | 换算成 token 的量级 | 100 万 token 大约等于 |
|---|---|---|---|
| 中文散文/报告 | 1 个汉字 | 0.6 ~ 1.0 | 100 万 ~ 160 万字 |
| 英文技术文档 | 1 个单词 | 1.3 ~ 1.4 | 70 万 ~ 75 万单词 |
| 源代码 | 1 行 | 10 ~ 15 | 6.5 万 ~ 10 万行 |
| 会议转写稿 | 1 分钟录音 | 150 ~ 220 | 75 ~ 110 小时会议 |
| 结构化日志 | 1 条记录 | 40 ~ 80 | 1.2 万 ~ 2.5 万条 |
这张表最有用的一行其实是源代码。一个中等规模的后端服务,核心业务代码加上配置、脚本、文档,很容易落在 5 万到 8 万行这个区间。也就是说,一百万 token 刚好够你把一个完整的中型仓库一次性摊在模型面前——这个能力在半年之前是不成立的,你得靠分块检索 + 多次追问才能勉强拼出全局视图,而每次拼接都会丢上下文。
1.2 名义上下文和有效上下文是两回事
这里是第一个必须讲清楚的概念:标称 100 万 token,不等于模型在 100 万 token 上都有同等质量的注意力。行业里已经反复验证过的现象是,信息放在材料开头和结尾时,模型的召回和推理质量明显高于放在中间。"中间遗忘"不是某个模型独有的毛病,它是长序列注意力在训练分布和位置编码外推共同作用下的普遍表现。
我自己的经验值是,在需要多跳推理的任务上,把有效材料控制在标称上限的 30% 到 50% 之间,效果最划算。也就是说,100 万 token 的窗口,我实际会当成 30 万到 50 万 token 的"高质量工作区"来用,剩下的额度留给三样东西:输出长度、模型内部的推理消耗、以及你反复追问时的历史累积。你要是把窗口塞到 95%,第一次回答可能还行,第二三轮追问就开始出现"忘掉前面说过什么"和"引用错编号"的情况。
提示:判断一段材料该不该全量喂进去,问自己一个问题——这段材料里有多少比例是模型真正需要逐字读的?如果只有 5% 的关键段落,剩下的都是铺垫,那分块检索反而更省更准。
1.3 这次升级真正的分水岭在哪
我的判断是,分水岭不在"更长",而在"够用"这条线被跨过去了。过去做长文档分析,标准做法是切片、向量化、召回 Top-K、拼装。这套流程的问题不在于不准,而在于它天然假设"我知道我要找什么"。可现实里大量的任务是开放式的——让模型读完整份技术规范,找出自相矛盾的条款;让模型扫完整个仓库,指出分层不合理的地方。这类任务你没法预先构造查询,检索根本无从下手。
全量加载把这类开放式任务解锁了,代价是成本从"检索开销"变成了"token 计费"。这就引出了后面的核心问题:同样的材料反复用,账单会以什么斜率往上走?答案是,如果没有前缀缓存,斜率会非常陡;有了缓存,斜率能压下来一个数量级。所以这轮升级里,真正决定你能不能把它用起来的,不是上下文上限,而是缓存命中率。
2. 长上下文背后的技术账:为什么它不是简单调大一个数字
我见过太多人把长上下文理解成"把数组上限从 20 万改成 100 万",觉得是个配置项。实际改一个数字的背后,是显存、算力、位置编码、缓存调度四本账同时要平。搞清楚这四本账,你在做方案取舍时才有依据,而不是靠感觉。
2.1 平方项与被吃掉的显存:一笔可以算清楚的账
自注意力对序列长度的复杂度是平方级的,100 万 token 意味着理论上 10 的 12 次方量级的注意力权重矩阵。这个规模不可能全量物化,工程上必然用了分块计算、稀疏化、或者分层注意力的组合方案。这一点对你有什么实际影响?影响在于:长上下文的推理延迟不会是线性的,你按"两倍长度两倍时间"去估容量,上线后会被打脸。
更硬的约束在 KV 缓存。这部分可以直接算。单个 token 在每层需要存 Key 和 Value 两份,每份的维度是注意力头数乘以每头维度。用一个假设配置做示意:64 层、8 个 KV 头、每头 128 维,那么每 token 每层的元素数是 2 × 8 × 128 = 2048,乘以 64 层就是 131072 个数值。按 FP16 两字节算,单个 token 的 KV 占用约 256 KB。
| 上下文长度 | 单 token KV 占用 | KV 总量(示意配置) |
|---|---|---|
| 1 万 token | 256 KB | 2.5 GB |
| 10 万 token | 256 KB | 25 GB |
| 50 万 token | 256 KB | 125 GB |
| 100 万 token | 256 KB | 250 GB |
250 GB 这个数量级,单卡显存放不下,必须做分页换出、多卡切分或者更激进的压缩。这就是为什么长上下文的单位 token 价格普遍高于短上下文,也是为什么"前缀缓存"会成为省钱的核心手段——它省的不只是算力,更是这 250 GB 的重复搬运。
2.2 位置编码外推与"远端注意力变弱"
模型训练时的序列长度是有限的,推理时要撑到 100 万,靠的是位置编码的外推技术,常见手段包括位置插值、频率缩放这一类。这些方法能让模型"不崩",但不能让它在远端位置上的分辨力和训练长度内完全等价。
表现出来就是:你把 80 万 token 塞进去,问一个位于第 40 万 token 附近的细节,模型答错的概率明显高于问开头和结尾的同类细节。这不一定是模型"没看到",更可能是它在这个位置上的注意力权重被稀释了。
实操层面的应对手段有三个,我按有效性排序:
- 重排材料:把最关键的内容放在最前面和最后面,次要材料夹中间。这个改动零成本,效果立竿见影。
- 加坐标锚点:给长材料的每个章节打上显式编号,在材料开头放一份目录,让模型可以通过编号做二次定位,而不是靠注意力硬扫。
- 二次回查:第一轮让模型输出"我需要看哪几个章节",第二轮只把那几个章节单独喂进去做精读。多花一次调用,准确率能拉回来一大截。
2.3 前缀缓存:省钱的关键全在这
缓存的基本原理很朴素:如果两次请求的开头有完全相同的 token 序列,那这段前缀对应的 KV 可以复用,不用重新计算。听起来简单,但它的约束条件很严格——必须逐 token 完全一致,中间多一个空格、时间戳、随机 ID,后面全部失效。
这个特性直接决定了你的提示词组织顺序。正确的顺序是:长期不变的系统指令 → 工具定义和格式约束 → 大块固定资料 → 变化的任务描述 → 本次的实时输入。把变化的东西统统往后放。
我踩过的最典型的一个坑,是在系统提示开头放了一句"当前时间:2026-XX-XX"。听起来很合理,实际效果是缓存命中率直接归零,因为每次调用前缀都不一样。同样的坑还有:把用户 ID、请求 ID、版本号哈希放在最前面;把随机排序的文档列表当固定资料;在固定资料里插入"本次任务共 N 条"这种每次都变的计数。
注意:缓存写入通常比普通输入有溢价,读取则便宜一个数量级左右。这意味着缓存适合"同一份大材料被反复问"的场景。如果你只问一次,缓存反而是净亏损。
2.4 长上下文和检索增强到底怎么选
这两者不是替代关系,我这边的实践结论是分层。下面这张表是我自己做方案时的判断依据:
| 判断维度 | 全量长上下文更合适 | 分块检索更合适 |
|---|---|---|
| 任务是否开放式 | 是,说不清要找什么 | 否,查询条件明确 |
| 材料规模 | 单次 30 万 token 以内 | 百万级以上知识库 |
| 复用频率 | 同一份材料反复问 | 每次问不同片段 |
| 更新频率 | 材料基本不变 | 材料每天新增 |
| 多跳推理需求 | 强,需要跨章节交叉 | 弱,单点查证为主 |
| 可解释性要求 | 需要精确引用原文 | 引用粒度要求不高 |
| 成本敏感度 | 有缓存可用,可接受 | 极度敏感,按次付费 |
最务实的组合是:用检索把候选范围从百万级缩到几十万级,再把这几十万 token 全量喂进去做精读。既避免了在百万级知识库里硬扫,又绕开了切片导致的上下文割裂。
3. 我的落地套路:把 100 万 token 用出价值的三层结构
光有窗口不够,你得有一套组织材料的方法。我目前的套路分三层,从提示词骨架到材料编排再到自校验,基本能覆盖八成的长上下文场景。
3.1 第一层:稳定前缀 + 变动后缀的提示词骨架
前面讲了缓存的原理,这里给具体的骨架顺序。我的习惯是分成五个区块,用明确的标签隔开,顺序固定死:
第一个区块是角色和输出约束,写清楚你希望它扮演什么、输出什么格式、哪些事情不许做。这个区块几乎永远不变,是缓存的主要收益来源。第二个区块是工具定义和字段说明,如果涉及结构化输出,JSON schema 或者字段清单放这里。第三个区块是固定资料区,也就是那份几十万 token 的大材料,用统一的分隔标签包起来。第四个区块是任务描述,说明这次要干什么。第五个区块是本轮的实时输入,比如新的问题、新的日志、新的用户消息。
这套顺序的核心价值是可预测。你团队里每个人写提示词都按这个骨架来,缓存命中率就是可控的,不会因为某个人的随手发挥把整个链路的成本翻倍。
3.2 第二层:给长材料装"目录"和"坐标"
一份 50 万 token 的材料,如果不做任何标记直接怼进去,模型在里面找东西基本靠运气。我做的第一件事是给它装坐标——每个章节前面打上显式编号,材料的开头放一份索引,列出章节编号、标题、大致内容、以及关键的表格和图表位置。
索引本身只占几千 token,但它给模型提供了一个"先看目录再定位"的路径,而不是靠注意力在整个序列上平铺扫描。实测下来,带索引的版本在细节召回上比不带索引的版本好出一截,尤其是问"哪一章提到了某个东西"这类定位型问题时,差距非常明显。
坐标之外还有一个小技巧:把最关键的结论或约束,在材料的开头和结尾各复述一遍。这利用了首尾位置注意力更强的特性,成本只是多几百 token。
3.3 第三层:强制引用与二次校验
开放式问答最怕的不是答不出,是答得像真的但其实错了。我的做法是强制模型输出引用坐标:每一条结论后面必须标注来源的章节编号或者原文片段,标不出坐标的结论直接视为不可信。
进一步的做法是二段式:第一次调用只让它做"证据收集",输出它认为相关的原文片段和坐标,不给结论;第二次调用基于这些片段做推理和总结。这样模型被迫先看原文再下判断,编造的空间小很多。多花一次调用的钱,换来的是可用性,在需要交付给业务方的场景里这笔钱花得值。
3.4 一份可以直接改的提示词模板
下面这个骨架我用了挺久,你把方括号里的内容替换掉就行。标签用的是普通尖括号风格,不要用花哨格式,模型对简洁的结构化标签识别更可靠。
<role> 你是[角色定位]。只基于<corpus>中的内容回答,不使用外部知识。 无法在材料中找到依据时,明确输出「材料未覆盖」,不要推测。 </role> <output_format> 每条结论格式:[结论] —— 依据:[章节编号]「原文摘录不超过30字」 最后附一段<uncertain>,列出你把握不足的点。 </output_format> <corpus> <index> [D1] 第1章 概述 —— 涉及范围界定、术语表 [D2] 第2章 架构 —— 涉及分层设计、依赖关系 [D3] 第3章 接口 —— 涉及字段定义、错误码 ...(把全部章节索引列完) </index> [D1] 第1章 概述 (原文……) [D2] 第2章 架构 (原文……) </corpus> <task> [本次要解决的问题,一到三句话,越具体越好] </task> <input> [本轮新增的实时信息,没有就留空] </input>这个模板有三个地方值得注意。索引放在 corpus 内部而不是外部,是为了让整块 corpus 保持字节级不变,方便缓存。output_format 放在 corpus 前面,同样是缓存考虑——格式约束基本不变,放前面能吃到复用。uncertain 区块是刻意留的,它给了模型一个"承认不确定"的出口,比逼它给确定答案要安全得多。
4. 场景实操:四个用法拆开讲
理论讲完,落到具体场景。这四个场景是我这边跑得比较多的,每一个我都写了流程和坑。
4.1 整仓库代码理解与跨文件改造
流程分四步。第一步,先只喂文件树和每个文件的头注释、导出符号,生成一份"仓库地图",这一步只用几万 token。第二步,基于地图选择需要精读的文件,把这些文件的完整内容连同它们的直接依赖一起喂进去,做架构问答或者缺陷定位。第三步,让模型输出改造方案,明确列出要改哪些文件、每个文件改什么、影响面在哪。第四步,逐个文件生成补丁,每个补丁单独一次调用,只喂那个文件和它的调用方。
这个流程的关键在于不要把"读代码"和"改代码"混在一次调用里。让模型一次性输出十个文件的完整改造代码,出错率高得离谱,而且你没法校验。分步走,每一步的输入输出都可控。
坑在哪?坑在依赖关系。你按文件路径挑出来的"相关文件",经常漏掉通过反射、配置注入、动态路由建立的隐式依赖。我的补救办法是让模型自己指出"这个改动可能影响哪些模块",把它列的清单和你的清单求并集,再人工过一遍。这一步花十分钟,能省掉后面两小时的调试。
4.2 长文档交叉比对:合同、规范、多版本对照
这类任务有个天然优势——材料是静态的,特别适合缓存。一份三十万 token 的规范文档,你可以在一天内问它几十个问题,只有第一次付全价,后面都是缓存读取。
我的做法是把两份待比对材料交替编号,A 文档用 [A1][A2] 标注条款,B 文档用 [B1][B2] 标注,然后要求模型输出对照表,每一行是"A 的第几条款、B 的对应条款、差异点、风险等级"。表格形式比段落形式好校验得多,业务方扫一眼就能定位问题。
坑在条款编号的混淆。两份文档的编号体系经常不一样,一个是 3.2.1,另一个是 三(2)(a),模型很容易张冠李戴。我的对策是在索引里把两套编号的映射关系先列出来,明确告诉它"A 的 3.2.1 对应 B 的 三(2)(a)"。这个映射要人工先做一遍,工作量不大,但能消掉一大半的错误引用。
4.3 长会话智能体的记忆管理
智能体跑久了,历史消息会撑爆窗口。全量保留不现实,粗暴截断又会丢掉关键约束。我现在的做法是三层记忆:
第一层是锚点层,永远保留在最前面,包含系统指令、用户的核心目标、关键约束条件。这一层几乎不变,是缓存的锚。第二层是摘要层,每聊 N 轮就把前面的对话压缩成一段结构化摘要,包含已确认的事实、已排除的方案、待办事项。第三层是原始层,保留最近若干轮的完整对话,保证短期连贯性。
压缩的触发时机很关键。我的经验是不要等窗口快满了才压缩,那时候压缩本身就要吃掉大量 token。按轮数或者按 token 增量触发更可控,比如每累积 5 万 token 就压缩一次。
坑在压缩的有损性。摘要会丢掉细节,而某些细节后面可能突然变得重要。我的补救是让摘要层保留"原始对话的轮次索引",真需要回溯时,可以按索引把某一轮原文单独捞回来。
4.4 长音频和会议记录的全量处理
一小时的会议转写大概一万多 token,一百小时的系列会议刚好在一百万量级。这类任务的价值在于跨会议的主题追踪——"上个季度讨论过的那个方案,后来为什么搁置了",这种问题只有全量喂进去才答得准。
我的流程是:转写稿先做说话人分离和时间戳标注,然后按议题切段,每段生成一个短摘要,把摘要汇总成一份全局议程,最后把全局议程和原始转写一起喂进去做问答。全局议程相当于前面说的索引,占不了多少 token,但让模型有了导航。
坑在错误的累积。转写本身有错字,说话人分离也会出错,这些错误在分层摘要的过程中会被放大。我的做法是涉及具体数字、人名、时间节点的问题,一律要求模型回到原文片段核对,不接受摘要层的答案。
5. 成本与性能的精算:别让账单教你做人
这一节可能是最容易被忽略但最致命的。长上下文用起来爽,账单涨起来也快。
5.1 一次调用到底花多少钱
成本的基本公式不复杂:
单次成本 = 未命中缓存的输入token / 1e6 × 输入单价 + 命中缓存的输入token / 1e6 × 缓存读取单价 + 缓存写入token / 1e6 × 缓存写入单价 + 输出token / 1e6 × 输出单价关键变量是缓存命中率。假设你的场景是八十万 token 的固定材料加两千 token 的提问,输入单价按每百万 token 十几美元这个量级代入(具体数字以你使用时的官方价目为准,我这里只做结构性演示):
| 场景 | 未命中部分 | 命中部分 | 相对成本 |
|---|---|---|---|
| 首次调用(全部写入) | 80 万 | 0 | 1.0 倍基准(含写入溢价) |
| 后续调用(全部命中) | 0.2 万 | 80 万 | 约 0.1 ~ 0.15 倍 |
| 缓存失效(前缀被改动) | 80 万 | 0 | 回落到 1.0 倍 |
看第三行。这意味着你团队里任何一个人在前缀里加了一句"当前时间",整条链路的成本就会回到原点。所以缓存命中率不是优化项,它是必须监控的核心指标。我建议在调用日志里把命中 token 数、未命中 token 数、缓存写入 token 数三个字段都记下来,做成日报,异常波动能立刻发现。
5.2 提升缓存命中率的三个实招
第一个是把动态内容彻底后置。时间戳、请求 ID、随机盐、当前用户信息,全部挪到提示词的最后一段。如果某个动态信息确实是系统指令的一部分,考虑把它做成"占位符 + 末尾注入"的形式。
第二个是固定材料的字节级一致。文档列表的排序要固定,不要用文件系统的遍历顺序;JSON 序列化要固定键序和缩进;不要在材料里嵌入"本次共加载 N 个文件"这类计数。这些细节听起来琐碎,但每一个都能让缓存全废。
第三个是控制缓存的续期节奏。缓存通常有存活时间,如果你的调用频率低于存活窗口,缓存会过期,下次又要重新写入。这时候要么提高调用频率批量化处理,要么接受重新写入的成本。批量化往往更划算——把一天内要问的几十个问题攒起来连续跑,比分散在全天更省。
5.3 延迟预期要现实一点
长上下文的首次响应时间,跟你塞进去的量是正相关的,而且不是线性。八十万 token 的首字延迟,做好等半分钟以上的心理准备。命中缓存后能快不少,但也不可能跟短上下文一样。
这个特性决定了交互形态。需要实时响应的场景,比如对话式客服,不适合用全量长上下文,该走检索还是走检索。长上下文适合的是批处理型任务:夜间跑的代码审查、定时执行的文档核对、离线的会议纪要生成。把这些任务从同步接口改成异步任务队列,用户体验和成本都会好很多。
6. 踩坑记录与排查速查表
下面这些是我实际撞过的,按现象整理成表,方便你对号入座。
6.1 典型故障现象与定位路径
| 现象 | 高概率原因 | 排查动作 |
|---|---|---|
| 回答完全忽略后半段材料 | 有效上下文不足,中间遗忘 | 把关键内容挪到首尾,或分两次调用 |
| 引用编号对不上原文 | 索引与正文编号不一致 | 检查索引生成逻辑,做编号唯一性校验 |
| 账单突然翻十倍 | 前缀被动态内容污染 | 对比两次请求的前缀哈希,定位差异位置 |
| 第二次追问开始答非所问 | 历史累积挤压了材料空间 | 统计实际 token 分布,做历史压缩 |
| 响应超时或直接失败 | 单次请求体过大 | 拆分任务,或改异步批处理 |
| 同一问题两次答案差异很大 | 材料中存在矛盾信息 | 让模型先列出矛盾点,再指定以哪份为准 |
这张表里最值得展开的是第二行。引用编号对不上,根源往往是索引和正文分开生成,中间出了偏差。我的解法是索引和正文用同一份数据结构渲染出来,保证一一对应,渲染完再做一次自动比对,编号不匹配直接报错,不要让请求发出去。
6.2 上下文污染与锚定效应
长上下文有个隐蔽的问题:材料里的错误信息,会被模型当成事实沿用,而且越往后越难纠正。你在一份长文档里放了一条过时的参数,模型后面所有基于这个参数的推算都是错的,但它看起来非常自信。
更麻烦的是锚定。一旦模型在第一轮回答了"这个模块依赖 A 服务",后面几轮它都会围绕这个判断展开,哪怕你后来补了新材料说依赖已经改成 B,它也可能只是把 B 当成补充,而不是推翻前面的判断。
我的应对是显式推翻指令:在新一轮里明确写"以下内容与之前的判断冲突,以本轮材料为准,请重新评估并指出之前判断错在哪"。这句话很有效,它给了模型一个推翻前文的许可,而不是让它自己纠结。
6.3 半天能搭完的最小评测集
不要凭感觉判断长上下文好不好用。花半天时间搭一个小评测集,收益远超你的投入。
我的做法是从真实材料里挑三十到五十个问题,分三类各占三分之一。第一类是单点定位题,问某个具体参数、某个条款原文,考的是召回。第二类是多跳推理题,答案需要跨三个以上章节拼出来,考的是整合。第三类是拒答题,问材料里根本没有的内容,考的是不编造。前两类看准确率,第三类看拒答率,拒答率低于八成就要警惕了。
跑评测的时候把材料按不同位置摆放各测一遍,开头、中间、结尾,你就能得到自己这份材料的"位置衰减曲线"。这个曲线比任何公开榜单都有参考价值,因为它对应的是你的真实数据。
7. 几条我在实际使用中攒下的体会
用到现在,我最大的感受是,长上下文真正的门槛不在模型,在你怎么组织材料。同样是一百万 token 的窗口,有人用它一次问出十个准确结论,有人塞满了却得到一堆似是而非的段落,差距全在索引、坐标、引用这三件事上。
第二个体会是关于成本的。别等到月底看账单才发现问题,第一天就把命中率埋进日志。我见过太多团队在测试环境跑得欢,切到生产一周后被迫回滚,原因不是效果差,是预算撑不住。
第三个是心态上的。长上下文不是"检索的替代品",它是"精读层"。检索负责把范围缩小,长上下文负责把缩小后的范围读透。把这两件事混为一谈,要么成本失控,要么准确率上不去。至于那一百万 token 的上限,我建议你永远只用一半多一点,剩下的留给输出、留给追问、留给你自己犯错的空间。窗口是拿来用的,不是拿来填满的。