13 ноября 2026 г.

LiteLLM на VPS: один API в стиле OpenAI перед Ollama и облачными моделями

Один адрес в стиле OpenAI для всех моделей: LiteLLM proxy на VPS с 2 vCPU, алиасы, ключ, фолбэк и systemd. Живой вывод терминала, без GPU.

Шлюз LLM — это небольшой сервер, который говорит на одном API, формате чата OpenAI, и пересылает каждый запрос той модели, которую вы назвали: локальной из Ollama или облачной. Приложения знают один адрес и один ключ, а замена модели сводится к правке YAML-файла. Мы запустили LiteLLM proxy на VPS с 2 vCPU без GPU, поставили за него две локальные модели и проверили ключ, фолбэк, потоковый ответ и клиент на Python.

Коротко. Поставьте litellm[proxy] в виртуальное окружение, опишите алиасы в model_list файла config.yaml, храните мастер-ключ в отдельном файле окружения и запустите прокси из systemd на 127.0.0.1:4000. Приложения обращаются к /v1/chat/completions и указывают алиас. На нашем сервере это стоило около 370 МиБ памяти и примерно 30 мс на запрос.

Всё ниже запущено на VPS HIP-HOSTING: Ubuntu 24.04.5, 2 vCPU, 3,8 ГБ памяти, без GPU. Ollama 0.40.16 обслуживала две небольшие модели, qwen2.5:0.5b и llama3.2:1b, а LiteLLM 1.109.1 поставили через pip. Выводы скопированы из терминала, мастер-ключ заменён на sk-xxxxxxxx.

Что даёт шлюз LLM и когда он не нужен

Одному приложению с одной моделью шлюз ни к чему: направьте его на Ollama и всё. Шлюз окупается, когда что-то часто меняется или ответов просит больше одной программы.

  • Один адрес и один ключ. Каждый скрипт, бот и сценарий n8n обращается по одному URL с одним заголовком, какая бы модель ни стояла за ним.
  • Алиасы. Приложения просят fast или smart. Когда вы меняете модель за smart, приложения остаются как есть.
  • Фолбэк. Если первая модель не ответила, шлюз повторяет запрос на другой, и вызывающий всё равно получает ответ.
  • Одно место для правил. Ограничения, журнал и ключи живут в одном сервисе, а не в каждом скрипте.

Если локальную модель вы ещё не запускали, начните с нашего руководства Ollama на VPS: шлюз стоит перед ней.

Установка LiteLLM proxy в виртуальное окружение

Прокси — программа на Python с большим числом зависимостей, поэтому ей нужно своё виртуальное окружение: отдельная папка с пакетами, которая не сломает системный Python. Часть [proxy] в названии добавляет компоненты веб-сервера, а openai — клиентская библиотека для проверки дальше.

Ушло 50 секунд и 753 МБ диска. Это первая цифра, которую стоит запомнить: инструмент не крошечный. На маленьком диске это надо учитывать.

config.yaml: алиасы, фолбэк и мастер-ключ

Сначала создайте папку и пользователя службы: mkdir -p /etc/litellm и useradd --system --no-create-home --shell /usr/sbin/nologin litellm. Сохраните конфиг как /etc/litellm/config.yaml. В нём три части. model_list сопоставляет имена, которые используют приложения (model_name), с реальной моделью за ними (litellm_params). В router_settings лежат правила повторов и фолбэка, в general_settings — мастер-ключ. Мы заводим три алиаса: fast и smart указывают на наши две локальные модели, а flaky — на модель, которой нет, чтобы специально проверить фолбэк.

model_list:  - model_name: fast    litellm_params:      model: ollama/qwen2.5:0.5b      api_base: http://127.0.0.1:11434  - model_name: smart    litellm_params:      model: ollama/llama3.2:1b      api_base: http://127.0.0.1:11434  - model_name: flaky    litellm_params:      model: ollama/no-such-model      api_base: http://127.0.0.1:11434router_settings:  num_retries: 0  fallbacks: [{"flaky": ["smart"]}]general_settings:  master_key: os.environ/LITELLM_MASTER_KEY

Разберём по строкам. ollama/qwen2.5:0.5b значит «провайдер Ollama, вот тег модели», а api_base — адрес, где слушает Ollama. num_retries: 0 отключает повторы на той же модели, поэтому фолбэк срабатывает сразу. Запись os.environ/LITELLM_MASTER_KEY велит LiteLLM читать ключ из переменной окружения, так что секрет не окажется в YAML, который вы можете случайно вставить в чат или закоммитить.

Мастер-ключ кладём в отдельный файл, читаемый только root и группой сервиса:

