W pracy z systemami rozproszonymi początek nowego projektu zwykle bywał żmudny. Wymagał przechodzenia przez wiele iteracji, dokładania kolejnych rozwiązań na różnych etapach oraz ciągłego poprawiania i przepisywania kodu. Każdy kolejny krok trzeba było okupić cierpliwością i czasem. Taki tryb pracy co prawda dawał kontrolę nad tworzonym systemem, lecz sprawiał też, że rozwój ciągnął się niemiłosiernie i brakowało w nim spontaniczności.

Kiedy w naszym świecie pojawiło się powszechnie dostępne AI, zacząłem eksperymentować z jego wykorzystaniem w codziennych projektach. Na początku traktowałem je jedynie jako coś w rodzaju konsultanta i generatora prostych fragmentów kodu – takiego podpowiadacza, który usprawniał codzienną pracę.

Z czasem współpraca z asystentem AI stała się dla mnie czymś naturalnym. Ostatnie miesiące pokazały przy tym, że AI potrafi być czymś więcej niż tylko podpowiadaczem kodu. Widziałem na własne oczy, jak inni wykorzystują je do generowania snippetów czy automatyzacji nużących zadań.

Pomyślałem wtedy: a co, jeśli da się z AI poprowadzić cały proces – od pierwszej myśli, przez szkic architektury, aż po działający system? Nie jako „narzędzie”, ale jako partnera do rozmowy i wspólnego projektowania.

W ten sposób narodził się eksperyment z nowym podejściem. Nie chodziło w nim o osiągnięcie perfekcji ani o to, by AI napisała za mnie całą aplikację. Liczył się flow – iteracja, możliwość zmiany kierunku w trakcie prac, swoboda eksperymentowania. Zamiast spędzać tygodnie na mozolnym dopieszczaniu kolejnych etapów projektu, chciałem jak najszybciej przejść od pomysłu do działającego kodu – i po prostu sprawdzić, czy to w ogóle działa.

I właśnie w ten sposób powstały moje pierwsze projekty tworzone w dużej mierze w oparciu o agentów AI. Ich historia najlepiej pokazuje, czym tak naprawdę vibe coding różni się od klasycznych metod tworzenia oprogramowania.

Wszystko zaczęło się od prostego pytania, które wpisałem do czatu:

„Chciałbym wdrożyć obsługę AI do naszych logów, jeśli chodzi o błędy i ich analizę + ewentualne poprawki. Mamy stream logów około 1000/min z jednego źródła – czy ma sens robić to przez OpenAI pod względem kosztów?”

To właśnie ten prompt zapoczątkował całą drogę. Z pozoru zwykłe pytanie o koszty okazało się punktem wyjścia do projektu, który później przekształcił się w narzędzie o nazwie Sherlog. Przy okazji, zupełnie niespodziewanie, cały ten proces pokazał mi, na czym tak naprawdę polega vibe coding.

Projektowanie z AI zamiast klasycznej specyfikacji

Na pierwszy rzut oka wszystko w tym projekcie wyglądało znajomo. Problem, który chciałem rozwiązać, był typowy dla dużych systemów: logi – mnóstwo logów, zbieranych z różnych klastrów i centrów danych. Do tego trzeba było je nie tylko przetwarzać, ale też rozumieć – wyciągać z nich wzorce, łączyć w klastry, a najlepiej zasugerować, co w kodzie powinno zostać poprawione. W klasycznym podejściu usiadłbym do specyfikacji, rozpisał moduły, API, zależności. Tym razem zrobiłem coś innego.

Zamiast mozolnego projektowania systemu w pojedynkę, postanowiłem rozpocząć rozmowę z GPT – potraktować AI jak partnera do burzy mózgów od pierwszych kroków projektu. Mając w głowie jedynie ogólny cel, dopytywałem asystenta, jak zrealizować system spełniający te założenia. Otrzymywane wskazówki nie przypominały klasycznej, sztywnej specyfikacji technicznej – były to raczej luźne notatki i pomysły, które dopiero z czasem układały się w spójny plan.

