Objawy
Nic się nie wywala. Nie ma wyjątków, nie ma timeoutów, dziennik wygląda tak samo jak zawsze. Po prostu odpowiedzi są gorsze.
Postacie, w jakich to się objawia:
Jakość. Agent zaczyna pomijać kroki, które wcześniej wykonywał, albo odpowiada ogólniej.
Format. Odpowiedzi mają inną długość, inny styl, więcej zastrzeżeń. Coś, co parsowałeś regularnie, przestaje się parsować.
Trajektoria. Ta sama sprawa idzie teraz inną drogą — więcej kroków, inne narzędzia, inny wynik.
Kluczowy sygnał: nikt niczego nie wdrażał. Albo wdrożył coś, co z tym zachowaniem nie miało nic wspólnego.
Mechanizm w trzech zdaniach
Wagi modelu są zamrożone, ale model dostępny przez API to usługa, nie plik — dostawca aktualizuje go, a ty zwykle wskazujesz alias, który po cichu przełącza się na nową wersję. Kolejne wydania przechodzą nowe dostrajanie, więc zmienia się ton, długość i skłonność do odmowy, choć „wiedza” pozostaje podobna.
Do tego dochodzi wszystko poza modelem: twoje API, twoje dane, cudze serwery, wersje bibliotek.
Zanim zaczniesz: czy to na pewno regresja
To pytanie trzeba zadać najpierw, bo w jednym przypadku na kilka odpowiedź brzmi „nie”.
Agent mógł nigdy nie działać dobrze. Wdrożenie sprawdzono na kilkunastu przypadkach, wszystkie wypadły poprawnie, więc uznano temat za zamknięty. Tymczasem odpowiedzi są niedeterministyczne — jeden udany przebieg nie mówi nic o dziewięciu kolejnych.
Test: weź pięć przypadków, które „przestały działać”, i uruchom każdy dziesięć razy. Jeśli wynik jest niestabilny również teraz, nie masz regresji — masz agenta, który zawsze działał w siedemdziesięciu procentach, tylko nikt tego nie zmierzył.
To rozróżnienie zmienia całą dalszą drogę: w pierwszym przypadku szukasz zmiany, w drugim budujesz ewaluację.
Diagnostyka różnicowa
1. Aktualizacja modelu po stronie dostawcy
Jak rozpoznać: data pogorszenia jest ostra — jeden dzień, czasem godzina. Zmienił się głównie styl i długość odpowiedzi.
Test: sprawdź, czy w śladzie zapisujesz pełną wersję modelu, a nie alias. Jeśli tak, porównaj wersję sprzed i po. Jeśli nie — to jest pierwsza rzecz do naprawienia, bo bez tego przyczyna jest niediagnozowalna.
2. Zmiana w danych wejściowych
Jak rozpoznać: pogorszenie dotyczy tylko części przypadków, powiązanych z jednym źródłem.
Dlaczego to boli: API dodało pole, zmieniło format daty, zaczęło zwracać null tam, gdzie wcześniej był pusty ciąg. Model dostaje inny tekst, więc podejmuje inne decyzje — mimo że twój kod się nie zmienił.
Test: porównaj surowe wyniki narzędzi ze śladów sprzed i po. Szukasz różnicy w strukturze, nie w wartościach.
3. Zmiana w zewnętrznym serwerze MCP
Jak rozpoznać: pogorszenie dotyczy narzędzi z konkretnego serwera. Twój kod ich nie definiuje.
Dlaczego to boli: katalog pobierany zdalnie może zmienić opisy narzędzi między jednym pobraniem a drugim. Zwykle to zwykła aktualizacja, czasem podmiana po zatwierdzeniu.
Test: zapisz skrót całego katalogu narzędzi w śladzie przebiegu. Różnica skrótów między datami jest rozpoznaniem w jednej linijce.
4. Dryf danych po twojej stronie
Jak rozpoznać: pogorszenie jest stopniowe, nie skokowe. Dotyczy wyszukiwania i odpowiedzi opartych na bazie wiedzy.
Dlaczego to boli: baza urosła, więc retrieval zwraca teraz inne fragmenty. Nic się nie zepsuło — zmieniła się konkurencja w rankingu.
Test: uruchom te same zapytania na wyszukiwaniu i porównaj zwrócone fragmenty ze śladem archiwalnym.
5. Zmiana w twoim kodzie, której nie uznałeś za zmianę promptu
Jak rozpoznać: wdrożenie było, ale dotyczyło „czegoś innego”.
Dlaczego to boli: dopisanie pola do wyniku narzędzia, zmiana kolejności kluczy, inny komunikat błędu, przesunięcie fragmentu w prompcie — wszystko to zmienia tekst trafiający do modelu. Każda zmiana czegokolwiek, co ląduje w kontekście, jest zmianą promptu.
Test: przejrzyj wdrożenia z okresu regresji pod kątem tego kryterium, a nie pod kątem „czy dotyczyło agenta”.
6. Zmiana wersji biblioteki lub frameworka
Jak rozpoznać: data pogorszenia zbiega się z aktualizacją zależności.
Dlaczego to boli: zmienione wartości domyślne — temperatura, limit tokenów, liczba ponowień, sposób składania historii. Nic w twoim kodzie nie musiało się zmienić.
Test: wypisz faktycznie wysyłane parametry wywołania, zamiast ufać, że są takie jak w konfiguracji.
7. Przeciążenie po stronie dostawcy
Jak rozpoznać: wzrost liczby ponowień i czasu odpowiedzi, jakość gorsza nierównomiernie.
Dlaczego to boli: timeouty prowadzą do ponowień, ponowienia do innych trajektorii, a przy braku idempotencji także do powtórzonych operacji.
Test: porównaj liczbę ponowień na przebieg przed i po.
8. Zmiana modelu embeddingowego
Jak rozpoznać: wyłącznie wyszukiwanie semantyczne działa gorzej, reszta bez zmian.
Dlaczego to boli: wektory z różnych modeli są nieporównywalne. Częściowe przeliczenie bazy daje wyniki, które wyglądają wiarygodnie i są bezużyteczne.
Test: sprawdź, czy wszystkie wektory w bazie pochodzą z jednego modelu i jednej wersji.
Postępowanie
Natychmiast: przypnij konkretną wersję modelu zamiast aliasu, jeśli dostawca to umożliwia. To zatrzymuje dalszy dryf i pozwala pracować na stabilnym podłożu.
Potem: uruchom zestaw testowy z archiwalnych przypadków. Jeśli go nie masz — zbuduj z logów sprzed regresji, bo to najlepszy dostępny materiał. Bez punktu odniesienia każda dalsza zmiana jest zgadywaniem.
Następnie bisekcja przez daty. Wypisz wszystko, co zmieniło się w oknie regresji: wersja modelu, wdrożenia, aktualizacje zależności, skrót katalogu narzędzi, rozmiar bazy wiedzy. Zwykle kandydat jest jeden.
Nie przepisuj promptu jako pierwszego ruchu. To najczęstszy odruch, kosztuje najwięcej czasu i przy siedmiu z ośmiu przyczyn nie ma nic do rzeczy.
Profilaktyka
Zapisuj w śladzie przebiegu: pełną wersję modelu, skrót katalogu narzędzi, wersje kluczowych bibliotek i faktycznie użyte parametry wywołania. Cztery pola, które zamieniają dochodzenie z dni na minuty.
Uruchamiaj zestaw testowy cyklicznie, nie tylko przy zmianie kodu. To jest kluczowa różnica wobec klasycznego CI: tutaj podłoże zmienia się bez twojego udziału, więc test odpalany wyłącznie przy wdrożeniu nie wykryje niczego. Wystarczy raz dziennie.
Jak zdiagnozować u siebie
Prosty sygnalizator dryfu: uruchamia zestaw kontrolny, porównuje z zapisanym punktem odniesienia i wypisuje, co się zmieniło w otoczeniu.
import hashlib, json, datetime
def odcisk_katalogu(narzedzia):
tresc = json.dumps(narzedzia, sort_keys=True, ensure_ascii=False)
return hashlib.sha256(tresc.encode()).hexdigest()[:12]
def kontrola(zestaw, uruchom, narzedzia, model, punkt_odniesienia=None):
"""zestaw: [(pytanie, oczekiwane)]; uruchom: funkcja -> (wynik, meta)"""
wyniki, trafienia = [], 0
for pytanie, oczekiwane in zestaw:
wynik, meta = uruchom(pytanie)
ok = oczekiwane in str(wynik)
trafienia += ok
wyniki.append({"pytanie": pytanie, "ok": ok,
"kroki": meta.get("kroki"), "model": meta.get("model")})
raport = {
"data": datetime.date.today().isoformat(),
"model": model,
"odcisk_katalogu": odcisk_katalogu(narzedzia),
"trafnosc": round(trafienia / len(zestaw), 3),
"srednie_kroki": round(sum(w["kroki"] or 0 for w in wyniki) / len(wyniki), 1),
}
if punkt_odniesienia:
print(f"trafność {punkt_odniesienia['trafnosc']:.0%} → {raport['trafnosc']:.0%}")
if raport["model"] != punkt_odniesienia["model"]:
print(f" ! ZMIANA MODELU: {punkt_odniesienia['model']} "
f"→ {raport['model']} (przyczyna 1)")
if raport["odcisk_katalogu"] != punkt_odniesienia["odcisk_katalogu"]:
print(f" ! ZMIANA KATALOGU NARZĘDZI (przyczyna 3 lub 5)")
if raport["srednie_kroki"] > punkt_odniesienia["srednie_kroki"] * 1.3:
print(f" ! DŁUŻSZE TRAJEKTORIE: "
f"{punkt_odniesienia['srednie_kroki']} → {raport['srednie_kroki']}")
return raport
Odcisk katalogu narzędzi jest tu najważniejszym pojedynczym polem. Wykrywa naraz dwie przyczyny — cudzą zmianę na serwerze MCP i twoją własną zmianę, o której nie pomyślałeś jako o zmianie promptu — a kosztuje jedną linijkę.
Ćwiczenie: zapisz punkt odniesienia dzisiaj, uruchamiaj kontrolę raz dziennie przez tydzień i zobacz, ile z tych pól zmieni się bez twojego udziału. Przy większości wdrożeń odpowiedź zaskakuje.
Powiązane
Co logować w pętli, żeby dało się cokolwiek zdiagnozować: Maszyneria agenta. Skąd bierze się charakter modelu i dlaczego zmienia się między wersjami: Anatomia LLM.
Następny syndrom: Agent podaje dane, których nie ma.





















