Autor:LUCA WINTERGERST

In diesem Blog testen wir eine Python-Anwendung mit OpenAI und analysieren ihre Leistung und die Kosten für die Ausführung der Anwendung. Anhand der aus der Anwendung gesammelten Daten zeigen wir außerdem, wie Sie LLMs in Ihre Anwendung integrieren.

1Ba6A5C2D4D54Ba9B0044C2F126A4C28

In einem früheren Blogbeitrag haben wir eine kleine Python-Anwendung erstellt, die Elasticsearch mithilfe einer Kombination aus Vektorsuche und BM25 abfragt, um dabei zu helfen, die relevantesten Ergebnisse in einem proprietären Datensatz zu finden. Die Top-Ergebnisse werden dann an OpenAI weitergeleitet, das die Frage für uns beantwortet.

In diesem Blog testen wir eine Python-Anwendung mit OpenAI und analysieren ihre Leistung und die Kosten für die Ausführung der Anwendung. Anhand der aus Ihrer Anwendung gesammelten Daten zeigen wir außerdem, wie Sie große Sprachmodelle (LLM) in Ihre Anwendung integrieren. Als zusätzlichen Bonus versuchen wir, diese Frage zu beantworten: Warum druckt chatgpt seine Ausgabe wörtlich?

Wenn Sie die Möglichkeit haben, probieren Sie unsere ausBeispielanwendungMöglicherweise stellen Sie fest, dass die Ergebnisse der Suchoberfläche nicht so schnell geladen werden, wie Sie es erwarten würden.

Die Frage ist nun, ob dies auf unseren zweiphasigen Ansatz zurückzuführen ist, bei dem die Abfrage zuerst in Elasticsearch ausgeführt wird, oder ob das langsame Verhalten von OpenAI herrührt oder ob es sich um eine Kombination aus beidem handelt.

1Ec96D8697D6495D8D94C56388687E97

Mit Elastic APM können wir die Anwendung einfach für ein besseres Erscheinungsbild instrumentieren. Zur Erkennung müssen wir lediglich Folgendes tun (das vollständige Beispiel zeigen wir am Ende des Blogbeitrags und im GitHub-Repository):

import elasticapm
# the APM Agent is initialized
apmClient = elasticapm.Client(service_name="elasticdocs-gpt-v2-streaming")

# the default instrumentation is applied
# this will instrument the most common libraries, as well as outgoing http requests
elasticapm.instrument()

Da unsere Beispielanwendung Streamlit verwendet, müssen wir außerdem mindestens eine Transaktion starten und diese schließlich wieder beenden. Darüber hinaus können wir APM Informationen über die Transaktionsergebnisse zur Verfügung stellen, damit wir Fehler ordnungsgemäß verfolgen können.

# start the APM transaction
apmClient.begin_transaction("user-query")

(...)

elasticapm.set_transaction_outcome("success")

# or "failure" for unsuccessful transactions
# elasticapm.set_transaction_outcome("success")

# end the APM transaction
apmClient.end_transaction("user-query")

Das ist alles – das reicht aus, um ein vollständiges APM-Tool für unsere Anwendung bereitzustellen. Abgesehen davon werden wir hier noch ein wenig zusätzliche Arbeit leisten, um weitere interessante Daten zu erhalten.

Als ersten Schritt fügen wir die Anfrage des Benutzers zu den APM-Metadaten hinzu. Auf diese Weise können wir überprüfen, wonach Benutzer suchen möchten, und einige häufig gestellte Suchanfragen analysieren oder Fehler reproduzieren.

elasticapm.label(query=query)

In unserer asynchronen Methode der Kommunikation mit OpenAI werden wir auch einige weitere Erkennungen hinzufügen, damit wir die empfangenen Token besser visualisieren und zusätzliche Statistiken sammeln können.

