Openclaw Pre-compaction memory 核心代码分析:从触发条件到记忆落盘的完整链路
1. 从一次记忆丢失说起Openclaw Pre-compaction memory 到底在做什么如果你在本地跑过 Openclaw 的长会话大概率遇到过这种诡异现象聊到第 40 轮前面明确交代过的项目路径、命名规范、接口约定突然就忘了。你回头翻会话记录发现上下文并没有被截断但模型就是答非所问。更麻烦的是日志里既没有报错也没有明显的压缩事件只有一条不起眼的compaction事件一闪而过。这个问题的根子就在 Openclaw 的 Pre-compaction memory 机制上。它是一套会话接近自动压缩前先把重要信息落盘的防护逻辑核心代码集中在src/auto-reply/reply/memory-flush.ts编译产物对应node_modules/openclaw/dist/extensionAPI.js。它要解决的核心矛盾是上下文窗口是有限的但会话里积累的持久信息比如这个项目用 pnpm 不用 npm是无限的。如果不做落盘压缩一发生这些信息就被摘要算法当成低价值 token丢掉了。Pre-compaction memory 适合谁三类人最需要吃透它一是本地复现 Openclaw 记忆机制的开发者二是被记忆丢失/重复压缩折磨的 Agent 调试者三是想把 Openclaw 的 compaction 策略迁移到自己项目里的工程师。它不是一个黑盒开关而是一条从token 计数到阈值判定再到落盘元数据的完整链路每一环都有可观测、可配置、可排障的抓手。我试过在本地把一个 200k 上下文窗口的会话硬聊到触发点观察memoryFlushAt和memoryFlushCompactionCount两个字段的变化才真正理解为什么有些场景会重复压缩、有些场景干脆不落盘。下面按源码链路拆开讲每一步都给出可复制的配置和验证动作。2. 前置准备TaoToken 接入与 Openclaw 运行环境搭建在拆源码之前得先把运行环境跑通否则你连compaction事件都看不到。Openclaw 的模型调用走的是标准 OpenAI 兼容协议所以任何兼容端点都能接。这里用 TaoToken 作为模型接入层原因是它的 Base URL 和 Key 管理足够干净方便你在调试 memory flush 时快速切换模型做对照实验。第一步拿到 API Key。访问 https://taotoken.net/api-keys 创建密钥注意这个页面是控制台里的密钥管理入口创建后只显示一次复制到本地环境变量里。第二步确认 Base URL 是https://taotoken.net/api注意这个地址不带任何查询参数是纯 API 根路径。第三步在 Openclaw 的配置文件里把 provider 指向这个端点。这里有个容易踩的坑Openclaw 的 provider 配置和模型 ID 是分开的Base URL 填错会导致local proxy failed或者 401但报错信息不会直接告诉你URL 错了而是抛一个模型调用失败。所以配置完先别急着聊长会话用一条最小请求验证连通性。# 验证 TaoToken 端点连通性确认 Key 和 Base URL 正确 curl -s https://taotoken.net/api/v1/models \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ | head -c 500如果返回模型列表 JSON说明接入层没问题。如果返回 401检查 Key 是否有多余空格如果返回 404检查 Base URL 是否误加了/v1之外的路径。这一步过了再进 Openclaw 的配置。Openclaw 的模型配置在openclaw.json的agents.defaults下provider 段需要写全三件套Base URL、API Key 引用、Model ID。很多人只填了 Key 和 Model忘了 Base URL结果 Openclaw 回落到默认端点触发local proxy failed。完整片段如下{ agents: { defaults: { provider: { baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, model: claude-sonnet-4-20250514 }, compaction: { memoryFlush: { enabled: true, softThresholdTokens: 4000 }, reserveTokensFloor: 8000 } } } }注意softThresholdTokens和reserveTokensFloor这两个值它们直接决定 memory flush 的触发时机后面会详细算。配置写完后用openclaw --print-config确认解析结果避免 JSON 语法错误导致配置被静默忽略。3. 可复制配置触发阈值、提示词与落盘路径的完整 settings 片段Pre-compaction memory 的触发逻辑全在shouldRunMemoryFlush这个函数里核心是一个减法公式。理解这个公式你就能精确控制什么时候落盘。阈值计算是这样的threshold contextWindow - reserveTokens - softThreshold。其中contextWindow是当前模型的上下文窗口 token 数reserveTokens是reserveTokensFloor默认保留给压缩后摘要的空间softThreshold是softThresholdTokens默认 4000。当会话的totalTokens超过这个 threshold且上一次 flush 的compactionCount不等于当前compactionCount才会触发。举个例子假设模型上下文窗口 200000reserveTokensFloor设 8000softThresholdTokens设 4000那么 threshold 200000 - 8000 - 4000 188000。也就是说会话累计到 188000 token 时memory flush 才会启动。如果你把softThresholdTokens调大到 20000threshold 变成 172000落盘会更早发生但代价是更频繁的额外模型调用。这里给出一个偏保守的配置适合本地调试时观察行为{ agents: { defaults: { compaction: { memoryFlush: { enabled: true, softThresholdTokens: 4000, prompt: Pre-compaction memory flush. Store durable memories now (use memory/YYYY-MM-DD.md; create memory/ if needed). If nothing to store, reply with NO_REPLY., systemPrompt: Pre-compaction memory flush turn. The session is near auto-compaction; capture durable memories to disk. You may reply, but usually NO_REPLY is correct. }, reserveTokensFloor: 8000 } } } }prompt和systemPrompt是发给模型的指令告诉它现在把持久信息写到memory/YYYY-MM-DD.md。注意ensureNoReplyHint会给这两个提示自动追加静默回复的约定所以模型在没有信息可存时会回NO_REPLY而不是硬编一段废话。这个设计很关键它避免了 flush 本身污染上下文。落盘路径由模型自己决定约定是memory/YYYY-MM-DD.md相对于 workspace 目录。如果memory/目录不存在模型需要自己创建。这里有个权限坑如果 Openclaw 跑在沙箱里workspaceAccess必须是rw否则memoryFlushWritable判定为 false整个 flush 直接跳过而且不会报错只在 verbose 日志里留一行。所以调试时先把 verbose 打开。# 打开 verbose 日志观察 memory flush 是否被跳过 openclaw --verbose --config ./openclaw.json如果你用的是 Claude Code 做本地开发可以把上面的配置片段直接放进项目的.claude/settings.json里做对照但注意 Openclaw 的配置键名和 Claude Code 不同别混用。需要看更多接入示例的话https://taotoken.net/doc 里有完整的协议说明。4. 验证请求从 compaction 事件到 memoryFlushAt 落盘的逐步确认配置就绪后怎么确认 memory flush 真的跑了不能只看模型回复要看会话存储里的元数据。Openclaw 在 flush 成功后会更新两个字段memoryFlushAt时间戳和memoryFlushCompactionCount触发时的压缩计数。这两个字段是判断是否落盘的唯一可信依据。验证分三步。第一步制造一个接近阈值的会话。最省事的办法是把softThresholdTokens临时调小比如设成 100这样几轮对话就能触发。第二步观察compaction事件流。在runEmbeddedPiAgent的onAgentEvent回调里当evt.stream compaction且phase end且willRetry为 false 时memoryCompactionCompleted会被置为 true随后incrementCompactionCount才会执行。第三步检查会话存储文件里的memoryFlushAt。# 触发一次 flush 后检查会话存储中的落盘元数据 cat ~/.openclaw/sessions/session-key.json | jq { compactionCount, memoryFlushAt, memoryFlushCompactionCount }如果memoryFlushAt有值且memoryFlushCompactionCount等于当时的compactionCount说明落盘成功。如果memoryFlushAt为空说明 flush 被跳过了回到第 3 步检查workspaceAccess和 verbose 日志。这里有个反直觉的点memoryFlushCompactionCount的作用是防止重复 flush。shouldRunMemoryFlush里有一行if (typeof lastFlushAt number lastFlushAt compactionCount) return false;意思是如果上一次 flush 已经记录在当前压缩计数上就不再触发。这解决的是同一轮压缩被多次判定的问题。但如果你发现记忆重复落盘往往是incrementCompactionCount没被调用导致compactionCount没变而memoryFlushAt被反复更新。验证模型侧是否真的写了文件可以直接看 workspace 下的memory/目录# 确认模型是否按约定写入了记忆文件 ls -la ./workspace/memory/ cat ./workspace/memory/$(date %F).md如果目录为空但memoryFlushAt有值说明模型收到了 flush 提示但判定无信息可存回了NO_REPLY。这不算 bug但如果你明确知道有信息该存就要检查prompt是否被ensureNoReplyHint改写得太激进或者模型本身对指令的遵循度不够。换一个遵循度更高的模型做对照能快速定位是提示词问题还是模型问题。5. 本篇常见错排查401、local proxy failed 与 reading choices 的真实报错对照调试 memory flush 时报错往往不直接指向根因。下面按真实遇到的报错逐条对照。401 Unauthorized最常见的是 Key 没读到。Openclaw 用apiKeyEnv引用环境变量如果变量名拼错或没 export请求会带空 Key。检查echo $TAOTOKEN_API_KEY是否有值以及openclaw.json里的apiKeyEnv是否和实际变量名一致。另一个隐蔽原因是 Key 前后有换行从网页复制时容易带上。local proxy failed这个报错通常出现在 Base URL 配置错误时。Openclaw 会尝试把请求发到配置的端点如果端点不可达或路径不对就抛这个。确认baseUrl是https://taotoken.net/api不要写成https://taotoken.net/api/v1或带尾斜杠。如果用了本地代理做请求转发检查代理是否在运行但更推荐直接用标准端点排除变量。reading choices of undefined这个报错说明响应体结构不符合预期代码在解析response.choices[0]时拿到 undefined。根因通常是端点返回了错误 JSON比如 401 的错误体但调用方没检查状态码就直接读choices。排查时先看原始响应# 打印原始响应确认返回结构 curl -s -w \nHTTP_STATUS:%{http_code}\n https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,messages:[{role:user,content:ping}]}如果 HTTP 状态是 401 但 body 里没有choices那就是 Key 问题如果状态 200 但choices为空检查 model ID 是否拼错。OAuth 相关报错如果你用的是需要 OAuth 的 providertoken 过期会抛 OAuth 错误。Openclaw 的runWithModelFallback会在主 provider 失败时尝试 fallback但如果 fallback 也没配最终错误会冒泡。检查resolveAgentModelFallbacksOverride的配置确保至少有一个可用的 fallback 模型。记忆重复落盘前面提过根因是compactionCount没递增。检查onAgentEvent里phase end !willRetry的条件是否满足。如果压缩事件带了willRetry: truememoryCompactionCompleted不会被置 trueincrementCompactionCount不执行但memoryFlushAt仍会被更新导致下次判定时lastFlushAt ! compactionCount再次触发。解决办法是确认压缩事件正常结束或者手动在配置里调大softThresholdTokens降低触发频率。沙箱权限导致静默跳过如果workspaceAccess不是rwmemoryFlushWritable为 false整个 flush 被跳过且无报错。这是最隐蔽的坑因为日志里只有一行 verbose。排查时先确认沙箱配置{ sandbox: { workspaceAccess: rw } }对照完这些报错你会发现大部分问题都集中在配置没生效和事件没走完两类。前者靠--print-config和 curl 验证后者靠 verbose 日志和会话存储元数据验证。6. 语义一致 CTA把 memory flush 调试沉淀成可复用的接入流程拆完这条链路你会发现 Pre-compaction memory 的设计思路其实很通用用 token 阈值做触发用压缩计数做去重用元数据做落盘确认。这套模式可以迁移到任何需要上下文压缩前抢救信息的 Agent 项目里。如果你在本地复现时卡在接入层建议先把模型端点跑通再调 memory flush否则你分不清是 flush 逻辑问题还是请求根本没发出去。模型对话调试入口在 https://taotoken.net/chat可以快速验证 Key 和模型 ID 是否匹配。需要长期跑编码类 Agent、反复触发 compaction 的场景用 Coding Plan 更划算入口在 https://taotoken.net/coding-plan。完整的接入协议和配置字段说明在 https://taotoken.net/doc遇到 401 或reading choices这类报错时对照文档里的响应结构能省不少时间。最后留一个实用技巧调试 memory flush 时把softThresholdTokens设成 100reserveTokensFloor设成 0这样几乎每轮对话都会触发你能在几分钟内观察到完整的触发-落盘-去重循环。等逻辑确认无误再改回生产值。这个办法比读十遍源码都管用。

相关新闻

免训练持续适应:边缘AI的零更新动态演化方案

免训练持续适应:边缘AI的零更新动态演化方案

1. 项目概述:当模型“学会遗忘”成为刚需“Continual Learning without Continual Training”——这个标题乍看像一句悖论,甚至带点哲学意味。但如果你正被真实业务场景反复捶打过,比如在边缘设备上部署一个需要随时间演进的视觉检测模型&…

2026/10/11 23:45:50 阅读更多 →
从环境到实战:一套高效的Python系统练习指南

从环境到实战:一套高效的Python系统练习指南

1. 为什么你需要一份 Python 练习计划先说个真实的场景。我见过太多人把 Python 教程从头看到尾,书买了好几本,视频课程收藏了几十个 G,代码也照着敲了,可一旦脱离教程自己写个东西,大脑就一片空白。问题不出在智商&am…

2026/10/11 23:44:49 阅读更多 →
C# WinForms 重绘TabControl高仿360浏览器选项卡实战

C# WinForms 重绘TabControl高仿360浏览器选项卡实战

简介:一份基于WinForm的C#自定义TabControl控件源码,高仿360浏览器选项卡外观,面向需要为桌面应用定制标签页样式的.NET开发者。针对原生控件多余的页边距、虚线框及闪烁问题,提供了添加/删除按钮、扁平化风格和低资源占用实现&am…

