agentmemory on NAS 完整部署文档(Tailscale + DeepSeek 压缩 + 局域网 viewer)
已对照
rohitg00/agentmemory源码核对(npm 最新0.9.26,引擎锁定iii v0.11.2,Apache-2.0)。架构:NAS 跑一个全功能 agentmemory 服务器(数据在
/data卷)。
- API(3111):经 Tailscale sidecar 接入 tailnet → 多设备/远程访问,不暴露局域网/公网。
- viewer(3113):发布到 NAS 局域网 → 同一内网用浏览器直接打开。
- 压缩 LLM:走 OpenAI 兼容通道接 DeepSeek
deepseek-v4-flash。- 每台开发机只装 Claude Code 插件 + 轻量 MCP shim,经 tailnet 指向 NAS,共享同一份记忆。
⚠️ 安全须知:viewer(3113)是免密特权界面(它代理请求时自动附带你的
AGENTMEMORY_SECRET)。
绑到局域网意味着同一内网任何设备都能全权读写你的记忆。家庭内网可接受;公共/办公网请改用 SSH 隧道(见附录 B)。
下面是整体架构图,帮你快速理解各组件之间的关系:
0. 前置准备
# 在 NAS 上(SSH;需 Docker / Container Manager / Portainer 能跑 compose)
cd /volume1/docker # 群晖示例,换成你的路径
git clone --depth 1 https://github.com/rohitg00/agentmemory.git
Tailscale auth key:登录 https://login.tailscale.com/admin/settings/keys → Auth keys →
Generate auth key,设置:
- Reusable:开(容器重建可再次认证)
- Ephemeral:关(NAS 是常驻节点,别让它离线被清除)
- Expiration:默认 90 天即可(只在首次认证用一次)
- Tags:可不打
生成的 tskey-auth-xxxx 一会儿填进 .env。
收尾:容器连上后,去 Tailscale 后台 Machines → 找到 agentmemory 节点 → Disable key expiry,
否则约 180 天后节点会因 node key 过期掉线。
DeepSeek API key(用于压缩):登录 https://platform.deepseek.com → API keys → 创建,得到 sk-xxxx。
(key 必须你自己申请;别人无法提供。)
1.(推荐)定制 Dockerfile:开启本地向量嵌入 + 中文分词
coolify 的 Dockerfile 默认用 --omit=optional,会跳过本地向量模型,退化成纯 BM25 关键词检索;
且对中文是整段切词。你写中文、要语义召回,就改一行。
编辑 agentmemory/deploy/coolify/Dockerfile,把那条 npm install ... 改成:
RUN printf '{"name":"agentmemory-deploy","version":"1.0.0","private":true,"overrides":{"iii-sdk":"%s"}}\n' "${III_SDK_VERSION}" > package.json \
&& npm install "@agentmemory/agentmemory@${AGENTMEMORY_VERSION}" --no-fund --no-audit \
&& npm install @xenova/transformers @node-rs/jieba tiny-segmenter --no-fund --no-audit \
&& ln -s /opt/agentmemory/node_modules/.bin/agentmemory /usr/local/bin/agentmemory
(去掉了 --omit=optional,显式装了本地嵌入模型 + 中日韩分词器。)
维护提示:你改过这个文件后不要直接
git pull(会被覆盖)。日常升级只改 compose 里的版本号即可(见第 6 节)。
2. docker-compose.yml
存成 docker-compose.yml,和 clone 出来的 agentmemory/ 目录同级。
services:
# Tailscale 节点:持有网络栈,agentmemory 共享它
ts-agentmemory:
image: tailscale/tailscale:latest
hostname: agentmemory # → MagicDNS:http://agentmemory:3111
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false # 内核模式(需 /dev/net/tun)
volumes:
- ts-state:/var/lib/tailscale
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
ports:
- "3113:3113" # viewer 发布到 NAS 局域网(端口须发布在网络栈持有者上)
restart: unless-stopped
agentmemory:
build:
context: ./agentmemory/deploy/coolify
dockerfile: Dockerfile
args:
AGENTMEMORY_VERSION: "0.9.26"
III_VERSION: "0.11.2"
III_SDK_VERSION: "0.11.2"
network_mode: service:ts-agentmemory # 与 Tailscale 容器共享网络
depends_on:
- ts-agentmemory
environment:
# ---- 压缩 LLM:DeepSeek(OpenAI 兼容)----
- OPENAI_API_KEY=${OPENAI_API_KEY}
- OPENAI_BASE_URL=${OPENAI_BASE_URL} #https://api.deepseek.com
- OPENAI_MODEL=${OPENAI_MODEL} #deepseek-v4-flash
# ---- viewer 局域网访问 ----
- AGENTMEMORY_VIEWER_HOST=0.0.0.0
- VIEWER_ALLOWED_HOSTS=${NAS_LAN_IP}:3113
- VIEWER_ALLOWED_ORIGINS=http://${NAS_LAN_IP}:3113
volumes:
- agentmemory-data:/data
restart: unless-stopped
volumes:
ts-state:
agentmemory-data:
.env(同目录,务必加入 .gitignore):
TS_AUTHKEY=tskey-auth-xxxxxxxx
OPENAI_BASE_URL=sk-xxxxxxxx
OPENAI_API_KEY=https://api.deepseek.com
OPENAI_MODEL=deepseek-v4-flash
NAS_LAN_IP=192.168.1.50 # 换成你 NAS 的局域网 IP
端口说明:API(3111)、stream(3112)被 entrypoint 绑到
0.0.0.0,通过 Tailscale 节点在 tailnet 上可达,
不发布到局域网;viewer(3113)默认绑 loopback,这里用AGENTMEMORY_VIEWER_HOST=0.0.0.0改绑 + 在ts-agentmemory上ports: 3113:3113发布到局域网。
下面是容器网络与服务依赖关系图:
3. 启动 + 取密钥
docker compose up -d --build
# 首次启动入口会生成一次性密钥,只打印一次,记下来:
docker compose logs agentmemory | grep AGENTMEMORY_SECRET
# 形如 AGENTMEMORY_SECRET=<64位hex>(持久化在 /data/.hmac)
验证:
# API(任意 tailnet 设备)
curl http://agentmemory:3111/agentmemory/health
# viewer(任意局域网设备浏览器)
# http://192.168.1.50:3113
下面是首次启动的完整流程:
4. 客户端 Tailscale + Claude Code 接入
每台开发机(Mac / Windows / Linux):
# 1) 装并登录 Tailscale,加入同一 tailnet
# https://tailscale.com/download → tailscale up
# 2) 装 Claude Code 插件(注册 hooks + skills + 自动接 MCP)
# 在 Claude Code 里:
# /plugin marketplace add rohitg00/agentmemory
# /plugin install agentmemory
# 3) 设两个环境变量(写进 ~/.zshrc / ~/.bashrc;Windows 用系统环境变量)
export AGENTMEMORY_URL="http://agentmemory:3111" # MagicDNS;或 http://100.x.x.x:3111
export AGENTMEMORY_SECRET="<第3节日志里的密钥>"
# 4) 重启 Claude Code,验证连通 + 鉴权
curl -H "Authorization: Bearer $AGENTMEMORY_SECRET" http://agentmemory:3111/agentmemory/health
hooks 和 MCP shim 都读这两个变量:AGENTMEMORY_URL 决定连哪、AGENTMEMORY_SECRET 以 Bearer 发送。
两台机器配好即共享同一份记忆。日常正常写代码,hooks 自动捕获;需要时用 /recall、/remember、/handoff 等 skill。
5. 压缩 LLM(DeepSeek)说明与验证
agentmemory 的 provider 检测:只要 OPENAI_API_KEY 有真实值,就走 provider: "openai",model 取 OPENAI_MODEL、baseURL 取 OPENAI_BASE_URL。这条通道官方注释支持
“OpenAI, DeepSeek, SiliconFlow, Azure, vLLM, LM Studio”。所以接 DeepSeek 就是把这三个变量指过去(已在第 2 节配好)。
deepseek-v4-flash是 cost-optimized 档,适合做后台高频压缩(源码里专门有针对贵模型的成本告警)。- base URL 用
https://api.deepseek.com(OpenAI SDK 习惯的https://api.deepseek.com/v1也行)。
验证:
# 变量是否真进了容器
docker compose exec agentmemory printenv | grep -E 'OPENAI_|VIEWER_|TS_'
# provider 是 openai 还是 noop
docker compose exec agentmemory agentmemory doctor
若日志里仍出现 “No LLM provider key found … using no-op provider”,说明 key 没被读到——
检查 .env 的 DEEPSEEK_API_KEY 和 compose 的 environment 引用。
6. 升级
三块各自独立,最常做的是 agentmemory 本身。
6.1 升级 agentmemory(改版本号 + 重建)
cd /volume1/docker
# 1) 先备份(数据唯一不可替代)
curl -s -H "Authorization: Bearer $AGENTMEMORY_SECRET" \
http://agentmemory:3111/agentmemory/export > backup-$(date +%F).json
# 并对 agentmemory-data 卷做 NAS 快照
# 2) 查新版 + 看 release 是否要求改引擎
npm view @agentmemory/agentmemory version
# 3) 改 docker-compose.yml 的 args.AGENTMEMORY_VERSION
# 4) 重建
docker compose build agentmemory && docker compose up -d
docker compose logs --tail=50 agentmemory # 确认无 EPIPE/报错
6.2 铁律:III_VERSION 别乱升
保持 0.11.2。升到 0.11.6+ 会出现 EPIPE 重连循环、保存后搜不到。
只有当 agentmemory 某新版 release notes 明确支持新引擎时,才按它给的版本同步改。
6.3 回滚
把 AGENTMEMORY_VERSION 改回旧值重建即可,数据卷不动。若新版动过状态库结构,
回滚旧二进制可能读不了已迁移数据——这时用第 6.1 步那份 JSON 导出 import 重建。
6.4 Tailscale 边车 / 客户端
docker compose pull ts-agentmemory && docker compose up -d # 边车
客户端插件在 Claude Code 里重装/更新;尽量让服务端与客户端小版本相近。
你的
AGENTMEMORY_SECRET存在/data/.hmac,升级/重建不变,客户端无需重配。
7. 把本地已有记忆迁到 NAS
import 接口要求 { "exportData": <export内容>, "strategy": "merge"|"replace"|"skip" }。
# (本地)先起本地 server:agentmemory 或 npx @agentmemory/agentmemory
curl -s http://127.0.0.1:3111/agentmemory/export > export.json
# 语料大、超时就分页:?maxSessions=10&offset=0 逐批拉
# 包一层
jq '{exportData: ., strategy: "merge"}' export.json > import.json
# 推到 NAS
curl -X POST http://agentmemory:3111/agentmemory/import \
-H "Authorization: Bearer $AGENTMEMORY_SECRET" \
-H "Content-Type: application/json" --data @import.json
merge 合并 / replace 覆盖 / skip 只补新。首次迁移用 merge。
(裸拷贝 ~/.agentmemory 的 SQLite 为备选,要求两端版本一致且停服时操作,优先用 export/import。)
8. 备份 / 维护 / 排错
- 备份:记忆在
agentmemory-data卷(/data/state_store.db),纳入 NAS 快照;或定期export出 JSON。 - 密钥轮换:删
/data/.hmac后重启会重新生成并打印。 - 只看到 7 个 MCP 工具:shim 没连上 server——查
AGENTMEMORY_URL可达、health 通。 - 存了搜不到 / EPIPE:多半 iii 引擎版本不符,保持
III_VERSION=0.11.2。 - viewer 打不开:确认
AGENTMEMORY_VIEWER_HOST=0.0.0.0且VIEWER_ALLOWED_HOSTS里的host:port
与你浏览器地址栏完全一致(含端口);改了要docker compose up -d重建容器生效。 - provider 显示 noop:DeepSeek key 没传进容器,见第 5 节。
附录 A:Option — 不用 sidecar,改 NAS 原生 Tailscale
若 NAS 容器拿不到 /dev/net/tun:套件中心装 Tailscale(NAS 得到 100.x.x.x),compose 去掉 sidecar,
agentmemory 直接发布端口:ports: ["100.x.x.x:3111:3111", "192.168.1.50:3113:3113"](API 走 tailnet IP、
viewer 走局域网 IP)。客户端 AGENTMEMORY_URL=http://100.x.x.x:3111。
附录 B:viewer 的三档访问方式(按安全性从高到低)
共同前提:viewer 是免密特权界面(代理时自动带
AGENTMEMORY_SECRET)。能打开它 = 全权读写记忆,无需令牌。
按你的暴露面选最小的一档。三档可按需共存(白名单逗号分隔),但暴露越广风险越大。
B1 — SSH 隧道(最安全,viewer 不出现在任何网络)
把第 2 节 ts-agentmemory 的 ports: ["3113:3113"] 改成 ["127.0.0.1:3113:3113"](只绑 NAS 本机回环),
并设:
agentmemory:
environment:
- AGENTMEMORY_VIEWER_HOST=0.0.0.0 # 端口转发到容器内 loopback 收不到,必须 0.0.0.0
- VIEWER_ALLOWED_HOSTS=localhost:3113,127.0.0.1:3113
- VIEWER_ALLOWED_ORIGINS=http://localhost:3113,http://127.0.0.1:3113
然后 ssh -L 3113:127.0.0.1:3113 <用户>@<NAS>,浏览器开 http://localhost:3113。
只有能 SSH 进 NAS 的人能用。
B2 — 局域网(主文档默认,家庭内网用)
见第 2 节:ports: ["3113:3113"] + VIEWER_ALLOWED_HOSTS=${NAS_LAN_IP}:3113。
同一局域网设备开 http://<NAS局域网IP>:3113。
B3 — 全域 / tailnet(你的任意 Tailscale 设备、任意地点可访问)
“全域”= 你 tailnet 内任意设备、任意网络位置可达;不是公网。
viewer 已绑 0.0.0.0、与 Tailscale 边车共享网络栈,所以它已在 tailscale 接口监听——
只需把 tailnet 主机加进白名单,无需再发布任何端口:
agentmemory:
environment:
- AGENTMEMORY_VIEWER_HOST=0.0.0.0
# 可与局域网并存,逗号分隔;host:port 必须与地址栏完全一致
- VIEWER_ALLOWED_HOSTS=${NAS_LAN_IP}:3113,agentmemory:3113,${NAS_TS_IP}:3113
- VIEWER_ALLOWED_ORIGINS=http://${NAS_LAN_IP}:3113,http://agentmemory:3113,http://${NAS_TS_IP}:3113
.env 补一行 NAS_TS_IP=100.x.x.x(NAS 的 Tailscale IP)。docker compose up -d 生效。
任意 tailnet 设备开 http://agentmemory:3113(MagicDNS)或 http://100.x.x.x:3113。
单人 tailnet 到此即可。若你的 tailnet 有别人,务必在 Tailscale 后台 Access controls 用 ACL
把 viewer 端口锁到只有你自己:给 NAS 节点打 tag(如 tag:agentmemory),并仅放行你这个用户访问该端口——
{
"tagOwners": { "tag:agentmemory": ["autogroup:owner"] },
"acls": [
// 你自己的设备:全放行
{ "action": "accept", "src": ["autogroup:owner"], "dst": ["*:*"] }
// 不要给其他用户/tag 添加指向 tag:agentmemory:3113 的规则,默认即拒绝
]
}
(打 tag 需让 TS_AUTHKEY 带 --advertise-tags=tag:agentmemory,或在后台给该节点手动加 tag。)
不推荐 — 公网直曝
viewer 无登录,真要从公网开必须在前面套一层带认证的反向代理(basic auth / OAuth)。
鉴于其特权性质,强烈建议改用 B3 的 tailnet 全域访问,而不是把它挂到公网。
附录 C:Headscale(连协调层都自托管)
NAS 的 ts-agentmemory 与各客户端 tailscale up 都加 --login-server=https://你的headscale;
auth key 由 headscale preauthkeys create 签发。数据平面行为不变。
更多推荐

所有评论(0)