Künstliche Intelligenz
SGLang: Effiziente Ausführung von strukturierten Sprachmodellprogrammen
Große Sprachmodelle (LLMs) werden zunehmend für komplexe Aufgaben eingesetzt, die mehrere Generationsschritte, erweiterte Prompting-Techniken, Kontrollfluss und strukturierte Eingaben/Ausgaben erfordern. Es fehlen jedoch effiziente Systeme für die Programmierung und Ausführung dieser Anwendungen. SGLang, ein neu eingeführtes System, zielt darauf ab, dies zu lösen, indem es eine effiziente Ausführung von komplexen Sprachmodellprogrammen ermöglicht. SGLang besteht aus einer Frontend-Sprache und einer Laufzeitumgebung. Die Frontend-Sprache vereinfacht die Programmierung mit Primitiven für Generation und Parallelismuskontrolle, während die Laufzeitumgebung die Ausführung durch neuartige Optimierungen wie RadixAttention für KV-Cache-Wiederverwendung und komprimierte endliche Automaten für schnellere strukturierte Ausgabedekodierung beschleunigt. Experimente zeigen, dass SGLang bis zu 6,4-mal höhere Durchsatzraten im Vergleich zu State-of-the-Art-Inferenzsystemen auf verschiedenen großen Sprach- und Multimodalmodellen erreicht, die Aufgaben wie Agentenkontrolle, logisches Denken, Few-Shot-Learning-Benchmarks, JSON-Dekodierung, retrieval-augmentierte Generierungspipelines und Multi-Turn-Chat bewältigen.
Die jüngsten Fortschritte in den Fähigkeiten von LLMs haben ihre Nützlichkeit erweitert und ermöglichen es ihnen, eine breitere Palette allgemeiner Aufgaben zu bewältigen und als autonome Agenten zu fungieren. In diesen Anwendungen sind LLMs an multi-runden Planung, Denken und Interaktion mit externen Umgebungen beteiligt. Dies wird durch Werkzeugnutzung, multiple Eingabemodi und verschiedene Prompting-Techniken wie Few-Shot-Learning, Selbstkonsistenz, Skelett-des-Gedankens und Baum-des-Gedankens ermöglicht. Diese neuen Anwendungsfälle erfordern mehrere, oft abhängige LLM-Generationsschritte, was einen Trend zur Verwendung von Multi-Call-Strukturen zur Erledigung komplexer Aufgaben anzeigen.
Dieser Wandel markiert einen Übergang von einfachem Chatten zu einer sophisticatederen programmaticen Nutzung von LLMs, bei der Programme die Generierungsprozesse von LLMs planen und kontrollieren. Diese Programme werden als “Sprachmodell-Programme” (LM-Programme) bezeichnet. Erweiterte Prompting-Techniken und agente Arbeitsabläufe fallen in den Bereich von LM-Programmen. Es gibt zwei gemeinsame Eigenschaften von LM-Programmen: (1) LM-Programme umfassen typischerweise mehrere LLM-Aufrufe, die mit Kontrollfluss zur Erledigung komplexer Aufgaben und zur Verbesserung der Gesamtkualität kombiniert werden. (2) LM-Programme erhalten strukturierte Eingaben und produzieren strukturierte Ausgaben, was die Zusammensetzung von LM-Programmen und die Integration in bestehende Softwaresysteme ermöglicht.
In diesem Artikel werden wir uns tiefer mit dem SGLang-Framework auseinandersetzen, seine Architektur erkunden, seine Leistung analysieren und es mit State-of-the-Art-Frameworks vergleichen. Also los geht’s.
Eine Einführung in SGLang
Trotz der weit verbreiteten Verwendung von LM-Programmen bleiben die aktuellen Systeme für ihre Ausdrucksweise und Ausführung ineffizient. SGLang identifiziert zwei primäre Herausforderungen im Zusammenhang mit der effizienten Verwendung von LM-Programmen:
- Programmierkomplexität: Die Entwicklung von LM-Programmen ist mühsam und schwierig aufgrund der nicht-deterministischen Natur von LLMs. Dies umfasst umfangreiche String-Manipulation, experimentelle Abstimmung von Prompts, brüchige Ausgabeparsing, Handhabung mehrerer Eingabemodi und Implementierung von Parallelismusmechanismen. Diese Komplexität verringert die Lesbarkeit sogar einfacher Programme erheblich.
- Ausführungsineffizienz: Die Ausführung von LM-Programmen ist ineffizient aufgrund redundanter Berechnungen und Speicherbedarfs. State-of-the-Art-Inferenzmotoren, die optimiert sind, um die Latenz zu reduzieren und den Durchsatz zu verbessern, haben keine direkte Kenntnis der Arbeitslast, was zu erheblichen Ineffizienzen führt. Ein bemerkenswertes Beispiel ist die Wiederverwendung des Key-Value-(KV)-Caches, der aus wiederverwendbaren Zwischenergebnistensoren besteht, die für generative Inferenz unerlässlich sind. Aktuelle Systeme haben keine effektiven Mechanismen, um die KV-Cache-Wiederverwendung über mehrere LLM-Aufrufe hinweg zu ermöglichen, die einen gemeinsamen Präfix teilen, was zu unnötigen Berechnungen und verschwendetem Speicher führt. Darüber hinaus ist die dekodierte Ausgabe für strukturierte Ausgaben wie JSON-Modus suboptimal, da bestehende Systeme nur ein Token auf einmal dekodieren.
Um diese Herausforderungen zu lösen, führt SGLang eine strukturierte Generierungssprache für LLMs ein. Die Kernidee besteht darin, die Multi-Call-Struktur in LM-Programmen systematisch für eine effiziente Ausführung auszunutzen. Wie in der folgenden Abbildung gezeigt, besteht SGLang aus zwei Teilen: einer Frontend-Sprache und einer Laufzeitumgebung.

