Перейти к содержимому
16 янв. 2026 г.·6 мин чтения

Timeout для LLM-задач: почему один лимит ломает сценарии

Timeout для LLM-задач нельзя ставить одним числом: у автодополнения, саммари, агента и batch разные бюджеты ожидания и риски.

Timeout для LLM-задач: почему один лимит ломает сценарии

Почему один timeout не подходит всем

Один и тот же timeout почти всегда ломает часть LLM-сценариев. Люди и системы ждут по-разному. В автодополнении задержка даже в 700-900 мс уже ощущается как пауза. Пакетная обработка, наоборот, может идти минуты, если пользователь не сидит перед экраном.

Когда команда ставит один общий лимит, она получает две проблемы сразу. Быстрые запросы ждут дольше, чем нужно, потому что запас слишком большой. Длинные задачи, наоборот, обрываются раньше времени, потому что лимит для них изначально слишком короткий.

Поэтому timeout выбирают не по названию модели, а по сценарию. Одна и та же модель может нормально работать для саммари, но не укладываться в агенте, где есть несколько шагов, вызовы инструментов и повторные попытки после ошибок. Модель здесь - только часть цепочки.

Ошибка timeout тоже часто уводит не туда. Команда видит одно и то же сообщение и решает, что "тормозит" модель. Но задержка нередко появляется раньше или позже самого инференса. Время может уйти в очередь, в ретраи, во внешний инструмент или в ожидание между шагами пайплайна. Поэтому общий лимит часто маскирует настоящую причину. На графике вы видите один timeout, а чинить нужно очередь, сетевой вызов или логику повторов.

Сначала лучше разделить задачи по типу ожидания: автодополнение, саммари, агент и batch. У каждого режима свой бюджет ожидания и свой риск для продукта. Иначе интерфейс станет вязким, а длинные фоновые процессы будут падать без пользы.

Из чего состоит бюджет ожидания

Таймаут для LLM-задач часто считают только по времени ответа модели. Это слишком грубо. Пользователь ждет не только "думание" модели. В бюджет входят все задержки по пути запроса.

Часть времени уходит еще до генерации. Запрос может постоять в очереди у провайдера или у шлюза. Затем сервис тратит время на маршрутизацию, проверку лимитов и запуск вызова. Даже задержка до первого токена сильно влияет на ощущение скорости.

После первого токена начинается другая фаза - сама генерация. И тут разница бывает большой. Короткий ответ на 80 токенов и подробное саммари на 1200 токенов не могут жить с одним и тем же лимитом, даже если стартовали одинаково быстро.

У агента бюджет тает еще быстрее. Он делает несколько шагов: вызывает модель, идет в поиск или базу, снова спрашивает модель, иногда повторяет это по кругу. Если один шаг занимает 6 секунд, а инструмент отвечает за 2, то даже три шага уже дают заметную задержку.

Отдельная ловушка - ретраи. Один ответ 429 или 5xx добавляет паузу, повтор запроса и новый прогрев очереди. На бумаге модель ответила за 7 секунд, а для пользователя прошло 18.

Поэтому лучше держать два лимита. Первый - клиентский timeout, после которого интерфейс перестает ждать. Второй - общий дедлайн операции, в который должны поместиться все шаги, ретраи и вызовы инструментов. Эти лимиты не равны. Клиент может ждать 10 секунд, а бэкенд - 25, если результат потом забирается асинхронно. Но в синхронном сценарии ранний обрыв на клиенте только скроет тот факт, что сервер все еще тратит деньги и время.

Автодополнение: ждать почти нельзя

Автодополнение ломается первым, когда команда ставит общий timeout на все сценарии. Человек печатает быстро и сразу замечает лишние 200-400 мс. Если подсказка приходит с опозданием, она уже не помогает, а мешает. Пользователь успевает ввести текст сам и перестает смотреть на предложения модели.

Здесь почти всегда лучше жесткий лимит, чем попытка вытянуть идеальный ответ. Автодополнение - не тот режим, где нужна максимальная полнота. Нужна короткая и уместная догадка, которая появилась вовремя. Если модель думает 3 секунды и потом выдает отличный вариант, пользы уже мало.

