Direkt zum Inhalt

Tutorial zum Aufrufen von GPT-5-Funktionen

Ein praktischer Leitfaden zum Aufrufen von GPT-5-Funktionen: von JSON-Schema-Funktionen bis hin zu Freiform-Tools, Lark/CFG-Einschränkungen, Präambeln und Tool-Zulassungslisten.
Aktualisierte 7. Okt. 2025  · 11 Min. Lesezeit

Mit der Einführung von GPT-5hat OpenAI die Tool-/Funktionsaufrufe in der API erweitert und jetzt auch freie Tool-Aufrufe (reiner Text, kein JSON), Grammatikbeschränkungen über Lark/CFG, Tool-Zulassungslisten und eine verbesserte Tool-Nutzungslogik eingebaut. Zusammen machen diese Funktionen GPT-5 zu einem echten agentenbasierten Modell: Du kannst APIs, Datenbanken und benutzerdefinierte Tools mit der Responses API verbinden und fundierte Antworten generieren oder sogar Arbeitsabläufe automatisieren.

In diesem Tutorial zeige ich dir Funktionswerkzeuge, benutzerdefinierte Werkzeuge, Grammatikbeschränkungen, Tool-Zulassungslistenund Präambeln, mit Code-Beispielen und klaren Erklärungen, wie sie funktionieren und wann man sie benutzt.

Funktionsaufruf in GPT-5: Was & Warum

Mit Function Calling in GPT-5 kannst du das Modell mit den Daten und Aktionen deiner App verbessern. Das Modell kann entscheiden, wann ein Tool aufgerufen werden soll, während du dich um die Logik kümmerst und Ergebnisse für eine endgültige, fundierte Antwort lieferst. 

Arten von Funktionsaufrufen:

  1. Funktionswerkzeuge (JSON-Schema): Die bieten strukturierte Ein- und Ausgänge, die das Modell genau abrufen kann.
  2. Benutzerdefinierte Werkzeuge (Freiform): Die bieten flexible Texteingaben und -ausgaben für Integrationen, bei denen die Daten nicht strukturiert sind.

Was ist ein Funktionsaufruf?

GPT-5 kann sowohl strukturierte Funktionstools (mit JSON-Schema) als auch benutzerdefinierte Tools, die Freitext-Payloads (wie SQL, Skripte oder Konfigurationen) akzeptieren, für eine nahtlose Integration mit externen Laufzeitumgebungen. 

Funktionswerkzeuge werden durch JSON Schema definiert, damit das Modell genau weiß, welche Argumente übergeben werden müssen, und eine strenge Eingabevalidierung möglich ist. Mehr dazu findest du in unserem Tutorial zu OpenAI Function Calling.

Warum Funktionsaufrufe verwenden?

  • Flexibilität: Mit Freiform-Tools kann das Modell genau den Text erstellen, den dein System braucht, ohne die Einschränkungen von JSON. Das macht sie super für Code, Abfragen oder Konfigurationen.
  • Zuverlässigkeit und Kontrolle: Funktionswerkzeuge sorgen für strukturierte Argumente, was die Vorhersagbarkeit verbessert und Parsing-Fehler reduziert.
  • Agentische Arbeitsabläufe: GPT-5 ist für komplizierte, mehrstufige Werkzeuganwendungen und Programmieraufgaben gemacht, wobei der Werkzeugaufruf eine der Hauptfunktionen ist.

Wie läuft das Aufrufen von Funktionen ab?

  1. Schick eine Eingabeaufforderung, die alle verfügbaren Tools enthält.
  2. Das Modell macht einen Tool-Aufruf (entweder mit Argumenten oder mit Freitext).
  3. Deine Anwendung führt das Tool aus (Python-Funktion ausführen).
  4. Gib die Ausgabe vom Tool an das Modell zurück.
  5. Das Modell reagiert dann oder kann weitere Tools aufrufen.

Quelle: Funktionsaufruf – OpenAI-API

Wann sollte man die Funktion verwenden? Benutzerdefinierte Tools

  • Benutze Funktionswerkzeuge , wenn du eine strenge Validierung und vorhersehbare, typisierte Argumente über JSON Schema willst.
  • Benutzerdefinierte Tools (Freiform) verwenden , wenn deine Laufzeit Rohtext braucht (wie Skripte, SQL oder Konfigurationen) oder wenn du schnelle Iterationen ohne Schemata brauchst.

Funktionswerkzeuge (JSON-Schema): Strukturierte Daten senden

Mit den Funktionswerkzeugen und JSON Schema kannst du vorhersehbare und strukturierte Ergebnisse aus dem Modell bekommen. Das Modell checkt die Tools, die du angegeben hast, entscheidet, wann welches Tool benutzt werden soll, schlägt JSON-validierte Argumente vor und führt dann die passende Funktion in deinem Code aus. 

