Wagi to nie wszystko, co model trzyma w pamięci. Obok nich rośnie druga struktura, która przy pierwszym tokenie zajmuje tyle co nic, a przy długiej rozmowie potrafi przekroczyć rozmiar samego modelu. I to ona, nie wagi, najczęściej decyduje o tym, gdzie kończy się kontekst — a także dlaczego dostawcy API liczą sobie za długie rozmowy tak, jak liczą.
W pierwszym artykule ustaliliśmy, że wagi trzeba przeczytać z pamięci przy każdym tokenie. W trzecim zobaczyliśmy, jak zmniejszyć ich rozmiar. Przez cały ten czas milcząco zakładaliśmy, że rozmiar wag to rozmiar modelu w pamięci. Nie jest.
Trzy pozycje, nie jedna
Kiedy runtime rezerwuje pamięć przed pierwszym obliczeniem, dzieli ją na trzy części.
Wagi. Stała wielkość, policzona w artykule pierwszym, znana z góry. Jedyna pozycja, która się nie zmienia.
Bufory robocze. Miejsce na wyniki pośrednie w trakcie przechodzenia przez graf. Zwykle drobne, kilkaset megabajtów, i — co ważne — wielokrotnie używane. Ten sam bufor obsługuje warstwę pierwszą i trzydziestą drugą, bo po wyjściu z warstwy jej wynik przestaje być potrzebny.
Pamięć podręczna kontekstu. I to jest bohater tego artykułu. Zaczyna od zera i rośnie liniowo z każdym tokenem rozmowy. Nigdy się nie zmniejsza, dopóki rozmowa trwa.
Zapamiętaj tę asymetrię, bo z niej wynika cała reszta: dwie pierwsze pozycje znasz przed uruchomieniem, trzecia zależy od tego, jak długo ktoś będzie pisał.
Dlaczego ta struktura w ogóle istnieje
Żeby zrozumieć, co się tam gromadzi, trzeba wrócić na moment do mechanizmu uwagi.
Model przy generowaniu każdego kolejnego tokena patrzy na wszystkie poprzednie. Nie na streszczenie, nie na ostatnie kilka — na wszystkie, po kolei, za każdym razem. Żeby to zrobić, potrzebuje dla każdego wcześniejszego tokena dwóch wektorów, które sobie kiedyś policzył. W żargonie nazywa się je kluczem i wartością i stąd nazwa całej struktury: pamięć podręczna kluczy i wartości.
Kluczowa obserwacja: te wektory się nie zmieniają. Klucz policzony dla trzeciego tokena rozmowy będzie identyczny w chwili generowania tokena czwartego, czterechsetnego i czterotysięcznego. Nic, co pojawi się później, nie ma na niego wpływu.
Można to liczyć od nowa przy każdym tokenie. Można też policzyć raz i zapamiętać.
Różnica jest dramatyczna. Bez pamięci podręcznej generowanie tysiąca tokenów wymaga przeliczenia całej historii tysiąc razy — koszt rośnie z kwadratem długości. Z pamięcią podręczną liczysz każdy token raz i sięgasz po gotowca. Koszt rośnie liniowo.
To jest ten sam handel, który zna każdy programista: zamieniasz obliczenia na pamięć. I jak zwykle rachunek przychodzi później.
Metafora, która tu pasuje
Wyobraź sobie tłumacza symultanicznego na długim spotkaniu. Żeby poprawnie przetłumaczyć bieżące zdanie, musi pamiętać, kto jest kim, co ustalono pół godziny temu, do czego odnosi się „to rozwiązanie”.
Ma dwie możliwości. Może przed każdym zdaniem odsłuchać nagranie całego spotkania od początku — wtedy niczego nie musi trzymać w głowie, ale przy trzeciej godzinie przestaje nadążać. Albo może notować na bieżąco i zerkać do notatek — szybko, tyle że notatnik rośnie i w pewnym momencie kończy się biurko.
Model wybiera to drugie. Zawsze. I dlatego ma biurko o skończonej wielkości.
Ile to naprawdę waży
Tu zaczyna się rzecz, która zaskakuje większość ludzi przy pierwszym kontakcie.
Wielkość pamięci podręcznej zależy od czterech rzeczy: liczby warstw modelu, wielkości wektora w każdej warstwie, liczby tokenów w rozmowie i precyzji zapisu. Mnoży się je przez siebie, razy dwa — bo klucz i wartość to dwie struktury.
Konkret dla modelu o siedmiu miliardach parametrów, trzydziestu dwóch warstwach, w szesnastobitowej precyzji: około pół megabajta na każdy token rozmowy.
Pół megabajta brzmi niegroźnie. Policzmy więc dalej.
Tysiąc tokenów, czyli mniej więcej dwie strony tekstu, to pół gigabajta. Osiem tysięcy tokenów — długa rozmowa albo jeden porządny dokument w kontekście — to cztery gigabajty, czyli tyle, ile waży cały ten model po kwantyzacji do czterech bitów. Trzydzieści dwa tysiące tokenów to szesnaście gigabajtów. Sto dwadzieścia osiem tysięcy, czyli kontekst, którym dostawcy chwalą się w materiałach marketingowych, to sześćdziesiąt cztery gigabajty samej pamięci podręcznej.
Zestaw to z liczbami ze sprzętu: mocna karta desktopowa ma dwadzieścia cztery gigabajty na wszystko. Karta serwerowa osiemdziesiąt.
Wniosek jest brutalny i wart wytłuszczenia: przy długich rozmowach to nie model zajmuje pamięć, tylko historia rozmowy. Model jest stałą. Historia jest zmienną, która rośnie, dopóki ktoś pisze.
Dlaczego kwantyzacja nie ratuje sytuacji
Naturalna reakcja: skoro wagi skwantyzowaliśmy z szesnastu bitów do czterech i wszystko działa, zróbmy to samo z pamięcią podręczną.
Robi się to i pomaga. Ale nie tak, jak przy wagach, i warto wiedzieć dlaczego.
Wagi są statyczne. Kwantyzujesz je raz, przed wydaniem modelu, na spokojnie, z kalibracją, ze sprawdzeniem wyniku. Masz czas i masz cały model przed sobą.
Pamięć podręczna jest dynamiczna. Powstaje w trakcie, token po tokenie. Kwantyzować trzeba w locie, bez wiedzy o tym, co przyjdzie dalej, doliczając ten koszt do każdego kroku generowania. Oszczędzasz pamięć, płacisz czasem.
Gorzej: błędy się tu kumulują inaczej. Wagi są używane raz na przejście przez warstwę. Wpis w pamięci podręcznej powstały przy dziesiątym tokenie jest czytany przy jedenastym, dwunastym i każdym następnym — tysiące razy w długiej rozmowie. Zaokrąglenie, które przy wagach ginie w redundancji, tutaj wraca przy każdym odczycie.
Dlatego praktyka jest ostrożna. Osiem bitów dla tej struktury to standard i działa dobrze. Cztery bity to już teren, na którym trzeba mierzyć. Poniżej — rzadko, i zwykle tylko dla kluczy, bo okazuje się, że wartości znoszą zaokrąglanie gorzej.
Inżynieria poszła zresztą inną drogą i to ona dała prawdziwy przełom: zamiast zapisywać tę strukturę oszczędniej, nowoczesne architektury produkują jej mniej. Kilka głów uwagi współdzieli jeden komplet kluczy i wartości zamiast trzymać własny. Redukcja bywa czterokrotna albo ośmiokrotna i jest darmowa w czasie. To dlatego modele wydane w ostatnich dwóch latach radzą sobie z długim kontekstem nieporównanie lepiej niż ich poprzednicy o tej samej liczbie parametrów — nie dlatego, że są mądrzejsze, tylko dlatego, że mają mniejszy notatnik.
Co to znaczy dla ciebie w praktyce
Twój model nie mieści się tak, jak myślisz. Jeśli liczyłeś dostępną pamięć jako „rozmiar wag plus zapas”, policzyłeś źle. Zapas jest zmienny i rośnie z każdą wymianą zdań. Model, który uruchomił się bez problemu i ładnie odpowiadał przez dziesięć minut, może wywalić się w dwudziestej.
Limit kontekstu nie jest kaprysem. Każdy runtime i każdy dostawca ustawia górną granicę długości rozmowy. To nie jest ograniczenie modelu — model policzyłby więcej. To jest deklaracja, ile pamięci wolno zająć jednej sesji. Podnoszenie tej liczby w konfiguracji działa dokładnie do momentu, w którym kończy się fizyczna pamięć.
Długi kontekst kosztuje podwójnie. Płacisz za tokeny wejściowe raz, przy wysłaniu. Ale rozmowa, która zajmuje dużo pamięci, blokuje miejsce, którego dostawca nie może dać nikomu innemu. Dlatego długie konteksty bywają wyceniane osobno i dlatego przy bardzo długich rozmowach odpowiedzi przychodzą wolniej — nawet jeśli sama odpowiedź jest krótka.
Czyszczenie historii to nie jest kosmetyka. Kiedy narzędzie do rozmowy „streszcza wcześniejszą część”, nie robi ci uprzejmości. Zwalnia pamięć, bo inaczej sesja przestałaby działać.
Trzy obserwacje, które teraz się tłumaczą
Pierwsza odpowiedź w długiej rozmowie przychodzi wolniej niż kolejne. Bo przy wznowieniu sesji cała historia musi zostać przeliczona od nowa i pamięć podręczna odbudowana. To jest prefill, o którym będzie następny artykuł.
Ten sam model z tym samym promptem odpowiada raz szybko, raz wolno. Bo dostawca dzieli pamięć między wiele równoległych sesji i czasem twoja czeka na miejsce.
Model gubi wątek pod koniec długiego zadania. Tu akurat pamięć podręczna nie jest przyczyną — ale kwantyzacja tej struktury już bywa. Jeśli twój dostawca agresywnie oszczędza na tej pozycji, żeby zmieścić więcej sesji, błędy nawarstwiają się dokładnie tam, gdzie historia jest najdłuższa. Objaw opisany od strony agenta ma tu jedno ze swoich źródeł w warstwie, o której agent nic nie wie.
Co dalej
Napisałem wcześniej, że przy wznowieniu rozmowy historia musi zostać przeliczona od nowa. To nie jest przypis — to osobna faza działania modelu, rządząca się zupełnie innymi prawami niż generowanie odpowiedzi.
Jest równoległa tam, gdzie generowanie jest sekwencyjne. Obciąża rdzenie tam, gdzie generowanie obciąża pamięć. Skaluje się inaczej, kosztuje inaczej i jest wyceniana inaczej.
I to właśnie ona odpowiada za to, że na pierwsze słowo odpowiedzi czekasz sekundę, a reszta leci potem strumieniem. Następny artykuł jest o tej sekundzie — i to on jest mostem do całego toru o API.
Pamięć jako sufit webflux · maszyneria modelu





















