LiteLLM: AI Gateway для LLM – overview можливостей
0 (0)

Автор |  04/06/2026
Click to rate this post!
[Total: 0 Average: 0]

В попередніх постах по OpenTelemetry і VictoriaTraces (див. OpenTelemetry: OTel Collectors в Kubernetes та інтеграція з VictoriaMetrics stack  та VictoriaTraces: Tracing, Observability та OpenTelemetry) розбирали загальні концепції того, що таке observability та як працювати з трейсами.

Але взагалі на проекті ця тема з’явилась коли ми зрозуміли, що використання LLM стає важливою частиною нашого продукту – але на відміну від інших компонентів в мене нема ніякого моніторингу того, як взагалі LLM використовується, скільки токенів витрачає кожен із сервісів, скільки помилок ми отримуємо.

Тому почали все це діло “обмазувати” трейсингом для отримання даних від наших сервісів. На додачу у нас є окремий самописний OpenAI Exporter, який з OpenAI API збирає дані по токенам і витраченим грошам.

Втім, коли все “обмазали” і почали отримувати дані з різних систем в єдиний бекенд – VictoriaMetrics/VictoriaTraces – та робити дашборди в Grafana і метрики з VMAlert, то виявилась одна неприємна річ: різні компоненти використовують різні бібліотеки для роботи з LLM, різні бібліотеки для створення spans, по різному створюють атрибути – а тому доводиться робити різні дашборди, різні алерти.

Варіанти рішення тут, звісно, є: або переписувати код всіх систем з використанням однакових бібліотек – або створювати кастомні атрибути для спанів, щоб вони були однакові в усіх сервісах.

Але це, по-перше – багато змін в коді, по-друге – не хочеться обмежувати девелоперів правилами типу “використовуй тільки цю бібліотеку” або “завжди додавай такі атрибути до спанів”.

Тому вирішив подивитись на інший підхід: нехай всі роблять те, що хочуть – але всі запити від всіх систем відправляти через єдиний шлюз, AI Gateway – а він вже сам буде створювати і трейси, і метрики – і тоді у всіх буде загальний контекст у вигляді загальних атрибутів/лейблів/метрик.

Крім того, загальний гейтвей вирішить ще пачку задач – і централізований менеджмент доступів, і бюджети з лімітами, і failover між OpenAI/Anthropic, якщо одна система впала.

Сьогодні подивимось на те, що таке LiteLLM взагалі, поганяємо локально в Docker, а потім, якщо сподобається (а so far – подобається, хоча деякі питання виникли) – то запустимо в Kubernetes та інтегруємо з нашим існуючим стеком моніторингу – VictoriaMetrics, VictoriaLogs, VictoriaTraces, Grafana.

LiteLLM – основні можливості

Сторінка проекту – litellm.ai, вся документація – docs.litellm.ai, GitHub проекту – BerriAI/litellm.

Отже, що таке таке LiteLLM: це система для створення єдиного шлюзу, яка через себе проксює всі запити до LLM і різних провайдерів – Backend API може слати запити до AWS Bedrock для RAG, клієнтські AI Agents можуть слати запити до OpenAI або Anthropic, і навіть Claude Code девелоперів можна зароутити через цей шлюз та отримати картину того, хто і скільки токенів використовує (правда, у випадку з Claude Code питання використання API, бо LiteLLM наче не вміє працювати через subscription – тільки API).

При цьому ми спокійно залишаємо вже існуючі метрики та трейси, які вже створюються із сервісів – бо вони вже звичні девелоперам і трохи інтегровані в наш моніторинг. А на додачу до них – отримаємо нові, з загальним контекстом для всього нашого проекту та AI/LLM в ньому.

Є також LiteLLM Python SDK – можна мати всі можливості LiteLLM прямо з коду без необхідності піднімати окремий proxy service.

