Cara menggunakan panggilan fungsi dengan model Microsoft Foundry

Catatan

Contoh ini menggunakan API Chat Completions yang kompatibel dengan OpenAI melalui endpoint Foundry Models. Panggilan fungsi melalui API Respons menggunakan format permintaan dan respons yang berbeda. Untuk informasi selengkapnya, lihat Menggunakan Api Respons Azure OpenAI.

Jika Anda menyertakan satu atau beberapa fungsi dalam permintaan Anda, model memutuskan apakah akan memanggil salah satu fungsi berdasarkan konteks prompt. Ketika model memutuskan untuk memanggil fungsi, model merespons dengan objek JSON yang menyertakan argumen untuk fungsi tersebut.

Model menghasilkan panggilan fungsi dan argumen terstruktur berdasarkan fungsi yang Anda tentukan. Aplikasi Anda menjalankan fungsi dan mengembalikan hasilnya ke model, sehingga Anda tetap mengontrol tindakan yang diambil.

Secara garis besar, Anda dapat memecah pekerjaan dengan fungsi menjadi tiga langkah:

  1. Panggil API penyelesaian obrolan dengan fungsi Anda dan input pengguna
  2. Gunakan respons model untuk memanggil API atau fungsi Anda
  3. Panggil API penyelesaian obrolan lagi, termasuk respons dari fungsi Anda untuk mendapatkan respons akhir

Prasyarat

  • Deploymen model Foundry yang mendukung pemanggilan fungsi melalui Chat Completions API.
  • Titik akhir sumber daya Foundry dalam format https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/.
  • Untuk autentikasi Microsoft Entra ID:
    • Subdomain kustom telah dikonfigurasi. Untuk informasi selengkapnya, lihat Nama subdomain kustom.
    • Paket: pip install openai azure-identity.

Contoh panggilan alat/fungsi tunggal

Contoh ini menunjukkan panggilan fungsi mainan yang memeriksa waktu di tiga lokasi yang dikodekan secara permanen dengan satu alat/fungsi yang ditentukan. Pernyataan cetak membuat eksekusi kode lebih mudah diikuti:

import os
import json
from openai import OpenAI
from datetime import datetime
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)

client = OpenAI(  
  base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",  
  api_key=token_provider,
)

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

Output:

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.

Jika kita menggunakan penyebaran model yang mendukung panggilan fungsi paralel, kita dapat mengonversi ini menjadi contoh panggilan fungsi paralel dengan mengubah array pesan untuk meminta waktu di beberapa lokasi, bukan satu.

Untuk mencapai hal ini, tukar komentar di dua baris ini:

    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

Agar tampak seperti ini, kemudian jalankan kode lagi.

    #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

Ini menghasilkan output berikut:

Output:

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

Panggilan fungsi paralel memungkinkan Anda melakukan beberapa panggilan fungsi bersama-sama, memungkinkan eksekusi paralel dan pengambilan hasil. Ini mengurangi jumlah panggilan ke API yang perlu dilakukan dan dapat meningkatkan performa keseluruhan.

Misalnya dalam aplikasi waktu sederhana kami, kami mengambil beberapa kali secara bersamaan. Ini menghasilkan pesan penyelesaian obrolan dengan tiga panggilan fungsi dalam tool_calls array, masing-masing dengan yang unik id. Jika Anda ingin menanggapi panggilan fungsi ini, Anda akan menambahkan tiga pesan baru ke percakapan, masing-masing berisi hasil satu panggilan fungsi, dengan tool_call_id mereferensikan id dari tool_calls.

Untuk memaksa model memanggil fungsi tertentu, atur tool_choice ke objek alat bernama, misalnya: tool_choice={"type": "function", "function": {"name": "get_current_time"}}. Untuk memunculkan pesan kepada pengguna, atur tool_choice="none".

Catatan

Perilaku default (tool_choice: "auto") adalah agar model memutuskan sendiri jika harus memanggil fungsi dan jika demikian fungsi mana yang akan dipanggil.

Panggilan fungsi paralel menggunakan beberapa fungsi

Sekarang kita menunjukkan contoh pemanggilan fungsi mainan lain kali ini dengan dua alat/fungsi berbeda yang ditentukan.

import os
import json
from openai import OpenAI
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)

client = OpenAI(  
  base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",  
  api_key=token_provider,
)

# 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"""
    location_lower = location.lower()
    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?

Penting

Respons JSON mungkin tidak selalu valid sehingga Anda perlu menambahkan logika tambahan ke kode Anda untuk dapat menangani kesalahan. Untuk beberapa kasus penggunaan, Anda mungkin perlu menggunakan penyesuaian lanjutan untuk meningkatkan performa panggilan fungsi.

Rekayasa pengarahan menggunakan fungsi

Saat Anda mendefinisikan fungsi sebagai bagian dari permintaan Anda, detail tersebut disuntikkan ke dalam pesan sistem menggunakan sintaks tertentu yang sudah dipelajari oleh model. Ini berarti bahwa fungsi mengkonsumsi token dalam prompt Anda dan Anda dapat menerapkan teknik rekayasa prompt untuk mengoptimalkan kinerja panggilan fungsi Anda. Model menggunakan konteks lengkap perintah untuk menentukan apakah fungsi harus dipanggil termasuk definisi fungsi, pesan sistem, dan pesan pengguna.

Meningkatkan kualitas dan keandalan

Jika model tidak memanggil fungsi Anda kapan atau seperti yang Anda harapkan, ada beberapa hal yang dapat Anda coba untuk meningkatkan kualitas.

Berikan detail selengkapnya dalam definisi fungsi Anda