async with elasticapm.async_capture_span('openaiChatCompletion', span_type='openai'):
        async for chunk in await openai.ChatCompletion.acreate(engine=engine, messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": truncated_prompt}],stream=True,):
            content = chunk["choices"][0].get("delta", {}).get("content")
            # since we have the stream=True option, we can get the output as it comes in
            # one iteration is one token
	  # we start a new span here for each token. These spans will be aggregated
            # into a compressed span automatically
            with elasticapm.capture_span("token", leaf=True, span_type="http"):
                if content is not None:
                    # concatenate the output to the previous one, so have the full response at the end
                    output += content
                    # with every token we get, we update the element
                    element.markdown(output)

Schließlich werden wir in der letzten Phase des Antrags auch den Token-Betrag und die ungefähren Kosten zur APM-Transaktion hinzufügen. Dadurch können wir diese Metriken später visualisieren und mit der Anwendungsleistung korrelieren.

Siehe auch  5 ChatGPT-Eingabeaufforderungen für Webentwickler

Wenn Sie kein Streaming verwenden, enthält die OpenAI-Antwort ein Feld „total_tokens“, das die Summe des von Ihnen gesendeten Kontexts und der zurückgegebenen Antwort darstellt. Wenn Sie die Option stream=True verwenden, liegt es in Ihrer Verantwortung, die Anzahl der Token oder eine ungefähre Zahl zu berechnen. Ein häufiger Vorschlag ist die Verwendung von „(len(prompt) + len(response)) / 4“ für englischen Text, aber insbesondere Codeausschnitte können von dieser Näherung abweichen.Wenn Sie genauere Zahlen benötigen, können Sie diese verwenden Tick ​​Tack Warten Sie, bis die Bibliothek die Anzahl der Token berechnet hat.

# add the number of tokens as a metadata label
elasticapm.label(openai_tokens = st.session_state['openai_current_tokens'])
# add the approximate cost as a metadata label
# currently the cost is $0.002 / 1000 tokens
elasticapm.label(openai_cost = st.session_state['openai_current_tokens'] / 1000 * 0.002)

Nach der Instrumentierung der Anwendung kann uns ein kurzer Blick auf die „Abhängigkeiten“ eine bessere Vorstellung davon geben, was vor sich geht. Es sieht so aus, als ob unsere Anfragen an Elasticsearch im Durchschnitt innerhalb von 125 Millisekunden zurückgegeben wurden, während OpenAI 8.500 Millisekunden brauchte, um die Anfrage abzuschließen. (Dieser Screenshot wurde mit einer Version der Anwendung aufgenommen, die kein Streaming verwendet. Wenn Sie Streaming verwenden, berücksichtigt die Standarderkennung nur die erste POST-Anfrage in der Abhängigkeitsantwortzeit, nicht die Zeit, die zum Streamen der vollständigen Antwort erforderlich ist. Erforderliche Zeit. )

1C957C6915C64E71Bca99Cec4367C84E

Wenn Sie ChatGPT selbst verwendet haben, fragen Sie sich möglicherweise, warum die Benutzeroberfläche jedes Wort einzeln ausgibt, anstatt sofort die vollständige Antwort zurückzugeben.

Es stellt sich heraus, dass die Nutzung der kostenlosen Version eigentlich nicht dazu gedacht ist, Sie zum Bezahlen zu verleiten! Dies ist eher eine Einschränkung des Inferenzmodells. Kurz gesagt, um den nächsten Token zu berechnen,ModellEs gibt noch ein letztes Zeichen, das berücksichtigt werden muss. Es gibt also nicht viel Raum für Parallelisierung. Da jeder Token einzeln verarbeitet wird, kann dieser Token auch an den Client gesendet werden, während die Berechnung für den nächsten Token läuft.

Um das Benutzererlebnis zu verbessern, kann es hilfreich sein, bei Verwendung der ChatCompletion-Funktion Streaming-Methoden zu verwenden. Auf diese Weise kann der Benutzer mit der Verwendung der ersten Ergebnisse beginnen, während die vollständige Antwort generiert wird. Sie können dieses Verhalten im GIF unten sehen. Auch wenn alle drei Antworten noch geladen werden, kann der Benutzer nach unten scrollen und prüfen, was bereits vorhanden ist.

Wie bereits erwähnt, haben wir mehr benutzerdefinierte Erkennung hinzugefügt als das Nötigste. Dadurch erhalten wir detaillierte Informationen darüber, wo wir unsere Zeit verbringen. Werfen wir einen Blick auf die vollständige Ablaufverfolgung, um zu sehen, wie dieser Stream tatsächlich aussieht.

Siehe auch  6 Schritte zur Verwendung von ChatGPT in Ihrer nächsten E-Mail-Marketingkampagne

Unsere Anwendung ist so konfiguriert, dass sie die drei besten Treffer von Elasticsearch erhält und dann parallel eine ChatCompletion-Anfrage gegen OpenAI ausführt.

126C11949De04265B0F6584471300De9

Wie wir im Screenshot sehen können, dauert das Laden eines einzelnen Ergebnisses etwa 15 Sekunden. Wir können auch sehen, dass die Rückgabe von OpenAI-Anfragen, die größere Antworten zurückgeben, länger dauert. Aber das ist nur eine Bitte. Tritt dieses Verhalten bei allen Anfragen auf? Gibt es einen klaren Zusammenhang zwischen der Reaktionszeit und der Anzahl der Token, die unsere vorherige Behauptung stützen?

Anstatt Elastic APM zur Visualisierung der Daten zu verwenden, können wir auch benutzerdefinierte Dashboards verwenden und Visualisierungen basierend auf APM-Daten erstellen. Wir können zwei interessante Diagramme erstellen, die die Beziehung zwischen der Anzahl der Token in der Antwort und der Dauer der Anfrage zeigen.

Wir können sehen, dass die Dauer umso länger ist (Y-Achse im ersten Diagramm), je mehr Token zurückgegeben werden (X-Achse im ersten Diagramm). Im Bild rechts können wir auch sehen, dass unabhängig von der Gesamtzahl der zurückgegebenen Token (x-Achse) die Dauer pro 100 zurückgegebenen Token nahezu konstant bei etwa 4 Sekunden bleibt.

Wenn Sie die Reaktionsfähigkeit einer Anwendung verbessern möchten, die ein OpenAI-Modell verwendet, ist es eine gute Idee, das Modell anzuweisen, die Antworten kurz zu halten.

A81C0C1Edecf420Ba7E79730B9Ae3Fdf

Darüber hinaus können wir unter anderem auch unsere Gesamtausgaben und die durchschnittlichen Kosten pro Seitenaufruf verfolgen.

F3334A0Da6Fa4F33Ae33198A10Ac24A0

Für unsere Beispielanwendung kostet eine einzelne Suche ca. 1,1 Cent. Diese Zahl hört sich nicht hoch an, wird aber wahrscheinlich in absehbarer Zeit nicht als Suchoption auf Ihrer öffentlichen Website angezeigt. Bei unternehmensinternen Daten und gelegentlich genutzten Suchoberflächen ist dieser Aufwand vernachlässigbar.

Bei unseren Tests stießen wir außerdem häufig auf Fehler bei der Verwendung der OpenAI-API in Azure, was uns letztendlich dazu veranlasste, der Beispielanwendung eine Wiederholungsschleife mit exponentiellem Backoff hinzuzufügen. Wir können Elastic APM auch verwenden, um diese Fehler abzufangen.

while tries 

Alle erfassten Fehler werden dann im Wasserfalldiagramm als Teil der Zeitspanne angezeigt, in der der Fehler aufgetreten ist.

E7Ea30F9B49448D880D1E19Aa06724Ea

Darüber hinaus bietet Elastic APM eine Übersicht aller Fehler. Im Screenshot unten sehen Sie die RateLimitError- und APIConnectionError-Fehler, auf die wir gelegentlich gestoßen sind. Mithilfe unseres groben exponentiellen Wiederholungsmechanismus können wir die meisten dieser Probleme abmildern.

F0A0Abf7A2F347C0991263Abee469B56

Mit allen integrierten Metadaten, die vom Elastic APM-Agenten erfasst werden, und den von uns hinzugefügten benutzerdefinierten Tags können wir problemlos analysieren, ob es Korrelationen zwischen der Leistung und Metadaten wie Dienstversion, Benutzerabfragen usw. gibt.

Wie unten gezeigt, besteht eine kleine Korrelation zwischen der Abfrage „Wie kann ich einen eingefrorenen Knoten mounten und indizieren?“ und langsamere Reaktionszeiten.

0147B26723De48Ee88A13C530408D84E

Eine ähnliche Analyse kann für jede Transaktion durchgeführt werden, die den Fehler verursacht hat. In diesem Beispiel schlagen die beiden Abfragen „Wie erstelle ich eine Aufnahmepipeline“ häufiger fehl als die anderen Abfragen, weshalb sie in dieser Korrelationsanalyse hervorstechen.

F337Ffb10D764Becb253Fd269986550A

import elasticapm
# the APM Agent is initialized
apmClient = elasticapm.Client(service_name="elasticdocs-gpt-v2-streaming")

# the default instrumentation is applied
# this will instrument the most common libraries, as well as outgoing http requests
elasticapm.instrument()

# if a user clicks the "Search" button in the UI
if submit_button:
	# start the APM transaction
apmClient.begin_transaction("user-query")
# add custom labels to the transaction, so we can see the users question in the API UI
elasticapm.label(query=query)

    async with elasticapm.async_capture_span('openaiChatCompletion', span_type='openai'):
        async for chunk in await openai.ChatCompletion.acreate(engine=engine, messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": truncated_prompt}],stream=True,):
            content = chunk["choices"][0].get("delta", {}).get("content")
            # since we have the stream=True option, we can get the output as it comes in
            # one iteration is one token
            with elasticapm.capture_span("token", leaf=True, span_type="http"):
                if content is not None:
                    # concatenate the output to the previous one, so have the full response at the end
                    output += content
                    # with every token we get, we update the element
                    element.markdown(output)
async def achat_gpt(prompt, result, index, element, model="gpt-3.5-turbo", max_tokens=1024, max_context_tokens=4000, safety_margin=1000):
    output = ""
    # we create on overall Span here to track the total process of doing the completion
    async with elasticapm.async_capture_span('openaiChatCompletion', span_type='openai'):
        async for chunk in await openai.ChatCompletion.acreate(engine=engine, messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": truncated_prompt}],stream=True,):
            content = chunk["choices"][0].get("delta", {}).get("content")
            # since we have the stream=True option, we can get the output as it comes in
            # one iteration is one token, so we create one small span for each
            with elasticapm.capture_span("token", leaf=True, span_type="http"):
                if content is not None:
                    # concatenate the output to the previous one, so have the full response at the end
                    output += content
                    # with every token we get, we update the element
                    element.markdown(output)

In diesem Blog testen wir eine in Python geschriebene Anwendung zur Verwendung von OpenAI und analysieren ihre Leistung. Wir untersuchten Antwortverzögerungen und fehlgeschlagene Transaktionen und bewerteten die Kosten für die Ausführung der Anwendung. Wir hoffen, dass Sie diesen Leitfaden nützlich finden!

Siehe auch  Wie Anwälte ChatGPT und andere große Sprachmodelle nutzen können, die die Rechtsbranche revolutionieren

Erfahren Sie mehr über die Möglichkeiten von Elasticsearch und KI

In diesem Blogbeitrag haben wir möglicherweise generative KI-Tools von Drittanbietern verwendet, die Eigentum ihrer jeweiligen Eigentümer sind und von diesen betrieben werden. Elastic hat keine Kontrolle über Tools von Drittanbietern und wir übernehmen keine Verantwortung für deren Inhalt, Betrieb oder Nutzung oder für Verluste oder Schäden, die aus Ihrer Nutzung solcher Tools entstehen können. Seien Sie vorsichtig, wenn Sie Tools der künstlichen Intelligenz zum Umgang mit persönlichen, sensiblen oder vertraulichen Informationen verwenden. Alle von Ihnen übermittelten Daten können für Schulungen zur künstlichen Intelligenz oder für andere Zwecke verwendet werden. Es gibt keine Garantie dafür, dass die von Ihnen bereitgestellten Informationen sicher oder vertraulich behandelt werden. Sie sollten sich mit den Datenschutzpraktiken und Nutzungsbedingungen jedes generativen KI-Tools vertraut machen, bevor Sie es verwenden.

Die in diesem Artikel genannten Kosten basieren auf den aktuellen OpenAI-API-Preisen und darauf, wie oft wir sie beim Laden der Beispielanwendung aufrufen.

Elastic, Elasticsearch und verwandte Marken sind Marken, Logos oder eingetragene Marken von Elasticsearch NV. in den Vereinigten Staaten und anderen Ländern. Alle anderen Firmen- und Produktnamen sind Marken, Logos oder eingetragene Marken ihrer jeweiligen Eigentümer.

Original:ChatGPT und Elasticsearch: APM-Instrumentierung, Leistung und Kostenanalyse – Elastic Search Labs

Anzeige
Nina Weber
Nina Weber is a renowned Journalist, who worked for many German Newspaper's Tech coloumns like Die Zukunft, Handelsblatt. She is a contributing Journalist for futuriq.de. She works as a editor also as a fact checker for futuriq.de. Her Bachelor degree in Humanties with Major in Digital Anthropology gave her a solid background for journalism. Know more about her here.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein