MAATRIX / Блог / LiteLLM на сервере: частые ошибки и решения

LiteLLM на сервере: частые ошибки и решения

LiteLLM на сервере: частые ошибки и решения

MAATRIX

LiteLLM разворачивается за пять минут, а дальше начинается интересное: клиент получает «LLM Provider NOT provided», OpenAI отвечает 403 «по стране», стриминг обрывается ровно на шестидесятой секунде, а через неделю диск съедает таблица логов. Ошибки LiteLLM на сервере повторяются от установки к установке, и почти каждая чинится одной строкой в конфиге. Разберём их по схеме «симптом — причина — решение».

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Как за две минуты понять, где именно сломалось

LiteLLM — это три слоя, и ошибка живёт в одном из них: процесс прокси (не стартует, падает, не слушает порт), маршрутизация в конфиге (не тот model, неподдерживаемый параметр) и апстрим (401, 403, 429, таймаут). Начинайте с определения слоя, а не с гугления текста ошибки.

Сначала — жив ли процесс, что он писал последним и слушает ли свой порт (по умолчанию 4000):

journalctl -u litellm -n 200 --no-pager | grep -iE "error|traceback"
docker logs --tail 200 litellm 2>&1 | tail -50
ss -ltnp | grep 4000

Здоровый ответ последней команды:

LISTEN 0 2048 0.0.0.0:4000 0.0.0.0:* users:(("python3",pid=1421,fd=9))

Нет строки — проблема в слое процесса, читайте следующую секцию. Порт слушается — проверьте готовность: curl -s http://127.0.0.1:4000/health/readiness. В ответе важны статус, состояние базы и версия LiteLLM: частая потеря времени — когда вы правите конфиг по документации свежей ветки, а на сервере образ полугодовой давности.

Для разбора конкретного запроса включите LITELLM_LOG=DEBUG или --detailed_debug. Режим шумный: в логи попадают тела запросов с промптами, выключайте его сразу.

Прокси не стартует: зависимости, YAML и занятый порт

Самая частая причина — установлен SDK, а не прокси. pip install litellm даёт только библиотеку, серверная часть живёт в extras, и litellm --config падает с ошибкой импорта. На Ubuntu 24.04 добавляется вторая грабля: системный Python 3.12 помечен как externally managed, и обычный pip install отвечает:

error: externally-managed-environment
× This environment is externally managed

Через --break-system-packages не надо — сломаете системные пакеты:

apt install -y python3-venv
python3 -m venv /opt/litellm/venv
/opt/litellm/venv/bin/pip install -U 'litellm[proxy]'

Третья причина — синтаксис config.yaml: кривой отступ даёт yaml.scanner.ScannerError: mapping values are not allowed in this context. Проверяйте до перезапуска: python3 -c "import yaml;yaml.safe_load(open('/etc/litellm/config.yaml'))".

Четвёртая — мастер-ключ: LITELLM_MASTER_KEY обязан начинаться с sk-, иначе виртуальные ключи и админ-роуты не работают. Генерируйте его как sk-$(openssl rand -hex 24) и держите в /etc/litellm/.env с chmod 600.

Пятая — занятый порт: [Errno 98] Address already in use. Владелец находится тем же ss -ltnp | grep 4000.

И про Docker: путь в --config — это путь внутри контейнера, а не на хосте. Отсюда «конфиг не найден» и дефолты без моделей:

docker run -d --name litellm --restart=always \
  -p 127.0.0.1:4000:4000 \
  -v /etc/litellm/config.yaml:/app/config.yaml:ro \
  --env-file /etc/litellm/.env \
  --log-opt max-size=50m --log-opt max-file=3 \
  ghcr.io/berriai/litellm:main-stable --config /app/config.yaml

Порт прокси держите на локалхосте, наружу — 443 через nginx с TLS: ufw allow 443/tcp и никакого ufw allow 4000. Открытый LiteLLM сканеры находят за часы.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть LiteLLM

База, Prisma и внезапно «отвалившиеся» модели

Виртуальные ключи, бюджеты и учёт расходов требуют PostgreSQL — не MySQL и не SQLite; в репозитории Ubuntu 24.04 лежит PostgreSQL 16, его достаточно. Самое частое сообщение здесь — от Prisma:

Error: P1001: Can't reach database server at `postgres`:`5432`

По адресу из DATABASE_URL базы нет. Типичные причины: имя сервиса из docker compose (postgres) в конфиге, а контейнер запущен обычным docker run вне этой сети, либо база слушает только UNIX-сокет. Проверьте: psql "postgresql://litellm:PASS@127.0.0.1:5432/litellm" -c "select 1;".

