KV-Cache auf 16-GB-GPUs: Lange Kontexte tatsächlich unterbringen

Warum der 128K-Kontext auf 16 GB scheitert

Inhaltsverzeichnis

Ein Modell kann einen 128K-Kontextfenster werben und dennoch bei 40K Tokens auf einer 16-GB-GPU scheitern. Die architektonische Obergrenze hat nie versprochen, dass Gewichte, KV-Cache, Rechenpuffer und der Desktop-Compositor gleichzeitig auf Ihrer Karte Platz finden.

Der KV-Cache ist normalerweise der Punkt, an dem langkontextige Pläne auf diese physikalische Grenze stoßen. Er wächst mit jedem aktiven Token und jeder Sequenz, sodass eine Konfiguration, die beim Start bequem aussieht, abrupt langsamer werden, in den Systemspeicher ausweichen oder während eines großen Prefills fehlschlagen kann.

KV-Cache-Speicherbudget auf einer 16-GB-GPU

Dieser Leitfaden wandelt das Problem in ein VRAM-Budget um. Er behandelt die Cache-Formel, reproduzierbare Größentabellen von 32K bis 128K und funktionierende Konfigurationen für llama.cpp --cache-type-k und --cache-type-v, vLLM paged und prefix caching sowie Ollama Kontextsteuerungen – plus die experimentellen Adaptive-Cache-Forks, die Aufmerksamkeit verdienen, aber nicht blindem Vertrauen. Für den breiteren Kontext zu Durchsatz, Latenz und Benchmarks hinter diesen Zahlen beginnen Sie mit dem LLM-Leistungs-Hub.

Die kurze Antwort für eine 16-GB-GPU

Beginnen Sie mit einer Sequenz, einem realistischen maximalen Kontext, Flash Attention und einem 8-Bit-KV-Cache. Messen Sie diese Konfiguration, bevor Sie 4-Bit-Cache, CPU-Offload, mehrere parallele Slots oder einen experimentellen Fork versuchen.

Ziel Vernünftiger erster Versuch auf 16 GB Hauptrisiko
32K Q4- oder Q5-Gewichte, Q8 KV, eine Sequenz Modellgewichte lassen zu wenig Pufferraum
64K Kleinere Modell oder aggressive Gewichtsquantisierung, Q8 KV Prefill-Latenz und Cache-Bandbreite
128K Kleines GQA-Modell, Q8 oder getesteter Q4 KV, eine Sequenz Allein der Cache kann einen Großteil des VRAMs verbrauchen
Zwei simultane 64K-Sitzungen Als rund 128K Cache-Budget behandeln Parallele Kapazität wird mit kostenlosem Durchsatz verwechselt

Meine Meinung ist einfach: Eine stabile 64K-Konfiguration ist in der Regel nützlicher als eine nominelle 128K-Konfiguration, die am Rande eines Out-of-Memory-Fehlers läuft. Kontextkapazität ist kein Trophäenstück; sie ist eine Entscheidung hinsichtlich Latenz, Qualität und Parallelität.

Was der KV-Cache speichert

Während der autoregressiven Generierung produziert jede Attention-Schicht Key- und Value-Tensoren für jeden verarbeiteten Token. Die Runtime behält diese Tensoren bei, damit der nächste Token auf frühere Tokens achten kann, ohne den gesamten Präfix neu berechnen zu müssen.

Der Cache spart enorme Rechenleistung, verbraucht aber Speicher in proportionalem Verhältnis zur Anzahl der beibehaltenen Tokens. Für einen konventionellen Transformer mit grouped-query attention ist eine nützliche Baseline:

KV bytes = sequences * tokens * layers * 2 * KV heads * head dimension * bytes pro Wert

Der Faktor zwei steht für Keys und Values. Multi-Head-Attention verwendet so viele KV-Heads wie Query-Heads, Grouped-Query-Attention verwendet weniger KV-Heads, und Multi-Head-Latent-Attention oder hybride rekurrente Architekturen benötigen andere Berechnungen.

Warum die Parameteranzahl nicht ausreicht

Zwei 8B-Modelle können sehr unterschiedliche KV-Cache-Kosten haben. Eines kann 32 Schichten und acht KV-Heads verwenden, während ein anderes weniger KV-Heads, gemeinsame KV-Schichten, Sliding-Window-Attention oder komprimierte latente Zustände verwendet.

Die Parameteranzahl sagt hauptsächlich den Speicherbedarf für Gewichte voraus. Die KV-Geometrie stammt aus der Attention-Architektur, daher lesen Sie die Modellmetadaten, anstatt aus 8B, 27B oder der GGUF-Dateigröße zu raten. Die klarste Illustration ist, wie weit sich das Attention-Design von reiner Multi-Head-Attention (MHA) entfernt hat:

  • Multi-Query Attention (MQA) teilt einen einzigen K/V-Head über alle Query-Heads – maximale Cache-Einsparungen, aber es ist der aggressivste Kompromiss bei der Qualität und wird selten allein in aktuellen Frontier-Modellen verwendet.
  • Grouped-Query Attention (GQA) gruppiert Query-Heads in Cluster, die jeweils einen K/V-Head teilen – der Mainstream-Kompromiss, der von den meisten offenen dichten Modellen verwendet wird und die Geometrie, die die obige Formel annimmt.
  • Multi-Head Latent Attention (MLA), eingeführt in DeepSeek-V2 und weitergeführt in DeepSeek-V3 und Kimi K2, verfolgt einen völlig anderen Ansatz: Anstatt K/V über Heads zu teilen, projiziert es Keys und Values in einen komprimierten Vektordarstellung niedrigen Rangs und rekonstruiert die K/V in voller Auflösung bei Bedarf zur Attention-Zeit. DeepSeek berichtete über eine KV-Cache-Reduktion von etwa 93 % im Vergleich zu einem gleich großen dichten MHA-Modell, während die Qualität konkurrenzfähig mit – manchmal besser als – GQA bei gleichem Speicherbudget bleibt.

