Součást série o stavbě cz-agents → pod kapotou

Otázka za desítky tisíc

Klientský use case zněl jednoznačně: RAG nad důvěrnými dokumenty — nabídkami v tendru — a tvrdá podmínka, že žádný z nich nesmí opustit lokální síť. Žádné API u třetí strany, žádný cloudový model. Data zůstávají doma, model taky. To je pro tento typ úloh čím dál běžnější zadání a technicky se dá splnit: Open WebUI jako rozhraní, bge-m3 na embeddingy běžící na ARM serveru a generativní model přes ollama na pracovním notebooku s procesorem Ryzen 6800H, kde jsem vyhradil šest jader.

Otázka nebyla, jestli to jde postavit. Otázka byla, jestli to stačí — a pokud ne, jestli je potřeba GPU a jaká. A za tou otázkou se schovává rozhodnutí o desítkách tisíc korun, protože kdo si grafiku koupí a pak zjistí, že mu na model nestačí VRAM, koupil špatně. Chtěl jsem to rozhodnutí opřít o čísla, ne o dojmy z fóra. A protože jde o citlivá data, nešlo jen o výkon — celý benchmark musel proběhnout tak, aby se k reálným nabídkám nedostal nikdo mimo lokální síť. To dvojí zadání, výkon i zachování důvěrnosti dat, určilo, jak jsem měřil.

Co zvládne CPU (a co ne)

Nejdřív jsem změřil to, co už mám. Model llama3.1:8b na šesti jádrech Ryzenu 6800H dával zhruba 20 tokenů za sekundu při čtení promptu a 6,5 tokenu za sekundu při generaci. Reálný RAG dotaz, který do kontextu natáhne kolem sedmi tisíc tokenů z nalezených dokumentů, tak trval 4 minuty a 22 sekund. Kvalita odpovědi byla použitelná. Latence nikoli — s takovým časem na jeden dotaz se interaktivně pracovat nedá, a analytik, který má projít desítky nabídek, u toho nevydrží.

Zkusil jsem větší model. qwen3:14b na stejném CPU vyprodukoval odpověď za zhruba 15 minut. Kvalitativně byl viditelně lepší — lepší struktura, spolehlivější čtení tabulek, méně přehlédnutých detailů. Ale 15 minut na dotaz je mrtvé číslo. Věděl jsem, že chci kvalitu čtrnáctimiliardového modelu a latenci pod minutou. To CPU neumí a žádný env var to nezmění. Otázka se tím zúžila: jaká nejlevnější GPU tu kombinaci dá.

Místo nákupu půjčovna

Tady většina lidí sáhne po specifikacích na webu výrobce a hádá. Já jsem místo toho grafiku na jeden večer pronajal. vast.ai je tržiště, kde si od lidí i datacenter půjčíte konkrétní GPU na hodiny; RTX 3090 s 24 GB VRAM tam vyšla na 0,126 USD za hodinu, se storage kolem 0,19 USD za hodinu. Nahrál jsem tam stejný stack, pustil identický prompt a měřil.

Výsledek: 1 889 tok/s při čtení promptu, 59 tok/s při generaci, odpověď za 14,7 sekundy. Osmnáctinásobek CPU. A hlavně — model správně našel obě ceny, které jsem do testovacích dokumentů schválně nastražil. Večer jsem si přidal ještě RTX 5090 s 32 GB za 0,416 USD za hodinu. Tam se qwen3:32b vešel celý do VRAM a odpovídal za 35 sekund, kdežto qwen3:14b jel na 1 986 tok/s / 108 tok/s / 19,6 s a na mé testovací sadě kvalitou dostačoval. Celý účet za oba benchmarky včetně storage: pár dolarů.

Rozhodnutí tím přestalo být vírou. Čtrnáctimiliardový model plus karta s 24 GB VRAM úlohu zvládne. Třicetdvamiliardový model kvalitu zásadně nezvedl, jen si řekl o dražší kartu. Nákup grafiky se odkládá, dokud ho nezaplatí reálná, měřená potřeba — a až přijde, vím přesně, po čem sáhnout.

Tolik příběh. Užitečnější než čísla ale byly věci, které se v průběhu rozbily. Polovina z nich neměla s výkonem karty nic společného.

Flash attention: jeden env var, pětinásobek

OLLAMA_FLASH_ATTENTION=1 je defaultně vypnutý. Na RTX 5090 znamenal rozdíl mezi 296 a 1 539 tok/s při čtení promptu — víc než pětinásobek, jedna proměnná prostředí. U RAG, kde je drtivá většina práce právě čtení dlouhého kontextu, to není detail, ale klíčový údaj.

Nebezpečnější je druhá strana téhle mince. Kdybych benchmark pustil s výchozím nastavením, prompt eval by vypadal mizerně, závěr by zněl „3090 je pomalá, kupte silnější kartu" a to rozhodnutí by bylo věcně špatné. Benchmark, který neběží se správnou konfigurací, nelže o něco — lže o všem. Než začnu srovnávat hardware, musím si být jistý, že měřím software v jeho nejlepší kondici. Jinak neporovnávám karty, ale svoji vlastní neznalost konfigurace — a to je nejdražší druh přesných čísel.

24 GB není 24 GB