Danach kannst du das Modell bitten, eine Antwort nur anhand der vom Tool zurückgegebenen Daten zu erstellen, damit die Ausgabe fundiert, maschinenlesbar und einfach zu integrieren ist.

Dieses Beispiel zeigt ein paar wichtige Sachen:

  • Tool-Erkennung und Argumentgenerierung: Das Modell sucht das passende Tool raus und füllt automatisch die JSON-Argumente aus.
  • Werkzeugausführungsschleife: Deine Anwendung führt die gewünschten Tools aus und schickt die Ergebnisse zurück an das Modell.
  • Schema-förmige endgültige Antwort: Die endgültige Antwort basiert komplett auf den Ergebnissen der Tools, was Ungenauigkeiten minimiert und die Zuverlässigkeit sicherstellt.

1. Einrichten

  1. Erstell ein OpenAI-Konto und hol dir einen API-Schlüssel im Dashboard der Plattform. Öffne im Dashboard den Bereich „API“, dann „API-Schlüssel anzeigen“ und klicke auf „Neuen geheimen Schlüssel erstellen“.
  2. Füge eine Zahlungsmethode oder Guthaben zu deinem Konto hinzu, damit API-Aufrufe funktionieren. Die Nutzung wird von deinem Prepaid-Guthaben abgezogen, wenn du Anfragen machst.
  3. Speicher deinen API-Schlüssel als Umgebungsvariable mit dem Namen OPENAI_API_KEY, bevor du deine App startest. 
  4. Installiere das offizielle OpenAI Python SDK mit pip install openai “.

2. Werkzeuge definieren

Du gibst eine Liste von Tools mit Namen, Beschreibung und JSON-Schema für Parameter an. Das Schema hilft dem Modell dabei, gut strukturierte Argumente zu liefern.

  • make_coffee Erwartet einen String-Parameter: coffee_type.
  • random_coffee_fact nimmt keine Parameter (leeres Objekt). Diese Definitionen werden über das Argument „ tools ” im API-Aufruf übergeben, damit das Modell weiß, was verfügbar ist.
import os
from openai import OpenAI
import json

client = OpenAI(api_key = os.environ["OPENAI_API_KEY"])

tools = [
    {
        "type": "function",
        "name": "make_coffee",
        "description": "Gives a simple recipe for making a coffee drink.",
        "parameters": {
            "type": "object",
            "properties": {
                "coffee_type": {
                    "type": "string",
                    "description": "The coffee drink, e.g. espresso, cappuccino, latte"
                }
            },
            "required": ["coffee_type"],
        },
    },
    {
        "type": "function",
        "name": "random_coffee_fact",
        "description": "Returns a fun fact about coffee.",
        "parameters": {"type": "object","properties":{}}
    }
]

3. Tools einführen

Du implementierst die Python-Funktionen, die die eigentliche Arbeit erledigen:

  • make_coffee(coffee_type) Gibt eine kurze Rezeptzeichenfolge zurück, die nach dem gewünschten Getränk sortiert ist.
  • random_coffee_fact() gibt eine kleine Faktenmenge zurück. 

Beide geben JSON-serialisierbare Dicts zurück, die sich super für die Rückmeldung an das Modell eignen.

def make_coffee(coffee_type):
    recipes = {
        "espresso": "Grind fine, 18g coffee → 36g espresso in ~28s.",
        "cappuccino": "Brew 1 espresso shot, steam 150ml milk, pour and top with foam.",
        "latte": "Brew 1 espresso shot, steam 250ml milk, pour for silky texture.",
    }
    return {"coffee_type": coffee_type, "recipe": recipes.get(coffee_type.lower(), "Unknown coffee type!")}

def random_coffee_fact():
    return {"fact": "Coffee is the second most traded commodity in the world, after oil."}

4. Ein Gespräch anfangen

Starte das Gespräch mit der Frage des Nutzers: {"role": "user", "content": "How do I make a latte?"}

Das Modell kann Nachrichten zurücksenden, die ein Element „ function_call “ enthalten, z. B. make_coffee “ mit „ {"coffee_type":"latte"}“. Dann solltest du die Meldungen des Modells wieder an input_list: input_list += response.output anhängen. Das hilft dabei, den Gesprächsstatus für die nächste Runde zu behalten.

# Track used tools
used_tools = []

input_list = [{"role": "user", "content": "How do I make a latte?"}]

response = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=input_list,
)
input_list += response.output

5. Führ Tool-Aufrufe aus und häng die Ausgaben dran

Du solltest die Liste „ response.output “ durchgehen und die Elemente finden, bei denen „ item.type “ gleich „ "function_call" “ ist. Für diese Elemente analysierst du item.arguments und leitest die Anfragen an deine Python-Funktionen weiter.

