A/B testing și shadow deployments pentru LLM în LLMOps, Evaluare & Securitate AI

Cum compari un model sau un prompt nou pe trafic real fără să afectezi utilizatorii: trafic shadow, lansare canary și A/B testing.

Configurare & comandă
# Trafic shadow: utilizatorul primește răspunsul modelului curent,
# iar aceeași cerere ajunge, separat, și la modelul candidat.
cerere -> model curent   -> răspuns către utilizator
       -> model candidat -> salvat pentru comparație (nu ajunge la utilizator)

Un model sau un prompt nou poate avea scoruri bune pe setul de evaluare și totuși să se comporte diferit pe datele reale. Shadow deployment (dark launch) trimite cererile reale și către varianta candidată, dar utilizatorul vede doar răspunsul variantei curente. Răspunsurile candidatului se salvează și se compară după calitate, cost și latență.

După faza shadow urmează de obicei o lansare canary (un procent mic de utilizatori primește varianta nouă, procent mărit treptat) sau un test A/B (două variante pe grupuri separate, comparate pe o metrică stabilită dinainte, de exemplu rata de feedback pozitiv). Langfuse, de exemplu, permite versionarea prompturilor și compararea metricilor pe versiuni.

Traficul shadow dublează costul apelurilor pentru porțiunea testată și nu trebuie să execute acțiuni cu efecte (unelte care scriu date, trimit emailuri sau fac plăți). Datele trimise unui furnizor nou trebuie să respecte aceleași reguli de confidențialitate ca în producție.

Concepte cheie și caracteristici

Concept / Parametru Descriere practică
Trafic shadow Copie a cererii trimisă candidatului, fără impact asupra răspunsului către utilizator.
Canary Rutarea unui procent mic de trafic real către varianta nouă, crescut treptat dacă metricile rămân bune.
A/B test Două variante pe grupuri de utilizatori separate, cu metrică și durată stabilite înainte de test.
Comparația automată Evaluatori LLM-as-a-judge, metrici de cost și latență, rate de refuz sau de eroare pe aceleași cereri.
Unelte cu efecte În modul shadow, apelurile de unelte care modifică date trebuie dezactivate sau simulate.

Exemple practice și scenarii reale

Exemplul 1: Trafic shadow cu FastAPI

BackgroundTasks rulează sarcina după ce răspunsul a fost trimis, deci cererea către candidat nu întârzie utilizatorul. salveaza_comparatie() este funcția ta de stocare.

import httpx
from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

async def apel_candidat(cerere: dict, raspuns_curent: dict):
    async with httpx.AsyncClient(timeout=120) as client:
        r = await client.post("http://model-candidat/v1/chat/completions", json=cerere)
    salveaza_comparatie(cerere, raspuns_curent, r.json(), eticheta="shadow-v2")

@app.post("/v1/chat/completions")
async def chat(cerere: dict, bg: BackgroundTasks):
    async with httpx.AsyncClient(timeout=120) as client:
        r = await client.post("http://model-curent/v1/chat/completions", json=cerere)
    raspuns = r.json()
    bg.add_task(apel_candidat, cerere, raspuns)
    return raspuns

Exemplul 2: Canary prin ponderi în LiteLLM

Două implementări în același grup; cu strategia implicită simple-shuffle, parametrul weight din litellm_params stabilește proporția de trafic (aici aproximativ 90% / 10%).

model_list:
  - model_name: asistent
    litellm_params:
      model: anthropic/claude-sonnet-5
      weight: 9
  - model_name: asistent
    litellm_params:
      model: anthropic/claude-sonnet-5-5
      weight: 1

Greșeli frecvente și capcane

  • Dublezi în shadow apelurile de unelte care scriu date, trimit emailuri sau fac tranzacții.
  • Lași traficul shadow activ fără limită de timp și fără să urmărești costul dublat.
  • Compari variantele pe cereri diferite. Comparația are sens doar pe aceleași cereri sau pe grupuri alese aleator.

Noțiuni și module înrudite