Token 与 Context Window:从计量单位到上下文预算
社区来稿 · batype由用户发布,不代表 batype 本人观点
结论#
Token 是大语言模型读取和生成文本时的基本处理单位;Context Window 是单次调用可容纳的 Token 总预算。
模型并不直接按“一个汉字”或“一个英文单词”来理解文本。它会先通过 tokenizer 将输入切分为 Token,再将这些 Token 转为可计算的编号。
在一次模型调用中,System Prompt、用户问题、历史会话、RAG 检索结果、工具调用结果,以及最终输出,都会消耗同一个上下文预算:
输入 Token + 输出 Token <= Context Window
因此,LLM 系统设计的关键不在于向模型塞入更多内容,而在于让模型在有限预算内获得最相关、最可信、最必要的信息。
Token 是什么#
Token 可以理解为模型处理语言时使用的“计量单位”,但它不严格等于:
- 一个汉字;
- 一个英文单词;
- 一个字符。
例如:
今天天气不错,Let's go!
这段文本不会简单按“每个汉字一个单位”或“每个英文单词一个单位”来处理,而会被 tokenizer 切成若干 Token。具体切分方式取决于模型使用的 tokenizer,因此同一段文本在不同模型中占用的 Token 数量可能不同。
代码、URL、JSON、表格、罕见术语等内容也可能被切得更碎。工程上不能只凭“字数”估算上下文消耗,应该以目标模型实际的 Token 统计为准。
Context Window 是什么#
Context Window,或称上下文窗口,是模型单次推理时能容纳的 Token 总量上限。
它不是纯粹的“输入长度上限”,因为输出同样占用上下文。一次请求的预算通常可拆成:
Context Window
= System Prompt
+ 用户当前问题
+ 历史会话
+ RAG 检索结果
+ 工具调用结果
+ 模型最终输出
例如,假设上下文窗口为 128K Token:
128K
- System Prompt:4K
- 历史会话:20K
- RAG 文档:50K
- 工具结果:10K
- 当前问题:1K
= 剩余约 43K
这部分剩余空间还需要覆盖模型输出,并留出必要余量。若请求中设置了较大的最大输出长度,也需要提前为输出预留预算。
为什么历史会话不能无限拼接#
长对话中,最直观的做法是每轮都携带全部历史消息。但历史会持续增长,最终会出现几个问题:
- 超过 Context Window,无法继续请求;
- 输入 Token 增多,成本和延迟上升;
- 早期无关信息干扰当前任务,回答质量下降;
- 重要信息被淹没在大量上下文中。
更合理的做法是分层保存会话信息:
- 保留最近若干轮原始消息,维持当前语境;
- 将较早历史压缩成摘要;
- 对用户偏好、已确认结论等长期信息做结构化存储;
- 当前任务需要时,再检索对应记忆。
摘要不是简单截断,而是保留后续对话仍有用的事实、约束、决定和未完成事项。
为什么 RAG 不是召回越多越好#
RAG 的目标是为当前问题补充外部知识,但“召回更多文档”并不必然提升效果。
过多、重复或低相关的片段会带来:
- 更高的 Token 消耗;
- 更长的生成延迟;
- 更高的调用成本;
- 信息噪声增加;
- 模型难以判断哪些内容真正可信、相关。
更合理的 RAG 流程通常是:
文档分块
→ 召回候选片段
→ 重排序或过滤
→ 控制片段数量与长度
→ 将高相关内容送入模型
重点不是“把知识库搬进 Prompt”,而是针对当前问题选择少量高质量证据。
工具返回为什么容易撑爆上下文#
Agent 或工具调用场景中,模型调用接口、数据库、搜索服务或业务系统后,工具结果通常会被再次放回上下文。
一个常见问题是工具返回完整原始 JSON:
{
"success": true,
"data": {
"user": {
"id": "u_123456",
"name": "张三",
"created_at": "2026-08-01T10:33:22Z"
}
},
"trace_id": "...",
"debug": "..."
}
字段名、嵌套结构、重复数据、调试信息和无关元数据都会消耗 Token。工具设计应尽量让返回内容面向模型任务,而不是直接复用给人或给程序的完整响应。
可行的优化包括:
- 只返回当前任务需要的字段;
- 限制列表返回数量;
- 移除调试字段、重复字段和无关元数据;
- 对长结果先在工具侧筛选或聚合;
- 必要时先返回摘要,再按需查询详情。
长文处理:分块、摘要与分层检索#
面对超长文档,直接整篇塞进 Prompt 往往既昂贵又不稳定。常见方案是:
1. 语义分块#
按标题、段落、语义边界或代码块切分文档,使每个块具有相对完整的含义。
分块太大,召回后浪费上下文;分块太小,语义容易断裂。实际系统通常还会保留标题、来源、章节位置等元数据,帮助检索和引用。
2. 分层摘要#
为段落、章节和整篇文档分别生成摘要。先用较短的高层摘要定位范围,再在需要时读取原文片段。
3. 分层检索#
先检索文档或章节,再检索具体片段;或先进行粗召回,再通过重排序筛出最相关内容。
这种方式比一次塞入大量文本更节省预算,也更容易保持回答聚焦。
工程上的预算意识#
Token 预算应当成为系统的显式约束,而不是请求失败后才处理的问题。
一个实用的预算分配可以是:
总窗口
- 固定 System Prompt
- 输出预留
- 当前用户输入
= 可供历史、RAG 和工具结果使用的预算
然后再为不同来源设置上限,例如:
历史消息:最多 20%
RAG 片段:最多 40%
工具结果:最多 20%
输出预留:至少 20%
具体比例没有固定答案,取决于任务类型:
- 问答系统通常需要给检索资料更多预算;
- 多轮客服更依赖会话历史;
- Agent 场景要严格限制工具返回;
- 写作任务要为最终输出预留更多空间。
总结#
理解 Token 和 Context Window 后,可以把很多 LLM 工程问题统一起来:
- 为什么长对话需要摘要;
- 为什么 RAG 要分块、筛选和重排序;
- 为什么工具结果必须精简;
- 为什么上下文越长不一定回答越好;
- 为什么成本、延迟和效果会彼此牵制。
核心原则始终是:不要追求把更多内容塞进上下文,而要让模型在当前任务中拿到最必要的信息。
相关文章
- 为什么我把博客首页做成了一个对话框
传统博客正在被 AI 问答取代,与其被动等 AI 抓取,不如自己成为那个 AI。