Answer quality, not just retrieval
Retrieval answers score 0.9593 on groundedness and hallucinate on two thirds of the questions the corpus cannot answer. Both numbers are correct, which is why groundedness alone certifies nothing.
Five interconnected services, independently runnable
Five AI services, each solving a different problem, plus an agent that drives all five as tools. Each runs standalone with its own fitted model and API, and they compose into one system through enrichment edges that degrade rather than fail. Every number below is measured on a held-out split and reproduced by CI — including the ones that came out worse than hoped.
What the measurements say
Retrieval answers score 0.9593 on groundedness and hallucinate on two thirds of the questions the corpus cannot answer. Both numbers are correct, which is why groundedness alone certifies nothing.
Local models drive all five services as tools. Neither beats a keyword router on task success (0.8000 against 0.4250 at 0.5B and 0.6250 at 1.5B). At 0.5B the agent refused 0 of 7 unanswerable questions and fabricated on 2 of 5 tasks whose service was killed mid-run; at 1.5B both failures are gone.
With sales killed while ops serves traffic, p95 goes from 4185 ms with the breaker closed to 74.6 ms once it opens — below the healthy figure, because a skipped call beats a successful one. Every request returned 200 throughout.
Retrieval appeared to peak at concurrency 4 and fall. That was reported as a GIL limit and it was wrong — the event store capped every endpoint. The obvious repair (WAL alone) measured worse than nothing; connection reuse plus WAL was ~5x, and throughput more than doubled. Both readings are kept.
Retrieval compute is 9 cents per million requests; the cheapest LLM answer on top is $1,100, so generation is 12,629x everything underneath it. Doubling throughput moves the bill 0.004%; changing model tier moves it 400%.
Request IDs propagate across process boundaries and are stored beside each event, so one decision reconstructs into a single ordered timeline — 18 hops across 5 services. A service that cannot be reached is named in the output rather than omitted.
Project matrix
Bring the whole stack up with docker compose up from this
repository; each service is then on the port shown. To run one alone,
clone its repository and follow its DEMO.md.
| Project | Problem | Headline result | Real-data track | Tests | Compose port |
|---|---|---|---|---|---|
| Enterprise RAG | Ranking retrieval methods against each other on benchmarks with human relevance judgments. | Dense nDCG@10 0.3727 against BM25's 0.2831 on BEIR/NFCorpus, with a per-query-type breakdown showing where each method wins and loses. | BEIR/NFCorpus — real human relevance judgments. | 93 | :8001 |
| Customer Ops | Deciding what to do about an inbound customer message, auditably. | Intent macro-F1 0.9164 across 77 real customer intents on BANKING77; 0.6476 on held-out synthetic phrasings the model has never seen. | BANKING77 — 13,083 queries real customers sent an online bank. | 92 | :8004 |
| Incident Detection | Finding anomalous service behaviour in telemetry without drowning the on-call in alerts. | Precision 0.7895 with all 17 held-out incidents caught and 32% fewer alerts than the z-score baseline. | Five weeks of real server telemetry, anomalies labelled by operators from actual incident reports. | 77 | :8003 |
| Sales Intelligence | Scoring account renewal propensity with an explanation that reconstructs the score. | Held-out ROC-AUC 0.8614 against a measured Bayes ceiling of 0.8898 — the model recovers most of the signal the generating process actually contains. | 41,188 actual campaign outcomes from the UCI Bank Marketing dataset. | 50 | :8002 |
| Meeting Intelligence | Pulling decisions and action items with owners out of a meeting transcript. | Macro-F1 0.5894 against 0.3235 for the keyword extractor it replaced, on the same held-out data. | AMI Meeting Corpus — 137 recorded meetings with human-annotated decisions and action items. | 67 | :8005 |
Deep dives
Retriever interface — BM25, LSA, a sentence-transformers dense bi-encoder, and reciprocal-rank fusion — with one evaluation harness, a fitted and a pretrained reranker, extractive answer generation with citation spans, and fitted abstention thresholds.GET /health, GET /metrics, GET /v1/query, POST /v1/query, POST /v1/documents, GET /v1/drift — see DEMO.md.GET /health, GET /metrics, POST /v1/decide, POST /v1/events/incident, GET /v1/proactive/outreach, GET /v1/drift — see DEMO.md.IsolationForest fitted on normal traffic only, scoring each minute of per-service metrics against that service's own healthy baseline, with a threshold calibrated to an explicit precision target. Chronological split, episode-level as well as point-level metrics. Anomalies push events to customer operations through an outbox with retries and a dead-letter queue.GET /health, GET /metrics, POST /v1/score, GET /v1/incidents/active, GET /v1/events/outbox, GET /v1/events/dlq, GET /v1/drift — see DEMO.md.StandardScaler into LogisticRegression pipeline, hyperparameters cross-validated on train only, with per-feature attribution that provably reconstructs the model's own output and segment thresholds derived from train-set score quantiles.GET /health, GET /metrics, POST /v1/score, GET /v1/accounts/{id}/score, GET /v1/drift — see DEMO.md.industry) is generated but excluded from training because it is not available at serving time, and that is stated in the model card.GET /health, GET /metrics, POST /v1/analyze, GET /v1/drift — see DEMO.md.Reviewer path
docker compose up from this repository brings all five up.pytest -q, its training script with --verify, and its evaluation script.python scripts/verify_contracts.py --local checks the cross-service contracts against live services.CI evidence
Documentation map
What this does not claim