Pierwszy token i cała reszta — prefill kontra decode

przez Łukasz | wrz 21, 2026

Model nie wykonuje jednej pracy, tylko dwie — i są to prace tak różne, że gdyby nie dzieliły wag, nikt nie nazwałby ich tym samym słowem. Jedna jest równoległa, obciąża rdzenie i przelatuje tysiące tokenów na sekundę. Druga jest ściśle sekwencyjna, obciąża pamięć i wyrabia kilkadziesiąt. Pierwsza odpowiada za to, ile czekasz na początek odpowiedzi. Druga — za to, jak szybko odpowiedź się potem rozwija.

To rozróżnienie jest najważniejszą rzeczą w całej tej serii. Bez niego cennik dostawców API wygląda na kaprys, limity na złośliwość, a wahania czasu odpowiedzi na awarię. Z nim wszystko trzy układa się w jeden mechanizm.

I co najlepsze, tę różnicę widać gołym okiem na własnym laptopie. Wystarczy przestać patrzeć na odpowiedź, a zacząć patrzeć na zegar.

Co się dzieje, zanim padnie pierwsze słowo

Wysyłasz do modelu prompt. Powiedzmy dwie strony tekstu, jakieś tysiąc tokenów. Model ma je streścić.

Zanim wyjdzie pierwsze słowo streszczenia, musi się wydarzyć coś, o czym łatwo zapomnieć: model musi ten tysiąc tokenów przeczytać. Przepuścić przez wszystkie warstwy, policzyć dla każdego tokena jego klucz i wartość, zapisać je do pamięci podręcznej opisanej w poprzednim artykule. Dopiero gdy cała historia jest przetworzona, może zacząć przewidywać, co powinno paść dalej.

Ta faza nazywa się prefill — wypełnienie. Dosłownie chodzi o wypełnienie pamięci podręcznej.

Potem zaczyna się decode. Model generuje jeden token. Dopisuje go do historii, liczy dla niego klucz i wartość, dokłada do pamięci podręcznej. Patrzy na całość i generuje następny token. I tak, po jednym, aż do końca odpowiedzi.

Dwie fazy. Te same wagi, ten sam graf operacji, ta sama matematyka. A zachowują się jak dwa różne programy.

Dlaczego czytanie jest szybkie

Kluczowa własność prefillu: wszystkie tokeny promptu można przetworzyć naraz.

Brzmi banalnie, ale nie jest. Skąd bierze się ta możliwość? Stąd, że cały prompt jest już znany. Model nie musi czekać, aż dowie się, co będzie trzysta pięćdziesiątym tokenem, żeby przetworzyć token dziesiąty. Wszystko leży na stole od początku.

A skoro tak, to zamiast przepuszczać przez warstwę jeden wektor, przepuszczasz przez nią macierz o tysiącu wierszy. Ta sama operacja, ten sam odczyt wag — tylko obsługujący tysiąc tokenów zamiast jednego.

I tu wracamy do wąskiego gardła z artykułu pierwszego. Mówiłem tam, że żeby wygenerować token, trzeba przeczytać cały model z pamięci. To nadal prawda. Ale w prefillu czytasz model raz na tysiąc tokenów, a nie raz na token. Koszt odczytu rozkłada się na tysiąc porcji pracy.

Wąskie gardło przestaje być pamięcią. Zaczyna być liczeniem — bo nagle rdzenie mają co robić. Karta graficzna, ta z tysiącami głupich rdzeni, wreszcie pracuje tak, jak została zaprojektowana: wszystkie na raz, nad jednym wielkim mnożeniem macierzy.

Stąd liczby, które przy pierwszym kontakcie wydają się pomyłką. Model, który generuje trzydzieści tokenów na sekundę, potrafi w prefillu przetwarzać dwa tysiące. Ten sam model, ten sam sprzęt, ta sama sekunda.

Jest jeden haczyk, o którym pisałeś już przy długim kontekście: w prefillu każdy token musi spojrzeć na każdy inny, więc koszt rośnie z kwadratem długości promptu. Przy tysiącu tokenów to nieistotne. Przy stu tysiącach — bardzo istotne. Prefill jest szybki, ale nie jest darmowy i nie skaluje się liniowo.

Dlaczego pisanie jest wolne

Teraz decode, i tu wszystko się odwraca.

Model wygenerował token. Żeby wygenerować następny, musi znać poprzedni — bo to on właśnie zmienił kontekst. Nie da się policzyć tokena numer siedem, zanim nie zna się szóstego. Nie ma tu żadnego marginesu na równoległość. To jest ograniczenie logiczne, nie techniczne: żaden sprzęt świata tego nie obejdzie.

Więc każdy krok decode wygląda tak: weź jeden wektor, przepuść go przez wszystkie warstwy, przeczytaj po drodze wszystkie wagi modelu, wypluj jeden token.

Przeczytaj cztery gigabajty. Żeby wyprodukować jedno słowo.