Ориентиры обычно такие:

  • 300-700 мс для inline-подсказок во время набора
  • 500-1200 мс для более длинных предложений или коротких перефразировок
  • до 2 секунд как редкий верхний предел, если интерфейс явно показывает ожидание

Если сервис не успевает, сначала режут объем работы. Сокращают контекст, убирают лишние инструкции, просят 5-15 токенов вместо абзаца. Иногда помогает более короткий системный промпт или более простой маршрут запроса. Для этого режима принцип простой: "достаточно хорошо и сразу" почти всегда лучше, чем "почти идеально, но поздно".

Саммари: можно ждать дольше

Саммари живет по другим правилам. Когда человек сам нажал кнопку и ждет краткий итог, он обычно терпимее к задержке. Пауза в 6-12 секунд часто воспринимается нормально, потому что пользователь уже передал текст и ждет готовый результат, а не мгновенный отклик на каждое действие.

Но и здесь нет одного общего лимита. Время зависит как минимум от двух вещей: сколько текста модель должна прочитать и в каком виде вы хотите ответ. Короткая заметка на пару абзацев обрабатывается быстро. Протокол встречи на 15 страниц, да еще с разбивкой по темам, решениям и рискам, почти всегда требует больше времени.

Формат ответа тоже сильно влияет на бюджет ожидания. Если нужен обычный абзац на 5-6 предложений, ответ придет раньше. Если вы просите JSON, цитаты из исходного текста, несколько блоков или строгую структуру для CRM, модель тратит больше времени и чаще упирается в лимит.

Для интерфейса многим командам хватает 5-20 секунд. Этого обычно достаточно для писем, заметок, коротких звонков и внутренних документов. Для фоновой задачи лимит можно поднимать заметно выше, например до 60-120 секунд, если пользователь не ждет результат сразу.

Хорошая развилка выглядит так: короткие тексты остаются в интерфейсе, а длинные документы уходят в фон. Частая ошибка - давать одинаковый timeout и для заметки, и для большого договора. В итоге короткие задачи проходят, а тяжелые срываются без пользы. Лучше хотя бы разделить их на два класса по объему текста.

Агент: считайте время на шаг и на весь запуск

Подберите маршрут для агента
Сравните быстрые и длинные шаги агента через один шлюз и тот же код.

Агент почти никогда не тратит время только на ответ модели. Он делает несколько шагов: выбирает действие, вызывает поиск или базу данных, ждет ответ инструмента, потом снова обращается к модели. Поэтому один общий timeout здесь особенно вреден. Короткий лимит обрывает полезные цепочки, а длинный позволяет агенту бесполезно крутиться.

Нужны два ограничения сразу. Первое - лимит на один шаг. Второе - лимит на весь запуск. Лимит шага защищает от медленного инструмента или зависшего запроса. Лимит запуска не дает агенту потратить минуту на серию мелких задержек.

Хорошее правило простое: держите запас под один медленный вызов, а не под бесконечный диалог агента с самим собой. Если поиск по внутренней базе иногда отвечает за 8 секунд, шагу можно дать 10-12 секунд. Но это не значит, что агенту стоит разрешить 20 шагов подряд.

Отдельно стоит проверить три вещи: сколько времени агент может ждать один вызов инструмента, сколько шагов подряд он может сделать за один запуск и после каких повторов вы останавливаете цикл.

Пустые циклы лучше резать рано. Если агент 2-3 раза подряд вызывает один и тот же инструмент без нового результата, повторно формулирует тот же запрос или снова получает тот же отказ доступа, запуск надо завершать. Иначе пользователь ждет, а система тратит токены и ресурсы без пользы.

Если агент не уложился в общий лимит, лучше вернуть частичный результат или ясную ошибку. Держать сессию открытой в надежде, что она когда-нибудь завершится, обычно плохая идея.

Пакетная обработка: смотрите шире, чем один HTTP timeout

В пакетной обработке timeout одного HTTP-ответа почти ничего не говорит о сроке всего job. Ночной прогон может простоять в очереди 10 минут и все равно закончиться вовремя. Куда хуже, когда один worker завис на редком файле на 40 минут и держит слот.

Обычно здесь считают три дедлайна:

  • на один элемент
  • на пачку
  • на весь job

