📌 定义
Context Window Management(上下文窗口管理)是指在LLM应用中对有限上下文窗口进行高效利用的技术手段,包括上下文压缩、优先级排序、滑动窗口、分段加载等策略,以在Token限制下最大化信息密度和任务效果。
🎭 为什么上下文管理是刚需?
主流模型的上下文限制
| 模型 | 上下文窗口 | 实际可用(扣除输出) |
|---|---|---|
| GPT-4o | 128K tokens | ~124K tokens |
| Claude 3.5 Sonnet | 200K tokens | ~195K tokens |
| Gemini 1.5 Pro | 1M tokens | ~950K tokens |
| GPT-3.5 Turbo | 16K tokens | ~14K tokens |
核心问题:即使有200K窗口,在以下场景仍会爆:
- 长文档问答(百万字报告)
- 多轮对话历史累积(几百轮)
- RAG检索结果注入(Top-100 chunks)
- 多Agent协作消息传递
🛠️ 六大上下文管理策略
1. 滑动窗口(Sliding Window)
// 保留最近N轮对话
function slidingWindow(messages, maxTurns = 10) {
// 始终保留system prompt
const systemPrompt = messages.filter(m => m.role === 'system');
// 只保留最近N轮对话
const recentMessages = messages
.filter(m => m.role !== 'system')
.slice(-maxTurns * 2);
return [...systemPrompt, ...recentMessages];
}
2. 上下文压缩(Context Compression)
// 使用LLM压缩历史对话为关键要点
async function compressContext(messages) {
const prompt = `将以下对话压缩为关键要点:
1. 用户核心需求
2. 已确定的关键信息
3. 待解决的问题
原始对话:${JSON.stringify(messages)}`;
return await llm.complete(prompt);
}
3. 优先级队列(Priority Queue)
// 按重要性排序消息
const priority = {
'system': 10, // 系统提示最高
'user': 8, // 用户输入次之
'tool_result': 6, // 工具结果
'assistant': 4 // 助手回复最低
};
function priorityQueue(messages, maxTokens) {
return messages
.sort((a, b) => priority[b.type] - priority[a.type])
.reduce((acc, msg) => {
if (countTokens(acc) + countTokens(msg) <= maxTokens)
acc.push(msg);
return acc;
}, []);
}
4. 摘要链(Summary Chain)
// 每N轮生成摘要替换历史
async function summaryChain(messages, every = 5) {
const summaries = [];
for (let i = 0; i < messages.length; i += every * 2) {
const chunk = messages.slice(i, i + every * 2);
const summary = await llm.summarize(chunk);
summaries.push(summary);
}
return summaries;
}
5. 语义检索(Semantic Retrieval)
// 根据当前问题检索最相关的历史消息
async function semanticRetrieval(query, history, topK = 5) {
const queryEmb = await embed(query);
const scored = history.map(m => ({
...m,
score: cosineSimilarity(queryEmb, m.embedding)
}));
return scored.sort((a, b) => b.score - a.score).slice(0, topK);
}
6. 分段加载(Chunk Loading)
// 按需加载文档片段
class ContextManager {
private chunks: Map;
private loaded: string[] = [];
loadChunk(id: string, maxTokens: number) {
while (this.totalTokens() + countTokens(this.chunks.get(id)) > maxTokens) {
this.loaded.shift();
}
this.loaded.push(id);
}
}
🔧 OpenClaw实战配置
OpenClaw内置了上下文管理模块,通过配置文件即可启用多种策略组合。
# openclaw-config.yaml
context:
max_tokens: 32000
strategy:
sliding_window:
enabled: true
max_turns: 10
compression:
enabled: true
method: "llm_summary"
compression_ratio: 0.3
priority:
enabled: true
system_weight: 10
user_weight: 8
summary:
enabled: true
interval_turns: 5
⚠️ 常见踩坑与最佳实践
踩坑一:压缩丢失关键信息
上下文压缩就像用手机拍名画——虽然省空间,但细节全丢了。关键指令(如"输出JSON格式")可能在压缩时被丢弃。建议将关键指令放在System Prompt中,不参与压缩。
上下文压缩就像用手机拍名画——虽然省空间,但细节全丢了。关键指令(如"输出JSON格式")可能在压缩时被丢弃。建议将关键指令放在System Prompt中,不参与压缩。
踩坑二:Token计数不准
不同模型的tokenizer不同。GPT的cl100k_base和Claude的tokenizer差异可能达30%。建议使用对应模型的token计数器,并预留10%安全余量。
不同模型的tokenizer不同。GPT的cl100k_base和Claude的tokenizer差异可能达30%。建议使用对应模型的token计数器,并预留10%安全余量。
踩坑三:"Lost in the Middle"现象
研究表明LLM对上下文中间部分的信息记忆最差。重要的信息应该放在开头(System Prompt)或结尾(最新用户消息),避免埋在长上下文中间。
研究表明LLM对上下文中间部分的信息记忆最差。重要的信息应该放在开头(System Prompt)或结尾(最新用户消息),避免埋在长上下文中间。
最佳实践:
- System Prompt始终保留,永远不压缩
- 预留10-15%的Token余量给输出
- 组合使用滑动窗口+摘要链效果最佳
- 监控Token使用率,超过80%时触发压缩
- 测试时使用不同的上下文长度验证效果