Phlebtrax.ai

A constraint-aware routing engine

One thousand patient draws to plan. Eleven constraints to honour per assignment. A four-hour planning window collapsed into minutes. A STAT walk-in re-routed in under thirty seconds. And the whole thing has to be auditable, three years from now, by a person who wasn't there.

020103Depot040908070506STATre-routeOR-Tools VRPTW · 2-opt
Industry
Home phlebotomy · mobile clinical services
Built
2025 · phased AI maturity in production
Stack
OR-Tools VRPTW · K-Means · OSRM · XGBoost · PostgreSQL
Team
3 engineers · 14 weeks to first production cohort
40%
Reduction in total fleet kilometres driven · the bar to beat was 25%
2.5min
To plan 1,000 orders — from 2-4 hours of manual planning
30s
End-to-end STAT re-optimization · vs 15-30 minutes manual
95%
Reduction in map-API spend · OSRM-primary hybrid distance

Every number measured against the manual baseline that the operations team used before. No demo-mode comparisons.

Routing is NP-hard. Most field-services teams plan it by hand.

A typical metro home-phlebotomy operation has thirty technicians, a thousand draws a day, and an operations lead who arrives at 5am to plan the routes on a whiteboard. They are tracking fasting windows, PT/INR peak-trough windows, specimen-stability drop-off deadlines, certification levels, equipment compatibility, contiguity, and the rest. The plan is finished by 7am. Five technicians call in sick. Three patients walk off. Two specimens hit their stability cliff. One STAT comes in from the hospital. The whiteboard is wrong by 8am.

The off-the-shelf dispatch software does not understand any of this. It treats a draw like a pizza order — distance and time, nothing else. So the operations lead patches it manually, and the engineering team builds an "AI routing" feature next quarter. We were called when the next quarter became this quarter.

What we found on day one

No "route" object
Orders carried a tech ID. Whether anybody could actually execute the sequence was a question the system could not ask.
No constraint vocabulary
Fasting, PT/INR, specimen stability, certifications — all of it lived in the operations lead's head.
No audit trail
Why was Tech 02 sent to Beacon Hill at 09:14? "Because that's where the operations lead put them." Cannot be defended to a regulator. Cannot be improved.
No recovery
Patient walk-off, vehicle breakdown, traffic incident — every disruption was a phone call back to the operations lead.
Map-API bill out of control
Distance matrix calls to Google Maps with no caching, run on every re-plan. $80–$200 a day, climbing as orders grew.

Five stages. One sequence of working code.

This is the pipeline the dispatch engine runs every morning, and every time a STAT walk-in changes the shape of the day. Each stage is a real piece of the production system — not a re-creation. Step through, or let it advance.

Raw orders

The day, as it lands in the system

24 orders, 3 technicians, one depot. No structure yet — just dots on a map and constraints in a database. This is where every shift starts.

POST /orders/batch?day=2025-10-14

"Why did that technician get that stop?" Three years from now, we can still answer.

Every routing decision in Phlebtrax writes a full audit record — every constraint result, every alternative we considered, every score factor that drove the choice. This is the actual record for order S04 · West End.

Order under decision
S04 · West End
TypeRoutine
Window10:00-14:00
Specimen drop-off≤ 16:00 · stability 6h
Decision time06:42:11 UTC · planning pass
Candidates considered

Tech 01 · Alex

Why this one won
11 hard constraints
✓Skill match
✓Capacity headroom
✓Time-window fit
✓Fasting window
✓PT/INR window
✓STAT-readiness
✓Specimen drop-off window
✓Certification level
✓Equipment compatibility
✓Contiguity (no detour wedge)
✓Walkoff-recovery cost
11 score factors
Proximity to current path0.95
Time-window fit0.90
Capacity headroom0.88
Skill match1.00
Drop-off window fit0.92
Specimen stability0.95
Tech historical efficiency0.85
Equipment match1.00
Contiguity (vs new wedge)0.80
Cross-fleet alternates0.78
Walkoff recovery cost0.90
Decision ID · DEC-2025-1014-0642-S04Retention · 7 years · WORM storage · reproducible from the same input batch

Eleven services. One sentence each — tap any block.

01 / 11

Order intake

REST · webhook · CSV import

Normalizes inbound orders from EMR webhooks, lab requisition imports, and the call-center app. Validates patient ID, draws a hash of PHI fields for downstream redaction, and stamps a UUID that follows the order through every downstream step.

"What if Google Maps doubles its prices?" We've thought about it.

Distance queries do not all need the same answer. Most need cheap and accurate; STAT needs traffic-aware; emergencies need anything. The cascade lets us tune the spend without losing the ability to operate. Pick a scenario.

✓ Answered
Tier 1

OSRM

self-hosted · primary · ~3 ms

We host OSRM on a single c6a.large in the same AWS region as the planner. It answers in two to four milliseconds for cache-hits, six to ten for cache-misses. It is free per call. It is the answer for 99% of distance queries.

When · Every planning batch · cached · defaultCost · Free per call
Skipped
Tier 2

Google Maps Distance Matrix

STAT only · ~120 ms · ~$0.005/call

Reserved exclusively for STAT walk-ins where traffic-aware ETA actually matters and the request count is small. Bypasses our OSRM cache because the value of the call is in 'now', not in 'recent'.

