内存服务(PostgreSQL + MCP + 自动嵌入 + 每日备份)

基于PostgreSQL的自托管内存服务,结合pgvector和pgai进行语义检索,通过MCP协议为代理和LLM工具提供共享内存层。

  • by Milad
  • Shell
  • 本地部署
  • 更新于
在 GitHub 查看 Milad/Open-Memory

使用说明

开放式内存(PostgreSQL+MCP+自动嵌入+每日备份)

基于PostgreSQL构建的自托管内存服务(pgvector + pgai)、MCP服务器和定时备份容器。

为什么

目标是运行一个MCP内存服务,所有代理和LLM驱动的工具都可以一起使用。 这种设置提供了一个跨客户端的共享内存/上下文层,而不是每个工具都保持隔离的内存“孤岛”。

它结合了:

  • PostgreSQL用于持久共享存储
  • pgvector + pgai 通过嵌入进行语义检索
  • MCP作为不同代理/服务的通用访问协议
  • 为确保操作安全而进行的定时备份

学分

灵感源自 人工智能新闻与战略日报|内特·B·琼斯 这个视频:

这是我对他开放大脑思想的解读。我没有看到他自己的实现。

服务

  • db:PostgreSQL 17(支持pgvector/pgai的时标HA映像)
  • pgai-installer:安装pgai DB对象并创建矢量器的一次性设置
  • vectorizer-worker:自动生成/更新嵌入的后台工作程序
  • mcp:Postgres MCP服务器在上暴露 http://localhost:8080 默认情况下;集 MCP_PORT 更改主机端口
  • pgbackups:每日转储备份写入 ./postgres/backups
  • postgres/mcp-data:持久MCP文件(tokens.json, users.json,对话)

先决条件

  • Docker引擎24+
  • Docker Compose v2+
  • git
  • 我只在Ubuntu上测试了这个,如果你使用其他系统,请随时测试。

检查:

docker --version
docker compose version

安装

  1. 克隆并进入仓库:
git clone https://github.com/Milad/open-memory.git open-memory
cd open-memory
  1. 创建env文件:
cp .env.example .env
  1. 编辑 .env 使用您的真实凭据和运行时设置。
chmod 600 .env

使用 .env 对于此部署模型中的配置和机密。在实时服务器上,保持 .env 未跟踪并设置为 0600.

如果希望MCP API在不同的主机端口上公开,请设置 MCP_PORT 在 .env。默认值为 8080.

MCP服务已从GitHub容器注册表中提取,目前固定在 docker-compose.yml 致:

  • ghcr.io/pgedge/postgres-mcp:1.0.0

在当前的Compose配置中,pgEdge内置的LLM功能被禁用(PGEDGE_LLM_ENABLED=false).此堆栈公开了MCP、嵌入和存储功能,但不公开pgEdge LLM/chat功能。

默认情况下,新安装会创建两个数据库角色:

  • memory_admin:PostgreSQL安装程序、pgai安装程序和矢量器工作程序使用的所有者/管理员角色
  • memory_mcp:仅由MCP服务器使用的最低权限角色,被授予访问权限 open_memory.memory_nodes 并明确撤销 ai

memory_mcp 在PostgreSQL的初始引导过程中创建 init-db/02-mcp-role.sh.

重要密码提示:

  • 集 MCP_DB_PASSWORD 明确地。
  • 如果你测试上游 ghcr.io/pgedge/postgres-mcp 没有此仓库包装器的图像,请避免在密码中使用shell元字符。
  • 字符如 !, $,回溯,引用, ;, &,以及 | 可能会破坏上游容器启动脚本。
  • 保守的安全模式 MCP_DB_PASSWORD 是字母、数字, _, -,以及 . 只有。

跑

在后台启动所有服务:

docker compose up -d

检查状态:

docker compose ps

尾梁:

docker compose logs -f db pgai-installer vectorizer-worker mcp pgbackups

自动嵌入(pgai矢量器)

此堆栈允许自动嵌入同步 open_memory.memory_nodes.content:

  • pgai-installer 运行一次,执行 pgai install,然后应用 pgai-init/vectorizer.sql
  • vectorizer-worker 连续处理队列作业
  • 新的/更新的行异步嵌入到 memory_nodes.embedding

