Loop engineering na lokalnym LLM-ie: pętle agenta, które same sprawdzają swoją pracę

Autor: Jakub Rusinowski · Ostatnia aktualizacja 2026-08-04 · Wartości sprzętowe wyliczone naszym silnikiem VRAM

Loop engineering to projektowanie cyklu zrób → obserwuj → zweryfikuj → powtórz wokół modelu, zamiast prowadzenia go promptem krok po kroku. Lokalnie waży więcej niż przy API z czołówki: deterministyczny weryfikator (zestaw testów, kontrola typów, build) dostarcza osądu, którego modelowi 27B brakuje, a limit iteracji plus czysty reset kontekstu powstrzymują go przed wpadnięciem w spiralę. Zasada, która rozstrzyga wszystko: nie ma obiektywnej kontroli — nie ma pętli.

W trzy lata nałożyły się na siebie trzy praktyki. Prompt engineering dotyczył brzmienia pojedynczego żądania. Context engineering — tego, co model widzi, gdy odpowiada. Loop engineering, termin, który wszedł do obiegu w połowie 2026, dotyczy tego, co dzieje się *po* odpowiedzi: model działa, coś obiektywnego obserwuje wynik, a system decyduje, czy go przyjąć, powtórzyć próbę, czy zatrzymać się. To warstwa pod spodem każdego poważnego agenta kodującego wydanego w tym roku i warstwa, w której lokalne modele zyskują najwięcej.\n\nPowód jest mało efektowny. Model z czołówki często doprowadzi mgliste polecenie do przyzwoitego wyniku za pierwszym razem, więc niechlujna pętla da się przeżyć. Model 22–32B na twoim własnym GPU zwykle tego nie zrobi — ale *jest* bardzo dobry w doprowadzaniu przechodzącego testu do zieleni, gdy podasz mu wyjście z porażki. Loop engineering zamienia słabość modelu (osąd, planowanie na długim horyzoncie) w coś, co pętla dostarcza za darmo, i opiera się na jego sile: szybkich, lokalnych, nierozliczanych iteracjach. Dobrze zaprojektowana pętla na karcie 24 GB rutynowo bije źle zaprojektowaną pętlę na modelu z API, który kosztuje przy każdej próbie.

Anatomia pętli agenta

Każdy agent kodujący — Aider, Cline, OpenCode, Claude Code, Codex — ma pod spodem ten sam pięciokrokowy cykl. Różnice polegają na tym, na co pozwala się każdemu krokowi.

Krok 4 jest tym, co odróżnia loop engineering od „puszczenia agenta jeszcze raz”. Weryfikator ma jedno zadanie: za każdym razem identycznie zwrócić sukces albo porażkę, bez udziału modelu w tej decyzji. pytest -q, tsc --noEmit, cargo test, go build ./..., ruff check, npm run lint — wszystkie się nadają. „Zapytaj drugi model, czy kod wygląda dobrze” już nie, przynajmniej nie jako bramka; LLM w roli sędziego ma miejsce *obok* obiektywnej kontroli, nigdy zamiast niej.

Dlatego pierwszym pytaniem przy każdym lokalnym projekcie z pętlą nie jest „jaki model?”, tylko „jakie mam polecenie zwracające sukces albo porażkę i jak długo się wykonuje?”. Repozytorium bez szybkiego, godnego zaufania polecenia testowego nie nadaje się do zapętlania. Naprawa tego idzie pierwsza.

Cztery poziomy pętli

