Self-service LLM-шлюз на Amazon Bedrock и LiteLLM собирается из предсказуемых частей: прокси на AWS Fargate, управляемая база для ключей и расходов, кэш, менеджер секретов и Application Inference Profiles в Bedrock. Разработчик получает один base URL и персональный API-ключ. Платформа получает контроль доступа и учёт затрат по пользователям. Состав компонентов и поток запроса AWS описывает в материале про self-service LLM gateway на Bedrock и LiteLLM.
Ломается такая схема чаще всего в двух местах. Первое: IAM-политика, где есть только ARN inference-профиля, но нет ресурсов базовой модели, и вызовы падают с AccessDenied. Второе: незаполненные cost-поля в конфигурации модели, из-за чего LiteLLM не может корректно посчитать расход, а бюджеты не срабатывают. Оба сюжета разобраны ниже, с чек-листами проверки.
Что такое self-service LLM-шлюз и кому он нужен
Паттерн простыми словами. LiteLLM работает на задаче AWS Fargate и выставляет foundation-модели Amazon Bedrock за OpenAI-совместимым API. Разработчик направляет свой инструмент на один эндпоинт и аутентифицируется персональным ключом, с самим Bedrock он не работает. Платформа видит расход по каждому пользователю и поведение моделей под нагрузкой.
Какие боли закрываются. Разработчику нужен привычный OpenAI-совместимый клиент и ключ, а не тикет в платформенную команду на каждый новый сервис. Платформе нужны контроль доступа, раздельные квоты по моделям и учёт затрат, причём по людям, а не по общему счёту аккаунта. Шлюз закрывает обе задачи одним сервисом.
В примере из исходного материала фигурируют Claude Sonnet и Claude Haiku. Это иллюстрация, а не рекомендация: набор моделей определяется задачами и доступностью в вашем регионе.
Границы применимости стоит обозначить сразу. Для команды из трёх человек с одним потребителем моделей схема избыточна: CloudFront, ALB, RDS, ElastiCache и Secrets Manager - это постоянная операционная нагрузка и отдельный счёт. Шлюз оправдан, когда потребителей много, у них разные бюджеты, а доступ к Bedrock напрямую выдавать не хочется.
Разработчик и платформа: две стороны одной схемы
Граница ответственности проходит по порталу LiteLLM. Это лёгкое веб-приложение для администраторов и разработчиков, которое может интегрироваться с корпоративным SSO. Операционные инженеры через портал задают политику расходов. Разработчики в этих рамках сами создают API-ключи, без обращения в платформенную команду.
Что остаётся на стороне платформы: состав доступных моделей, лимиты на ключ, IAM-периметр задачи Fargate, алерты по RPM и TPM. Что уходит разработчику: выбор модели в пределах разрешённых, свой ключ, свой бюджет и метрики по своим вызовам. Такое разделение снимает типовой конфликт, когда за скорость выдачи доступа отвечает один человек и он же становится узким местом.
Один нюанс, который лучше узнать до пилота: часть функций самообслуживания и разграничения ролей в LiteLLM относится к платной части. Об этом подробнее в разделе про ограничения.
Архитектура и поток запроса: от клиента до Bedrock
Запрос разработчика идёт по фиксированному маршруту. OpenAI-совместимый клиент обращается к шлюзу через Amazon Route 53, Amazon CloudFront и Application Load Balancer. На ALB запрос попадает в LiteLLM на Fargate, где аутентифицируется персональным API-ключом. Дальше LiteLLM обращается к Amazon RDS (PostgreSQL) за состоянием виртуальных ключей и расходов, к Amazon ElastiCache for Valkey как к кэшу и к AWS Secrets Manager за секретами. Вызов модели идёт в Amazon Bedrock Application Inference Profiles через scoped AWS IAM task role, а Amazon CloudWatch фиксирует метрики запросов в минуту (RPM) и токенов в минуту (TPM) и квотный алерт. Так этот поток описан в первоисточнике.
Задача LiteLLM на Fargate масштабируется по target-tracking политике на загрузку CPU. Практический вывод: пики трафика на шлюзе приходят вместе с ростом числа одновременных стримов, поэтому политику стоит привязать к наблюдаемому поведению, а не к среднему за сутки.
| Компонент | Роль в схеме |
|---|---|
| Amazon Route 53 | DNS-имя шлюза, на которое настроены клиенты |
| Amazon CloudFront | CDN-слой на входном контуре перед ALB |
| Application Load Balancer | Балансировка запросов между задачами LiteLLM |
| LiteLLM на AWS Fargate | Аутентификация по персональному ключу, OpenAI-совместимый API, политика расходов |
| Amazon RDS (PostgreSQL) | Состояние виртуальных ключей и расходов |
| Amazon ElastiCache for Valkey | Кэш |
| AWS Secrets Manager | Секреты шлюза |
| Amazon Bedrock Application Inference Profiles | Вызов моделей с изоляцией квот |
| Amazon CloudWatch | Метрики RPM и TPM, квотный алерт |
Входной контур: Route 53, CloudFront и ALB
Три компонента на входе решают разные задачи. Route 53 даёт стабильное DNS-имя, которое прописывается в инструментах разработчиков и не меняется при пересборке инфраструктуры. CloudFront стоит перед ALB как CDN-слой. ALB распределяет запросы по задачам LiteLLM и выводит из балансировки нездоровые.
Убирать что-то из этой цепочки можно, но осознанно. Без CloudFront останется прямая связка Route 53 и ALB, что проще и дешевле для внутреннего контура. WAF, терминация TLS и правила кэширования на уровне CloudFront - это общие места архитектуры, а не то, что описано в исходном паттерне. Ответы LLM кэшировать на CDN обычно не стоит: контекст запроса уникален, а политика хранения таких ответов требует отдельного решения.
Состояние и секреты: RDS PostgreSQL, ElastiCache for Valkey, Secrets Manager
RDS PostgreSQL хранит состояние виртуальных ключей и расходов LiteLLM. Это источник правды для бюджетов: если запись о расходе не обновилась, никакой лимит не сработает. Отсюда практическое следствие, ошибки в cost-полях конфигурации модели бьют именно по бюджетам, а не по доступности сервиса. Сервис продолжит отвечать, просто бесплатно с точки зрения учёта.
ElastiCache for Valkey работает как кэш LiteLLM. Не путайте его с кэшированием префикса промпта на стороне модели: это разные механизмы с разной экономикой. Про второе есть отдельный разбор, prompt caching для AI-агентов на Amazon Bedrock.
Secrets Manager держит секреты шлюза: ключи доступа к провайдерам, строку подключения к базе, служебные токены. Схемы таблиц и версии LiteLLM в исходном материале не раскрываются, поэтому планируйте миграции базы как обычную задачу эксплуатации, с бэкапами и проверкой восстановления.
Вызов модели и наблюдаемость: Application Inference Profiles и CloudWatch
LiteLLM вызывает Amazon Bedrock Application Inference Profiles от имени scoped IAM task role. Профиль задаёт отдельную единицу квоты, поэтому лимиты по разным моделям не смешиваются в общий аккаунтный котёл.
CloudWatch собирает RPM и TPM и обслуживает квотный алерт. Эти две метрики закрывают базовый вопрос: упираемся ли мы в лимит модели или в собственные настройки шлюза. Телеметрия на уровне промптов, например через Langfuse, даёт другой разрез, качество и содержание запросов, но деталей интеграции в исходном материале AWS нет. Считайте это точкой расширения, которую нужно проектировать отдельно.
Изоляция квот и IAM: Application Inference Profiles и CDK
Application Inference Profiles нужны, когда у моделей разные лимиты, а потребителей много. Один общий счётчик на аккаунт означает, что тяжёлый эксперимент одного разработчика съедает квоту у всей команды. Профиль на модель (или на пару модель плюс команда) разводит эти потоки и делает алерты осмысленными.
CDK-конструкции в исходном материале иллюстративные. Из них собирается собственная версия паттерна, готового продакшен-развёртывания там нет.
Почему одного ARN профиля в IAM недостаточно
Ситуация типичная: в политике роли задачи указан ARN inference-профиля, запрос всё равно отклоняется с AccessDenied. Причина в том, что при вызове через профиль проверка прав идёт не только на ресурсе профиля, но и на ресурсах базовой модели, которую профиль маршрутизирует. Политика, покрывающая только ARN профиля, этот случай не закрывает.
Для моделей, которые вызываются через inference profile, а не напрямую по ARN foundation-модели, IAM-политика должна разрешать вызов и на ресурсе inference profile, и на ресурсе базовой модели. Если разрешён только один тип ресурса, запрос завершается с AccessDeniedException. Кроме разрешения на вызов модели, для работы с inference profile может потребоваться действие bedrock:GetInferenceProfile.
Отдельный случай - кросс-региональный вызов. AccessDeniedException возникает, когда у IAM-роли нет прав на вызов API в целевых регионах, куда профиль направляет запрос. Bedrock при cross-region inference автоматически выбирает регион в пределах выбранной географии, включая регионы, которые не были включены для ресурсов и IAM-данных. Поэтому в политике нужно учитывать ресурсы регионов, куда профиль может маршрутизировать запрос, а в организациях с SCP - расширять и сами Service Control Policies, чтобы cross-region inference не требовал отдельного управления каждым новым регионом.
Чек-лист проверки, когда вызов через профиль не проходит:
- в policy перечислены ресурсы базовой модели, а не только ARN профиля;
- добавлено действие
bedrock:GetInferenceProfile, если оно требуется для вашего способа вызова; - регион и аккаунт в ARN совпадают с теми, где реально работает задача Fargate;
- нет явного Deny в другой политике, прикреплённой к той же роли или к boundary-политике;
- для кросс-регионального вызова (Global CRIS) в политике учтены ресурсы тех регионов, куда профиль может увести запрос, и при необходимости расширены SCP.
Точный набор action и resource зависит от модели и способа вызова, поэтому сверяйте политику с документацией по своей модели, а не копируйте JSON из чужой статьи. Про региональные и IAM-нюансы при работе с новыми моделями в Bedrock есть отдельный материал, Claude Fable 5.1 в AWS Bedrock.
Практика CDK: что параметризовать
Смысл CDK здесь в том, чтобы новая модель добавлялась параметром, а не правкой пяти стеков. Разумный минимум для параметризации:
- список моделей, их профилей и cost-значений в одном месте;
- IAM-ресурсы базовых моделей, выводимые из этого же списка;
- переменные окружения LiteLLM, включая base URL и настройки кэша;
- секреты в Secrets Manager, а не в переменных окружения задачи;
- размер задачи Fargate и политики Auto Scaling;
- алиасы моделей, которые видят разработчики, отдельно от внутренних ARN.
Разделение внешнего имени модели и внутреннего ARN позволяет менять профиль без перевыпуска ключей у потребителей.
Контроль расходов: почему бюджеты не срабатывают и как это исправить
Механика отказа простая. LiteLLM считает стоимость запроса из количества токенов и цены за токен, заданной в model_info. Для расчёта используются параметры input_cost_per_token и output_cost_per_token. Если модель подключена по inference-profile ARN и эти поля не заполнены, LiteLLM не получает цену за токен и не может корректно отнести стоимость вызова к spend. Дальше цепочка разворачивается сама: расход не растёт, бюджет не превышен, лимит не срабатывает, ответ 429 не приходит. Деньги тратятся, счётчик стоит.
LiteLLM относит spend каждого запроса одновременно к ключу, пользователю, команде и организации и проверяет бюджеты на каждом уровне: запрос блокируется, когда любой уровень на его пути превышает бюджет. Поэтому корректные cost-поля критичны именно для бюджетов, а не для доступности сервиса.
В исходном материале AWS этот момент не разобран, поэтому воспринимайте его как практику эксплуатации, которую нужно проверить по документации LiteLLM вашей версии. Проверка занимает минуты и стоит того.
Чек-лист по бюджетам:
- Для каждой модели и каждого профиля заполнены input_cost_per_token и output_cost_per_token.
- Цены соответствуют актуальному прайсу провайдера и модели, а не скопированы с прошлогодней конфигурации.
- Бюджеты привязаны к ключам, командам и пользователям, а не только к общему аккаунту.
- Тестовый запрос реально увеличивает spend в интерфейсе LiteLLM.
- При превышении бюджета приходит именно 429, а не молчаливый пропуск запроса.
Пятый пункт проверяется один раз и вручную: поставьте заведомо крошечный лимит, сделайте несколько вызовов и убедитесь, что шлюз начал отказывать. Без такой проверки вы не знаете, работает контроль или создаёт видимость.
Ставки зависят от того, куда уходит запрос. Кросс-региональный инференс и разные режимы обработки контекста дают разные цены за токен, поэтому в конфигурации должны быть значения для каждого фактически используемого варианта. Общую картину по региональным изменениям и контролю расходов в Bedrock удобно держать под рукой, обновления Amazon Bedrock и AgentCore за август 2026.
Подводные камни эксплуатации: таймауты, fallback, CI/CD и память Fargate
Эти грабли редко видны на стейдже и почти всегда проявляются в проде. Конкретных значений в исходном материале нет, поэтому ниже принципы и способ подобрать числа под свою нагрузку.
Таймауты и extended thinking
Режим extended thinking заставляет модель рассуждать до выдачи ответа, поэтому ответ приходит позже, чем при обычном вызове. Дефолтные таймауты клиента, ALB и LiteLLM проектировались под обычные ответы и могут обрывать такие запросы. Точные значения задержек зависят от модели и длины рассуждения, поэтому ориентируйтесь на замеры на своей нагрузке.
В LiteLLM таймаут LLM-запроса настраивается в секундах через litellm.request_timeout: по его истечении возникает Timeout error. Правило согласования: самый длинный таймаут ставится на самом медленном участке, иначе верхний уровень рвёт соединение раньше, чем нижний успевает ответить. Проверьте три места: настройку HTTP-клиента в инструменте разработчика, idle timeout балансировщика и таймаут запроса в LiteLLM. Для extended thinking ориентируйтесь на фактическое распределение длительности ответов, а не на среднее значение.
Повторные попытки вместо fallback
Fallback на другую модель выглядит как страховка, а на практике меняет поведение сервиса без ведома потребителя. Промпт, отлаженный под одну модель, на другой может дать иной формат, другой тон и другую длину ответа. Для вызывающего кода это выглядит как нестабильность.
Retry на той же модели предсказуемее: временная ошибка или троттлинг лечатся повтором, а качество ответа не меняется. Fallback оправдан, когда важнее доступность, чем идентичность результата, и когда переключение видно в логах и метриках. Если fallback всё же нужен, делайте его явным: отдельный флаг в конфигурации, запись в лог с указанием фактической модели, отдельный ключ для сценариев, где подмена допустима. Про то, как аккуратно строить деградацию и оценку качества, есть разбор пяти техник контроля качества LLM на Amazon Bedrock.
Отдельные профили для CI/CD
Автотесты генерируют трафик, который выглядит как пользовательский: те же модели, те же ретраи, иногда те же большие промпты. Если он идёт в общий профиль, тесты выедают квоты и бюджеты продакшена, а разбор инцидента превращается в археологию.
Решение: отдельный Application Inference Profile и отдельный виртуальный ключ для CI/CD. Вы получаете изолированные квоты, отдельный бюджет и чистую атрибуцию трафика: по метрикам сразу видно, чей запрос упёрся в лимит. Цена вопроса - одна дополнительная сущность в конфигурации.
Память Fargate и IAM-описания
Память задачи Fargate подбирается по факту, а не по привычке. Признаки нехватки: задача перезапускается по OOM, стриминговые ответы обрываются на середине, латентность растёт при росте числа одновременных запросов. Смотрите на потребление памяти процессом LiteLLM под нагрузкой, а не на холостом ходу, и закладывайте запас на пики. Заниженная память даёт деградацию, которую легко списать на провайдера модели.
Описания в IAM-политиках держите в ASCII. Кириллица и спецсимволы в description ломают часть инструментов валидации и сравнения политик, а диагностика такой ошибки занимает время, которое жалко. Правило скучное, но экономит часы.
Ограничения и что сделать перед продакшеном
Первое ограничение касается лицензирования LiteLLM. Часть функций разграничения доступа и самообслуживания относится к Enterprise-версии: организации как внешний уровень поверх команд и назначение team admin требуют Enterprise-лицензии, тогда как команды остаются верхнеуровневой границей в open source. Полный self-service сценарий, где разработчики сами выдают себе ключи через портал, нужно проверять по актуальной документации LiteLLM для вашей редакции: в бесплатной версии часть таких возможностей недоступна. Либо планируйте лицензию, либо оставляйте выдачу ключей через заявку. Лицензионные условия меняются, сверяйтесь с актуальной страницей проекта перед бюджетированием.
Второе: паттерн не покрывает Amazon Bedrock Guardrails, включая content filtering и grounding. В исходном материале AWS это указано прямо: для простоты изложения такие контроли не рассматриваются, хотя перед продакшеном их обычно включают. Для внутреннего инструмента допустим более мягкий режим. Для клиентского продукта фильтрация и заземление на источники входят в базовые требования.
Третье, чего в паттерне нет по определению: политика работы с логами. Телеметрия на уровне промптов полезна для отладки и оценки качества, но требует ответов на три вопроса. Что именно пишем: полные промпты, только метаданные или хеши. Что маскируем: персональные данные, ключи, внутренние идентификаторы. Сколько храним и кто имеет доступ. Без этого «наблюдаемость» превращается в накопление чувствительных данных в сервисе, который к этому не готов.
Чек-лист запуска и итог
Список проверок перед тем, как открывать шлюз команде:
- base URL и персональные ключи работают, клиент разработчика подключается без правок кода;
- IAM-политика роли задачи включает ресурсы базовой модели и при необходимости
bedrock:GetInferenceProfile, проверено вызовом через профиль; - для кросс-регионального вызова учтены регионы маршрутизации профиля и расширены SCP;
- cost-поля заданы для каждой модели и профиля, значения сверены с прайсом;
- тестовый запрос увеличивает spend, а при превышении бюджета приходит 429;
- таймауты клиента, балансировщика и LiteLLM согласованы под extended thinking;
- retry настроен осознанно, fallback либо выключен, либо логируется с фактической моделью;
- CI/CD вынесен в отдельный профиль и отдельный ключ;
- память задачи Fargate подобрана по нагрузке, а не по значению из примера;
- Guardrails и политика хранения логов продуманы до запуска;
- лицензия LiteLLM Enterprise учтена, если нужны организации, team admin и самостоятельная выдача ключей.
Паттерн даёт реальный контроль доступа и наблюдаемость, но держится на двух скучных вещах: аккуратной IAM-политике и заполненных cost-полях. Без них шлюз продолжит работать и отвечать 200, а контроль расходов останется декорацией. Начните с проверки бюджета на одном ключе: если лимит срабатывает, остальную схему можно масштабировать.