这 ai pgai/矢量器内部的模式仍然安装,但MCP服务器与受限制的 memory_mcp 角色,并从中明确撤销 ai,因此模式发现仍然集中在 open_memory.memory_nodes.

检查矢量器状态:

docker compose logs -f vectorizer-worker

SQL检查就绪:

-- 1) pgai installed
SELECT extname FROM pg_extension WHERE extname IN ('ai', 'vector') ORDER BY extname;

-- 2) vectorizer registered
SELECT id, name FROM ai.vectorizer ORDER BY id;

-- 3) embeddings present
SELECT id, content, embedding IS NOT NULL AS has_embedding
FROM open_memory.memory_nodes
ORDER BY id DESC
LIMIT 20;

如果需要,可以从主机shell运行它们:

DBPASS="${DB_ADMIN_PASSWORD:-$(grep '^DB_ADMIN_PASSWORD=' .env | cut -d= -f2-)}"
DBUSER="${DB_ADMIN_USER:-$(grep '^DB_ADMIN_USER=' .env | cut -d= -f2-)}"
DBNAME="${DB_NAME:-$(grep '^DB_NAME=' .env | cut -d= -f2-)}"
docker compose exec -T -e PGPASSWORD="$DBPASS" db psql \
  -U "$DBUSER" -d "$DBNAME" \
  -c "SELECT extname FROM pg_extension WHERE extname IN ('ai', 'vector') ORDER BY extname;" \
  -c "SELECT id, name FROM ai.vectorizer ORDER BY id;" \
  -c "SELECT id, content, embedding IS NOT NULL AS has_embedding FROM open_memory.memory_nodes ORDER BY id DESC LIMIT 20;"

如果查询3返回零行,则没有什么可嵌入的。在中插入/更新行 memory_nodes 并在短暂延迟后再次检查。

使用MCP端点

MCP服务器在以下位置公开:

  • http://localhost:<MCP_PORT>/mcp/v1
  • 违约: http://localhost:8080/mcp/v1

此端点仅用作MCP工具服务器。分阶段的Compose配置禁用上游pgEdge LLM功能,因此不要期望此部署具有pgEdge托管的聊天或模型代理行为。

身份验证标头格式:

  • Authorization: Bearer <token-from-INIT_TOKENS-in-.env>

Codex MCP配置示例

在中添加/更新此块 ~/.codex/config.toml:

[mcp_servers.openmemory]
enabled = true
startup_timeout_sec = 30
command = "npx"
args = [
  "-y", "mcp-remote", "http://localhost:<MCP_PORT>/mcp/v1",
  "--allow-http", "--transport", "http-only",
  "--header", "Authorization:${OPENMEMORY_AUTH_HEADER}",
  "--silent"
]
env = {"OPENMEMORY_AUTH_HEADER" = "Bearer <your-token>"}

编辑配置后,重新启动Codex客户端/会话。

跨代理自动使用开放内存

连接MCP服务器只是设置的一半。如果希望代理定期从Open Memory中检索和写入,而不每次都重复相同的提示,请添加一个持久指令文件,该文件将告诉每个代理如何使用内存。

推荐共享说明文本:

Use the connected Open Memory MCP server as shared long-term memory when it is relevant.

Open Memory MCP server Policy:
- Before answering, retrieve relevant memory for the user, project, repo conventions, prior decisions, and ongoing work if that context would improve the answer.
- After completing meaningful work, store only durable, high-signal facts:
  - user preferences
  - project conventions
  - architectural or operational decisions
  - stable troubleshooting knowledge
  - unresolved follow-ups worth carrying forward
- Do not store secrets, tokens, passwords, API keys, auth headers, `.env` contents, or raw credentials.
- Do not store transient chatter, low-value logs, or duplicate memories.
- Prefer short, factual summaries over verbose notes.
- If memory is not relevant, do not force its use.

建议模式:

  1. 例如,将上述文本保存在计算机上的一个规范文件中 ~/.agents/AGENTS.md.
  2. 使用符号链接或副本从特定于工具的指令位置重用它。
  3. 必要时,在repo本地指令文件中保留特定于repo的重写。

Codex CLI和Codex for VS Code

