Engineering the Agentic Stack · Część 6

Inżynieria harnessu dla agentów AI: projektowanie pętli sterowania

Tłumaczenie automatyczne Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.

Aktualizacja artykułu

Pierwotnie opublikowano 22 lipca 2026 r. Przejrzano i zaktualizowano 6 września 2026 r. Aktualizacja dodaje nowsze dane z benchmarków harnessu i przypadki interwencji dostawców oraz precyzuje, co wynika z raportowanych rezultatów.

Agent może zakończyć swoją turę, mimo że praca nadal jest nieukończona. W przypadku agenta programistycznego użytecznymi dowodami są zmodyfikowany artefakt i wymagane wyniki testów. Końcowa wiadomość „gotowe” nie potwierdza żadnej z tych rzeczy.

Harness to kod sterujący wokół pętli rozumowania. Dostarcza kontekst, waliduje i autoryzuje wywołania narzędzi, rejestruje wyniki oraz decyduje, czy dowody wystarczają do zaakceptowania pracy. Warstwa runtime utrzymuje pod spodem aktywne wykonywanie i stan.

Podczas przeglądu harnessu zadałbym dwa pytania: co uniemożliwia mu zaakceptowanie nieukończonej pracy oraz które awarie uzasadniają dodanie kolejnych mechanizmów kontroli? W tym artykule omawiam testy akceptacyjne, ponowienia i przekazywanie pracy, a następnie pokazuję, jak porównywać mechanizm kontroli ze stałym baseline’em. Przykłady sklepu są fikcyjne; dołączone laboratorium to deterministyczna symulacja, a nie pomiar działającego agenta.

Najprostszy test akceptacyjny łatwo napisać dla małego agenta badawczego, którego budowaliśmy w tej serii — agenta LangGraph pobierającego dane rynkowe i tworzącego raport analityka. Hook poza modelem waliduje raport względem schematu i sprawdza, czy rzeczywiście zawiera tickery akcji; niepoprawny raport utrzymuje uruchomienie w toku. Dwanaście linii zwykłego kodu wystarcza, by model nie mógł samodzielnie uznać własnego wyjścia za poprawnie sformatowane. Repozytorium wykorzystuje łagodniejszy test: głosuje ewaluator działający w świeżym kontekście, a następnie wynik przegląda człowiek. (Część 4 szkicuje wersję deterministyczną).

Ten przykład nie pokazuje interesującej części: co dzieje się, gdy dowody są niejednoznaczne, gdy ponowienie może obciążyć kogoś podwójną opłatą albo gdy praca trwa dłużej niż sesja, która ją rozpoczęła. Do tego potrzebne jest zadanie z wyraźniejszą granicą zaliczenia niż raport badawczy. Agent badawczy pozostaje przykładem testu akceptacyjnego; do przypadków ponowień i przekazywania pracy dołącza małe, fikcyjne repozytorium sklepu. Zadanie programistyczne polega na obniżeniu progu automatycznego rabatu 10% z $100 do $75 w src/checkout.py. Repozytorium ma dwa wymagane testy:

  • pytest tests/test_checkout.py weryfikuje obliczanie rabatu.
  • pnpm playwright test tests/checkout_discount.spec.ts dodaje element za $80 w lokalnym sklepie testowym i sprawdza, czy strona checkoutu pokazuje rabat $8.

Przykład jest pomocniczym fixture’em, a nie prawdziwą aplikacją ani benchmarkiem. Każda próba zaczyna się od tego samego commita i tych samych zainicjalizowanych danych testowych. Harness może zaakceptować zmianę tylko wtedy, gdy oba polecenia zakończą się powodzeniem, a trwały rekord akceptacji powiąże oba wyniki z czystym zatwierdzonym kandydatem lub skrótem kompletnego testowanego snapshotu, obejmującego również istotne nieśledzone pliki.

Diagram przedstawia przepływ zmiany rabatu od propozycji do dowodów. Harness dostarcza zadanie i pliki, sprawdza argumenty oraz uprawnienia proponowanego wywołania edit_file i wysyła zaakceptowane wywołanie. Po zastosowaniu edycji przez runtime harness uruchamia wskazane testy jednostkowe i akceptacyjne testy przeglądarkowe. Nieudane polecenie wraca do modelu jako dowód do kolejnej tury; dwa pomyślnie zakończone polecenia kwalifikują zmianę do akceptacji.

Zmiana rabatu w pętli sterowania harnessuZmiana rabatu w pętli sterowania harnessu


Za co odpowiada harness

Przewodnik OpenAI dotyczący pętli Codex opisuje podstawowy cykl. Harness składa prompt, prosi model o następną akcję, wysyła zaakceptowane wywołanie narzędzia do runtime’u i dołącza wynik. Następnie pyta ponownie. Proces powtarza się do chwili, gdy harness zaakceptuje rezultat albo przekaże sterowanie użytkownikowi.

Implementacje mogą łączyć kilka odpowiedzialności w jednym procesie. Granice awarii nadal są jednak różne:

TerminZadaniePrzykład dla agenta programistycznego
ModelProponuje tekst, wywołanie narzędzia lub odpowiedź końcowąSugeruje edycję w src/checkout.py
Pętla rozumowaniaWybiera następny krok na podstawie dostępnego kontekstuInspekcja, edycja, test, ponowna inspekcja
HarnessDostarcza kontekst, waliduje propozycje, autoryzuje je, wysyła zaakceptowane wywołania, rejestruje wyniki i sprawdza ukończenieZezwala na edycje w src/ i wymaga obu wskazanych testów
RuntimeWykonuje zaakceptowane wywołania i utrzymuje stan poza procesem workeraLog sesji, sandbox, magazyn checkpointów, backend trace’ów

