Context Window
上下文窗口是模型在单次请求中能够关注的最大 token 数量,由提示、历史记录、文档和回复共同占用。
上下文窗口是模型在单次请求中能够纳入考量的最大词元数量。对于大语言模型(LLM),模型读取和生成的所有内容都会占用这部分预算:系统提示、工具定义、对话历史、检索到的文档、用户问题以及模型生成的回复。窗口之外的文本不会传给模型,因此当较早的对话轮次被裁掉后,聊天机器人就会忘记超长对话的开头。上下文窗口从 GPT-3 的 2,048 个词元,扩展到了 2023 年末 GPT-4 Turbo 的 128K 个词元,以及 Google Gemini 1.5 Pro 在 2024 年达到的 100 万个词元;Meta 的 Llama 4 Scout 则宣称支持 1,000 万个词元。
上下文窗口包含什么#
词元化会将文本拆分为子词片段;平均而言,每个英语词元约有四个字符,因此 128K 词元的窗口大致相当于 300 页文本。视觉语言模型(VLM)还会将词元用于图像,通常每张图像就需要数百个图像块词元,因此长视频会比其文字转录更快占满窗口。生成的词元也计入同一上限,服务提供商还会单独限制窗口内的输出长度。因此,运行长对话或AI 智能体的应用需要在每轮对话时重新组装提示,并决定保留哪些内容:
上下文窗口为何有限#
长度增加会带来两项成本。自注意力会比较每个词元与其他所有词元,因此注意力计算量会随着词元数量呈二次方增长。在文本生成期间,KV 缓存会保存所有先前词元的键和值:Llama 3.1 8B 有 32 层,每层有 8 个键值头,每个头的维度为 128;在 16 位精度下,每个词元需要存储 128 KiB,满 131,072 词元窗口时则需 16 GiB,超过其权重占用的 16 GB。
上下文窗口也受训练影响。使用 8K 词元序列训练的模型从未见过这些位置之外的内容,因此要扩展窗口,就需要使用 YaRN 等方法重新缩放旋转位置嵌入(RoPE),并通过较短时间的长文本微调来适应更长上下文。服务长上下文时依赖节省内存的技术:闪存注意力无需存储完整的分数矩阵即可精确计算注意力;分组查询注意力(GQA)可缩小 KV 缓存;滑动窗口注意力将每个词元的注意范围限制在附近位置;环形注意力则将一个序列拆分到多张 GPU 上处理。
标称上下文与有效上下文#
支持百万词元的模型并不一定能同样有效地利用所有词元。2023 年的研究 Lost in the Middle发现,当相关段落位于提示开头或结尾时,模型回答效果最好;位于中间时,效果最差。大海捞针(NIAH)测试会在不同深度和长度处插入事实,以测量模型能否回忆该事实;更难的 RULER 基准测试发现,17 个宣称支持 32K 词元或更多的模型中,只有一半在 32K 词元时表现令人满意。输入变长时性能逐渐下降的现象称为上下文退化;检索增强生成(RAG)和上下文工程会通过只将相关材料放入窗口来缓解这一问题。
上下文窗口与相关术语的区别#
- 感受野:输入图像中会影响卷积神经网络(CNN)一个输出的区域。感受野由卷积核大小和网络深度决定,而上下文窗口则是词元预算。
- 批量大小:同时处理的独立序列数量。上下文窗口限制每个序列的长度。
- 记忆:智能体记忆(例如存储在向量数据库中的情景记忆)可以在窗口之外持久保存,并在相关时复制回窗口。
开放词汇检测中的上下文窗口#
视觉模型中的文本编码器也有上下文窗口。Ultralytics YOLOE和 YOLO-World会使用 CLIP 系列文本编码器为每个类别提示编码;这类编码器的上下文窗口为 77 个词元。Ultralytics 文本编码器默认会截断较长的提示。相同的 CLIP 分词器可以显示被截掉的内容:
import clip
from clip.simple_tokenizer import SimpleTokenizer
prompt = (
"a warehouse worker wearing a yellow high-visibility vest, a white hard hat, blue gloves and clear safety "
"glasses, standing beside a red forklift that carries wooden pallets stacked with brown cardboard boxes, "
"under bright ceiling lights in a narrow aisle between tall metal shelves, next to a fire extinguisher "
"mounted on the wall, a green emergency exit sign, an open loading dock door and a black dog"
)
# CLIP's BPE tokenizer wraps the text in start and end tokens
tokenizer = SimpleTokenizer()
print(f"Prompt length: {len(tokenizer.encode(prompt)) + 2} tokens")
# The text encoder reads a fixed 77-token window, so truncation drops the tail
tokens = clip.tokenize(prompt, truncate=True)[0]
kept = tokenizer.decode(tokens[1:-1].tolist())
print(f"Window: {len(tokens)} tokens ending in '{' '.join(kept.split()[-4:])}'")
print(f"'black dog' kept: {'black dog' in kept}")该提示有 80 个词元,因此窗口会保留前 75 个文本词元以及起始和结束标记,内容止于“loading dock door and”,并在编码器看到“a black dog”之前将其截掉。










