SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor

Как развернуть LiteLLM в качестве LLM-шлюза

Настройте единый OpenAI-совместимый API для всех моделей. Узнайте, как управлять виртуальными ключами, лимитами бюджета и отказоустойчивостью на собственном VPS сервере.

Что делает self-hosted LLM gateway

LiteLLM — это LLM gateway с открытым исходным кодом, который вы размещаете самостоятельно: это единая HTTP-точка входа, к которой обращаются все ваши приложения, а она перенаправляет каждый запрос нужному провайдеру. LLM означает large language model. Шлюз поддерживает OpenAI chat completions API (application programming interface), поэтому любая клиентская библиотека, работающая с OpenAI, будет работать и с ним после двух изменений: базового URL и ключа.

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

Вот что вы получаете после запуска:

  • Единая точка входа. Приложения обращаются к https://gateway.example.com/v1 и запрашивают имя модели, которое вы придумали, например bulk или strong.
  • Виртуальные ключи. Каждое приложение получает собственный ключ с собственным списком разрешенных моделей и лимитом расходов. Вы можете отозвать один ключ, не затрагивая остальные.
  • Резервные варианты (fallbacks). Неудачный вызов или слишком большой промпт автоматически повторяются с использованием другой модели.
  • Журнал записей. Каждый запрос записывается в строку с указанием стоимости, поэтому на вопрос «какое приложение потратило эти средства» есть ответ.

Зачем запускать шлюз самостоятельно

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

Что вам потребуется

  • VPS (виртуальный выделенный сервер) под управлением Ubuntu 24.04 с установленными Docker и плагином Compose.
  • Доменное имя, указывающее на этот сервер, если к шлюзу будут обращаться внешние машины по протоколу TLS (transport layer security).
  • Как минимум один API-ключ провайдера.

Шлюз не выполняет вычисления. Он пересылает запросы и передает потоковые ответы обратно, поэтому нагрузка на CPU зависит от объема запросов, а не от размера модели. Сервер с 1 vCPU без проблем справляется с несколькими внутренними приложениями. Растет только база данных, так как шлюз записывает одну строку расходов для каждого запроса.

Сначала создайте config.yaml

Файл конфигурации определяет, какие модели может запрашивать клиент. Важны четыре раздела верхнего уровня: model_list, litellm_settings, router_settings и general_settings.

model_list:
  - model_name: bulk
    litellm_params:
      model: anthropic/claude-haiku-4-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: strong
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: strong
    litellm_params:
      model: openai/gpt-5.5
      api_key: os.environ/OPENAI_API_KEY

litellm_settings:
  num_retries: 2
  request_timeout: 120
  json_logs: true
  set_verbose: false

router_settings:
  allowed_fails: 3
  cooldown_time: 30
  fallbacks: [{"bulk": ["strong"]}]
  context_window_fallbacks: [{"bulk": ["strong"]}]

general_settings:
  background_health_checks: true
  health_check_interval: 300

model_name — это имя, которое отправляют ваши клиенты. litellm_params.model — это реальная модель, записанная как provider/model. Называйте модели по их назначению, а не по вендору. Приложение, запрашивающее bulk, продолжит работать, когда в следующем месяце вы решите, что bulk должна быть другой моделью.

api_key: os.environ/ANTHROPIC_API_KEY указывает LiteLLM считывать эту переменную во время выполнения. Сам ключ никогда не появляется в файле, что важно, так как config.yaml — это файл, который вы фиксируете в репозитории.

Две записи имеют одинаковое имя strong намеренно. Когда несколько развертываний имеют одинаковый model_name, маршрутизатор считает их взаимозаменяемыми и распределяет запросы для этого имени между ними. Именно так strong продолжает работать, если у одного провайдера возникли временные проблемы: как только развертывание переходит в состояние cooldown (см. ниже), новые запросы для strong направляются на другое.