З цікавих можливостей LiteLLM:

  • Admin Web UI: єдиний веб-інтерфейс для моніторингу і налаштувань
  • Alerting & Monitoring: з коробки маємо логи, метрики, алерти, інтеграцію з Prometheus/VictoriaMetrics та системами типу Phoenix/Langfuse
  • Cost tracking: з коробки автоматично моніторить витрати на роботу з моделями, повертає метрики та трейси з вартістю, можна налаштовувати бюджети на різні ключі, команди, юзерів
  • Centralized authentication: єдина система для управління доступами – групи, юзери, ключі, окремі бюджети і ліміти, та навіть обмеження доступу до LiteLLM по IP
  • Budgets, Rate Limits: багато налаштувань для контролю використання провайдерів
  • Skills Registry: тримаємо всі скіли в одному місці – але це начебто тільки для Claude Code
  • MCP Gateway: можна мати всі налаштовані MCP servers на LiteLLM – і клієнти типу VSCode, Cursor, Claude Code просто звертаються до нього
  • Agent Gateway: можна мати проксі для agent-to-agent комунікації і моніторити всю цю активність
  • LLM Response caching: LiteLLM може тримати кеш відповідей від LLM – на той самий запит від клієнта повертати закешовану відповідь, а не робити новий запит до LLM
  • Memory: зберігання налаштувань і контексту між сесіями
  • Vector Store: LiteLLM може грати роль проксі до різних Vector Stores і записувати додаткові дані для моніторингу
  • Guardrails: захист конфіденційних даних – prompt injection, маскування даних юзерів
    • Policies: є набір готових політик, можна створювати власні
  • Load Balancing: автоматичне балансування між різними провайдерами та/або моделями в залежність від навантаження чи пріорітетів
    • Model Health Status: перевірка статусу LLM і виключення з роутінгу тих провайдерів, які недоступні
  • Fallbacks: автоматичний роутинг запитів, якщо модель чи провайдер недоступні
  • Traffic Mirroring: цікава можливість – відправляти запити одночасно до двох різних моделей, аби порівнювати результати їхньої роботи

Для чого це нам?

Кожного разу, коли хочеться запустити щось новеньке – треба спитати себе “А яку, власне, проблему ми вирішуємо”?

Конкретно в нашому випадку це:

  • менеджмент доступів: замість 100500 API ключів в OpenAI/Anthropic – мати налаштовані групи в LiteLLM, кожен з власними бюджетами і лімітами
  • моніторинг: мати загальні метрики, логи, трейси з загальними лейблами/атрибутами
  • failover: мати можливість автоматично переключитись на іншого провайдера, якщо на поточному вперлись в ліміти (або якщо Claude знову впав)

Запуск LiteLLM з Docker

Для повноцінної роботи Лайт потрібна база даних – в ній будуть зберігатись всі юзери та групи, налаштування моделей, бюджетів, витрати на LLM, див. What is stored in the DB.

Тому з Docker створимо два контейнери – сам Gateway та PostgreSQL для нього.

Документація – Getting Started Tutorial.

Для Production setup ще варто додавати Redis – але про це будемо говорити в наступній частині. Див. Deployment Options та High Availability Setup (Resolve DB Deadlocks).

Для запуску в Kubernetes є Helm chart (beta) і неофіційний litellm-operator.

Config.yaml – налаштування LiteLLM

Перед запуском LiteLLM нам потрібен конфіг того, як він буде працювати – див. документацію Config.yaml, а всі параметри в All settings.

Створюємо файл litellm_config.yaml з мінімальними налаштуваннями:

model_list:
  - model_name: gpt-4o-mini
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

litellm_settings:
  callbacks: 
  - prometheus

