Головна / Статті

Мінімальна функціональна платформа для експериментування з AI-агентами: тести типу A/B та тіньові запуски

Як вирішити, чи слід версія агента B замінити A, використовуючи визначення конвеєрів, локальне призначення, події експозиції, сліди, оцінку в пісочниці, тестування в тіні та захисні механізми.

Видавець: REACTAPP.TOP11 хв читання2558 слів

Джерела: A minimum viable experimentation platform for AI agents

Визначити, чи нова версія агента краща за ту, що використовується у продакшені, складніше, ніж здається. Під час розробки цей процес під контролем: достатньо мати набір тестових випадків, запустити обидві версії, переглянути кілька результатів, доручити іншій моделі оцінити вихідні дані та вирішити, чи варто приділити більше зусиль цим змінам. Справи ускладнюються, коли метою є не просто запит чи один виклик моделі, а система, компоненти якої змінюються за власними графіками та взаємодіють способами, які не завжди є очевидними.

Уявіть собі агента підтримки клієнтів, складеного з цих компонентів:

agent runtime
memory and retrieval
system prompt
model
tools
guardrails
application logic

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

Нижче наведений опис найменшої платформи, на яку можна буде зручно покластися для відповіді на досить просте запитання:

should version B replace version A?

Це має сенс лише при певному розмірі. Один агент, двадцять тест-кейсів, перевірених вручну, та кілька внутрішніх користувачів не потребують більшої частини цього. Платформа стає корисною тоді, коли кілька команд незалежно змінюють моделі, запити, пам’ять, інструменти та реалізації агентів, експерименти тривають безперервно, і хтось у кінцевому підсумку має схвалити зміни в продакшені, надавши докази, які залишатимуться зрозумілими навіть через кілька місяців. Платформа агентів для всієї компанії відповідає цьому опису.

Що насправді є B

Перша проблема є базовою. Припустимо, експеримент стверджує:

A = agent-v17
B = agent-v18

Що саме таке agent-v18? Якщо під час експерименту змінюється запит, індекс пошуку перебудовується, а шлюз моделі замінює свою стандартну модель, тоді позначка майже нічого не говорить про те, що саме оцінювалося. Це особливо сильно впливає на агентів, оскільки поведінка, яку спостерігають у кінцевому підсумку, є результатом всього процесу обробки, а не лише одного окремого виклику моделі.

Отже, об’єктом оцінки є незмінна визначення процесу обробки. Воно може виглядати так:

pipeline:
  name: support-agent
  version: 18

components:

  runtime:
    artifact: agent-runtime@sha256:...

  memory:
    artifact: memory-service@sha256:...
    configuration:
      strategy: hybrid
      top_k: 8

  model:
    route: support
    model: provider/model-x

  prompt:
    artifact: sha256:...

  tools:
    - artifact: customer-lookup@sha256:...
    - artifact: refund-tool@sha256:...

Точний формат артефакта майже не має значення. Важливо те, що варіант можна відновити у вигляді конфігурації системи, щоб через кілька місяців хтось міг сказати, що саме мав запустити користувач, призначений до B. Це також забезпечує незалежність платформи для експериментів від усього, що може змінюватися. Один експеримент може порівнювати:

model X vs model Y

Інший може порівняти:

memory top_k=5 vs top_k=8

А ще один підхід може протиставити одна одній два абсолютно різних варіанти реалізації агентів. З точки зору експерименту кожен із цих варіантів є просто різною версією конвеєру обробки даних. Коли починається експеримент, ці визначення стають незмінними. Якщо необхідно змінити схему обробки, створюється нова ітерація експерименту, тож історичне значення B ніколи не переписується таємно.

Завдання не повинні стати залежністю від продакшну

Далі постає питання про те, хто отримуватиме A, а хто — B. Привабливим рішенням є таке, коли кожен запит звертається до центральної служби експериментування за відповідною схемою обробки. Це втягує платформу експериментування у параметри доступності та затримки самого додатку, що є поганою заміною для системи, основною метою якої є вимірювання.

Перша версія використовує детерміністичне хешування. Контрольний рівень надсилає свою поточну конфігурацію до SDK, який знаходиться всередині додатку, і вибір архітектури здійснюється безпосередньо там, локально. Це забезпечує корисну властивість при збоях: якщо сервіс експериментів виходить з ладу, платформа тимчасово не може запускати нові експерименти чи змінювати розподіл ресурсів, проте додаток залишається недоторканим, а SDK продовжує працювати зі своєю останньою дійсною конфігурацією.

Для MVP достатньо кількох пристроїв випадковостей:

request
user
session
workflow_instance

Останній варіант існує тому, що агенти не обов’язково працюють стільки ж часу, скільки триває веб-запит. Агент може розпочати міграцію репозиторію сьогодні, почекати на зовнішнє схвалення та продовжити завтра. Якби призначення обчислювалося на основі конфігурації завтрашнього дня, той самий процес міг би розпочатися в одній реалізації та завершитися в іншій, що зробило б як операції, так і аналіз зайво складними. Тому призначення залишається незмінним:

