上下文窗口:模型的"工作台"
上下文窗口是模型的工作台——它能在一次推理中处理的所有信息。窗口越大,模型能"看到"的信息越多,但也意味着更高的计算成本和更慢的推理速度。如何在有限的窗口中放入最有价值的信息,是一个核心工程问题。
窗口大小的演进
GPT-3 (2020): 2K tokens
GPT-3.5 (2022): 4K-16K tokens
GPT-4 (2023): 8K-128K tokens
Gemini 1.5 (2024): 1M-2M tokens
Llama 4 (2026): 256K-10M tokens
窗口在持续增长,但"能用"和"用好"是两回事。研究表明,即使支持百万token的窗口,模型在长上下文中的表现也远不如短上下文——这就是"Lost in the Middle"问题。
Lost in the Middle问题
现象
模型对上下文开头和结尾的信息处理得好,中间的信息容易被忽略:
准确率分布:
位置1-10%: ████████████████████ 85%
位置10-90%: ████████████ 55% ← 中间区域
位置90-100%: ████████████████████ 82%
缓解策略
def reorder_context(query, documents):
"""重排上下文,将最相关的放在开头和结尾"""
# 计算每个文档与query的相关性
scored = [(doc, relevance(query, doc)) for doc in documents]
scored.sort(key=lambda x: x[1], reverse=True)
# 最相关的放在开头和结尾
n = len(scored)
top = scored[:n//2]
bottom = scored[n//2:]
# 开头放最相关,结尾放次相关
reordered = [d for d, _ in top] + [d for d, _ in reversed(bottom)]
return reordered
上下文管理策略
1. 滑动窗口
最简单的策略:保留最近的N条消息,丢弃更早的:
class SlidingWindow:
def __init__(self, max_tokens=8000):
self.max_tokens = max_tokens
self.messages = []
def add(self, message):
self.messages.append(message)
self._truncate()
def _truncate(self):
while self._total_tokens() > self.max_tokens:
self.messages.pop(0) # 移除最早的消息
问题:完全丢失早期上下文,可能遗忘关键信息。
2. 摘要压缩
将早期对话压缩为摘要:
class SummaryCompression:
def __init__(self, max_tokens=8000, summary_threshold=6000):
self.max_tokens = max_tokens
self.summary_threshold = summary_threshold
self.messages = []
self.summary = ""
def add(self, message):
self.messages.append(message)
if self._total_tokens() > self.summary_threshold:
self._compress()
def _compress(self):
# 保留最近N条消息
keep_count = min(5, len(self.messages) // 3)
recent = self.messages[-keep_count:]
old = self.messages[:-keep_count]
# 摘要旧消息
old_text = "\n".join([m["content"] for m in old])
self.summary = llm.generate(f"""
概括以下对话的关键信息,保留:
1. 用户的意图和需求
2. 已经做出的决定
3. 关键的技术细节
4. 尚未解决的问题
对话内容:
{old_text}
""")
self.messages = recent
def get_context(self):
context = []
if self.summary:
context.append({
"role": "system",
"content": f"之前的对话摘要:{self.summary}"
})
context.extend(self.messages)
return context
3. 选择性记忆
不是所有消息都同等重要。选择性记忆保留关键信息,丢弃闲聊:
class SelectiveMemory:
def __init__(self):
self.importance_classifier = ImportanceClassifier()
self.important_messages = []
self.recent_messages = []
self.max_recent = 10
self.max_important = 20
def add(self, message):
# 评估消息重要性
importance = self.importance_classifier.score(message)
if importance > 0.7:
# 重要消息:长期保留
self.important_messages.append({
**message,
"importance": importance,
"timestamp": datetime.now()
})
if len(self.important_messages) > self.max_important:
self._evict_least_important()
# 所有消息都加入最近列表
self.recent_messages.append(message)
if len(self.recent_messages) > self.max_recent:
self.recent_messages.pop(0)
def get_context(self):
return self.important_messages + self.recent_messages
class ImportanceClassifier:
def score(self, message):
"""评估消息的重要性"""
score = 0.0
# 包含决策性内容
if any(kw in message["content"] for kw in ["决定", "选择", "确认", "同意"]):
score += 0.3
# 包含技术细节
if any(kw in message["content"] for kw in ["代码", "配置", "路径", "版本"]):
score += 0.2
# 包含用户偏好
if any(kw in message["content"] for kw in ["我喜欢", "不要", "请记住"]):
score += 0.3
# 消息长度(长消息通常更重要)
if len(message["content"]) > 200:
score += 0.1
return min(score, 1.0)
4. 结构化上下文
将非结构化的对话历史组织为结构化状态:
class StructuredContext:
def __init__(self):
self.user_profile = {} # 用户信息
self.task_state = {} # 任务状态
self.decisions = [] # 已做决策
self.open_questions = [] # 待解决问题
self.technical_context = {} # 技术上下文
def update(self, message):
"""从消息中提取结构化信息"""
# 使用LLM提取结构化信息
extracted = llm.generate(f"""
从以下对话消息中提取结构化信息:
{message["content"]}
提取:
- 用户信息(姓名、偏好、背景)
- 任务状态(当前在做什么、进展如何)
- 决策记录(做了什么决定)
- 待解决问题(还有什么未解决)
- 技术细节(代码、配置、错误信息)
输出JSON格式。
""")
self._merge(extracted)
def get_context(self):
"""生成结构化的上下文"""
return f"""
## 用户信息
{json.dumps(self.user_profile, ensure_ascii=False)}
## 当前任务
{json.dumps(self.task_state, ensure_ascii=False)}
## 已做决策
{json.dumps(self.decisions, ensure_ascii=False)}
## 待解决问题
{json.dumps(self.open_questions, ensure_ascii=False)}
## 技术上下文
{json.dumps(self.technical_context, ensure_ascii=False)}
"""
5. 检索增强上下文
将历史对话存入向量数据库,按需检索:
class RetrievalAugmentedContext:
def __init__(self, embedder, vector_store):
self.embedder = embedder
self.store = vector_store
self.recent = [] # 最近几条消息
def add(self, message):
self.recent.append(message)
if len(self.recent) > 5:
old = self.recent.pop(0)
# 存入向量数据库
embedding = self.embedder.encode(old["content"])
self.store.add({
"embedding": embedding,
"message": old,
"timestamp": datetime.now()
})
def get_context(self, current_query):
# 检索与当前查询相关的历史消息
query_embedding = self.embedder.encode(current_query)
relevant = self.store.search(query_embedding, top_k=5)
context = []
# 添加检索到的相关历史
for item in relevant:
context.append(item["message"])
# 添加最近的消息
context.extend(self.recent)
return context
策略组合
实际系统中通常组合多种策略:
class HybridContextManager:
def __init__(self):
self.structured = StructuredContext() # 结构化状态
self.selective = SelectiveMemory() # 选择性记忆
self.retrieval = RetrievalAugmentedContext() # 检索增强
self.recent = [] # 最近5条消息
def add(self, message):
self.structured.update(message)
self.selective.add(message)
self.retrieval.add(message)
self.recent.append(message)
def get_context(self, query):
context_parts = []
# 1. 结构化状态(始终包含)
context_parts.append({
"role": "system",
"content": self.structured.get_context()
})
# 2. 检索到的相关历史
relevant = self.retrieval.get_context(query)
context_parts.extend(relevant)
# 3. 重要记忆
context_parts.extend(self.selective.get_context())
# 4. 最近消息
context_parts.extend(self.recent)
return context_parts
Token预算分配
class TokenBudgetAllocator:
def __init__(self, total_budget=32000):
self.budget = total_budget
def allocate(self, components):
"""智能分配token预算"""
# 权重配置
weights = {
"system_prompt": 0.10, # 系统提示
"structured_state": 0.15, # 结构化状态
"retrieved_context": 0.25, # 检索上下文
"important_memory": 0.15, # 重要记忆
"recent_messages": 0.25, # 最近消息
"current_query": 0.05, # 当前查询
"reserved": 0.05, # 预留(用于输出)
}
allocation = {}
for component, weight in weights.items():
allocation[component] = int(self.budget * weight)
return allocation
结语
上下文窗口管理是在有限空间内最大化信息价值的艺术。随着模型支持越来越长的上下文,管理策略的复杂性也在增长。但核心原则不变:放入最相关的信息,丢弃冗余,保持结构化。好的上下文管理可以让8K窗口的效果超过糟糕的128K窗口管理——关键不在于窗口多大,而在于你放进了什么。