Nigdy nie czerpałem z samego pisania kodu takiej przyjemności jak niektórzy inżynierowie. Co innego z rozwiązywaniem problemów - mniej lub bardziej złożonych. To zawsze mnie kręciło. Ale kod sam w sobie był dla mnie tylko środkiem do celu. Nie bez powodu od lat na moim LinkedInie widnieją dwa słowa, które mówią to wprost: „tech agnostic”.

Większość zawodowej kariery przepracowałem z Pythonem. Nie z wielkiej miłości do tej technologii - z powodu jej zasięgu. Automatyzacja provisioningu usług sieciowych, data platform przetwarzająca setki gigabajtów dziennie, scrape’owanie każdego dostępnego formatu danych, własny framework do monitoringu setek systemów działających na infrastrukturze złożonej z kilku tysięcy maszyn wirtualnych - Python za każdym razem robił robotę. Był jak multitool Leathermana zaczepiony na pasie taktycznym strzelca: sięgasz po niego, działa, idziesz dalej. Ale to wcale nie przeszkadzało mi sięgać po Rusta, PHP, Hack, JavaScript, TypeScript, Bash, a nawet Ruby, jeżeli któreś z nich pozwalało uzyskać rezultat szybciej. Każdy z tych języków to nic więcej niż narzędzie. Środek do osiągnięcia celu.

Zaczynam od tego, bo to jest soczewka, przez którą patrzę na to, co dzieje się teraz.

Prawidłowa ewolucja

Jesteśmy świadkami prawdziwej ewolucji - takiej, która wywraca do góry nogami to, co mieliśmy za pewnik, i redefiniuje samą dziedzinę, z której się wywodzi: informatykę. Przyznam, że tempo tego rozwoju zaskoczyło mnie mocno, mimo że pod skórą czułem, iż najbliższych kilka lat zmieni bardzo dużo. Modele i narzędzia pędzą - procesy kuleją z tyłu, dopiero się kształtują. Zmienia się to, jak powstaje oprogramowanie i jak wchodzi do codziennego życia.

A rzeczą, która w tym wszystkim zyskuje na znaczeniu, jest dokładnie to podejście, od którego zacząłem: technologia jako środek, nie jako cel. Połącz to z podejściem systemowym, a wracasz do tego, co zawsze było istotne - do rozwiązywania problemu, a nie do zachwycania się narzędziem, które go rozwiązało.

To ten sam wątek, który ciągnę od dłuższego czasu: w Idei jako kod - źródło prawdy przenoszące się z kodu wyżej, do intencji. W Dniu, w którym Twoje AI przestaje myśleć - dosadniejsza wersja tej samej myśli:

To, co redukuje ryzyko, to nie lepszy model. To lepsze narzędzia, klarowniejsze procesy i środowisko zbudowane tak, żeby wchłaniać niedoskonałości, a nie udawać, że ich nie ma.

Słowo, na którym wciąż ląduję, brzmi: środowisko. Agent to nie jest system. To jeden komponent systemu, który - szczerze mówiąc - jeszcze prawie nie istnieje.

Jak wygląda brak tego systemu

Wersja odczuwalna, u mnie na biurku, teraz: Warp z kilkunastoma kartami, w każdej pracuje agent. Kilka projektów jednocześnie na kilkunastu repozytoriach - i ja pośrodku, przełączam się między nimi jak kontroler ruchu lotniczego, który dodatkowo musi sam pilotować samoloty.

Każdy z agentów jest zdolny. Każdy potrafi wziąć zadanie i wyprodukować działającą zmianę. To przestało być problemem. Problemem jest wszystko dookoła agenta. Który czeka na moją akceptację? Który po cichu zrobił rebase na gałąź, która ruszyła dwadzieścia minut temu? Które z tych trzech zmian dotykają tego samego pliku? Ile kosztował tamten run? A jeśli zamknę laptopa - czy mogę bezpiecznie pozwolić któremuś pracować dalej z telefonu?

