Some checks failed
verify / verify (push) Has been cancelled
The API and ingestion tools now use a fixed internal model gateway while governed profiles, embedding cache assignments, traceable citations, and stable API errors establish the boundaries required by later workflows. Constraint: The current Alibaba Cloud workspace rejects all three live model calls with authentication failures Rejected: Give the API or seed tools the Bailian key and direct egress | combines database access, cloud credentials, and public network access Rejected: Mix offline and Bailian vectors in one demo namespace | makes profile activation and retrieval ambiguous Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep Bailian credentials and egress exclusive to model-gateway and create a new immutable profile hash for any embedding identity change Tested: make verify; 121 backend tests; 14 frontend tests; fresh and populated Alembic upgrade-downgrade-upgrade; two idempotent offline seeds; Docker health and HTTP retrieval; isolated provider smoke Not-tested: Successful live Bailian responses because the supplied workspace credential currently fails authentication
332 lines
8.8 KiB
YAML
332 lines
8.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}"
|
|
|
|
x-model-client-config: &model-client-config
|
|
MODEL_GATEWAY_BASE_URL: http://model-gateway:8000
|
|
MODEL_GATEWAY_TOKEN_FILE: /run/secrets/model_gateway_api_token
|
|
MODEL_GATEWAY_CALLER: api
|
|
MODEL_GATEWAY_TIMEOUT_SECONDS: "${MODEL_GATEWAY_TIMEOUT_SECONDS:-120}"
|
|
|
|
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
|
|
model-gateway:
|
|
condition: service_healthy
|
|
environment:
|
|
<<: [*runtime-config, *model-client-config]
|
|
secrets:
|
|
- postgres_app_password
|
|
- model_gateway_api_token
|
|
networks:
|
|
- data
|
|
- model
|
|
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
|
|
|
|
model-gateway:
|
|
build:
|
|
context: ./backend
|
|
command: ["uvicorn", "app.model_gateway:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
environment:
|
|
<<: *rag-config
|
|
MODEL_GATEWAY_ALLOWED_TOKEN_FILES: >-
|
|
api=/run/secrets/model_gateway_api_token,worker=/run/secrets/model_gateway_worker_token
|
|
secrets:
|
|
- bailian_api_key
|
|
- model_gateway_api_token
|
|
- model_gateway_worker_token
|
|
networks:
|
|
- model
|
|
- egress
|
|
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"]
|
|
depends_on:
|
|
model-gateway:
|
|
condition: service_healthy
|
|
environment:
|
|
<<: *model-client-config
|
|
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}
|
|
secrets:
|
|
- model_gateway_api_token
|
|
networks:
|
|
- model
|
|
restart: "no"
|
|
|
|
seed-demo:
|
|
build:
|
|
context: ./backend
|
|
command: ["python", "-m", "app.tools.seed_demo"]
|
|
profiles: ["tools"]
|
|
depends_on:
|
|
migrate:
|
|
condition: service_completed_successfully
|
|
model-gateway:
|
|
condition: service_healthy
|
|
environment:
|
|
<<: [*runtime-config, *rag-config, *model-client-config]
|
|
DEMO_PROVIDER_MODE: bailian
|
|
DEMO_DOCUMENTS_PATH: /demo/demo_documents.jsonl
|
|
DEMO_QUERIES_PATH: /demo/demo_queries.jsonl
|
|
MODEL_GATEWAY_TOKEN_FILE: /run/secrets/model_gateway_worker_token
|
|
MODEL_GATEWAY_CALLER: worker
|
|
secrets:
|
|
- postgres_app_password
|
|
- model_gateway_worker_token
|
|
networks:
|
|
- data
|
|
- model
|
|
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
|
|
model:
|
|
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
|
|
model_gateway_api_token:
|
|
file: ./secrets/model_gateway_api_token
|
|
model_gateway_worker_token:
|
|
file: ./secrets/model_gateway_worker_token
|
|
bailian_api_key:
|
|
file: ./secrets/bailian_api_key
|