Inspiration

Every minute a paramedic spends on hold with a hospital switchboard is a minute a critical patient isn't receiving treatment. Emergency dispatch today is still built on phone calls, spreadsheets, and radio coordination — manual processes that introduce dangerous latency at exactly the moment it matters least. We wanted to see whether an autonomous agent pipeline, not a chatbot, could actually remove that latency: take a case, reason over it, and make a real dispatch decision, end to end, with zero human phone calls in the loop.

What it does

LifeLine Agent takes an incoming emergency case and:

  • Computes a real clinical triage score (NEWS2, the Royal College of Physicians' public early-warning formula) from patient vitals — grounding the AI's reasoning in an actual clinical number instead of letting it guess severity from raw vitals alone.
  • Reasons over that score with Gemini to determine severity and the required medical specialty.
  • Matches the patient to the best available hospital using real hospital locations and real driving ETAs, not just "nearest facility."
  • Writes an immutable, timestamped audit record of every decision the pipeline made, so the whole chain of reasoning is traceable after the fact.

The result: a dispatch decision in seconds, with a full, auditable trail — instead of a paramedic waiting on hold.

How we built it

Agent architecture. Rather than one flat chain of LLM calls, we structured the pipeline in three levels using Google ADK:

  • A thin top-level orchestrator (SequentialAgent) that sequences everything but does no domain reasoning itself.
  • Mid-level coordinator agents — one per capability (triage, bed-matching, reporting) — each wrapping a LoopAgent so the system can retry, re-rank, or refine instead of failing outright. The Bed-Matching coordinator, for example, loops through ranked alternatives if its first choice turns out to have no available bed, rather than dead-ending.
  • Leaf agents that each make exactly one focused Gemini call and hand back a structured, schema-validated result.

We used Genkit to define and version each leaf agent's prompt independently of the ADK orchestration logic, which made it much easier to trace exactly what each level of the hierarchy was doing during testing.

Grounding over guessing. Deterministic tools — the NEWS2 formula, hospital location lookups (OpenStreetMap Overpass API), and driving-route data (OSRM) — do the factual work, and agents only reason over the results those tools return. NEWS2 aggregates seven physiological sub-scores into a single risk-banded number:

$$ \text{NEWS2} = \sum_{i=1}^{7} s_i, \quad s_i \in {0,1,2,3} $$

with roughly $0\text{–}4$ mapping to low risk, $5\text{–}6$ to medium, and $\geq 7$ to high risk. The Triage Agent never computes this itself — it receives the number and reasons over it, e.g.:

def triage_input(case: PatientCase) -> TriagePrompt:
    news2 = compute_news2(case.vitals)          # deterministic, no LLM
    return TriagePrompt(case=case, news2_score=news2)

This kept outputs grounded instead of hallucinated: a NEWS2 score of 12 always maps to "critical," because the agent is reasoning over a real, pre-computed number, not inventing one.

LifeLine Agent architecture diagram

Stack. FastAPI on Cloud Run serves the pipeline; every case and every agent decision is written to Cloud Firestore as an audit record. The frontend is React + Vite (TypeScript), restructured around role-based views — a hospital operations console, a government/oversight dashboard, and a lightweight donor-facing app — behind a shared login, rather than one dashboard with everything crammed onto a single screen.

Challenges we ran into

  • Free public APIs are demo-day fragile. The Overpass and OSRM endpoints we rely on for real hospital and routing data are unmetered public instances with no uptime guarantee — we cache results locally immediately after the first successful pull so the demo doesn't depend on their availability at judging time.
  • Making failure a feature, not a crash. An emergency system can't silently break. We built explicit fallback paths for every agent — if the Triage Agent's call times out, the pipeline falls back to the raw NEWS2 score with a "needs human review" flag instead of stalling; if Bed-Matching exhausts its alternatives, it falls back to a simple non-AI nearest-hospital heuristic, clearly labeled as such. Every fallback is written to the audit log the same way a normal decision is — a fallback is a recorded decision path, not a hidden failure.
  • Keeping scope honest. It was tempting to keep adding features mid-build. We kept a running decision log documenting every locked choice (model, framework, data source, scope boundary) so the whole team — and every AI coding session — stayed in sync instead of quietly diverging.
  • Coordinating parallel workstreams under a deadline. With frontend, backend, data, and deploy work happening at the same time, we locked a single shared interface contract (exact API shapes, Firestore schema, role definitions) before any of it started, so the pieces could be built independently and still fit together at integration time.

What we learned

  • Giving an LLM a real clinical formula to reason over, instead of asking it to assess severity from raw numbers directly, meaningfully reduces hallucinated judgments.
  • ADK's LoopAgent pattern is a clean way to express "try again, try an alternative, or fall back" without hand-rolling retry logic in application code.
  • An audit trail is only as trustworthy as its coverage of failure paths — logging successes but not fallbacks would have left exactly the gaps a real compliance reviewer would ask about.

What's next

Real-time bed availability would require direct HL7/FHIR integration with hospital EHR systems — out of scope for a hackathon build, but the natural next step. We'd also want a human-in-the-loop confirmation step before a dispatch is finalized in any production setting, live ambulance telemetry instead of preset scenarios, and support for coordinating across multiple hospital networks during mass-casualty events.

Built With

  • cloud-firestore
  • fastapi
  • firebase-authentication
  • gemini-3.1-pro
  • gemini-3.5-flash
  • genkit
  • google-adk
  • google-cloud-run
  • news2
  • openstreetmap
  • osrm
  • overpass-api
  • pydantic
  • python
  • react
  • tailwindcss
  • typescript
  • vite
  • web-speech-api
Share this project:

Updates

Submission history