Comment tester la charge d’une API LLM avec Gatling
Lors de la création d’applications avec de grands modèles de langage (LLMs), il est essentiel de s’assurer qu’elles peuvent gérer des niveaux de demande variables. C’est là que les tests de charge entrent en jeu. Les tests de charge simulent le trafic du monde réel afin d’évaluer les performances de votre API dans différentes conditions. Cette approche aide à identifier les goulots d’étranglement potentiels et les axes d’amélioration, garantissant que l’application reste fiable et réactive.
Lors d’un récent Unstructured Data Meetup de Berlin, Samir Akarioh, developer advocate chez Gatling, a expliqué comment effectuer un test de charge d’une API LLM avec Gatling. Gatling est un framework open source de test de performance utilisé pour effectuer des tests de charge d’applications web javascript. Ses observations ont mis en lumière l’importance des tests de charge des API LLM et les différentes méthodes utilisées. Dans cet article de blog, nous récapitulerons ses points clés et discuterons de la manière d’effectuer des tests de charge d’applications basées sur de grands modèles de langage, en particulier les applications RAG (retrieval augmented generation) alimentées par des bases de données vectorielles comme Milvus afin d’améliorer les performances, la charge et les temps de réponse.
Regardez le replay de la présentation de Samir sur YouTube.
Qu’est-ce que le test de charge ?
Le test de charge est un type de test de performance qui évalue le comportement d’un système dans des conditions de charge spécifiques, généralement en tentant de soumettre le système à un test de stress avec de très grandes quantités de données. L’objectif principal est d’évaluer si le système peut gérer le trafic utilisateur ou le volume de données attendu dans des conditions normales et de pic. Pendant le test de charge, le comportement du système est surveillé afin d’identifier les goulots d’étranglement, les dégradations de performance ou les défaillances susceptibles d’affecter l’expérience utilisateur.
Pour les API LLM, le test de charge est particulièrement important en raison de la nature complexe de ces systèmes et des fortes exigences computationnelles du traitement du langage naturel. Ne pas mener de tests de charge appropriés peut entraîner des interruptions de service, des temps de réponse lents ou des résultats inexacts, ce qui peut nuire à la confiance des utilisateurs et à la fiabilité globale des applications alimentées par l’IA.
Lors de ce meetup sur les données non structurées, Samir a passé en revue trois types de tests de charge : test de capacité, test de stress, et test d’endurance. Ralentissons un peu et examinons chacun d’eux en profondeur.
Test de capacité
Un test de capacité détermine la charge maximale que votre API peut gérer tout en respectant les exigences de performance. L’objectif est d’identifier le « point idéal » où le système fonctionne à sa charge maximale sans dégradation du temps de réponse ni du débit. Pour une API LLM, le test de capacité détermine le nombre maximal de requêtes par seconde qu’elle peut gérer tout en fournissant encore des réponses précises et rapides.
Par exemple, un test de capacité pourrait consister à augmenter progressivement le nombre d’utilisateurs simultanés envoyant des prompts à l’API jusqu’à ce que les temps de réponse commencent à augmenter ou que la précision commence à diminuer. Ces informations sont inestimables pour la planification de capacité et peuvent éclairer les décisions concernant le moment où il faut faire évoluer l’infrastructure ou optimiser l’API.
Les tests de capacité nous aident à planifier le trafic attendu et à comprendre les limites avant de commencer à observer des baisses de performance. Ils sont essentiels pour garantir que le système peut gérer la croissance anticipée et les périodes de pic d’utilisation sans compromettre l’expérience utilisateur.
Test de stress
Alors qu’un test de capacité identifie la charge optimale, un test de stress pousse le système au-delà de ses limites afin de découvrir son point de rupture. L’objectif est d’évaluer le comportement de votre API dans des conditions extrêmes, comme une augmentation soudaine des requêtes ou un volume de données étonnamment élevé.
Les tests de stress peuvent simuler des situations réelles, comme une publication virale sur les réseaux sociaux qui génère soudainement un trafic massif vers une application alimentée par l’IA. Pendant ces tests, il est important de surveiller non seulement les temps de réponse et le débit, mais aussi les taux d’erreur, l’utilisation des ressources (CPU, mémoire, réseau) et la qualité des réponses de l’API.
Les tests de stress sont essentiels pour comprendre comment l’API LLM pourrait échouer et ce qui se passe lorsqu’elle échoue — qu’elle plante, ralentisse ou récupère. Ces informations sont essentielles pour améliorer la résilience du système et garantir qu’il peut gérer avec élégance les pics d’utilisation inattendus. Elles peuvent également aider à concevoir de meilleures stratégies de basculement et d’équilibrage de charge.
Test d’endurance
Le test d’endurance, ou test de longue durée, évalue les performances de votre API sur une période prolongée. Il identifie des problèmes tels que les fuites de mémoire, la dégradation des performances ou la saturation des connexions à la base de données, qui peuvent ne pas être évidents lors de tests plus courts. Pour une API LLM, un test d’endurance exécute un flux régulier de requêtes pendant plusieurs heures ou jours afin d’observer comment le système maintient ses performances.
La durée idéale d’un test d’endurance peut varier selon le système et ses modèles d’utilisation attendus. Pour certaines API LLM, un test de 24 heures peut suffire, tandis que d’autres peuvent bénéficier de tests d’une semaine pour révéler des problèmes subtils qui ne se manifestent que sur de longues périodes.
Les tests d’endurance sont particulièrement efficaces pour révéler une dégradation progressive des performances. Par exemple, ils peuvent montrer que les temps de réponse augmentent lentement avec le temps, ou que la qualité du texte généré diminue subtilement après le traitement d’un grand nombre de requêtes. Ces informations peuvent être cruciales pour mettre en œuvre des mesures de maintenance proactive et optimiser les performances à long terme.
Ce test garantit que l’API peut gérer une demande soutenue sans se détériorer, ce qui est crucial pour les applications censées fonctionner en continu ou gérer un trafic constant sur le long terme.
Bonnes pratiques pour les tests de charge des API LLM
Lors de la réalisation de tests de charge sur des API LLM, prenez en compte les bonnes pratiques suivantes :
Utilisez des données et des scénarios réalistes qui imitent les modèles d’utilisation réels.
Augmentez progressivement la charge afin d’identifier précisément les seuils de performance.
Surveillez un large éventail de métriques, notamment les temps de réponse, les taux d’erreur et l’utilisation des ressources.
Effectuez des tests depuis différentes zones géographiques afin de tenir compte de la latence réseau.
Incluez un mélange de différents types de requêtes que votre API traite généralement.
Outils pour les tests de charge Plusieurs outils peuvent être utilisés pour les tests de charge des API LLM, notamment :
Apache JMeter : un outil open source pouvant être utilisé pour divers types de tests de charge.
Locust : un outil basé sur Python particulièrement adapté aux tests de charge distribués.
Gatling : un outil basé sur Scala excellent pour les tests de charge à haut volume. La section suivante abordera les tests de charge avec Gatling.
Tester la charge d’une API LLM avec Gatling
Gatling est un outil de test de charge pour les applications web conçu pour DevOps et l’intégration continue. Puisque vous avez compris la théorie des tests de charge, voyons comment nous pouvons réaliser concrètement un test de charge sur l’API Chat Completions d’OpenAI à l’aide de Gatling. Suivez ce guide pour configurer votre projet Gatling.
1. Configuration de la classe de simulation
Tout d’abord, commencez par importer les bibliothèques nécessaires et configurer la classe de simulation :
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
Ces imports apportent le DSL (Domain-Specific Language) principal et le DSL HTTP pour créer des scénarios et gérer les requêtes HTTP dans Gatling. Après avoir importé les bibliothèques, définissez la classe de simulation.
public class SSELLM extends Simulation {
String api_key = System.getenv("api_key");
Dans le code ci-dessus, la classe SSELLM étend Simulation , une classe de base requise pour toutes les simulations Gatling. La variable api_key récupère la clé API depuis vos variables d’environnement, garantissant que les informations sensibles ne sont pas codées en dur.
2. Configuration du protocole HTTP
Après avoir transmis la clé API, l’étape suivante consiste à spécifier l’URL de base du service de votre LLM.
HttpProtocolBuilder httpProtocol =
http.baseUrl("https://api.openai.com/v1/chat")
.sseUnmatchedInboundMessageBufferSize(100);
Le baseUrl spécifie le point de terminaison de base de l’API, et sseUnmatchedInboundMessageBufferSize(100) configure la taille du tampon pour gérer les messages d’événements envoyés par le serveur (SSE) qui ne correspondent à aucune réponse attendue.
3. Définition du scénario
Le cœur de tout test Gatling est le scénario qui simule le comportement de l’utilisateur. Définissons un scénario pour notre test.
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()
);
Dans le scénario ci-dessus, nous simulons un utilisateur envoyant une requête à l’API OpenAI Chat et attendant une réponse. Le test établit une connexion SSE (Server-Sent Events) à l’API. Une requête POST est ensuite envoyée au point de terminaison /completions avec un message demandant au modèle de définir une base de données vectorielle. Le test continue de traiter les messages SSE entrants avec asLongAs("#{stop.isUndefined()}") , ce qui maintient la connexion ouverte jusqu’à ce qu’une condition spécifique soit remplie.
À mesure que les messages sont reçus, sse.processUnmatchedMessages(...) vérifie si la réponse contient le signal "[DONE]" , indiquant que l’interaction est terminée. Une fois ce signal détecté, la session s’arrête, et la connexion est fermée avec sse("close").close().
4. Injection d’utilisateurs virtuels
Après avoir créé le scénario, la dernière étape consiste à spécifier le nombre d’utilisateurs à simuler et à configurer le protocole.
{
setUp(
prompt.injectOpen(atOnceUsers(3))
).protocols(httpProtocol);
}
}
Le code ci-dessus injecte simultanément trois utilisateurs virtuels dans le scénario. Ce test de charge simple vérifie les performances de l’API lorsqu’elle gère trois requêtes concurrentes.
Utilisez la commande suivante pour exécuter le code :
.mvnw.cmd gatling:test
Une fois le code exécuté, Gatling fournira un chemin de fichier dans le terminal. Il s’agit du chemin vers le rapport de test. Voici un extrait d’exemple du rapport.
Figure 1 : rapport Gatling sur la plage des temps de réponse lors du test de l’API OpenAI chat completion
Comme prévu pour l’API OpenAI chat completion, le test démontre que l’API OpenAI a traité efficacement les requêtes concurrentes, toutes les réponses ayant été reçues dans de bons délais. Mais souvenez-vous, nous n’avons envoyé que trois requêtes concurrentes et utilisé un prompt très court.
Dans un scénario réel, votre LLM pourrait recevoir des milliers de requêtes simultanément et des prompts plus longs. Les prompts plus longs apparaissent principalement lorsque l’utilisateur fournit davantage de contexte au LLM. Envisagez d’ajouter le nombre d’utilisateurs virtuels et la longueur des prompts lors d’un cas réel.
Gatling ne se limite pas aux API de LLM. Vous pouvez également l’utiliser pour tester en charge des API qui alimentent des applications de Retrieval Augmented Generation (RAG). Cette approche fournira une évaluation globale des performances de l’application. Créons un scénario dans lequel nous pouvons tester en charge une application alimentée par RAG.
Mais avant cela, vous pourriez vous demander : qu’est-ce que RAG ? Comprenons d’abord le concept de RAG.
Comprendre la Retrieval Augmented Generation (RAG)
RAG, ou retrieval augmented generation, est une technique qui combine les capacités génératives d’un grand modèle de langage (LLM) avec un mécanisme de récupération permettant d’extraire des informations pertinentes depuis une base de données vectorielle telle que Milvus et Zilliz Cloud (le Milvus géré). En exploitant des données externes comme contextes, le LLM est moins susceptible d’halluciner et génère des réponses plus précises et contextuellement pertinentes. En outre, RAG vous permet également de récupérer des données privées ou propriétaires pour votre LLM en tant que contexte afin d’obtenir des réponses plus personnalisées, sans vous soucier des problèmes de sécurité des données.
Dans une configuration RAG typique, lorsqu’une requête utilisateur est reçue, le système RAG récupère des documents ou extraits pertinents depuis une base de connaissances alimentée par une base de données vectorielle. Ces documents sont ensuite utilisés pour fournir du contexte au LLM afin que celui-ci génère une réponse plus éclairée et complète.
Figure 2 : Fonctionnement de RAG
Créer un scénario qui teste une application RAG
Maintenant que nous avons compris RAG, apprenons à tester en charge une application RAG avec Gatling.
Imaginez une situation dans laquelle une application de support client est alimentée par un LLM. Les utilisateurs peuvent interroger le système avec des questions nécessitant des réponses détaillées et sensibles au contexte. L’application exploite RAG pour extraire des documents pertinents depuis une base de données vectorielle comme Milvus afin d’améliorer la qualité de ces réponses. Ces documents fournissent au LLM le contexte nécessaire, lui permettant de produire des réponses plus précises et éclairées.
Nous concevrions un scénario avec les processus ci-dessous pour notre test de charge.
Requêtes utilisateur simulées : Les utilisateurs virtuels envoient des requêtes complexes qui nécessitent un contexte supplémentaire. Par exemple, un utilisateur pourrait demander : « Comment puis-je résoudre un problème de connexion avec mon appareil ? » Cette question seule ne fournit pas suffisamment d’informations pour obtenir une réponse de haute qualité de la part d’un LLM, le système doit donc récupérer des documents de dépannage pertinents depuis la base de données vectorielle Milvus .
Récupération contextuelle : Le système récupère les documents les plus pertinents depuis Milvus en fonction de la requête utilisateur. Cette étape est cruciale, car elle détermine la qualité du contexte fourni au LLM, ce qui influence directement la précision de la réponse générée. Dans un pipeline RAG, Milvus indexe une vaste quantité de documentation et effectue une recherche par similarité vectorielle pour trouver rapidement les informations les plus pertinentes.
Génération de réponse par le LLM : Une fois les documents pertinents récupérés, ils sont fournis comme contexte au LLM. Le LLM utilise ensuite ces informations pour répondre à la requête de l’utilisateur. Ce processus génère la réponse et cite potentiellement des sources spécifiques issues des documents récupérés.
Tests de charge avec utilisateurs concurrents : Vous injectez ensuite un nombre plus élevé d’utilisateurs virtuels pour simuler des conditions d’utilisation de pointe.
Surveillance et analyse : Lorsque Gatling génère le rapport, vous surveillez les éventuels goulots d’étranglement que l’API alimentant votre application pourrait rencontrer. Il est important de noter que les résultats des tests sont influencés à la fois par les performances des grands modèles de langage et par l’efficacité du mécanisme de récupération sous charge. Cela vous donne une évaluation complète des performances de l’ensemble du système.
Tester en charge votre application alimentée par RAG à l’aide du scénario ci-dessus vous permettra d’identifier tout problème de scalabilité.
Conclusion
Samir a fait du bon travail en fournissant des informations précieuses sur les tests de charge d’une API LLM avec Gatling. Il a expliqué les différents types de tests de charge et comment nous pouvons tester en charge une API LLM. Nous avons également élargi l’article afin d’explorer comment effectuer des tests de charge encore plus poussés sur d’autres applications alimentées par des LLM, telles que des applications de support client basées sur RAG. Grâce à ces connaissances, vous pouvez développer des tests d’API pour vos API, afin de garantir que vos produits peuvent évoluer sans problème. Lorsque vous effectuez des tests de charge sur des API LLM, tenez compte des bonnes pratiques suivantes :
Bonnes pratiques pour les tests de charge des API LLM
Utilisez des données et des cas de test réalistes qui imitent les schémas d’utilisation réels.
Augmentez progressivement la charge afin d’identifier précisément les seuils de performance.
Surveillez un large éventail de métriques, notamment les temps de réponse, les taux d’erreur et l’utilisation des ressources.
Effectuez des tests depuis différentes zones géographiques afin de tenir compte de la latence réseau.
Incluez un mélange de différents types de requêtes que votre API traite généralement.
Ressources complémentaires sur RAG, GenAI et la recherche vectorielle
Continuer à lire

3 Easiest Ways to Use Claude Code on Your Mobile Phone
Run Claude Code from your phone with Remote Control, Happy Coder, or SSH + Tailscale. Comparison table, setup steps, and tools for typing, memory, and parallel tasks.

How to Improve Retrieval Quality for Japanese Text with Sudachi, Milvus/Zilliz, and AWS Bedrock
Learn how Sudachi normalization and Milvus/Zilliz hybrid search improve Japanese RAG accuracy with BM25 + vector fusion, AWS Bedrock embeddings, and practical code examples.

Vector Databases vs. Time Series Databases
Use a vector database for similarity search and semantic relationships; use a time series database for tracking value changes over time.


