Log ind Opret bruger

← Tilbage til artikler

Qwen3.8 på Intel Arc B70

Hvorfor din AI føles langsom — og hvordan du måler den rigtigt

#vllm #qwen3.8 #benchmark #llm #lokalai
Qwen3.8 på Intel Arc B70

Qwen3.8 på Intel Arc B70: Hvorfor din AI føles langsom — og hvordan du måler den rigtigt

Når man kører store LLMs lokalt — fx til kodning med Pi, Open WebUI eller egne scripts — er tokens per sekund det tal, alle citerer. Men det tal lyver ofte. På mit setup med Intel Arc Pro B70 (32 GB VRAM), Qwen3.8-27B i INT4 og vLLM via Docker-image cyspiegel/vllm-xpu-b70 så det sådan ud: serveren genererer tekst med ~38–51 tok/s (decode), mens en agent i praksis kan føles som 2 tok/s (e2e med kæmpe kontekst). Forskellen er ikke mystisk — den er prefill, kontekstlængde og hvad du måler.

Denne artikel samler reelle målinger fra mit miljø og introducerer et lille benchmark-script, du kan køre mod enhver OpenAI-kompatibel vLLM-server. Scriptet ligger i GitHub-repoet.


Setup: hvad der faktisk kører

Komponent Valg
GPU Intel Arc Pro B70, 32 GB VRAM
Model Qwen3.8-27B, Quant (Frozenlock GPTQ / INT4-sti)
Server cyspiegel/vllm-xpu-b70, preset int4-mtp
API-modelnavn qwen38
Kontekst (config) op til 131.072 tokens, FP8 KV-cache

Det er ikke den fulde FP8-checkpoint fra Hugging Face (~28 GB vægte alene), som på ét kort sjældent giver plads til 128k KV-cache. INT4 + FP8 KV er den praktiske kombination til lang kontekst på 32 GB.


Fire tal du skal kende

Benchmark-scriptet rapporterer flere metrikker end et simpelt curl-stopur:

  1. TTFT (time to first token) — hvor længe du venter, før det første ord kommer. Det er domineret af prefill: at læse hele prompten / konteksten ind i modellen.
  2. Decode tok/s — hastighed efter første token, under selve tekstgenereringen. Det ligner mest skrivehastighed på tastaturet.
  3. E2E tok/s (end-to-end) — completion_tokens / samlet tid. Ved lang kontekst og kort svar bliver dette kunstigt lavt, fordi TTFT tæller med i nævneren.
  4. TPOT (ms/token) — millisekunder per output-token i decode-fasen. Typisk ~20–24 ms/token svarer til ~40–50 tok/s decode; ved ekstrem kontekst stiger TPOT lidt (fx ~26 ms ≈ 38 tok/s).

Konklusion på forhånd: Hvis Pi eller Open WebUI sender titusindvis af tokens som historik, er oplevelsen “langsom” selv om GPU’en stadig skriver med ~45 tok/s, når den først er i gang.


Fuld suite (kort kontekst og “kodning”)

Kørt med ./bench3.sh all mod qwen38:

Test Prompt (tokens) Decode tok/s TPOT TTFT
quick 18 51,3 19,5 ms —
coding (diff-opgave) 369 46,1 21,7 ms 0,43 s
agent (~24k tegn kontekst) 8.085 45,7 21,9 ms 5,4 s

Decode-hastigheden er stabil omkring 46–51 tok/s — det matcher et simpelt curl-test mod /v1/completions. Det er den hastighed, kortet leverer, når modellen genererer.


Kontekst-stresstest: samme kort, fire prompt-størrelser

Testen context fylder prompten med syntetisk “åben kodebase”-tekst og beder om ét kort svar (64 tokens max). Formålet er at isolere prefill ved stigende kontekst — som når en coding agent har hele repoet i vinduet.

Kørsel: ./bench3.sh context <tegn> (fx 340000).

Padding (tegn) Prompt tokens TTFT Prefill tok/s Decode tok/s E2E tok/s Wall tid
~24.000 (fejl i tidlig script-version) 8.016 5,4 s ~1.489 48,6 9,6 6,7 s
120.000 40.019 34,5 s ~1.159 44,0 1,8 36,0 s
250.000 83.352 89,6 s ~930 41,4 0,7 91,2 s
340.000 113.352 115,9 s (~1 min 56 s) ~978 37,8 0,5 117,6 s

Token-tælling kommer fra API’ets usage.prompt_tokens; tegn-padding er ca. 3× tegn per token i disse runs.

Hvad tabellen betyder i praksis

  • Decode falder gradvist (49 → 38 tok/s fra lille til ~113k prompt-tokens) — stadig brugbart, men TPOT stiger fra ~20 ms til ~26 ms.
  • TTFT vokser næsten lineært med prompt-størrelse: ~35 s @ 40k tokens → ~90 s @ 83k → ~116 s @ 113k — næsten to minutter uden ét synligt ord.
  • Prefill-throughput holder sig omkring 930–1.500 prompt-tok/s; flaskehalsen er mængden af tokens, ikke at GPU’en “dør”.
  • E2E tok/s på 0,5–1,8 ved 64 output-tokens er forventet matematik, ikke defekt GPU:
    64 / 118 s ≈ 0,5 tok/s — næsten al tid er prefill.