Вторая засада — закрытый исходящий трафик: при старте Prisma-клиент тянет бинарные движки с внешнего хоста binaries.prisma.sh, и если egress режет фаервол, контейнер зависает на старте.

Третья, самая недооценённая — LITELLM_SALT_KEY: если ключи провайдеров хранятся в базе, они шифруются этим значением. Симптом потери: после переезда или пересоздания контейнера все модели разом отвечают ошибками авторизации, хотя в базе они на месте. Расшифровать без прежней соли нельзя — только заводить ключи заново, поэтому salt ставится один раз и попадает в бэкап рядом с дампом:

pg_dump -Fc "postgresql://litellm:PASS@127.0.0.1:5432/litellm" > /var/backups/litellm-$(date +%F).dump

«LLM Provider NOT provided» и ошибки маршрутизации

Текст, который приносит больше всего вопросов:

litellm.BadRequestError: LLM Provider NOT provided. Pass in the LLM provider
you are trying to call. You passed model=my-gpt

Причина одна: в litellm_params.model нет префикса провайдера, и LiteLLM не знает, куда слать my-gpt. Различайте два поля: model_name — псевдоним для ваших клиентов, litellm_params.model — реальный идентификатор у провайдера с префиксом.

model_list:
  - model_name: fast
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY
  - model_name: smart
    litellm_params:
      model: anthropic/claude-sonnet-4-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: local
    litellm_params:
      model: ollama/llama3.1
      api_base: http://172.17.0.1:11434

litellm_settings:
  drop_params: true

Второй симптом — клиент шлёт имя, которого нет в model_list, и получает 400. Спросите у прокси: curl -s -H "Authorization: Bearer sk-КЛЮЧ" http://127.0.0.1:4000/v1/models.

Третий — жалоба на неподдерживаемый параметр: чужая библиотека или нода n8n шлёт frequency_penalty либо logit_bias, а провайдер их не принимает. Строка drop_params: true выбрасывает такие поля вместо падения, но глушит симптом: если параметр влиял на качество, вы потеряете его молча.

Четвёртый — локальная модель. Внутри контейнера localhost указывает на сам контейнер, до Ollama на хосте запрос не дойдёт, и вы увидите APIConnectionError с причиной All connection attempts failed. Берите адрес docker-моста http://172.17.0.1:11434 (сверьте через ip -4 addr show docker0) или --add-host=host.docker.internal:host-gateway. И помните: Ollama слушает только 127.0.0.1, ей нужен OLLAMA_HOST=0.0.0.0.

403 по стране, таймауты и обрывы стриминга

Этот класс ошибок не про конфиг, а про то, откуда идёт запрос. Если шлюз стоит в России, крупные провайдеры отказывают ещё до проверки ключа:

OpenAIException - Error code: 403 - {'error': {'code':
'unsupported_country_region_territory', 'message': 'Country, region, or
territory not supported', 'type': 'request_forbidden'}}

Признак: 403 и слово country вместо invalid_api_key. Ключ рабочий, дело в IP, правки config.yaml бессильны. Замер с нашего нью-йоркского узла командой curl -o /dev/null -s -w "connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n" https://api.openai.com/v1/models:

connect=0.004 tls=0.021 total=0.089

С московской машины через цепочку VPN тот же запрос занимает 0,6–1,1 с, а часть попыток отдаёт всё тот же 403: диапазоны публичных VPN провайдеры давно отсекают.

Вторая сетевая причина зависаний — нерабочий IPv6-маршрут: клиент уходит по нему и ждёт таймаута. Проверка — curl -4 против curl -6, лечение — строка precedence ::ffff:0:0/96 100 в /etc/gai.conf. Ретраи и фолбэки задавайте явно, иначе единичный сбой апстрима сразу видит пользователь:

router_settings:
  num_retries: 2
  timeout: 120
  fallbacks: [{"smart": ["fast"]}]

Ретраи не бесплатны: каждая попытка — ещё один оплаченный запрос, так что для 429 разумнее фолбэк, чем повторы в ту же модель.

Теперь стриминг. Симптом: через curl ответ идёт токен за токеном, а через веб-интерфейс приходит одним куском или обрывается. Виноват nginx: он буферизует ответ апстрима, SSE-поток превращается в блок, а на длинной генерации падает по таймауту. В error.log лежит upstream timed out (110: Connection timed out) while reading response header from upstream, ровно через 60 секунд — подпись дефолтного proxy_read_timeout. Рабочая секция:

location /v1/ {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
}

Применяйте через nginx -t && systemctl reload nginx. Если перед сервером Cloudflare в режиме проксирования, помните его потолок: ответ, не начавший приходить примерно за 100 секунд, закрывается ошибкой 524 — домен шлюза лучше держать в режиме DNS-only.

Что ломается на второй неделе: диск, воркеры и обновления

Первое — база расходов. Таблица LiteLLM_SpendLogs пишет строку на каждый запрос; у нас выходило около 2 КБ на запись: сто тысяч запросов — 200–300 МБ с индексами, миллион — пара гигабайт. Смотрите размер и чистите старое по крону:

psql -U litellm -d litellm -c "SELECT pg_size_pretty(pg_total_relation_size('\"LiteLLM_SpendLogs\"'));"
psql -U litellm -d litellm -c "DELETE FROM \"LiteLLM_SpendLogs\" WHERE \"startTime\" < NOW() - INTERVAL '30 days';"

Если детальный лог запросов не нужен, в general_settings есть disable_spend_logs: true — агрегированные траты по ключам сохранятся. Заодно ограничьте логи Docker: json-file по умолчанию безлимитный и кладёт десятки гигабайт в /var/lib/docker/containers.

Второе — мониторинг, который стоит денег. Эндпоинт /health дёргает каждую модель из model_list тестовым запросом: чекер с интервалом в минуту даёт круглосуточный расход токенов. Для внешних проверок берите /health/liveliness.

Третье — память и воркеры. Флаг --num_workers множит потребление: каждый воркер это отдельный процесс. На нашем тестовом узле один воркер в простое держал около 400 МБ RSS, четыре — под полтора гигабайта, и на машине с 2 ГБ ядро начинало убивать процессы: Worker (pid:2431) was sent SIGKILL! Perhaps out of memory? Подтверждает dmesg -T | grep -i "out of memory".

Четвёртое — обновления. Тег main-latest меняется под вами, и однажды прокси не поднимется после планового docker pull. Берите main-stable или фиксируйте версию. Перед апгрейдом — дамп базы и копия config.yaml с .env.

Какой сервер брать под LiteLLM в MAATRIX

Хорошая новость: сам шлюз лёгкий — он не считает нейросети, а разбирает JSON, подставляет ключи и проксирует потоки, поэтому GPU не нужен. Плохая: почти всё разобранное выше — 403 по стране, лишние сотни миллисекунд на рукопожатии, обрывы через кривые прокси — упирается не в мощность, а в точку выхода в интернет.

Минимум, на котором это честно работает: 2 vCPU, 4 ГБ RAM, 40–60 ГБ NVMe. Хватает на «LiteLLM в один-два воркера плюс PostgreSQL в контейнере» и десятки запросов в минуту — нагрузка команды из 5–15 человек или пары агентов. Диск берите с запасом из-за SpendLogs и логов.

Комфортный вариант: 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe. Это 4 воркера, Redis для общих лимитов между ними, база с местом под историю расходов и запас на пики. Redis чинит и неочевидную проблему: без него лимиты RPM и TPM считает каждый воркер отдельно, и суммарно вы вылетаете за квоту провайдера раньше, чем ожидали.

Локация — США (Нью-Йорк). Для шлюза к OpenAI, Anthropic и Google это вариант без танцев: чистый IP, который не встречает unsupported_country_region_territory, и минимальная задержка до API. Российская площадка нужна в одном сценарии: LiteLLM ходит только к своим моделям (Ollama, vLLM) или российским провайдерам, а 152-ФЗ важнее зарубежных API. Лондон и Францию берут, когда шлюзом пользуется команда из ЕС.

Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT; зарубежная карта не нужна. LiteLLM разворачивается из каталога приложений: связка с прокси и базой поднимается автоматически, дальше вы правите config.yaml под свои модели. Не уверены в конфигурации — опишите профиль нагрузки, подберём без запаса «на всякий случай».

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть LiteLLM

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Почему ключ рабочий, а прокси получает 403?

Если в тексте ошибки unsupported_country_region_territory, дело не в ключе, а в IP сервера: провайдер отказывает по геолокации до проверки авторизации. Лечится переносом шлюза в разрешённую локацию.

Стриминг приходит одним куском — это баг LiteLLM?

Почти никогда: виноват обратный прокси, нужны proxy_buffering off и увеличенный proxy_read_timeout в nginx. Если домен проксируется через Cloudflare, учитывайте его лимит около 100 секунд.

Можно ли обойтись без PostgreSQL?

Да, если нужен только маршрутизатор без виртуальных ключей, бюджетов и учёта расходов — хватит config.yaml и мастер-ключа. С ключами на пользователей и лимитами база обязательна, а с ней бэкап дампа и LITELLM_SALT_KEY.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.