【Bug已解决】openclaw context window exceeded / Token limit reached — OpenClaw 上下文窗口超限解决方案

【Bug已解决】openclaw: "context window exceeded" / Token limit reached — OpenClaw 上下文窗口超限解决方案

1. 问题描述

在使用 OpenClaw 处理大型代码库或长对话时,系统报出上下文窗口超限或 Token 数量超出限制错误:

# 上下文窗口超限 $ openclaw "分析整个项目代码" Error: context window exceeded Total tokens: 128547 Maximum: 128000 Exceeded by: 547 tokens # Token 限制达到 $ openclaw "继续之前的对话" Error: token limit reached Input tokens: 95000 Output tokens: 33000 Total: 128000 (at limit) Cannot process further input # 上下文被截断 $ openclaw "分析大型文件" Warning: Context truncated File: src/large_module.ts (45000 tokens) Only first 30000 tokens loaded 33000 tokens omitted # 对话历史过长 $ openclaw "继续讨论" Error: Conversation too long Previous messages: 127 turns Total tokens: 150000 Exceeds model limit: 128000

这个问题在以下场景中特别常见:

  • 分析大型代码文件(>5000行)
  • 长时间对话累积大量上下文
  • 同时加载多个文件到上下文
  • 代码库搜索结果过多
  • API 响应包含大量数据
  • 递归调用导致上下文叠加

2. 原因分析

用户输入 + 历史上下文 + 系统提示 ↓ 计算总Token数 ←──── Tokenizer分词 ↓ 总Token > 限制 ←──── 128K/200K限制 ↓ 拒绝请求/截断内容 → 上下文超限
原因分类具体表现占比
大文件加载单文件>30K Token约 30%
对话过长历史消息累积约 25%
多文件加载多文件叠加约 20%
搜索结果多大量匹配约 10%
API响应大返回数据多约 8%
系统提示长模板过大约 7%

深层原理

大语言模型的上下文窗口是其能处理的最大 Token 数量。Token 是文本的最小语义单元,英文中约 1 个单词 ≈ 1.3 个 Token,中文中约 1 个字符 ≈ 1.5-2 个 Token,代码中因符号和缩进而可能更多。当所有输入(系统提示 + 对话历史 + 用户输入 + 加载的文件)的总 Token 数超过模型的上下文窗口限制时,模型无法处理。不同模型有不同限制:GPT-4 为 128K,Claude 为 200K。超出限制时,系统要么拒绝请求,要么自动截断内容(可能丢失关键信息),导致分析不完整或回答不准确。

3. 解决方案

方案一:智能上下文管理(最推荐)

# 配置 OpenClaw 的上下文管理 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context'] = { 'maxTokens': 120000, # 保守限制(低于128K) 'reserveOutput': 8000, # 预留输出Token 'maxInputTokens': 112000, # 最大输入=120K-8K 'strategy': 'sliding', # sliding | summarization | selective 'autoManage': True, # 自动管理 'truncateThreshold': 0.9, # 90%时开始截断 'warnThreshold': 0.8, # 80%时警告 'fileChunkSize': 10000, # 文件分块大小 'maxFileTokens': 30000, # 单文件最大Token 'maxFilesInContext': 5, # 上下文最大文件数 'historyRetention': 20, # 保留最近20轮对话 'summarizeThreshold': 50, # 50轮后摘要 'compressionLevel': 'medium' # low | medium | high } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('上下文管理: 滑动窗口+自动截断+文件分块+对话摘要') " # 查看当前上下文使用情况 openclaw --context-stats # 输出: # System prompt: 2000 tokens # Conversation history: 45000 tokens (35 turns) # Loaded files: 30000 tokens (3 files) # Available: 51000 tokens # Total: 77000 / 120000 (64%)

方案二:对话历史压缩和摘要

# 创建对话历史管理器 import json import os from datetime import datetime class ConversationManager: """对话历史管理器""" def __init__(self, max_history_tokens=50000, max_turns=30): self.max_history_tokens = max_history_tokens self.max_turns = max_turns self.history = [] self.summaries = [] def add_message(self, role, content, tokens=None): """添加消息""" if tokens is None: # 简化的 Token 估算 tokens = self.estimate_tokens(content) message = { 'role': role, 'content': content, 'tokens': tokens, 'timestamp': datetime.now().isoformat() } self.history.append(message) # 检查是否需要压缩 total_tokens = sum(m['tokens'] for m in self.history) if total_tokens > self.max_history_tokens or len(self.history) > self.max_turns: self.compress_history() def compress_history(self): """压缩历史对话""" # 保留最近的 N 条消息 keep_recent = min(10, len(self.history) // 3) recent = self.history[-keep_recent:] to_summarize = self.history[:-keep_recent] # 生成摘要 if to_summarize: summary = self.generate_summary(to_summarize) self.summaries.append({ 'summary': summary, 'original_count': len(to_summarize), 'original_tokens': sum(m['tokens'] for m in to_summarize), 'summary_tokens': self.estimate_tokens(summary), 'timestamp': datetime.now().isoformat() }) self.history = recent print(f" 📦 压缩: {len(to_summarize)} 条消息 -> 摘要") def generate_summary(self, messages): """生成对话摘要""" # 构建摘要提示 summary_parts = [] for msg in messages: role = msg['role'] content = msg['content'][:500] # 截取前500字符 summary_parts.append(f"[{role}]: {content}") # 简化的摘要(实际应调用LLM) full_text = '\n'.join(summary_parts) # 关键信息提取 key_points = [] if 'error' in full_text.lower(): key_points.append('讨论了错误处理') if 'config' in full_text.lower(): key_points.append('涉及配置修改') if 'test' in full_text.lower(): key_points.append('包含测试相关内容') summary = f"之前{len(messages)}轮对话摘要: {'; '.join(key_points) if key_points else '讨论了项目相关问题'}" return summary def estimate_tokens(self, text): """估算Token数""" # 简化估算: 英文~4字符/Token, 中文~2字符/Token chinese_chars = sum(1 for c in text if '\u4e00' <= c <= '\u9fff') other_chars = len(text) - chinese_chars return int(chinese_chars * 1.5 + other_chars / 4) def get_context(self): """获取当前上下文""" # 合并摘要 + 最近历史 context_parts = [] # 添加摘要 for s in self.summaries: context_parts.append(s['summary']) # 添加最近历史 for msg in self.history: context_parts.append(f"[{msg['role']}]: {msg['content']}") total_tokens = sum(s['summary_tokens'] for s in self.summaries) total_tokens += sum(m['tokens'] for m in self.history) return { 'context': '\n'.join(context_parts), 'total_tokens': total_tokens, 'summaries_count': len(self.summaries), 'history_count': len(self.history) } def save(self, filepath): """保存对话状态""" data = { 'history': self.history, 'summaries': self.summaries } with open(filepath, 'w') as f: json.dump(data, f, indent=2, ensure_ascii=False) def load(self, filepath): """加载对话状态""" if os.path.exists(filepath): with open(filepath, 'r') as f: data = json.load(f) self.history = data.get('history', []) self.summaries = data.get('summaries', []) # 使用示例 if __name__ == "__main__": manager = ConversationManager(max_history_tokens=50000, max_turns=20) # 模拟长对话 for i in range(25): manager.add_message('user', f'这是第{i+1}轮对话,包含一些问题和代码示例...') manager.add_message('assistant', f'这是第{i+1}轮回复,包含解决方案和说明...') context = manager.get_context() print(f"总Token: {context['total_tokens']}") print(f"摘要数: {context['summaries_count']}") print(f"历史数: {context['history_count']}")

方案三:文件智能分块加载