Относитесь к этому ключу как к паролю root от шлюза: у кого он есть, тот может пользоваться всеми моделями за ним.

Запуск как службы systemd на localhost

Сервис, запущенный руками, умирает вместе с SSH-сессией. systemd — менеджер служб системы: он стартует прокси при загрузке и перезапускает при падении. Мы запускаем прокси от отдельного пользователя без оболочки и привязываем к 127.0.0.1, чтобы снаружи сервера до него пока никто не дотянулся.

[Unit]Description=LiteLLM proxyAfter=network-online.target ollama.service[Service]User=litellmEnvironmentFile=/etc/litellm/envExecStart=/opt/litellm/venv/bin/litellm --config /etc/litellm/config.yaml --host 127.0.0.1 --port 4000Restart=on-failureRestartSec=5[Install]WantedBy=multi-user.target

Сохраните как /etc/systemd/system/litellm.service, запустите и проверьте, что он слушает там, где нужно:

Старт занял около десяти секунд. В журнале видны три ваших алиаса: так быстрее всего убедиться, что конфиг прочитан.

Первые запросы: проверка ключа и список моделей

У прокси есть адрес проверки жизни, которому ключ не нужен, и список моделей, которому нужен. Запрос списка без ключа должен провалиться, и он проваливается:

Последняя строка — наш однострочный фильтр на Python поверх JSON-ответа, сокращённый до имён моделей. Теперь настоящий запрос. Тело — стандартный формат чата OpenAI: имя модели и список сообщений. JSON-ответ мы сокращаем однострочным скриптом до нужных полей, здесь и в проверке фолбэка ниже.

Работает. Этот первый запрос занял 5 секунд на двух ядрах, и в это время входит загрузка модели в память. Но посмотрите на ответ: он неверный. VPS — не «ПО, где несколько физических серверов управляются одним хостером». Модель на 0,5 миллиарда параметров говорит бегло и часто ошибается, и шлюз этого не исправит. Алиас smart, модель на 1B, на тот же вопрос ответил правильно (7,5 секунды, тоже первый запрос с загрузкой модели): «виртуализированная вычислительная среда, которая выделяет пользователю собственное серверное пространство». Выбирайте модель под задачу: шлюз лишь делает переключение дешёвым.

Вызов из Python: меняется одна строка

Шлюз говорит на формате OpenAI, поэтому официальный клиент openai работает с ним без доработок. Вы меняете base_url и ключ, остальной код остаётся прежним.

import osfrom openai import OpenAIc = OpenAI(base_url="http://127.0.0.1:4000/v1", api_key=os.environ["LITELLM_MASTER_KEY"])r = c.chat.completions.create(    model="fast",    messages=[{"role": "user", "content": "Name one Linux command that shows free disk space. One line."}],    max_tokens=40,)print(r.choices[0].message.content)

Правильная команда — df, то есть суть модель уловила. А флаг --format выдуман (настоящий — -h). Урок тот же: не запускайте то, что предложила маленькая модель, не прочитав. В нашем руководстве про ИИ-агента показано, как держать вывод модели подальше от оболочки.

Фолбэк: если одна модель не ответила, отвечает другая

Эта возможность оправдывает лишнее звено. Наш алиас flaky указывает на модель, которой в Ollama нет. При прямом обращении Ollama отказывает. Через шлюз запрос повторяется на smart и проходит:

Вызывающий попросил flaky и получил обычный ответ 200, а поле model в ответе показывает, кто на самом деле ответил. Заметьте: обычный ответ показывает алиас, который вы просили (fast), а ответ после фолбэка показал настоящее имя модели. Это поле стоит писать в журнал приложения: тихий фолбэк удобен и легко забывается. То же правило работает и при настоящем сбое, например когда облачный API недоступен, а локальная модель жива.

Потоковый ответ тоже работает

Чат-приложения выводят ответ по слову, не дожидаясь всего текста. С "stream": true шлюз пропускает куски по мере поступления. Строки ниже мы сократили: у настоящих кусков больше полей.

Сколько это стоит по памяти и времени

Шлюз — лишняя работа на каждом запросе, поэтому мы её измерили. Сначала память: процесс прокси занимал около 370 МиБ, systemd показал для службы 359 МиБ. При загруженных обеих моделях Ollama на сервере оставалось 1,0 ГиБ доступной памяти из 3,8 ГиБ. Для скорости мы 5 раз отправили запрос на один токен прямо в Ollama и 5 раз через шлюз:

