Як я перестав переписувати код при кожній зміні LLM-провайдера. Архітектура, що економить нерви
Знаєте це відчуття? П’ятниця, вечір. Ви щойно завершили міграцію кодової бази з GPT-4 на Claude — переписали API-виклики, полагодили парсинг відповідей, оновили логіку стримінгу. Тиждень був пеклом, але фух — тести зелені.
І тут Google випускає новий Gemini з бенчмарками, від яких решта моделей виглядає як калькулятор із 1995 року.
Так. Я через це проходив. Не раз.

Після третьої міграції за пів року я сів і подумав: навіщо я переписую інтеграційний код, якщо єдине, що змінюється, — це HTTP-ендпоінт? Запит — JSON. Відповідь — JSON. Усі моделі приймають повідомлення на вхід і віддають текст на виході. Але дідька лисого. Чому зміна провайдера відчувається як заміна двигуна на ходу?
Саме так я натрапив на
Чому ваш інтеграційний код — це бомба сповільненої дії
Давайте чесно глянемо на еволюцію типового
Місяць 1: просто візьмемо OpenAI. Один провайдер, один SDK, усе просто.
Місяць 3: для задачі сумаризації Claude насправді працює краще. Давайте додамо Anthropic. Тепер у вас два різні SDK, два потоки автентифікації, два формати відповідей і один if/else, який переслідує вас уві сні.
Місяць 5: Gemini Flash набагато дешевший для простих запитів. Давайте перенаправимо туди нескладні задачі. Логіка маршрутизації тепер розповзлася по трьох файлах, обробка помилок для кожного провайдера — своя, а новий розробник вбив два дні лише на те, щоб розібратися, який API-ключ куди підставляти.
Місяць 7: хтось питає: «А можемо підняти локальну модель для чутливих даних?» — і ви починаєте оновлювати LinkedIn.
Корінь зла простий: кожен
Те, що нам потрібно — це універсальний перекладач. Reverse proxy, який зовні прикидається старим добрим OpenAI API, а всередині мовчки робить брудну роботу з перекладу запитів на «діалекти» інших провайдерів.
Рішення: LM-Proxy за одну хвилину
Його філософія проста:
Ваш застосунок спілкується з одним API.
LM-Proxy спілкується з усіма іншими.
OpenAI, Anthropic, Google (AI Studio / Vertex AI), локальні PyTorch-моделі, Ollama, /v1/chat/completions.
«Окей, черговий
Чому це працює
1. Радикальний мінімалізм
Жодного Kubernetes. Жодного Redis. Ніякої архітектури з 47 мікросервісів.
pip install lm-proxy lm-proxy
Один Python-пакет. Один TOML-конфіг. Одна команда. Запускається на VPS за $2/місяць у Docker-контейнері або вбудовується напряму в Python-застосунок як FastAPI-суб-застосунок. Ядро навмисно компактне — жодного зайвого баласту для задачі, яка його не потребує.
2. Конфігурація, для якої не потрібна наукова ступінь
Ось повний робочий конфіг, який маршрутизує GPT-запити до OpenAI, Claude — до Anthropic, а Gemini — до Google:
host = "0.0.0.0" port = 8000 # Підключення до провайдерів (upstream) [connections.openai] api_type = "open_ai" api_base = "https://api.openai.com/v1/" api_key = "env:OPENAI_API_KEY" [connections.anthropic] api_type = "anthropic" api_key = "env:ANTHROPIC_API_KEY" [connections.google] api_type = "google_ai_studio" api_key = "env:GOOGLE_API_KEY" # Магія маршрутизації [routing] "gpt*" = "openai.*" "claude*" = "anthropic.*" "gemini*" = "google.*" "*" = "openai.gpt-4o-mini" # fallback # Групи доступу [groups.default] api_keys = ["my-team-api-key-1", "my-team-api-key-2"]
Прочитайте зверху донизу. Ви зрозуміли його за 30 секунд, правда? Чистий TOML з очевидною семантикою — ніяких кошмарів з відступами в YAML і JSON-простирадл на 200 рядків. До речі, YAML, JSON і Python-формати конфігурації теж підтримуються.
Префікс env: підтягує секрети зі змінних оточення або .env-файлів — ключі ніколи не потрапляють у git.
3. Маршрутизація за патернами (кілер-фіча)
Секція [routing] — це місце, де відбувається магія. Ключі — це glob-патерни, що зіставляються з назвою моделі, яку надсилає клієнт. Суфікс .* означає «передати назву моделі провайдеру як є». Тобто коли клієнт запитує claude-sonnet-4-5-20250929,
Можна й прив’язати патерн до конкретної моделі:
[routing] "custom*" = "local.llama-7b" # Будь-який "custom*" запит → локальна Llama "gpt-3.5*" = "openai.gpt-3.5-turbo" # Прив'язка до конкретної моделі "*" = "openai.gpt-4o-mini" # Все інше → дешевий fallback
Це означає, що клієнтський код ніколи не змінюється. Хочете спробувати нову модель — оновіть один рядок у конфігу. A/B-тест двох провайдерів — додайте правило. Вивести модель з обігу — перенаправте патерн. Нуль змін у коді.
4. Віртуальні ключі та контроль доступу
Ця фіча перетворює
# Преміум-користувачі мають доступ до всього [groups.premium] api_keys = ["premium-key-1", "premium-key-2"] allowed_connections = "*" # Безкоштовний тариф — лише OpenAI [groups.free] api_keys = ["free-key-1"] allowed_connections = "openai" # Внутрішні інструменти — лише локальні моделі [groups.internal] api_keys = ["internal-key-1"] allowed_connections = "local"
Upstream API-ключі ніколи не потрапляють до клієнтів. Можна проводити їх ротацію, не чіпаючи жодної клієнтської конфігурації. Можна створювати гранулярні рівні доступу — преміум-користувачі отримують Claude Opus, безкоштовні — GPT-4o-mini, внутрішні інструменти працюють на локальних моделях. Усе управляється одним конфіг-файлом.
Підтримується навіть зовнішня автентифікація — валідація віртуальних API-ключів через Keycloak, Auth0 або будь-який OIDC-провайдер:
[api_key_check]
class = "lm_proxy.api_key_check.CheckAPIKeyWithRequest"
method = "POST"
url = "http://keycloak:8080/realms/master/protocol/openid-connect/userinfo"
response_as_user_info = true
use_cache = true
cache_ttl = 60
[api_key_check.headers]
Authorization = "Bearer {api_key}"
Ваші наявні OAuth-токени автоматично стають ключами до LLM API. А якщо вбудовані валідатори не підходять, можна написати кастомний — просто Python-функція, яка приймає рядок API-ключа і повертає назву групи.
5. Повноцінна підтримка стримінгу
Cтримінг працює з коробки. Клієнти отримують відповіді в реальному часі, токен за токеном, незалежно від того, хто і в якому форматі їх генерує.
6. Бібліотека, а не лише сервер
Реальний сценарій: 5 хвилин до production
Розглянемо конкретну ситуацію. Ви розробляєте SaaS-продукт, який використовує LLM. Хочете GPT-4o для складних міркувань, Claude Sonnet для роботи з великими документами та Gemini Flash для дешевої класифікації.
Крок 1: Встановлення
pip install lm-proxy
Крок 2: Створити .env
OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... GOOGLE_API_KEY=AI...
Крок 3: Створити config.toml
host = "0.0.0.0" port = 8000 [connections.openai] api_type = "open_ai" api_base = "https://api.openai.com/v1/" api_key = "env:OPENAI_API_KEY" [connections.anthropic] api_type = "anthropic" api_key = "env:ANTHROPIC_API_KEY" [connections.google] api_type = "google_ai_studio" api_key = "env:GOOGLE_API_KEY" [routing] "gpt*" = "openai.*" "claude*" = "anthropic.*" "gemini*" = "google.*" "*" = "google.gemini-2.0-flash" [groups.backend] api_keys = ["backend-service-key"] allowed_connections = "*" [groups.frontend] api_keys = ["frontend-widget-key"] allowed_connections = "google" # лише дешеві моделі
Крок 4: Запуск
lm-proxy
Крок 5: Використання з вашого застосунку
from openai import OpenAI
# Зверніть увагу: ми стукаємо на наш проксі
client = OpenAI(
api_key="backend-service-key",
base_url="http://localhost:8000/v1"
)
# Складні міркування → GPT-4o
response = client.chat.completions.create(
model="gpt-5.2",
messages=[{"role": "user", "content": "Проаналізуй цей контракт..."}]
)
# Великий документ → Claude
response = client.chat.completions.create(
model="claude-opus-4-6",
messages=[{"role": "user", "content": "Підсумуй цей 100-сторінковий звіт..."}]
)
# Швидка класифікація → Gemini Flash (дешево)
response = client.chat.completions.create(
model="gemini-2.0-flash",
messages=[{"role": "user", "content": "Це лист — спам? ..."}]
)
Один клієнт, один base URL, три провайдери. А завтра, коли вийде чергова модель, на 50% дешевша, ви зміните один рядок у config.toml і перезапустите сервер. Код застосунку залишиться незмінним.
LM-Proxy vs LiteLLM: Давид і Голіаф
У коментарях обов’язково запитають: «А чим це краще за LiteLLM?»
Скажемо чесно — LiteLLM — це
То чому ж обирати
З тієї ж причини, з якої ви обираєте Flask замість Django або SQLite замість PostgreSQL. Не кожній задачі потрібен «повний фарш» ентерпрайз-стеку.
- Філософія: мінімальне ядро, розширюйте за потреби.
- Налаштування:
pip install lm-proxy+ один TOML-файл. - Залежності: FastAPI + MicroCore (легковісно).
- Конфіг: TOML / YAML / JSON / Python.
- Вбудовування як бібліотеки: першокласний сценарій використання.
- Віртуальні ключі + групи: вбудовано.
- OIDC / Keycloak авт.: вбудовано.
- Трекінг витрат, guardrails, кеш: немає з коробки (розширюється через плагіни).
- Адмін-панель: ні.
- Підтримка провайдерів: усі основні + локальні моделі / вбудований інференс.
LiteLLM Proxy:
- Філософія: все включено.
- Налаштування:
pip install 'litellm[proxy]'+ YAML + опціонально БД. - Залежності: важче дерево залежностей.
- Конфіг: YAML.
- Вбудовування як бібліотеки: підтримується, але не рекомендується документацією.
- Віртуальні ключі + групи: вбудовано (більш розвинуто).
- OIDC / Keycloak авт.: вбудовано (більш розвинуто: JWT-валідація, мапінг ролей, SSO UI).
- Трекінг витрат, guardrails, кеш: вбудовано.
- Адмін-панель: так.
- Підтримка провайдерів: усі основні.
Обирайте
Обирайте LiteLLM, коли: вам потрібен enterprise-рівень трекінгу витрат, UI для управління, десятки інтеграцій, guardrails, кешування та підтримка 100+ провайдерів і інтеграцій з коробки.
Інші альтернативи, як-от Portkey, схиляються ще більше в бік enterprise.
Що вже є (і що хотілося б бачити далі)
Варто визнати —
- Структуроване логування — система логування з підключенням
JsonLogWriterіLogEntryTransformer(відстежує токени, тривалість, групу, з’єднання, IP-адресу), плюс застосунок lm-proxy-db-connector для запису логів у PostgreSQL, MySQL, SQLite та інші бази через SQLAlchemy - Балансування навантаження — є приклад конфігурації, який розподіляє запити випадковим чином між кількома
LLM-серверами за допомогою Python-формату конфігурації. - Обробники запитів — механізм, подібний до middleware, для перехоплення запитів перед надсиланням до upstream-провайдерів, що дозволяє реалізувати наскрізні завдання на кшталт аудиту та маніпуляцій заголовками.
- Підтримка Vertex AI — Google Cloud Vertex AI підтримується поряд із простішим AI Studio API, з окремим прикладом конфігурації.
Проєкт розвивається (остання версія: v3.0.1), і кілька речей залишаються в моєму особистому списку побажань:
- Usage analytics dashboard — інфраструктура логування та БД уже солідна, але вбудований UI для візуалізації витрат і використання був би вишенькою на торті.
- Wildcard model expansion — режим
expand_wildcardsдля/v1/modelsзапланований, але ще не реалізований — наразі потрібно явно перелічувати моделі в конфігурації маршрутизації. - Automatic provider failover — якщо OpenAI повертає 5xx, автоматично перенаправити запит до Anthropic. Балансування між інстансами одного провайдера вже є, але кросс-провайдерний failover доповнив би картину.
Філософія «extensibility-by-design» означає, що більшість можливостей можна додавати у вигляді плагінів, не чіпаючи ядро. Наприклад, існує пакет db-connector для підключення до БД, логування в неї та перевикористання підключення SQLAlchemy для інших потреб — зокрема як сховища API-ключів тощо.
Кодова база має ліцензію MIT і достатньо компактна, щоб прочитати її повністю за один вечір.
Підсумок
Якщо ви працюєте з кількома
pip install lm-proxy
А як ви вирішуєте проблему зоопарку моделей і їх API/SDK? Пишете свої врапери чи використовуєте готові шлюзи? Запрошую до холівару в коментарях.
42 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарівДякую, цей патерн перший раз в школі в класі 9му заюзав. Дивно як час йде і треба описати кожне окреме застосування патерну, скоро окремий спеціаліст по кожному патерну зʼявиться походу
Коментар порушує правила спільноти і видалений модераторами.
Пане Вадиме, перелогіньтесь. Бо після ваших коментарів я починаю думати про вашу маму. Чи заслужила вона таке.
Я шкодую, що зачепив вас, піддавши сумнівам вашу освіту. Перепрошую і пропоную збавити обороти.
Нас читають зокрема молоді інженери, люди, що щиро бажають розібратись в тематиці. І ваші коментарі «архітектора» вводять їх в оману.
Проксі є класичним будівельним блоком системного дизайну. І для додатків, працюючих з LLM він часто є зручним, тому щоLLM-request — це так би мовити, новий будівельний блок програмного забезпечення сьогодення. Я б сказав — Unit of AI work. І цей блок — досить генералізований. Може виникати безліч причин, сому нам може знадобитись наскрізний функціонал поверх LLM-запитів: Observability, бюджетування, модерація, safety-контроль, in-stream PII Data masking, роутінг, load-balancing, збір метрик/телеметрії і ще тисяча інших.
Дуже часто подібні функціональні вимоги з’являються, скажем так, не на найперших життєвих стадіях проєкту.
Спочатку у вас є PoC / MvP, і ви живете собі з цьою апкою, нарощуєте функціонал.
Так от, на якомусь етапі, краще на ранньому, ніж на пізньому, ймовірно і виникає переосмислення архітектури з введенням proxy. І дуже класно, якщо це виникло до того моменту, як ми пекельно роздули доменну логіку цільового додатку, обмазавши його подібним наскрізним функціоналом по всій кодовій базі і отримавши low cohesion & high coupling, що дуже погано для maintainability.
чел ты больной чи шо?
Це вайбкодінгархітект
Народження
О, фасад над ШІ вже є, чекаємо фасад фасадів і фасад фасад фасадів які просто ганяють трафік між апішками (ми це вже
проходили з мікросервісами, graphql ітд)
Ви є противником мікросервісного підходу?
Розкажіть, why not. Якщо не утрирувати до маленького сайтику, де менше мільйону рядків коду і проблема масштабування не стоїть в принципі.
Я є противником переускладнень заради переускладнень. До речі кількість рядків — це взагалі не критерій розділення на мікросервіси
Я теж. І розумію ваш біль, якщо мова про переускладнення солюшена накладними витратами на підтримку мікросервісів там, де це не потрібно.
Саме стосовно мікросервісів — безумовно, не критерій, але для розділення кодової бази вцілому — дуже навіть критерій.
Знаєте, зараз, коли стало модно застосовувати ШІ для кодінгу — агенти дуже краще працюють з кодом, якщо він компактний і повністю поміщається в контекст.
І свіжі розробники, що залітають на проєкт, краще пораються в маленьких, атомарних кодових базах.
Тому вважаю інженерним гріхом, що породжує потвор кривавого ентерпрайзу, дублювання, неорганізовану складність і когнітивну тяжкість проєкту, наприколад... не винести, якийсь низькорівневий вузькоспеціалізований і зфокусований функціонал в бібліотечку, де це можливо.
А якщо в організації, в рамках якої ведеться розробка, ще й практикується OpenSource — то це взагалі чудово, бо дає стимули для створення якіснішої документації, кращого коду, надихає професійних розробників розвиватись, співпрацювати і взаємодіяти в рамках цілих екосистем програмного забезпечення.
Зачекайте, схоже я не зрозумів. Це якась вундервафля чи вайбкодери винайшли Проксі та Фасад патерн? Чи знижувати coupling між шарами і сторонніми сервісами це щось нове?
Ігоре, дякую за коментар.
Вайбкодери не знають слова «coupling» — вони думають, це щось із Тіндера.
«Нема нічого нового під сонцем», сказав Еклезіаст три тисячі років тому, і відтоді ніхто не зміг його спростувати.
Доречі, у вас білди на github впали.
Ну тобто по ділу немає що сказати, так? Хай мої білди вас не турбують. Я про них статтю на доу не викатую.
Мені по ділу сказать — як два байта переслать.
Але тоді ж давайте і грунтовніший наїзд, щоб на нього цікаво було відповідати.
Бо про що мова?
— Так, ви праві, дійсно нічого нового, просто проксі для LLM. Так, ви праві, зниження coupling з3-rd party сервісами. Ніяких див, винаходів чи архітектурної езотерики, просте рішення.
А щодо вайбкодерів — розкрийте думку, будь-ласка. Схоже, я не зрозумів.
Це претензія до якості рішення? Тоді в чому саме? Чи просто осуд віртуальних вайб-кодерів, які гіпотетично десь от обертаються навколо цієї статті і циркулюють десь приблизно тут (були зізнання нижче в коментарях☝️)
Очевидно ніякого наїзду не було. Лише хіба на тон статті, який явно носить клікбейтний/викривальний характер.
От я вам тут нагенерував, щоб було цікаво:
Стаття — Класичний приклад того, як індустрія розробки ходить по колу, видаючи старі концепції за нові «одкровення». Якщо відкинути хайп навколо LLM, то перед нами типова історія про «винайдення велосипеда», яку можна розкритикувати з кількох позицій у стилі «нічого нового».
1. Патерни проектування
Автор з великим ентузіазмом описує те, що в класичній архітектурі ПЗ називається патерном «Адаптер» (Adapter) або «Фасад» (Facade). Книга «Банди чотирьох» (GoF) вийшла у 1994 році, і там детально описано, як об’єднати різні інтерфейси сторонніх сервісів під одним універсальним інтерфейсом, щоб код не залежав від конкретної реалізації.
У
2. Еволюція API Gateway
Те, що автор називає
Кожен раз, коли з’являється нова ніша (як-от LLM), з’являється армія розробників, які кажуть: «Ой, у них різні API, давайте зробимо проксі!». Це стандартний етап дорослішання будь-якої технології, а не якась архітектурна знахідка.
3. Культ «Конфігурацій» замість Коду
Автор підносить TOML-конфіг як «магію маршрутизації». Але ми вже бачили це в Apache, Nginx,
Ідея «винесемо логіку в конфіг, щоб не чіпати код» часто призводить до того, що конфіг стає настільки складним, що його важче підтримувати, ніж сам код. Це просто перекладання відповідальності з Python-файлу на TOML-файл.
4. Черговий прошарок залежностей
Коментарі під статтею влучно підмічають: щоб просто «перекладати JSON з одного формату в інший», пропонується тягнути в проект монстра на 128 МБ (або 24 МБ, як стверджує автор) із десятками залежностей.
В епоху, коли ми боремося за продуктивність і безпеку ланцюжка постачання (supply chain security), додавання ще одного проміжного проксі-сервісу — це просто створення додаткової точки відмови (SPOF) і збільшення затримки (latency).
Підсумок:
Стаття написана живою мовою і справді вирішує біль початківців, але для досвідченого інженера це виглядає як: «Привіт, я відкрив для себе інкапсуляцію сторонніх залежностей і назвав це новим терміном». Нічого нового — лише чергова ітерація старої як світ боротьби з vendor lock-in за допомогою ще одного рівня абстракції.
В самому слові «вайбкодери» нічого поганого немає. Але воно вже досить давно набуло значення людини, яка бездумно запускає Ральф луп і чекає на готовий результат не задумуючись над деталями (архітектурою, подальшою підтримкою і розширенням) аби тести позеленіли.
Стосовно клікбейту, і більшості накиданого ШІ: Мій оригінальний текст англійською не містить взагалі таких гучних слів як **Архітектура**, назва статті How I Stopped Rewriting My Code Every Time I Switched LLM Providers.
Ось це про архітектуру в заголовку, було, якщо не помиляюсь, знахідкою редакторів ДОУ в процесі редактури. Мені особисто ця зміна подобається. Але чомусь багатьох тут трігерить.
Стаття наративно орієнтована на початківців, всім відразу не догодиш
¯\_(⊙_ʖ⊙)_/¯
А профі може бути цікаво, якщо вони вже знають, навіщо їм LLM Proxy, і знаходяться в пошуку найбільш підходящого рішення під їх специфіку (мінімалізм, простота, розширюваність, написано на python / FastApi).
Просто ржу)))
Дякую))))
Лайнокод переходить на новий рівень.
Якщо раніше бухтіли над недолугим спагеті кодом та матюкалися що перебираємо масив там, де можно отримати елемент по індексу, то тепер ми напихали купу лайна генерованого АІ, десь так трохи розуміючи що воно там робить (яке там нахрін О(1), головне швидко нагенерили і працює) і думаємо як його організувати так, щоб хоча б на рівні АРІ воно пристойно виглядало і милуємося лаконічністю конфігурації файла, який налаштовує оті генерилки щоб вони одна одній не заважали.
Це п****ць
Крапка
Та чого ти переживаєш, в нас рейти пдіростуть. :-) Галер люблять старий гівнокод, можна доїти роками багато грошей.
Та нас взагалі веселі часи чекають.
Це ж тут нові архітектурні патерни навигадують, оно вже цілу проблему з конкарренсі між АІ агентами вирішують, а це ж тільки початок.
Які там нафіг солід, хренячиш по агенту на фронтенд, бекенд і куа і хопа, ти не нудний гребець з веслом, а цілий АІ-агент лід!!
Треба тільки пару років почекати поки це покоління вайбкодерів нагенерить достатньо коду)))
Ну я тебе розумію але мені агенти подобаються, це гарна тула, дуже, але за розумним використанням. Не розумні викорситання збільшать попит на нас, бо сотанні роки щось мяса тіграм не докладають та знову в офіси тягнуть :-) Ну така вже доля з оцим програмуванням — розгрібати гівно папередніків.
Я теж в захваті від того ж гітхаб копайлота.
Це ж готова документація під рукою зрозумілою мовою, та ще й в контексті відкритого солюшена. Не треба нічого гуглити — просто виділяєш кусок коду і питаєш що воно робить.
Особливо подобається, коли є шматок коду і лінь в ньому розбиратися, то копайлот завжди підкаже що воно таке.
А ще генерація усіляких там мапінгів, коменти в коді.
Усіляка девопс фігня, коли хз що деплоїться через тераформ в оті всі ежури з кубернейтісами і треба додати якийсь флаг — раніше день можно було витратити намагаючись розібратися в отіх всіх змінних та енварймнетах, зараз питання вирішується за три хвилини.
Але про генерацію коду... Ну копайлот часто генерив код який навіть не компілювався, іноді таки тупив на очевидних речах і йому треба було підказувати.
На днях випробував кодклауд — ну що сказати, згенерував в ньому вебморду для chess.com API — перша версія це тупо набір *.ts файлів з захардкоженим в них html та css.....
Ну воно начебто і запрацювало, але сидіти покроково пояснювати йому очевидні речі, як, наприклад, що іконки це окремі svg файли, а не захардкожені стрінги мене вже не вистачило. І це я ще до NGRX з усілякими там авторизаціями не дійшов.
Але народ щось там генерує, в них все літає, вони хапонули бога за бороду і тепер кожний може відчути себе програмістом.
Ну хай граються)
Мені вже смішно з цього цирку, але найцікавіше буде попереду, коли вони нагенерують достатньо лайна та будуть розмірковувати про якість генерованого коду, бо воно щось зовсім якось криво працює)
Та хоча вже почали. І цей топік цьому підтвердження — як подружити генерилки щоб вони одна одній незаважали і навіть GoFовські паттерни до цього лайна приплели.
У вашому випадку це «shit in — shit out». Погугліть в контексті кодінг агентів та llm
Я щось подібне робив з langchain.
Різні провайдери підключаєш до агента і все
Але не знаю чи воно повноцінно працює з стримінгом. Я не пробував
Стрімінг тут — це якраз болюча частина з нюансованою реалізацією.
Але вкрай необхідна, якщо ми робимо не пайплайни з автоматизацією, а щось, що має на увазі розмовну взаємодію з користувачем.
docs.langchain.com/...gchain/streaming/overview
І до речі, проект починав одразу з langchain. За два роки багато чого було зроблено перероблено але всі два роки проект жив з ChatGPT. Учора за пів години перемкнув на anthropic. Дякувати langchain — все запрацювало майже без фіксів.
Як вам загалом LangChain?
Я дивлюсь на нього — і тягне оперувати низькорівневішими абстракціями (LLM Request, Vector DB Request), щоб потім не вгризатися під капот того, що вони називають «агентом». Хочеться від початку мати повний нюансований контроль: як саме працює пам’ять, яку репрезентацію має кожне повідомлення для моделі, а яку для користувача, і так далі в такому дусі.
Але з іншого боку, LangChain сьогодні № 1 за популярністю, тож однозначно заслуговує уваги.
Жодних нарікань. Гнучкий, підтримує більшість вендорів. LangSmith — окреме дякую. Стосовно контролю: немає проблем можеш користуватись або самим базовим chain, або високорівневим Graph, Agent тощо. З часом приходить розуміння як воно все поєднано та перестаєш боятись високорівневі абстракції. Claude Code дуже гарно розуміє фреймворк та може написати або готовий код або ж кастомну реалізацію чогось.
Хіба що спочатку було важко зрозуміти LCEL.
просто добавление слоя абстракции через структурный паттерн это не архитектура... более того это глобально ничего не даст, ведь ты этим не решил проблемы, которые описал, ты просто их сдвинул в другое место
Вадиме, «просто зсунув проблему в інше місце» — це те саме, що сказати про Nginx: «ти не вирішив TLS, просто зсунув його в проксі». Так. Саме так працює інженерія. Це називається separation of concerns.
Вам в університеті не викладали принцип «Розділяй і володарюй»?
это не тоже самое, не говоря что то что ты зачем-то в пример привел несравнимое по масштабу и возможностям
я знаю, но при чем здесь это, если ты описываешь проблему вендорлока и как решение предлагаешь лок на нишевый проект (5 контрибьюторов, 9 форков, 73 лайка)
нет, 95% математика и ее производные, 100 сортов программирования, теория по железу от печатных плат до робототехники, нейросети, криптография, моделирование
А вам не викладали основи психології та тлумачення поняття «пасивної агресії»? )
Нажаль ні, я за освітою інженер.
А питання є справелдивим. Я поясню свою репліку — мене щиро здивувало, як людині з атрибуцією авторитетної інженерної ролі у підписі (Solution Architect), вдається писати таку нісенітницю — буквально і формально нікчемні твердження з точки зору одночасно кількох базових університетських курсів з інженерії програмного забезпечення.
Може, власне, пан Вадим кваліфікований спеціаліст, але саме тут в нього є суттєва прогалина в знаннях. Тому я й питаю про університет.
Це направду потребує пояснень🤔
Мінімальне ядро казали вони.
pip installlm-proxy lm-proxy
......
Installing collected packages: pyperclip, websockets, urllib3, typing-extensions, tqdm, sniffio, six, shellingham, rpds-py, regex, PyYAML, python-multipart, python-dotenv, pygments, pycparser, pathable, more-itertools, mdurl, MarkupSafe, lazy-object-proxy, jiter, isodate, idna, httpx-sse, h11, exceptiongroup, docutils, docstring_parser, dnspython, distro, colorama, click, charset_normalizer, chardet, certifi, attrs, annotated-types, annotated-doc, werkzeug, uvicorn, typing-inspection, rfc3339-validator, requests, referencing, pydantic-core, markdown-it-py, Jinja2, httpcore, email-validator, cffi, anyio, tiktoken, starlette, rich, pydantic, jsonschema-specifications, jsonschema-path, httpx, cryptography, typer, sse-starlette, rich-rst, pydantic-settings, openapi-pydantic, openai, jsonschema, fastapi, authlib, openapi-schema-validator, mcp, cyclopts, openapi-spec-validator, openapi-core, fastmcp, ai-microcore,
Successfully installed Jinja2-3.1.6 MarkupSafe-3.0.3 PyYAML-6.0.3 ai-microcore-5.3.0 annotated-doc-0.0.4 annotated-types-0.7.0 anyio-4.12.1 attrs-25.4.0 authlib-1.6.8 certifi-2026.1.4 cffi-2.0.0 chardet-5.2.0 charset_normalizer-3.4.4 click-8.3.1 colorama-0.4.6 cryptography-46.0.5 cyclopts-4.5.3 distro-1.9.0 dnspython-2.8.0 docstring_parser-0.16 docutils-0.22.4 email-validator-2.3.0 exceptiongroup-1.3.1 fastapi-0.129.0 fastmcp-2.12.5 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 httpx-sse-0.4.3 idna-3.11 isodate-0.7.2 jiter-0.13.0 jsonschema-4.26.0 jsonschema-path-0.3.4 jsonschema-specifications-2025.9.1 lazy-object-proxy-1.12.0 lm-proxy-3.0.2 markdown-it-py-4.0.0 mcp-1.16.0 mdurl-0.1.2 more-itertools-10.8.0 openai-1.109.1 openapi-core-0.22.0 openapi-pydantic-0.5.1 openapi-schema-validator-0.6.3 openapi-spec-validator-0.7.2 pathable-0.4.4 pycparser-3.0 pydantic-2.12.5 pydantic-core-2.41.5 pydantic-settings-2.13.1 pygments-2.19.2 pyperclip-1.11.0 python-dotenv-1.1.1 python-multipart-0.0.22 referencing-0.36.2 regex-2026.1.15 requests-2.32.5 rfc3339-validator-0.1.4 rich-14.3.3 rich-rst-1.3.2 rpds-py-0.30.0 shellingham-1.5.4 six-1.17.0 sniffio-1.3.1 sse-starlette-3.2.0 starlette-0.52.1 tiktoken-0.12.0 tqdm-4.67.3 typer-0.24.0 typing-extensions-4.15.0 typing-inspection-0.4.2 urllib3-2.6.3 uvicorn-0.41.0 websockets-14.2 werkzeug-3.1.6
128 Мегабайт, щоб перекладати JSON
Шановний, та ну не 128, а лише 23.9 мегабайтиків зі всім деревом залежностей.
І щодо “перекладати JSON”. Тут, на хвилиночку, повноцінний HTTP reverse proxy / API gateway з маршрутизацією за патернами, streaming-підтримкою, системою контролю доступу (віртуальні ключі, групи), кількома форматами конфігурації та CLI. Для цього потрібен відповідний стек, і він тут цілком стандартний для python-мікросервісу.
Пропоную подивитись на прямі залежності нашого піддослідного:
```
dependencies = [
“ai-microcore>=5.1.2,<6”,
“fastapi>=0.121.3,<1”,
“uvicorn>=0.41.0”,
“typer>=0.24.0”,
“requests~=2.32.5”,
“pydantic~=2.12.5”,
]
```
І для контрасту, прямі залежності litellm, не рахуючи JS-стеку (!)
```
[tool.poetry.dependencies]
python = “>=3.9,<4.0”
fastuuid = “>=0.13.0”
httpx = “>=0.23.0”
openai = “>=2.8.0”
python-dotenv = “>=0.2.0”
tiktoken = “>=0.7.0”
importlib-metadata = “>=6.8.0”
tokenizers = “*”
click = “*”
jinja2 = “^3.1.2”
aiohttp = “>=3.10”
pydantic = “^2.5.0”
jsonschema = “>=4.23.0,<5.0.0”
numpydoc = {version = “*”, optional = true} # used in utils.py
uvicorn = {version = “^0.31.1”, optional = true}
uvloop = {version = “^0.21.0”, optional = true, markers="sys_platform != ’win32’“}
gunicorn = {version = “^23.0.0”, optional = true}
fastapi = {version = “>=0.120.1”, optional = true}
backoff = {version = “*”, optional = true}
pyyaml = {version = “^6.0.1”, optional = true}
rq = {version = “*”, optional = true}
orjson = {version = “^3.9.7”, optional = true}
apscheduler = {version = “^3.10.4”, optional = true}
fastapi-sso = { version = “^0.16.0”, optional = true }
PyJWT = { version = “^2.10.1”, optional = true, python = “>=3.9” }
python-multipart = { version = “^0.0.22”, optional = true, python = “>=3.10”}
cryptography = {version = “*”, optional = true}
prisma = {version = “0.11.0”, optional = true}
azure-identity = {version = “^1.15.0”, optional = true, python = “>=3.9”}
azure-keyvault-secrets = {version = “^4.8.0”, optional = true}
azure-storage-blob = {version="^12.25.1“, optional=true}
google-cloud-kms = {version = “^2.21.3”, optional = true}
google-cloud-iam = {version = “^2.19.1”, optional = true}
google-cloud-aiplatform = {version = “>=1.38.0”, optional = true}
resend = {version = “>=0.8.0”, optional = true}
pynacl = {version = “^1.5.0”, optional = true}
websockets = {version = “^15.0.1”, optional = true}
boto3 = { version = “1.40.76”, optional = true }
redisvl = {version = “^0.4.1”, optional = true, markers = “python_version >= ’3.9′ and python_version < ’3.14’”}
mcp = {version = “>=1.25.0,<2.0.0”, optional = true, python = “>=3.10”}
a2a-sdk = {version = “^0.3.22”, optional = true, python = “>=3.10”}
litellm-proxy-extras = {version = “0.4.44”, optional = true}
rich = {version = “13.7.1”, optional = true}
litellm-enterprise = {version = “0.1.32”, optional = true}
diskcache = {version = “^5.6.1”, optional = true}
polars = {version = “^1.31.0”, optional = true, python = “>=3.10”}
semantic-router = {version = “>=0.1.12”, optional = true, python = “>=3.9,<3.14”}
mlflow = {version = “>3.1.4”, optional = true, python = “>=3.10”}
soundfile = {version = “^0.12.1”, optional = true}
pyroscope-io = {version = “^0.8”, optional = true, markers = “sys_platform != ’win32’”}
```
Красномовно?
Так.
Корисніше було б порівняти споживання RAM у runtime — бо саме це впливає на вартість інфраструктури, а не розмір site-packages.
Ні, не красномовно. Зовсім. Бо:
1. На питання «чому так зроблено» ви кажете «так усі роблять, ось дивіться у сусіда ще гірше» — це не відповідь на запитання, це чорна риторика.
2. Нащо ви приводити у приклад залежності сервера litellm коли мова йде про клієнтську лібу?
3. Якщо ми вже порівнюємо — чим ваше рішення краще ніж litellm?
Ну дивістья, можна навелосипедити все з нуля і ми отримаєм нульовий об’єм залежностей, але драматично більшу кодову базу, яка тим не менше, ймовірно впишеться в кілобайти, а не десятки мегабайтів.
Якщо навелосипедити всі другорядні утилітні функції з нуля — це вже не буде мінімалістична й елегантна кодова база, яку зручно підтримувати і розширювати, фокус дуже розмиється з доменної задачі, яку вирішуєм, на все що попало.
Є такий критерій, як maintainability.
У довгостроковій перспективі підтримувати велосипед з нуля без жодної залежності буде дорого, а втрата інженера, що це велосипедив, буде фатальною для організації. Тому ми використовуєм якісні industry-standard пакети з відкритим кодом.
І це має певні накладні витрати, як то розмір site packages.
Якщо ваш бекенд розроблений в тій же екосистемі (python), то більшість цих пакетів може бути перевикористана і не скачуватись повторно, бо вони тут ну прям дуже-дуже мейнстрімні для python.
Я відповів на ваше запитання?
Не зовсім зрозумів, що мається на увазі під клієнтською лібою.
ІLM-Proxy і LiteLLM — імплементації проксі-серверів для LLM, це сервіси, що крутяться на бекенді.
LiteLLM — рішення для enterprise з великим об’ємом власної кодової бази, більшою складністю коду, містить в собі WEB-адмінку, нафаршироване купою різних плагінів.
Треба швидко запроксювати LLM запити, щоб не зашивати API-ключі від LLM в клієнтський додаток? Вам сюди.
Треба додати наскрізну логіку обробкиLLM-запитів, а в код кінцевого додатку лізти не хочеться чи не можеться? Вам сюди.
Треба подебажити, які запити шле 3rd party AI апка до LLM? Втикніть між нею та цільовою LLMLM-Proxy і дивіться.
LiteLLM віджирає всю пам’ять на бюджетному VPS? Вам сюди.
ні, див. docs.litellm.ai/docs/#how-to-use-litellm
You can use LiteLLM through either the Proxy Server or Python SDK.Так це була відповідь на коментар про «клієнтську лібу»
Python SDK має на увазі саме використання на бекенді.
Наприклад, бекенд сервіс, що обслуговує ваш додаток, може включати в себе LiteLLM абоLM-Proxy як бібліотеку, замість того, щоб менеджети окремий сервіс.
Ну, тобто, ви звичайно можете і те і те підключити в клієнт/фронт, якщо він у вас на Python, ніхто не забороняє. Але ж навіщо?
¯\_(ツ)_/¯
зрозумів, схоже виникла деяка плутаниця в тому, що ви розглядаєте LiteLLM для побудови server gateway/proxy, хоча більшість використовує LiteLLM як адаптер для уніфікації взаємодії з різнимиLLM-провайдерами, і саме Python SDK (бібліотека-клієнт) призначений якраз для цих цілей
цікаво, чи можна це якось об’єктивно виміряти...чи це тільки відчуття 🤔
(так розумію суммаризація — це конспектування?)
я неайтівець. вайбкодер, практики мало, а теоретично це питання бачу на даний момент так:
є платформа Google Cloud,
там є щось під назвою Vertex AI,
і там є Model Garden (назва красномовна.. це можливість підключити будь-яку модель (!)... крім джемінаїв, є і антропік, і безкоштовні... і можна вибрати регіон дата-центру... і т.д.)
......
### 1. Як це працює (Механізм)
Замість того, щоб вписувати довгий API-код у змінну, ви просто кажете скрипту: «Дивись у цей файл».
* Ви створюєте **Service Account** у консолі Google Cloud.
* Генеруєте для нього **JSON-ключ** і завантажуєте на комп’ютер/сервер.
* У скрипті або в терміналі вказуєте шлях до цього файлу.
### 2. Чому це зручно (один раз і назавжди)
Вам достатньо додати лише один рядок у термінал (або в початок скрипта), і **всі моделі** з Model Garden стануть доступними:
```bash
export GOOGLE_APPLICATION_CREDENTIALS="/шлях/до/вашого/ключа.json"
```
Після цього код виглядає максимально «чистим» — жодних паролів, токенів чи секретів:
```python
import vertexai
from vertexai.generative_models import GenerativeModel
# Скрипт сам підхопить JSON-файл із системної змінної
vertexai.init(project="my-project", location="us-central1″)
model = GenerativeModel("gemini-1.5-flash") # Або будь-яка інша модель з Garden
print(model.generate_content("Привіт!«).text)
```
### 3. Головні переваги JSON-файла:
* **Універсальність:** Один файл дає доступ і до Gemini, і до розгорнутої Llama, і до сховища файлів (Bucket).
* **Безпека:** Ви додаєте файл у `.gitignore`, і ваш секретний ключ ніколи не потрапить у публічний доступ (на відміну від API-ключа, який часто випадково «засвічують» у коді).
* **Автономність:** Це ідеально для серверів (ботів, сайтів), де немає живої людини, щоб натиснути «Увійти через Google».
---
**Резюме:** JSON-файл — це ваша **безстрокова перепустка**, яку ви один раз показуєте системі, і вона більше не ставить зайвих питань про доступ до моделей.
Хочете підкажу, де саме в консолі Google Cloud натиснути кнопку, щоб згенерувати цей файл?