Skieruj dwóch agentów na ten sam katalog, a dostaniesz wyścigi i nadpisane zmiany. Zmiana przez trzy repozytoria to trzy pull requesty spięte kawałkiem sznurka. Agenci dostają szerokie, długo żyjące poświadczenia, bo ograniczanie ich ręcznie to tarcie. Dashboardy pokazują „teraz”, nigdy „jak długo to czekało na mnie”. Tokeny na stronie z rozliczeniem nie mapują się na nic, co cię obchodzi. I generujesz znacznie szybciej, niż jesteś w stanie zrecenzować, ogarnąć i bezpiecznie opublikować - a właśnie tam mieszka prawdziwe ryzyko.

Nic z tego nie jest problemem modelu. To problem koordynacji i kontroli. Lepszy model czyni każdego agenta lepszym - i poszerza lukę między nimi. A ciebie zostawia w środku, z cognitive load, od którego w końcu głowa wybuchnie. I ogarnięcie tego jest prawdziwym zadaniem.

Tego nie da się kupić z półki

„AI Software Factory” to głośna fraza od jakiegoś czasu i wiele firm sprzeda ci taki produkt z półki. Jest jednak haczyk, z którym produkt z półki radzi sobie ciężko: każda organizacja ma inne procesy, każdy człowiek ma inne workflow, każdy zespół ma inne ograniczenia. Software factory to nie generyczne urządzenie, które się podpina. To twoje własne, codzienne workflow - zmapowane uczciwie i dopasowane do pracy z agentami. Nikt nie poda ci tego gotowego, bo nikt inny nie działa według twojego procesu.

Więc buduję własne - najpierw dla siebie. Nie dlatego, że na rynku brakuje produktów, ale dlatego, że użyteczna wersja tego jest nierozerwalnie związana z tym, jak faktycznie pracuję. I to prowadzi do niewygodnej części:

Nie da się efektywnie pracować z GenAI bez wywrócenia swojego dotychczasowego podejścia do pracy do góry nogami.

Nie podkręcenia. Wywrócenia. Fabryka to kształt, który to nowe podejście przyjmuje, kiedy zapiszesz je wprost.

Launcher to jeszcze nie fabryka

Sprowadzone do sedna, „zmapowanie workflow do agentów” oznacza rozdzielenie dwóch rzeczy, które dziś są splątane:

  • Control plane - intencja, stan, historia, polityki, akceptacje, koszt, audyt. Część, w której nigdy nie wykonuje się niezaufanego kodu.
  • Execution plane - miejsce, gdzie agenci faktycznie działają, każdy w izolowanym, jednorazowym sandboksie, na prywatnym workspace wyciętym z niezmiennego snapshotu repozytorium. Część, która zakłada, że wszystko, co uruchamia, może być wrogie.

Pomiędzy nimi: znormalizowane zdarzenia zamiast surowego wyjścia z terminala, trwałe workflowy, które potrafią zatrzymać się na dobę i wznowić bez gubienia wątku, bramki jakości i krok publikacji, który otwiera diff do recenzji - a nie cichy merge.

Metafora fabryki jest celowa. Fabryka nie jest autonomiczna. Jest oprzyrządowana. Widzisz linię, możesz ją zatrzymać, obejrzeć, co z niej zeszło, i rozliczyć, ile kosztowała.

Ludzki osąd, nie ludzkie wąskie gardło

To najłatwiejsze miejsce, żeby powiedzieć coś nie tak, więc doprecyzuję. Human-in-the-loop nie oznacza, że człowiek siedzi na końcu taśmy i czyta każdy diff. Przeglądanie tysięcy wygenerowanych linii dziennie to nie osąd - to wąskie gardło przebrane za osąd. Pisałem o tym już wcześniej i tutaj to się nie zmienia.

Mechaniczna część review to dokładnie to, co powinno być zautomatyzowane i wbudowane w proces: testy, kontrola typów, lintery, audyty bezpieczeństwa i zależności, kontrole polityk, asystenci przeglądu kodu. To są własności, które waliduje się narzędziami - a nie takie, które zmęczony człowiek wypracowuje, czytając linijka po linijce. Zadaniem fabryki jest je uruchomić i oddać zwięzły werdykt - co się zmieniło, co przetestowano, co nie przeszło, ile kosztowało, gdzie leży ryzyko - zamiast ściany kodu.

Po stronie człowieka zostaje to, co zawsze było właściwą pracą: wybór, który problem warto rozwiązać, własność architektury i intencji, ocena, czy output faktycznie rozwiązuje problem, oraz utrzymanie władzy nad decyzjami o konsekwencjach - które wrażliwe akcje się wykonają, kiedy praca przekroczy próg kosztu i co zostanie opublikowane, i kiedy.

Granica kontroli wynika wprost z tego. Agenci nigdy nie trzymają kluczy do repozytorium. Osobny serwis publikacji bierze zaakceptowaną zmianę, pobiera krótko żyjące poświadczenia, odtwarza ją w czystym środowisku, uruchamia bramki i otwiera draft pull requesta. Agent produkuje kontrybucję, człowiek - czytając dowody, nie przewijając kod - decyduje, czy stanie się ona publikacją. Ta granica się nie przesuwa. Za to stos kodu, który człowiek musi przeczytać, żeby za nią ręczyć, powinien dążyć do zera.

Czego świadomie NIE buduję

Uczciwy zakres to w tym samym stopniu lista „nie”, co „tak”. To nie jest zamiennik dla inżynierów, code review, dostawców Gita czy CI - to się kręci wokół nich. Nie nowy agent ani model - orkiestruję te dobre, które już istnieją. Nie wspólny, zapisywalny folder do „współpracy” agentów - z założenia odwrotnie. Nie coś, co do uruchomienia wymaga Kubernetesa - najpierw ma być użyteczne na jednej maszynie. I nie „autonomiczny zespół software’owy”, który usuwa człowieka z czegokolwiek, co ma znaczenie. Jeśli któryś z kolejnych wpisów zboczy w stronę teatru autonomii - potraktuj to jak błąd w pisaniu.

Start local first

Wersja pierwsza działa na Mac mini, sterowana z przeglądarki i z iPhone’a. To ograniczenie jest zaletą. Local first, nie local only: na tyle mała, żeby wymusić realne decyzje o tym, co udźwignie jeden węzeł, i tak ułożona, żeby control plane mógł później przenieść się na zawsze-włączony serwer, a Mac został prywatnym węzłem wykonawczym. Zacznij od najmniejszego systemu, który zachowuje właściwe granice. Dokładaj infrastrukturę dopiero wtedy, gdy zażąda tego pomiar - a nie trend.

Dlaczego piszę o tym, zanim to zbudowałem

Bo plan tej serii brzmi build first, claim second i zamierzam się tego trzymać. Ten wpis nie zawiera pomiarów i niczego nie dowodzi - to deklaracja intencji, zapisana na papierze, żeby kolejne wpisy musiały być uczciwe. Każdy z nich weźmie jedno realne pytanie - jak izolować wykonanie agenta, jak wielu agentów dzieli projekt bez jego psucia, jak run zatrzymuje się na akceptację z telefonu i bezpiecznie wznawia, ile naprawdę kosztuje zweryfikowana zmiana - i odpowie na nie dowodami, łącznie z tymi niewygodnymi. Tam, gdzie założenie z tego wpisu okaże się błędne, wolę pokazać korektę, niż po cichu zredagować przeszłość.

Jeśli mechaniczne tłumaczenie z intencji na kod przenosi się na agentów, to ciekawa praca przenosi się razem z nią: precyzyjne opisywanie intencji i budowanie środowiska, które zamienia intencję w oprogramowanie, któremu można zaufać. To środowisko jest właściwym produktem. Agenci to tylko ta część, która już działa.

W następnym odcinku: dlaczego control plane i execution plane muszą być rozdzielone - i co się psuje, kiedy harness kodujący działa wewnątrz twojego backendu.

— Adrian