Inteligencia artificial
SGLang: Ejecución eficiente de programas de modelos de lenguaje estructurados
Los grandes modelos de lenguaje (LLM) se utilizan cada vez más para tareas complejas que requieren múltiples llamadas de generación, técnicas de prompting avanzadas, control de flujo y entradas/salidas estructuradas. Sin embargo, faltan sistemas eficientes para programar y ejecutar estas aplicaciones. SGLang, un sistema recién introducido, pretende abordar esto proporcionando una ejecución eficiente de programas de modelos de lenguaje complejos. SGLang comprende un lenguaje de frontend y un tiempo de ejecución. El frontend simplifica la programación con primitivas para generación y control de paralelismo, mientras que el tiempo de ejecución acelera la ejecución a través de optimizaciones novedosas como RadixAttention para la reutilización de la caché KV y máquinas de estado finito comprimidas para una decodificación de salida estructurada más rápida. Los experimentos demuestran que SGLang logra un rendimiento hasta 6,4 veces mayor en comparación con los sistemas de inferencia de estado de la técnica en varios modelos de lenguaje grande y multimodal, abordando tareas como control de agente, razonamiento lógico, benchmarks de aprendizaje de pocos disparos, decodificación JSON, pipelines de generación mejorada por recuperación y chat de varios giros.
Los avances recientes en las capacidades de los LLM han ampliado su utilidad, permitiéndoles manejar una gama más amplia de tareas generales y funcionar como agentes autónomos. En estas aplicaciones, los LLM participan en la planificación, razonamiento e interacción con entornos externos en varias rondas. Esto se facilita a través del uso de herramientas, múltiples modalidades de entrada y diversas técnicas de prompting, como el aprendizaje de pocos disparos, la autoconsistencia, el esqueleto de pensamiento y el árbol de pensamiento. Estos nuevos casos de uso necesitan llamadas de generación de LLM múltiples y a menudo dependientes, lo que indica una tendencia hacia el uso de estructuras de llamadas múltiples para completar tareas complejas.
Este cambio marca una transición desde el simple chat hacia un uso programático más sofisticado de los LLM, donde los programas programan y controlan los procesos de generación de los LLM. Estos programas se denominan “Programas de modelo de lenguaje” (LM Programs). Las técnicas de prompting avanzadas y los flujos de trabajo de agente caen dentro del alcance de los programas LM. Hay dos propiedades comunes de los programas LM: (1) Los programas LM suelen involucrar múltiples llamadas a LLM intercaladas con control de flujo para completar tareas complejas y mejorar la calidad general. (2) Los programas LM reciben entradas estructuradas y producen salidas estructuradas, lo que permite la composición de programas LM y la integración en sistemas de software existentes.
En este artículo, profundizaremos en el marco de SGLang, explorando su arquitectura, analizando su rendimiento y comparándolo con marcos de estado de la técnica. Así que comencemos.
Introducción a SGLang
A pesar del uso generalizado de los programas LM, los sistemas actuales para expresar y ejecutarlos siguen siendo ineficientes. SGLang identifica dos desafíos principales asociados con el uso eficiente de los programas LM:
- Complejidad de programación: Desarrollar programas LM es tedioso y difícil debido a la naturaleza no determinista de los LLM. Esto implica una manipulación extensiva de cadenas, un ajuste experimental de prompts, un análisis de salidas frágil, el manejo de múltiples modalidades de entrada y la implementación de mecanismos de paralelismo. Esta complejidad reduce significativamente la legibilidad incluso de programas simples.
- Ineficiencia de ejecución: La ejecución de programas LM es ineficiente debido a cálculos y uso de memoria redundantes. Los motores de inferencia de estado de la técnica, optimizados para reducir la latencia y mejorar el rendimiento, carecen de conocimiento directo de la carga de trabajo, lo que resulta en ineficiencias significativas. Un ejemplo notable es la reutilización de la caché KV, que consiste en tensores intermedios reutilizables esenciales para la inferencia generativa. Los sistemas actuales carecen de mecanismos efectivos para facilitar la reutilización de la caché KV en varias llamadas a LLM que comparten un prefijo común, lo que lleva a cálculos y memoria innecesarios. Además, la decodificación de salidas estructuradas restringidas, como el modo JSON, es subóptima, ya que los sistemas existentes solo decodifican un token a la vez.
Para abordar estos desafíos, SGLang introduce un lenguaje de generación estructurado para LLM. La idea central es explotar sistemáticamente la estructura de llamadas múltiples en los programas LM para una ejecución eficiente. Como se muestra en la figura siguiente, SGLang tiene dos partes: un lenguaje de frontend y un tiempo de ejecución de backend.

