Startseite / Artikel

Portieren eines Chat-Loops von OpenAI zu Claude in Python: Eine Seite mit Änderungen

Ein stateless Message Loop in die Anthropic Messages API verschieben: der oberste Systemparameter, der erforderliche max_tokens-Wert, die Inhaltseinheiten sowie eine strenge Abwechslung der Rollen.

Verlag: REACTAPP.TOP4 Min. Lesezeit867 Wörter

Quellen: Part 3 — Call the Claude API in Python (same messages, system on the side)

Jeder, der bereits eine Chat-Schleife für OpenAI entwickelt hat, kann sie mit etwa einer Seite an Änderungen auf Anthropics Claude übertragen. Beide Anbieter verwenden denselben Grundaufbau: Eine mit Rollen versehene messages-Liste wird bei jedem Aufruf vollständig übermittelt, wobei die Antwort anschließend hinzugefügt wird. Nur ein Element ändert sich, und es ist hilfreich, genau zu wissen, welches.

Dieselbe Liste, anderes System dahinter

Claudes Messages-API akzeptiert das bereits bekannte Konversationsformat: Eine Liste von Dictionaries mit role und content, die auf dem Server zustandslos sind und jedes Mal vollständig erneut übermittelt werden. Die Rollennamen und -bedeutungen sind identisch, nämlich user und assistant.

Der einzige strukturelle Unterschied besteht darin, dass system keine Nachricht ist. OpenAI platziert die Anweisungen in Zeile null der Liste. Anthropic verschiebt sie in einen übergeordneten system=-Parameter, der zusammen mit der Liste übertragen wird. Die Liste enthält nur das eigentliche Gespräch, also die abwechselnden Nachrichten des Benutzers und des Assistenten.

import anthropic

client = anthropic.Anthropic()  # key from env

resp = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=300,
    system="You are a concise Python assistant.",
    messages=[
        {
            "role": "user",
            "content": "Why is system a parameter "
                       "here, not a message?",
        },
    ],
)
print(resp.content[0].text)

Zwei kleinere Unterschiede treten bereits vor dem Ausführen dessen auf:

  • max_tokens muss festgelegt werden. OpenAI erlaubt es, eine Anfrage ohne Obergrenze für die Ausgabe zu senden. Claude verlangt diese Einstellung bei jeder Anfrage – was etwas ärgerlich ist, aber die Kosten im Blick hält, denn eine Anfrage kann erst gestellt werden, nachdem man entschieden hat, wie lang die Antwort dauern darf.
  • Antworten kommen als Inhaltsteile. Anstelle eines einzigen Strings erhält man eine Liste, wobei der reine Text sich bei resp.content[0].text befindet. Heute erscheint das übertrieben, doch später kommen Toolaufrufe in derselben Struktur an, wodurch diese Vorgehensweise sinnvoll wird.

Einrichtung und ein einziger Turn

Installieren Sie das SDK mit pip install anthropic, exportieren Sie anschließend den Schlüssel aus der Anthropic-Konsole (er beginnt mit sk-ant-) als ANTHROPIC_API_KEY. Der Client lädt diesen Schlüssel automatisch herunter.

Setzen Sie es neben den OpenAI-Aufruf – der gesamte Unterschied besteht aus vier Änderungen. Die Methode client.chat.completions.create wird zu client.messages.create, die Systemzeile wird in system= verschoben, eine Ausgaboberreichengrenze wird erforderlich, und der Text wird aus content[0].text anstelle von choices[0].message.content gelesen. Eine Anmerkung zum SDK: Das aktuelle anthropic-Paket akzeptiert temperature= bei messages.create nicht, sodass ältere Beispiele, die es verwenden, Fehler auslösen werden. Es wird die Standard-Stichprobenmethode angewendet, was für diese Beispiele in Ordnung ist.

Die Tokenzahlen finden sich in resp.usage.input_tokens und resp.usage.output_tokens. Es handelt sich um denselben Messwert mit leicht unterschiedlichen Feldnamen – es lohnt sich, diese jedes Mal zu protokollieren.

Der History-Loop bei Claude

Hier ist die übertrugene ask()-Funktion aus der OpenAI-Version. Die Logik zum Hinzufügen und erneuten Senden hat sich nicht geändert. Nur der Aufruf in der Mitte hat sich geändert.

msgs = []

def ask(text: str) -> str:
    msgs.append(
        {"role": "user", "content": text}
    )
    resp = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=300,
        system="You are a concise assistant.",
        messages=msgs,  # full history
    )
    reply = resp.content[0].text
    msgs.append(
        {"role": "assistant", "content": reply}
    )
    return reply

print(ask("Define a context window."))
print(ask("Now for a five-year-old."))
print(ask("Which answer was shorter?"))

Die dritte Frage in einem Gespräch belegt weiterhin den Kreislauf, denn sie funktioniert nur, wenn beide vorherigen Antworten in msgs gespeichert sind und erneut übermittelt werden. Dasselbe gilt für die Kostenstruktur: Die Anzahl der Eingabetoken nimmt mit jeder Runde zu, wodurch lange Gespräche mehr pro Aufruf kosten.

Claude ist außerdem anspruchsvoller, was die Reihenfolge angeht – Nachrichten müssen abwechselnd vom Benutzer und vom Assistenten gesendet werden. Zwei Benutzernachrichten in Folge, was leicht passiert, wenn ein fehlgeschlagener Antrag erneut versucht wird, führen dazu, dass Claude den Aufruf ablehnt, während OpenAI dies toleriert. Betrachten Sie das als eine kostenlose Überprüfungsregel für das System, das Ihre Historie verwalten wird.

Ausführung

Das Skript führt eine einzelne Runde sowie anschließend ein Gespräch mit drei Runden aus und protokolliert nach jedem Aufruf die Eingab- und Ausgabetoken. Es stoppt frühzeitig mit einer klaren Meldung, falls ANTHROPIC_API_KEY fehlt. Zudem werden gebührenpflichtige Anfragen gestellt, weshalb es aus jedem CI-Aufruf entfernt werden sollte.

pip install -r requirements.txt
export ANTHROPIC_API_KEY="sk-ant..."
python examples/part03_claude.py

Warum der Portwechsel einfach war und was Sie gewinnen

Es handelte sich um eine kleine Änderung, da beide Anbieter denselben Vertrag bereitstellen: einen statelessen Endpunkt, der bei jedem Aufruf den gesamten Dialog entgegennimmt und einmal antwortet. Was sich unterscheidet, sind die Details wie der Standort des Systemprompt, das Aussehen des Antwortobjekts sowie welche Parameter erforderlich sind. LangChain abstrahiert diese feinen Unterschiede, und seine Klassen ChatOpenAI sowie ChatAnthropic dienen dazu, den vierzeiligen Unterschied, den Sie gerade manuell geschrieben haben, zu übernehmen. Zu wissen, was hinter der Abstraktion verborgen ist, macht den Unterschied zwischen deren Nutzung und dem darin Gefangensein aus.

Es gibt auch einen praktischen Vorteil. Zwei Anbieter hinter einer einzigen ask()-Struktur ermöglichen es Ihnen, Modelle im A/B-Test zu vergleichen, bei schlechten API-Bedingungen auf einen Ersatzanbieter umzusteigen oder einfache Fragen an den einen und schwierige an den anderen Anbieter zu leiten – alles ohne Änderung des Anwendungscode. Googles Gemini API folgt derselben Konversationsstruktur, wobei nur eine Rolle umbenannt wurde: Der Assistent wird nun model genannt.