Cómo utilizar la llamada a funciones con Azure OpenAI Service (versión preliminar)
Las versiones más recientes de gpt-35-turbo y gpt-4 se han ajustado para trabajar con funciones y pueden determinar cuándo y cómo se debe llamar a una función. Si una o varias funciones se incluyen en la solicitud, el modelo determina si se debe llamar a alguna de las funciones en función del contexto del símbolo del sistema. Cuando el modelo determina que se debe llamar a una función, responde con un objeto JSON que incluye los argumentos de la función.
Los modelos formulan llamadas API y salidas de datos de estructura, todas basadas en las funciones que especifique. Es importante señalar que, aunque los modelos pueden generar estas llamadas, depende de usted ejecutarlas, lo que le garantiza que mantiene el control.
En general, el trabajo con funciones puede dividirse en tres pasos:
- Llamar a la API de finalización de chat con sus funciones y la entrada del usuario
- Uso de la respuesta del modelo para llamar a la API o función
- Vuelva a llamar a la API de finalizaciones de chat, incluida la respuesta de la función para obtener una respuesta final
Importante
Los parámetros functions
y function_call
han quedado en desuso con la versión de 2023-12-01-preview
de la API. El reemplazo de functions
es el parámetro tools
. El reemplazo de function_call
es el parámetro tool_choice
.
Compatibilidad con la llamada de funciones
Llamada a funciones paralelas
gpt-35-turbo
(1106)gpt-35-turbo
(0125)gpt-4
(1106-Preview)gpt-4
(0125-Preview)gpt-4
(vision-preview)gpt-4
(2024-04-09)gpt-4o
(13/05/2024)gpt-4o-mini
(18-07-2024)
La compatibilidad con la función en paralelo se agregó por primera vez en la versión de API 2023-12-01-preview
Llamada a funciones básicas con herramientas
- Todos los modelos que admiten llamadas a funciones paralelas
gpt-4
(0613)gpt-4-32k
(0613)gpt-35-turbo-16k
(0613)gpt-35-turbo
(0613)
Ejemplo de llamada a una sola herramienta o función
En primer lugar, mostraremos una llamada de función de prueba sencilla que puede comprobar la hora en tres ubicaciones codificadas de forma codificada con una sola herramienta o función definida. Hemos agregado instrucciones de impresión para ayudar a que la ejecución del código sea más fácil de seguir:
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())
Salida:
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.
Si usamos una implementación de modelos que admite llamadas a funciones paralelas, podríamos convertirla en un ejemplo de llamada de función paralela cambiando la matriz de mensajes para solicitar la hora en varias ubicaciones en lugar de una.
Para ello, cambie los comentarios de estas dos líneas:
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
Para que tenga este aspecto, y vuelva a ejecutar el código:
#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
Esto genera la siguiente salida:
Salida:
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
Las llamadas de función paralelas permiten realizar varias llamadas de función a la vez, lo que permite la ejecución en paralelo y la recuperación de resultados. Esto reduce el número de llamadas a la API que se deben realizar y puede mejorar el rendimiento general.
Por ejemplo, en nuestra aplicación de período simple recuperamos varias veces al mismo tiempo. Esto dio lugar a un mensaje de finalización del chat con tres llamadas de función en la matriz tool_calls
, cada una con un id
único. Si desea responder a estas llamadas de función, debe agregar tres nuevos mensajes a la conversación, cada uno con el resultado de una llamada de función, con un tool_call_id
que haga referencia al id
de tools_calls
.
Para hacer que el modelo llame a una función específica, establezca el parámetro tool_choice
con un nombre de función específico. También puede hacer que el modelo genere un mensaje orientado al usuario mediante el establecimiento de tool_choice: "none"
.
Nota:
El comportamiento predeterminado (tool_choice: "auto"
) es para que el modelo decida por sí mismo si va a llamar a una función y, en caso afirmativo, a qué función va a llamar.
Llamada a funciones paralelas con varias funciones
Ahora mostraremos otro ejemplo de función de prueba que llama a este tiempo con dos herramientas o funciones diferentes definidas.
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())
Salida
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?
Importante
Es posible que la respuesta JSON no siempre sea válida, por lo que debe agregar lógica adicional al código para poder controlar los errores. En algunos casos de uso, es posible que tenga que usar el ajuste preciso para mejorar el rendimiento de las llamadas a funciones.
Ingeniería de mensajes con funciones
Cuando se define una función como parte de la solicitud, los detalles se insertan en el mensaje del sistema mediante una sintaxis específica para la que se ha entrenado el modelo. Esto significa que las funciones consumen tokens en su solicitud y que puede aplicar técnicas de ingeniería de solicitud para optimizar el rendimiento de sus llamadas a funciones. El modelo usa el contexto completo de la solicitud para determinar si se debe llamar a una función, incluida la definición de función, el mensaje del sistema y los mensajes de usuario.
Mejora de la calidad y confiabilidad
Si el modelo no llama a su función cuando o como usted espera, hay algunas cosas que puede intentar para mejorar la calidad.
Proporcione más detalles en la definición de la función
Es importante que proporcione un significado description
de la función y proporcione descripciones para cualquier parámetro que no sea obvio para el modelo. Por ejemplo, en la descripción del parámetro location
, podría incluir detalles adicionales y ejemplos sobre el formato de la ubicación.
"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)"
},
Proporcionar más contexto en el mensaje del sistema
El mensaje del sistema también se puede usar para proporcionar más contexto al modelo. Por ejemplo, si tiene una función llamada search_hotels
podría incluir un mensaje de sistema como el siguiente para indicar al modelo que llame a la función cuando un usuario pida ayuda para encontrar un hotel.
{"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."}
Indicar al modelo que haga preguntas aclarando
En algunos casos, conviene indicar al modelo que haga preguntas aclaratorias y evitar que se hagan suposiciones sobre qué valores usar con las funciones. Por ejemplo, con usted search_hotels
querría que el modelo pidiera aclaraciones si la solicitud del usuario no incluyera detalles sobre location
. Para indicar al modelo que formule una pregunta aclaratoria, puede incluir en el mensaje del sistema un contenido como el siguiente.
{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}
Reducción de errores
Otra área en la que la ingeniería de solicitudes puede ser valiosa es reducir los errores en las llamadas de función. Se ha entrenado a los modelos para generar llamadas a funciones que coincidan con el esquema que usted defina, pero los modelos pueden producir una llamada a una función que no coincida con el esquema que usted definió o pueden intentar llamar a una función que usted no incluyó.
Si encuentra que el modelo está generando llamadas de función que no se proporcionaron, intente incluir una oración en el mensaje del sistema que indica "Only use the functions you have been provided with."
.
Uso de llamadas de función de forma responsable
Al igual que cualquier sistema de inteligencia artificial, el uso de llamadas de funciones para integrar modelos de lenguaje con otras herramientas y sistemas presenta posibles riesgos. Es importante comprender los riesgos que podrían presentar las llamadas a funciones y tomar medidas para asegurarse de que usa las funcionalidades de forma responsable.
Aquí tiene algunos consejos que le ayudarán a utilizar las funciones de forma segura:
- Validar llamadas de función: compruebe siempre las llamadas de función generadas por el modelo. Esto incluye comprobar los parámetros, la función a la que se llama y asegurarse de que la llamada se alinea con la acción prevista.
- Usar herramientas y datos de confianza: use solo datos de orígenes de confianza y comprobados. Los datos que no son de confianza en la salida de una función se pueden usar para indicar al modelo que escriba llamadas de función de una manera distinta a la prevista.
- Siga el principio de privilegios mínimos: conceda solo el acceso mínimo necesario para que la función realice su trabajo. Esto reduce el impacto potencial si una función se usa o se aprovecha de forma incorrecta. Por ejemplo, si usa llamadas de función para consultar una base de datos, solo debe conceder a la aplicación acceso de solo lectura a la base de datos. Tampoco debe depender únicamente de la exclusión de funcionalidades en la definición de función como control de seguridad.
- Considere el impacto en el mundo real: sea consciente del impacto en el mundo real de las llamadas a funciones que planea ejecutar, especialmente aquellas que desencadenan acciones como la ejecución de código, la actualización de bases de datos o el envío de notificaciones.
- Implementar pasos de confirmación de usuario: especialmente para las funciones que realizan acciones, se recomienda incluir un paso en el que el usuario confirme la acción antes de que se ejecute.
Para obtener más información acerca de nuestras recomendaciones sobre cómo utilizar los modelos de Azure OpenAI de forma responsable, consulte la Descripción general de las prácticas de IA responsable para los modelos de Azure OpenAI.
Pasos siguientes
- Obtenga información sobre Azure OpenAI.
- Para más ejemplos sobre cómo trabajar con funciones, consulta el repositorio GitHub de muestras de Azure OpenAI
- Comience a trabajar con el modelo GPT-35-Turbo con elInicio rápido de GPT-35-Turbo.