Třicetdvamiliardový model v kvantizaci Q4 se s osmitisícovým kontextem nevejde do 24 GB. Ollama to nevyhodí jako chybu — místo toho tiše přesune část vrstev na CPU (partial offload) a výkon spadne z desítek tokenů za sekundu na 9,5 tok/s. Degradace o řád, bez jediného varování, jen z logu se dá vyčíst, že část modelu neběží na GPU.

Poučení je banální, a přesto ho pořád opakuju i sobě: do VRAM se nepočítá jen model, ale model včetně KV cache, která roste s délkou kontextu. Čím delší kontext (a RAG je z definice dlouhý kontext), tím větší cache. Kdo dimenzuje kartu podle velikosti váhového souboru, dimenzuje špatně a zjistí to až v provozu, kde se to pozná nejhůř.

num_ctx 4096 tiše ořezává RAG

Výchozí délka kontextu v ollamě je 4096 tokenů. Když do promptu natlačíte sedm tisíc tokenů nalezených dokumentů, model prostě první polovinu zahodí — v logu se objeví lakonické truncating input prompt a nic víc. Odpověď přijde, zní sebejistě, a přitom vznikla z poloviny podkladů. Nikdo si toho nevšimne, protože výstup vypadá kompletně.

Tohle je nejzákeřnější chyba z celého benchmarku, protože nemá žádný vnější projev. Pomalý model poznáte. Model, který nevidí půlku dokumentů a přesvědčivě o nich mlčí, poznáte jen tehdy, když máte testovací sadu se známou odpovědí. Bez ní RAG s výchozím nastavením tiše zhoršuje kvalitu a tváří se, že je vše v pořádku.

Když streaming mlčí

Image ollama:latest měl streaming, který se s Open WebUI nekamarádil — rozhraní dostávalo prázdné odpovědi, zatímco stejný dotaz přes non-stream API vracel korektní text. Půl hodiny jsem hledal chybu v promptu a v RAG pipeline, než mi došlo, že problém je v nekompatibilitě verzí na koncích streamu.

Řešení bylo nudné: nastavit pevné verze na obou stranách, ne se spoléhat na latest. Ale je to připomínka, že u lokálního stacku nesete integrační riziko sami. Když spolu dvě open-source komponenty přestanou mluvit, není za vámi žádný dodavatel — jste vy, log a dvě verze, které se musí potkat.

Pomalá síť = SIGBUS

Levné GPU hosty na tržišti mají jednu tichou nevýhodu: pomalé připojení. Když se stahování runtime knihoven utne v půlce, dostanete SIGBUS za běhu — pád, který vypadá jako chyba hardwaru, ale ve skutečnosti je to nedostažený soubor. Ztratil jsem tak jednu instanci, než mi došlo, kde je příčina.

Do filtru instancí proto patří inet_down>1000 stejně samozřejmě jako typ karty a velikost VRAM. Rychlost sítě není luxus, je to podmínka toho, aby se stack vůbec spolehlivě rozběhl. Nejlevnější nabídka s pomalou linkou vás nakonec stojí víc než o pár centů dražší instance, na které vše naběhne napoprvé.

Na cizí GPU jen fiktivní data

A teď to nejdůležitější, co s výkonem nesouvisí vůbec. Pronajatá grafika běží na cizím stroji, ke kterému má hostitel root. To se pro benchmark důvěrných dat vzájemně vylučuje — takže na půjčenou GPU šla jen fiktivní data. Reálné nabídky z tendru se strojů na platformě vast.ai ani nedotkly.

Tím ale governance nekončí, začíná. Testovací sadu jsem sestavil jako vygenerované fiktivní dokumenty, do kterých jsem schválně vložil nastražené háčky: dvě podobné položky, které se liší v jednom detailu — třeba dvě varianty téhož komponentu s jinou specifikací a jinou cenou. Díky tomu se dá objektivně změřit, jestli RAG ten detail našel, nebo jestli obě položky splynuly do jedné sebejisté nepravdy. Právě na tomhle háčku se pozná rozdíl mezi kartou, která odpověděla rychle, a kartou, která odpověděla rychle a správně.

Eval bez ground truth je jen dojmologie. „Vypadá to dobře" není metrika. Bez známé správné odpovědi neumíte odlišit model, který úlohu vyřešil, od modelu, který ji přesvědčivě předstíral — a u RAG nad citlivými dokumenty v tomto rozdílu spočívá hodnota celého produktu. Testovací sada s nastraženými háčky je levnější než jedna špatná nákupní objednávka a odpoví na otázku, kterou benchmark rychlosti sám o sobě nezodpoví.

Co si z toho beru

GPU za desítky tisíc se dnes dá vyzkoušet před koupí za cenu oběda. Pár dolarů na tržišti s GPU, vlastní testovací sada se známými odpověďmi a večer měření — a nákupní rozhodnutí přestane být vírou v datasheet. To je samo o sobě dost důvodů, proč napřed půjčovat a teprve pak kupovat.

Ale hlavní lekce je jinde. Z šesti věcí, které rozhodly o výsledku, byla jen jedna doopravdy o hardwaru. Zbytek byly dva env vary, jedno nenápadné výchozí nastavení, jedna nekompatibilita verzí a jeden filtr na rychlost sítě. Kdybych měřil naivně, dostal bych přesná čísla o špatně nakonfigurovaném systému a s klidným svědomím koupil dražší kartu, než bylo potřeba. Nejdražší chyba v dimenzování není pomalá GPU. Je to sebejisté měření, které nikdo neověřil.

Řešíte podobné rozhodnutí ve vaší firmě? → AI konzultace