上下文窗口总 Token 是多少?压缩机制是什么?面试官问 Context Window 时到底想考什么

发布时间:2026/7/3 9:16:52

上下文窗口总 Token 是多少?压缩机制是什么?面试官问 Context Window 时到底想考什么 摘要Context Window 是 LLM 的核心限制。GPT-4 有 128K 的窗口Claude 有 200KGemini 甚至到了 1M。但「有 128K」不等于「128K 都有效」。为什么模型上下文一长就开始「失忆」压缩机制是怎么工作的面试官问这个问题的背后到底想考什么本文从 Attention 的计算原理讲起拆解 Context Window 的物理上限、实际可用量、以及常见的压缩优化策略。 目录开篇128K 的窗口不代表 128K 都看得见Token 是怎么计算的Attention 的计算瓶颈「有效窗口」比「标称窗口」短得多三大压缩机制实战你的 Agent 的 Context 是怎么被吃掉的面试追问总结开篇128K 的窗口不代表 128K 都看得见面试官问「Context Window 总 Token 是多少」这是一个陷阱题。背参数的人会答GPT-4 Turbo 是 128KClaude 3.5 Sonnet 是 200KGemini 1.5 Pro 是 1M。这个答案拿到 60 分——你知道数字但面试官想知道的是你知不知道这些数字背后的「水分」。Context Window 有两个关键数字标称窗口和有效窗口。模型标称窗口有效窗口实测衰减比例GPT-4 Turbo128K~64K-80K约 50%-60%Claude 3.5 Sonnet200K~120K-150K约 60%-75%Gemini 1.5 Pro1M~500K-700K约 50%-70%Llama 3 70B8K / 32K (扩展)~6K / 24K约 75%核心结论当你的输入接近标称上限时模型在窗口中间和末尾的「记忆力」显著下降。这不是 Bug是 Attention 机制的自然结果——Token 越多每个 Token 分到的 Attention 权重越稀疏。开篇金句面试官问「Context Window 有多大」他真正想听到的是「我知道标称值也知道这个数字在长上下文中会折扣多少」。Token 是怎么计算的Token 不是字符是「语义碎片」LLM 不读「字」它读「Token」。Token 是模型内部的最小语义单元——可以是一个词的一部分、一个完整的词、甚至是一个标点符号。同一个句子不同 Tokenizer 的计数差异句子上下文窗口的总 Token 是多少 # GPT 系列tiktoken cl100k_base 上下文 → 1 token 窗口 → 1 token 的 → 1 token 总 → 1 token Token → 1 token 是多少 → 1 token → 1 token 总计: ~7 tokens # Claude有自己的 Tokenizer 同上句子分词粒度不同 总计: ~6-9 tokens取决于具体实现 # 英文占比 这句话在中文里约 7 tokens 如果是英文 What is the total token count of the context window? 约 14 tokens ← 多了整整一倍关键知识点中文 Token 效率大约是英文的 2 倍——同样的语义中文用的 Token 更少。这也是为什么中文用户的 Context 窗口看起来「更宽」的原因。怎么精确计算 TokenToken 计数代码示例# OpenAI 的 tiktokenPython 库 import tiktoken enc tiktoken.encoding_for_model(gpt-4) tokens enc.encode(上下文窗口的总 Token 是多少) print(fToken 数量: {len(tokens)}) print(fToken 列表: {tokens}) # 还原 decoded enc.decode(tokens) print(f还原文本: {decoded}) # 输出 # Token 数量: 7 # Token 列表: [24234, 4983, 925, 833, 15321, 9673, 25634] # 还原文本: 上下文窗口的总 Token 是多少Token 计算的实战意义在设计 System Prompt 和 Tool 定义时你需要精确知道每个部分的 Token 占用System Prompt: ~2,000-5,000 tokens不可省略Agent 的核心人格 Tool Definitions: ~1,000-3,000 tokens每个 Tool 的 name description parameters Conversation History: 取决于轮次每轮 ~500-2,000 tokens Recent User Input: ~50-500 tokens当前问题 总计10 轮对话后: ~10,000-30,000 tokens → 距 128K 还很远 总计100 轮对话后: ~70,000-200,000 tokens → 已经超过标称窗口Attention 的计算瓶颈为什么窗口越长模型越慢Transformer 的 Attention 机制的核心公式Attention(Q,K,V) softmax(QK^T / sqrt(d)) V。其中QK^T的时间复杂度是O(n²)——n 是 Token 数量。窗口翻倍计算量翻四倍。窗口大小Attention 计算量与 8K 窗口的倍数8K64M1x32K1,024M16x128K16,384M256x1M1,000,000M15,625x这就是为什么大多数模型的标称窗口是 128K而不是更大的数字——不是因为训练数据不够是O(n²) 的计算复杂度把硬件瓶颈给卡死了。长窗口的「注意力稀释」问题当 n 较小时8K 每个 Token 可以分配到足够的注意力权重 Attention 矩阵是「信息密集」的 → 模型能「看到」所有 Token 当 n 较大时128K 每个 Token 能分配的平均权重被稀释了 Attention 矩阵变得稀疏 模型倾向于把权重集中在开头和结尾的 Token 上 → 中间的 Token 被「遗忘」了这就是Lost in the Middle现象——模型在处理长文档时位于中间位置的信息被检索到的概率最低。研究表明当需要的信息位于文档的 0%-15% 位置时准确率约 80%位于 50%-85% 位置时准确率下降到约 40%。金句Attention 的 O(n²) 复杂度和「Lost in the Middle」现象是你永远无法用满标称窗口的两个根本原因。面试官问的是「你知不知道天花板在哪」而不是「你记不记得参数」。「有效窗口」比「标称窗口」短得多官方数据和实际数据的差距标准评测方法如 RULER 和 Needle-in-a-Haystack是在文档中插入一条关键信息看模型能不能找到它。在这种评测里模型的表现通常还不错——因为模型知道「肯定有答案找就行了」。但实际场景不是这样的。在实际的 Agent 对话中信息不是被「插进去」的是自然累积的——没有明确的「这条是关键那条不是」。模型需要自己在海量 Token 中判断「哪部分信息是相关的」。真实场景的有效窗口通常只有标称窗口的40%-60%。三种「窗口损耗」损耗一Lost in the Middle信息在窗口中间位置时模型检索到它的概率最低。如果你把关键信息放在 System Prompt 开头或结尾模型记得住。放在中间——大概率被忽略。损耗二Positional Encoding 衰退模型的 Positional Encoding位置编码有精度上限。对于 RoPE旋转位置编码GPT-4/Claude/Llama 采用当序列长度超出预训练窗口时位置编码的旋转角度会「缠绕」——远处的 Token 和近处的 Token 在位置编码上不再可区分。这是 RoPE 的周期性问题。损耗三信息冗余长上下文里充满了重复信息、无意义填充、和当前任务无关的寒暄。模型需要从这些「噪音」里找到「信号」——但 Attention 不分好信息坏信息它给所有 Token 一样的计算资源。噪音越多信号越弱。有效窗口的估算公式Effective Window ≈ Nominal Window × α × β × γ α 模型自身的 Attention 衰减系数~0.6-0.8 β 信息在当前上下文中的「密度」系数0.3-0.9 如果信息密度高比如满篇都是关键数据β 趋近 0.9 如果信息密度低比如大部分是寒暄β 趋近 0.3 γ 位置编码的可用范围系数~0.5-1.0 对于预训练窗口内的 Tokenγ 趋近 1.0 对于超出预训练窗口的 Tokenγ 快速衰退 估算示例GPT-4 Turbo 128KAgent 对话 80 轮 128K × 0.7 × 0.5 × 0.8 ≈ 35.8K → 实际有效的上下文只有不到 36K三大压缩机制当 Context 窗口撑满时你有三种压缩策略按优先级使用。策略一Token 级别的压缩最精确最低损耗去掉输入中的冗余 Token减少无用信息。Token 级别的去冗余# ❌ 冗余的 Tool 返回 Tool search_kb returned: { status: success, code: 200, data: { results: [ { id: 12345, title: Q3 营收报告, content: Q3 营收为 3.2 亿元, source: internal, timestamp: 2025-10-15T14:30:00Z, version: v2.1, metadata: { ... } } ] } } # ✅ 压缩后的 Tool 返回去掉无意义字段保留核心 Tool search_kb: Q3 营收为 3.2 亿元可优化的项去掉 Tool 返回中的 status、code、metadata 等固定字段把 JSON 转成自然语言去掉日志级别信息限制每条 Tool 返回的 Token 上限。策略二摘要压缩有损但保留核心语义用 LLM 自己把长文本压缩成短摘要。摘要压缩的 Prompt摘要压缩 Prompt 以下是一段对话/文档请将它压缩到 1/3 的长度。 保留以下信息 1. 用户的核心诉求和偏好 2. 已经完成的步骤和结论 3. 未解决的关键问题 移除以下信息 1. 寒暄、确认、客套话 2. 重复的推理过程 3. 无关的细节 原文{long_text} 压缩后注意摘要压缩是有损的。压缩率越高信息丢失越多。推荐的压缩率是 50%-70%保留 30%-50% 信息。策略三滑动窗口 外部存储零丢失但需要检索把对话历史存到外部数据库只保留最近的 N 轮在上下文中。当 Agent 需要「回忆」早期对话时通过 RAG 检索外部存储。滑动窗口 外部存储的完整实现class ContextCompressor: def __init__(self, max_context_tokens64000): self.max_tokens max_context_tokens self.external_store [] # 外部存储可以是向量数据库 def add_to_context(self, new_message, system_prompt, tools): # 1. 构造完整 Context context system_prompt tools self.external_store new_message # 2. 检查 Token 数量 current_tokens count_tokens(context) if current_tokens self.max_tokens: # 够用直接加入 self.external_store.append(new_message) return context # 3. 超了触发压缩 compressed self.compress() context system_prompt tools compressed new_message # 4. 如果还超了再次压缩 while count_tokens(context) self.max_tokens: compressed self.compress_more(compressed) context system_prompt tools compressed new_message return context def compress(self): 多级压缩策略 compressed [] total 0 # 第一级移除 Tool 返回中的 JSON 冗余字段 cleaned self.trim_tool_results(self.external_store) # 第二级将 Tool 返回格式化为自然语言 natural self.format_as_natural(cleaned) # 第三级LLM 摘要保留核心决策和用户偏好 for segment in reversed(natural): segment_tokens count_tokens(segment) if total segment_tokens self.max_tokens * 0.4: # 只保留 40% compressed.insert(0, segment) total segment_tokens else: # 对超出的部分做 LLM 摘要 summary self.llm_summarize( f将以下历史摘要到 50 tokens 以内\n{segment} ) compressed.insert(0, summary) total count_tokens(summary) break return compressed金句Context 压缩不是「能不压缩就不压缩」而是「知道什么时候该用哪种压缩」——Token 级压缩去冗余摘要压缩去噪音外部存储去历史。实战你的 Agent 的 Context 是怎么被吃掉的一个 Agent 对话的 Token 账单假设你的 Agent 和用户聊了 20 轮每轮包含用户的提问、Agent 的响应、可能还有 Tool 调用。下面是一个典型的 Token 账单组件每轮 Token20 轮总计System Prompt2,000固定2,000Tool Definitions5,000固定5 个 Tool5,000用户提问~2004,000Agent 思考 回复~80016,000Tool 调用 返回~1,50030,000每轮额外上下文注入~1002,000合计~59,00020 轮对话结束你的 Context 已经占了 59K。如果 GPT-4 Turbo 的有效窗口是 64K你只剩 5K 的余量——再聊 1-2 轮Agent 就开始「失忆」了。Token 黑洞 Top 3第一名Tool 返回结果Tool 返回是最大的 Token 消耗者。一个简单的数据库查询可能返回 10 条记录每条 500 Token一次 Tool 调用就是 5,000 Token。10 轮后光是 Tool 返回就占了 50K。第二名重复的 Tool 定义System Prompt 里的 Tool 定义是每轮都传的。如果你有 10 个 Tool每个 800 Token8,000 Token 是固定的「基础设施税」——你还没开始干活就已经花了这么多。第三名格式冗余JSON 格式本身有大量的冗余字符花括号、引号、逗号、字段名。一个 JSON 表示的 Tool 返回如果转成自然语言可以减少 30%-50% 的 Token。金句你不会因为「模型参数大」而耗尽 Context——你会因为「Tool 返回没格式化」而耗尽。99% 的 Context 溢出问题可以通过优化输入格式化解决。面试追问Q1如果有两个模型一个 128K 窗口但有效 64K另一个 32K 但有效 30K你选哪个取决于你的应用场景。如果 Agent 需要处理很长的上下文比如长篇文档分析、长对话摘要128K 的模型仍然有价值因为即使只有 64K 有效它也远大于 32K 的窗口。但如果 Agent 的任务是短对话、快速查询比如客服问答、单轮 Tool 调用32K 窗口但更稳定的模型更好——因为你不需要处理「中间位置信息丢失」的问题。这也是 Llama 3 保留 8K 原生窗口的原因之一对于短上下文它更稳定。Q2Ring Attention / Flash Attention 解决了 O(n²) 问题吗Flash Attention 解决了 Attention 的显存瓶颈从 O(n²) 显存降到 O(n)但没解决计算复杂度问题——计算量仍然是 O(n²)只是不需要把整个 Attention 矩阵载入显存了。Ring Attention 在分布式场景下解决了超长序列比如 1M的显存问题允许你在多个 GPU 上分片计算 Attention。但「计算量」和「注意力稀释」这两个问题目前没有任何技术能真正解决——这是 Attention 机制的固有特性。Q3MQA/MHA/GQA 对 Context Window 有什么影响MQAMulti-Query Attention和 GQAGrouped-Query Attention主要是为了推理加速不是为了解决窗口大小问题。它们减少了 Key-Value Cache 的参数量让模型在推理时可以缓存更多 Token——本质上是在「相同显存预算下可以处理更长的上下文」。但它们不解决注意力稀释的问题。所以 MQA 和 GQA 可以让模型跑得更远但跑得更远不等于跑得更好。Q4在实践中怎么尽可能利用长上下文三个技巧① 重要信息放在开头和结尾——利用 Position Bias开头效应 末尾效应不要藏到中间② 关键信息重复一遍——关键指令在开头说一次、结尾再说一次显著提高模型记住的概率③ 分段注入——把长文档分段每段加上「摘要前缀」让模型在 Attention 层面给每段一个「标题」减少中间位置的信息稀释。总结问题答案标称窗口是多少GPT-4 128KClaude 200KGemini 1M有效窗口是多少标称的 40%-60%为什么有效窗口更短Attention 的 O(n²) 复杂度 Lost in the Middle Positional Encoding 衰退怎么压缩Token 级去冗余 → 摘要压缩 → 滑动窗口 外部存储Context 被什么吃掉了Tool 返回最大头 Tool 定义 格式冗余核心一句话面试官问 Context Window考的不是参数记忆是三层理解——标称值是多少、实际能用多少、怎么在有限容量下最大化信息密度。 你在开发中遇到过 Context 溢出吗怎么解决的评论区聊聊。

相关新闻