El frontend simplifica la programación de los programas LM, y el tiempo de ejecución acelera su ejecución. Estas partes pueden trabajar juntas para un mejor rendimiento o funcionar de forma independiente.
SGLang es un lenguaje específico de dominio incrustado en Python, que proporciona primitivas para generación (por ejemplo, extend, gen, select) y control de paralelismo (por ejemplo, fork, join). Es compatible con el control de flujo y las bibliotecas de Python, lo que permite a los usuarios desarrollar flujos de trabajo de prompting avanzados con facilidad mediante la sintaxis nativa de Python. SGLang incluye un intérprete y un compilador. El intérprete gestiona el estado de prompt como un flujo y envía operaciones primitivas al flujo para su ejecución asíncrona, garantizando un control adecuado sobre la sincronización y el paralelismo intra-programa. Además, los programas SGLang se pueden trazar y compilar para optimizaciones adicionales. El tiempo de ejecución de SGLang propone varias optimizaciones novedosas para acelerar la ejecución de los programas LM:
- RadixAttention: Esta técnica permite la reutilización automática de la caché KV en varias llamadas de generación. En los motores de inferencia existentes, la caché KV de una solicitud se descarta después del procesamiento, lo que impide la reutilización en varias llamadas y ralentiza la ejecución. SGLang mantiene una caché LRU de la caché KV dentro de un árbol radix, gestionando la caché KV como una caché tradicional y utilizando el árbol radix para un emparejamiento, inserción y expulsión eficientes. Esto permite al tiempo de ejecución manejar varios patrones de reutilización de forma eficiente.
- Máquina de estado finito comprimida: Esta técnica permite una decodificación de salidas estructuradas más rápida. Los sistemas existentes siguen las restricciones solo para el próximo token, lo que les permite decodificar un token a la vez. En cambio, SGLang analiza las restricciones y construye una máquina de estado finito comprimida para representarlas, comprimiendo una ruta de varios tokens en una ruta de un solo paso siempre que sea posible, lo que permite la decodificación de varios tokens a la vez para una mayor velocidad.
- Ejecución especulativa de API: Para modelos de API como OpenAI’s GPT-4, SGLang introduce la ejecución especulativa de API para optimizar programas de llamadas múltiples.
Usando SGLang, se implementaron varias aplicaciones de LLM, incluyendo control de agente, razonamiento lógico, benchmarks de aprendizaje de pocos disparos, decodificación JSON, pipelines de generación mejorada por recuperación y chat de varios giros. El rendimiento se probó en modelos que incluyen Llama-7B/70B, Mistral-8x7B, LLaVA-v1.5-7B (imagen) y LLaVA-NeXT-34B (video) en GPU NVIDIA A10G y A100. Los resultados experimentales muestran que SGLang logra un rendimiento hasta 6,4 veces mayor en una amplia gama de cargas de trabajo, modelos y configuraciones de hardware, en comparación con los sistemas de programación y inferencia existentes, incluyendo Guidance, vLLM y LMQL.
SGLang: Modelo de programación y metodología
El modelo de programación de SGLang se introduce a través de un ejemplo en ejecución, describiendo sus primitivas de lenguaje y modos de ejecución, y esbozando oportunidades de optimización de tiempo de ejecución. Este modelo simplifica operaciones tediosas en flujos de trabajo de llamadas múltiples (por ejemplo, manipulación de cadenas, llamadas a API, especificación de restricciones, paralelismo) proporcionando primitivas flexibles y componibles. SGLang es un lenguaje específico de dominio incrustado en Python. La siguiente figura muestra un programa que evalúa un ensayo sobre una imagen utilizando el método de prompting de rama-resolución-combinación.