Тут:

  • model_list: список моделей, які будуть доступні клієнтам – див. LLM configs model_list
    • model_name: ім’я, яке отримуємо в запиті від клієнта (як ми його будемо вказувати в коді, наприклад client.chat.completions.create(model="gpt-4o-mini")
      • кожна модель в цьому списку – це окремий deployment в термінології LiteLLM – див. Quick Start та Proxy – Load Balancing
      • litellm_params: параметри провайдера для цієї моделі
  • general_settings: див. General Settings general_settings
    • master_key: головний ключ для аутентифікації і в Web UI для адміна
    • тут же можна передати і параметри для бази даних, але зараз зробимо через змінні оточення
  • litellm_settings: налаштування самого LiteLLM – моніторинг, логгінг, кешування, див. litellm_settings – Reference
    • callbacks: відкриваємо метрики (ендпоінт /metrics/), пізніше сюди додамо відправку трейсів, див. Prometheus metrics

Створюємо docker-compose.yml – описуємо запуск самого LiteLLM та PostgreSQL для нього:

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: litellm
      POSTGRES_PASSWORD: litellm
      POSTGRES_DB: litellm
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U litellm"]
      interval: 5s
      timeout: 5s
      retries: 5

  litellm:
    image: ghcr.io/berriai/litellm:main-latest
    ports:
      - "4000:4000"
    volumes:
      - ./litellm_config.yaml:/app/config.yaml
    env_file:
      - .env
    environment:
      DATABASE_URL: postgresql://litellm:litellm@postgres:5432/litellm
      LITELLM_LOG: DEBUG
    command: ["--config", "/app/config.yaml", "--port", "4000"]
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  postgres_data:

Тут PostgreSQL з health check, який використовується інстансом LiteLLM, а через змінну оточення DATABASE_URL для LiteLLM передаємо connection string для підключення до бази даних.

Генеруємо ключ для $LITELLM_MASTER_KEY – в OpenAI форматі, з префіксом sk- (“secret key”):

$ echo "sk-$(openssl rand -hex 16)"
sk-db69761228204509fa80f934bff6e0f5

Задаємо в змінні оточення:

$ export LITELLM_MASTER_KEY=sk-db69761228204509fa80f934bff6e0f5

Створюємо файл .env з API ключем для OpenAI та самого LiteLLM:

$ echo "OPENAI_API_KEY=$OPENAI_API_KEY" > .env
$ echo "LITELLM_MASTER_KEY=$LITELLM_MASTER_KEY" >> .env

Запускаємо – перший запуск буде кілька хвилин, поки накатяться всі міграції в базу.

Чекаємо на повідомлення “Application startup complete” та “Uvicorn running on“:

$ docker compose up
...
litellm-1   | INFO:     Waiting for application startup.
litellm-1   | 
litellm-1   |    ██╗     ██╗████████╗███████╗██╗     ██╗     ███╗   ███╗
litellm-1   |    ██║     ██║╚══██╔══╝██╔════╝██║     ██║     ████╗ ████║
litellm-1   |    ██║     ██║   ██║   █████╗  ██║     ██║     ██╔████╔██║
litellm-1   |    ██║     ██║   ██║   ██╔══╝  ██║     ██║     ██║╚██╔╝██║
litellm-1   |    ███████╗██║   ██║   ███████╗███████╗███████╗██║ ╚═╝ ██║
litellm-1   |    ╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝╚══════╝╚═╝     ╚═╝
litellm-1   | 
litellm-1   | query-engine ac9d7041ed77bcc8a8dbd2ab6616b39013829574
litellm-1   | INFO:     Application startup complete.
litellm-1   | INFO:     Uvicorn running on http://0.0.0.0:4000 (Press CTRL+C to quit)

Заходимо на http://0.0.0.0:4000 – тут посилання на Admin UI та документація по API самого LiteLLM (Swagger  Docs можна відключити з NO_DOCS=true, див. environment variables – Reference, але вцілому її цікаво глянути – бо можливостей в API дуже багато):

LiteLLM: AI Gateway для LLM - overview можливостей

Логінимось в адмінку – дефолтний логін “admin“, пароль – $LITELLM_MASTER_KEY, який створювали вище:

LiteLLM: AI Gateway для LLM - overview можливостей

І попадаємо в дуже приємний інтерфейс:

LiteLLM: AI Gateway для LLM - overview можливостей

Вже маємо метрики, але ендпоінт саме /metrics/ – зі слешем в кінці (хоча в документації вказаний як /metrics):

$ curl -s http://localhost:4000/metrics/ 
...
# HELP litellm_in_flight_requests Number of HTTP requests currently in-flight on this uvicorn worker
# TYPE litellm_in_flight_requests gauge
litellm_in_flight_requests 1.0

По різним налаштуванням пройдемось далі – зараз давайте створимо “клієнта” – простенький скрипт, який звертається до OpenAI через LiteLLM.

Demo Python App – AI Client

Пишемо скрипт, який використовує OpenAI і передає один промпт:

#!/usr/bin/env python

import os
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:4000",
    api_key=os.getenv("LITELLM_MASTER_KEY"),
)

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Say hello in one sentence"}],
)

