Od „gumowej kaczki” do LLM‑ów – jak zmienia się debugowanie
Od printfów do IDE naszpikowanych inteligencją
Debugowanie przez lata wyglądało zaskakująco podobnie: dodatkowe printfy, prymitywne logowanie, ręczne śledzenie stanu programu. Później doszły breakpointy w IDE, krokowe wykonywanie kodu, podgląd zmiennych i profilerów. W pewnym momencie standardem stały się:
- logi – od prostych plików tekstowych po scentralizowane systemy typu ELK,
- debuggery – wbudowane w IDE, z możliwością zdalnego podłączenia do procesu,
- profilery – do śledzenia wydajności i zużycia zasobów,
- „rubber duck debugging” – wyjaśnianie problemu na głos, często do… gumowej kaczki.
Ten ostatni punkt brzmi żartobliwie, ale jest bardzo prawdziwy: większość trudnych błędów ujawnia się, gdy spróbujesz komuś (lub czemuś) w logiczny sposób opowiedzieć, co naprawdę robi twój kod i gdzie jest rozjazd względem oczekiwań. LLM‑y są de facto cyfrową, bardzo rozmowną gumową kaczką, tyle że potrafią też czytać kod i logi.
Złożoność systemów wyprzedziła klasyczne narzędzia
Od monolitów hostowanych na jednym serwerze przeszliśmy do architektur z dziesiątkami mikroserwisów, rozproszonych po chmurze, kontenerach, kubernetesach i edge’u. Do tego dochodzi:
- komunikacja asynchroniczna (kolejki, eventy, strumienie),
- scentralizowane logowanie z różnych regionów i środowisk,
- feature flagi, canary release, blue‑green deployment,
- różne wersje usług współistniejące jednocześnie.
Prosta odpowiedź „sprawdź logi” nagle przestaje być prosta. Logów mogą być gigabajty, metryk – setki, a incydent często jest efektem subtelnej interakcji kilku pozornie niezwiązanych ze sobą zmian. Człowiek radzi sobie z tym coraz gorzej, zwłaszcza pod presją czasu, w nocy, podczas incydentów P1.
Skąd w tym wszystkim LLM‑y i dlaczego „kliknęło”?
Modele językowe (LLM) pojawiły się dokładnie w momencie, gdy złożoność przekroczyła próg ludzkiej percepcji, a jednocześnie kod i logi zaczęliśmy traktować jak tekst, który można maszynowo przetwarzać. Dla LLM‑a kod jest po prostu kolejnym językiem, z własną składnią i semantyką. To samo dotyczy:
- stack trace’y,
- logów aplikacyjnych i infrastrukturalnych,
- konfiguracji YAML/JSON/Terraform/Helm,
- dokumentacji API, RFC, README.
Kiedy da się to wrzucić do jednego kontekstu, model zyskuje możliwość powiązania faktów: log z serwisu A, konfiguracja serwisu B, testy jednostkowe dla C i komunikat błędu z frontendu. To nie jest jeszcze pełna, formalna analiza jak w klasycznym programowaniu statycznym, ale bywa wystarczająco dobra, żeby szybko dojść do hipotezy.
LLM jako obietnica dla devów i DevOpsów
Modele językowe nie są magiczną różdżką, ale składają bardzo konkretną obietnicę:
- skrócenie czasu od błędu do pierwszej sensownej hipotezy – zamiast 40 minut scrollowania logów, masz 3–4 kandydackie przyczyny do weryfikacji,
- odciążenie od nudnych zadań – generowanie powtarzalnych fragmentów kodu obsługi błędów, parsowania logów, zapytań do bazy,
- pomoc przy wejściu w obcy system – wyjaśnienie starego modułu, diagram zależności, opis interfejsów,
- lepsze „gumowe kaczkowanie” – możliwość zadawania pytań, doprecyzowywania, proszenia o alternatywy i kontrprzykłady.
W praktyce często oznacza to, że zamiast „siedzieć i cierpieć” nad jednym bugiem przez pół dnia, spędzasz pół godziny na sensownej rozmowie z LLM‑em, a potem godzinę na konkretnych eksperymentach.
Nocny incident, który nie przerodził się w koszmar
Wyobraź sobie klasyczny scenariusz: jest 2:17 w nocy, dzwoni pager. Usługa płatności ma 5% podwyższony error rate, SLA się pali. Logów – masa, komunikat z frontu: „We’re sorry, an error occurred”. W dawnej rzeczywistości zespół SRE budziłby backend developera, razem przeklikiwaliby się przez Kibane, szukając sensownego wzorca.
Z LLM‑em wygląda to inaczej. SRE zaciąga z ostatnich 20 minut próbkę logów z kilku serwisów, fragment konfiguracji release’u i opisuje w jednym promptcie: „Production incident, payments, increased 5xx, here’s the diff between previous and current deployment, here are logs from gateway, payments-service and inventory-service. Proszę wygeneruj hipotezy przyczyny w kolejności najbardziej prawdopodobnych i wypisz konkretne miejsca w kodzie/konfiguracji, które powinniśmy sprawdzić.”
Model wskazuje, że we wszystkich błędnych requestach używany jest nowy endpoint z dodatkowym parametrem, a logi inventory-service mają charakterystyczny wzorzec timeoutów po deployu. Hipoteza: nowa wersja płatności czeka dłużej na odpowiedź inventory, nie ma odpowiedniego fallbacku i robi retry w pętli, aż do timeoutu gatewaya. Po kilku minutach manualnej weryfikacji – bingo. Incident zamyka się w kilkudziesięciu minutach zamiast w kilku godzinach ślepego grzebania.

