Verwenden von Funktionsaufrufen mit Azure OpenAI Service (Vorschau)
Die neuesten Versionen von gpt-35-turbo und gpt-4 wurden für die Arbeit mit Funktionen optimiert und können bestimmen, wann und wie eine Funktion aufgerufen werden soll. Wenn eine oder mehrere Funktionen in Ihrer Anforderung enthalten sind, bestimmt das Modell basierend auf dem Kontext des Prompts, ob eine der Funktionen aufgerufen werden soll. Wenn das Modell bestimmt, dass eine Funktion aufgerufen werden soll, antwortet es mit einem JSON-Objekt, das die Argumente für die Funktion enthält.
Die Modelle formulieren API-Aufrufe und strukturieren Datenausgaben, die alle auf den von Ihnen angegebenen Funktionen basieren. Wichtig: Die Modelle können diese Aufrufe zwar generieren, aber es liegt an Ihnen, sie auszuführen. Auf diese Weise wird sichergestellt, dass Sie die Kontrolle behalten.
Im Allgemeinen kann die Arbeit mit Funktionen in drei Schritte unterteilt werden:
- Aufrufen der Chat Completions-API mit Ihren Funktionen und der Benutzereingabe
- Verwenden der Antwort des Modells zum Aufrufen Ihrer API oder Funktion
- Erneutes Aufrufen der Chat Completions-API, einschließlich der Antwort Ihrer Funktion, um eine endgültige Antwort zu erhalten
Wichtig
Die Parameter functions
und function_call
wurden mit der Veröffentlichung der Version 2023-12-01-preview
der API als veraltet markiert. Der Ersatz für functions
ist der Parameter tools
. Der Ersatz für function_call
ist der Parameter tool_choice
.
Unterstützung für Funktionsaufruf
Paralleler Funktionsaufruf
gpt-35-turbo
(1106)gpt-35-turbo
(0125)gpt-4
(1106-Vorschau)gpt-4
(0125-Preview)gpt-4
(vision-preview)gpt-4
(2024-04-09)gpt-4o
(2024-05-13)gpt-4o-mini
(2024-07-18)
Die Unterstützung für parallele Funktion wurde zuerst in der API-Version 2023-12-01-preview
hinzugefügt.
Grundlegende Funktionsaufrufe mit Tools
- Alle Modelle, die parallele Funktionsaufrufe unterstützen
gpt-4
(0613)gpt-4-32k
(0613)gpt-35-turbo-16k
(0613)gpt-35-turbo
(0613)
Beispiel für Einzeltool-/Funktionsaufrufe
Zunächst werden wir einen einfachen Funktionsaufruf demonstrieren, mit dem Sie die Zeit an drei fest kodierten Stellen mit einem einzigen definierten Tool/Funktion überprüfen können. Wir haben print-Anweisungen hinzugefügt, um die Ausführung des Codes leichter nachvollziehen zu können:
import os
import json
from openai import AzureOpenAI
from datetime import datetime
from zoneinfo import ZoneInfo
# Initialize the Azure OpenAI client
client = AzureOpenAI(
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version="2024-05-01-preview"
)
# Define the deployment you want to use for your chat completions API calls
deployment_name = "<YOUR_DEPLOYMENT_NAME_HERE>"
# Simplified timezone data
TIMEZONE_DATA = {
"tokyo": "Asia/Tokyo",
"san francisco": "America/Los_Angeles",
"paris": "Europe/Paris"
}
def get_current_time(location):
"""Get the current time for a given location"""
print(f"get_current_time called with location: {location}")
location_lower = location.lower()
for key, timezone in TIMEZONE_DATA.items():
if key in location_lower:
print(f"Timezone found for {key}")
current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
return json.dumps({
"location": location,
"current_time": current_time
})
print(f"No timezone data found for {location_lower}")
return json.dumps({"location": location, "current_time": "unknown"})
def run_conversation():
# Initial user message
messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
#messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
# Define the function for the model
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
},
"required": ["location"],
},
}
}
]
# First API call: Ask the model to use the function
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# Process the model's response
response_message = response.choices[0].message
messages.append(response_message)
print("Model's response:")
print(response_message)
# Handle function calls
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
if tool_call.function.name == "get_current_time":
function_args = json.loads(tool_call.function.arguments)
print(f"Function arguments: {function_args}")
time_response = get_current_time(
location=function_args.get("location")
)
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": "get_current_time",
"content": time_response,
})
else:
print("No tool calls were made by the model.")
# Second API call: Get the final response from the model
final_response = client.chat.completions.create(
model=deployment_name,
messages=messages,
)
return final_response.choices[0].message.content
# Run the conversation and print the result
print(run_conversation())
Ausgabe:
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
The current time in San Francisco is 09:24 AM.
Wenn wir eine Modellimplementierung verwenden, die parallele Funktionsaufrufe unterstützt, könnten wir dies in ein Beispiel für einen parallelen Funktionsaufruf umwandeln, indem wir das Nachrichten-Array so ändern, dass die Zeit an mehreren Stellen statt an einer abgefragt wird.
Um dies zu erreichen, tauschen Sie die Kommentare in diesen beiden Zeilen aus:
messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
#messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
Damit es so aussieht, und führen Sie den Code erneut aus:
#messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
Die folgende Ausgabe wird generiert:
Ausgabe:
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_IjcAVz9JOv5BXwUx1jd076C1', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_XIPQYTCtKIaNCCPTdvwjkaSN', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_OHIB5aJzO8HGqanmsdzfytvp', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
As of now, the current times are:
- **San Francisco:** 11:15 AM
- **Tokyo:** 03:15 AM (next day)
- **Paris:** 08:15 PM
Parallele Funktionsaufrufe ermöglichen es Ihnen, mehrere Funktionsaufrufe zusammen auszuführen, wodurch parallele Ausführung und Abruf von Ergebnissen ermöglicht werden. Dadurch wird die Anzahl der Aufrufe an die API reduziert, die ausgeführt werden müssen, und kann die Gesamtleistung verbessert werden.
In unserer einfachen Zeit-App haben wir zum Beispiel mehrere Zeiten gleichzeitig abgerufen. Das Ergebnis war eine Chat-Vervollständigungsnachricht mit drei Funktionsaufrufen im Array tool_calls
, jeder mit einem eindeutigen id
. Wenn Sie auf diese Funktionsaufrufe antworten möchten, fügen Sie der Unterhaltung drei neue Nachrichten hinzu, die jeweils das Ergebnis eines Funktionsaufrufs enthalten, wobei tool_call_id
auf id
von tools_calls
verweist.
Um zu erzwingen, dass das Modell eine bestimmte Funktion aufruft, legen Sie den Parameter tool_choice
mit einem bestimmten Funktionsnamen fest. Sie können auch erzwingen, dass das Modell eine Nachricht für Benutzer*innen generiert, indem Sie tool_choice: "none"
festlegen.
Hinweis
Das Standardverhalten (tool_choice: "auto"
) dient dazu, dass das Modell selbst entscheiden kann, ob eine Funktion und welche Funktion aufgerufen werden soll.
Paralleler Funktionsaufruf mit mehreren Funktionen
Jetzt werden wir ein weiteres Beispiel für einen Funktionsaufruf demonstrieren, diesmal mit zwei verschiedenen definierten Tools/Funktionen.
import os
import json
from openai import AzureOpenAI
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
# Initialize the Azure OpenAI client
client = AzureOpenAI(
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version="2024-05-01-preview"
)
# Provide the model deployment name you want to use for this example
deployment_name = "YOUR_DEPLOYMENT_NAME_HERE"
# Simplified weather data
WEATHER_DATA = {
"tokyo": {"temperature": "10", "unit": "celsius"},
"san francisco": {"temperature": "72", "unit": "fahrenheit"},
"paris": {"temperature": "22", "unit": "celsius"}
}
# Simplified timezone data
TIMEZONE_DATA = {
"tokyo": "Asia/Tokyo",
"san francisco": "America/Los_Angeles",
"paris": "Europe/Paris"
}
def get_current_weather(location, unit=None):
"""Get the current weather for a given location"""
print(f"get_current_weather called with location: {location}, unit: {unit}")
for key in WEATHER_DATA:
if key in location_lower:
print(f"Weather data found for {key}")
weather = WEATHER_DATA[key]
return json.dumps({
"location": location,
"temperature": weather["temperature"],
"unit": unit if unit else weather["unit"]
})
print(f"No weather data found for {location_lower}")
return json.dumps({"location": location, "temperature": "unknown"})
def get_current_time(location):
"""Get the current time for a given location"""
print(f"get_current_time called with location: {location}")
location_lower = location.lower()
for key, timezone in TIMEZONE_DATA.items():
if key in location_lower:
print(f"Timezone found for {key}")
current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
return json.dumps({
"location": location,
"current_time": current_time
})
print(f"No timezone data found for {location_lower}")
return json.dumps({"location": location, "current_time": "unknown"})
def run_conversation():
# Initial user message
messages = [{"role": "user", "content": "What's the weather and current time in San Francisco, Tokyo, and Paris?"}]
# Define the functions for the model
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
}
},
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
},
"required": ["location"],
},
}
}
]
# First API call: Ask the model to use the functions
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# Process the model's response
response_message = response.choices[0].message
messages.append(response_message)
print("Model's response:")
print(response_message)
# Handle function calls
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"Function call: {function_name}")
print(f"Function arguments: {function_args}")
if function_name == "get_current_weather":
function_response = get_current_weather(
location=function_args.get("location"),
unit=function_args.get("unit")
)
elif function_name == "get_current_time":
function_response = get_current_time(
location=function_args.get("location")
)
else:
function_response = json.dumps({"error": "Unknown function"})
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
})
else:
print("No tool calls were made by the model.")
# Second API call: Get the final response from the model
final_response = client.chat.completions.create(
model=deployment_name,
messages=messages,
)
return final_response.choices[0].message.content
# Run the conversation and print the result
print(run_conversation())
Output
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_djHAeQP0DFEVZ2qptrO0CYC4', function=Function(arguments='{"location": "San Francisco", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_q2f1HPKKUUj81yUa3ITLOZFs', function=Function(arguments='{"location": "Tokyo", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_6TEY5Imtr17PaB4UhWDaPxiX', function=Function(arguments='{"location": "Paris", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_vpzJ3jElpKZXA9abdbVMoauu', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_1ag0MCIsEjlwbpAqIXJbZcQj', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_ukOu3kfYOZR8lpxGRpdkhhdD', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function call: get_current_weather
Function arguments: {'location': 'San Francisco', 'unit': 'celsius'}
get_current_weather called with location: San Francisco, unit: celsius
Weather data found for san francisco
Function call: get_current_weather
Function arguments: {'location': 'Tokyo', 'unit': 'celsius'}
get_current_weather called with location: Tokyo, unit: celsius
Weather data found for tokyo
Function call: get_current_weather
Function arguments: {'location': 'Paris', 'unit': 'celsius'}
get_current_weather called with location: Paris, unit: celsius
Weather data found for paris
Function call: get_current_time
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function call: get_current_time
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function call: get_current_time
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
Here's the current information for the three cities:
### San Francisco
- **Time:** 09:13 AM
- **Weather:** 72°C (quite warm!)
### Tokyo
- **Time:** 01:13 AM (next day)
- **Weather:** 10°C
### Paris
- **Time:** 06:13 PM
- **Weather:** 22°C
Is there anything else you need?
Wichtig
Die JSON-Antwort ist möglicherweise nicht immer gültig, so dass Sie Ihrem Code eine zusätzliche Logik hinzufügen müssen, um Fehler behandeln zu können. In einigen Anwendungsfällen werden Sie feststellen, dass Sie eine Feinabstimmung vornehmen müssen, um die Leistung von Funktionsaufrufen zu verbessern.
Prompt Engineering mit Funktionen
Wenn Sie eine Funktion als Teil Ihrer Anforderung definieren, werden die Details mithilfe der spezifischen Syntax, für die das Modell trainiert wurde, in die Systemmeldung eingefügt. Das bedeutet, dass Funktionen Token in Ihrem Prompt nutzen und Sie Prompt-Engineering-Techniken anwenden können, um die Leistung Ihrer Funktionsaufrufe zu optimieren. Das Modell verwendet den vollständigen Kontext des Prompts, um zu bestimmen, ob eine Funktion aufgerufen werden soll, einschließlich der Funktionsdefinition, der Systemmeldung und der Benutzermeldungen.
Verbesserung von Qualität und Zuverlässigkeit
Wenn das Modell Ihre Funktion nicht wann oder wie erwartet aufruft, können Sie versuchen, die Qualität zu verbessern.
Angeben weiterer Details in der Funktionsdefinition
Es ist wichtig, einen aussagekräftigen description
-Wert für die Funktion und Beschreibungen für jeden Parameter anzugeben, der für das Modell möglicherweise nicht offensichtlich ist. Beispielsweise können Sie in der Beschreibung für den location
-Parameter zusätzliche Details und Beispiele für das Format des Speicherorts angeben.
"location": {
"type": "string",
"description": "The location of the hotel. The location should include the city and the state's abbreviation (i.e. Seattle, WA or Miami, FL)"
},
Angeben von mehr Kontext in der Systemmeldung
Die Systemmeldung kann auch verwendet werden, um mehr Kontext für das Modell bereitzustellen. Wenn Sie beispielsweise über eine Funktion mit dem Namen search_hotels
verfügen, können Sie eine Systemmeldung wie die folgende einschließen, um das Modell anzuweisen, die Funktion aufzurufen, wenn ein*e Benutzer*in um Hilfe bei der Suche nach einem Hotel bittet.
{"role": "system", "content": "You're an AI assistant designed to help users search for hotels. When a user asks for help finding a hotel, you should call the search_hotels function."}
Anweisen des Modells, klärende Fragen zu stellen
In einigen Fällen sollten Sie das Modell ggf. anweisen, klärende Fragen zu stellen, um zu verhindern, dass es Annahmen darüber trifft, welche Werte für Funktionen zu verwenden sind. Sie könnten das Modell bei search_hotels
beispielsweise anweisen, um Klärung zu bitten, wenn die Benutzeranforderung keine Details zu location
enthält. Um das Modell anzuweisen, eine klärende Frage zu stellen, können Sie Inhalte wie im folgenden Beispiel in Ihre Systemmeldung aufnehmen.
{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}
Reduzieren von Fehlern
Ein weiterer Bereich, in dem das Prompt Engineering nützlich sein kann, ist die Reduzierung von Fehlern bei Funktionsaufrufen. Die Modelle werden trainiert, um Funktionsaufrufe zu generieren, die dem von Ihnen definierten Schema entsprechen. Sie erzeugen jedoch einen Funktionsaufruf, der nicht mit dem von Ihnen definierten Schema übereinstimmt, oder versuchen, eine Funktion aufzurufen, die Sie nicht eingeschlossen haben.
Wenn Sie feststellen, dass das Modell Funktionsaufrufe generiert, die nicht vorgesehen wurden, versuchen Sie, einen Satz wie "Only use the functions you have been provided with."
in die Systemmeldung aufzunehmen.
Verantwortungsvolles Verwenden von Funktionsaufrufen
Wie bei jedem KI-System birgt die Verwendung von Funktionsaufrufen zur Integration von Sprachmodellen in andere Tools und Systeme potenzielle Risiken. Es ist wichtig, die Risiken zu verstehen, die Funktionsaufrufe darstellen können, und Maßnahmen zu ergreifen, um sicherzugehen, dass die Funktionen verantwortungsvoll genutzt werden.
Hier sind einige Tipps, die Ihnen dabei helfen, Funktionen sicher zu verwenden:
- Überprüfen von Funktionsaufrufen: Überprüfen Sie immer die vom Modell generierten Funktionsaufrufe. Dazu zählt das Überprüfen der Parameter und der aufgerufenen Funktion. Außerdem müssen Sie sich vergewissern, dass der Aufruf der beabsichtigten Aktion entspricht.
- Verwenden von vertrauenswürdigen Daten und Tools: Verwenden Sie nur Daten aus vertrauenswürdigen und verifizierten Quellen. Nicht vertrauenswürdige Daten in der Ausgabe einer Funktion können verwendet werden, um das Modell anzuweisen, Funktionsaufrufe auf nicht beabsichtigte Weise zu schreiben.
- Anwenden des Prinzips der geringsten Rechte: Gewähren Sie nur den mindestens erforderlichen Zugriff, den die Funktion benötigt, um ihre Aufgabe zu erfüllen. Dadurch sind die potenziellen Auswirkungen weniger schwerwiegend, wenn eine Funktion missbraucht oder ausgenutzt wird. Wenn Sie beispielsweise Funktionsaufrufe zum Abfragen einer Datenbank verwenden, sollten Sie Ihrer Anwendung nur schreibgeschützten Zugriff auf die Datenbank gewähren. Funktionen in der Funktionsdefinition auszuschließen sollte nicht Ihre einzige Sicherheitsmaßnahme sein.
- Berücksichtigen der realen Auswirkungen: Beachten Sie die realen Auswirkungen von Funktionsaufrufen, die Sie ausführen möchten, insbesondere solche, die Aktionen auslösen, z. B. das Ausführen von Code, das Aktualisieren von Datenbanken oder das Senden von Benachrichtigungen.
- Implementieren von Benutzerbestätigungsschritten: Insbesondere für Funktionen, die Aktionen ausführen, wird empfohlen, einen Schritt aufzunehmen, in dem Benutzer*innen die Aktion bestätigen müssen, bevor sie ausgeführt wird.
Weitere Informationen zu unseren Empfehlungen zur verantwortungsvollen Verwendung von Azure OpenAI-Modellen finden Sie unter Übersicht über Methoden der verantwortungsbewussten KI-Anwendung für Azure OpenAI-Modelle.
Nächste Schritte
- Weitere Informationen zu Azure OpenAI.
- Weitere Beispiele zur Arbeit mit Funktionen finden Sie im GitHub-Repository für Azure OpenAI-Beispiele.
- Erste Schritte mit dem GPT-35-Turbo-Modell mit dem GPT-35-Turbo-Schnellstart.