# 创建文件分块加载器 import os class FileChunkLoader: """智能文件分块加载器""" def __init__(self, max_tokens=30000, chunk_size=5000): self.max_tokens = max_tokens self.chunk_size = chunk_size def estimate_tokens(self, text): """估算Token数""" chinese = sum(1 for c in text if '\u4e00' <= c <= '\u9fff') other = len(text) - chinese return int(chinese * 1.5 + other / 4) def load_file_chunked(self, filepath, chunk_index=0): """分块加载文件""" with open(filepath, 'r', encoding='utf-8', errors='replace') as f: content = f.read() total_tokens = self.estimate_tokens(content) if total_tokens <= self.max_tokens: return { 'content': content, 'tokens': total_tokens, 'chunk_index': 0, 'total_chunks': 1, 'complete': True } # 分块 lines = content.split('\n') chunks = [] current_chunk = [] current_tokens = 0 for line in lines: line_tokens = self.estimate_tokens(line) if current_tokens + line_tokens > self.chunk_size: if current_chunk: chunks.append('\n'.join(current_chunk)) current_chunk = [line] current_tokens = line_tokens else: current_chunk.append(line) current_tokens += line_tokens if current_chunk: chunks.append('\n'.join(current_chunk)) # 返回指定块 if chunk_index < len(chunks): chunk_content = chunks[chunk_index] return { 'content': chunk_content, 'tokens': self.estimate_tokens(chunk_content), 'chunk_index': chunk_index, 'total_chunks': len(chunks), 'complete': chunk_index == len(chunks) - 1, 'file_path': filepath, 'start_line': sum(len(c.split('\n')) for c in chunks[:chunk_index]) + 1 } return None def load_file_selective(self, filepath, keywords=None, context_lines=10): """选择性加载文件(基于关键词)""" with open(filepath, 'r', encoding='utf-8', errors='replace') as f: lines = f.readlines() if not keywords: # 如果没有关键词,加载前 max_tokens 部分 content = '' for line in lines: if self.estimate_tokens(content + line) > self.max_tokens: break content += line return { 'content': content, 'tokens': self.estimate_tokens(content), 'total_lines': len(lines), 'loaded_lines': content.count('\n') + 1, 'complete': content.count('\n') + 1 >= len(lines) } # 基于关键词选择相关部分 relevant_sections = [] for i, line in enumerate(lines): if any(kw.lower() in line.lower() for kw in keywords): start = max(0, i - context_lines) end = min(len(lines), i + context_lines + 1) section = ''.join(lines[start:end]) relevant_sections.append({ 'content': section, 'start_line': start + 1, 'end_line': end, 'keyword_lines': [i + 1] }) # 合并重叠的部分 merged = self._merge_sections(relevant_sections) total_tokens = sum(self.estimate_tokens(s['content']) for s in merged) # 如果仍然太大,截断 if total_tokens > self.max_tokens: result_content = '' for section in merged: if self.estimate_tokens(result_content + section['content']) > self.max_tokens: break result_content += section['content'] total_tokens = self.estimate_tokens(result_content) else: result_content = '\n---\n'.join(s['content'] for s in merged) return { 'content': result_content, 'tokens': total_tokens, 'sections': len(merged), 'total_lines': len(lines), 'keywords': keywords } def _merge_sections(self, sections): """合并重叠的段落""" if not sections: return [] merged = [sections[0]] for section in sections[1:]: if section['start_line'] <= merged[-1]['end_line'] + 1: # 重叠或相邻,合并 merged[-1]['end_line'] = section['end_line'] # 需要重新获取合并后的内容 else: merged.append(section) return merged # 使用示例 if __name__ == "__main__": loader = FileChunkLoader(max_tokens=30000, chunk_size=5000) # 测试分块加载 import sys filepath = sys.argv[1] if len(sys.argv) > 1 else __file__ result = loader.load_file_chunked(filepath) print(f"文件: {filepath}") print(f"总块数: {result['total_chunks']}") print(f"当前块: {result['chunk_index']}") print(f"Token: {result['tokens']}") print(f"完整: {result['complete']}") # 选择性加载 result = loader.load_file_selective(filepath, keywords=['class', 'def']) print(f"\n选择性加载:") print(f"Token: {result['tokens']}") print(f"段落数: {result['sections']}")

方案四:配置上下文优先级

# 配置上下文优先级策略 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context']['priority'] = { 'systemPrompt': 1, # 最高优先级 'currentUserInput': 2, # 当前用户输入 'recentHistory': 3, # 最近对话(5轮内) 'loadedFiles': 4, # 加载的文件 'olderHistory': 5, # 较早的对话 'searchResults': 6, # 搜索结果 'summaries': 7 # 摘要(最低) } config['context']['eviction'] = { 'strategy': 'priority', # 按优先级淘汰 'evictWhen': 0.85, # 85%时开始淘汰 'evictWhat': 'olderHistory', # 先淘汰旧历史 'compressBefore': True, # 淘汰前先压缩 'notifyUser': True # 通知用户内容被移除 } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('上下文优先级: 系统提示>用户输入>最近历史>文件>旧历史>搜索>摘要') " # 手动管理上下文 openclaw --context-clear # 清除所有上下文 openclaw --context-clear-history # 仅清除对话历史 openclaw --context-clear-files # 仅清除加载的文件 openclaw --context-keep 5 # 保留最近5轮 openclaw --context-summarize # 手动触发摘要