Co LLM‑y naprawdę potrafią w kontekście debugowania
Zadania, w których LLM‑y są mocne
Modele językowe szczególnie dobrze radzą sobie w debugowaniu tam, gdzie problem da się oddać w formie tekstu: kod, logi, konfiguracja, dokumentacja. Najbardziej typowe i praktyczne zastosowania to:
Diagnoza błędów na podstawie stack trace
Stack trace to dla LLM‑a gotowa mapa zdarzeń: jaka metoda wywołała jaką, w jakiej kolejności, z jakim błędem na końcu. Model może:
- nazwać typ błędu w zrozumiały sposób („masz null pointera, bo to pole nie zostało zainicjalizowane przed użyciem w linii X”),
- wskazać „prawdziwe źródło” – nie zawsze linia na końcu stack trace’u jest przyczyną; model potrafi skojarzyć wcześniejsze ostrzeżenia/logi,
- powiązać błąd z frameworkiem – „to typowy błąd konfiguracji session store w Springu / Django / Expressie”.
Przykład promptu:
Oto stack trace z aplikacji Spring Boot (Java 17).
Dołączam też fragment pliku konfiguracyjnego application.yml oraz klasę,
w której wywoływana jest problematyczna metoda.
1) Zidentyfikuj najbardziej prawdopodobną przyczynę błędu.
2) Zaproponuj 2–3 różne sposoby naprawy z uwzględnieniem istniejącej konfiguracji.
3) Zaproponuj dodatkowe logi lub asercje, które pomogą potwierdzić przyczynę.
Wyjaśnianie obcej bazy kodu i zależności
Wejście w duży, stary projekt to często kilka dni orientowania się „co z czym gada”. LLM, który dostanie:
- listę plików i strukturę katalogów,
- kluczowe klasy/kontrolery,
- główne pliki konfiguracyjne,
jest w stanie wygenerować przyzwoity opis architektury: jakie moduły istnieją, jakie są główne przepływy danych, gdzie wejścia, gdzie wyjścia. Z punktu widzenia debugowania pomaga to skrócić drogę od „nic nie wiem” do „wiem, w której części kodu szukać problemu”.
Proponowanie hipotez i ścieżek dochodzenia do przyczyny
LLM‑y są bardzo dobre w generowaniu hipotez, zwłaszcza gdy w promptcie jasno poprosisz o alternatywy, a nie jedną „prawdę objawioną”. W kontekście debugowania mogą:
- rozszerzyć listę potencjalnych przyczyn, o których sam byś nie pomyślał,
- zaproponować kolejność sprawdzania („najpierw wyklucz X, potem Y, na końcu Z”),
- wskazać konkretne logi, metryki lub narzędzia, po które sięgnąć.
To szczególnie przydatne w sytuacjach, gdy jesteś zmęczony, a mózg uparcie krąży wokół jednej teorii. Model „wciąga” cię w bardziej systematyczne myślenie.
Obszary, w których LLM‑y zawodzą lub bywają groźne
Halucynacje: zmyślone API, parametry i konfiguracje
Największa pułapka: model zawsze coś odpowie, nawet jeśli nie ma racji. W debugowaniu oznacza to:
- wymyślone klasy, metody lub parametry („ta flaga w tym frameworku po prostu nie istnieje”),
- podawanie nieaktualnych rozwiązań, niekompatybilnych z używaną wersją biblioteki,
- tworzenie „ładnie wyglądających” konfiguracji, które nie przechodzą walidacji.
W praktyce trzeba trzymać się zasady: LLM generuje hipotezy, a nie fakty. Jeśli funkcja/parametr nie pojawia się w oficjalnej dokumentacji ani w twoim kodzie, traktuj to jako błąd modelu, a nie „tajne API”.
Płytkie zrozumienie domeny i logiki biznesowej
Model widzi kod, ale nie zna wszystkich niepisanych reguł biznesowych. Przykłady:
- w systemie płatności jest zasada„refund możliwy tylko do północy czasu lokalnego sklepu” – w kodzie to tylko sprytna kombinacja dat, stref czasowych i feature flag; model nie wie, dlaczego to tak działa,
- specyficzne reguły domenowe (np. w logistyce czy finansach) mogą być opisane w Confluence, w kontraktach, w głowach ludzi – LLM nie ma do nich dostępu.
Dlatego sugestie typu „prościej będzie to usunąć” mogą być biznesowo katastrofalne. Model nie ma wbudowanego pojęcia odpowiedzialności za konsekwencje swojej „refaktoryzacji”.
„AI, napraw to za mnie” kontra „AI jako partner w myśleniu”
Największe rozczarowania biorą się z błędnego oczekiwania: „tu masz stack trace, napraw kod”. Taki tryb „autopilota” bywa przydatny w generowaniu boilerplate’u, ale w debugowaniu rzadko działa dobrze. Dużo skuteczniejsze jest traktowanie LLM‑a jako rozmówcy, który:
- zadaje dopytujące pytania („jakie są wartości tego parametru? czy logi pokazują X?”),
- pomaga strukturyzować proces dochodzenia do przyczyny,
- proponuje plan eksperymentów i testów.
Różnicę widać w promptach. Zamiast: „Napraw ten kod, bo test nie przechodzi”, lepiej napisać:
Oto failing test i implementacja funkcji.
1) Wyjaśnij, jak rozumiesz wymaganie na podstawie testu.
2) Pokaż, w którym miejscu implementacja jest niespójna z tym wymaganiem.
3) Zaproponuj zmianę kodu oraz dodatkowy test, który zabezpieczy ten przypadek graniczny.
Nowoczesne modele: czego realnie można oczekiwać
Najnowsze generacje modeli (GPT‑4+, Claude, Llama w nowszych wersjach) to nieco inna liga niż pierwsze „AI asystenty do kodu”. W praktyce oznacza to:
- duży kontekst – analiza setek stron kodu, logów i dokumentacji w jednym zapytaniu; możesz wrzucić kilka powiązanych plików zamiast pojedynczych funkcji,
- wielojęzyczność technologiczna – jeden model potrafi sensownie rozmawiać o Java + Kotlin + TypeScript + YAML + Terraform w ramach jednego problemu,
- lepsza „pamięć” w ramach sesji – model pamięta wcześniejsze wątki i potrafi do nich wrócić, jeśli mu o tym przypomnisz.
To otwiera drzwi do debugowania całych przepływów – od frontu, przez backend, aż po infrastrukturę – a nie tylko pojedynczych funkcji.

