# apps/ai-service configuration — every setting is a field on `Settings` in # config.py, which is the authority. Copy to `.env` and edit. # # cp apps/ai-service/.env.example apps/ai-service/.env # # Values shown are the CODE DEFAULTS from config.py unless marked otherwise. # Production uses `.env.prod`, which is gitignored and lives on the host. # Never commit a real secret to this file. # # Reference: docs/15-configuration.md # ─── Operating mode ────────────────────────────────────────────────────────── # These three decide which runtime graph bootstrap.py builds. See # docs/10-rag-orchestration.md. # `cohere-v4` = semantic query embedding against the corpus's own vector space # (needs live AWS Bedrock). # `disabled` = no retrieval at all. /ready still returns 200 but # POST /v1/rag/query returns 503. This is the setting the test # suite uses. # No other value is accepted — bootstrap.py raises at startup. EMBEDDING_PROVIDER=disabled # `disabled` = retrieval-only, single-turn, verbatim source quotes. # No RagAgent, no query understanding, no multi-turn. # `stub` = runs the whole answer path (prompt, schema parsing, # grounding, fallback) with NO cloud call. # `bedrock-converse` = DeepSeek / Qwen / GLM / Nova via the Converse API. # `bedrock-claude` = Anthropic via the Messages path. ANSWER_PROVIDER=disabled # Bedrock model id for the generation/understanding/entailment calls. ANSWER_MODEL_ID=deepseek.v3.2 # ─── Vector store ──────────────────────────────────────────────────────────── QDRANT_URL=http://localhost:6333 QDRANT_COLLECTION=duocthu_v1 # Only needed for a Qdrant instance that requires auth. SECRET. # QDRANT_API_KEY= # Must match the `dimensions` recorded in the `__manifest` sidecar, # or startup fails with ManifestMismatch and the process does not come up. EMBEDDING_DIMENSIONS=1024 # Score floor for the dense routes only. The deterministic section route is an # exact payload match and never compares against this. EVIDENCE_MINIMUM_SCORE=0.12 # ─── PostgreSQL ────────────────────────────────────────────────────────────── # Retrieval traces, conversation turns, answer feedback. All three writes are # fail-open: an outage degrades memory/tracing, never an answer. SECRET. POSTGRES_DSN=postgresql://duoc_thu:duoc_thu@localhost:5432/duoc_thu # ─── AWS ───────────────────────────────────────────────────────────────────── # Credentials come from the standard boto3 chain — in production, the EC2 # instance's IAM role. Do NOT put AWS keys in this file. AWS_REGION=us-east-1 # Optional cross-encoder rerank (cohere.rerank-v3-5:0) on the similarity / # overview fallback. Fail-open. The section route never reranks. RERANK_ENABLED=false # ─── Per-request budget ────────────────────────────────────────────────────── # Checked BETWEEN provider calls; it cannot cancel a call already in flight # (that is bounded by read_timeout=20 in adapters/bedrock_converse.py). The # browser timeout in ChatPanel.tsx is derived from these — raising them without # raising that will make the client give up first. MAX_WALL_CLOCK_MS=40000 MAX_LLM_CALLS_PER_TURN=8 # ─── Drug catalog ──────────────────────────────────────────────────────────── # Defaults to a repo-relative path resolved from config.py. The container image # flattens apps/ai-service/ into its own root, so that default is wrong there # and .env.prod must set this explicitly (the Dockerfile bakes the file in): # ENTITIES_PATH=./ingestion_data/drug_entities.json # ─── Observability ─────────────────────────────────────────────────────────── METRICS_ENABLED=true # Optional bearer token for GET /metrics. Empty = unauthenticated, which is the # current production setting and is only safe because ai-service publishes no # host port and Caddy proxies only `web`. SET THIS before exposing the service # through an Ingress — metrics carry query volumes, provider failure counts and # abstain reasons. SECRET. METRICS_TOKEN= # Opt-in so a deployment with no collector keeps answering. The Docker and # Kubernetes observability profiles turn this on. OTEL_ENABLED=false OTEL_SERVICE_NAME=ai-service OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces OTEL_SAMPLE_RATIO=1.0 # ─── Misc ──────────────────────────────────────────────────────────────────── APP_NAME=vsf-duoc-thu-ai-service # Label only; also sent as `deployment.environment` on the OTel resource. ENVIRONMENT=local