前置课 · 第一部分 LLM · L2

Token、上下文窗口与成本:大脑的物理约束

20 min · 一切工程妥协(压缩、检索、按需加载)的起点都在这一课

🎒 预备知识:完成上一课「L1」(零基础入口:第 0 课)

本课唯一结论:LLM 的世界用 token 计量一切——窗口是容量、token 是货币。 读懂三件事就能解释 agent 的一半设计:tokenizer 怎么切、窗口怎么分、账单怎么算。

一、tokenizer:模型眼中的文字

模型不读"字",读 token——tokenizer(主流是 BPE(字节对编码)类算法)把文本切成高频子串碎片。 手感数字(做预算必备):

英文:1 token ≈ 4 个字符 ≈ 0.75 个单词("internationalization" 可能占 5-6 个 token)
中文:常用字多为一字 1 token,生僻词/专业词 1 字 2-3 token
代码:缩进和符号很贵——Python 代码平均比同义英文贵 20-50%
经验换算:1000 个汉字 ≈ 1300-1800 token

两个直接影响工程的事实:① 模型"数不清"字符——它看到的是碎片不是字, 让它"限制在 200 字以内"或"提取前 12 个字符"天然不可靠,字数校验要用代码做 (Easel 的 wordcount.py 就是这个原因存在);② 中文比英文贵——同样内容, 中文 prompt 成本常高出 30–80%。

二、窗口的三段分配(溢出前发生了什么)

┌──────────────── 上下文窗口(如 128K)────────────────┐
│ system + 工具定义        常驻区,每轮都在                  │
│ 对话历史                 增长区,随轮数变大                │
│ 本轮新内容 + 模型输出    工作区,必须预留                  │
└──────────────────────────────────────────────────┘

关键认知:输出也占窗口。max_tokens 设太低,JSON 生成到一半被截断—— 这是结构化输出莫名解析失败的常见根因。窗口满了有两种表现:provider 直接报错(好的情况), 或静默截断开头(坏的情况——system prompt 被切掉,agent 行为突变且无报错)。 所以永远留输出预留(Easel 的 compaction reserve 16384 就是这个思想,正课 L18)。

三、账单怎么算:长对话的复利

API 按 token 计费,两个要点:输出价通常是输入价的 2–5 倍; 每轮输入 = 全部历史重发(L1 的无状态)。于是 10 轮对话的输入成本是复利曲线:

每轮新增 1000 token(含工具结果),10 轮累计输入成本:
轮1 输入 1K + 轮2 输入 2K + … + 轮10 输入 10K = 累计 55K
第 20 轮时单轮输入已 20K——是第一轮的 20 倍
省钱开关:prompt cache 命中部分约 1/10 价(各家略有差异)

这就是 A5(上下文工程)四原则的经济学根源:稳定前缀为缓存、渐进披露为省输入、 压缩历史为斩复利。KV cache 与 prompt cache 的区别顺带说清: KV cache 是推理引擎层对重复计算的消除(微秒级提速),prompt cache 是它在计费层的产品化—— 工程上你只需要管"前缀稳定"这一件事,两个都会来。

四、常见踩坑

坑 1:不看 usage 字段。响应里的 usage(prompt/completion tokens)是唯一的真实账本, 估算和真实常差 30%。上线第一天就该把 usage 记进日志(也是 A11 可观测的素材)。

坑 2:长对话不设熔断。没有轮数/成本上限的会话,成本曲线后期失控—— 和 A3 铁律③同源:预算是工程问题,不是模型问题。

坑 3:让模型数字数。任何精确计数(字数、列表第 N 项、前 X 字符)交给代码做。 模型给的是"大概",契约要的是"精确"。

五、检索练习

六、出口检验

算一笔账:一个 agent,system 800 token、8 个工具定义共 1200、每轮工具结果 1500、 输出平均 800。第 6 轮结束时累计输入 token 是多少?如果第 4 轮起做了"历史摘要压缩到 1000"呢? (按第三节复利示例的口径:累计=各轮输入之和。答案发到对话里,我核对你的算式。)