Die Frontend-Sprache vereinfacht die Programmierung von LM-Programmen, und die Laufzeitumgebung beschleunigt ihre Ausführung. Diese Teile können zusammen für bessere Leistung oder unabhängig voneinander arbeiten.
SGLang ist eine domänenspezifische Sprache, die in Python eingebettet ist und Primitiven für Generation (z. B. extend, gen, select) und Parallelismuskontrolle (z. B. fork, join) bereitstellt. Es ist kompatibel mit Pythons Kontrollfluss und Bibliotheken, was es Benutzern ermöglicht, erweiterte Prompting-Workflows mit nativer Python-Syntax leicht zu entwickeln. SGLang umfasst einen Interpreter und einen Compiler. Der Interpreter verwaltet den Prompt-Zustand als Stream und übermittelt primitive Operationen an den Stream für asynchrone Ausführung, wodurch eine ordnungsgemäße Kontrolle über Synchronisation und intra-Programm-Parallelismus gewährleistet ist. Darüber hinaus können SGLang-Programme nachverfolgt und kompiliert werden, um weitere Optimierungen vorzunehmen. Die Laufzeitumgebung von SGLang schlägt mehrere neuartige Optimierungen vor, um die Ausführung von LM-Programmen zu beschleunigen:
- RadixAttention: Diese Technik ermöglicht die automatische Wiederverwendung des KV-Caches über mehrere Generationsschritte hinweg. In bestehenden Inferenzmotoren wird der KV-Cache eines Antrags nach der Verarbeitung verworfen, was die Wiederverwendung über mehrere Aufrufe hinweg verhindert und die Ausführung verlangsamt. SGLang verwaltet einen LRU-Cache des KV-Caches innerhalb eines Radix-Baums, wodurch der KV-Cache wie ein traditioneller Cache verwaltet und der Radix-Baum für effizientes Matching, Einfügen und Verwerfen verwendet wird. Dies ermöglicht es der Laufzeitumgebung, verschiedene Wiederverwendungsmodelle effizient zu handhaben.
- Komprimierter endlicher Automat: Diese Technik ermöglicht eine schnellere dekodierte Ausgabe für strukturierte Ausgaben. Bestehende Systeme folgen nur für das nächste Token den Einschränkungen, was sie nur in der Lage macht, ein Token auf einmal zu dekodieren. Stattdessen analysiert SGLang die Einschränkungen und erstellt einen komprimierten endlichen Automaten, um sie darzustellen, wodurch ein multi-token-Pfad in einen einzelnen Schritt-Pfad komprimiert wird, wenn möglich, was die Dekodierung von mehreren Token auf einmal für eine schnellere Geschwindigkeit ermöglicht.
- API-Spekulative Ausführung: Für API-Modelle wie OpenAIs GPT-4 führt SGLang API-spezifische Ausführung ein, um Multi-Call-Programme zu optimieren.
Mit SGLang wurden verschiedene LLM-Anwendungen implementiert, darunter Agentenkontrolle, logisches Denken, Few-Shot-Learning-Benchmarks, JSON-Dekodierung, retrieval-augmentierte Generierungspipelines, Multi-Turn-Chat und Multi-Modal-Verarbeitung. Die Leistung wurde auf Modellen wie Llama-7B/70B, Mistral-8x7B, LLaVA-v1.5-7B (Bild) und LLaVA-NeXT-34B (Video) auf NVIDIA A10G- und A100-GPUs getestet. Experimentelle Ergebnisse zeigen, dass SGLang bis zu 6,4-mal höhere Durchsatzraten über eine breite Palette von Workloads, Modellen und Hardware-Konfigurationen erreicht, im Vergleich zu bestehenden Programmier- und Inferenzsystemen, einschließlich Guidance, vLLM und LMQL.
SGLang: Programmiermodell und Methodik
Das SGLang-Programmiermodell wird durch ein laufendes Beispiel eingeführt, das seine Sprachprimitiven und Ausführungsmodi beschreibt und die Laufzeitoptimierungsmöglichkeiten skizziert. Dieses Modell vereinfacht mühsame Operationen in Multi-Call-Workflows (z. B. String-Manipulation, API-Aufrufe, Einschränkungsspezifikation, Parallelismus) durch flexible und komponierbare Primitiven. SGLang ist eine domänenspezifische Sprache, die in Python eingebettet ist. Die folgende Abbildung zeigt ein Programm, das eine Abhandlung über ein Bild mit der branch-solve-merge-Prompting-Methode bewertet.

