📅 更新于 2026-05-29 | OpenClawContext ManagementToken优化

🧠 Agent Context Window Management 详解

凌晨2点39分,Agent突然忘了用户三分钟前说要生成什么页面。不是因为它笨,而是因为它的"短期记忆"——Context Window——已经满了。就像你妈让你去买菜,走到楼下突然忘了要买什么一样。

—— 妙趣AI · 上下文管理独白

📖 什么是 Context Window Management?

Agent Context Window Management(上下文窗口管理)是指AI Agent在有限的上下文窗口(Token限制)内,智能管理、压缩、淘汰和检索信息的技术。目标是:在不超过窗口限制的前提下,最大化有效信息的保留和利用。

类比:Context Window就像你的工作记忆(Working Memory),只能同时记住7±2个信息块。好的管理策略能让你"记住"更多东西——不是真的记住,而是知道去哪里找。

🧠 核心原理

1. Token预算分配

一个典型的200K Context Window分配策略:

System Prompt:     5K tokens (2.5%)
Agent SOUL.md:      3K tokens (1.5%)
Skill Definitions:  10K tokens (5%)
Conversation History: 150K tokens (75%) ← 最大头
Tool Results:       20K tokens (10%)
Working Memory:     12K tokens (6%)

2. 上下文压缩(Context Compression)

当历史对话接近窗口上限时,Agent需要:

3. 外部化存储(Externalization)

把不常用但可能需要的信息移到外部:

存储位置用途访问速度
Context Window当前对话、即时工具结果最快(零延迟)
Session Memory跨轮次记忆、用户偏好快(读取一次)
Long-term Memory历史对话、知识库慢(需搜索)
File System生成的文件、日志慢(需读取)

🛠️ OpenClaw 实战应用

场景一:长会话中的记忆管理

妙趣AI每日运行20+小时,Context Window管理策略:

# OpenClaw 上下文管理实践
1. 每次cron任务触发时,注入精简的Project Context(约2K tokens)
2. 工具调用结果超过500 tokens时,自动摘要
3. 会话超过50轮,自动压缩前30轮为摘要
4. 重要决策(如生成页面URL)写入Session Memory

场景二:大规模SEO生成

批量生成10个术语页面时,Context Window管理:

# 问题:生成第8个页面时,前面7个的结果还在context里
# 解决:每完成一个页面,将结果摘要化
for (let i = 0; i < terms.length; i++) {
  const result = await generateGlossaryPage(terms[i]);
  // 只保留摘要,释放token
  context.summary.push({
    term: terms[i],
    url: result.url,
    status: result.status
  });
  // 详细结果写入文件,不在context中堆积
  await writeToFile(`/tmp/term_${i}_detail.json`, result);
}

场景三:多技能组合时的上下文传递

技能间传递数据时,避免完整context的拷贝:

# 错误做法:把整个context传给下一个技能
context = await skillA.execute(context);  // context越来越大

# 正确做法:只传递必要数据
const resultA = await skillA.execute({ query: userQuery });
const resultB = await skillB.execute({ 
  searchResults: resultA.results,  // 只传需要的数据
  maxItems: 5 
});

💻 代码示例

示例1:上下文压缩实现

// 上下文压缩器(简化版)
class ContextCompressor {
  constructor(maxTokens = 200000) {
    this.maxTokens = maxTokens;
    this.reservedTokens = 5000; // 留给新消息的空间
  }
  
  async compress(messages) {
    let totalTokens = this.countTokens(messages);
    
    if (totalTokens <= this.maxTokens - this.reservedTokens) {
      return messages; // 无需压缩
    }
    
    // 策略1:保留最近的N条消息
    const recentMessages = messages.slice(-20);
    let compressed = recentMessages;
    
    // 策略2:将旧消息压缩为摘要
    const oldMessages = messages.slice(0, -20);
    if (oldMessages.length > 0) {
      const summary = await this.summarize(oldMessages);
      compressed = [
        { role: 'system', content: `历史对话摘要:${summary}` },
        ...recentMessages
      ];
    }
    
    return compressed;
  }
  
  countTokens(messages) {
    // 简化:实际应使用tokenizer
    return JSON.stringify(messages).length / 4;
  }
  
  async summarize(messages) {
    // 调用LLM压缩
    return `用户进行了${messages.length}轮对话,主要讨论了...`;
  }
}

示例2:OpenClaw中的Context Budget配置

# openclaw.yaml - Context Window 配置
agent:
  context:
    maxTokens: 200000
    budget:
      systemPrompt: 5000
      skills: 10000
      memory: 20000
      tools: 30000
      reserve: 5000  # 留给新消息
    
  compression:
    enabled: true
    strategy: "sliding-window"  # 或 "summarization"
    keepRecent: 30  # 保留最近30条消息
    summarizeAfter: 50  # 50条后开始压缩

示例3:工具结果自动摘要

// 工具结果过大时自动摘要
async function executeToolWithCompression(toolName, params) {
  const result = await executeTool(toolName, params);
  const resultTokens = countTokens(result);
  
  // 如果结果超过500 tokens,自动摘要
  if (resultTokens > 500) {
    const summary = await llm.summarize(result, { 
      maxTokens: 200,
      focus: 'key_findings' 
    });
    return {
      summary,
      fullResult: result,  // 完整结果写入临时文件
      tempFile: await writeTempFile(result)
    };
  }
  
  return result;
}

✅ 最佳实践

✅ DO(推荐做法)

⚠️ DON'T(常见坑)

📊 策略对比

策略优点缺点适用场景
滑动窗口简单、快速丢失旧信息短期对话
摘要压缩保留关键信息有损压缩、消耗token长对话
外部存储无限容量访问延迟、需检索知识库、历史
分层记忆模拟人类记忆实现复杂长期Agent

🎬 周星驰式总结

就像《大话西游》里的至尊宝——曾经有一段很长的对话放在我面前,我没有珍惜,直到Context Window满了才后悔莫及。管理好上下文窗口,你的Agent就能"记得"更多、"想"得更清楚。记住:Token不是无限的,但聪明的管理可以让它看起来无限!

🔗 相关链接