Pętle się zagnieżdżają. Każdy poziom otacza ten pod sobą i dokłada inny rodzaj korekty. Świadomość, na którym poziomie działasz, mówi ci, co powinno być twoją kolejną poprawą.\n\n| Poziom | Czym jest | Kto decyduje, że „gotowe” | Realia lokalnego sprzętu |\n|---|---|---|---|\n| 1 · Pętla narzędziowa | Model wywołuje narzędzia w kółko, aż sam ogłosi ukończenie (klasyczny cykl ReAct) | Model | Działa od 22B wzwyż przy solidnym tool callingu. Zawodzi po cichu, gdy „ogłasza” sukces, którego nie osiągnął |\n| 2 · Pętla celu | Definiujesz mierzalny warunek sukcesu; pętla działa, dopóki nie zostanie spełniony | Deterministyczna kontrola | Złoty środek dla lokalnych modeli. Ta kontrola jest tą inteligencją, której model nie ma |\n| 3 · Pętla weryfikacji | Kilka bramek jedna na drugiej — testy, potem typy, potem lint, potem przebieg przeglądu | Łańcuch kontroli | Lokalnie tanie: bramki to praca procesora, nie tokeny. Każda dołożona bramka obniża próg modelu, którego potrzebujesz |\n| 4 · Metapętla | Pętla poprawia własne wejścia — porażki wracają do pliku z regułami, promptów albo podziału zadania | Ty, co jakiś czas | Tu lokalne konfiguracje procentują. Każda poprawka wpisana do AGENTS.md jest trwała i darmowa |\n\nWiększość ludzi mówiących „agent nie działa” tkwi na poziomie 1 z modelem zbyt słabym, by ocenić samego siebie. Przejście na poziom 2 — ten sam model, ten sam sprzęt, jedna dołożona bramka pytest — to zwykle największy pojedynczy skok jakości, jaki jest do wzięcia, i nie kosztuje nic.

Co się zmienia, gdy model jest lokalny

Sama koncepcja jest niezależna od dostawcy; ograniczenia inżynierskie już nie. Pięć różnic napędza każdą decyzję projektową na własnym sprzęcie.\n\n- Iteracje są darmowe, ale nie szybkie. Nie ma rachunku za tokeny, więc dwunastoiteracyjna pętla jest finansowo w porządku. Ale 27B na Q4 na karcie 24 GB daje jakieś 30–60 tokenów na sekundę, a każda iteracja czyta od nowa rosnący kontekst. Pętle ogranicza czas na zegarze, nie budżet — co odwraca zwykłą radę: wybieraj *mniej, lepiej poinformowanych* iteracji zamiast siłowego przemiału.\n- Kontekst to koszt sprzętowy. Każda ponowna próba dokłada wyjście z porażki. W API okno jest problemem kogoś innego; lokalnie cache KV to VRAM, który musisz mieć. Kontekst 32K przy 27B dokłada kilka gigabajtów ponad wagi — dokładną liczbę wylicz kalkulatorem VRAM, zanim zaprojektujesz pętlę zakładającą 64K.\n- To niezawodność wywołań narzędzi jest miejscem awarii. Modele z czołówki emitują poprawne wywołania praktycznie zawsze. Lokalne dryfują — złe nazwy argumentów, proza owinięta wokół JSON-a, drugie wywołanie zmyślone po pierwszym. Pętla, która nie sparsuje akcji, nie zadziała. Rozwiązanie oparte na gramatyce opisuje tool calling przy lokalnych modelach.\n- Degradacja jest stromsza. Lokalne modele szybciej tracą spójność w miarę zapełniania kontekstu. Praktyczna konsekwencja: resetuj kontekst między próbami, zamiast kumulować dziesięć nieudanych podejść w jednym oknie. Przenoś dalej cel, bieżący diff i *najświeższą* porażkę — nie cały zapis rozmowy.\n- Cały stack jest twój. Nic cię nie limituje, nikt nie wycofa ci modelu i żaden dostawca nie zagląda do repozytorium. Przy pętli działającej bez nadzoru na prywatnej bazie kodu to cały argument.

Minimalna pętla, którą uruchomisz dziś wieczorem

Zanim sięgniesz po framework, zbuduj wersję na dwadzieścia linijek — uwidacznia ruchome części i naprawdę się przydaje. Ta obsłuży dowolny lokalny endpoint zgodny z OpenAI (Ollama na :11434, LM Studio na :1234, llama-server, vLLM), a bramkuje na twoim własnym poleceniu testowym.

# loop.py — pętla celu (poziom 2) przeciw lokalnemu endpointowi
import subprocess, json, urllib.request

ENDPOINT = "http://localhost:11434/v1/chat/completions"
MODEL    = "qwen3-coder:8b"          # cokolwiek udźwignie twój VRAM
VERIFY   = ["pytest", "-q"]          # TA bramka. Musi być deterministyczna.
MAX_ITERS = 6                        # zawsze limituj. zawsze.

def verify():
    p = subprocess.run(VERIFY, capture_output=True, text=True)
    return p.returncode == 0, (p.stdout + p.stderr)[-4000:]   # tylko ogon

