PABLO.ENGINEERING
// WRÓĆ DO WSZYSTKICH WPISÓW
// 5 min

Martwy slug modelu, cichy failover i jawny limit 8192 tokenów

#daily#agents#aneta#eval#anki

Dzień upłynął na sprzątaniu konfiguracji modeli i domykaniu jakości treści do nauki. Najwięcej czasu zjadł cron walidujący config, który od kilku dni świecił na czerwono z powodu jednego wpisu.

Problem: awaria, której nikt nie widział, bo fallback działał

Zadanie crona, które sprawdza poprawność konfiguracji workspace'u, padało 4 razy pod rząd. Cron to zadanie uruchamiane automatycznie o wyznaczonych porach. Powód nie siedział w kodzie, tylko w configu: model wizyjny w łańcuchu fallback nie miał zadeklarowanego maxTokens. Fallback to model zapasowy, na który system przełącza się, gdy model główny nie odpowie. Reguła limitu wyjścia w workspace była liczona ze zgadywanego dolnego progu, więc jej wartość zależała od środowiska.

Drugi problem to martwy slug. Slug to krótka nazwa, którą identyfikuję model w configu. Wpis gpt-6-luna wyprodukował 6 błędów 400 w ciągu około 11 minut. Każde żądanie kończyło się sukcesem, bo zadziałał failover, czyli automatyczne przełączenie na model główny. Z perspektywy użytkownika nie działo się nic. Z perspektywy logów działo się bardzo dużo: bramka nazbierała 171 linii błędów.

Bolało to podwójnie. Po pierwsze, zielone światło na zewnątrz i czerwone w środku to najgorszy możliwy układ, bo uczy ignorować logi. Po drugie, hałas z martwego wpisu zakopywał prawdziwe błędy, które pojawiły się w tym samym oknie.

Co zrobiłem: konkret

  • Dodałem jawne maxTokens: 8192 dla modelu wizyjnego w łańcuchu fallback. Zrobiłem backup configu, sprawdziłem schemat w trybie dry-run, czyli bez wprowadzania zmian, i nie restartowałem usługi.
  • Uruchomiłem dokładnie to samo polecenie crona, które wcześniej padało. Wychodzi z exit 0, czyli kodem sukcesu.
  • Usunąłem martwy slug gpt-6-luna z configu.
  • Przyjąłem 8192 tokeny jako konserwatywny, jawny limit, z notatką, że podniosę go świadomie później.
  • Rozdzieliłem krok synchronizacji (exit 0) od bramki --check i alertuję tylko na bramkę.
  • Przyjąłem zasadę live-probe dla każdego sluga, zanim zaufam mu w łańcuchu fallback. Live-probe to jedno realne wywołanie testowe przed wdrożeniem.
  • Zebrałem próbkę 42 błędów bramki. Dominowały błędy odczytu configu, w których worker SQLite w trybie read-only nie potrafił się ustabilizować. Zapisuję to jako osobną ścieżkę naprawy, a nie jako powód do kolejnych retry.
  • Skorelowałem ostrzeżenie o ciśnieniu na pamięć (RSS 1.71 GiB, 101% progu) z 4 restartami bramki w oknie 11:50-12:02. Od 12:02:12 uptime się trzyma, wolne jest około 8.6 GiB.
  • Złapałem jedną awarię heartbeatu, czyli cyklicznego sygnału życia, zaklasyfikowaną jako błąd na poziomie narzędzia.
  • W agencie hiszpańskim dodałem zabezpieczenia jakości fiszek: walidację wejścia, separację promptów i reguły na poziomie SOUL, czyli warstwy bazowych instrukcji agenta. Wcześniej zły kandydat na kartę mógł przejść do talii niezauważony.
  • Podniosłem generator talii Anki do wersji v4 z parsowaniem świadomym nawiasów i czystą separacją promptów. Pola z tekstem w nawiasach były źle dzielone i psuły wpisy.
  • Przeniosłem znacznik [sound:...] do pola notatki z szablonu. To naprawiło wykrywanie mediów i synchronizację z Anki.
  • Wdrożyłem Engineering Lab i DevLog modeli floty oraz komendy /modele i /odswiez_modele, w wzorcu edit-in-place, czyli aktualizacji tej samej wiadomości zamiast wysyłania kolejnej. Wcześniej każde odświeżenie statusu dokładało duplikat na czacie.
  • Dodałem router STT/TTS i obsługę notatek głosowych w czterech agentach (gym, aneta, main, spanish). STT to rozpoznawanie mowy, TTS to jej synteza. Wcześniej każdy bot obsługiwał głos po swojemu.
  • Wypuściłem 11 commitów na agent-brain, w tym 5 commitów synchronizacji wiedzy i pamięci (main 20, spanish 13, aneta 6, gym 6 śledzonych plików).
  • Sprawdziłem jakość: skaner plików przeszedł po 3 workspace'ach agentów i 306 plikach, JSON z fiszkami zwalidował się na 492 kartach.
  • Uruchomiłem weryfikator pamięci 12 razy między 19:00 a 21:45. Zero rekordów do naprawy.
  • Watchdog quizu, czyli proces pilnujący, czy coś się nie wysypało, zalogował przebieg w 8 sekundach i milczał w dniu bez słownictwa.
  • Do tego drobne prace: safety-signal guardian wykonał 12 skanów w oknie 20:55-21:50 i zgłosił czyste okno. W aoc i typer_bot nie weszły żadne zmiany i zapisuję to jawnie, żeby puste repo nie wyglądało jak brak danych.

Dlaczego to ważne (Use Case)

Najważniejsza rzecz z tego dnia to rozdzielenie dwóch sygnałów. Cron był czerwony, bo config był zepsuty, a nie dlatego, że system padł. Alert ustawiony na bramkę --check mówi o prawdziwym problemie. Alert ustawiony na całe zadanie krzyczałby o zdrowej synchronizacji i po tygodniu przestałbym go czytać.

Drugi use case to fiszki. Błąd w potoku treści uczy złego materiału i nikt tego nie zauważa, bo karta wygląda poprawnie. Walidacja wejścia i separacja promptów łapią takie rzeczy przed uczniem, a nie po fakcie. Audio w talii wymowy to nie ozdoba: zły znacznik [sound:...] po cichu degraduje każdą kartę z dźwiękiem.

Trzecia sprawa dotyczy bezpieczeństwa treści wejściowej. Guardian sprawdza, czy ktoś nie próbuje nadpisać instrukcji w treści, którą dostaje agent. Czyste okno z 12 skanów traktuję jako słaby sygnał, a nie dowód. Mam podejrzenie injection drift, czyli powolnego przesuwania się takich prób: pojedyncze skany mogą nic nie złapać, bo zmiana rozkłada się na wiele dni. Dlatego wolę trzymać ten kanał w tle i patrzeć na trendy, zamiast ogłaszać sukces po jednym czystym oknie.

Czego się nauczyłem

  1. Failover, który działa, ukrywa zepsutą konfigurację. 6 błędów 400, 171 linii w logach i zero nieudanych żądań u użytkownika to nie sukces, to odroczony problem.
  2. Jawny, nawet trochę za niski limit, jest lepszy od dorozumianego. 8192 tokeny to konserwatywna liczba, ale jest powtarzalna i widoczna w review. Wartość liczona ze zgadywanego progu zmienia się razem ze środowiskiem.
  3. Zadanie celowo czerwone trzeba zaprojektować, a nie łatać. Rozdzielenie kroku synchronizacji od bramki walidacji kosztowało kilka linii, a ratuje zaufanie do kanału alertów.