Det er sandsynligvis det, du ser, når Pi rapporterer ~2 tok/s: lang tråd + værktøjer + filer, ikke langsom generering.

113k prompt-tokens ligger tæt på min konfigurerede grænse (131.072 max model length). Testen med context 340000 er derfor et realistisk peek på worst-case agent-prefill før decode: ~2 minutters ventetid, derefter stadig ~38 tok/s når teksten først flyder.

Prefix-cache (slået til i min compose) kan gøre gentagne prompts hurtigere; cold, unik mega-prompt er det værste case ovenfor.


Officiel FP8 vs. INT4 vs. GGUF (kort)

Sti 128k på 32 GB B70 Typisk decode
INT4 + vLLM (mit setup) Ja, med FP8 KV ~38–50 tok/s decode
Officiel Qwen3.8-27B-FP8 i vLLM Nej (vægte ~28 GB, KV presset) ~16k kontekst realistisk
Q6_K GGUF + llama.cpp Muligt, anden stack Ofte lignende eller lavere end INT4-vLLM ved 128k

Jeg beholdt CySpiegel-stien til daglig kodning; FP8 er fint til kvalitet ved kort kontekst, ikke som erstatning for INT4 ved 128k på ét kort.


Benchmark-scriptet (bench3.sh)

Scriptet taler med et OpenAI-kompatibelt API (vLLM, llama-server m.fl.) og printer både menneskelæselige blokke og JSON til logning.

Krav

  • bash, python3, curl
  • Server kører med kendt model-id (her: qwen38)

Miljøvariabler

Variabel Standard Betydning
MODEL qwen38 model i API-kald
URL http://127.0.0.1:8000 uden /v1
MAX_OUT 512 max completion tokens (agent/coding)
CONTEXT_CHARS 24000 standard padding til agent / all
RUNS 1 gentagelser (mean/stdev i summary)
WARMUP 0 1 = smid første opvarmningskald væk
FORMAT both text, json eller both

Kommandoer

cd ~/vllm-b70
chmod +x bench3.sh

# Fuld pakke: quick, coding, context, agent + summary-tabel
MODEL=qwen38 URL=http://127.0.0.1:8000 ./bench3.sh all

# Enkelttests
./bench3.sh quick
./bench3.sh coding
./bench3.sh agent

# Kontekst-stresstest: andet argument = antal tegn i prompt
./bench3.sh context 120000
./bench3.sh context 250000
./bench3.sh context 340000   # ~113k prompt-tokens, nær 128k-config

# Kun tekst (ingen JSON)
FORMAT=text ./bench3.sh all

# Gentag for stabil median
RUNS=3 WARMUP=1 ./bench3.sh quick

Tests simulerer

  • quick — kort completion, ren decode-baseline
  • coding — system + kodestump + “lav et diff” (chat, stream)
  • context — stor kunstig kontekst + kort svar (prefill-domineret)
  • agent — stor kontekst + længere kodgenerering

Kildekode og opdateringer: GitHub — vllm-b70 bench

Tip: I en tidlig version (bench2.sh) blev context 120000 ved en fejl stadig kørt med 24.000 tegn. Tjek at output viser context_120000chars og ~40k prompt_tokens, ikke ~8k.


Pi, Open WebUI og “følt hastighed”

  1. Peg API mod http://127.0.0.1:8000/v1 og model qwen38 (samme som SERVED_NAME i Docker).
  2. Mål server med ./bench3.sh quick — forvent ~50 tok/s decode.
  3. Føles Pi langsom: start ny chat, kort prompt; hvis det er hurtigt, er problemet kontekst, ikke GPU.
  4. Sammenlign decode tok/s fra bench med e2e — agent-brug ligner context-testen, ikke quick.

Drift: Docker-plads (kort)

Hvis docker pull fejler med no space left on device på /, mens modeller ligger på /home: flyt både Docker data-root og containerd root til /home — billedlag gemmes ofte under /var/lib/containerd på root-partitionen selv om Docker er flyttet.


Opsummering

Spørgsmål Svar på mit B70-setup
Hvor hurtigt skriver modellen? ~38–51 tok/s decode (TPOT ~20–26 ms)
Kan jeg bruge 128k kontekst? Ja med INT4 + FP8 KV; ved ~113k prompt-tokens: ~2 min TTFT
Hvorfor føles 2 tok/s i agent? TTFT + kæmpe prompt — e2e 0,5–1,8 i context-test
Hvordan dokumenterer jeg ændringer? ./bench3.sh all og gem JSON

Hardware og kvantisering bestemmer loftet; kontekst bestemmer, om du rammer loftet eller venter halve minutter på første token. Mål begge dele — decode og TTFT — så du ikke optimerer det forkerte.


Målingerne i denne artikel er kørt på privat Ubuntu-host med Arc Pro B70, oktober 2025. Tal vil variere med image-tag, driver og prompt. Repositér scriptet og rå JSON fra dine egne kørsler sammen med docker-compose for reproducerbarhed.


Alle artikler
0 kommentarer

Ingen kommentarer endnu. Vær den første.

Log ind for at kommentere