def ask(messages):
    body = json.dumps({"model": MODEL, "messages": messages,
                       "temperature": 0.1, "stream": False}).encode()
    req = urllib.request.Request(ENDPOINT, body, {"Content-Type": "application/json"})
    with urllib.request.urlopen(req) as r:
        return json.load(r)["choices"][0]["message"]["content"]

goal = "Make the failing tests in tests/ pass. Change only src/."
for i in range(1, MAX_ITERS + 1):
    ok, output = verify()
    if ok:
        print(f"PASS after {i-1} iteration(s)"); break
    # Świeży kontekst przy każdej próbie: sam cel i bieżąca porażka.
    reply = ask([
        {"role": "system", "content": "You are editing a repo. Reply ONLY with a unified diff."},
        {"role": "user", "content": f"{goal}\n\nTest output:\n{output}"},
    ])
    subprocess.run(["git", "apply", "-"], input=reply, text=True)
    print(f"--- iteration {i} applied ---")
else:
    print("Cap reached without a green suite — reverting.")
    subprocess.run(["git", "checkout", "--", "."])

Cztery decyzje projektowe w tym pliku to cała lekcja: weryfikator jest podprocesem, nie promptem; wyjście błędu jest przycięte do ogona, żeby kontekst nie eksplodował; kontekst powstaje od nowa w każdej iteracji, zamiast się kumulować; a pętla cofa zmiany po osiągnięciu limitu, zamiast zostawiać za sobą niedokończone edycje. Uruchamiaj ją w worktree gita albo w kontenerze, żeby zły diff nic cię nie kosztował — zobacz sandbox dla lokalnego agenta kodującego.

Prompty w skrypcie zostawiliśmy po angielsku celowo: modele kodujące są trenowane głównie na angielskich instrukcjach i po polsku wypadają wyraźnie gorzej.

Projektowanie weryfikatora (część, którą wszyscy pomijają)

Pętla dziedziczy jakość swojej kontroli co do joty. Oceń swoją według poniższych punktów, w kolejności wartości za minutę pracy:\n\n1. Szybkość przed pokryciem. Czterosekundowy podzbiór odpalany w każdej iteracji jest wart więcej niż sześciominutowy pełny zestaw odpalany raz. Wyceluj pętlę w szybki podzbiór, a pełny zestaw uruchom raz na koniec. Na lokalnym sprzęcie przebieg testów kosztuje często mniej czasu na zegarze niż jedna tura modelu — ta asymetria jest powodem, żeby bramkować agresywnie.\n2. Padaj głośno i konkretnie. Tekst porażki *jest* następnym promptem. Komunikaty asercji mówiące, czego oczekiwano wobec tego, co otrzymano, uczą model w jednej turze; samo AssertionError spala trzy.\n3. Tanie bramki układaj jako pierwsze. Kontrola typów (tsc --noEmit, mypy) i lint wyłapują sporą część błędów lokalnych modeli — złe ścieżki importu, wymyślone nazwy metod, pomyłki w liczbie argumentów — w niecałą sekundę, zanim ruszy choć jeden test.\n4. Zamknij dziury na reward hacking. Model, któremu każesz „doprowadzić testy do zieleni”, przy pierwszej okazji zmieni test, usunie asercję albo dopisze @pytest.mark.skip. Ogranicz ścieżkę, do której wolno mu pisać (Change only src/, dokładnie tak jak w skrypcie wyżej), i dołóż bramkę padającą, gdy zmienią się pliki testów: git diff --exit-code -- tests/. To nie paranoja, tylko najczęstszy sposób, w jaki wynik pętli wygląda na zielony i jest nic niewart.\n5. Wiedz, czego kontrola nie obejmuje. Zielone testy znaczą „brak znanej regresji”, nie „poprawnie”. Każda pętla potrzebuje na końcu ludzkiego przeglądu diffa. Zadaniem pętli jest podać ci mały, wiarygodny, już przechodzący diff — nie zmergować go.

Sposoby, w jakie to się psuje, i poprawka na każdy

