SSD Nodes Learn 🎉 VPS ab $4.99/Monat
Anleitungen Matt ConnorVon Matt Connor

Warum Ihr LLM bei 5 Benutzern langsam wird

Ein Benutzer läuft, fünf warten: Ollamas Standardwert parallelism ist 1. Erfahren Sie, wie Batching, KV-Cache, Prefill und Warteschlangentiefe die Kapazität begrenzen.

Warum wird ein selbst gehostetes LLM langsamer, wenn mehr Benutzer hinzukommen?

Ein selbst gehostetes LLM kommt bei 5 gleichzeitigen Benutzern zum Stillstand, weil der Server weiterhin jeweils nur eine Antwort generiert und die anderen vier in einer Warteschlange stehen. In der Dokumentation von Ollama wird der Standardwert eindeutig beschrieben: OLLAMA_NUM_PARALLEL ist „the maximum number of parallel requests each model will process at the same time, default 1“. Es ist nichts defekt. Vier von fünf Personen warten auf ihren Zug.

Die Lösung ist nur selten ein größerer Server. Erforderlich ist eine Serving-Engine, die viele Anfragen im selben Forward-Pass durch das Modell verarbeitet, sowie ausreichend freier Speicher, um währenddessen die Konversationen aller Benutzer zu halten. Beide Aspekte sind wichtig. Der zweite bestimmt tatsächlich Ihre Obergrenze.

Die zwei Phasen jeder Anfrage

Beim Prefill wird der gesamte Prompt auf einmal gelesen und der Attention-Cache dafür aufgebaut. Alle Prompt-Tokens durchlaufen das Modell gemeinsam. Daher besteht der Prefill aus einer großen Matrixmultiplikation und ist durch den Rechendurchsatz begrenzt. Beim Decode wird die Antwort anschließend Token für Token erzeugt. Für jedes Token müssen die vollständigen Gewichte des Modells erneut aus dem Speicher gelesen werden, während die für dieses einzelne Token ausgeführten Berechnungen gering sind. Der Decode ist durch die Speicherbandbreite begrenzt.

Diese Asymmetrie ist der gesamte Grund dafür, dass Batching funktioniert. Beim Decodieren für einen Benutzer werden beispielsweise pro Token 5 GB an Gewichten gelesen, während die meisten Recheneinheiten ungenutzt bleiben. Kommt eine zweite Anfrage hinzu, liest die Engine dieselben 5 GB einmal und berechnet anschließend daraus zwei Tokens. Der zweite Benutzer verursacht dadurch nahezu keinen zusätzlichen Zeitaufwand. Werden Anfragen strikt nacheinander verarbeitet, geht dieser Vorteil verloren.

Zwei Werte bestimmen, was ein Benutzer wahrnimmt. TTFT (time to first token) setzt sich aus der Wartezeit in der Warteschlange und dem Prefill zusammen. ITL (inter-token latency) ist der Abstand zwischen den gestreamten Tokens und wird durch den Decode bestimmt. Ein langsamer Server ist meist bei einem dieser Werte langsam. Die Gegenmaßnahmen sind nicht dieselben.

Statisches Batching lässt alle auf die langsamste Antwort warten

Statisches Batching ist die naive Variante. Sie entsteht, wenn Sie Anfragen selbst im Anwendungscode gruppieren. Die Engine sammelt N Anfragen, verarbeitet sie gemeinsam und hält jeden Slot belegt, bis die längste Generierung in der Gruppe abgeschlossen ist.

Wenn ein Benutzer eine Zusammenfassung mit 1,200 Tokens anfordert, bleiben vier einzeilige Antworten im Batch blockiert, weil der Batch keinen Slot freigibt, bevor sein langsamstes Mitglied fertig ist.

Daraus entstehen zwei Nachteile. Abgeschlossene Sequenzen belegen weiterhin Slots, ohne noch nützliche Berechnungen auszuführen. Dadurch sinkt der effektive Durchsatz, wenn die Ausgabelängen variieren. Bei Chat-Anfragen schwanken die Ausgabelängen stark. Eine Anfrage, die einen Schritt nach der Batch-Bildung eintrifft, wartet, bis der gesamte Batch abgearbeitet ist, bevor ihr Prefill überhaupt beginnt. Dadurch wird ihre TTFT durch den langen Text eines anderen Benutzers bestimmt.

