다음을 통해 공유


Azure OpenAI Service(미리 보기)에서 함수 호출을 사용하는 방법

gpt-35-turbo 및 gpt-4의 최신 버전은 함수와 함께 작동하도록 미세 조정되었으며 함수를 호출해야 하는 시기와 방법을 모두 결정할 수 있습니다. 요청에 하나 이상의 함수가 포함된 경우 모델은 프롬프트의 컨텍스트에 따라 호출해야 하는 함수가 있는지 결정합니다. 모델이 함수를 호출해야 한다고 결정하면 함수에 대한 인수가 포함된 JSON 개체로 응답합니다.

모델은 모두 사용자가 지정하는 함수를 기반으로 API 호출 및 구조 데이터 출력을 수식화합니다. 모델이 이러한 호출을 생성할 수 있지만 이를 실행하여 제어권을 유지하는 것은 사용자에게 달려 있다는 점을 기억하는 것이 중요합니다.

높은 수준에서는 함수 작업을 세 단계로 나눌 수 있습니다.

  1. 함수와 사용자 입력을 사용하여 채팅 완료 API를 호출하세요.
  2. 모델의 응답을 사용하여 API 또는 함수 호출
  3. 최종 응답을 얻으려면 함수의 응답을 포함하여 채팅 완료 API를 다시 호출하세요.

Important

functionsfunction_call 매개 변수는 API의 2023-12-01-preview 버전이 릴리스되어 사용되지 않습니다. functions를 바꾸는 것은 tools 매개 변수입니다. function_call를 바꾸는 것은 tool_choice 매개 변수입니다.

함수 호출 지원

병렬 함수 호출

  • gpt-35-turbo(1106)
  • gpt-35-turbo (0125)
  • gpt-4 (1106-미리 보기)
  • gpt-4 (0125-미리 보기)
  • gpt-4(vision-preview)
  • gpt-4(2024-04-09)
  • gpt-4o(2024-05-13)

병렬 함수에 대한 지원이 API 버전 2023-12-01-preview에 처음 추가되었습니다.

도구를 사용하는 기본 함수 호출

  • 병렬 함수 호출을 지원하는 모든 모델
  • gpt-4(0613)
  • gpt-4-32k(0613)
  • gpt-35-turbo-16k(0613)
  • gpt-35-turbo(0613)

단일 도구/함수 호출 예

예에서는 먼저 단일 도구/함수가 정의된 세 개의 하드 코드된 위치에서 시간을 확인할 수 있는 간단한 토이 함수 호출을 보여 줍니다. 코드 실행을 더 쉽게 따라갈 수 있도록 print 문을 추가했습니다.

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

출력:

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가 있는 3개의 함수 호출이 포함된 채팅 완료 메시지가 생성되었습니다. 이러한 함수 호출에 응답하려면 대화에 세 개의 새 메시지를 추가해야 했습니다. 각 메시지에는 tools_callsid를 참조하는 tool_call_id와 함께 하나의 함수 호출 결과가 포함됩니다.

모델이 특정 함수를 호출하도록 하려면 특정 함수 이름으로 tool_choice 매개 변수를 설정합니다. tool_choice: "none"을 설정하여 모델이 사용자에게 표시되는 메시지를 생성하도록 강제할 수도 있습니다.

참고 항목

기본 동작(tool_choice: "auto")은 모델이 함수 호출 여부와 호출할 함수를 자체적으로 결정하는 것입니다.

여러 함수를 사용하여 병렬 함수 호출

이제 두 개의 서로 다른 도구/함수가 정의된 다른 토이 함수 호출 예를 보여 드리겠습니다.

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

출력

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?

Important

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."이라는 문장을 포함해 보세요.

책임 있게 함수 호출 사용하기

다른 AI 시스템과 마찬가지로 함수 호출을 사용하여 언어 모델을 다른 도구 및 시스템과 통합하면 잠재적인 위험이 있습니다. 함수 호출로 인해 발생할 수 있는 위험을 이해하고 해당 기능을 책임감 있게 사용할 수 있도록 조치를 취하는 것이 중요합니다.

다음은 기능을 안전하게 사용하는 데 도움이 되는 몇 가지 팁입니다.

  • 함수 호출 확인: 모델에서 생성된 함수 호출을 항상 확인합니다. 여기에는 매개 변수, 호출되는 함수 확인, 호출이 의도한 작업과 일치하는지 확인하는 작업이 포함됩니다.
  • 신뢰할 수 있는 데이터 및 도구 사용: 신뢰할 수 있고 검증된 원본의 데이터만 사용하세요. 함수 출력의 신뢰할 수 없는 데이터는 의도한 것과 다른 방식으로 함수 호출을 작성하도록 모델에 지시하는 데 사용될 수 있습니다.
  • 최소 권한 원칙 따르기: 기능이 작업을 수행하는 데 필요한 최소한의 액세스 권한만 부여합니다. 이렇게 하면 기능이 잘못 사용되거나 악용될 경우 발생할 수 있는 영향이 줄어듭니다. 예를 들어 함수 호출을 사용하여 데이터베이스를 쿼리하는 경우 애플리케이션에 데이터베이스에 대한 읽기 전용 액세스 권한만 부여해야 합니다. 또한 보안 제어로서 기능 정의에서 기능을 제외하는 것에만 의존해서는 안 됩니다.
  • 실제 영향 고려: 실행하려는 함수 호출, 특히 코드 실행, 데이터베이스 업데이트, 알림 전송과 같은 작업을 트리거하는 함수 호출이 실제 영향을 미치는지 파악하세요.
  • 사용자 확인 단계 구현: 특히 작업을 수행하는 기능의 경우 작업이 실행되기 전에 사용자가 확인하는 단계를 포함하는 것이 좋습니다.

Azure OpenAI 모델을 책임감 있게 사용하는 방법에 대한 권장 사항을 자세히 알아보려면 Azure OpenAI 모델에 대한 책임 있는 AI 사례 개요를 참조하세요.

다음 단계