Dispatch Optimizer
Decision optimization Synthetic benchmarkA constraint-based field-service dispatch optimizer for Atlas Field Services, a synthetic commercial-facilities maintenance company. It uses a synthetic backlog, technician capacity, skill matching, SLA rules, travel penalties, and scenario controls to recommend operationally feasible job assignments, then benchmarks an OR-Tools CP-SAT plan against naive and greedy plus 2-opt baselines to measure planning performance under controlled synthetic scenarios.




Problem
On a typical day a field-service dispatcher faces more work than the crews can finish: twelve technicians, more than a hundred jobs, six skills, hard SLA deadlines, travel between sites, fixed shifts, limited overtime, and some jobs blocked on parts. The common-sense approach, highest priority first to the nearest qualified technician, makes locally reasonable choices that are globally poor: it strands specialists, books avoidable travel, and breaches SLAs that better sequencing would have saved.
The question is not what happened. It is what should we do next, given limited people, time, travel, skills, and SLA risk. That is an optimization problem, not a reporting problem, and it is the gap this project fills: operational decision-making under constraints rather than another dashboard.
Users and decisions
Dispatchers and field-service operations managers are the intended users. They use the plan and scenario controls to decide which technician should take each job, which work must be deferred, and whether added capacity or overtime is justified under SLA, skill, travel, and shift constraints.
The interactive demo is built for portfolio demonstration on a fully synthetic, seeded dataset. No proprietary or employer data is used. It is not a production dispatch system for a real field-service operation.
Dispatch as routing plus assignment, solved with CP-SAT
Technician dispatch is modeled as a vehicle-routing problem with time windows plus assignment and solved with Google OR-Tools CP-SAT. Per technician, a routing circuit is built over home plus candidate jobs using AddCircuit, with self-loop arcs making each job optional and arc literals carrying travel time. Start times respect travel and service sequencing, skills and certifications restrict which assignments can exist, parts-blocked jobs are never candidates, and the objective maximizes priority-weighted completion minus travel, SLA-breach, and overtime penalties. SLAs are soft by default and become hard for top-priority jobs under strict mode.
The comparison is the point. A deliberately naive manual baseline obeys the same feasibility rules, so the delta is planning quality, not different assumptions. Two techniques keep an eight-second live solve reliable: per-technician candidate capping keeps routing circuits small, and the baseline is warm-started into CP-SAT as a complete feasible incumbent, so the optimized plan never loses to the baseline even when optimality cannot be proven in the time budget. The solver also reports its optimality gap so the user knows how close the incumbent is to the proven bound.
Architecture
Greedy plus 2-opt takes 12 breaches off the baseline
An earlier version of this page led with a single seeded day against the naive baseline. That comparison did not reproduce, and it measured the strawman rather than the solver, so it has been replaced. The benchmark now runs 200 randomized scenarios against greedy nearest-qualified with a 2-opt improvement pass.
Two readings matter. Cold CP-SAT at the eight-second budget is a median six SLA breaches worse than greedy plus 2-opt and loses on 81% of scenarios. Warm-started from that same heuristic, which is what the product ships, it reaches median parity: tied on 57%, ahead on 39%, and behind on 4%.
Evidence for
12 fewerSLA breaches per day, median across 200 randomized scenarios, for a greedy nearest-qualified dispatcher with a 2-opt improvement pass against the naive priority-first baseline (5th to 95th percentile: 3 to 22 fewer). Better on 99% of scenarios and worse on none. Fully deterministic and reproducible.Evidence for
3.35 hrsOvertime removed per day by that same improvement pass, median across the same 200 scenarios (5th to 95th percentile: 0.3 to 7.7 hours).Evidence against
6 behindSLA breaches for cold CP-SAT at the shipped eight-second budget against greedy plus 2-opt, median across 200 randomized scenarios. It lost on 81% of those scenarios.Evidence against
ParityWarm-started CP-SAT against greedy plus 2-opt over 200 randomized scenarios: median zero SLA breaches apart, tied on 57%, ahead on 39%, and behind on 4%. The warm start is the result, not an implementation detail.Evidence against
45.6%Share of the deadlines the naive baseline misses among the jobs it schedules, median across 200 scenarios. That rate is why beating it proves very little.Tools used
Key features
- A real optimizer, not a heuristic dressed up as one: a VRPTW plus assignment model in OR-Tools CP-SAT with a bounded live solve.
- An honest baseline foil that obeys the same feasibility rules, so the measured delta is planning quality rather than different assumptions.
- Warm start plus per-technician candidate capping, which keeps the live solve tractable and guarantees the optimized plan never loses to the naive warm-start baseline.
- Optimality-gap reporting so the operator knows how close the returned incumbent is to CP-SAT's proven bound.
- Decision support, not just assignment: bottleneck-skill detection, the overtime-versus-SLA trade-off, and explicit reason-coded deferrals on every unassigned job.
- Marginal Value of Capacity: a crew-size sweep through the optimizer that charts the hire-versus-overtime decision frontier.
- Scenario Simulator: pull technicians, raise the traffic penalty, create a skill shortage, tighten SLA strictness, or spike emergencies, and re-solve live.
- A pluggable travel provider behind one seam: offline haversine by default, with real road durations from OpenRouteService or OSRM, set server-side or per visitor with no key stored.
- Full stack with a clean seam: a pure-Python, database-free optimizer core, SQLAlchemy persistence, portable analytical SQL views, and a seven-page dashboard.
Tradeoffs and constraints
A live, anytime solver on an eight-second budget cannot always prove optimality on the full instance. Candidate capping and the naive warm-start baseline are the deliberate response: they shrink the search and guarantee a usable plan at least as good as that baseline on every solve, at the cost of occasionally leaving a small, reported optimality gap. The throughput floor keeps the optimizer from ever finishing fewer jobs than the naive warm-start baseline while it trims breaches, travel, and overtime above that floor.
The default travel model is offline haversine so the public demo is free, reproducible, and quota-free. Real road durations drop in through OpenRouteService or OSRM with no model change, because travel is resolved behind a single seam and the CP-SAT model already uses directional arcs that handle asymmetric road times.
Methodology
Appropriate use: portfolio demonstration of constraint-based optimization and decision support on a fully synthetic, seeded dataset.
Inappropriate use: as a production dispatch system, or as ground truth for staffing, routing, or service-level decisions in a real operation. The live demo begins with one canonical seeded day. The baseline benchmark spans 200 randomized synthetic scenarios, and the solver time-budget sweep spans 24.
Limitations
The optimizer plans a single canonical day from a seeded synthetic generator. It is deterministic and reproducible by design, not a forecast of real demand. SLA deadlines, durations, skills, and parts availability are modeled, but real-world frictions such as no-shows, re-work, mid-day reprioritization, and stochastic travel are not.
The live solve is intentionally time-boxed, so on the hardest scenarios the returned plan can carry a small optimality gap rather than a proven optimum. The objective weights are sensible defaults exposed through the UI sliders; a real deployment would tune them against that operation's actual cost of a breach, an overtime hour, and a mile.
Decisions and rejected alternatives
CP-SAT over simulated annealing or a genetic algorithm. Metaheuristics would have found comparable schedules faster to build. I chose a declarative constraint model because a dispatcher has to be told why a job was deferred. The application derives reason codes from modeled constraints, while CP-SAT provides an objective bound. The cost is real: an 8-second solve budget, a model that gets harder to change as constraints accumulate, and runs that terminate on the time limit rather than at proven optimality.
Warm-starting the baseline as a feasible incumbent. This guarantees the optimizer never returns a worse plan than the manual one, which is the right engineering choice for an operator-facing tool. It also means the direction of the result is decided before the solver runs, and only the magnitude is empirical. I would rather state that plainly than present a guaranteed outcome as a discovery.
A deliberately naive baseline, which was the weakest choice here. Priority-first dispatch misses 45.6 percent of the deadlines it schedules, median across 200 randomized scenarios. No real operation tolerates that, so beating it flattered the optimizer. I have since built the comparison that should have been there from the start: a greedy nearest-qualified dispatcher with a 2-opt improvement pass, which is roughly what a competent engineer writes in an afternoon without a solver. It takes a median of 12 breaches off the naive baseline on its own.
The finding that came out of fixing it. Cold CP-SAT at eight seconds is a median six SLA breaches behind greedy plus 2-opt and loses on 81% of the 200 scenarios. Warm-starting from that heuristic, which is what the product ships, changes the result to median parity: tied on 57%, ahead on 39%, and behind on 4%. The original comparison hid both facts because the strawman baseline was too easy. At this time budget, the warm start is what makes the constrained model operationally defensible.
What is not reproducible, and why I am not quoting per-scenario win rates. The solver runs with eight search workers against a wall-clock limit, so setting a random seed does not make it deterministic; re-running the same scenarios shifts individual results and flips the verdict on roughly a fifth of them. The greedy and naive arms are bit-identical across runs and their numbers can be trusted directly. The CP-SAT numbers are honest as distributions and unreliable per scenario, which is a property of racing a portfolio search against a clock and worth stating rather than papering over.
Still open. Real road-network travel as the default with a cached matrix. Rolling re-optimization so the plan absorbs no-shows and emergencies instead of solving one static instance. Operator-tuned weights fit to a specific operation's costs. Multi-day and overtime-budget planning.