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

Anti-Slop Guardrails: jak oduczyłem agenta AI oszukiwania w kodzie TypeScript

#ai-agents#typescript#anti-slop#frontend#zod#architecture

Kiedy dajesz modelom sztucznej inteligencji wolną rękę przy pisaniu kodu frontendowego, szybko pojawia się zjawisko określane jako AI Slop - kod, który na pierwszy rzut oka wygląda profesjonalnie, ale w środku jest pełen pułapek i kruchych założeń.

Problem: Kiedy sztuczna inteligencja udaje, że kod działa

Najczęstszym grzechem modeli LLM w języku TypeScript jest tzw. Compiler Bluffing (oszukiwanie kompilatora). Można to porównać do mechanika samochodowego, który zamiast sprawdzić, dlaczego stuka w silniku, po prostu zakleja czerwoną kontrolkę na desce rozdzielczej czarną taśmą izolacyjną.

W kodzie objawia się to następująco:

  • Podwójne rzutowania (as unknown as T): Gdy model gubi się w typach, na siłę wmawia TypeScriptowi: „Uwierz mi na słowo, to na pewno jest profil użytkownika”.
  • Worek na śmieci (any i Record<string, any>): Wyłączenie sprawdzania typów dla wygody, co niszczy całe bezpieczeństwo języka.
  • Brak weryfikacji danych z sieci: Model zakłada, że serwer ZAWSZE zwróci idealne dane dokładnie w takim formacie, jakiego oczekuje.

Skutek w praktyce? Aplikacja kompiluje się bez ani jednego ostrzeżenia, ale gdy żywy użytkownik wejdzie na stronę i serwer zwróci pusty wynik lub błąd, przeglądarka wyświetla biały ekran (TypeError: Cannot read properties of undefined).

Co zrobiłem: Twarde barierki na autostradzie (Guardrails)

Zamiast prosić model w promptach o „staranne pisanie kodu”, w projekcie Agent Operations Center (AOC) wdrożyłem zestaw twardych reguł inżynierskich (.agents/rules/anti-slop.md), których żaden agent kodujący nie ma prawa złamać.

1. Bezwzględny zakaz rzutowań na skróty

Agent ma zakaz stosowania konstrukcji as unknown as T. Jeśli w newralgicznym miejscu musi użyć asercji typu, jest zobowiązany dodać komentarz // SAFETY: z logicznym uzasadnieniem. Jeśli uzasadnienia brak - kod jest automatycznie odrzucany w fazie review.

2. Strażnik graniczny na wejściu (Biblioteka Zod)

Dane przychodzące z sieci nie mają prawa trafić do wnętrza aplikacji na słowo honoru. Agent musi przepuścić surowy JSON przez schemat walidacyjny w bibliotece Zod, który weryfikuje każdy parametr w czasie rzeczywistym.

// ❌ Przed: Typowy kod pisany przez AI (pozorne bezpieczeństwo)
const fetchProfile = async (id: string) => {
  const res = await fetch(`/api/users/${id}`);
  // Oszukanie kompilatora - zero gwarancji, co naprawdę zwrócił serwer:
  const data = (await res.json()) as unknown as UserProfile;
  return { ...(data.isAdmin ? { role: 'admin' } : {}) };
};

// ✅ Po: Standard Anti-Slop wymuszony na agencie
const fetchProfile = async (id: string): Promise<UserRoleProps> => {
  const res = await fetch(`/api/users/${id}`);
  const raw = await res.json();

  // Bezpieczna bramka: Zod weryfikuje dane w runtime i rzuca czytelny błąd, jeśli format jest zły
  const data = UserProfileSchema.parse(raw);

  return {
    role: data.isAdmin ? 'admin' : undefined
  };
};

3. Precyzyjne stany zamiast niejednoznaczności

Zamiast wrzucać do komponentu 5 osobnych flag typu isLoading, isError, isSuccess (co prowadzi do sytuacji, gdzie isLoading i isError są jednocześnie prawdziwe), agent musi stosować jawne stany rozłączne (tzw. unie dyskryminowane): stan to albo loading, albo error, albo ready.

Dlaczego to ważne (Use Case)

Dlaczego warto narzucać tak surowy rygor na modele AI?

  • Stabilność na produkcji: Gdy agent buduje nowy moduł w panelu AOC, mamy 100% pewności, że niespodziewana zmiana w API czy chwilowa awaria bazy nie wysypie całego interfejsu.
  • Koniec z długiem technologicznym: Kod produkowany przez bota nie wymaga wielogodzinnego poprawiania przez programistę. Spełnia standardy kodu pisanego przez Senior Developera od pierwszej minuty.
  • Szybkie wykrywanie błędów: Jeśli backend zmieni strukturę danych, błąd wychodzi natychmiast na poziomie schematu Zod z precyzyjną informacją: „Brakujące pole: email w obiekcie użytkownika”, zamiast losowego błędu gdzieś głęboko w widoku.

Czego się nauczyłem

  1. AI potrzebuje ograniczeń, a nie wolności: Rola inżyniera pracującego z agentami to nie bycie pisarzem promptów, lecz architektem reguł i ograniczeń (Constraint Architect).
  2. Kompilator to nie wróg, którego trzeba oszukać: Jeśli kompilator zgłasza błąd typów, to znak, że w logice biznesowej brakuje obsługi jakiegoś przypadku brzegowego.
  3. Zasada ograniczonego zaufania (Zero Trust) do danych z sieci: Niezależnie od tego, czy kod pisze człowiek, czy maszyna, walidacja na granicach systemu to fundament stabilnego oprogramowania.