Für die Funktion „ make_coffee “ rufst du sie mit „ make_coffee(args["coffee_type"]) “ auf. Für die Funktion „ random_coffee_fact ” ruf einfach random_coffee_fact() auf.

Nachdem du die Funktionen ausgeführt hast, füge eine function_call_output ”-Meldung hinzu, die Folgendes enthält:

  • call_id (was diese Ausgabe mit der Anfrage des Modells verbindet) 
  • output (eine JSON-Zeichenkette mit dem Ergebnis deiner Funktion).
for item in response.output:
    if getattr(item, "type", "") == "function_call":
        used_tools.append(item.name)
        args = json.loads(item.arguments or "{}")

        if item.name == "make_coffee":
            result = make_coffee(args["coffee_type"])
        elif item.name == "random_coffee_fact":
            result = random_coffee_fact()
        else:
            result = {"error": f"Unknown tool {item.name}"}

        input_list.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": json.dumps(result)
        })

6. Die endgültige Antwort erstellen

Du machst einen zweiten Aufruf von „ client.responses.create “ und gibst dabei die aktualisierte input_list weiter, die jetzt die Tool-Ausgaben enthält.

Die Variable „ used_tools ” speichert die Namen der Tools, die in den Funktionsaufrufen des Modells auftauchen. Wir werden es nutzen, um zu zeigen, welche Tools verwendet wurden. 

final = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=input_list,
    instructions="Answer using only the tool results."
)

print("Final output:\n", final.output_text)

print("\n--- Tool Usage ---")
for t in tools:
    status = "USED ✅" if t["name"] in used_tools else "NOT USED ❌"
    print(f"{t['name']}: {status}")

Weil der Nutzer nach einem Latte gefragt hat, hat das Modell make_coffee “ mit coffee_type = "latte" ausgewählt, dein Code hat das ausgeführt und die endgültige Antwort wurde nur aus dem Ergebnis dieses Tools erstellt.

Final output:
 {"coffee_type":"latte","recipe":"Brew 1 espresso shot, steam 250ml milk, pour for silky texture."}

--- Tool Usage ---
make_coffee: USED ✅
random_coffee_fact: NOT USED ❌

Benutzerdefinierte Werkzeuge (Freiform): Rohtext senden

Nutze die frei gestaltbaren Tools von GPT-5, damit das Modell Rohtext direkt an dein Tool schicken kann, wie zum Beispiel Code, SQL, shell-Befehle oder einfache CSV-Dateien, ohne dass ein JSON-Schema nötig ist. 

Diese Funktion geht über die älteren, nur JSON-basierten Funktionsaufrufe hinaus und bietet dir mehr Flexibilität bei der Integration mit Executoren, Abfrage-Engines oder Interpretern für domänenspezifische Sprachen (DSL). 

Im Freiformmodus macht das Modell einen benutzerdefinierten Toolaufruf mit einer unstrukturierten Text-Nutzlast, die du an deine Laufzeit weiterleiten kannst. Dann gibst du das Ergebnis zurück, damit das Modell die Antwort für den Nutzer fertigstellen kann.

Jetzt schreiben wir den Code, mit dem das Modell die richtigen Tools auswählen und unstrukturierten Rohtext als Ergebnis liefern kann. Diese Ausgabe wird dann an eine Python-Funktion weitergeleitet, um ein Ergebnis zu erzeugen. So kannst du einfach die Zutaten angeben, die du hast, und das Modell macht dann Rezepte, die genau auf deine Bedürfnisse zugeschnitten sind.

In diesem Beispielcode haben wir:

  1. Ich hab den OpenAI-Client gestartet und ein eigenes Tool namens meal_planner eingerichtet, das reine Texteingaben akzeptiert.
  2. Ich hab das Python- plan_meal -Modul gemacht, das eine durch Kommas getrennte Zeichenfolge von Zutaten nimmt und eine Idee für ein Gericht zurückgibt.
  3. Ich hab das Gespräch mit einer Nachricht gestartet, in der ich die verfügbaren Zutaten aufgelistet hab.
  4. Ich hab ein erstes Modell erstellt, das GPT-5 sagt, dass es das Tool nur mit einer sauberen Zutatenliste nutzen soll, und die Ausgabe des Modells zum Gesprächsverlauf hinzugefügt.
  5. Hab den ausgegebenen benutzerdefinierten Tool-Aufruf gefunden und die rohe, durch Kommas getrennte Eingabezeichenfolge rausgezogen.
  6. Hab das Tool gestartet, indem ich die Liste an plan_meal weitergeleitet hab, und dann das Ergebnis als function_call_output über call_id mit dem Modell verbunden.
  7. Hab einen letzten Modellaufruf gemacht, um die grobe Idee des Tools in eine klare Schritt-für-Schritt-Anleitung umzuwandeln, und dann die Details des Toolaufrufs und das Endergebnis ausgedruckt.
