Udostępnij za pośrednictwem


Jak używać wywoływania funkcji z usługą Azure OpenAI Service (wersja zapoznawcza)

Najnowsze wersje gpt-35-turbo i gpt-4 są dostrojone do pracy z funkcjami i są w stanie określić, kiedy i jak należy wywołać funkcję. Jeśli co najmniej jedna funkcja jest uwzględniona w żądaniu, model określa, czy którakolwiek z funkcji powinna być wywoływana na podstawie kontekstu monitu. Gdy model ustali, że należy wywołać funkcję, odpowiada za pomocą obiektu JSON, w tym argumentów funkcji.

Modele formułują wywołania interfejsu API i strukturę danych wyjściowych, wszystkie na podstawie podanych funkcji. Należy pamiętać, że chociaż modele mogą generować te wywołania, wykonanie tych wywołań jest konieczne, dzięki czemu będziesz mieć kontrolę.

Na wysokim poziomie można podzielić pracę z funkcjami na trzy kroki:

  1. Wywoływanie interfejsu API uzupełniania czatów przy użyciu funkcji i danych wejściowych użytkownika
  2. Użyj odpowiedzi modelu, aby wywołać interfejs API lub funkcję
  3. Ponownie wywołaj interfejs API uzupełniania czatu, w tym odpowiedź z funkcji, aby uzyskać ostateczną odpowiedź

Ważne

Parametry functions i function_call zostały przestarzałe wraz z wydaniem 2023-12-01-preview wersji interfejsu API. Zamiana parametru functions tools to parametr . Zamiana parametru function_call tool_choice to parametr .

Obsługa wywoływania funkcji

Wywoływanie funkcji równoległej

  • 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 (2024-05-13)
  • gpt-4o-mini (2024-07-18)

Obsługa funkcji równoległej została po raz pierwszy dodana w wersji interfejsu API 2023-12-01-preview

Podstawowe wywoływanie funkcji za pomocą narzędzi

  • Wszystkie modele, które obsługują wywoływanie funkcji równoległych
  • gpt-4 (0613)
  • gpt-4-32k (0613)
  • gpt-35-turbo-16k (0613)
  • gpt-35-turbo (0613)

Przykład wywoływania pojedynczego narzędzia/funkcji

Najpierw przedstawimy proste wywołanie funkcji toy, które może sprawdzić czas w trzech zakodowanych na stałe lokalizacjach za pomocą zdefiniowanego jednego narzędzia/funkcji. Dodaliśmy instrukcje drukowania, aby ułatwić wykonywanie kodu:

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())

Wyjście:

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.

Jeśli używamy wdrożenia modelu obsługującego wywołania funkcji równoległych, możemy przekonwertować je na przykład wywołania funkcji równoległej, zmieniając tablicę komunikatów, aby poprosić o czas w wielu lokalizacjach zamiast jednego.

Aby to zrobić, zamień komentarze w tych dwóch wierszach:

    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

Aby wyglądać następująco, uruchom kod ponownie:

    #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

Spowoduje to wygenerowanie następujących danych wyjściowych:

Wyjście:

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

Wywołania funkcji równoległych umożliwiają jednoczesne wykonywanie wielu wywołań funkcji, co umożliwia równoległe wykonywanie i pobieranie wyników. Zmniejsza to liczbę wywołań interfejsu API, które należy wykonać i może poprawić ogólną wydajność.

Na przykład w naszej prostej aplikacji czasowej pobraliśmy wiele razy w tym samym czasie. Spowodowało to zakończenie czatu z trzema wywołaniami funkcji w tablicy tool_calls , z których każda ma unikatową wartość id. Jeśli chcesz odpowiedzieć na te wywołania funkcji, należy dodać do konwersacji trzy nowe wiadomości, z których każdy zawiera wynik jednego wywołania funkcji, z odwołaniem tool_call_id id z .tools_calls

Aby wymusić wywołanie określonej funkcji, ustaw tool_choice parametr z określoną nazwą funkcji. Możesz również wymusić wygenerowanie komunikatu użytkownika przez model, ustawiając wartość tool_choice: "none".

Uwaga

Domyślne zachowanie (tool_choice: "auto") dotyczy modelu samodzielnego decydowania, czy wywołać funkcję, a jeśli tak, która funkcja ma być wywoływana.

Równoległe wywoływanie funkcji z wieloma funkcjami

Teraz pokażemy kolejny przykład wywołania funkcji toy z dwoma różnymi narzędziami/funkcjami zdefiniowanymi.

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())

Wyjście

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?

Ważne

Odpowiedź JSON może nie zawsze być prawidłowa, dlatego należy dodać dodatkową logikę do kodu, aby móc obsługiwać błędy. W niektórych przypadkach użycia może być konieczne użycie dostrajania w celu zwiększenia wydajności wywoływania funkcji.

Monituj inżynierię za pomocą funkcji