Kontinuierliches Batching nimmt in jedem Token-Schritt Anfragen an und entfernt sie

Kontinuierliches Batching plant auf Ebene eines einzelnen Decodierungsschritts. Nach jedem Schritt entfernt der Scheduler Sequenzen, die gerade ihr Stop-Token ausgegeben haben, und nimmt wartende Anfragen in die freien Slots auf. Eine Antwort, die in Schritt 40 endet, gibt ihren Slot in Schritt 40 frei, nicht erst am Ende eines Batches.

Das ist kein exotisches Verfahren. llama-server dokumentiert -cb, --cont-batching als „ob kontinuierliches Batching (auch dynamisches Batching genannt) aktiviert werden soll (Standard: aktiviert)“, und vLLM basiert auf diesem Konzept. Auch Ollama verarbeitet parallele Anfragen. Der Standardwert begrenzt die Anzahl jedoch auf eins. Deshalb schließen viele Nutzer, dass ihre Hardware keine Nebenläufigkeit unterstützt, obwohl ihre Konfiguration dies verhindert.

Veröffentlichte Ergebnisse zu kontinuierlichem Batching werden in der Regel auf Data-Center-Karten gemessen, die sowohl freie Rechenkapazität als auch mehrere Dutzend Gigabyte für den Cache haben. Die Tendenz dieser Ergebnisse lässt sich auf Ihr System übertragen. Ihre Größenordnung jedoch nicht. Der folgende Abschnitt zum Speicher erklärt den Grund.

Prefill konkurriert beim gleichen Rechenaufwand mit Decode

Wenn eine neue Anfrage eingeht, während vier Antworten gestreamt werden, muss ihr Prompt zuerst als Prefill verarbeitet werden. Prefill ist rechenintensiv. Weist der Scheduler diesem Prefill einen eigenen Schritt zu, erhalten die vier laufenden Benutzer währenddessen kein Token. Bei einem langen Prompt ist das in jedem geöffneten Fenster als sichtbare Pause bemerkbar. Das ist das Stottern, das gemeint ist, wenn der Server jedes Mal kurz stockt, sobald jemand auf „Senden“ klickt.

Chunked Prefill teilt einen langen Prompt in Abschnitte und verarbeitet jeden Abschnitt im selben Schritt wie die laufenden Decodes. Der Tuning-Leitfaden von vLLM beschreibt den Zielkonflikt direkt: Kleinere Chunk-Budgets „erreichen eine bessere ITL, weil weniger Prefills die Decodes verlangsamen“, während höhere Werte „eine bessere Zeit bis zum ersten Token (TTFT) erreichen, da mehr Prefill-Tokens in einem Batch verarbeitet werden können“. Sie entscheiden, wessen Erfahrung geschützt werden soll: die der Person, die auf den Beginn einer Antwort wartet, oder die der Personen, die den Text beim Streamen beobachten.

Die Prompt-Länge bestimmt, wie stark sich das auswirkt. Ein Prompt mit 6,000 Tokens und einer Antwort mit 200 Tokens verursacht 6,000 Tokens Prefill-Arbeit gegenüber 200 Decode-Schritten. Retrieval-augmented Chat und lange System-Prompts führen beide in diesen Bereich. Dadurch ist Prefill kein Rundungsfehler mehr, sondern der Vorgang, auf den Benutzer warten. Prefix Caching hilft, wenn sich der lange Teil wiederholt: vLLM stellt --enable-prefix-caching bereit. Damit wird der Cache für ein gemeinsames Prompt-Präfix wiederverwendet, anstatt es für jede Anfrage neu zu berechnen.

Der KV-Cache läuft zuerst voll

