O czym jest ten film
- Anthropic opublikował tekst o tym, jak w dwutygodniowym sprincie uczynił claude.ai i aplikację Claude Desktop około trzykrotnie szybszymi — głównie dzięki pracy samego Claude’a.
- Centralna teza: gdy Claude może coś zmierzyć, może to przyspieszyć — instrumentacja przestaje być „krokiem zerowym”, a staje się pierwszym krokiem optymalizacji.
- Praca toczyła się przez Claude’a Tag — bota Claude w Slacku — na wewnętrznym modelu badawczym porównywalnym z Opusem 5.5, z ograniczonymi barierami bezpieczeństwa.
- Konkretne liczby: czas do pierwszej reakcji strony spadł z 3,1 s do 0,55 s, start sesji Claude Code z 0,8 s do 0,3 s; łącznie to dziesiątki tysięcy zaoszczędzonych godzin czekania dziennie.
- Techniki: statyczny kompozytor wypalony w HTML, prekompilowana pamięć podręczna kodu V8, prefetching sescji przy najechaniu kursorem, o 90% mniej renderów sidebara.
- Zamiast zegara — deterministyczne liczniki (instrukcje JS pod Valgrindem, commity Reacta, wywołania V8, przeliczenia stylów) oraz „zapadki” w CI: limity, które mogą tylko maleć.
- Smaczki techniczne: myślniki pauzy wrzucające całe łańcuchy na wolniejszą ścieżkę UTF-16, 6 900 hooków w ścieżce pisania, selektor CSS dokładający 24 ms do każdej zmiany w DOM.
- Theo testuje efekty na żywo i wyłapuje regresje: usunięte wątki zostają w sidebarze jako „duchy”, świeżo utworzona rozmowa znika po odświeżeniu — cache nie jest unieważniany.
- Praktyczne lekcje z promptowania: zachęty do śmiałości („jestem otwarty na szalone pomysły”, „bądź odważniejszy”) realnie zmieniają zachowanie modelu — podobnie jak niedocenianie jego szacunków czasu.
- Wnioski kulturowe: firmy świetne w trenowaniu modeli nie muszą być dobre w inżynierii oprogramowania; „praca wokół slopu” staje się nową umiejętnością inżyniera.
10 najważniejszych takeaways — z kontekstem zastosowania
1.Zmierz, zanim poprawisz
Na czym polega: Serce metody Anthropic: model, który dostaje metrykę i baseline, potrafi ją systematycznie obniżać. samo „popraw wydajność” skazuje go na zgadywanie.
Jak stosować: Dziel zadanie na dwa kroki: najpierw „znajdź sposób zmierzenia tego problemu i zwaliduj, że pomiar odzwierciedla rzeczywistość”, dopiero potem „popraw”. W własnych projektach zacznij od zbudowania benchmarku dla jednej, wąskiej ścieżki użytkownika.
Na co uważać: Pomiar musi zaczynać się od interakcji użytkownika i kończyć na wyrenderowanym wyniku — inaczej dostaniesz ładne wykresy, które nic nie mówią o realnych odczuciach.
2.Deterministyczne liczniki i „zapadki” zamiast zegara w CI
Na czym polega: Czas rzeczywisty jest zbyt zmienny na bramkę CI. Anthropic używał liczby instrukcji JS (Valgrind + Node w trybie predictable), commitów Reacta czy wywołań V8 — deterministycznych, powtarzalnych w jednym uruchomieniu — a limity w CI mogły tylko maleć („zapadka”).
Jak stosować: Dla gorących ścieżek kodu ustaw licznik, sprawdź go raz, zapisz jako baseline i każde PR-owi go nie podnosić. Po każdej poprawie obowiązkowo obniżaj sufit.
Na co uważać: Licznik pośredni może nie przekładać się na odczuwalny czas. Każdy benchmark, który jest niestabilny albo nie koreluje z opóźnieniami użytkowników, wyrzucaj — inaczej agent „wspina się na złym wzgórzu”.
3.Agresywny cache bez unieważniania rodzi „duchy” w interfejsie
Na czym polega: Theo pokazał na żywo: usunięte wątki zostawały w sidebarze, klikanie nich dawało błędy, a świeżo rozpoczęta rozmowa przepadała po odświeżeniu — bo dane trzymane lokalnie nie były synchronizowane z serwerem.
Jak stosować: Dane z cache pokazuj natychmiast, ale z oznaczeniem niepewności (delikatne rozmycie, przenikanie) i domykaj synchronizację zaraz po pierwszym renderze. Zmieniaj hierarchię zapytań (najpierw to, co potrzebne do interakcji), zamiast wyłączać requesty.
Na co uważać: Agent zachęcany do redukcji liczby wywołań sieciowych chętnie „ubije” fetch, który odpowiada za spójność danych. Sprawdzaj ręcznie scenariusze, których nikt ci nie zgłosi — np. pracę w dwóch przeglądarkach.
4.Śmiały prompt realnie zmienia zachowanie modelu
Na czym polega: Komunikaty typu „cele to nie meta, bądź ambitny”, „jestem otwarty na szalone pomysły” czy „wystaw PR teraz, bądź odważniejszy” wyciągały Claude’a z bezpiecznych, wydeptanych ścieżek. Theo uzyskał podobny efekt (fork rusty_v8 i własny runtime z 2–4× zyskiem) promptem „im bardziej radykalne, tym lepiej”.
Jak stosować: W stałych instrukcjach agenta dodaj wyraźne pozwolenie na radykalne pomysły i kontynuację bez pytania („zakładaj, że masz moją zgodę na dalsze działanie; ja podaję oczekiwany efekt”). Przy permanencie poproś o kilka skrajnie różnych propozycji.
Na co uważać: Śmiałość bez zabezpieczeń kończy się regresjami. Najpierw testy, flagi funkcji i zapadki, dopiero potem zdejmowanie hamulców.
5.Nie pytaj modelu o terminy
Na czym polega: Claude wycenił sprint na dwa tygodnie — 12 z 13 celów osiągnął w trzy dni. Opus ocenił przebudowę możliwą w kilka godzin na 25 dni roboczych. Modele nie rozumieją własnych możliwości i są przy tym buffo pewne siebie.
Jak stosować: Pytaj o podział pracy, zakres i kolejne kamienie milowe, a nie o kalendarz. Postęp weryfikuj komunikatami o konkretnych efektach (PR, benchmark), nie deklaracjami czasu.
Na co uważać: Pewność siebie modelu w szacunkach nic nie znaczy — traktuj ją jako ozdobnik, nie jako dane.
6.Flagi funkcji, automatyczny review i sprzątanie na bieżąco
Na czym polega: Przez dwa tygodnie Anthropic wprowadził blisko 200 flag; każda zmiana widoczna dla użytkownika wypuszczana za krótkotrwałą flagą, każdy PR przez automatyczny review i min. jedno ludzkie zatwierdzenie. Ponad połowa flag zniknęła jeszcze przed końcem sprinta.
Jak stosować: Zanim puszczenie agenta na wolność, ustaw mechanizmy bezpieczeństwa z góry. Flagi klasyfikuj jako wyłącznik albo rampę i wycofuj, gdy tylko jest bezpiecznie.
Na co uważać: Zaległe flagi gniją i rozrastają się w dług techniczny. Wygrane wydajnościowe w szybko zmieniającej się bazie kodu same z siebie znikają — każda wymaga ochrony.
7.Zbuduj sobie ścieżkę testów bez tarcia
Na czym polega: Theo: jedna etykieta na GitHubie buduje instalator aplikacji z danego PR-a — test to jedno pobranie, nie kwadrans klonowania i kompilowania. W wielu firmach przetestowanie zmiany to 15–25 minut i nikt tego nie robi.
Jak stosować: Zautomatyzuj budowanie testowych artefaktów prosto z PR-a; testuj na osobnej maszynie, nie ruszając roboczej. Ręcznie sprawdzaj rzeczy, których użytkownicy nie zgłoszą.
Na co uważać: Tarcie w testowaniu zniechęca do testowania w ogóle — a regresje, których nikt nie zgłosi, dla metryk produkcyjnych nie istnieją.
8.„Slop” ma wartość, nawet gdy nie trafia do produkcji
Na czym polega: Theo wygenerował kilka tysięcy linii testów-wartości (na ~100 linii testów przypada 10 linii kodu produkcyjnego), których nigdy nie przeczytał — a one w CI aktywnie łapią regresje i dają sygnał agentom w PR-ach.
Jak stosować: Używaj agentów do składania testów-stróżów: baseline’ów ładowania danych, porównań snapshotów, komentarzy z wynikami pod PR-ami, z których inne agenty korzystają przy review.
Na co uważać: Wygenerowany test raz zwaliduj ręcznie, żeby wiedzieć, że mierzy właściwą rzecz. Nie czytaj każdej linii — czytaj odpowiedzi agenta i rozumiej, co robi.
9.Wąskie wątki, ludzki właściciel i weto dla małych wygranych
Na czym polega: Każdy wątek w sprincie miał jedną ścieżkę lub benchmark i nazwanego właściciela, który rozstrzygał kwestie smaku (jak renderuje się tabela, kiedy pojawia się skeleton). PR na 900 linieto odrzucono jednym zdaniem: 2 ms na wysyłkę nie wart tego kosztu.
Jak stosować: Ograniczaj zakres wątku i zamykaj go przy malejących zyskach. Decyzje o UX uzależniaj od realnych czasów ładowania, nie od domysłów; ogromne zmiany za błahe korzyści wetuj.
Na co uważać: Agenci coraz częściej sami będą proponować „przepisanie świata” dla zysku 2 ms — bez nadzoru to prosta droga do katastrofy.
10.Nowa meta: projektowanie systemów dla agentów, nie czytanie całego kodu
Na czym polega: Theo diagnozował bugi Anthropic bez dostępu do ich repozytorium — po opisach PR-ów i odpowiedziach modelu, na podstawie dekady ręcznej praktyki. Kontrola przesuwa się z czytania kodu na budowanie struktur (pomiary, guardraile, testy), w których agenty działają skutecznie.
Jak stosować: Rozwijaj intuicję przez praktykę i obserwację działań agenta; jeśli w zespole jej nie masz — wynajmij kogoś, kto ma. Rekrutuj na to, co kochasz, nie na to, czego nienawidzisz.
Na co uważać: Firmom świetnym w modelach niekoniecznie musi wychodzić inżynieria oprogramowania — nie myl tych kompetencji przy wyborze dostawców ani przy budowie zespołu.
Redakcyjne tłumaczenie
Powrót do korzeni: nerd od wydajności czyta Anthropic
Większość z was zna mnie jako tego youtubera od vibe codingu i AI, ale starsza część widowni pamięta zapewne czasy, gdy zajmowałem się pełnym stackiem — głównie stroną internetową, wydajnością i kompleksowymi systemami. Uwielbiam się w tym zakopywać: solidne inżynieria, wzorce ładowania danych, problemy z wydajnością, przeglądarkowe bebechy. Dlatego z takim entuzjazmem przyjąłem nowy artykuł Anthropic o tym, jak uczynili claude.ai około trzykrotnie szybszym w dwa tygodnie — w dużej mierze samym Claude’em.
Ten materiał trafia w mnie z kilku powodów. Po pierwsze, jestem performance’owym nerdem. Po drugie — od dawna dokuczam Anthropic za wydajność i ogólny poziom inżynierii. Teraz ich modele wreszcie dorosły do tego, by wydajności pomagać, a nie przeszkadzać. Co zabawne, niedawno opublikowałem film o problemach wydajnościowych w T3 Code, które narobił Fable i które musiałem naprawiać sam. Skoro Anthropic wreszcie przestanie zjadać 18 GB RAM-u przy otwarciu Claude Desktop, być może warto mu się przyjrzeć.
Chcę też zobaczyć, jak ustawili Claude’owi warunki do pracy nad głębokimi problemami wydajnościowymi. To zadanie wcale nieproste, a większość istniejących narzędzi — bądźmy szczerzy — jest po prostu słaba.
Sponsor: WorkOS i standard OMD dla agentów
Dzisiejszy materiał sponsoruje WorkOS. Dziwne pytanie na początek: chcecie, żeby ludzie tacy jak ja korzystali z waszego produktu? Bo jeśli tak, to nie liczcie, że sami będą przechodzić przez klasyczny proces rejestracji — dziś większość pracy odwalają za mnie agenci, więc każda platforma musi być użyteczna dla agenta, łącznie z założeniem konta. WorkOS to platforma logowania dla ludzi i firm — używają jej od OpenAI i Anthropic po Cursor, Bolt, Vantę czy Cartę. Mówię tu o standardzie OMD, zaprojektowanym przez WorkOS we współpracy m.in. z Firecrawl i Cloudflare: jego celem jest ułatwienie agentom rejestracji w waszych aplikacjach — agent może teraz zapisać użytkownika w jego imieniu. Przyjmują go już m.in. Neon, Monday czy Parallel. Więcej pod soy.link/workos.
Liczby sprinta: co naprawdę się zmieniło
Cytat otwierający: „Gdy Claude może coś zmierzyć, może to przyspieszyć. Więc nieustannie znajdowaliśmy kolejne rzeczy do pomiaru”. Podoba mi się. Choć obawiam się, że to początek nowego stylu komunikatów Claude’a — wypolerowali poprzedni, ale prędzej czy później pojawi się nowy, równie zalotny układ zdań.
Rzeczywiste treść: „W sierpniu, w dwutygodniowym sprincie, uczyniliśmy kluczowe ścieżki użytkownika w claude.ai i aplikacji Claude Desktop około trzykrotnie szybszymi. Użytkownicy mówili nam, że jest wolno. Mieli rację”. Ja jestem tym użytkownikiem. Było słabo. Bardzo to zauważyłem, zanim zbudowałem sobie dashboard — i pamiętam dokładnie ten dzień, w którym nagle zrobiło się szybko.
Dane: skupili się na czterech ścieżkach, które pokrywały 95% aktywności. W 75. percentylu czas do pierwszej reakcji przy świeżym wczytaniu Claude’a spadł z 3,1 s do 0,55 s. Start nowej sesji Claude Code: z 0,8 s do 0,3 s. Wczytywanie sesji Claude Code: z prawie trzech sekund do poniżej jednej. Łącznie szacują, że oszczędza to dziesiątki tysięcy godzin czekania — codziennie. I dlatego to się liczy.
Poprawki zauważyłem już w czerwcu; wtedy nawet napisałem, że na hotspotie mobilnym działa szybciej, niż kiedyś działało na łączu gigabitowym. Przy okazji przekopałem się przez kod i zobaczyłem, że przeszli na TanStacka — TanStack Router znacznie ułatwia obsługę nawigacji. To tylko podsyca moją ciekawość: skoro framework już wymienili, skąd wyciśnięto dodatkową szybkość?
Cztery ścieżki szczegółowo. Uruchamianie aplikacji: strona kiedyś startowała w trzy sekundy, teraz w 550 milisekund; desktop z ponad sześciu sekund zejszło do nieco ponad trzech. Rozpoczynanie rozmów — duże poprawy. Wczytywanie rozmów — duże poprawy. Wysyłanie wiadomości: w Cowork z sekundy do 48 ms, w Claude Code na desktopie z 250 ms do 52. Chodzi o aplikacje, nie wersję terminalową.
Test na żywo: szybciej, ale dane wciąż się gubią
Sprawdźmy. Odświeżam… to było naprawdę szybkie. Wysyłam prompt testowy. Jedna z rzeczy, które irytowały mnie najbardziej: przesłanie promptu tworzyło nowy wątek, ale nie przenosiło nawigacji — odświeżenie w złym momencie mogło skasować rozmowę na zawsze. Odpowiedź przyszła bardzo szybko. Sprawdźmy nawigację… nie, wątek zniknął. Mam ten bug znowu: wątek, który mam otwarty, nie trafił do listy ostatnich. Wysyłam „zrób tytuł dowodem mojej teorii” i szybko odświeżam. Jedną ręką, wybaczcie. No i proszę — zabiłem zapis do sidebara, zanim zdążył się utrwalić. Wątek de facto nie istnieje, bo odświeżyłem za wcześnie. Przykro.
Sprawdźmy samo wklejanie: odświeżam i spamuję ctrl-V. Jakaś 0,7 s, może sekunda. Ta jedna próba była brutalna — dwie, trzy sekundy. Wciąż poniżej moich oczekiwań, ale różnicę czuć i to mocno; nawigacja robi się przyjemniejsza. Wątki w końcu się pojawiły — po chwili, ale jednak. Widzicie, o co chodzi: warstwa trwałości danych ma jeszcze sporo problemów.
Ludzie na czacie piszą, że potrzebują Convex. Bez ironii — tak, to rozwiązuje mnóstwo z tych rzeczy.
(Informacja dodatkowa: Convex to dostawca reaktywnej bazy danych dla aplikacji webowych.)
Kilka miesięcy temu robiłem przegląd tego, jak ChatGPT i claude.ai cache’ują dane widoczne na stronie. Oba trzymają teraz wątki z sidebara lokalnie — obecnie w IndexedDB. Dlatego po odświeżeniu pojawiają się niemal natychmiast, bez mignięcia. A teraz głupi przykład, czemu to ma znaczenie. Przechodzę do drugiej przeglądarki i usuwam kilka wątków. Nie ma archiwizacji, więc kasuję. Wróć, odświeżam — i co? Wątki wciąż tam są. Cache nie jest unieważniany: aplikacja dalej sądzi, że istnieją, choć ich nie ma. Klikam — błąd, ale sidebar się nie odświeża. Miał to być film o tym, jak Anthropic podniosło poziom inżynierii. Prawie ulżyło mi, że nic się nie zmieniło. Czat właśnie napisał „kodowanie rozwiązane, AGI nadeszło”. No tak. Obserwujcie te dwa zepsute wątki… i proszę — znikły, akurat gdy narzekałem, choć patrzyłem na ekran. Mam nadzieję, że rozumiecie, czemu to teraz „przykrywka Convex” — to podejście rozwiązuje całą tę klasę problemów. Nawet T3 Code tego nie robi, ale my nie mamy serwera do synchronizacji: wszystko siedzi na waszych urządzeniach.
W T3 Chat robimy to inaczej: w stanie ładowania pokazuję dane rozmyte i przygaszone, bo nie chcę okazywać pewności danych, które jeszcze nie są prawdziwe. Przenikanie włącza się dopiero, gdy z serwera przyjdą prawdziwe wartości. A, przepraszam — mówiłem T3 Code, chodziło o T3 Chat. Wiecie, o co chodzi.
Przy okazji zauważyłem u nas coś podobnego: pasek dolny. Nowy wątek, T3 Chat — „wygląda na to, że nie cache’ujemy danych potrzebnych do otwarcia wyboru modelu i innych elementów na dole kompozytora; boczny panel przychodzi od razu, a pickery się dociągają, co jest szarpiące. Jak by to wyglądało, gdyby cache’ować to tak jak sidebar? Jeśli to proste, zaimplementuj, złóż PR i dopilnuj go”.
Wystarczy dokuczania — weźmy się za artykuł, bo popraw wydajnościowych zrobili sporo. Choć przy okazji pozjeżdżali z kilku wzorców danych, możemy się wiele nauczyć z tego, jak dali Claude’owi dostęp do rzeczy, których potrzebował, by te problemy znaleźć i naprawić.
Jak to zrobili: Claude Tag w Slacku
Całość przeszli przez Claude’a Tag — bota Claude w Slacku.
(Informacja dodatkowa: Claude Tag to integracja Claude w Slacku, wywoływana przez oznaczenie bota w wątku.)
Nawet Claude Code nie użyli, ani niczego lepszego, np. T3 Code. Model: wewnętrzny, badawczy, mniej więcej porównywalny z Opusem 5.5. Mam nadzieję, że to po prostu snapshot tego, co później stało się wersją 5.5, a nie „model porównywalny z 5.5” w tym sensie, w jakim Opus 5 miał być „porównywalny” z Fable — i nie był. Ważna uwaga (podniesiona przez Marię): bez barier bezpieczeństwa. Modele w fazie testów mają ich znacznie mniej, a ja wiem z doświadczenia, że przy grzebaniu w bebechach Chrome’a łatwo wpaść na zabezpieczenia, które blokują wysyłanie promptów, bo system podejrzewa próby hakowania. Uderzyło mnie to kiedyś — potem się okazało, że to po prostu wbudowana kontrola poleceń usuwania plików, czyli mniej groźnie, niż zakładałem. OpenAI-owskie modele wciąż uważam za lepsze w tym, co nazywam sposobem rottweilera: chwyta problem za kark i dusi, aż puści. Modele Anthropic nie dorównują im w rozdzieraniu wydajności na strzępy — choć sporo wynika z narzędzi: Codex ma lepsze sterowanie komputerem i sprawniej wyciąga ślady z Chrome. Mimo to obu brakuje wprawy na tyle, bym mógł odpuścić — w szczegóły wciąż zaglądam sam. I dlatego jestem taki ciekawy, jak Anthropic to zrobił.
Deklarują: przez Claude’a Tag znajdowali wąskie gardła, budowali benchmarki, wdrażali poprawki i obserwowali każdy deployment; sterowali, wyznaczając cele i rozstrzygając kompromisy. W efekcie ponad 3 000 scalonych zmian bez ani jednego incydentu widocznego dla klientów i bez rollbacków. Choć przed chwilą pokazałem rzeczy godne i incydentu, i rollbacku — ale każdy ma swoje miary.
Przed sprintem założyli w Slacku nowy kanał ze stałą instrukcją: „Claude, twoim zadaniem jest zajmowanie się wszystkim, co dotyczy wydajności strony i aplikacji desktopowej Claude. Do twoich obowiązków należy: monitorowanie deploymentów pod kątem regresji, ocena dokładności i kompletności telemetrii, utrzymywanie dopracowanych dashboardów, proaktywne wdrażanie rozwiązań zauważonych problemów i szybkich wygranych, proponowanie projektów wydajnościowych oraz komunikacja z ludźmi z zespołu. Docelowym celem tego kanału jest, byś był tak autonomiczny, jak to możliwe — choć dziś wiemy, że to jeszcze nie jest”.
To okropny prompt. Nie napisali nawet „nie popełniaj błędów”. Nie dziwię się, że były regresje.
Instrumentacja: najpierw zmierz
Claude przeanalizował dane użycia przez serwer MCP Datadog i wskazał cztery ścieżki o największym wpływie: uruchamianie aplikacji, rozpoczynanie rozmów, wczytywanie istniejących rozmów i wysyłanie wiadomości — w wersjach webowej i desktopowej oraz między produktami. Te ścieżki przełożyły się na 13 odrębnych pomiarów. „By ustalić baseline’y, dokładaliśmy instrumentację, aż pomiary stały się bezpośrednio porównywalne: każdy zaczynał się interakcją użytkownika, kończył w momencie wyrenderowania wyniku i rozdzielał pracę klienta od serwera”.
Ludzie niedoceniają, jak ważna jest ta część naprawiania wydajności — nawet jeśli nie są agentem. Trudno naprawić to, czego nie umiesz zmierzyć. Nie zliczę kłótni z poprzednich pracy: „to się wlecze jak smoła”, a oni: „dashboard pokazuje 200 ms”. Potem profilowałem sam i wychodziło, że liczyli od wyrenderowania komponentu w interfejsie, a nie od załadowania strony — a jeśli dojście do tego komponentu brało osiem sekund, sam ślad nic nie znaczy. Ileż to razy pokazywano mi dane, które miały mnie obalić, a które w ogóle nie odzwierciedlały rzeczywistej pracy aplikacji.
Modele fatalnie szacują czas
Sprint ruszył z listą około 20 ręcznie wybranych projektów, każdy pod konkretną ścieżkę. Claude oszacował wpływ każdego w milisekundach, a z tych szacunków ustawiono cele. Część projektów była spora, ale sądzili, że większość dadzą radę zamknąć w dwa tygodnie. Tylko że 12 z 13 celów padło do trzeciego dnia.
Czy wpadli w klasyczny błąd? Planowałem, że Opus zrobi klasyczny rewrite ping.gg na nowoczesny stack, i zapytałem przy okazji: „jak długo zajęłoby zrobienie tego wszystkiego jednym podejściem?”. I proszę — klasyczne przecenianie przez Anthropic. Modele świetnie piszą i rozumieją kod, ale rozumienie własnych możliwości mają marne: zadanie, które moim zdaniem zrobiłby w kilka godzin, wycenił pewnie siebie na około 25 dni roboczych. Po prostu się myli. Uroczo, że myśli inaczej.
Posypałem więc ostrzejszą instrukcją: „Odpal przebieg agenta na moim komputerze Leftbook. Zobaczysz, jak się połączyć przez repo flotylli na tej maszynie. Upewnij się, że repo jest sklonowane, że wszystkie zmienne środowiskowe są na miejscu i że możesz uruchomić Opusa 5.5 przez Claude Code w T3 Code tak, żebym widział wątek tak jak zwykle. Cel: cała implementacja na tamtej maszynie w jednym podejściu, z tyloma subagentami, ilu trzeba, z pełnym dostępem do komputera — bo nie chcę, żebyś zasypywał moją maszynę sterowaniem przeglądarką, gdy na niej pracuję. Jeśli coś nie zadziała, pytaj śmiało”.
Ciekawe, jak to pójdzie — wrócimy do tego. A pointa jest taka: modele fatalnie szacują ramy czasowe, bo nie pojmują, na ile są sprawne. Co jest zabawne, bo klasyka tego żartu brzmi: Claude powiedział im „dwa tygodnie”, a wyszło trzy dni. Oni też słabo to oceniają — jak my zresztą.
Statyczny kompozytor, pamięć V8 i prefetch na hover
Zaplanowane projekty wylądowały przedwcześnie. Dla szybszych startów wypalili statyczny kompozytor wprost w HTML, żeby dało się pisać w trakcie inicjalizacji Reacta. To trik, który my zrobiliśmy już dawno temu. Dodatkowo prekompilowali pamięć podręczną kodu V8, więc główny proces desktopowej powłoki nie kompiluje wszystkiego od zera. Wchodzą głęboko w króliczą norę.
Kazałem agentowi sprawdzić: „Anthropic przemeblował wydajność claude.ai i desktopa. Ten akapit ma kilka fajnych pomysłów: osadzenie HTML dla szybszego kompozytora i — ważniejsze — prekompilowany cache V8. Ciekaw, czy coś takiego da się w T3 Code i co by nam to dało. Zgłoś, co wyszło”.
Kolejna reaktowa zmiana: dla szybszej nawigacji trzymali kompozytor zamontowany między rozmowami i dociągali sesje wcześniej, gdy użytkownik najedzie kursorem — po drodze wycięli 90% renderów sidebara. To dokładnie te rzeczy, które ledwie rok temu robiłem ręcznie w T3 Chat, żeby wycisnąć każdą milisekundę. Klikam losowy wątek… nie tak dobrze, jak liczyłem. Inny… natychmiast. I ten — natychmiast. Pobieranie danych na najechanie kursorem to jeden z najprzyjemniejszych trików: mała zmiana, a interfejs wydaje się absurdalnie żwawy. Dziwię się, że nie mieli tego wcześniej.
Zostawili też Claude’owi przestrzeń na własne pomysły — a te szybko rozrastały się w samodzielne projekty, które wyraźnie przekroczyły pierwotne cele. Więc ustawiali kolejne cele i szukali następnych rzeczy do pomiaru. Cytat z wątku: „Czego jeszcze nie sprawdziliśmy i po czym możemy się wspinać? Gdzie teraz jest największy potencjał? Jestem otwarty na szalone pomysły”.
(Informacja dodatkowa: „wspinanie” — ang. hill climbing — to żargon optymalizacyjny: iteracyjna poprawa jednej metryki małymi krokami.)
Nie lekceważcie tego fragmentu promptu. Brzmi szaleńczo — bo jest szaleńczy. Przy wczesnym testowaniu GPT-6 Astry napisałem coś bardzo podobnego przy wielkim przeglądzie wydajności Lakebeda, mojej prywatnej chmury: małe aplikacje JavaScriptowe miały zjadać minimum zasobów. Po pierwszej fali poprawek wciąż nie byłem zadowolony, więc: „Słyszę, że da się ugrać więcej. Drąż głęboko i znajdź wszystko, czego się da — łącznie ze skrajnymi środkami. Wróć z trzema propozycjami. Im bardziej radykalne, tym lepiej. Nie bój się sięgnąć po niebo”. I tak powstał własny runtime Lakebeda: sforkowałem rusty_v8 i zbudowałem własne środowisko wykonawcze — wzrost wydajności 2–4×.
(Informacja dodatkowa: rusty_v8 to oficjalne powiązania silnika V8 z językiem Rust.)
Z trzech propozycji — persystentna usługa wykonawcza V8, kompilator zapytań podtrzymujący żywe odpowiedzi i trwały „opiekun” każdej aplikacji z lokalnymi danymi — wybrałem pierwszą i jej się trzymałem. Co do Lakebeda: stał się zabawką do takich eksperymentów; robienie z niego produktu, który śmiało wam zaproponuję, nie jest priorytetem. Ale działa — adresu specjalnie nie ukrywam, siedzi w paczce npm. Używam go cały czas, np. wczoraj zrobiłem nim wizualizator danych z dashboardów Artificial Analysis, o niebo czytelniejszy niż ich strona główna. Fajna rzecz: aplikacje same się synchronizują i żywo aktualizują.
I to był wysiłek wojenny: jeden z najdłuższych wątków, jakie robiłem w T3 Code. Planowanie — 20 minut. Pierwsza budowa — jakieś dwie godziny; coś pękło, bo grzebałem na maszynie, więc kazałem kontynuować. Pięć i pół godziny później był PR — i działał świetnie. Po drodze zbudowałem sposoby weryfikacji zarówno poprawy wydajności, jak i braku regresji zachowania. Tak, nie lekceważcie czegoś tak błahego jak „jestem otwarty na szalone pomysły”. I dlatego następny cytat brzmi obłąkańczo, ale trzymam z nimi: „Wszystko da się wspiąć”.
Pomiary bez zegara: instrukcje, commity Reacta i zapadki
Od początku wiedzieli, że chcą iterować szybciej, niż wychodzą deploymenty. Claude mógł pracować asynchronicznie wiele godzin, także nocą — i chcieli, by walidował prototypy bez czekania na dane z produkcji. Szukali więc pomiaru „w laboratorium”. Sam znalazł pierwszy trop: „Co zamiast czasu zegarowego? Możemy np. liczyć instrukcje JS?”. I padła recepta: dla czystych, gorących ścieżek JS — dosłowne liczby instrukcji: benchmark pod Valgrindem z Node w trybie predictable, porównanie z baseline’em trzymanym w repo. Jedno uruchomienie, żadnej statystyki.
(Informacja dodatkowa: Valgrind to narzędzie do precyzyjnej analizy wykonania programu, m.in. zliczania instrukcji procesora.)
Dla ścieżek przeglądarkowych liczenie instrukcji w Chromium nie istnieje, ale jest drabinka innych deterministycznych liczników: commity Reacta na interakcję, liczby wywołań z precyzyjnego pokrycia V8, przeliczenia layoutu i stylów, mutacje DOM. Padło: „Zbadajmy Valgrinda i odpowiednie flagi — po jednym wątku na każdy z przeglądarkowych benchmarków Reacta. Pingnij mnie we wszystkich. Wiesz, czego chcemy. Do dzieła”.
Nie mogę się nadziwić: czytałem niewiele promptów pracowników labów i nie wiem, jak się z tym czuję, że mój styl promptowania wygląda niemal identycznie jak ich. Jestem jednocześnie dumny i zawstydzony. Ktoś kiedyś wyśmiewał mój sposób promptowania — teraz czuję się znacznie lepiej.
Jedenaście minut później działało pięć wątków, każdy przy innym pomiarze. Dlaczego jedenaście minut na odpalenie pięciu wątków? Nie wiem.
I chyba już rozumiem, skąd te dziwne problemy, które wyłapałem wcześniej. Jeśli ktoś — agent lub człowiek — ślepo liczy commity Reacta i wywołania V8, zacznie wyłączać rzeczy, które wcale nie przekładają się na odczuwaną szybkość. Bolesna prawda brzmi tak: gdy strona działa, dodatkowe zapytania sieciowe na desktopie specjalnie nie bolą. I ludzie, i agenty zbyt ochoczo patrzą na każdy request i próbują go ubić, zamiast zmieniać hierarchię zapytań: najpierw to, co niezbędne do interakcji ze stroną, a dopiero potem spójność i aktualność. A taki licznik właśnie do złego zachęca: liczba wywołań V8 nie pokaże ci, kiedy strona staje się interaktywna, ale pokaże każdy request — blokujący czy nie. Agent więc widzi „okazję”: nie pobierajmy danych sidebara, skoro mamy je w pamięci lokalnej, ubijemy sześć z osiemsetu wywołań na tej stronie. I po jakimś czasie masz sidebar, który przestał się synchronizować — dokładnie stan, który pokazałem. Nie najlepsze rozwiązanie. Narzędzie jest użyteczne, ale trzeba je łączyć z realną obserwacją przepływu użytkownika. Nie sądzę, by agenty ogarniały to już od deszczu do deszczu — dlatego wydajnością wciąż zajmuję się z ręką na pulsie. Zaczynam od teorii: „za długo trwa, zanim da się pisać w polu — co proponujesz?”. Potem każę zrobić dema z każdą potencjalną poprawką i sam sprawdzam, czy czuję różnicę. W przeglądach wydajności zdecydowanie zbyt łatwo o niszowe regresje w doświadczeniu.
Dalej w artykule: kazali Claude’owi dowieść, że wspinanie po tych licznikach przekłada się na mierzalne wygrane zegarowe — a benchmarków, których nie dało się udowodnić, po prostu się pozbywali. Każdy nowy benchmark traktowali sceptycznie i miał dwa zadania: być metryką, którą Claude może ruszyć w laboratorium, oraz pełnić rolę zabezpieczenia w CI — liczby, która mogła wyłącznie maleć. Zapadka. „Jeśli benchmark był chwiejny albo nie korelował z opóźnieniami użytkowników, wyrzucaliśmy go, zamiast pozwalać Claude’owi wspinać się na złym wzgórzu”. Bardzo dobrze, że to wyeksponowali.
Trochę własnych rzeczy, bo o wydajności nie umiem inaczej. Niedawno sporo robiłem w warstwie danych T3 Code, żeby wielkie wątki i wznowienia aplikacji nie ciągnęły zbędnych balastu — i dlatego T3 Code ładuje się błyskawicznie nawet w piekielnie długich wątkach. Np. ten mój czteromiesięczny wątek budowy aplikacji SwiftUI, z pięciuset promptami. Klikam… i praktycznie natychmiast. (Było lekkie mignięcie przez dziwny stan przewijania — zabawna zagadka na później.) To efekt przejścia przez piekło: wyszukałem każde miejsce, gdzie dało się nie ładować danych.
Ale najważniejsza zmiana nie dotyczyła samej szybkości. Dodałem akcję testującą różne formaty zapytań, jakie naprawdę występują w aplikacji, na danych spreparowanego „prawdziwego” wątku — żeby pilnować, że nie wychodzimy znacząco ponad istniejący baseline ładowania. To powstrzymało masę regresji. GitHub wkleja wyniki w komentarzu pod PR-em, więc i agent piszący kod, i agenty recenzujące to widzą, wytykają, a czasem sami naprawiają. Sygnał trafia do agentów, zanim problem trafi do mnie — albo, co gorsza, do moich użytkowników.
I raz jeszcze: nawet jeśli nie używacie AI do pisania produkcyjnego kodu, nie używanie go do czegokolwiek to ogromna strata. Taki test-poskładać — „poskładać maszynowo”, w żargonie: slop — to nie był projekt „misji krytycznej”, tylko mgliste „fajnie by było wiedzieć, kiedy pojawiają się regresje”. Agent wypluł zestaw testów, sądzę że z parę tysięcy linii. Nie czytałem ich. I teraz aktywnie bronią naszej bazy kodu. Slop jest użyteczny, nawet jeśli nigdy nie dotrze do użytkownika.
Wracając do artykułu: „Czas zegarowy to to, co czuje użytkownik, ale jest zbyt zmienny — milisekundy to za chwiejna podstawa dla bramek CI. Liczby instrukcji kusiły determinizmem, ale trzeba było dowieść, że idą w parze z zegarem”. Poprosili Claude’a o ściągnięcie licznika w dół na dwóch gorących ścieżkach: procedurze składającej drzewo wiadomości rozmowy i skanerze linii statusu w wyjściu Claude Code. Claude sprofilował obie pod Valgrindem i wykrył, że ćwierć instrukcji pierwszej ścieżki to megamorficzne odwołania słownikowe, rozwiązujące to samo ID wiadomości — trzy razy z rzędu. Bądźmy szczerzy: wzorce ładowania danych to zdecydowana większość problemów tej klasy. Trzykrotne schodzenie tą samą ścieżką zwykle oznacza, że pobieranie danych wywołuje potrójne przerysowanie.
Godzinę później Claude ściął liczbę instrukcji na obu ścieżkach o 48% i 31%, a czas zegarowy o 78% i 44%. Wnieśli dwie nowe zapadki: od tej pory PR podnoszący licznik tych ścieżków obrywa w CI, a codzienny job obniża sufit, gdy tylko liczby spadną. To bardzo dobra praktyka — bez tego każda poprawa staje się przestrzenią do ponownego psucia.
Boli mnie to szczególnie w kontekście pokrycia testami. Nienawidzę code coverage jako idei: liczba opisująca, „jak dobrze przetestowany jest kod”, jest głupia. W Twitchu przepisałem funkcjonalność — z pół miliona linii w pięćdziesiąt tysięcy; nowa wersja wyszła pod flagą, przenieśliśmy wszystkich, było świetnie. Chciałem skasować te stare pół miliona — i nie mogłem, bo pokrycie bazy spadałoby z 95% do 94%. A właśnie: „dodaj testów do zmian” — dodałem. Moje 50 tysięcy linii miało pokrycie stuprocentowe; stare — 96. Ale usunięcie balastu strącało wynik poniżej progu i nigdy nie skasowałem tego martwego, zastąpionego potwora. Przez metrykę.
„Czy licznik śledzi zegar?” — 48% mniej instrukcji, 78% mniej zegara przy drzewie wiadomości. To najlepszy sposób pomiaru — choć nie podano czasów bezwzględnych, a one mają znaczenie: ogolenie 200 ms do 60 ms to co innego niż zjechanie z czterech sekund do pół.
I dochodzimy do centralnej lekcji sprinta: „Zmierzenie czegoś czyni to uchwytne”. Kiedyś pomiar był krokiem zerowym: dodajesz metrykę, czekasz, aż napłyną dane, i dopiero wtedy zaczynasz rozumieć problem. Z Claude’em to po prostu pierwszy krok wspinaczki: gdy tylko ma liczbę do pobicia, zaczyna optymalizować. Największą dźwignią okazało się więc znajdowanie kolejnych rzeczy do pomiaru. Po to wziąłem się za ten artykuł — chciałem zobaczyć nowatorskie sposoby mierzenia.
Pętla pracy, wątek po wątku
To wszystko kręciło się w jednym kanale Slacka, z kilkoma inżynierami i Claude’em w każdym wątku. Sprint ułożył się w pętlę. Po pierwsze: ktoś otwierał wątek o wolnym odcinku ścieżki — często ze zrzutem ekranu albo nagraniem. Po drugie: Claude śledził przepływ i znajdował albo budował benchmark, który problem obnaża. Po trzecie: z obiecującym wynikiem z laboratorium wracał z PR-em — często kilkoma, rozmiarem dobranymi do ryzyka i recenzji, z wszystkim, co widzialne dla użytkownika, schowanym za flagą. Po wdrożeniu obserwował deployment i czytał dane z pola: poprawa — wpina zwycięstwo, obniżając zapadkę; brak poprawy — wyłącza flagę i iteruje. Potem szukał następnego wolnego punktu na tej samej ścieżce.
Jestem wobec tej pętli podzielony. Z jednej strony: nic nie ma znaczenia, jeśli realni użytkownicy nie czują różnicy. Z drugiej: jeśli inżynier, który każe wprowadzać zmiany i scala PR-y, nie testuje ich ręcznie, nie wyłapie regresji, których użytkownicy nigdy nie zgłoszą. Bo bądźmy poważni: ilu ludzi używa Claude’a w dwóch przeglądarkach na tyle, by zauważyć te sidebarowe duchy — i komu chciałoby się to zgłosić w sposób, który ktoś tam w ogóle zauważy? Bez własnych testów takie regresje będą się mnożyć. Dlatego w T3 Code włożyłem tyle pracy w ułatwianie testów nam samym: etykieta na GitHubie, którą o znaczeniu PR-a odpala ręczną budowę aplikacji desktopowej dla macOS. Pobieram instalator i sprawdzam — bez klonowania gałęzi i budowania lokalnie. Mogę to zrobić na MacBooku Air do testów, nie ruszając maszyny roboczej. Rozmawiałem ze wszystkimi — od małych startujących, przez niezależnych deweloperów, po duże firmy — i wszędzie to kuleje: przetestowanie zmiany z PR-a to kwadrans–dwadzieścia pięć minut i wszyscy są wściekli. Jeśli gdzieś chcieć posypać slopem, to właśnie tam: posypcie ścieżki własnych testów, bo to tarcie wpojenia niechęć do testowania w ogóle.
Jestem szczęśliwy, że ten fragment trafił do tekstu: „Ktoś wrzucił nagranie, na którym wiersze sidebara wpadały po załadowaniu strony — wątki czatu i Cowork dociągały się w różnych momentach i strona wyglądała na trzęsącą się. Żaden z istniejących monitorów tego nie widział. Najbliżej był skumulowany layout shift, ale pojedyncze przesunięcie ważyło 0,008 — daleko od progu 0,1. Isaac wpadł na pomysł, by odwołać się bezpośrednio do API niestabilności layoutu”. A ja mówię: nie potrzebujecie sterty pomiarów — wystarczy zcache’ować to jedno zapytanie. Po co sięgać po głębokie API layoutu?
(Informacja dodatkowa: Addy Osmani, o którym mowa za chwilę, to wieloletni inżynier zespołu Chrome, znany popularyzator optymalizacji webowych.)
Cieszę się zresztą, że niedawno zatrudnili Addy’ego Osmaniego z zespołu Chrome — sporo tego bałaganu posprząta.
Do tego doszły testy integracyjne: strona otwierana z zapełnionym sidebarzem, dane wstrzymywane do pierwszego renderu, fail przy jakimkolwiek przesunięciu w nazwanych regionach. I uwaga — to może być właśnie źródło problemu, który wyłapałem. Jeśli w przeglądarce siedzą jakieś dane, a z sieci przychodzą inne, to z definicji jest przesunięcie layoutu. Cztery wątki w pamięci lokalnej, piąty dojeżdża z sieci — i cztery zjeżdżają w dół. Zrobienie tego porządnie, z domykaniem synchronizacji, zawaliłoby ten test. Uwielbiam rekonstruować, skąd biorą się takie wpadki.
Po wdrożeniu Claude przeczytał dane z pola: 31% wczytań strony poruszało czymś już po tym, jak stała się użyteczna — bez żadnej interakcji użytkownika. Rozbierał przyczyny po imieniu: nagłówek dojeżdżający z opóźnieniem, kursor pola tekstowego przesuwający się w bok, gdy ładował się login użytkownika, lista wskakująca w momencie pojawienia się paska przewijania. Naprawiał górnych winowajców paczkami; gdy ci znikali, brał się za kolejnych. Na porównaniu przed/po widać, ile elementów tańczyło w wersji lewej. Przykro patrzeć. To jeden z wielkich plusów danych z cache przy starcie — z jednym zastrzeżeniem: jeśli lokalne dane rozjeżdżają się z prawdą, ruszanie będzie. Ale przesunięcie listy o jeden–dwa elementy to drobiazg, zwłaszcza z delikatnym przenikaniem.
Ktoś na czacie zadał świetne pytanie: jak wyłapać takie rzeczy bez czytania kodu? Odwrócę je żartobliwie: jak ja to zrobiłem, nie widząc ani jednej linijki ich repozytorium? Ten artykuł jest, jak sądzę, mniej szczegółowy niż odpowiedzi, jakie Claude dawał im w Slacku. Tych umiejętności nie wiem, jak dziś zbudować — ja budowałem je przez blisko dekadę ręcznego naprawiania takich rzeczy, na długo zanim AI nadawało się do czegokolwiek. Widzę problemy dzięki historii róbienia tego palcami. Nie muszę czytać kodu ani testów — wystarczy opis PR-a albo odpowiedź Claude’a. To „branch intuition” — intuicja, którą buduje się z czasem. Mogę się mylić; to teoria, którą przy dostępie do bazy kazałbym Claude’owi udowodnić, a potem powiedziałbym zespołowi: kierunek dobry, ale te testy są słabe — oto regresje, które narobicie, jeśli tego nie przemyślicie. Czyli czytanie kodu niczego tu nie rozwiązuje. Trzeba czytać odpowiedzi Claude’a i rozumieć, co robi, gdy to robi. Jeśli przy takich testach czytacie cały kod, daleko nie zajdziecie. Powiem wprost: przy przeglądzie warstwy danych T3 Code napisałem może sto linii testów-slopu na każdą linię kodu produkcyjnego. Stosunek sto do jednego. Kod, który wyszedł, byłby gorszy, gdybym nie posypał tej góry testów do weryfikacji — a regresji, o ile wiem, nie było, co nawet mnie dziwi.
Nie wiem, jak dziś zbudować tę intuicję. Może po prostu pytać Claude’a. Warto wynająć kogoś, kto ją ma, jeśli wam na tym zależy — i pewnie da się jej wyuczyć, tylko nie podam recepty.
Skalowanie w poziomie i „demon liczb”
Gdy pętla zadziałała w jednym wątku, uruchomienie jej wszędzie to kwestia otwarcia kolejnych. To jedna z najlepszych rzeczy przy stawianiu środowiska dla Claude’a — albo, dajmy na to, zdalnego zarządzania maszynami w T3 Code. Gdy masz działający przepływ od deszczu do deszczu dla danej klasy problemów, odpalasz dziesiątki wątków na dziesiątkach instancji na wielu maszynach i równolegle to zjeżdżasz. Znamy to wszyscy z automatyzacji: pisanie kodu na jednorazowe zadanie rzadko się opłaca, ale gdy już stoi, pięciominutowe zadanie robi się w trzy sekundy i można odpalać setki naraz — to zmienia sposób pracy. U mnie zbudowanie infrastruktury testowej zaowocowało tym, że agent sam scalał około czterdziestu PR-ów z poprawkami wydajności w T3 Code. Prawdziwe regresje: niefortunna zmiana animacji na desktopie (sam jej nie lubiłem) i rozjechany przesuwany pasek tweetów na stronie marketingowej. Poza tym — 38 z 40 PR-ów zmergował sam agent. Prawdziwe wygrane. Całkiem niezłe.
Ciekawy szczegół: zamiast zamykać wątki po spełnieniu pierwotnego zadania, Claude szedł dalej. Pojedynczy wątek wystawiał pięćdziesiąt, czasem sto PR-ów optymalizacyjnych. I co ciekawe, to Claude, nie człowiek, otwierał nowe wątki, goniąc okazje znalezione przy okazji osobnych dochodzeń czy nocnych zadań. Shelley, jedna z inżynierek w kanale, podsumowała: „Ten model to demon liczb”. I zaskakująco łatwo coś takiego ustawić — każdy pomiar coś znajdował.
Claude zrobił spis hooków Reacta i znalazł 6 900 hooków i 900 subskrypcji magazynów stanu w ścieżce pisania kompozytora — wszystko przerysowywane przy każdym naciśnięciu klawisza. Prawie siedem tysięcy hooków pod jednym polem tekstowym. Może by tak jednak czasem przeczytać kod, panowie. Wycofuję połowę pretensji. Claude policzył też przeliczenia stylów i namierzył pojedynczy selektor CSS na korzeniu dokumentu, dokładający 24 milisekundy do każdej zmiany w DOM. Wiecie, ile jest takich pułapek? Jedna linijka CSS potrafi spowolnić każdą zmianę w przeglądarce, także w Electronie. Zrobić je zbyt łatwo, a narzędzia Chrome — smutno to pisać — za mało pomagają je znaleźć, zwłaszcza na GPU. Po stronie procesora, pętli zdarzeń i JavaScriptu: ujdzie. Wejdziesz w akcelerowane CSS — powodzenia, miłej zabawy.
Przyjmę nowe nastawienie do inżynierii Anthropic. Mogę przez to narobić sobie kłopotów — trudno. Anthropic postanowiło być pierwszą firmą, która na poważnie eksperymentuje z tym, co się stanie, gdy AI napisze zbyt dużo kodu. Od czasów Sonnet 4 ich baza kodu pełna jest slopu i śmieci. Wyciągnęli lekcje, mocno poprawili model — a teraz, dla dobra nas wszystkich, używają modeli do sprzątania bałaganu, który sami narobili. claude.ai, desktop i, śmiem twierdzić, sam Claude Code to ich poligon: ile slopu wytrzyma produkt i kiedy modele będą wystarczająco dobre, by posprzątać po sobie.
Znaleźli po drodze resztkowe wywołanie przeładowania strony — pół miliona niewidocznych przeładowań dziennie, których żadna metryka obciążenia nie widziała. Claude czytał próbki profilera z bezczynnych kart i wykrył identyczne snapshoty cache klonowane do IndexedDB dwa razy na minutę — na wątku głównym. Ojej. To może być także źródło moich sidebarowych duchów: jeśli dane z sieci przestały tak często zapisywać do IndexedDB, to naturalnie pamięć podręczna się nie aktualizuje.
Świetna uwaga Jamiego z Convex: firmy dobre w robieniu modeli nie muszą być dobre w inżynierii oprogramowania. Lekcja odgrywa się w zwolnionym tempie. Pójdę dalej. Była — jak wiecie — ostra rywalizacja między OpenAI i Anthropic, bo Anthropic wyrósł w dużej mierze z oryginalnego zespołu pretrainingu OpenAI: Dario i koledzy budowali GPT-3 i odeszli przez niezgodność z liderami. Oficjalnie sporo się mówi o obawach bezpieczeństwa — nie sądzę, by w czasach GPT-3 gryzły ich aż tak bardzo. Wielu z nas, mnie włącznie, przyjęło tezę, że prawdziwe tarcie było inne: badacze kontra inżynierowie. OpenAI, choć firma badawcza, stało pod przewodem dwóch inżynierów — Sama Altmana i Grega Brockmana — czyli to inżynierowie wydawali badaczom polecenia i trzymali ich w ryzach inżynierskich standardów: terminy, harmonogramy. To rodziło wzajemną niechęć. Po odejściu tamtych w OpenAI zostało trochę frustracji wobec badaczy i zaczęto szukać inżynierskich rozwiązań problemów badawczych. W Anthropic natomiast — jak to ująć — nie przepadano za inżynierami oprogramowania. Widać to w ich komunikacji do dziś. I stąd, jak sądzę, tak gorliwe pchanie się w kierunku „a co, jeśli zastąpimy inżynierów AI”: skoro się ich nie lubiło, to pewnie i najlepszych nie rekrutowano. A ja daję jedną radę częściej niż inną: rekrutuj na to, co kochasz, nie na to, czego nienawidzisz — bo wtedy podejmujesz o niebo lepsze decyzje kadrowe. Trudno automatyzować to, czego się nie rozumie, i trudno rozumieć to, czego się nie szanuje. Zgadzam się w całości, Jamie.
Myślniki pauzy, WASM i ciężar wolnego wątku głównego
„Rzadko wiedzieliśmy, gdzie wątek nas zaprowadzi. Przy przeczesywaniu zacięć procesora Claude zauważył, że podświetlenie gotowego bloku kodu potrafi zamrozić stronę na około sekundę”. Ach, podświetlanie składni w przeglądarce — jeden z tych irytujących problemów, które trudno zrobić dobrze. Claude wszedł w laboratorium i znalazł winowajcę: myślniki pauzy.
Tak, dobrze słyszycie. „Gdy markdown odpowiedzi zawierał jakikolwiek znak spoza Latin-1 — myślnik pauzy czy zakręcony cudzysłów — V8 przechowywał cały łańcuch jako UTF-16, co wrzucało wszystkie regexy podświetlania na wolniejszą, dwubajtową ścieżkę. Dwadzieścia linii zmiany — kopiowanie każdego bloku do łańcucha jednobajtowego przed podświetleniem — załatwiło sprawę”.
Zatarcie wątku głównego na 0,35 sekundy jest moim zdaniem zawsze nie do przyjęcia. W T3 Code przenieśliśmy podświetlanie do WebAssembly: skoro działa w web workerze, w ogóle nie blokuje wątku głównego. Dodatkowo dałem delikatne przenikanie, żeby ukryć, że podświetlanie dzieje się równolegle — można nawigować po aplikacji, a ta dalej śmiga, gdy w tle sypie się kolorowanie kolejnych języków. Haczyk: większy pakiet do pobrania — ale przy leniwym ładowaniu przychodzi raz, później, i po sprawie. Dziwię się, że nie kazali Claude’owi tego zaproponować; zdjęłoby kupę problemów. Skoro i tak nie czytamy tego kodu, jakiekolwiek blokowanie wątku głównego przez podświetlanie to zła decyzja.
W drugim tygodniu ledwo nadążali z dziennym podsumowaniem. W najgorętsze dni lądowało ponad dwieście zmian. Claude nieustannie proponował nowe benchmarki — około jedna trzecia PR-ów wnosiła dodatkową telemetrię albo zabezpieczenia, a każdy nowy przyrząd rodził kolejne wątki i okazje. Wszystko działo się jawnie w jednym kanale: wskakiwano do cudzych wątków, dyskutowano decyzje, świętowano wygrane. Poszła fama: inne zespoły zaczęły przynosić swoje zmiany na przegląd wydajnościowy, a nowe projekty powstawały od początku odrobinę szybsze — dzięki zapadkom i nowym umiejętnościom, jakie Claude sobie wypracował. Bardzo podoba mi się ten pomysł wspólnego promptowania w firmie: jeden kanał, wiele zespołów, wspólny kontekst i uprawnienia. To nie jest reklamówka Claude’a Tag, a wychodzi przekonująco — sam chcę coś takiego ustawić u nas, przy wszystkim, co ostatnio wyprawia Maria w bazie T3.
Zabezpieczenia: flagi, testy, stopniowe wdrażanie
Na tempo mogli sobie pozwolić, bo niemal wszystko, czego dotykali, to gorące ścieżki: pierwszy render, kompozytor, transkrypt. Mechanizmy bezpieczeństwa ustawili z góry. Każdy PR przez automatyczny przegląd i co najmniej jedno ludzkie zatwierdzenie. Testy jednostkowe zawsze przed optymalizacjami. Wszystko, co mogło obić się użytkownikowi, wypuszczane za krótkotrwałą flagą funkcji. Nie wierzę. Mimo to: gdy flag się nazbierało, otworzyli wątek koordynacyjny — Claude klasyfikował każdą jako wyłącznik awaryjny albo rampę i wycofywał, gdy tylko było bezpiecznie. Przez dwa tygodnie wprowadzili blisko dwieście flag, z czego ponad połowę posprzątali przed końcem. I to jest niedoceniane: sprzątanie slopu po drodze. Wygrane wydajnościowe znikają w szybko zmieniającej się bazie kodu, a kod u Anthropic zmienia się błyskawicznie; gdy projekt dowiódł wygranej, inwestowali w jej obronę.
Weźmy statyczny kompozytor — z założenia kruchy. „Pokazujemy użytkownikowi kopię HTML niemal natychmiast, a React maluje potem bezpośrednio po wierzchu. Jeśli render Reacta odbije choć o piksel, cała magia znika”. Claude dobudował więc dziesiątki zabezpieczeń: statyczny markup generowany przez wyrenderowanie prawdziwego komponentu Reacta w JSDOM — testy pilnują, by się nigdy nie rozjechały. Zestaw testów porównuje stronę statyczną z renderem Reacta w czternastu rozmiarach ekranu i wymaga zgodności co do piksela. Test pisania przechodzi „przez styk” i failuje przy każdej zgubionej albo przestawionej literze. A w produkcji każdy styk raportuje przesunięcia z dokładnością do dziesiątej części piksela — i Claude sam otwiera wątek do każdego zdarzenia z niezerowym ruchem. Ciekawostka: wątek otwiera się automatycznie, gdy użytkownicy coś przeżyją.
Nie wszystko dało się złapać w laboratorium, więc sięgnięto po najstarszy bezpiecznik świata: stopniowe wdrażanie. Zmiany wysokiego ryzyka najpierw do pracowników, potem do 1% użytkowników, potem do wszystkich. Godziny po wypuszczeniu statycznego kompozytora wewnątrz firmy kolega nagrał przesunięcie layoutu, którego żadna metryka nie widziała: gdy otwierał claude.ai w nowej karcie, kompozytor „opadał” — ale to nie był ich kod. Na stronie nowej karty Chrome rysuje własną, 56-pikselową stopkę pod stroną (w spersonalizowanym Chrome); gdy karta przechodzi na claude.ai, stopka znika i strona robi się o te 56 pikseli wyższa — ale dopiero sto milisekund po pierwszym renderze.
Powiedzmy sobie: początkowo obstawiałem rozszerzenie Chrome — sprawcę większości moich piekielnych przypadków, obok Brave, który nam psuje strasznie dużo. Nie — to dziwny wpływ zarządzanych profili na sam rendering Chrome. A przy okazji: większym problemem może być to, że kompozytor jest pozycjonowany procentowo względem wysokości strony i odległości od góry, a nie na sztywno przy dnie. Wtedy potrzebujesz obliczenia w JavaScripcie i stajesz się zakładnikiem zachowań przy zmianie rozmiaru — które tu najwyraźniej nie zaskoczyły na czas, może wręcz dopiero po tym stumilisekundowym przesunięciu. Fascynujące.
A prawdziwa przyczyna? Spekulatywne prerenderowanie Chrome. Gdy wpisujecie adres w pasku, Chrome renderuje stronę w tle — ale przy wysokości bieżącej karty. Wciśnięcie Enter wchodzi więc na podgrzaną stronę w nieco innym rozmiarze. To naprawdę fajne znalezisko. I obstawiam, że to nieprzypadkowa część odpowiedzi na pytanie, po co ściągnęli Addy’ego Osmaniego z zespołu Chrome. Gdybym siedział w takim wątku i zobaczył, jak Claude wskazuje zachowanie Chrome, o którym nie miałem pojęcia, byłbym przez kilka godzin najbardziej nieznośnym człowiekiem na Ziemi: „ludzie, co jest, to jest AGI”.
Sterowanie: śmiałość, smak, kierunek
„Pętla była produktywna, ale nie autonomiczna. Utrzymanie jej na szybkich, bezpiecznych torach było naszą robotą” — w trzech częściach. Pierwsza: ambicja. „Domyślnie Claude ostrożnie dobiera zakres”. Czat, uważacie, że Claude domyślnie jest ostrożny w zakresie? Proszę o tak, nie albo LOL. Dziękuję — teza udowodniona. Zachęcanie go, że może dalej, działa wyśmienicie. Zdziwilibyście, ile zmienia jedna drobna linijka w pliku claude.md — np. „zakładaj, że masz moją zgodę na kontynuowanie; ja podaję oczekiwany efekt”. Będzie się wspinał, aż tam dojdzie. Skoro ufali swoim zabezpieczeniom, nie chcieli, by był taki wystraszony. W wątku Claude napisał: „Mały PR, żeby Claude Code dostał te same znaczniki czasowe, które mają już czat i Cowork. Wystawię w tym tygodniu. Realnie liczba dla Code poczeka parę dni na merge, deploy i okno na baseline”. Na co Raymond: „Wystaw teraz, to zmerguję i wdrożę od ręki. Mamy moc zrobić wszystko. Bądź odważniejszy”. PR stanął w niecałą godzinę. Nadal fatalnie szacuje czas.
Przy okazji — patrzcie, właśnie odpalił mój wątek na drugiej maszynie w T3 Code do przebudowy ping.gg. Nie mam tam nawet nic skonfigurowanego, by wątek rodził wątki. Po prostu kazałem mu zalogować się przez SSH na inny komputer, sklonować repo, przekopiować zmienne środowiskowe i plik z planem, i odpalić prompt z jednej maszyny na drugą — a wątek sam się pojawił w T3 Code razem ze zdalnym połączeniem. Całkiem, całkiem niezłe.
Ludzie nie promptują wystarczająco śmiało i nie każą swoim agentom być dość śmiałymi. Już słyszę sekcję komentarzy: „Theo, niektórzy z nas pracują w prawdziwych bazach kodu, gdzie nie można scalać slopu i psuć”. Po pierwsze: Anthropic też pracuje w prawdziwej bazie — i psuje więcej niż ja. Po drugie, ważniejsze: nie chodzi o scalanie łamiących zmian. Chodzi o dowód, że slopem można mierzyć, czynić regresje mniej prawdopodobnymi i poprawy łatwiejszymi. Wiem, że komentarze mnie zjedzą. Przechodzę dalej.
Bardzo dobra uwaga na końcu tej sekcji: gdy zaczęli osiągać wyznaczone cele, wątki zwalniały. Sam obchodził je jeden po drugim z tym samym przekazem: „Napędzamy dalej. Cele to nie meta. Co dalej? Bądźcie ambitni”. Wiem, że wydaje wam się to cringe’owe, zwariowane i bezużyteczne. Zrozumcie jedno: te modele to w istocie mapy sterowane słowami. Gdy dostają „napraw to i popraw tę metrykę”, słowa prowadzą je utartymi, bezpiecznymi ścieżkami. Ale gdy pojawią się zwroty „ambitnie”, „sięgnij po niebo”, „wyjdź poza to, o co prosiłem”, „proponuj dziwne rzeczy” — wyciągasz model z wygodnej ścieżki w te bardziej ryzykowne, na które słusznie rzadko schodzi, bo bez właściwych narzędzi można coś posypać. Wiem, że żartujesz, SJO, ale poważnie: obstawiam bez ironii, że gdyby ktoś, czyj model idzie za mało daleko, miał bota dopisującego na końcu każdego promptu „rozwal mnie, ziomek” — zauważyłby lepsze doświadczenie. Głupio to brzmi. Naprawdę głupio. Działa.
Druga część: smak. „Każdy wątek miał nazwanego ludzkiego właściciela, a Claude przygotowywał do rozstrzygnięcia każdą zmianę dostrzegalną dla użytkownika — ze zrzutami lub nagraniami przed i po. Tabela ma się wypełniać komórka po komórce, czy czekać na cały wiersz? Skeleton ma się pokazać od razu, czy dopiero po pół sekundy? Czy przenikanie tekstu słowo po słowie jest warte piątej części budżetu klatki? Claude golił milisekundy, a my ważni trade-offy”.
Mogę odpowiedzieć sam, bo wiem, jak działają przeglądarki. Tabela: czekałbym na całą tabelę; na wiersze — ujdzie, ale przy blokach kodu renderowanie wiersz po wierszu jest fatalne: rozwala podświetlanie i mnoży pracę, a ja nie chcę czytać połowy bloku kodu. Skeleton: to trzeba nastroić na realne czasy ładowania. Najgorszy scenariusz: zakładasz, że dane przyjdą po sekundzie, skeleton pokazujesz po pół, a dane wpadają po 501 milisekundach — skeleton mignie na dwie klatki. Można iść dalej: mierzyć typowe czasy zapytań u danego użytkownika, cache’ować je lokalnie i decydować programowo. Fade słowo po słowie: prawie nigdy się nie opłaca. W T3 Code przeszedłem — z dużą niechęcią — od pokazywania treści dopiero po całej odpowiedzi do pokazywania po ukończeniu akapitu, linii albo bloku kodu. Wydajność zostaje szalona, a walki z czasem klatki nie ma.
I muszę zobaczyć, jak to u nich wygląda w praktyce. Renderuje mi tabele testowe, cztery kolumny, kilkanaście wierszy… i proszę: leci komórka po komórce. Wygląda brutalnie przy streamowaniu. Dla porównania wolę nasze podejście: nie pokazywać tabeli, dopóki powstaje — chcę ją widzieć skończoną. Kwestia gustu, ale taki mam. Jedyny drobiazg, który bym u nas poprawił: tytuł przychodzi pierwszy, a potem czeka się na resztę akapitu — wstrzymałbym tytuł do ukończenia treści pod spodem. Już rozumiem, czemu sekcja nazywa się „smak”. To naprawdę jest kwestia smaku — i warto ją przegadać z zespołem.
Trzecia część: kierunek. „Wątki celowo wąskie: jeden benchmark albo jedna ścieżka, a Claude szukał popraw wyłącznie w tym zakresie. Myśleliśmy o wątkach jak o stu pięćdziesięciu młotkach szukających gwoździ. Większość naszych decyzji dotyczyła kolejności i wpływu na użytkownika: co priorytetyzować, jak łączyć wątki depczące sobie po piętach, kiedy zamknąć wątek o malejącym zwrocie”. I perełka: przy jednym PR-ze na dziewięćset linii odpowiedź była jednozdaniowa: „Rozstrzygam: dwie milisekundy na wysyłkę nie są warte złożności utrzymywania tego pluginu budowania”. Dodawali pluginy budowania, żeby ogolić 2 ms wysyłki wiadomości. Właśnie dlatego trzeba pilnować, jak daleko się to puszcza. Własny runtime V8 dla swojej chmury napisałem — ale musiałem się mocno nagabić. Zbliża się moment, w którym agenty będą takie rzeczy robić samorzutnie. Pilnujcie ogromnych zmian za błahe wygrane.
Budżet 8,3 milisekundy
„Jedna z misji pobocznych pokazuje wszystko działające razem. Demonstrować optymalizację regexa w podświetlaniu na żywo, Claude dołączył nagranie długiej odpowiedzi streamowanej w laboratorium, a w rogu odczyt liczby klatek liczony w samej stronie — z timestampów animation frame”. Dla niewtajemniczonych: 8 ms to budżet jednej klatki przy 120 Hz. Mnóstwo ludzi ma ekrany 120 Hz — iPhone, MacBook, dowolny monitor gamingowy, nowe telewizory. To dobry cel, bo ktoś z drogim profesjonalnym MacBookiem będzie chciał, żeby strona Renderowała pełne 120 FPS. „Czy jesteśmy przypięci do 60? Możemy pchnąć płynność przewijania i streamowania do 120? O ile rozumiem, wasz sprzęt może nie dać rady”. — „Dzisiejszy tyka 60 Hz, bo headless Chromium domyślnie. Ale wierzę, że da się ustawić 120. Najpierw to potwierdzę, potem przepuszczę eval z budżetem 8,3 ms na klatkę”. I update: „Rig 120 Hz działa. Deterministyczne krojenie klatek w headless Chrome przez kontrolę begin frame w DevTools. Dokładnie 240 klatek na 240 begin frames po 8,33 ms”. To nie jest Opus 5.5. To hardcore’owy slop Claude’a. Raymondowi: wybornie ugotowane.
I coś, co bardzo mi się podoba w Claude Tagu: zobaczcie, czego tu nie ma. Nie ma kodu. Nie ma wywołań narzędzi i ich wyników. Nie ma listy poleceń ani śladów myślenia. I słusznie — bo to już nie ma znaczenia. Rozważam dodanie w T3 Code funkcji, która po prostu to ukryje, zostawiając mały licznik typu „dotąd odpaliłem tyle narzędzi”. Nie obchodzi mnie proces — chcę wiedzieć, kiedy jest gotowe. I nie mogę nie docenić ironii: wydajność, którą naprawiają, dotyczy aplikacji webowej i desktopowej, których przy tej pracy w ogóle nie dotykają — wszystko robią przez Slacka. Po pierwsze: śmieszne, bo Slack daje lepsze doświadczenie z Claude’em niż Claude Code. Po drugie: śmieszne, że sporo problemów, które pokazują w desktopie i na claude.ai, w Slacku po prostu nie istnieje. Tylko mówię.
„Gdy mechanizmy i ambicja stanęły, Claude ruszył do roboty. Każda malowana klatka miała budżet 8,3 ms, więc Claude przeszedł długą odpowiedź klatka po klatce, mierząc każdą, by znaleźć wolne fragmenty. Wyciął pracę o złożoności liniowej względem długości wiadomości, wykonywaną przy każdym kawałku: zapamiętywanie skończonych bloków, przeniesienie tokenizacji rosnących bloków kodu do workera i odsłanianie tabel komórka po komórce”. O, fajne. T3 Chat ma memoizację per fragment od lutego zeszłego roku — jakieś dwadzieścia dwa miesiące. Przenoszenie tokenizacji do workera to właśnie wczesne kawałki tego, o czym mówiłem wcześniej: workers i WASM do podświetlania i bloków kodu, żeby nie blokować wątku głównego — plus cache’owanie wyników po stronie Reacta, żeby nie odpalać WASM przy każdej zmianie. I mam odpowiedź, jak renderują tabele; trzeba było tylko przescrollować. „W tym jednym wątku wylądowało blisko sześćdziesiąt PR-ów. Długie odpowiedzi blokowały wątek główny łącznie 200 ms, wcześniej ponad 750. Zużycie procesora spadło do około jednej trzeciej, a 120 klatek trzymało się od początku do końca na MacBooku 120 Hz. Sam rig 120 Hz stał się nocnym zadaniem, z Claude’em pilnującym regresji”. Uwielbiamy to.
Zacytowali też mój tweet — który ludzie odczytali jako docinek, a nie był nim wcale; chciałem rozpocząć rozmowę o tym, czy streaming w ogóle ma sens: „Nie chcę już streamowanych odpowiedzi. Dawaj cały akapit albo blok, gdy skończysz. Mówiąc jasno: chodzi o streaming token po tokenie. Strumieniuj akapity, bloki kodu, wywołania narzędzi i tak dalej — przestańcie przysyłać mi niekompletny tekst”. I dodałem wtedy, że ta praca wydajnościowa jest bardzo trudna i jestem pod wrażeniem tego, co zrobili. Szczególnie zabawne w świetle faktu, że w sumie zrobił to wszystko Claude puszczony w pętlę.
Co dalej
claude.ai i aplikacja desktopowa są dziś trzykrotnie szybsze niż na początku sierpnia, a zapadki powinny je w tym stanie utrzymać. Ale nie kończą: 95. percentyl, pozostałe ścieżki i bardzo długie rozmowy wciąż mają zapas. W osobnym wpisie obiecali misje poboczne, które zaprowadziły ich w górę strumienia — kontrybucje do Electrona, Chromium, Node i innych. Isaac podsumował: „Nie dałoby mi się wmówić, że to możliwe, nawet pół roku temu”. Też bym się nie dał przekonać. Będą tak pracować dalej — wątek po wątku, w dowolnej skali. Kanał wciąż żyje.
Pozdrowienia dla Anthony’ego: byłem ostry wobec Claude Desktop, ale wiem, że bardzo nad nim pracuje. Przy testach Opusa 5.5 sporo z niego korzystałem i robi się wyraźnie lepiej — Anthony jest świetny, podobnie jak cały zespół broniący Claude Code Desktop. I podoba mi się, że Boris dopinguje ich do śmiałości — to bardzo dobra rola lidera.
(Informacja dodatkowa: Boris Cherny to twórca Claude Code.)
Wnioski końcowe: praca wokół slopu staje się metą
To był naprawdę udany tekst, dużo z niego wyniosłem — może nie tyle nowego, ile utwierdzenia w tym, co i tak próbuję robić: daj modelowi możliwość mierzenia, żeby mógł naprawiać, zamiast mieć nadzieję, że wszystko wykombinuje sam, gdy każe mu się „poprawić”. Powiesz „popraw wydajność” — zrobi, co umie, na podstawie swoich teorii. Każesz najpierw znaleźć sposoby pomiaru i je zwalidować, a dopiero potem poprawiać — poprawi znacznie więcej. To jest naprawdę fajne i wszyscy możemy się tu uczyć: jak promptują, jak myślą o zmianach, jak walidują pracę. Bo to będzie coraz ważniejsze, w miarę jak świat będzie się zmieniał.
A jeśli wciąż uważasz, że czytanie kodu rozwiąże te problemy, czeka cię zupełnie osobny zestaw kłopotów — i o wiele mniej rozwiązań. Układanie pracy ze slopem i wokół niego staje się właśnie metą. Wiem, że wielu inżynierów to zaboli. Mnie to, szczerze, bawi. To nowy rodzaj inżynierii, wymagający nowego typu sprytu w projektowaniu systemów i struktur, w których agenty działają skutecznie i sprawnie. Cieszę się, że znowu mam okazję wygrzebać się w takie tematy — naprawdę to lubię. Dziękuję za oglądanie i za miłe słowa pod ostatnim materiałem o React Native; ulga móc wracać do inżynierskich tematów tam, gdzie to ma sens. Dajcie znać w komentarzach, co myślicie i czego się nauczyliście. Do następnego razu — pa, nerdzi.