摘要本文基于 OpenClaw 4.9 的更新内容系统拆解其“做梦Dreaming”记忆整合系统浅睡眠 / REM / 深睡眠三阶段管线、Jaccard 去重、加权打分与历史回填机制并结合多模型评测、安全加固等特性给出一个可在自研 Agent 中复用的实现思路与 Python API 示例基于薛定猫 AI 平台 xuedingmao.com。一、背景介绍为什么智能体需要“做梦”在大部分应用里LLM Agent 的“记忆”通常是一份长期记忆如memory.md记录用户偏好、约定事实一堆短期交互日志按天滚动的对话/笔记文件常见问题短期记忆只向前不向内演化每日笔记不断堆积但系统只自动加载“今天昨天”更早的内容闲置无法在推理中被利用。长期记忆需要人工整理memory.md只在显式指令下更新导致两周前、一个月前反复出现的偏好/模式并不会自动沉淀。缺乏“选择性遗忘”和“抽象提炼”机制结果是要么上下文暴涨变贵要么有用经验被淹没在噪音中。OpenClaw 4.9 引入的 Dreaming 系统实际上就是一个面向 Agent 的“睡眠期记忆巩固架构”在你不使用 Agent 时默认凌晨 3 点托管 cron后台自动完成记忆抽取、去重、聚类与晋升。从工程视角看它解决的是两个核心问题如何从大量 session log 中提炼出稳定、可复用的“事实/偏好”如何在控制成本的前提下让 Agent 的能力随时间“复利式增强”二、核心原理三阶段 Dreaming 管线与加权评分2.1 三阶段睡眠模型Dreaming 被拆成三个阶段对应大脑睡眠类比但本质是一个异步 ETL Ranking 流程。1Light Sleep浅睡眠数据摄入与去重读取近期每日记忆文件如最近 N 天的日记 / session log切分为 snippet摘要片段存入memory/.dreams/session_corpus/通过Jaccard 相似度去重阈值 0.9两条文本的 token 集合交并比 ≥ 0.9则保留一条记录 “light phase signal hits” 作为候选加分信号特点只做“暂存 标记”不写入memory.md。2REM Sleep主题聚合与候选抽取Lookback 窗口默认 7 天回顾过去 7 天的 staged material对各 snippet 进行概念标注/标签化concept tags统计标签频率识别“跨 session 反复出现”的主题如用户多次提到“我用的是 VSCode Python 3.11”被多次提及的 idea/topic 会被标记为candidate truth记录 REM signal hits为候选在最后排名加分将观测写入 dreaming trail类似梦境日志3Deep Sleep加权评分与晋升深睡眠阶段是真正写入长期记忆的决策步骤。收集所有 candidate来自 LightREM使用包含 6 个加权信号的 scoring 算法信号权重含义简述Relevance0.30与用户/任务目标的相关性Frequency0.24在多日、多 session 中出现的频率Query Diversity0.15在不同问题类型下反复出现Recency0.15最近出现的时间是否较近Consolidation0.10在前几轮 Dreaming 中是否也被选为候选Conceptual Richness0.06信息是否足够“原子且具体”、非空洞抽象超过阈值的候选会被“晋升”到memory.md成为长期记忆的一部分。2.2 Backfill Lane历史数据的再加工早期版本 Dreaming 仅处理近期笔记历史文件长期闲置。4.9 新增backfill lane可以将 Dreaming 管线指向旧的历史 notes把历史日志按同一流程重新“重放”与抽取等价于给你的 Agent 做一次“过去半年履历扫描”同时增加Diary commit reset 流程如果有不希望晋升的暂存条目可重置 dreaming state 重新开始2.3 提取逻辑优化抑制噪音、保留原子事实新版 durable fact extraction 重点做了两件事更好地过滤“操作噪音”如临时 debug、路径/ID 噪音等更偏向保留“原子、具体”的事实例如“用户默认使用 ‘黑暗主题 14px 字号 JetBrains Mono’”而不是“用户喜欢好看的界面”这类模糊抽象这会显著提升长期记忆的“可执行性”和调用价值。三、实战演示在自研 Agent 中实现类 Dreaming 记忆整合下面给出一个简化版 Dreaming 管线示例核心目标从多天对话日志中抽取“可晋升的事实/偏好”使用 LLM 作为“事实提取 标签生成打分器”通过 Jaccard 去重 Python 实现评分逻辑为方便落地示例使用薛定猫 AI 平台xuedingmao.com的 OpenAI 兼容 API默认模型为claude-sonnet-4-6。说明xuedingmao 提供统一的 OpenAI 风格接口聚合了 GPT-5.4、Claude 4.6、Gemini 3 Pro 等 500 模型适合作为多模型评测/路由的统一接入层。3.1 环境准备pipinstallrequests python-dotenv scikit-learn.env中配置XUEDINGMAO_API_KEY你的_api_key XUEDINGMAO_BASE_URLhttps://xuedingmao.com3.2 Python 代码示例简化版 Dreaming 管线importosimportjsonimportglobfromdotenvimportload_dotenvimportrequestsfromsklearn.feature_extraction.textimportCountVectorizerfromsklearn.metricsimportjaccard_scoreimportnumpyasnpfromdatetimeimportdatetime,timedelta load_dotenv()API_KEYos.getenv(XUEDINGMAO_API_KEY)BASE_URLos.getenv(XUEDINGMAO_BASE_URL,https://xuedingmao.com)MODELclaude-sonnet-4-6defcall_llm(system_prompt,user_prompt): 调用薛定猫 AI 平台OpenAI 兼容模式的通用函数 urlf{BASE_URL}/v1/chat/completionsheaders{Authorization:fBearer{API_KEY},Content-Type:application/json,}data{model:MODEL,messages:[{role:system,content:system_prompt},{role:user,content:user_prompt},],temperature:0.1,}resprequests.post(url,headersheaders,jsondata,timeout60)resp.raise_for_status()returnresp.json()[choices][0][message][content]# ---------- 1. Light Sleep加载多日日志 Jaccard 去重 ----------defload_daily_notes(folder,days_lookback7): 从指定文件夹读取最近 N 天的日记文件 文件命名约定: YYYY-MM-DD.md cutoffdatetime.now()-timedelta(daysdays_lookback)filesglob.glob(os.path.join(folder,*.md))selected[]forfinfiles:baseos.path.basename(f).split(.)[0]try:dtdatetime.strptime(base,%Y-%m-%d)exceptValueError:continueifdtcutoff:selected.append(f)selected.sort()returnselecteddefjaccard_dedup(snippets,threshold0.9): 对文本片段进行 Jaccard 去重保留代表性片段 ifnotsnippets:return[]vecCountVectorizer().fit_transform(snippets)matvec.toarray().astype(bool)keep[]fori,rowinenumerate(mat):duplicateFalseforjinkeep:scorejaccard_score(row,mat[j])ifscorethreshold:duplicateTruebreakifnotduplicate:keep.append(i)return[snippets[i]foriinkeep]defextract_snippets_from_text(text): 使用 LLM 将长文本切分为若干“可候选的事实/偏好”片段 返回一个列表每个元素是一条短句描述 system_prompt你是一个帮助从对话日志中抽取候选事实和偏好的助手。user_prompt(以下是最近几天的对话/笔记内容请提取 5-15 条简短、原子、可复用的事实或偏好每条不超过 100 字以 JSON 数组返回每个元素为字符串。\n\ntext)contentcall_llm(system_prompt,user_prompt)try:returnjson.loads(content)exceptjson.JSONDecodeError:# 简单回退按行分割return[line.strip()forlineincontent.splitlines()ifline.strip()]deflight_sleep_stage(notes_folder,days_lookback7):filesload_daily_notes(notes_folder,days_lookback)raw_snippets[]forfinfiles:withopen(f,r,encodingutf-8)asrf:raw_snippets.append(rf.read())ifnotraw_snippets:return[]# 合并多日文本给 LLM 做一次 snippet 抽取combined\n\n.join(raw_snippets)snippetsextract_snippets_from_text(combined)dedupedjaccard_dedup(snippets,threshold0.9)returndeduped# ---------- 2. REM Sleep主题标签 候选抽取 ----------deftag_and_group_snippets(snippets): 使用 LLM 为每个 snippet 生成标签并根据标签聚合。 返回: {tag: [snippets...]} system_prompt你是一个为用户事实片段打标签并按主题聚类的助手。user_prompt(下面是若干条用户相关事实/偏好请为每条生成 1-3 个主题标签中文并按标签聚类以 JSON 形式返回: {tag: [snippet1, snippet2, ...]}。\n\njson.dumps(snippets,ensure_asciiFalse,indent2))contentcall_llm(system_prompt,user_prompt)try:groupsjson.loads(content)returngroupsexceptjson.JSONDecodeError:return{未分类:snippets}defrem_sleep_stage(snippets): REM 阶段按主题聚类统计频次生成 candidate truths。 groupstag_and_group_snippets(snippets)candidates[]fortag,itemsingroups.items():iflen(items)1:continue# 出现频次太低可视为噪音# 将同主题的多条 snippet 汇总成候选事实merged_factf主题{tag}总结{.join(items)}candidates.append({tag:tag,snippets:items,merged_fact:merged_fact,frequency:len(items),})returncandidates# ---------- 3. Deep Sleep加权评分 晋升到长期记忆 ----------defscore_candidates(candidates,relevance_weight0.30,freq_weight0.24,diversity_weight0.15,recency_weight0.15,consolidation_weight0.10,richness_weight0.06): 用 LLM 评估每个候选相关性、查询多样性、时间性、巩固程度、丰富度。 这里示例中简化只用 LLM 返回各项 0-1 分再按权重求和。 system_prompt(你是一个为候选用户长期记忆打分的评估器。对于每条候选事实请根据以下维度打 0~1 分relevance, diversity, recency, consolidation, richness。返回 JSON 数组每个元素形如{\relevance\: 0.8, \diversity\: 0.6, \recency\: 0.7,\consolidation\: 0.5, \richness\: 0.9}。频率 frequency 已在外部提供无需打分。)descriptions[c[merged_fact]forcincandidates]user_promptjson.dumps(descriptions,ensure_asciiFalse,indent2)contentcall_llm(system_prompt,user_prompt)try:scores_listjson.loads(content)exceptjson.JSONDecodeError:# 回退全部给中性分scores_list[{relevance:0.5,diversity:0.5,recency:0.5,consolidation:0.5,richness:0.5}for_incandidates]# 归一化频率freqsnp.array([c[frequency]forcincandidates],dtypefloat)iffreqs.max()0:freqsfreqs/freqs.max()else:freqsnp.zeros_like(freqs)results[]forc,s,f_norminzip(candidates,scores_list,freqs):total_score(s.get(relevance,0)*relevance_weightf_norm*freq_weights.get(diversity,0)*diversity_weights.get(recency,0)*recency_weights.get(consolidation,0)*consolidation_weights.get(richness,0)*richness_weight)c[score]total_score results.append(c)returnresultsdefpromote_to_long_term_memory(scored_candidates,memory_md_path,threshold0.6,max_items20): 将超过阈值的候选事实写入 memory.md追加方式 scored_candidates.sort(keylambdax:x[score],reverseTrue)selected[cforcinscored_candidatesifc[score]threshold]selectedselected[:max_items]ifnotselected:return# 读现有长期记忆避免重复写入existingifos.path.exists(memory_md_path):withopen(memory_md_path,r,encodingutf-8)asrf:existingrf.read()withopen(memory_md_path,a,encodingutf-8)aswf:wf.write(\n\n## Dreaming Consolidation - {}\n.format(datetime.now().strftime(%Y-%m-%d %H:%M)))forcinselected:ifc[merged_fact]inexisting:continuewf.write(f-{c[merged_fact]}score{c[score]:.2f}\n)defrun_dreaming_pipeline(notes_folder,memory_md_path,days_lookback7): 一次完整的 Dreaming 流程浅睡眠 - REM - 深睡眠 可挂载到 cron每天凌晨执行一次。 snippetslight_sleep_stage(notes_folder,days_lookback)ifnotsnippets:print(No snippets extracted. Skip.)returncandidatesrem_sleep_stage(snippets)ifnotcandidates:print(No candidates from REM stage. Skip.)returnscoredscore_candidates(candidates)promote_to_long_term_memory(scored,memory_md_path)print(Dreaming pipeline finished.)if__name____main__:# 示例notes_folder 存放你的 daily notesmemory.md 为长期记忆文件NOTES_FOLDER./memory/dailyMEMORY_MD./memory/memory.mdrun_dreaming_pipeline(NOTES_FOLDER,MEMORY_MD,days_lookback7)你可以将run_dreaming_pipeline挂在系统cron实现类似 OpenClaw 的“凌晨做梦”。四、注意事项与工程实践建议4.1 安全与可信输入视频中另一重要更新是远程节点输出标记为不受信任并过滤以及阻止不受信任的workspace.env覆盖安全配置。在自研 Agent/工具链时建议将“本地工具执行结果 / 远程节点输出”视为untrusted input在进入 LLM 上下文前明确标注来源并做必要的 sanitization对任何可能影响系统配置的输入做白名单过滤而非黑名单4.2 多模型评估与人格一致性Character Vibes QA 系统提供了一个很值得借鉴的思路使用统一 persona 文件如persona.md定义 Agent 角色对同一组测试 prompt分别调用多个模型GPT 系列 / Claude / Gemini / 本地 Llama…自动生成 side-by-side 报告对比语气、风格、一致性工具调用行为安全合规表现这与我们在上文代码中使用的统一 API 接入层非常契合。在实际项目中可以直接基于薛定猫 AI同一接口下切换不同模型GPT-5.4 / Claude 4.6 / Gemini 3 Pro / 本地模型代理快速完成模型选型与 A/B 测试而不用改动业务逻辑代码4.3 移动端与多渠道路由Android 配对完整重构更可靠的二维码绑定、错误状态恢复与电量优化Slack / Matrix / Telegram 路由修复解决消息泄露与重复发送如果你的 Agent 是“多渠道消息枢纽”务必明确 session 归属每个 channel / thread 对应独立上下文做好消息路由隔离避免“跨群串话”在日志中记录channel_id, session_id, user_id方便审计与 Debug4.4 本地模型推理链可视化对于通过本地 Llama 模型如 Ollama运行的 Agent4.9 支持在 UI 中显式展示“思考过程”。在自研系统中建议将reasoning_tracetool_call_logmemory_read/write trace统一序列化保存既方便调试也有助于解释智能体行为。五、技术资源与平台选型建议在构建具备“做梦记忆 多模型评估 安全加固”的 Agent 系统时底层模型与 API 平台的选型非常关键建议关注模型覆盖与更新速度是否能第一时间接入新出的前沿模型如 GPT-5.4、Claude 4.6、Gemini 3 Pro 等可以直接影响多模型评估的有效性。统一 API 接口与路由能力对于类似 Character Vibes QA 的场景使用统一的 OpenAI 兼容接口能显著降低代码复杂度。上文示例使用的薛定猫 AIxuedingmao.com就是这种模式聚合 500 模型支持主流商业 / 开源模型统一接入方式切换模型只需改一个参数适合构建多模型路由、评测与 fallback 策略稳定性与生产可用性尤其是 Dreaming 这类后台 cron 任务对 API 稳定性和限流策略很敏感推荐优先选择在生产环境实测稳定的平台。结语Dreaming 系统的价值不在于“多了一个记忆文件”而在于它为 Agent 引入了一个持续、自动、可解释的记忆演化机制每天只做一点点抽取与整理三个月后 Agent 对你的业务与习惯有“质变级理解”比起每次从空白上下文起步的 Agent有明显竞争优势如果你正在自研 Agent不妨将本文的简化 Dreaming 管线接入现有项目再配合多模型评测与安全加固逐步搭建属于自己的“生产级智能体基座”。#AI #大模型 #Python #机器学习 #技术实战