To jest ta sama arytmetyka, którą liczyliśmy w artykule pierwszym — przepustowość pamięci podzielona przez rozmiar modelu — i teraz widać, że dotyczyła ona wyłącznie tej drugiej fazy. Sufit prędkości z tamtego kalkulatora to sufit decode. Prefill w ogóle nie podlega tej regule.

Marnotrawstwo, które wyjaśnia resztę serii

Zatrzymajmy się tu, bo to najważniejszy akapit tego artykułu.

W trakcie decode karta graficzna prawie nic nie robi. Owszem, przepycha przez siebie cztery gigabajty danych, i to zajmuje jej cały czas. Ale samych obliczeń wykonuje śmiesznie mało — jedno mnożenie wektora przez macierz na warstwę. Rdzenie, wszystkie tysiące, stoją bezczynnie i czekają, aż dane do nich dojadą.

Typowe wykorzystanie mocy obliczeniowej w fazie decode to kilka procent. Reszta się marnuje.

Weź teraz kartę serwerową za trzydzieści tysięcy dolarów, na której w ten sposób działa jedna rozmowa jednego użytkownika, i zadaj sobie pytanie, które zadał sobie każdy dostawca API: skoro rdzenie i tak stoją, co by się stało, gdyby przepuścić przez nie dwieście rozmów naraz?

Odpowiedź brzmi: prawie nic. Wagi odczytane z pamięci są te same dla wszystkich. Jeden odczyt obsłuży dwieście rozmów zamiast jednej, bo to nie odczyt był wąskim gardłem dla rdzeni, tylko rdzenie czekały na odczyt. Dwieście razy więcej pracy w mniej więcej tym samym czasie.

To jedno zdanie wyjaśnia cały tor o API, który zaczyna się w następnym artykule. Kolejki, limity, zmienny czas odpowiedzi, różnica w cenie między wejściem a wyjściem — wszystko to są konsekwencje faktu, że decode marnuje kartę, a prefill nie.

Jak to wygląda na zegarze

Załóżmy typowy laptop, model siedmiomiliardowy w czterech bitach. Prefill przerabia około sześciuset tokenów na sekundę, decode wyrabia około osiemnastu. Różnica trzydziestokrotna i będzie ona rosła wraz z mocą sprzętu, bo mocniejsza karta poprawia prefill znacznie bardziej niż decode.

Krótkie pytanie, długa odpowiedź. Prompt pięćdziesiąt tokenów, odpowiedź osiemset. Prefill trwa niecałą dziesiątą sekundy — pierwsze słowo pojawia się natychmiast. Potem czterdzieści pięć sekund mozolnego wypluwania. Całość jest zdominowana przez decode w ponad dziewięćdziesięciu dziewięciu procentach.

Długi dokument, krótkie streszczenie. Prompt osiem tysięcy tokenów, odpowiedź sto. Prefill trwa trzynaście sekund — tyle patrzysz w pusty ekran, zastanawiając się, czy to się zawiesiło. Potem sześć sekund generowania. Tym razem prefill zjada dwie trzecie czasu.

To są dwa zupełnie różne problemy wydajnościowe i nie ma jednej optymalizacji, która pomaga na oba. Skracanie promptu nie przyspieszy generowania długiej odpowiedzi. Szybsza karta nie skróci znacząco czekania na osiemsetny token. Zanim zaczniesz cokolwiek optymalizować, musisz wiedzieć, w której z dwóch faz tkwi twój czas.

Cztery rzeczy, które teraz mają sens

Dlaczego wejście jest tańsze niż wyjście. Zajrzyj do cennika dowolnego dostawcy: tokeny wejściowe kosztują zwykle trzy do pięciu razy mniej niż wyjściowe. To nie jest polityka cenowa ani zachęta do pisania krótkich promptów. To jest odzwierciedlenie kosztu. Token przetworzony w prefillu zajmuje kartę ułamek tego, co token wygenerowany w decode. Cennik jest mapą fizyki.

Dlaczego istnieje streaming. Nikt nie wymyślił wyświetlania odpowiedzi po kawałku dlatego, że tak ładnie wygląda. Wymyślono to, bo decode trwa i bez strumienia użytkownik siedziałby czterdzieści sekund przed pustym ekranem. Strumień nie przyspiesza niczego — maskuje wolność, której nie da się usunąć. To plaster na ograniczenie fizyczne.

Dlaczego dwie metryki, nie jedna. Czas do pierwszego tokena i tokeny na sekundę mierzą dwie różne fazy i mogą iść w przeciwnych kierunkach. Dostawca, który agresywnie łączy żądania w partie, poprawia przepustowość i pogarsza czas do pierwszego tokena. Który z nich jest „szybszy”, zależy wyłącznie od tego, co robisz. Porównywanie dostawców po jednej liczbie jest bez sensu.

Dlaczego wznowiona rozmowa startuje wolniej. W poprzednim artykule wspomniałem o tym na marginesie, teraz można to nazwać: wznowienie sesji to ponowny prefill całej historii. Pamięć podręczna, którą model zbudował w poprzedniej rundzie, została zwolniona. Musi powstać od nowa. Im dłuższa rozmowa, tym dłuższe to wznowienie — i tym większa pokusa, żeby ten wynik gdzieś zachować. Ta pokusa ma nazwę, jest jedną z najważniejszych optymalizacji w całym torze API i poświęcę jej osobny artykuł.

Zobacz to sam

Widget pod tym akapitem nie generuje tekstu. Robi coś prostszego i bardziej wymownego: rozkłada czas odpowiedzi na dwie fazy i pokazuje je jako pasek.

Ustaw krótki prompt i długą odpowiedź. Prefill jest niewidoczną kreską na początku, cała reszta paska to decode. Teraz odwróć: prompt na osiem tysięcy tokenów, odpowiedź na sto. Pasek przewraca się na drugą stronę.

Zwróć uwagę na licznik wykorzystania karty pod paskiem. W prefillu siedzi wysoko, w decode spada do kilku procent — i to jest wizualizacja tego marnotrawstwa, z którego wyrośnie cały następny tor.

Na koniec przełącz sprzęt z laptopa na kartę serwerową. Wszystko przyspiesza — i prefill, i decode. Spójrz jednak na wykorzystanie karty w fazie decode: spada. Z trzech procent na laptopie do półtora na sprzęcie za trzydzieści tysięcy dolarów. Im droższa karta, tym większa jej część stoi bezczynnie, kiedy model pisze. To jest najkrótsze możliwe podsumowanie tego artykułu i zarazem cały powód, dla którego istnieje następny tor.

Co dalej

Zamykamy tor lokalny. Przez cztery artykuły oglądaliśmy mechanizm z bliska, bo na własnym urządzeniu wszystko jest widoczne: rozmiar wag, przepustowość pamięci, błąd kwantyzacji, rosnąca historia rozmowy, dwie fazy generowania.

Od następnego artykułu ten sam mechanizm przestaje być widoczny. Trafia na cudzy serwer, gdzie twoja prośba jest jedną z dwustu, a jedyne, co możesz zmierzyć, to czas i rachunek.

Ale już wiesz, co tam się dzieje. I wiesz, dlaczego oni to robią akurat tak — bo widziałeś, jak bardzo decode marnuje kartę.

Prefill kontra decode

webflux · maszyneria modelu

1 tys. tokenów
800 tokenów
80 GB/s · 14 TFLOPS
bez pamięci podręcznej
Model 7 mld / 4 bity · wartości szacunkowe Inference — token po tokenie →

Ścieżka przez widget

Domyślnie profil zrównoważony. Przesuń prompt na 50 i odpowiedź na 800 — pasek jest niemal w całości turkusowy, prefill to nieczytelna kreska. Teraz prompt 8 tys., odpowiedź 100: pasek przewraca się na drugą stronę i komunikat pod spodem zmienia zalecenie na odwrotne.

Dolny pasek pokazuje, co by było bez pamięci podręcznej z poprzedniego artykułu. Przy domyślnych ustawieniach na laptopie to trzydzieści cztery minuty zamiast pięćdziesięciu sekund.

Agent kończy, ale zadania nie wykonał

Agent kończy, ale zadania nie wykonał

Objawy Agent odpowiada: „Przygotowałem i wysłałem potwierdzenie do klienta." Potwierdzenie nie zostało wysłane. Albo: „Zaktualizowałem wszystkie rekordy" — zaktualizował trzy z dwunastu. Albo: „Nie znalazłem żadnych zamówień" — bo narzędzie zwróciło błąd, którego nikt...

Agent zrobił coś, o co nikt nie prosił

Agent zrobił coś, o co nikt nie prosił

Objawy Operacja, której nikt nie zlecił. Dane wysłane pod adres, którego nie ma w żadnej konfiguracji. Rekord zmieniony poza zakresem zadania. Odpowiedź, z której wynika, że agent dostał instrukcje od kogoś innego niż ty. Cecha wspólna: technicznie wszystko zadziałało...

Agent zrobił to samo dwa razy

Agent zrobił to samo dwa razy

Objawy Ten syndrom różni się od pozostałych jedną rzeczą: objaw widzi klient, nie ty. Trzy identyczne wiadomości w skrzynce. Dwa zamówienia zamiast jednego. Podwójne obciążenie. Duplikaty rekordów, które ktoś zauważa tydzień później. W twoim dzienniku wszystko wygląda...

Agent gubi wątek w długim zadaniu

Agent gubi wątek w długim zadaniu

Objawy Pierwsze kroki idą wzorowo. Po kilkunastu agent zaczyna się rozjeżdżać. Przestaje przestrzegać reguły z promptu systemowego, której trzymał się na początku. Zmienia format odpowiedzi w połowie zadania. Wraca do czegoś, co już ustalił, i ustala to inaczej....