num_retries: 2 повторяет попытку при возникновении ошибки, которую можно повторить, до 2 раз. Эти повторные попытки могут выбрать другое доступное развертывание в той же группе моделей: документация по архитектуре LiteLLM, проверенная 2026-10-29, описывает повторные попытки внутри группы и переключение на резервные группы как отдельные этапы. Таким образом, повторная попытка для strong может быть направлена другому провайдеру без включения взвешенного переключения при отказе (weighted failover). Переключение на резервный вариант срабатывает только после того, как эти попытки исчерпаны.

allowed_fails и cooldown_time являются параметрами маршрутизатора, поэтому они находятся в разделе router_settings. Прокси строит свой маршрутизатор на основе этого раздела, и в версии v1.95.0 параметр cooldown_time, записанный в litellm_settings, не учитывается, поэтому время cooldown остается равным значению по умолчанию — 5 секунд. cooldown_time: 30 задает время, в течение которого развертывание остается вне ротации после перехода в состояние cooldown. Справочник по конфигурации описывает allowed_fails как количество сбоев, которое развертывание должно превысить в течение cooldown_time, прежде чем оно будет переведено в состояние cooldown. В исходном коде v1.95.0 значением по умолчанию является allowed_fails: 3, и при этом значении маршрутизатор придерживается встроенных триггеров; счетчик сбоев начинает действовать только при установке другого числа. Эти триггеры включают немедленный cooldown при ответе 429 для группы с более чем одним развертыванием, более 50% сбоев в текущую минуту после как минимум 5 запросов для такой группы, а также ошибки, которые маршрутизатор не будет повторять, например 401 из-за неверного ключа. Отдельный триггер также переводит в состояние cooldown одиночное развертывание, когда все запросы в текущую минуту завершаются с ошибкой, а трафик достигает SINGLE_DEPLOYMENT_TRAFFIC_FAILURE_THRESHOLD, что по умолчанию составляет 1000 запросов. Провайдер, возвращающий ошибки 500 серией, перестает опрашиваться при каждом запросе, в то время как единичная ошибка 500 раз в несколько минут никогда не активирует cooldown.

fallbacks и context_window_fallbacks имеют разные триггеры, и второй из них является полезным, который часто пропускают.

  • fallbacks срабатывает, когда основной вызов завершается с ошибкой.
  • context_window_fallbacks срабатывает, когда провайдер отклоняет запрос из-за того, что он превышает контекстное окно модели, поэтому слишком большой промпт отправляется модели с достаточным объемом вместо возврата ошибки вызывающей стороне.

Также существует content_policy_fallbacks для случаев, когда провайдер отказывает по причине нарушения политики контента. Устанавливайте его только в том случае, если у вас есть подходящее место для перенаправления таких вызовов.

Развертывание LiteLLM на VPS с помощью Docker Compose

Создайте каталог, содержащий три файла: config.yaml, docker-compose.yml и .env. В upstream quickstart используется тег latest. Вместо этого зафиксируйте конкретный тег релиза, чтобы docker compose up -d в следующем месяце предоставил вам тот же шлюз, что и сегодня, и чтобы откат версии выполнялся одной строкой.

services:
  litellm:
    image: ghcr.io/berriai/litellm:v1.95.0
    restart: unless-stopped
    command: ["--config", "/app/config.yaml", "--num_workers", "1"]
    ports:
      - "127.0.0.1:4000:4000"
    volumes:
      - ./config.yaml:/app/config.yaml:ro
    env_file: .env
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: litellm
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      POSTGRES_DB: litellm
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U litellm"]
      interval: 5s
      timeout: 5s
      retries: 10
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Compose считывает .env здесь дважды. Первый раз для подстановки ${POSTGRES_PASSWORD} непосредственно в файл compose, и второй раз через env_file для передачи всех переменных внутрь контейнера.

v1.95.0 был текущим релизом в августе 2026 года. Проверьте страницу релизов проекта и зафиксируйте ту версию, которая является актуальной на момент развертывания. Каждый релиз публикует подпись, поэтому вы можете проверить образ перед тем, как доверять ему:

cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0