| Objaw | Co się naprawdę dzieje | Poprawka |\n|---|---|---|\n| W kółko ta sama edycja | Model nie widzi, że już tego próbował | Dołącz diff poprzedniej próby — albo *powód jej odrzucenia* — do następnego promptu, a nie cały zapis rozmowy |\n| Jakość wali się w okolicach piątej iteracji | Context rot: okno zapchane starymi porażkami | Buduj kontekst od nowa przy każdej próbie; zostaw sam cel, bieżący diff i najświeższą porażkę |\n| Testy przechodzą, a kod jest bez sensu | Reward hacking na bramce | Zamroź pliki testów, dołóż drugą bramkę (typy, build, kontrola wzorcowego wyjścia) |\n| Pętla nigdy się nie kończy | Brak limitu albo niestabilny test, który losowo nie przechodzi | Twardy limit iteracji; odizoluj niestabilne testy, zanim puścisz pętlę |\n| Agent staje w połowie zadania, ogłaszając sukces | Pętla poziomu 1 z modelem, który źle się samoocenia | Przejdź na poziom 2 — warunkiem wyjścia musi być weryfikator, nigdy opinia modelu |\n| Zepsute wywołanie narzędzia, pętla umiera na parsowaniu | Lokalny model zjechał ze schematu | Dekodowanie ograniczone gramatyką plus jedna próba naprawy parsowania, która nie liczy się do limitu |\n| Maszyna nie do użycia, kiedy pętla pracuje | Model plus cache KV wysycają GPU | Niższa kwantyzacja albo krótszy kontekst; albo puść pętlę przez noc na wynajętym GPU |\n\nDwa nawyki zapobiegają większości z tych rzeczy: limituj wszystko (iteracje, czas na zegarze na iterację, tokeny na turę) i zapisuj każdą iterację na dysk — prompt, wywołanie narzędzia, wyjście weryfikatora. Ten log jest sposobem na odróżnienie „model jest za mały” od „mój prompt był niejednoznaczny”, a te dwie diagnozy wymagają przeciwnych reakcji.

Jak duży model jest właściwie potrzebny do pętli

Dobra pętla obniża poprzeczkę, ale jej nie usuwa. Podłogę wyznaczają dwie umiejętności: wyemitowanie poprawnego wywołania narzędzia albo diffa oraz prawidłowe odczytanie stack trace'u.\n\n- 8B (karta 8 GB) — na poziomie 2 nadaje się do wąskich, jednoplikowych celów z klarownym niezaliczonym testem. Licz się z niańczeniem; trzymaj limit na 3–4. Najlepiej w parze ze ścisłymi formatami diffa i dekodowaniem ograniczonym gramatyką.\n- Próg 16 GB — pierwszy, na którym pętla bez nadzoru ma sens. Devstral-2 22B jest wprost dostrojony pod pracę agentową i dobrze trzyma się formatów edycji.\n- Próg 24 GB — Qwen 3.6 27B albo Qwen 2.5 Coder 32B: cele obejmujące wiele plików, znośne odczytywanie porażek, pętle kończące się, zanim zaparzysz kawę. To próg, w który większość ludzi powinna celować.\n- Stacja robocza / Mac od 96 GB — Qwen3-Coder 80B-A3B. Szybkie dekodowanie MoE czyni długie pętle praktycznymi, co po wprowadzeniu weryfikatora liczy się bardziej niż sama jakość.\n\nUzasadnienie progów i dokładne wartości VRAM znajdziesz w najlepszych lokalnych modelach do kodowania; uczciwą drabinkę możliwości pod autonomię rozpisuje VRAM dla modeli kodujących.

Gdzie loop engineering opłaca się lokalnie

Nie każde zadanie zasługuje na pętlę. Te, które zasługują, mają wspólny kształt: maszynowo sprawdzalną definicję ukończenia i dość powtarzalności, by opłacało się napisać tę kontrolę.\n\n- Naprawa sterowana testami — przypadek kanoniczny. Na wejściu niezaliczony test, na wyjściu zielony diff.\n- Mechaniczne migracje — podbicia wersji frameworka, zmiany nazw w API, adnotacje typów w setkach plików. Weryfikatorem jest build; model odwala mozół.\n- Dług lintowy i typowy — wyceluj pętlę w tsc --noEmit i pozwól jej przez noc zemleć licznik błędów w dół, na sprzęcie, który już masz.\n- Generowanie testów z bramką na pokrycie — generuj testy, bramkuj na przyroście pokrycia *oraz* na tym, że zestaw dalej przechodzi.\n- Rozjazd dokumentacji i kodu — wygeneruj dokumentację ze źródeł, zweryfikuj, uruchamiając ponownie przykłady z dokumentacji.\n\nZadania oporne na pętle: wszystko, czego sukces jest kwestią gustu (projekt API, nazewnictwo), wszystko, gdzie napisanie kontroli kosztuje więcej niż wykonanie pracy ręcznie, i wszystko dotykające systemu, którego nie da się bezpiecznie uruchomić ponownie. Przy tych zostań w interaktywnym trybie asystenta opisanym w macierzy narzędzi.