print(response.choices[0].message.content)
print(f"Tokens: {response.usage}")

Тут:

  • base_url для OpenAI: замість дефолтного OpenAI ендпоінта api.openai.com перевизначаємо ендпоінт нашого інстансу LiteLLM
  • model: ім’я моделі, як ми його задавали в параметрах LiteLLM – model_list.model_name

Встановлюємо залежності:

$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install openai

Запускаємо скрипт:

$ ./demo-llm.py
Hello! How can I assist you today?
Tokens: CompletionUsage(completion_tokens=9, prompt_tokens=12, total_tokens=21, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0), prompt_tokens_details=PromptTokensDetails(audio_tokens=0, cached_tokens=0))

Переходимо в адмінку > Usage – і вже маємо дані по запитам:

LiteLLM: AI Gateway для LLM - overview можливостей

Трейси дивимось в Logs:

LiteLLM: AI Gateway для LLM - overview можливостей

Та нові метрики:

 $ curl -s http://localhost:4000/metrics/ | grep "# HELP lite"
# HELP litellm_in_flight_requests Number of HTTP requests currently in-flight on this uvicorn worker
# HELP litellm_proxy_failed_requests_metric_total Total number of failed responses from proxy - the client did not get a success response from litellm proxy
# HELP litellm_proxy_total_requests_metric_total Total number of requests made to the proxy server - track number of client side requests
# HELP litellm_proxy_total_requests_metric_created Total number of requests made to the proxy server - track number of client side requests
...
# HELP litellm_total_users Total number of users in LiteLLM
# HELP litellm_teams_count Total number of teams in LiteLLM

Тепер, як маємо сам LiteLLM та клієнта – можна подивитись що ж можемо з LiteLLM цікавого робити, і перше, що цікавить особисто мене – це моніторинг.

Monitoring, OpenTelemetry та Traces

Метрики будемо збирати з VMAgent або OTel Collector, логи – просто аутпут, який, якщо в Kubernetes, то збираємо з Promtail, vlagent, OTel filelog, whatever.

Цікаві метрики розберемо далі, але сьогодні їх збирати не будемо – бо зараз все локально в Docker, документація по всім доступним метрикам – Prometheus metrics.

А от глянути як можна писати трейси до VictoriaTraces можемо.

Документація – OpenTelemetry та OpenTelemetry – Tracing LLMs with any observability tool.

OpenTelemetry та VictoriaTraces

LiteLLM може писати дані з OpenTelemetry Protocol. Для VictoriaTraces використовуємо ендпоінт /insert/opentelemetry/v1/traces, див. Data ingestion.

Відкриваємо локальний порт до інстансу VictoriaTraces в Kubernetes, аби отримати доступ із Docker container з LiteLLM – додаємо --address=0.0.0.0:

$ kk port-forward svc/atlas-victoriametrics-vt-single-server 10428 --address=0.0.0.0

В docker-compose.yaml додаємо параметр extra_hosts:

litellm:
  image: ghcr.io/berriai/litellm:main-latest
  ...
  extra_hosts:
    - "host.docker.internal:host-gateway"

В .env для LiteLLM додаємо змінні для відправки трейсів:

OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://host.docker.internal:10428/insert/opentelemetry/v1/traces
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

