Как использовать функциональный вызов с Azure OpenAI в моделях Microsoft Foundry

Если одна или несколько функций включены в запрос, модель определяет, следует ли вызывать какие-либо функции в зависимости от контекста запроса. Когда модель определяет, что функцию нужно вызвать, она отвечает JSON-объектом, содержащим аргументы для функции.

Модели сформулируют вызовы API и структурируют данные вывода, исходя из указанных вами функций. Важно отметить, что хотя модели могут создавать эти вызовы, необходимо использовать их, чтобы убедиться, что контроль остается за вами.

На высоком уровне можно разбить работу с функциями на три шага:

  1. Вызов API завершения чата с функциями и входными данными пользователя
  2. Используйте ответ модели для вызова API или функции
  3. Снова вызовите API завершения чата, включая ответ от функции, чтобы получить окончательный ответ

Необходимые условия

  • Развернутая модель Azure OpenAI
  • Для проверки подлинности Microsoft Entra ID:

Пример вызова одного инструмента или функции

Сначала продемонстрируйте вызов простой функции, которая может проверить время в трех предопределенных местоположениях с помощью одного инструмента или функции. Мы добавили инструкции печати, чтобы упростить выполнение кода.

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

Выход:

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.

Если мы используем развертывание модели, поддерживающей параллельные вызовы функций, мы можем преобразовать это в пример параллельного вызова функций, изменив массив сообщений, чтобы запросить время в нескольких местах вместо одного.

Для этого поменяйте местами комментарии в этих двух строках:

    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

Чтобы это выглядело вот так, запустите код снова:

    #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

Это создает следующие выходные данные:

Выход:

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

Параллельные вызовы функций позволяют выполнять несколько вызовов функций вместе, что позволяет параллельно выполнять и извлекать результаты. Это уменьшает количество вызовов API, которые необходимо выполнить и могут повысить общую производительность.

Например, в нашем простом приложении времени мы извлекли несколько раз одновременно. Это привело к сообщению о завершении чата с тремя вызовами функций в массиве tool_calls , каждый из которых имеет уникальный id. Если вы хотите ответить на эти вызовы функций, вам следует добавить три новых сообщения в беседу, каждое из которых содержит результат одного вызова функции, с ссылкой tool_call_id на id из tool_calls.

Чтобы принудительно вызвать определенную функцию, задайте tool_choice для именованного объекта средства, например: tool_choice={"type": "function", "function": {"name": "get_current_time"}} Чтобы принудительно вывести сообщение для пользователя, установите его.tool_choice="none"

Примечание

Поведение по умолчанию (tool_choice: "auto") предназначено для модели, чтобы решить самостоятельно, следует ли вызывать функцию и если да, какую функцию следует вызывать.

Параллельные вызовы функций с несколькими функциями

Теперь мы демонстрируем другой пример вызова простейшей функции, на этот раз с двумя разными инструментами и функциями, которые определены.

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

Выход

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?

Важно

Ответ JSON может не всегда быть допустимым, поэтому необходимо добавить дополнительную логику в код, чтобы иметь возможность обрабатывать ошибки. В некоторых случаях использования может потребоваться использовать точную настройку для повышения производительности вызова функций.

Инжиниринг запросов с применением функций

При определении функции в рамках запроса сведения внедряются в системное сообщение с использованием определенного синтаксиса, на который была обучена модель. Это означает, что функции потребляют токены в вашем запросе и можно применять техники оптимизации запросов для улучшения производительности вызовов функций. Модель использует полный контекст запроса, чтобы определить, должна ли вызываться функция, включая определение функции, системное сообщение и сообщения пользователя.

Улучшение качества и надежности

Если модель не вызывает вашу функцию в нужное время или необходимым образом, вы можете попробовать улучшить качество вызова функций.

Дополнительные сведения в определении функции

Важно предоставить значимые description сведения о функции и предоставить описания для любого параметра, который может быть не очевиден для модели. Например, в описании параметра location можно включить дополнительные сведения и примеры по формату расположения.

"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)"
},
Укажите больше контекста в системном сообщении

Системное сообщение также можно использовать для предоставления большего контекста модели. Например, если у вас есть функция, вызванная search_hotels , можно включить системное сообщение, например следующее, чтобы указать модели вызвать функцию, когда пользователь запрашивает помощь при поиске отеля.

{"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."}
Указание модели задавать уточняющие вопросы

В некоторых случаях необходимо указать модели задавать уточняющие вопросы, чтобы предотвратить предположение о том, какие значения следует использовать с функциями. Например, с search_hotels вы хотите, чтобы модель запрашивала уточнение, если запрос пользователя не содержит деталей о location. Чтобы указать модели задать уточняющий вопрос, можно включить содержимое, например следующий пример в системном сообщении.

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

Сокращение ошибок