Typologia scenariuszy: jak dev i DevOps mogą używać LLM‑ów
Debugowanie lokalne kontra produkcyjne
Lokalne bugi, testy, refaktoryzacja
Lokalnie masz komfort: możesz przełączyć się w tryb debug, podstawić breakpoint, uruchomić test tysiąc razy. Typowe zadania, w których LLM jest tutaj pomocny:
- wyjaśnianie błędów kompilacji i linkowania,
- tłumaczenie komunikatów linterów i statycznej analizy („co dokładnie mam poprawić?”),
- pomoc w napisaniu testu, który odtwarza błąd zgłoszony z produkcji,
- refaktoryzacja pod kątem czytelności obsługi błędów i logów.
LLM świetnie sprawdza się jako ktoś, kto „patrzy na ekran razem z tobą” i podpowiada, czemu kompilator się obraził albo jak rozwiązać konflikt typów.
Incydenty produkcyjne, post‑mortem i SRE
Incydenty produkcyjne, post‑mortem i SRE (ciąg dalszy)
Przy incydentach produkcyjnych LLM może pełnić rolę „drugiego SRE”, który nie śpi, nie panikuje i ma w głowie całkiem sporą bibliotekę wzorców awarii. Kluczem jest traktowanie go jako narzędzia do przyspieszenia analizy, a nie jako automatycznego „remediatora” zmieniającego infrastrukturę za twoimi plecami.
Dobry schemat wygląda tak:
- zespół zbiera fakty: timeline, metryki, logi, zmiany z ostatnich deployów,
- LLM dostaje uładzony, tekstowy opis plus wycinki danych,
- na tej podstawie pomaga ułożyć hipotezy, pytania i ewentualny plan eksperymentów.
Przykład promptu z incydentu SLO/SLA:
Jesteś inżynierem SRE w zespole e‑commerce.
Mamy incydent P1: wzrost mediany i 95p latencji checkout o 40–60% w ciągu ostatnich 2 godzin.
Dane wejściowe:
- opis architektury (monorepo, mikrousługi A/B/C, komunikacja synchroniczna REST),
- timeline ostatnich deployów i zmian infrastrukturalnych,
- wycinki metryk z Prometheusa (CPU, RAM, GC, latencje, error rate),
- fragmenty logów z gatewaya i serwisu payment.
1) Wypisz 3–5 najbardziej prawdopodobnych klas przyczyn (np. regress wydajnościowy, hot spot DB, throttling zewnętrznego API).
2) Dla każdej klasy podaj konkretne eksperymenty/obserwacje, które mogą ją potwierdzić lub wykluczyć.
3) Zaproponuj tymczasowe workaroundy, które można bezpiecznie wdrożyć w ciągu najbliższych 30 minut.
Po zakończonym incydencie model przydaje się jeszcze raz – przy przygotowaniu post‑mortem. Z notatek na kanale incidentowym, ticketów i timeline’u generuje:
- wstępny opis zdarzenia (co, kiedy, jaki wpływ),
- listę contributing factors („co zadziałało razem, że poszło źle”),
- propozycje akcji prewencyjnych i detekcyjnych.
Dopiero to potem weryfikuje człowiek, ale zamiast dwóch godzin ślęczenia nad pustym dokumentem masz sensowny szkic w kilkanaście minut.
Praca indywidualna kontra współpraca zespołowa
LLM jako „cichy pair programmer”
Podczas codziennej pracy wielu devów używa LLM‑a jak kumpla z biurka obok. Zamiast pisać na Slacku „kto zna ten dziwny błąd z Webpackiem?”, wrzucasz go do modelu wraz z fragmentem konfiguracji i pytasz o możliwe przyczyny. Szybki feedback pozwala odsiać banały (zła ścieżka, brak pluginu) od rzeczy bardziej podchwytliwych.
Taki tryb jest szczególnie efektywny, gdy:
- próbujesz zrozumieć nową bibliotekę lub framework i dostajesz krypticzne komunikaty,
- przepisujesz „legacy” i boisz się, że ruszysz zły klocek Jengi,
- masz blokadę poznawczą – patrzysz na ten sam kod od godziny i nic nie widzisz.
Zamiast „napraw mi to”, bardziej produktywne są pytania typu: „jakie widzisz ryzyka tej zmiany?”, „co może się zepsuć, jeśli wprowadzę taki refactoring?”. Model rzadko odpowie „nic”, za to często wskaże kilka newralgicznych miejsc, o których nie pomyślałeś.
LLM w rytuale code review
W zespole LLM może być używany przed lub po ludzkim code review. Oba warianty mają sens, tylko trzeba je dobrze ustawić.
Przed CR:
- autor puszcza swoje zmiany przez bota „lintującego na sterydach”,
- prosi o wykrycie potencjalnych regresji, braków w obsłudze błędów, niespójnych nazw,
- na podstawie uwag modelu poprawia kod, zanim pokaże go ludziom.
Po CR:
- reviewerzy mogą poprosić model o przykład alternatywnej implementacji (dla edukacji, nie jako „prawda objawiona”),
- LLM może pomóc przeformułować komentarze w bardziej konstruktywny sposób,
- w dużych zmianach – streścić PR i wypunktować miejsca wymagające szczególnej uwagi.
W kontekście debugowania CR z AI staje się miejscem, gdzie szybciej wyłapujesz potencjalne „future bugs”: brak obsługi edge casów, nieintuicyjne API, niekompatybilność z istniejącymi kontraktami.
Logi, metryki, trace – jak LLM wspiera obserwowalność
Analiza logów „hurtowo”, a nie linijka po linijce
Klasyczny scenariusz: masz 2000 linii logów z kilku serwisów, a wiesz, że istotne są może dwie krótkie sekwencje. LLM świetnie nadaje się do:
- grupowania podobnych błędów w „klasy problemów”,
- wyszukiwania rzadkich, ale powtarzalnych wzorców (np. „błąd zawsze, gdy user‑agent zawiera X”),
- tworzenia skrótowego opisu tego, co w logach się zmieniło między dobrą a złą wersją.
Dobrym nawykiem jest dostarczanie modelowi par logów: „tak wygląda poprawne wykonanie, tak – błędne”. Zamiast kazać mu zgadywać z jednego zrzutu, prosisz o porównanie dwóch ścieżek wykonania.
Metryki i alerty – od szumu do hipotez
Czysty wykres z Prometheusa czy Datadoga daje dużo informacji, ale nie zawsze jest jasne, które metryki są symptomem, a które przyczyną. Tu LLM może posłużyć jako „komentator sportowy”, który wiąże dane w prostą narrację.
Przykładowy prompt:
Masz przed sobą opis metryk z ostatnich 4 godzin (CPU, RAM, GC, latencje, liczba requestów, error rate) oraz informacje o 2 deployach.
1) Opisz możliwy łańcuch przyczynowo-skutkowy prowadzący do wzrostu latencji.
2) Wskaż, które metryki wyglądają na skutek, a które mogą być przyczyną.
3) Zaproponuj dodatkowe metryki lub logi, które warto dołożyć, żeby lepiej widzieć ten typ problemu w przyszłości.
Dla DevOpsa czy SRE to dobry sposób na „drugi zestaw oczu” przy projektowaniu nowych dashboardów czy polityk alertowania. Model podsuwa pomysły: brakujące histogramy, rozdzielenie error rate na typy błędów, dodatkowe metryki biznesowe (np. porzucone koszyki).
Przegląd narzędzi: jak głęboko integrować LLM z codzienną pracą
Chatbot w przeglądarce: najniższy próg wejścia
Najprostszy poziom to po prostu zakładka z chatem (OpenAI, Claude, inny provider). Nie wymaga to żadnej integracji, ale ma ograniczenia: ręcznie kopiujesz kod, logi, konfiguracje, pilnujesz redakcji sekretów.
Ten tryb sprawdza się, gdy:
- szukasz szybkiej podpowiedzi do błędu kompilacji czy konfiguracji,
- chcesz zrozumieć fragment obcego kodu lub wzorzec z logów,
- potrzebujesz „gumowej kaczki deluxe” do przedyskutowania hipotez.
Dla bezpieczeństwa warto od razu przyjąć zasadę: żadnych kluczy, haseł, danych klientów wklejanych do publicznego chata. Jeśli musisz pokazać config, zredaguj wrażliwe fragmenty („***”).
Pluginy i rozszerzenia do IDE
Kolejny poziom to pluginy typu „AI Copilot” w VS Code, JetBrainsach czy Vimie. W kontekście debugowania dają kilka konkretnych plusów:
- model widzi kontekst projektu – sąsiednie pliki, strukturę katalogów, importy,
- możesz zaznaczyć fragment kodu, kliknąć „wyjaśnij” lub „znajdź potencjalne bugi”,
- w części narzędzi da się odpalić mini‑chat „przywiązany” do konkretnego pliku.
Z taką integracją debugowanie przypomina rozmowę nad otwartym plikiem w edytorze: „spójrz na tę funkcję i test obok, co tu może pójść źle?”. Model nie musi wtedy operować na wyrwanych z kontekstu snippetach.
Agent „obserwujący” testy i lokalny runtime
Bardziej zaawansowane narzędzia potrafią przyglądać się uruchamianym testom i procesom. Gdy test pada, agent:
- zbiera stack trace,
- sprawdza powiązane pliki i konfigurację,
- generuje wstępną diagnozę widoczną od razu w IDE lub CI.
W praktyce wygląda to tak, że po odpaleniu pakietu testów zamiast „Test X failed: AssertionError” widzisz krótkie, ludzkie podsumowanie przyczyny oraz link do propozycji poprawki kodu lub testu. W małych zespołach to czasem różnica między „naprawię to po lunchu” a „w ogóle zauważyłem, że coś jest nie tak”.
Integracja z CI/CD: AI jako strażnik pipeline’u
Na poziomie CI/CD LLM może brać udział w kilku etapach:
- analiza failing buildów i testów – zamiast suchego logu z joba dostajesz streszczenie przyczyn niepowodzenia,
- klasyfikacja awarii – flaky test vs. regresja vs. problem środowiskowy,
- propozycje rollbacku lub feature flag – model na podstawie manifestów i historii deployów pomaga dobrać najbezpieczniejszy ruch.
Typowy scenariusz: pipeline padł, bo seria testów e2e zgłasza time‑outy. LLM analizuje logi z Selenium, backendu i proxy, po czym układa hipotezę: „zwiększony czas odpowiedzi serwisu płatności po ostatniej zmianie konfiguracji bazy, proponuję najpierw wykonać A/B comparison na poprzednim connection poolu, zamiast od razu rollbacku całego release’u”. Decyzję i tak podejmuje człowiek, ale ma lepsze dane startowe.
Obserwowalność + AI: integracje z APM i log management
Coraz więcej narzędzi APM i log managementu (Datadog, New Relic, Elastic, Sentry) dodaje swoje „AI assistenty”. Ich mocna strona to dostęp do:
- pełnych logów i trace’ów (często z kilku środowisk),
- metryk infrastrukturalnych i biznesowych,
- historii wcześniejszych incydentów i wzorców awarii.
Przy zgłoszonym błędzie w Sentry możesz dostać od razu:
- klastrowanie podobnych eventów (czy to jednostkowy przypadek, czy fala),
- opis, który release wprowadził daną klasę błędu,
- wstępną sugestię – czy to NPE, błąd konfiguracji, czy może limit zewnętrznego API.
Im bliżej źródeł prawdy (logi, metryki, trace, historia deployów) siedzi model, tym bardziej wartościowe są jego hipotezy. Dlatego integracja na poziomie platformy obserwowalności, choć trudniejsza i droższa, potrafi odwdzięczyć się znaczącym skróceniem MTTR.
Bezpieczeństwo i prywatność w debugowaniu z LLM
Co wolno wysłać do chmury, a co lepiej „przeżuć” lokalnie
Debugując z AI łatwo przekroczyć granicę i wrzucić do modelu coś, czego nie powinno tam być: dane klientów, dane finansowe, tajne algorytmy. Tu przydaje się prosty podział:
- Bezpieczne: ogólne fragmenty kodu, pseudonimizowane logi, abstrakcyjne opisy architektury,
- Ryzykowne: pełne payloady requestów z danymi personalnymi, klucze API, hasła, sekrety w configach,
- Wrażliwe biznesowo: unikalne algorytmy pricingu, modele scoringowe, szczegóły integracji z partnerami.
Jeśli często debugujesz w oparciu o produkcyjne logi, dobrym krokiem jest wdrożenie pseudonimizacji i filtracji przed wysłaniem tekstu do LLM‑a: maskowanie emaili, numerów kart, identyfikatorów klientów, a czasem wręcz generowanie syntetycznych przykładów opartych o rzeczywisty błąd.
Self‑hosted LLM i „air‑gapped debugging”
W firmach z ostrą polityką bezpieczeństwa coraz częściej pojawia się opcja lokalnego, samodzielnie hostowanego modelu (lub wersji „enterprise” dostawcy). Z perspektywy debugowania zyskujesz wtedy:
- możliwość karmienia modelu realnymi logami i kodem bez wynoszenia ich na zewnątrz,
- większą kontrolę nad tym, co jest logowane i jak długo przechowywane,
- szansę na fine‑tuning pod waszą domenę: specyficzne wzorce błędów, wasza architektura, nazewnictwo serwisów.
To nie jest darmowe – wymaga kompetencji MLOpsowych, utrzymania klastra GPU i monitorowania samego modelu – ale w zamian dostajesz narzędzie, które lepiej rozumie twoje środowisko niż generyczny chatbot. Przy incydentach produkcyjnych, gdzie liczą się minuty i gdzie operujesz na bardzo wrażliwych danych, to bywa jedyne sensowne rozwiązanie.

