
1. 为什么我要折腾一个可编程记忆系统第一次接触 OpenClaw-SuperMemory 是在一个做企业知识库的朋友那里。他当时吐槽说团队用了一堆笔记软件文档散落在飞书、Notion、本地 Markdown 和微信收藏里每次新人问“上次那个接口文档在哪”所有人都要翻半天。后来他把 OpenClaw-SuperMemory 部署在一台闲置的迷你主机上把所有资料灌进去用自然语言就能检索到具体段落还能让系统自动把相关记忆串联起来。我当时就来了兴趣因为我自己也有类似痛点做项目时查过的资料、踩过的坑、写过的配置过两个月就忘得一干二净再遇到同样问题又得重新搜一遍。OpenClaw-SuperMemory 本质上是一个可编程记忆系统它和普通笔记软件最大的区别在于“可编程”三个字。普通笔记是你手动整理、手动打标签、手动搜索而 SuperMemory 允许你通过 API 和脚本把记忆的写入、检索、关联、过期策略全部自动化。你可以把它理解成一个带向量检索能力的本地数据库外加一层智能调度逻辑。它解决的核心问题是让知识不再被动等待检索而是主动参与你的工作流。这篇文章适合谁看如果你手头有闲置的电脑或服务器想搭建一个完全本地化、数据不出内网的智能知识管理系统并且愿意写一点 Python 或 Shell 脚本做自动化那这篇实战记录就是为你准备的。如果你只是想找个开箱即用的笔记软件那 SuperMemory 可能不是最优解因为它需要你投入一些配置成本。但一旦跑通你会发现它带来的效率提升是普通工具给不了的。我这次部署的环境是一台 Dell T30 服务器刷了工作站 BIOS 后装了 Ubuntu 22.04配置是 Xeon E3-1225 v5、16GB 内存、256GB SSD 加 2TB 机械盘。这个配置不算高但跑 SuperMemory 加一个轻量级本地大模型做 embedding 完全够用。下面我把整个部署过程、核心配置、踩过的坑和优化技巧全部拆开讲。2. 部署前的整体设计与选型思路2.1 为什么选择本地部署而不是云服务很多人第一反应是为什么不直接用 Notion AI 或者飞书知识库答案很简单——数据主权和可编程性。云服务的数据在别人服务器上你没法直接通过脚本批量写入记忆也没法自定义检索策略。比如我想实现“每天早上 8 点自动把昨天 Git 提交记录里的关键变更写入记忆系统”云笔记的 API 要么不开放要么限制重重。而本地部署的 SuperMemory 就是一个 HTTP 服务我想怎么调就怎么调。另一个原因是成本。云服务的 AI 检索功能通常按调用次数收费长期使用下来不便宜。本地部署一次性投入硬件后续只有电费。我这台 T30 二手买来一千多块跑了一年多没出过问题。对于个人开发者或小团队来说这个投入产出比很划算。还有一个容易被忽略的点离线可用。有时候在没网的环境下比如出差路上、客户现场本地记忆系统依然能工作。虽然 embedding 模型需要本地跑但现在的轻量级模型在 CPU 上也能跑出可接受的速度。2.2 核心组件选型与版本锁定SuperMemory 本身是一个 Python 项目依赖几个关键组件。我在选型时主要考虑兼容性和资源占用最终确定的组合如下组件选型版本选择理由操作系统Ubuntu Server22.04 LTS长期支持社区资料多Dell T30 驱动兼容好PythonCPython3.10.12SuperMemory 要求 3.93.10 在稳定性和新特性间平衡最好向量数据库ChromaDB0.4.24轻量、纯 Python、支持持久化适合单机部署Embedding 模型BAAI/bge-small-zh-v1.5-中文效果好模型小约 100MBCPU 推理快本地大模型Ollama Qwen2.5:7b-用于记忆摘要和关联生成7B 量化版在 16GB 内存下流畅反向代理Nginx1.18做 HTTPS 和访问控制方便外部设备接入进程管理systemd-系统自带开机自启日志管理方便这里重点说一下 embedding 模型的选择。我试过text-embedding-ada-002的本地替代方案也试过m3e-base最后锁定bge-small-zh-v1.5。原因有三第一它对中文语义的捕捉明显优于同尺寸的英文模型第二模型体积小加载后内存占用不到 500MB第三推理速度快一条 200 字的文本在 CPU 上大约 30ms 就能出向量。如果你追求更高精度可以换bge-large-zh-v1.5但内存占用会翻倍推理速度也会慢不少。Ollama 的选择是因为它把模型下载、量化、服务化都封装好了一条命令就能跑起来。Qwen2.5:7b 的 q4_K_M 量化版大约 4.5GB在 16GB 内存的机器上跑得很稳。它的作用是当 SuperMemory 需要生成记忆摘要或建立关联时调用本地 Ollama 接口不需要联网。2.3 目录结构与数据流设计在动手之前我先规划了目录结构避免后期文件乱放。最终确定的布局如下/opt/supermemory/ ├── app/ # SuperMemory 主程序 ├── data/ │ ├── chroma/ # 向量数据库持久化目录 │ ├── raw/ # 原始文档存储 │ └── backup/ # 每日备份 ├── models/ # 本地模型文件 ├── scripts/ # 自定义脚本 │ ├── ingest.py # 批量导入脚本 │ ├── daily_digest.py # 每日摘要生成 │ └── cleanup.py # 过期记忆清理 ├── logs/ # 日志目录 └── config/ ├── supermemory.yaml # 主配置 └── nginx.conf # 反向代理配置数据流是这样的外部数据源Markdown 文件、网页剪藏、Git 提交记录通过ingest.py脚本写入 SuperMemory写入时自动调用本地 embedding 模型生成向量存入 ChromaDB。检索时用户输入自然语言查询系统先把查询转成向量在 ChromaDB 里做相似度搜索返回最相关的记忆片段。如果开启了“智能关联”功能系统还会调用 Ollama 对检索结果做二次摘要和关联推荐。这个设计的关键在于原始文档和向量数据分离。raw/目录存原始文件chroma/存向量索引。这样做的好处是如果向量模型升级了我可以重新生成索引而不影响原始数据。备份时也只需要备份raw/和config/向量索引可以重建。3. 核心细节解析与实操要点3.1 系统环境准备与依赖安装Ubuntu 22.04 装好后第一件事是更新系统并安装基础依赖。我习惯先换国内源不然下载速度太慢。这里以清华源为例sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo sed -i s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list sudo apt update sudo apt upgrade -y然后安装 Python 环境和编译工具。SuperMemory 的一些依赖需要编译所以build-essential和python3-dev必须装sudo apt install -y python3.10 python3.10-venv python3-pip build-essential python3-dev git curl nginx接下来创建专用用户和目录。我不建议直接用 root 跑服务权限太大容易出问题sudo useradd -r -s /bin/bash -m -d /opt/supermemory supermemory sudo mkdir -p /opt/supermemory/{app,data/{chroma,raw,backup},models,scripts,logs,config} sudo chown -R supermemory:supermemory /opt/supermemory注意目录权限一定要提前设好否则后面 SuperMemory 写入 ChromaDB 时会报权限错误。我一开始忘了改data/chroma的属主排查了半小时才发现是权限问题。3.2 SuperMemory 主程序部署与配置SuperMemory 目前没有发布到 PyPI需要从源码安装。我用的版本是 commita3f8c21这个版本在中文环境下比较稳定sudo -u supermemory git clone https://github.com/openclaw/supermemory.git /opt/supermemory/app cd /opt/supermemory/app sudo -u supermemory python3.10 -m venv venv sudo -u supermemory ./venv/bin/pip install -r requirements.txt安装完成后复制示例配置并修改。核心配置项如下# /opt/supermemory/config/supermemory.yaml server: host: 127.0.0.1 port: 8765 workers: 2 storage: chroma_path: /opt/supermemory/data/chroma raw_path: /opt/supermemory/data/raw backup_path: /opt/supermemory/data/backup embedding: model: BAAI/bge-small-zh-v1.5 device: cpu batch_size: 16 cache_dir: /opt/supermemory/models llm: provider: ollama base_url: http://127.0.0.1:11434 model: qwen2.5:7b timeout: 60 memory: max_tokens: 512 similarity_threshold: 0.65 auto_expire_days: 90 enable_association: true这里有几个参数需要解释。similarity_threshold设为 0.65 是经过多次测试的结果。设太高比如 0.8很多相关但表述不同的记忆会被漏掉设太低比如 0.5会返回大量无关内容。0.65 在中文场景下召回率和准确率比较平衡。auto_expire_days设为 90 天意思是超过 90 天没有被访问过的记忆会自动归档避免数据库无限膨胀。这个值可以根据你的使用频率调整。enable_association开启后每次检索会额外调用 Ollama 生成关联推荐。这个功能很实用但会增加响应时间。如果你追求速度可以关掉或者只在特定查询时开启。3.3 本地 Embedding 模型与 Ollama 配置Embedding 模型第一次使用时会自动下载但国内网络下载 HuggingFace 模型经常超时。我建议提前手动下载并放到models/目录cd /opt/supermemory/models sudo -u supermemory git lfs install sudo -u supermemory git clone https://huggingface.co/BAAI/bge-small-zh-v1.5如果 git lfs 速度慢也可以用wget直接下载模型文件。下载完成后在配置里把model改成绝对路径/opt/supermemory/models/bge-small-zh-v1.5避免运行时再去联网。Ollama 的安装很简单curl -fsSL https://ollama.com/install.sh | sh sudo systemctl enable ollama sudo systemctl start ollama ollama pull qwen2.5:7b拉取模型需要一些时间7B 的 q4 量化版大约 4.5GB。拉完后测试一下ollama run qwen2.5:7b 用一句话解释什么是向量数据库如果能在几秒内返回结果说明 Ollama 工作正常。这里有个小技巧Ollama 默认只监听127.0.0.1:11434如果你想让 SuperMemory 和 Ollama 在同一台机器上通信这个默认配置就够了。但如果分开部署需要改OLLAMA_HOST环境变量。3.4 系统服务化与开机自启为了让 SuperMemory 在后台稳定运行我把它做成 systemd 服务。创建/etc/systemd/system/supermemory.service[Unit] DescriptionSuperMemory Service Afternetwork.target ollama.service Wantsollama.service [Service] Typesimple Usersupermemory Groupsupermemory WorkingDirectory/opt/supermemory/app EnvironmentPATH/opt/supermemory/app/venv/bin:/usr/local/bin:/usr/bin:/bin ExecStart/opt/supermemory/app/venv/bin/python -m supermemory.server --config /opt/supermemory/config/supermemory.yaml Restartalways RestartSec10 StandardOutputappend:/opt/supermemory/logs/supermemory.log StandardErrorappend:/opt/supermemory/logs/supermemory.error.log [Install] WantedBymulti-user.target然后启用并启动sudo systemctl daemon-reload sudo systemctl enable supermemory sudo systemctl start supermemory sudo systemctl status supermemory如果状态显示active (running)说明服务跑起来了。这时候可以用curl测试一下 APIcurl -X POST http://127.0.0.1:8765/api/v1/memory \ -H Content-Type: application/json \ -d {content: Dell T30 刷工作站 BIOS 后需要重新配置风扇策略, tags: [硬件, 服务器]}返回{status: ok, id: mem_xxx}就说明写入成功了。4. 实操过程与核心环节实现4.1 批量导入历史文档的完整脚本部署完成后第一件事是把历史资料灌进去。我写了一个ingest.py脚本支持 Markdown、TXT 和 HTML 文件批量导入。核心逻辑是遍历目录读取文件内容按段落切分然后调用 SuperMemory API 写入。#!/usr/bin/env python3 # /opt/supermemory/scripts/ingest.py import os import sys import requests import hashlib from pathlib import Path API_BASE http://127.0.0.1:8765/api/v1 SUPPORTED_EXT {.md, .txt, .html, .py, .sh, .yaml, .yml} def chunk_text(text, max_len500, overlap50): 按段落切分保证每段不超过 max_len 字符 paragraphs [p.strip() for p in text.split(\n\n) if p.strip()] chunks [] current for para in paragraphs: if len(current) len(para) max_len: current para \n\n else: if current: chunks.append(current.strip()) current para \n\n if current: chunks.append(current.strip()) return chunks def ingest_file(filepath): path Path(filepath) if path.suffix.lower() not in SUPPORTED_EXT: return 0 try: content path.read_text(encodingutf-8, errorsignore) except Exception as e: print(f[SKIP] {filepath}: {e}) return 0 chunks chunk_text(content) count 0 for i, chunk in enumerate(chunks): doc_id hashlib.md5(f{filepath}_{i}.encode()).hexdigest() payload { content: chunk, tags: [imported, path.suffix.lstrip(.)], source: str(filepath), doc_id: doc_id } try: resp requests.post(f{API_BASE}/memory, jsonpayload, timeout30) if resp.status_code 200: count 1 else: print(f[FAIL] {filepath} chunk {i}: {resp.text}) except Exception as e: print(f[ERROR] {filepath} chunk {i}: {e}) return count if __name__ __main__: if len(sys.argv) 2: print(Usage: ingest.py directory_or_file) sys.exit(1) target sys.argv[1] total 0 if os.path.isfile(target): total ingest_file(target) else: for root, _, files in os.walk(target): for f in files: total ingest_file(os.path.join(root, f)) print(fDone. Total chunks ingested: {total})这个脚本有几个设计考虑。第一用doc_id做去重同一个文件重复导入不会产生重复记忆。第二按段落切分而不是按固定字符数硬切避免把一句话截断。第三overlap参数虽然定义了但实际没用上因为按段落切分已经保证了语义完整性。如果你处理的是长技术文档可以考虑加滑动窗口。运行方式sudo -u supermemory /opt/supermemory/app/venv/bin/python /opt/supermemory/scripts/ingest.py /home/user/documents/notes导入 1000 个文件大约需要 10-15 分钟取决于文件大小和 CPU 性能。导入过程中可以看日志确认进度tail -f /opt/supermemory/logs/supermemory.log4.2 每日自动摘要与记忆关联生成SuperMemory 的“可编程”特性最实用的地方是定时任务。我配置了一个daily_digest.py每天早上 8 点自动把前一天新增的记忆做摘要并生成关联推荐。#!/usr/bin/env python3 # /opt/supermemory/scripts/daily_digest.py import requests import datetime API_BASE http://127.0.0.1:8765/api/v1 OLLAMA_URL http://127.0.0.1:11434/api/generate def get_recent_memories(days1): since (datetime.datetime.now() - datetime.timedelta(daysdays)).isoformat() resp requests.get(f{API_BASE}/memory/recent, params{since: since}, timeout30) return resp.json().get(memories, []) def summarize(memories): if not memories: return 昨日无新增记忆。 text \n.join([m[content][:200] for m in memories[:20]]) prompt f请用中文总结以下记忆片段的主题和关键信息控制在200字以内\n\n{text} resp requests.post(OLLAMA_URL, json{ model: qwen2.5:7b, prompt: prompt, stream: False }, timeout120) return resp.json().get(response, ).strip() def save_digest(summary): payload { content: f[每日摘要] {datetime.date.today().isoformat()}\n\n{summary}, tags: [digest, daily], source: auto_digest } requests.post(f{API_BASE}/memory, jsonpayload, timeout30) if __name__ __main__: memories get_recent_memories(1) summary summarize(memories) save_digest(summary) print(fDigest saved. Memories processed: {len(memories)})然后加 crontabsudo -u supermemory crontab -e # 添加一行 0 8 * * * /opt/supermemory/app/venv/bin/python /opt/supermemory/scripts/daily_digest.py /opt/supermemory/logs/digest.log 21这个摘要功能的好处是你不需要每天手动整理笔记系统会自动帮你把零散记忆归纳成主题。我用了三个月每天早上花两分钟看摘要就能回忆起前一天学到的关键内容。4.3 检索接口的调用与结果优化SuperMemory 的检索 API 支持多种模式。最基础的是语义检索curl -X POST http://127.0.0.1:8765/api/v1/search \ -H Content-Type: application/json \ -d {query: Dell T30 风扇策略怎么配置, top_k: 5}返回结果包含content、score、source和tags。score是余弦相似度范围 0 到 1越高越相关。我实测下来score在 0.7 以上的结果基本可以直接用0.6 到 0.7 之间的需要人工判断低于 0.6 的基本是噪音。如果你想让检索结果更精准可以在查询时加标签过滤{ query: 风扇策略, top_k: 5, filter: {tags: {$contains: 硬件}} }这个功能在记忆库大了之后特别有用。比如你只想在“项目实战”类记忆里搜索就可以加filter条件避免返回无关的读书笔记。还有一个高级用法是“混合检索”先用关键词过滤缩小范围再做语义排序。SuperMemory 支持在查询里同时传keyword和query参数{ query: 如何配置反向代理, keyword: Nginx, top_k: 3 }这样系统会先找包含“Nginx”的记忆再按语义相似度排序。实测下来混合检索的准确率比纯语义检索高 20% 左右尤其是在技术术语多的场景下。4.4 数据备份与迁移方案本地部署最大的风险是硬件故障。我配置了每日自动备份把raw/和config/打包压缩保留最近 30 天。#!/bin/bash # /opt/supermemory/scripts/backup.sh BACKUP_DIR/opt/supermemory/data/backup DATE$(date %Y%m%d) tar -czf ${BACKUP_DIR}/supermemory_${DATE}.tar.gz \ -C /opt/supermemory \ data/raw config # 删除30天前的备份 find ${BACKUP_DIR} -name supermemory_*.tar.gz -mtime 30 -delete echo Backup completed: ${DATE}加到 crontab 每天凌晨 3 点执行0 3 * * * /bin/bash /opt/supermemory/scripts/backup.sh /opt/supermemory/logs/backup.log 21迁移到新机器时只需要把raw/和config/复制过去重新生成向量索引即可。重新索引的命令sudo -u supermemory /opt/supermemory/app/venv/bin/python -m supermemory.reindex --config /opt/supermemory/config/supermemory.yaml这个过程会遍历raw/下所有文件重新调用 embedding 模型生成向量。1000 个文件大约需要 5 分钟。虽然比直接复制chroma/慢但好处是向量模型升级后可以无缝迁移。5. 常见问题与排查技巧实录5.1 服务启动失败与端口占用排查第一次启动 SuperMemory 时我遇到了Address already in use错误。原因是 8765 端口被另一个测试服务占用了。排查方法sudo lsof -i :8765 # 或者 sudo ss -tlnp | grep 8765找到占用进程后要么杀掉它要么改 SuperMemory 的端口。我选择改端口在supermemory.yaml里把port改成8766然后重启服务。另一个常见问题是 Python 依赖冲突。SuperMemory 依赖的chromadb和pydantic版本有严格要求如果系统里已经装了其他版本的包可能会报ImportError。解决办法是用虚拟环境隔离我前面已经建了venv所有依赖都装在虚拟环境里不会和系统 Python 冲突。如果服务启动后立刻退出查看错误日志sudo journalctl -u supermemory -n 50 --no-pager日志里通常会明确告诉你缺哪个模块或哪个配置项写错了。5.2 Embedding 模型加载慢或内存不足在 16GB 内存的机器上同时跑 ChromaDB、Ollama 和 embedding 模型内存会比较紧张。我遇到过 embedding 模型加载时 OOMOut of Memory的情况。解决办法有两个第一限制 Ollama 的并发数。在/etc/systemd/system/ollama.service.d/override.conf里加[Service] EnvironmentOLLAMA_MAX_LOADED_MODELS1 EnvironmentOLLAMA_NUM_PARALLEL1第二把 embedding 模型的batch_size从 16 降到 8。虽然导入速度会慢一些但内存峰值能降低 30% 左右。如果你用的是bge-large-zh-v1.5建议至少 32GB 内存。bge-small在 16GB 下跑得很稳精度也够用除非你做的是法律或医疗等对精度要求极高的场景。5.3 检索结果不准确或返回空检索返回空结果通常有三个原因。第一记忆库确实是空的检查一下导入脚本是否成功执行。第二similarity_threshold设得太高把阈值降到 0.5 试试。第三查询语言和记忆语言不一致比如用英文查中文记忆embedding 模型对跨语言检索支持有限。如果检索结果不准确先检查 embedding 模型是否匹配。bge-small-zh-v1.5对中文优化过但如果你导入的是英文文档效果会打折扣。这种情况下可以换bge-m3这种多语言模型但模型体积会大很多。还有一个容易被忽略的点记忆切分粒度。如果一条记忆太长比如超过 1000 字embedding 会稀释关键信息导致检索时匹配度下降。我建议每条记忆控制在 200 到 500 字之间。导入脚本里的chunk_text函数就是干这个的。5.4 常见问题速查表问题现象可能原因排查命令解决方案服务启动失败端口占用ss -tlnp | grep 8765改端口或杀占用进程导入时报权限错误目录属主不对ls -la /opt/supermemory/datachown -R supermemory:supermemory检索返回空阈值为高或库为空curl .../api/v1/stats降阈值或重新导入内存不足 OOM模型并发太多free -h限制 Ollama 并发降 batch_size摘要生成超时Ollama 响应慢ollama ps换更小模型或增加 timeout向量索引损坏异常断电查看 chroma 日志删除chroma/重新索引提示每次修改配置后记得sudo systemctl restart supermemory否则改动不会生效。我踩过这个坑改完配置以为自动加载结果排查了半天才发现服务没重启。5.5 性能优化与长期维护心得跑了一段时间后我做了几项优化效果比较明显。第一把 ChromaDB 的持久化目录放到 SSD 上检索速度提升了大约 40%。机械盘虽然容量大但随机读写性能跟不上向量检索的需求。第二给 Ollama 设置了OLLAMA_KEEP_ALIVE24h让模型常驻内存避免每次调用都重新加载。第三定期清理过期记忆我设了 90 天自动归档但每月还会手动检查一次把确实没用的记忆彻底删除。长期维护方面我建议每周看一眼日志确认没有异常报错。每月做一次完整备份恢复测试确保备份文件真的能用。每季度评估一次 embedding 模型看看有没有更好的中文模型发布。这个系统不是一劳永逸的但维护成本很低每周花十分钟就够了。我个人在实际操作中的体会是SuperMemory 最大的价值不在于它用了多先进的 AI 技术而在于它把“记忆”变成了一个可编程的组件。你可以像调用数据库一样调用你的知识这才是它和普通笔记软件的本质区别。如果你也在为知识管理头疼不妨试试这个方案从导入第一批文档开始慢慢体会它带来的变化。