Як вижити під час різких сплесків трафіку в багатоагентних системах за допомогою трьохрівневого контракту.
Підтримка роботи багатоагентних систем під час зростання навантаження в десять разів: контролер черги, обмеження пропускної здатності кожного інструменту та синхронні перевірки політик, а також метрики та демонстрація різкого зростання навантаження.
Джерела: Multi-Agent Orchestration in Production: Handling Traffic Spikes at Scale
Граф агентів може функціонувати стабільно при 10 запитах на секунду, але зламатися при 100. Запити накопичуються, перевірки політик ігноруються, виклики інструментів конфліктують між собою, і система, яка здавалася надійною, перетворюється на джерело проблем. Рідко коли причиною є самі агенти. Насправді бракує чіткої домовленості між чергою, шаром оркестрації та механізмами контролю. Більшість команд усвідомлюють цю прогалину лише тоді, коли вже починається реальний трафік.
Чому сплески трафіку настають раніше, ніж очікувалося
Системи агентів виходять з демо-режиму та переходять у реальну експлуатацію, тому сплески є неминучими: раптова розпродаж, функція, яка швидко набирає популярності, запланована операція з обробки даних чи просто кожен користувач, який звертається до API у вівторок вранці. Коли навантаження зростає, відбуваються дві речі одночасно.
По-перше, маршрутизація відбувається в реальному часі. Вибір того, який агент буде обробляти запит, або рішення про те, чи потрібно його відразу відправити у чергу, є вимірюваним процесом.
По-друге, системи схильні до несправностей під тиском. Це зазвичай не через те, що інженери в паніці обходять перевірки. Це наївне оброблення помилок, яке за замовчуванням дозволяє дії при виході за час, або альтернативний маршрутизаційний механізм, який тихо ігнорує проміжні модулі валідації. Коли контроль за дотриманням правил зникає під навантаженням, зазвичай причиною є саме цей архітектурний антипаттерн, а не людське втручання.
Лікуванням є чітка, обов’язкова до виконання угода між трьома сторонами: чергою (що потрапляє всередину), графом оркестрації (куди це йде) та двигуном політик (що він може робити). Домовтесь про цю угоду заздалегідь, і раптовий сплеск навантаження стане вирішеним проблемою, а не надзвичайною ситуацією.
Контракт із трьома шарами
Шар 1: черга як контролер
Черга — це перше місце для застосування правил. Перш ніж будь-який запит досягне агента, він проходить перевірку контракту, яка охоплює три аспекти:
- Пріоритет. Запити не є однаковими. Інтерактивні запити користувачів можуть мати вищий пріоритет, ніж пакетні завдання, а клієнт, який платить, може випередити клієнта з безкоштовного тарифу. Черга має забезпечувати таку ієрархію, щоб агентам ніколи не доводилося про неї знати.
- Обмеження та квоти на використання ресурсів. Найекономніше відмовити ще до того, як будуть витрачені ресурси обчислювальної системи. Користувач, який досяг щоденної квоти API, має отримати чітку відмову, а не місце в черзі, що коштує значно менше, ніж обробка запиту агентом.
- Дотримання схеми. Дані, які система не може обробити, мають бути відхилені на цьому етапі, а не виявлені під час роботи агента.
Цей рівень гарантує, що кожен запит у черзі пройшов перевірку, був ранжований та схвалений для використання ресурсів.
Рівень 2: оркестрація визначає маршрутизацію та темп виконання
Після того, як запит потрапляє у чергу, система оркестрації вибирає його напрямок та те, що йому дозволено робити. Саме тут контролюється конкурентність та доступ до інструментів.
Контракт маршрутизації відповідає на кілька запитань. Яка група агентів має обробляти запит – наприклад, швидкі агенти для простих запитів та повільніші для складних обчислень? Скільки запитів може обробляти кожен агент одночасно? Що відбувається, коли всі агенти зайняті: запит очікує у черзі, відхиляється чи переходить на альтернативний варіант?
Контракт обмеження використання інструментів враховує те, що інструменти відрізняються один від одного. Виклик зовнішнього API сто разів на секунду зовсім не схожий на виконання локальних операцій. Кожен інструмент має своє власне обмеження на кількість одночасних викликів. Інструмент, який базується на базі даних, може дозволити десять одночасних викликів, тоді як інструмент, який використовує API сторонньої організації, – п’ять. Коли інструмент досягає свого ліміту, запит очікує у власній черзі цього інструмента, а не у головній черзі.
Щоб підтримувати стабільність черг інструментів та запобігати ланцюговим збоям, примітиви виробничого рівня допомагають:
- Механізми Circuit Breaker та token buckets швидко реагують на проблеми на рівні інструментів, запобігаючи надмірним спробам повторного виконання, коли залежність перевантажена.
- Черги для некоректних повідомлень зберігають пошкоджені або несправні дані інструментів, тож одна погана заявка ніколи не зупиняє весь цикл роботи агента.
- Механізми типу „Leaky Buckets“, які використовуються для кожного інструменту, застосовують його власні обмеження на швидкість обробки, що захищає паралельні процеси агентів від зовнішніх обмежень.
Завдяки цим механізмам вузькі місця на рівні інструментів залишаються контрольованими та видимими, не поширюючись на всю систему. Обіцянка цього рівня: заявка надсилається до агента з вільною потужністю, кожен інструмент дотримується свого ліміту одночасних операцій, а якщо інструмент перевантажений, заявка чекає на нього, а не на агента.
Рівень 3: політики, які ніколи не змінюються
Складність полягає у тому, що політики мають виконуватися щоразу, навіть під високим навантаженням. Не існує опції «перевірити пізніше» чи «це, здається, безпечно».
Контракт політики містить чотири пункти:
- Перевірка політики виконується перед кожним викликом інструменту, синхронно та блокуючи подальші дії.
- Ця перевірка є дешевою — не більше кількох мілісекунд. Якщо це не так, конструкція є неправильною.
- Якщо перевірка провалюється, запит також провалюється. Агент не має можливості спробувати ще раз чи домовитися.
- Провали фіксуються та відстежуються, а зростання кількості провалів політик є самим по собі сигналом.
Типові правила виглядають так: агент може використовувати лише інструменти, позначені як «тільки для читання» для цього користувача; інструмент може працювати лише для автентифікованого користувача; агент може здійснювати не більше п’яти викликів інструментів за запит. Цей шар гарантує, що перед кожним викликом інструменту відбувається перевірка, а правила є швидкими, детермінованими та абсолютними.
Структура конвеєра
У мінімальному псевдографі запит надходить через контролер черги, потім потрапляє до маршрутизатора, доходить до агента, а кожен виклик інструменту перед виконанням проходить перевірку відповідно до правил та обмеження, встановлені для кожного інструменту.
[ Incoming Request ]
│
▼
[ Queue Gatekeeper ]
• Validate Schema
• Enforce Rate Limits
• Assign Priority
│ (Pass)
▼
[ Orchestration Router ]
• Check Agent Capacity
• Route to Target Node
│
▼
[ Tool-Level Gate ]
• Sync Policy Check
• Per-Tool Concurrency Limits
• Circuit Breaker / DLQ
│ (Pass)
▼
[ Tool Execution ]
Важливою деталлю є місце застосування правил. Вони діють на рівні інструментів, а не на рівні агентів, що запобігає тому, щоб агенти випадково обійшли їх, використовуючи інструменти неправильним чином.
Сценарій різкого зростання навантаження з умовою наявності та відсутності контракту
Уявіть собі агента служби підтримки клієнтів, який може шукати замовлення, обробляти повернення грошей та надсилати електронні листи, і раптово обсяг трафіку зростає в десять разів.
Без контракту проблема розвивається поетапно:
- Надходження запитів вичерпують кількість доступних агентів.
- Агенти починають чергувати виклики до інструментів, і інструмент send_email накопичує 500 запитів у очікуванні.
- Служба електронної пошти починає виходити за межі часу відповіді.
- Агенти намагаються знову, тож тепер чекає 1 000 викликів.
- Активуються механізми аварійного відновлення. Таймаути чи перевантажені альтернативні маршрути обходять застосування правил, щоб зберегти доступність системи.
- Агент надсилає електронний лист із поверненням грошей неправильному клієнту.
За наявності контракту ситуація розвивається інакше:
- Система керування чергою регулює доступ за пріоритетом та квотою.
- Роутер бачить, що інструмент для надсилання листів досяг свого ліміту одночасних операцій у десять, тому подальші запити на надсилання листів відправляються у чергу до цього інструменту, а не до агента.
- Перевірки політик продовжують виконуватися під час кожного виклику інструменту. Якщо агент намагається надіслати повернення грошей неправильному клієнту, перевірка провалюється, і запит відхиляється.
- Система залишається стабільною. Затримки зростають, але надійність не знижується.
Підсумок
Почніть з LangGraph
Команда, яка вже працює над LangGraph, володіє більшістю примітивів. Агенти та інструменти є вузлами, а ребра — це варіанти маршрутизації; умовні ребра здійснюють маршрутизацію залежно від стану. Що потрібно додати, — це черга спереду, чи то Redis, RabbitMQ, чи проста черга в оперативній пам’яті, а також проміжний компонент політики, який обгортає виклики інструментів.
Сам обгорткувач політики може бути невеликим декоратором, який виконує перевірки та генерує помилку порушення ще до того, як функція інструменту виконається.
from functools import wraps
from typing import Callable, Any
class PolicyViolation(Exception):
"""Raised when policy check fails."""
pass
def enforce_tool_policy(
policy_fn: Callable[[str, dict], bool]
):
"""Sync tool execution guardrail."""
def decorator(func: Callable):
@wraps(func)
def wrapper(*args, **kwargs):
tool_name = func.__name__
context = kwargs.get(
"request_context", {}
)
# Must fail closed
if not policy_fn(tool_name, context):
raise PolicyViolation(
f"Denied: {tool_name}"
)
return func(*args, **kwargs)
return wrapper
return decorator
# Example Usage
def strict_policy_check(tool_name: str, context: dict) -> bool:
if not context.get("is_authenticated"):
return False
if (context.get("role") != "admin" and tool_name.startswith("execute_")):
return False
return True
@enforce_tool_policy(strict_policy_check)
def execute_refund(
order_id: str,
amount: float,
request_context: dict = None
):
# Downstream API call
return f"Refund ${amount} sent: {order_id}"
Виміряйте це
Одного лише впровадження та сподівань недостатньо. Необхідно обладнати систему інструментами для моніторингу та стежити за наступним:
- Глибину черги на кожному рівні.
- Як часто та які інструменти досягають своїх обмежень.
- Чи відхиляють політики запити та чому.
- Затримки p50, p95 та p99, які відстежуються окремо для різних типів запитів.
- Витрати на один запит під навантаженням. Якщо вони зростають, це означає наявність неефективностей.
Скептичний погляд
Цілком справедливо стверджувати, що це схоже на надмірну інфраструктуру для проблеми, якої поки що немає. Система, яка обробляє десять запитів на секунду та залишатиметься при цьому, не потребує її. Інша справа — функція, яка може стати популярною, або корпоративні клієнти з непередбачуваним трафіком; у таких випадках проектування має бути завершене ще до запуску.
Створення системи заздалегідь коштує небагато порівняно з її модернізацією після того, як пік навантаження пошкодив її. Також не варто її перебудовувати. Проста черга, функція перевірки правил та обмеження одночасної роботи окремих інструментів дозволяють вирішити більшість проблем, пов’язаних із піками навантаження. Не потрібні ні алгоритми дистрибуйованого консенсусу, ні моделі машинного навчання для прогнозування навантаження. Важливими є чіткість та обмеження.
Основні моменти
- Піки навантаження виявляють проблеми в дизайні системи. Коли система агентів зламується під впливом високого навантаження, це не через те, що агенти занадто повільні. Ніхто не встановив чітких правил щодо того, як мають взаємодіяти черга, механізм маршрутизації та правила.
- Черга виконує також функцію контролю. Вона може перевіряти запити, визначати їх пріоритет та відхиляти їх, щоб уникнути марнування ресурсів обчислювальної потужності.
- Правила є абсолютними та не підлягають переговорам. Вони виконуються на рівні кожного інструменту синхронно та щоразу, без жодних винятків.
- Обмежуйте роботу інструментів раніше, ніж агентів. Вузькі місця зазвичай знаходяться нижче у ланцюжку, у зовнішніх API чи базах даних, які надають контекст агентам, а не у постачальнику LLM.
- Вимірюйте все: глибину черги, одночасність використання інструментів, кількість помилок політики, відсоткові показники затримки та витрати за запит. Того, що не вимірюється, не можна покращити.
З чого почати
- Запишіть умови черги: що приймається, а що відхиляється.
- Запишіть умови маршрутизації: які агенти виконують які завдання та які є обмеження на одночасність.
- Запишіть умови політики: які перевірки виконуються перед кожним викликом інструменту.
- Створіть систему за допомогою такого інструменту, як LangGraph, додайте шар черги та обгорніть інструменти перевірками політики.
- Пройдіть тест на навантаження. Симулюйте десятикратне зростання навантаження та спостерігайте, що може зламатися.
Усе це найкраще робити ще до запуску в продакшн, поки ще є час спокійно з цим розібратися.
Пов’язані матеріали
- Агент — це цикл while: як LangChain create_agent та LangGraph Fit — Агент, який викликає інструменти, у двадцяти рядках, чотири проблеми продакшну, з якими стикається цикл, та коли варто перейти від LangChain create_agent до графів станів LangGraph.
- Практичні нотатки: я створив цикл дебатів з кількома агентами та жодного разу не перевіряв, що відбувається — Покрокове пояснення до Практичних нотаток: я створив цикл дебатів з кількома агентами та жодного разу не перевіряв, що відбувається: контракти, перевірки та готові фрагменти коду для команд, які використовують цю схему.