from openai import OpenAI
import json
import random

client = OpenAI()

# --- Custom tool ---
tools = [
    {
        "type": "custom",
        "name": "meal_planner",
        "description": "Takes ONLY a comma-separated list of ingredients and suggests a meal idea."
    }
]

# --- Fake meal planner ---
def plan_meal(ingredients: str) -> str:
    ideas = [
        f"Stir-fry: {ingredients} with garlic & soy sauce.",
        f"One-pot rice: cook {ingredients} together in broth until fluffy.",
        f"Soup: simmer {ingredients} in stock with herbs.",
        f"Sheet-pan bake: roast {ingredients} at 200°C for ~20 min."
    ]
    return random.choice(ideas)

# --- Start conversation ---
messages = [
    {"role": "user", "content": "I only have chicken, rice, and broccoli. Any dinner ideas?"}
]

# 1) Ask model with clear instruction
resp = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=messages,
    instructions="If the user mentions ingredients, call the meal_planner tool with ONLY a comma-separated list like 'chicken, rice, broccoli'."
)

messages += resp.output

# 2) Find the tool call
tool_call = next((x for x in resp.output if getattr(x, "type", "") == "custom_tool_call"), None)
assert tool_call, "No tool call found!"

# Get clean CSV input
ingredients_csv = tool_call.input.strip()

# 3) Run the tool
meal_result = plan_meal(ingredients_csv)

# 4) Send tool output back
messages.append({
    "type": "function_call_output",
    "call_id": tool_call.call_id,
    "output": meal_result
})

# 5) Final model response
final = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=messages,
    instructions="Turn the meal idea into a short recipe with 3-4 steps."
)

print("\n--- Tool Call ---")
print("Name:", tool_call.name)
print("Input:", ingredients_csv)
print("Output:", meal_result)


print("\n--- Final Output ---\n", final.output_text)

So haben wir Statistiken zu den verwendeten Tools bekommen, einschließlich Installation, Eingabe und Ausgabe. Außerdem gibt's am Ende ein komplettes Rezept, wie man das Essen macht.

--- Tool Call ---
Name: meal_planner
Input: chicken, rice, broccoli
Output: One-pot rice: cook chicken, rice, broccoli together in broth until fluffy.

--- Final Output ---
 One-Pot Chicken, Rice & Broccoli

- Season bite-size chicken pieces with salt and pepper; sear in a little oil in a pot until lightly browned.
- Add 1 cup rinsed rice and 2 cups broth (or water + salt). Bring to a boil, then cover and simmer on low for 12 minutes.
- Scatter 2 cups small broccoli florets on top, cover, and cook 5-7 more minutes until rice is fluffy and broccoli is tender.
- Rest 5 minutes off heat, fluff, and adjust seasoning. Optional: stir in a knob of butter or a splash of soy.

Grammatikregeln (Lark): Werkzeug-Ausgaben einschränken

GPT-5 kann jetzt kontextfreie Grammatik (CFG) und sorgt so dafür, dass die Ausgabeformate genau kontrolliert werden. 

Durch die Anwendung einer Grammatik wie SQL oder einer domänenspezifischen Sprache (DSL) auf seine Antworten stellt GPT-5 sicher, dass die Ausgaben immer der geforderten Struktur folgen. CFG ist besonders wichtig für automatisierte Prozesse und Workflows mit hohem Risiko. 

GPT-5 kann Grammatiken nutzen, die in Formaten wie Lark definiert sind, um die Ergebnisse des Tools während der Generierung zu beschränken. Dieser Ansatz für eingeschränkte Dekodierung macht das Ganze zuverlässiger, indem er Formatabweichungen verhindert und dafür sorgt, dass die Struktur einheitlich bleibt.

Wir schreiben jetzt den Code, mit dem das Modell ein Tool auswählt und NUR einen grammatikalisch korrekten arithmetischen Ausdruck ausgibt. Dieser Ausdruck wird dann in Python ausgewertet, das Ergebnis wird an die Konversation zurückgegeben und die endgültige Antwort wird klar in natürlicher Sprache dargestellt.