2026/10/11 23:44:49 阅读更多 →

最新新闻

拆解Amical的whisper.cpp封装:如何构建带Metal/CUDA/CPU自动回退的C++原生模块

拆解Amical的whisper.cpp封装:如何构建带Metal/CUDA/CPU自动回退的C++原生模块

【免费下载链接】amical 🎙️ AI Dictation App - Open Source and Local-first ⚡ Type 3x faster, no keyboard needed. 🆓 Powered by open source models, works offline, fast and accurate. 项目地址: https://gitcode.com/gh_mirrors/…

2026/10/12 0:27:12 阅读更多 →
基于YOLO的管道缺陷检测:980张图像训练实战与避坑指南

基于YOLO的管道缺陷检测:980张图像训练实战与避坑指南

简介:本资源为面向YOLO系列目标检测算法的下水管道缺陷检测数据集,适用于从事管道巡检、市政设施维护与工业视觉检测的开发者及研究人员,可解决缺陷样本稀缺、标注格式不统一等问题。压缩包共2000个文件,约33.89MB,包含…

2026/10/12 0:27:12 阅读更多 →
物联网模组柔性FPC天线方案全解析:选型、布局与调试

物联网模组柔性FPC天线方案全解析:选型、布局与调试

1. 项目背景与选型思路做物联网产品硬件设计的朋友,十有八九都遇到过同一个问题:模组选好了、主板画完了、结构堆叠也敲定了,结果天线没地方放。尤其是这两年,NB-IoT、Cat.1、BLE、LoRa 这些模组方案层出不穷,模组本身…

