部署指南
通过 Docker Compose 启动指南
仓库提供两份编排:
docker-compose.yml:中心服务与单节点执行,包含 PostgreSQL、RustFS、Memory Service、Gotenberg、Backend、Executor Manager 和 Frontend。docker-compose.worker.yml:边缘执行节点,通过中心 Backend 领取任务,在本机创建 Executor。
Executor 是动态容器,不是常驻 Compose 服务。m3e 仅在 m3e profile 开启时启动,AI 听记 Worker 仅在 ai-note profile 开启时启动。默认镜像来自 registry.cn-hangzhou.aliyuncs.com/ripper;私有仓库需事先登录。
部署前准备
需要 Docker Engine / Desktop、Compose v2、可用模型服务和可达的对象存储。主编排默认 Memory Service 的向量服务指向 http://m3e:6008/v1,应开启 m3e profile,或显式配置可用的外部 embedding 地址、模型、密钥与一致的向量维度。
使用外部 S3 时,在现有编排的环境配置中设置 S3_ENDPOINT、S3_REGION、S3_BUCKET 与凭据,并显式设置浏览器可访问的 S3_PUBLIC_ENDPOINT。主编排仍包含 RustFS,没有单独的 R2 编排文件。外部 bucket 需提前创建,避免把内网地址或默认 localhost 作为远程用户的下载地址。应用数据中页面上传的图片和附件也存放在该对象存储中,每个应用的文件总量由 USER_APP_MAX_FILE_STORAGE_MB 控制(默认 10240,即 10GB),请按存储容量调整。
应用数据的共享和个人私有记录不设置数量上限,单条记录大小由 Backend 的 USER_APP_MAX_DOCUMENT_SIZE_MB 控制(默认 1MB)。主 Compose 会将该变量传入 Backend,修改根目录 .env 后需重建 Backend 容器。CSV 导出会使用 Backend 容器的临时目录暂存所选集合的记录,请为临时目录预留对应磁盘容量。
手动启动(本地开发/自部署)
先准备 .env 并修改必填密钥:
cp .env.example .env至少需要把这些占位值改成真实值:
INTERNAL_API_TOKEN:Backend 与 Executor Manager 内部 API 鉴权 tokenCALLBACK_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 和会话运行时代次的限权令牌传给动态 Executor,用于直连 Backend 实时消息入口;实时回调请求不直接复用全局 INTERNAL_API_TOKEN。该地址必须能从动态 Executor 容器访问:Executor 已加入 Compose 网络时可以使用 http://backend:8000,否则应使用宿主机或节点可达的 Backend 地址。Backend、Executor Manager 与 Executor 必须使用同一版本整体部署,不支持混合版本运行;升级前必须排空或停止旧运行。事件在数据库提交后才被确认,网络中断时只重放本地事件日志,不重新执行模型或工具。
执行器会将 SDK 临时目录固定到工作区内的 .poco/sdk-tmp/,后台任务输出随工作区挂载持久保存。部署时必须保留会话工作区卷,不能只保存 SDK 对话历史;容器删除不应删除仍需保留的会话工作区。
Backend 主数据库仅支持 PostgreSQL,并要求显式配置 DATABASE_URL;缺少配置或使用 SQLite 等其他数据库时,服务会拒绝启动。Backend 启动时会执行 alembic upgrade heads,确保 Alembic 版本图中的全部 head 都被应用。PostgreSQL 迁移会先获取 advisory lock;多个 Backend 实例同时启动时,迁移阶段会等待并串行执行,连接关闭后自动释放锁。若部署平台已有独立迁移任务,Backend 实例可统一设置 RUN_MIGRATIONS=false。
默认 Compose 面向 32 GB 单节点,将 PostgreSQL POSTGRES_MAX_CONNECTIONS 设为 300,每个 Backend 进程使用 DATABASE_POOL_SIZE=100 和 DATABASE_MAX_OVERFLOW=100。部署多个 Backend 实例时,按实例数计算连接池总上限,并确保所有实例的常驻连接与突发连接总和低于 PostgreSQL 上限,为 Memory Service、数据库迁移和运维连接预留容量。修改这些参数后需要依次重建 PostgreSQL 和 Backend 容器;PostgreSQL 重建期间会短暂中断数据库连接,恢复健康后再启动 Backend。
然后在仓库根目录执行:
docker compose --profile m3e up -d上述命令启用默认本地向量服务;已有外部向量服务时可不启用该 profile。
默认会从阿里云镜像仓库拉取 backend / executor-manager / frontend 镜像,并拉取 Postgres/RustFS 镜像。执行任务时,executor-manager 会使用 EXECUTOR_IMAGE 动态拉起 executor 容器(本机缺镜像时会自动 pull)。
注意:当前仓库的
docker-compose.yml不包含单独的executor服务;executor 容器由executor-manager动态创建。
沙箱镜像预装官方技能的文档、PDF、OCR、GIF、MCP 和 Python/Node 工具依赖,前端技能的依赖及 pnpm 缓存保存在 /opt/poco/,不会被工作区挂载覆盖。完整镜像通过 PLAYWRIGHT_BROWSERS_PATH=/opt/poco/ms-playwright 定位预装 Chromium。依赖清单变更后需先重建沙箱基础镜像,再重建 Executor 镜像,并更新执行节点使用的镜像;已有容器不会自动获得新依赖。
资源下载认证需要同时部署更新后的 executor-manager 与 executor:管理器会自动注入
POCO_RESOURCE_DOWNLOAD_ENV_KEYS,执行器据此限制下载工具可读取的用户环境变量。
部署时无需为它添加 Compose 或 .env 配置。工作区磁盘需为下载内容、冻结副本和压缩快照
预留空间;下载工具会在传输前检查容量并拒绝超额下载。
Playwright MCP 的原生下载通过执行器自带的页面初始化脚本接入,需保留镜像中的
/app/app/utils/browser_resource_init.cjs 和 /app/.venv/bin/python。
POCO_PLAYWRIGHT_LANE_ID 由路由器为各子进程生成,无需在部署配置中设置。
主、子节点各自运行的本地浏览器均可归档原生下载;外部独立浏览器的远端路径不作为工作区文件发布。
初始化脚本缺失或归档依赖不可用时,继续使用原浏览器流程。归档失败保留原下载结果,
不取消原下载或阻止工作区快照;归档前的短暂等待不覆盖原浏览器工具的超时配置。
默认 Compose 会给 Frontend 配置 Backend 运行时地址:
INTERNAL_API_BASE_URL:Next.js server 和/api/v1/*、/api/v2/*同源代理访问 Backend 的首选地址;未配置时依次回退到BACKEND_URL、http://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 镜像。
可选集成:WeKnora 知识库检索
启用前先在 WeKnora 创建集成应用,并将回调地址登记为:
${BACKEND_URL}/api/v1/connectors/oauth/callback这里使用 Backend 容器自身的 BACKEND_URL。它必须是最终用户浏览器可访问的 HTTP(S) Origin,不能使用仅 Compose 网络可解析的 http://backend:8000。Frontend 继续通过同源 /api/v1/* 代理访问 Backend,不需要直接暴露用户凭据。
在 Poco 管理后台 → 连接器管理 上传独立的 WeKnora knowledge-base ZIP,填写 WeKnora Origin、wkapp_ Client ID 和 wks_ Client Secret 后发布,所有正常登录用户都可以连接自己的账号。知识空间由用户在 WeKnora 授权页选择,Poco 不保存全局空间 ID。Backend 必须能够访问 WeKnora 的 Token 和检索 API。
连接器归档保存在 S3,Executor Manager 从与运行快照完全匹配的归档加载 Skill。确认 Backend 与 Executor Manager 使用相同的 S3 bucket 和凭据,并整体升级 Backend、Executor Manager、Executor 与 Frontend。完整架构与排障边界见连接器与知识库检索。
连接器框架版本的发布顺序
连接器框架升级会同时改变数据库结构、运行快照和 Executor 契约。生产发布应进入维护窗口,停止新的连接器配置、授权和任务,等待在途连接器任务结束,再使用同一版本的 Backend 镜像依次执行:
export EXECUTOR_IMAGE=registry.cn-hangzhou.aliyuncs.com/ripper/poco-executor:RELEASE_TAG
docker compose pull backend executor-manager frontend
docker pull "${EXECUTOR_IMAGE}"
docker compose run --rm backend /app/.venv/bin/alembic upgrade heads
docker compose up -d连接器目录由管理员安装的 S3 归档生成,不再执行代码目录同步脚本。多副本部署时先完成迁移,再同时切换 Backend、Executor Manager、Executor 和 Frontend;确认 Backend 与 Executor Manager 使用同一 S3 bucket。升级完成后,在管理后台安装或更新所需连接器包。
专业模式/办公模式由 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=130GOTENBERG_TIMEOUT_SECONDS 应略大于 GOTENBERG_API_TIMEOUT,避免 Backend 在 Gotenberg 完成转换前提前断开。如需关闭增强 PDF 导出并恢复原有回退行为,将地址显式留空:
GOTENBERG_URL=修改超时后重新创建 Gotenberg 和 Backend 容器:
docker compose up -d --force-recreate gotenberg backendHTML 和 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=falseSITE_ANALYTICS_DOMAIN 填 Umami 服务根地址,不要包含 /script.js。如果前端页面使用 https,Umami 服务也应提供 https 地址,避免浏览器拦截混合内容。
网站统计启用后,前端会自动用内部用户 id 调用 Umami identify 识别已登录用户。需要额外上报 username、full_name、department 时,将 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 工作流,不会更新正式环境使用的 latest 和 full 标签:
- 打开 GitHub 仓库的 Actions 页面。
- 选择 docker-images-testing。
- 点击 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 -dexecutor 不是常驻 Compose 服务,需要单独拉取。新创建的 Executor 容器会使用更新后的本地 testing 镜像,已经运行的容器不会被替换。
访问地址(默认端口)
- Frontend:
http://localhost:3000 - Backend:
http://localhost:8000 - Executor Manager:
http://localhost:8001 - RustFS(S3)(仅
docker-compose.yml):http://localhost:9000(Console:http://localhost:9001) - Memory Service:
http://localhost:8005
Backend、Executor Manager、Executor、Memory Service 和 AI Note Worker 均已关闭 FastAPI 自动文档(/docs、/redoc、/openapi.json)。对外接口说明请查看前端网站的 API 文档,业务接口仍正常提供服务。
生产环境反向代理(HTTPS / HTTP/2 / gzip)
主编排直接暴露 Frontend 的 3000 端口,Next.js 自带服务只支持 HTTP/1.1。浏览器访问的 /api/v1、/api/v2 接口和页面跳转都经过 Frontend 转发,生产环境应在 Frontend 前面放置反向代理,并满足以下两点:
- 开启 HTTP/2:HTTP/1.1 下浏览器对同一域名最多同时建立 6 个连接。会话页会常驻多条 SSE 长连接,剩余连接被普通接口占满时,点击菜单要排队等待,表现为页面跳转卡住。HTTP/2 没有这个限制。
- 不要压缩 SSE 响应:gzip 会把流式数据攒在缓冲区,导致流式输出不显示、任务状态和侧边栏状态不更新。Backend 的 SSE 响应已带
Cache-Control: no-transform和X-Accel-Buffering: no,但 nginx 的 gzip 和部分防火墙不识别no-transform,必须在代理层排除text/event-stream。
浏览器只在 HTTPS 下使用 HTTP/2,纯 http:// 地址无法开启。内网没有正式证书时,可以使用企业内部 CA 签发的证书,或将自签证书导入客户端受信任列表。只需要浏览器到最外层代理之间使用 HTTP/2,代理到 Frontend 之间保持 HTTP/1.1 即可。
nginx 示例
server {
listen 80;
server_name poco.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on; # nginx 1.25.1 以前的版本改为:listen 443 ssl http2;
server_name poco.example.com;
ssl_certificate /etc/nginx/certs/poco.crt;
ssl_certificate_key /etc/nginx/certs/poco.key;
# 不小于 MAX_UPLOAD_SIZE_MB(默认 100)
client_max_body_size 100m;
gzip on;
# 不要加入 text/event-stream
gzip_types text/plain text/css application/json application/javascript;
location / {
proxy_pass http://127.0.0.1:3000; # Frontend 实际地址
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_read_timeout 600s; # SSE 长连接,与 Frontend 转发超时一致
}
}Backend 的 SSE 响应带有 X-Accel-Buffering: no,nginx 会自动关闭这类响应的缓冲,无需全局设置 proxy_buffering off。修改后执行 nginx -t && nginx -s reload。
防火墙、WAF 或云负载均衡
在 HTTPS 监听器或站点设置中启用 HTTP/2;在压缩或内容优化设置中排除 text/event-stream,无法按类型排除时对 /api/ 路径关闭压缩。
验证
- 打开浏览器开发者工具的 Network 面板,在列名上右键勾选 Protocol,刷新页面后请求显示
h2即 HTTP/2 已生效。 - 打开一个正在执行的任务,流式输出应逐段出现,而不是结束后一次性显示;同时确认
/stream请求的响应头中没有Content-Encoding: gzip。
关键说明(很重要)
executor-manager需要访问 Docker daemon:
- Compose 已默认挂载:
/var/run/docker.sock:/var/run/docker.sock - 因此
executor-manager才能动态创建 executor 容器 - Manager 镜像内置
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 能区分进程重启与新容器实例。该变量无需手动配置。
- 消息与回调地址:
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 天,应大于最长会话运行时存活时间)CALLBACK_QUEUE_STREAM_SHARDS=32CALLBACK_QUEUE_STREAM_MAXLEN=400000CALLBACK_QUEUE_FORWARD_RETRY_ATTEMPTS=6STREAM_OUTBOX_REPLAY_ENABLED=true(每个节点只重放自己的本地WORKSPACE_ROOT)STREAM_OUTBOX_REPLAY_INTERVAL_SECONDS=5STREAM_OUTBOX_REPLAY_BATCH_BYTES=1048576(每批补发目标上限,不超过 1MiB;超过的单个事件单独成批。升级时同步编排文件,仍为旧默认值524288时只是批次更小)
- 工作区目录(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_FILES和SCHEDULED_TASK_ARTIFACT_MAX_SIZE_MB限制定时任务单轮联动产物,并限制同一会话工作区内项目、定时任务或 API Key 共享历史产物快照的单次及累计文件数与未压缩总大小;多 worker 部署时应保持各节点配置一致
- 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会幂等执行,不会清理已有对象存储数据
- 预签名 URL 对外地址:
- Backend 会用
S3_PUBLIC_ENDPOINT生成给浏览器访问的预签名 URL: - 本地 rustfs(
docker-compose.yml)默认是http://localhost:9000 - 外部 S3 显式设置可被用户浏览器访问的
S3_PUBLIC_ENDPOINT;主 Compose 默认仍为 localhost,不会因只改 S3_ENDPOINT 自动改变
- Warm 容器(降低首 token 延迟):
executor-manager支持为交互式对话保留一段时间的“warm executor 容器”,减少重复冷启动开销- 可通过
EXECUTOR_CPU_LIMIT限制每个动态拉起的 Executor 容器最大 CPU 核数,例如2表示最多 2 核;0或不配置表示不限制 - 可通过
EXECUTOR_MEMORY_LIMIT限制每个动态拉起的 Executor 容器 RAM + swap 总上限,例如4g或4096m;空值或0表示不限制 - Compose 已默认启用(可在
.env覆盖): WARM_CONTAINER_ENABLED=trueWARM_CONTAINER_IDLE_TTL_SECONDS=600WARM_CONTAINER_CLEANUP_INTERVAL_SECONDS=60WARM_CONTAINER_IMMEDIATE_ENABLED=true
- 远程浏览器(用户登录入口,可选):
- 前端「设置 -> 远程浏览器」会通过 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 配公网域名;主编排同机部署通常使用host.docker.internal;边缘节点需填写该节点 Manager 可访问的本机地址。BROWSER_BASE_PUBLISHED_HOST(主编排同机默认host.docker.internal):Backend 访问“已映射到宿主机随机端口”的基础浏览器容器时使用的 host。边缘编排默认是CHANGE_ME_WORKER_HOST,必须改为中心 Backend 可访问的 worker 主机,并允许访问随机发布端口。用户浏览器通过 Backend 固定代理 URL 访问远程浏览器。BROWSER_BASE_AUTH_STATE_FLUSH_TIMEOUT_SECONDS(默认10):停止远程浏览器前同步 Backend Auth State 的超时BROWSER_BASE_STOP_TIMEOUT_SECONDS(默认3):停止远程浏览器容器的 Docker 超时。Chrome Profile 仅作为运行时缓存,不再阻塞停止。
- 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):SDK 产生首个结果后,executor 等待会话进入idle的秒数;超时后任务会失败,避免后台 Agent 或主 Agent 续执行尚未结束时误标 completed
- Playwright / MCP 超时(可选):
MCP_TIMEOUT(默认120000):MCP 连接/初始化超时(毫秒)MCP_TOOL_TIMEOUT(默认120000):MCP 工具调用超时(毫秒),必须配置为正整数;后台模型高级配置会在保存时拒绝非法值,直接注入 Executor 的非法值会让任务以明确的配置错误失败- 页面加载较慢时建议将两者同时调大(例如
180000或240000) - 文生图启用后,Executor Manager 会为新 Executor 容器注入
MCP_TOOL_TIMEOUT=600000,避免图片生成还没返回就被工具层超时打断。 - 符合条件的即时交互任务注册了定时任务提案工具,或注册了需要用户确认的连接器工具时,Executor 会将对应 SDK 子进程的
MCP_TOOL_TIMEOUT提高到至少900000(15 分钟),已有更大值则保留。用户确认窗口仍为 10 分钟,其余时间用于请求和实际执行;该 SDK 子进程内的其他 MCP 工具共享此超时,容器全局默认值及其他任务不变。定时任务语义相似提示可通过SCHEDULED_TASK_SEMANTIC_SIMILARITY_THRESHOLD调整,默认值为0.75;该配置只影响相似候选提示,精确重复任务仍会阻止创建。
文生图(可选):
- 在管理后台「系统配置」开启
text_to_image_enabled,并按需调整text_to_image_model(默认gpt-image-2)。 - 在
.env配置POCO_TEXT_TO_IMAGE_API_KEY和POCO_TEXT_TO_IMAGE_BASE_URL;未配置专用变量时会回退到OPENAI_API_KEY/OPENAI_BASE_URL。 - 图片生成结果会先由 Executor 上传到 Executor Manager,再写入 S3 兼容对象存储;因此
S3_*与S3_PUBLIC_ENDPOINT仍需正确配置。
- 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。先用目标镜像只读预演,核对输出数量后再选择是否补齐 hash、text_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 或生命周期残留,并由负责人确认回滚备份不再需要。
- AI Note Worker(AI 听记,可选):
- AI 听记架构说明见:AI 听记架构设计
ai-note-worker需要单独部署为独立容器,不能在 Backend Web 进程内执行 ASR、LLM 摘要、ffprobe 或 ffmpeg。- Worker 通过 Backend 内部 API 领取任务和回写进度,需要配置
BACKEND_URL与INTERNAL_API_TOKEN。 - Worker 镜像需要包含
ffprobe和ffmpeg。V1 使用ffprobe校验媒体时长;当源文件是视频时,使用ffmpeg抽取第一条音轨并转为 ASR 输入音频,不做音频切片。 - 主
docker-compose.yml已提供ai-note-workerprofile:docker compose --profile ai-note up -d ai-note-worker。 - 建议通过
AI_NOTE_MAX_CONCURRENT_JOBS=1或2控制单实例并发,并在容器层设置 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 的声纹接口;声纹管理仅依赖离线入口,POCO 不要求实时与离线服务使用同一个声纹数据库。 - 多个 Backend Web 实例必须共用同一个 PostgreSQL 数据库和同一个 S3 bucket。审核申请通过唯一约束和数据库行锁避免并发处理同一版本;首次录入直接调用 ASR 创建说话人,不能把结果未知的网络失败当作未写入并自动重新录入。Backend 主数据库不支持 SQLite。
- 声纹录入、维护及审核批准会同步调用 ASR。网关或 Ingress 对
/api/v1/admin/ai-note-speakers*和/api/v1/admin/ai-note-speaker-revisions*的请求超时应不少于 600 秒,前端同类请求超时为 600 秒。 - 声纹原始样本保存在 Poco 的 S3 兼容对象存储中。上线前需确认 bucket 为私有、备份和删除策略符合声音生物特征数据要求,并执行最新 Alembic 迁移创建声纹三张表及样本
remote_template_ids字段。 ai_note_enabled=false时,前端不会展示 AI 听记入口;启用前需先配置ai_note_asr_provider、ai_note_asr_base_url、ai_note_asr_api_key、ai_note_asr_options、必填的ai_note_summary_model,并确认ai_note_summary_max_tokens足以容纳模型思考过程和最终 JSON(默认6000)。如果使用openai_compatible,还需要配置ai_note_asr_url与ai_note_asr_model。需要语音输入或 AI 听记实时记录时,还应确认realtime_asr_provider、realtime_asr_base_url、realtime_asr_api_key指向可用的流式 ASR 服务;realtime_asr_api_key留空时会复用离线听记 ASR Token。
- Executor 包管理源:
- Executor Python 依赖依据
uv.lock从 PyPI 安装,不内置 pip / uv 镜像配置 - Executor 镜像默认将 npm registry 设置为
https://registry.npmmirror.com - 如需覆盖,可在自定义 Executor 镜像或动态容器环境里设置
NPM_CONFIG_REGISTRY
常用操作
以下命令使用主编排;边缘节点需显式使用 -f docker-compose.worker.yml,并选用该编排的服务名。
查看日志:
docker compose logs -f backend executor-manager升级平台请按 系统更新说明 完成排空任务、停止所有执行服务、数据库迁移和动态 Executor 镜像替换。
停止:
docker compose down停止并删除命名卷(会删除 PostgreSQL 与 Memory Service 的命名卷;RustFS 的 ./oss_data 是宿主机绑定目录,不会被 -v 删除):
docker compose down -v配置入口
大多数配置都通过环境变量完成,重点包括模型访问、默认模型、视觉能力、工作区 diff、推荐追问、会话标题与摘要、发布中心、智能工作台、能力推荐、记忆服务、PDF 转换、定时分析、对象存储、Auth State、内部调用 token、应用标题和 SSO 等配置。完整字段见配置参考。
OpenAPI 登录 Token 默认有效期为 24 小时,可通过 OPENAPI_LOGIN_TOKEN_TTL_SECONDS 调低,允许范围为 60~86400 秒。
OpenAPI 后台任务默认按 API Key 限制 20 个未完成任务和 2 个执行中任务,按用户限制 50 个未完成任务;全局容量为可用 OpenAPI Worker 容量的 10 倍;从未注册 Worker 时使用固定容量 5,排队超过 3600 秒后失败。后台结果查询限流按 Backend 实例生效,多实例部署如需限制集群总频率,应在统一入口配置限流。可通过 OPENAPI_BACKGROUND_* 变量调整,完整字段见配置参考。启用该能力前必须执行 Backend Alembic 迁移,以创建后台运行字段和并发约束索引。
若部署环境启用抚顺新钢铁 SSO 或 APP 快捷登录,Backend 需要配置 XGT_SSO_BASE_URL。系统会基于该根地址访问登录、用户信息和注销接口,并在用户登录时将用户信息中的 secondUnit 同步到部门字段。
若部署环境启用建龙集团 SSO,Backend 需要同时配置 JIANLONG_SSO_BASE_URL、JIANLONG_SSO_APP_ID 和 JIANLONG_SSO_APP_SECRET;前端只会拿到不含密钥的登录跳转地址。
若需要为建龙集团 SSO 用户提供“切换账号”,还需配置 JIANLONG_SSO_LOGOUT_URL;抚顺新钢铁 SSO 注销地址会从 XGT_SSO_BASE_URL 自动拼接。前端会在清理本地登录状态后跳转对应注销接口,并自动附加 redirect 参数。
首页语音输入和 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 启动时设置 ENABLE_TOOL_SEARCH=false,不再提供模型配置开关;升级后需重新构建并发布 Executor 镜像,已有容器不会自动生效。
实验性功能通过当前生效模型配置中的开关控制,默认关闭;Executor Manager 会向后续新启动的 Executor 容器注入 CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=0 或 1。
模型配置中的“高级配置”支持向 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 时只需配置一次。