给你的Agent植入记忆-——文章搬运工

在 ClawdBot (MoltBolt / OpenClaw) 中增加记忆插件 PowerMem 的新玩儿法

image

Moltbot 是什么?

Clawdbot(后更名为 Moltbot,又更名为 OpenClaw)是一款开源、以通讯为核心的AI智能体项目,运行在你自己的设备上,通过你已有的渠道(WhatsApp、Telegram、Slack、Discord、Google Chat、Signal、iMessage、Teams、WebChat 等)和你对话,支持语音、Canvas、多代理路由等。

简单点说:Moltbot 最大的特点是不仅能回答问题,更能真正“动手”操作你的电脑系统,执行命令、控制浏览器、管理文件,就像一个 7 x 24 小时在线的 “数字员工”。

官网 :https://www.molt.bot/

github 地址:GitHub - openclaw/openclaw: The AI that really does things. Any OS. Any Platform. The lobster way. 🦞 · GitHub

Moltbot 部署

方式一:NPM 全局安装

npm install -g moltbot@latest
# 或使用 pnpm
pnpm add -g moltbot@latest

# 初始化并安装守护进程
moltbot onboard --install-daemon

方式二:源代码安装

# 克隆仓库
git clone https://github.com/moltbot/moltbot.git
cd moltbot

# 安装依赖
pnpm install
pnpm ui:build  # 首次运行会自动安装 UI 依赖
pnpm build

# 初始化
pnpm moltbot onboard --install-daemon

# 开发模式(监听 TypeScript 变更自动重载)
pnpm gateway:watch

上面两种安装方式二选一,因为我是走的源代码安装:

  1. pnpm moltbot onboard --install-daemon 初始化

  1. 同意风险提示

这里会让你确认风险。Moltbot 功能强大,能执行系统命令、读写文件、控制浏览器,但这也意味着如果配置不当或被滥用,可能会带来安全风险,请谨慎使用。

  1. 选择快速开始
  2. 配置 AI 模型授权,我手里头有qwen的

  1. 启动web

问个小问题:“查一下我的电脑型号”,很快 moltbot 回复了我机器的具体型号,虽然任务非常简单,但是还是挺惊喜的,距离“贾维斯”又进了一步了。

Moltbot 的原生记忆解读

Moltbot 的持久记忆可以概括为:「Markdown 文件为单一事实来源 + 可选向量/混合检索」。

存储形态:纯 Markdown 文件

  • 事实来源:模型「记得」的内容 = 写入磁盘的 Markdown;不依赖模型内部状态。
  • 默认布局(在 workspace 下,如 ~/clawd):
  • memory/YYYY-MM-DD.md:按日期的日志,仅追加;会话开始时读「今天 + 昨天」。
  • MEMORY.md(可选):长期、人工可维护的记忆;只在 main 私聊 session 加载,群聊不加载。

也就是说:

  • 短期、按天的记录 → memory/YYYY-MM-DD.md
  • 长期、精选事实 → MEMORY.md
  • 持久化完全靠「写进这些文件」,而不是靠对话历史本身。

写入时机与「记忆冲刷」(Memory Flush)

  • 平时:模型通过 工具(如 write、edit)或技能,把要记住的内容写到 MEMORY.md 或 memory/YYYY-MM-DD.md。
  • 自动冲刷:当 session 快触发自动 compaction 前,Moltbot 会跑一轮 静默的 agent 回合,专门提醒模型「把该持久化的东西写进记忆文件」,并鼓励用 NO_REPLY 不回复用户,避免用户看到这次内部回合。
  • 触发条件由 agents.defaults.compaction.memoryFlush 控制,例如在「剩余 token ≈ softThresholdTokens」时触发;每轮 compaction 只做一次 flush,并在 sessions.json 里记 memoryFlushCompactionCount 等,避免重复。

相关代码在 src/auto-reply/reply/memory-flush.ts:

  • shouldRunMemoryFlush():根据当前 token、context 上限、reserve、softThreshold 判断是否该 flush。