Die praktische Konsequenz ist, dass ein „27B GQA Modell" und ein „27B MLA Modell" KV-Cache-Fußabdrücke haben können, die für dieselbe Kontextlänge um eine Größenordnung unterschiedlich sind. Nehmen Sie nicht an, dass die obige Formel auf ein Modell angewendet werden kann, das sich als Nutzung von latenter Attention, DeltaNet-Stil-Zustand oder Sliding-Window-Schichten dokumentiert – prüfen Sie zuerst den Architekturabschnitt der Modellkarte.

Mit Ollama ollama show MODEL --verbose werden Modellmetadaten einschließlich Schichtanzahl, Attention-Heads, KV-Heads und Kontextlänge offengelegt, wo das Format sie bereitstellt. Mit llama.cpp enthält die Modell-Loader-Ausgabe, die beim Start gedruckt wird, normalerweise äquivalente GGUF-Metadaten und die tatsächliche Cache-Allokation der Runtime.

Modellgrenze, zugeordneter Kontext und genutzter Kontext

Das sind drei separate Zahlen. Die Modellgrenze ist das Maximum, das durch Training und Positions-Encoding unterstützt wird, der zugeordnete Kontext ist das, was die Runtime reserviert oder erlaubt, und der genutzte Kontext sind die Tokens, die derzeit für eine Sequenz beibehalten werden.

Das Erhöhen einer Engine-Flagge kann ein Modell nicht sicher über sein unterstütztes Positionsschema hinaus erweitern. RoPE-Scaling kann einige Architekturen erweitern, aber es ist ein Modellqualitäts-Experiment, keine KV-Speicher-Optimierung.

KV-Cache-Größentabelle: 32K, 64K und 128K Kontextbudgets

Betrachten Sie ein repräsentatives GQA-Modell mit 32 Schichten, acht KV-Heads und einer Head-Dimension von 128. Diese Dimensionen erzeugen 65.536 Key- und Value-Elemente pro Token, bevor die Speichergröße jedes Elements multipliziert wird.

Die Tabelle verwendet binäre GiB und die physischen Blockgrößen, die häufig mit llama.cpp f16, q8_0 und q4_0 assoziiert werden. Es ist eine Baseline-Berechnung, keine Zusage zum gesamten Prozessspeicher; Ausrichtung, Metadaten, hybride Schichten und Backend-Workspaces fügen Overhead hinzu.

Cache-Typ Ungef. Bytes pro gespeichertem Wert 32K Kontext 64K Kontext 128K Kontext
F16 2.0000 4.00 GiB 8.00 GiB 16.00 GiB
Q8_0 1.0625 2.13 GiB 4.25 GiB 8.50 GiB
Q4_0 0.5625 1.13 GiB 2.25 GiB 4.50 GiB
Q8_0 K plus Q4_0 V Gemischt 1.63 GiB 3.25 GiB 6.50 GiB

Doppeln Sie nun die Schichtanzahl auf 64, während die anderen Dimensionen unverändert bleiben. Der FP16-Cache wird 8 GiB bei 32K, 16 GiB bei 64K und 32 GiB bei 128K, was zeigt, warum eine einzige Kontextempfehlung nicht jedes Modell abdecken kann.

Die tatsächliche 16-GB-Gleichung

Ein praktisches Budget ist breiter als die KV-Formel:

nutzbares VRAM = totales VRAM - Desktop- und Treiberreserve

KV-Budget = nutzbares VRAM
          - auf der GPU residente Modellgewichte
          - Graph- und Aktivierungspuffer
          - Runtime-Workspace
          - State für spekulatives Dekodieren
          - Sicherheitsmarge

Auf einer an einen Display angeschlossenen 16-GB-Karte planen Sie nicht damit, dass alle 16 GiB verfügbar sind. Reservieren Sie mindestens einige hundert MiB für den Desktop und den Treiber, und lassen Sie dann eine weitere Marge für arbeitslastabhängige Puffer; 1.0 bis 1.5 GiB Gesamtatmung sind eine vernünftige Startannahme, aber Ihre Logs sind die Autorität.

Angenommen, ein GGUF-Modell belegt 10.8 GiB auf der GPU und der Runtime-Overhead erreicht einen Spitzenwert von etwa 1.2 GiB. Nach einer 1-GiB-Sicherheitsmarge bleiben nur etwa 3 GiB für KV übrig, sodass das repräsentative Modell bei Q8_0 etwa 45K Tokens oder bei Q4_0 87K Tokens fasst, bevor engine-spezifischer Overhead hinzukommt.

Das macht Q4_0 nicht automatisch zur richtigen Wahl. Wenn die Genauigkeit im langen Kontext in Ihrer Arbeitslast abnimmt, kann ein kleineres oder aggressiver quantisiertes Modell mit einem Q8_0-Cache besser sein als größere Gewichte mit einem fragilen Cache. Gemessene Anker für genau diese Arithmetik finden Sie in den 16-GB-VRAM-llama.cpp-Benchmark-Tabellen, wo VRAM pro Modell bei 19K, 32K und 64K Kontext aufgezeichnet wird. Für eine breitere Umfrage, welche Modellgrößen und Quantisierungsebenen gut unter Ollama auf derselben Kartenclasse funktionieren, siehe Vergleich der LLM-Leistung auf Ollama auf 16-GB-VRAM-GPU.

Berechnen Sie das KV-Cache-Budget für Ihr Modell