Die Funktion multi_dimensional_judge nimmt drei Argumente: `s`, `path` und `essay`. s verwaltet den Prompt-Zustand, path ist der Pfad zur Bilddatei und essay ist der Text der Abhandlung. Neue Strings und SGLang-Primitiven können dem Zustand s für die Ausführung mithilfe des +=-Operators hinzugefügt werden. Zuerst fügt die Funktion das Bild und die Abhandlung zum Prompt hinzu. Dann überprüft es, ob die Abhandlung mit dem Bild in Beziehung steht, indem es select verwendet und das Ergebnis in s[“related”] speichert. Wenn sie in Beziehung stehen, wird der Prompt in drei Kopien für die parallele Auswertung aus verschiedenen Dimensionen aufgeteilt, indem gen verwendet wird, um die Ergebnisse in f[“judgment”] zu speichern. Als Nächstes werden die Urteile zusammengeführt, eine Zusammenfassung generiert und eine Buchstabenbewertung zugewiesen. Schließlich werden die Ergebnisse im JSON-Format zurückgegeben, das einem durch eine reguläre Ausdrucksbeschränkung definierten Schema folgt regex. SGLang vereinfacht dieses Programm erheblich, da ein äquivalentes Programm mit einer OpenAI-API-ähnlichen Schnittstelle 2,1-mal so viele Codezeilen benötigen würde, aufgrund manueller String-Manipulation und Parallelismuskontrolle.
SGLang bietet Primitiven für die Kontrolle des Prompt-Zustands, der Generation und des Parallelismus, die mit Python-Syntax und -Bibliotheken verwendet werden können. Hier sind die Primitiven:
gen: ruft ein Modell auf, um zu generieren und speichert die Ergebnisse in einer Variable mit dem Namen, der in seinem ersten Argument angegeben ist. Es unterstützt ein `regex`-Argument, um die Ausgabe auf eine Grammatik einzuschränken, die durch eine reguläre Ausdrucksbeschränkung definiert ist (z. B. ein JSON-Schema).
- select: Ruft ein Modell auf, um die höchstwahrscheinliche Option aus einer Liste auszuwählen.
- += oder extend: Fügt eine Zeichenfolge zum Prompt hinzu.
- [Variable_Name]: Holt die Ergebnisse einer Generation ab.
- fork: Erstellt parallele Forks des Prompt-Zustands.
- join: Vereint den Prompt-Zustand wieder.
- image und video: Nehmen Bild- und Video-Eingaben entgegen.
Die einfachste Möglichkeit, ein SGLang-Programm auszuführen, ist durch einen Interpreter, bei dem ein Prompt als asynchroner Stream behandelt wird. Primitiven wie extend, gen und select werden dem Stream für asynchrone Ausführung übermittelt. Diese nicht-blockierenden Aufrufe ermöglichen es dem Python-Code, ohne auf die Fertigstellung der Generation zu warten, weiterzulaufen, ähnlich wie bei der asynchronen Ausführung von CUDA-Kernen. Jeder Prompt wird von einem Stream-Executor in einem Hintergrundthread verwaltet, wodurch intra-Programm-Parallelismus ermöglicht wird. Das Abrufen von Generierungsergebnissen wird blockieren, bis sie bereit sind, wodurch eine korrekte Synchronisation gewährleistet ist. Alternativ können SGLang-Programme als Rechennetze kompiliert und mit einem Graph-Executor ausgeführt werden, was weitere Optimierungen ermöglicht. Dieser Artikel verwendet standardmäßig den Interpreter-Modus und diskutiert die Ergebnisse des Compiler-Modus in Anhang D. SGLang unterstützt Open-Weight-Modelle mit seinem eigenen SGLang-Laufzeit-System (SRT) sowie API-Modelle wie OpenAI und Anthropic-Modelle.
Programmiersysteme für LLMs können in Hoch- und Niedrigstufige Systeme eingeteilt werden (z. B. LangChain, DSPy). Hochstufige Systeme bieten vordefinierte oder automatisch generierte Prompts, wie DSPys Prompt-Optimizer. Niedrigstufige Systeme ändern Prompts normalerweise nicht, sondern ermöglichen die direkte Manipulation von Prompts und Primitiven. SGLang ist ein Niedrigstufiges System, ähnlich wie LMQL und Guidance. Die folgende Tabelle vergleicht ihre Funktionen.