Строка порта — 127.0.0.1:4000:4000, которая публикует порт только на интерфейсе loopback. Напишите 4000:4000, и ваш шлюз станет доступен из всего интернета, так как Docker добавляет свои правила в цепочку iptables FORWARD, и они проверяются раньше правил ufw, поэтому ufw deny 4000 его не остановит. Это самый распространенный способ, которым self-hosted шлюз оказывается открытым: см. как Docker публикует порт контейнера в обход ufw. Трафик извне должен поступать через reverse proxy.

Храните ключи провайдеров вне образа

Файл .env содержит все секретные данные. Он передается в виде переменных окружения во время выполнения, поэтому он никогда не встраивается в образ и не попадает в систему контроля версий.

LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...

Сгенерируйте два ключа LiteLLM с использованием качественного источника случайных чисел, а затем ограничьте права доступа к файлу:

printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .env

LITELLM_MASTER_KEY — это учетные данные администратора. Они используются для аутентификации в Management API и являются паролем для Admin UI по адресу /ui. Ни одно приложение не должно хранить их у себя.

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

STORE_MODEL_IN_DB=True позволяет добавлять и редактировать модели через Admin UI, не изменяя config.yaml. Это удобно, но разделяет источник истины на две части. Определите, какой из них является приоритетным, и зафиксируйте это решение рядом с конфигурационным файлом.

Логика, согласно которой ключи не должны находиться в конфигурационном файле, применима и к инструментам, которые вы предоставляете агенту. В Хранение секретов провайдеров вне AI-агентов описан этот подход, а в env-файлы и секреты в Docker Compose — техническая реализация.

Запустите систему и отслеживайте первый процесс загрузки:

docker compose up -d
docker compose logs -f litellm

Проверка работоспособности

Существует две неавторизованные проверки и одна авторизованная; они завершаются ошибкой по разным причинам.

curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness

/health/liveliness не требует аутентификации и отвечает "I'm alive!", пока процесс запущен. /health/readiness также не требует аутентификации. Он возвращает JSON-объект с полями "status": "healthy" и db или код 503, если база данных недоступна. Настройте мониторинг на readiness, так как liveliness остается в статусе green даже на шлюзе, который не может найти ни одного виртуального ключа.

Авторизованная проверка взаимодействует с провайдерами:

curl -s http://127.0.0.1:4000/health \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

Она отвечает массивами healthy_endpoints и unhealthy_endpoints. Если модель находится в unhealthy_endpoints с ошибкой аутентификации, это означает, что ключ провайдера в .env неверен или отсутствует — именно эту проблему сейчас нужно обнаружить. Поскольку background_health_checks: true задан, прокси самостоятельно выполняет эти проверки каждые health_check_interval секунд, а /health возвращает последний результат, поэтому опрос этого эндпоинта не отправляет тестовый запрос к вашим провайдерам каждый раз.

Виртуальные ключи и бюджеты для отдельных ключей

Каждое приложение получает собственный ключ, созданный на основе мастер-ключа.

curl -s http://127.0.0.1:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "key_alias": "nightly-summariser",
    "models": ["bulk"],
    "max_budget": 5,
    "budget_duration": "30d",
    "rpm_limit": 60,
    "tpm_limit": 200000
  }'

Ответ содержит поле key, начинающееся с sk-. Эта строка — то, что получает приложение, и это единственное, что ему доступно.

  • models — это список разрешенных запросов для данного ключа. Указанный выше ключ может запрашивать только bulk и ничего больше.
  • max_budget: 5 с budget_duration: "30d" составляет пять долларов США в календарный месяц. LiteLLM сбрасывает бюджет 30d 1-го числа каждого месяца в полночь по UTC (если вы не задали timezone в litellm_settings), а не за скользящий период в 30 дней. Как только ключ исчерпает пять долларов, он перестанет работать до 1-го числа следующего месяца.
  • rpm_limit и tpm_limit ограничивают количество запросов в минуту и токенов в минуту исключительно для этого ключа.
  • key_alias — это идентификатор, который вы увидите в журнале расходов спустя шесть недель. Всегда задавайте его.

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

Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>

Код состояния зависит от версии релиза. В зафиксированной версии v1.95.0 это HTTP 429. Начиная с v1.104.0 по умолчанию используется HTTP 422, а установка budget_exceeded_status_code: 429 в litellm_settings возвращает прежний код. Реальные срабатывания rpm_limit и tpm_limit по-прежнему возвращают 429 в любом релизе. Проверяйте, какой код вы получаете после каждого обновления.

Код состояния создает путаницу, так как ни один из них не указывает на «бюджет». Клиентская библиотека интерпретирует 429 как ограничение частоты запросов (rate limit) и может пытаться повторить их с экспоненциальной задержкой, хотя бюджет не восстановится до момента сброса. Код 422 интерпретируется как запрос, который не удалось обработать. Записывайте тело ответа рядом с кодом состояния, иначе исчерпание бюджета каждый раз будет выглядеть как другая проблема.

Просматривайте и изменяйте ключи через тот же API управления:

curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

curl -s -X POST http://127.0.0.1:4000/key/update \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"key": "sk-...", "max_budget": 25}'

Бюджет, контролируемый на уровне шлюза, действует, даже если проблема возникла в самом агенте. Именно поэтому он является основой контроля расходов на AI-агентов на VPS.

Перенаправление массовых задач на бюджетную модель

Укажите клиенту адрес шлюза. Базовый URL, ключ, имя модели:

curl -s http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-<the virtual key>" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "bulk",
    "messages": [{"role": "user", "content": "Say hello in five words."}]
  }'

Любая клиентская библиотека OpenAI работает аналогично: установите base_url в https://gateway.example.com/v1, а api_key — в виртуальный ключ.

Политика маршрутизации из config.yaml теперь применяется автоматически, без участия вызывающей стороны. Запрос к bulk направляется на бюджетную модель. Если этот вызов завершается ошибкой после всех попыток повтора, запрос перенаправляется на strong. Если промпт слишком длинный для bulk, context_window_fallbacks отправляет его на strong вместо возврата ошибки. Массовые задачи, такие как классификация или обработка очереди суммаризации, по умолчанию выполняются дешево, и только сложные запросы требуют больших затрат.

Здесь шлюз также доказывает свою эффективность при работе с агентами, использующими инструменты. MCP (model context protocol) сервер на том же VPS и управляющий им агент могут обращаться к одной точке входа, что позволяет менять модель без переразвертывания любого из компонентов.

Как узнать, что произошел переход на резервную модель?

Это режим сбоя, который приводит к финансовым потерям, так как внешне всё выглядит исправно. Успешный переход на резерв возвращает HTTP 200 с обычным телом ответа. Ваша дешевая модель может не работать целый день, при этом каждый запрос будет незаметно обрабатываться дорогой моделью, и первым признаком проблемы станет счет на оплату.

Доказательства существуют в заголовках ответа. Проверьте их:

curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-<the virtual key>" \
  -H 'Content-Type: application/json' \
  -d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
  | grep -i '^x-litellm'
  • x-litellm-model-group — это имя модели, по которому был направлен запрос, например bulk. x-litellm-model-id — это идентификатор развертывания, который дал ответ; его можно найти с помощью /v1/model/info?litellm_model_id=.... Если этот ID не совпадает ни с одним из ваших развертываний bulk, значит, произошел переход на резерв.
  • x-litellm-attempted-fallbacks и x-litellm-attempted-retries подсчитывают их. При штатном вызове ни один из них не показывает значение выше 0.
  • x-litellm-response-cost — это стоимость одного вызова в долларах США.
  • x-litellm-call-id — это идентификатор, который вы используете для поиска того же вызова в своих логах.

Записывайте x-litellm-attempted-fallbacks для каждого запроса и настройте оповещение, если значение превышает 0. Это число — разница между работающей политикой маршрутизации и политикой, которая незаметно превратилась в «всегда использовать дорогую модель».