In diesem Beispielcode haben wir:

  1. Den OpenAI-Client gestartet und ein eigenes Tool namens „ math_solver eingerichtet, das NUR einen grammatikalisch korrekten arithmetischen Ausdruck (Lark CFG) ausgeben darf.
  2. Das Gespräch wurde mit einer mathematischen Frage in natürlicher Sprache vom Nutzer gestartet.
  3. Hab ein erstes Modell aufgerufen, das GPT-5 sagt, dass es math_solver mit einem Ausdruck anrufen soll, der der Grammatik entspricht.
  4. Hab den Tool-Aufruf gefunden und die Rohausdruckszeichenfolge aus der Tool-Nutzlast rausgezogen.
  5. Ich habe die Aussage lokal in einer eingeschränkten Umgebung geprüft, um ein konkretes Ergebnis zu bekommen.
  6. Das Ergebnis der Tool-Ausführung wurde zurück in die Konversation geschickt, verbunden über den ursprünglichen Link call_id.
  7. Hab ein letztes Mal das Modell aufgerufen, um das ausgewertete Ergebnis klar in natürlicher Sprache zu zeigen.
from openai import OpenAI
import json

client = OpenAI()

# --- Local fake evaluator ---
def eval_expression(expr: str) -> str:
    try:
        # Evaluate safely using Python's eval on restricted globals
        result = eval(expr, {"__builtins__": {}}, {})
        return f"{expr} = {result}"
    except Exception as e:
        return f"Error evaluating expression: {e}"

# --- Custom tool with grammar constraint ---
tools = [
    {
        "type": "custom",
        "name": "math_solver",
        "description": "Solve a math problem by outputting ONLY a valid arithmetic expression.",
        "format": {
            "type": "grammar",
            "syntax": "lark",
            "definition": r"""
start: expr

?expr: term
     | expr "+" term   -> add
     | expr "-" term   -> sub

?term: factor
     | term "*" factor -> mul
     | term "/" factor -> div

?factor: NUMBER
       | "(" expr ")"

%import common.NUMBER
%ignore " "
"""
        },
    }
]

# --- User asks ---
msgs = [
    {"role": "user", "content": "What is (12 + 8) * 3 minus 5 divided by 5?"}
]

# 1) First model call: GPT-5 must emit a grammar-valid expression
resp = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=msgs,
    instructions="Always call the math_solver tool with a grammar-valid arithmetic expression like '(12 + 8) * 3 - 5 / 5'."
)

msgs += resp.output

tool_call = next(
    x for x in resp.output
    if getattr(x, "type", "") in ("custom_tool_call", "tool_call", "function_call")
)

expr = getattr(tool_call, "input", "") or getattr(tool_call, "arguments", "")
print("\n=== Grammar-Constrained Expression ===")
print(expr)

# 2) Run the local evaluator
tool_result = eval_expression(expr)
print("\n=== Tool Execution Result ===")
print(tool_result)

# 3) Return tool output
msgs.append({
    "type": "function_call_output",
    "call_id": tool_call.call_id,
    "output": tool_result
})

# 4) Final pass: GPT-5 presents answer nicely
final = client.responses.create(
    model="gpt-5",
    input=msgs,
    tools=tools,
    instructions="Present the evaluated result clearly in natural language."
)

print("\n=== Final Output ===")
print(final.output_text)

Wie du sehen kannst, hat das Modell das Werkzeug ausgewählt und dann einen grammatikalisch korrekten Ausdruck generiert. Danach wird es durch die Python-Funktion geschickt, um die Antwort zu machen. Am Ende haben wir eine richtige Antwort in natürlicher Sprache.

=== Grammar-Constrained Expression ===
(12 + 8) * 3 - 5 / 5

=== Tool Execution Result ===
(12 + 8) * 3 - 5 / 5 = 59.0

=== Final Output ===
59

Tool-Zulassungslisten: Sicher einschränken, was das Modell nutzen kann

Mit der Einstellung „ allowed_tools “ kannst du das Modell auf eine sichere Auswahl von Werkzeugen aus deinem kompletten Werkzeugsatz beschränken. Das macht alles berechenbarer und verhindert, dass man aus Versehen Tools aufruft, während das Modell trotzdem flexibel innerhalb der erlaubten Grenzen bleibt. 

Du kannst das Modell zwischen erlaubten Tools wählen lassen oder es dazu zwingen, ein bestimmtes Tool zu verwenden, ähnlich wie bei „Force Tool“-Verhalten in anderen Stacks und im Einklang mit den allgemeinen Best Practices für die Orchestrierung von Tool-Aufrufen.

Jetzt schreiben wir den Code, mit dem wir ein einzelnes Tool zulassen, das Modell nur dieses Tool aufrufen lassen, es ausführen, die Ergebnisse zurückgeben und dann eine kurze, für den Benutzer verständliche Zusammenfassung erstellen.

Anmerkung: Mach dir doch einfach 'ne kostenlose Firecrawl-Konto -Konto an, mach dir einen API-Schlüssel, speicher ihn als Umgebungsvariable FIRECRAWL_API_KEY und installier das Firecrawl Python SDK über pip install firecrawl-py.