When · STAT walk-ins · STAT re-routes · explicit ops overrideCost · ≈ $0.005 / call
Skipped
Tier 3

Haversine fallback

always-on · ~0.0 ms · free

The cheap, dumb, last-resort straight-line distance. Used when OSRM is unavailable and the system needs to keep moving. Worse routes — but the system never stops.

When · OSRM unreachable · Google quota exhausted · degraded modeCost · Free

Each tier has a clean adapter behind it. Adding a fourth provider — Mapbox, HERE, a private gazetteer — is a one-class change. Swapping out Google Maps when its prices move is a config flag, not a rewrite.

Six decisions worth defending in a code review.

We choseOR-Tools VRPTWovera hand-rolled metaheuristic

We could have written our own. We have written ours before. OR-Tools is twelve years of routing research compressed into a battle-tested C++ engine, with first-class Python bindings, that other engineers will recognize on the team in three years. Choosing OR-Tools was choosing to be replaceable.

We choseK-Means with capacity constraintoverHierarchical clustering

Hierarchical produced cleaner cluster shapes but at O(n³) it became the bottleneck above 200 stops. K-Means at O(n·k·iterations), with our capacity-aware reassignment step, handles 1,000+ stops in under a second on a single core. Aesthetics lost.

We chose11 hard constraints, then a 11-factor scoreoverOne unified objective function

Modelling fasting-window violations as a score penalty meant the optimizer would sometimes 'pay' for the violation and still produce a route that broke clinical safety. Hard constraints cannot be paid for. Score factors can.

We choseWrite every decision to an append-only ledgeroverRecompute on demand from inputs

We tested 'recompute when audit asks'. It took 19 seconds for a single day's decision and assumed all upstream services were still running. The ledger is 200 KB per day. The choice was not close.

We choseOSRM-primary distance, Google for STAToverGoogle for everything

Day-one Google Maps spend was $80–$200/day at a tenth of target volume. With OSRM-primary, the bill is single dollars. The difference funds three months of engineering every year. We pay Google when we actually need traffic-aware routing — i.e., almost never.

We choseRules first, then XGBoost, then LLMoverLLM-first dispatch

An LLM with a routing tool would have shipped a demo in two weeks. It would also have made decisions we could not defend to a regulator, retrained itself with subtle distribution shift, and burned cents per inference for a problem rules solve in milliseconds. Phased maturity is the path.

We will not lead with an LLM for a problem rules already solve.

Every phase is shipped in production with an explicit fallback to the phase before it. There is no flag day, no "we replaced the rules engine," no live customer ever discovers that the system below their dispatch has gone from determinism to a learned model.

Live · today
Phase 1

Rules

Deterministic, fast, auditable. Every decision can be traced through a constraint filter and a scoring formula with weights stored as configuration. Zero training data required. Drift cannot happen because there are no learned weights to drift. This is where every Phlebtrax tenant starts, and where most stay.

ms latencyzero training data
In pilot · per tenant
Phase 2

XGBoost

Where rules consistently produce a sub-optimal answer for a known scenario (specimen rejection at the lab, technician complaints about a specific pairing), we train an XGBoost model on the historic decision log + outcome data and let it nudge the weights. Still explainable: SHAP values for every prediction. Falls back to rules if the model's confidence is below a threshold or the input is out of distribution.

learned weightsSHAP-explainablefallback to rulesper-tenant training
In design
Phase 3

LLM explainability

Not for dispatch decisions — for explanation. A local LLM turns the audit record into prose for operators and regulators: 'Tech 02 was selected because the fasting window required arrival before 09:00, Tech 01 was already committed, and Tech 03 lacked the PT/INR certification.' The LLM never decides; it only narrates from the structured record.

narration onlylocal modelstructured inputno autonomy

Built in 14 weeks by three engineers.

No new framework adopted in production. No new database introduced. No proprietary research published. The work was in choosing the right algorithms, modelling the right constraints, and writing the audit ledger so the operations team — and three years from now, a regulator — can ask any question and get an answer.

Routing coreOR-Tools (VRPTW)K-Means · capacity-constrained2-opt metaheuristicXGBoost · SHAP
Distance & geoOSRM · self-hostedGoogle Maps Distance MatrixHaversine fallbackPostGIS
PlatformPython 3.12 · FastAPIPostgreSQL 16Redis · job queueAWS · multi-AZ
Observability & auditStructured JSON logsOpenTelemetry tracesWORM ledger · 7yr retentionPrometheus · Grafana

If you have a field-service routing problem, the patterns are portable.

We have applied this architecture pattern to home phlebotomy, mobile imaging, in-home infusion, and discussed it for last-mile delivery, HVAC dispatch, and mobile mechanics. The constraint vocabulary changes. The bones don't.

Book discovery callBook a call→

30 minutes.
No deck.
Just a conversation.

If you're thinking about AI for your business and you want to talk to someone who will tell you the truth — including when AI is the wrong answer — book a call. We'll spend 30 minutes understanding what you're trying to do, what you're worried about, and whether we're the right fit.

No sales pitch. No deck. No follow-up pressure.
Calls are taken by a senior engineer who has shipped the work, not a BDR.
You'll walk away with at least one practical idea — even if we never work together.
Discovery call · pick a slot UTC
Choose a day
Choose a time (30 min)
Your local time · UTC