2026/10/12 0:27:12 阅读更多 →
用Tauri构建桌面天气应用:从技术选型到打包发布的完整实践

用Tauri构建桌面天气应用:从技术选型到打包发布的完整实践

桌面天气应用这个需求,看起来挺简单,但真做起来会发现它横跨了数据接口、桌面端集成、界面设计、异常处理好几个层面的问题。我前后用了两个周末把一套完整方案跑通,过程中踩了不少坑,这里把从选型到发布的完整链路梳理出来&#…

2026/10/12 0:27:12 阅读更多 →
UML四层建模实战:从用例图到部署图构建教务管理系统

UML四层建模实战:从用例图到部署图构建教务管理系统

简介:本资源是南京邮电大学软件工程课程设计的完整实验报告,面向高校计算机类专业本科生及软件工程初学者,聚焦教务管理系统的面向对象分析与UML建模实践。报告系统呈现了从需求分析到UML建模的全流程:涵盖用例图(管理…

2026/10/12 0:26:12 阅读更多 →
UML用例图与顺序图建模核心:抓准动作主体与交互时序

UML用例图与顺序图建模核心:抓准动作主体与交互时序

简介:本资源是一份面向软件工程专业学生、UML初学者及备考人员的系统性试题汇编,聚焦用例图、顺序图与协作图等核心交互建模技能,帮助读者深入理解UML动态建模原理与实际应用差异。资料以1个62KB的Word文档形式呈现,内容涵盖7大知…

2026/10/12 0:26:12 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →