Files
RAG/compose.yaml
YoVinchen c3bad0f186
Some checks failed
verify / verify (push) Has been cancelled
Make the offline RAG chain observable without widening credential access
Expose the verified synthetic retrieval path through a typed React client and a non-root Nginx edge while keeping database credentials and data-network reachability out of the browser tier. A fixed-origin gateway preserves request boundaries and now closes upstream streams even when downstream disconnects before body iteration. The deployment ADR and runbooks record the four-network topology and its accepted Web edge-egress risk.

Constraint: The previously exposed Bailian key must be revoked and no live provider credential may enter Git, images, logs, or the browser.
Rejected: Connect Web directly to the data network | expands lateral reach to PostgreSQL.
Rejected: Publish the database-aware API on the edge network | gives a credential-bearing process a public default route.
Rejected: Buffer streaming responses in either proxy | prevents incremental chat delivery in the future.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Do not mark Stage 1 or Stage 2 complete until the rotated-key live smoke and remaining stage gates pass.
Tested: make verify; 65 backend tests; 14 frontend tests; Docker image build; container health and isolation probes; real HTTP demo/status/search/docs/OpenAPI checks.
Not-tested: Live Bailian models, real document ingestion, business chat SSE generation, and final browser screenshot automation because the browser skill runtime was unavailable.
2026-07-12 17:38:57 +08:00

265 lines
6.8 KiB
YAML

name: geological-rag
x-runtime-config: &runtime-config
APP_ENV: ${APP_ENV:-development}
APP_NAME: ${APP_NAME:-geological-rag}
POSTGRES_HOST: db
POSTGRES_PORT: "5432"
POSTGRES_DB: ${POSTGRES_DB:-geological_rag}
POSTGRES_USER: ${POSTGRES_APP_USER:-geological_rag_app}
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_app_password
UPLOAD_ROOT: ${UPLOAD_ROOT:-/data/uploads}
MAX_UPLOAD_MB: "${MAX_UPLOAD_MB:-100}"
x-rag-config: &rag-config
DASHSCOPE_API_KEY_FILE: /run/secrets/bailian_api_key
BAILIAN_OPENAI_BASE_URL: "${BAILIAN_OPENAI_BASE_URL:-}"
BAILIAN_NATIVE_BASE_URL: "${BAILIAN_NATIVE_BASE_URL:-}"
BAILIAN_RERANK_BASE_URL: "${BAILIAN_RERANK_BASE_URL:-}"
EMBEDDING_MODEL: ${EMBEDDING_MODEL:-text-embedding-v4}
EMBEDDING_DIMENSION: "${EMBEDDING_DIMENSION:-1024}"
RERANK_MODEL: ${RERANK_MODEL:-qwen3-rerank}
LLM_MODEL: ${LLM_MODEL:-deepseek-v4-flash}
CHUNK_TARGET_TOKENS: "${CHUNK_TARGET_TOKENS:-512}"
CHUNK_MAX_TOKENS: "${CHUNK_MAX_TOKENS:-800}"
CHUNK_OVERLAP_TOKENS: "${CHUNK_OVERLAP_TOKENS:-64}"
VECTOR_TOP_K: "${VECTOR_TOP_K:-50}"
RERANK_TOP_N: "${RERANK_TOP_N:-10}"
CONTEXT_TOP_N: "${CONTEXT_TOP_N:-8}"
MAX_CONTEXT_TOKENS: "${MAX_CONTEXT_TOKENS:-10000}"
MODEL_TIMEOUT_SECONDS: "${MODEL_TIMEOUT_SECONDS:-90}"
MODEL_MAX_RETRIES: "${MODEL_MAX_RETRIES:-3}"
MODEL_MAX_CONCURRENCY: "${MODEL_MAX_CONCURRENCY:-4}"
services:
db:
image: pgvector/pgvector:0.8.2-pg17@sha256:feb68f4f15446397d8cac7f4fe48fe4586de83160d1fc48b46283312d1a33966
environment:
POSTGRES_DB: ${POSTGRES_DB:-geological_rag}
POSTGRES_USER: ${POSTGRES_BOOTSTRAP_USER:-postgres}
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_bootstrap_password
POSTGRES_MIGRATOR_USER: ${POSTGRES_MIGRATOR_USER:-geological_rag_migrator}
POSTGRES_MIGRATOR_PASSWORD_FILE: /run/secrets/postgres_migrator_password
POSTGRES_APP_USER: ${POSTGRES_APP_USER:-geological_rag_app}
POSTGRES_APP_PASSWORD_FILE: /run/secrets/postgres_app_password
secrets:
- postgres_bootstrap_password
- postgres_migrator_password
- postgres_app_password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./ops/postgres/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test:
- CMD-SHELL
- >-
pg_isready -h 127.0.0.1 -p 5432 -U $$POSTGRES_USER -d $$POSTGRES_DB
&& test -f $$PGDATA/.rag-bootstrap-complete
interval: 5s
timeout: 3s
retries: 20
networks:
- data
restart: unless-stopped
migrate:
build:
context: ./backend
command: ["alembic", "upgrade", "head"]
depends_on:
db:
condition: service_healthy
environment:
POSTGRES_HOST: db
POSTGRES_PORT: "5432"
POSTGRES_DB: ${POSTGRES_DB:-geological_rag}
POSTGRES_USER: ${POSTGRES_MIGRATOR_USER:-geological_rag_migrator}
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_migrator_password
secrets:
- postgres_migrator_password
networks:
- data
restart: "no"
api:
build:
context: ./backend
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
depends_on:
db:
condition: service_healthy
migrate:
condition: service_completed_successfully
environment: *runtime-config
secrets:
- postgres_app_password
networks:
- data
healthcheck:
test:
- CMD
- python
- -c
- >-
import urllib.request;
urllib.request.urlopen('http://127.0.0.1:8000/health/ready', timeout=2)
interval: 10s
timeout: 3s
retries: 5
start_period: 5s
init: true
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
restart: unless-stopped
gateway:
build:
context: ./backend
command: ["uvicorn", "app.gateway:app", "--host", "0.0.0.0", "--port", "8000"]
depends_on:
api:
condition: service_healthy
networks:
- ingress
- data
healthcheck:
test:
- CMD
- python
- -c
- >-
import urllib.request;
urllib.request.urlopen('http://127.0.0.1:8000/health/ready', timeout=2)
interval: 10s
timeout: 3s
retries: 5
start_period: 5s
init: true
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
restart: unless-stopped
web:
build:
context: ./frontend
depends_on:
gateway:
condition: service_healthy
ports:
- "127.0.0.1:8000:8080"
networks:
- edge
- ingress
healthcheck:
test:
- CMD
- wget
- --quiet
- --output-document=-
- http://127.0.0.1:8080/nginx-health
interval: 10s
timeout: 3s
retries: 5
start_period: 5s
init: true
user: "101:101"
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=16m,uid=101,gid=101,mode=1770
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
restart: unless-stopped
provider-smoke:
build:
context: ./backend
command: ["python", "-m", "app.tools.provider_smoke"]
profiles: ["tools"]
environment: *rag-config
secrets:
- bailian_api_key
networks:
- egress
restart: "no"
seed-demo:
build:
context: ./backend
command: ["python", "-m", "app.tools.seed_demo"]
profiles: ["tools"]
depends_on:
migrate:
condition: service_completed_successfully
environment:
<<: [*runtime-config, *rag-config]
DEMO_PROVIDER_MODE: bailian
DEMO_DOCUMENTS_PATH: /demo/demo_documents.jsonl
DEMO_QUERIES_PATH: /demo/demo_queries.jsonl
secrets:
- postgres_app_password
- bailian_api_key
networks:
- data
- egress
volumes:
- ./data/samples/public:/demo:ro
restart: "no"
seed-demo-offline:
build:
context: ./backend
command: ["python", "-m", "app.tools.seed_demo"]
profiles: ["tools"]
depends_on:
migrate:
condition: service_completed_successfully
environment:
<<: *runtime-config
DEMO_PROVIDER_MODE: fake
DEMO_DOCUMENTS_PATH: /demo/demo_documents.jsonl
DEMO_QUERIES_PATH: /demo/demo_queries.jsonl
secrets:
- postgres_app_password
networks:
- data
volumes:
- ./data/samples/public:/demo:ro
restart: "no"
volumes:
postgres_data:
networks:
edge:
driver: bridge
ingress:
driver: bridge
internal: true
data:
driver: bridge
internal: true
egress:
driver: bridge
secrets:
postgres_bootstrap_password:
file: ./secrets/postgres_bootstrap_password
postgres_migrator_password:
file: ./secrets/postgres_migrator_password
postgres_app_password:
file: ./secrets/postgres_app_password
bailian_api_key:
file: ./secrets/bailian_api_key