W trakcie tego dialogu pytałem AI o różne kluczowe aspekty projektu. Dociekałem, jak zapanować nad kosztami korzystania z modeli LLM oraz jak poradzić sobie z potencjalnymi wyścigami między pollerami. Zastanawiałem się nawet, czy w ogóle warto zaczynać od klasycznej deduplikacji logów. Każda odpowiedź zamiast zamykać temat otwierała przede mną kolejne drzwi, prowadząc do nowych pomysłów i rozwiązań. W ten sposób powstał dokument (nazwijmy go spec.md), który nie stanowił żadnego ostatecznego „wyroku”, a jedynie solidny punkt startowy do dalszych prac. Dopiero po fakcie natknąłem się na określenie vibe coding i uświadomiłem sobie, że właśnie taką metodą tworzyłem Sherloga.

Pivot 1: Normalizacja logów – od regexów do Drain3

Pierwsze zderzenie z rzeczywistością nastąpiło na etapie normalizacji logów. Razem z agentem AI zaprojektowaliśmy początkowo mechanizm oparty na wyrażeniach regularnych. W końcu „tak robi się to od lat” – dopasowania, zamiany, klasyczne regexy, które każdy programista zna aż za dobrze. Niestety, okazało się, że nawet wiele zdefiniowanych wzorców nie wystarczało, bo niemal każdy nowy log wymykał się tym regułom i wymagał dopisywania kolejnych wyjątków. Logi były po prostu zbyt różnorodne – różniły się nie tylko wartościami, ale i strukturą. Regexów przybywało lawinowo – rosły jak kula śnieżna – a ja wiedziałem, że za chwilę po prostu utonę w tym podejściu.

Korzystając z wcześniejszych doświadczeń, przeprowadziłem razem z AI małe dochodzenie, jak inaczej podejść do tematu normalizacji. Tak natrafiliśmy na rozwiązanie o nazwie Drain3. Szczerze mówiąc, sam prawdopodobnie bym na nie nie wpadł – to AI podsunęło mi ten trop, a potem krok po kroku wyjaśniło, że Drain3 to nie zwykły parser, lecz heurystyczny model online learning, który potrafi uczyć się szablonów logów w locie. Brzmiało to jak coś zupełnie innego niż kaskada regexów, w której właśnie tonąłem. Gdyby nie to wsparcie, pewnie dalej brnąłbym w gąszczu wyrażeń regularnych. Po przeniesieniu pomysłu do kodu i wykonaniu pierwszych testów stało się coś niesamowitego – logi zaczęły same układać się w powtarzalne schematy. Regexy wylądowały w koszu, a normalizacja stała się częścią przepływu, której nie musiałem już ręcznie doglądać.

Był to pierwszy pivot w projekcie Sherlog, ale jak się wkrótce okazało – nie ostatni.

Pivot 2: Semantyka logów – embeddingi i optymalizacja

Kolejnym wyzwaniem okazała się semantyka – czyli wprowadzenie tzw. embeddingów (wektorowych reprezentacji) logów. Potrzebowałem osadzić logi w przestrzeni wektorowej, żeby grupować je nie tylko według identycznego hash’u czy szablonu z Drain3, ale także wtedy, gdy różne szablony w praktyce opisywały ten sam błąd. Inspiracją był tu film o Embedding Gemma, lecz szybko wyszło na jaw, że użyty tam model ma zbyt mały kontekst dla naszych potrzeb. Poprosiłem więc AI o rekomendację innego modelu – propozycja nie była optymalna, więc dopiero trzecia iteracja dała wreszcie sensowne rezultaty.

I znów okazało się, że sam prawdopodobnie brnąłbym w ślepy zaułek, a to AI wskazało mi właściwy kierunek i pomogło znaleźć rozwiązanie. Jednak decyzja o użyciu embeddingów otworzyła przede mną kolejne problemy. Początkowo generowanie wektorów odbywało się w tym samym strumieniu co normalizacja, więc każdy log blokował główną kolejkę na kilka cennych sekund. Musiałem więc wydzielić proces embeddingu do osobnej kolejki i wprowadzić mechanizm deduplikacji, aby nie tworzyć wielokrotnie tej samej reprezentacji dla identycznych wpisów. Był to kolejny pivot – i kolejny dowód na to, że vibe coding to nie tylko samo pisanie kodu, ale ciągły dialog i wspólne odkrywanie, jak system powinien działać.

Pivot 3: Sink – prostota zamiast złożonych locków