Der folgende Python-Snippet schätzt einen konventionellen Full-Attention-GQA-Cache. Ersetzen Sie die Geometrie mit Werten aus der Modellkonfiguration oder GGUF-Metadaten.

def kv_gib(tokens, layers, kv_heads, head_dim, bytes_per_value, sequences=1):
    total = (
        sequences
        * tokens
        * layers
        * 2
        * kv_heads
        * head_dim
        * bytes_per_value
    )
    return total / (1024 ** 3)


model = {
    "layers": 32,
    "kv_heads": 8,
    "head_dim": 128,
}

types = {
    "f16": 2.0,
    "q8_0": 34 / 32,
    "q4_0": 18 / 32,
}

for tokens in (32768, 65536, 131072):
    row = {
        name: round(kv_gib(tokens=tokens, bytes_per_value=size, **model), 2)
        for name, size in types.items()
    }
    print(tokens, row)

Die Q8_0- und Q4_0-Verhältnisse enthalten einfache Block-Metadaten, weshalb sie etwas größer sind als genau ein Byte und ein halbes Byte pro Wert. Der Startbericht der Runtime bleibt genauer, da er modell-spezifische Cache-Layouts kennt.

Wenn diese Formel falsch ist: Hybride und Sliding-Window-Architekturen

Zwingen Sie keine hybriden Architekturen in die konventionelle GQA-Gleichung. Sliding-Window-Schichten behalten nur ein kürzliches Fenster bei, gemeinsame KV-Schichten reduzieren Duplikation, rekurrente Schichten können Zustände fester Größe tragen, und Multi-Head-Latent-Attention speichert eine komprimierte Repräsentation statt K/V-Tensoren pro Head – der MLA-Fall oben ist das dramatischste Beispiel.

Moderne Engines verwalten diese gemischten Layouts zunehmend explizit. Verwenden Sie die Formel, um die dominierenden Terme zu erklären, und bestätigen Sie dann die von der exakten Engine-Version und dem Backend gemeldete Allokation, die Sie planen zu deployen.

llama.cpp: Direkte Kontrolle der K- und V-Präzision

llama.cpp stellt separate --cache-type-k und --cache-type-v-Optionen in seinem aktuellen Argumentparser bereit. Dies ist die nützlichste lokale Inferenz-Schnittstelle, wenn Sie Cache-Präzision gegen Kontextkapazität tauschen müssen, anstatt ein globales Preset zu akzeptieren. Wenn Sie zuerst das umgebende Installations- und Serving-Setup benötigen, deckt der llama.cpp-Leitfaden llama-cli, llama-server und die wichtigsten VRAM-Flags ab.

Eine konservative 64K-Einbenutzer-Konfiguration sieht so aus:

./llama-server \
  --model /models/model.gguf \
  --n-gpu-layers 999 \
  --ctx-size 65536 \
  --parallel 1 \
  --flash-attn on \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --batch-size 1024 \
  --ubatch-size 256

Flag-Syntax und Backend-Unterstützung ändern sich schnell, daher führen Sie llama-server --help für die installierte Build aus. Wichtiger ist, den Start-Log zu inspizieren: Er sollte den beabsichtigten Kontext, die Cache-Typen, das GPU-Offload und die zugeordneten K- und V-Puffer anzeigen.

Welche llama.cpp-Cache-Typen man ausprobieren sollte

Beginnen Sie mit Q8_0 für beide K und V. Es halbiert den KV-Speicher ungefähr im Vergleich zu F16, und unabhängige Perplexity-Tests an Modellen über 20B (Qwen3.6-27B, Nemotron-30B) zeigen, dass der aggregierte Qualitätsunterschied von F16 innerhalb des Messrauschens liegt – eine viel weniger dramatische Wette, als direkt zu Q4_0 zu wechseln, was die gleichen Tests als Zusammenbruch der Dekodiergeschwindigkeit und Genauigkeit im langen Kontext bei kleineren Modellen zeigten.

Wenn Q8_0 nicht passt, testen Sie Q8_0-Keys mit Q4_0-Values, bevor Sie beide Seiten zu Q4_0 quantisieren. Diese Reihenfolge hat wissenschaftliche Stützung, nicht nur Aberglauben: Kontrollierte Bit-Allocationsstudien an Llama-, Phi-4-, Qwen3- und Mistral-Checkpoints stellten fest, dass Key-Tensoren konsistent zwei- bis zehnfach empfindlicher gegen Quantisierungsfehler sind als Value-Tensoren, und dass das Gewähren des größeren Bit-Budgets für Keys (z. B. 4-Bit-Keys mit 2-Bit-Values) bis zu 94–98 % der Genauigkeit in voller Präzision wiederherstellen kann – während die invertierte Aufteilung (2-Bit-Keys, 4-Bit-Values) auf Aufgaben wie GSM8K 30 Prozentpunkte verlieren kann. Keys bestimmen, welche früheren Tokens die Attention tatsächlich matcht, daher ist der Schutz von Keys zuerst die architektonisch sinnvolle Wahl, nicht nur die klanglich sicherere.

Konfiguration Speicher Qualtätsrisiko Empfehlung
F16 K und V Höchstes Niedrigstes Baseline, wenn es passt
Q8_0 K und V Etwa die Hälfte von F16 Niedrig, aber nicht null Standard-16-GB-Startpunkt
Q8_0 K, Q4_0 V Zwischen Q8 und Q4 Moderat Nützlicher zweiter Schritt
Q4_0 K und V Etwa ein Viertel von F16 Höchstes Bei Zieltiefe validieren

