大模型的 Token 到底怎么算一篇讲清上个月我的 Agent 已经能跑通 demo上线后账单直接翻了 5 倍。查下来问题很朴素——他每次都把完整对话历史无脑塞回去平均单次请求带 4 万多 token。我在想「我也不知道为什么这么贵代码就是照着教程写的。」这就是我想写这篇的原因。做 AI Agent 开发大模型教程能带你跑通 demo但决定你成本和稳定性的永远是那 4 个底层概念。我们把它们一次讲透。一、Token计费的真实单位先说最反直觉的一点你花钱买的不是字数是 token。token 是分词器把文本切出来的片段。它不等于一个字也不等于一个词。我用tiktokenOpenAI 的公开分词库实测了一组数据类型样本字符数token 数每字成本中文大模型的上下文窗口不是越大越好15181.20英文The context window of an LLM is not always better49110.22代码def cosine_similarity(a, b): return a b41110.27看第三行和第一行的差距中文每字要 1.2 个 token英文只要 0.22。同样 200 个词英文 201 token中文 600 token差了近 3 倍。再看更狠的。「上下文窗口」这 5 个字被切成了 6 个 token上 - b\xe4\xb8\x8a 下 - b\xe4\xb8\x8b 文 - b\xe6\x96\x87 - b\xe7\xaa ← 碎片 - b\x97 ← 碎片 口 - b\xe5\x8f\xa3窗这个字被劈成了两个半截 token。为什么因为分词器用的是字节级 BPE一个汉字在 UTF-8 里占 3 个字节词表里没有「窗」这个完整条目就只能拆。这件事的实际影响**你的 Prompt 越「口语化」、越堆大白话token 越贵。**给文档做摘要、抽取、分类时写精简的指令词比写长句子更省钱。二、温度与采样输出不是模型说了算很多人以为大模型的输出是确定的——同样的输入输出必然一样。这是幻觉之外的第二个幻觉。模型内部给每个候选 token 打一个分数叫 logits然后按概率抽样。temperature这个参数就是把 logits 除以一个系数T 1分布变尖锐更倾向于选最高分输出更稳T 0退化成贪心永远选最高分完全确定T 1分布变平输出更多样但更容易跑偏我写了一段不调 API 的演示直接拿一个手写概率分布看效果importmath,randomfromcollectionsimportCounterdefsoftmax(logits):数值稳定的 softmax先减最大值避免 exp 溢出mmax(logits)exps[math.exp(x-m)forxinlogits]ssum(exps)return[e/sforeinexps]deftemperature_scale(logits,temperature):温度就是给 logits 除一个系数不改别的return[x/temperatureforxinlogits]defsample(probs,rng):按累积概率抽一个下标rrng.random()acc0.0fori,pinenumerate(probs):accpifracc:returnireturnlen(probs)-1tokens[北京,上海,广州,深圳,杭州,南京]base_logits[3.0,2.4,1.2,1.1,0.4,0.3]# 假装是模型内部算出的分数forTin(0.0,0.5,1.0,2.0):ifT0.0:probs[1.0ifi0else0.0foriinrange(len(tokens))]else:probssoftmax(temperature_scale(base_logits,T))# 关键rng 必须放在循环外创建。# 若写成 sample(probs, random.Random(42)) 嵌在推导式里# 每轮都会新建一个同种子的 rng抽出来的永远是同一个数概率全失真。rngrandom.Random(42)countsCounter(sample(probs,rng)for_inrange(2000))pct[counts.get(i,0)/20foriinrange(len(tokens))]print(fT{T}: .join(f{t}:{p:.1f}%fort,pinzip(tokens,pct)))实测 2000 次采样的结果T0.0: 北京:100.0% 上海:0.0% ...完全确定 T0.5: 北京:73.3% 上海:22.1% 广州:2.0% ... T1.0: 北京:48.4% 上海:29.2% 广州:8.3% ... T2.0: 北京:32.1% 上海:24.1% 广州:13.6% 深圳:13.1% 杭州:8.8% 南京:8.3%规律很清楚T 越低越集中T 越高越分散。top_p核采样是另一个正交的旋钮它不管分布形状只做截断——按概率从大到小累加保留刚好到 p 的最小集合其余直接置零deftop_p_filter(probs,p):idxsorted(range(len(probs)),keylambdai:-probs[i])kept,cum[],0.0foriinidx:ifcump:breakkept.append(i)cumprobs[i]out[0.0]*len(probs)foriinkept:out[i]probs[i]ssum(out)return[v/sforvinout]ifs0elseout# 截断后必须重新归一化实测top_p0.3只留北京0.6留北京上海0.9留四个。上面那句「重新归一化」很关键漏掉它总概率不足 1很多采样器会直接报错。实践建议做信息抽取、分类、格式转换这类要可复现的任务温度给 0做文案、起名、头脑风暴温度往上调。评测场景尤其必须锁 0否则你永远测不出模型改进没有。三、上下文窗口别把预算全花在历史上下文窗口是模型一次能看进去的 token 总量。这个数字现在动辄 128K、200K但窗口大不等于塞满就好。我算过一笔账假设窗口 128K系统提示词 800 token █ 工具定义 3,000 token █ RAG 召回 12,000 token ███ 历史对话 40,000 token ████████████ 输出预留 4,000 token █ 合计 55,800 / 128,000剩余 68,200 ✓这里暴露了那个读者的典型问题历史对话吃掉 40K占了窗口的 31%而真正需要模型回答的信息可能只有最后两轮。除了贵更麻烦的是准。塞满窗口会触发「注意力稀释」——信息越杂模型对关键指令的遵循度越差。你会看到一个很迷惑的现象把知识库全塞进去答案反而不如只塞 5 条准。知识库 B5 记忆系统那篇给了几个可直接用的经验值top_k3–8 条超过 8 条模型会忽略其中大部分相似度阈值 0.30–0.40低于阈值就不注入省 token 也减少干扰注入预算≤ context 的 10%128K 窗口对应约 12.8K token还有一条我特别想强调召回后要按「最近更新」再排一次序。否则三条互相冲突的旧记忆会一起挤进 top-3模型只能随机采信一个——这是幻觉的常见来源之一而且极难排查。四、KV Cache延迟从哪来前三个概念管成本这个管延迟。LLM 是自回归生成的一次吐一个 token每吐一个都要把前面的全看一遍。如果每次都从头算生成 n 个 token 就是 O(n²)。KV Cache 的做法是把已经算过的 Key/Value 缓存下来用空间换时间把 O(n²) 压到 O(n)。这就是为什么同样一个 Prompt首 token 延迟TTFT慢 → 瓶颈在「读进去」也就是 prefill 阶段后续每个 token 都慢→ 瓶颈在显存带宽或缓存没命中但 KV Cache 是把双刃剑。知识库 B2_05 那篇讲得很直接它既是加速的关键也是显存的主要占用者直接限制了你能开多大窗口、能并发多少请求。这也是我上面说「窗口大不等于该塞满」的底层原因。调试时的实用做法缩短输入 → 看 TTFT 是否下降能判断是不是 prefill 瓶颈固定相同前缀如系统提示词→ 提高缓存命中率用流式输出 → 体感延迟大幅改善用户不等全部生成完五、常见坑清单坑 1用字符数估算成本—— 表现账单比预期高 2-3 倍中文场景尤其明显。解法上线前用len(enc.encode(text))实测别用len(text)。坑 2评测时没锁温度—— 表现同一模型两次跑分差好几个点你以为模型有提升其实是随机波动。解法temperature0且固定测试集版本。坑 3只调 temperature 不调 top_p—— 表现调低温度后长尾内容里出现莫名其妙的话。解法两个一起调top_p管截断长尾。坑 4无脑全量塞历史—— 表现Agent 多轮对话后变慢变贵答案质量还下降。解法历史做摘要 只保留最近 N 轮原文。坑 5截断后忘重新归一化—— 表现top_p截断后采样器抛异常或概率和不足 1。解法截断后除以剩余概率和。六、小结Token 是计费单位中文比英文贵 3 倍。学的时候写 Prompt 尽量精简中文长文先做切片再送。温度决定输出的随机性。要可复现就锁 0要创意就往上调。这条在做评测时是及格线。上下文窗口要有预算思维。历史摘要 RAG 只取 top 3-8 条别拿窗口当仓库。KV Cache 决定延迟。首 token 慢看输入长度逐 token 慢看显存和缓存命中。各个厂商的Credits计费不固定Credits 没有固定的 Token 换算比例1 个 Credits 不等于固定数量的 Token。Credits 是按模型分档抵扣系数动态计费的单次消耗由模型类型、Token 用量、思考模式及工具调用等因素共同决定。有可能是 1 Credits 1 Token / 倍率如 x0.09等