Полноценное решение этой задачи — трассировка, которая заслуживает отдельной настройки: self-hosted Langfuse для трассировки вызовов агентов. LiteLLM поставляется с готовым callback, поэтому его подключение занимает две строки плюс учетные данные.

litellm_settings:
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.com

Для Langfuse версии 3 и выше страница LiteLLM по Langfuse теперь рекомендует использовать пресет langfuse_otel; callback langfuse, упомянутый выше, по-прежнему задокументирован. Установите failure_callback, а также success_callback. Если пропустить этот шаг, вы сохраните только те трассировки, в которых не возникло ошибок. Помимо этого, LiteLLM записывает строку с данными о расходах для каждого запроса в Postgres, а панель администратора по адресу /ui считывает эту таблицу. Она растет вместе с трафиком, поэтому следите за свободным местом на диске.

Размещение шлюза за обратным прокси-сервером

Ни один внешний узел не должен иметь доступ к порту 4000. Выполняйте TLS termination на стороне nginx или Caddy и перенаправляйте трафик на адрес loopback.

location / {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_read_timeout 600s;
}

Две из этих строк часто упускают из виду. Параметр proxy_buffering off важен, так как потоковая генерация (streaming completion) представляет собой последовательность событий server-sent events. При включенной буферизации nginx собирает фрагменты в буферах перед отправкой, что задерживает доставку данных клиенту. Параметр proxy_read_timeout 600s важен, поскольку стандартное значение nginx в 60 секунд — это максимальное время ожидания между двумя операциями чтения из шлюза, а не ограничение на весь ответ целиком. При не потоковой генерации данные не отправляются до завершения процесса, поэтому длительная генерация превышает 60 секунд без передачи байтов, и клиент получает ошибку 504, а в лог ошибок записывается upstream timed out (110: Connection timed out) while reading response header from upstream. Потоковая генерация, которая постоянно отправляет фрагменты, может длиться значительно дольше 60 секунд; тайм-аут срабатывает только в том случае, если модель перестает отвечать на такой промежуток времени.

Для получения сертификата кратчайший путь — использование Certbot с Let's Encrypt в nginx. Если на сервере уже работает несколько контейнеров, Traefik перед несколькими приложениями Compose позволит управлять маршрутизацией и сертификатами в одном месте.

Шлюз теперь является единой точкой отказа

Будьте честны в отношении того, что вы построили. Каждое ваше приложение теперь зависит от одного контейнера на одном VPS. Пока он не работает, ничто не может обратиться к какой-либо модели, включая провайдеров, которые полностью исправны. Из этого следуют четыре вывода.

  • Неверная конфигурация выводит из строя всё сразу. restart: unless-stopped перезапускает процесс при сбое, и он снова и снова перезапускает контейнер, который не может прочитать config.yaml. Читайте docker compose logs litellm после каждого изменения конфигурации и вносите изменения, когда у вас есть время проконтролировать их.
  • Postgres находится на пути запроса при промахе кэша. Поиск виртуального ключа использует его, когда ключ не кэширован; запись расходов выполняется асинхронно после ответа. /health/readiness, возвращающий 503, — это ваше предупреждение о том, что шлюз запущен, но не может выполнить ни то, ни другое.
  • Сначала используйте ядра, затем добавляйте экземпляры. Рекомендация проекта по эксплуатации «один воркер на экземпляр» (--num_workers 1) предназначена для Kubernetes или другого автоскейлера подов, который добавляет экземпляры за вас. Для одной виртуальной машины или отдельного контейнера, как в данном случае, правило обратное: установите количество воркеров равным количеству vCPU машины. На машине с 1 vCPU, указанной выше, это всё ещё --num_workers 1; на более мощной машине увеличьте это число, помня, что каждый воркер потребляет собственную память. Второй шлюз за балансировщиком нагрузки исключает единственный контейнер из этой схемы. Это не исключает базу данных.
  • Делайте резервные копии того, что нельзя восстановить. Это config.yaml и .env вместе с pg_dump базы данных. Потеря LITELLM_SALT_KEY делает зашифрованные учетные данные провайдеров внутри этого дампа бесполезными, поэтому файл окружения и дамп должны быть частью одного задания резервного копирования: резервное копирование restic во внешнее хранилище.

Обновление заключается в редактировании тега образа и выполнении docker compose up -d. LiteLLM по умолчанию запускает prisma migrate deploy при старте, поэтому новый контейнер выполняет миграцию схемы базы данных при первой загрузке. Сделайте дамп до смены тега, так как возврат к старому образу не отменяет уже выполненную миграцию.

Читайте примечания к выпуску для каждой версии, которую вы пропускаете, а не только для той, на которую переходите. Переход с v1.95.0 на v1.104.0 или более позднюю версию затрагивает несколько критических изменений: упомянутый выше код состояния бюджета, прокси-сервер, который отказывается запускаться с не заданным, пустым или публично известным мастер-ключом, и прокси-сервер, который завершает работу, если настройка базы данных не удалась при запуске, что при restart: unless-stopped выглядит как цикл перезагрузок. При переходе с v1.102.x или более ранних версий примечания к v1.104.0 также содержат просьбу самостоятельно создать два индекса LiteLLM_SpendLogs.

FAQ

Добавляет ли LiteLLM заметную задержку к каждому вызову?

Проект заявляет о 8 мс на 95-м перцентиле при нагрузке 1000 запросов в секунду, согласно README по состоянию на октябрь 2026 года. Рассматривайте это как маркетинговую цифру вендора. Реальная задержка зависит от сетевого расстояния между вашими приложениями и шлюзом, так как вы добавляете один дополнительный round trip к каждому вызову. Запускайте шлюз в том же регионе, где находятся вызывающие его приложения, а затем измерьте собственные накладные расходы с помощью заголовка x-litellm-overhead-duration-ms на реальном ответе.

Почему стриминг перестал работать после установки nginx перед шлюзом?

Потому что nginx по умолчанию буферизирует ответы от upstream, а потоковая генерация (streaming completion) представляет собой серию server-sent events. При включенном proxy_buffering nginx собирает фрагменты в буферы перед отправкой, задерживая доставку клиенту. Установите proxy_buffering off; в блоке location. Также увеличьте proxy_read_timeout в том же блоке. По умолчанию nginx прерывает соединение через 60 секунд отсутствия данных от шлюза, что легко случается при длинной нестриминговой генерации, и клиент получает 504 ошибку.

Что происходит, когда у виртуального ключа заканчивается бюджет?

Вызов завершается с ошибкой типа budget_exceeded и сообщением вида Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>. В зафиксированной версии v1.95.0 статус равен HTTP 429; начиная с v1.104.0 по умолчанию возвращается HTTP 422. Ни один из этих кодов не указывает на бюджет, в этом и заключается ловушка: клиентская библиотека интерпретирует 429 как ограничение частоты запросов (rate limit) и может попытаться повторить вызов, поэтому администраторы начинают бороться с троттлингом вместо того, чтобы прочитать текст ошибки. Логируйте тело ответа вместе с кодом статуса. Проверьте реальное состояние ключа с помощью /key/info?key=sk-... относительно мастер-ключа и увеличьте лимит через /key/update, если бюджет был установлен слишком низким.

Может ли шлюз маршрутизировать запросы как на локальные, так и на облачные модели?

Да, это просто еще одна запись в model_list. Используйте префикс ollama_chat/ вместе с api_base, например model: ollama_chat/llama3.1 наряду с api_base: http://ollama:11434. В стандартной сети Docker Compose адрес localhost внутри контейнера указывает на сам этот контейнер, поэтому используйте имя сервиса Compose или адрес хоста в сети Docker, но никогда не 127.0.0.1. Исключением является host networking, когда контейнер использует сетевой стек хоста. Развертывание локальной модели — это отдельная задача: см. самостоятельный хостинг LLM с помощью Ollama на VPS.

Была ли эта статья полезной?