方案五:使用检索增强生成(RAG)

# 创建简易 RAG 系统减少上下文使用 import os import json import hashlib class SimpleRAG: """简易检索增强生成系统""" def __init__(self, index_dir='.openclaw/rag_index'): self.index_dir = index_dir os.makedirs(index_dir, exist_ok=True) self.index = [] self.load_index() def index_file(self, filepath): """索引文件内容""" with open(filepath, 'r', encoding='utf-8', errors='replace') as f: content = f.read() # 按段落分割 paragraphs = content.split('\n\n') for para in paragraphs: if len(para.strip()) < 50: continue # 创建文档块 doc = { 'file': filepath, 'content': para, 'hash': hashlib.md5(para.encode()).hexdigest()[:8], 'keywords': self.extract_keywords(para) } self.index.append(doc) self.save_index() print(f"已索引 {filepath}: {len(paragraphs)} 段落") def search(self, query, top_k=3): """搜索相关文档""" query_keywords = self.extract_keywords(query) scores = [] for doc in self.index: score = self.calculate_relevance(query_keywords, doc['keywords']) if score > 0: scores.append((score, doc)) # 排序并返回 top_k scores.sort(reverse=True, key=lambda x: x[0]) results = [] for score, doc in scores[:top_k]: results.append({ 'file': doc['file'], 'content': doc['content'], 'score': score, 'keywords': doc['keywords'] }) return results def extract_keywords(self, text): """提取关键词(简化版)""" # 移除常见停用词 stopwords = {'the', 'a', 'an', 'is', 'are', 'was', 'were', 'and', 'or', 'but', 'in', 'on', 'at', 'to', '的', '了', '是', '在', '有', '和', '与'} words = text.lower().split() keywords = [w for w in words if w not in stopwords and len(w) > 2] return keywords def calculate_relevance(self, query_kw, doc_kw): """计算相关性""" if not query_kw or not doc_kw: return 0 common = set(query_kw) & set(doc_kw) return len(common) / max(len(query_kw), 1) def save_index(self): """保存索引""" with open(os.path.join(self.index_dir, 'index.json'), 'w') as f: json.dump(self.index, f, ensure_ascii=False) def load_index(self): """加载索引""" index_file = os.path.join(self.index_dir, 'index.json') if os.path.exists(index_file): with open(index_file, 'r') as f: self.index = json.load(f) # 使用示例 if __name__ == "__main__": rag = SimpleRAG() # 索引项目文件 import glob for f in glob.glob('src/**/*.py', recursive=True)[:10]: rag.index_file(f) # 搜索 results = rag.search("如何处理错误") for r in results: print(f" [{r['score']:.2f}] {r['file']}") print(f" {r['content'][:100]}...")

方案六:Token 计数和监控

# 配置 Token 监控 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['tokenMonitoring'] = { 'enabled': True, 'countOnEveryRequest': True, 'logToFile': True, 'logFile': '.openclaw/logs/token_usage.json', 'warnAt': 0.8, # 80%警告 'criticalAt': 0.95, # 95%严重 'trackByType': True, # 按类型跟踪 'trackByFile': True, # 按文件跟踪 'dailyReport': True, # 每日报告 'reportFile': '.openclaw/logs/token_daily.json' } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('Token 监控已启用: 80%警告, 95%严重, 每日报告') " # 查看 Token 使用统计 openclaw --token-stats # 输出: # 今日使用: 450000 tokens # 输入: 380000 (84%) # 输出: 70000 (16%) # 平均每请求: 8500 tokens # 最大单次: 120000 tokens # 峰值时间: 14:00-15:00 # 查看详细报告 cat .openclaw/logs/token_usage.json | python3 -m json.tool | head -30 # 创建 Token 预算 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['tokenBudget'] = { 'daily': 2000000, # 每日200万Token 'perRequest': 128000, # 每请求128K 'perFile': 30000, # 每文件30K 'perConversation': 500000, # 每对话50万 'actionOnExceed': 'warn' # warn | block | summarize } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('Token 预算: 每日200万, 每请求128K, 每文件30K') "

4. 各方案对比总结

