Model językowy pisze poprawny kod. To nie jest ironia — naprawdę pisze. Problem polega na tym, że „poprawny” i „działający na produkcji przez rok” to dwie różne rzeczy, a różnica między nimi nie mieści się w składni.
Poniżej dziesięć przypadków z naszych własnych projektów. Każdy wystąpił naprawdę, każdy wygląda w kodzie sensownie i każdy przeszedłby przegląd osoby, która nie widziała jeszcze, jak to samo się psuje.
1. Cache, który zjadł dysk
Trasa catch-all pod filtry katalogu cache’owała każdą permutację adresu podaną przez crawlera. Cache urósł do 38 GB w 1 395 316 plikach, dysk serwera doszedł do stu procent i położył pięć usług: API jednej aplikacji na sześć godzin, silnik automatyzacji, statystyki, bazę PostgreSQL i trzy jednostki systemd.
Kod był poprawny. Problem powstaje po tygodniach, przy ruchu bota, w warstwie zapisywalnej kontenera — nie widać go ani w przeglądzie kodu, ani w testach. Naprawa poszła celowanym find -delete z wnętrza kontenera, bez przestoju: rm -rf całego katalogu zabiłby trasę, bo obok cache leżą artefakty builda.
2. Nazwa pliku, która była szablonem
W tym samym cache leżał plik o dosłownej nazwie ${encodeURIComponent(e.slug)}.html. Niezinterpolowany szablon łańcucha, który stał się realnym adresem URL.
Składnia poprawna, TypeScript nie protestuje, strona się buduje. Zobaczyliśmy to dopiero przy przeglądaniu zawartości cache po awarii z punktu pierwszego.
3. Nagranie, którego model nigdy nie usłyszał
Nagranie .m4a z telefonu szło prosto do modelu transkrypcji. Model czyta pliki przez libsndfile, które nie zna AAC — notatka powstawała bez treści nagrania.
Kod „działa”: nie ma wyjątku, jest pusty wynik. A model chętnie napisze tekst „na temat” pliku, którego nie przeczytał. Naprawa: ffmpeg w obrazie, przekodowanie na 16 kHz mono, cięcie na segmenty i jawny zakaz zgadywania treści w prompcie.
4. Dwa razy ta sama strona skanu
Załączniki dopasowywane po nazwie pliku. Telefon wysyła każde zdjęcie jako image.jpg, więc dwie strony skanu dawały dwie kopie pierwszej strony.
Wygląda rozsądnie: find(a => a.name === p.name). Błąd widać tylko na realnych danych z telefonu. Naprawa: dopasowanie po indeksie plus numeracja [i/N] w prompcie.
5. Sklep w Zatoce Gwinejskiej
Panel treści zapisuje brak współrzędnej jako 0, a lat: 0, lng: 0 to punkt na Atlantyku u wybrzeży Afryki. Pinezka sklepu lądowała w oceanie.
Walidacja typeof === "number" przechodzi, bo zero jest poprawną liczbą. Potrzebny jest świadomy filtr wartości zerowych w warstwie danych — nikt go nie napisze, jeśli nie zobaczył wcześniej pinezki w oceanie.
6. Oszczędność 57 kB, która kosztowała 11 punktów
Font monospace wyjęty z preload „na oszczędność 57 kB”: plakietka łamała się na dwie linie w foncie zastępczym i po podmianie skakała cała treść. CLS 0,22, minus 11 punktów Lighthouse.
Zysk był policzony, koszt nie. Bez pomiaru brzmi to jak oczywista optymalizacja. Zmiana wróciła na miejsce, a zysk wzięliśmy inną drogą — własnym subsetem fontów.
7. Tekst, który brzmi dobrze i kłamie
Model generujący treść przy 97,6 procent wierności przekręcał czytelne fragmenty źródła: „Canada” na „w Kanaanach”, odwrócona relacja między osobami, słowa pieśni przypisane Pismu.
Wynik brzmi dobrze i czyta się gładko. Błąd widać wyłącznie po porównaniu ze źródłem. Wyszedł z benchmarku: dwa niezależne przebiegi, liczone fakty krytyczne, ręczna weryfikacja w transkrypcie.
8. Poradnik opisujący starszą wersję
Silnik automatyzacji od wersji 2.0 nie udostępnia zmiennych środowiskowych w węźle z kodem. Każdy poradnik w sieci pokazuje starszą wersję, więc model odtwarza to, czego się nauczył.
Jedyne, co pomaga: test na żywej instancji przed zbudowaniem automatu.
9. Archiwizacja, która kasuje historię
Archiwizacja zadania przez przeniesienie do innego kubełka zeruje datę wykonania. API przyjmuje żądanie i zwraca 200, więc nic nie sygnalizuje problemu.
Historia „co zostało zrobione” znika po cichu. Archiwizujemy etykietą, nie kubełkiem.
10. Częściowy POST, który czyści pola
W tym samym API częściowy POST czyści pola, których nie ma w treści żądania. Wysyłasz {"priority": 4}, a tracisz opis.
REST bez schematu na to pozwala, a klient nie widzi problemu. Wykryte przy pierwszej integracji i opisane w kanonie narzędzia, żeby nie wróciło.
Co z tego wynika
Żaden z tych błędów nie jest błędem składni. To błędy sensu, danych i eksploatacji — specyficzne dla wersji biblioteki, dla hostingu i dla realnych danych. Model językowy nie ma o nich wiedzy, bo nie ma dostępu do waszej produkcji ani do waszego dysku.
Wyłapuje je programista, który wie, gdzie patrzeć, i który zostaje po wdrożeniu.
To jest dokładnie ta różnica, za którą warto zapłacić: nie za pisanie kodu, bo to akurat AI robi szybciej, tylko za wiedzę, co sprawdzić, zanim ten kod zacznie żyć własnym życiem.