const shouldFlushMemory =
  memoryFlushSettings &&
  memoryFlushWritable &&
  !params.isHeartbeat &&
  !isCliProvider(params.followupRun.run.provider, params.cfg) &&
  shouldRunMemoryFlush({
    entry:
      params.sessionEntry ??
      (params.sessionKey ? params.sessionStore?.[params.sessionKey] : undefined),
    contextWindowTokens: resolveMemoryFlushContextWindowTokens({
      modelId: params.followupRun.run.model ?? params.defaultModel,
      agentCfgContextTokens: params.agentCfgContextTokens,
    }),
    reserveTokensFloor: memoryFlushSettings.reserveTokensFloor,
    softThresholdTokens: memoryFlushSettings.softThresholdTokens,
  });
  • 若 workspace 只读(如 sandbox workspaceAccess: “ro”),则不做 flush。

检索层:向量 + 可选 BM25 混合检索

数据流

MoltbotConfig (raw)
  → agents.defaults.memorySearch           [默认]
  → agents.<agentId>.memorySearch         [按 agent 覆盖,由 resolveAgentConfig 解析]
       ↓
  mergeConfig(defaults, overrides, agentId)
       ↓
  ResolvedMemorySearchConfig(扁平、带默认、已 clamp)
       ↓
  resolveMemorySearchConfig 若 enabled 则返回,否则 null
       ↓
  getMemorySearchManager / MemoryIndexManager 用其决定 backend、索引路径、embedding、检索参数等

