18 ChatGPT-API
18.1 Vorab
18.1.1 Lernziele
- Sie können gängige Anfragen an die OpenAI-ChatGPT-API senden.
18.1.2 Benötigte Software (R+Python)
import os
18.1.3 Spielzeug-Daten
tweets <- c(
'@corinnamilborn Liebe Corinna, wir würden dich gerne als Moderatorin für uns gewinnen! Wärst du begeisterbar?', '@Martin28a Sie haben ja auch Recht. Unser Tweet war etwas missverständlich. Dass das BVerfG Sachleistungen nicht ausschließt, kritisieren wir.')
18.2 Grundlagen
18.2.1 ChatGPT ist auch ein Transformer
👨🏫 Bist du ein Transformer?
🤖 Ja, ich bin ein Modell, das auf der GPT-3.5-Architektur von OpenAI basiert, und diese Architektur wird als “Transformer” bezeichnet. Der Begriff “Transformer” bezieht sich auf die spezifische Architektur des neuronalen Netzwerks, die von Vaswani et al. in ihrem Paper “Attention is All You Need” vorgestellt wurde. Die Transformer-Architektur hat sich als äußerst leistungsfähig für natürliche Sprachverarbeitungsaufgaben erwiesen und bildet die Grundlage für Modelle wie GPT (Generative Pre-trained Transformer), einschließlich GPT-3.5, auf dem meine Fähigkeiten basieren.
[Quelle: ChatGPT-3.5, 2023-11-23]
18.2.2 Alles ist API
Die Python- (oder R-)Pakete zum Zugriff zur ChatGPT-API sind letztlich nur Wrapper um den “direkten” Zugriff auf die API.
Definition 18.1 (API (Application Programming Interface)) Eine API stellt genormte Befehle zur Verfügung, um von einem Dienst (über eine Webseite) Daten abzufragen oder einzustellen. \(\square\)
18.2.3 curl
curl
ist eine gängige Methode (auf der Kommondozeile), um Daten von einer Webseite abzufragen (oder einzustellen).
Laut Dokumentation der API lautet der CURL-Befehl wie folgt (Pseudocode):
```{zsh}
#| eval: false
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Was ist die Frage zur Antwort '42'?"}] ,
"temperature": 0,
"max_tokens": 256
}'
```
Entscheidend ist der “Endpunkt” der URL: completions
.
OpenAi stellt eine Reihe von spezialisierten Diensten zur Verfügung, z.B. zur Sentimentanalyse von Tweets oder, natürlich, Textgeneration, und vieles mehr. \(\square\)
Obige Syntax übersetzt sich so nach Python:
# This code is for v1 of the openai package: pypi.org/project/openai
from openai import OpenAI
= OpenAI()
client
= client.chat.completions.create(
response ="gpt-3.5-turbo",
model=[],
messages=0,
temperature=256
max_tokens )
18.2.4 Prompting
Als Prompt kann man z.B. übergeben (bezeichnet als “System”):
🧑🦰 You will be provided with a tweet, and your task is to classify its sentiment as positive, neutral, or negative. USER
Dann kommt der zu klassifizierende Textschnipsel (bezeichent als “user”):
📄 I loved the new Batman movie!
Und schließlich antwortet der Bot:
🤖 positive
Es ist günstig, dem Bot zu sagen, in welcher Sprache der Tweet ist. Außerdem ist es nützlich, den Prompt (die Anweisung) bereits in der Zielsprache zu formulieren.
prompt_stem <- "Nach dem Doppelpunkt folgt ein Tweet in deutscher Sprache. Klassifizieren Sie das Sentiment dieses Tweets als positiv, neutral oder negativ. Antworten Sie nur mit einem Wort. Hier ist der Tweet: "
prompts <-
str_c(prompt_stem, tweets)
prompts
## [1] "Nach dem Doppelpunkt folgt ein Tweet in deutscher Sprache. Klassifizieren Sie das Sentiment dieses Tweets als positiv, neutral oder negativ. Antworten Sie nur mit einem Wort. Hier ist der Tweet: @corinnamilborn Liebe Corinna, wir würden dich gerne als Moderatorin für uns gewinnen! Wärst du begeisterbar?"
## [2] "Nach dem Doppelpunkt folgt ein Tweet in deutscher Sprache. Klassifizieren Sie das Sentiment dieses Tweets als positiv, neutral oder negativ. Antworten Sie nur mit einem Wort. Hier ist der Tweet: @Martin28a Sie haben ja auch Recht. Unser Tweet war etwas missverständlich. Dass das BVerfG Sachleistungen nicht ausschließt, kritisieren wir."
18.2.5 Anmelden an der API
Die API erlaubt nur Zugriffe angemeldeter Nutzer.
OPENAI_API_KEY <- Sys.getenv("OPENAI_API_KEY")
Damit eine Environment-Variable OPENAI_API_KEY
ausgelesen werden kann, muss sie in .Rprofile
definiert sein. Alternativ kann man aber die Variable auch auf anderen Wegen definieren, etwa aus einer Textdatei einlesen.
Lassen Sie sensible Daten, wie API-Keys, niemals auf öffentlichen Ordnern oder Repos (etwa auf Github) herumliegen. Stellen Sie sich vor, Sie haben bei dem Dienst ihre Kreditkarte hinterlege und ein übelwollender Dritter nutzt kostenpflichtige Dienste mit sehr hohem Budget. 🤯 \(\square\)
18.3 Wrapper um curl
Dieser Abschnitt basiert auf einem Blogpost bei R-Bloggers von Rasmus Bååth.
response <- POST(
# curl https://api.openai.com/v1/chat/completions
url = "https://api.openai.com/v1/chat/completions",
# -H "Authorization: Bearer $OPENAI_API_KEY"
add_headers(Authorization =
paste("Bearer", Sys.getenv("OPENAI_API_KEY"))),
# -H "Content-Type: application/json"
content_type_json(),
# -d '{
# "model": "gpt-3.5-turbo",
# "messages": [{"role": "user", "content": "What is a banana?"}]
# }'
encode = "json",
body = list(
model = "gpt-3.5-turbo",
messages = list(list(role = "user", content = prompts[1]))
))
content(response)
$object
[1] "chat.completion"
$created
[1] 1700753610
$model
[1] "gpt-3.5-turbo-0613"
$choices
$choices[[1]]
$choices[[1]]$index
[1] 0
$choices[[1]]$message
$choices[[1]]$message$role
[1] "assistant"
$choices[[1]]$message$content
[1] "Das Sentiment dieses Tweets ist positiv. "
$choices[[1]]$finish_reason
[1] "stop"
$usage
$usage$prompt_tokens
[1] 76
$usage$completion_tokens
[1] 10
$usage$total_tokens
[1] 86
Der für uns entscheidende Punkt ist:
Das Sentiment dieses Tweets ist positiv.
18.3.1 Curl-Wrapper in eine Funktion gebracht
ask_chatgpt <- function(prompt) {
response <- POST(
# curl https://api.openai.com/v1/chat/completions
url = "https://api.openai.com/v1/chat/completions",
# -H "Authorization: Bearer $OPENAI_API_KEY"
add_headers(Authorization =
paste("Bearer", Sys.getenv("OPENAI_API_KEY"))),
# -H "Content-Type: application/json"
content_type_json(),
# -d '{
# "model": "gpt-3.5-turbo",
# "messages": [{"role": "user", "content": "What is a banana?"}]
# }'
encode = "json",
body = list(
model = "gpt-3.5-turbo",
messages = list(list(role = "user", content = prompt))
))
str_trim(content(response)$choices[[1]]$message$content)
}
18.3.2 Schleife
prompts |>
sapply(ask_chatgpt)
sapply
ist sehr ähnlich wie map
aus purrr, braucht aber kein Extrapaket.
Nach dem Doppelpunkt folgt ein Tweet in deutscher Sprache. Klassifizieren Sie das Sentiment dieses Tweets als positiv, neutral oder negativ. Antworten Sie nur mit einem Wort. Hier ist der Tweet: @corinnamilborn Liebe Corinna, wir würden dich gerne als Moderatorin für uns gewinnen! Wärst du begeisterbar?
"positiv"
Nach dem Doppelpunkt folgt ein Tweet in deutscher Sprache. Klassifizieren Sie das Sentiment dieses Tweets als positiv, neutral oder negativ. Antworten Sie nur mit einem Wort. Hier ist der Tweet: @Martin28a Sie haben ja auch Recht. Unser Tweet war etwas missverständlich. Dass das BVerfG Sachleistungen nicht ausschließt, kritisieren wir.
"neutral"
18.4 Einfache Anfrage an die OpenAI-API
Der API-Aufruf von ChatGPT kostet Geld 💸. \(\square\)
18.4.1 Authentifizierung
Wir müssen uns zunächst bei der API anmelden:
openai_key_r <- Sys.getenv("OPENAI_API_KEY")
= os.environ.get("OPENAI_API_KEY") openai_key_py
Speichern Sie keine sensiblen Daten in geteilten Ordner/Repos. Achten Sie auch auf Log-Dateien wir .Rhistory
, in der u.U. Ihre sensiblen Daten enthalten sein können. \(\square\)
Eine sichere Variante als das unverschlüsselte Speichern von Passwörtern ist es, sensible Daten mit einem Passwort zu schützen. Dazu kann man z.B. in R das Paket keyring
nutzen. Dieses Paket greift auf die Schlüsselbundverwaltung Ihres Betriebssystems zurück (sowohl Windows, Mac, als auch (einige?) Linux-Distrubitionen).
18.4.2 Setup
= []
sentiment_scores = []
sentiment_analysis = '@Martin28a Sie haben ja auch Recht. Unser Tweet war etwas missverständlich. Dass das BVerfG Sachleistungen nicht ausschließt, kritisieren wir.' text
18.4.3 Anfrage an die API
= f"Analysiere das Sentiment des folgenden Texts: \n{text}"
prompt
= openai.Completion.create(
response =prompt,
prompt="davinci",
engine=100,
max_tokens=0.5,
temperature )
18.5 Vertiefung
Mit etwas Zusatzaufwand kann man den Kontext bzw. den Verlauf der Konversation mit dem Bot berücksichtigen, wie dieser Post zeigt.
Die OpenAI-API bietet ebenfalls Fine-Tuning an, wie in diesem Post beschrieben.
18.6 Aufgaben
Schauen Sie sich die Aufgaben mit dem Tag ‘Transformer’ auf dem Datenwerk an.