Wiersz runtime’u obejmuje cztery elementy: sesję, sandbox, checkpoint i trace. Wszystkie cztery przechowują stan lub ograniczają wykonywanie. Model proponuje akcję, a pętla rozumowania wybiera następny krok. Harness decyduje, czy proponowane wywołanie może zostać uruchomione oraz czy dowody wystarczają do zakończenia pracy — dlatego poświęcono mu osobny artykuł. Część 5 traktuje harness, obok tych czterech elementów, jako jeden z pięciu prymitywów, które trzeba umieścić przed wdrożeniem; ten artykuł ponownie wydziela go jako osobną warstwę.

Gdy pojawia się awaria, zdiagnozuj granicę, która powinna na nią zareagować. Słaby plan może wymagać lepszych instrukcji lub rozumowania modelu. Jeśli edit_file wskazuje ścieżkę poza src/, harness powinien ją odrzucić. Proces sandboxu, który kończy się przed uruchomieniem edycji, należy do runtime’u; runtime musi zrestartować workera albo zgłosić awarię.

Gdzie trafiają wcześniejsze części

Wiersz harnessu powyżej wykonuje większość pracy w tej tabeli i właśnie do niego sprowadzają się Części 2, 3 i 4. Każda z nich rozstrzyga jedną rzecz dotyczącą pojedynczej tury:

Wcześniejsza częśćCo rozstrzyga w tej turzeGdzie działa w omówieniu z następnej sekcji
Część 2 — pamięćKtóry wcześniejszy stan trafia do promptuKrok 1, builder kontekstu
Część 3 — korzystanie z narzędziJakie akcje istnieją i jak wygląda zwalidowany wynikWalidacja argumentów w kroku 3 oraz struktura wyniku w kroku 4
Część 4 — bezpieczeństwoCzy to konkretne wywołanie może teraz zostać uruchomioneKrok 3, sprawdzenie ścieżki i decyzja o akceptacji
Część 6 — ten artykułCzy wynikające z pracy dowody kończą uruchomienieKroki 5–7, testy akceptacyjne i trace

Gdzie znajduje się każda część serii Engineering the Agentic StackGdzie znajduje się każda część serii Engineering the Agentic Stack

Części 3 i 4 współdzielą krok 3, a to nakładanie się odpowiedzialności jest głównym argumentem za traktowaniem ich jako jednego programu. Ta sama warstwa kodu harnessu, która odrzuca niepoprawny argument, odrzuca również wywołanie dozwolone, ale jeszcze niezatwierdzone. Jeśli walidacja i autoryzacja działają w osobnych usługach, zachowaj zwalidowane argumenty pomiędzy tymi granicami, aby decyzja autoryzacyjna dotyczyła wywołania, które faktycznie zostanie wykonane.

Podział nadal ma znaczenie podczas debugowania: edycja niewłaściwego pliku to reguła ścieżki z Części 4, a nie problem z wyszukiwaniem z Części 2. Sekcja pod koniec tego artykułu zamienia to w tabelę routingu.

Własne studium przypadku OpenAI dotyczące harness engineering opisuje uruchamialną instancję aplikacji dla każdego worktree. Zespół podłączył również automatyzację przeglądarki do środowiska agenta oraz udostępnił logi, metryki i trace’y.

Zadanie takie jak „żaden span w tych czterech kluczowych ścieżkach użytkownika nie może trwać dłużej niż dwie sekundy” stało się testowalne, ponieważ agent mógł uruchamiać aplikację i odpytywać te same sygnały, które analizowałby inżynier. Studium przypadku jest specyficzne dla produktu. Przenośny wniosek wynika z warunku stojącego za rezultatem: aplikacja i jej sygnały wydajności musiały być dostępne wewnątrz środowiska agenta.

Lopopolo, autor tego studium, prowadzi również przewodnik terenowy po harness engineering. Wskazuje on dwie dźwignie wykorzystywane w tym artykule: traktować model i agenta programistycznego jako czarną skrzynkę oraz projektować otaczający je kontekst i narzędzia. To ujęcie wyjaśnia również, dlaczego tak duża część harnessu kończy jako zwykły kod.

Standardy jakości organizacji, procedury, historia wyjątków i relacje uprawnień znajdują się poza tym, co może wiedzieć model ogólnego przeznaczenia. Harness ujawnia je w postaci instrukcji repozytorium, reguł uprawnień i testów akceptacyjnych. Każde zaakceptowane uruchomienie może przekazać wnioski z powrotem do tych artefaktów, zamiast zmuszać następną sesję do ponownego ich odkrywania.


Prześledź zmianę rabatu od propozycji do akceptacji

Dla zdefiniowanego wyżej zadania rabatowego model proponuje zmianę calculate_discount w src/checkout.py. Zanim ta edycja zostanie uznana za postęp, dzieje się kilka rzeczy:

  1. Builder kontekstu dostarcza zadanie, instrukcje repozytorium, istotne pliki, wcześniejsze wyniki narzędzi i bieżący plan.
  2. Model proponuje wywołanie edit_file z podaną ścieżką i tekstem zastępującym.
  3. Granica narzędzia (kod harnessu pomiędzy propozycją a wykonaniem) waliduje argumenty, sprawdza ścieżkę względem dozwolonego zakresu i prosi o akceptację, jeśli operacja jej wymaga.
  4. Runtime stosuje edycję w sandboxie i zwraca ustrukturyzowany wynik.
  5. Harness uruchamia pytest tests/test_checkout.py, a następnie pnpm playwright test tests/checkout_discount.spec.ts, i odczytuje oba kody wyjścia. Test przeglądarkowy sprawdza widoczny rabat $8 w zainicjalizowanym koszyku za $80.
  6. Harness decyduje, co oznaczają wyniki. Nieudany test staje się nowym kontekstem dla kolejnej tury modelu, a pomyślne uruchomienie czyni zadanie kandydatem do ukończenia.
  7. Pomyślny wynik staje się dowodem ukończenia dopiero po trwałym zapisaniu przez harness polecenia, kodu wyjścia, testowanego snapshotu, gradera i wersji środowiska; trace może powiązać się z tym rekordem.

