Od wag do odpowiedzi — co runtime robi z plikiem modelu

przez Łukasz | wrz 21, 2026

Model nie jest uruchamiany. Model jest kompilowany. Między wczytaniem pliku a pierwszym tokenem dzieje się praca, o której nie mówi ani nazwa modelu, ani jego rozmiar — a która potrafi zmienić prędkość dwudziestokrotnie. To dlatego ten sam model u dwóch różnych dostawców to w praktyce dwa różne produkty.

W poprzednim artykule ustaliliśmy, że plik z wagami jest martwy i że wąskim gardłem jest przepustowość pamięci. Teraz zobaczymy, co ktoś z tym martwym plikiem robi, żeby powstała odpowiedź — i gdzie po drodze ucieka albo zostaje odzyskana większość prędkości.

Co model deklaruje, a czego nie

W pliku z modelem są dwie rzeczy: liczby i opis kolejności. Opis kolejności nazywa się grafem obliczeniowym i wygląda mniej więcej tak: weź wejście, pomnóż przez tę macierz, dodaj tamten wektor, znormalizuj wynik, przepuść przez tę funkcję, powtórz całość trzydzieści dwa razy.

Zwróć uwagę, czego w tym opisie nie ma. Nie ma informacji, w jakiej kolejności fizycznie czytać dane z pamięci. Nie ma podziału pracy między rdzenie. Nie ma decyzji, czy dwie sąsiednie operacje wykonać osobno, czy za jednym zamachem. Nie ma nic o tym, jakim sprzętem to policzyć.

Graf mówi co ma wyjść. Nie mówi jak to zrobić. Cała ta druga warstwa jest do dopisania i dopisuje ją runtime.

To jest ta sama różnica, co między listą składników a organizacją kuchni. Przepis mówi, że trzeba pokroić cebulę, zeszklić ją, dodać czosnek. Nie mówi, czy najpierw przygotować wszystko na deskach, czy biegać do lodówki po każdy składnik osobno. Danie wyjdzie identyczne. Czas — nie.

Cztery rzeczy, które robi runtime

Wczytuje wagi. Zwykle nie kopiując ich do pamięci w klasyczny sposób, tylko mapując plik — system operacyjny podciąga fragmenty dopiero wtedy, gdy są potrzebne. Dlatego pierwsze uruchomienie po restarcie maszyny trwa, a kolejne są natychmiastowe: za drugim razem plik siedzi już w pamięci podręcznej systemu.

Buduje plan wykonania. Bierze graf i przepisuje go na konkretne jądra obliczeniowe — gotowe procedury napisane pod konkretną architekturę sprzętu. Tu następuje właściwa kompilacja i o niej za chwilę osobno.

Rezerwuje pamięć. Z góry, całą, zanim policzy cokolwiek. Wagi to tylko jedna z trzech pozycji — obok nich idą bufory na wyniki pośrednie i miejsce na pamięć podręczną kontekstu, która rośnie z każdym tokenem rozmowy. Ile dokładnie i dlaczego tak szybko, rozłożymy w artykule czwartym.

Wykonuje pętlę. Token po tokenie, przepuszczając dane przez cały graf od początku do końca, aż do warunku zatrzymania. Sama ta pętla, wraz z samplingiem, była już opisana — tu ważne jest tylko, że wykonuje ją ta sama warstwa, która wcześniej skompilowała plan.

Fuzja, czyli skąd bierze się prawdziwa różnica

Wróćmy do wąskiego gardła z poprzedniego artykułu: liczy się nie to, jak szybko sprzęt mnoży, tylko jak szybko przepycha dane między pamięcią a rdzeniami.

Naiwne wykonanie grafu wygląda tak: przeczytaj dane z pamięci, wykonaj operację, zapisz wynik do pamięci. Przeczytaj ten wynik z powrotem, wykonaj następną operację, zapisz. I tak kilkadziesiąt razy na warstwę.

To jest magazynier, który po każdej pojedynczej czynności odwozi paletę z powrotem na regał, żeby zaraz po nią wrócić. Sama czynność trwa sekundę. Jazda tam i z powrotem — dwie minuty.

Fuzja operatorów polega na tym, że runtime rozpoznaje sekwencję operacji i wykonuje je za jednym podejściem, bez odkładania wyniku pośredniego do pamięci głównej. Dane zostają w szybkiej pamięci przy rdzeniach przez kilka kroków naraz. Wynik jest co do bitu ten sam. Liczba przejazdów spada kilkukrotnie.

Najbardziej znanym przykładem jest przepisany mechanizm uwagi — ten sam attention, który już był opisywany, liczony w innej kolejności, tak żeby nigdy nie tworzyć w pamięci całej macierzy pośredniej. Nie zmienia matematyki. Zmienia to, ile razy trzeba sięgnąć do pamięci.

I tu jest odpowiedź na pytanie, skąd biorą się te dwudziestokrotne różnice. Nie z tego, że jeden runtime „lepiej liczy”. Z tego, że jeden jeździ na regał po każdej palecie, a drugi nie.

Dlaczego pierwszy przebieg jest wolniejszy

Kompilacja planu kosztuje czas. Niektóre runtime’y robią ją w całości przy starcie, inne dopiero przy pierwszym faktycznym użyciu danej ścieżki — i wtedy pierwsze wywołanie potrafi trwać kilkakrotnie dłużej niż setne.

Nazywa się to rozgrzewką i ma dwa praktyczne skutki. Po pierwsze, każdy benchmark bez rozgrzewki kłamie. Po drugie — i to jest ważniejsze — ta sama zasada działa piętro wyżej, u dostawcy API, tylko że tam rozgrzewa się nie twoje żądanie, lecz cudzy proces, który akurat się podniósł. Stąd biorą się pojedyncze odpowiedzi wolniejsze bez żadnego powodu widocznego z twojej strony.

Do tego wątku wrócimy w torze drugim.

Czego nie mówi nazwa modelu

Zbierzmy to razem, bo wniosek jest praktyczny.

Kiedy dostawca pisze, że serwuje konkretny model o ośmiu miliardach parametrów, podaje ci jedną informację z czterech. Nie wiesz, w jakiej precyzji trzyma wagi. Nie wiesz, jakim runtime’em go wykonuje. Nie wiesz, jak agresywnie fuzjuje operacje. Nie wiesz, na jakim sprzęcie to stoi.

Te same wagi obsłużone przez dwie różne maszynerie dają odpowiedzi tej samej jakości w czasie różniącym się o rząd wielkości i w cenie różniącej się podobnie. Porównywanie dostawców po nazwie modelu jest jak porównywanie restauracji po tym, że obie mają w karcie schabowego.

Dlatego w tej serii pytanie „jakiego modelu użyć” jest mniej ciekawe niż pytanie „czym on u ciebie jest wykonywany”. Pierwsze ma odpowiedź w marketingu. Drugie ma odpowiedź w rachunku.

Co dalej

Zostało nam jedno założenie, którego jeszcze nie ruszyliśmy. Przez dwa artykuły powtarzam, że mniejsza precyzja to mniej bajtów do przeczytania, czyli więcej tokenów na sekundę — i konsekwentnie pomijam pytanie, ile przy tym tracimy.

Następny artykuł to sprawdza. Ten sam model, ta sama prośba, dwie precyzje, dwie odpowiedzi obok siebie. Bez benchmarków i bez tabelek z cudzych publikacji — na twoim ekranie, na twoim tekście.

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....