La función multi_dimensional_judge toma tres argumentos: `s`, `path` y `essay`. s gestiona el estado de prompt, path es la ruta del archivo de imagen y essay es el texto del ensayo. Nuevas cadenas y primitivas SGLang se pueden agregar al estado s para su ejecución utilizando el operador +=. Primero, la función agrega la imagen y el ensayo al prompt. Luego, verifica si el ensayo está relacionado con la imagen utilizando select, almacenando el resultado en s[“related”]. Si están relacionados, el prompt se bifurca en tres copias para una evaluación paralela desde diferentes dimensiones, utilizando gen para almacenar los resultados en f[“judgment”]. A continuación, combina los juicios, genera un resumen y asigna una calificación por letra. Finalmente, devuelve los resultados en formato JSON, siguiendo un esquema definido por una restricción de expresión regular regex. SGLang simplifica enormemente este programa, ya que un programa equivalente que utilice una interfaz similar a la de OpenAI requeriría 2,1 veces más líneas de código debido a la manipulación manual de cadenas y el control de paralelismo.
SGLang proporciona primitivas para controlar el estado de prompt, la generación y el paralelismo, que se pueden utilizar con la sintaxis y las bibliotecas de Python. A continuación se presentan las primitivas:
gen: Llama a un modelo para generar y almacena los resultados en una variable con el nombre especificado en su primer argumento. Admite un argumento `regex` para restringir la salida a seguir una gramática definida por una expresión regular (por ejemplo, un esquema JSON).
- select: Llama a un modelo para elegir la opción con mayor probabilidad de una lista.
- += o extend: Agrega una cadena al prompt.
- [variable_name]: Recupera los resultados de una generación.
- fork: Crea bifurcaciones paralelas del estado de prompt.
- join: Reune el estado de prompt.
- image y video: Toman entradas de imagen y video.
La forma más sencilla de ejecutar un programa SGLang es a través de un intérprete, donde un prompt se trata como un flujo asíncrono. Primitivas como extend, gen y select se envían al flujo para su ejecución asíncrona. Estas llamadas no bloqueantes permiten que el código de Python continúe ejecutándose sin esperar a que la generación termine, similar a lanzar kernels de CUDA de forma asíncrona. Cada prompt es gestionado por un ejecutor de flujo en un hilo de fondo, lo que permite el paralelismo intra-programa. La recuperación de los resultados de la generación bloqueará hasta que estén listos, garantizando una sincronización correcta. Alternativamente, los programas SGLang se pueden compilar como gráficos computacionales y ejecutar con un ejecutor de gráficos, lo que permite más optimizaciones. Este artículo utiliza el modo intérprete de forma predeterminada y discute los resultados del modo compilador en el Apéndice D. SGLang admite modelos de peso abierto con su propio SGLang Runtime (SRT), así como modelos de API como OpenAI y Anthropic.
Los sistemas de programación para LLM se pueden clasificar en de alto nivel (por ejemplo, LangChain, DSPy) y de bajo nivel (por ejemplo, LMQL, Guidance, SGLang). Los sistemas de alto nivel proporcionan prompts predefinidos o generados automáticamente, como el optimizador de prompts de DSPy. Los sistemas de bajo nivel generalmente no alteran los prompts, pero permiten la manipulación directa de los prompts y las primitivas. SGLang es un sistema de bajo nivel similar a LMQL y Guidance. La siguiente tabla compara sus características.

SGLang se centra más en la eficiencia del tiempo de ejecución y viene con su propio tiempo de ejecución codiseñado, lo que permite optimizaciones novedosas. Los lenguajes de alto nivel (por ejemplo, DSPy) se pueden compilar a lenguajes de bajo nivel (por ejemplo, SGLang). La integración de SGLang como backend en DSPy para una mejor eficiencia de tiempo de ejecución se demuestra más adelante.

El ejemplo anterior ilustra las operaciones de RadixAttention con una política de expulsión LRU a lo largo de nueve puntos de tiempo, mostrando la evolución dinámica del árbol radix en respuesta a diferentes solicitudes. Estas solicitudes incluyen dos sesiones de chat, un lote de consultas de aprendizaje de pocos disparos y muestreos de autoconsistencia. Cada arista del árbol lleva una etiqueta que denota una subcadena o una secuencia de tokens. Los nodos están codificados por colores para reflejar diferentes estados: verde para nodos agregados recientemente, azul para nodos en caché accedidos durante el punto de tiempo y rojo para nodos que han sido expulsados.
Paso 1: El árbol radix está inicialmente vacío.
Paso 2: El servidor procesa un mensaje de usuario entrante “Hola” y responde con la salida de LLM “Hola”. El prompt del sistema “Eres un asistente útil”, el mensaje del usuario “Hola” y la respuesta de LLM “Hola” se consolidan en el árbol como una sola arista vinculada a un nuevo nodo.
Paso 3: Llega un nuevo prompt y el servidor encuentra el prefijo del prompt (es decir, el primer turno de la conversación) en el árbol radix y reutiliza su caché KV. El nuevo turno se agrega al árbol como un nuevo nodo.
Paso 4: Comienza una nueva sesión de chat. El nodo del paso 3 se divide en dos nodos para permitir que las dos sesiones de chat compartan el prompt del sistema.
Paso 5: La segunda sesión de chat continúa. Sin embargo, debido a los límites de memoria, un nodo del paso 4 debe expulsarse. El nuevo turno se agrega después del nodo restante del paso 4.
Paso 6: El servidor recibe una consulta de aprendizaje de pocos disparos, la procesa y la inserta en el árbol. El nodo raíz se divide porque la nueva consulta no comparte ningún prefijo con los nodos existentes.
Paso 7: El servidor recibe un lote de consultas de aprendizaje de pocos disparos adicionales. Estas consultas comparten los mismos ejemplos de pocos disparos, por lo que un nodo del paso 6 se divide para permitir el intercambio.
Paso 8: El servidor recibe un nuevo mensaje de la primera sesión de chat. Expulsa todos los nodos de la segunda sesión de chat, ya que son los menos recientemente utilizados.
Paso 9: El servidor recibe una solicitud para muestrear más respuestas para las preguntas de un nodo del paso 8, probablemente para prompting de autoconsistencia. Para hacer espacio para estas solicitudes, se expulsan varios nodos.
Este ejemplo demuestra cómo RadixAttention maneja la asignación y expulsión dinámica de nodos en respuesta a diferentes tipos de solicitudes, garantizando una reutilización eficiente de la caché KV y un manejo de memoria.
SGLang: Evaluación y resultados
Resultados en modelos de peso abierto
Los resultados de latencia y rendimiento se muestran en las siguientes figuras. SGLang mejora el rendimiento hasta 6,4 veces y reduce la latencia hasta 3,7 veces. Estas mejoras se deben a la reutilización de la caché KV, la explotación del paralelismo dentro de un solo programa y la decodificación de salidas estructuradas más rápida.