全球指令:

  • ~/.codex/AGENTS.md

推荐设置:

mkdir -p ~/.agents ~/.codex
ln -sf ~/.agents/AGENTS.md ~/.codex/AGENTS.md

Codex将在未来的聊天中看到开放内存使用策略,而MCP服务器仍将通过以下方式进行配置 ~/.codex/config.toml.

对于特定于回购的行为,添加 AGENTS.md 存储库根目录或更近的子目录中的文件。对于该树中的工作,回购当地指示优先。

克劳德代码

全球指令:

  • ~/.claude/CLAUDE.md

推荐设置:

mkdir -p ~/.claude
ln -sf ~/.agents/AGENTS.md ~/.claude/CLAUDE.md

Claude Code自动加载 CLAUDE.md 内存/指令文件,因此这是使开放内存使用成为未来克劳德代码聊天的一部分的最简单方法。

对于特定于回购的行为,请添加 CLAUDE.md 在项目根中。

Claude还需要单独配置Open Memory MCP服务器。在以下位置添加MCP服务器:

  • ~/.claude.json

将指令文件和MCP服务器配置分为两部分:

  • ~/.claude/CLAUDE.md 告诉克劳德何时以及如何使用记忆
  • ~/.claude.json 告诉克劳德如何连接到Open Memory MCP服务器

VS代码中的GitHub副本

Copilot不依赖 ~/.github/copilot-instructions.md 作为标准的自动发现路径。要在VS Code中使用一个共享的全局文件,请将Copilot的全局自定义指令设置指向您的规范文件。

一个可行的设置是:

mkdir -p ~/.github
ln -sf ~/.agents/AGENTS.md ~/.github/copilot-instructions.md

然后在VS代码中:

  1. 打开副驾驶设置。
  2. 启用自定义指令。
  3. 集 Chat: Instructions Files Locations 到 ~/.github/copilot-instructions.md.

