Несоответствие, если сказать прямо
У человеческого веб-трафика есть форма. Он пульсирующий, привязан к сессии и самоограничивающийся: человек открывает страницу, читает её, кликает и в конце концов останавливается. Браузеры не разворачиваются на тысячу URL параллельно, а человек, получивший 429, обычно сдаётся или ждёт. Планирование мощностей последние двадцать лет строилось на этом допущении.
У трафика агентов форма другая. Он параллельный, постоянный и дёшево усиливается. Один оркестратор может породить субагентов, каждый из которых повторяет один и тот же шаблон запросов с множества исходных адресов, повторяет попытки при сбое без усталости и держит сессию открытой часами, пока прорабатывает план извлечения. Стоимость отправки ещё одного запроса близка к нулю, поэтому естественное равновесие — не «вежливо прочитать и уйти», а «повторять, пока что-нибудь не поддастся».
Это несоответствие теперь видно с обеих сторон. Сайты, публикующие справочные материалы, сообщают о наводнении автоматизированными клиентами, которые ведут себя совсем не как читатели, а другие сайты начали закрывать доступ агентов за явными условиями и техническими средствами контроля. Корпус показывает обе половины режима отказа: агенты перегружают справочный сайт, а операторы отвечают, ограничивая машинный доступ целиком. Ни один из исходов не является устойчивым решением.
Корневая причина — не объём. Она в том, что сайт понятия не имеет, что делает клиент, а клиент не обязан об этом говорить.
Почему ограничение скорости по IP предполагает не того клиента
Большинство ограничений скорости написано для клиента, который ведёт себя как браузер. Оно привязывается к IP-адресу или API-ключу, применяет token bucket и возвращает 429 с Retry-After. Для браузера это замкнутый цикл: человек видит ошибку, вкладка перестаёт загружаться, корзина токенов пополняется.
Агенты ломают каждую часть этого цикла.
- Повторные попытки игнорируют намерение backoff. Клиентская библиотека, которая считает 429 временной ошибкой, будет повторять попытку, часто с джиттером экспоненциального backoff, который всё равно умножается на субагентов.
- Разветвление побеждает привязку к IP. Нагрузка, зеркалируемая по адресам, регионам или пулам исходящего трафика, выглядит как множество благонадёжных клиентов, а не как один агрессивный.
- Зеркалирование побеждает лимиты на эндпоинт. Если лимит на путь, агент распределяет работу по путям. Если на ключ, агент распределяет по ключам. Лимит хорош ровно настолько, насколько хороша идентичность, к которой он привязан.
Хуже того, лимиты по IP наказывают не ту сторону. Общий NAT, корпоративный прокси или CI-раннер могут быть заторможены из-за того, что одна нагрузка за ними вела себя неправильно. Лимит реален, а подотчётности нет.
Что содержит контракт на допуск
Альтернатива — перестать относиться к запросам агентов как к анонимному HTTP и начать относиться к ним как к согласованной нагрузке. Контракт на допуск — это небольшое явное соглашение, устанавливаемое до того, как первый настоящий запрос достигнет сервиса-источника. В нём три части.

