Arbiter AI
Arbiter answers questions about clinical documents with citations, and it is built around one rule enforced in code: nothing reaches a model until the document is marked de-identified. It is a prototype tested on synthetic records only. No real patients, no customers, no compliance claim. Code: github.com/yoonbo1/arbiterai. Research and the agent's rules: arbiterai.tech.
November 2026: a policy-bound agent and a research hub
- An agent that runs under a written policy. It answers questions about one patient's records with a closed set of tools: search, read structured facts, answer with a citation, or hand off to a person. 23 rules in one versioned file govern it, each citing the HIPAA section, state law (California AB 3030, SB 1120, SB 503; Colorado HB 26-1139) or Arbiter finding behind it, plus the tests that prove it. Code enforces them at seven points, from startup to release. Every audit row records the policy version and the rules that fired, never content.
- What it refuses. Marketing use, tenants without a BAA, psychotherapy notes and substance-use records without consent, coverage or medical-necessity decisions, and patient messages that don't name a state. California patients get the AI disclosure the law requires. 8 of 8 policy scenarios pass on a local 7B model, and 319 tests pass.
- Fixing a finding instead of the model. The groundedness judge scored correct negations 0.00, exactly like fabrications. Splitting answers into positive and negative claims, and checking negations against the source, fixed it. Correct answers now pass or are restated as "not documented", and wrong ones are still rejected.
- Changes go through a person. A research routine reads new laws and results every two to three days and proposes rule changes with evidence. Nothing merges without me; two proposals so far became policy 1.1.0.
- Practices other builders can adopt. The findings are published as 15 safe practices for AI agents on health data, available as AGENTS.md, a Claude skill, a system prompt, JSON and a standalone Python policy kit (arbiterai.tech/practices).
- A research hub. Sourced reads with charts and data, such as the HTI-5 model-card rollback and the 46 AI and privacy duties starting on 1 January 2027, plus a law tracker of 95 start dates each verified in the primary text.
- Weaknesses I publish. The planner sometimes escalates questions the record could answer. The release gate fails until the 346-question eval runs on the full stack.
How it works
- FastAPI gateway, Redis Streams, LangGraph workers, Postgres with pgvector.
- Documents are scrubbed with Presidio before indexing. The map back to the original identifiers is encrypted per tenant, never stored in the vector index, and used only at the last step for the caller's own patient.
- Hybrid retrieval scoped to tenant and patient: pgvector cosine over bge-small embeddings fused with BM25 by reciprocal rank fusion.
- Every answer is checked before it's returned. It's rejected on an identifier leak, a missing citation, or a faithfulness score below 0.7.
Results on the synthetic set
- De-identification recall went from 0.967 to 1.000 on a strict per-component metric. The first metric matched whole strings and hid ZIP codes surviving in 14 of 20 documents.
- Answer accuracy went from 23/40 to 38/40 in four measured iterations. The two misses are OCR misreads the model copied faithfully.
- Zero cross-patient leaks. p50 3.6 s, p95 4.1 s.
- A power analysis showed 40 questions couldn't resolve differences under about 15 points, so the gold set grew to 346 questions.
What testing found
- Presidio's defaults missed labelled MRNs and phone numbers with extensions, and its date filter removed "daily" and "nightly" from medication lists. Custom recognizers fixed each one, including OCR-tolerant MRN labels after Tesseract read "MRN:" as "MAN:".
- The services were connecting as the Postgres superuser, which bypasses row-level security entirely. Now they connect as an RLS-bound role, and cross-tenant probes prove it: another tenant's job returns 404, zero rows are visible, and inserts are rejected.
- The output leak check used a looser threshold than the input scrub, so a bare SSN redacted on the way in could pass on the way out. One threshold now applies in both directions.
- 62 passing tests across auth, de-identification and retrieval. A tenant can't process anything until its BAA is marked signed.
Write-up: What I learned de-identifying clinical documents for an LLM