OpenClaw 上下文瘦身:3 个实验
这篇不是讲“提示词怎么写得更优雅”。我只看一个更硬的问题Agent 跑久以后上下文到底是怎么胖起来的哪一刀最值得先砍。实验脚本和结果都放在本地目录里可以复跑。你大概见过这种故障Agent 前 10 分钟很听话工具也能正常调。跑到后面开始变慢、重复解释、忘记刚才的发布规则甚至把已经验证过的 URL 又验证一遍。很多人第一反应是“模型不稳”。我现在更倾向于先怀疑上下文管线。模型只是消费上下文的人真正把它喂撑的通常是这三类东西全量历史每轮重发工具结果原样塞回对话工具 schema 和说明越写越长我用一个很小的 Python 脚本跑了 3 个实验。不是线上 API benchmark也不拿它证明某个模型强弱它只回答一个工程问题在 Agent 系统里哪些上下文最容易失控。实验目录experiments/run_experiments.py。什么是 OpenClaw 上下文工程OpenClaw 上下文工程指的是在多工具、多轮、多 agent 的运行过程中控制“发给模型的输入材料”历史消息、工具 schema、工具返回值、规则锚点、摘要状态和验证证据。它不是单纯缩短 prompt。更准确地说它是一套预算系统哪些内容必须每轮出现哪些内容只保留摘要哪些内容应该写入文件或 receipt而不是继续塞进下一轮对话。实验环境只测 payload不测模型能力为了避免把话说大我把实验限定得很窄Python 3 标准库json.dumps(..., ensure_asciiFalse)序列化UTF-8 bytes 作为 payload 大小指标固定随机种子519合成 40 轮 Agent 对话每轮包含用户请求、工具结果、助手回复这里没有调用线上模型所以我不会写“某模型实测提升多少”。我测的是输入材料本身的体积变化。完整实验骨架如下importjson,random,string random.seed(519)defcjk(n:int)-str:words上下文 工具调用 文件搜索 发布脚本 运行日志 失败重试 摘要 压缩 预算 规则 锚点 验证 响应 状态 证据 结构化 输出.split()s[]whilelen(.join(s))n:s.append(random.choice(words))s.append()return.join(s)[:n]defmake_turn(i:int):tool{tool:search_files,args:{pattern:context|token|publish,path:f/repo/module_{i%7}},matches:[{path:fsrc/module_{i%7}/file_{j}.ts,line:20j,content:cjk(90),score:round(random.random(),4),mtime:2026-05-19T09:00:0008:00,debug:{rank:j,trace:x*48},}forjinrange(10)],}return[{role:user,content:f第{i}轮请继续定位上下文膨胀问题。},{role:tool,name:search_files,content:json.dumps(tool,ensure_asciiFalse)},{role:assistant,content:cjk(420)},]这个构造不复杂但很接近真实 Agent 的痛点文件搜索、日志检索、发布脚本输出都很容易返回一大坨结构化文本。实验 1全量历史不是慢慢变贵是迟早把你拖死我比较了三种历史策略轮数全量历史 bytes最近 6 轮 bytes摘要 最近 6 轮 bytes16,8296,9847,197534,15534,31034,5231068,31341,14541,35820136,63241,14641,35940273,26941,14541,358这里有个反直觉点前 5 轮全量历史看起来没什么问题甚至比“摘要 窗口”更小一点。因为摘要和规则锚点本身也占空间。但从第 10 轮开始差距就拉开了。到第 40 轮全量重放已经到273,269 bytes最近 6 轮策略稳定在41,145 bytes左右。也就是说在这个合成场景里滑动窗口把历史 payload 压到了全量的约15.1%。这就是很多 Agent 故障“不在开头暴露”的原因。系统刚启动时你怎么写都行。历史还短工具结果还少规则还在上下文前面。等它跑到第 20 轮、第 40 轮规则被挤远、工具日志开始堆积、模型要在一堆旧证据里找当前任务。它不是突然变笨是你给它的输入变脏了。最小修复代码很短CRITICAL关键规则 1) 缺证据不下结论。 2) 工具结果先摘要再回灌。 3) 发布后必须打开公开页验证。 defbuild_messages(turns,keep6,summary):recentturns[-keep*3:]messages[{role:system,content:CRITICAL}]ifsummary:messages.append({role:system,content:会话摘要summary})messages.extend(recent)returnmessages我不建议一上来就做复杂记忆系统。先做 3 件事就够了关键规则每轮重复短一点最近 N 轮完整保留更早的内容只保留摘要和 receipt 路径在 OpenClaw 这种会跨渠道、跨 agent、跨 cron 跑的系统里receipt 路径很重要。比如发布结果、截图、日志不要全塞进对话写入文件再把文件路径和 2 行摘要放回上下文。实验 2工具结果原样回灌是最容易砍的一刀第二个实验更直接构造 80 条 search match每条带 path、line、content、before、after、score、mtime、sha、debug trace。然后做一个紧凑版只保留总匹配数top 8path / line / score45 字 snippet结果工具结果版本bytes相对原始体积原始 JSON98,387100%摘要 JSON2,0432.1%减少比例-97.9%这个结果比我预期更夸张。原因不是 JSON 本身“坏”而是工具结果里混了太多对下一步决策没用的字段。mtime、sha、debug.trace、完整上下文行在定位工具自身 bug 时有价值但在让 Agent 决定“下一步读哪个文件”时它们大多是噪声。我现在更喜欢把工具分成两层输出defcompact_search_result(raw:dict,top_k:int8)-dict:matchesraw.get(matches,[])matchessorted(matches,keylambdax:x.get(score,0),reverseTrue)return{query:raw.get(query),match_count:len(matches),top_matches:[{path:m[path],line:m[line],score:round(m.get(score,0),3),snippet:m.get(content,)[:80],}forminmatches[:top_k]],}如果下一步真的需要完整证据再让 Agent 读文件或打开日志。不要因为“可能有用”就把所有字段每轮都带着跑。这里有个实际经验很多失败不是“缺信息”而是“信息太多但没有优先级”。模型看到 80 条 match每条都有很多字段它会尝试做阅读理解你给它 top 8 score snippet它更像是在做决策。实验 3schema 也会胖而且胖得很安静第三个实验测工具 schema。每个工具包含 name、description、6 个参数说明。工具数从 6 增加到 100。工具数量schema bytesPython JSON parse p50p95611,7710.015 ms0.031 ms1223,5330.029 ms0.043 ms2447,0650.053 ms0.064 ms60117,6610.131 ms0.169 ms100196,1010.227 ms0.269 ms别误会parse 时间不是重点。Python 本地解析这点 JSON 很快。真正的问题是这些 schema 最终会变成模型输入。100 个工具的说明在这个构造里已经接近196KB。如果每轮都带上再叠加历史和工具结果你的上下文预算会被“静态说明书”吃掉一大块。这也是为什么我不喜欢给一个 agent 挂 50 个“可能会用到”的工具。工具越多不只是选择更难输入也更脏。更稳的做法是按任务装载工具TOOLSETS{publish:[read_file,write_file,browser_publish,screenshot],debug:[read_file,search_files,run_command,process_log],research:[web_search,web_fetch,note_save],}defselect_tools(intent:str)-list[str]:if发布inintentorCSDNinintentor掘金inintent:returnTOOLSETS[publish]if报错inintentor日志inintentor定位inintent:returnTOOLSETS[debug]returnTOOLSETS[research]这段代码很粗糙但方向对先缩工具面再让模型选工具。我更推荐把“工具选择”前置成路由问题而不是把所有工具摊开让模型自己挑。尤其是 OpenClaw 这种多 agent 场景writing-studio、coder、brain、publisher本来就应该有不同工具边界。一个可落地的上下文预算表我会把 Agent 输入拆成 5 个桶每个桶给一个粗预算。这里的数字不是行业标准是这次实验后我自己的默认值输入桶建议预算超预算时怎么处理关键规则1-2KB只留不可破坏的规则删解释当前任务2-6KB让用户意图保持原文不要摘要过度最近历史30-50KB滑动窗口保留最近 4-8 轮工具结果单次 2-8KBtop_k snippet 证据路径工具 schema10-60KB按任务装载不全量挂载如果你只能改一处我建议先改“工具结果”。原因很简单它收益最大、风险最小。历史摘要可能会丢细节工具裁剪则可以保留原始文件路径需要时再读。你不是删除证据只是不把证据全文塞进下一轮。我会怎么改一个真实 Agent拿一个发布型 agent 举例。它需要写文章、生成封面、发 CSDN、发掘金、验证公开页。最容易出问题的地方不是写作而是发布后状态回灌。错误做法# 不要这样把整段浏览器日志、HTML、Network 输出全部塞回对话messages.append({role:tool,content:full_browser_logfull_htmlfull_network_trace,})更好的做法frompathlibimportPathimportjsondefsave_receipt(platform:str,payload:dict,run_dir:str)-dict:pathPath(run_dir)/receipts/f{platform}.jsonpath.parent.mkdir(parentsTrue,exist_okTrue)path.write_text(json.dumps(payload,ensure_asciiFalse,indent2),encodingutf-8)return{platform:platform,status:payload.get(status),url:payload.get(url),receipt_path:str(path),evidence:payload.get(evidence,[])[:3],}对 Agent 来说下一轮只需要知道成功没、URL 是什么、证据在哪。如果它要复盘再读 receipt 文件。这个模式还有一个好处人也更容易审计。你不用在一大段对话里找“到底发没发成功”直接看 receipts。非显而易见的发现摘要不是越早越好实验 1 里第 1 轮和第 5 轮“摘要 最近 6 轮”比全量历史略大。这说明一个小坑别把摘要当成银弹。对短会话摘要本身也是负担。真正该做的是阈值触发低于 6 轮不摘要超过 6 轮滑动窗口出现跨阶段任务生成阶段摘要发布、部署、删除这类动作写 receipt不靠记忆伪代码如下defshould_summarize(turn_count:int,stage_changed:bool,payload_bytes:int)-bool:ifstage_changed:returnTrueifturn_count6:returnFalsereturnpayload_bytes50_000这个判断比“每 5 轮自动摘要一次”更实用。因为真正的切点不是轮数而是阶段和 payload。OpenClaw 场景里的 4 条规则我现在会给 OpenClaw agent 加这 4 条默认规则工具结果默认摘要完整原文写文件每个 agent 只挂当前任务需要的工具集发布、部署、外部副作用必须写 receipt最终状态必须二次验证不能只信脚本返回第 4 条尤其重要。发布脚本返回 success只能说明“提交动作完成”公开页是否可见、是否审核通过还要打开 URL 看一次。这不是洁癖是为了防 phantom publish。自动化最危险的不是失败而是假成功。常见问题Q: 为什么不用 token 计数而用 bytesA: 这次实验只想测 payload 体积变化不比较模型。bytes 可以稳定复现也不依赖具体 tokenizer。真实上线时应该把 bytes 和模型 tokenizer 计数都打进日志。Q: 工具结果摘要会不会漏掉关键证据A: 会所以不要只保留摘要。正确做法是“摘要进上下文原文进文件”。Agent 需要细节时再按路径读取。这样既保留证据又不污染每一轮输入。Q: OpenClaw Agent 最先该优化哪里A: 先看 receipts 和工具日志。如果一次工具调用返回超过 20KB却只用其中 3 行做决策就先做 compaction。比改 prompt 更快见效。结论别先调模型先管输入这 3 个小实验给我的结论很朴素Agent 变慢、变飘、重复工作很多时候不是“智商问题”而是输入治理问题。全量历史会线性膨胀工具结果原样回灌最浪费schema 数量太多会安静吃掉预算。我自己后面会把这套规则直接放进 OpenClaw 写作和发布 agent工具结果先压缩关键动作写 receipt公开页再验证。等这些基础管住了再讨论换模型、换路由、换工作流才有意义。