Token 与上下文窗口
Token 计量、上下文窗口、成本估算,以及 Agent 系统中的压缩与预算策略。
上下文窗口是 Agent 系统最常碰到的硬约束。它不是“尽量多塞一点历史”,而是要在目标、证据、工具结果和推理链之间做预算分配。
Token 是什么
Token 是模型处理文本的最小单位,不等于“一个字”或“一个单词”。英文常按子词切分,中文通常一个字或一个词片段对应一个或多个 Token。同一段内容在不同模型、不同分词器下的 Token 数可能不同。
工程上应遵守三条规则:
- 不要凭直觉估长度,用 provider 的 tokenizer 或官方计数 API。
- 工具结果往往比用户输入更长,读文件、跑测试、抓网页都会快速吃掉预算。
- 系统提示、工具定义、历史消息都占窗口,不是只有用户说的话算 Token。
上下文窗口的分工
| 区域 | 典型内容 | 管理要点 |
|---|---|---|
| 系统层 | 角色、规则、安全边界、输出格式 | 保持稳定,避免频繁变动导致缓存失效 |
| 任务层 | 当前目标、约束、计划、待办 | 随任务阶段更新,必要时单独摘要 |
| 证据层 | 文件片段、检索结果、工具输出 | 截断、引用、分层加载,不要整包灌入 |
| 历史层 | 过往对话、决策、失败记录 | 压缩、选择性回放、结构化存档 |
| 预留层 | 模型回复和下一轮工具参数 | 为输出和 tool call 留出安全边际 |
《Claude Code Harness Engineering》指出,活跃编码 Agent 每轮可能消耗数千 Token,复杂重构会很快逼近上限,因此需要压缩、记忆和缓存协同工作。来源:《Claude Code Harness Engineering:从入门到实战》,pp. 88-95。
成本与性能
Token 同时影响钱和延迟:
- 输入 Token 越多,首 Token 延迟通常越高。
- 输出 Token 越多,总耗时和费用越高。
- 工具定义如果冗长且不稳定,会重复消耗预算并破坏提示缓存。
Agent 产品应至少记录:
- 每轮
input_tokens、output_tokens、cached_tokens(如果 provider 支持)。 - 工具调用前后的窗口占用变化。
- 压缩或截断发生时的触发原因。
常见预算策略
- 分层加载:先给目录、签名、摘要,确认需要后再读全文。
- 结果截断:工具输出设最大字符或最大 Token,保留头尾和错误信息。
- 摘要压缩:长会话折叠成结构化状态,而不是原文堆叠。
- 引用而非复制:用文件路径、行号、chunk id 指向证据,减少重复文本。
- 工具定义瘦身:描述清楚即可,避免把教程塞进 schema。
估算上下文预算
实际项目里不需要手算每个 token,但需要在设计阶段保留预算意识。一个简化估算方式是:
| 预算项 | 示例内容 | 设计建议 |
|---|---|---|
| 固定开销 | system prompt、developer instructions、工具 schema | 尽量稳定,避免每轮重复塞大段说明 |
| 会话状态 | 计划、已完成步骤、失败记录、用户偏好 | 用结构化摘要替代完整聊天历史 |
| 当前证据 | 文件片段、检索结果、日志、网页 | 按相关性分层加载,并保留来源定位 |
| 输出预留 | 模型回答、tool arguments、解释文本 | 任务开始前预留,不要把输入塞满 |
如果上下文窗口是 window,输入最好不要长期逼近 window。Agent 还需要为模型输出、工具调用参数、错误重试和压缩摘要留出空间。
压缩不是总结一段话
上下文压缩应该保留任务继续执行所需的状态,而不是把历史对话压成文学摘要。常见压缩结构可以是:
目标:
- 当前要完成的可验证结果。
已完成:
- 文件、命令、决策和证据链接。
未完成:
- 下一步动作、阻塞点、风险。
约束:
- 用户明确要求、禁止事项、格式要求。
可丢弃:
- 已经验证无关的尝试、重复日志、过长原文。这样压缩后的内容可以被下一轮 Agent 直接接手;单纯写“我们讨论了很多上下文工程问题”没有工程价值。
失败模式
| 现象 | 常见原因 | 系统层应对 |
|---|---|---|
| 模型“忘记”早期约束 | 窗口被历史挤占 | 把关键约束提升到系统层或任务摘要 |
| 工具结果丢失细节 | 过度截断 | 分级截断,保留错误栈和关键字段 |
| 成本突然飙升 | 大文件反复注入 | 去重、缓存读取结果、限制重试 |
| 回答变短或变敷衍 | 接近窗口上限 | 主动压缩或拆分子任务 |
可观测指标
生产系统至少要记录这些上下文指标:
input_tokens、output_tokens、cached_tokens和总费用。- 每个工具返回被截断前后的长度。
- 压缩触发时间、压缩前后 token 数、压缩摘要版本。
- 任务成功率与上下文占用的关系,尤其是长任务尾部失败。
- 因窗口不足导致的重试、降级、人工接管次数。
这些指标能帮助你判断问题是“模型不够强”,还是上下文装配策略把模型逼到了错误状态。
与 Agent 设计的关系
记忆不是“把所有东西塞进 prompt”。记忆是原材料,上下文工程是装配方式。详见 工具调用与记忆 和 上下文工程。
检查清单
- 是否给输出和工具参数预留了 token,而不是把输入填满。
- 是否对大文件、大日志和网页结果做了截断策略。
- 是否能从 trace 里看见哪一轮触发了压缩。
- 是否区分长期记忆、会话摘要和当前证据。
- 是否在成本异常时能定位到具体工具或上下文层。
延伸阅读
- 推理参数与提示词基础:控制输出长度和稳定性。
- Harness 工程构件:Session、压缩和可恢复执行。
- 可观测性与轨迹回放:记录 Token 与成本指标。
参考来源
- Claude Code Harness Engineering:pp. 88-95,长任务上下文、压缩和缓存策略。
- Demystifying Claude Code v1.8:pp. 154-180,上下文优化、延迟加载和工具结果截断。
- OpenAI Models documentation:模型上下文窗口和能力边界应以官方当前文档为准。