LEX — AI Legal Platform for Law Firms

AI-powered legal analysis platform for law firms and corporate counsel.

Features

Resources

Blog Articles

Technology

Built on AWS (EC2, Bedrock Claude AI, ALB, WAF, S3, ACM, KMS). PostgreSQL, Redis, Qdrant vector database. TypeScript, React, Node.js.

Start free — 50 credits on registration. Sign up

TECH 8 хв

Чому ми відмовились від Round-Robin між OpenAI та Anthropic

Ми інтегрували OpenAI та Anthropic із round-robin маршрутизацією. На архітектурній діаграмі це виглядало ідеально. У продакшені це ледь не вбило наш продукт. Один і той самий промпт давав різні результати залежно від провайдера. Дебагінг 5-крокового агентного циклу? Це не інженерія — це археологія. Ми все вирізали. Захардкодили одного провайдера. Найкращий рядок коду за рік.

Чому ми відмовились від Round-Robin між OpenAI та Anthropic — і що використовуємо замість

Розробка юридичної AI-платформи навчила нас: мультипровайдерна LLM-маршрутизація чудово виглядає на архітектурних діаграмах, але ламається у продакшені.


Ідея, яка мала ідеальний сенс

Коли ми почали будувати LEX AI — платформу для аналізу мільйонів українських судових рішень — ми зробили те, що робить кожна AI-first команда: інтегрували кілька LLM-провайдерів.

OpenAI для структурованого виводу. Anthropic для глибокого юридичного аналізу. Round-robin між ними для стійкості та оптимізації витрат.

На папері це виглядало елегантно. У продакшені це був кошмар.

Що пішло не так

1. Фрагментація форматів відповідей

Наш агентний пайплайн виконує до 5 ітерацій tool-calling на кожен запит користувача. Кожна ітерація очікує нормалізовану відповідь: tool_calls, finish_reason, структурований JSON.

OpenAI та Anthropic повертають це по-різному. Ми побудували шар нормалізації. Він обробляв 90% випадків. Решта 10% — порожні відповіді, неповний JSON, неочікувані stop reasons — спричиняли тихі збої глибоко в циклі.

Один баг ми шукали 3 дні: Anthropic іноді повертав валідну відповідь зі stop_reason: "end_turn" замість "tool_use", яку наш нормалізатор пропускав далі, але наступна ітерація сприймала як фінальну відповідь. Користувач отримував напівготовий аналіз без жодної індикації, що щось пішло не так.

2. Один промпт — дві різні поведінки

Юридичний AI живе і вмирає від точності промптів. Наш системний промпт інструктує модель діяти як український юридичний асистент, класифікувати наміри, обирати інструменти та відповідати в структурованому форматі.

Claude точніше виконував інструкції українською мовою. GPT генерував чистіші JSON tool calls. Коли модель змінювалась на кожній ітерації агентного циклу, якість результату ставала підкиданням монети.

3. Дебагінг перетворився на археологію

Коли користувач повідомляв про поганий результат, ми дивились на трейс:

Який крок зламався? Модель чи нормалізація? Чи можемо відтворити? Ні — наступний запуск маршрутизує інакше.

4. "Оптимізація" витрат, якої не було

Round-robin мав балансувати витрати. Натомість:

5. Два набори всього

Кожен провайдер має своє: rate limits, retry-стратегії, формати помилок, оновлення SDK. Наш "уніфікований" retry-шар насправді був двома retry-шарами у одному тренчкоті.

Що ми робимо зараз

Ми перейшли на strategy-based вибір провайдера з OpenAI як основним та AWS Bedrock як альтернативою — і інвестували зекономлену складність у budget-aware вибір моделі:

Бюджет OpenAI AWS Bedrock Застосування
quick gpt-5-nano Amazon Nova Micro класифікація, маршрутизація
standard gpt-5-mini Amazon Nova Lite виконання інструментів, сумаризація
deep gpt-5.1 Amazon Nova Pro юридичний аналіз, витяг патернів

Змінна LLM_PROVIDER_STRATEGY контролює вибір: openai-first (дефолт) або bedrock-first (якщо є AWS credentials). Один формат API. Одна обробка помилок. Одна retry-логіка. Передбачувані витрати. Відтворювані результати.

Як правильно використовувати кілька провайдерів

Task routing, а не round-robin — призначте кожному провайдеру конкретні типи завдань назавжди.

Fallback, а не чергування — Провайдер Б активується лише коли Провайдер А повертає 429 або 500.

Мультиключ одного провайдера — кілька API-ключів від одного провайдера з ротацією для обходу rate limits.

Чому AWS Bedrock змінює правила гри

Прямий API ключ AWS Bedrock
Моделі Один провайдер Claude + Llama + Mistral через один SDK
Безпека API key в .env IAM roles, нема ключів у коді
Дані Летять у хмару провайдера Залишаються у вашому AWS регіоні
Білінг Окремі інвойси Єдиний рахунок AWS
Rate limits Жорсткі, per-key Provisioned Throughput

Тег @deprecated на нашому методі getNextProvider() — найкращий рядок коду, який ми написали за рік.


Епілог: березень 2026

Коли ми писали цю статтю, fallback на Anthropic API був тимчасовим рішенням. У березні 2026 ми нарешті закрили цю главу: PR #722 замінив прямий Anthropic API на AWS Bedrock.

Що це дало на практиці? Один SDK (@aws-sdk/client-bedrock-runtime) замість двох клієнтських бібліотек. IAM-автентифікація замість ротації API-ключів. Дані залишаються в eu-central-1 — наш DPO нарешті перестав нервувати. Єдиний білінг через AWS Cost Explorer замість окремих інвойсів від OpenAI та Anthropic.

Бюджетні тіри, про які ми мріяли, тепер працюють через Bedrock: quick йде на Nova Micro, standard — на Nova Lite, deep — на Nova Pro. OpenAI залишається primary для основного пайплайну, але весь fallback-ланцюг тепер на AWS.

Виходить, рішення відмовитись від round-robin було правильним не лише тактично, а й стратегічно. Ми не просто обрали одного провайдера — ми обрали інфраструктурну платформу, яка масштабується разом з продуктом. Той @deprecated тег досі в коді. Як нагадування.