In diesem Beispielcode haben wir:

  1. Ein komplettes Toolset mit dummy_web_search und firecrawl_search definiert.
  2. Das Modell wurde nur über tool_choice = { type: "allowed_tools", mode: "required", tools: [...] } auf firecrawl_search beschränkt.
  3. Hab den ersten Modellaufruf gemacht, den Namen und die Argumente des Toolaufrufs gespeichert und sie zur besseren Übersicht ausgegeben.
  4. Wenn firecrawl_search “ aufgerufen wird, werden die Argumente deserialisiert, Firecrawl ausgeführt, die Antwort in ein JSON-serialisierbares Dict umgewandelt und die sicheren Daten extrahiert.
  5. Hab die Ergebnisse vom Tool über function_call_output, verlinkt über call_id, wieder in die Unterhaltung eingebracht und dann einen letzten Modellaufruf gemacht, um alles in 3–4 Stichpunkten mit Markdown-Links zusammenzufassen.
  6. Ich hab einen Fallback-Zweig eingebaut, der das Dummy-Tool ausführt (auch wenn die Zulassungsliste das in diesem Durchlauf verhindert).
  7. Die endgültige Antwort in natürlicher Sprache ausgedruckt.
from openai import OpenAI
from firecrawl import Firecrawl
import json
import os

client = OpenAI()
firecrawl = Firecrawl(api_key=os.environ["FIRECRAWL_API_KEY"])

# --- Full toolset ---
tools = [
    {
        "type": "function",
        "name": "dummy_web_search",
        "description": "A fake web search that always returns static dummy results.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "limit": {"type": "integer"}
            },
            "required": ["query"]
        },
    },
    {
        "type": "function",
        "name": "firecrawl_search",
        "description": "Perform a real web search using Firecrawl.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "limit": {"type": "integer"}
            },
            "required": ["query"]
        },
    },
]

# --- Dummy implementation ---
def dummy_web_search(query, limit=3):
    return {
        "query": query,
        "results": [f"[Dummy] Result {i+1} for '{query}'" for i in range(limit)]
    }

# --- User asks ---
messages = [
    {"role": "user", "content": "Find me the latest info about the stock market."}
]

# --- Restrict to Firecrawl only ---
resp = client.responses.create(
    model="gpt-5",
    tools=tools,
    input=messages,
    instructions="Only the firecrawl_search tool is allowed. Do not use dummy_web_search.",
    tool_choice={
        "type": "allowed_tools",
        "mode": "required",  # force Firecrawl
        "tools": [{"type": "function", "name": "firecrawl_search"}],
    },
)

for item in resp.output:
    if getattr(item, "type", "") in ("function_call", "tool_call"):
        print("\n--- Tool Call ---")
        print("Tool name:", item.name)
        print("Arguments:", item.arguments)

        if item.name == "firecrawl_search":
            args = json.loads(item.arguments)

            # Firecrawl returns a SearchData object → convert it
            results_obj = firecrawl.search(
                query=args["query"],
                limit=args.get("limit", 3),
            )

            # 🔥 Convert to JSON-serializable dict
            if hasattr(results_obj, "to_dict"):
                results = results_obj.to_dict()
            elif hasattr(results_obj, "dict"):
                results = results_obj.dict()
            else:
                results = json.loads(results_obj.json()) if hasattr(results_obj, "json") else results_obj

            print("\n--- Firecrawl Raw Results ---")
            print(json.dumps(results, indent=2)[:500])

            # ✅ Extract only the data portion for summarization
            safe_results = results.get("data", results)

            # Feed back to GPT
            messages += resp.output
            messages.append({
                "type": "function_call_output",
                "call_id": item.call_id,
                "output": json.dumps(safe_results)  # now safe
            })

            # Final pass
            final = client.responses.create(
                model="gpt-5",
                tools=tools,
                input=messages,
                instructions="Summarize the Firecrawl search results into 3-4 bullet points with clickable [Title](URL) links."
            )

            print("\n--- Final Natural Language Answer ---")
            print(final.output_text)

        elif item.name == "dummy_web_search":
            args = json.loads(item.arguments)
            results = dummy_web_search(args["query"], args.get("limit", 3))
            print("\n--- Dummy Web Search Results ---")
            print(json.dumps(results, indent=2))

Es hat die Firecrawl-Suche ausgewählt und damit die endgültige Antwort im Markdown-Format erstellt.

Präambeln: Sag dem Modell, wie es Tools aufrufen soll

Präambeln sind kurze Erklärungen, die das Modell vor dem Aufruf eines Tools generiert, um den Grund für den Aufruf zu erklären. Sie machen alles transparenter, schaffen Vertrauen bei den Nutzern und machen die Fehlerbehebung in komplizierten Arbeitsabläufen übersichtlicher. Du kannst sie mit einer einfachen Anweisung wie „vor dem Aufruf eines Tools erklären“ aktivieren, normalerweise ohne dass es zu einer merklichen Verzögerung kommt. 

