c1420b5665
排查「fulltext 路 0 命中」时发现的真问题,比原以为的分词器问题严重得多。
现状:mcp-go 容器**没有任何 volume**,也没设 BLEVE_PATH,于是索引落到相对
CWD 的 .data/bleve。而运行阶段没有 WORKDIR(CWD=/)、进程又是非 root(uid 10001),
两种结局都糟:
- 在 / 下建不了目录 → openBleve 静默退回内存索引,重启即清零;
- 就算建得了,也只是写进容器可写层,每次发版重建容器一样清零。
更糟的是它不报错:混合检索少一路只表现为召回变差,看不出故障。
改动:
- Dockerfile:建 /data 并 chown 给 app,WORKDIR 设为 /data;
- 两份 compose:BLEVE_PATH=/data/bleve + 挂持久卷(132 那份此前连
顶层 volumes 段都没有);
- .env.example:写清默认相对路径相对的是**启动目录**——本地从仓库根起
和从 sundynix-mcp-go/ 起会写出两份互不相干的索引,排查时极易被坑。
附带澄清:中文分词本身没问题。直接开落盘索引验证过,mapping 里 text 字段
确实是 cjk,实测「星间链」命中 4 条、「海关监管」命中 104 条,BM25 打分正常。
a4852c3 那次修复是有效的,之前怀疑分词器的判断作废。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
190 lines
6.9 KiB
YAML
190 lines
6.9 KiB
YAML
# sundynix-agentix · 生产/独立部署编排(应用 + 基建一把拉起)
|
||
#
|
||
# cp .env.example .env # 然后按提示填密钥(见 DEPLOY.md)
|
||
# docker compose -f docker-compose.prod.yml up -d --build
|
||
#
|
||
# 设计:
|
||
# - 应用经服务名互连(postgres:5432 等),不依赖 127.0.0.1;基建端口不对宿主暴露(仅内网)。
|
||
# - 仅暴露 gateway(:${GATEWAY_PORT},内嵌 admin 控制台 + API + 供桌面端直连) + Jaeger UI(可选)。
|
||
# - 引导密钥从 .env 注入(SUNDYNIX_SECRET_KEY/JWT_SECRET/各库密码);模型 API key 仍在控制台配、加密存 PG。
|
||
# - APP_ENV=production → 强制校验密钥、锁 CORS、启用管理员白名单。
|
||
|
||
x-secret-key: &secret-key ${SUNDYNIX_SECRET_KEY:?需在 .env 设置(openssl rand -base64 32)}
|
||
|
||
services:
|
||
# ---------- 应用层 ----------
|
||
gateway:
|
||
build: { context: ., dockerfile: sundynix-gateway/Dockerfile }
|
||
image: sundynix/gateway:${TAG:-latest}
|
||
restart: unless-stopped
|
||
environment:
|
||
APP_ENV: production
|
||
GATEWAY_ADDR: ":8080"
|
||
NATS_URL: nats://nats:4222
|
||
POSTGRES_DSN: postgres://sundynix:${POSTGRES_PASSWORD:?}@postgres:5432/sundynix?sslmode=disable
|
||
REDIS_ADDR: redis:6379
|
||
MINIO_ENDPOINT: minio:9000
|
||
MINIO_ACCESS_KEY: minioadmin # minio 仅 compose 内网可达,不对宿主暴露
|
||
MINIO_SECRET_KEY: minioadmin
|
||
SUNDYNIX_SECRET_KEY: *secret-key
|
||
JWT_SECRET: ${JWT_SECRET:?需在 .env 设置(openssl rand -base64 32)}
|
||
ADMIN_USER_IDS: ${ADMIN_USER_IDS:-}
|
||
CORS_ALLOW_ORIGIN: ${CORS_ALLOW_ORIGIN:-*}
|
||
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4318
|
||
ports: ["${GATEWAY_PORT:-8080}:8080"]
|
||
depends_on:
|
||
postgres: { condition: service_healthy }
|
||
redis: { condition: service_started }
|
||
nats: { condition: service_started }
|
||
|
||
dispatcher:
|
||
build: { context: ., dockerfile: sundynix-dispatcher/Dockerfile }
|
||
image: sundynix/dispatcher:${TAG:-latest}
|
||
restart: unless-stopped
|
||
environment:
|
||
APP_ENV: production
|
||
NATS_URL: nats://nats:4222
|
||
SUNDYNIX_SECRET_KEY: *secret-key
|
||
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4318
|
||
DISPATCHER_CONCURRENCY: ${DISPATCHER_CONCURRENCY:-8}
|
||
TASK_TOKEN_BUDGET: ${TASK_TOKEN_BUDGET:-200000}
|
||
depends_on:
|
||
nats: { condition: service_started }
|
||
|
||
mcp-go:
|
||
build: { context: ., dockerfile: sundynix-mcp-go/Dockerfile }
|
||
image: sundynix/mcp-go:${TAG:-latest}
|
||
restart: unless-stopped
|
||
environment:
|
||
APP_ENV: production
|
||
NATS_URL: nats://nats:4222
|
||
POSTGRES_DSN: postgres://sundynix:${POSTGRES_PASSWORD:?}@postgres:5432/sundynix?sslmode=disable
|
||
REDIS_ADDR: redis:6379
|
||
MILVUS_ADDR: milvus:19530
|
||
NEO4J_URI: neo4j://neo4j:7687
|
||
NEO4J_USER: neo4j
|
||
NEO4J_PASS: ${NEO4J_PASSWORD:?}
|
||
# 报告源/产物 + KB 正文对象存储(blob)——与 gateway 同一 MinIO,勿漏否则 fallback localhost。
|
||
MINIO_ENDPOINT: minio:9000
|
||
MINIO_ACCESS_KEY: minioadmin
|
||
MINIO_SECRET_KEY: minioadmin
|
||
MINIO_BUCKET: sundynix-docs
|
||
SUNDYNIX_SECRET_KEY: *secret-key
|
||
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4318
|
||
# 全文(bleve)索引落盘位置。不设则相对 CWD,写进容器可写层 → 每次重建容器就清零,
|
||
# 而混合检索只是静默少一路召回、不报错,很难发现。必须配合下面的持久卷。
|
||
BLEVE_PATH: /data/bleve
|
||
depends_on:
|
||
nats: { condition: service_started }
|
||
milvus: { condition: service_healthy } # mcp-go 须在 Milvus 后起,否则工具 no responders
|
||
volumes:
|
||
- mcp_go_data:/data
|
||
|
||
mcp-py:
|
||
build: { context: sundynix-mcp-py, dockerfile: Dockerfile }
|
||
image: sundynix/mcp-py:${TAG:-latest}
|
||
restart: unless-stopped
|
||
environment:
|
||
NATS_URL: nats://nats:4222
|
||
# secure_sandbox(代码隔离执行)需访问宿主 Docker 拉起一次性容器。
|
||
# 安全敏感:等于把宿主 Docker 暴露给该服务;不需要代码执行工具可注释掉这行。
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock
|
||
depends_on:
|
||
nats: { condition: service_started }
|
||
|
||
# admin 运维控制台已内嵌进 gateway(go:embed,见 sundynix-gateway/internal/webui),
|
||
# 不再需要单独的 nginx 容器:访问 gateway:${GATEWAY_PORT} 即同时得到控制台 UI + API。
|
||
|
||
# ---------- 基础设施(端口不对宿主暴露,仅 compose 内网) ----------
|
||
nats:
|
||
image: nats:2-alpine
|
||
command: ["-c", "/etc/nats/nats-server.conf"]
|
||
restart: unless-stopped
|
||
volumes:
|
||
- ./deploy/nats/nats-server.conf:/etc/nats/nats-server.conf:ro
|
||
- nats_data:/data/jetstream
|
||
|
||
postgres:
|
||
image: postgres:16-alpine
|
||
restart: unless-stopped
|
||
environment:
|
||
POSTGRES_USER: sundynix
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
|
||
POSTGRES_DB: sundynix
|
||
volumes: ["pg_data:/var/lib/postgresql/data"]
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U sundynix"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 10
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
restart: unless-stopped
|
||
volumes: ["redis_data:/data"]
|
||
|
||
jaeger:
|
||
image: jaegertracing/all-in-one:1.60
|
||
restart: unless-stopped
|
||
environment:
|
||
COLLECTOR_OTLP_ENABLED: "true"
|
||
ports: ["${JAEGER_UI_PORT:-16686}:16686"] # 链路追踪 UI(演示可看 span 瀑布图;不需要可去掉)
|
||
|
||
milvus-etcd:
|
||
image: quay.io/coreos/etcd:v3.5.14
|
||
restart: unless-stopped
|
||
environment:
|
||
ETCD_AUTO_COMPACTION_MODE: revision
|
||
ETCD_AUTO_COMPACTION_RETENTION: "1000"
|
||
ETCD_QUOTA_BACKEND_BYTES: "4294967296"
|
||
ETCD_SNAPSHOT_COUNT: "50000"
|
||
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
|
||
volumes: ["milvus_etcd:/etcd"]
|
||
|
||
minio:
|
||
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
|
||
restart: unless-stopped
|
||
environment:
|
||
MINIO_ACCESS_KEY: minioadmin # 内网专用(不对宿主暴露端口),与 milvus/gateway 默认对齐
|
||
MINIO_SECRET_KEY: minioadmin
|
||
command: minio server /minio_data
|
||
volumes: ["minio_data:/minio_data"]
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||
interval: 30s
|
||
timeout: 20s
|
||
retries: 3
|
||
|
||
milvus:
|
||
image: milvusdb/milvus:v2.4.13
|
||
command: ["milvus", "run", "standalone"]
|
||
restart: unless-stopped
|
||
environment:
|
||
ETCD_ENDPOINTS: milvus-etcd:2379
|
||
MINIO_ADDRESS: minio:9000
|
||
volumes: ["milvus_data:/var/lib/milvus"]
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
|
||
interval: 15s
|
||
timeout: 10s
|
||
retries: 10
|
||
depends_on: [milvus-etcd, minio]
|
||
|
||
neo4j:
|
||
image: neo4j:5-community
|
||
restart: unless-stopped
|
||
environment:
|
||
NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:?}
|
||
volumes: ["neo4j_data:/data"]
|
||
|
||
volumes:
|
||
nats_data:
|
||
pg_data:
|
||
redis_data:
|
||
milvus_etcd:
|
||
minio_data:
|
||
milvus_data:
|
||
neo4j_data:
|
||
mcp_go_data:
|