So führen Sie einen Lasttest einer LLM-API mit Gatling durch
Beim Erstellen von Anwendungen mit Large Language Models (LLMs) ist es unerlässlich sicherzustellen, dass sie unterschiedliche Nachfragevolumina bewältigen können. Hier kommt Load Testing ins Spiel. Load Testing simuliert realen Datenverkehr, um die Leistung Ihrer API unter verschiedenen Bedingungen zu bewerten. Dieser Ansatz hilft dabei, potenzielle Engpässe und Verbesserungsbereiche zu identifizieren und stellt sicher, dass die Anwendung zuverlässig und reaktionsschnell bleibt.
Bei einem kürzlich stattgefundenen Berliner Unstructured Data Meetup sprach Samir Akarioh, ein Developer Advocate bei Gatling, darüber, wie man eine LLM-API mit Gatling Lasttests unterzieht. Gatling ist ein Open-Source-Framework für Performance-Tests, das verwendet wird, um JavaScript-Webanwendungen Lasttests zu unterziehen. Seine Einblicke verdeutlichten die Bedeutung von Load Testing für LLM-APIs und die verschiedenen verwendeten Methoden. In diesem Blog fassen wir seine wichtigsten Punkte zusammen und diskutieren, wie man Anwendungen mit Large Language Models Lasttests unterzieht, insbesondere RAG-Apps (retrieval augmented generation), die von Vektordatenbanken wie Milvus unterstützt werden, um Leistung, Last und Antwortzeiten zu verbessern.
Sehen Sie sich die Aufzeichnung von Samirs Vortrag auf YouTube an.
Was ist Load Testing?
Load Testing ist eine Art von Performance-Test, der bewertet, wie sich ein System unter bestimmten Lastbedingungen verhält, üblicherweise mit dem Versuch, das System mit riesigen Datenmengen einem Stresstest zu unterziehen. Das Hauptziel besteht darin zu beurteilen, ob das System den erwarteten Benutzerverkehr oder das Datenvolumen unter normalen und Spitzenbedingungen bewältigen kann. Während des Load Testing wird das Verhalten des Systems überwacht, um Engpässe, Leistungsabfälle oder Ausfälle zu identifizieren, die die Benutzererfahrung beeinträchtigen könnten.
Für LLM-APIs ist Load Testing aufgrund der komplexen Natur dieser Systeme und der hohen Rechenanforderungen bei der Verarbeitung natürlicher Sprache besonders wichtig. Wenn kein ordnungsgemäßes Load Testing durchgeführt wird, kann dies zu Dienstausfällen, langsamen Antwortzeiten oder ungenauen Ergebnissen führen und potenziell das Vertrauen der Nutzer sowie die allgemeine Zuverlässigkeit KI-gestützter Anwendungen beeinträchtigen.
Bei diesem Unstructured Data Meetup ging Samir kurz auf drei Arten von Load Testing ein: Capacity Test, Stress Test, und Soak Test. Lassen Sie uns das etwas verlangsamen und uns jede davon genauer ansehen.
Capacity Test
Ein Capacity Test bestimmt die maximale Last, die Ihre API bewältigen kann, während sie die Leistungsanforderungen erfüllt. Das Ziel ist es, den „Sweet Spot“ zu identifizieren, an dem das System mit seiner Spitzenlast arbeitet, ohne dass sich Antwortzeit oder Durchsatz verschlechtern. Für eine LLM-API findet Capacity Testing die maximale Anzahl von Anfragen pro Sekunde, die sie verarbeiten kann, während sie weiterhin genaue und zeitnahe Antworten liefert.
Beispielsweise könnte ein Capacity Test darin bestehen, die Anzahl gleichzeitiger Benutzer, die Prompts an die API senden, schrittweise zu erhöhen, bis die Antwortzeiten zu steigen beginnen oder die Genauigkeit nachlässt. Diese Informationen sind für die Kapazitätsplanung von unschätzbarem Wert und können Entscheidungen darüber unterstützen, wann die Infrastruktur skaliert oder die API optimiert werden sollte.
Capacity Testing hilft uns, den erwarteten Traffic zu planen und die Grenzen zu verstehen, bevor Leistungsabfälle auftreten. Es ist unerlässlich, um sicherzustellen, dass das System erwartetes Wachstum und Spitzenlastzeiten bewältigen kann, ohne die Benutzererfahrung zu beeinträchtigen.
Stress Test
Während ein Kapazitätstest die optimale Last ermittelt, treibt ein Stresstest das System über seine Grenzen hinaus, um seinen Bruchpunkt zu finden. Ziel ist es zu bewerten, wie sich Ihre API unter extremen Bedingungen verhält, etwa bei einem plötzlichen Anstieg von Anfragen oder einem unerwartet hohen Datenvolumen.
Stresstests können reale Situationen simulieren, wie einen viralen Social-Media-Beitrag, der plötzlich massiven Traffic zu einer KI-gestützten Anwendung lenkt. Während dieser Tests ist es wichtig, nicht nur Antwortzeiten und Durchsatz zu überwachen, sondern auch Fehlerraten, Ressourcenauslastung (CPU, Arbeitsspeicher, Netzwerk) und die Qualität der Antworten der API.
Stresstests sind unerlässlich, um zu verstehen, wie die LLM API ausfallen könnte und was passiert, wenn dies geschieht—ob sie abstürzt, langsamer wird oder sich erholt. Diese Informationen sind entscheidend, um die Systemresilienz zu verbessern und sicherzustellen, dass es unerwartete Nutzungsspitzen zuverlässig bewältigen kann. Sie können außerdem dabei helfen, bessere Failover- und Load-Balancing-Strategien zu entwickeln.
Soak-Test
Soak-Testing oder Ausdauertests bewerten, wie Ihre API über einen längeren Zeitraum hinweg funktioniert. Dabei werden Probleme wie Speicherlecks, Leistungsabfall oder die Sättigung von Datenbankverbindungen identifiziert, die in kürzeren Tests möglicherweise nicht erkennbar sind. Für eine LLM API führt ein Soak-Test über mehrere Stunden oder Tage einen gleichmäßigen Strom von Anfragen aus, um zu beobachten, wie das System seine Leistung aufrechterhält.
Die ideale Dauer eines Soak-Tests kann je nach System und seinen erwarteten Nutzungsmustern variieren. Für einige LLM APIs kann ein 24-Stunden-Test ausreichend sein, während andere von einwöchigen Tests profitieren könnten, um subtile Probleme aufzudecken, die sich erst über längere Zeiträume zeigen.
Soak-Tests eignen sich besonders gut, um allmähliche Leistungsverschlechterungen aufzudecken. Sie könnten beispielsweise zeigen, dass die Antwortzeiten im Laufe der Zeit langsam ansteigen oder dass die Qualität des generierten Textes nach der Verarbeitung einer großen Anzahl von Anfragen subtil abnimmt. Diese Erkenntnisse können entscheidend sein, um proaktive Wartungsmaßnahmen umzusetzen und die langfristige Leistung zu optimieren.
Dieser Test stellt sicher, dass die API eine anhaltende Nachfrage ohne Verschlechterung bewältigen kann, was für Anwendungen entscheidend ist, die kontinuierlich laufen oder langfristigen, konstanten Traffic verarbeiten sollen.
Best Practices für Load-Testing von LLM APIs
Berücksichtigen Sie bei der Durchführung von Load-Tests für LLM APIs die folgenden Best Practices:
Verwenden Sie realistische Daten und Szenarien, die tatsächliche Nutzungsmuster nachbilden.
Erhöhen Sie die Last schrittweise, um Leistungsschwellenwerte genau zu identifizieren.
Überwachen Sie eine breite Palette von Metriken, einschließlich Antwortzeiten, Fehlerraten und Ressourcenauslastung.
Testen Sie von verschiedenen geografischen Standorten aus, um Netzwerklatenz zu berücksichtigen.
Beziehen Sie eine Mischung verschiedener Arten von Anfragen ein, die Ihre API typischerweise verarbeitet.
Tools für Load-Testing Mehrere Tools können für Load-Testing von LLM APIs verwendet werden, darunter:
Apache JMeter: Ein Open-Source-Tool, das für verschiedene Arten von Load-Tests verwendet werden kann.
Locust: Ein Python-basiertes Tool, das sich besonders gut für verteiltes Load-Testing eignet.
Gatling: Ein Scala-basiertes Tool, das hervorragend für Load-Testing mit hohem Volumen geeignet ist. Der nächste Abschnitt wird in das Load-Testing mit Gatling einsteigen.
Load-Testing einer LLM API mit Gatling
Gatling ist ein Load-Testing-Tool für Webanwendungen, das für DevOps und Continuous Integration entwickelt wurde. Da Sie die Theorie des Load-Testings verstanden haben, sehen wir uns nun an, wie wir praktisch einen Load-Test für die OpenAI Chat Completions API mit Gatling durchführen können. Folgen Sie dieser Anleitung, um Ihr Gatling-Projekt einzurichten.
1. Einrichten der Simulationsklasse
Beginnen Sie zunächst damit, die erforderlichen Bibliotheken zu importieren und die Simulationsklasse einzurichten:
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
Diese Imports binden die Kern-DSL (domänenspezifische Sprache) und die HTTP-DSL ein, um Szenarien zu erstellen und HTTP-Anfragen in Gatling zu verarbeiten. Nach dem Importieren der Bibliotheken definieren Sie die Simulationsklasse.
public class SSELLM extends Simulation {
String api_key = System.getenv("api_key");
Im obigen Code erweitert die Klasse SSELLM Simulation , eine erforderliche Basisklasse für alle Gatling-Simulationen. Die Variable api_key ruft den API-Schlüssel aus Ihren Umgebungsvariablen ab und stellt sicher, dass sensible Informationen nicht fest im Code hinterlegt werden.
2. Konfigurieren des HTTP-Protokolls
Nach der Übergabe des API-Schlüssels besteht der nächste Schritt darin, die Basis-URL des Dienstes Ihres LLM anzugeben.
HttpProtocolBuilder httpProtocol =
http.baseUrl("https://api.openai.com/v1/chat")
.sseUnmatchedInboundMessageBufferSize(100);
Die baseUrl gibt den Basisendpunkt der API an, und sseUnmatchedInboundMessageBufferSize(100) konfiguriert die Puffergröße für die Verarbeitung von Server-Sent-Events-(SSE)-Nachrichten, die keiner erwarteten Antwort entsprechen.
3. Definieren des Szenarios
Das Herzstück jedes Gatling-Tests ist das Szenario, das das Nutzerverhalten simuliert. Definieren wir ein Szenario für unseren 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()
);
Im obigen Szenario simulieren wir einen Nutzer, der eine Anfrage an die OpenAI Chat API sendet und auf eine Antwort wartet. Der Test stellt eine SSE-Verbindung (Server-Sent Events) zur API her. Anschließend wird eine POST-Anfrage an den Endpunkt /completions mit einer Nachricht gesendet, die das Modell auffordert, eine Vektordatenbank zu definieren. Der Test verarbeitet eingehende SSE-Nachrichten weiterhin mit asLongAs("#{stop.isUndefined()}") , wodurch die Verbindung offen bleibt, bis eine bestimmte Bedingung erfüllt ist.
Wenn Nachrichten empfangen werden, prüft sse.processUnmatchedMessages(...) , ob die Antwort das Signal "[DONE]" enthält, das anzeigt, dass die Interaktion abgeschlossen ist. Sobald dieses Signal erkannt wird, stoppt die Sitzung, und die Verbindung wird mit sse("close").close() geschlossen.
4. Virtuelle Nutzer injizieren
Nach dem Erstellen des Szenarios besteht der letzte Schritt darin, die Anzahl der zu simulierenden Nutzer anzugeben und das Protokoll zu konfigurieren.
{
setUp(
prompt.injectOpen(atOnceUsers(3))
).protocols(httpProtocol);
}
}
Der obige Code injiziert gleichzeitig drei virtuelle Nutzer in das Szenario. Dieser einfache Lasttest überprüft die Leistung der API bei der Verarbeitung von drei gleichzeitigen Anfragen.
Verwenden Sie den folgenden Befehl, um den Code auszuführen:
.mvnw.cmd gatling:test
Sobald der Code ausgeführt wird, stellt Gatling im Terminal einen Dateipfad bereit. Dies ist der Pfad zum Testbericht. Hier ist ein beispielhafter Ausschnitt des Berichts.
Abbildung 1: Gatling-Bericht zum Antwortzeitbereich beim Testen der OpenAI Chat Completion API
Wie für die OpenAI Chat Completion API erwartet, zeigt der Test, dass die OpenAI API die gleichzeitigen Anfragen effizient verarbeitet hat, wobei alle Antworten innerhalb guter Zeitrahmen eingingen. Denken Sie jedoch daran, dass wir nur drei gleichzeitige Anfragen gesendet und einen sehr kurzen Prompt verwendet haben.
In einem realen Szenario könnte Ihr LLM Tausende von Anfragen gleichzeitig und längere Prompts erhalten. Die längeren Prompts treten meist auf, wenn der Benutzer dem LLM mehr Kontext bereitstellt. Erwägen Sie, in einem realen Anwendungsfall die Anzahl der virtuellen Benutzer und die Länge der Prompts hinzuzufügen.
Gatling ist nicht auf LLM-APIs beschränkt. Sie können es auch verwenden, um APIs, die Retrieval Augmented Generation (RAG)-Anwendungen antreiben, per Lasttest zu prüfen. Dieser Ansatz liefert eine Gesamtbewertung der Leistung der Anwendung. Lassen Sie uns ein Szenario erstellen, in dem wir eine RAG-gestützte Anwendung einem Lasttest unterziehen können.
Doch bevor wir das tun, fragen Sie sich vielleicht: Was ist RAG? Lassen Sie uns zuerst das Konzept von RAG verstehen.
Verständnis von Retrieval Augmented Generation (RAG)
RAG, oder Retrieval Augmented Generation, ist eine Technik, die die generativen Fähigkeiten eines Large Language Model (LLM) mit einem Retrieval-Mechanismus kombiniert, um relevante Informationen aus einer Vektordatenbank wie Milvus und Zilliz Cloud (dem verwalteten Milvus) abzurufen. Durch die Nutzung externer Daten als Kontexte ist es weniger wahrscheinlich, dass das LLM halluziniert, und es generiert genauere und kontextuell relevantere Antworten. Darüber hinaus ermöglicht RAG Ihnen auch, private oder proprietäre Daten für Ihr LLM als Kontext für stärker personalisierte Antworten abzurufen, ohne sich über Datensicherheitsprobleme Sorgen machen zu müssen.
In einem typischen RAG-Setup ruft das RAG-System beim Eingang einer Benutzeranfrage relevante Dokumente oder Ausschnitte aus einer Wissensdatenbank ab, die von einer Vektordatenbank unterstützt wird. Diese Dokumente werden dann verwendet, um dem LLM Kontext bereitzustellen, sodass das LLM eine fundiertere und umfassendere Antwort generiert.
Abbildung 2: Wie RAG funktioniert
Erstellen eines Szenarios, das eine RAG-Anwendung testet
Nachdem wir RAG verstanden haben, lernen wir nun, wie man eine RAG-Anwendung mit Gatling einem Lasttest unterzieht.
Stellen Sie sich eine Situation vor, in der eine Kundensupport-Anwendung von einem LLM unterstützt wird. Benutzer könnten das System mit Fragen abfragen, die detaillierte, kontextbewusste Antworten erfordern. Die Anwendung nutzt RAG, um relevante Dokumente aus einer Vektordatenbank wie Milvus abzurufen und so die Qualität dieser Antworten zu verbessern. Diese Dokumente liefern dem LLM den notwendigen Kontext und ermöglichen es ihm, genauere und fundiertere Antworten zu erstellen.
Für unseren Lasttest würden wir ein Szenario mit den folgenden Prozessen entwerfen.
Simulierte Benutzeranfragen: Virtuelle Benutzer senden komplexe Abfragen, die zusätzlichen Kontext erfordern. Zum Beispiel könnte ein Benutzer fragen: „Wie behebe ich ein Verbindungsproblem mit meinem Gerät?“ Diese Frage allein liefert nicht genügend Informationen, um eine hochwertige Antwort von einem LLM zu erhalten, daher muss das System relevante Dokumente zur Fehlerbehebung aus der Milvus Vektordatenbank abrufen.
Kontextuelles Retrieval: Das System ruft basierend auf der Benutzeranfrage die relevantesten Dokumente aus Milvus ab. Dieser Schritt ist entscheidend, da er die Qualität des dem LLM bereitgestellten Kontexts bestimmt und sich direkt auf die Genauigkeit der generierten Antwort auswirkt. In einer RAG-Pipeline indiziert Milvus eine enorme Menge an Dokumentation und führt eine Vektorähnlichkeitssuche durch, um die relevantesten Informationen schnell zu finden.
LLM-Antwortgenerierung: Sobald die relevanten Dokumente abgerufen wurden, werden sie dem LLM als Kontext bereitgestellt. Das LLM verwendet diese Informationen dann, um auf die Anfrage des Benutzers zu antworten. Dieser Prozess generiert die Antwort und zitiert möglicherweise spezifische Quellen aus den abgerufenen Dokumenten.
Lasttests mit gleichzeitigen Benutzern: Anschließend fügen Sie eine höhere Anzahl virtueller Benutzer hinzu, um Spitzenlastbedingungen zu simulieren.
Überwachung und Analyse: Wenn Gatling den Bericht erstellt, überwachen Sie alle Engpässe, auf die die API, die Ihre Anwendung antreibt, stoßen könnte. Es ist wichtig zu beachten, dass die Testergebnisse sowohl von der Leistung der großen Sprachmodelle als auch von der Effizienz des Retrieval-Mechanismus unter Last beeinflusst werden. Dies gibt Ihnen eine umfassende Bewertung darüber, wie das gesamte System funktioniert.
Das Lasttesten Ihrer RAG-gestützten App mit dem oben genannten Szenario stellt sicher, dass Sie etwaige Skalierbarkeitsprobleme identifizieren.
Fazit
Samir hat gute Arbeit geleistet, indem er wertvolle Einblicke in das Lasttesten einer LLM-API mit Gatling gegeben hat. Er erklärte die verschiedenen Arten von Lasttests und wie wir eine LLM-API lasttesten können. Wir haben den Artikel außerdem erweitert, um zu untersuchen, wie Lasttests noch weitergehend bei anderen LLM-gestützten Anwendungen durchgeführt werden können, beispielsweise bei RAG-basierten Kundensupport-Anwendungen. Mit diesem Wissen können Sie API-Tests für Ihre APIs entwickeln und sicherstellen, dass Ihre Produkte problemlos skalieren können. Beachten Sie bei der Durchführung von Lasttests für LLM-APIs die folgenden Best Practices:
Best Practices für Lasttests von LLM-APIs
Verwenden Sie realistische Daten und Testfälle, die tatsächliche Nutzungsmuster nachahmen.
Erhöhen Sie die Last schrittweise, um Leistungsgrenzen genau zu identifizieren.
Überwachen Sie eine breite Palette von Metriken, einschließlich Antwortzeiten, Fehlerraten und Ressourcenauslastung.
Testen Sie von verschiedenen geografischen Standorten aus, um Netzwerklatenz zu berücksichtigen.
Beziehen Sie eine Mischung verschiedener Arten von Anfragen ein, die Ihre API typischerweise verarbeitet.
Weitere Ressourcen zu RAG, GenAI und Vector Search
Weiterlesen

Zilliz Skills Breakdown: How AI Agents Master Vector Databases
Zilliz's Milvus Skill (pymilvus, 7 files) and Zilliz Cloud Skill (zilliz-cli, 14 modules) bring vector-DB dev and ops into one Claude Code session.

My Wife Wanted Dior. I Spent $600 on Claude Code to Vibe-Code a 2M-Line Database Instead.
Write tests, not code reviews. How a test-first workflow with 6 parallel Claude Code sessions turns a 2M-line C++ codebase into a daily shipping pipeline.

Zilliz Cloud Now Available in Azure North Europe: Bringing AI-Powered Vector Search Closer to European Customers
The addition of the Azure North Europe (Ireland) region further expands our global footprint to better serve our European customers.


