Every chat request passes through thirteen stages. The model call is stage 8 and 9.
Stages 1 through 4 run Presidio and spaCy over the prompt. SSNs, account numbers, names, emails, dates, phone numbers, IP addresses. Each match becomes an opaque token like <SSN_x123>. The mapping goes into an encrypted vault. The provider only ever sees tokens. If redaction fails, the request is rejected. There is no bypass flag.
Stage 5 scores risk on a 0.0 to 1.0 scale. Stage 6 classifies complexity as LOW, MID, or HIGH from entity density, regulatory keywords, and prompt length. Stage 7 assembles the system prompt: guardrails plus user profile.
The guardrails are hard-coded. EchelonAI refuses credit decisions. It refuses to use protected attributes under Reg B / ECOA. It flags geographic proxies such as ZIP codes and census tracts. For ambiguous queries it asks a clarifying question instead of blocking outright. Loan decision support is advisory. Humans decide.
Stage 10 scans the response for guardrail violations. Stage 11 checks the risk score. Anything above 0.6 goes to a principal review queue and the caller gets a 202. A compliance officer approves or denies, and that action is logged too.
Stage 12 writes the audit row. PostgreSQL triggers block UPDATE, DELETE, and TRUNCATE on compliance_audit_log. Redacted prompts are encrypted with AES-256-GCM, so plaintext is never persisted. A weekly job verifies the HMAC chain. Retention is six years.
Routing runs OpenRouter first, with Qwen 2.5 7B, Claude Haiku, and Claude Sonnet mapped to the three tiers. Azure OpenAI and a local Ollama model are optional fallbacks. The circuit breaker opens after 3 consecutive failures or latency over 5 seconds. Every cloud call carries X-OpenRouter-ZDR: true, and that header cannot be turned off. Ollama never leaves the box.
Celery Beat runs a daily disparate impact snapshot that compares approval rates across cohorts and alerts on variance above 10%. Examiners get a read-only forensic view. Their queries are logged separately.
The stack is FastAPI, async SQLAlchemy, PostgreSQL 16, Redis, and a React frontend. It runs on the bank’s infrastructure. A 59-check smoke test covers the pipeline end to end.