Eine Einschränkung, die sich einprägen lohnt: „niedriges Qualtätsrisiko" auf Aggregat-Benchmarks bedeutet nicht null Risiko auf Token-Ebene. Ein kontrollierter Test, der Flash Attention konstant hielt und nur die KV-Präzision unter greedy (deterministischer) Dekodierung änderte, fand, dass Q8_0-Cache den exakten generierten Text auf dem Großteil der Prompts veränderte, und Q4_0 ihn auf praktisch allen veränderte – sobald ein Token kippt, kann der Rest der Fortsetzung divergieren. Perplexity- und Downstream-Aufgabenscores können im Durchschnitt gut aussehen, während individuelle Outputs dennoch vom F16-Baseline abweichen. Wenn Ihre Anwendung Byte-für-Byte-Reproduzierbarkeit benötigt (Regressionstests, zwischengespeicherte Antworten, deterministische Agenten), behandeln Sie jede KV-Quantisierung als Verhaltensänderung, nicht nur als Speicheroptimierung, und validieren Sie gegen Ihren eigenen festen Prompt-Satz.

Quantisierter V-Cache kann Flash Attention oder einen kompatiblen Backend-Pfad erfordern. Ein Server, der still auf einen anderen Typ zurückfällt, invalidiert das Experiment, weshalb Start-Logs wichtiger sind als kopierte Befehlszeilen.

Kontext, parallele Slots und einheitlicher Cache

--ctx-size beschreibt eine Engine-Kapazität, keine Garantie, dass jeder parallele Slot diese Anzahl Tokens unabhängig erhält. Die Cache-Verwaltung hat sich in llama.cpp weiterentwickelt, einschließlich des einheitlichen-Cache-Verhaltens, daher testen Sie die exakte Build, anstatt auf eine ältere Regel zu vertrauen, die einfach Kontext durch Slotanzahl teilt.

Die Kapazitätsgleichung überlebt Implementierungsänderungen: simultan einzigartige Tokens benötigen irgendwo Speicher. Wenn zwei Agenten-Sitzungen jeweils 48K erreichen können, kalkulieren Sie mit etwa 96K live Tokens, es sei denn, die Arbeitslast teilt Präfixe oder toleriert Eviction und Neuberechnung.

Batch-Größe verkleinert nicht gespeicherten KV

--batch-size und --ubatch-size beeinflussen die Prompt-Verarbeitung und temporären Speicher. Das Herabsetzen kann ein großes Prefill vor einem Aktivierungsspeicher-Spike retten, ändert aber nicht die anhaltenden Bytes, die für jeden beibehaltenen Token benötigt werden.

Diese Unterscheidung erklärt ein häufiges Fehlmuster: Das Modell startet und eine leere Anfrage funktioniert, aber ein 60K-Prompt scheitert während der Ingestion. Reduzieren Sie die Micro-Batch, um den transienten Peak zu diagnostizieren; reduzieren Sie Kontext, Cache-Präzision, Parallelität oder Gewichts-Residenz, um die anhaltende Kapazität zu ändern.

vLLM: Paged Kapazität ist immer noch Kapazität

vLLM nähert sich dem Problem als Serving-Engine. Es profilisiert verfügbaren Speicher, reserviert einen KV-Cache-Pool und allokiert Cache in Blöcken, damit gleichzeitige Sequenzen nicht jeweils eine große zusammenhängende Region benötigen. Wenn Sie entscheiden, ob Sie überhaupt zu vLLM wechseln, deckt der Ollama-zu-vLLM-Migrationsleitfaden die Arbeitslast-Signale ab; hier ist die Frage rein, wie viel Cache der Pool halten kann, und der vLLM-Quickstart deckt Installation und allgemeine Serving-Flags ab, die über die Kapazitätshebel unten hinausgehen.

PagedAttention reduziert Fragmentierung und Verschwendung um variable Sequenzlängen – paged Allokation entfernt Fragmentierung, nicht die pro-Token-Speicherkosten, sodass eine einzigartige 128K-Anfrage immer noch genug Blöcke für ihren KV-State braucht.

Der offizielle vLLM-Speichersparleitfaden empfiehlt, max_model_len und max_num_seqs zu begrenzen, wenn Speicher knapp ist, und stellt fest, dass CUDA-Graphen zusätzlichen GPU-Speicher verbrauchen. Auf einer 16-GB-Karte sollten beide Einstellungen absichtlich gesetzt werden, nicht von der maximalen Konfiguration des Modells übernommen.

Ein fokussierter Einzel-Sequenz-Server könnte hier starten:

vllm serve MODEL_ID \
  --max-model-len 65536 \
  --max-num-seqs 1 \
  --gpu-memory-utilization 0.90 \
  --kv-cache-dtype fp8 \
  --enable-prefix-caching

Nicht jede 16-GB-GPU, jedes Modell, jede Quantisierungsmethode oder jedes Attention-Backend unterstützt diese exakte Kombination. Behandeln Sie es als Konfigurationsform: Beschränken Sie Länge und Parallelität, reservieren Sie Puffer, wählen Sie einen unterstützten Cache-Dtype und validieren Sie den Initialisierungsbericht.

FP8 KV-Cache in vLLM

Die aktuelle vLLM-Quantisiert-KV-Cache-Dokumentation unterstützt FP8-Cacheformate auf kompatiblen CUDA- und ROCm-Pfaden. FP8 halbiert den rohen Cache-Speicher ungefähr im Vergleich zu BF16 oder FP16 und kann daher die Token-Kapazität oder Parallelität erhöhen.

Scaling ist wichtig. Die Dokumentation unterscheidet Standard-Scala, Warm-up-Berechnung und Dataset-Kalibrierung und empfiehlt Dataset-basierte Kalibrierung für die höchste Genauigkeit; einfach FP8 mit Scala 1.0 zu setzen ist bequem, aber nicht automatisch die zuverlässigste Qualitätswahl.

Prefix-Caching ist eine Wiederverwendungs-Optimierung

