Ask hard questions
of healthcare denials.
ClaimsRAG Pro is a production-oriented RAG pipeline over claim-denial data. An agentic router sends each question to hybrid vector retrieval or a GraphRAG knowledge graph, self-reflects when confidence is low, and answers only from grounded evidence. This page is an interactive simulation of that system.
A miniature data platform for denial analytics
Not a single-row lookup tool. The engine is always running: claims stream through and pulse the bars in real time. Cross-filter the live dataset by reason, department, payer, and status, watch it re-process, inspect the matching claims, and flag any for human review. It's the same grounded aggregation the pipeline runs to answer questions.
Reason distribution
click to filtermatching claims
showing 9 of 300, ⚑ flags a claim for review
Continuous ingestion
A watchdog daemon validates each new CSV, de-dupes on claim_id, and rebuilds the vector + graph indexes.
GraphRAG
A NetworkX graph links payers, departments, statuses, and denial reasons for multi-hop reasoning.
Agentic routing
A heuristic (optionally LLM) router sends each question to the vector or graph engine.
Self-reflective retrieval
On low confidence it rewrites the query with extracted constraints and retries via the graph.
Async batch
An asyncio runner answers large question sets concurrently with latency metadata.
From a raw CSV to a grounded answer
Watch one question travel the whole system: a new file is ingested and validated, de-duplicated, then routed. Hybrid retrieval runs first, and when its confidence is low, the agent reflects, rewrites the query, and falls back to the graph before synthesizing an answer that cites only real rows.
- 01 Continuous ingestion rebuilds both indexes on every new file.
- 02 The agentic router chooses vector or graph per question.
- 03 Self-reflection catches weak retrievals instead of hallucinating.
- 04 Answers are deterministic and grounded in evidence.
Live pipeline · a question's journey
“Why are cardiology claims denied most often?”
A new claims file lands; the daemon picks it up automatically. No manual trigger.
The denial embedding space
Every dot is a real claim, positioned by its embedding. Semantically similar claims sit together and cluster by department. Ask a question; its vector lands in the space, a radar sweep fires, and curved arcs trace the nearest neighbors the retriever hands to the synthesizer.
query vector
Why are cardiology claims denied?
retrieved · nearest 6
- [1]C000068 · Duplicate claimPending0.10
- [2]C000177 · Coding errorDenied0.28
- [3]C000097 · Medical necessityPaid0.34
- [4]C000119 · Expired coveragePending0.62
- [5]C000114 · Out of networkAppealed0.73
- [6]C000251 · Duplicate claimPaid1.01
grounded answer
Nearest neighbors in Cardiology are dominated by “Duplicate claim” (6 of 37 · 16%).
Distances are true Euclidean nearest-neighbor over the embedding. Production swaps this for dense vectors (BGE / E5) in a FAISS / HNSW index, fused with BM25 via RRF.
The payer knowledge graph
Vector search can't answer “how are these connected?”. The graph index links every payer to the departments it sees denials in and the reasons behind them. Pick a payer; click a department to traverse the multi-hop path PAYER → DEPARTMENT → REASON.
payers
click a department node
Aetna sees denials across 5 departments; leading reason overall is “Bundled service”. Click a department to traverse deeper.
Interrogate the denials
The same pipeline, at your fingertips. Ask in plain English; watch the router pick an engine, reflect when unsure, and answer from real rows. Nothing is invented; every number is recomputed live.
Grounded is not enough. It has to be safe.
Claims data is PHI. ClaimsRAG is offline-first: identifiers are de-identified before anything reaches a model, every answer passes input and output guardrails, quality is measured by evals, and the data never leaves your network perimeter. Explore each control below.
3 PHI fields tokenized or generalized before the model. The reversible mapping lives only in your vault; the model answers from de-identified context and never sees raw identifiers.