ai-memory 家庭服务器(Homelab)部署指南:从 Docker 模板到生产级 MCP 服务的完整落地
【免费下载链接】ai-memorySolution for long term memory for agent coding CLIs and to facilitate handoff between different agent vendors项目地址: https://gitcode.com/GitHub_Trending/ai/ai-memory
本文基于 ai-memory 仓库官方部署文档与真实部署脚本,系统讲解如何在一台家庭服务器(homelab)上用 Docker 部署一个长期运行的 ai-memory MCP 服务:覆盖首次配置、密钥注入、bearer-token 鉴权、TLS 加密传输、例行更新、备份、容量规划、磁盘回收与回滚排障。读完你可以完整复现bin/deploy文档化的部署模式,把"单机单用户"的记忆服务升级为"LAN 内多 Agent、多人共享"的稳定服务。
部署形态总览:两种目标架构
ai-memory 提供两条部署路径,选择取决于你的主机形态:
- Docker 部署(本文主线):按照 bin/deploy 脚本封装的模式,在 homelab 主机上跑一个长期运行的容器,LAN 内通过
http://<host>:49374/mcp访问,配置好 LLM/Embedding API 密钥后即可供各 Agent CLI 使用。备份沿用你现有对/var/opt/docker/...目录的备份方案。 - 原生 Linux systemd 服务:若你不想用 Docker,可走 docs/install.md 中的 Arch/AUR 安装路径。该模式系统服务使用
/var/lib/ai-memory与/etc/ai-memory/,用户服务则使用 XDG 用户路径;而 Docker 部署的数据目录始终是容器内/data、宿主机/var/opt/docker/...。
两条路径的行为差异在优雅停机一节还会体现:容器内服务是 PID 1,systemd 下不是,二者的信号处理历史教训完全不同。
多架构支持:发布的 Docker 镜像同时包含linux/amd64与linux/arm64两种 manifest,因此 x86_64 与 ARM64 的 homelab 主机都能以原生架构拉取同一 tag(树莓派等 ARM 主机无需模拟运行)。
仓库只提交模板,真实配置全部 gitignore
仓库奉行一条明确原则:只提交.example模板,绝不提交真实配置。你的 homelab 专属值与 API 密钥存放在去掉.example后缀的同名文件里,这些文件全部被.gitignore排除。
| 提交的模板 | 实际使用的(gitignored) | 存放内容 |
|---|---|---|
bin/deploy | (脚本本身,可安全提交) | 构建/推送/重启逻辑 |
bin/deploy.env.example | bin/deploy.env | SERVER、DEPLOY_DIR、IMAGE |
docker/docker-compose.prod.yml.example | docker/docker-compose.prod.yml | 镜像 tag、端口映射、卷路径 |
docker/.env.production.example | docker/.env.production | LLM + Embedding API 密钥 |
如果哪天在 git status 里看到这些真实文件被暂存,说明发生了漂移(有人误提交),提交前务必取消暂存。
模板内容逐项解读
bin/deploy.env.example(见 bin/deploy.env.example)定义三个必填变量:
SERVER="me@homelab.example.com":SSH 目标(user@host,或已在~/.ssh/config配好则直接写 host);DEPLOY_DIR="/var/opt/docker/utils/ai-memory":homelab 上docker-compose.yml与.env.production所在的绝对路径,脚本在其中执行docker compose pull/down/up;IMAGE="akitaonrails/ai-memory:homelab":要构建+推送+拉取的镜像 tag。必须使用你自己的私有 tag(详见下文"多架构防误覆盖");另有可选的CONTAINER_NAME用于覆盖默认容器名ai-memory。
docker/docker-compose.prod.yml.example(见 docker/docker-compose.prod.yml.example)与本地开发用的docker/docker-compose.yml有四点关键差异:
- 引用 registry 镜像而不是内联构建;
- 绑定
0.0.0.0:49374,让 LAN 可以访问 MCP 端点; - 密钥通过
env_file: .env.production注入而不是内联; - 卷挂载宿主路径(
/var/opt/docker/utils/ai-memory/data:/data),使 rsync 等工具可直接备份 wiki 与 db,无需绕道 Docker volume API。
模板还预置了两个值得注意的细节:
security_opt: - label:disable # openSUSE MicroOS / Fedora / RHEL 等默认对 bind mount 强制 SELinux; # 不加此行容器读不了自己的 /data。对不启用 SELinux 的主机是 no-op healthcheck: test: ["CMD", "/usr/local/bin/ai-memory", "status"] # 容器内嵌健康检查 interval: 30s timeout: 5s retries: 3 start_period: 5sRUST_LOG=ai_memory=info,ai_memory_store=info,ai_memory_wiki=info,ai_memory_mcp=info,tracing_appender=warn是预置的日志过滤规则,需要排查某模块时可以不改镜像、直接在此提升日志级别。健康检查复用二进制自身的ai-memory status子命令(见 docker/Dockerfile 中同款HEALTHCHECK),这也是后面排障一节"unhealthy"状态的直接来源。
docker/.env.production.example(见 docker/.env.production.example)是密钥与行为开关的集中地。它的注释透露一个重要的降级逻辑:不设置任何 LLM/Embedding 密钥,ai-memory 依然可以运行——退回纯 FTS5 模式 + 基于规则的会话摘要。所有变量都是可选的。
首次配置(一次性操作)
官方文档给出了标准四步:
# 1. 将 homelab 专属值写入本地配置 cp bin/deploy.env.example bin/deploy.env $EDITOR bin/deploy.env # 填写 SERVER / DEPLOY_DIR / IMAGE cp docker/docker-compose.prod.yml.example docker/docker-compose.prod.yml $EDITOR docker/docker-compose.prod.yml # 设置镜像 tag,必要时调整端口 cp docker/.env.production.example docker/.env.production $EDITOR docker/.env.production # 填入凭据;选择 LLM provider(模型覆盖可选) # 2. 在 homelab 上创建部署目录。source bin/deploy.env 让 SERVER/DEPLOY_DIR # 在当前 shell 中导出 source bin/deploy.env ssh "$SERVER" "sudo mkdir -p $DEPLOY_DIR/data && \ sudo chown -R 1000:1000 $DEPLOY_DIR" # 3. 把 compose 与 env 拷贝到 homelab scp docker/docker-compose.prod.yml "$SERVER:$DEPLOY_DIR/docker-compose.yml" scp docker/.env.production "$SERVER:$DEPLOY_DIR/.env.production" # 4. 执行首次部署 bin/deploy关于第 2 步的chown 1000:1000:容器以 uid 1000 的非 root 用户运行(docker/Dockerfile 中useradd --system --uid 1000 ... --home-dir /data创建),数据目录属主必须是 1000,否则容器内写/data会失败,表现为健康检查unhealthy。
第 4 步bin/deploy的真实执行序列(见 bin/deploy)是:
- 读取并校验
bin/deploy.env,三个必填变量缺失任一即退出(exit 64,并提示如何初始化); docker build -t "$IMAGE" -f docker/Dockerfile .——本地构建镜像;docker push "$IMAGE"——推送到 registry;- SSH 到 homelab 执行
docker compose pull && docker compose down && docker compose up -d——拉取新 tag、停旧容器、起新容器(服务器上不做docker compose build,二进制已经烤进镜像); sleep 3后docker inspect --format='{{.State.Status}} ({{.State.Health.Status}})' ai-memory打印容器状态与健康状态;- 提示验证命令:
curl ${SERVER#*@}:49374/mcp。
多架构防误覆盖(bin/deploy 的 fail-closed 保护)
bin/deploy 内有一段关键保护逻辑:如果$IMAGE当前解析为多架构 manifest(docker manifest inspect结果含"manifests"),脚本会拒绝执行并提示改用私有 tag。
原因写得很清楚:docker build只产出本机架构的镜像。把它 push 到一个原本是多架构的 tag 上,会把 manifest 列表替换成单架构,另一架构的主机下次 pull 就会exec format error。这不是假设——2026-08-18 它真实发生在:latest上(issue #427):CI 发布的 release tag 是 amd64+arm64 联合 manifest,一台 x86 工作站的 homelab 部署曾静默把它压扁成 amd64-only。因此:
- release tag(
:latest、:X.Y.Z)只允许 CI 发布,部署不得覆盖; - 部署请用私有 tag,如
IMAGE="akitaonrails/ai-memory:homelab"; - 若只想跑已发布镜像而不重建,直接在服务器上
ssh "$SERVER" "cd $DEPLOY_DIR && docker compose pull && docker compose up -d"即可,完全不需要bin/deploy。
部署后验证
curl http://<homelab>:49374/mcp # 期望看到 JSON-RPC 错误 —— 说明端口可达、服务在响应。 # "Connection refused" 说明容器没起来或端口映射错误。 ssh "$SERVER" "docker inspect --format='{{.State.Health.Status}}' ai-memory" # 期望输出: healthy/mcp是 MCP 协议端点,不带凭据直接 curl 它必然返回协议层错误,这恰恰证明 HTTP 层已经通了。
安全第一道闸:bearer-token 鉴权 + 加密传输
模板默认把端口绑定在0.0.0.0:49374让 LAN 可达,但这带来一个必须正视的威胁模型:无鉴权的 LAN 绑定服务,让网络上任何人都能调用破坏性 MCP 工具——删除所有页面、注入伪造 observation、耗尽你的 LLM 预算。因此官方文档明确要求:首次部署前就打开鉴权。
生成并启用 token
# 1. 生成 token(32 字节 = 64 个十六进制字符) ai-memory generate-auth-token >> docker/.env.production $EDITOR docker/.env.production # 把新行前缀改成 AI_MEMORY_AUTH_TOKEN= # 2. 同步到 homelab 并重启 scp docker/.env.production "$SERVER:$DEPLOY_DIR/.env.production" ssh "$SERVER" "cd $DEPLOY_DIR && docker compose up -d"ai-memory generate-auth-token的实现位于 crates/ai-memory-cli/src/commands/generate_auth_token.rs,底层调用ai_memory_mcp::auth::generate_token_hex(32):用操作系统 RNG 填充 32 字节熵池再十六进制编码,得到 64 字符 token(crates/ai-memory-mcp/src/auth.rs)。默认 32 字节(256 bit)熵足以覆盖任何合理威胁模型。
启动日志随后会出现auth=true。从笔记本上验证:
curl -sI http://homelab:49374/handoff # → HTTP/1.1 401 Unauthorized curl -sI http://homelab:49374/handoff \ -H "Authorization: Bearer $TOKEN" # → HTTP/1.1 200 OK然后为每个 MCP 客户端配置同一个 token:ai-memory install-mcp --client <name> --auth-token <token>会为 README 支持矩阵 中的每种客户端打印精确的配置片段,ai-memory install-mcp --help可查看当前接受的取值。Agent CLI 会在每次调用时携带Authorization: Bearer <token>头。
常量时间比较:防 LAN 时序侧信道
ai-memory 的鉴权中间件位于 crates/ai-memory-mcp/src/auth.rs。其中最关键的实现细节是 token 比较使用了subtle::ConstantTimeEq(auth.rs):
if let Some(expected) = state.expected.as_deref() && bool::from(provided.as_bytes().ct_eq(expected.as_bytes())) { req.extensions_mut().insert(state.root_actor.clone()); req.extensions_mut().insert(AuthLevel::Root); return Ok(BearerAuth::Authenticated); }文件头注释点明了原因:同一 LAN 上的攻击者无法通过响应时间差异逐字节还原 token。中间件还做了 fail-closed 设计:
- 未配置任何 token 时中间件是 no-op(保留零配置 loopback 的可用性,auth.rs);
- 未配置 token 却收到一个意外 bearer 头时按匿名请求放行而非拒绝(兼容曾加固过的旧部署);
- Basic 认证、Cookie 永远不是机器凭据(有专项测试覆盖);
- 401 响应只声明
WWW-Authenticate: Bearer,绝不广告 Basic(auth.rs)。
加密传输:什么时候必须上 TLS
明文 HTTP 意味着任何能抓包的人都能读到传输中的 bearer token(多用户模式开启后还包括原生aim_密钥)。当绑定范围超出 loopback、或开启多用户时,必须在 ai-memory 前面加 TLS 终止反向代理。完整部署指南见 docs/https-via-proxy.md,包括:
- 何时需要 TLS、何时可以跳过:loopback + stdio 的场景诚实地说并不需要;
- 可直接复制的 docker compose 模板:docker/compose.tls.caddy.yml(Caddy + Let's Encrypt 或 Caddy 内部 CA)与 docker/compose.tls.cloudflared.yml(Cloudflare Tunnel);
- 各操作系统信任库安装(内部 CA 路径中承重的关键手工步骤);
- 子路径托管(https-via-proxy.md 中的 Hosting under a subpath):通过
--base-path/AI_MEMORY_BASE_PATH让 ai-memory 与其他应用共享同一主机名; - 官方文档专门保留了"哪里会出错"章节,避免你意外部署出"安全剧场"。
对单用户 loopback 快速上手场景,仅 bearer token 依然可接受——token 挡住 LAN 邻居,loopback 挡住抓包;一旦部署形态不再是"单用户、单机器",TLS 就物有所值了。
例行部署:一次bin/deploy完成构建-推送-拉取-重启
首次配置完成后,后续每次部署都简化为:
bin/deploy脚本在本地构建镜像 → 推送到你的 registry → homelab 拉取 → 重启。homelab 上的 compose 文件与 env 文件在部署间保持不变;如果需要改它们,重新 scp 新副本后再跑bin/deploy。
优雅停机:5 秒有界 drain 与 PID 1 的历史教训
重启步骤用 SIGTERM 停止运行中的容器。服务在两个传输(stdio 与 HTTP)上都安装 SIGINT/SIGTERM 处理器,且关闭路径上的每次等待都限制在 5 秒,因此一次重启(或普通的docker stop、docker compose down)只需几秒即可 drain 并退出,而不是耗尽 supervisor 的宽限期后以 SIGKILL 收场。
这个 5 秒常量在源码中有明确出处:crates/ai-memory-cli/src/commands/serve.rs:
/// How long a wait on the shutdown path may run before the drain it is /// waiting for is abandoned. axum's graceful shutdown waits for every /// in-flight connection and a stateful or SSE MCP client can hold one open /// indefinitely, so an unbounded drain is indistinguishable from ignoring the /// signal: `docker stop` and `systemctl stop` would still burn their own /// grace period and finish with SIGKILL (#699). Each wait is bounded on its /// own, so a stop can take a small multiple of this. const SHUTDOWN_GRACE: Duration = Duration::from_secs(5);这段注释背后的历史很值得了解。在信号处理器存在之前,两种部署形态以不同方式失败:
- 容器内:服务是 PID 1。Linux 内核会丢弃"没有安装处理器"的信号,因此
docker stop白白烧掉整个宽限期,只能docker kill强杀; - 原生 systemd 单元下:服务不是 PID 1,
systemctl stop直接落入内核默认处置,瞬间被杀——快是快,但没有 drain,进行中的持久化 SessionEnd 合并 worker 会被拦腰斩断。现在那次停机"更慢但干净"。
5 秒上界是固定值、不可配置;docker kill仍是"不等 drain 直接停"的途径。不需要任何 init shim:二进制自己安装信号处理器,作为 PID 1 也能正确停机,你无需tini或docker run --init(相关测试见 tests/suite/shutdown_signals.rs 与 tests/suite/serve_shutdown.rs)。
更新 API 密钥
$EDITOR docker/.env.production scp docker/.env.production "$SERVER:$DEPLOY_DIR/.env.production" ssh "$SERVER" "cd $DEPLOY_DIR && docker compose up -d"docker compose up -d会读取 env 文件并用新值重建容器,无需重新构建镜像。
LLM Provider 选型
.env.production.example 默认配置是Kimi 2.6 走 OpenRouter(openai-compat 传输,$0.73/$3.49 每百万 token)。官方文档给出的合理备选:
| Provider | 模型 | 单次合并(consolidation)约计成本 | 备注 |
|---|---|---|---|
| anthropic | claude-haiku-4-5 | ~$0.02 | 推荐默认。速度、克制与分类质量的最佳平衡。非推理模型 |
| openai-compat (OpenRouter) | moonshotai/kimi-k2.6 | ~$0.013 | 推理模型;单次合并延迟约 2–3 分钟。可接受,因为合并是 fire-and-forget |
| openai | gpt-5.4-mini | ~$0.002 | 更便宜、更快,质量尚可 |
| openai-oauth | gpt-5.5 | ChatGPT 订阅 | ChatGPT/Codex 后端。需在服务器主机执行docker exec -it ai-memory ai-memory auth login openai-oauth,让<data_dir>/auth.json落在挂载的数据卷内 |
| copilot | gpt-5.5 | GitHub Copilot 订阅 | GitHub Copilot Chat 后端。同样在服务器主机执行docker exec -it ai-memory ai-memory auth login copilot,或设置COPILOT_GITHUB_TOKEN |
| gemini | gemini-3.5-flash | 免费额度覆盖个人使用 | Google 托管,原生responseSchema结构化输出。设置GEMINI_API_KEY(或GOOGLE_API_KEY) |
| openai-compat (Ollama) | qwen3:32b | $0 | 自托管。设置AI_MEMORY_LLM_BASE_URL=http://host.docker.internal:11434/v1。质量取决于模型 |
官方不推荐:推理模式模型(Kimi-K2.6 推理模式、开启 extended thinking 的 Claude、GPT-o3、Gemini "thinking" 变体)——它们会在输出前烧 token 做内部推理,并且面对严格 JSON 的合并提示词容易挂起或返回空响应。若必须用,请关闭推理。
provider 细节与兼容性开关
- ai-memory 托管的 OpenAI 系 provider 对结构化输出使用
json_schema严格模式;OpenAI provider 会把 schemars 输出归一化为 OpenAI 支持的子集(additionalProperties: false、完整required、生成的 enumanyOf、纯$ref节点)。openai-compat的本地与网关端点默认使用同样的 schema 约束请求,对明确的能力拒绝或畸形输出有宽容回退。对不兼容端点可设AI_MEMORY_LLM_COMPAT_STRICT=false。 - 换成小众本地模型前,先跑一次
ai-memory llm-test验证。 - 每个 chat provider 将单个 HTTP 请求上限设为300 秒。慢速托管网关(免费聚合层实测会出现)流式输出长完成可能超过这个上限,导致每个请求都报
http: error sending request;此时在容器环境中调高AI_MEMORY_LLM_TIMEOUT_SECS以匹配网关最坏情况的生成时间。
额外请求头
.env.production.example还支持AI_MEMORY_LLM_HEADERS:逗号分隔的Name=Value(或Name: Value)条目,为需要请求关联的网关附加自定义头。注意:header 值内不能包含逗号(否则用 config.toml 的llm_headers = [...]);ai-memory 自己会设置的头(authorization、content-type、x-api-key 等)在启动时被拒绝设置;值永不记日志。opencodeprovider 无需此项——它已为每个逻辑操作发送稳定的x-opencode-session,覆盖它仅用于区分多个实例。
备份策略
2.0 升级提示:2.0 镜像首次启动会执行 OKF 格式迁移,在触碰任何数据前先把整个数据目录归档到卷上的
/data/backups/(容器会被自动检测到;AI_MEMORY_BACKUP_DIR可覆盖)。wiki 主页会一直显示归档位置直到你删除它。详见 docs/MIGRATION-2.0.md。
数据目录就是你在docker-compose.prod.yml里挂载的目录(默认/var/opt/docker/utils/ai-memory/data/),结构如下:
data/ ├── wiki/ # markdown —— 用 rsync 或 git push 到远端备份 ├── raw/ # 不可变的会话日志归档 ├── db/ # memory.sqlite (FTS5 + entities + page_embeddings) ├── logs/ # 每日滚动追踪日志 └── models/ # 预留给未来的本地 embedder点时间一致性快照:
ssh "$SERVER" "docker exec ai-memory /usr/local/bin/ai-memory backup --to /data/snapshot-$(date +%F).tar.gz" scp "$SERVER:$DEPLOY_DIR/data/snapshot-$(date +%F).tar.gz" ./backups/ai-memory backup命令的实现位于 crates/ai-memory-cli/src/commands/backup.rs:它向服务器的/admin/backup端点发起 POST,把返回的 gzip 压缩包流式写入目标路径。文档明确说明服务器端使用SQLite 的 online backup API,因此快照期间正在进行的写入也能保持一致——数据库不会被争用。
多人 / 多 harness 共享一台服务器
部署形态的最终形态通常是"共享":同事之间共享一个项目,或你自己的多个 harness 共用一个后端。发 URL 前有两件事必须知道。
一个数据目录只能跑一个 server。让两个ai-memory serve进程指向同一份data/(同步文件夹、NFS 挂载、共享卷上的两个容器),它们会各自运行自己的 writer 与 wiki git 句柄。SQLite 扛得住这种并发,wiki 与进程内状态扛不住。正确做法是只跑一个 server,让所有人连它——这也正是共享知识模型成立的前提。
检查隔离模式。无作用域(unscoped)MCP 调用通过一个指针解析"当前项目",自 v1.39 起该指针按调用方(PerActor)键控。启动日志会打印当前生效的模式:
active-project isolation mode mode=PerActor …PerActor是默认值,也是共享服务器上想要的那个。Single是进程级单槽位——单个 harness 没问题,但并发会话会共享它,且无作用域的写入也通过它解析。详见 docs/auto-scope.md 与 docs/users.md。
一台服务器能扛多少负载
所有写入都经过单一 writer actor——这对 SQLite 是正确设计,随之而来的问题自然是"它何时成为瓶颈"。以下数据是实测而非估算,复现命令:cargo test -p ai-memory-store --test writer_throughput -- --ignored --nocapture:
| 并发写入者 | 吞吐 | 平均延迟 |
|---|---|---|
| 1 | 42/s | 23.9 ms |
| 8 | 295/s | 3.4 ms |
| 32 | 698/s | 1.43 ms |
| 128 | 700/s | 1.43 ms |
分两部分解读:
天花板约 700 次写入/秒,在约 32 个并发写入者时触达并保持平直——128 个写入者得到相同吞吐与延迟。饱和之后服务器施加背压而非降级:队列上限 1024,配以 awaiting send,所以超过队列的突发会放慢生产者,但每条写入最终都会落盘。没有丢弃,也没有无界增长。
单写入者延迟由fsync主导,而非 CPU。每次提交一条 observation 约等于一次磁盘同步;并发让 SQLite 合并 WAL 提交,这正是吞吐提升 17 倍而单写延迟反而下降的原因。
容量规划参考:一个活跃工作的 Agent 每个工具调用约产生一条生命周期写入。即便按悲观的"每个 Agent 每秒一次工具调用"估算,~700/s 也对应数百个同时活跃的 Agent——远超一个团队,也超过大多数共享安装。writer 不会是第一个坏掉的东西。
两条使用前提:数据测自本地快速磁盘;因为成本在fsync,网络文件系统或慢卷会显著降低数字——这是数据目录必须放本地存储的又一理由。且测的是 store 而非 HTTP 前门——真能打满它的安装,瓶颈更可能出在 Agent 侧而不是 SQLite。
回收磁盘空间
SQLite不会把删除的空间还给文件系统。被删行留下的页挂在freelist上,数据库再次增长时会被复用。对稳态使用的 store,这是正确行为,无需关注。
ai-memory status会报告决策依据的数字:
storage: 2.4 GiB on disk, 610.0 MiB reclaimable (25.4%) `ai-memory compact --confirm` would return it (blocks writes while it runs)这行建议只在积压值得处理时才出现。出现时:
ssh "$SERVER" "docker exec ai-memory /usr/local/bin/ai-memory compact --confirm"压缩不删除任何数据——它重建 FTS 索引并执行VACUUM(compact.rs 会打印bytes_reclaimed,无空闲页可回收时也会如实说明)。
不要安排无条件的每日 VACUUM
最自然的想法是每天 cron 一次,官方文档明确反对:
VACUUM需要排他锁并重写整个数据库。期间所有写入阻塞——在大 store 上是分钟级。而这台服务器的本职是响应 hook 流量,阻塞写入 = 丢捕获;- 它需要大约数据库自身大小的空闲磁盘,等于给每日任务设置了永久的空闲空间下限;
- SQLite 复用空闲页,稳态使用的 store 通常几乎无可回收。夜间跑一次,大多数晚上付出全价却毫无收益。
真正会留下大 freelist 的是一次性删除——purge-project、大范围保留期清扫、跨数月 episodic 页面的forget-sweep。这些是事件而非节奏,且破坏性命令本身就提供内联--compact用于那一刻。
若仍要自动化,请条件化触发并放在非高峰时段:
#!/usr/bin/env bash # /usr/local/bin/ai-memory-compact-if-worthwhile set -euo pipefail RECLAIMABLE=$(ai-memory status --json | jq '.storage.reclaimable_bytes') THRESHOLD=$((1024 * 1024 * 1024)) # 1 GiB —— 按你的 store 调 if [ "$RECLAIMABLE" -ge "$THRESHOLD" ]; then ai-memory compact --confirm fi用 systemd timer(OnCalendar=Sun 04:00、Persistent=true)或主机 cron 驱动。每周一次通常什么都不做的检查,代价只是一次廉价的status调用;每晚一次通常什么都没用的VACUUM,代价是每晚一次写入停顿。
压缩不是什么
它不是擦除。wiki 的 git 历史把页面内容保留在对象与提交信息中,之前任何备份也仍保有全部内容。压缩只是从活跃的 SQLite 文件中归还字节——按它自身的价值值得做,但不保证内容不可恢复。完整边界见 docs/lifecycle-ops.md。
回滚
ssh "$SERVER" "cd $DEPLOY_DIR && \ docker tag $IMAGE $IMAGE-rollback && \ docker pull $IMAGE@sha256:<old-digest>" ssh "$SERVER" "cd $DEPLOY_DIR && docker compose up -d"最简单的回滚是按 digest 找回旧镜像。项目没有bin/rollback脚本,因为正确做法是每次部署前保留上一个镜像 tag(Docker Hub 免费按 digest 保留每次推送)。先docker tag当前镜像为-rollback再拉旧 digest,是为了给当前部署留一条退路,避免拉取失败后两头落空。
查看日志
ssh "$SERVER" "docker logs -f --tail 100 ai-memory"或在主机上翻阅每日滚动日志:
ssh "$SERVER" "ls -la $DEPLOY_DIR/data/logs/" ssh "$SERVER" "tail -100 $DEPLOY_DIR/data/logs/ai-memory.log.$(date +%F)"排障手册
curl http://<host>:49374/mcp报Connection refused:容器没起来,或端口映射绑到了127.0.0.1而非0.0.0.0。在 homelab 上查docker ps。状态
unhealthy:容器在运行但内嵌的ai-memory status健康检查失败。最常见原因是数据目录权限与容器用户(uid 1000)不匹配。在主机上修复:sudo chown -R 1000:1000 $DEPLOY_DIR/data。更换模型后 Embedding 不匹配:存储的
(provider, model, dim)三元组与配置不一致时启动日志会告警。混合检索会忽略过期行,直到它们被重新嵌入。正常启动服务器后执行ai-memory embed --force重建工作区所有项目,或加--project <name>限定范围。启用定时 embedding backfill 也能补缺失行。捕获看起来延迟,或 observation 缺失:
ai-memory status报告本地 hook-spool 健康度——客户端排队了多少事件、最老事件年龄、失败投递总次数:spool: pending: 2 oldest: 15m 0s retries: 4非空 spool 且最老条目持续老化 = hook 已到达本地队列但没到服务器;事件不会丢,服务器可达后会自动 drain。
pending: 0说明捕获跟上了。注意 spool 是客户端侧的,因此这段反映的是你执行命令的那台机器而非服务器——即使
AI_MEMORY_SERVER_URL指向 homelab,它也读取本地数据目录。服务器完全不可达时它也会打印(输出到 stderr,--json消费者仍能在 stdout 拿到单一对象)——这正是积压最值得看的时候。--json以spool对象携带同样数字(pending、oldest_age_ms、retries_total)。Provider 失败:
ai-memory status报告最近一次真实 provider 调用得到的被动式 LLM 与 embedding 健康度。新进程在服务器真正使用该角色前显示unknown;它不会主动探测 provider、也不会为健康报告花费 token。容器重启循环:查看
docker logs ai-memory——顶部的ai-memory starting行报告解析后的配置;缺少必要 env var(例如选了openai-compat但没设LLM_API_KEY也没有模型)会在这里以清晰错误失败退出。
小结
把 docs/deploy.md 的部署模式落地为生产服务,核心动作可以压缩成一句话:模板复制 → 填值 → 首次 scp +bin/deploy→ 打开 bearer 鉴权 → 按需上 TLS → 例行bin/deploy。真正决定部署质量的不是命令本身,而是几个容易被跳过的细节:数据目录必须chown 1000:1000、镜像 tag 必须用私有 tag 以免压扁多架构 manifest、LAN 绑定必须配AI_MEMORY_AUTH_TOKEN、备份要认准 SQLite online backup 的一致性保证、磁盘回收要条件化而非无条件每晚 VACUUM。理解了 5 秒有界 shutdown 与单 writer 背压设计之后,你对这台服务器的运维判断会从"照抄命令"升级为"理解机理"。
【免费下载链接】ai-memorySolution for long term memory for agent coding CLIs and to facilitate handoff between different agent vendors项目地址: https://gitcode.com/GitHub_Trending/ai/ai-memory
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考