Automatisches Prefix-Caching lässt eine neue Anfrage KV-Blöcke für ein identisches gezwischertes Präfix wiederverwenden. Es ist ausgezeichnet für wiederholte Abfragen über dasselbe lange Dokument, geteilte System-Prompts und Mehr-Runden-Unterhaltungen, da es die Neuberechnung des matchenden Prefills vermeidet.

Es macht eine einzigartige lange Anfrage nicht kleiner und beschleunigt keine Generierung neuer Tokens. Die vLLM-Prefix-Caching-Dokumentation begrenzt den Nutzen explizit auf geteilten-Präfix-Prefill-Arbeit.

GPU-Speichernutzung ist kein freier Speicher

Das Erhöhen von --gpu-memory-utilization gibt vLLM ein größeres Reservierungsziel, aber es schafft kein VRAM. Es zu nah an 1.0 zu schieben, kann unzureichenden Raum für das Display, einen anderen Prozess, sich ändernde Aktivierungs-Peaks oder nicht-PyTorch-Allokationen lassen.

Beginnen Sie bei etwa 0.88 bis 0.92 auf einer dedizierten 16-GB-GPU, inspizieren Sie das Profil und erhöhen Sie nur, wenn die Arbeitslast stabil bleibt. Wenn die Initialisierung erfolgreich ist, aber echte Prompts fehlschlagen, reduzieren Sie gebatchte Tokens, Sequenz-Parallelität, CUDA-Graph-Aufnahme oder den maximalen Kontext, bevor Sie annehmen, dass der Allocator kaputt ist.

Ollama: Einfachere Steuerungen, weniger granulare Diagnose

Ollama bietet absichtlich eine kleinere operative Oberfläche. Seine aktuelle Kontextlängendokumentation setzt GPUs unter 24 GiB auf 4K Kontext, empfiehlt mindestens 64K für Agenten- und Coding-Arbeitslasten und warnt, dass größerer Kontext mehr Speicher verbraucht.

Setzen Sie das serverweite Standard und bestätigen Sie das geladene Modell wie folgt:

OLLAMA_CONTEXT_LENGTH=65536 ollama serve

ollama ps

Sie können auch num_ctx pro Anfrage oder Modell setzen. ollama ps ist wichtig, da seine PROCESSOR- und CONTEXT-Spalten offenlegen, ob das Modell vollständig auf der GPU blieb und ob der angeforderte Kontext tatsächlich allokiert wurde. Seien Sie sich bewusst, dass das Scheduling-Verhalten hinter diesen Zahlen sich zwischen Ollama-Versionen geändert hat; mein Vergleich der Ollama v0.12.1-Speicherallokation zeigt, wie der neue Scheduler einige Modelle weiter auf die CPU schiebt auf einer 16-GB-Karte, daher pinnen Sie die Version, die Sie gemessen haben.

Quantisierter KV-Cache in Ollama

Ollama stellt OLLAMA_KV_CACHE_TYPE mit f16, q8_0 und q4_0-Wahlmöglichkeiten in seiner aktuellen FAQ bereit. Quantisierter KV erfordert Flash Attention, was Ollama automatisch auf unterstützten Backends verwendet oder mit OLLAMA_FLASH_ATTENTION=1 angefordert werden kann.

Ein 16-GB-Langkontext-Dienst kann daher so gestartet werden:

OLLAMA_CONTEXT_LENGTH=65536 \
OLLAMA_FLASH_ATTENTION=1 \
OLLAMA_KV_CACHE_TYPE=q8_0 \
OLLAMA_NUM_PARALLEL=1 \
ollama serve

Q8_0 ist Ollamas empfohlene Alternative zu F16. Die FAQ warnt, dass Q4_0 einen auffälligeren Qualitätsverlust verursachen kann, besonders bei höherem Kontext, daher sollte es ein gemessener Fallback sein, nicht ein automatisches 16-GB-Preset.

Ollama-Parallelität multipliziert das Kontextbudget

Ollama dokumentiert eine besonders klare Regel: benötigter Speicher skaliert mit OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH. Vier parallele Anfragen bei einer 32K-Einstellung können eine aggregierte Kontextallokation von 128K für dieses Modell implizieren.

Für einen persönlichen Agenten auf 16 GB halten Sie OLLAMA_NUM_PARALLEL=1, bis eine lange Sitzung stabil ist. Das Queueing einer zweiten Anfrage ist in der Regel vorzuziehen, das erste Modell teilweise auf die CPU zu schieben und beide Anfragen langsam zu machen. Die Queueing-, 503- und Modell-Entlademechanismen hinter dieser Wahl sind dokumentiert in wie Ollama parallele Anfragen behandelt.

CPU-Offload: Ein gültiger Ausweg mit einem Preis

Das Verschieben einiger Modellschichten oder KV-State in den System-RAM kann einen Allokationsfehler in einen funktionierenden Prozess verwandeln. Es platziert auch PCIe-Bandbreite und Host-Speicherlatenz in den Decode-Pfad, wo jeder generierte Token die Kosten zahlen kann. Die Spur- und Generationsnachweise, wann PCIe tatsächlich beißt, finden Sie in LLM-Leistung und PCIe-Lanes.

Offload kann für gelegentliche Batch-Arbeit sinnvoll sein, ist aber selten der beste Standard für einen interaktiven Coding-Agenten. Vergleichen Sie zuerst eine kleinere Gewichtsquantisierung, Q8 KV, reduzierte Parallelität und eine realistische Kontextobergrenze; verwenden Sie Offload, wenn Kapazität wichtiger ist als Latenz.

Achten Sie auf die Kante, nicht auf den Durchschnitt. Ein Server kann schnell bei 8K dekodieren, dann nachteilig langsam werden, nachdem ein Teil des Arbeitsbereichs ausweicht, daher benchmarken Sie bei 32K, 64K und der beabsichtigten Maximalstelle, anstatt nur eine Rate für leeren Kontext zu berichten.