Jetzt schreiben wir den Code, wo das Modell erst mal eine kurze „Preamble:“-Zeile macht, in der es erklärt, warum es ein Tool aufruft, dann das Tool aufruft, du es lokal ausführst, das Ergebnis zurücksendest und das Modell eine klare endgültige Antwort gibt.

In diesem Beispielcode haben wir:

  1. Ich hab den OpenAI-Client gestartet und ein streng typisiertes Funktionswerkzeug (medical_advice) mit JSON-Schema definiert.
  2. Ich hab 'ne Systemanweisung hinzugefügt, die dem Modell sagt, dass es vor jedem Tool-Aufruf 'ne einzeilige Meldung “Preamble:” ausgeben soll.
  3. Starte das Gespräch mit einer Frage zu den Symptomen des Nutzers.
  4. Hab den ersten Modellaufruf gemacht, um sowohl die Präambel als auch den Toolaufruf mit seinen Argumenten zu kriegen.
  5. Das Tool wurde lokal extrahiert und ausgeführt, um Empfehlungen zu generieren.
  6. Hab die Ausgabe des Tools wieder ins Modell zurückgeschickt, verbunden über call_id.
  7. Ich hab's mit dem finalen Modell probiert, damit GPT-5 das Ergebnis als knappe, benutzerfreundliche Antwort präsentiert.
from openai import OpenAI
import json
import random

client = OpenAI()

# --- Fake tool implementation ---
def medical_advice(symptom: str):
    remedies = {
        "headache": "You can take acetaminophen (paracetamol) or ibuprofen, rest in a quiet room, and stay hydrated.",
        "cough": "Drink warm fluids, use honey in tea, and consider over-the-counter cough syrup.",
        "fever": "Use acetaminophen to reduce fever, stay hydrated, and rest. See a doctor if >39°C.",
    }
    return {"advice": remedies.get(symptom.lower(), "Please consult a healthcare provider for guidance.")}

# --- Tool definition ---
tools = [{
    "type": "function",
    "name": "medical_advice",
    "description": "Provide safe, general over-the-counter advice for common symptoms.",
    "parameters": {
        "type": "object",
        "properties": {"symptom": {"type": "string"}},
        "required": ["symptom"],
        "additionalProperties": False
    },
    "strict": True,
}]

# --- Messages (system preamble instruction) ---
messages = [
    {"role": "system", "content": "Before you call a tool, explain why you are calling it in ONE short sentence prefixed with 'Preamble:'."},
    {"role": "user", "content": "What should I take for a headache?"}
]

# 1) First call: expect preamble + tool call
resp = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("=== First Response ===")
for item in resp.output:
    t = getattr(item, "type", None)
    if t == "message":
        # Extract just the model's text
        content = getattr(item, "content", None)
        text = None
        if isinstance(content, list):
            text = "".join([c.text for c in content if hasattr(c, "text")])
        elif content:
            text = str(content)
        if text:
            # ✅ Only print once
            print(text)
    if t in ("function_call", "tool_call", "custom_tool_call"):
        print("Tool:", getattr(item, "name", None))
        print("Args:", getattr(item, "arguments", None))

# Extract tool call
tool_call = next(x for x in resp.output if getattr(x, "type", None) in ("function_call","tool_call","custom_tool_call"))
messages += resp.output

# 2) Execute tool locally
args = json.loads(getattr(tool_call, "arguments", "{}"))
symptom = args.get("symptom", "")
tool_result = medical_advice(symptom)

# 3) Return tool result
messages.append({
    "type": "function_call_output",
    "call_id": tool_call.call_id,
    "output": json.dumps(tool_result)
})

# 4) Final model call → natural answer
final = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("\n=== Final Answer ===")
print(final.output_text)

Du siehst, dass vor dem Aufruf des Tools erklärt wird, warum es aufgerufen wird. Das ist super für die Beobachtbarkeit und das Debugging.

Zusammenfassung

GPT-5 ist das bisher fortschrittlichste Modell von OpenAI und ist besonders gut in Sachen Programmierung und agentenbasierte Arbeitsabläufe. Die neuesten API-Funktionen machen es einfach, von Anfang bis Ende produktionsreife Systeme zu entwickeln.