方案适用场景推荐指数
方案一:上下文管理通用配置⭐⭐⭐⭐⭐
方案二:对话压缩长对话⭐⭐⭐⭐⭐
方案三:文件分块大文件⭐⭐⭐⭐⭐
方案四:优先级策略复杂场景⭐⭐⭐⭐
方案五:RAG大代码库⭐⭐⭐⭐
方案六:Token监控运维⭐⭐⭐⭐

5. 常见问题 FAQ

5.1 Windows 上 Token 计数差异

Windows 换行符可能导致 Token 计数不同:

# Windows 使用 \r\n,可能增加 Token # 配置统一换行符 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context']['normalizeLineEndings'] = True # 统一为 \n config['context']['stripBOM'] = True with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('换行符标准化已启用') "

5.2 Docker 中上下文丢失

容器重启后对话历史丢失:

# 持久化对话历史 docker run -v openclaw_data:/app/.openclaw openclaw "任务" # 配置对话持久化 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context']['persistence'] = { 'enabled': True, 'saveDir': '.openclaw/conversations/', 'autoSave': True, 'saveInterval': 300000, # 5分钟自动保存 'maxSavedConversations': 50, # 保留50个对话 'compressSaved': True # 压缩保存 } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('对话持久化: 自动保存+压缩+保留50个') "

5.3 CI/CD 中上下文管理

CI 中每次都是新对话:

# CI 中使用一次性上下文 env: OPENCLAW_CONTEXT_MODE: single # 单次模式 steps: - name: Run with minimal context run: | openclaw --no-history --max-tokens 50000 "一次性任务" - name: Save context for reuse run: | openclaw --context-export .openclaw/context_snapshot.json - name: Restore context run: | openclaw --context-import .openclaw/context_snapshot.json

5.4 多文件加载超出限制

同时加载多个文件导致超限:

# 配置多文件加载策略 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context']['multiFile'] = { 'strategy': 'priority', # priority | round-robin | selective 'maxFiles': 5, # 最大文件数 'maxTotalTokens': 50000, # 文件总Token上限 'perFileLimit': 15000, # 每文件Token上限 'priorityBy': 'relevance', # relevance | size | recency 'lazyLoad': True, # 懒加载(需要时才加载) 'autoUnload': True # 自动卸载不相关的文件 } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('多文件加载: 最多5文件, 总50K Token, 懒加载') " # 使用选择性加载 openclaw --load src/index.ts --load src/utils.ts "分析这两个文件" # 如果超出限制,自动截断

5.5 代码 Token 消耗过大

代码文件 Token 密度高:

# 代码精简工具 class CodeCompactor: """代码精简工具,减少Token""" @staticmethod def compact_code(code): """精简代码""" lines = code.split('\n') compacted = [] for line in lines: # 移除空行 if not line.strip(): continue # 移除注释(保留重要注释) stripped = line.strip() if stripped.startswith('//') and not stripped.startswith('//!'): continue if stripped.startswith('#') and not any(stripped.startswith(f'#{m}') for m in ['!', 'TODO', 'FIXME']): continue # 移除多余空格 line = ' '.join(line.split()) # 简化常见模式 line = line.replace('function ', 'fn ') line = line.replace('return ', 'ret ') line = line.replace('const ', 'c ') line = line.replace('let ', 'l ') compacted.append(line) return '\n'.join(compacted) @staticmethod def extract_signatures(code): """只提取函数签名和类定义""" import re lines = code.split('\n') signatures = [] patterns = [ r'^\s*(export\s+)?(async\s+)?function\s+\w+', # 函数 r'^\s*(export\s+)?class\s+\w+', # 类 r'^\s*(export\s+)?(const|let|var)\s+\w+\s*=', # 变量 r'^\s*(export\s+)?interface\s+\w+', # 接口 r'^\s*(export\s+)?type\s+\w+', # 类型 ] for line in lines: if any(re.match(p, line) for p in patterns): signatures.append(line) return '\n'.join(signatures) # 使用 code = open('src/index.ts').read() signatures = CodeCompactor.extract_signatures(code) print(f"完整代码: {len(code)} 字符") print(f"签名摘要: {len(signatures)} 字符 (节省 {100 - len(signatures)*100//len(code)}%)")

5.6 不同模型 Token 限制不同

切换模型可能导致限制变化:

# 配置模型特定的 Token 限制 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['models'] = { 'gpt-4': {'contextWindow': 128000, 'maxOutput': 4096}, 'gpt-4-turbo': {'contextWindow': 128000, 'maxOutput': 4096}, 'claude-3': {'contextWindow': 200000, 'maxOutput': 4096}, 'claude-3.5': {'contextWindow': 200000, 'maxOutput': 8192} } config['context']['autoDetectModel'] = True config['context']['adjustForModel'] = True with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('模型Token限制已配置: 自动检测+调整') " # 切换模型时自动调整 openclaw --model claude-3 "任务" # 200K 限制 openclaw --model gpt-4 "任务" # 128K 限制

5.7 上下文丢失关键信息

压缩后丢失重要上下文:

# 配置摘要保留策略 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['context']['summarization'] = { 'preserveCodeBlocks': True, # 保留代码块 'preserveErrorMessages': True, # 保留错误信息 'preserveFilePaths': True, # 保留文件路径 'preserveDecisions': True, # 保留决策记录 'preserveUserPreferences': True, # 保留用户偏好 'summarizeStyle': 'detailed', # detailed | brief | bullet 'maxSummaryTokens': 2000 # 摘要最大Token } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('摘要保留: 代码块+错误+路径+决策+偏好') " # 手动标记重要信息 openclaw --pin "这段代码很重要" # 标记为重要,不会被压缩 openclaw --pinned-list # 查看已标记的内容

5.8 API 请求 Token 费用过高

Token 消耗直接关联费用:

# 配置费用控制 python3 -c " import json with open('.openclaw/config.json', 'r') as f: config = json.load(f) config['costControl'] = { 'dailyBudget': 10.0, # 每日10美元 'perRequestBudget': 1.0, # 每请求1美元 'alertThreshold': 0.8, # 80%告警 'blockThreshold': 0.95, # 95%阻止 'costPerMToken': { 'input': 0.01, # 输入$0.01/1K Token 'output': 0.03 # 输出$0.03/1K Token }, 'optimizeMode': 'balanced' # cheap | balanced | quality } with open('.openclaw/config.json', 'w') as f: json.dump(config, f, indent=2) print('费用控制: 每日$10, 每请求$1, 80%告警') " # 查看费用统计 openclaw --cost-stats # 输出: # 今日费用: $3.50 # 输入: $2.80 (280K tokens) # 输出: $0.70 (23K tokens) # 预算使用: 35% # 预计月费: $105

排查清单速查表

□ 1. 检查上下文使用: openclaw --context-stats □ 2. 配置 maxTokens=120000(保守值) □ 3. 设置对话压缩: summarizeThreshold=50 □ 4. 文件分块加载: chunkSize=5000 □ 5. 配置优先级淘汰策略 □ 6. 使用 RAG 检索替代全量加载 □ 7. 启用 Token 监控和预算 □ 8. 代码精简: 只加载签名 □ 9. 对话持久化防止丢失 □ 10. 费用控制: 设置每日预算

6. 总结

  1. 最常见原因:大文件加载(30%)和对话历史累积(25%)导致总 Token 超限
  2. 智能管理:配置滑动窗口策略,80% 警告,90% 开始淘汰低优先级内容
  3. 对话压缩:达到阈值后自动将旧对话摘要化,保留代码块、错误信息和决策记录
  4. 文件分块:大文件按 5000 Token 分块加载,支持基于关键词的选择性加载
  5. 最佳实践建议:使用 RAG 系统索引代码库按需检索,启用 Token 监控和每日预算控制费用,代码分析时只加载函数签名而非完整实现,持久化对话历史防止重启丢失

故障排查流程图

flowchart TD A[上下文超限] --> B[检查Token使用] B --> C[openclaw --context-stats] C --> D{哪部分超限?} D -->|对话历史| E[压缩历史] D -->|文件加载| F[分块加载] D -->|总Token| G[全局管理] E --> H[summarizeThreshold=50] H --> I[保留代码/错误/决策] I --> J[openclaw测试] F --> K[chunkSize=5000] K --> L[选择性关键词加载] L --> J G --> M[配置滑动窗口] M --> N[优先级淘汰策略] N --> J J --> O{成功?} O -->|是| P[✅ 问题解决] O -->|否| Q[使用RAG检索] Q --> R[索引代码库] R --> S[按需检索相关段落] S --> T[只加载签名] T --> J P --> U[部署Token监控] U --> V[配置每日预算] V --> W[✅ 长期可控]