Token 与上下文窗口

0 阅读11分钟

为什么和 AI 聊得越久,有时它反而越容易遗漏之前说过的信息?为什么上传一份很长的文档,模型可能无法一次处理?

这背后涉及两个基础概念:Token 和上下文窗口。理解它们,才能理解大模型的信息处理能力,以及 AI 应用为什么需要上下文管理。

一、Token:大模型是怎样读取文字的?

我们习惯用汉字、单词和句子理解文字,但大语言模型处理文本时,使用的基本单位并不是汉字或完整单词,而是 Token(词元)。

Token 可以是一个字符、一个词的一部分、一个完整单词,也可以是标点符号等。

例如:

原始文本:
Today is a beautiful day!

模型处理:
Today | is | a | beautiful | day | !

上面只是便于理解的示意切分,真实的 Token 切分由模型使用的 Tokenizer 决定。

Tokenizer(分词器) 就是负责把文本转换为 Token 序列的工具。

这里有三个容易混淆的地方:

  • 一个汉字不一定对应一个 Token。
  • 一个英文单词可能被拆成多个 Token。
  • 同一段文字,在不同模型中可能产生不同数量的 Token。

因此,Token 数量不能简单按照字数或单词数量计算。语言、编码方式、空格和文本内容都会影响切分结果。

Token 为什么重要?

Token 不仅是模型处理文本的基本单位,还直接影响三个方面:

1. 模型处理能力

模型接收输入时,需要将文本转换为 Token 序列,再进行后续处理。

2. 上下文容量

模型一次能够处理多少内容,通常以 Token 数量衡量。

3. API 使用成本

许多模型平台按照输入和输出 Token 计费。输入内容越多,通常意味着需要处理的 Token 越多,具体费用取决于模型和平台的计费规则。

在 OpenAI 的 API 中,还需要区分输入 Token、输出 Token、缓存输入 Token,以及部分推理模型使用的推理 Token。

因此,一段看起来很短的回答,也不一定只消耗显示出来的文字对应的 Token。

二、为什么 AI 需要上下文窗口?

理解 Token 后,就可以回答一个更重要的问题:

如果模型处理文字依赖 Token,那么它一次最多能处理多少 Token?

这就涉及 Context Window(上下文窗口)。

上下文窗口可以理解为模型一次请求能够处理的信息容量,通常以 Token 数量表示。

例如,假设某个模型的上下文窗口是 32K Token。

这并不意味着用户可以输入 32K Token 的文字。

因为模型接收到的内容不只有用户输入。

一次请求中可能包含:

  • 系统指令:告诉模型应该遵循什么规则。
  • 用户输入:当前提出的问题。
  • 历史对话:之前交流过的内容。
  • 工具定义:Function Calling 的工具和参数说明。
  • 工具返回:外部 API 或 MCP 工具执行后的结果。
  • 检索资料:RAG 从知识库中找到的相关内容。
  • 多模态输入:图片、文件等内容。

这些信息都会影响请求的 Token 使用量。

此外,模型生成的输出,以及部分模型使用的推理 Token,也可能占用上下文容量。具体计算方式取决于模型和接口。

用一个例子理解上下文容量

假设一个模型的上下文窗口为 32K Token。

某次请求已经使用:

内容Token 数量
系统指令2K
历史对话8K
工具定义2K
RAG 检索资料10K
当前用户输入2K
合计输入24K

此时已经使用了 24K Token。

如果该模型的输入和输出共用 32K 上下文容量,那么留给输出及其他内部处理的空间就会受到限制。

32K 只是示例,不代表所有模型的实际上下文窗口。不同模型的上下文容量、最大输出长度和计算规则都可能不同。

上下文窗口决定了模型一次能够处理多少信息,而不是决定模型永久能够记住多少信息。

三、为什么对话越长,AI 越容易遗漏信息?

假设你正在咨询一笔订单退款。

对话刚开始时,你提供了订单编号:

订单编号:20261103001

随后又讨论了退款政策、商品问题、物流进度和其他订单。

经过几十轮交流,你再次询问:

“刚才那笔订单现在是什么状态?”

AI 却回答:

“请提供订单编号。”

这是不是意味着模型忘记了?

不一定。至少存在以下几种可能。

1. 早期信息已经不在当前上下文中

当历史对话不断增长,应用程序可能需要裁剪较早的消息,避免超过上下文窗口限制。

如果订单编号被裁剪掉,模型本次请求就无法直接读取它。

2. 历史内容经过摘要,但关键信息丢失

有些系统不会一直保存完整对话,而是把较早的内容压缩成摘要。

例如,原始对话包含:

订单编号:20261103001
申请时间:11月3日
退款原因:商品质量问题
当前状态:退款处理中

但摘要只保留:

用户正在咨询商品质量问题导致的退款。

订单编号和具体状态就丢失了。

3. 信息仍然存在,但模型没有正确利用

即使订单编号还在上下文中,周围存在大量无关信息,也可能影响模型定位和使用关键信息的能力。

因此,扩大上下文窗口不等于模型一定能够准确利用其中所有内容。

4. 检索或生成环节出现错误

如果系统通过 RAG 检索历史资料,可能检索到了错误订单。

也可能是资料本身正确,但模型在生成回答时理解错误。

所以,AI 遗漏信息不能全部归因于上下文窗口。

需要区分:信息没有进入上下文、信息进入了但没有被正确利用,以及外部检索和生成环节出现错误。