Penting bagi Anda untuk memberikan fungsi yang bermakna description dan memberikan deskripsi untuk parameter apa pun yang mungkin tidak jelas untuk model. Misalnya, dalam deskripsi untuk location parameter , Anda dapat menyertakan detail dan contoh tambahan pada format lokasi.

"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)"
},
Berikan konteks lainnya dalam pesan sistem

Pesan sistem juga dapat digunakan untuk memberikan lebih banyak konteks ke model. Misalnya, jika Anda memiliki fungsi yang disebut search_hotels , Anda dapat menyertakan pesan sistem seperti berikut untuk menginstruksikan model untuk memanggil fungsi ketika pengguna meminta bantuan untuk menemukan 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."}
Menginstruksikan model untuk mengajukan pertanyaan klarifikasi

Dalam beberapa kasus, Anda ingin menginstruksikan model untuk mengajukan pertanyaan klarifikasi untuk mencegah pembuatan asumsi tentang nilai apa yang akan digunakan dengan fungsi. Misalnya, dengan search_hotels Anda ingin model meminta klarifikasi jika permintaan pengguna tidak menyertakan detail tentang location. Untuk menginstruksikan model untuk mengajukan pertanyaan klarifikasi, Anda dapat menyertakan konten seperti contoh berikutnya dalam pesan sistem Anda.

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

Mengurangi kesalahan

Area lain di mana rekayasa prompt bisa berharga adalah mengurangi kesalahan dalam panggilan fungsi. Model dilatih untuk menghasilkan panggilan fungsi yang cocok dengan skema yang Anda tentukan, tetapi model menghasilkan panggilan fungsi yang tidak cocok dengan skema yang Anda tentukan atau mencoba memanggil fungsi yang tidak Anda sertakan.

Jika Anda menemukan model menghasilkan panggilan fungsi yang tidak disediakan, coba masukkan kalimat dalam pesan sistem yang mengatakan "Only use the functions you have been provided with.".

Menggunakan panggilan fungsi secara bertanggung jawab

Seperti sistem AI apa pun, menggunakan panggilan fungsi untuk mengintegrasikan model bahasa dengan alat dan sistem lain menghadirkan potensi risiko. Penting untuk memahami risiko yang mungkin ditimbulkan oleh panggilan fungsi dan mengambil tindakan untuk memastikan Anda menggunakan fitur secara bertanggung jawab.

Berikut adalah beberapa tips untuk membantu Anda menggunakan fungsi dengan aman dan aman:

  • Memvalidasi Panggilan Fungsi: Selalu verifikasi panggilan fungsi yang dihasilkan oleh model. Ini termasuk memeriksa parameter, fungsi yang dipanggil, dan memastikan bahwa panggilan selaras dengan tindakan yang dimaksudkan.
  • Gunakan Data dan Alat Tepercaya: Hanya gunakan data dari sumber tepercaya dan terverifikasi. Data yang tidak tepercaya dalam output fungsi dapat digunakan untuk menginstruksikan model untuk menulis panggilan fungsi dengan cara selain yang Anda inginkan.
  • Ikuti Prinsip Hak Istimewa Paling Sedikit: Hanya berikan akses minimum yang diperlukan agar fungsi dapat melakukan pekerjaannya. Ini mengurangi dampak potensial jika fungsi disalahgunakan atau dieksploitasi. Misalnya, jika Anda menggunakan panggilan fungsi untuk mengkueri database, Anda hanya boleh memberi aplikasi Anda akses baca-saja ke database. Anda juga tidak boleh hanya bergantung pada mengecualikan kemampuan dalam definisi fungsi sebagai kontrol keamanan.
  • Pertimbangkan Dampak di Dunia Nyata: Perhatikan dampak nyata dari panggilan fungsi yang Anda rencanakan untuk dilakukan, terutama yang memicu tindakan seperti menjalankan kode, memperbarui database, atau mengirim pemberitahuan.
  • Terapkan Langkah Konfirmasi Pengguna: Terutama untuk fungsi yang mengambil tindakan, sebaiknya masukkan langkah di mana pengguna mengonfirmasi tindakan sebelum eksekusi.

Untuk mempelajari selengkapnya tentang praktik AI yang bertanggung jawab untuk Model Foundry, lihat Gambaran Umum praktik AI yang bertanggung jawab.

Penting

Dalam Chat Completions API, parameter functions dan function_call sudah tidak digunakan lagi. Gunakan parameter tools alih-alih functions, dan gunakan parameter tool_choice alih-alih function_call.

Dukungan fungsi panggilan

Model Foundry mendukung panggilan fungsi melalui API Penyelesaian Obrolan atau API Respons. Dukungan bervariasi menurut model, API, jenis penyebaran, dan versi model.

Untuk menemukan model yang mendukung panggilan fungsi, tinjau katalog berikut:

Dalam detail model, cari kemampuan berikut:

  • API Penyelesaian Obrolan atau API Respons, tergantung pada API yang Anda rencanakan untuk digunakan.
  • Fungsi atau alat untuk dukungan panggilan fungsi.
  • Panggilan alat paralel jika aplikasi Anda memerlukan model untuk meminta beberapa panggilan fungsi dalam satu respons.

Artikel ini menunjukkan cara menerapkan panggilan fungsi dengan API Penyelesaian Obrolan. Untuk format permintaan dan respons API Respons, lihat Menggunakan AZURE OpenAI Responses API.

Catatan

Parameter tool_choice sekarang didukung dengan o3-mini dan o1. Untuk informasi selengkapnya, lihat panduan model penalaran.

Penting

Deskripsi alat dan fungsi saat ini dibatasi hingga 1.024 karakter. Kami akan memperbarui artikel ini jika batas ini berubah.

Langkah berikutnya