# mem0-integration Skill ## 功能概述 为 OpenClaw 提供基于 mem0 + Qdrant 的对话记忆系统 (Memory Layer 4),包括: - Pre-Hook 语义检索注入(对话前自动召回相关记忆) - Post-Hook 异步写入(对话后智能筛选并存储记忆) - 三级可见性隔离 (public / project / private) - 记忆衰减 (expiration_date: 7d / 30d / permanent) - 智能写入过滤(跳过无价值对话) - Layer 3 FTS5 本地全文检索 fallback(Qdrant 不可达时接管) - 冷启动记忆预加载(新会话自动注入最近上下文) > 架构全景文档: `docs/MEMORY_ARCHITECTURE.md` --- ## 文件结构 ``` skills/mem0-integration/ ├── SKILL.md # 本文档 — 开发者参考 ├── openclaw.plugin.json # OpenClaw 插件声明 (lifecycle hook) ├── skill.json # Skill 元数据 ├── index.js # JS 入口,桥接 OpenClaw Gateway ↔ Python │ │ ── 核心运行时 ── ├── mem0_client.py # 核心客户端:初始化、检索、写入、队列、缓存 ├── openclaw_interceptor.py # Pre/Post-Hook 拦截器(Gateway 调用入口) ├── session_init.py # 冷启动记忆预加载 │ │ ── 配置 ── ├── config.yaml # mem0 全局配置(Qdrant / LLM / Embedder / Cache) ├── project_registry.yaml # Agent-项目归属关系(决定 project 级可见性) │ │ ── 辅助工具 ── ├── local_search.py # Layer 3: SQLite FTS5 本地全文检索 fallback ├── memory_cleanup.py # 月度记忆统计与清理脚本 ├── migrate_to_single_collection.py # 从旧多 Collection 迁移到单库融合架构 ├── recover_memories.py # 记忆恢复工具 v1 ├── recover_memories_v2.py # 记忆恢复工具 v2 │ │ ── 旧版 / 命令 ── ├── commands.py # /memory 命令处理 ├── openclaw_commands.py # OpenClaw 原生命令扩展 ├── mem0_integration.py # 旧版集成入口(已被 mem0_client.py 取代) │ │ ── 测试 ── ├── test_mem0.py # mem0 单元测试 ├── test_integration.py # 集成测试 └── test_production.py # 生产环境测试 ``` --- ## 环境变量 | 变量名 | 用途 | 必需 | 默认值 | |--------|------|------|--------| | `MEM0_DASHSCOPE_API_KEY` | DashScope API 密钥 (LLM + Embedding) | 是 | — | | `DASHSCOPE_API_KEY` | 备选 key 名称 (二选一) | — | — | | `MEM0_QDRANT_HOST` | Qdrant 地址 | 否 | `localhost` | | `MEM0_QDRANT_PORT` | Qdrant 端口 | 否 | `6333` | | `MEM0_LLM_MODEL` | LLM 模型名 | 否 | `qwen-plus` | | `MEM0_EMBEDDER_MODEL` | Embedding 模型名 | 否 | `text-embedding-v4` | API 密钥查找顺序: `MEM0_DASHSCOPE_API_KEY` → `DASHSCOPE_API_KEY` → 已有 `OPENAI_API_KEY` DashScope 兼容模式需要同时设置 `OPENAI_API_BASE` 和 `OPENAI_BASE_URL`,代码在模块加载时自动完成。 --- ## 核心模块说明 ### mem0_client.py — 核心客户端 **类: `Mem0Client`** - `_init_memory()` — 初始化 mem0 Memory 实例(Qdrant + DashScope Embedder 1024 维) - `start()` — 启动异步写入队列的后台 worker(必须在 event loop 中调用) - `pre_hook_search()` — Pre-Hook: 三阶段检索(public → project → private → legacy fallback),带缓存和超时 - `post_hook_add()` — Post-Hook: 智能过滤 + 自动分类(memory_type / visibility)+ 入队 - `_execute_write()` — 后台异步写入 Qdrant,附带 metadata 和 expiration_date **类: `AsyncMemoryQueue`** - 基于 `collections.deque` 的有界异步队列 - 后台 worker 每秒轮询,批量处理 **全局实例:** `mem0_client = Mem0Client()` — 模块加载时自动创建 ### openclaw_interceptor.py — 拦截器 Gateway 调用入口。从 `context` dict 中提取 `user_id`、`agent_id`、`visibility`、`project_id`、`memory_type`,桥接到 `mem0_client`。 ### local_search.py — Layer 3 FTS5 Fallback 基于 SQLite FTS5 的本地全文检索,Qdrant 不可达时接管。 - CJK 字符逐字拆分 + ASCII 单词保持完整(过滤标点噪音) - 每个 Agent 维护独立的 FTS5 索引文件 - `rebuild_index()` 扫描 MEMORY.md + memory/*.md + 共享核心文件 --- ## 开发者注意事项 ### mem0 filter 格式 mem0 `search()` 的 `filters` 参数使用**扁平 dict**,多个条件为隐式 AND: ```python # 正确: 扁平 dict (mem0 Python SDK) filters={"visibility": "private", "agent_id": "main"} # 错误: 嵌套 AND (Qdrant 原生 API 语法,mem0 不支持) filters={"AND": [{"visibility": "private"}, {"agent_id": "main"}]} ``` 直接操作 Qdrant (如 `memory_cleanup.py`) 时使用原生 Filter 对象: ```python from qdrant_client.models import Filter, FieldCondition, MatchValue Filter(must=[FieldCondition(key="visibility", match=MatchValue(value="public"))]) ``` ### mem0 add() 的 agent_id `mem0.add()` 必须同时传递 `agent_id` 作为顶层参数和 metadata 字段: ```python self.local_memory.add( messages=messages, user_id=user_id, agent_id=agent_id, # 顶层: mem0 内部索引用 metadata={ "agent_id": agent_id, # metadata: 自定义 filter 查询用 "visibility": "private", ... } ) ``` 原因: mem0 的 `search(agent_id=...)` 匹配顶层字段;`search(filters={"agent_id": ...})` 匹配 metadata 字段。两处都写入确保两种检索路径均能命中。 ### FTS5 中文分词 `local_search.py` 使用字符级分词(非 jieba),仅保留 CJK 统一表意文字 (U+4E00–U+9FFF) 和 ASCII 字母数字: - 输入 `"你好,world!"` → 输出 `"你 好 world"` - 标点、emoji、特殊符号被过滤,避免 FTS5 索引噪音 - 搜索精度低于 jieba 词级分词,但零依赖、零内存开销 ### 可见性自动分类 `_classify_visibility()` 只返回 `"public"` 或 `"private"`(不自动推断 `"project"`)。项目级可见性必须由调用方通过 `context` 显式传入 `visibility="project"` + `project_id`。 ### 记忆写入过滤规则 以下对话自动跳过写入: 1. 用户消息长度 < 5 字符 2. 匹配 SKIP_PATTERNS: 好的、收到、OK、嗯、行、没问题、感谢、谢谢 等 3. 以 `/` 开头的系统命令 --- ## 命令 通过 Telegram 使用: ``` /memory add <内容> # 手动添加记忆 /memory search <关键词> # 搜索记忆 /memory list # 列出所有记忆 /memory delete # 删除记忆 /memory status # 查看状态 ``` --- ## 依赖 ``` mem0ai # 核心记忆管理 qdrant-client # Qdrant 向量数据库客户端 pyyaml # YAML 配置解析 ``` --- ## 更新记录 ### v2.1 (2026-03-01) - 修复: `_execute_search` filter 格式从 Qdrant 嵌套语法改为 mem0 扁平 dict - 修复: `_execute_write` 补充 `agent_id` 顶层参数 - 修复: `session_init.py` 补充 `OPENAI_API_BASE` 环境变量 - 修复: `local_search.py` 中文分词过滤标点噪音 - 清理: 移除未使用的 import (Optional, os, re) ### v2.0 (2026-02-28) - 新增: 三级可见性 (public / project / private) + 三阶段检索 - 新增: 记忆衰减 (expiration_date) - 新增: 智能写入过滤 - 新增: 项目注册表 (project_registry.yaml) - 新增: Layer 3 SQLite FTS5 本地全文检索 - 新增: 月度清理脚本 (memory_cleanup.py) - 安全: 所有 API Key 改为环境变量 ### v1.0 (2026-02-22) - 初始版本: mem0 + Qdrant 基础集成