The post has been translated automatically. Original language: Russian
The AI agent demo almost always looks convincing: the model gets the task, calls up a couple of tools, and returns the result. The problems begin when the chain becomes longer than three steps, and it's not about a weak model.
Where exactly is the crash happening
- The error accumulates. With 95% accuracy at each step, after ten steps, about 60% remains. The agent doesn't make a lot of mistakes, he makes mistakes little by little and repeatedly.
- The context is overflowing with garbage. Each call to the tool adds a raw response to the history: JSON for a thousand lines, logs, duplicates. After a few steps, the model searches for a task among its own intermediate results.
- The model does not distinguish between "failed" and "turned out empty". An empty API response is often interpreted as a valid result, and the agent confidently continues to work on an empty basis.
- There is no stopping point. Without an explicit completion criterion, the agent either spins in a loop or stops before the task is completed.
What helps in practice
- Compress the results of the tools. The extracted fields should go into the context, not the full body of the response. This reduces both the request price and the noise level.
- Divide the task into deterministic sections. Filtering, sorting, and arithmetic should be left to the usual code. The model is good at choosing an action, not executing it.
- Do the verification in a separate step. A cheap model or a simple validation function at the output intercepts most of the silent errors.
- Log every intermediate solution, not just the final answer. Without tracing the steps, debugging the agent turns into guessing.
- Set a budget: maximum steps, maximum tool calls, timeout. A restriction from above is almost always more useful than hoping that the model will figure it out on its own.
Things to keep in mind when choosing an architecture
The more freedom an agent has, the worse the reproducibility. A rigid pipeline with one or two model solutions is usually more reliable than a free loop and debugging is much easier. A free agent scheme is justified where scenarios are unknown in advance, for example, in research tasks or when working with poorly structured data.
How to measure
Evaluating an agent based on the final answer alone is not enough. It is more useful to look at three indicators: the proportion of tasks that are completely solved, the average length of the successful chain, and the proportion of steps with the wrong tool. The third indicator most often indicates that the problem is not in the quality of generation, but in the description of the tools.
Most improvements in agent-based systems are achieved not by changing the model, but by working with context, constraints, and checks. Boring engineering, which determines whether a demo will survive to production.
And what is your practical limit on the length of the chain, after which the agent ceases to be reliable?
Когда сервис начинает тормозить, первое предложение обычно звучит как «добавим ресурсов». Иногда это работает, но чаще проблема не в мощности, а в том, что одна и та же работа выполняется заново тысячи раз в минуту.
Что обычно тормозит на самом деле
- Запросы в базу за данными, которые не менялись сутками. Справочники, настройки, тарифы, списки городов. Каждый пользователь платит за поход в базу, хотя ответ у всех одинаковый.
- Проблема N+1. Один запрос списка и потом по одному запросу на каждый элемент. На двадцати элементах незаметно, на двух тысячах страница просто не открывается.
- Отсутствие индексов на полях, по которым идёт фильтрация. База честно перебирает всю таблицу, и с ростом данных время растёт линейно.
- Синхронные вызовы внешних API внутри обработки запроса. Пользователь ждёт, пока ваш сервис ждёт чужой сервис.
Кэш и его подводные камни
Кэш ускоряет, но добавляет новый класс задач. Основных три.
- Инвалидация. Данные изменились, а в кэше лежит старое значение. Самое частое решение это TTL, но подобрать его непросто: слишком долгий даёт устаревшие данные, слишком короткий убивает смысл кэша.
- Cache stampede. TTL истёк, и сразу сотня параллельных запросов пошла в базу за одним и тем же значением. Лечится блокировкой на пересчёт или обновлением значения заранее, до истечения срока.
- Кэширование пустых ответов. Если по ключу ничего нет и это не сохраняется, каждый такой запрос уходит в базу. Иногда стоит кэшировать и сам факт отсутствия данных.
Порядок действий, который экономит время
- Сначала измерить. Профилировать запрос и увидеть, где реально уходит время, вместо догадок.
- Устранить очевидное: индексы, N+1, лишние выборки полей.
- Только потом кэшировать, начиная с данных, которые меняются реже всего.
- Вынести из обработки запроса всё, что можно сделать асинхронно: отправку писем, генерацию отчётов, обращения к внешним сервисам.
- Масштабировать инфраструктуру последним шагом, когда понятно, что упор именно в ресурсы.
Почему порядок важен
Если добавить сервер, не разобравшись с запросами, вы получите то же самое поведение, только дороже. Плохой запрос на более мощном железе остаётся плохим запросом, а счёт за инфраструктуру растёт каждый месяц. Оптимизация же выполняется один раз.
Отдельно стоит помнить про мониторинг: без метрик времени ответа по перцентилям (не по среднему) вы не увидите, что 5% пользователей ждут по десять секунд.
А что у вас чаще всего оказывалось причиной деградации: запросы к базе, внешние вызовы или всё же нехватка ресурсов?