En estas pruebas de referencia, la tasa de acierto de la caché oscila entre el 50% y el 99%. La Figura 13 (Apéndice) enumera las tasas de acierto de la caché logradas y óptimas para todos ellos, lo que muestra que la programación consciente de la caché de SGLang se acerca al 96% de la tasa de acierto óptima en promedio.

Resultados en modelos más grandes con paralelismo de tensor
Se probaron modelos más grandes, Mixtral-8x7B y Llama-70B, con paralelismo de tensor en el mismo conjunto de pruebas de referencia, y los resultados se informan en la siguiente figura. La aceleración en modelos más grandes muestra una tendencia similar a la observada en modelos más pequeños, lo que indica que las optimizaciones de SGLang se generalizan bien a modelos más grandes. Se omitieron Guidance y LMQL debido a la falta de implementaciones eficientes de paralelismo de tensor.

Resultados en modelos multimodales
SGLang tiene soporte nativo para modelos multimodales con las primitivas de imagen y video. Las optimizaciones de este artículo son compatibles con modelos multimodales. Para RadixAttention, se calcula el hash de las imágenes de entrada y se utiliza como clave en el árbol radix, lo que permite la reutilización de la caché KV de los tokens de imagen de la misma imagen. Se ejecutó LLaVA-v1.5-7B (imagen) en llava-bench-in-the-wild y LLaVA-NeXT-34B (video) en ActivityNet. Debido a que estos modelos no están bien soportados por otros sistemas de referencia, se utilizó la implementación original de los autores del modelo en Hugging Face Transformers como referencia. Como se muestra en la siguiente tabla, SGLang proporciona un rendimiento hasta 6 veces mayor en estas pruebas de referencia. En llava-bench-in-the-wild, se manejaron varias preguntas sobre la misma imagen, y SGLang reutilizó la caché KV en este caso.

Despliegue en producción
SGLang se ha desplegado en Chatbot Arena para servir modelos de peso abierto. Debido al bajo tráfico para algunos modelos, solo un trabajador de SGLang sirve a cada uno. Después de un mes, se observó una tasa de acierto de la caché RadixAttention del 52,4% para LLaVA-Next-34B y del 74,1% para Vicuna-33B. Los aciertos de la caché provenían de mensajes del sistema comunes, imágenes de ejemplo reutilizadas con frecuencia y historias de chat de varios giros. Esto redujo la latencia del primer token en un promedio de 1,7 veces para Vicuna-33B.

Pensamientos finales
En este artículo, hemos hablado sobre SGLang, un sistema recién introducido que pretende abordar la ejecución eficiente de programas de modelos de lenguaje complejos. SGLang comprende un lenguaje de frontend y un tiempo de ejecución de backend. El frontend simplifica la programación con primitivas para generación y control de paralelismo, mientras que el tiempo de ejecución acelera la ejecución a través de optimizaciones novedosas como RadixAttention para la reutilización de la caché KV y máquinas de estado finito comprimidas para una decodificación de salidas estructuradas más rápida. Los experimentos demuestran que SGLang logra un rendimiento hasta 6,4 veces mayor en comparación con los sistemas de inferencia de estado de la técnica en varios modelos de lenguaje grande y multimodal, abordando tareas como control de agente, razonamiento lógico, benchmarks de aprendizaje de pocos disparos, decodificación JSON, pipelines de generación mejorada por recuperación y chat de varios giros.