Jedes Token in jeder aktiven Konversation hinterlässt in jeder Modellschicht einen Key-Vektor und einen Value-Vektor. Das ist der KV-Cache (Key/Value-Cache). Er verhindert, dass beim Decoding für jedes neue Token der gesamte Prompt erneut berechnet werden muss. Seine Größe pro Token wird durch die Modellstruktur festgelegt: 2 (ein Key und ein Value) mal die Anzahl der Schichten, mal die Anzahl der Key/Value-Heads, mal die Head-Dimension, mal die Byte-Anzahl pro Wert. Lesen Sie diese Zahlen aus dem config.json des Modells ab.

Berechnen Sie diesen Wert einmal. Dann ist die Obergrenze nachvollziehbar. Ein typisches 8B-Modell mit 36 Schichten, 8 Key/Value-Heads und einer Head-Dimension von 128 benötigt bei einem Cache mit 16 Bit pro Wert 2 36 8 128 2 Byte pro Token. Das sind 147,456 Byte, also etwa 144 KiB. Eine Konversation mit 8,192 Token benötigt daher ungefähr 1.2 GB Cache. Fünf solcher Konversationen benötigen zusätzlich zu den Gewichten ungefähr 6 GB. Das ist die entscheidende Antwort auf die Frage, wie viele Benutzer gleichzeitig unterstützt werden.

Parallelität vervielfacht den Kontext. Die Werkzeuge weisen ausdrücklich darauf hin. In Ollamas FAQ heißt es: „Die parallele Verarbeitung von Anfragen für ein bestimmtes Modell führt dazu, dass sich die Kontextgröße um die Anzahl der parallelen Anfragen erhöht. Ein Kontext von 2K mit 4 parallelen Anfragen ergibt beispielsweise einen Kontext von 8K und eine zusätzliche Speicherzuweisung.“ Der erforderliche Arbeitsspeicher skaliert mit OLLAMA_NUM_PARALLEL multipliziert mit OLLAMA_CONTEXT_LENGTH. In llama-server wird der mit -c angeforderte Kontext auf die -np Slots verteilt. Wenn Sie nur die Anzahl der Slots erhöhen, verringert sich daher die Kapazität jeder Anfrage. Lesen Sie den Kontext pro Slot aus dem Start-Log, statt ihn anzunehmen.

vLLM reserviert den Speicher dagegen vorab. --gpu-memory-utilization (Standardwert 0.92) ist „der Anteil des GPU-Speichers, der für den Model Executor verwendet werden soll“. Der nach den Gewichten verbleibende Speicher wird zum ausgelagerten KV-Pool. Wenn dieser Pool nicht mehr ausreicht, verdrängt der Scheduler eine Anfrage, statt sie fehlschlagen zu lassen:

WARNING 05-09 00:49:33 scheduler.py:1057] Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space.

In der V1-Engine von vLLM ist der standardmäßige Preemption-Modus RECOMPUTE. Eine verdrängte Anfrage verwirft dabei ihren Cache und führt beim erneuten Einreihen den Prefill erneut aus. Diese Arbeit wird zweimal ausgeführt. Die Dokumentation warnt, dass „Preemption und Neuberechnung die End-to-End-Latenz nachteilig beeinflussen können“. Diese Logzeile ist die beste Erklärung dafür, warum ein einzelner Benutzer deutlich länger warten musste als alle anderen, obwohl der Durchschnitt unauffällig war. Setzen Sie disable_log_stats=False, um den kumulierten Zähler zu protokollieren, oder lesen Sie den Preemption-Zähler aus den von vLLM bereitgestellten Prometheus-Metriken ab.

Was sich bei 2, 5 und 20 gleichzeitigen Benutzern ändert

Zwei Benutzer. Auf einer GPU mit freien Cache-Ressourcen ist der zusätzliche Aufwand nahezu unsichtbar, weil der zweite Decodierungsstream dem ersten mit sehr geringem zusätzlichem Zeitaufwand folgt. Auf einer CPU-only-VPS mit 4 bis 8 GB RAM ist der zusätzliche Aufwand jedoch nicht kostenlos: Beide Streams teilen sich dieselben wenigen vCPUs und dieselbe RAM-Bandbreite. Dadurch sieht jeder Benutzer ungefähr die Hälfte der Tokens pro Sekunde, während sich der Cache-Bedarf bei einem deutlich kleineren Budget verdoppelt.

Fünf Benutzer. Ab diesem Punkt reichen die Standardwerte nicht mehr aus, und zunächst entsteht ein Warteschlangenproblem. Bei OLLAMA_NUM_PARALLEL auf 1 warten vier Personen auf den Benutzer, der die lange Antwort angefordert hat. Sobald sie an der Reihe sind, sehen sie jeweils die normale Geschwindigkeit. Wenn Sie die Anzahl der parallelen Anfragen erhöhen, verändert sich das Problem: Fünf Slots mit jeweils 8K Kontext entsprechen einem Cache von 40K Tokens. Passt dieser nicht in den VRAM, lagert die Engine Layer in den System-RAM aus. Passt er auch nicht in den RAM, verwendet das System Swap, und die Tokens pro Sekunde brechen ein.

Zwanzig Benutzer. Zwanzig Menschen in einer Chat-Oberfläche sind normalerweise nicht zwanzig gleichzeitige Anfragen. Das ist der wichtigste Punkt, den Sie vor dem Kauf der Hardware verstehen sollten. Eine Person liest eine Antwort und denkt zwischen den Eingaben 20 bis 60 Sekunden nach. Der größte Teil ihrer Sitzung ist daher im Leerlauf. Zwanzig Agenten oder zwanzig Aufgaben zur Dokumentzusammenfassung sind dagegen zwanzig echte Streams ohne jede Leerlaufzeit. Dafür ist eine andere Maschine erforderlich.

Sind Ihre Benutzer gleichzeitig aktiv oder lediglich angemeldet?

Ermitteln Sie die Anzahl der laufenden Anfragen, bevor Sie die Größe der Umgebung festlegen. Die Berechnung ist einfach: Laufende Anfragen entsprechen der Benutzerzahl multipliziert mit der Generierungsdauer pro Durchlauf und geteilt durch die Zeit zwischen den Durchläufen.

  1. Messen Sie zuerst die Geschwindigkeit eines einzelnen Datenstroms auf Ihrem eigenen System, sowohl für Prefill als auch für Decode. Übernehmen Sie keinen Wert von der Grafikkarte eines anderen Systems: Tokens pro Sekunde auf dem eigenen System messen und verwenden Sie den gemessenen Wert.
  2. Schätzen Sie den Auslastungszyklus. Bei 20 Chat-Benutzern, 12 Sekunden Generierung pro Durchlauf und einem Durchlauf alle 90 Sekunden ergibt sich 20 * 12 / 90, also etwa 2.7 laufende Anfragen.
  3. Setzen Sie die Anzahl der Slots etwas höher an und prüfen Sie sie anschließend gegen den Speicherbedarf: Die Anzahl der Slots multipliziert mit dem Kontext pro Anfrage muss in die tatsächlich verfügbaren Cache-Tokens passen.
  4. Halten Sie die Warteschlange kurz, damit ein Überlauf schnell und sichtbar fehlschlägt.

Die verfügbaren Cache-Tokens entsprechen dem freien Speicher nach dem Laden der Gewichte, geteilt durch den Kostenaufwand pro Token aus dem vorherigen Abschnitt. Eine 24-GB-Grafikkarte, auf der ein 8B-Modell mit 16-bit ausgeführt wird, verwendet etwa 16 GB für die Gewichte und verfügt bei der Standardauslastung über ungefähr 6 GB nutzbaren Cache. Das reicht für etwa fünf 8K-Konversationen. Um mehr Konversationen unterzubringen, verkürzen Sie den Kontext pro Anfrage oder speichern Sie den Cache mit 8-bit (llama-server benötigt --cache-type-k q8_0). Beides erhöht die gleichzeitige Verarbeitung, erfordert aber einen entsprechenden Kompromiss. Lesen Sie die genaue Abwägung, bevor Sie Geld für Hardware ausgeben: ab wann sich ein GPU-VPS gegenüber API-Tokens amortisiert.

Wenn Ollamas Standardwerte nicht mehr ausreichen

Erhöhen Sie die Anzahl paralleler Anfragen über die Service-Unit, weil ein Export in der Shell einen von systemd verwalteten Daemon nicht erreicht.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_MAX_QUEUE=64"
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment
ollama ps

systemctl show sollte die drei Variablen ausgeben, die Sie gerade gesetzt haben. Ist das nicht der Fall, wurde das Drop-in nicht gespeichert. Dann sind alle weiteren Schritte wirkungslos. ollama ps listet anschließend das geladene Modell mit einer größeren Größe als nur der Größe der Gewichte auf, weil vier Slots mit jeweils 8,192 Tokens zusätzlich 32,768 Tokens Cache reservieren. Wenn die Spalte PROCESSOR einen Teil des Modells auf der CPU anzeigt, obwohl Sie das gesamte Modell auf der GPU erwartet haben, wurde mehr Cache angefordert, als auf der Karte noch verfügbar war. Verringern Sie eine der beiden Zahlen.

Der Standardwert für die Warteschlange verdient eine genauere Betrachtung. Ollama reiht bis zu OLLAMA_MAX_QUEUE Anfragen ein, und „der Standardwert ist 512“. Darüber hinaus antwortet es „mit einem 503-Fehler, der angibt, dass der Server überlastet ist“. Eine Warteschlange mit einer Tiefe von 512 auf einem System, das vier Anfragen gleichzeitig verarbeitet, ist ein Versprechen, das Sie nicht halten können, weil für den Client an Position 300 die Zeitüberschreitung lange vor seiner Verarbeitung eintritt. Eine kurze Warteschlange liefert einen Fehler, den Ihre Anwendung erneut versuchen oder melden kann. Das ist besser als ein Ladesymbol, das nie verschwindet.

Testen Sie das Verhalten unter realen Bedingungen. Senden Sie von zwei Terminals gleichzeitig zwei Anfragen und beobachten Sie beide. Wenn die zweite Anfrage erst nach Abschluss der ersten eine Ausgabe erzeugt, wurde die Einstellung für parallele Anfragen nicht übernommen.

Wenn eine echte Serving-Engine sich amortisiert

vLLM rechtfertigt den zusätzlichen Einrichtungsaufwand, wenn Sie eine GPU mit freien Kapazitäten haben und tatsächlich mehr als ungefähr vier Anfragen gleichzeitig verarbeitet werden. Der Scheduler arbeitet pro Token, der Cache ist seitenweise organisiert, sodass freie Fragmente wiederverwendet werden, und vLLM wandelt freien VRAM in Parallelität um, statt ihn ungenutzt zu lassen. Stand August 2026 bestehen die dokumentierten Installations- und Startbefehle aus zwei Befehlen:

uv pip install vllm --torch-backend=auto
vllm serve Qwen/Qwen2.5-1.5B-Instruct
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "Qwen/Qwen2.5-1.5B-Instruct",
        "messages": [{"role": "user", "content": "Say hello."}]
    }'

Eine Antwort mit einem choices-Array bedeutet, dass der Server läuft und das Modell geladen ist. Unter Last sind die beiden wichtigen Stellschrauben --max-num-seqs, die „maximale Anzahl der Sequenzen, die in einer einzelnen Iteration verarbeitet werden“, und --max-num-batched-tokens, die „maximale Anzahl der Tokens, die in einer einzelnen Iteration verarbeitet werden“. Die erste begrenzt die Parallelität. Die zweite legt das zuvor beschriebene Budget für Chunked Prefill fest.

Bei weniger als ungefähr vier gleichzeitig verarbeiteten Anfragen oder auf einem System ohne unterstützte GPU verursacht vLLM zusätzliche Komplexität und bringt wenig. vLLM setzt eine CUDA-Karte voraus und reserviert beim Start den Großteil des Speichers. Auf einem VPS mit 4 bis 8 GB ist das der falsche Kompromiss. Dort ist ein kleineres Modell mit kürzerem Kontext und einer von Ihnen kontrollierten Warteschlange die bessere Lösung. wie sich Ollama und vLLM als Serving-Engines unterscheiden behandelt diese Auswahl vollständig. Qwen 3 8B auf einem VPS ausführen zeigt, welche Anforderungen ein mittelgroßes Modell stellt, bevor Sie einen einzigen zusätzlichen Benutzer hinzufügen.