Sliding-Window- und adaptive KV-Caches

Sliding-Window-Attention ändert das Budget, indem nur ein kürzliches Fenster für ausgewählte Schichten beibehalten wird. Hybride Modelle können diese Schichten mit gelegentlicher globaler Attention oder rekurrentem Zustand kombinieren, was eine flache Vollkontext-Berechnung deutlich überschätzen oder Speicher falsch platzieren lässt.

Die Optimierung ist Teil der Modellarchitektur, kein generischer Schalter, der ohne Konsequenzen angewendet werden kann. Eine Engine muss das Schichtmuster, Evictionsregeln, Positionen und alle globalen Tokens korrekt verstehen.

Was adaptiver KV versuchen zu verbessern

Experimentelle Forks gehen weiter, indem sie Cache-Präzision oder Layout pro Schicht und Kontexttiefe wählen. Das Ziel ist attraktiv: Höhere Präzision beibehalten, wo es zählt, weniger empfindliche Schichten komprimieren und das Mischungsverhältnis ändern, bevor VRAM-Druck einen harten Spill verursacht – die oben beschriebene Erkenntnis, dass Keys empfindlicher sind als Values, ist genau die Art von Signal, die ein adaptiver Allocator automatisch ausnutzen würde, statt es manuelle --cache-type-k/--cache-type-v-Tuning zu überlassen.

Ein August 2026-Downstream-Projekt, llama.cpp-adaptive-turboquant, berichtet über einen automatischen Selektor für mehrere schichtadaptive Modi und veröffentlicht Langtiefen-Tests auf einer RTX 5080 16 GB. Diese Zahlen sind autorberichtete Ergebnisse aus einer spezialisierten Fork, keine Beweis dafür, dass upstream llama.cpp sich gleich verhält.

Warum es immer noch experimentell ist

Die Fork kombiniert benutzerdefinierte Cache-Typen, CUDA-Kernels, modell-spezifische Pfade und Toolchain-Einschränkungen. Das ist weit mehr Code zu vertrauen, als upstream-Cache-Speicher von F16 auf Q8_0 umzuschalten.

Verwenden Sie eine solche Fork nur, wenn upstream eine echte Anforderung nicht erfüllen kann und Sie Qualität, Stabilität und Geschwindigkeit auf Ihrem Modell reproduzieren können. Notieren Sie Commit und CUDA-Version, da ein Ergebnis, das nur an einen Projektnamen gekoppelt ist, nicht reproduzierbar ist.

Ein fairer Adaptive-Cache-Test

Vergleichen Sie die Fork gegen eine upstream-Q8_0-Baseline mit demselben GGUF, Prompt, Sampler, Kontexttiefe und Ausgabelänge. Messen Sie Start-VRAM, Peak-Prefill-VRAM, Prompt-Verarbeitungsgeschwindigkeit, Dekodiergeschwindigkeit und eine Qualitätaufgabe, die tatsächlich Beweise aus dem ältesten Teil des Kontexts benötigt.

Akzeptieren Sie keine erfolgreiche Allokation als vollständiges Ergebnis. Ein Cache kann 128K fassen und dennoch frühe Fakten verlieren, spät in der Sequenz Ausgaben beschädigen oder zu langsam dekodieren, um nützlich zu sein.

Ein gerechnetes 16-GB-Tuning-Verfahren: Eine Variable auf einmal

Der schnellste Weg zu einer stabilen Konfiguration ist, eine Speicherdimension auf einmal zu ändern. Das zufällige Ändern von Cache-Typ, Batch-Größe, Layer-Offload, Parallelität und Kontext zusammen produziert einen funktionierenden Befehl ohne Erklärung.

flowchart TD A["Schritt 1: bei 8K Kontext laden, eine Sequenz, Warm-up-VRAM aufzeichnen"] --> B{"Gewichte + Runtime unter etwa 14.5 GiB?"} B -- "nein" --> C["Kleinere Quant oder Modell wählen, Schritt 1 wiederholen"] C --> A B -- "ja" --> D["Schritt 2: F16/BF16 KV Qualitätsbaseline, Aufgabenoutputs speichern"] D --> E["Schritt 3: auf Q8_0 / FP8 KV mit Flash Attention wechseln"] E --> F["Schritt 4: Kontext stufenweise erhöhen - 32K, 64K, 96K, 128K"] F --> G{"Fehler während Prefill?"} G -- "ja" --> H["Schritt 5: Batch / ubatch Größe reduzieren"] H --> F G -- "nein" --> I{"Fehler nur bei gleichzeitigen Anfragen?"} I -- "ja" --> J["Schritt 5: parallele Slots / max-num-seqs reduzieren"] J --> F I -- "nein" --> K["Erst jetzt: gemischter Q8/Q4, voller Q4, Offload, adaptive Fork"]

Schritt 1: Den Gewichts-Fußboden etablieren

Laden Sie das Modell bei 8K Kontext, einer Sequenz und dem beabsichtigten GPU-Offload. Notieren Sie Prozess-VRAM nach Warm-up und verify, dass keine Schichten unerwartet auf die CPU gewechselt sind.

Wenn die Gewichte und die Runtime bereits mehr als etwa 14.5 bis 15 GiB verbrauchen, hat langer Kontext keinen gesunden Puffer. Wählen Sie eine kleinere Gewichtsquant oder ein Modell, bevor Sie den Cache tunen.

Schritt 2: F16 oder BF16 KV als Qualitätsbaseline messen

Führen Sie den kleinsten Kontext aus, der Ihren Test unterstützt, und behalten Sie den Standard-Hochpräzisions-Cache. Speichern Sie Outputs von Abruf-, Codebearbeitungs-, Werkzeugauswahl- und Langinstruktionsaufgaben.

