Kontekst
Buduję dwupoziomowy system konsultacji AI dla mojej strony freelancerskiej. Darmowy bot (Claude Haiku) kwalifikuje leady w 8 wymianach, premium (Claude Opus) daje pogłębioną analizę techniczną za 200 zł. Cały system — od pustego repo do działającego produktu — powstał w jeden dzień.
Ten artykuł nie jest o architekturze systemu (o tym pisałem tutaj). Ten artykuł jest o tym, czego nie widać w dokumentacji technicznej: o iteracyjnym procesie dopracowywania promptów, o eksperymencie, który się nie udał, i o lekcjach z tego wyciągniętych.
Faza 1: MVP działa, ale bot ma problemy z tożsamością
Pierwszy prompt był prosty: “Jesteś asystentem Artura Mrowickiego, przeprowadź kwalifikację BANT.” Bot działał — zadawał pytania, zbierał dane. Ale pierwsze testy ujawniły coś nieprzyjemnego:
Bot mówił “ja realizuję projekty”, “moja architektura”, “mogę Ci pomóc”. Klient rozmawiał z botem myśląc, że rozmawia ze mną. To nie tyle problem techniczny, co problem zaufania — gdy klient się zorientuje, poczuje się oszukany.
Commit c8c8bee: bot identity — separate AI entity, never impersonate Artur.
Dodałem pierwszą regułę tożsamości: “Jesteś ODDZIELNYM bytem AI. NIGDY nie mów w pierwszej osobie jako Artur.” Problem rozwiązany. Ale to był dopiero początek.
Faza 2: Kaskada poprawek — jeden test, pięć bugów
Przeprowadziłem pełny test rozmowy, udając wymagającego klienta technicznego. Wynik: bot zebrał dane, ale po drodze:
- Przyjął email w czacie — napisał “zarejestrowuję Twój email”. Nie ma takiej funkcji. Formularz kontaktowy wyświetla się dopiero po rozmowie.
- Obiecał czas odpowiedzi — “Artur odezwie się dziś wieczorem”. Jedyny termin, który mogę obiecać, to 48 godzin.
- Wymyślił funkcje systemu — wspomniał o “ticketach”, “kolejce zgłoszeń”, “czacie asynchronicznym z Arturem”. Nic z tego nie istnieje.
- Mieszał języki — “deadline”, “scope”, “track record”, “low-overhead approach”. W rozmowie po polsku brzmi to nieprofesjonalnie.
- Wymyślał doświadczenia — podał konkretne technologie, z którymi “Artur pracował”, nie mając o tym informacji.
Pięć problemów, pięć nowych reguł. Prompt rozrósł się z 6 do 15 zasad.
Commit 003a9c0: harden bot prompts — no fake promises, no email acceptance, no invented features.
Każda reguła była odpowiedzią na konkretny błąd. Każda miała sens w izolacji. Problem? 15 reguł to dużo dla Haiku — model zaczął gubić kontekst i stosował reguły niespójnie.
Faza 3: Problemy z podsumowaniem
Bot prowadził rozmowę poprawnie, ale podsumowanie JSON — generowane po zakończeniu — miało własne problemy:
- Hallucynowane SLA: bot napisał “odpowiedź w ciągu 24 godzin”, choć w rozmowie nikt tego nie ustalił.
- Brakujące technologie: klient wspomniał o Istio i mTLS, a podsumowanie je pominęło.
- Polglish w podsumowaniu: “low-overhead approach”, “direct communication” — mimo że prompt czatu wymuszał polszczyznę, prompt podsumowania tego nie robił.
- Email klienta w podsumowaniu: klient podał email w czacie (mimo reguły zakazującej), a podsumowanie go wyciągnęło i wysłało klientowi. Email powinien być widoczny tylko dla mnie.
Commit ce022df: harden summary prompts — no hallucinated SLA, no polglish, complete tech extraction.
Dodałem cztery nowe reguły do promptu podsumowania: wymuszenie języka, zakaz wymyślania ustaleń, pełna ekstrakcja technologii, pole wewnętrzne _client_contact. To zadziałało. Ale odkryło głębszy problem.
Faza 4: Eksperyment z Gemini — i dlaczego się nie udał
Haiku miał jeden fundamentalny problem: polszczyzna. Nie chodziło o gramatykę — zdania były poprawne. Chodziło o naturalność. Bot brzmiał jak przetłumaczony z angielskiego. Wtrącał anglicyzmy mimo 15-punktowej listy zakazanych słów. Klient to czuje.
Pomysł: a gdyby zamienić Haiku na Gemini 3 Flash? Google trenował modele na większym korpusie polskich danych. Może polska jakość będzie lepsza?
Commit fe01dd1: switch free chat from Claude Haiku to Gemini 3 Flash.
Zamiana modelu wymagała:
- Nowego SDK (
@google/genai) - Innego formatu wiadomości (
role: 'model'zamiast'assistant',parts: [{ text }]zamiastcontent) - Innego API (
ai.models.generateContent()zamiastanthropic.messages.create()) - Konfiguracji myślenia (
thinkingConfig: { thinkingLevel: 'low' })
Pierwszy test był obiecujący. Polszczyzna Gemini była naturalniejsza, płynniejsza, bez anglicyzmów. Ale pojawiły się nowe problemy.
Iteracja 1: Gemini wymyśla doświadczenia Artura
Gemini odpowiedział klientowi: “Artur w procesie diagnozy wąskich gardeł stawia na obserwowalność bez ingerencji w kod źródłowy, wykorzystując narzędzia oparte na eBPF.”
Brzmi profesjonalnie. Problem? Nie mam pojęcia, czy Artur kiedykolwiek używał eBPF. Gemini wymyślił to na podstawie kontekstu rozmowy, nie na podstawie faktów.
Commit 97fac69: strengthen anti-hallucination rules — no invented tools/methods.
Dodałem regułę: “Jeśli nie wiesz, czy Artur pracował z daną technologią, powiedz wprost: Nie mam tej informacji.”
Iteracja 2: Gemini jest zbyt pasywny
Po dodaniu reguły anti-hallucynacji bot zaczął odpowiadać na wszystko: “Nie mam tej informacji. Artur odpowie osobiście.” Na 8 wymian, 6 kończyło się tym samym zdaniem. Bot przestał być użyteczny — klient nie dowiadywał się niczego, a ja dostawałem puste podsumowania.
Commit 5b8b003: make bot actively dig into client problems instead of repeating “I don’t know”.
Dodałem instrukcję aktywnego drążenia: zamiast mówić “nie wiem”, bot ma pytać głębiej o problem klienta. Ale to stworzyło kolejny problem.
Iteracja 3: Gemini zamyka rozmowę po swoim pytaniu
Bot zadał pytanie, klient nie odpowiedział, bot sam zamknął rozmowę po jednej wymianie. Marker [ZAKOŃCZ] pojawiał się za wcześnie, formularz kontaktowy wyskakiwał po drugiej wiadomości.
Commit 5b8b003 (ta sama sesja): two-stage closing procedure.
Dodałem dwuetapowe zamykanie: bot musi najpierw zapytać “Czy jest coś jeszcze?”, i dopiero po potwierdzeniu klienta może dodać marker.
Iteracja 4: Za sztywno vs. za luźno
Po trzech rundach poprawek bot był albo za sztywny (odmawiał odpowiedzi na pytania techniczne), albo za luźny (wymyślał doświadczenia). Nie mogłem znaleźć złotego środka w ramach promptu.
Commit fcd0937: balanced bot approach — share industry knowledge, don’t attribute to Artur.
Próba kompromisu: bot może dzielić się wiedzą branżową (“zazwyczaj stosuje się X”), ale nie może przypisywać jej Arturowi. Działało w teorii. W praktyce Gemini wciąż miał tendencję do tworzenia narratywu, w którym “Artur zazwyczaj stosuje” brzmiało jak “Artur robi”.
Faza 5: Revert — akceptacja ograniczeń
Po czterech iteracjach prompt Gemini miał więcej reguł niż prompt Haiku. Każda poprawka rozwiązywała jeden problem, ale tworzyła nowy. Klasyczna pętla overcorrection:
za luźno → dodaj regułę → za sztywno → poluzuj regułę → za luźno (w innym miejscu)
Decyzja: pełny revert do stanu sprzed Gemini.
Commit 00e293e: revert — restore free chat to Claude Haiku, remove Gemini.
Usunąłem @google/genai z zależności, przywróciłem chat-free.ts na Haiku, przywróciłem oryginalne prompty. 4 commity pracy — do kosza.
Dlaczego revert był właściwą decyzją
Haiku ma gorszy polski. Ale:
- Lepiej trzyma się reguł (mniej hallucynacji)
- Nie wymyśla doświadczeń
- Jest przewidywalny
Gemini ma lepszy polski. Ale:
- Hallucynuje doświadczenia mimo reguł zakazujących
- Jest “kreatywny” tam, gdzie powinien być sztywny
- Wymaga więcej reguł, żeby zachowywał się poprawnie — a więcej reguł = gorsza adherencja
Gorszy polski jest mniejszym problemem niż wymyślone doświadczenia. Klient wybaczy anglicyzm. Nie wybaczy kłamstwa o kompetencjach.
Faza 6: Mniej reguł, więcej swobody
Po revercie spojrzałem na prompt z dystansem. 15 reguł — wiele się powtarzało lub było zbyt rozwlekłych. Zamiast dodawać kolejne, uszczupliłem:
Commit a6477b4: refactor — slim down free bot prompts — 15 rules to 10.
Kluczowe zmiany:
- Połączyłem reguły, które się powtarzały (np. “nie zgaduj” + “nie wymyślaj doświadczeń” → jedna reguła o merytorycznej swobodzie)
- Usunąłem zbyt szczegółowe skrypty (verbatim odpowiedź na niski budżet, lista 30 zakazanych angielskich słów)
- Dodałem disclaimer: “Ta rozmowa ma na celu przyśpieszyć proces realizacji. Ustalenia techniczne będą weryfikowane przez Artura.”
Ten disclaimer zmienił wszystko. Bot mógł teraz mówić “zazwyczaj w takich przypadkach stosuje się X” bez obawy, że klient potraktuje to jako obietnicę. Bo disclaimer jasno mówił: to wstępna rozmowa, Artur zweryfikuje.
Trzy nowe zasady zamiast piętnastu starych
-
Budżet: pytaj raz, potem odpuść. Zamiast forsować konkretną kwotę, akceptuj “stawki eksperckie” i idź dalej. Klient, który odmawia podania budżetu, i tak go nie poda po trzecim pytaniu.
-
Pilność: traktuj poważnie, ale nie obiecuj. Zamiast ignorować “pożar na produkcji” i odpowiadać standardowym 48h, bot zaznacza priorytet i mówi: “Artur widzi priorytet i czasem reaguje szybciej w sytuacjach awaryjnych.”
-
Swoboda techniczna z disclaimerem. Bot może dzielić się wiedzą, proponować kierunki, nazywać narzędzia. Ale nie może wymyślać konkretnych projektów Artura.
Prompt skurczył się o 40%. Haiku lepiej go trzymał.
Faza 7: Formularz pilny z Telegramem
Ostatnia lekcja z testów: bot, który rozpoznaje pilność, ale nic z nią nie robi, frustruje klienta. “Widzę, że sprawa pilna. Artur odezwie się w ciągu 48 godzin.” — to brzmi jak kpina, gdy komuś leży produkcja.
Rozwiązanie: dwa markery zakończenia zamiast jednego.
Commit e9af61a: urgent contact form with Telegram notification.
- Bot używa
[ZAKOŃCZ_PILNE]zamiast[ZAKOŃCZ], gdy rozpoznaje sytuację awaryjną - Frontend pokazuje inny formularz: email + telefon (oba wymagane), czerwony przycisk
- Formularz wysyła powiadomienie na Telegrama z pełnym podsumowaniem
- Komunikat: “Artur zwykle odzywa się w ciągu godziny. Jeśli nie — standardowo w ciągu 48h.”
Bot nie obiecuje szybszej reakcji. Mówi “zwykle” — bo czasem faktycznie reaguję szybciej na pilne sprawy. A Telegram sprawia, że dowiaduję się natychmiast, nie po 2 godzinach od sprawdzenia maila.
Wnioski z procesu
1. Overcorrection jest prawdziwym problemem
Każda reguła w prompcie ma koszt. Nie tylko w tokenach — w adherencji modelu. 15 reguł to za dużo. Model zaczyna je interpretować selektywnie, łączyć, ignorować. 10 dobrze napisanych reguł działa lepiej niż 15 rozwlekłych.
2. Zmiana modelu nie rozwiązuje problemów z promptem
Gemini miał lepszy polski, ale wymagał więcej reguł do kontrolowania hallucynacji. Haiku miał gorszy polski, ale był bardziej posłuszny. Zmiana modelu przeniosła problem z jednego miejsca w inne — nie rozwiązała go.
3. Revert to nie porażka
4 commity pracy trafiły do kosza. Ale wiedza z nich nie zniknęła. Wiem teraz, że Gemini hallucynuje doświadczenia, że overcorrection tworzy pętle, że disclaimer “ustalenia będą weryfikowane” jest lepszy niż lista 15 zakazów. Tej wiedzy nie miałbym bez eksperymentu.
4. Disclaimer > zakaz
“Nie wymyślaj doświadczeń Artura” to zakaz. Model próbuje go obejść. “Ustalenia techniczne będą weryfikowane przez Artura” to kontekst. Model go przyjmuje. Zamiast mówić “czego nie robić”, lepiej powiedzieć “w jakim kontekście działasz”.
5. Feature na końcu, nie na początku
Formularz pilny z Telegramem to ostatni commit, nie pierwszy. Gdybym zaczął od niego, nie wiedziałbym, że bot potrzebuje swobody technicznej, żeby w ogóle rozpoznać pilność. Najpierw napraw fundamenty (tożsamość, reguły, ton), potem dodawaj feature’y.
Linia czasu (git log)
1a99878 Initial commit — arturmrowicki.pl
4657ef3 feat: two-tier consultation system
c8c8bee fix: bot identity — never impersonate Artur
7dc3199 fix: no polglish, no guessing, Artur decides
003a9c0 fix: no fake promises, no email acceptance
ce022df fix: harden summary prompts
fe01dd1 feat: switch to Gemini 3 Flash ← eksperyment
97fac69 fix: anti-hallucination for Gemini ← iteracja 1
5b8b003 fix: active digging, not "I don't know" ← iteracja 2
fcd0937 fix: balanced approach ← iteracja 3
0dcdc7f revert: restore prompts ← revert
00e293e revert: remove Gemini, back to Haiku ← pełny revert
a6477b4 refactor: 15 rules → 10, more freedom ← przełom
e9af61a feat: urgent form + Telegram ← feature
36 commitów. 4 z nich w koszu. Ale system, który z tego wyszedł, jest lepszy niż gdybym trafił za pierwszym razem — bo wiem dlaczego każda decyzja jest taka, a nie inna.
Chcesz zobaczyć, jak bot działa? Porozmawiaj z nim — jest dostępny 24/7.