CareFinder
Independent project · Aug 2026
An agentic triage system that tells uninsured patients where to go and what it will cost — before they leave home.
The Problem
If you are uninsured in the United States and wake up with a fever, you face two questions and can answer neither: where should I go, and what will it cost me.
Getting the first wrong is expensive in both directions. Under-triage risks harm. Over-triage costs money you do not have:
- Retail clinic — roughly $60–100
- Urgent care — roughly $150–250
- Emergency room — $1,200 or more, for the same complaint
The gap between the cheapest correct answer and the most cautious one is most of a month's rent. Which is why so many people default to the ER: it is open, it cannot turn you away, and it is the single most expensive door in American healthcare.
Getting the second question wrong is why people skip care entirely.
What It Does
Four inputs — age, gender, symptoms in plain language, ZIP code. No insurance questions, because the users this is built for do not have any. It returns what level of care the presentation warrants, real facilities that can provide it, and what each one charges a self-pay patient.
Telehealth options sit alongside the mapped results. They are geography-independent and often the cheapest correct answer — particularly in rural areas where the nearest clinic is forty minutes away.
Live output: 22F, fever 103°F, Manhattan KS. Three real clinics from OpenStreetMap, mapped, each priced for the labs the clinical model identified — $135–$350 at one, $275–$550 at another 0.6 miles away. Four telehealth options below at $35–$99.
How It Works
Two models with different jobs. MedGemma 27B, a medical-domain model running on Vertex AI, makes the clinical calls. A Gemini Flash orchestrator coordinates the tools around it.
The emergency gate sits outside the orchestration graph and can exit to 911 on its own — no downstream failure can swallow it. Everything after runs as a LangGraph cycle whose review step can send work back, bounded at two retries.
The Decision That Shapes Everything
A fabricated price is worse than no price. For someone deciding whether they can afford to be seen, an invented number is not a helpful approximation — it is misinformation that changes a health decision.
So the system never estimates locally. If a price cannot be retrieved, the interface says price not available. If nothing is found nearby, it says so rather than filling the gap. Every displayed figure carries the basis it was retrieved on.
This mattered. An earlier version returned invented prices whenever an API key was missing or a request failed, and synthetic clinics — "Local Hospital ER" — whenever a search came back empty. Neither was distinguishable from real data in the output.
Why a Model Had to Do the Filtering
The first version routed deterministically in Python, which kept clinical judgement in one place and made the system auditable. It broke on real data.
OpenStreetMap has no reliable "this is an urgent care" tag. The tag that exists, healthcare=urgent_care, returns zero results in both Manhattan NY and Manhattan KS. A proximity search therefore returns every medical feature nearby, and a keyword filter cannot tell a walk-in clinic from a chiropractor, a medspa, or a paediatric practice.
A model can. Given the patient and the candidates, Flash rejects them with reasons:
Pediatric Associates: Pediatric specialty practice that does not treat adult patients.
That is judgement about the patient's age against the facility's scope, and no keyword list produces it. The guarantee stays in code rather than trust — the orchestrator can only keep facilities that were passed to it. It rejects; it cannot invent.
Evaluation
Two full cycles over 20 cases against a live MedGemma 27B endpoint, with an independent audit recomputing every coordinate and tracing every price back to the text it came from.
Care-level accuracy 14/20. Cases differing between two identical runs at temperature 0.1: 0/20. Hallucinated facilities and hallucinated prices across 40 case-runs: zero. Under-triage errors: zero.
Because the model is effectively deterministic on this set, 70% is a property of the prompt rather than of sampling noise — re-running will not improve it, and the six failures are reproducible targets.
| Care level | Score | Failure direction |
|---|---|---|
| Emergency | 5/5 | — |
| Urgent care | 5/5 | — |
| Home care | 4/5 | one escalated to retail clinic |
| Retail clinic | 0/5 | all five escalated to urgent care |
Every error was over-triage — clinically safe, and financially backwards for exactly the person this is built for. Pink eye, UTI, strep, ear infection and a rash all went to urgent care, and those are the canonical retail-clinic presentations. A system that always says "urgent care" has stopped answering the question it exists to answer. That finding reshaped the roadmap rather than being quietly dropped.
Engineering Notes
- Structured output from the API, not a parser. Pydantic models are passed to Gemini as
response_schema, so malformed output is not possible. LangChain's prompt-based parsers were evaluated and dropped. - LangGraph rather than a chain. The review node sends work back to pricing. That is a cycle, and chains are acyclic.
- The review node is the evaluation instrument. It already reasons about whether an answer is complete, so its findings are the analysis — logged per case, in production, for free.
- 141 tests, all offline. No credentials, no endpoint, no network. Dependencies are injected throughout.
- A failed safety check is not a clear result. The gate returns three states, and the third one never proceeds.
Marginal cost is about $0.11 per query, of which search grounding is 97% — so the lever that matters is how many facilities get priced, not token spend.
Source and full write-up on GitHub →
A research prototype. Not a medical device, not clinically validated, and not medical advice.