In diesem Tutorial hast du gelernt, wie du:

  1. Strukturierte Ausgaben zurückgeben mit Funktions-Tools und JSON-Schema für zuverlässige nachgelagerte Automatisierung.
  2. Aktiviere die freie Ausführung mit benutzerdefinierten Tools (Rohtext) zu ermöglichen, damit das Modell nicht nur JSON-Aufrufe, sondern auch Code, SQL, shell-Skripte und CSV-Dateien erstellen kann.
  3. Eingeschränkte Formate Verwendung von Lark-Grammatikbeschränkungen, wenn es auf Genauigkeit ankommt, wie zum Beispiel in der Mathematik, bei SQL oder in domänenspezifischen Sprachen (DSLs).
  4. Schränke den Zugriff auf Tools mit Zulassungslisten (oder indem man nur ein einziges Tool zulässt), um die Sicherheit, Kontrolle und Vorhersagbarkeit zu verbessern.
  5. Mach die Transparenz besser mit kurzen Einleitungen, damit das Modell erklärt, warum es ein bestimmtes Tool aufruft, was die Beobachtbarkeit und Fehlerbehebung erleichtert.

Um mehr darüber zu erfahren, was du mit den verschiedenen Tools von OpenAI machen kannst, empfehle ich dir, unseren OpenAI-Grundlagenkurs-Lernpfad und den Kurs „ Kurs „Arbeiten mit der OpenAI-API“zu besuchen.


Abid Ali Awan's photo
Author
Abid Ali Awan
LinkedIn
Twitter

Als zertifizierter Data Scientist ist es meine Leidenschaft, modernste Technologien zu nutzen, um innovative Machine Learning-Anwendungen zu entwickeln. Mit meinem fundierten Hintergrund in den Bereichen Spracherkennung, Datenanalyse und Reporting, MLOps, KI und NLP habe ich meine Fähigkeiten bei der Entwicklung intelligenter Systeme verfeinert, die wirklich etwas bewirken können. Neben meinem technischen Fachwissen bin ich auch ein geschickter Kommunikator mit dem Talent, komplexe Konzepte in eine klare und prägnante Sprache zu fassen. Das hat dazu geführt, dass ich ein gefragter Blogger zum Thema Datenwissenschaft geworden bin und meine Erkenntnisse und Erfahrungen mit einer wachsenden Gemeinschaft von Datenexperten teile. Zurzeit konzentriere ich mich auf die Erstellung und Bearbeitung von Inhalten und arbeite mit großen Sprachmodellen, um aussagekräftige und ansprechende Inhalte zu entwickeln, die sowohl Unternehmen als auch Privatpersonen helfen, das Beste aus ihren Daten zu machen.

Themen

Die besten DataCamp-Kurse

Lernpfad

OpenAI Grundlagen

0 Min.
Beginne mit der Erstellung von KI-Systemen mit Modellen von OpenAI. Lerne, wie du die OpenAI-API nutzt, um die GPT- und Whisper-Modelle von OpenAI aufzurufen.
Siehe DetailsRight Arrow
Kurs starten
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Top 30 Generative KI Interview Fragen und Antworten für 2024

Dieser Blog bietet eine umfassende Sammlung von Fragen und Antworten zu generativen KI-Interviews, die von grundlegenden Konzepten bis hin zu fortgeschrittenen Themen reichen.
Hesam Sheikh Hassani's photo

Hesam Sheikh Hassani

15 Min.

Der Blog

Arten von KI-Agenten: Ihre Rollen, Strukturen und Anwendungen verstehen

Lerne die wichtigsten Arten von KI-Agenten kennen, wie sie mit ihrer Umgebung interagieren und wie sie in verschiedenen Branchen eingesetzt werden. Verstehe einfache reflexive, modellbasierte, zielbasierte, nutzenbasierte, lernende Agenten und mehr.
Vinod Chugani's photo

Vinod Chugani

14 Min.

Lernprogramm

Python JSON-Daten: Ein Leitfaden mit Beispielen

Lerne, wie man mit JSON in Python arbeitet, einschließlich Serialisierung, Deserialisierung, Formatierung, Leistungsoptimierung, Umgang mit APIs und Verständnis der Einschränkungen und Alternativen von JSON.
Moez Ali's photo

Moez Ali

Lernprogramm

Python-Lambda-Funktionen: Ein Leitfaden für Anfänger

Lerne mehr über Python-Lambda-Funktionen, wozu sie gut sind und wann man sie benutzt. Enthält praktische Beispiele und bewährte Methoden für eine effektive Umsetzung.
Mark Pedigo's photo

Mark Pedigo

Lernprogramm

Python-Tutorial zum Verknüpfen von Zeichenfolgen

Lerne verschiedene Methoden zum Verknüpfen von Zeichenfolgen in Python kennen, mit Beispielen, die jede Technik zeigen.
DataCamp Team's photo

DataCamp Team

Lernprogramm

Python-Listenfunktionen und -Methoden – Tutorial und Beispiele

Lerne die Funktionen und Methoden von Python-Listen kennen. Schau dir jetzt die Code-Beispiele für list() und andere Python-Funktionen und -Methoden an!
Abid Ali Awan's photo

Abid Ali Awan

Mehr anzeigenMehr anzeigen