四、上下文、长期记忆、RAG 和数据库有什么区别?

解决长对话信息丢失,不能只依赖扩大上下文窗口。

还需要理解四种不同的能力。

概念主要职责典型内容
上下文窗口提供当前请求需要的信息当前对话、系统指令、检索结果
长期记忆保存跨会话仍有价值的信息用户偏好、稳定事实
RAG 知识库从外部资料中检索相关知识企业 SOP、产品手册、技术文档
业务数据库保存真实业务状态订单、支付、退款、库存

它们不是相互替代的关系。

1. 长期记忆:保存值得长期保留的信息

例如,用户长期偏好简洁的回答,或者某个业务助手需要记住用户的常用设置。

这些信息可以保存在记忆系统中,在后续任务中按需读取。

但长期记忆不应该被理解为保存全部聊天记录。

2. RAG:需要知识时再检索

假设企业有几万份产品文档和售后政策。

如果每次都把全部文档发送给模型,显然不现实。

RAG 的处理方式是:

  1. 用户提出问题。
  2. 检索系统从知识库中查找相关资料。
  3. 选取与问题有关的内容。
  4. 将检索结果放入当前请求的上下文。
  5. 模型结合资料生成回答。

因此,RAG 并不是扩大上下文窗口,而是减少无关信息,让有限的上下文空间优先容纳真正需要的知识。

3. 数据库:保存真实业务状态

如果用户询问:

“我的退款到账了吗?”

退款状态属于实时业务数据,应该通过业务 API 查询真实数据库,而不是依赖模型记忆或普通知识库检索。

例如:

用户提出退款查询
       ↓
调用订单查询 API
       ↓
读取真实退款状态
       ↓
将查询结果加入上下文
       ↓
模型组织回答

模型负责理解和表达,业务系统负责提供真实状态。

这一区分非常重要:知识库适合回答规则是什么,业务数据库适合回答现在发生了什么。

五、实际 AI 应用如何管理上下文?

当 AI 应用需要持续处理大量对话、知识和工具调用时,不能简单地把所有历史信息一直追加到请求中。

通常需要采用几种管理方式。

1. 历史消息裁剪

保留当前任务相关的消息,删除已经没有价值的历史内容。

适合简单对话,但需要注意不能误删重要事实。

2. 历史摘要

将较长的历史对话压缩成结构化摘要。

例如:

{
  "order_id": "20261103001",
  "refund_reason": "商品质量问题",
  "refund_status": "processing",
  "next_action": "查询退款到账情况"
}

相比保留全部聊天记录,结构化摘要更容易保留关键业务信息。

但摘要仍然可能遗漏事实,重要业务状态不能只依赖摘要作为最终依据。

3. RAG 按需检索

不把所有知识库内容放进上下文,而是根据当前问题检索相关资料。

这既能控制 Token 使用量,也能降低无关内容对模型的干扰。

4. 外部状态存储

对于订单编号、审批结果、任务进度等关键数据,应该保存在数据库或其他可靠的状态存储中。

需要时通过 API 查询,再把必要结果加入上下文。

这样即使对话被裁剪或重新开始,关键业务状态仍然可以恢复。

5. Token 预算管理

在工程实现中,还需要关注:

  • 系统指令占用了多少 Token?
  • 工具定义是否过于冗长?
  • 历史对话是否需要压缩?
  • RAG 是否检索了过多无关内容?
  • 是否为模型输出预留足够空间?
  • 实际请求的 Token 使用量是否超过预期?

这些都属于上下文工程需要解决的问题。

六、开发中如何统计 Token?

如果使用 OpenAI 模型,可以通过官方 Tokenizer 或 tiktoken 进行文本 Token 统计。

例如:

import tiktoken

encoding = tiktoken.encoding_for_model("gpt-4o")

text = "为什么 AI 需要上下文窗口?"

tokens = encoding.encode(text)

print("Token 数量:", len(tokens))
print("Token 内容:", tokens)

这里需要注意:

  • Tokenizer 应与目标模型匹配。
  • 不同模型可能使用不同编码。
  • 单独统计一段文本,不等于完整统计一次 API 请求。
  • 消息结构、工具定义、Schema、图片和文件等,也可能影响完整请求的 Token 数量。

如果需要统计完整 API 请求,应优先使用模型平台提供的输入 Token 统计能力,并在请求完成后检查实际 usage 数据。[^1]

七、总结:上下文窗口不是 AI 的长期记忆

理解 Token 和上下文窗口,实际上是在理解大模型的信息处理边界。

几个概念需要明确区分:

  • Token:模型处理文本的基本单位。
  • Tokenizer:负责将文本转换为 Token。
  • 上下文窗口:模型一次能够处理的信息容量。
  • 长期记忆:保存跨会话仍有价值的信息。
  • RAG:从外部知识库检索当前需要的资料。
  • 业务数据库:保存真实业务状态。

它们之间的关系可以概括为:

外部系统负责保存信息,记忆和检索负责找到信息,上下文负责把当前需要的信息交给模型,模型负责理解和生成。

AI 应用的能力,不仅取决于模型本身有多强,也取决于能否在有限的上下文容量内,准确提供完成任务所需要的信息。

参考资料

  1. OpenAI:Understanding and counting tokens
  2. OpenAI:Conversation state
  3. OpenAI:Tokenizer
  4. OpenAI Cookbook:How to count tokens with tiktoken
  5. Anthropic:How do usage and length limits work?