Mem0 自托管服务器实战指南:FastAPI + pgvector + Dashboard 的本地部署、安全加固与 Postgres 镜像迁移
【免费下载链接】embedchainThe Memory Layer for AI Agents - Drop-in memory infrastructure for AI agents and apps. Context that persists. Built for production.项目地址: https://gitcode.com/GitHub_Trending/em/embedchain
Mem0(原 embedchain 项目演进而来)除了 Python SDK 之外,还内置了一个可自托管的 FastAPI REST 服务端与本地 Web 仪表盘。本文基于仓库中的 server/README.md,结合服务端源码、Docker 编排与运维脚本,完整讲解:如何用一条命令拉起整套记忆服务、如何理解其"安全默认"设计、如何管理请求日志与遥测,以及如何将 Postgres 镜像从已归档的ankane/pgvector平滑迁移到官方pgvector/pgvector:pg17。读完本文,你可以独立完成 Mem0 记忆服务的本地部署、日常运维与跨大版本升级。
一、服务端架构总览:三个容器组成的最小记忆栈
从 server/docker-compose.yaml 可以看到,自托管栈由三个服务构成,通过mem0_networkbridge 网络互通:
| 服务 | 镜像/构建 | 端口映射 | 职责 |
|---|---|---|---|
mem0 | 基于 server/dev.Dockerfile 构建 | 8888:8000 | FastAPI REST API,挂载源码并--reload热更新 |
postgres | pgvector/pgvector:pg17 | 8432:5432 | 向量存储(memories)+ 应用库(用户、API Key、请求日志) |
mem0-dashboard | 基于 server/dashboard/ 构建的 Next.js 应用 | 3000:3000 | Web 仪表盘,走/api/health健康检查 |
几个值得注意的编排细节:
- Postgres 凭据强制注入:
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}(server/docker-compose.yaml),:?语法意味着.env中未设置该变量时 compose 直接拒绝启动——这正是 README 中"POSTGRES_PASSWORD 现为必填项"的实现来源。 - 双数据库分工:server/init-db.sh 在 Postgres 首次初始化时额外创建
mem0_app库,存放用户、API Key、请求日志等应用数据;默认的postgres库则供 pgvector 存放记忆向量。 - 启动时序:
mem0服务depends_onPostgres 的service_healthy,其启动命令先执行alembic upgrade head再拉起uvicorn main:app,即 API 容器启动时会自动跑数据库迁移。
二、快速启动
2.1 前置准备:配置.env
复制示例环境文件并至少填写 Postgres 密码与一个 LLM 提供商的 Key:
cd server cp .env.example .env # Edit .env — at minimum set POSTGRES_PASSWORD and OPENAI_API_KEYserver/.env.example 中各变量的完整含义如下:
| 变量 | 默认值 | 说明 |
|---|---|---|
OPENAI_API_KEY | 空 | 默认 LLM/Embedder 提供商的 Key;也可改用ANTHROPIC_API_KEY/GOOGLE_API_KEY |
POSTGRES_HOST/POSTGRES_PORT/POSTGRES_DB/POSTGRES_USER | postgres/5432/postgres/postgres | 向量库连接参数 |
POSTGRES_PASSWORD | 必填 | 未设置时 docker compose 拒绝启动 |
POSTGRES_COLLECTION_NAME | memories | pgvector 集合(表)名 |
ADMIN_API_KEY | 空 | 遗留的直连管理密钥,建议长度 ≥ 16 位 |
JWT_SECRET | 空 | 认证启用时的 JWT 签名密钥,可用openssl rand -base64 48生成 |
AUTH_DISABLED | false | 仅本地开发可设为true,生产环境禁用 |
DASHBOARD_URL | http://localhost:3000 | CORS 白名单来源 |
APP_DB_NAME | mem0_app | 应用数据库名 |
MEM0_DEFAULT_LLM_MODEL | gpt-5-mini | 默认 LLM 模型,可覆盖以固定版本 |
MEM0_DEFAULT_EMBEDDER_MODEL | text-embedding-3-small | 默认 Embedder 模型 |
MEM0_TELEMETRY | true | 匿名遥测开关,设为false退出 |
REQUEST_LOG_RETENTION_DAYS | 30 | 请求日志保留天数 |
默认运行时配置由 server/main.py 中的DEFAULT_CONFIG组装:向量存储固定为pgvector,LLM 与 Embedder 默认走 OpenAI(gpt-5-mini+text-embedding-3-small)。此外 server/main.py 定义了镜像内置的提供商白名单BUNDLED_LLM_PROVIDERS = ("openai", "anthropic", "gemini")与BUNDLED_EMBEDDER_PROVIDERS = ("openai", "gemini")——通过POST /configure切换到未打包的提供商会直接返回 400,源码中的错误提示明确给出了扩展方式(安装对应 Python 包、重建容器并扩展白名单)。
2.2 Agent-first:一条命令完成全部初始化
cd server make bootstrapserver/Makefile 中bootstrap: up wait-api wait-dashboard seed,即依次完成四步:
up:先检查 3000/8888 端口未被占用(避免与已有服务冲突),再docker compose up -d --build;wait-api:轮询GET /auth/setup-status直到 API 就绪(每 2 秒一次);wait-dashboard:轮询GET /api/health直到仪表盘就绪;seed:执行 server/scripts/seed.sh 完成账号与 Key 初始化。
seed 脚本的完整调用链值得展开(见 server/scripts/seed.sh):
- 调
GET /auth/setup-status判断是否已有管理员; - 若无,调
POST /auth/register创建首个 admin(密码未指定时用secrets.token_urlsafe(16)随机生成); - 调
POST /auth/login换取 JWT access token; - 携带 Bearer token 调
POST /api-keys创建标签为dev-seed-key的 API Key; - 在
=== Ready ===块中一次性打印 Email、Password、API Key。
凭据只打印一次:关闭终端前务必保存密码与 API Key——API Key 在数据库里只保存 bcrypt 哈希(见 server/auth.py 的
generate_api_key),无法事后找回。
可覆盖生成的凭据:
cd server make bootstrap EMAIL=admin@company.com PASSWORD='strong-password' NAME='Admin'面向机器解析的场景(如 CI、Agent 自动化)可用 JSON 输出:
cd server OUTPUT=json make seed此时 server/scripts/seed.sh 只输出一行 JSON,包含dashboard_url、api_url、email、password、api_key五个字段,方便直接jq解析。
注意:make bootstrap跳过设置向导,因此"使用场景 → 自定义指令"步骤不会执行。若之后想补充自定义指令,直接POST /configure提交{"custom_instructions": "..."}即可(/configure端点定义见 server/main.py,读取配置时敏感字段会自动脱敏为[redacted])。
2.3 Browser-first:走浏览器设置向导
cd server make up然后打开http://localhost:3000,按向导完成管理员注册与使用场景配置。相比 Agent-first 流程,向导会多触发一个遥测事件(见第五节),并且向导最后一步可让 LLM 基于你填写的use_case自动生成custom_instructions与一条测试消息——对应 API 侧的POST /generate-instructions(server/main.py)。
2.4 拆除与清理
# Stop the stack cd server && make down # Wipe all data (including the Postgres volume) cd server && make cleanmake clean等价于docker compose down -v,会永久删除postgres_db卷,包含全部记忆与应用数据,执行前确认无需保留。
三、安全默认:认证、API Key 与响应头
README 的 "Security Defaults" 一节列出四条规则,均可在源码中得到印证:
- 仪表盘登录使用 JWT。server/auth.py 中:算法为 HS256,access token 有效期 30 分钟,refresh token 有效期 30 天。refresh token 采用 jti 表 + 条件 UPDATE 原子消费(server/auth.py),关闭了"读取-检查-写入"竞态,同一 token 并发重放最多只有一个成功。
- 程序化访问使用
X-API-Key头。Key 由secrets.token_urlsafe(32)生成并加m0sk_前缀;数据库api_keys表(server/models.py)只存前 12 位前缀与 bcrypt 哈希,泄露数据库也无法还原 Key 原文。 - 认证默认启用。若既无管理员也无
ADMIN_API_KEY,server/main.py 启动时会打印醒目警告块,列出三种修复途径(设置ADMIN_API_KEY、到http://<host>:3000/setup注册管理员、仅限本地开发时设AUTH_DISABLED=true)。 AUTH_DISABLED=true仅限本地开发。该值通过 compose 的${AUTH_DISABLED:-false}透传,生产环境应保持 false。
此外,所有受保护请求都会经过请求日志中间件,且响应附带X-Request-ID便于排障(server/main.py)。
仪表盘安全响应头
server/dashboard/next.config.mjs 对所有路径统一设置:
X-Frame-Options: DENYContent-Security-Policy: frame-ancestors 'none'X-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-origin
前两者双重阻止 iframe 嵌入(防点击劫持),nosniff防止浏览器嗅探错误标注的 MIME 类型,Referrer-Policy限制跨域 Referer 泄露。如需更强防护(如 HSTS、CSP nonce),README 建议在自己的反向代理层追加。
忘记密码的官方恢复路径
在栈运行期间从宿主机重置管理员密码:
cd server make reset-admin-password EMAIL=admin@example.com PASSWORD='new-strong-password'该 target 通过docker compose exec在mem0容器内执行 server/scripts/reset_admin_password.py(见 server/Makefile)。README 的解释是:任何能拿到宿主 shell 的人本就对数据库和密钥拥有完全访问权,因此这条命令并不扩大攻击面——它是支持的恢复路径,而非绕过机制。
四、仪表盘功能
登录后,仪表盘(Next.js 应用,源码位于 server/dashboard/src/)提供六类能力:
- Requests— API 调用的实时审计日志(method、path、status、latency),数据即
request_logs表(server/models.py); - Memories— 浏览记忆,按 user ID 过滤;
- Entities— 列出所有持有记忆的
user_id、agent_id、run_id及其数量;删除实体即级联删除其记忆; - API Keys— 创建、打标签、吊销每个用户的 Key;
- Configuration— 运行时覆盖 LLM 与 Embedder 配置;变更持久化到应用库(
settings表),重启后重新生效,并分层叠加在.env值之上(对应 API 的GET/POST /configure与GET /configure/providers); - Settings— 账号资料与密码管理。
API 侧能力与之对应:server/main.py 暴露了POST /memories、GET /memories(不带标识符时全量列出,需 admin 角色,上限 1000 条)、GET /memories/{id}、POST /search、PUT /memories/{id}、GET /memories/{id}/history、DELETE /memories/{id}、DELETE /memories、POST /reset等端点,OpenAPI 文档位于http://localhost:8888/docs。
五、请求日志保留策略
request_logs表只增不删,会随流量增长(README 给出的量级参考:10 req/s 下约 86.4 万行/天),需要周期性清理:
cd server make prune-logs # defaults to 30 days make prune-logs REQUEST_LOG_RETENTION_DAYS=7 # shorter window其背后的实现分两部分:
- 写入侧:server/main.py 的
log_requests中间件记录每个请求的 method、path、status、latency 与 auth_type,并在finally中通过run_in_executor异步落库;OPTIONS预检请求、/api/health、/docs、/redoc、/openapi.json以及/requests前缀路径被排除(server/main.py),避免审计接口本身制造噪声。 - 删除侧:server/scripts/prune_request_logs.py 读取
REQUEST_LOG_RETENTION_DAYS(默认 30,必须 ≥ 1 的整数),按 UTC 时间截断执行DELETE ... WHERE created_at < cutoff。README 建议生产环境将其接入 cron 或 systemd timer。
为什么大表上这个删除依然便宜?因为created_at列上建了BRIN 索引——迁移文件 server/alembic/versions/006_request_logs_brin.py 将其从 btree 换成了CREATE INDEX ... USING BRIN (created_at)。对按时间天然有序追加的日志表,BRIN 以极小的索引体积让范围删除快速定位块范围,这正是 README 中"range deletes stay cheap even on large tables"的依据。
六、遥测:默认开启、最多两个事件、可一键退出
遥测实现见 server/telemetry.py,与 Mem0 OSS 库一致默认开启,指向同一个匿名 PostHog 项目,每个安装最多发送两个事件:
| 事件 | 触发时机 | 属性 |
|---|---|---|
admin_registered | 首个管理员被创建(向导或 API 直连均可) | 邮箱域名、服务端版本、安装 UUID |
onboarding_completed | 设置向导到达最终成功态 | 同上,外加操作者填写的自由文本use_case |
几个可验证的实现细节:
- 纯 API 引导(
make bootstrap)永远不会发出onboarding_completed,因为向导成功态不存在; - 每个事件通过状态文件(默认
/app/history/telemetry.json)保证"至多一次"(_capture_once中的幂等键,见 server/telemetry.py); distinct_id是随机生成的安装 UUID,属性里只有邮箱域名(非完整邮箱),不含 PII;- 退出方式:在
.env中设MEM0_TELEMETRY=false(compose 中经${MEM0_TELEMETRY:-true}透传,server/telemetry.py 解析)。
七、从ankane/pgvector迁移到pgvector/pgvector
ankane/pgvector镜像已归档停止维护,当前版本换成官方pgvector/pgvector:pg17(PostgreSQL 17、pgvector 0.8.0)。变更对照:
| Before | After | |
|---|---|---|
| Docker 镜像 | ankane/pgvector:v0.5.1 | pgvector/pgvector:pg17 |
| PostgreSQL 版本 | 15 | 17 |
| pgvector 版本 | 0.5.1 | 0.8.0 |
| 凭据 | 硬编码postgres/postgres | 由POSTGRES_USER/POSTGRES_PASSWORD环境变量驱动 |
7.1 全新安装(无存量数据)
无需迁移:复制.env.example为.env,设置POSTGRES_PASSWORD,然后make up。
7.2 存量安装(保留数据)
PostgreSQL 17 无法直接读取 15 写下的数据文件,必须"先导出、再导入"。
第 1 步:在旧栈运行时导出数据
cd server # Dump all databases (mem0 memories + mem0_app auth/config data) docker compose exec -T postgres pg_dumpall -U postgres > mem0_backup.sql ls -lh mem0_backup.sql # 确认 dump 文件非空第 2 步:停旧栈并删除旧卷
docker compose down docker compose down -v # 删除 postgres_db 卷——务必先确认备份可用!第 3 步:更新.env
凭据不再硬编码于docker-compose.yaml,需显式写入:
POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=postgres POSTGRES_USER=postgres POSTGRES_PASSWORD=<your-password> # required — compose will refuse to start without it POSTGRES_COLLECTION_NAME=memories若此前依赖硬编码的postgres/postgres,设POSTGRES_PASSWORD=postgres保持凭据一致。
第 4 步:只启动 Postgres
docker compose up -d postgres docker compose exec -T postgres pg_isready -q && echo "ready" || echo "not ready"必须只先起 Postgres、不起 mem0 API:API 启动即执行alembic upgrade head,会创建空表而与恢复冲突。
第 5 步:恢复数据
docker compose exec -T postgres psql -U postgres < mem0_backup.sqlrole "postgres" already exists之类的提示无害。
关键点:恢复必须先于启动 mem0 API 容器。API 启动时的迁移会建空表——之后再恢复会因重复键失败,并丢失 API Key 与设置。
第 6 步:启动 API
docker compose up -d mem0Alembic 检测到既有表后只增量应用新迁移。
第 7 步:验证
make health curl -s "http://localhost:8888/memories?user_id=<your-user-id>" -H "X-API-Key: <your-api-key>"make health会分别检查 API/docs的 HTTP 状态、仪表盘/api/health与pg_isready(见 server/Makefile)。
7.3 回滚
如需回退,将 server/docker-compose.yaml 中的镜像改回ankane/pgvector:v0.5.1,执行docker compose down -v、docker compose up -d --build,再把mem0_backup.sql以同样方式灌入旧容器即可。
八、本地端口速查与继续深入
| 入口 | 地址 |
|---|---|
| 仪表盘 | http://localhost:3000 |
| API | http://localhost:8888 |
| OpenAPI 文档 | http://localhost:8888/docs |
常用命令回顾:make up(启动并等待就绪)、make down/make clean(停止 / 停止并删卷)、make logs(docker compose logs -f)、make health(三件套体检)、make bootstrap(Agent-first 一键初始化)、make reset-admin-password、make prune-logs。
如需进一步阅读实现:REST 端点与默认配置在 server/main.py,认证与 Key 生成在 server/auth.py,路由层在 server/routers/,数据库模型在 server/models.py,应用库迁移在 server/alembic/versions/,仪表盘前端在 server/dashboard/src/,服务端行为有对应测试覆盖(如 tests/test_server_auth.py、tests/test_api_keys_router.py、tests/test_server_params.py)。
【免费下载链接】embedchainThe Memory Layer for AI Agents - Drop-in memory infrastructure for AI agents and apps. Context that persists. Built for production.项目地址: https://gitcode.com/GitHub_Trending/em/embedchain
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考