Der Zielkonflikt, den die gängige Überlieferung verschweigt

Continuous Batching erhöht den Gesamtdurchsatz und verbessert meist auch die mediane Latenz, weil eine Anfrage aus der Warteschlange früher startet. Die Tail-Latenz entwickelt sich in die entgegengesetzte Richtung. Dieser Aspekt wird nur selten erwähnt.

Jede zusätzliche Sequenz in einem Schritt verursacht etwas mehr Arbeit. Deshalb steigt die ITL für alle, wenn sich der Batch füllt. Das Prefill einer neu eingehenden Anfrage beansprucht einen Teil eines Schritts, der den bereits laufenden Streaming-Anfragen sonst zur Verfügung gestanden hätte. Unter Cache-Druck präemptiert der Scheduler Anfragen. Dadurch muss eine teilweise generierte Anfrage wieder am Anfang ihres Prefill beginnen.

Eine Chat-Oberfläche macht die Tail-Latenz sichtbar, nicht die Durchschnittswerte. Ein Stream, der mitten im Satz zwei Sekunden pausiert, wirkt fehlerhaft, selbst wenn die Gesamtdauer bis zur Fertigstellung gut ist. Messen Sie p95 TTFT und p95 ITL unter der erwarteten Last. Betrachten Sie die mittlere Anzahl von Tokens pro Sekunde als Kapazitätswert und nicht als Beschreibung der tatsächlichen Nutzungserfahrung.

Die praktische Einstellung ergibt sich daraus. Begrenzen Sie die Parallelität etwas unterhalb dessen, was der Speicher zulässt, damit die Engine nie präemptieren muss. Eine kurze, vorhersehbare Warteschlange ist besser als ein tiefer Batch, der ständig unter hoher Last wechselt. Ein Benutzer, der vier Sekunden wartet und anschließend einen gleichmäßigen Stream erhält, ist zufriedener als ein Benutzer, dessen Stream sofort startet und anschließend zweimal stockt.

Was bei langsamer Verarbeitung zu prüfen ist

Jeder einzelne Benutzer erhält normale Antwortzeiten, aber die Wartezeit ist lang. Das ist eine Warteschlange und kein Geschwindigkeitsproblem. Prüfen Sie zuerst die Einstellung für die Parallelität. Das Modell verarbeitet Anfragen korrekt, aber jeweils nur eine Anfrage gleichzeitig.

HTTP 503 von Ollama. Die Warteschlange ist voll. Entweder ist der Server tatsächlich ausgelastet, oder OLLAMA_MAX_QUEUE ist absichtlich niedrig gesetzt, um Last abzuweisen. Genau dafür ist diese Einstellung vorgesehen.

Die Token-Rate pro Sekunde bricht auf einem CPU-Server unter Last ein. Führen Sie währenddessen vmstat 1 aus. Werte ungleich 0 in den Spalten si und so bedeuten, dass der Rechner auslagert. Dadurch werden die Gewichte für jedes Token vom Datenträger gelesen. Keine Konfigurationsänderung kann dieses Problem beheben. Verwenden Sie ein kleineres Modell oder reduzieren Sie die Anzahl der Slots.

Einer von zehn Benutzern wartet deutlich länger als die übrigen. Durchsuchen Sie das vLLM-Log nach preempted. Präemption und die anschließende Neuberechnung sind meist die Ursache. Das bedeutet, dass der Cache für die erlaubte Kontextlänge überbelegt ist.

Die TTFT ist schlecht, obwohl der Server im Leerlauf ist. Das ist Prefill und kein Problem der Parallelität. Lange Prompts benötigen vor der Ausgabe des ersten Tokens tatsächlich Zeit. Prüfen Sie daher zunächst die Prompt-Größe und das Prefix-Caching, bevor Sie die Hardware untersuchen.

FAQ

Warum wird mein selbst gehostetes LLM langsamer, wenn eine zweite Person es verwendet?

