把记忆模块塞进 OpenClaw,听起来是个小需求,但真正做过的朋友都知道,这一步卡住的人不在少数。OpenClaw 最近的热度大家有目共睹,Windows 离线整合包、Ubuntu 部署、飞牛 NAS、京东云服务器都有人折腾过,可装完以后,很多人第一反应是“然后呢”——对话结束,上下文清零,智能体还是像个金鱼。今天要分享的 Memoria,就是专门给 OpenClaw 补上持久记忆这一环的解决方案:它能让智能体跨会话记住用户偏好、项目背景和关键决策,而不是每次重新聊。这篇内容适合所有已经装好 OpenClaw、正在找记忆方案的开发者,目标是让你按下面的步骤走完,1 分钟跑通核心链路。
1. 为什么 OpenClaw 需要 Memoria:先把需求想清楚
1.1 没装记忆模块时,OpenClaw 的对话状态什么样
OpenClaw 本身是个能接模型、接工具、接各种插件的智能体运行时。很多人第一次跑通它,确实会被“它能调用浏览器、能操作文件、能自动剪视频”这种能力震撼到。但实际用几天就会发现一个尴尬点:它没有真正意义上的长期记忆。
不装任何记忆模块时,OpenClaw 的状态基本是:每个会话开始时,只能带走你写在系统提示词里的内容;会话进行中,模型通过上下文窗口理解当前任务;一旦会话结束,之前聊过的细节就没了。举一个我很常见的例子:你在第一次对话里明确说了“我写技术文档时偏好轻量级 Markdown,不喜欢花哨排板”,第二次开个新会话问它“帮我写个技术方案”,它大概率又会中规中矩地给你生成一段带复杂结构的文本。不是模型能力不够,是它的记忆根本没落盘。
这还不是最难受的。如果 OpenClaw 接入了浏览器控制、文件读写这类 Skill,工作状态同样不会自动保留。比如你让它在某个项目目录下做开发,它这次记住了路径,下次同一台机器上又得重新告诉它。这种重复沟通,一次两次还能忍,用久了真的会怀疑自己是在用智能体还是在训练一个新的实习生。
1.2 Memoria 到底管什么、不管什么
Memoria 这个名字直译过来就是“记忆”,它在 OpenClaw 生态里的定位,就是给智能体补上一个可持久化的记忆存储与检索模块。具体到能力层,它主要管三件事:写入、存储、召回。
写入是指对话过程中,Agent 判断某条信息值得留下时,主动调用 Memoria 接口把内容存下来。存储是指这些数据不是放在上下文窗口里,而是落到本地文件、SQLite 或向量数据库中,保证进程重启后依然存在。召回则是在未来的会话里,Agent 根据当前问题去检索相关记忆,把有用的老信息重新放回到提示词里。这三件事合起来,才构成一个“能记住”的闭环。
但 Memoria 不是什么都能管。它不管模型本身的微调,不管会话日志的审计,更不会替你决定“哪句话该记、哪句话该扔”——这个判断完全靠 Agent 的系统提示词设计和 Skill 的调用约定。也就是说,Memoria 更像一个抽屉柜,而不是管家。抽屉柜负责帮你把东西分类放好,管家才是那个决定什么东西该进抽屉的人。理解这一点,后面配置提示词时你才不会走偏。
1.3 什么场景才值得上记忆模块
不是所有 OpenClaw 部署都需要记忆模块。如果你只是偶尔跑个一次性任务,比如“帮我把这篇文章总结成要点”,那上下文窗口完全够用,加记忆模块反而是负担。真正值得上 Memoria 的场景,我归纳下来大致有三类。
第一类是长期个人助理场景。比如你要求它记住你的工具偏好、写作风格、工作日程,希望每次对话都像同一个熟悉的人在陪你工作。第二类是知识库与项目积累场景。你在一个固定项目里反复让它处理文档、整理代码、维护方案说明,这时候跨会话的项目背景就非常重要。第三类是自动化流程中有中间状态产生、且状态需要被后续步骤读取的场景。比如视频批量处理,第一步分析了每段素材的关键信息,第二步要根据这些信息做剪辑决策,如果关键信息只存在于某个临时会话里,流程一断,全部白干。
反过来,如果你的场景非常简单,或者数据安全要求高到不允许任何本地落盘,那就别硬上记忆模块。先想清楚需求边界,接的时候才不会被一堆配置和召回逻辑折腾到怀疑人生。
2. 接入前的准备:确认环境、拿到 Memoria
2.1 快速确认 OpenClaw 环境状态
动手之前,先花二十秒确认一件事:你现在手上的 OpenClaw 到底是哪种形态的安装。这个很重要,因为不同的安装形态,skills 目录的位置、配置文件加载方式、重启命令都不太一样。
常见的形态有这么几种:从 GitHub main 分支源码检出的部署方式,一般会有完整仓库目录,skills 文件夹在源码根目录下;用 Windows 离线整合包部署的,通常在安装目录里可以找到同名目录;还有 Docker 容器方式部署的,skills 目录大概率挂在宿主机某个持久化卷里,得先找到挂载映射关系;另外,有人在飞牛 NAS、京东云服务器、Ubuntu 22.04 + CUDA 这些环境上部署,本质上也跑不出这几种形态的范围。
确认完形态后,查看一下当前版本。你可以在 OpenClaw 的 CLI 里执行版本查询命令,比如openclaw --version,确保版本不太老。记忆类 Skill 对 Agent 自动调用工具的稳定性要求高,太老的版本可能在工具声明解析上存在兼容问题。如果版本比较旧,建议先顺手升个级,很多安装脚本已经支持指定 git 安装方式,从 main 分支重新拉一份源码也是常规操作。
2.2 获取 Memoria 与安装依赖
环境心里有数了,就可以把 Memoria 拉下来。当前比较主流的做法是走 OpenClaw 的 Skill 安装命令。如果你习惯用命令行动手,在 OpenClaw 所在环境中执行技能安装命令即可,名称直接指定 memoria。安装命令装好后,OpenClaw 会自动把它放到正确的 skills 目录下,同时注册技能元信息。
另一种方式是手动拉取。直接把 Memoria 的仓库克隆到 skills 目录中,比如:
# 假设你的 OpenClaw 源码根目录位于 ~/openclaw cd ~/openclaw git clone --depth 1 https://github.com/你的来源/memoria.git skills/memoria克隆完成后,检查一下 Memoria 有没有额外的 Python 依赖。我见过不少朋友栽在这步:Skill 目录拉下来了,但依赖没装,启动 OpenClaw 后 Agent 一调用记忆工具就报错。这时你需要看它的 requirements.txt 或者 pyproject.toml,用 pip 安装缺的包:
pip install -r skills/memoria/requirements.txt装完后先别急着配复杂的东西,做一次最小启动验证:把 OpenClaw 跑起来,然后在对话里问它“你现在有哪些技能”,看返回的工具列表里是否出现了 memoria 开头的工具名。如果能看见,说明 Memoria 已经被正常加载,可以进入配置环节了。
2.3 目录结构与配置项说明
Memoria 拉下来后,它内部的目录结构大概长这样:
skills/memoria/ ├── SKILL.md # 技能声明文件 ├── main.py # 工具主实现 ├── config.yaml # 记忆存储与召回配置 ├── requirements.txt └── data/ # 本地存储目录(首次运行自动创建)SKILL.md 是 OpenClaw 识别这个技能身份的关键,里面声明了技能名、描述、作者、版本和对外提供的工具列表。main.py 是核心逻辑,写入、检索、删除记忆的函数都写在里面。config.yaml 则控制存储后端类型、召回参数、是否启用向量检索等。
配置项里我建议优先关注三个:存储后端、召回数量和本地模型。存储后端决定记忆数据到底放在哪,最简单的有 JSON 文件或 SQLite,复杂点可以接向量数据库。召回数量决定每次对话最多塞多少条相关记忆给模型,太少可能漏,太多会挤占上下文。本地模型主要用于生成向量表示,如果你在 OpenClaw 里已经配置了 Ollama 这类本地模型服务,可以把向量生成也指到本地,避免额外申请云端接口。
3. 1 分钟接入实操:核心配置与调用链
3.1 创建技能目录与声明
网上很多教程喜欢一上来就扔一大段配置,结果读者连“这个参数是干嘛的”都不知道。我换一种讲法,我们先从最小可用的 SKILL.md 写起,让 Memoria 先能被 OpenClaw 加载出来。
在 skills/memoria/ 下新建或修改 SKILL.md,核心内容如下:
name: memoria description: 提供持久记忆的读写与搜索能力,支持跨会话记住用户偏好和项目信息。 version: 0.1.0 tools: - memoria.add - memoria.search - memoria.forget - memoria.list注意 description 里一定要写清楚“跨会话记住用户偏好和项目信息”这类字样。OpenClaw 让 Agent 决定调用哪个工具时,很大程度靠的是描述。描述越接近真实用途,Agent 越能在合适的时机主动调用,而不是每次都需要你手动指定。
main.py 里,我们先用最简单的 SQLite 做一个最小实现。之所以选 SQLite 而不是 JSON,因为并发安全性和查询能力都好得多,避免多个 Skill 同时读写一个 JSON 文件时互相覆盖。
# skills/memoria/main.py,最小可用版本 import sqlite3 from pathlib import Path DB_PATH = Path(__file__).parent / "data" / "memoria.db" def _connect(): Path(__file__dir__).joinpath("data").mkdir(exist_ok=True) conn = sqlite3.connect(DB_PATH) conn.execute(""" CREATE TABLE IF NOT EXISTS memory ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, tags TEXT DEFAULT '', importance INTEGER DEFAULT 1, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) """) return conn def add(content: str, tags: str = "", importance: int = 1) -> int: """写入一条记忆。content 是必填内容,tags 用逗号分隔,importance 是重要程度。""" conn = _connect() cur = conn.execute( "INSERT INTO memory (content, tags, importance) VALUES (?, ?, ?)", (content, tags, importance), ) conn.commit() conn.close() return cur.lastrowid def search(query: str, limit: int = 5) -> list[dict]: """按关键词匹配返回相关记忆,按重要程度降序排列。""" conn = _connect() cur = conn.execute( "SELECT id, content, tags, importance FROM memory " "WHERE content LIKE ? OR tags LIKE ? " "ORDER BY importance DESC, id DESC LIMIT ?", (f"%{query}%", f"%{query}%", limit), ) rows = cur.fetchall() conn.close() return [dict(row) for row in rows]这套代码很简单,但已经具备“写入”和“召回”两大核心能力。生产环境如果要接 OpenAI Embeddings 或本地向量库,是在这个基础上做加法,而不是推倒重来。
3.2 配置存储与召回参数
接下来改 config.yaml。这份配置的意义在于,让 Memoria 的数据存储路径和召回策略与你现有的运行环境对齐。
storage: backend: sqlite # 也可填 json / chroma / qdrant path: data/memoria.db retrieval: top_k: 5 # 每次最多召回几条记忆 min_score: 0.3 # 召回最低分,低于此分数的记忆不返回 embedding: provider: offline # 可选 offline / ollama / api model: "" # 使用 ollama 时填模型名,如 nomic-embed-text我个人的建议是,第一次跑通链路时,storage.backend 先别动,用 SQLite 就好。向量检索虽然看起来更高级,但配置成本高,还要考虑 embedding 服务的稳定性和调用延迟。先用关键词召回把链路跑通,再考虑升级成向量检索,这样排障时你至少能确定问题出在哪一层。
3.3 让 Agent 在对话中自动调用记忆
配置完 Skill,关键一步来了:怎么让 Agent 在对话中主动想起 Memoria?这里涉及 OpenClaw 的系统提示词或者 Agent 的指令配置。
你需要在系统提示词里写清楚类似的话:
你有一个长期记忆工具 memoria。当用户提到个人偏好、项目背景、待办事项等值得长期保留的信息时, 调用 memoria.add 记录下来。在回答与历史信息相关的问题前,先调用 memoria.search 检索相关记忆。然后重启 OpenClaw,让配置生效。建议重启而不是热加载,尤其是你改了 SKILL.md 和 main.py 的情况,热加载经常出现工具注册不完整的怪问题,不如一次干净重启来得省心。
启动后进入对话,先输一句“记住:我写文档时喜欢用 Markdown”,然后观察 OpenClaw 的日志,正常情况下你应该能看到工具调用记录,memoria.add 被触发。再输入“我写文档时有什么偏好?”,正常情况下应该触发 memoria.search,并返回上一条记忆。
到这里,你已经成功跑通了“写入—存储—召回—再使用”的最小链路。整个过程熟练的话确实只要一分钟。
3.4 从 JSON 到向量库:存储升级路径
基础链路跑通后,你迟早会遇到一个问题:关键词搜索太死板。比如你存了一条“用户偏好用 Python 写脚本”,下次用户问“我在服务器上的自动化任务用什么语言”,关键词完全对不上,记忆就召不回。
解决办法是升级成向量检索。简单理解,就是把每条记忆转换成一组数字向量,语义相近的内容在向量空间里也会靠近。再配合余弦相似度计算,就能做到“意思差不多就能查出来”。
升级步骤大致是三步:第一步,选一个 embedding 生成服务,本地环境装好的 Ollama 是个不错的选择,也可以用现成的 API 服务;第二步,在 config.yaml 里把 embedding.provider 改成 ollama 或 api,填上模型名;第三步,把 main.py 的 search 函数从 SQL LIKE 换成向量相似度查询,把存储后端从 SQLite 换成 Chroma 或 Qdrant。这一步开始代码量变大,建议你把旧数据保留一份做回归验证,确保升级后新老记忆都能查到。
4. 记忆数据的组织与召回:存得下也要想得起
4.1 给记忆打标签
很多人的记忆模块用一段时间就废了,不是因为存不进去,而是因为存得太乱。比如你存了一百条记忆,每条都是大白话,没有分类,没有重要程度,召回时不管问什么都返回一堆相似结果,模型看不过来,自然就“忘记”了。
Memoria 的 add 接口里有 tags 和 importance 两个字段,很多人直接忽略。这俩字段其实是记忆整理的关键。我建议每次写入时给记忆打上 1 到 3 个标签,比如 user-preference、project-context、task-status,同时用 importance 区分优先级。重要程度高的记忆,比如用户明确强调“以后都用这个方案”,给 5;普通偏好在 1 到 3 之间浮动。
打标签的价值在召回阶段体现得最明显。当 Agent 收到一个问题,它可以先用标签做粗过滤,再在候选记忆里做细匹配,这样既快又准。实际操作中,我会在 SKILL.md 的工具描述里加一句“写入时请尽量给出合理的 tags 和 importance”,相当于把整理习惯内置到 Agent 的调用行为里。
4.2 相关性召回策略
召回策略直接决定记忆模块有没有用。最简单的关键词召回已经能满足一部分场景,但想要更好的效果,需要设计一个组合检索流程。
我的常见做法是三步走。第一步,用标签初筛。比如当前问题涉及“用户偏好”,就先从记忆库中筛选出带有 user-preference 标签的记录。第二步,在初筛结果里做关键词或向量相关性打分。这时需要计算每条候选记忆与当前问题的相关度,可以简单用文本包含关系,也可以用余弦相似度。第三步,按“相关度 × 重要程度”的加权值排序,取 top_k 条输出给模型。
举一个我自己的例子。我让 OpenClaw 管理一个技术博客的写作辅助工作,Memoria 里存了大量主题方向、写作风格、历史读者反馈。有次我让它写一篇“智能体部署环境对比”的初稿,Agent 先搜出与“部署环境”相关的记忆,又通过标签筛出了“写作风格偏好”,最终产出的文章确实比没带记忆时的默认风格要更贴近我平时的调性。这就是相关性和重要程度加权起的作用。
4.3 记忆的生命周期:更新、过期、删除
记忆存储最怕的是“永远只增不减”。时间一长,库里堆满了过时信息,比如昨天的临时目录路径、已经被推翻的方案决定,这些记忆不仅没有帮助,反而会在召回时干扰模型判断。
所以我在实际使用时,会给记忆加上生命周期策略。第一条,同主题覆盖更新。Memoria 里可以做一个 update 操作,根据 content 的关键部分匹配已有记忆,如果存在就更新内容而不是新增一条。这样能避免同一个偏好被记了五遍。第二条,临时记忆和长期记忆分开。有些信息当前会话有用,比如“这次的视频素材在 /tmp/raw_01”,但下一周就没意义了,这类记忆可以设置过期间隔,比如 24 小时或 7 天后自动清理。第三条,定期手动清理。我会写一个简单的清理任务,在 OpenClaw 里定时触发,把 importance 低、更新日期老的记忆归档或删除。
生命周期管理做到位后,Memoria 的召回质量会明显上一个台阶。存进去的每一条都是“活”的,而不是一堆积灰的旧纸条。
5. 常见问题与排查技巧实录
5.1 安装与依赖的坑
Memoria 接入过程中,我见到最多的问题就是“已经装好了但找不到这个 Skill”。如果你确认已经克隆到 skills 目录,但 OpenClaw 列表里就是没有,先检查 SKILL.md 格式,YAML 缩进错误是头号杀手。其次是目录名和 SKILL.md 里的 name 不一致,OpenClaw 加载时以声明为准,不一致会导致注册失败。
依赖报错也很常见。有些环境里 pip 装包装到了系统 Python,而 OpenClaw 跑在虚拟环境,两边互不相通。排查方法简单粗暴:在 OpenClaw 所在的 Python 环境里执行pip list,确认依赖真的装到了同一个解释器下。另外,如果你的 OpenClaw 是通过 Docker 部署的,记得在容器里装依赖,装完以后要提交镜像或者挂载完整依赖目录,否则重启后一切归零。
5.2 调用链不通怎么办
“技能列表里有 memoria,但对话里它就是不调用。”这个问题我太熟了。原因多半不是 Memoria 写错了,而是 Agent 不知道什么时候该用。
优先检查系统提示词里有没有说清楚调用时机。如果你只说“你可以使用记忆工具”,模型大概率会犹豫。我的做法是把调用规则写得非常具象,比如“当用户说出‘记住’、‘以后都’、‘我偏好’等关键词时,必须调用 memoria.add”。这种明确指令比模糊的“可以”要有效得多。
其次检查工具描述是否和调用场景对齐。如果你的工具描述写得过于技术化,模型也容易判断失误。最好的方式是想象你在给一个人解释这个工具:“这个工具用来保存你不想重复告诉我的话”,这种描述模型反而更容易理解。
5.3 长对话与并发下的性能问题
OpenClaw 跑了几个月后,Memoria 里的数据量可能上万条,这时候 SQLite 的 LIKE 查询会变慢。解决办法有两个方向:一是给 tags 和 content 建索引,能缓解一部分;二是升级为向量库配合索引检索,这才是治本。
还有并发问题。OpenClaw 同时接了微信插件、浏览器插件、多个 Skill 时,多个工具可能同时调用 Memoria,SQLite 默认模式在高并发下容易报 database is locked。我的经验是把 SQLite 切到 WAL 模式,一句PRAGMA journal_mode=WAL;就能显著减少锁冲突。如果并发量再大,就直接上独立数据库服务,别在文件型数据库上死磕。
5.4 与微信、浏览器等插件组合时的注意点
很多朋友会把 OpenClaw 接到微信或浏览器控制这类插件上,这时候记忆模块会和它们产生交互。印象最深的教训是:插件触发了某些平台服务端的风控或会话残留问题时,问题清单会被记忆系统一并记录,导致后面的回复一直被错误的历史信息引导。我的建议是,在对接第三平台插件时,记忆内容里关于“平台状态”“会话环境”的记录要加独立的标签,并设置短过期时间,别让这些临时信息污染长期记忆。
另外,多个插件共用同一个 Memoria 实例时,注意工具调用时的时序问题。比如浏览器插件在页面操作后写了一条记忆,Agent 立刻读取,可能因为数据尚未提交而查不到。遇到这种情况,我一般会在记忆工具里加一个强制刷新参数,或者确保每次写入都完成后才返回。资源受限的端侧环境,比如有人折腾 ESP32 之类的小设备跑轻量智能体,就别指望上完整记忆模块了,建议只做最小化的关键状态保存,检索逻辑放到云端做。
说实话,把 Memoria 接入 OpenClaw 这一步本身不难,真正花时间的,是后面怎么设计记忆的内容和生命周期。我个人实际跑下来的一点体会是:先别求全,别一开始就上向量库、上分布式存储,用 SQLite 把写入、召回、清理这个闭环跑顺,再用真实对话去观察 Agent 哪些时机调用得好、哪些时机明显漏了,一步步调整提示词和标签策略。最后再分享一个小技巧:每次调整完 Memoria 相关提示词,别急着大量对话测试,先准备一组固定的验证场景,比如“记住我的偏好—问我偏好—告诉我偏好变了—再问我偏好”,来回测几轮。这套固定回归法,比盲目聊天好用得多,能让你快速判断每一次改动到底有没有效果。