Dela via


Använda funktionsanrop med Azure OpenAI Service (förhandsversion)

De senaste versionerna av gpt-35-turbo och gpt-4 är finjusterade för att fungera med funktioner och kan både avgöra när och hur en funktion ska anropas. Om en eller flera funktioner ingår i din begäran avgör modellen om någon av funktionerna ska anropas baserat på promptens kontext. När modellen fastställer att en funktion ska anropas svarar den med ett JSON-objekt, inklusive argumenten för funktionen.

Modellerna formulerar API-anrop och strukturerar datautdata, allt baserat på de funktioner du anger. Det är viktigt att observera att även om modellerna kan generera dessa anrop är det upp till dig att köra dem, vilket säkerställer att du har kontroll.

På hög nivå kan du dela upp arbetet med funktioner i tre steg:

  1. Anropa API:et för chattens slutförande med dina funktioner och användarens indata
  2. Använd modellens svar för att anropa ditt API eller din funktion
  3. Anropa API:et för chattens slutförande igen, inklusive svaret från din funktion för att få ett slutligt svar

Viktigt!

Parametrarna functions och function_call har inaktuella med versionen av API: 2023-12-01-preview ets version. Ersättningen för functions är parametern tools . Ersättningen för function_call är parametern tool_choice .

Stöd för funktionssamtal

Parallell funktionsanrop

  • gpt-35-turbo (1106)
  • gpt-35-turbo (0125)
  • gpt-4 (1106-förhandsversion)
  • gpt-4 (0125-Preview)
  • gpt-4 (vision-preview)
  • gpt-4 (2024-04-09)
  • gpt-4o (2024-05-13)
  • gpt-4o-mini (2024-07-18)

Stöd för parallell funktion lades först till i API-version 2023-12-01-preview

Grundläggande funktionsanrop med verktyg

  • Alla modeller som stöder parallella funktionsanrop
  • gpt-4 (0613)
  • gpt-4-32k (0613)
  • gpt-35-turbo-16k (0613)
  • gpt-35-turbo (0613)

Exempel på enstaka verktyg/funktionsanrop

Först ska vi demonstrera ett enkelt leksaksfunktionsanrop som kan kontrollera tiden på tre hårdkodade platser med ett enda verktyg/en definierad funktion. Vi har lagt till utskriftsuttryck för att göra kodkörningen enklare att följa:

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

Utdata:

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.

Om vi använder en modelldistribution som stöder parallella funktionsanrop kan vi konvertera detta till ett exempel på parallella funktionsanrop genom att ändra meddelandematrisen så att den frågar efter tiden på flera platser i stället för en.

För att åstadkomma detta växlar du kommentarerna på dessa två rader:

    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

Så här ser du ut och kör koden igen:

    #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

Detta genererar följande utdata:

Utdata:

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

Med parallella funktionsanrop kan du utföra flera funktionsanrop tillsammans, vilket möjliggör parallell körning och hämtning av resultat. Detta minskar antalet anrop till API:et som behöver göras och kan förbättra den övergripande prestandan.

I vår enkla tidsapp hämtade vi till exempel flera gånger samtidigt. Detta resulterade i ett meddelande om chattens slutförande med tre funktionsanrop i matrisen tool_calls , var och en med en unik id. Om du vill svara på dessa funktionsanrop lägger du till tre nya meddelanden i konversationen, var och en innehåller resultatet av ett funktionsanrop, med en tool_call_id referens id från tools_calls.

Om du vill tvinga modellen att anropa en specifik funktion anger du parametern tool_choice med ett specifikt funktionsnamn. Du kan också tvinga modellen att generera ett användaranslutet meddelande genom att ange tool_choice: "none".

Kommentar

Standardbeteendet (tool_choice: "auto") är att modellen på egen hand bestämmer om en funktion ska anropas och i så sätt vilken funktion som ska anropas.

Parallell funktionsanrop med flera funktioner

Nu ska vi demonstrera ett annat exempel på leksaksfunktionen som anropar den här gången med två olika verktyg/funktioner definierade.

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?

Viktigt!

JSON-svaret kanske inte alltid är giltigt, så du måste lägga till ytterligare logik i koden för att kunna hantera fel. För vissa användningsfall kan du behöva använda finjustering för att förbättra prestanda för funktionsanrop.