SGLang konzentriert sich stärker auf Laufzeit-Effizienz und kommt mit seiner eigenen co-designten Laufzeitumgebung, die neuartige Optimierungen ermöglicht. Hochstufige Sprachen (z. B. DSPy) können in Niedrigstufige Sprachen (z. B. SGLang) kompiliert werden. Die Integration von SGLang als Backend in DSPy für bessere Laufzeit-Effizienz wird später demonstriert.

Das obige Beispiel zeigt RadixAttention-Operationen mit einer LRU-Verdrängungsstrategie über neun Zeitpunkte, die die dynamische Entwicklung des Radix-Baums als Reaktion auf verschiedene Anfragen veranschaulicht. Diese Anfragen umfassen zwei Chat-Sitzungen, eine Charge von Few-Shot-Learning-Anfragen und Selbstkonsistenz-Stichproben. Jede Baumkante trägt eine Beschriftung, die eine Teilzeichenfolge oder eine Sequenz von Token darstellt. Die Knoten sind farbcodiert, um verschiedene Zustände darzustellen: grün für neu hinzugefügte Knoten, blau für im Zeitpunkt abgerufene Cache-Knoten und rot für evigierte Knoten.
Schritt 1: Der Radix-Baum ist zunächst leer.
Schritt 2: Der Server verarbeitet eine eingehende Benachrichtigung “Hallo” und antwortet mit der LLM-Ausgabe “Hi”. Der System-Prompt “Sie sind ein hilfreicher Assistent”, die Benachrichtigung “Hallo!” und die LLM-Antwort “Hi!” werden im Baum als eine Kante mit einem neuen Knoten konsolidiert.
Schritt 3: Eine neue Anfrage wird eingegangen, und der Server findet den Präfix der Anfrage (d. h. die erste Runde des Gesprächs) im Radix-Baum und wiederverwendet seinen KV-Cache. Die neue Runde wird als neuer Knoten im Baum hinzugefügt.
Schritt 4: Eine neue Chat-Sitzung beginnt. Der Knoten aus Schritt 3 wird in zwei Knoten aufgeteilt, um es beiden Chat-Sitzungen zu ermöglichen, den System-Prompt zu teilen.
Schritt 5: Die zweite Chat-Sitzung wird fortgesetzt. Aufgrund von Speicherbeschränkungen muss jedoch ein Knoten aus Schritt 4 evigiert werden. Die neue Runde wird nach dem verbleibenden Knoten aus Schritt 4 hinzugefügt.
Schritt 6: Der Server erhält eine Few-Shot-Learning-Anfrage, verarbeitet sie und fügt sie dem Baum hinzu. Der Wurzelknoten wird geteilt, da die neue Anfrage keinen Präfix mit bestehenden Knoten teilt.
Schritt 7: Der Server erhält eine Charge von zusätzlichen Few-Shot-Learning-Anfragen. Diese Anfragen teilen die gleiche Menge von Few-Shot-Beispielen, sodass ein Knoten aus Schritt 6 geteilt wird, um die gemeinsame Nutzung zu ermöglichen.
Schritt 8: Der Server erhält eine neue Nachricht von der ersten Chat-Sitzung. Er evidiert alle Knoten der zweiten Chat-Sitzung, da sie am wenigsten kürzlich verwendet wurden.
Schritt 9: Der Server erhält eine Anfrage, um weitere Antworten für die Fragen in einem Knoten aus Schritt 8 zu sampeln, wahrscheinlich für Selbstkonsistenz-Prompting. Um Platz für diese Anfragen zu schaffen, werden mehrere Knoten evigiert.
Dieses Beispiel zeigt, wie RadixAttention die dynamische Zuweisung und Eviktion von Knoten auf verschiedene Anfragen reagiert, wodurch eine effiziente KV-Cache-Wiederverwendung und Speicherbewirtschaftung gewährleistet ist.
SGLang: Auswertung und Ergebnisse
Ergebnisse auf Open-Weight-Modellen
Die Latenz- und Durchsatzergebnisse sind in den folgenden Abbildungen dargestellt. SGLang verbessert den Durchsatz um bis zu 6,4-mal und reduziert die Latenz um bis zu 3,7-mal. Diese Verbesserungen resultieren aus der Wiederverwendung des KV-Caches, der Ausnutzung von Parallelismus innerhalb eines einzelnen Programms und der schnelleren dekodierten Ausgabe.

