# LiteLLM: прокси и роутер LLM для команды. Гайд

> Поднимите LiteLLM Proxy: config.yaml, ключи с бюджетами, fallback на Ollama, подключение Claude Code и OpenAI SDK, CVE и защита self-hosted.
> Author: Roman Belov · Published: 2026-11-02 · Source: https://futurecraft.pro/ru/blog/litellm-guide/

LiteLLM - открытая (MIT) Python-библиотека и прокси-сервер, которые приводят вызовы 100+ LLM-провайдеров к формату OpenAI. Python SDK подключают в код одного приложения. Proxy (в документации AI Gateway) поднимают как общий шлюз для команды: виртуальные ключи на сотрудника, бюджеты, fallback между моделями, логи в одном месте. У репозитория [BerriAI/litellm](https://github.com/BerriAI/litellm) около 62 тысяч звёзд, последний stable-релиз на 2 ноября 2026 года - 1.106.6 от 28 октября.

Первый `config.yaml` укладывается в два десятка строк. Сложности начинаются, когда прокси отдают команде: виртуальные ключи и бюджеты молча не работают без Postgres, часть функций из документации требует Enterprise-лицензии, а сам прокси хранит ключи всех провайдеров. За 2026 год у LiteLLM вышло больше десятка CVE с оценкой High и Critical, а в марте на PyPI на 40 минут попали два релиза с вредоносным кодом.

Статья о том, как поднять LiteLLM Proxy, описать модели в `config.yaml`, настроить fallback с локальной модели на облачную, выдать ключи с бюджетами, подключить OpenAI SDK, Claude Code и OpenCode и как эксплуатировать прокси с учётом его истории уязвимостей. Fallback, накладные расходы прокси, авторизация без базы и Anthropic-формат проверены на LiteLLM 1.108.1 (вышла 5 ноября) с Ollama 0.40.14 на Mac с Apple M4 Max. Docker, Postgres, Redis, Admin UI и Enterprise-функции описаны по документации.

## Что такое LiteLLM и когда он нужен

Запрос «litellm» объединяет два продукта с разными задачами.

| | LiteLLM SDK | LiteLLM Proxy |
|---|---|---|
| Что это | Python-библиотека | Отдельный HTTP-сервер, порт 4000 |
| Клиенты | Код на Python | Любой язык, OpenAI SDK, агенты, curl |
| Функции | `completion()` для 100+ провайдеров, Router с ретраями и fallback, стоимость ответа, callbacks | Всё из SDK плюс virtual keys, бюджеты, rate limits, учёт расходов, Admin UI, кэш, guardrails, MCP Gateway |
| Хранилище | Не нужно | Postgres для ключей и бюджетов, Redis для нескольких инстансов |
| Кому | Одному приложению | Команде, нескольким сервисам, агентам |

Выбор по ситуации:

| Ситуация | Что брать |
|---|---|
| Одно Python-приложение, два-три провайдера | SDK |
| Один разработчик, одна модель | Ни то, ни другое: хватит SDK провайдера |
| Несколько сервисов на разных языках ходят к LLM | Proxy |
| Нужны ключи на сотрудника, лимиты и отчёт по расходам | Proxy + Postgres |
| Локальная модель с запасной облачной | SDK Router или Proxy |
| Нет желания администрировать сервер | Облачный агрегатор, например OpenRouter |

Где self-hosted proxy стоит в общей архитектуре провайдеров рядом с адаптерами в коде и managed-шлюзами, разобрано в статье [о провайдерах LLM в production](https://futurecraft.pro/ru/blog/multi-provider-llm-architecture/).

### Чем LiteLLM отличается от OpenRouter и Portkey

| | LiteLLM | OpenRouter | Portkey Gateway |
|---|---|---|---|
| Модель | Self-hosted SDK и Proxy, MIT + каталог `enterprise/` | SaaS, единый API и счёт | Open-source шлюз (MIT, ~13 тысяч звёзд) плюс облачный Portkey |
| Ключи провайдеров | Ваши, лежат на вашем сервере | Ключ OpenRouter или свои (BYOK) | Ваши |
| Деньги | Софт бесплатный, платите за инфраструктуру; Enterprise по запросу | Комиссия платформы 5,5% (Standard), 8% (Business); BYOK без комиссии до $25 000 в месяц по прайсу, дальше 5% | Условия на сайте Portkey |
| Данные | Через ваш хост | Через серверы OpenRouter | Через ваш хост (open-source версия) |

Цены OpenRouter взяты со [страницы pricing](https://openrouter.ai/pricing) в начале ноября 2026. Подробно облачный вариант разобран в [гайде по OpenRouter](https://futurecraft.pro/ru/blog/openrouter-guide/). Схемы совмещаются: OpenRouter подключается к LiteLLM как ещё один провайдер.

## Быстрый старт LiteLLM Proxy

Установка по [quick start](https://docs.litellm.ai/docs/proxy/quick_start):

```bash
uv tool install 'litellm[proxy]==1.106.6'
# или
pip install 'litellm[proxy]==1.106.6'
```

С версии 1.84.0 LiteLLM требует Python 3.10 или новее, верхняя граница на PyPI `<3.15`. `uv tool install` сам подберёт подходящий интерпретатор. Голый `pip` на старом Python, по документации, молча поставит последнюю совместимую старую версию. Если системный Python 3.15 или новее, версию интерпретатора для uv задают явно, разовый запуск выглядит так:

```bash
uvx --python 3.12 --from 'litellm[proxy]==1.106.6' litellm --config config.yaml --host 127.0.0.1 --port 4000
```

Версию лучше указывать сразу. Релизы выходят несколько раз в неделю, исправления выпускают сразу для нескольких минорных линий, а версии 1.82.7 и 1.82.8 были вредоносными (подробности в разделе о безопасности).

Минимальный `config.yaml` с локальной и облачной моделью:

```yaml
model_list:
  - model_name: local-qwen
    litellm_params:
      model: ollama_chat/qwen3:8b
      api_base: http://127.0.0.1:11434
  - model_name: cloud-sonnet
    litellm_params:
      model: anthropic/claude-sonnet-5-5
      api_key: os.environ/ANTHROPIC_API_KEY

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY   # должен начинаться с sk-
```

Первый запрос:

```bash
curl http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "local-qwen", "messages": [{"role": "user", "content": "ping"}]}'
```

Клиент OpenAI SDK меняет только адрес и ключ:

```python
from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:4000", api_key="sk-...")  # master или virtual key
resp = client.chat.completions.create(
    model="cloud-sonnet",  # model_name из config.yaml
    messages=[{"role": "user", "content": "ping"}],
)
print(resp.choices[0].message.content)
```

Клиент видит только `model_name`. Какой провайдер стоит за алиасом, решает конфиг, и модель меняют без правки кода приложений.

### SDK: LiteLLM без сервера

Если шлюз не нужен, тот же вызов делается библиотекой:

```python
from litellm import completion

resp = completion(
    model="ollama_chat/qwen3:8b",
    api_base="http://127.0.0.1:11434",
    messages=[{"role": "user", "content": "ping"}],
)
print(resp.choices[0].message.content)
```

Для балансировки и fallback в SDK есть класс `Router` с тем же форматом `model_list`, что и в конфиге прокси.

## config.yaml: модели, роутинг, секреты

В [config.yaml](https://docs.litellm.ai/docs/proxy/configs) пять секций:

| Секция | Что в ней |
|---|---|
| `model_list` | Модели: `model_name` (алиас для клиента), `litellm_params` (провайдер, модель, `api_base`, `api_key`, `rpm`, `tpm`), опционально `model_info` |
| `router_settings` | Стратегия роутинга, ретраи, cooldown, fallbacks |
| `litellm_settings` | Поведение библиотеки: fallbacks, таймауты, кэш, callbacks, глобальный бюджет |
| `general_settings` | Master key, база данных, параметры сервера |
| `environment_variables` | Переменные окружения прямо в конфиге |

Секреты не пишут в файл открытым текстом. Запись `os.environ/ИМЯ` прокси читает из окружения при старте.

Несколько записей с одинаковым `model_name` образуют группу, и прокси распределяет запросы между ними:

```yaml
model_list:
  - model_name: fast
    litellm_params:
      model: anthropic/claude-haiku-5-5
      api_key: os.environ/ANTHROPIC_API_KEY
      rpm: 500
  - model_name: fast
    litellm_params:
      model: openai/<модель GPT-6>
      api_key: os.environ/OPENAI_API_KEY
      rpm: 300

router_settings:
  routing_strategy: simple-shuffle
```

Стратегии по [документации роутинга](https://docs.litellm.ai/docs/routing):

| Стратегия | Как выбирает |
|---|---|
| `simple-shuffle` | По умолчанию, рекомендована для production; выбирает с учётом `rpm`/`tpm` или `weight`, без них случайно |
| `least-busy` | Деплой с наименьшим числом запросов в работе |
| `latency-based-routing` | Самый быстрый по недавним замерам |
| `usage-based-routing-v2` | По текущему расходу rpm/tpm через Redis; документация не советует её для production |
| `cost-based-routing` | Самый дешёвый деплой |

Имена моделей в примерах документации LiteLLM меняются вместе с релизами провайдеров и не всегда совпадают с актуальными ID. Реальный идентификатор берут из документации провайдера: у Anthropic на ноябрь 2026 это `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`.

### Ollama за прокси

LiteLLM поддерживает два префикса для [Ollama](https://docs.litellm.ai/docs/providers/ollama). `ollama_chat/` отправляет запросы в `/api/chat`, его рекомендует документация. `ollama/` идёт в `/api/generate`. `api_base` указывает на сервер Ollama, по умолчанию `http://localhost:11434`.

```yaml
  - model_name: local-qwen
    litellm_params:
      model: ollama_chat/qwen3:8b
      api_base: http://127.0.0.1:11434
      keep_alive: 30m
    model_info:
      supports_function_calling: true
```

`supports_function_calling` нужен, когда модель умеет нативные tool calls, а LiteLLM этого не определил: иначе он эмулирует вызовы инструментов через JSON-режим. Какие модели Ollama действительно справляются с инструментами и почему агенту нужен контекст от 64k, разобрано в [гайде по Ollama](https://futurecraft.pro/ru/blog/ollama-guide/). Выбор между Ollama и LM Studio как локальным бэкендом - в [отдельном сравнении](https://futurecraft.pro/ru/blog/lm-studio-vs-ollama/).

## Fallback, ретраи и таймауты

Fallback - запасная модель, на которую прокси переключает запрос после ошибки основной. Параметры по [документации reliability](https://docs.litellm.ai/docs/proxy/reliability):

| Параметр | Что делает |
|---|---|
| `fallbacks: [{"a": ["b", "c"]}]` | При ошибке группы `a` пробует `b`, затем `c` |
| `context_window_fallbacks` | Переключение при превышении контекста; для проверки до отправки нужен `router_settings.enable_pre_call_checks: true` |
| `content_policy_fallbacks` | Переключение, когда провайдер отказал по контент-политике |
| `default_fallbacks` | Запасные модели для всех групп без своего правила |
| `num_retries` | Повторы на той же группе до перехода к fallback |
| `request_timeout` | Таймаут запроса, секунды |
| `allowed_fails`, `cooldown_time` | Сколько ошибок допустимо, прежде чем деплой уйдёт в cooldown, и на сколько |

Документация показывает `fallbacks` в `litellm_settings`. Ключ принимается и в `router_settings`, так он и настроен в проверке ниже. Отключить fallback для одного запроса можно полем `"disable_fallbacks": true` в теле.

Сценарий «локальная модель упала, отвечает облако»:

```yaml
model_list:
  - model_name: local-qwen
    litellm_params:
      model: ollama_chat/qwen3:8b
      api_base: http://127.0.0.1:11434
  - model_name: cloud-deepseek
    litellm_params:
      model: deepseek/deepseek-flash
      api_key: os.environ/DEEPSEEK_API_KEY

router_settings:
  num_retries: 0
  fallbacks:
    - local-qwen: ["cloud-deepseek"]
```

**Проверено:** 7 ноября 2026 года, LiteLLM 1.108.1 через `uvx --python 3.12`, без Docker и Postgres, Ollama 0.40.14 с `qwen3:8b`, резервная модель DeepSeek `deepseek-flash`. Падение Ollama имитировала отдельная группа с `api_base` на закрытый порт, это та же ошибка соединения. Запрос к ней вернул ответ облачной модели, в заголовках ответа: `x-litellm-model-group: cloud-deepseek`, `x-litellm-attempted-fallbacks: 1`, `x-litellm-attempted-retries: 0`, `x-litellm-response-duration-ms: 1280.09`, `x-litellm-overhead-duration-ms: 234.18`.

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

В той же проверке всплыла деталь про резервную модель. `deepseek-flash` - рассуждающая модель, и при `max_tokens: 200` все 200 токенов ушли в `reasoning_tokens`, а текст ответа оказался пустым. У запасной модели в цепочке должен быть запас по `max_tokens`, либо в fallback ставят модель без рассуждений.

Как проектировать роутинг и деградацию на уровне всего стека, а не одного прокси, описано в статье [Production LLM Stack](https://futurecraft.pro/ru/blog/production-llm-stack/).

## Накладные расходы прокси

Прокси добавляет ещё один сетевой хоп. Насколько это заметно, проверялось на локальной модели, где сеть до провайдера не маскирует задержку самого LiteLLM.

**Проверено:** 7 ноября 2026 года, LiteLLM 1.108.1, Ollama 0.40.14, прогретая `qwen3:8b`, запросы с `max_tokens: 1`. 15 запросов на каждый путь, первые 3 отброшены, n=12.

| Путь | Медиана, мс | p90, мс |
|---|---|---|
| Напрямую в Ollama (`/v1/chat/completions`) | 19,5 | 19,7 |
| Через LiteLLM Proxy | 26,8 | 26,9 |

Разница около 7 мс на запрос. Заголовок `x-litellm-overhead-duration-ms` в трёх отдельных запросах показал 7,13, 6,77 и 5,59 мс. Первый запрос после старта прокси медленнее: в fallback-запросе выше overhead 234 мс, и туда входит переключение на запасную модель. Для облачных моделей, где ответ занимает секунды, 7 мс теряются в шуме. Под параллельной нагрузкой замер не делался.

## Virtual keys, бюджеты и лимиты

Virtual key - ключ вида `sk-...`, который прокси выдаёт сотруднику, сервису или агенту вместо ключа провайдера. Для них нужны две вещи ([virtual keys](https://docs.litellm.ai/docs/proxy/virtual_keys)): Postgres в `DATABASE_URL` и master key, начинающийся с `sk-`.

```yaml
general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  database_url: os.environ/DATABASE_URL
```

Ключ с доступом к одной группе моделей, бюджетом $10 на 30 дней и лимитом 60 запросов в минуту:

```bash
curl http://127.0.0.1:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"models": ["cloud-sonnet"], "max_budget": 10, "budget_duration": "30d",
       "rpm_limit": 60, "metadata": {"owner": "dev-1"}}'
```

Команда с общим бюджетом создаётся через `/team/new`, ключ привязывается к ней полем `team_id`:

```bash
curl http://127.0.0.1:4000/team/new \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"team_alias": "backend", "max_budget": 100, "budget_duration": "30d"}'
```

Уровни бюджетов по [документации](https://docs.litellm.ai/docs/proxy/users):

| Уровень | Как задаётся |
|---|---|
| Ключ | `/key/generate`: `max_budget`, `budget_duration`, `rpm_limit`, `tpm_limit`, `max_parallel_requests` |
| Пользователь | `/user/new` |
| Команда | `/team/new` |
| Участник команды | `/team/member_add` с `max_budget_in_team` |
| Внешний клиент | `/budget/new` + `/customer/new`, поле `user` в запросе |
| Весь прокси | `litellm_settings.max_budget` и `budget_duration` |

`budget_duration` принимает секунды, минуты, часы и дни: `30s`, `30m`, `30h`, `30d`. Ключ сверх бюджета получает ошибку с `ExceededTokenBudget` или `ExceededBudget` в тексте.

Нюансы, которые легко пропустить:

- Без базы бюджеты не применяются. Документация показывает пример: в конфиге `max_budget`, а прокси продолжает отвечать.
- Модели с нулевой стоимостью обходят проверку бюджета целиком. Документация описывает это для моделей с явными `input_cost_per_token: 0` и `output_cost_per_token: 0`, чтобы ключ с исчерпанным бюджетом мог уйти на бесплатную модель. В карте цен LiteLLM модели Ollama записаны с нулевой стоимостью: расход по ним не растёт, и денежный бюджет их не ограничит. Локальную модель ограничивают через `rpm_limit` и `tpm_limit`.
- У ключа с `team_id` личный бюджет владельца не действует, работают командные лимиты.

**Проверено:** 7 ноября 2026 года, LiteLLM 1.108.1 через uvx, без Postgres и без пакета `prisma` в окружении. Запрос без заголовка `Authorization` получил 500 Internal Server Error, неверный ключ `sk-wrong` - 400, верный master key - 200. В логе `ModuleNotFoundError: No module named 'prisma'`: обработка ошибки авторизации обращается к слою базы данных, которого нет.

Запросы без ключа прокси отклонил, но кодом 500 вместо 401. Мониторинг, который ловит неавторизованные попытки по 401, в такой конфигурации ничего не увидит. Без Postgres прокси годится для локального теста, для команды база обязательна.

### budget_fallbacks и бюджеты по моделям

С версии 1.92.0 у ключа есть поле [`budget_fallbacks`](https://docs.litellm.ai/docs/proxy/budget_fallbacks): когда бюджет ключа на конкретную модель исчерпан, запрос уходит на модель из цепочки вместо ошибки. Страница `budget_fallbacks` пометки Enterprise не содержит. Но срабатывает он только при `model_max_budget` (бюджет ключа по отдельным моделям), а `model_max_budget` документация бюджетов помечает как Enterprise, и в коде `/key/generate` без лицензии отказывает с сообщением, что для `model_max_budget` нужен Enterprise. На практике `budget_fallbacks` без лицензии не работает.

## Docker и production

Быстрый старт с Postgres по [Docker quickstart](https://docs.litellm.ai/docs/proxy/docker_quick_start):

```bash
curl -sSLO https://github.com/BerriAI/litellm/raw/main/docker/docker-compose.quickstart.yml
printf 'LITELLM_MASTER_KEY=sk-%s\nLITELLM_SALT_KEY=sk-%s\n' \
  "$(openssl rand -hex 32)" "$(openssl rand -hex 32)" > .env
docker compose -f docker-compose.quickstart.yml up -d
```

Compose поднимает шлюз на порту 4000 и Postgres. Перед запуском файл стоит прочитать и заменить тег образа на конкретную версию. Одиночный `docker run` с конфигом без базы даёт только OpenAI-совместимый API: без ключей, бюджетов и учёта расходов.

Образы и теги по [Docker Image Security](https://docs.litellm.ai/docs/proxy/docker_image_security):

- `ghcr.io/berriai/litellm` - основной образ, есть варианты `litellm-non_root` и `litellm-spend_logs`;
- теги `vX.Y.Z` неизменяемы, `main-stable` и `main-latest` помечены deprecated, `latest` в production не используют;
- с v1.83.0 все образы в GHCR подписаны cosign, подпись проверяют до деплоя:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/<commit>/cosign.pub \
  ghcr.io/berriai/litellm:v1.106.6
```

Что нужно для чего ([production](https://docs.litellm.ai/docs/proxy/prod), [deploy](https://docs.litellm.ai/docs/proxy/deploy)):

| Компонент | Когда нужен |
|---|---|
| Postgres | Virtual keys, команды, пользователи, бюджеты, журнал расходов, модели из UI |
| Redis 7+ | Больше одного инстанса или воркера: общие rate limits, состояние роутера, кэш |
| `LITELLM_SALT_KEY` | Шифрует креды провайдеров в базе. Менять после добавления моделей нельзя: сохранённые ключи станут нечитаемыми |
| `DISABLE_SCHEMA_UPDATE=true` | На инстансах прокси, миграции выполняет отдельная job |
| `/health/readiness`, `/health/liveliness` | Пробы для Kubernetes |

Рекомендации документации по размеру: 1 vCPU и 4 GiB на воркер, в Kubernetes `--num_workers 1` на pod и 2+ реплики. Среди прочего там советуют `proxy_batch_write_at: 60` (пакетная запись расходов в базу) и `LITELLM_LOG=ERROR`. Флаг `allow_requests_on_db_unavailable` пропускает запросы при недоступной базе, документация разрешает его только внутри VPC.

## Admin UI и наблюдаемость

Admin UI открывается по адресу `<прокси>/ui` и требует базу данных. Логин - `UI_USERNAME` (по умолчанию `admin`) и `UI_PASSWORD`. Если пароль не задан, подходит master key, и любой вошедший так получает права админа прокси ([Admin UI](https://docs.litellm.ai/docs/proxy/ui)). Через UI выпускают ключи, добавляют модели без рестарта, заводят команды и смотрят расходы и логи.

Трейсы и метрики отправляют через callbacks:

- **Langfuse.** Для Langfuse v3 и v4 [документация LiteLLM](https://docs.litellm.ai/docs/observability/langfuse_integration) рекомендует пресет `langfuse_otel` через OpenTelemetry v2 вместо старого SDK-колбэка `langfuse`. Пошаговая настройка Langfuse, включая строку про LiteLLM, есть в [гайде по Langfuse](https://futurecraft.pro/ru/blog/langfuse-step-by-step/), а какие метрики и алерты собирать - в статье [об LLM observability](https://futurecraft.pro/ru/blog/llm-observability-langfuse/).
- **OpenTelemetry v2.** `litellm_settings.callbacks: ["otel"]` и `LITELLM_OTEL_V2=true`, адрес коллектора в `OTEL_EXPORTER`, `OTEL_ENDPOINT`, `OTEL_HEADERS`. На запрос пишется один trace: аутентификация, guardrails, вызов модели с атрибутами `gen_ai.*`, запись в базу. Содержимое промптов по умолчанию в трейс не попадает.

### Кэш и guardrails

[Кэш](https://docs.litellm.ai/docs/proxy/caching) бывает точным (`local`, `disk`, `redis`, `s3`, `gcs`) и семантическим (`redis-semantic`, `valkey-semantic`, `qdrant-semantic`). In-memory кэш живёт внутри воркера: у прокси с четырьмя воркерами четыре отдельных кэша, поэтому начиная со второго воркера нужен Redis. Точный кэш ключуется по хешу всего запроса, и любое изменение диалога даёт промах. Семантический кэш, по словам самой документации, подходит для одиночных промптов и сильно ошибается на агентском трафике.

Guardrails подключаются блоком `guardrails:` с режимами `pre_call`, `post_call`, `during_call` и `logging_only`. Встроены `litellm_content_filter`, Presidio для маскирования PII, интеграции Lakera, Bedrock, Aporia и другие ([guardrails](https://docs.litellm.ai/docs/proxy/guardrails/quick_start)). Конкретный guardrail включают на запрос полем `"guardrails": ["имя"]`.

## Подключение клиентов

### OpenAI SDK

Любой клиент OpenAI-формата: `base_url` на прокси, в `api_key` виртуальный ключ, в `model` - `model_name` из конфига. Пример в разделе быстрого старта.

### Claude Code

По [туториалу LiteLLM](https://docs.litellm.ai/docs/tutorials/claude_responses_api) Claude Code подключается двумя переменными:

```bash
export ANTHROPIC_BASE_URL="http://127.0.0.1:4000"
export ANTHROPIC_AUTH_TOKEN="sk-..."   # virtual key или master key
claude --model cloud-sonnet            # model_name из config.yaml
```

Master key даёт Claude Code доступ ко всем моделям прокси, виртуальный ключ ограничивает его моделями, разрешёнными этому ключу. Если за прокси стоит Bedrock, туториал советует `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`: Bedrock принимает не все beta-заголовки Claude Code.

Две оговорки из [документации Claude Code](https://code.claude.com/docs/en/llm-gateway):

- Anthropic поддерживает шлюзы с совместимым форматом API для моделей Claude, но не аудирует сторонние шлюзы и не поддерживает работу Claude Code с не-Claude моделями через любой шлюз. Технически LiteLLM это позволяет, но качество и совместимость - на вашей стороне.
- Пока задана переменная с кредом шлюза, запросы идут с этим ключом, а не с логином подписки claude.ai. Лимиты подписки к ним не применяются, оплата - по токенам на владельца ключа.

**Проверено:** 7 ноября 2026 года, LiteLLM 1.108.1. `POST /v1/messages` с заголовками `x-api-key` и `anthropic-version: 2023-06-01` на группу `local-qwen` вернул ответ в формате Anthropic: `type: message`, `stop_reason: end_turn`, размышления Qwen3 отдельным блоком `thinking`, ответ блоком `text`, usage 16 входных и 98 выходных токенов. Сам Claude Code в этой проверке не запускался.

Клиент Anthropic-формата, значит, может разговаривать с локальной моделью через прокси. Справится ли 8B-модель с агентным циклом Claude Code, это уже вопрос модели, и в тестах OpenCode локальные модели этого размера работали нестабильно. Что из Claude Code доступно в России и как ведут себя альтернативные провайдеры, разобрано в [отдельной статье](https://futurecraft.pro/ru/blog/claude-code-russia/).

### OpenCode

Отдельной записи про LiteLLM в документации OpenCode нет, работает общий механизм OpenAI-совместимого провайдера ([providers](https://opencode.ai/docs/providers/)). Пример для OpenCode 1, в том же формате, что и подключение Ollama в [гайде по OpenCode](https://futurecraft.pro/ru/blog/opencode-guide/):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "litellm": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "LiteLLM",
      "options": {
        "baseURL": "http://127.0.0.1:4000/v1",
        "apiKey": "{env:LITELLM_API_KEY}"
      },
      "models": {
        "cloud-sonnet": { "name": "Sonnet 5.5 via LiteLLM" }
      }
    }
  }
}
```

Ключ в `models` должен совпадать с `model_name` в конфиге прокси. В OpenCode 2 схема другая: блок `providers`, поля `package` и `settings.baseURL`. Адрес прокси подставляется туда же.

### Локальные модели

Ollama подключается к прокси как обычный провайдер (раздел про `config.yaml`). Клиенты тогда ходят на один адрес и одним ключом и к локальной, и к облачной модели, а fallback переключает их без участия приложения. Обзор вариантов локального запуска собран в [гайде по локальным LLM](https://futurecraft.pro/ru/blog/local-llm-guide/).

## Что платное: MIT и Enterprise

[Лицензия](https://github.com/BerriAI/litellm/blob/main/LICENSE) делит репозиторий на две части. Всё вне каталога `enterprise/` распространяется под MIT. Код в `enterprise/` можно копировать и менять для разработки и тестов, а в production он работает только при действующей подписке BerriAI на нужное число мест; распространять его нельзя. Enterprise - тот же образ, функции включает лицензионный ключ `LITELLM_LICENSE` после полного рестарта.

| Бесплатно (MIT) | Нужен Enterprise-ключ |
|---|---|
| Python SDK, Router, fallback | SSO и SCIM (SSO бесплатен до 5 пользователей) |
| Virtual keys, бюджеты и rate limits на ключ, пользователя, команду | JWT-аутентификация, назначение админов команд |
| Учёт расходов, Admin UI | Audit logs с retention, RBAC (организации, команды, роли) |
| Балансировка и роутинг | IP allowlist, ротация ключей, secret managers |
| Guardrails-фреймворк, кастомные guardrails, Presidio | Guardrail-колбэки `llmguard_moderations`, `llamaguard_moderations`, `hide_secrets`, `openai_moderations`, `google_text_moderation`, `lakera_prompt_injection`, `aporia_prompt_injection` |
| MCP gateway | Теговые бюджеты, бюджеты по моделям на ключ (`model_max_budget`), временное повышение бюджета |
| Кэш, логирование в Langfuse и OTel | Soft-budget алерты на email, отчёты по расходам, логи по командам, выгрузка в GCS и Azure Blob, guardrails на ключ и команду, лимиты размера запроса и ответа |

Список взят со [страницы Enterprise](https://docs.litellm.ai/docs/enterprise). Цена зависит от объёма использования и обсуждается с продажами, есть бесплатный 30-дневный trial, покупка через AWS и Azure Marketplace или по счёту.

## Безопасность LiteLLM: инциденты и CVE 2026

Прокси хранит master key, ключи всех провайдеров и креды в базе. Взлом прокси означает утечку всех этих ключей сразу. Поэтому история уязвимостей за 2026 год важна для любого self-hosted развёртывания.

**Компрометация PyPI, 24 марта 2026.** Версии 1.82.7 и 1.82.8 содержали вредоносный код, собиравший креды, в 1.82.8 был ещё файл `litellm_init.pth`, который Python выполняет при старте интерпретатора. По [отчёту команды](https://docs.litellm.ai/blog/security-update-march-2026) пакеты были доступны с 10:39 UTC около 40 минут, затронутыми считаются установки через pip с 10:39 до 16:00 UTC. Официальный Docker-образ прокси не пострадал. Источником команда называет зависимость Trivy в CI, к расследованию подключили Mandiant. Чистые версии - 1.82.6 и раньше, 1.83.0 и новее.

Основные CVE и advisories по [NVD](https://nvd.nist.gov/) и [GitHub Security Advisories](https://github.com/BerriAI/litellm/security/advisories), оценка CVSS от GitHub как CNA:

| ID | Опубликовано | CVSS | Суть | Исправлено в |
|---|---|---|---|---|
| CVE-2026-35030 | 06.04 | 9.4 | Обход аутентификации при включённом JWT-auth (коллизия ключа кэша OIDC userinfo), по умолчанию выключено | 1.83.0 |
| CVE-2026-35029 | 06.04 | 8.7 | `/config/update` не проверял роль admin | 1.83.0 |
| CVE-2026-42208 | 08.05 | 9.3 | SQL-инъекция в проверке API-ключа: запрос без аутентификации на любой LLM-роут читает и меняет базу прокси (1.81.16-1.83.6) | 1.83.7 |
| CVE-2026-42203 | 08.05 | 8.6 | SSTI в `POST /prompts/test`: выполнение кода с любым валидным ключом | 1.83.7 |
| CVE-2026-42271 | 08.05 | 8.7 | Выполнение команд через тестовые MCP-эндпоинты с stdio-транспортом | 1.83.7 |
| CVE-2026-49468 | 22.06 | 9.5 | Обход аутентификации через заголовок Host: доступ к management-роутам без ключа | 1.84.0 |
| CVE-2026-59822 | 08.07 | 8.8 | Обход аутентификации в MCP Streamable HTTP через OAuth2 passthrough | 1.84.0 |
| CVE-2026-89032 | 25.09 | 8.7 | Семантический кэш отдавал ответы другим тенантам (`/v1/responses`, `/bedrock/*`) | 1.101.0-rc.1 |
| CVE-2026-93355 | 28.09 | 7.6 | JWT-auth: вход под любым пользователем по email без проверки `email_verified` | В записи NVD не указано |
| CVE-2026-114612 | 22.10 | 9.9 | Общий криптоконтекст для секретов и сессий: `internal_user` подделывает admin-токен и выполняет команды через MCP stdio; с 1.91.0 в конфигурации по умолчанию | 1.100.4, 1.101.3, 1.102.2, 1.103.1 |
| GHSA-w4c7-34wj-hqm8 | 27.10 | 10.0 | Только Enterprise: запрос без аутентификации заставляет прокси прочитать локальный файл (например, `/proc/self/environ` с master key и ключами провайдеров) и отправить его на адрес атакующего | 1.103.10, 1.104.8, 1.105.6, 1.106.5 |

Даты - публикация в NVD, у GitHub advisory обычно раньше на несколько дней или недель. Кроме таблицы, в 2026 году были SSRF и утечки кредов провайдера через `api_base` и `user_config` в теле запроса (CVE-2026-84377, CVE-2026-59823, Moderate), выполнение кода через тест кастомных guardrails (CVE-2026-40217) и чтение локальных файлов через `vertex_ai_credentials` (GHSA-g5ff-637f-6q2m).

Почти все серьёзные дыры сидят в аутентификации, management-, test- и MCP-эндпоинтах, JWT и SSO, а не в маршрутизации запросов. Последний critical был в коде Enterprise: лицензия расширяет поверхность атаки.

Чек-лист для self-hosted:

1. Фиксировать версию: `litellm[proxy]==X.Y.Z` или тег образа `vX.Y.Z`, лучше digest, но не `latest`.
2. Проверять подпись образа cosign (подписаны с v1.83.0).
3. Для pip и uv: убедиться, что не стоят 1.82.7 и 1.82.8 (`pip show litellm`), и поискать `litellm_init.pth` в site-packages.
4. Не выставлять прокси в интернет. Доступ через VPN, mTLS, аутентифицирующий ingress или IP allowlist. Отдельно закрыть `/ui`, `/key/*`, `/team/*`, `/config/*` и MCP-роуты.
5. Ограничить исходящий трафик прокси адресами провайдеров. В GHSA-w4c7 именно это обрывает эксфильтрацию даже при уязвимой версии.
6. Не включать MCP gateway, JWT и SSO, если они не нужны.
7. Задать отдельный `LITELLM_SALT_KEY`, master key по возможности держать в secret manager, а не в переменных окружения процесса.
8. Подписаться на advisories репозитория и обновляться по ним: исправления выходят сразу в нескольких поддерживаемых линиях.

Риски MCP-эндпоинтов не уникальны для LiteLLM, общая модель угроз описана в статье [о MCP-серверах](https://futurecraft.pro/ru/blog/mcp-servers-explained/).

## Ограничения и подводные камни LiteLLM

### Postgres обязателен для команды

Без базы нет ключей, бюджетов, Admin UI и журнала расходов, а лимиты из конфига молча игнорируются. В проверке без базы запрос без ключа получил 500 вместо 401. Для команды Postgres закладывают с первого дня.

### Лишний хоп и лишняя точка отказа

Около 7 мс на запрос на локальной машине мало, но прокси становится единой точкой отказа для всех клиентов. В production нужны 2+ реплики, Redis и health-пробы, то есть ещё одна система, которую надо администрировать.

### Версия каждую неделю

Релизы выходят несколько раз в неделю: 27 октября одно и то же исправление вышло в четырёх линиях сразу (1.103.10, 1.104.8, 1.105.6, 1.106.5). Поведение между версиями меняется: проверки этой статьи сделаны на 1.108.1, вышедшей через три дня после даты статьи. Перед обновлением в production читают changelog и advisories.

### Плейсхолдеры в документации

Примеры в документации LiteLLM используют имена моделей, которые не всегда совпадают с актуальными ID провайдеров. Копировать их в конфиг без сверки с документацией провайдера не стоит.

### Семантический кэш и агенты

Семантический кэш отдаёт ближайший по смыслу ответ. Для агентского трафика с вызовами инструментов это источник ошибок, а в CVE-2026-89032 он ещё и отдавал ответы между тенантами.

### Когда LiteLLM не нужен

Одна модель и один сервис обходятся SDK провайдера. Одному разработчику с несколькими провайдерами хватит LiteLLM SDK без сервера. Если администрировать шлюз некому, облачный агрегатор дешевле по времени, хотя и дороже по комиссии.

## С чего начать

1. Поставьте зафиксированную версию: `uv tool install 'litellm[proxy]==1.106.6'` и проверьте `litellm --version`.
2. Напишите `config.yaml` с одной локальной и одной облачной моделью, master key из переменной окружения, запустите прокси на `127.0.0.1`.
3. Проверьте запрос через curl и OpenAI SDK, затем настройте `fallbacks` и посмотрите заголовки `x-litellm-attempted-fallbacks` при недоступной основной модели.
4. Для команды поднимите Postgres (compose-quickstart), задайте `LITELLM_SALT_KEY`, выпустите ключи с `max_budget` и `rpm_limit`.
5. Подключите клиентов: OpenAI SDK, Claude Code через `ANTHROPIC_BASE_URL`, OpenCode через OpenAI-совместимый провайдер.
6. Пройдите чек-лист безопасности: закрытая сеть, ограниченный egress, подпись образа, подписка на advisories.
