news 2026/9/20 3:09:54

ai-memory 家庭服务器(Homelab)部署指南:从 Docker 模板到生产级 MCP 服务的完整落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ai-memory 家庭服务器(Homelab)部署指南:从 Docker 模板到生产级 MCP 服务的完整落地

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/amd64linux/arm64两种 manifest,因此 x86_64 与 ARM64 的 homelab 主机都能以原生架构拉取同一 tag(树莓派等 ARM 主机无需模拟运行)。

仓库只提交模板,真实配置全部 gitignore

仓库奉行一条明确原则:只提交.example模板,绝不提交真实配置。你的 homelab 专属值与 API 密钥存放在去掉.example后缀的同名文件里,这些文件全部被.gitignore排除。

提交的模板实际使用的(gitignored)存放内容
bin/deploy(脚本本身,可安全提交)构建/推送/重启逻辑
bin/deploy.env.examplebin/deploy.envSERVERDEPLOY_DIRIMAGE
docker/docker-compose.prod.yml.exampledocker/docker-compose.prod.yml镜像 tag、端口映射、卷路径
docker/.env.production.exampledocker/.env.productionLLM + 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: 5s

RUST_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)是:

  1. 读取并校验bin/deploy.env,三个必填变量缺失任一即退出(exit 64,并提示如何初始化);
  2. docker build -t "$IMAGE" -f docker/Dockerfile .——本地构建镜像;
  3. docker push "$IMAGE"——推送到 registry;
  4. SSH 到 homelab 执行docker compose pull && docker compose down && docker compose up -d——拉取新 tag、停旧容器、起新容器(服务器上不做docker compose build,二进制已经烤进镜像);
  5. sleep 3docker inspect --format='{{.State.Status}} ({{.State.Health.Status}})' ai-memory打印容器状态与健康状态;
  6. 提示验证命令:curl ${SERVER#*@}:49374/mcp

多架构防误覆盖(bin/deploy 的 fail-closed 保护)

bin/deploy 内有一段关键保护逻辑:如果$IMAGE当前解析为多架构 manifestdocker 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 客户端配置同一个 tokenai-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 stopdocker 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 也能正确停机,你无需tinidocker 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)约计成本备注
anthropicclaude-haiku-4-5~$0.02推荐默认。速度、克制与分类质量的最佳平衡。非推理模型
openai-compat (OpenRouter)moonshotai/kimi-k2.6~$0.013推理模型;单次合并延迟约 2–3 分钟。可接受,因为合并是 fire-and-forget
openaigpt-5.4-mini~$0.002更便宜、更快,质量尚可
openai-oauthgpt-5.5ChatGPT 订阅ChatGPT/Codex 后端。需在服务器主机执行docker exec -it ai-memory ai-memory auth login openai-oauth,让<data_dir>/auth.json落在挂载的数据卷内
copilotgpt-5.5GitHub Copilot 订阅GitHub Copilot Chat 后端。同样在服务器主机执行docker exec -it ai-memory ai-memory auth login copilot,或设置COPILOT_GITHUB_TOKEN
geminigemini-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

并发写入者吞吐平均延迟
142/s23.9 ms
8295/s3.4 ms
32698/s1.43 ms
128700/s1.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:00Persistent=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/mcpConnection 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 拿到单一对象)——这正是积压最值得看的时候。--jsonspool对象携带同样数字(pendingoldest_age_msretries_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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 7:10:53

JSP+SQL Server抽奖系统实战:事务控制与连接池优化

简介&#xff1a;本资源是一份完整的本科毕业设计论文&#xff0c;面向计算机专业学生及Web开发初学者&#xff0c;聚焦JSP技术在企业级抽奖场景中的工程化落地&#xff0c;解决客户关系管理与营销活动数字化中的抽奖功能模块设计难题。论文涵盖B/S架构设计、SQL Server数据库建…

作者头像 李华
网站建设 2026/9/20 17:39:41

Python列表批量删除与去重的高效实现方案

1. 从实际需求出发&#xff1a;Python列表批量删除与去重的场景分析在日常数据处理中&#xff0c;我们经常会遇到这样的需求&#xff1a;从一个包含重复元素的列表中&#xff0c;既要删除指定的多个值&#xff0c;又要确保结果列表中的元素唯一。这种"批量删除去重"的…

作者头像 李华
网站建设 2026/9/19 23:58:12

NKR智能气体涡轮流量计:从Modbus接入到温压补偿与K系数修正

简介&#xff1a;NKR系列智能气体涡轮流量计选型/使用说明书是一份面向燃气计量、工业气体流量监测工程师与运维人员的完整技术文档&#xff0c;主要解决NKR系列流量计选型、安装、参数设置与维护问题。文档按GB/T32201-2015标准编制&#xff0c;涵盖技术性能指标、工作原理与结…

作者头像 李华
网站建设 2026/9/20 9:35:10

3条命令跑通OpenResearch:orx up研究智能体仪表盘完整走查

3条命令跑通OpenResearch&#xff1a;orx up研究智能体仪表盘完整走查 【免费下载链接】OpenResearch Turn your coding agents into research agents 项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearch OpenResearch 是一个本地优先的研究智能体工作台&a…

作者头像 李华