In diesen Benchmarks liegt die Cache-Trefferquote zwischen 50 % und 99 %. Abbildung 13 (Anhang) listet die erreichten und optimalen Cache-Trefferquoten für alle auf, was zeigt, dass SGLangs cache-bewusste Planung im Durchschnitt 96 % der optimalen Trefferquote erreicht.

Ergebnisse auf größeren Modellen mit Tensor-Parallelismus
Größere Modelle, Mixtral-8x7B und Llama-70B, wurden mit Tensor-Parallelismus auf dem gleichen Satz von Benchmarks getestet, und die Ergebnisse werden in der folgenden Abbildung berichtet. Die Geschwindigkeitssteigerung auf größeren Modellen zeigt eine ähnliche Tendenz wie die auf kleineren Modellen, was darauf hinweist, dass SGLangs Optimierung gut auf größere Modelle verallgemeinert.

Ergebnisse auf Multi-Modal-Modellen
SGLang hat native Unterstützung für Multi-Modal-Modelle mit den Bild- und Video-Primitiven. Die Optimierungen in diesem Artikel sind kompatibel mit Multi-Modal-Modellen. Für RadixAttention wird der Hash der Eingabebilder berechnet und als Schlüssel im Radix-Baum verwendet, was die Wiederverwendung des KV-Caches der Bild-Token aus dem gleichen Bild ermöglicht. LLaVA-v1.5-7B (Bild) wurde auf llava-bench-in-the-wild und LLaVA-NeXT-34B (Video) auf ActivityNet ausgeführt. Da diese Modelle von anderen Basissystemen nicht gut unterstützt werden, wurde die ursprüngliche Implementierung der Modellautoren in Hugging Face Transformers als Basissystem verwendet. Wie in der folgenden Tabelle gezeigt, bietet SGLang bis zu 6-mal höhere Durchsatzraten auf diesen Benchmarks. In llava-bench-in-the-wild wurden mehrere Fragen zu demselben Bild behandelt, und SGLang-Laufzeit wiederverwendete den KV-Cache in diesem Fall.

Produktionsbereitstellung
SGLang wurde in Chatbot Arena bereitgestellt, um Open-Weight-Modelle zu bedienen. Aufgrund geringer Traffic für einige Modelle dient nur ein SGLang-Worker jedem. Nach einem Monat wurde eine RadixAttention-Cache-Trefferquote von 52,4 % für LLaVA-Next-34B und 74,1 % für Vicuna-33B beobachtet. Cache-Treffer kamen von gemeinsamen Systemnachrichten, häufig wiederverwendeten Beispielbildern und Multi-Turn-Chat-Verlaufsprotokollen. Dies reduzierte die Latenz des ersten Tokens im Durchschnitt um 1,7-mal für Vicuna-33B.

Letzte Gedanken
In diesem Artikel haben wir über SGLang gesprochen, ein neu eingeführtes System, das darauf abzielt, die effiziente Ausführung komplexer Sprachmodell-Programme zu ermöglichen. SGLang besteht aus einer Frontend-Sprache und einer Laufzeitumgebung. Die Frontend-Sprache vereinfacht die Programmierung mit Primitiven für Generation und Parallelismuskontrolle, während die Laufzeitumgebung die Ausführung durch neuartige Optimierungen wie RadixAttention für KV-Cache-Wiederverwendung und komprimierte endliche Automaten für schnellere strukturierte Ausgabedekodierung beschleunigt. Experimente zeigen, dass SGLang bis zu 6,4-mal höhere Durchsatzraten im Vergleich zu State-of-the-Art-Inferenzsystemen auf verschiedenen großen Sprach- und Multimodalmodellen erreicht, die Aufgaben wie Agentenkontrolle, logisches Denken, Few-Shot-Learning-Benchmarks, JSON-Dekodierung, retrieval-augmentierte Generierungspipelines und Multi-Turn-Chat bewältigen.