Diese Baseline sagt Ihnen, ob spätere Fehler von Cache-Quantisierung kommen. Ohne sie kann ein Chat-Template-Problem oder schwaches Modell leicht Q4 KV zur Last gelegt werden.

Schritt 3: Zu Q8 oder FP8 wechseln

Aktivieren Sie Flash Attention, wo erforderlich, wählen Sie Q8_0 in llama.cpp oder Ollama, oder einen unterstützten FP8-Modus in vLLM. Wiederholen Sie dieselben Prompts bei denselben Token-Tiefen und bestätigen Sie, dass der Log den beabsichtigten Cache-Typ zeigt.

Für viele 16-GB-Deployment ist dies der nützliche Haltepunkt. Es verdoppelt die rohe KV-Kapazität ungefähr, ohne die Cache-Kompression zur aggressivsten Quantisierung im Stack zu machen.

Schritt 4: Kontext in Stufen erhöhen

Testen Sie 32K, 64K, 96K und 128K, anstatt direkt zur beworbenen Maximalstelle zu springen. Notieren Sie an jeder Stufe Prompt-Verarbeitung Tokens pro Sekunde, Decode Tokens pro Sekunde, Peak-VRAM und ob Beweise nahe am Anfang noch wiederhergestellt werden können.

Langer Kontext Decode wird oft langsamer, selbst nachdem Speicher passt, weil Attention mehr gecachten Zustand liest. Kapazität und Leistung sind separate Achsen.

Schritt 5: Transienten Speicher tunen

Wenn Fehler während Prefill statt Initialisierung auftreten, reduzieren Sie Micro-Batch oder maximale gebatchte Tokens. Wenn Fehler nur bei gleichzeitigen Anfragen auftreten, reduzieren Sie Sequenz-Parallelität oder parallele Slots.

Erst nachdem diese Steuerungen verstanden sind, sollten Sie gemischten Q8/Q4-Cache, vollen Q4-Cache, CPU-Offload oder eine adaptive Fork versuchen. Behalten Sie den upstream-Q8-Lauf als Vergleichsbaseline. Wenn Sie später spekulatives Dekodieren oder MTP hinzufügen, erinnern Sie sich, dass seine Entwurfspuffer eine weitere Zeile in der Budgetgleichung sind, keine kostenlose Geschwindigkeit – der Spekulatives-Dekodieren-Leitfaden deckt die Mechanik und ihre VRAM-Kosten ab, und mein Qwen 3.6 27B und 35B MTP vs. Standard-Benchmark zeigt genau, wie viel Kontext der zusätzliche Zustand eines MTP-Kopfes auf einer 16-GB-Karte kosten kann.

Was man in einem Langkontext-Benchmark aufzeichnen sollte

Eine einzelne tokens/s-Ziffer versteckt genau das Problem, das dieser Artikel zu lösen versucht. Langkontext-Tests sollten genug Details bewahren, damit ein anderer Operator die Speicher-Grenze reproduzieren kann.

Feld Warum es wichtig ist
GPU und nutzbares VRAM Display-Nutzung und andere Prozesse ändern das Budget
Engine-Version oder Commit Cache-Verhalten und Flags entwickeln sich schnell
Treiber-, CUDA-, ROCm- oder Vulkan-Version Bestimmt Backend- und Kernel-Verhalten
Exaktes Modell und Gewichtsquant Definiert Gewichts-Residenz und Architektur
K- und V-Cache-Typen Definiert anhaltende Cache-Größe und Qualtätsrisiko
Kontextkapazität und Prompt-Tiefe Allokation ist nicht dasselbe wie tatsächliche Tiefe
Parallele Sequenzen Multipliziert oder teilt Cache-Nachfrage
Batch und Micro-Batch Beeinflusst Prefill-Peaks und Geschwindigkeit
Prompt-Verarbeitungsgeschwindigkeit Offenbart Lang-Prefill-Nutzbarkeit
Decode-Geschwindigkeit bei jeder Tiefe Offenbart Cache-Bandbreiten-Verlangsamung
Peak-VRAM und CPU-Offload Unterscheidet Passen von Spill
Langkontext-Qualitätsergebnis Erkennung von Kompressions- oder Positionsfehlern

Verwenden Sie nvidia-smi-Sampling oder die äquivalente Vendor-Tooling während sowohl Prefill als auch Decode. Der Allokationsbericht der Engine ist notwendig, aber Peak-Gerätespeicher während eines echten Prompts ist die Zahl, die Stabilität entscheidet.

Häufige KV-Cache-Fehler auf 16-GB-GPUs

128K-Unterstützung als Hardware-Versprechen behandeln

Das Kontextfeld in einer Modellkonfiguration ist eine architektonische Obergrenze. Es sagt nichts über den Speicher, der nach dem Laden einer bestimmten Quantisierung auf einer bestimmten Engine übrig bleibt.

Berechnen Sie den Cache und verify die Runtime. Marketing-Größe-Kontext ohne VRAM-Budget ist nur ein verzögertes OOM bis zum ersten ernsthafte Prompt.

Gewichte quantisieren, aber KV vergessen

Ein 4-Bit-GGUF reduziert Modellgewichte, nicht einen F16-KV-Cache. Bei langem Kontext kann der Cache die gesamte Ersparnis aufheben und schließlich die Gewichtsfläche überschreiten.

Berichten Sie beide Quantisierungen. Q4_K_M Modell, Q8_0 KV ist sinnvoll; 4-Bit-Modell ist unvollständig.

Annehmen, dass Paged Attention Tokens komprimiert