实现方式

  • 插件控制:默认使用 memory-core 插件(可设 plugins.slots.memory = “none” 关掉)。
  • 工具:
    • memory_search:对 MEMORY.md 和 memory/*.md 做语义检索(按 ~400 token 分块、80 token 重叠),返回片段 + 文件路径 + 行号;可选开启 BM25 + 向量 的混合检索。
    • memory_get:按路径(及可选 from/lines)读取 MEMORY 或 memory 下的文件片段,供在检索后精确拉取,控制上下文长度。
  • 向量索引:
    • 对 MEMORY.md 和 memory/*.md 建索引;索引按 agent 存于 ~/.clawdbot/memory/.sqlite(路径可配)。
    • 支持远程 embedding(OpenAI、Gemini 等)或本地模型(如 GGUF);可选 sqlite-vec 做向量加速。
    • 文件变更有 watcher(debounce),索引异步更新;若 embedding 模型/端点等变化,会整库重建索引。

混搜权重分配

const DEFAULT_HYBRID_ENABLED = true;    // 是否开启混搜,默认同时用向量相似度和 BM25 全文,向量找语义、BM25 找精确词(如 ID、命令)。
const DEFAULT_HYBRID_VECTOR_WEIGHT = 0.7;   // 向量权重 70%,
const DEFAULT_HYBRID_TEXT_WEIGHT = 0.3;     // 关键词权重 30%,最终得分 = 0.7×向量分 + 0.3×文本分(归一化后),偏重语义。
const DEFAULT_HYBRID_CANDIDATE_MULTIPLIER = 4;  // 候选池倍数
const DEFAULT_MAX_RESULTS = 6;              // 最大返回结果数
const DEFAULT_MIN_SCORE = 0.35;             // 最低分数阈值

最终分数的计算公式非常简单(src/memory/hybrid.ts):

// 线性加权合并
const score = vectorWeight * vectorScore + textWeight * textScore;

// BM25 排名转分数(排名越高,分数越高)
function bm25RankToScore(rank: number): number {
  return 1 / (1 + rank);  // rank=0 → score=1, rank=9 → score=0.1
}

这意味着:

  • 向量搜索和文本三七开:最终得分 = 0.7×向量分 + 0.3×文本分(归一化后),偏重语义。
  • 候选池放大 4 倍:先取 maxResults × 4 的候选再合并、排序、截到 maxResults,提高最终 Top‑N 质量。

Moltbot + powermem 方案

有 PowerMem VS 没有 PowerMem

维度 没加 PowerMem(只用 core) 加了 PowerMem(backend=powermem)
存储形态 工作区 Markdown(MEMORY.md、memory/*.md)+ 本地 SQLite 向量索引 记忆存在 PowerMem 服务端(向量 + 全文 + 图(可选)),Moltbot 不落盘
智能抽取与去重 无:依赖模型自己写 Markdown,可能重复、冲突 有:PowerMem 可做 LLM 事实抽取、去重、冲突更新,记忆更干净
遗忘与衰减 无:内容一旦写入就一直在 有:PowerMem 支持艾宾浩斯遗忘曲线、时间衰减,可「自然遗忘」旧信息
多智能体 / 多用户 按 agent 隔离(目录与索引分离) PowerMem 原生 agent_id / user_id、权限与协作,适合多 agent、多用户场景
部署与依赖 仅需 Moltbot + 可选 embedding API,无额外服务 需单独部署/运维 PowerMem 服务(HTTP API),多一个组件
检索能力 向量 + 可选 BM25,单机、可控 向量 + 全文 + 图检索(可选)、用户画像改写等,能力更丰富、可扩展
适用场景 个人/单机、强调「文件即真相」、简单运维 多用户/多 agent、要智能抽取与遗忘、愿多维护一个记忆服务

集成 powermem 方案

集成方式:已插件的方式进行集成

┌─────────────────────────────────────────────────────────────────┐
│  Moltbot (Node/TS)                                               │
│  ┌─────────────────────────────────────────────────────────────┐ │
│  │  extension: memory-powermem                                 │ │
│  │  - register() → tools + lifecycle hooks + CLI               │ │
│  │  - HTTP client → PowerMem API (fetch)                       │ │
│  └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                                    │
                                    │ HTTPS / HTTP
                                    ▼
┌─────────────────────────────────────────────────────────────────┐
│  PowerMem Server (Python)                                        │
│  - POST /api/v1/memories        (add, optional infer=true)       │
│  - POST /api/v1/memories/search (semantic search)                │
│  - DELETE /api/v1/memories/:id (forget)                          │
│  - GET  /api/v1/system/health   (health check)                   │
└─────────────────────────────────────────────────────────────────┘
  • 集成方式:新增插件 extensions/memory-powermem,通过 HTTP 调用 PowerMem 已启动的 API 服务;不把 PowerMem 作为库嵌入 Moltbot 进程。
  • 部署:用户需单独启动 PowerMem(如 powermem-server --host 0.0.0.0 --port 8000 或 Docker),并在 Moltbot 配置中填写 baseUrl(及可选 apiKey)。

代码结构

代码地址:GitHub - ob-labs/memory-powermem: openclaw(clawdbot) Plugin: give your bot long-term memory with PowerMem—smart extraction, Ebbinghaus recall, multi-agent isolation. · GitHub

moltbot-extension-powermem/
├── index.ts              # 插件入口:定义插件、注册工具/CLI/生命周期
├── client.ts             # PowerMem HTTP 客户端
├── config.ts             # 配置解析与校验
├── moltbot.plugin.json   # 插件元数据与 UI 配置
├── package.json          # 依赖与 npm 配置
├── tsconfig.json         # TypeScript 配置
└──── types/
    └── clawdbot-plugin-sdk.d.ts   # Moltbot 插件 SDK 类型声明

在 Moltbot Agent 里会暴露这些能力:

  • memory_recall — 按查询搜索长期记忆
  • memory_store — 写入一条记忆(可选是否智能抽取)
  • memory_forget — 按记忆 ID 或按搜索条件删除

使用 powermem 插件

Step1: 前置条件

  • 已安装 Moltbot(CLI + gateway 能正常用)
  • PowerMem 服务:需要单独安装并启动(见下文两种方式,任选其一)
  • 若用 PowerMem 的「智能抽取」:需在 PowerMem 的 .env 里配置好 LLM + Embedding 的 API Key(如通义千问 / OpenAI)

Step2:把本插件装进 Moltbot

在你本机执行(路径改成你实际克隆的目录):

# 若插件在本机目录(例如克隆下来的)
moltbot plugins install /path/to/moltbot-extension-powermem

# 开发时想改代码即生效,可用链接方式(不拷贝)
moltbot plugins install -l /path/to/moltbot-extension-powermem

安装成功后,可用 moltbot plugins list 确认能看到 memory-powermem。

Step3:配置 Moltbot 使用本插件

编辑 Moltbot 的配置文件(常见位置:~/.clawdbot/config.json 或项目里的 moltbot.json),在 根级 增加或合并 plugins 段,并把记忆槽指向本插件,并写上 PowerMem 的地址。

示例(JSON):

{
  "plugins": {
    "slots": { "memory": "memory-powermem" },
    "entries": {
      "memory-powermem": {
        "enabled": true,
        "config": {
          "baseUrl": "http://localhost:8000",
          "autoCapture": true,
          "autoRecall": true,
          "inferOnAdd": true
        }
      }
    }
  }
}

说明:

  • baseUrl:PowerMem 的 HTTP 地址,不要加 /api/v1,就写 http://localhost:8000 或你的实际主机/端口。
  • 若 PowerMem 开了 API Key 鉴权,在 config 里增加 "apiKey": "你的key"。
  • 改完配置后重启 Moltbot gateway(或重启 Mac 菜单栏应用),配置才会生效。

Step4:验证插件与 PowerMem 连通

在终端执行:

# 检查 PowerMem 服务是否可达
moltbot ltm health

若输出里没有报错、能看到健康状态,说明插件已连上 PowerMem。

Step5: 测试手动写入 + 搜索

我们来简单测试一下,用手动写入验证数据库是否有数据

pnpm moltbot ltm add "喜欢软件界面为炫酷黑"

pnpm moltbot ltm search "黑色"

若搜索能返回刚写的那条(或类似内容),说明「安装 PowerMem → 安装插件 → 配置 Moltbot」全流程已打通。

下面是执行结果:

➜  moltbot git:(add_powermem) ✗ pnpm moltbot ltm add "我喜欢软件的界面为炫酷黑"

> moltbot@2026.1.27-beta.1 moltbot /Users/jingshun.tq/project/moltbot
> node scripts/run-node.mjs ltm add '我喜欢软件的界面为炫酷黑'

10:52:13 [plugins] memory-powermem: plugin registered (baseUrl: http://localhost:8000, user: moltbot-user, agent: moltbot-agent)

🦞 Moltbot 2026.1.27-beta.1 (6e09492) — I can run local, remote, or purely on vibes—results may vary with DNS.

Stored 1 item(s): [ 672030219405623300 ]
➜  moltbot git:(add_powermem) ✗ pnpm moltbot ltm add "我喜欢软件的界面为炫酷黑"

> moltbot@2026.1.27-beta.1 moltbot /Users/jingshun.tq/project/moltbot
> node scripts/run-node.mjs ltm add '我喜欢软件的界面为炫酷黑'

10:52:47 [plugins] memory-powermem: plugin registered (baseUrl: http://localhost:8000, user: moltbot-user, agent: moltbot-agent)

🦞 Moltbot 2026.1.27-beta.1 (6e09492) — Give me a workspace and I'll give you fewer tabs, fewer toggles, and more oxygen.

Stored 1 item(s): [ 672031428522803200 ]
➜  moltbot git:(add_powermem) ✗ pnpm moltbot ltm search "黑色"

> moltbot@2026.1.27-beta.1 moltbot /Users/jingshun.tq/project/moltbot
> node scripts/run-node.mjs ltm search '黑色'

10:53:16 [plugins] memory-powermem: plugin registered (baseUrl: http://localhost:8000, user: moltbot-user, agent: moltbot-agent)

🦞 Moltbot 2026.1.27-beta.1 (6e09492) — I'll do the boring stuff while you dramatically stare at the logs like it's cinema.

[
  {
    "memory_id": 672031428522803200,
    "content": "喜欢软件界面为炫酷黑",
    "score": 0.01639344262295082,
    "metadata": {
      "_vector_similarity": 0.7113943570021182,
      "_quality_score": 0.7113943570021182,
      "_fusion_score": 0.01639344262295082,
      "_fusion_info": {
        "vector_rank": 1,
        "fts_rank": null,
        "sparse_rank": null,
        "rrf_score": 0.01639344262295082,
        "fusion_method": "rrf",
        "vector_weight": 0.5,
        "fts_weight": 0.5,
        "sparse_weight": 0
      },
      "last_searched_at": "2026-01-29T10:53:21.808320Z",
      "search_count": 1
    }
  }
]

看一眼数据库,妥妥的已经写入了

obclient(root@obmysql)[powermem]> select id,document,metadata,user_id,agent_id,run_id,actor_id,hash,created_at,updated_at,category,fulltext_content from memories limit10\G;
*************************** 1. row ***************************
              id: 672031428522803200
        document: 喜欢软件界面为炫酷黑
        metadata: {}
         user_id: moltbot-user
        agent_id: moltbot-agent
          run_id: NULL
        actor_id:
            hash: c7d63391192d288848068a185d2fd42b
      created_at: 2026-01-29T10:52:57.638765+00:00
      updated_at: 2026-01-29T10:52:58.886383+00:00
        category:
fulltext_content: 喜欢软件界面为炫酷黑
1 row in set (0.006 sec)