Cómo realizar pruebas de carga de una API de LLM con Gatling
Al crear aplicaciones con grandes modelos de lenguaje (LLMs), es esencial garantizar que puedan manejar distintos niveles de demanda. Aquí es donde entran en juego las pruebas de carga. Las pruebas de carga simulan tráfico del mundo real para evaluar el rendimiento de tu API bajo diferentes condiciones. Este enfoque ayuda a identificar posibles cuellos de botella y áreas de mejora, garantizando que la aplicación siga siendo fiable y receptiva.
En un reciente Unstructured Data Meetup de Berlín, Samir Akarioh, developer advocate en Gatling, habló sobre cómo realizar pruebas de carga de una API de LLM usando Gatling. Gatling es un framework de pruebas de rendimiento de código abierto que se utiliza para realizar pruebas de carga de aplicaciones web javascript. Sus perspectivas arrojaron luz sobre la importancia de las pruebas de carga de APIs de LLM y los diferentes métodos utilizados. En este blog, recapitularemos sus puntos clave y analizaremos cómo realizar pruebas de carga de aplicaciones de grandes modelos de lenguaje, en particular aplicaciones RAG (generación aumentada por recuperación) impulsadas por bases de datos vectoriales como Milvus para mejorar el rendimiento, la carga y los tiempos de respuesta.
Mira la repetición de la charla de Samir en YouTube.
¿Qué son las pruebas de carga?
Las pruebas de carga son un tipo de prueba de rendimiento que evalúa cómo se comporta un sistema bajo condiciones de carga específicas, generalmente con intentos de someter el sistema a pruebas de estrés con grandes cantidades de datos. El objetivo principal es evaluar si el sistema puede manejar el tráfico de usuarios o el volumen de datos esperado en condiciones normales y de pico. Durante las pruebas de carga, se monitoriza el comportamiento del sistema para identificar cuellos de botella, degradación del rendimiento o fallos que podrían afectar la experiencia del usuario.
Para las APIs de LLM, las pruebas de carga son particularmente importantes debido a la naturaleza compleja de estos sistemas y las altas exigencias computacionales del procesamiento del lenguaje natural. No realizar pruebas de carga adecuadas puede provocar interrupciones del servicio, tiempos de respuesta lentos o resultados inexactos, lo que podría dañar la confianza de los usuarios y la fiabilidad general de las aplicaciones impulsadas por IA.
En este meetup de datos no estructurados, Samir repasó rápidamente tres tipos de pruebas de carga: prueba de capacidad, prueba de estrés, y prueba de resistencia. Vamos a ir un poco más despacio y a analizar cada una en profundidad.
Prueba de capacidad
Una prueba de capacidad determina la carga máxima que tu API puede manejar cumpliendo los requisitos de rendimiento. El objetivo es identificar el "punto óptimo" donde el sistema opera a su carga máxima sin degradación en el tiempo de respuesta ni en el rendimiento. Para una API de LLM, las pruebas de capacidad encuentran el número máximo de solicitudes por segundo que puede manejar sin dejar de proporcionar respuestas precisas y oportunas.
Por ejemplo, una prueba de capacidad podría implicar aumentar gradualmente el número de usuarios concurrentes que envían prompts a la API hasta que los tiempos de respuesta comiencen a aumentar o la precisión empiece a disminuir. Esta información es invaluable para la planificación de capacidad y puede orientar las decisiones sobre cuándo escalar la infraestructura u optimizar la API.
Las pruebas de capacidad nos ayudan a planificar el tráfico esperado y a comprender los límites antes de que empecemos a ver caídas de rendimiento. Son esenciales para garantizar que el sistema pueda manejar el crecimiento previsto y los períodos de uso máximo sin comprometer la experiencia del usuario.
Prueba de estrés
Mientras que una prueba de capacidad identifica la carga óptima, una prueba de estrés empuja el sistema más allá de sus límites para descubrir su punto de ruptura. El propósito es evaluar cómo se comporta tu API bajo condiciones extremas, como un aumento repentino de solicitudes o un volumen de datos inesperadamente alto.
Las pruebas de estrés pueden simular situaciones del mundo real, como una publicación viral en redes sociales que de repente genera tráfico masivo hacia una aplicación impulsada por IA. Durante estas pruebas, es importante monitorear no solo los tiempos de respuesta y el rendimiento, sino también las tasas de error, la utilización de recursos (CPU, memoria, red) y la calidad de las respuestas de la API.
Las pruebas de estrés son esenciales para entender cómo podría fallar la API de LLM y qué sucede cuando lo hace: si se bloquea, se ralentiza o se recupera. Esta información es vital para mejorar la resiliencia del sistema y garantizar que pueda manejar con elegancia picos inesperados de uso. También puede ayudar a diseñar mejores estrategias de conmutación por error y balanceo de carga.
Prueba de resistencia
Las pruebas de resistencia, o pruebas de duración, evalúan cómo funciona tu API durante un período prolongado. Identifican problemas como fugas de memoria, degradación del rendimiento o saturación de conexiones a la base de datos que podrían no ser evidentes en pruebas más cortas. Para una API de LLM, una prueba de resistencia ejecuta un flujo constante de solicitudes durante varias horas o días para observar cómo el sistema mantiene el rendimiento.
La duración ideal de una prueba de resistencia puede variar según el sistema y sus patrones de uso esperados. Para algunas API de LLM, una prueba de 24 horas podría ser suficiente, mientras que otras podrían beneficiarse de pruebas de una semana para descubrir problemas sutiles que solo se manifiestan durante períodos prolongados.
Las pruebas de resistencia son especialmente buenas para revelar una degradación gradual del rendimiento. Por ejemplo, podrían mostrar que los tiempos de respuesta aumentan lentamente con el tiempo, o que la calidad del texto generado disminuye sutilmente después de procesar una gran cantidad de solicitudes. Estos conocimientos pueden ser cruciales para implementar medidas de mantenimiento proactivas y optimizar el rendimiento a largo plazo.
Esta prueba garantiza que la API pueda manejar una demanda sostenida sin deteriorarse, lo cual es crucial para aplicaciones que se espera que funcionen continuamente o manejen tráfico constante a largo plazo.
Mejores prácticas para pruebas de carga de API de LLM
Al realizar pruebas de carga en API de LLM, considera las siguientes mejores prácticas:
Usa datos y escenarios realistas que imiten patrones de uso reales.
Aumenta gradualmente la carga para identificar con precisión los umbrales de rendimiento.
Monitorea una amplia gama de métricas, incluidos los tiempos de respuesta, las tasas de error y la utilización de recursos.
Prueba desde diferentes ubicaciones geográficas para tener en cuenta la latencia de red.
Incluye una combinación de diferentes tipos de solicitudes que tu API maneja habitualmente.
Herramientas para pruebas de carga Se pueden usar varias herramientas para pruebas de carga de API de LLM, incluidas:
Apache JMeter: Una herramienta de código abierto que puede utilizarse para varios tipos de pruebas de carga.
Locust: Una herramienta basada en Python que es particularmente buena para pruebas de carga distribuidas.
Gatling: Una herramienta basada en Scala que es excelente para pruebas de carga de alto volumen. La siguiente sección profundizará en las pruebas de carga con Gatling.
Pruebas de carga de una API de LLM con Gatling
Gatling es una herramienta de pruebas de carga para aplicaciones web diseñada para DevOps e Integración Continua. Como ya has entendido la teoría de las pruebas de carga, veamos cómo podemos realizar en la práctica una prueba de carga en la API Chat Completions de OpenAI usando Gatling. Sigue esta guía para configurar tu proyecto de Gatling.
1. Configuración de la clase de simulación
Primero, comienza importando las bibliotecas necesarias y configurando la clase de simulación:
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
Estas importaciones incorporan el DSL (lenguaje específico de dominio) principal y el DSL HTTP para crear escenarios y gestionar solicitudes HTTP en Gatling. Después de importar las bibliotecas, define la clase de simulación.
public class SSELLM extends Simulation {
String api_key = System.getenv("api_key");
En el código anterior, la clase SSELLM extiende Simulation , una clase base obligatoria para todas las simulaciones de Gatling. La variable api_key recupera la clave de API de tus variables de entorno, lo que garantiza que la información sensible no esté codificada directamente.
2. Configuración del protocolo HTTP
Después de pasar la clave de API, el siguiente paso es especificar la URL base del servicio de tu LLM.
HttpProtocolBuilder httpProtocol =
http.baseUrl("https://api.openai.com/v1/chat")
.sseUnmatchedInboundMessageBufferSize(100);
El baseUrl especifica el endpoint base de la API, y sseUnmatchedInboundMessageBufferSize(100) configura el tamaño del búfer para gestionar mensajes de eventos enviados por el servidor (SSE) que no coinciden con ninguna respuesta esperada.
3. Definición del escenario
El núcleo de cualquier prueba de Gatling es el escenario que simula el comportamiento del usuario. Definamos un escenario para nuestra prueba.
ScenarioBuilder prompt = scenario("Scenario").exec(
sse("Connect to LLM and get Answer")
.post("/completions")
.header("Authorization", "Bearer " + api_key)
.body(StringBody("{"model": "gpt-3.5-turbo","stream":true,"messages":[{"role":"user","content":"What is a vector database "}]}"))
.asJson(),
asLongAs("#{stop.isUndefined()}").on(
sse.processUnmatchedMessages((messages, session) -> {
return messages.stream()
.anyMatch(message -> message.message().contains("{"data":"[DONE]"}")) ? session.set("stop", true) : session;
})
),
sse("close").close()
);
En el escenario anterior, simulamos a un usuario que envía una solicitud a la API de Chat de OpenAI y espera una respuesta. La prueba establece una conexión SSE (eventos enviados por el servidor) con la API. Luego se envía una solicitud POST al endpoint /completions con un mensaje que solicita al modelo definir una base de datos vectorial. La prueba continúa procesando los mensajes SSE entrantes con asLongAs("#{stop.isUndefined()}") , lo que mantiene la conexión abierta hasta que se cumple una condición específica.
A medida que se reciben mensajes, sse.processUnmatchedMessages(...) verifica si la respuesta contiene la señal "[DONE]" , lo que indica que la interacción ha finalizado. Una vez detectada esta señal, la sesión se detiene y la conexión se cierra con sse("close").close().
4. Inyección de usuarios virtuales
Después de crear el escenario, el paso final es especificar el número de usuarios que se simularán y configurar el protocolo.
{
setUp(
prompt.injectOpen(atOnceUsers(3))
).protocols(httpProtocol);
}
}
El código anterior inyecta tres usuarios virtuales en el escenario simultáneamente. Esta prueba de carga sencilla verifica el rendimiento de la API al gestionar tres solicitudes concurrentes.
Usa el siguiente comando para ejecutar el código:
.mvnw.cmd gatling:test
Una vez que se ejecute el código, Gatling proporcionará una ruta de archivo en la terminal. Esta es la ruta al informe de la prueba. Aquí hay una parte de muestra del informe.
Figura 1: Informe de rango de tiempo de respuesta de Gatling al probar la API de finalización de chat de OpenAI
Como se esperaba para la API de finalización de chat de OpenAI, la prueba demuestra que la API de OpenAI gestionó las solicitudes concurrentes de manera eficiente, con todas las respuestas recibidas en buenos intervalos de tiempo. Pero recuerda, solo enviamos tres solicitudes concurrentes y usamos un prompt muy corto.
En un escenario del mundo real, tu LLM podría recibir miles de solicitudes simultáneamente y prompts más largos. Los prompts más largos suelen darse cuando el usuario proporciona más contexto al LLM. Considera añadir el número de usuarios virtuales y la longitud de los prompts durante un caso del mundo real.
Gatling no se limita a las API de LLM. También puedes usarlo para realizar pruebas de carga en API que impulsan aplicaciones de Retrieval Augmented Generation (RAG). Este enfoque proporcionará una evaluación general del rendimiento de la aplicación. Creemos un escenario en el que podamos realizar pruebas de carga a una aplicación impulsada por RAG.
Pero antes de hacerlo, quizá te preguntes: ¿qué es RAG? Entendamos primero el concepto de RAG.
Entendiendo Retrieval Augmented Generation (RAG)
RAG, o generación aumentada por recuperación, es una técnica que combina las capacidades generativas de un modelo de lenguaje grande (LLM) con un mecanismo de recuperación para obtener información relevante de una base de datos vectorial como Milvus y Zilliz Cloud (el Milvus gestionado). Al aprovechar datos externos como contextos, es menos probable que el LLM alucine y genera respuestas más precisas y contextualmente relevantes. Además, RAG también te permite recuperar datos privados o propietarios para tu LLM como contexto para respuestas más personalizadas sin preocuparte por problemas de seguridad de los datos.
En una configuración típica de RAG, cuando se recibe una consulta de usuario, el sistema RAG recupera documentos o fragmentos relevantes de una base de conocimiento impulsada por una base de datos vectorial. Luego, estos documentos se utilizan para proporcionar contexto al LLM, de modo que el LLM genere una respuesta más informada y completa.
Figura 2: Cómo funciona RAG
Creación de un escenario que prueba una aplicación RAG
Ahora que hemos entendido RAG, aprendamos cómo realizar pruebas de carga a una aplicación RAG usando Gatling.
Imagina una situación en la que una aplicación de soporte al cliente está impulsada por un LLM. Los usuarios podrían consultar el sistema con preguntas que requieren respuestas detalladas y conscientes del contexto. La aplicación aprovecha RAG para extraer documentos relevantes de una base de datos vectorial como Milvus con el fin de mejorar la calidad de estas respuestas. Estos documentos proporcionan al LLM el contexto necesario, lo que le permite producir respuestas más precisas e informadas.
Diseñaríamos un escenario con los siguientes procesos para nuestra prueba de carga.
Solicitudes de usuarios simuladas: Los usuarios virtuales envían consultas complejas que requieren contexto adicional. Por ejemplo, un usuario podría preguntar: "¿Cómo soluciono un problema de conexión con mi dispositivo?" Esta pregunta por sí sola no proporciona suficiente información para obtener una respuesta de alta calidad de un LLM, por lo que el sistema necesita recuperar documentos relevantes de solución de problemas de la base de datos vectorial Milvus .
Recuperación contextual: El sistema obtiene los documentos más relevantes de Milvus en función de la consulta del usuario. Este paso es crucial, ya que determina la calidad del contexto proporcionado al LLM, lo que impacta directamente en la precisión de la respuesta generada. En un pipeline RAG, Milvus indexa una gran cantidad de documentación y realiza una búsqueda de similitud vectorial para encontrar rápidamente la información más relevante.
Generación de respuestas del LLM: Una vez recuperados los documentos relevantes, se proporcionan como contexto al LLM. Luego, el LLM usa esta información para responder a la consulta del usuario. Este proceso genera la respuesta y potencialmente cita fuentes específicas de los documentos recuperados.
Pruebas de carga con usuarios concurrentes: Luego inyectas un número mayor de usuarios virtuales para simular condiciones de uso pico.
Monitoreo y análisis: Cuando Gatling genera el informe, monitoreas cualquier cuello de botella que pueda encontrar la API que impulsa tu aplicación. Es importante señalar que los resultados de las pruebas están influenciados tanto por el rendimiento de los modelos de lenguaje grandes como por la eficiencia del mecanismo de recuperación bajo carga. Esto te brinda una evaluación integral de cómo está funcionando todo el sistema.
Realizar pruebas de carga en tu aplicación impulsada por RAG usando el escenario anterior garantizará que identifiques cualquier problema de escalabilidad.
Conclusión
Samir hizo un buen trabajo al proporcionar información valiosa sobre las pruebas de carga de una API de LLM usando Gatling. Explicó los diferentes tipos de pruebas de carga y cómo podemos realizar pruebas de carga en una API de LLM. También hemos ampliado el artículo para explorar cómo realizar pruebas de carga aún más en otras aplicaciones impulsadas por LLM, como las aplicaciones de atención al cliente basadas en RAG. Con este conocimiento, puedes desarrollar pruebas de API para tus API, asegurando que tus productos puedan escalar sin problemas. Al realizar pruebas de carga en API de LLM, considera las siguientes mejores prácticas:
Mejores prácticas para pruebas de carga de API de LLM
Usa datos y casos de prueba realistas que imiten patrones de uso reales.
Aumenta gradualmente la carga para identificar con precisión los umbrales de rendimiento.
Monitorea una amplia gama de métricas, incluidos los tiempos de respuesta, las tasas de error y la utilización de recursos.
Prueba desde diferentes ubicaciones geográficas para tener en cuenta la latencia de red.
Incluye una combinación de diferentes tipos de solicitudes que tu API maneja normalmente.
Más recursos sobre RAG, GenAI y búsqueda vectorial
Sigue leyendo

Zilliz Cloud Now Available in AWS Asia Pacific (Seoul)
Zilliz Cloud is now available in AWS Seoul — low-latency vector search, in-country data residency, and one-step migration for Korean AI teams. 31 regions across 5 clouds.

Bringing AI to Legal Tech: The Role of Vector Databases in Enhancing LLM Guardrails
Discover how vector databases enhance AI reliability in legal tech, ensuring accurate, compliant, and trustworthy AI-powered legal solutions.

DeepSeek Always Busy? Deploy It Locally with Milvus in Just 10 Minutes—No More Waiting!
Learn how to set up DeepSeek-R1 on your local machine using Ollama, AnythingLLM, and Milvus in just 10 minutes. Bypass busy servers and enhance AI responses with custom data.