Jak rozmawiać z LLM‑em o błędach – praktyczny prompt engineering
Konkretny kontekst zamiast „magii AI”
LLM nie czyta ci w myślach. Działa raczej jak senior, który dostał skrawki informacji na Slacku i ma z tego złożyć sensowną hipotezę. Im bardziej podasz mu sytuację jak na tacy, tym mniej będzie „fantazjowania”, a więcej realnej pomocy.
Przy debugowaniu opłaca się opisać kontekst w kilku warstwach:
- Co próbujesz zrobić – biznesowo lub funkcjonalnie,
- Co się faktycznie dzieje – objawy, logi, stack trace, metryki,
- Co już sprawdziłeś – żeby model nie powtarzał oczywistości,
- Jakie masz ograniczenia – nie mogę zmienić schematu bazy, muszę zachować kompatybilność API itd.
Zamiast:
Nie działa mi logowanie użytkownika. Co jest źle?
lepiej podać coś w tym stylu:
Cel: użytkownik ma móc zalogować się przez OAuth2 (Google) do naszej aplikacji webowej.
Objaw: po kliknięciu "Zaloguj przez Google" dostajemy 500 na /oauth/callback.
Kontekst:
- backend: Spring Boot 3, Spring Security 6, Java 17
- frontend: React, redirect na /oauth/callback z parametrami od Google
- środowisko: DEV, single instance, lokalna baza PostgreSQL
Dane:
- log z backendu (poniżej)
- konfiguracja Spring Security (poniżej)
- stack trace (poniżej)
To już sprawdziłem:
- poprawność client_id i client_secret
- adres redirect_uri w konsoli Google (zgadza się z tym w aplikacji)
- po stronie frontu parametry przekazywane są poprawnie
Oceń:
1) najprawdopodobniejszą przyczynę 500,
2) co konkretnie poprawić w konfiguracji lub kodzie,
3) jakie 2-3 dodatkowe logi/metryki dodać, żeby podobny problem szybciej diagnozować w przyszłości.
Ten sam błąd, ale opisany jak do człowieka, który nie siedzi z tobą przy klawiaturze. Model może wtedy wykorzystać swoją „encyklopedię” zamiast losowo zgadywać.
Struktura promptu: tryb „task list” zamiast luźnej gadki
Model lubi jasne zadania. Gdy zamiast jednego wielkiego pytania dajesz mu listę kroków, coraz rzadziej dostajesz odpowiedzi typu „to zależy”. W debugowaniu kluczowe są trzy części:
- krótki opis kontekstu,
- dokładne dane (kod, logi, konfiguracja),
- jasny format odpowiedzi.
Przykład ogólnego „szkieletu” dla problemu z backendem:
Jesteś doświadczonym inżynierem backendu & SRE.
Kontekst:
- Technologia: <stack>
- Co miało się wydarzyć: <oczekiwane zachowanie>
- Co się dzieje: <rzeczywiste objawy>
Dane:
- Fragment kodu: <code>
- Fragment logów: <logs>
- Konfiguracja / manifest: <config>
Zadania:
1) Wypisz 3-5 najbardziej prawdopodobnych hipotez przyczyny problemu. Przy każdej hipotezie wskaż linijki kodu / logu, które ją wspierają.
2) Zaproponuj minimalną poprawkę (patch lub pseudokod), która naprawiłaby najprawdopodobniejszą przyczynę.
3) Zaproponuj 2-3 dodatkowe testy (jednostkowe lub integracyjne), które pokryją ten przypadek na przyszłość.
Odpowiadaj zwięźle, bez ogólnych porad typu "sprawdź logi".
Taka struktura zmusza model do myślenia w kategoriach hipotez, a nie „jednej słusznej odpowiedzi”. To bliżej faktycznego procesu debugowania, jaki stosuje człowiek.
Dzielenie problemu na kroki: najpierw diagnoza, potem patch
Gdy prosisz LLM-a o wszystko naraz („znajdź błąd i napraw”), często dostajesz ładnie wyglądający patch, którego nikt nie potrafi wyjaśnić. Rozsądniej jest rozbić rozmowę na fazy, jak przy pracy z juniorem.
Jedna z prostszych sekwencji wygląda tak:
- Faza 1 – zrozumienie:
Najpierw wyjaśnij, co robi ten kod oraz jak rozumiesz błąd na podstawie logów. Nie proponuj jeszcze poprawek. Skup się na: - przepływie danych, - zależnościach między modułami, - miejscach, w których może dochodzić do błędu. - Faza 2 – hipotezy:
Na podstawie poprzedniego opisu podaj 3 hipotezy przyczyny błędu. Przy każdej hipotezie: - podaj dowody z kodu/logów, - wskaż brakujące informacje, które pomogłyby ją potwierdzić lub odrzucić. Jeszcze nie pisz kodu. - Faza 3 – rozwiązanie:
Załóżmy, że najbardziej prawdopodobna jest hipoteza X. Teraz: 1) zaproponuj konkretną zmianę w kodzie (patch), 2) opisz ryzyka uboczne tej zmiany, 3) zaproponuj testy/regresję.
Taka „rozmowa etapami” ma dodatkowy plus: możesz w każdej chwili powiedzieć „nie, ta hipoteza odpada, patrz nowe logi” i skorygować model, zamiast za każdym razem zaczynać od zera.
Jak podawać kod i logi, żeby model ich nie „ugotował”
Modele mają ograniczone okno kontekstu. Jeśli wkleisz im pełny plik z mikroserwisu, docker-compose, 300 linii logów i jeszcze kawałek dokumentacji, to często zaczną „przegapiać” istotne szczegóły. Lepiej podać mniej, ale wyselekcjonowane.
Kilka praktycznych zasad przy debugowaniu:
- zamiast całego pliku, wklej funkcję + najbliższe otoczenie (importy, definicje używanych struktur),
- z logów wybierz kilkanaście–kilkadziesiąt linii wokół pierwszego błędu – plus ewentualnie fragment poprawnego wykonania do porównania,
- konfigurację przytnij do sekcji powiązanych z problemem (np. tylko definicja jednego serwisu w Kubernetesie, a nie cały manifest klastra).
Pomaga też czytelne oznaczenie bloków kodu w promptach:
--- PLIK: src/payments/service.js ---
<tu kod>
--- KONIEC PLIKU ---
--- LOGI Z BACKENDU (czas: 2024-02-01 10:15-10:16) ---
<tu logi>
--- KONIEC LOGÓW ---
Dzięki takim separatorom model łatwiej „trzyma w głowie”, co jest czym, zamiast mieszać logi z kodem.
Ograniczanie halucynacji: każ modelowi podawać źródła swoich wniosków
Modele mają skłonność do wymyślania rzeczy, których w twoim kodzie po prostu nie ma. Można to mocno ograniczyć jednym prostym nawykiem: każ, żeby każde twierdzenie podpierał cytatem z kodu lub logów.
Przykładowy fragment promptu:
Przy każdej hipotezie lub twierdzeniu:
- zacytuj linijki kodu lub fragment logu, na których się opierasz,
- nie odwołuj się do nieistniejących plików, klas ani funkcji.
Jeśli brakuje ci informacji, napisz wprost, jakich danych potrzebujesz (np. "pokaż konfigurację X", "pokaż definicję klasy Y").
Jeżeli model zacznie opowiadać o konfiguracji, której nie masz, łatwiej to wychwycisz: brak cytatu to sygnał „coś tu pachnie spekulacją”. Z czasem można pójść dalej i wprowadzić wręcz check-listę:
- „Czy to twierdzenie wynika z kodu/logów, czy jest domysłem?”,
- „Jakie alternatywne wyjaśnienie jest równie prawdopodobne?”.
Da się to wręcz zahardkodować w promptach używanych w narzędziach zespołowych.
„Tryb konsultanta”: doprecyzowywanie zamiast jednorazowego strzału
Jednorazowy, ogromny prompt z całą historią problemu rzadko daje lepszy efekt niż kilka krótszych wymian. LLM dobrze sprawdza się jako konsultant „na żywo”: coś pokazujesz, dostajesz opinię, doprecyzowujesz, dokładasz dane.
Dobrym wzorcem jest sekwencja typu Q&A:
- Ty: podajesz minimalny, ale konkretny opis i dane.
- Model: odpowiada, ale na końcu wymienia 2–3 pytania, na które brak mu informacji.
- Ty: dostarczasz brakujące elementy lub odrzucasz błędne założenia.
Można to wymusić drobnym zapisem w promptach:
Na końcu odpowiedzi wypisz:
1) 2-3 najważniejsze pytania, na które nie masz danych,
2) co konkretnie mam ci pokazać (np. "stack trace wyjątku", "definicję tabeli users").
W praktyce rozmowa zaczyna przypominać rozmowę z kolegą z zespołu: „pokaż jeszcze konfigurację reverse proxy, bo coś tu mi nie pasuje”.
Wymuszanie formatu: tabelki, patche, checklisty
Kiedy nie narzucisz struktury odpowiedzi, model potrafi popłynąć w długi esej. Przy debugowaniu liczą się konkretne artefakty: diff, lista hipotez, kroki do odtworzenia błędu. Format da się kontrolować.
Kilka przydatnych schematów.
1. Patch w formacie diff:
Zaproponuj patch w formacie unified diff, tak żebym mógł go wkleić do `git apply`.
Nie tłumacz zmian w tekście, tylko:
1) najpierw krótki opis (3-4 zdania),
2) potem sam diff.
Użyj struktury:
Opis:
<opis>
Patch:
```diff
<diff>
```
2. Tabela hipotez z „pewnością”:
Przedstaw hipotezy w formie tabeli Markdown:
| # | Hipoteza przyczyny | Dowody z kodu/logów | Prawdopodobieństwo (niska/średnia/wysoka) | Jak zweryfikować? |
| - | ------------------ | ------------------- | ------------------------------------------ | ------------------ |
3. Checklista kroków diagnostycznych:
Na końcu odpowiedzi dodaj checklistę kroków diagnostycznych:
[ ] krok 1
[ ] krok 2
...
Kroki mają być weryfikowalne (np. "uruchom komendę X i wklej wynik").
Dzięki takim formatom łatwiej włączyć LLM-a w istniejące procesy: wrzucasz tabelkę do ticketu Jiry, patch do review, checklistę do playbooka incydentowego.
Prompty dla DevOpsa i SRE: incydenty, capacity i „brzydkie” środowiska
Debugowanie w operacjach rzadko dotyczy jednej linijki kodu. Częściej chodzi o połączenie wielu źródeł: metryk, logów, manifestów K8s, polityk sieciowych. Tutaj prompt musi jasno opisać, gdzie kończą się fakty, a gdzie zaczyna interpretacja.
Przykładowy szablon dla incydentu produkcyjnego:
Rola: Działasz jak SRE z doświadczeniem w systemach rozproszonych.
Cel: Zidentyfikować najbardziej prawdopodobną przyczynę incydentu i zaproponować działania doraźne (mitigation) oraz docelowe (fix).
Dane:
- Opis incydentu z punktu widzenia użytkownika: <opis>
- Oś czasu zdarzeń (deploy, zmiany konfigów, releasy): <timeline>
- Metryki (zagregowany opis): <metryki>
- Fragmenty logów z kluczowych serwisów: <logi>
- Manifesty K8s / configi usług (tylko powiązane z problemem): <config>
Zadanie:
1) Odtwórz spójną narrację "co się stało" w 5-8 punktach.
2) Wypisz 3 możliwe przyczyny incydentu (od najbardziej do najmniej prawdopodobnej), z odniesieniem do danych.
3) Zaproponuj:
- 2-3 działania doraźne do wdrożenia w ciągu <czas>,
- 2-3 działania docelowe (zmiany w architekturze/kodzie/obserwowalności).
4) Wypisz, jakich danych brakuje, żeby mieć 80% pewności.
W trybie capacity planningu lub problemów wydajnościowych można dołożyć osobną sekcję:
Na końcu dodaj:
- sekcję "Bottlenecks", gdzie wypunktujesz potencjalne wąskie gardła,
- sekcję "Experiments", z 3 eksperymentami (np. zmiana limitów, skalowanie, cache) do przetestowania.
Jeśli taki szablon stanie się standardem w zespole SRE, każdy incydent zaczyna wyglądać podobnie – łatwiej porównać sprawy między sobą i wyciągać wnioski.
Prompty dla code review: szukanie bugów zanim trafią na produkcję
LLM może pełnić funkcję „drugiego reviewera”, szczególnie przy prostszych PR-ach, gdzie senior zwykle tylko zerka, czy nic oczywistego nie wybuchnie. Kluczem jest, żeby nie robił randomowego refactoringu, tylko skupił się na ryzykach.
Konstrukcja promptu może wyglądać tak:
Najczęściej zadawane pytania (FAQ)
Jak konkretnie LLM-y pomagają w debugowaniu kodu?
LLM-y działają jak bardzo rozmowna „gumowa kaczka”, która dodatkowo rozumie stack trace, kod i logi. Możesz wkleić fragment błędnego kodu, stack trace i kawałek konfiguracji, a model wskaże prawdopodobną przyczynę, zasugeruje poprawki oraz dodatkowe logi lub asercje do dopisania. Zamiast samodzielnie żonglować dziesiątkami plików, łączysz je w jednym kontekście i „opowiadasz historię” błędu modelowi.
Dobrze dobrany prompt pozwala przejść od „co tu się w ogóle dzieje?” do kilku sensownych hipotez w kilkanaście minut. To nie zastępuje myślenia, ale mocno przyspiesza pierwszą fazę: lokalizację problemu i zrozumienie, jak różne elementy systemu składają się na obserwowany błąd.
Czy LLM-y faktycznie skracają czas debugowania w produkcji?
W rozproszonych systemach odpowiedź brzmi: bardzo często tak. Typowy scenariusz wygląda tak, że przy incydencie P1 ktoś ściąga próbkę logów z kilku serwisów, diff konfiguracji między wersjami i opisuje modelowi kontekst: objawy, ostatnie zmiany, kluczowe komponenty. LLM na tej podstawie generuje listę hipotez w kolejności od najbardziej do najmniej prawdopodobnych wraz z miejscami w kodzie lub konfiguracji do sprawdzenia.
Zespół nie traci godzin na ślepe przeklikiwanie się przez dashboardy, tylko szybko zawęża pole poszukiwań. Zdarza się, że po kilku minutach manualnej weryfikacji jednej z hipotez trafiasz w źródło problemu, zamiast męczyć się całą noc.
Do jakich zadań debugowych LLM-y nadają się najlepiej?
Modele językowe sprawdzają się tam, gdzie problem da się opisać tekstowo: w kodzie, logach, konfiguracji i dokumentacji. Bardzo dobrze radzą sobie z analizą stack trace’ów (szczególnie dla popularnych frameworków), wyjaśnianiem obcych modułów i zależności czy generowaniem listy potencjalnych przyczyn błędu wraz z proponowaną kolejnością sprawdzania.
Przykładowe użycia, które przynoszą szybki zwrot:
- diagnoza błędów HTTP 4xx/5xx na podstawie logów z kilku usług,
- opis architektury starego systemu na bazie struktury repozytorium i kluczowych plików,
- podpowiadanie, jakie dodatkowe metryki i logi dopisać, by lepiej łapać podobne bugi w przyszłości.
Jak bezpiecznie używać LLM-ów przy debugowaniu, żeby nie „nawinąć się” na halucynacje?
Trzeba założyć, że model zawsze coś odpowie, nawet gdy nie ma racji. Typowe pułapki to wymyślone flagi konfiguracyjne, nieistniejące parametry w API albo rozwiązania niepasujące do wersji używanego frameworka. Dlatego odpowiedź LLM-a traktuj jak hipotezę do weryfikacji, a nie jako gotowy „fix”.
Pomagają proste nawyki:
- proś o kilka alternatywnych wyjaśnień, a nie jedną „prawdę” („podaj 3 możliwe przyczyny i wskaż, co sprawdzić najpierw”),
- zawsze sprawdzaj w dokumentacji frameworka lub w kodzie, czy sugerowana flaga/metoda faktycznie istnieje,
- oddzielaj w promptcie wiedzę „pewną” (logi, stack trace, konfigurację) od przypuszczeń.
Czy LLM może pomóc zrozumieć duży, stary projekt przed debugowaniem?
Tak, i to często jest największa oszczędność czasu. Gdy przejmujesz duży monolit albo rozbudowany zestaw mikroserwisów, możesz wrzucić do modelu listę plików, strukturę katalogów, główne kontrolery, serwisy i pliki konfiguracyjne. LLM jest w stanie zbudować opis architektury: główne moduły, przepływy danych, miejsca wejścia i wyjścia.
Dzięki temu zamiast błądzić po repozytorium, szybciej wiesz, w której części kodu w ogóle szukać przyczyny błędu. To trochę jak rozmowa z doświadczonym członkiem zespołu, który robi ci ekspresowe oprowadzenie po systemie, zanim zaczniecie łatać konkretny bug.
Jak tworzyć skuteczne prompty do debugowania z użyciem LLM?
Dobry prompt do debugowania przypomina solidny zgłoszony ticket: musi mieć kontekst, objawy i dane. Zamiast pisać „nie działa, napraw”, lepiej jasno opisać środowisko, ostatnie zmiany i załączyć kluczowe fragmenty:
- stack trace lub komunikat błędu (z wersją języka/frameworka),
- istotne fragmenty kodu i konfiguracji,
- opis, co dokładnie próbowałeś zrobić i jaki był oczekiwany efekt.
Dobrze jest też zadać konkretne podpunkty, np.: „1) Podaj najbardziej prawdopodobną przyczynę. 2) Zaproponuj 2–3 sposoby naprawy. 3) Zaproponuj dodatkowe logi/asercje do dodania”. Model wtedy działa bardziej jak systematyczny asystent niż generator przypadkowych porad.
Czy LLM-y mogą zastąpić klasyczne narzędzia: logi, debuggery, profilery?
Nie. LLM-y opierają się na tym, co im podasz, więc bez logów, metryk i sensownej obserwowalności szybko trafiasz na ścianę. Debugger, profiler, centralne logowanie czy monitoring nadal są fundamentem. Model jedynie pomaga szybciej łączyć fakty i sugerować kierunek dalszych eksperymentów.
W praktyce najlepsze efekty przynosi połączenie obu światów: klasyczne narzędzia zbierają dane, a LLM pomaga je przesiać, zinterpretować i przełożyć na konkretny plan działania. To nie jest „zamiast”, tylko bardzo mocne „obok”.
Kluczowe Wnioski
- LLM‑y pełnią rolę „gumowej kaczki 2.0” – możesz im w szczegółach opowiedzieć problem, dorzucić kod, logi i konfigurację, a one nie tylko „słuchają”, ale też aktywnie podsuwają hipotezy.
- Klasyczne narzędzia debugowania (logi, debuggery, profilery) nie nadążają za złożonością mikroserwisów, chmury i feature flag – pojedynczy człowiek nie jest już w stanie ogarnąć całego obrazu pod presją czasu.
- Dla LLM‑a kod, logi, stack trace’y, YAML/JSON czy dokumentacja to po prostu tekst, który można wspólnie analizować w jednym kontekście, łącząc ze sobą pozornie oderwane fakty.
- Największa przewaga LLM‑ów to drastyczne skrócenie drogi od błędu do pierwszej sensownej hipotezy – zamiast godzin szukania „igły w stogu logów” masz kilka konkretnych tropów do szybkiej weryfikacji.
- Modele dobrze sprawdzają się w zadaniach tekstowych: diagnozują błędy ze stack trace’ów, tłumaczą je „po ludzku”, wskazują prawdziwe źródło problemu i rozpoznają typowe wpadki związane z danym frameworkiem.
- Dla devów i DevOpsów LLM‑y są wsparciem w nudnych, powtarzalnych czynnościach (generowanie obsługi błędów, parserów logów, zapytań), a jednocześnie pomagają szybciej wejść w obcy, stary lub słabo udokumentowany system.