Kolejnym problemem okazała się obsługa wielu równolegle działających pollerów. Pojawił się klasyczny dylemat systemów rozproszonych: co, jeśli dwa procesy pobiorą ten same log i spróbują przetworzyć go jednocześnie? Asystent AI zaczął proponować tu istną rakietę do lotu na drugie piętro – wymyślał skomplikowane mechanizmy: locki na różnych poziomach (na zdarzeniach, na szablonach), a nawet semantyczne blokady bazujące na embeddingach, które miały chronić przed tworzeniem bliźniaczych klastrów błędów. Technicznie dałoby się to wszystko zaimplementować, ale czułem, że wpadam w pułapkę over-engineeringu.

I wtedy pomyślałem: a może wcale nie trzeba tego wszystkiego? Może wystarczy zrobić krok wstecz i – zamiast rozwiązywać każdy wyścig z osobna – sprawić po prostu, by wyścigów w ogóle nie było? Tak narodził się pomysł sinka. Poszczególne pollery nadal działały niezależnie, zbierając logi z różnych źródeł, ale wszystkie odkładały wyniki do jednej wspólnej kolejki. Z tej kolejki logi były następnie przetwarzane sekwencyjnie, jeden po drugim, już synchronicznie i bez szans na wyścig. Go channels okazał się w zupełności wystarczający. Prosta kolejka w pamięci, a za nią jeden procesor single-thread, który spokojnie "kroplował" logi do pipeline’u.

Ta zmiana diametralnie uprościła architekturę całego rozwiązania. Cała skomplikowana maszyneria blokad przestała być potrzebna. W efekcie powstał prosty, liniowy pipeline przetwarzania logów: najpierw Drain3 do ich normalizacji, potem generowanie embeddingów w osobnej kolejce, następnie clustering (grupowanie) w bazie wektorowej Qdrant, a na końcu triggery, czy warto angażować do dalszej analizy duży model LLM. Ten duży model LLM nie zajmował się jednak bezpośrednią analizą logu, lecz tłumaczył go na zrozumiałe polecenie dla kolejnego agenta – Codex (lub alternatywnie Claude Code). Ten agent zaglądał już w realny kod źródłowy, szukał potencjalnych przyczyn błędu i sugerował poprawki.

Co ważne, cały proces nie kończył się na wyświetleniu wyników w konsoli. Wszystkie informacje zbierane były w formie przejrzystego raportu, który można było na spokojnie przejrzeć, zweryfikować i zdecydować, co dalej zrobić z takimi danymi. Dodatkowo zadbałem o to, by system nie marnował zasobów. Powtarzające się logi i tak trafiały do tego samego klastra błędów, a mechanizm cooldown per klaster sprawiał, że nie generowaliśmy podwójnych analiz ani niepotrzebnych kosztów. W efekcie pełna analiza każdego błędu przechodziła cały cykl – od surowego logu, poprzez wnioskowanie semantyczne, aż do faktycznej propozycji zmiany w kodzie – i wszystko to w możliwie zoptymalizowany sposób.

Lekcje i obserwacje z vibe codingu w Sherlogu

  1. Od ślepych uliczek do prostych rozwiązań

Na tym etapie podejście vibe coding pokazało zarówno swoją moc, jak i pewne ograniczenia. Początkowy plan oparty na regexach i lockach prawdopodobnie rozrósłby się do architektury bardzo trudnej w utrzymaniu. Iteracyjne eksperymenty z AI prowadziły mnie co prawda od jednej ślepej uliczki do kolejnej, ale każda z nich była potrzebna, by ostatecznie znaleźć prostsze i bardziej eleganckie rozwiązanie. Nie było tu mowy o rysowaniu perfekcyjnej architektury na tablicy jeszcze przed startem prac – to była raczej podróż od wyjściowej potrzeby, przez wspólnie z AI spisaną specyfikację, aż po działające MVP rozwiązujące realny problem.

  1. Doświadczenie i know-how w erze AI

Choć vibe coding potrafi znacząco przyspieszyć tworzenie oprogramowania, nie oznacza to, że każdy, kto uruchomi edytor i podłączy się do AI, z miejsca stanie się pełnoprawnym inżynierem. Taka metoda wymaga solidnego know-how: znajomości narzędzi, świadomości kosztów działania modeli oraz umiejętności wydobycia z AI przydatnych informacji. To nie jest magiczna sztuczka ani „droga na skróty” dla laików – to raczej nowy styl pracy, który może dać przewagę doświadczonym deweloperom, przyspieszając rozwój systemów, ale tylko pod warunkiem, że potrafią oni odróżnić ślepe uliczki od pomysłów z potencjałem.

  1. Znaczenie audytu i utrzymania jakości