workflow_instance = migration-8291
variant           = B
pipeline          = agent-v18

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

Призначення відрізняється від експозиції

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

Візьмемо дві реалізації пам’яті, які перебувають на тестуванні. Користувач потрапляє до версії B — нової версії пам’яті, але агент відповідає, не здійснюючи жодного пошуку в пам’яті. Призначення існує, проте тестовий компонент так і не мав можливості вплинути на результат. Це мають бути окремі події:

ASSIGNMENT
user-18271 → B

EXPOSURE
memory-v2 retrieval started

Це також надає інформацію про стан експерименту. Окрім кількості користувачів, рандомізованих до кожної групи, можна переглянути дані про вплив:

assigned          10,428
exposed            8,912
exposure rate      85.46%

Якщо A та B демонструють несподівано різні показники експозиції, саме ця різниця потребує першочергової уваги.

Подібна проблема виникає, коли призначений спосіб обробки не є тим, який насправді використовується. Наприклад, B обирає модель Y, але вона повертає помилку 503, тож шлюз переходить на модель X. Запис виглядає так:

assigned_variant = B
realized_model   = X
fallback_reason  = provider_unavailable

і виконання залишається у B.

Це відповідає правилу наміру лікування, ITT. Кожен учасник аналізується у групі, до якої він був рандомізований, навіть якщо фактичне виконання відрізняється. Такий підхід є частиною досвіду групи B, і видалення подібних запитів пізніше призведе до зміни складу групи на основі події, яка сталася після рандомізації. Дані про вплив та фактичне лікування залишаються цінними, переважно як сигнали щодо стану здоров’я та діагностики, якщо тільки аналіз не вказує на щось інше.

Трекінг пояснює, що сталося

Результат експерименту вказує, чи змінився результат, але нічого не говорить про причину. Для з’ясування причини розумним вибором є OpenTelemetry, а не новий протокол трекінгу. Шар експериментування має лише додати трохи додаткового контексту до кожного інтервалу:

experiment.id
experiment.version
experiment.variant
experiment.assignment_id

pipeline.id
pipeline.version

execution.purpose

З урахуванням цього загальний результат буде таким:

B has a lower task completion rate

може перетворитися на набагато корисніше запитання:

show failed B traces

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

Слід все одно не є записом експерименту. Він добре пояснює, як відбувалась одна з експекуацій, але результати експерименту можуть існувати довше. Клієнт може поговорити з агентом сьогодні та оновити підписку через тиждень, дуже довго після завершення початкового сліду. Тож поруч із відстеженням працює менша потік подій експерименту:

assignment
exposure
outcome
feedback
evaluation

Журнал слідування фіксує процес виконання. Потік подій здійснює облік, який пов’язує процес випадкового формування з наслідками, що надходять пізніше.

Офлайн-оцінка використовує той самий процес

Перш ніж B потрапить до користувачів у продакшені, він має пройти перевірку на відповідність відомим сценаріям. Для агентів сценарій не повинен зводитися до:

prompt
expected answer

адже цікавим результатом часто є не повернутий текст, а стан середовища після цього. Сценарій підтримки може бути написаний ось так:

scenario:
  id: duplicate-charge-001

input:
  message: >
    I was charged twice for order 9811.

environment:
  fixture: duplicate-charge-customer

expected:
  refund_count: 1
  ticket_status: resolved

limits:
  max_turns: 15
  max_tool_calls: 20
  max_cost: 0.50

Та сама ситуація потім применюється до пайплайну A та пайплайну B, можливо, кілька разів, оскільки виконання агентів є стохастичними, і два запуски з однією конфігурацією можуть слідувати різними траєкторіями від одного й того ж початкового стану. MVP використовує сандбокс, який можна скинути, з послугами, підтримуваними фікстурами, або тестовими базами даних. Створення здатності до повторного відтворення багатьох етапів краще залишити на пізніший час.

Повторне відтворення можливе лише тоді, коли кандидат запитує взаємодії, які вже були записані. Припустимо, B приймає інше рішення на третьому етапі та використовує інструмент, якого не торкалася початкова траєкторія. Тоді жоден з записаних станів не містить цього розгалуження. Чесний результат буде таким:

REPLAY_DIVERGED

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

Виконання в тіні заповнює прогалину

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

latency
cost
tool usage
model fallbacks
guardrail failures
judge scores
trajectory differences

Перш ніж будь-який користувач побачить результат обробки.

Шадоу-тестування не можуть показати, чи покращує B найважливіший результат, оскільки користувачі ніколи не бачать B і тому не можуть на це відреагувати. Вони є проміжним етапом: реалістичні вхідні дані та справжня поведінка під час виконання, без ризиків, пов’язаних із живим експериментом.

Не кожна перевірка потребує оцінки від ШІ

Коли агент завершує сценарій, результат все одно потребує оцінки, тому перша версія містить два типи оцінювачів.

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