Po kroku 2 żaden plik nie został zmieniony. Harness może odrzucić ../../secrets.env, wymagać akceptacji dla destrukcyjnego polecenia albo zatrzymać uruchomienie, które wyczerpało budżet. To ostatni tani moment na taką decyzję. Po wykonaniu testów harness sam odczytuje ich kody wyjścia. Model nie może oznaczyć własnej edycji jako zaliczonej.

Rekord akceptacji powinien identyfikować testowany snapshot, oba polecenia i ich wyniki oraz wersje gradera i środowiska; trace’y mogą powiązać się z tym rekordem. Wymagane testy trzymaj poza zakresem zapisu agenta albo niezależnie zatwierdzaj zmiany przed gradingiem. Każda późniejsza edycja pliku unieważnia wynik. Te testy realizują zasady stabilnego środowiska i gradera odpornego na obejście opisane w wytycznych ewaluacyjnych Anthropic. Końcowa wiadomość done bez tych rekordów nie dowodzi, że zmiana przeszła wymagane testy.


Zdecyduj, gdzie egzekwować poszczególne reguły

Wymóg, aby tests/checkout_discount.spec.ts zakończyło się powodzeniem, należy umieścić w kodzie deterministycznym, a nie w prompcie. Harness wysyła polecenie Playwright do runtime’u, odczytuje jego kod wyjścia i odmawia zakończenia uruchomienia, dopóki test nie przejdzie. Prompt może przypominać modelowi o uruchomieniu testu. Nie może jednak uniemożliwić modelowi ogłoszenia sukcesu bez dowodów.

Pozostałe reguły pasują do innych warstw:

Umieść regułę wDobre zastosowaniePrzykład
Prompcie lub skilluKolejność wyszukiwania, konwencje kodowania i format planuPrzeczytaj AGENTS.md przed edycją kodu checkoutu
Granicy narzędziaWalidacja argumentów, dozwolone ścieżki, akceptacje i dostęp do narzędziZezwalaj na zapisy tylko w src/
Kodzie deterministycznymBudżety, timeouty, ponowienia, kody wyjścia testów i wymagania wydanioweUtrzymuj uruchomienie otwarte, dopóki test Playwright nie przejdzie
Ewaluatorze w świeżym kontekściePrzegląd wizualny lub kryteria wymagające osądu przypominającego ludzkiPorównaj wygenerowany diagram z pisemną rubryką

Kontrakty narzędzi oddzielają propozycję od uprawnienia

Zadanie rabatowe wymaga jedynie edycji plików i poleceń testowych. API zmieniające stan ma inny tryb awarii, dlatego w tej sekcji zmieńmy przykład. Załóżmy, że podczas przygotowywania danych testowych agent może wywoływać create_test_order względem stagingowej usługi zamówień. To narzędzie nie jest jednym z testów akceptacyjnych zadania rabatowego. Jest tutaj przydatne, ponieważ timeout może ukryć informację, czy usługa utworzyła zamówienie.

Granica narzędzia potrzebuje czegoś więcej niż opisu w języku naturalnym. Potrzebuje jawnego kontraktu narzędzia. Część 3 argumentowała za takim kontraktem z perspektywy modelu: jasne akcje, zwięzłe informacje zwrotne i błędy możliwe do odzyskania. Harness potrzebuje tego samego kontraktu z innego powodu. Musi bez pytania modelu zdecydować, czy wywołanie może zostać uruchomione i czy nieudane wywołanie można powtórzyć. W przypadku create_test_order oznacza to kontrakt obejmujący:

  • zwalidowane argumenty, aby niepoprawne dane wejściowe były odrzucane przed wykonaniem
  • ustrukturyzowany wynik, taki jak { "order_id": "123", "created": true }, aby późniejsze kontrole nie musiały parsować tekstu o dowolnym formacie
  • kategorię efektu, która rejestruje, czy wywołanie jedynie pobiera informacje, czy zmienia plik, rekord w bazie danych albo zewnętrzną usługę. Rejestruje również, czy bezpieczne jest powtórzenie wywołania. Etykieta ta informuje harness, czy automatyczne ponowienie mogłoby zduplikować pracę. Harness może ponowić get_order_status, gdy usługa definiuje to wyszukiwanie jako tylko do odczytu. Nie może bezrefleksyjnie ponawiać create_test_order, ponieważ pierwsze wywołanie mogło już utworzyć zamówienie
  • timeout i politykę ponowień, aby utracona odpowiedź nie uruchomiła nieograniczonej sekwencji wywołań
  • regułę uprawnień określającą wymaganą akceptację. Odczyt statusu zamówienia może być wykonywany automatycznie, natomiast utworzenie zamówienia może wymagać potwierdzenia

Opis w języku naturalnym to tekst wyświetlany modelowi. Może brzmieć: „Utwórz zamówienie testowe do weryfikacji checkoutu”. Zdanie pomaga modelowi zdecydować, kiedy zaproponować create_test_order. Nie autoryzuje jednak wywołania. W tym przykładzie klient Model Context Protocol (MCP) należący do harnessu waliduje argumenty, stosuje własne reguły oraz sprawdza zaufanie do serwera, wymagania akceptacji i bezpieczeństwo ponowień, zanim cokolwiek wyśle. Łączy to reguły uprawnień i kontrole przed wywołaniem narzędzia omówione w Części 4 z jednym dodatkowym pytaniem: czy wywołanie, które już się nie powiodło, można wysłać ponownie.

Serwer MCP publikuje opisy narzędzi i opcjonalne adnotacje dotyczące zachowania dla klienta. Wadliwy lub złośliwy serwer może opisać narzędzie zmieniające stan jako nieszkodliwe. Klient, który automatycznie przyjąłby takie twierdzenie, mógłby bez akceptacji uruchomić lub ponowić create_test_order i utworzyć duplikat. Specyfikacja MCP wymaga więc, aby klienci traktowali adnotacje narzędzi jako niezaufane, chyba że sam serwer jest zaufany.

Specyfikacja nie narzuca jednego uniwersalnego ustawienia zaufania, dlatego dla wdrożenia potrzebujesz jawnej polityki zaufania; serwer nie może sam uczynić swoich adnotacji wiarygodnymi. Polityka ta decyduje, które metadane mogą wpływać na decyzje dotyczące uprawnień lub ponowień, a które adnotacje pozostają jedynie wskazówkami.

Ponowienie wywołania zmieniającego stan wymaga ochrony przed replay

Część 5 wymaga trwałej tożsamości operacji dla efektów ubocznych, które mogą zostać zduplikowane przy ponowieniu. Harness decyduje, kiedy ten klucz musi przejąć tę odpowiedzialność. create_test_order tworzy zamówienie, ale odpowiedź HTTP zostaje utracona. Harness widzi timeout i nie może stwierdzić, czy serwer zakończył żądanie. Powtórzenie wywołania może utworzyć drugie zamówienie.

Zapisz identyfikator operacji należący do aplikacji przed wysłaniem i powiąż go z zaakceptowanymi argumentami. Użyj go ponownie podczas odzyskiwania tego samego zamówienia, nawet jeśli model wygeneruje nowy identyfikator wywołania narzędzia; identyfikatory modelu zachowaj osobno do korelacji. Zmienione payloady lub wygasłe okna deduplikacji dostawcy uzgadniaj zamiast bezrefleksyjnie wysyłać żądanie ponownie. Na przykład kontrakt Stripe zezwala na usuwanie kluczy po co najmniej 24 godzinach.

Wyszukiwanie statusu można ponowić, gdy usługa definiuje je jako operację tylko do odczytu. Wywołanie tworzące zasób potrzebuje klucza: klient dołącza unikalny identyfikator żądania, a usługa zwraca pierwszy wynik zamiast tworzyć kolejne zamówienie, gdy ponownie zobaczy ten identyfikator. Bez tej ochrony harness powinien sprawdzić, czy zamówienie istnieje, albo poprosić człowieka o decyzję przed kolejną próbą. AWS opisuje ten wzorzec w swoich wytycznych dotyczących idempotentnych API.

Akceptacja wymaga niezależnych dowodów

Pomyślna odpowiedź create_test_order potwierdza jedynie, że narzędzie zwróciło dane. Nie dowodzi, że zadanie programistyczne przeszło testy. Jeśli późniejszy test przeglądarkowy zależy od przygotowanego zamówienia, harness musi zwalidować schemat odpowiedzi i mimo to uruchomić ten test przed zaakceptowaniem zmiany kodu.

Niektórych kryteriów nie da się sprowadzić do kodu wyjścia. W osobnym zadaniu dotyczącym projektu wizualnego ewaluator w świeżym kontekście może porównać wyrenderowaną stronę lub diagram z pisemną rubryką — „świeży kontekst” oznacza drugą sesję modelu, która rozpoczyna się bez historii uruchomienia i odczytuje wytworzone artefakty, a nie transkrypt. Zanim pozwolisz, by jego wynik decydował o ukończeniu zadania, porównaj go z przeglądami wykonywanymi przez ludzi.


Migracja adaptera płatności wymaga przekazania pracy

Ponownie zmieńmy zadanie, ale pozostańmy w fikcyjnym repozytorium sklepu. Agent musi teraz przeprowadzić migrację checkoutu z adaptera płatności v1 do v2. Praca obejmuje handler checkoutu, klienta płatności, konfigurację i testy, więc może trwać dłużej niż jedna sesja modelu — jeden ciągły odcinek kontekstu modelu, zakończony restartem albo świadomym rozpoczęciem od nowa, a nie przenoszony dalej.

Zanim pierwsza sesja osiągnie limit kontekstu, zmodyfikowała kilka plików, uruchomiła lokalny sandbox płatności i pozostawiła tests/payment_migration.spec.ts w stanie niezaliczonym. Ten przeglądarkowy test akceptacyjny wykonuje jedną płatność przez adapter v2 i weryfikuje zapisany identyfikator dostawcy. Podsumowanie rozmowy może ukierunkować kolejną sesję modelu, ale nie zrestartuje sandboxu ani nie dowiedzie, które pliki są aktualnie zmodyfikowane.

Następna sesja musi odzyskać trzy rzeczy:

Co należy odzyskaćCo obejmujeJak może wystąpić awaria
Historia rozmowyWiadomości, wywołania narzędzi i zwrócone wynikiStare szczegóły wypierają bieżące zadanie
Środowisko roboczePliki, sandbox płatności i stan testów przeglądarkowychTranskrypt twierdzi, że usługa działa, choć już się zatrzymała
Postęp zadaniaPlan, ukończone testy, oczekująca akceptacja i następna akcjaNastępna sesja powtarza zakończoną pracę

Kompakcja zastępuje starsze wiadomości krótszym podsumowaniem, aby bieżąca sesja mogła działać dalej. Przekazanie postępu zapisuje to, czego potrzebuje następna sesja: bieżącą gałąź, zmienione pliki, ostatnie polecenie testowe i jego wynik oraz kolejny nierozwiązany krok.

Plik przekazania pracy to pamięć dokumentowa dla następnej sesji modelu. Checkpoint może już zachowywać plan, ukończone kroki, wyniki i pozostałą pracę. Dodaj przekazanie, gdy te informacje są nieobecne albo nieużyteczne w następnym kontekście, i zweryfikuj pliki oraz działające usługi względem aktywnego środowiska.

Jeśli stara rozmowa zawiera nieaktualne założenia, harness może rozpocząć świeżą sesję modelu z tym przekazaniem i bieżącym workspace’em. Zastąpienie uszkodzonego workera i odtworzenie jego procesów to osobne zadanie związane z odzyskiwaniem runtime’u.

Mała edycja dokumentacji może nie wymagać żadnego z tych mechanizmów. Migracja płatności wymaga przekazania, jeśli zapisany stan nie przenosi użytecznego postępu zadania, ponieważ następna sesja modelu musi odtworzyć zarówno workspace, jak i status zadania.

Eksperymenty Anthropic dotyczące długotrwałych agentów programistycznych wykorzystywały historię git i plik postępu pomiędzy sesjami. Późniejszy raport Anthropic dotyczący projektowania harnessu oddziela kompakcję od przekazania w świeżym kontekście i podaje, że przekazania zwiększają nakład orkiestracji, zużycie tokenów i czas ścienny, bez publikowania danych przypisujących te koszty samemu przekazaniu.


Używaj trace’ów do rozróżniania trzech awarii

Poniższe trzy wiersze to ilustracyjne szkice trace’ów, a nie zmierzone uruchomienia ani dane wyjściowe dołączonego laboratorium. Każdy wiersz pokazuje inną awarię, a więc wymaga innej reakcji harnessu.

Co rejestruje traceCo się stałoWłaściwa reakcja
Wywołanie tylko do odczytu get_order_status zwraca 503; żadne wywołanie zmieniające stan nie jest w tokuTymczasowe wyszukiwanie zakończyło się niepowodzeniemPonów wyszukiwanie z limitem i backoffem
create_test_order przekracza timeout, a następnie wyszukiwanie statusu znajduje zamówienie 123 z kluczem idempotencji checkout-42Usługa utworzyła zamówienie, ale odpowiedź została utraconaZwróć istniejące zamówienie; nie twórz kolejnego
Edycja i test jednostkowy przechodzą, ale trace nie zawiera wyniku tests/checkout_discount.spec.ts dla testowanego snapshotuBrakuje wymaganego dowodu akceptacjiPozostaw uruchomienie otwarte i wyślij przeglądarkowy test akceptacyjny

Awaria wyglądająca na tymczasową nie sprawia, że każde wywołanie można bezpiecznie powtórzyć. Pierwszy wiersz dotyczy wyszukiwania tylko do odczytu. Drugi dotyczy żądania zmieniającego stan, więc klucz idempotencji i status po stronie serwera decydują, czy dozwolona jest kolejna próba utworzenia. Trzeci nie jest w ogóle awarią narzędzia; harness nie zebrał jeszcze dowodu wymaganego do zaakceptowania zmiany rabatu.

Transkrypt rozmowy rejestruje to, co widział model. Nie może potwierdzić, czy usługa zamówień zatwierdziła żądanie przed zniknięciem odpowiedzi. Trace może dostarczyć taki dowód tylko wtedy, gdy zawiera odpowiedni wynik serwera lub wyszukiwanie statusu; sam timeout po stronie klienta pozostawia wynik nierozstrzygnięty. Trwałe rekordy operacji i akceptacji muszą łączyć wywołanie klienta, decyzję o akceptacji, tożsamość operacji, wynik serwera lub wyszukiwanie statusu, testowany snapshot i wynik testu akceptacyjnego. Trace’y mogą ujawniać te powiązania podczas debugowania, ale nie powinny stawać się rejestrem odzyskiwania. Te pola informują harness, którą z trzech ścieżek należy obrać.

Powtarzający się objawMała zmiana do wypróbowaniaCo mierzyć
Wyszukiwania tylko do odczytu kończą się przejściowymi błędamiOgraniczone ponowienie z backoffemWspółczynnik odzyskania, dodatkowe wywołania, czas ścienny
Wznowione sesje powtarzają ukończoną pracęUstrukturyzowane przekazanie postępuZduplikowane akcje narzędzi po wznowieniu
Przy ukończeniu brakuje wymaganych testówOdrzucaj ukończenie, dopóki każdy wymagany test nie przejdzieZadania zaakceptowane bez wszystkich wymaganych testów
Wady wizualne przechodzą przez testy deterministyczneEwaluator w świeżym kontekście z rubrykąWykryte wady, fałszywe odrzucenia, czas przeglądu
Agent edytuje pliki poza zakresemWęższe uprawnienia narzędziZablokowane wywołania i ręczne nadpisania
Przypomniana pamięć wypiera bieżące zadanieOgranicz liczbę przywoływanych faktów; uszereguj je przed wstrzyknięciemTokeny zużyte na przywoływanie, ukończone zadania, koszt zadania

W przypadku opcjonalnej pomocy, takiej jak wsparcie planowania, podsumowania i dodatkowi ewaluatorzy, nazwij awarię i zmierz, czy komponent zwraca poniesiony koszt. Uprawnienia, izolacja, wymagania prywatności i obowiązkowe testy akceptacyjne nadal obowiązują, nawet jeśli zwykłe zadania przechodzą bez tych mechanizmów. Testuj te ograniczenia za pomocą przypadków adwersarialnych i jawnych niezmienników; mały benchmark sukcesu nie uzasadnia ich usunięcia.

Przekształcenie tych powtarzających się awarii w wersjonowany zestaw regresyjny to osobne zadanie. Opisałem je w osobnym artykule Ewaluacja agenta AI w produkcji.


Mierz jedną zmianę naraz

Ablation mierzy, czy komponent harnessu wywołuje oczekiwany efekt, zmieniając go lub usuwając, podczas gdy reszta eksperymentu pozostaje stała. Na przykład: czy linting edytora pomaga temu modelowi na tym zestawie zadań?

Stosuj następujący protokół:

  1. Zamroź wersję modelu, instancje zadań, środowisko, gradera i prompty niezwiązane z testowanym komponentem.
  2. Przydziel obu wariantom taki sam łączny budżet tokenów, czasu i pieniędzy.
  3. Wybierz liczbę prób lub regułę zatrzymania przed uruchomieniem porównania.
  4. Uruchom te same instancje zadań w obu wariantach. Ponieważ wyniki modelu są zmienne, powtórz każde zadanie kilka razy.
  5. Raportuj średnią wraz z rozrzutem lub przedziałem ufności.
  6. Policz każdą rozpoczętą próbę, w tym timeouty, zatrzymania przez politykę, awarie harnessu i błędy ewaluatora.

Sam współczynnik sukcesu może ukrywać kosztowny komponent. Co najmniej śledź zadania błędnie zaakceptowane jako ukończone, koszt i czas ścienny ukończonego zadania, błędy narzędzi, zduplikowane zamówienia, minuty przeglądu i ręczne nadpisania uprawnień. Wybierz metrykę, która odzwierciedla rzeczywisty koszt produktu. Wzrost liczby ukończonych zadań o dwa punkty to zła wymiana, jeśli podwaja kolejkę do przeglądu.

Parowany eksperyment migracji płatności pozwala mierzyć przekazanie postępu. Każda para control/treatment zaczyna od tego samego commita repozytorium i zainicjalizowanego checkpointu, z tym samym modelem, zadaniem, graderem i łącznym budżetem. Jedynym przełącznikiem jest przekazanie. Główna metryka liczy zduplikowane akcje narzędzi po wznowieniu: akcja jest duplikatem, gdy jej operacja i artefakt odpowiadają krokowi, który poprzednia sesja już ukończyła.

Parowany test ablation przekazania postępuParowany test ablation przekazania postępu

Artykuł SWE-agent utrzymuje GPT-4 Turbo na stałym poziomie w 300-zadaniowym podzbiorze SWE-bench Lite i raportuje 18,0% rozwiązanych zadań dla pełnego interfejsu, w porównaniu z 11,0% dla agenta działającego wyłącznie w shellu, któremu dostarczono działającą demonstrację, oraz 7,3% dla tego samego agenta bez demonstracji. Nagłówkowa różnica 10,7 punktu jest mierzona względem baseline’u 7,3%; Część 3 omawia te same trzy liczby od strony projektowania interfejsu. Artykuł zmieniał również pojedyncze cechy interfejsu:

Zmiana interfejsuRozwiązane
Pełny interfejs SWE-agent (referencyjny, bez zmian)18,0%
Edytor bez lintingu15,0%
Pełny plik zamiast widoku 100 linii12,7%
Pełna historia obserwacji zamiast pięciu ostatnich15,0%

Liczby te dotyczą tego modelu, benchmarku i limitu $4 na zadanie. Trzy wiersze poniżej referencyjnego to użyteczne testy jednej cechy: w każdym zmieniono jedną cechę interfejsu, a model i konfiguracja ewaluacji pozostały stałe.

LangChain opublikował szersze porównanie ze stałym modelem dla deepagents-cli. Raportuje wzrost w Terminal-Bench 2.0 z 52,8% do 66,5% przy stałym gpt-5.2-codex, podczas gdy zespół zmieniał system prompt, narzędzia i middleware. Wpis łączy kilka zmian i nie podaje przedziału ufności, porównania ze stałym łącznym budżetem ani tabeli ablation dla poszczególnych zmian. Wynik ten nie pozwala ustalić, która zmiana pomogła. Nazwy modeli w tej sekcji to modele utrzymywane jako stałe przez poszczególne badania w czasie ich przeprowadzania; przenośny jest protokół, a nie lista modeli.

Nowsze porównanie pokazuje, dlaczego konfiguracja API należy do zamrożonego baseline’u. W swoim raporcie ARC-AGI-3 z 29 lipca 2026 r. OpenAI podaje, że publiczny wynik GPT-5.6 Sol wzrósł z 13,3% do 38,3%, gdy harness zachowywał rozumowanie i używał kompaktowania zamiast usuwać rozumowanie i skracać historię. Metryką jest Relative Human Action Efficiency, a nie odsetek rozwiązanych zadań. To raportowane przez dostawcę, zagregowane porównanie; nie izoluje obu ustawień ani nie ustala rozmiaru efektu w produkcji. Przy aktualizacji zapisuj API, zachowywanie rozumowania, politykę kompaktowania i budżety obok identyfikatora modelu. W przeciwnym razie pozorna regresja modelu może wynikać z braku możliwości w adapterze.

Uwzględnij interwencję dostawcy w zestawie awarii. misalignment_policy_violation musi trafić na ścieżkę zatrzymania i przeglądu nawet po strumieniowaniu danych wyjściowych; nie jest to przypadek tymczasowy, który należy ponawiać. Część 4 omawia zakres zależny od API. Sprawdź, czy harness zatrzymuje wysyłanie kolejnych wywołań i rejestruje już ukończone efekty.

Raport Anthropic dotyczący długotrwałego tworzenia aplikacji to jakościowe, specyficzne dla produktu studium przypadku, a nie kontrolowany benchmark. Aplikacją jest RetroForge, narzędzie do tworzenia gier 2D w stylu retro; w Sprincie 3 ewaluator harnessu sprawdzał 27 kryteriów obejmujących edytor poziomów. Prace rozpoczęto na wcześniejszych modelach Opus, a po wydaniu Opus 4.6 zespół usuwał komponenty harnessu jeden po drugim, aby sprawdzić, które z nich nowszy model uczynił zbędnymi. Raport wskazuje, że wywołania ewaluatora stały się narzutem w zadaniach, które Opus 4.6 potrafił niezawodnie ukończyć samodzielnie, ale nadal pomagały na granicy możliwości modelu. Przykład uzasadnia ponowną walidację starego scaffolding’u po zmianie modelu; nie szacuje ogólnego rozmiaru efektu.


Utrzymuj możliwość edycji harnessu po uzasadnieniu jego obecności

Ablation pomaga utrzymać harness w niewielkim rozmiarze, ale jego kod może przetrwać model, pod który go dostrojono. Żądanie takie jak „maskuj sekrety w każdej ścieżce przechwytywania” opisuje zachowanie, a nie plik. W produkcyjnym harnessie takie zachowanie może obejmować wiele etapów wykonywania i współdzielony stan. Zanim bezpiecznie je zmienisz, musisz znaleźć wszystkie miejsca implementacji — i to samo musi zrobić agent programistyczny, któremu delegujesz zadanie.

Opcją na etapie badawczym jest preprint z 2026 roku autorstwa Wang et al., Harness Handbook, który nazywa to lokalizacją zachowania. Handbook buduje mapę bazy kodu harnessu zorientowaną na zachowania. Analiza statyczna, niewymagająca wywołań modelu, wyodrębnia graf programu, a następnie LLM porządkuje jego jednostki według etapów wykonywania.

Maintainer lub agent programistyczny zaczyna od przeglądu systemu, otwiera odpowiedni etap wykonywania i schodzi do wpisów zakotwiczonych w kodzie źródłowym dla funkcji lub pliku. Rejestr stanu zapisuje, gdzie stan współdzielony jest zapisywany i odczytywany pomiędzy etapami. Hierarchia ta utrzymuje niewielki rozmiar przeglądu, zachowując jednocześnie ścieżkę do źródła.

Aktualność to osobna reguła. Mapa jest pomocą nawigacyjną; zachowanie ustala aktualny kod źródłowy. Każdy locator musi rozwiązywać się względem aktywnego repozytorium. Handbook zamraża nieaktualne wpisy zamiast zgadywać, a każda niepusta różnica synchronizuje ponownie wpisy, na które wpływa.

Diagram kompresuje pętlę modyfikacji: żądanie dotyczące wyłącznie zachowania schodzi przez poziomy handbooka, każdy kandydat na locator jest weryfikowany względem aktywnego repozytorium przed zapisaniem planu, a każda zastosowana różnica synchronizuje mapę.

Przekierowanie zmiany zachowania przez harness handbookPrzekierowanie zmiany zachowania przez harness handbook

Ewaluacja Handbook porównuje dopasowane warianty po 30 żądań na repozytorium. Nie dowodzi równości łącznych budżetów, nie obejmuje powtarzanych stochastycznych prób ani estymat niepewności, a raportowane porównania wykluczają brakujące wyniki i błędy plannera. Ilustruje zatem część powyższego protokołu, a nie jego całość. Obejmuje dwa harnessy open source: Terminus-2 (sześć plików Python) i monorepo Codex (2267 plików Rust). W każdym przypadku planner tylko do odczytu, zasilany przez DeepSeek-V4-Pro, badał repozytorium bezpośrednio albo korzystał z routingu przez handbook. Żądania, repozytorium, uprawnienia narzędzi i dekodowanie były identyczne w obu wariantach. Trzech judge’y (GPT-5.5, Opus 4.8, DeepSeek-V4-Pro) oceniało każdy plan edycji pod względem lokalizacji, kontroli zakresu i rozumowania — należy zauważyć, że jeden z judge’y jest tym samym modelem, który tworzył plany. Zwycięstwo oznacza, że wynik jakości w skali 0–100 jednego wariantu przewyższył wynik drugiego o co najmniej trzy punkty; w przeciwnym razie porównanie judge–żądanie uznawano za remis. Raportowany współczynnik to liczba zwycięstw podzielona przez prawidłowe porównania judge–żądanie:

HarnessWspółczynnik zwycięstw baseline’uWspółczynnik zwycięstw z handbookiemTokeny plannera
Terminus-2 (6 plików)26,7%45,6%−8,6%
Monorepo Codex (2267 plików)28,3%38,3%−12,7%

Planner wspomagany handbookiem wygrywał częściej i używał mniej tokenów plannera w obu repozytoriach. Wynik należy interpretować wraz z warunkami: trzech judge’y LLM oceniało plany edycji utworzone przez jeden model plannera dla dwóch harnessów. Badanie oceniało plany, a nie wykonane różnice ani wskaźniki defektów w produkcji.


Wypróbuj metodę w dołączonym laboratorium

Projekt harness-demo z commitem 517353f3 to małe, deterministyczne ćwiczenie obejmujące 12 ogólnych zadań syntetycznych dotyczących zmian w kodzie, takich jak fix-parser-edge-case, split-large-module i wire-browser-test. Nie implementuje fikcyjnego repozytorium sklepu.

Każdy fixture zadania deklaruje poziom trudności oraz cztery warunki logiczne: niestabilne narzędzie, utracony postęp, pominiętą lukę implementacyjną i niejednoznaczne ukończenie. Symulator wyprowadza piąty warunek dla trudnych zadań, które wymagają również pliku postępu: bez context_reset kompaktowanie zachowuje nieaktualne założenia. Deterministyczny grader oznacza zadanie jako zaliczone tylko wtedy, gdy wybrana konfiguracja obsłuży każdy mający zastosowanie warunek. Nie jest uruchamiany żaden model ani zewnętrzna usługa.

Polecenia odpowiadają na różne pytania:

  • make check uruchamia Ruff i siedem testów jednostkowych, w tym walidator odrzucający każdą parę ablation, która zmienia więcej niż jeden komponent.
  • make run wyświetla skumulowaną macierz dydaktyczną, a następnie pięć prawidłowych porównań leave-one-component-out.
  • make failures podaje nieobsłużony warunek dla każdego nieudanego zadania. Pełny harness powinien zakończyć się wynikiem all synthetic tasks pass.
make check
make run
make failures

Sekcja przyczynowa make run wygląda następująco:

component                 control  treatment  delta
retry_policy              8/12     12/12       +4
progress_handoff          7/12     12/12       +5
evaluator                 8/12     12/12       +4
fail_closed_acceptance    7/12     12/12       +5
context_reset            10/12     12/12       +2

W każdym wierszu control to pełna konfiguracja z usuniętym jednym komponentem; treatment przywraca wyłącznie ten komponent. Wcześniejsza macierz skumulowana jest przydatna jako orientacja, ale niektóre jej sąsiednie wiersze dodają jednocześnie kilka komponentów i dlatego nie pozwalają zidentyfikować przyczyny.

Laboratorium waliduje każdą zadeklarowaną parę przed jej uruchomieniem. Testy regresyjne obejmują również celowo nieprawidłową parę, która jednocześnie zmienia politykę ponowień i ewaluator; walidator ją odrzuca.

Laboratorium porównuje wszystkie pięć pól komponentów podczas walidacji pary. Ten uruchamialny fragment pokazuje tę samą ochronę dla jednej prawidłowej pary przekazania postępu:

from dataclasses import dataclass, fields

@dataclass(frozen=True)
class Config:
    progress_handoff: bool = False
    evaluator: bool = False
    retry_policy: bool = False
    fail_closed_acceptance: bool = False
    context_reset: bool = False

def changed_components(control: Config, treatment: Config) -> tuple[str, ...]:
    return tuple(
        field.name
        for field in fields(control)
        if getattr(control, field.name) != getattr(treatment, field.name)
    )

control = Config(progress_handoff=False, evaluator=True, retry_policy=True)
treatment = Config(progress_handoff=True, evaluator=True, retry_policy=True)
assert changed_components(control, treatment) == ("progress_handoff",)

Którą warstwę otworzyć, gdy uruchomienie się nie powiedzie

Seria wychodziła od pętli rozumowania na zewnątrz. Zacznij od pierwszej zaobserwowanej awarii, a następnie zbadaj komponent odpowiedzialny za daną funkcję. Uruchomienie może obejmować więcej niż jeden komponent:

Co zrobiło uruchomienieGdzie znajduje się poprawkaCzęść
Wybrało słaby następny krok mimo właściwych informacji dostępnych przed nimPętla rozumowania lub model1
Powtarzało pracę albo utraciło decyzję podjętą godzinę wcześniejSkładanie kontekstu i przekazywanie pracy2
Nie potrafiło wyrazić potrzebnej akcji albo błędnie odczytało zwrócony wynikKontrakt narzędzia3
Zrobiło coś, do czego w ogóle nie powinno mieć dostępuReguły uprawnień4
Utraciło wszystko po śmierci workera w trakcie wywołaniaSesja, checkpoint, sandbox5
Ogłosiło sukces przy nieukończonej pracyTesty akceptacyjne i trace’y6

Cztery wiersze wskazują kod harnessu, natomiast wiersz 5 wskazuje runtime. Instrukcje mogą wpływać na zachowanie, ale nie zastąpią kontroli uprawnień, trwałego checkpointu ani testu akceptacyjnego.


Zacznij od jednej pętli i jednego testu akceptacyjnego

Zacząłbym harness agenta programistycznego od jednego kompetentnego modelu, instrukcji repozytorium, kilku wąskich narzędzi, sandboxu i jednego jawnego testu akceptacyjnego. Rejestrowałbym wywołania narzędzi, wyniki, koszty i ten końcowy test w jednym trace, aby pierwsze użyteczne awarie były widoczne bez odtwarzania ich z logów terminala i transkryptów rozmów. To proponowany baseline, a nie dowód z wdrożonego systemu.

Następnie dodawaj tylko to, co uzasadnia trace. Rejestruj, kto utrzymuje każdy komponent, ile tokenów lub sekund dodaje oraz jaki test regresyjny uzasadniłby jego usunięcie po aktualizacji modelu.

Sześć miesięcy później osoba, która zobaczy progress_handoff=True, powinna móc znaleźć trace’y awarii uzasadniające jego obecność oraz przypadki regresyjne, które nadal go utrzymują. Trace’y wyjaśniają, dlaczego komponent istnieje; aktualna mapa zachowania wyjaśnia, gdzie go zmienić.

Jeśli trafiłeś tutaj z wyszukiwarki, pięć poprzednich artykułów zbudowało system wokół pętli rozumowania:

  1. Pętla wybiera następny krok.
  2. Pamięć dostarcza kontekst, a rzeczywisty magazyn checkpointów Postgres zachowuje go.
  3. Kontrakty narzędzi definiują akcje i struktury wyników, które mogą odczytać późniejsze kontrole.
  4. Bezpieczeństwo dodaje hook odmowy i walidator stop-hooka. W przykładzie oba pozostają szkicami, ale wyznaczają punkty kontroli.
  5. Runtime utrzymuje proces aktywny pomiędzy sesjami i awariami.

Seria dodała również opcjonalną powierzchnię serwera MCP i węzeł ewaluatora, który sprawdza szkic raportu, zanim zobaczy go człowiek. Przekierowanie workera przez proxy przechowujące poświadczenia pozostaje proponowanym rozszerzeniem. To zwykłe elementy kodu wokół wywołania modelu. Router jest kodem harnessu z tego samego powodu: wybiera wzorzec rozumowania, zanim rozpocznie się pętla rozumowania.

W przypadku następnego opcjonalnego komponentu pomocniczego zachowaj razem trace awarii, regułę akceptacji i porównanie z wyłączonym komponentem. Pomiń go, jeśli nie potrafisz wskazać jego korzyści. Wymagane ograniczenia bezpieczeństwa i akceptacji nie zależą od tego porównania.


Referencje


The Market Analyst Agent code is on GitHub.