
1. 那句“继续”到底触发了什么从一次账单异常说起很多人第一次注意到这个问题都是在月底对账的时候。明明感觉自己没写多少东西账单却比预估高出一大截。我一开始也以为是单价算错了或者中转站的倍率有问题换了三四家之后发现账单结构惊人地一致——问题不在平台而在我们自己的使用习惯里。具体场景是这样的你和模型来回对话了十几轮上下文已经堆到几万 token这时候你敲了一句“继续”或者“接着上面那个思路往下写”。在人的直觉里这是一句极短的话应该很便宜。但在计费系统眼里这句话携带的是整个对话历史一起重新进入模型。也就是说你为这一句“继续”付出的钱等于把前面几万 token 的上下文又完整地“读”了一遍。这就是标题里说的“最容易算漏的钱”。它不是隐藏收费也不是平台套路而是大模型按输入 token 计费的机制决定的。你每发一次请求模型都要把当前完整的上下文窗口重新处理一遍历史对话不会因为你“已经说过了”就免费。理解这一点是从“凭感觉用”到“算得清账”的分水岭。这篇文章适合三类人一是刚开始用 Codex 这类命令行/API 工具、对 token 计费还没概念的新手二是已经用了一段时间、但账单总是对不上的中级用户三是想从工程角度优化成本、把上下文管理做成一套方法的人。我会把上下文、缓存命中率、输入计费这几个关键词串起来讲清楚并且给出可以直接抄的操作方法。先说结论方便你带着问题往下看省钱的核心不是少说话而是管好上下文。一句“继续”贵不贵取决于它前面挂着多长的历史。把历史控制住同样的“继续”可以便宜十倍甚至更多。2. 输入计费的底层逻辑为什么历史对话每次都要重新付费2.1 大模型没有“记忆”只有“每次重读”要理解账单先要理解模型是怎么工作的。大模型本身是无状态的它不像数据库那样把你说过的话存起来。每一次请求你都要把“到目前为止的全部对话”作为输入发给它它基于这份完整输入生成回复。下一轮你再把“全部对话 它的回复 你的新话”一起发过去。打个生活化的比方模型像一个每次都要你把整本书重新递给他的读者。你问“第三章讲了啥”他得先把第一、二、三章都读一遍才能回答。你下一句问“那第四章呢”他不会记得第三章你得把整本书再递一次。所谓“上下文窗口”就是这一次他最多能读多少页。所以当你敲下“继续”的时候系统实际发送的内容是系统提示词 前面所有轮次的用户消息 前面所有轮次的模型回复 这次的“继续”。计费按这份完整输入的总 token 数算。前面堆得越多这一句“继续”就越贵。2.2 输入 token 和输出 token 的价差大多数平台的定价里输入 token 和输出 token 是两个价格通常输出更贵。这容易让人产生一个错觉只要我少让它输出就省钱。但实际上在长对话场景里输入 token 才是那个悄悄膨胀的大头。举个具体的账假设一段对话历史累积到 30000 token你发一句“继续”模型输出 500 token。按常见的定价比例输入约为输出的三分之一到五分之一这一轮的成本里输入部分可能占到总成本的 80% 以上。你以为你只花了 500 token 的钱实际上你花了 30500 token 的输入 500 token 的输出。更关键的是这个 30000 的历史在下一轮还会变成 30500再下一轮变成 31000……它是滚雪球式增长的。每一轮你都在为全部历史付费而不是只为新增部分付费。这就是为什么长对话的边际成本会越来越高。2.3 上下文窗口用完之前成本先失控很多人担心的是“上下文窗口用完了怎么办”但真正的风险是在窗口用完之前你的单轮成本已经涨到离谱。一个 128K 窗口的模型如果对话堆到 10 万 token你每发一句话哪怕只有一个字都要为这 10 万 token 的输入买单。我实测过一个典型场景连续让模型改一段代码来回 20 轮每轮它输出几百 token我也就回几个字。最后统计发现总输入 token 是总输出 token 的 40 倍以上。账单里绝大部分钱花在了“重复发送历史”上而不是花在模型真正生成的内容上。提示判断自己是否踩了这个坑最简单的办法是看账单里输入 token 和输出 token 的比例。如果输入是输出的 20 倍以上说明你的上下文管理有优化空间。3. 缓存命中率被大多数人忽略的省钱杠杆3.1 缓存到底缓存了什么既然历史每次都要重发那有没有办法让平台“记住”这部分、少收点钱有这就是缓存命中机制。它的原理是如果你这次请求的前缀通常是系统提示词 前面若干轮对话和上一次请求完全一致平台可以复用上次已经计算过的中间结果这部分命中的 token 按更低的费率计费通常是正常输入价的十分之一甚至更低。注意关键词是“前缀完全一致”。缓存是从头开始逐 token 比对的一旦中间有一个字符不同从那个位置往后就全部算未命中。这就像两个人对暗号从第一句开始对对到哪句不一样后面的就都不算了。3.2 为什么“继续”常常打不中缓存回到“继续”这个场景。理想情况下你上一轮的完整上下文这一轮应该能命中缓存因为你只是在前缀后面追加了一句“继续”。但实际中经常打不中原因有几个系统提示词不稳定有些工具每次请求会带上时间戳、随机 ID、动态拼接的指令导致前缀每次都变缓存直接失效。上下文被重排某些客户端会把历史消息重新排序或者插入新的系统消息破坏了前缀连续性。工具调用结果变化如果中间夹着工具调用比如读文件、执行命令返回结果每次不同也会打断缓存。跨会话不共享缓存通常有有效期几分钟到几小时隔太久再发缓存已经过期。我踩过最典型的一个坑某个客户端每次请求都会在系统提示词里插入当前时间。结果就是缓存命中率长期接近 0每一轮都在按全价重算历史。后来把时间戳去掉命中率立刻上来了账单肉眼可见地降了一截。3.3 提高命中率的几个实操动作想把缓存命中率拉起来核心思路是让前缀尽可能稳定、尽可能长。具体可以这样做固定系统提示词把所有不变的内容角色设定、规则、示例放在最前面确保每次逐字一致。不要在里面塞时间、随机数、会话 ID。把变化的内容往后放用户的新输入、动态数据放在最后。前缀越稳定能命中的部分越多。避免频繁切换模型或参数不同模型、不同温度参数的缓存通常不互通来回切会不断打断缓存。控制会话间隔如果缓存有效期是 5 分钟而你每隔 10 分钟才发一句那基本每次都从头算。密集操作时命中率天然更高。减少工具调用的抖动工具返回结果如果包含时间戳、随机内容尽量在拼接进上下文前做归一化处理。下面这张表可以帮你快速判断自己的缓存状况现象可能原因优化方向命中率长期低于 20%系统提示词含动态内容移除时间戳、随机 ID命中率忽高忽低会话间隔不稳定集中操作缩短间隔切换模型后命中率归零缓存不跨模型固定主力模型工具调用后命中率骤降工具结果每次不同归一化工具输出注意缓存命中率不是所有平台都会在账单里明确展示。如果看不到可以通过对比“同样长度的请求费用是否明显低于首次”来间接判断。4. 上下文工程把“继续”变成可控成本4.1 上下文不是越长越好很多人有个误区觉得上下文给得越多模型越“懂我”。实际上超长上下文不仅贵还可能让模型注意力分散回答质量反而下降。真正有效的做法是只保留和当前任务相关的上下文把无关的历史清掉。这就像你找同事帮忙不需要把过去一个月所有聊天记录都翻给他看只要把当前这个问题相关的背景说清楚就行。上下文工程的核心就是判断“哪些信息对当前这一步是必要的”。4.2 三种实用的上下文压缩策略策略一摘要替换原文。当对话进行到一定轮次把前面的详细历史用一段摘要代替。比如把 20 轮讨论压缩成 300 字的要点后续对话基于摘要继续。这样既保留了关键信息又把 token 数砍掉一大截。策略二分段开新会话。一个任务做完果断开新会话不要在一个超长会话里连续做多件事。每开一个新会话上下文从零开始成本回到最低。很多人舍不得关会话觉得“万一还要回头查”结果就是一直背着沉重的历史包袱。策略三按需检索而非全量携带。如果确实需要历史信息不要全塞进上下文而是把它存在外部文件、数据库需要时再检索相关片段拼进去。这就是常说的 RAG 思路用在个人工作流里同样有效。4.3 一个可复制的上下文管理流程我现在的习惯是这样你可以直接参考任务开始前明确这次要解决什么只带必要的背景进上下文。进行中每 5 到 8 轮检查一次如果发现历史已经很长且前面内容不再需要主动做一次摘要压缩。任务切换时立刻开新会话不复用旧上下文。需要长期记忆的内容写到本地文件里下次用时手动引入而不是让它一直挂在上下文里。这套流程执行下来我的平均单轮输入 token 降了大概六成账单自然跟着降。更重要的是模型回答反而更聚焦了因为上下文里没有一堆无关噪音。5. 实测对比同一句“继续”成本能差多少5.1 实验设计为了把这件事说清楚我做了一组对照测试。同样的任务让模型帮我完善一段技术文档。分两种方式方式 A放任式一个会话从头做到尾不做任何压缩每轮都带着完整历史。方式 B管理式每 6 轮做一次摘要压缩任务切换时开新会话系统提示词固定不变。两种方式完成的是同一份文档最终产出质量我人工核对过差异可以忽略。5.2 数据对比指标方式 A方式 B总轮次2424累计输入 token约 41 万约 13 万累计输出 token约 1.1 万约 1.1 万输入/输出比约 37:1约 12:1缓存命中率约 8%约 55%相对成本基准 100%约 32%方式 B 的成本只有方式 A 的三成左右产出几乎一样。差距主要来自两点一是压缩历史直接减少了输入量二是固定前缀让缓存命中率大幅提升。5.3 从数据里读出的三个结论第一成本差异主要来自输入不是输出。两种方式的输出 token 几乎一样但输入差了 3 倍多。这说明优化重点应该放在“怎么少发历史”上。第二缓存命中率是可以被工程手段影响的。方式 B 的命中率是方式 A 的近 7 倍这不是运气而是固定前缀、集中操作带来的必然结果。第三管理上下文不会牺牲质量。很多人担心压缩会丢信息但实测下来只要摘要抓准了关键点模型的表现没有明显下降。反而因为噪音少了回答更干净。6. 那些年我踩过的上下文坑6.1 坑一以为“继续”是免费的最开始我真心觉得“继续”就两个字能花几个钱。直到有一次连续用“继续”让模型写一篇长文写了十几轮最后账单出来吓一跳。后来才明白每一句“继续”都在为前面所有内容重新付费。这个认知转变花了我不少冤枉钱。6.2 坑二系统提示词里塞了动态内容有段时间我用一个自定义客户端它默认在系统提示词里加了当前日期和会话 ID。结果缓存命中率一直是 0我还纳闷为什么同样的操作比别人贵。排查了半天才发现是这个动态内容在作祟。去掉之后命中率立刻上来了。这个坑很隐蔽因为从界面上你根本看不出系统提示词里有什么。6.3 坑三舍不得关会话我曾经有一个会话开了整整两天中间做了七八件不相关的事。上下文堆到十几万 token每发一句话都肉疼。后来强迫自己养成“任务结束就关会话”的习惯成本立刻下来了。心理上那点“万一还要用”的不舍其实价值远低于它带来的成本。6.4 坑四忽略工具调用的上下文污染用带工具调用的工作流时工具返回的结果会进入上下文。如果这些结果里包含时间戳、随机 ID、每次都不同的状态信息就会不断打断缓存。我后来在拼接工具结果前做了一层清洗把动态字段去掉命中率稳定了不少。提示排查上下文成本问题建议按“系统提示词是否稳定 → 会话是否过长 → 工具输出是否抖动 → 缓存是否过期”的顺序逐一检查基本能覆盖九成以上的情况。7. 把成本意识变成日常习惯7.1 建立自己的成本监控不用等平台账单自己就可以粗略估算。每次请求前心里过一下“这次带了多少历史”。如果感觉历史已经很长就先压缩再发。养成这个反射比事后看账单有用得多。具体做法在客户端或脚本里记录每轮的输入 token 数画一条趋势线。正常应该是锯齿状压缩后下降然后缓慢上升如果是一条单调上升的直线说明你从来没做过压缩。7.2 给不同任务设定上下文预算我现在会给任务分类短任务改个函数、查个语法预算 5000 token 以内中等任务写一段文档、调试一个模块预算 2 万以内长任务完整项目才允许超过但必须配合定期压缩。有了预算超了就主动处理不会放任它膨胀。7.3 把“继续”用对地方“继续”本身没问题问题是在什么上下文里用它。如果前面只有几百 token随便用如果前面已经几万 token用之前先想想值不值。更好的做法是在需要“继续”时先做一次摘要然后用摘要 “继续”重新开始成本能降一个数量级。7.4 定期复盘账单结构每个月花十分钟看看账单里输入和输出的比例、缓存命中情况。这个习惯帮我发现过好几次异常比如某次工具升级后系统提示词变了导致命中率下降。账单不会说谎它是最诚实的反馈。说到底用大模型工具就像开车油门谁都会踩但真正省油的是那些懂得什么时候换挡、什么时候松油门的人。上下文就是那个油门管好它同样的路你能少烧一半的油。这些经验都是我一次次对账、一次次踩坑换来的希望你看完能少走点弯路。