Fråga efter teknik med funktioner

När du definierar en funktion som en del av din begäran matas informationen in i systemmeddelandet med hjälp av specifik syntax som modellen har tränats på. Det innebär att funktioner använder token i prompten och att du kan använda teknik för att optimera prestanda för dina funktionsanrop. Modellen använder den fullständiga kontexten för prompten för att avgöra om en funktion ska anropas, inklusive funktionsdefinition, systemmeddelande och användarmeddelanden.

Förbättra kvalitet och tillförlitlighet

Om modellen inte anropar din funktion när eller hur du förväntar dig finns det några saker du kan försöka förbättra kvaliteten på.

Ange mer information i funktionsdefinitionen

Det är viktigt att du anger en meningsfull description funktion och anger beskrivningar för alla parametrar som kanske inte är uppenbara för modellen. I beskrivningen för parametern location kan du till exempel inkludera extra information och exempel på platsens format.

"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)"
},
Ange mer kontext i systemmeddelandet

Systemmeddelandet kan också användas för att ge modellen mer kontext. Om du till exempel har en funktion med namnet search_hotels kan du inkludera ett systemmeddelande som följande för att instruera modellen att anropa funktionen när en användare ber om hjälp med att hitta ett hotell.

{"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."}
Instruera modellen att ställa klargörande frågor

I vissa fall vill du instruera modellen att ställa klargörande frågor för att förhindra antaganden om vilka värden som ska användas med funktioner. Du vill till exempel search_hotels att modellen ska be om förtydligande om användarbegäran inte innehåller information om location. Om du vill instruera modellen att ställa en klargörande fråga kan du inkludera innehåll som nästa exempel i systemmeddelandet.

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

Minska fel

Ett annat område där promptteknik kan vara värdefull är att minska felen i funktionsanrop. Modellerna tränas att generera funktionsanrop som matchar det schema som du definierar, men modellerna skapar ett funktionsanrop som inte matchar schemat du definierade eller försöker anropa en funktion som du inte tog med.

Om du upptäcker att modellen genererar funktionsanrop som inte har angetts kan du prova att inkludera en mening i systemmeddelandet som säger "Only use the functions you have been provided with.".

Använda funktionsanrop på ett ansvarsfullt sätt

Precis som alla AI-system innebär användning av funktionsanrop för att integrera språkmodeller med andra verktyg och system potentiella risker. Det är viktigt att förstå de risker som funktionsanrop kan medföra och vidta åtgärder för att säkerställa att du använder funktionerna på ett ansvarsfullt sätt.

Här följer några tips som hjälper dig att använda funktioner på ett säkert och säkert sätt:

  • Verifiera funktionsanrop: Verifiera alltid de funktionsanrop som genereras av modellen. Detta inkluderar att kontrollera parametrarna, funktionen som anropas och se till att anropet överensstämmer med den avsedda åtgärden.
  • Använd betrodda data och verktyg: Använd endast data från betrodda och verifierade källor. Ej betrodda data i en funktions utdata kan användas för att instruera modellen att skriva funktionsanrop på ett annat sätt än du avsåg.
  • Följ principen för minsta behörighet: Bevilja endast den minsta åtkomst som krävs för att funktionen ska kunna utföra sitt jobb. Detta minskar den potentiella effekten om en funktion missbrukas eller utnyttjas. Om du till exempel använder funktionsanrop för att fråga en databas bör du bara ge programmet skrivskyddad åtkomst till databasen. Du bör inte heller enbart vara beroende av att exkludera funktioner i funktionsdefinitionen som en säkerhetskontroll.
  • Överväg verklig påverkan: Var medveten om den verkliga effekten av funktionsanrop som du planerar att köra, särskilt de som utlöser åtgärder som att köra kod, uppdatera databaser eller skicka meddelanden.
  • Implementera steg för användarbekräftelse: Särskilt för funktioner som vidtar åtgärder rekommenderar vi att du inkluderar ett steg där användaren bekräftar åtgärden innan den körs.

Mer information om våra rekommendationer om hur du använder Azure OpenAI-modeller på ett ansvarsfullt sätt finns i Översikt över ansvarsfulla AI-metoder för Azure OpenAI-modeller.

Nästa steg