Лимит на элемент нужен, чтобы битый PDF, слишком длинный prompt или медленный провайдер не съедали весь пул воркеров. Лимит на пачку помогает понять, когда конкретную группу уже пора отменить и перераздать. Лимит на весь job привязан к окну бизнеса: например, все 50 000 записей должны обработаться до утренней выгрузки.

Еще один частый промах - смотреть только на среднее время ответа. На дашборде можно видеть 7 секунд в среднем и все равно не укладываться в окно, если p95 уже 28 секунд, а часть запросов висит до жесткого таймаута. Для batch p95 по элементу обычно полезнее, чем красивое среднее.

Небольшой пример. Пачка из 10 000 документов идет на 25 воркеров. Если один документ должен завершаться за 20 секунд, а p95 ушел к 45, весь job растянется не на минуты, а на часы. Длинная очередь при этом может быть нормой. Бесконечно живущий worker - нет. Его лучше остановить, пометить элемент как failed и освободить слот для следующей задачи.

Один сценарий из жизни команды

Команда поддержки интернет-магазина подключила LLM сразу в четыре места. Оператору в чате нужны короткие подсказки почти мгновенно, иначе он перестает ими пользоваться. После закрытия диалога система пишет саммари разговора, и там допустимы несколько секунд ожидания.

Параллельно отдельный агент проверяет статус заказа, затем смотрит базу знаний, а иногда делает еще один шаг, если ответ не нашелся с первой попытки. Ночью пакетная задача разбирает тысячи обращений, ставит теги и раскладывает темы по очередям. Все это шло через один API, и команда решила не усложнять конфиг: поставили один лимит в 10 секунд на все.

Сначала решение казалось разумным. На деле чат стал раздражать операторов уже в первую неделю. Для автодополнения 10 секунд - почти вечность. Пользователь ждет 1-2 секунды, а потом просто печатает сам.

Саммари при таком лимите работало терпимо, потому что задача длиннее по своей природе. А вот агент начал падать даже чаще, чем чат. Его 10 секунд уходили не на один ответ, а на целую цепочку шагов: запрос к модели, проверка заказа, еще один запрос, чтение базы знаний. Если каждый шаг съедал по 3-4 секунды, весь запуск упирался в потолок слишком рано.

Ночной batch пострадал по-своему. Отдельный запрос иногда укладывался в 10 секунд, но на больших объемах всплывали повторы, ретраи и редкие медленные ответы. К утру очередь просто не успевала обработаться полностью.

После этого команда развела лимиты по сценариям. Для чата оставили короткий жесткий таймаут. Для саммари дали больше времени. Для агента ввели лимит на шаг и общий дедлайн на весь запуск. Для batch стали считать не только время одного ответа, но и пропускную способность за ночь. После этого система стала вести себя предсказуемо.

Как назначать лимиты по шагам

Запустите LLM в РФ
Если важны 152-ФЗ и логи в РФ, начните с одного совместимого подключения.

Хороший timeout появляется не из среднего числа, а из списка отдельных сценариев. Даже если все идет через один API, ждать их одинаково нельзя.

Сначала разложите путь запроса на части: пользовательский экран, вызов модели, retry, постобработка, запись результата в базу. У каждой части свое время. Иначе вы видите только общий обрыв, но не понимаете, где система теряет секунды.

Рабочая схема обычно такая:

  • выпишите все LLM-сценарии отдельно, не объединяя их в одну категорию вроде "генерация текста"
  • для каждого сценария задайте мягкий и жесткий лимит
  • снимите p50, p95 и долю запросов, которые упираются в timeout
  • отдельно решите, где retry окупается, а где он только добавляет задержку

Мягкий лимит нужен там, где можно аккуратно ухудшить поведение системы. Например, после 2-3 секунд интерфейс может показать частичный результат, более короткую версию ответа или перевести задачу в фон. Жесткий лимит нужен, чтобы единичные долгие запросы не съедали ресурсы всего сервиса.

Смотрите не только на задержку, но и на цену ошибки. Если автодополнение оборвалось, пользователь просто продолжит печатать. Если агент не успел на одном из шагов, вы можете получить сломанную цепочку действий и повторный запуск всей задачи. Один и тот же лимит для них почти всегда дает плохой результат.

После смены модели старые цифры быстро устаревают. Особенно это заметно в схемах, где провайдера или маршрут можно поменять без переписывания приложения. Код остается прежним, а хвост задержек уже другой. Поэтому лимиты лучше хранить как настройки сценария, а не как одно число в конфиге на весь сервис.

Где команды ошибаются чаще всего

Первая ошибка простая: команда смотрит на среднее время ответа и успокаивается. Но пользователю не важно, что в среднем запрос идет 2 секунды, если каждый десятый висит 18. Для таймаутов полезнее смотреть хотя бы на p95 и p99, отдельно по типам запросов.

Вторая путаница возникает между timeout клиента и дедлайном всей операции. Клиент может ждать 8 секунд, а серверный пайплайн жить 20, потому что внутри есть ретраи, маршрутизация, проверки политики и вызовы инструментов. В итоге фронт уже показал ошибку, а бэкенд все еще тратит деньги и держит ресурсы.

Часто ломают агента слишком щедрыми лимитами. Один шаг вроде "сходи в поиск и верни ответ" кажется коротким, но агент может сделать 6-8 вызовов подряд, еще и с повторами при сбое. Если не ограничить число шагов, время на каждый шаг и общий дедлайн запуска, агент зависает не из-за модели, а из-за собственной петли.

Еще одна ошибка - одинаковый бюджет повторов для UI и batch. В интерфейсе второй или третий retry часто уже бесполезен: человек ушел, окно закрылось, ценность ответа упала. В пакетной обработке все наоборот. Лишняя минута там может быть нормальной ценой за высокий процент успешно завершенных задач.

Многие забывают и о том, что время съедает не только модель. До генерации легко накапливаются очередь у провайдера или в вашем воркере, холодный старт, длинный контекст, промежуточные прокси, логирование, проверки и медленные инструменты. Из-за этого один и тот же лимит ведет себя по-разному утром, вечером и после релиза новой функции.

Хорошее правило здесь одно: считайте не "сколько обычно отвечает модель", а "сколько живет весь запрос от клика до финального результата".

Быстрая проверка перед релизом

Поймайте длинный хвост
Смотрите, как ведут себя модели под нагрузкой утром, днем и вечером.

Перед релизом полезно пройтись по лимитам еще раз. Один общий timeout часто ломает сразу несколько сценариев, и это всплывает уже после выкладки.

Короткий список для проверки:

  • для UI, фоновых задач и агентов заданы разные лимиты
  • у агента есть отдельный timeout на шаг и общий дедлайн на весь сценарий
  • в логах видно, где ушло время: очередь, модель, сеть или инструмент
  • запасной сценарий описан заранее, а не придумывается во время инцидента
  • после релиза команда смотрит p95, а не только среднее время

Логи обычно быстро показывают неприятную правду. Проблема часто оказывается не в модели, а в очереди, ретраях или внешнем поисковом инструменте. Поэтому смотреть нужно по слоям, а не только на итоговый timeout.

Запасной сценарий лучше формулировать как обычное правило. Если длинный ответ не успевает, сервис отдает короткую версию. Если медленная модель не укладывается в лимит, запрос уходит на более быструю. Если задача не срочная, система переносит ее в фон и возвращает статус вместо ошибки.

Что делать дальше

Не ищите один универсальный timeout. Начните с четырех отдельных профилей и сразу дайте им разные правила. Для автодополнения ставьте самый жесткий лимит. Для саммари - умеренный. Для агента считайте время на шаг и на весь запуск. Для batch смотрите не только на ответ одной задачи, но и на очередь, повторы и общий срок обработки.

Следующий шаг проще, чем кажется: вынесите все лимиты в один конфиг. Не держите таймауты в SDK, в бизнес-логике и в воркере одновременно. Когда значения лежат в разных местах, команда чинит одно узкое место и случайно ломает другое.

Обычно хватает такого набора параметров:

  • timeout до первого токена
  • timeout на весь ответ
  • лимит на число шагов агента
  • число ретраев
  • бюджет времени на весь job

Дальше проверьте не теорию, а реальные задержки. Возьмите одинаковые запросы, один и тот же размер контекста и прогоните их через несколько моделей и провайдеров. Смотрите не только на среднее время. Картину чаще всего портят длинный хвост, редкие зависания и резкий рост задержки под нагрузкой.

Если данных мало, начните с простого: 20-30 запросов на каждый сценарий утром, днем и вечером. Этого уже хватает, чтобы увидеть, где модель отвечает быстро, а где p95 уезжает настолько, что выбранный лимит теряет смысл.

Если вы тестируете несколько маршрутов через один OpenAI-совместимый endpoint внутри РФ, такой прогон удобно делать через RU LLM на rullm.com. Можно сравнивать задержки по разным провайдерам и моделям без смены SDK, кода и промптов. Для команд с требованиями 152-ФЗ это еще и способ проверить сценарии, где логи и бэкапы остаются в РФ.

Хороший результат здесь выглядит просто: у вас есть четыре профиля, один конфиг и таблица с реальными задержками. После этого лимиты перестают браться с потолка.

Часто задаваемые вопросы

Почему нельзя поставить один timeout на все LLM-задачи?

Нет. Один лимит почти всегда вредит сразу двум режимам: быстрые запросы ждут лишнее, а длинные обрываются слишком рано. Проще и надежнее держать отдельные профили хотя бы для автодополнения, саммари, агента и batch.

Какой timeout выбрать для автодополнения?

Для inline-подсказок обычно держат очень жесткий предел: примерно 300–700 мс. Если ответ приходит позже, человек уже печатает дальше, и подсказка только мешает.

Если сервис не успевает, сначала режут контекст и длину ответа, а не растягивают ожидание.

Сколько можно ждать саммари без вреда для UX?

В интерфейсе многим хватает 5–20 секунд, если текст не очень большой. Для длинных документов лучше сразу уводить задачу в фон и давать ей отдельный дедлайн, например до пары минут.

Смотрите на объем входного текста и формат ответа. Структурированный JSON или длинный разбор почти всегда требует больше времени, чем короткий абзац.

Как считать timeout для агента, если у него много шагов?

Для агента задают минимум два ограничения: на один шаг и на весь запуск. Лимит шага спасает от медленного инструмента или зависшего запроса, а общий дедлайн не дает агенту крутиться слишком долго.

Еще стоит ограничить число шагов и рано резать пустые повторы. Если агент несколько раз делает одно и то же без нового результата, лучше остановить запуск.

Чем client timeout отличается от общего дедлайна операции?

Клиентский timeout — это момент, когда интерфейс перестает ждать. Общий дедлайн операции — это весь бюджет времени на сервере, включая очередь, ретраи, инструменты и постобработку.

Эти значения часто не равны. Клиент может ждать 8–10 секунд, а сервер завершит работу позже и отдаст результат асинхронно.

Нужно ли делать retry после timeout?

Не всегда. В UI лишний retry часто уже бесполезен: пользователь ушел, а ответ потерял ценность. В batch повторы полезнее, потому что там важнее довести больше задач до конца.

Правило простое: делайте retry там, где он реально повышает успех, а не просто добавляет паузу и расход.

Почему среднего времени ответа недостаточно?

Среднее время ответа почти ничего не гарантирует. Смотрите хотя бы на p95 и p99, а еще на долю запросов, которые упираются в timeout.

Именно длинный хвост обычно ломает продукт: один из десяти медленных ответов заметнее, чем красивое среднее на дашборде.

Когда задачу лучше сразу отправлять в фон?

Когда задача не требует мгновенного ответа, лучше не держать человека у экрана. Длинные саммари, разбор больших документов и пакетные прогоны обычно удобнее запускать асинхронно.

Так вы не ломаете интерфейс и не прячете долгую работу за случайным timeout.

Как понять, где именно теряется время в LLM-запросе?

Разбейте путь запроса на этапы и логируйте каждый из них отдельно. Полезно видеть время в очереди, время до первого токена, полную генерацию, вызовы инструментов, ретраи и запись результата.

Тогда вы чините реальное узкое место, а не обвиняете модель во всех задержках.

Что стоит проверить перед релизом, чтобы timeout не сломал сервис?

Сначала вынесите лимиты в один конфиг и разделите их по сценариям. Потом прогоните одинаковые запросы утром, днем и вечером и сравните не только среднее, но и p95.

Перед релизом проверьте запасной путь: короткий ответ вместо длинного, перевод в фон или более быстрый маршрут. Это спасает чаще, чем еще пара секунд ожидания.