Можна задати через власні змінні LiteLLM – OTEL_EXPORTER та OTEL_ENDPOINT:

OTEL_ENDPOINT=http://host.docker.internal:10428/insert/opentelemetry/v1/traces
OTEL_EXPORTER=otlp_http

Трохи mess в документації (хоча взагалі документація дуже класна) – але обидва варіанти працюють. Див. також Exporter & resource.

В конфіг litellm_config.yaml до callbacks додаємо “otel” – включаємо відправку трейсів:

...
litellm_settings:
  callbacks: 
  - prometheus
  - otel

Замість або на додачу до “otel” можна вказати “langfuse” або “arize” для Phoenix (див. Arize Phoenix: сервіс моніторингу LLM – запуск в Kubernetes) – тоді трейси будуть відправлятись в кілька сервісів – тестив, працює, зручно, прикольно.

Перезапускаємо контейнери, в логах маємо побачити, що експортери активні:

...
 11:31:57 - LiteLLM Proxy:DEBUG: callback_utils.py:34 - initializing callbacks=['prometheus', 'otel'] on proxy
...
litellm-1 | self.OTEL_EXPORTER: otlp_http
litellm-1 | self.OTEL_ENDPOINT: http://host.docker.internal:10428/insert/opentelemetry/v1/traces
litellm-1 | self.OTEL_HEADERS: None
...

Перевіряємо, що змінні оточення з .env застосувались – при першому запуску трохи довелось подебажити:

$ docker compose exec litellm env | grep OTEL
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://host.docker.internal:10428/insert/opentelemetry/v1/traces
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

Ще раз запускаємо наш скрипт клієнта:

$ ./demo-llm.py 
Hello! How can I assist you today?
Tokens: CompletionUsage(completion_tokens=9, prompt_tokens=12, total_tokens=21, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0), prompt_tokens_details=PromptTokensDetails(audio_tokens=0, cached_tokens=0))

І в VictoriaTraces шукаємо спани по {"resource_attr:service.name"="litellm"}:

LiteLLM: AI Gateway для LLM - overview можливостей

Або відразу в Grafana з групуванням:

LiteLLM: AI Gateway для LLM - overview можливостей

LiteLLM Span Attributes

Атрибутів прям дуже багато – просто відразу маємо все, без всяких інструментаріїв в коді.

“Корневий” спан у нас буде “Received Proxy Server Request“, див. Span Hierarchy та Span name reference.

Див. також документацію самого OpenTelemetry Semantic conventions for generative client AI spans – імена спанів та атрибутів.

Всі атрибути разом простіше подивитись в самій VictoriaTraces:

LiteLLM: AI Gateway для LLM - overview можливостей

Також можна включити спани LiteLLM як дочірні до спанів клієнта, якщо там налаштований трейсінг – див. Context propagation (W3C traceparent).

Всі атрибути див. в Attributes Reference, тут коротко з основних, які можуть бути цікавими далі для моніторингу.

Costs – можна будувати графіки витрат по моделях, юзерах, командах:

  • gen_ai.cost.total_cost: скільки грошей витратили на обробку запиту
  • gen_ai.cost.input_cost / gen_ai.cost.output_cost: розбивка вартості по вхідним/вихідним токенам

Tokens Usage:

  • gen_ai.usage.input_tokens / output_tokens / total_tokens

Execution time – час обробки запиту:

  • duration: загальний час обробки
  • hidden_params => litellm_overhead_time_ms: скільки часу зайняла робота самого проксі

Model і провайдер:

  • gen_ai.request.model: яка модель використовувалась в запиті
  • gen_ai.response.model: яка модель реально відповіла (може відрізнятись, наприклад – якщо спрацював fallback)
  • gen_ai.system: провайдер

Дані по юзеру:

  • metadata.user_api_key_hash: який ключ використовувався
  • metadata.user_api_key_user_id / team_id: хто зробив запит – конкретний юзер чи група
  • metadata.requester_ip_address: адреса клієнта