Nie masz sprzętu? Najpierw wynajmij kartę

Pętle ogranicza czas na zegarze: to samo dwunastoiteracyjne zadanie, które na karcie 8 GB zajmuje wieczór, na wynajętej karcie 48 GB kończy się w porze lunchu. Wynajem na godziny jest też najtańszym sposobem, żeby sprawdzić, czy większy model faktycznie naprawia twoją pętlę, czy problemem był weryfikator.

Pełna lista w katalogu chmurowej AI.

Najczęstsze pytania

Czym jest loop engineering?
Loop engineering to praktyka projektowania iteracyjnego cyklu, w którym pracuje agent AI — zrób, zobacz wynik, skonfrontuj go z obiektywnym warunkiem, a potem powtórz albo zakończ — zamiast prowadzenia modelu promptem krok po kroku. Elementem definiującym jest deterministyczny weryfikator (testy, kontrola typów, build), który decyduje, czy pętla trwa dalej. Bez tej kontroli masz automatyzację, nie pętlę.
Czym loop engineering różni się od prompt engineeringu?
Prompt engineering optymalizuje pojedyncze żądanie; context engineering — to, co model widzi; loop engineering — to, co dzieje się po odpowiedzi modelu. W praktyce robisz nadal wszystkie trzy, ale to pętla daje niezawodność: przeciętny prompt wewnątrz zweryfikowanej pętli bije doskonały prompt bez żadnej kontroli wyniku.
Czy loop engineering zadziała z małym lokalnym modelem?
Tak i małym modelom pomaga nieproporcjonalnie mocno. Weryfikator dostarcza osądu, którego modelowi brakuje, a lokalne iteracje kosztują wyłącznie czas. Model 8B poradzi sobie z wąskimi, jednoplikowymi celami przy klarownym niezaliczonym teście; od 22B wzwyż ciągnie pracę na wielu plikach bez nadzoru. Czego mały model nie potrafi, to samodzielnie stwierdzić, że skończył — i dokładnie to zadanie przejmuje weryfikator.
Ile iteracji powinna wykonywać pętla agenta kodującego?
Ogranicz ją, zwykle do 4–8. Sukces prawie zawsze przychodzi w pierwszych kilku próbach; dalej model najczęściej krąży wokół wariantów tego samego nieporozumienia, a degradacja kontekstu sprawia, że każda kolejna próba jest gorsza od poprzedniej. Po osiągnięciu limitu cofnij zmiany i przekrój zadanie na nowo, zamiast podnosić limit.
Dlaczego mój agent przechodzi testy, ale produkuje zepsuty kod?
To reward hacking na bramce — najczęściej model zmienił albo pominął test, zamiast naprawić kod. Ogranicz ścieżki, do których wolno mu pisać, dołóż bramkę padającą przy zmianie plików testowych (git diff --exit-code -- tests/) i ułóż na tym drugą niezależną kontrolę, na przykład przebieg typów albo build. Zielone testy znaczą „brak znanej regresji”, nigdy „poprawnie”.
Czy do loop engineeringu potrzebny jest framework, czy wystarczy skrypt?
Skrypt na dwadzieścia linijek obejmujący złóż → zadziałaj → zweryfikuj → powtórz wystarcza do pętli naprawczych, migracyjnych i tych zbijających dług lintowy, a przy okazji pokazuje, gdzie twoja konfiguracja naprawdę pęka. Po pełny harness agenta — Aider, Cline, OpenCode — sięgaj wtedy, gdy potrzebujesz edycji wielu plików, przeszukiwania repozytorium, obsługi uprawnień i kompaktowania kontekstu, czyli części, które faktycznie męczy się odbudowywać.

Co dalej