refund_count == 1
ticket_status == resolved

Запитувати інший модель, чи, ймовірно, завдання виконано, не має сенсу, якщо можна перевірити отриманий стан.

Другий тип ґрунтується на моделях та використовується для властивостей, які не піддаються підтвердженню:

helpfulness
clarity
tone
quality of explanation

Суддя у вигляді ШІ допомагає в цьому, але стає ще одним компонентом з версіями та ніколи не є анонімним джерелом істини:

evaluator
evaluator version
judge model
judge prompt
rubric

Кожен створений рейтинг зберігає своє походження. Також підтримується невеликий набір даних для калібрування, позначених людьми, і суддя періодично порівнюється з ними. Суддя на основі ШІ є вимірювальним інструментом, і коли інструмент змінюється, важливо, чи змінилися також його показники. Агентні судді, які переглядають інформацію, використовують інструменти чи знаходять додаткові докази, є корисними та, ймовірно, неминучими в деяких галузях, але вони не мають місця у першій версії.

Статистика, у обмеженій кількості

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

A/B allocation
binary metrics
continuous metrics
95% confidence intervals
sample ratio mismatch detection
fixed-horizon analysis

Цього достатньо, щоб відповісти на багато корисних запитань, а узагальнення результатів може виглядати так:

Experiment
support-agent-v18

Randomization
user

Primary metric
ticket resolution

A       81.4%
B       85.1%

Difference
+3.7 percentage points

95% CI
[...]

Experiment health
SRM PASS

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

Оперативні механізми захисту також належать до цього ж рівня стану. Варіант може зазнати невдачі з точки зору витрат, не маючи технічних проблем. Уявіть собі цикл запитів, який постійно надсилає виклики з:

4 model calls

У:

47 model calls

І відповідь все одно може бути HTTP 200, навіть якщо це правильна відповідь. Тому потрібні верхні межі:

max cost / execution
max tokens / execution
max agent turns
max tool calls
max variant spend / hour

Перетинання «капи» може зупинити цю обробку або призупинити подальший вплив варіанту. Тоді звіт про стан здоров’я може виглядати так:

Variant B

SRM                PASS
Error rate         PASS
Cost / request     +312%

Circuit breaker    TRIPPED
New exposure       PAUSED

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

Більш складні методи можуть почекати: CUPED, послідовне тестування, контрольні групи, різні рівні експериментів, кластерна випадковізація, адаптивне розподілення та інші. Модель даних має залишати простір для них, але перша версія має лише правильно виконувати звичайні експерименти типу A/B.

Що будувати спочатку

Після видалення більшості елементів, які можна відкласти, платформа стає керованою. Їй потрібен сервіс керування, який буде містити:

  • реєстр експериментів
  • реєстр потоків обробки даних
  • реєстр наборів даних
  • реєстр оцінювачів
  • визначення метрик

Нагорі розташований SDK, який завантажує конфігурацію експерименту та детерміновано її присвоює на стороні клієнта. Для цього потрібен шлях імпорту:

assignment
exposure
outcome
feedback
evaluation

Також обробляються треки OpenTelemetry. Розумним вибором для зберігання є PostgreSQL для стану керуючої платформи, NATS JetStream або Kafka для подій, ClickHouse для аналізу експериментів та треків, а також об’єктне зберігання, сумісне з S3, для великих об’ємів даних. Офлайн-запускник використовує набір даних для тестування в середовищах типу A та B, які можна скинути.

Багато чого навмисно відсутнє. MVP не передбачає довільної віртуалізації середовищ із станом, тонких взаємодій між експериментами, аналізу причин проблем автоматично, тривалих ефектів лікування чи причинно-наслідкових зв’язків між кількома агентами, і може обійтися без цього. Те, що має значення з самого початку, — це те, виправлення чого є складним, коли від нього залежать історичні дані:

what was randomized
what treatment was assigned
what treatment actually ran
what pipeline version produced the execution
what outcome was measured
how that outcome was evaluated

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

Корисний підхід полягає у тому, що офлайн-оцінка, тіньове виконання та прямі експерименти можуть користуватися спільними визначеннями потоків обробки, записами та інструментами оцінювання, хоча кожен з них відповідає на своє запитання. Офлайн-виконання показують, як поводяться A та B у контрольованих сценаріях. Тіньові виконання демонструють, як B справляється з вхідними даними у реальних умовах, не впливаючи на користувачів. Прямі експерименти виявляють зміни, які виникають при випадковому розподілі справжніх користувачів. Записи виконань фіксують усе, що відбувається під час кожного виконання, та допомагають інтерпретувати результати, проте діагностика на рівні записів ніколи не повинна замінювати причинно-наслідковий аналіз. Разом вони дозволяють створити MVP, який може надійно відповісти на три запитання:

What exactly did we run?
What happened when we ran it?
Did assigning users to B improve the outcome we care about?

Усе інше може рости навколо цього.