Rate limits від провайдера (в hidden_params), див. Rate Limit Headers:

  • x_ratelimit_remaining_requests: скільки запитів ще залишилось до того, як провайдер почне повертати помилку 429 – Too Many Requests
  • x_ratelimit_remaining_tokens: те саме, але по токенам

Content (може містити конфіденційні дані, можна відключити, див. Redacting Messages, Response Content та Capturing Message Content):

  • gen_ai.input.messages: сам промпт
  • gen_ai.output.messages: відповідь моделі

Status запиту:

  • status_code: 1 – OK (2 = ERROR)
  • gen_ai.response.finish_reasons: чому зупинилась генерація

Access Management

Основна концепція – можемо мати різні Organizations (але це Enterprise feature), кожна Organization може містити кілька Teams, в кожній Team – тримаємо Users, а кожен User може створювати власні API Keys – див. User Management Hierarchy.

Users логіняться у Web UI або API, а API Keys використовуємо для сервісів.

Аутентифікація та доступ

Основний метод – API Keys для сервісів або юзерів, які працюють з LiteLLM через API – там звичайні паролі для юзерів, які користуються Web UI.

Є підтримка аутентифікації з JWT – але це Enterprise фіча.

З коробки маємо SSO – “SSO is now Free for up to 5 users“, більше юзерів тільки в Enterprise, див. SSO for Admin UI.

Є навіть підтримка Users Provisioning з SCIM (див Okta: інтеграція з Google Workspaces, частина 1 – Provisioning) – але і тут Premium.

Втім, можемо автоматизувати це з litellm-operator – може якось спробую, але не впевнений, бо оператор не офіційний.

І дуже прикольна штука – обмеження по IP, див. IP Address Filtering – але знов-таки Enterprise фіча 🙁

В результаті з Free-опцій маємо тільки власне, Teams, юзерів та API Keys.

Teams та Users

Кожній Team можна налаштувати параметри того, до яких моделей із model_list юзери і ключі цієї групи будуть мати доступ, максимальний бюджет Costs, яка група може витратити на день/тиждень/місяць, можемо задати ліміти на Tokens per minute Limit (TPM) та Requests per minute Limit (RPM) – див. Budgets, Rate Limits та Setting Team Budgets.

Крім того, є Access Groups – групуємо списки моделей, MCP або агентів в єдиний список, який потім можна підключати до Teams або Users.

Ну і в моніторингу, як бачили вище, маємо атрибути з іменами груп та юзерів – тому потім можемо будувати графіки та алерти по ним.

Окрім звичайних юзерів можемо мати Service Accounts.

Бюджети та ліміти

Бюджети та ліміти на Tokens/Requests Per Minute можна задати на рівні всього Gateway, на рівні Team, для кожного юзера в цій Team, або на окремих юзерів поза Team чи на конкретні API Keys.

Але тут є одна трохи дивна, як на мене, штука:

  • Team Limits застосовуються тільки для тих API Keys, які явно були створені юзером або адміном для цієї групи (мають team_id)
  • при цьому User з Global Proxy Role == Internal User (Create/Delete/View) може створювати власні ключі (не прив’язані до Team), не задавати їм ніяких лімітів – і спокійно спамити LLM запитами
  • єдине обмеження, яке ми можемо задати в Web UI при створенні нового юзера – це які моделі йому будуть доступні (хоча в API docs для /user/new є параметри max_budget, rpm_limit та tpm_limit – нижче буде приклад)

Тобто з одного боку – начебто є User, який є членом Team, і в Team ми задаємо, наприклад, Team Member RPM Limit – але при цьому цей юзер може створювати ключі, на які цей ліміт ніяк не впливає.

А єдине обмеження, яке ми можемо задати при створенні юзера в Web UI – це те, які моделі йому будуть доступні – хоча через конфіг-файл ще можна задати upperbound_key_generate_params, див. All Settings for Self Serve.

Виглядає так, наче UI просто ще не має всіх опцій, які доступні в API.

Взагалі, мабуть, треба буде писати окремий пост на тему доступів і лімітів, бо тут “нє всьо так однозначно”.

RBAC та System Roles

Простенький (принаймні на зараз, у версії v1.82.6), з кількома дефолтними ролями – але є RBAC.

Ролі поділені на три основних групи:

  • глобальні всього LiteLLM – admin та admin_read_only
  • user roles – user та user_read_only
  • Organization та Team Roles – org/team admin

Див. User Roles та Available Roles.

Ну і давайте глянемо як це все виглядає на практиці: створимо Team з бюджетом та лімітами на Requests per minute, потім в цю групу додамо юзера, юзеру створимо API Key – і використаємо його в нашому Demo App.

Створення Team

Переходимо в Teams > Create Team:

LiteLLM: AI Gateway для LLM - overview можливостей

Створюємо групу:

LiteLLM: AI Gateway для LLM - overview можливостей

Тут задаємо доступ до всіх моделей, вказуємо загальний бюджет групи в 100 долларів на день (Reset Budget: daily), і для перевірки задамо жорсткий ліміт в 1 запит на хвилину.

Бюджети і ліміти в Team задаються на двох “рівнях” – самої групи і всіх юзерів в ній, та окремо на кожного юзера (точніше – його ключів, як створені в цій групі – див. далі), тобто:

  • Max Budget (USD): це бюджет всіх разом, а Team Member Budget (USD) – на кожного юзера в групі
  • Requests per minute Limit (RPM): на всю Team, а Team Member RPM Limit – кожного юзера в групі

Бюджети створюються як окремі об’єкти, доступні в Budgets:

LiteLLM: AI Gateway для LLM - overview можливостей

LiteLLM: AI Gateway для LLM - overview можливостей

І тут ловив ще одну чи то багу, чи то фічу, що після зміни значень в Team Budget значення бюджету для юзера не змінились, поки не зробив це руками саме в Budgets.

Нижче в параметрах нової Team у Router Settings можна налаштувати власні параметри для Load Balancing та Fallbacks:

LiteLLM: AI Gateway для LLM - overview можливостей

Створення User у Web UI

Юзери в UI створюються через Invite, який відправляється на пошту – тому треба мати SMTP, але після створення Invite у нас буде показаний лінк, за яким можемо зареєструватись.

Клікаємо Invite User:

LiteLLM: AI Gateway для LLM - overview можливостей

Задаємо роль з правами на створення ключів, вибираємо створену вище групу, в Personal Key Creation можна обмежити доступ до моделей – і це, власне, єдине обмеження, яке ми тут можемо встановити для юзера:

LiteLLM: AI Gateway для LLM - overview можливостей

Ба більше: під час створення юзера в Team – йому не можна  відразу задати Team Role, і він буде створений з дефолтною роллю User – але це можна змінити потім.

Клікаємо на Invite User – отримуємо посилання, яке було відправлено на пошту:

LiteLLM: AI Gateway для LLM - overview можливостей

Відкриваємо його в Incognito, задаємо пароль нового юзера, і попадаємо в Web UI – але тут вже, звісно, набагато менше доступів:

LiteLLM: AI Gateway для LLM - overview можливостейTeam Permissions

Вже після інвайту можемо змінити роль юзера в цій групі – бо без Admin ролі він не зможе створювати ключі в групі, і навіть встановити йому власні Member Limits/Budget:

LiteLLM: AI Gateway для LLM - overview можливостей

Інший варіант дозволити створення ключів для групи –  задати через Member Permissions:

LiteLLM: AI Gateway для LLM - overview можливостей

Створення User API Key для Team у Web UI

Тепер під цим юзером створюємо ключ – вказуємо групу, але не задаємо RPM:

LiteLLM: AI Gateway для LLM - overview можливостей

 

Зберігаємо ключ:

LiteLLM: AI Gateway для LLM - overview можливостей

Задаємо нову змінну:

$ export LITELLM_USER_KEY=sk-1WezQOWNC55fyt_z6y7V7w

В коді Demo App міняємо назву змінної з LITELLM_MASTER_KEY на LITELLM_USER_KEY, і  можна додати max_retries – аби ловити Exception відразу, як LiteLLM поверне клієнту 429:

...

client = OpenAI(
    base_url="http://localhost:4000",
    api_key=os.getenv("LITELLM_USER_KEY"),
    max_retries=0,
)

...

Запускаємо скрипт два рази підряд – перший спрацював, а на другий раз ловимо 429 Rate limit exceeded – бо задавали RPM Limit в Team:

 $ ./demo-llm.py 
Hello! How can I assist you today?
...

$ ./demo-llm.py 
...
openai.RateLimitError: Error code: 429 - {'error': {'message': 'Rate limit exceeded for team: aa65abde-4a51-49ee-9271-d16b09fd2058. Limit type: requests. Current limit: 1, Remaining: 0. Limit resets at: 2026-06-04 09:13:21 UTC', 'type': 'None', 'param': 'None', 'code': '429'}}

Створення User API Key у Web UI без Team і без Limits

Тепер під тим жеж юзером створюємо ще один ключ – але вже без Team, і теж не задаємо ніяких лімітів:

LiteLLM: AI Gateway для LLM - overview можливостей

Оновлюємо змінну:

$ export LITELLM_USER_KEY=sk-K7Dvc7gSFye6RKsFBB2PyQ

Запускаємо скрипт – і спокійно спамимо LiteLLM запитами:

$ ./demo-llm.py 
Hello! How can I assist you today?
...

$ ./demo-llm.py 
Hello! How can I assist you today?
...

Тобто, якщо ми даємо юзерам можливість створювати ключі – то вони спокійно можуть робити ключі без всяких обмежень (окрім тих, що ми задамо глобально у upperbound_key_generate_params).

Але при створенні юзера чи ключа через API ми відразу можемо задавати всі потрібні ліміти.

Створення User та API Key з LiteLLM API з Rate Limit

Див. LiteLLM API /user/new.

Створюємо юзера з rpm_limit:

$ curl -X POST http://localhost:4000/user/new \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_email": "[email protected]",
    "rpm_limit": 1,
    "user_role": "internal_user"
  }'

В response отримуємо його ключ, там жеж бачимо, що team_id пусте – юзер не належить до групи, але має власний rpm_limit:

{..., "max_budget":null, "user_id":"7a9a6ced-ae6a-497e-a9ba-e35825139845", "team_id":null, ..., "rpm_limit":1, ..., "key":"sk-cazziUlsSKQEGTsTUGILRA", ... ,"user_email":"[email protected]","user_role":"internal_user", ... }

Задаємо цей ключ в змінну:

$ export LITELLM_USER_KEY=sk-cazziUlsSKQEGTsTUGILRA

Запускаємо скрипт два рази – і на другий знов отримуємо 429:

$ ./demo-llm.py 
Hello! How can I assist you today?
...

$ ./demo-llm.py 
...
openai.RateLimitError: Error code: 429 - {'error': {'message': 'Rate limit exceeded [...] }

Замість висновків

Система виглядає дійсно круто в плані того, що дозволяє мати загальний моніторинг LLM – з коробки маємо купу корисних метрик, маємо трейси. Ну і 50,000 зірок на GitHub далеко не всі збирають.

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

Але от з юзер менеджментом в мене виникли питання – бо якось не дуже інтуїтивно зроблено. Місцями, на перший погляд, заплутано, місцями з чимось, що виглядає як баги. Хоча вцілому можливостей по менеджменту доступів дійсно багато.

Все ж спробуємо її запустити у нас і подивимось вже в реальній роботі – благо, коли проект в MVP то можна собі дозволити експерименти.

Ну і коли буду запускати в Kubernetes – мабуть, ще раз окремо пройдусь по доступам і юзерам, бо тут треба розібратись додатково.

Loading