Заявленная цель и область действия, привязанные к идентичности нагрузки
Контракт называет, что делает клиент и какие ресурсы он охватывает. Ключевое: он привязан к идентичности нагрузки — проверяемому удостоверению для выполняемой задачи, — а не к статическому API-ключу, который можно скопировать, передать или слить. API-ключ идентифицирует арендатора; идентичность нагрузки идентифицирует задачу. Различие важно, потому что бюджеты, цели и отзывы — это свойства задач, а не организаций.
Область действия следует выражать как набор разрешённых операций и префиксов ресурсов, а не как описание свободным текстом. «Извлекать документацию под /docs/» — исполняемо. «Исследовательский ассистент» — нет.
Бюджет параллелизма и запросов в терминах сайта
Бюджет должен быть выражен в единицах, которые контролирует сайт, а не в единицах, которые предпочитает клиент. Это значит:
- максимальное число запросов в полёте, а не только запросов в секунду;
- общий лимит запросов за время жизни контракта, чтобы долгоиграющая задача не могла тихо потреблять неограниченную мощность;
- отдельный, меньший лимит для операций, изменяющих состояние.
Выражение бюджета в терминах сайта — это то, что делает его защитимым. Клиент не может утверждать, что его собственное понятие «одного логического запроса» должно соответствовать пятидесяти вышестоящим вызовам.
Истечение срока и отзыв, работающие в середине выполнения
Контракты истекают по умолчанию. Что важнее, их можно отозвать, пока задача выполняется, и отзыв вступает в силу на периферии при следующем запросе, а не в следующем окне выдачи. Именно здесь большинство реализаций ошибаются: они рассматривают допуск как разовый шлагбаум при выдаче токена, из-за чего неправильно ведущий себя клиент сохраняет доступ до истечения токена.
Дескриптор отзыва — это короткий идентификатор, который сайт может аннулировать, плюс плоскость управления, распространяющая это аннулирование на каждый периферийный узел. От клиента ожидается, что он обработает отзыв как нормальный, неповторяемый исход — а не как временную ошиб

Завершайте контракт на периферии
Решения о допуске принадлежат шлюзу или слою CDN, перед сервисами-источниками. Источники никогда не должны видеть несогласованный трафик; к моменту, когда запрос достигает сервера приложения, контракт уже проверен, бюджет уменьшен, а решение залогировано. Это сохраняет единообразие принуждения по всем сервисам и предотвращает распространённый сбой, когда источник одной команды защищён, а другой — нет.
Периферия — также единственное место с достаточной точкой обзора, чтобы принуждать лимиты параллелизма, потому что она видит все запросы в полёте для идентичности нагрузки независимо от того, на какой источник они нацелены.
Записывайте решения о допуске как структурированные события
Каждый allow, deny, throttle и revoke должен порождать структурированное событие с идентичностью нагрузки, идентификатором контракта, классом операции и причиной. Смысл в диагностируемости: злоупотребление должно выглядеть как нарушение политики с именованным контрактом, а не как необъяснимый всплеск трафика, на атрибуцию которого уходит час.
Это также меняет операционный разговор. Вместо вопроса «почему вырос трафик?» вопрос становится «какой контракт превысил свой бюджет, и было ли это ожидаемо?» — вопрос с владельцем и ответом.
Отделяйте извлечение только для чтения от вызовов, изменяющих состояние
Чтения и записи имеют разные профили риска и должны иметь разные разрешения. Контракт на извлечение может быть широким, дешёвым и легко отзываемым. Контракт, изменяющий состояние, требует более сильного разрешения, отдельного бюджета и, в идеале, явного шага одобрения человеком или политикой. Смешение их — это то, как агент, который должен был суммировать страницу, в итоге публикует что-то в эндпоинт, потому что удостоверение, которое он держал, было с избыточной областью действия.
Конкретный механизм: выдавайте из контракта короткоживущие токены с областью действия по операции, и пусть периферия отклоняет любой запрос, чьи метод и путь выходят за пределы объявленного класса операции токена, даже если лежащая в основе идентичность нагрузки действительна.
Что это не решает
Контракт на допуск не делает агентов заслуживающими доверия. Он делает их подотчётными и останавливаемыми. Клиент, который лжёт о своей цели, всё равно будет лгать — декларация это механизм координации, а не граница безопасности.
Именно поэтому путь отзыва важнее декларации. Если единственное, что стоит между нечестным клиентом и источником, — это самостоятельно заявленная строка цели, система — театр. Если сайт может отрезать нагрузку в середине выполнения, приписать решение именованному контракту и увидеть нарушение в структурированных логах, тогда декларация становится полезным сигналом, а не несущим допущением.
Честный компромисс — трение. Согласование контракта добавляет шаг настройки, требует от клиентов нести идентичность нагрузки и вынуждает сайты поддерживать плоскость управления для отзыва. Сайты, которые это пропускают, будут и дальше поглощать трафик агентов так, будто это веб-трафик, и продолжать обнаруживать, что клиент на другом конце не устаёт.