如果您更喜欢基于文档的仓库设置,而不是用户级的VS代码设置,请创建:

  • .github/copilot-instructions.md 用于存储库范围的说明
  • .github/instructions/*.instructions.md 获取特定路径的指令
  • AGENTS.md 用于面向代理的仓库指令

当您希望行为随存储库一起传播或应用于其他协作者时,请使用repo文件。

GitHub.com副驾驶聊天

GitHub.com个人指令是在GitHub UI中配置的,而不是通过本地文件路径配置的。如果您在GitHub.com上使用Copilot Chat,并希望那里有相同的政策,请将说明文本复制到GitHub web界面中的个人Copilot说明中。

备注

  • 这些指令文件告诉代理何时以及如何使用Open Memory;它们不会取代MCP服务器连接本身。
  • Codex、Claude Code和Copilot在全局和回购本地指令文件之间都有自己的优先级规则。
  • 切勿在这些指令文件中放置机密。仅将令牌和密码保存在适当的配置或秘密存储中。
  • 如果您需要其他代理、IDE或线束的设置说明,请打开问题或联系我们,我们可以记录正确的集成模式。

Nginx背后的自主机(/open-memory)

如果您想在以下位置公开此服务:

  • https://mcp.example.com/open-memory

使用Nginx作为反向代理,并将路径前缀转发到本地MCP服务(mcp:8080 Docker内部,或 127.0.0.1:<MCP_PORT> 在主机上)。

Nginx服务器块示例:

server {
    listen 443 ssl http2;
    server_name mcp.example.com;

    # TLS config (cert paths, ciphers, etc.) goes here

    # Redirect /open-memory -> /open-memory/
    location = /open-memory {
        return 301 /open-memory/;
    }

    # Proxy prefix path to MCP service root
    location /open-memory/ {
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Authorization $http_authorization;

        # Strip "/open-memory/" prefix
        rewrite ^/open-memory/(.*)$ /$1 break;
        proxy_pass http://127.0.0.1:8080;
    }
}

如果你改变 MCP_PORT,更新主机端 proxy_pass 相应的目标。

通过此设置,您的公共MCP端点将变为:

  • https://mcp.example.com/open-memory/mcp/v1

反向代理的Codex MCP配置示例:

[mcp_servers.openbrain]
enabled = true
startup_timeout_sec = 30
command = "npx"
args = [
  "-y", "mcp-remote", "https://mcp.example.com/open-memory/mcp/v1",
  "--transport", "http-only",
  "--header", "Authorization:${OPENBRAIN_AUTH_HEADER}",
  "--silent"
]
env = {"OPENBRAIN_AUTH_HEADER" = "Bearer <your-token>"}

备份

pgbackups 使用:

  • SCHEDULE="@daily"
  • 保留:
    • BACKUP_KEEP_DAYS=15
    • BACKUP_KEEP_WEEKS=4
    • BACKUP_KEEP_MONTHS=6

备份文件存储在:

  • ./postgres/backups

从备份中恢复

  1. 从以下位置选择备份文件 ./postgres/backups.
  2. 还原到正在运行的数据库中:
DBPASS="${DB_ADMIN_PASSWORD:-$(grep '^DB_ADMIN_PASSWORD=' .env | cut -d= -f2-)}"
DBUSER="${DB_ADMIN_USER:-$(grep '^DB_ADMIN_USER=' .env | cut -d= -f2-)}"
DBNAME="${DB_NAME:-$(grep '^DB_NAME=' .env | cut -d= -f2-)}"
cat ./postgres/backups/<backup-file.sql.gz> | gunzip | docker exec -i -e PGPASSWORD="$DBPASS" open-memory-db psql -U "$DBUSER" -d "$DBNAME"

如果你的垃圾堆很干净 .sql (非gzip压缩),使用:

DBPASS="${DB_ADMIN_PASSWORD:-$(grep '^DB_ADMIN_PASSWORD=' .env | cut -d= -f2-)}"
DBUSER="${DB_ADMIN_USER:-$(grep '^DB_ADMIN_USER=' .env | cut -d= -f2-)}"
DBNAME="${DB_NAME:-$(grep '^DB_NAME=' .env | cut -d= -f2-)}"
cat ./postgres/backups/<backup-file.sql> | docker exec -i -e PGPASSWORD="$DBPASS" open-memory-db psql -U "$DBUSER" -d "$DBNAME"

项目结构

  • docker-compose.yml:服务编排
  • .env.example:必需的环境变量
  • init-db/01-init.sql:数据库扩展/表/索引引导
  • pgai-init/installer.sh:运行 pgai install 并应用矢量化SQL
  • pgai-init/vectorizer.sql:pgai矢量器创建SQL
  • scripts/runtime/*.sh:MCP/矢量器启动包装器
  • postgres/data/:本地PostgreSQL绑定挂载的数据目录
  • postgres/backups/:本地备份目录
  • postgres/mcp-data/:持久MCP运行时状态(tokens.json, users.json,对话)

常见操作

停止堆栈:

docker compose down

停止并删除卷(删除数据库数据):

docker compose down -v

仅重新创建MCP服务:

docker compose up -d mcp

重新运行pgai安装程序(幂等):

docker compose up --force-recreate pgai-installer

安全须知

生产认证姿势

此设置中当前观察到的状态:

  • password_encryption = scram-sha-256
  • DB用户密码哈希为SCRAM
  • pg_hba.conf 有:
    • local all all scram-sha-256
    • host all all all scram-sha-256
  • ssl = off 在Postgres服务器内部(仅当流量停留在一个主机上的受信任的私有Docker网络内,并且外部访问在您的反向代理(Nginx/Caddy/Traefik)上受到HTTPS保护时才可接受)。)

如何实施更严格的政策:

  1. 这个compose文件设置了严格的init auth: POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 --auth-local=scram-sha-256
  2. 如果无法重新初始化,请编辑 pg_hba.conf 在数据目录中,重新加载配置: SELECT pg_reload_conf();

环境文件设置

此组合堆栈直接从以下位置读取凭据和令牌 .env.

  • DB_ADMIN_PASSWORD:PostgreSQL管理员密码
  • MCP_DB_PASSWORD:MCP数据库用户密码
  • PGEDGE_VOYAGE_API_KEY:用于矢量化的Voyage API键
  • INIT_TOKENS:API访问的comm-aseparated承载令牌

保持真实 .env 文件不受版本控制,并将其设置为 0600 关于生产系统。