Paging verbessert Allokations- und Sharing-Verhalten. Es ändert nicht die Tensor-Präzision oder entfernt den KV-State, der von einer einzigartigen Sequenz benötigt wird.

Verwenden Sie paged Allokation, um variable Arbeitslasten effizient zu bedienen. Verwenden Sie Cache-Präzision, Modellarchitektur, Kontextobergrenzen und Parallelitätsgrenzen, um Kapazität zu kontrollieren.

Annehmen, dass Prefix-Caching jedem langen Prompt hilft

Prefix-Caching spart wiederholte Prefill-Berechnung, wenn Anfragen ein exaktes Präfix teilen. Ein einmaliger 100K-Repository-Dump erhält keine magische Speicher-Rabatt einfach, weil Prefix-Caching aktiviert ist.

Es ist eine Arbeitslast-Optimierung, kein Ersatz für die Budgetgleichung. Messen Sie Trefferquote und beibehaltenen Cache-Druck in Multi-User-Serving.

Q4 KV ohne Qualitätstest verwenden

Niedrig-Bit-Cache kann subtil fehlschlagen. Das Modell schreibt immer noch flüssigen Text, aber Attention über entfernte Beweise, exakte Namen, Werkzeugargumente oder Code-Abhängigkeiten kann degradieren – und wie die oben gezeigte Token-Divergenz-Forschung zeigt, ist sogar die „sichere" Q8_0-Einstellung nicht garantiert, die exakte F16-Ausgabe unter deterministischer Dekodierung zu reproduzieren, sondern nur die Genauigkeit im Aggregat zu erhalten.

Testen Sie die Zielaufgabe bei der Zieltiefe. Kurze Chat-Benchmarks sind fast nutzlos für die Validierung eines Langkontext-Caches.

Parallelität auf Auto lassen

Eine Engine kann Parallelität wählen, die für Durchsatz sinnvoll ist, aber für Ihre Langkontext-Ziel unmöglich. Auf 16 GB sind eine tiefe Sequenz und mehrere kurze Sequenzen fundamental unterschiedliche Arbeitslasten.

Setzen Sie die Grenze explizit, und erhöhen Sie sie mit gemessenem Traffic. Andernfalls kann eine zweite Anfrage eine stabile 64K-Konfiguration in eine Allokations- oder Latenzüberraschung verwandeln.

Empfohlene 16-GB-Profile

Diese Profile sind Startpositionen, keine universellen Presets. Ein Modell mit ungewöhnlicher KV-Geometrie – insbesondere ein MLA- oder hybrider Sliding-Window-Design – kann viel billiger oder teurer sein als das konventionelle GQA-Beispiel.

Interaktiver Coding-Agent

Verwenden Sie eine Sequenz, 48K bis 64K Kontext, Q8-Cache, Flash Attention und vollständige GPU-Gewichts-Residenz, wenn möglich. Dieses Profil favorisiert vorhersehbare Latenz und gute Cache-Präzision gegenüber einer beeindruckenden, aber selten nützlichen Maximalstelle.

Aktivieren Sie Prefix-Wiederverwendung, wenn die Engine es unterstützt, da Coding-Runden oft ein großes Repository- oder Gesprächs-Präfix teilen. Kompaktieren Sie dennoch Werkzeugoutput und alte Transkripte; Cache-Engineering macht irrelevante Tokens nicht wertvoll.

Langdokument-Analyse

Verwenden Sie ein kleineres Modell mit 64K bis 128K Kapazität, Q8 oder kalibrierter FP8-Cache, und wiederholten-Präfix-Caching, wenn mehrere Fragen dasselbe Dokument zielen. Messen Sie Zeit zum ersten Token, da Prefill dominieren kann, selbst wenn Decode akzeptabel bleibt.

Wenn nur eine Frage gestellt werden soll, kann Abruf oder chunk-basierte Zusammenfassung schneller und zuverlässiger sein, als den gesamten Korpus durch eine 16-GB-Karte zu zwingen. Langer Kontext ist ein Werkzeug, kein Ersatz für Informationsarchitektur.

Kleiner Multi-User-Server

Begrenzen Sie Kontext pro Anfrage und aktive Gesamtsequenzen, anstatt die Modellmaximalstelle jedem Client zu werben. vLLMs paged Allokation ist hier nützlich, während Ollama und llama.cpp auch explizite Aufmerksamkeit für aggregierte Live-Tokens erfordern.

Bevorzugen Sie Queueing vor unkontrolliertem Spill. Eine langsamere Zulassungspolitik ist weniger schädlich als jede Anfrage plötzlich PCIe während Decode zu überqueren.

Finale Empfehlung für 16-GB-Langkontext

Für langen Kontext auf 16 GB sind Q8 KV und eine aktive Sequenz die richtige Baseline. Sie exponieren die echte Grenze, ohne niedrig-Bit-Cache-Qualität, parallele Allokation und Offload-Latenz gleichzeitig scheitern zu lassen.

Berechnen Sie aus Attention-Geometrie, subtrahieren Sie Gewichte und Runtime-Overhead, und bestätigen Sie dann das Ergebnis in Engine-Logs und Peak-Speichermessungen. Wenn 128K immer noch nicht passt, ist ein kleineres Modell oft die sauberste Optimierung; wenn es passt, aber kriecht, ist die Reduktion des Kontexts oft die ehrlichste.

Paged Attention, Prefix-Caching, Sliding-Window und adaptive Präzision lösen alle nützliche, aber verschiedene Probleme. Die gewinnende Konfiguration ist die, die auf der GPU bleibt, alte Beweise korrekt abruft und akzeptable Decode-Geschwindigkeit bei der Kontexttiefe hält, die Sie tatsächlich verwenden.

Referenzen

Abonnieren

Neue Beiträge zu Systemen, Infrastruktur und KI-Engineering.