Другая область, где инженерия запросов может быть полезной, — это сокращение ошибок в вызовах функций. Модели обучены создавать вызовы функций, соответствующие определенной схеме, но модели создают вызов функции, который не соответствует определенной схеме или пытается вызвать функцию, которую вы не включили.

Если модель создает вызовы функций, которые не были предоставлены, попробуйте включить предложение в системное сообщение, которое говорит "Only use the functions you have been provided with.".

Использование вызовов функций ответственно

Как и любая система ИИ, используя вызов функции для интеграции языковых моделей с другими инструментами и системами, представляет потенциальные риски. Важно понимать риски, которые могут представлять вызов функций и принимать меры, чтобы обеспечить ответственное использование возможностей.

Ниже приведены несколько советов, которые помогут вам безопасно и безопасно использовать функции:

  • Проверка вызовов функций. Всегда проверяйте вызовы функций, созданные моделью. Это включает проверку параметров, вызываемую функцию и обеспечение соответствия вызова предполагаемому действию.
  • Используйте доверенные данные и средства. Используйте только данные из доверенных и проверенных источников. Ненадежные данные в выходных данных функции могут быть использованы для инструкции модели записывать вызовы функций, отличающиеся от ожидаемых.
  • Следуйте принципу наименьшей привилегии: предоставьте только минимальный доступ, необходимый для выполнения функции. Это снижает потенциальное влияние, если функция используется неправильно или эксплуатируется. Например, если вы используете вызовы функций для запроса базы данных, вы должны предоставить приложению доступ только для чтения к базе данных. Вы также не должны зависеть исключительно от исключения возможностей в определении функции в качестве элемента управления безопасностью.
  • Учитывайте реальное влияние: Осознавайте реальное влияние вызовов функций, которые вы планируете выполнить, особенно тех, которые запускают такие действия, как выполнение кода, обновление баз данных или отправка уведомлений.
  • Реализуйте действия подтверждения пользователей. Особенно для функций, которые выполняют действия, рекомендуется включить шаг, в котором пользователь подтверждает действие перед выполнением.

Дополнительные сведения о наших рекомендациях по ответственному использованию моделей Azure OpenAI см. в статье Обзор практик ответственного использования ИИ для моделей Azure OpenAI.

Важно

Параметры functions и function_call устарели с выпуском версии API 2023-12-01-preview. Для замены functions используется tools параметр. Для замены function_call используется tool_choice параметр.

Поддержка вызовов функций

Вызов параллельной функции

  • gpt-4 (2024-04-09)
  • gpt-4o (2024-05-13)
  • gpt-4o (2024-08-06)
  • gpt-4o (2024-11-20)
  • gpt-4o-mini (2024-07-18)
  • gpt-4.1 (2025-04-14)
  • gpt-4.1-mini (2025-04-14)
  • gpt-5 (2025-08-07)
  • gpt-5-mini (2025-08-07)
  • gpt-5-nano (2025-08-07)
  • gpt-5-codex (2025-09-11)
  • gpt-5.1 (2025-11-13)
  • gpt-5.1-chat (2025-11-13)
  • gpt-5.1-codex (2025-11-13)
  • gpt-5.1-codex-mini (2025-11-13)
  • gpt-5.1-codex-max (2025-12-04)
  • gpt-5.2 (2025-12-11)
  • gpt-5.2-chat (2025-12-11)
  • gpt-5.2-codex (2026-01-14)
  • gpt-5.2-chat (2026-02-10)
  • gpt-5.3-codex (2026-02-24)
  • gpt-5.3-chat (2026-03-03)
  • gpt-5.4 (2026-03-05)
  • gpt-5.4 (2026-03-05)
  • gpt-5.4-mini (2026-03-17)
  • gpt-5.4-nano (2026-03-17)
  • gpt-5.5 (2026-04-24)
  • gpt-chat-latest (2026-05-05)
  • gpt-chat-latest (2026-05-28)

Поддержка параллельной обработки была добавлена в версию API 2023-12-01-preview

Базовый вызов функций с инструментами

  • Все модели, поддерживающие параллельные вызовы функций
  • gpt-5.4-pro (2026-03-05)
  • gpt-5-pro (2025-10-06)
  • codex-mini (2025-05-16)
  • o3-pro (2025-06-10)
  • o4-mini (2025-04-16)
  • o3 (2025-04-16)
  • gpt-4.1-nano (2025-04-14)
  • o3-mini (2025-01-31)
  • o1 (2024-12-17)

Примечание

Теперь параметр tool_choice поддерживается с o3-mini и o1. Дополнительные сведения см. в руководстве по моделям причин.

Важно

В настоящее время описания инструментов и функций ограничены 1024 символами с Azure OpenAI. Если это ограничение будет изменено, мы обновим эту статью.

Дальнейшие действия