Коротко: оптимизатор считает мультиточечный маршрут строго по тем данным, которые вы передали. Если в запросе нет временных окон, грузоподъёмности и длительности работ на точке, сервис честно минимизирует километраж, но полученный порядок объезда развалится при первом же звонке клиента. Задача оптимизации маршрута решается в три шага: описать объекты (точки, депо, машины), наложить ограничения, выбрать параметры расчёта.
Ниже два сквозных сценария для DevOps-инженеров и системных администраторов, которые уже вызывают API и хотят получать предсказуемый результат: курьерская доставка по 10-20 адресам и выездное обслуживание сервисных инженеров с заявками разной длительности. Для каждого показаны структура запроса, набор ограничений и способ проверки ответа, плюс числовые примеры сравнения ручного планирования и автоматической оптимизации.
Названия полей, лимиты на количество точек и доступные параметры сверяйте с официальной документацией сервиса на дату работы. Примеры ниже описывают типовую структуру задачи оптимизации и логику расчёта, а не гарантированную схему конкретной версии API.
Постановка задачи оптимизации маршрута: от бизнес-требований к параметрам API
Бизнес-требование звучит как «развезти 15 заказов за смену», а API ждёт координаты, окна и веса. Перевод занимает четыре вопроса.
- Что везём или что делаем на точке. Вес, объём и длительность работ превращаются в атрибуты точки.
- Кто везёт. Количество машин, их стартовые и конечные адреса, грузоподъёмность, часы смены.
- Когда можно приезжать. Временные окна точек и обеденные перерывы экипажа.
- Что важнее при конфликте. Минимум километража, минимум времени или обязательное обслуживание конкретных точек.
Координаты передавайте в порядке «долгота, широта», а не наоборот. Перепутанная пара даёт точку в океане у берегов Африки, и оптимизатор послушно построит маршрут через неё: формально валидный ответ с абсурдным пробегом в тысячи километров. Проверяйте первые ответы на карте, пока данные не устоялись.
Практическое правило по объёму задачи: держите один запрос в пределах 100-200 точек, даже если интерфейс допускает больше. Точное значение лимита и поведение при его превышении смотрите в документации: сложные ограничения (окна, ёмкости, запреты пар) на больших наборах резко увеличивают время расчёта.
Ключевые параметры запроса: что обязательно, а что можно опустить
Минимальный набор для запуска оптимизации: список точек с координатами, депо как начало и конец маршрута, хотя бы одна машина и режим расчёта. Всё остальное влияет на качество результата, но не блокирует вызов.
- Обязательно по смыслу: координаты точек, старт машины, число машин, признак замкнутого или разомкнутого маршрута (возвращается ли курьер на склад).
- Можно опустить, но с последствиями: временные окна (без них оптимизация идёт по расстоянию), грузоподъёмность (машина станет безразмерной), длительность работ на точке (считается нулевой).
- Параметр качества расчёта: чем выше уровень, тем дольше считается ответ и тем короче итоговый маршрут. На 10-30 точках разница между уровнями обычно измеряется минутами работы алгоритма, на 200 точках она уже заметна в секундах ответа.
Минимальный запрос выглядит так:
{
"depot": {"point": [37.588144, 55.733842]},
"locations": [
{"point": [37.601234, 55.741122]},
{"point": [37.612345, 55.752233]},
{"point": [37.623456, 55.763344]}
],
"vehicles": [
{
"vehicle_id": "courier_1",
"start": [37.588144, 55.733842],
"end": [37.588144, 55.733842]
}
],
"options": {"quality": "normal"}
}
Здесь нет ни окон, ни весов. Оптимизатор вернёт геометрически короткий порядок объезда, который не учитывает график клиентов и загрузку машины. Для тестового вызова этого достаточно, для боевого сценария нет.
Как формализовать временные окна и приоритеты точек
Окно доступности задаётся для каждой точки, а рабочие часы машины отдельно. Разделение важно: сумма окон точек может быть шире смены, и тогда часть заказов физически не помещается в день даже при идеальном порядке.
Пример с двумя точками: первая принимает с 9:00 до 11:00, вторая с 14:00 до 16:00. При смене 8:00-18:00 и получасе на каждую точку маршрут реалистичен: утро у первой точки, днём переезд, после обеда вторая. Если добавить третью точку с окном 10:00-12:00 в другом конце города, задача может стать неразрешимой, и оптимизатор либо исключит одну из точек, либо вернёт ошибку.
{
"locations": [
{
"point": [37.601234, 55.741122],
"time_window": ["2026-09-19T09:00:00+03:00", "2026-09-19T11:00:00+03:00"],
"service_time": "PT15M",
"penalty": 1000
},
{
"point": [37.612345, 55.752233],
"time_window": ["2026-09-19T14:00:00+03:00", "2026-09-19T16:00:00+03:00"],
"service_time": "PT15M",
"penalty": 100
}
],
"vehicles": [
{
"vehicle_id": "courier_1",
"vehicle_time_window": ["2026-09-19T08:00:00+03:00", "2026-09-19T18:00:00+03:00"]
}
]
}
Приоритет выражается штрафом за необслуживание точки. Чем выше штраф, тем дороже оптимизатору пропустить адрес. Очень высокий штраф делает точку фактически обязательной, низкий разрешает выкинуть её из маршрута, если она ломает всю картину. Именно поэтому в первом примере штраф первой точки выше в десять раз: пропустить клиента с узким окном дороже, чем переставить доставку с широким интервалом.
Время указывайте с часовым поясом. Сервер, клиент и оператор в разных зонах дают окна, сдвинутые на несколько часов, и курьер уезжает к закрытому офису.
Ограничения оптимизации: какие бывают и как их учитывать в API
Ограничения делятся на четыре группы, и у каждой своя цена ошибки.
| Тип ограничения | Пример из практики | Что задаём в запросе | Что ломается без него |
|---|---|---|---|
| Временное | Доставка в офис с 9:00 до 11:00 | Окно доступности точки | Курьер приезжает к закрытым дверям, повторный выезд съедает день |
| Ёмкостное | Борт берёт 500 кг, заказы суммарно 1050 кг | Вместимость машины, вес точки | Задача нерешаема, часть точек выпадает из маршрута |
| Логическое | Сначала забрать груз, потом сдать | Порядок точек, запрет на пары адресов | Маршрут физически невыполним |
| Ресурсное | 2 машины, смена 10 часов | Количество машин, часы смены | Маршрут длиннее смены, переработка или срыв доставки |
| Мягкое (штраф) | Горячий заказ, который нельзя пропустить | Штраф за необслуживание точки | Оптимизатор выкинет неудобный адрес как нерентабельный |
Проверка перед отправкой запроса: посчитайте суммарное время работ и переездов и сравните с доступным фондом времени машин. Если сумма окон точек больше, чем смена всех экипажей, задача неразрешима в текущем виде, и никакие настройки качества это не исправят.
Временные окна и рабочие часы: как не нарушить SLA
Разберём на числах. 12 точек с окнами по 2 часа, одна машина, смена 12 часов, длительность работ на точке 15 минут, средний переезд 20 минут. Суммарно: 12 x 15 = 3 часа работ, 11-12 переездов по 20 минут, это около 4 часов, итого 7 часов чистого времени плюс запас. Такая задача решается с запасом, и окна можно оставить жёсткими.
Теперь те же 12 точек, но переезды по 45 минут: 3 часа работ плюс 8-9 часов дороги дают 11-12 часов. Запас исчезает, и любая пробка выбивает маршрут из графика. Варианты действий: расширить окна на 30 минут, добавить вторую машину, снизить качество работ на точке или перенести часть заказов на другой день. Смягчение окна работает точнее, чем повышение уровня расчёта: оптимизатор не нарушит жёсткое окно, но охотно воспользуется гибким.
Обеденный перерыв водителя удобнее задавать как отдельный интервал недоступности внутри смены. Если этого не сделать, оптимизатор поставит точку ровно в середину дня, а водитель уедет обедать с грузом в машине.
Грузоподъёмность и вместимость: как распределить заказы между машинами
Вместимость задаётся для машины, вес или объём для точки, а распределение по машинам оптимизатор делает сам. Классический пример с превышением: две машины по 500 кг, шесть точек с весами 100, 200, 150, 50, 300 и 250 кг. Сумма заказов 1050 кг при общей вместимости 1000 кг. Задача неразрешима, и никакой порядок объезда её не спасёт.
Решения: добавить третью машину, перенести точку на 300 кг в другой день, разрешить разгрузку в депо с повторным выездом (двойной рейс). Первые два варианта меняют входные данные, третий требует отдельной логики, потому что оптимизатор считает одну непрерывную поездку.
Другой пример, который уже решается: три машины по 1 тонне и 10 точек с общим весом 2,4 тонны. Запас есть, и оптимизатор распределит заказы с учётом геометрии: машина, чей первый адрес рядом с тяжёлой точкой, получит её первой, если окна позволяют. Когда весов несколько (вес и объём), задавайте оба параметра. Иначе поедет машина, в которую груз влез по массе, но не влез по кузову.
Сравнение ручного и автоматического планирования: цифры и факты
Ручной порядок объезда строится на интуиции и привычке. Автоматический расчёт перебирает комбинации и учитывает ограничения одновременно. Разница на малых наборах скромная, на больших растёт быстро.
| Сценарий | Ручное планирование | Автоматическая оптимизация | Разница |
|---|---|---|---|
| 10 адресов, 1 курьер | 45 км, 3 часа | 32 км, 2 часа 10 минут | минус 29% пробега, минус 28% времени |
| 20 адресов, 3 курьера | 120 км суммарно | 95 км суммарно | минус 21% пробега |
Почему выигрыш на первом примере выше, чем на втором: при одном курьере человек ошибается сильнее, потому что держит в голове весь список сразу. При трёх курьерах появляется дополнительный фактор, распределение заказов между экипажами, и здесь человек иногда попадает в неплохое решение почти случайно.
Число вариантов объясняет, где интуиция сдаёт. Для 10 точек существует 10! = 3 628 800 возможных порядков объезда, для 15 точек уже 1,3 x 10^12. Человек проверяет один-два варианта, оптимизатор работает с эвристиками по всему пространству и потому уходит от очевидных, но длинных маршрутов вроде «сначала все дворы слева, потом все справа».
Учёт дорожной ситуации меняет результат сильнее, чем сам алгоритм. Если передать режим расчёта с пробками, маршрут строится по прогнозу времени в пути, а не по километрам, и порядок точек в час пик может отличаться от порядка в спокойное время. Для доставки в центре это критично: два адреса в 2 км друг от друга утром могут разойтись на 25 минут.
Все цифры выше - модельный расчёт при одинаковых исходных данных для обоих методов. Ваш фактический выигрыш зависит от геометрии точек, плотности окон и того, сколько времени экипаж тратит на месте. На десяти точках, разбросанных по прямой вдоль одной улицы, разница между ручным и автоматическим планом приблизится к нулю.
Практические кейсы оптимизации маршрутов доставки и сервисного обслуживания
Два кейса показывают, как одни и те же механизмы работают в логистике и в выездном сервисе. Разница в акцентах: доставка гонится за окнами и температурой заказа, сервис за квалификацией инженера и длительностью работ.
Доставка: как оптимизировать маршрут курьера с несколькими адресами
Исходные данные: 15 адресов, 2 курьера, окна по 30 минут, у трёх заказов приоритет (горячие блюда). Смена с 10:00 до 22:00. Порядок работы: собрать точки, проставить окна, веса не задавать, задать штрафы для приоритетных адресов, включить расчёт с учётом пробок.
{
"depot": {"point": [37.588144, 55.733842]},
"locations": [
{
"point": [37.601234, 55.741122],
"time_window": ["2026-09-19T12:00:00+03:00", "2026-09-19T12:30:00+03:00"],
"service_time": "PT5M",
"penalty": 5000
},
{
"point": [37.612345, 55.752233],
"time_window": ["2026-09-19T12:15:00+03:00", "2026-09-19T12:45:00+03:00"],
"service_time": "PT5M",
"penalty": 100
}
],
"vehicles": [
{"vehicle_id": "courier_1", "vehicle_time_window": ["2026-09-19T10:00:00+03:00", "2026-09-19T22:00:00+03:00"]},
{"vehicle_id": "courier_2", "vehicle_time_window": ["2026-09-19T10:00:00+03:00", "2026-09-19T22:00:00+03:00"]}
],
"options": {"quality": "high", "traffic_mode": "jam"}
}
В ответе смотрите на два поля по каждой машине: порядок точек и время прибытия. Типичный результат на таких данных: 8 адресов первому курьеру, 7 второму, приоритетные заказы стоят в начале цепочки, а не в конце. Если приоритетный адрес оказался последним, проверьте штраф: низкое значение означает, что для оптимизатора пропуск точки дешевле лишнего километра.
Длительность работ на точке для еды ставьте реальную, 3-7 минут. Ноль в этом поле превращает маршрут в фантастику: оптимизатор считает, что курьер обслуживает адрес мгновенно, и добавляет в план лишние точки.
Сервисное обслуживание: учёт длительности работ и квалификации инженеров
Исходные данные: 8 заявок, 2 инженера, у одной заявки жёсткое окно, у другой повышенный приоритет. Длительность работ различается: замена блока питания 30 минут, диагностика сети 60 минут. Квалификация тоже разная: часть работ доступна только инженеру с допуском к электрооборудованию.
Квалификацию удобно выражать через отдельные профили машин: каждой машине в запросе соответствует набор навыков и допустимых работ, а точка требует определённый навык. Оптимизатор не поставит электромонтаж в маршрут инженера без допуска, если вы описали это ограничение.
{
"locations": [
{
"point": [37.601234, 55.741122],
"service_time": "PT60M",
"time_window": ["2026-09-19T09:00:00+03:00", "2026-09-19T11:00:00+03:00"],
"required_skill": "electrical",
"penalty": 10000
},
{
"point": [37.612345, 55.752233],
"service_time": "PT30M",
"required_skill": "general",
"penalty": 100
}
],
"vehicles": [
{"vehicle_id": "engineer_1", "skills": ["electrical", "general"]},
{"vehicle_id": "engineer_2", "skills": ["general"]}
]
}
Проверка загрузки дня: смена 9:00-18:00, 4 заявки на инженера, средняя длительность 45 минут, это 3 часа работ. Остаётся 6 часов на переезды, что комфортно для города. Пять заявок с той же длительностью дают 3 часа 45 минут работ и почти 5 часов дороги, запас тает. Шесть заявок уже требуют либо второй смены, либо переноса.
Жёсткое окно у сервисной заявки держите по-настоящему жёстким, а неудобные переезды компенсируйте штрафом. Иначе оптимизатор перенесёт визит на вечер, и клиент останется без инженера в согласованное время.
Как интерпретировать результат оптимизации и проверить его корректность
Ответ содержит маршрут на каждую машину: идентификатор, порядок точек, время прибытия и убытия, пробег, длительность. Плюс общий статус расчёта. Читать его нужно сверху вниз, как план дня водителя.
{
"status": "ok",
"routes": [
{
"vehicle_id": "courier_1",
"distance": "32.4 km",
"duration": "2h10m",
"points": [
{"location_index": 3, "arrival_time": "2026-09-19T12:04:00+03:00"},
{"location_index": 1, "arrival_time": "2026-09-19T12:26:00+03:00"}
]
}
],
"unassigned": []
}
Четыре проверки, которые ловят большинство проблем.
- Все точки обслужены. Пустой список нераспределённых адресов означает полный план. Заполненный список говорит, что часть заказов вы физически не вписали в ограничения.
- Порядок точек на карте. Пять минут визуальной проверки заменяют час разбора логов: маршрут не должен рисовать «звезду» через весь город.
- Средняя скорость. Разделите пробег на время в пути. Значение ниже 15 км/ч для города с пробками нормально, а вот 60 км/ч на маршруте по центру говорит о том, что прогноз трафика не учли.
- Соблюдение окон. Сравните время прибытия с окнами точек. Систематические опоздания на 5-10 минут обычно означают нулевую длительность работ на точке.
Коэффициент эффективности считайте просто: отношение пробега автоматического маршрута к пробегу ручного плана на тех же адресах. Значение 0,7 означает экономию 30%. Второй ориентир: сравните маршрут с нижней оценкой, длиной кратчайшего пути между крайними точками в порядке удаления от депо. Если автоматический план ближе к оценке, значит ограничения не мешают расчёту, и упор стоит делать на данные о пробках, а не на дополнительные итерации оптимизации.
Когда статус ответа отличается от успешного, в теле приходит причина: противоречивые окна, превышение вместимости, нехватка машин. Разбирайте причину, а не перезапускайте запрос: на тех же данных получите тот же результат.
Типичные ошибки при работе с API Яндекс Маршрутизации и способы их устранения
Большинство неудачных маршрутов объясняется пятью причинами, и все они диагностируются за минуты.
| Ошибка | Как проявляется | Решение |
|---|---|---|
| Широта и долгота перепутаны | Пробег в тысячи километров, точка в океане | Привести координаты к единому порядку долгота-широта, добавить валидацию диапазонов |
| Слишком много точек в одном запросе | Долгий ответ, таймаут, часть точек не обслужена | Разбить на партии по 50-100 точек, сложные ограничения считать отдельно |
| Нет ключа идемпотентности | Повторный запрос создаёт дубликат задачи или заказа | Генерировать новый ключ на каждый логический вызов, хранить его с задачей |
| Игнорирование лимитов запросов | Ошибка о превышении частоты вызовов | Экспоненциальная задержка между попытками плюс случайный разброс |
| Нулевая длительность работ | Маршрут невыполним по времени | Проставить реальное время на точке для каждой категории заказов |
Отдельно про часовые пояса: окна без указания зоны интерпретируются по настройке сервера, и при разнице в 3 часа сдвигается весь план дня. Ещё один источник ошибок, неучтённые логические связи: если груз нужно забрать до сдачи, а порядок не задан, оптимизатор поставит точки как удобно геометрии.
При превышении частоты вызовов помогает не только задержка, но и разбор ответа сервиса: полезно логировать код, текст ошибки и идентификатор запроса. Приёмы отладки HTTP-вызовов, работы с логами и трассировкой подробно разобраны в материале диагностика проблем маршрутизации: инструменты и методы для DevOps и сисадминов.
Интеграция оптимизации в существующую инфраструктуру: советы для DevOps
Вызовы оптимизатора встраиваются в тот же контур, что и остальные внешние API: секреты, повторы, таймауты, метрики.
- Ключ в секретах. Храните его в Vault или Kubernetes Secret, выдавайте отдельный ключ на каждое окружение и ограничивайте права тем, что действительно нужно сервису.
- Идемпотентность на своей стороне. Свой ключ на каждую задачу оптимизации плюс запись в журнал: повтор при сетевом сбое не должен создавать вторую поездку.
- Повторы с задержкой. Повторяйте только сетевые ошибки и ответы 429, 500, 502, 503, с ростом паузы и случайным разбросом. Ошибку валидации повторять бессмысленно.
- Таймаут и предохранитель. Расчёт на 150 точек может идти дольше обычного, поэтому таймаут ставьте отдельно от коротких запросов, а предохранитель настраивайте на долю неуспешных вызовов.
- Метрики. Время ответа, доля неуспешных расчётов, число нераспределённых точек, отклонение фактического пробега от плана. Рост последнего показателя сигналит о смене данных, а не о проблеме сервиса.
- Асинхронная обработка. Большие задачи удобнее отправлять на расчёт и получать результат уведомлением, чем держать открытое соединение.
Схемы защиты внешних вызовов и готовые конфигурации для Kubernetes, Docker и Nginx собраны в статье типичные ошибки в проектировании маршрутизации процессов и методы их предотвращения.
Минимальный рабочий вызов на Python с повторами и ключом идемпотентности:
import os
import random
import time
import uuid
import requests
API_KEY = os.environ["ROUTE_API_KEY"]
API_URL = os.environ["ROUTE_API_URL"]
payload = {
"depot": {"point": [37.588144, 55.733842]},
"locations": [{"point": [37.601234, 55.741122]}],
"vehicles": [{"vehicle_id": "courier_1"}],
}
headers = {
"Authorization": "Api-Key " + API_KEY,
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
}
for attempt in range(5):
response = requests.post(API_URL, json=payload, headers=headers, timeout=30)
if response.status_code == 200:
plan = response.json()
break
if response.status_code in (429, 500, 502, 503):
time.sleep(2 ** attempt + random.random())
continue
raise RuntimeError(response.status_code, response.text)
else:
raise TimeoutError("route optimizer did not respond")
Адрес точки входа держите в переменной окружения, а не в коде: при смене версии API или эндпоинта правка займёт одну строку в конфигурации. Логируйте запрос без ключа авторизации, но с ключом идемпотентности и идентификатором задачи: по ним связываются события в сервисе и записи в вашей базе.
Начните с одного сценария и десяти реальных адресов: соберите запрос по чеклисту выше, сверьте ответ с картой, зафиксируйте пробег и время в пути, затем сравните с привычным ручным планом за ту же смену. Полученная разница и станет вашей точкой отсчёта для следующих итераций.