Meistens wird es überhaupt nicht langsamer. Die Anfrage wird in eine Warteschlange gestellt. Ollama wird mit OLLAMA_NUM_PARALLEL auf 1 ausgeliefert, sodass die zweite Anfrage wartet, bis die erste ihr letztes Token ausgegeben hat. Unterscheiden Sie die beiden Fälle, indem Sie den Token-Stream eines Benutzers messen, während ein anderer wartet: Wenn die Tokenrate pro Sekunde nach dem Start normal ist, liegt eine Warteschlange vor, und eine Erhöhung der Anzahl paralleler Anfragen behebt das Problem. Wenn beide Streams mit halber Geschwindigkeit laufen, teilen sie sich tatsächlich die Speicherbandbreite. Das ist eine Hardwaregrenze.

Wie viele gleichzeitige Benutzer kann eine kleine GPU bedienen?

Zählen Sie den Speicher, nicht die Benutzer. Zuerst kommen die Gewichte, danach der KV-Cache. Dieser benötigt pro Token und pro aktiver Unterhaltung 2 mal Layeranzahl mal Key/Value-Heads mal Head-Dimension mal Byteanzahl. Ein typisches 8B-Modell mit 36 Layern, 8 Key/Value-Heads und einer Head-Dimension von 128 benötigt im 16-Bit-Format etwa 144 KiB pro Token. Eine Unterhaltung mit 8,192 Token benötigt daher ungefähr 1.2 GB. Eine 24-GB-Karte, die dieses Modell im 16-Bit-Format enthält, hat etwa 6 GB für den Cache übrig. Das reicht für ungefähr fünf Unterhaltungen mit vollständigem Kontext oder für mehr Unterhaltungen bei kürzerem Kontext.

Macht Continuous Batching die Antwort für jeden Benutzer langsamer?

Die mediane Latenz verbessert sich normalerweise, weil Anfragen nicht mehr warten müssen, bis ein kompletter Batch fertig ist. Die Tail-Latenz wird schlechter. Jede zusätzliche Sequenz erzeugt bei jedem Decodierungsschritt zusätzlichen Aufwand. Das Prefill einer neu eingehenden Anfrage beansprucht einen Teil eines Schritts der Benutzer, deren Antworten gerade gestreamt werden. Eine unterbrochene Anfrage muss außerdem zweimal ein Prefill durchführen. Messen Sie die p95-Inter-Token-Latenz und nicht den Durchschnitt. In einem Chatfenster sind Pausen deutlich sichtbar, während der Durchschnitt sie verbergen kann.

Sollte ich OLLAMA_NUM_PARALLEL erhöhen oder zu vLLM wechseln?

Erhöhen Sie zuerst die Anzahl paralleler Anfragen. Das kostet nichts, erfordert nur eine einzelne Drop-in-Datei und behebt den häufigen Fall, dass vier Personen hinter einer langen Antwort warten. Der Speicher ist die begrenzende Ressource: Parallele Anfragen vervielfachen den vorzuhaltenden Kontext. Achten Sie daher darauf, ob Layer auf die CPU ausgelagert werden. Wechseln Sie zu vLLM, wenn Ihre GPU noch VRAM frei hat und tatsächlich mehr als ungefähr vier Anfragen gleichzeitig verarbeitet werden. Ab diesem Punkt liefern der paginierte Cache und die Planung pro Token meist mehr Nutzen, als sie an zusätzlichen Kosten verursachen.

Beheben mehr CPU-Kerne einen langsamen LLM-Server?

Nicht bei dem Teil, den Benutzer am deutlichsten wahrnehmen. Beim Decodieren wird das gesamte Modell für jedes Token aus dem Speicher gelesen. Der Vorgang ist daher durch die RAM-Bandbreite begrenzt. Zusätzliche Kerne helfen nicht mehr, sobald die Bandbreite ausgelastet ist. Das Prefill skaliert dagegen mit der Anzahl der Kerne. Mehr Kerne verkürzen daher bei langen Prompts die Zeit bis zum ersten Token. Bei einem VPS mit 4 bis 8 GB ist normalerweise die Speicherkapazität der begrenzende Faktor. Die wirksame Lösung ist dann meist ein kleineres Modell oder ein kürzerer Kontext und nicht mehr vCPUs.

#vllm#ollama#batching#throughput#self-hosted-ai