Podczas definiowania funkcji w ramach żądania szczegóły są wstrzykiwane do komunikatu systemowego przy użyciu określonej składni, na której został wytrenowany model. Oznacza to, że funkcje używają tokenów w monicie i że można zastosować techniki inżynieryjne monitów w celu zoptymalizowania wydajności wywołań funkcji. Model używa pełnego kontekstu monitu, aby określić, czy należy wywołać funkcję, w tym definicję funkcji, komunikat systemowy i komunikaty użytkownika.

Poprawa jakości i niezawodności

Jeśli model nie wywołuje funkcji, gdy lub jak się spodziewasz, istnieje kilka rzeczy, które można spróbować poprawić jakość.

Podaj więcej szczegółów w definicji funkcji

Ważne jest, aby podać opis description funkcji i podać opisy dla dowolnego parametru, który może nie być oczywisty dla modelu. Na przykład w opisie parametru location można uwzględnić dodatkowe szczegóły i przykłady dotyczące formatu lokalizacji.

"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)"
},
Podaj więcej kontekstu w komunikacie systemowym

Komunikat systemowy może również służyć do zapewnienia większego kontekstu dla modelu. Jeśli na przykład masz funkcję o nazwie search_hotels , możesz dołączyć komunikat systemowy podobny do poniższego, aby poinstruować model o wywołanie funkcji, gdy użytkownik poprosi o pomoc w znalezieniu hotelu.

{"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."}
Poinstruuj model, aby zadawał wyjaśnienia pytań

W niektórych przypadkach chcesz poinstruować model o zadawaniu wyjaśnień pytań, aby zapobiec założeniu, jakie wartości mają być używane z funkcjami. Na przykład jeśli chcesz, search_hotels aby model poprosił o wyjaśnienie, czy żądanie użytkownika nie zawiera szczegółów dotyczących locationelementu . Aby poinstruować model, aby zadać wyjaśnienie pytania, możesz dołączyć zawartość podobną do następnego przykładu w komunikacie systemowym.

{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}

Zmniejszanie błędów

Innym obszarem, w którym może być cenna inżynieria monitu, jest zmniejszenie błędów w wywołaniach funkcji. Modele są trenowane w celu generowania wywołań funkcji pasujących do zdefiniowanego schematu, ale modele tworzą wywołanie funkcji, które nie jest zgodne ze zdefiniowanym schematem lub spróbuje wywołać funkcję, która nie została uwzględniona.

Jeśli okaże się, że model generuje wywołania funkcji, które nie zostały podane, spróbuj zastosować zdanie w komunikacie systemowym z informacją "Only use the functions you have been provided with.".

Odpowiedzialne wywoływanie funkcji

Podobnie jak w przypadku każdego systemu sztucznej inteligencji użycie wywołania funkcji w celu zintegrowania modeli językowych z innymi narzędziami i systemami stwarza potencjalne ryzyko. Ważne jest, aby zrozumieć czynniki ryzyka, które mogą przedstawiać wywołania funkcji i podejmować działania w celu zapewnienia odpowiedzialnego korzystania z możliwości.

Poniżej przedstawiono kilka wskazówek ułatwiających bezpieczne i bezpieczne korzystanie z funkcji:

  • Weryfikowanie wywołań funkcji: zawsze weryfikuj wywołania funkcji wygenerowane przez model. Obejmuje to sprawdzenie parametrów, wywoływanie funkcji i upewnienie się, że wywołanie jest zgodne z zamierzonym działaniem.
  • Użyj zaufanych danych i narzędzi: używaj tylko danych z zaufanych i zweryfikowanych źródeł. Niezaufane dane w danych wyjściowych funkcji mogą służyć do poinstruowania modelu, aby zapisywał wywołania funkcji w inny sposób niż zamierzone.
  • Postępuj zgodnie z zasadą najniższych uprawnień: przyznaj tylko minimalny dostęp niezbędny do wykonania zadania przez funkcję. Zmniejsza to potencjalny wpływ, jeśli funkcja jest nadużywana lub wykorzystywana. Jeśli na przykład używasz wywołań funkcji w celu wykonywania zapytań dotyczących bazy danych, musisz przyznać aplikacji dostęp tylko do odczytu do bazy danych. Nie należy również zależeć wyłącznie od wykluczania możliwości w definicji funkcji jako kontroli zabezpieczeń.
  • Rozważ rzeczywisty wpływ: należy pamiętać o rzeczywistym wpływie wywołań funkcji, które planujesz wykonać, zwłaszcza tych, które wyzwalają akcje, takie jak wykonywanie kodu, aktualizowanie baz danych lub wysyłanie powiadomień.
  • Implementowanie kroków potwierdzenia użytkownika: szczególnie w przypadku funkcji, które podejmują działania, zalecamy dołączenie kroku, w którym użytkownik potwierdzi akcję przed wykonaniem.

Aby dowiedzieć się więcej na temat naszych zaleceń dotyczących odpowiedzialnego używania modeli Usługi Azure OpenAI, zobacz Omówienie praktyk dotyczących odpowiedzialnego używania sztucznej inteligencji dla modeli azure OpenAI.

Następne kroki