После первого, более медленного запроса шлюз добавлял от 20 до 35 мс. На фоне нескольких секунд на ответ это шум, на фоне крошечного запроса — заметно. Честный итог: рассчитывайте на около 400 МБ памяти и 750 МБ диска только под прокси, поэтому мы бы не ставили его на сервер с 1 ГБ; серверы на 1 и 2 ГБ мы не проверяли. Скорость самих моделей на этих двух ядрах: 22,5 токена в секунду у модели 0,5B и 10,0 у модели 1B.

Три вещи, которые нас удивили

  1. Неверный ключ даёт HTTP 400, а не 401. Отсутствующий ключ возвращает аккуратный 401, показанный выше, а ключ, не совпавший с мастер-ключом, вернул {"error":{"message":"No connected db.","type":"no_db_connection",...}} [400]. LiteLLM ищет незнакомые ключи в базе данных как «виртуальные ключи», а базу мы не подключали. Если ваше приложение считает «плохим ключом» только 401, обработайте и этот случай.
  2. Неизвестный алиас — понятная ошибка 400. model=nope вернул «Invalid model name passed in model=nope. Call /v1/models to view available models for your key.» Хорошо: опечатки в именах моделей видно сразу.
  3. Перезапуск проходит чисто. После systemctl restart litellm проверка здоровья снова отвечала в течение 20 секунд, а служба включена в автозапуск.

Облачная модель и что мы не проверяли

Облачная модель — ещё одна запись в model_list, под новым алиасом, например hosted. Если взять существующий алиас, LiteLLM начнёт распределять запросы между двумя моделями. Набросок ниже следует формату из документации проекта; мы его не запускали, потому что нужен ключ от вашего собственного аккаунта, поэтому сверьте имя модели у вашего провайдера, прежде чем на него полагаться:

  - model_name: hosted    litellm_params:      model: openai/gpt-4o-mini            # not run here: needs your key      api_key: os.environ/OPENAI_API_KEY

Если несколько записей используют один model_name, LiteLLM умеет распределять запросы между ними, но и это мы не проверяли. Базу данных мы тоже не поднимали, поэтому ключи для отдельных пользователей и лимиты расходов не проверены, а Admin UI и Docker не использовались. Всё в разделах выше — то, что мы действительно запускали.

Чтобы шлюз был доступен с других машин, не открывайте просто порт 4000. Поставьте перед ним веб-сервер с HTTPS, как в нашем руководстве по nginx и ufw, и пускайте только нужные адреса.

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

Что такое шлюз LLM, или LLM-роутер?

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

Нужен ли GPU для LiteLLM?

Нет. Сам LiteLLM только пересылает запросы и использует процессор и память, около 370 МиБ в нашем тесте. GPU важен лишь для моделей за ним, а наши две небольшие работали на процессоре.

LiteLLM proxy бесплатный?

Мы поставили его через pip и пользовались, ничего не платя. Проект при этом продаёт и некоторые функции отдельно, так что перед тем как строить бизнес на конкретной функции, прочитайте актуальную страницу лицензии.

Как подключить приложение к шлюзу?

Задайте в приложении базовый адрес API http://127.0.0.1:4000/v1, используйте мастер-ключ как ключ API и алиас вроде fast как имя модели. Подойдёт любой клиент, умеющий формат API OpenAI, как показывает пример на Python выше.

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

Да, это обычная схема: локальная модель для приватных дешёвых запросов, облачная для сложных вопросов, а между ними фолбэк. Мы проверили локальные модели и фолбэк; облачная запись выше не проверена.

Итоги

  • Шлюз даёт каждому приложению один адрес, один ключ и стабильные имена моделей. Он стоит того, когда вызывающих несколько или вы меняете модели.
  • Запускайте его из systemd на 127.0.0.1, с мастер-ключом в файле окружения, принадлежащем root, а не в YAML.
  • Фолбэк сработал как задумано: неработающий алиас ответил HTTP 200 от другой модели. Пишите поле model в журнал, чтобы заметить подмену.
  • Это стоило 370 МиБ памяти, 753 МБ диска и от 20 до 35 мс на тёплый запрос на 2 vCPU.
  • Неверный ключ вернул 400 «No connected db», а не 401, потому что у нас не было базы для виртуальных ключей.

Здесь не проверялось: облачные API, Postgres и виртуальные ключи, балансировка между несколькими развёртываниями, серверы на 1 и 2 ГБ, системы кроме Ubuntu 24.04. Всё это мы запускали на VPS HIP-HOSTING с 2 vCPU и 4 ГБ памяти; если нужен такой для этой задачи, смотрите hip.hosting и проверяйте текущее наличие в форме заказа.

PUBLISHED
13 ноября 2026 г.
AUTHOR
HIP-HOSTING
LANGUAGES
EN · RU