Build a domain RAG (legal, medical)
CiteNexus is built for domains where a wrong answer is worse than no answer — legal, medical, finance, compliance. The recipe is the same across them: cite or abstain, and prove it on a golden set that rewards abstention.
-
Curate authoritative sources. Ingest the documents you’d actually cite — a statute, a clinical guideline, a policy PDF — not the open web. Idempotent ingest (bulk) means you can re-run as the corpus grows.
for path in guideline_pdfs:rag.ingest(str(path), document_id=path.stem) -
Keep strict mode. It’s the default, and it’s the guarantee — the answer is generated only from retrieved passages and every claim is verified against its citation (what that check actually proves). For a regulated surface, do not drop to
normal/exploratory.response = rag.ask("What is the maximum pediatric dose of drug X?") # strictif response.evidence.decision.value == "answered":src = response.sources[0]print(response.answer, "—", src.document, "p.", src.page) # cite the exact passageelse:print("abstained:", response.answer) # no dosage invented -
Inject your models. Any OpenAI-compatible embedding + LLM (+ reranker, + vision for figures). Keep it local (Ollama) for data-residency, or use a hosted endpoint — see custom endpoints & auth.
-
Prove it with a golden set — and assert the refusals separately.
evaluate()scores the answerable rows: put the text you expect quoted in theexpectedcolumn and readgroundedness_rate,citation_rateandexpected_support_rate.question,expected"What notice must a CA landlord give a >1yr month-to-month tenant?","60"Must-refuse rows do not belong in that CSV. A blank
expectedis scored as supported only when the row was answered, so a correct refusal lowersexpected_support_raterather than raising it. Assert abstention directly instead:from citenexus.answer.result import Decisionmust_refuse = ["What is the maximum security deposit under this statute?"]for q in must_refuse:assert rag.ask(q).evidence.decision is Decision.refused, q
The order those guards run in matters for a regulated surface — grounding first, then the authority floor, then the per-claim gate, and no stage can promote what an earlier one rejected. How it works lays the pipeline out stage by stage.
A real, measured example: law
Section titled “A real, measured example: law”The law worked example is exactly this recipe on California landlord–tenant law, run live against Jina + Gemini: 100% groundedness and citation, zero fabricated answers across an 11-question golden set — versus the 17–33% hallucination rate reported for generic legal RAG (Stanford RegLab, 2024, cited as context). It also shows the honest failure mode to watch for.
That is a single live run against a generator that is not reproducible at temperature 0 — an identical re-run moved the rate metrics by a question. The safety metrics (100% groundedness, 100% citation, 0 out-of-jurisdiction citations) held across both. Treat the rates as illustration and the safety numbers as the result.
Medical, specifically
Section titled “Medical, specifically”The same shape applies: ingest the guideline / formulary / label, keep strict mode
so a dose or contraindication is only ever quoted from the source (never
synthesized), cite the exact page, and keep a separate list of “not in the
guideline” questions asserted against Decision.refused — abstention has to be
measured outside evaluate(). In any supported script,
answers come back in the clinician’s language while the citation stays verbatim
in its own language, so an English answer can carry a non-English quote — see
languages.