Poco 使用手册
运维部署

部署指南

通过 Docker Compose 启动指南

仓库提供两套 Compose 文件:

  • docker-compose.yml:本地一体化(含 rustfs,用于本地 S3 兼容对象存储)
  • docker-compose.r2.yml:更轻量(不含 rustfs,适合接入 Cloudflare R2 / 其他 S3 兼容服务)

docker-compose.yml 已包含:

  • backend(FastAPI)
  • executor-manager(FastAPI + APScheduler,会通过 Docker API 动态拉起 executor 容器)
  • frontend(Next.js)
  • postgres
  • memory-service(FastAPI + mem0)
  • rustfs(默认 rustfs/rustfs:latest,S3 兼容)+ rustfs-init(创建 bucket,可选)
  • m3e(本地向量化服务,默认端口映射 5012:6008

说明:Compose 里不会长期运行 executor 服务;执行任务时由 executor-manager 通过 Docker API 动态创建 executor 容器。 AI 听记启用后需要额外部署 ai-note-worker。它是独立计算服务,不应放在 Backend Web 进程内运行。


前置条件

  • Docker Desktop / Docker Engine
  • Docker Compose v2(docker compose 命令)
  • 若 GHCR 镜像为私有:先执行 docker login ghcr.io

轻量方案:使用 Cloudflare R2(或其他 S3 兼容服务)

当你不想在本地启动 rustfs,可以改用 docker-compose.r2.yml,并在 .env 里配置外部对象存储(bucket 需要提前创建好)。

典型的 R2 配置示例:

# Cloudflare R2 (S3-compatible)
S3_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
S3_REGION=auto
S3_BUCKET=<bucket-name>
S3_ACCESS_KEY=<r2-access-key-id>
S3_SECRET_KEY=<r2-secret-access-key>
S3_FORCE_PATH_STYLE=false

# 可选:用于生成给浏览器的预签名 URL;不填则默认用 S3_ENDPOINT
# S3_PUBLIC_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com

启动(不会启动 rustfs):

docker compose -f docker-compose.r2.yml up -d

手动启动(本地开发/自部署)

先准备 .env 并修改必填密钥:

cp .env.example .env

至少需要把这些占位值改成真实值:

  • INTERNAL_API_TOKEN:Backend 与 Executor Manager 内部 API 鉴权 token
  • CALLBACK_TOKEN:Executor 回调到 Executor Manager 的鉴权 token;不能使用默认占位值,否则 Executor Manager 会拒绝启动
  • BACKEND_SECRET_KEY:Backend JWT 签名密钥
  • ROOT_PASSWORD / ROOT_PASSWORD_SALT:首次创建固定 root 账号所需的初始凭据。账号创建后,重启不会用这两个值覆盖数据库中的密码
  • ANTHROPIC_AUTH_TOKEN:执行任务所需的模型访问 token

Executor Manager 会把自身的 BACKEND_URL 和单次 run 的限权令牌传给动态 Executor,用于直连 Backend 实时消息入口;实时回调请求不直接复用全局 INTERNAL_API_TOKEN。该地址必须能从动态 Executor 容器访问:Executor 已加入 Compose 网络时可以使用 http://backend:8000,否则应使用宿主机或节点可达的 Backend 地址。Backend、Executor Manager 与 Executor 必须使用同一版本整体部署,不支持混合版本运行;直连入口握手失败时 Executor 会回退到原有 Manager 回调链路。

Backend 主数据库仅支持 PostgreSQL,并要求显式配置 DATABASE_URL;缺少配置或使用 SQLite 等其他数据库时,服务会拒绝启动。Backend 启动时会执行 alembic upgrade heads,确保 Alembic 版本图中的全部 head 都被应用。PostgreSQL 迁移会先获取 advisory lock;多个 Backend 实例同时启动时,迁移阶段会等待并串行执行,连接关闭后自动释放锁。若部署平台已有独立迁移任务,Backend 实例可统一设置 RUN_MIGRATIONS=false

然后在仓库根目录执行:

docker compose up -d

默认会从 GHCR(ghcr.io)拉取 backend / executor-manager / frontend 镜像,并拉取 Postgres/RustFS 镜像。执行任务时,executor-manager 会使用 EXECUTOR_IMAGE 动态拉起 executor 容器(本机缺镜像时会自动 pull)。

注意:当前仓库的 docker-compose.yml 不包含单独的 executor 服务;executor 容器由 executor-manager 动态创建。

默认 Compose 会给 Frontend 配置 Backend 运行时地址:

  • INTERNAL_API_BASE_URL:Next.js server 和 /api/v1/*/api/v2/* 同源代理访问 Backend 的首选地址;未配置时依次回退到 BACKEND_URLhttp://backend:8000
  • BACKEND_URL:Backend 公开地址,同时作为未配置 INTERNAL_API_BASE_URL 时的 Frontend 代理目标。

浏览器普通 HTTP API 请求只访问 Frontend 同源 /api/v1/*,不需要直接访问 Backend。需要将 BACKEND_URL 配置为公开域名、同时让 Frontend 直连内部 Backend 时,应显式配置 INTERNAL_API_BASE_URL。运行时调整这两个变量不需要重建 Frontend 镜像。

业务场景/办公场景由 Backend 账号设置和“场景切换”权限菜单共同管理,不再需要 Frontend 环境变量。部署包含该功能的版本前需执行 Backend Alembic 迁移;迁移会创建权限菜单并向现有功能角色授予该权限,避免正在使用场景切换的用户升级后失去入口。如需全局关闭,可在权限菜单中禁用“场景切换”资源。

默认集成:Gotenberg 增强 PDF 导出

docker-compose.yml 已集成 Gotenberg 8。执行 docker compose up -d 时会自动启动 Gotenberg,Backend 默认通过 Compose 内部地址 http://gotenberg:3000 调用,无需额外配置。启用后,HTML、Markdown、Office、OpenDocument、常见图片等受支持产物可以直接导出 PDF;现有 PDF 文件仍下载原文件,不做二次转换。

Gotenberg 默认只在 Compose 内部网络开放 3000 端口,不映射到宿主机。可以通过以下命令检查运行状态和日志:

docker compose ps gotenberg
docker compose logs --tail=50 gotenberg

调整超时或关闭增强导出

主编排默认允许 Gotenberg 单次转换执行 120 秒,Backend 最多等待 130 秒。需要临时覆盖时,在 Poco 的 .env 中配置:

GOTENBERG_API_TIMEOUT=120s
GOTENBERG_TIMEOUT_SECONDS=130

GOTENBERG_TIMEOUT_SECONDS 应略大于 GOTENBERG_API_TIMEOUT,避免 Backend 在 Gotenberg 完成转换前提前断开。如需关闭增强 PDF 导出并恢复原有回退行为,将地址显式留空:

GOTENBERG_URL=

修改超时后重新创建 Gotenberg 和 Backend 容器:

docker compose up -d --force-recreate gotenberg backend

HTML 和 Markdown 使用当前预览已经解析过资源地址和样式的 HTML,通过 Gotenberg Chromium 转换;其他格式由 Backend 从当前会话对象存储读取后,通过 Gotenberg LibreOffice 转换。如果显式留空 GOTENBERG_URL,HTML 和 Markdown 回退到浏览器打印,其他格式维持原下载行为;如果已经配置但服务异常,页面会直接提示导出失败。

为尽可能保留图片、Web 字体和外链样式,HTML 与 Markdown 中的资源 URL 必须能从 Gotenberg 容器访问。容器无法通过 localhost 访问宿主机上的资源,应改用容器可达的地址或在产物中内嵌资源;所需字体也要安装到 Gotenberg 运行环境。由于 HTML 转换会发起出站请求,生产环境还应隔离 Gotenberg 网络,并按 官方出站 URL 过滤说明 限制非必要目标。

网站统计默认关闭。需要启用时,先部署 Umami 统计服务并创建站点,然后在 .env 中配置 Frontend 运行时变量,重启 Frontend 容器即可,不需要重建镜像:

SITE_ANALYTICS_ENABLED=true
SITE_ANALYTICS_DOMAIN=http://10.6.80.164:8856
SITE_ANALYTICS_WEBSITE_ID=1bc25bd6-e5dc-4ea4-8d74-5ca8d8af6ddf
SITE_ANALYTICS_PERFORMANCE_ENABLED=false
SITE_ANALYTICS_SENSITIVE_USER_INFO_ENABLED=false

SITE_ANALYTICS_DOMAIN 填 Umami 服务根地址,不要包含 /script.js。如果前端页面使用 https,Umami 服务也应提供 https 地址,避免浏览器拦截混合内容。 网站统计启用后,前端会自动用内部用户 id 调用 Umami identify 识别已登录用户。需要额外上报 usernamefull_namedepartment 时,将 SITE_ANALYTICS_SENSITIVE_USER_INFO_ENABLED 设为 true。 需要采集 Web Vitals 时,将 SITE_ANALYTICS_PERFORMANCE_ENABLED 设为 true;该能力要求 Umami v3.1.0+

如果你要固定版本(例如 v0.1.0),可通过环境变量覆盖镜像 tag(示例):

export BACKEND_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-backend:v0.1.0
export EXECUTOR_MANAGER_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor-manager:v0.1.0
export EXECUTOR_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor:v0.1.0
export MEMORY_SERVICE_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-memory-service:v0.1.0
export AI_NOTE_WORKER_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-ai-note-worker:v0.1.0
export FRONTEND_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-frontend:v0.1.0

docker compose up -d

手动构建和部署测试镜像

测试镜像使用独立的 docker-images-testing 工作流,不会更新正式环境使用的 latestfull 标签:

  1. 打开 GitHub 仓库的 Actions 页面。
  2. 选择 docker-images-testing
  3. 点击 Run workflow,选择要测试的分支后运行。

工作流会先发布 test-<commit>-<run_number>-<run_attempt> 不可变标签。所有服务构建成功后,再将这些镜像更新到固定的 testing 标签;如果当前分支修改了 sandbox,则同时更新 sandbox:testing-full。测试服务器可以长期使用以下配置,无需在每次构建后修改标签:

BACKEND_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-backend:testing
EXECUTOR_MANAGER_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor-manager:testing
EXECUTOR_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor:testing
MEMORY_SERVICE_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-memory-service:testing
AI_NOTE_WORKER_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-ai-note-worker:testing
FRONTEND_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-frontend:testing

测试构建完成后,在测试服务器执行:

docker compose pull
docker pull registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor:testing
docker compose up -d

executor 不是常驻 Compose 服务,需要单独拉取。新创建的 Executor 容器会使用更新后的本地 testing 镜像,已经运行的容器不会被替换。

访问地址(默认端口)

  • Frontend: http://localhost:3000
  • Backend: http://localhost:8000(OpenAPI: /docs
  • Executor Manager: http://localhost:8001(OpenAPI: /docs
  • RustFS(S3)(仅 docker-compose.yml):http://localhost:9000(Console: http://localhost:9001
  • Memory Service: http://localhost:8005

关键说明(很重要)

  1. executor-manager 需要访问 Docker daemon:
  • Compose 已默认挂载:/var/run/docker.sock:/var/run/docker.sock
  • 因此 executor-manager 才能动态创建 executor 容器
  • Compose 会挂载 docker/executor_manager/start.sh 作为启动脚本。脚本内置自检 watchdog,请求 http://127.0.0.1:8001/api/v1/health;单次超时默认 15s,连续 3 次失败后会停止主进程,并由 restart: always 自动重启容器。可通过 EXECUTOR_MANAGER_HEALTHCHECK_* 环境变量覆盖。

自检 watchdog 相关环境变量:

  • EXECUTOR_MANAGER_HEALTHCHECK_URL(默认 http://127.0.0.1:8001/api/v1/health):容器内自检地址
  • EXECUTOR_MANAGER_HEALTHCHECK_TIMEOUT_SECONDS(默认 15):单次自检请求超时时间(秒)
  • EXECUTOR_MANAGER_HEALTHCHECK_FAILURE_THRESHOLD(默认 3):连续失败次数达到阈值后触发容器重启
  • EXECUTOR_MANAGER_HEALTHCHECK_INTERVAL_SECONDS(默认 15):自检间隔(秒)
  • EXECUTOR_MANAGER_HEALTHCHECK_START_PERIOD_SECONDS(默认 60):容器启动后的自检宽限期(秒)
  • EXECUTOR_MANAGER_HEALTHCHECK_STOP_GRACE_SECONDS(默认 5):触发重启时等待主进程优雅退出的时间(秒),超时后强制结束

启动脚本还会默认使用 Docker 容器 hostname 生成 EXECUTOR_WORKER_BOOT_ID。watchdog 触发同一容器重启时,该 ID 保持不变;容器重建后,该 ID 随 hostname 变化,使 Backend 能区分进程重启与新容器实例。该变量无需手动配置。

  1. 消息与回调地址:
  • CALLBACK_BASE_URL 是 Executor 到 Executor Manager 的普通回调地址,默认 http://host.docker.internal:8001
  • Executor Manager 的 BACKEND_URL 会同时下发给 Executor,用于高频流消息直达 Backend 的 /api/v1/callback/stream
  • 动态创建的 executor 容器默认不在 compose 网络里,两个地址都必须从该容器内可访问
  • executor-manager 会在创建 executor 容器时注入 host.docker.internal:host-gateway;Compose 也为 executor-manager 容器配置了该映射(Linux 下也可用)
  • 正常高频流消息不进入 Executor Manager 回调队列;普通状态、终态仍回调 Manager。直达 Backend 持续失败时,Executor 才把未持久化事件按有序批次交给 Manager 转发

多 Executor Manager 节点部署时,每台执行机器都运行自己的 Executor Manager、Docker daemon 和本地 WORKSPACE_ROOT

  • 详细部署拓扑、节点管理和故障恢复请阅读:多节点执行部署
  • 每个节点配置唯一且稳定的 EXECUTOR_WORKER_ID(不要使用同一个默认值复制到多台机器)
  • 每个节点配置 Backend 可访问的 EXECUTOR_MANAGER_PUBLIC_URL
  • Backend 会接收节点注册和心跳,并把同一个 session 固定路由回首次 claim 它的 worker
  • 如果从单机升级到多节点,先将 Backend 的 LEGACY_UNBOUND_SESSION_WORKER_ID 设为原单机节点的 EXECUTOR_WORKER_ID,让历史未绑定 session 回到原本存放本地工作区的节点
  • 任务浏览器实时预览由 Backend WebSocket 代理到绑定 worker;外网用户不需要直接访问每个 worker
  • 用户级远程浏览器会绑定到创建它的 worker;登录态 flush、停止和删除都会回到该 worker
  • 不需要共享 WORKSPACE_ROOT;完成后的工作区文件通过 S3/RustFS 导出供 Backend 和前端访问
  • 下线节点前先将该 worker 置为 draining,等待 active_runs=0 后再停止服务

Manager 回调队列(普通回调与实时消息降级)默认参数:

  • STREAM_CALLBACK_TOKEN_TTL_SECONDS=604800(7 天,应大于最长 run 时长)
  • CALLBACK_QUEUE_STREAM_SHARDS=32
  • CALLBACK_QUEUE_STREAM_MAXLEN=400000
  • CALLBACK_QUEUE_FORWARD_RETRY_ATTEMPTS=6
  • STREAM_OUTBOX_REPLAY_ENABLED=true(每个节点只重放自己的本地 WORKSPACE_ROOT
  • STREAM_OUTBOX_REPLAY_INTERVAL_SECONDS=5
  1. 工作区目录(Workspace):
  • Compose 默认使用 ${PWD}/tmp_workspace 作为 WORKSPACE_ROOT,也可通过 .env 覆盖
  • 该目录会被 Executor Manager 创建的 executor 容器以 bind mount 方式挂载到 /workspace
  • 首次启动会先运行 workspace-init,自动创建 active/archive/temp/shared/browser_profiles/auth_state_baselines/ 并修正权限
  • 重复启动时 workspace-init 会幂等执行,不会清理已有工作区数据
  • 启用 WORKSPACE_CLEANUP_ENABLED 后,可通过 WORKSPACE_CLEANUP_INTERVAL_HOURS 调整扫描间隔,通过 WORKSPACE_MAX_AGE_HOURS 调整活动工作区的最短保留时间;主 Compose 和 worker Compose 都会将这些配置传入 Executor Manager
  • 清理不会处理仍有任务运行标记的工作区;任务结束后,过期工作区按 WORKSPACE_ARCHIVE_ENABLED 选择本地归档或直接删除
  • 定时任务联动产物由 SCHEDULED_TASK_ARTIFACT_MAX_FILESSCHEDULED_TASK_ARTIFACT_MAX_SIZE_MB 限制单轮文件数与未压缩总大小;多 worker 部署时应保持各节点配置一致
  1. RustFS 数据目录权限(Linux 常见坑,仅 docker-compose.yml):
  • rustfs 会把 ${RUSTFS_DATA_DIR} bind mount 到容器的 /data
  • 默认 RUSTFS_DATA_DIR=./oss_data(仓库根目录)
  • 首次启动会先运行 rustfs-data-init,自动创建 /data/${S3_BUCKET}(默认对应 oss_data/poco)并修正 /data 与 bucket 目录权限
  • rustfs-data-init 不假设 RustFS 镜像内部用户,目录会设置为可写权限,避免首次启动因宿主机目录权限不一致失败
  • 重复启动时 rustfs-data-init 会幂等执行,不会清理已有对象存储数据
  1. 预签名 URL 对外地址:
  • Backend 会用 S3_PUBLIC_ENDPOINT 生成给浏览器访问的预签名 URL:
  • 本地 rustfs(docker-compose.yml)默认是 http://localhost:9000
  • Cloudflare R2(docker-compose.r2.yml)通常保持与 S3_ENDPOINT 一致,或填你的自定义域名
  1. Warm 容器(降低首 token 延迟):
  • executor-manager 支持为交互式对话保留一段时间的“warm executor 容器”,减少重复冷启动开销
  • 可通过 EXECUTOR_CPU_LIMIT 限制每个动态拉起的 Executor 容器最大 CPU 核数,例如 2 表示最多 2 核;0 或不配置表示不限制
  • 可通过 EXECUTOR_MEMORY_LIMIT 限制每个动态拉起的 Executor 容器 RAM + swap 总上限,例如 4g4096m;空值或 0 表示不限制
  • Compose 已默认启用(可在 .env 覆盖):
  • WARM_CONTAINER_ENABLED=true
  • WARM_CONTAINER_IDLE_TTL_SECONDS=600
  • WARM_CONTAINER_CLEANUP_INTERVAL_SECONDS=60
  • WARM_CONTAINER_IMMEDIATE_ENABLED=true
  1. 远程浏览器(用户登录入口,可选):
  • 前端「设置 -> 远程浏览器」会通过 Executor Manager 拉起一个用户浏览器容器(使用 EXECUTOR_IMAGE,含 VNC/noVNC)
  • 用户在该 VNC 画面内手动登录网站后,登录态会同步到 Backend Auth State
  • 远程浏览器与任务浏览器都只通过 Backend Auth State 持久化登录态;Chrome Profile/cache 仅为容器内临时运行时数据
  • 当前持久化范围为 cookies/localStorage;需要稳定复用登录态的任务建议使用 Playwright MCP 浏览器链路

相关环境变量(在 .env 或 Compose 覆盖):

  • AUTH_STATE_ENCRYPTION_KEY(可选):Backend 用于加密浏览器 Auth State 的密钥;生产环境建议单独配置
  • BROWSER_BASE_IDLE_TTL_SECONDS(默认 600,10 分钟):基础浏览器容器空闲回收时长
  • BROWSER_BASE_CLEANUP_INTERVAL_SECONDS(默认 30):回收任务运行间隔
  • BROWSER_STREAM_PUBLISHED_HOST:任务浏览器实时预览的 worker 内部上游 host。前端连接 Backend 代理,不需要为每个 worker 配公网域名;Compose 内通常使用 host.docker.internal
  • BROWSER_BASE_PUBLISHED_HOST(Compose 默认 host.docker.internal):Backend 访问“已映射到宿主机随机端口”的基础浏览器容器时使用的 host。用户浏览器通过 Backend 固定代理 URL 访问远程浏览器。
  • BROWSER_BASE_AUTH_STATE_FLUSH_TIMEOUT_SECONDS(默认 10):停止远程浏览器前同步 Backend Auth State 的超时
  • BROWSER_BASE_STOP_TIMEOUT_SECONDS(默认 3):停止远程浏览器容器的 Docker 超时。Chrome Profile 仅作为运行时缓存,不再阻塞停止。
  1. Playwright 截图返回(可选):
  • POCO_PLAYWRIGHT_IMAGE_RESPONSES(默认 omit):控制 Playwright MCP 是否在工具返回 JSON 中内嵌截图/图片(base64)
  • omit:不内嵌(推荐,避免截图过大触发 1MB 上限导致工具卡死)
  • allow:允许内嵌(截图较大时可能失败)
  • POCO_PLAYWRIGHT_MCP_MAX_LANES(默认 30):单个 executor 容器内最多保留的 Playwright MCP Router lane 数量;Router 默认启用,在同一个 Chrome/CDP 内为并行 subagent 分配独立 MCP lane;小于 2 时按 2 处理
  • POCO_PLAYWRIGHT_MCP_ROUTING_LEDGER:Playwright MCP Router 路由账本路径,通常保持为空并使用工作区内默认路径
  • POCO_ASYNC_SUBAGENT_JOIN_TIMEOUT_SECONDS(默认 7200):executor 等待异步 subagent 完成的秒数;超时后任务会失败,避免未汇总结果时误标 completed
  1. Playwright / MCP 超时(可选):
  • MCP_TIMEOUT(默认 120000):MCP 连接/初始化超时(毫秒)
  • MCP_TOOL_TIMEOUT(默认 120000):MCP 工具调用超时(毫秒)
  • 页面加载较慢时建议将两者同时调大(例如 180000240000
  • 文生图启用后,Executor Manager 会为新 Executor 容器注入 MCP_TOOL_TIMEOUT=600000,避免图片生成还没返回就被工具层超时打断。

文生图(可选):

  • 在管理后台「系统配置」开启 text_to_image_enabled,并按需调整 text_to_image_model(默认 gpt-image-2)。
  • .env 配置 POCO_TEXT_TO_IMAGE_API_KEYPOCO_TEXT_TO_IMAGE_BASE_URL;未配置专用变量时会回退到 OPENAI_API_KEY / OPENAI_BASE_URL
  • 图片生成结果会先由 Executor 上传到 Executor Manager,再写入 S3 兼容对象存储;因此 S3_*S3_PUBLIC_ENDPOINT 仍需正确配置。
  1. Executor 访问记忆服务地址(可选):
  • EXECUTOR_MEMORY_SERVICE_URL:用于覆盖 Executor Manager 注入给动态 Executor 容器的 MEMORY_SERVICE_URL
  • 默认值:http://host.docker.internal:${MEMORY_SERVICE_PORT}
  • memory-service 内部 MEM0_LLM_API_KEY / MEM0_LLM_BASE_URL 默认会回退到 OPENAI_API_KEY / OPENAI_BASE_URL(若设置了 MEM0_LLM_*,则优先使用自定义值)
  • Compose 同时会向 memory-service 注入 OPENAI_API_KEY / OPENAI_BASE_URL(值与 MEM0_LLM_* 解析结果一致),兼容部分记忆服务运行时读取标准环境变量的路径
  • Compose 默认设置 MEM0_TELEMETRY=false,避免私有化环境连接 PostHog;如确需匿名遥测可显式开启
  • Compose 默认给 Executor 设置 MEMORY_SEARCH_MIN_SCORE=0.45,并给 Memory Service 设置 MEMORY_SEARCH_DEFAULT_MIN_SCORE=0.45;前者由 SDK 检索请求显式发送,后者是直接接口未传值时的兜底,两者调整时必须保持一致
  • memory-service 使用 public.poco_memories 保存主记忆,并由 Mem0 v2 自动维护 public.poco_memories_entities 作为内部实体关联索引;不再需要 Neo4j
  • 任务完成后的自动候选以真实 user/assistant 角色使用 infer=true 提炼新事实;语言漂移只允许再执行一次带约束的 infer=true 重试,禁止原文直存;Agent 新增、更新和遗忘通过 manage_user_memory 显式执行,更新和删除必须携带真实记忆 ID;同一 Run 发生显式管理后会跳过自动候选,避免旧事实回写;Executor 自动队列只投递一次,Memory Service 对自动提炼中的 Mem0 后端异常最多尝试 4 次(1/2/4 秒退避),Executor 收尾等待采用请求超时加 5 秒,默认 65 秒,最终失败不影响主任务
  • Compose 将 Mem0 SQLite 操作轨迹和隐式消息上下文持久化到 memory_service_data 卷,容器内路径为 /data/mem0/history.db;主记忆不存放在 SQLite,物理遗忘会同步删除对应记忆 ID 的历史轨迹
  • 镜像构建时会固定安装 en_core_web_sm 3.8.0,不要依赖生产容器首次请求时在线下载 NLP 模型

从旧版升级时,应安排维护窗口:停止接收新任务,等待正在运行的 Executor 结束,再暂停 Executor Manager 和 Memory Service。备份、索引和迁移期间不要恢复记忆写入。

docker compose stop executor-manager memory-service

先为主记忆表、实体表和已停止写入的 SQLite 文件创建一致备份。以下命令从仓库根目录执行;旧 Neo4j 数据卷按原部署方式另行保留离线备份,不需要启动 Neo4j 服务。

backup_dir="backups/memory-$(date +%Y%m%d%H%M%S)"
mkdir -p "$backup_dir"

docker compose exec -T postgres pg_dump \
  -U "${POSTGRES_USER:-postgres}" \
  -d "${POSTGRES_DB:-poco}" \
  -Fc -t 'public.poco_memories*' \
  > "$backup_dir/postgres.dump"

memory_container="$(docker compose ps -aq memory-service)"
docker cp "$memory_container:/data/mem0/history.db" \
  "$backup_dir/history.db"

确认两个备份文件均非空后,使用 PostgreSQL 容器内置的 psql 执行非破坏性索引脚本,不依赖宿主机安装 psql 或导出 DATABASE_URL

docker compose exec -T postgres psql \
  -U "${POSTGRES_USER:-postgres}" \
  -d "${POSTGRES_DB:-poco}" \
  < memory_service/scripts/upgrade_mem0_v2.sql

该脚本不会改写旧记忆。此时不要清理旧 Neo4j 资源;应先完成预检、旧数据召回和完整升级门禁,稳定观察后再处理旧容器和数据卷。

部署流程必须先把部署 Compose 中的 memory-service.image 固定为已批准的目标 tag 或 digest,再拉取镜像并重建处于停止状态的服务容器。记录实际镜像 ID,并确认容器中的 mem0ai 版本为 2.0.12;任一结果不符合目标都应停止升级。随后使用同一镜像执行只读上线检查:

docker compose pull memory-service
docker compose create --force-recreate memory-service
docker compose images memory-service
docker compose run --rm memory-service \
  /app/.venv/bin/python -c \
  'from importlib.metadata import version; print(version("mem0ai"))'

docker compose run --rm memory-service \
  /app/.venv/bin/python /app/scripts/verify_mem0_v2_preflight.py

只有旧向量维度、必要索引、embedding 输出维度和 NLP 模型全部通过后,才能继续;不要仅凭 /health 恢复写流量。

旧数据继续原位保留在 public.poco_memories。先用目标镜像只读预演,核对输出数量后再选择是否补齐 hashtext_lemmatized 和 v2 策略字段:

docker compose run --rm \
  -v "$PWD/memory_service/scripts:/app/scripts:ro" \
  memory-service \
  /app/.venv/bin/python /app/scripts/migrate_mem0_v2_data.py

docker compose run --rm \
  -v "$PWD/memory_service/scripts:/app/scripts:ro" \
  memory-service \
  /app/.venv/bin/python /app/scripts/migrate_mem0_v2_data.py --apply

迁移脚本是运维工具,当前不打包进运行镜像,所以上述命令只读挂载仓库中的 memory_service/scripts--apply 不改变记忆 ID,也不重新生成向量。只有确需清理实体噪声时,才单独执行实体表重建;工具会先创建带时间戳的实体备份表,不能清空主向量表。

docker compose run --rm \
  -v "$PWD/memory_service/scripts:/app/scripts:ro" \
  memory-service \
  /app/.venv/bin/python /app/scripts/migrate_mem0_v2_data.py \
  --apply \
  --rebuild-entities \
  --confirm-entity-reset poco_memories_entities

完成门禁测试后再恢复服务:

docker compose up -d memory-service executor-manager

升级 Mem0 SDK、provider、embedding 模型或存储实现时,还必须完成 Mem0 SDK 升级门禁中的内部接口核对、旧/新数据召回、原语言保护、上下文隔离、生命周期和回滚检查。稳定观察后才能清理旧 Neo4j 容器和数据卷。

上线验收还必须验证删除响应状态透传:完整成功为 deleted + success=true;不存在、越权、后端失败和历史/实体部分清理均为 success=false,其中 partial_cleanup 必须触发告警并由运维复核,不得仅凭 HTTP 200 判断删除成功。

如升级失败,先保持写入停止并恢复原镜像配置,再执行以下恢复。backup_dir 必须指向本次升级前创建的目录:

docker compose exec -T postgres pg_restore \
  -U "${POSTGRES_USER:-postgres}" \
  -d "${POSTGRES_DB:-poco}" \
  --clean --if-exists --no-owner \
  < "$backup_dir/postgres.dump"

docker compose create --force-recreate memory-service
memory_container="$(docker compose ps -aq memory-service)"
docker cp "$backup_dir/history.db" \
  "$memory_container:/data/mem0/history.db"
docker compose run --rm --user root memory-service \
  chown app:app /data/mem0/history.db

恢复后重新执行旧版本预检,验证通过再启动服务。恢复会覆盖升级后的记忆变更,因此只能在维护窗口内执行,并应保留恢复日志。删除旧 Neo4j 资源前,至少要满足:完整门禁通过、旧/新记忆样本在 0.45 阈值下均通过、连续观察期内无未解释的记忆 5xx 或生命周期残留,并由负责人确认回滚备份不再需要。

  1. AI Note Worker(AI 听记,可选):
  • AI 听记架构说明见:AI 听记架构设计
  • ai-note-worker 需要单独部署为独立容器,不能在 Backend Web 进程内执行 ASR、LLM 摘要、ffprobe 或 ffmpeg。
  • Worker 通过 Backend 内部 API 领取任务和回写进度,需要配置 BACKEND_URLINTERNAL_API_TOKEN
  • Worker 镜像需要包含 ffprobeffmpeg。V1 使用 ffprobe 校验媒体时长;当源文件是视频时,使用 ffmpeg 抽取第一条音轨并转为 ASR 输入音频,不做音频切片。
  • docker-compose.yml 已提供 ai-note-worker profile:docker compose --profile ai-note up -d ai-note-worker
  • 建议通过 AI_NOTE_MAX_CONCURRENT_JOBS=12 控制单实例并发,并在容器层设置 CPU、内存和临时目录容量限制。
  • 后台系统配置中的 ai_note_asr_base_url 是离线听记 ASR 地址,必须是 Worker 容器可访问的 Qwen v2 ASR 服务根地址;127.0.0.1 在容器内代表 Worker 自身,不一定是宿主机或 Compose 中的 ASR 服务。
  • 后台系统配置中的 realtime_asr_base_url 是实时语音 ASR 地址,必须是 Backend Web 进程可访问的 Qwen v2 流式 ASR 服务根地址,默认值为 http://127.0.0.1:8766。多节点部署建议单独配置,避免离线转写占用实时 WebSocket 服务资源。
  • 启用后台声纹库时,ai_note_asr_base_url 也必须能被 Backend Web 进程访问。Backend 会通过 ASR 已有的 /v2/speakers* 接口把管理员录入的声纹分别同步到实时和离线入口;两个入口相同且 Token 相同时自动去重,不同入口必须使用独立声纹库,不能依赖共享数据库同步进程内声纹缓存。
  • 多个 Backend Web 实例必须共用同一个 PostgreSQL 数据库和同一个 S3 bucket。声纹首次录入使用 PostgreSQL 事务级 advisory lock 防止多实例并发重复录入;Backend 主数据库不支持 SQLite。
  • 声纹管理接口会同步完成 ASR 预检和双入口写入。网关或 Ingress 对 /api/v1/admin/ai-note-speakers* 的请求超时应不少于 600 秒,前端同类请求超时为 600 秒。
  • 声纹原始样本保存在 Poco 的 S3 兼容对象存储中。上线前需确认 bucket 为私有、备份和删除策略符合声音生物特征数据要求,并执行最新 Alembic 迁移创建声纹三张表及样本 remote_template_ids 字段。
  • ai_note_enabled=false 时,前端不会展示 AI 听记入口;启用前需先配置 ai_note_asr_providerai_note_asr_base_urlai_note_asr_api_keyai_note_asr_options、必填的 ai_note_summary_model,并确认 ai_note_summary_max_tokens 足以容纳模型思考过程和最终 JSON(默认 6000)。如果使用 openai_compatible,还需要配置 ai_note_asr_urlai_note_asr_model。需要语音输入或 AI 听记实时记录时,还应确认 realtime_asr_providerrealtime_asr_base_urlrealtime_asr_api_key 指向可用的流式 ASR 服务;realtime_asr_api_key 留空时会复用离线听记 ASR Token。
  1. Executor npm / pip / uv 镜像源:
  • Executor 镜像默认内置国内源:npm 使用 https://registry.npmmirror.com,pip / uv 使用 https://mirrors.aliyun.com/pypi/simple/
  • 如需覆盖,可在自定义 Executor 镜像或动态容器环境里设置 NPM_CONFIG_REGISTRY / PIP_INDEX_URL / UV_INDEX_URL

常用操作

如果你使用的是 docker-compose.r2.yml,请在下列命令中追加 -f docker-compose.r2.yml

查看日志:

docker compose logs -f backend executor-manager

更新到最新镜像(或拉取你指定的 tag):

docker compose pull
docker compose up -d

停止:

docker compose down

停止并清理数据(会删除 Postgres/对象存储 volume):

docker compose down -v

配置入口

大多数配置都通过环境变量完成,重点包括模型访问、默认模型、视觉能力、工作区 diff、推荐追问、会话标题与摘要、发布中心、智能工作台、能力推荐、记忆服务、PDF 转换、定时分析、对象存储、Auth State、内部调用 token、应用标题和 SSO 等配置。完整字段见配置参考。 OpenAPI 登录 Token 默认有效期为 24 小时,可通过 OPENAPI_LOGIN_TOKEN_TTL_SECONDS 调低,允许范围为 60~86400 秒。 若部署环境启用 APP 快捷登录,Backend 需要同时配置 SSO_DO_LOGIN_URLSSO_GET_USER_INFO_URL,前者用于账号密码换取 satoken,后者用于按 satoken 获取用户信息。 若部署环境启用建龙集团 SSO,Backend 需要同时配置 JIANLONG_SSO_BASE_URLJIANLONG_SSO_APP_IDJIANLONG_SSO_APP_SECRET;前端只会拿到不含密钥的登录跳转地址。 首页语音输入和 AI 听记实时记录复用后台系统配置中的实时语音 ASR 配置;realtime_asr_api_key 留空时会复用离线听记 ai_note_asr_api_key。开关 voice_input_enabled 与 AI 听记相关配置统一在「语音与听记」中维护。 代理团队实验功能通过后台系统配置 experimental_agent_teams_enabled 控制,开启后只影响后续新启动的 Executor 容器。 文生图通过后台系统配置 text_to_image_enabled 控制,开启后只影响后续新启动的 Executor 容器;实际图片接口凭证由 POCO_TEXT_TO_IMAGE_*OPENAI_* 环境变量提供。 工具搜索通过当前生效模型配置中的开关控制,Executor Manager 会向后续新启动的 Executor 容器注入 ENABLE_TOOL_SEARCH=10。 实验性功能通过当前生效模型配置中的开关控制,默认关闭;Executor Manager 会向后续新启动的 Executor 容器注入 CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=01。 模型配置中的“高级配置”支持向 Executor 容器新增或覆盖自定义环境变量,最多 100 项,每项名称和值均不超过 255 个字符,不额外限制总数据大小。自定义值的优先级高于容器中的同名运行时默认值;平台鉴权、会话身份、工作区和隔离相关变量受保护,不允许覆盖。修改后只影响后续新启动或因环境配置变化而重建的容器。 AI 听记使用独立 ai-note-worker,详见:AI 听记架构设计。 对于 backend 的“推荐追问”模型,若希望使用默认轻量模型别名,请将 FOLLOWUP_MODEL 留空。 对于 backend 的“会话摘要”模型,默认使用 SESSION_SUMMARY_MODEL;未显式配置模型配置记录时会回退到默认轻量模型别名。

详见:配置参考

可选:自动创建 bucket(仅 docker-compose.yml

默认启动不会运行 rustfs-init(避免不同 OSS 镜像/权限差异导致阻塞启动)。如需自动创建 S3_BUCKET

docker compose --profile init up -d rustfs-init

定时任务联动产物保留策略

定时任务联动产物存放在 bucket 的 scheduled-task-artifacts/ 前缀下。生产环境应在对象存储侧为该前缀单独配置过期规则,避免历史 Run 的归档和清单长期累积;不要将规则扩大到整个 bucket,以免删除工作区导出、会话附件等其他对象。

建议从 30 天开始,再按实际联动模式调整:

  • “前置完成后触发”:保留天数必须长于下游 Run 可能处于排队、重试状态的最长时间。
  • “按自身计划取最新产物”:保留天数还必须覆盖上游两次有效非空产物之间可能出现的最长间隔。系统不会设置固定的最大产物年龄;如果业务允许长期复用最后一份产物,应使用足够长的保留期,或不要对该前缀设置自动过期。

仍在队列中的下游 Run 或新触发的“计划取最新”Run 如果引用对象已经过期,输入暂存会失败,因此不能使用短于业务复用窗口的保留期。

RustFS/MinIO 可使用兼容的 mc 客户端配置并检查规则(请替换 alias、bucket 和保留天数):

mc ilm rule add --prefix "scheduled-task-artifacts/" --expire-days 30 <alias>/<bucket>
mc ilm rule ls <alias>/<bucket>

本地 RustFS 还需要设置 RUSTFS_ENABLE_SCANNER=true 后重启 RustFS,使对象扫描器执行到期回收。

Cloudflare R2 或其他 S3 兼容服务应在其管理控制台中创建等价的前缀生命周期规则。多 worker 共用同一 bucket 时只需配置一次。

On this page