Do tego dochodzi konieczność regularnego audytu tworzonego w ten sposób kodu. Nawet jeśli kod pisany metodą vibe coding powstaje szybko i sprawnie, nie zwalnia to nas z obowiązku kontrolowania jakości. Należy na bieżąco sprawdzać powtarzające się wzorce, wyłapywać potencjalnie błędne praktyki i korygować kurs rozwoju, tak aby nie utonąć w długu technologicznym. AI potrafi odciążyć nas od żmudnych zadań, ale nie zdejmie z nas odpowiedzialności za ostateczny kształt i jakość kodu.

  1. Testy – z mozolnego obowiązku do dynamicznej automatyzacji

Tradycyjnie każda większa zmiana architektury oznacza godziny lub nawet dni poprawiania testów jednostkowych i integracyjnych. W moim eksperymencie było inaczej – AI okazała się nieocenionym wsparciem także na tym polu. Asystent potrafił nie tylko wygenerować scenariusze testowe na podstawie logiki aplikacji, ale również błyskawicznie je dostosować, gdy zmieniała się struktura kodu. Zamiast mozolnie aktualizować dziesiątki plików testów po każdej dużej modyfikacji, mogłem po prostu poprosić AI o ich dostosowanie do nowej architektury – i w kilka minut otrzymywałem kompletny, działający zestaw. Testy przestały być dzięki temu uciążliwym balastem, a stały się naturalną częścią procesu – równie dynamiczną i elastyczną jak sam kod.

  1. Codex vs Claude – który lepszy partner?

W trakcie eksperymentu mogłem porównać w działaniu modele Codex (OpenAI) i Claude Code (Anthropic). Codex sprawdzał się dobrze na starcie projektu i przy mniejszych zadaniach, ale przy większych refaktoryzacjach miewał tendencję do zapętlania się i nie domykał rozpoczętych wątków. Claude z kolei lepiej rozumiał szerszy kontekst i potrafił skuteczniej rozwijać kod w dłuższej perspektywie, dlatego to on ostatecznie stał się moim głównym partnerem w vibe codingu.

Podsumowanie – Sherlog jako przykład vibe codingu

Po kilku miesiącach pracy tą metodą mogę powiedzieć, że mam już na koncie dwa projekty ukończone w stylu vibe coding, a trzeci – całkiem ambitny – jest w toku. Takie podejście sprawiło, że jako pojedynczy deweloper byłem w stanie przejąć zadania, które zwykle rozdziela się na cały zespół. Nie dlatego, że czyjaś rola staje się zbędna, ale dlatego, że AI w roli partnera pozwala błyskawicznie przechodzić od pomysłu do działającego kodu. AI to dla mnie multiplikator, a nie zamiennik – daje pojedynczej osobie możliwość objęcia szerszego spektrum prac, uwypuklając zarazem, jak ważne pozostaje doświadczenie i świadome decyzje przy prowadzeniu projektu.

Najlepszym przykładem możliwości vibe codingu pozostaje jednak właśnie projekt Sherlog. Przeszedł on długą drogę pivotów: od regexów do Drain3, od rozproszonych locków do prostego sinka, od przekombinowanych pomysłów do spokojnego MVP, które można wdrożyć i rozwijać. Najważniejsze w tym wszystkim nie było jednak to, że „udało się napisać kod”, ale to, jak zmienił się sam proces myślenia i rozwiązywania problemów.

Więcej – dzięki agentom AI żmudne, długie refaktoryzacje sprowadzają się dziś do tego, że większość pracy wykonuje sztuczna inteligencja, a my, jako nadzorcy, dbamy jedynie o to, by kod spełniał nasze oczekiwania. Przy okazji możemy nauczyć się czegoś nowego i dostarczyć produkt kompletny, przetestowany oraz gotowy do wdrożenia w ciągu tygodni – zamiast miesięcy.

Poza samymi agentami odkryłem też, że ogromną wartość ma prowadzenie konsultacji w dłuższych wątkach na czacie – czasem w jednym, czasem w kilku równoległych. Takie podejście ułatwia podsumowania, powroty do wcześniejszych decyzji i budowanie z nich czegoś większego, na przykład fundamentów pod tekst, który właśnie przeczytaliście.

I to właśnie jest vibe coding.

Autorem tekstu jest Paweł Babilas.