Jump to content

AI 어시스턴트 제작 레시피: Function calling 활용하기


Recommended Posts

image.png.f37d3395334675330dfda68a23ec65bc.png

들어가며


본 쿡북에서는 CLOVA StudioChat Completions v3 API활용해, 외부 데이터를 조회하거나 도구를 실행하고 결과를 반영해 응답하는 AI 어시스턴트를 구축하는 방법을 소개합니다.

Chat Completions v3 API 가이드는 다음 링크를 참고해 주세요. (링크)

작동 원리


본 쿡북에서는 금융 어시스턴트를 제작하는 과정을 예제로 다룹니다. 먼저, 어시스턴트의 작동 원리를 살펴보겠습니다.

사용자가 입력한 내용은 messages와 사전에 정의된 tools(functions) 정보가 함께 Function calling 모델에 전달되어 검토됩니다. Function calling 모델은 적합한 function을 선택하고 arguments 값을 응답하는데, 이 과정에서 사용자 발화가 정의된 tools와 무관하다고 판단이 되면 고정 응답이 반환됩니다. 생성된 Function calling 응답은 사용자가 직접 실행하여 그 결과를 messages에 업데이트한 뒤, 다시 Chat Completions API에 전달합니다. Chat Completions이 호출되면 설정된 시스템 프롬프트와 파라미터 값에 기반하여 LLM이 최종 답변을 생성합니다.

image.png.0d528c4701bac6044e14d79e8117d0ed.png

사용 시나리오


다음으로, 금융 어시스턴트의 사용 시나리오를 살펴보겠습니다. 시나리오는 아래와 같이 1) 특정 종목의 주가 정보 2) 주식 주문 3) 환율 계산기 도구와 4) 고정 응답으로 구성됩니다. 다음 가이드를 따라 금융 어시스턴트를 직접 만들어 보고, 자신만의 AI 어시스턴트로 확장해 보세요! 🚀

image.png.c1642502482aa09a9edf89e0821f2552.png

환경 설정

Quote

본 쿡북은 Jupyter Notebook(.ipynb) 환경 기준으로 설계되어, 셀 단위로 코드 실행하고 결과를 확인할 수 있습니다.

필요한 라이브러리 설치 및 임포트

FinanceDataReader는 국내 및 해외의 금융 데이터(주가, 지수 등)를 불러올 수 있는 파이썬 오픈소스 라이브러리 입니다. 다음 코드를 실행하여 필요한 라이브러리를 설치하고 임포트 하세요.

Quote
!pip install finance-datareader

 

Quote
import json
import requests
import base64
import FinanceDataReader as fdr

 

Chat Completions v3 API 요청 정의

Chat Completions v3 API를 통해 함수 호출(Function calling)일반 대화 응답 생성을 모두 처리할 수 있습니다.

요청 본문에 도구 정의(tools)를 함께 전달하면, 사용자의 입력에 따라 필요한 도구가 자동으로 선택되고 실행됩니다. 이때 주식 데이터 조회(get_stock_data), 주식 주문(order_stock), 환율 계산(calculate_currency)의 세 가지 도구를 사용할 수 있으며, "toolChoice": "auto"로 설정하면 도구 선택이 자동으로 이뤄집니다. 반대로, 도구를 포함하지 않은 요청은 일반 LLM 응답 생성으로 처리됩니다. 이 경우 temperature, maxTokens 등의 생성 파라미터를 활용해 응답의 스타일과 길이를 조절할 수 있습니다. 성능과 목적에 따라 적합한 모델(HCX-DASH-002, HCX-005)을 선택하여 활용해 주세요. 

def chat_completions(messages, tools=None, tool_choice="auto", **generation_params):
    url = "YOUR_API_URL" # 테스트 앱/서비스 앱을 통해 발급 받은 Chat Completions API 호출 경로를 입력하세요.
    headers = {
        "Authorization": "Bearer YOUR_API_KEY", # 본인이 발급 받은 API Key를 입력하세요.
        "X-NCP-CLOVASTUDIO-REQUEST-ID": "YOUR_REQUEST_ID", # 본인이 발급 받은 API의 요청 ID를 입력하세요.
        "Content-Type": "application/json"
    }
    data = {
        "messages": messages,
        "toolChoice": tool_choice if tools else "none",
        **generation_params
    }
    if tools:
        data["tools"] = tools

    response = requests.post(url, headers=headers, json=data)
    return response.json()

Tools 정의

도구 호출을 활용하려면, API 요청 본문에 사용할 함수 목록을 tools 필드에 정의해야 합니다. 아래는 이 예제에서 사용되는 세 가지 함수 정의입니다.

  • get_stock_data: 특정 종목의 주가나 거래량을 조회합니다.

  • order_stock: 주식을 매수하거나 매도할 수 있습니다. 시장가 또는 지정가 주문을 지원합니다.

  • calculate_currency: 특정 금액을 다른 통화로 환산할 수 있습니다.

각 함수는 이름(name), 설명(description), 입력 파라미터(parameters)로 구성되며, 파라미터는 모두 JSON Schema 형식으로 정의됩니다. 이 정의를 통해 LLM은 어떤 도구가 어떤 인자를 필요로 하는지 이해하고, 사용자 입력에 따라 적절히 호출할 수 있게 됩니다.

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_data",
            "description": "특정 종목의 현재 혹은 과거 주가와 거래량을 조회할 수 있습니다.",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {
                        "description": "조회할 종목 코드(ticker)입니다. ex. 네이버의 종목코드는 035420",
                        "type": "string"
                    },
                    "date": {
                        "description": "조회 날짜입니다. (형식: 'YYYY-MM-DD')",
                        "type": "string"
                    },
                    "result_type": {
                        "description": "조회 유형입니다.",
                        "type": "string",
                        "enum": ["price", "volume"]
                    }
                },
                "required": ["ticker", "date", "result_type"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "order_stock",
            "description": "시장가/지정가로 주식을 주문할 수 있습니다.",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {
                        "description": "주문할 종목 코드(ticker)입니다. ex. 네이버의 종목코드는 035420",
                        "type": "string"
                    },
                    "action_type": {
                        "description": "매수/매도를 지정합니다.",
                        "type": "string",
                        "enum": ["매수", "매도"]
                    },
                    "shares": {
                        "description": "주문 주식 수를 설정합니다.",
                        "type": "integer"
                    },
                    "order_type": {
                        "description": "주문 유형을 지정합니다.",
                        "type": "string",
                        "enum": ["시장가", "지정가"]
                    },
                    "order_price": {
                        "description": "지정가일 경우 가격을 설정합니다.",
                        "type": "number"
                    }
                },
                "required": ["ticker", "action_type", "shares", "order_type"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate_currency",
            "description": "환율 계산을 도와줍니다.",
            "parameters": {
                "type": "object",
                "properties": {
                    "from_currency": {
                        "description": "환전 대상 화폐 종류를 설정합니다.",
                        "type": "string",
                        "enum": ["KRW", "USD", "EUR", "JPY"]
                    },
                    "to_currency": {
                        "description": "환전하고자 하는 화폐 종류를 설정합니다.",
                        "type": "string",
                        "enum": ["KRW", "USD", "EUR", "JPY"]
                    },
                    "amount": {
                        "description": "총 환전 대상 금액입니다. (from_currency 기준)",
                        "type": "number"
                    },
                    "date": {
                        "description": "환율 기준 날짜입니다. (형식: 'YYYY-MM-DD')",
                        "type": "string"
                    }
                },
                "required": ["from_currency", "to_currency", "amount", "date"]
            }
        }
    }
]

사용자 함수 정의

앞서 정의한 세 가지 도구를 처리하는 사용자 정의 함수를 구현합니다. 사용자 함수는 API 뿐만 아니라 데이터베이스, 로컬 또는 클라우드 저장소의 파일 등 다양한 소스 및 기능과 연동하여 활용될 수 있습니다.

get_stock_data

파이썬 오픈소스 라이브러리(FinanceDataReader)를 활용해 주식 데이터를 조회하는 함수를 정의합니다. 종목 코드와 날짜를 기반으로, 해당 시점의 주가 또는 거래량 데이터를 반환합니다.

이외 다양한 금융 데이터 소스와 연동하거나, 데이터 처리 로직을 추가해 보다 심화된 결과를 제공할 수 있습니다. 

def get_stock_data(ticker, date, result_type):
    stock_data = fdr.DataReader(ticker, date)

    if stock_data.empty:
        return [{"name": "get_stock_data", "response": f"{ticker}에 대한 {date} 데이터가 없습니다."}]

    row = stock_data.iloc[0]
    if result_type == "price":
        return [{"name": "get_stock_data", "response": {"date": date, "price": float(row['Close'])}}]
    elif result_type == "volume":
        return [{"name": "get_stock_data", "response": {"date": date, "volume": int(row['Volume'])}}]
    else:
        return [{"name": "get_stock_data", "response": "잘못된 조회 유형입니다. '가격' 또는 '거래량'만 조회 가능합니다."}]
order_stock

주식 주문을 처리하는 함수를 정의합니다. 종목 코드, 주문 유형(매수, 매도) 등을 바탕으로 처리한 결과를 반환합니다.

현재는 예제로서 단순 메시지를 반환하지만, 실제로는 주문 데이터를 DB에 기록하거나 주문 API를 호출하는 방식으로 확장 가능합니다. 

def order_stock(ticker, action_type, shares, order_type, order_price=None):
    if order_type == "지정가" and (order_price is None or order_price <= 0):
        return [{"name": "order_stock", "response": "지정가 주문에는 유효한 가격이 필요합니다."}]
	# DB 연동하여 확장 가능
    return [{"name": "order_stock", "response": f"{ticker} 종목 {shares}주 {order_type}로 '{action_type}' 주문 완료"}]
calculate_currency

환율 계산을 수행하는 함수를 정의합니다. 환전할 금액, 통화 종류 등을 입력 받아 계산 결과를 반환합니다. 

현재는 예제로서 하드코딩 된 가상의 고정 환율 데이터를 사용하고 있지만, 실제로는 로컬 파일(json, xls, txt 등) 또는 외부 API를 통해 데이터를 읽어오는 방식으로 확장할 수 있습니다.

def calculate_currency(from_currency, to_currency, amount, date):
    exchange_rates = {
        "KRW": {"USD": 0.0006725, "EUR": 0.0006178, "JPY": 0.09817},
        "USD": {"KRW": 1487.07, "EUR": 1.0884, "JPY": 150.99},
        "EUR": {"KRW": 1618.79, "USD": 0.9188, "JPY": 138.74},
        "JPY": {"KRW": 10.187, "USD": 0.00662, "EUR": 0.00721},
    }
    rate = exchange_rates.get(from_currency, {}).get(to_currency)
    if not rate:
        return [{"name": "calculate_currency", "response": "지원되지 않는 통화입니다."}]
    converted_amount = round(amount * rate, 2)
    return [{"name": "calculate_currency", "response": f"{converted_amount} {to_currency}"}]

함수 실행 처리

다음으로 정의한 process_tool_calls는 해당 도구에 정의된 함수와 매개변수를 매핑하여 동적으로 실행해 주는 역할을 합니다. 이를 통해 다양한 도구 호출 시 공통 로직을 단순화할 수 있습니다.

def process_tool_calls(tool_name, arguments):
    tool_map = {
        "get_stock_data": get_stock_data,
        "order_stock": order_stock,
        "calculate_currency": calculate_currency
    }
    func = tool_map.get(tool_name) # 추출한 매개변수를 키워드 인수로 함수에 전달하여 실행합니다.
    return func(**arguments)

실행 및 테스트

사용자 요청을 처리하고 최종 응답을 생성하는 전체 실행 과정을 테스트합니다. 

사용자 쿼리를 입력하면 적합한 도구를 선택해 실행한 결과를 AI 대화 흐름에 추가하여 응답을 제공합니다. 사용자 요청이 정의된 도구와 일치하지 않거나, 적합한 도구를 선택할 수 없는 경우 "toolCalls"가 비어 있을 수 있습니다. 다음 코드에서는 이러한 상황을 감지하고 적절한 오류 메시지를 반환하도록 처리합니다.

query = "YOUR_QUERY"
messages = [{"role": "user", "content": query}]
print(f"User: {query}")

# Step 1. 요청 — 입력 및 함수 정의 전달
function_response = chat_completions(
    messages = messages,
    tools = tools
) 

# Step 2. 응답 — 호출할 함수 및 인수 추출
tool_calls = function_response.get("result", {}).get("message", {}).get("toolCalls", [])

try:
    if not tool_calls:
        # 도구 호출이 없을 경우
        error_message = "죄송하지만, 입력하신 내용은 제가 처리할 수 있는 범위를 벗어났습니다. 주식 정보나 환율 계산과 관련된 요청으로 다시 시도해 주세요."
        messages.append({"content": error_message, "role": "assistant"})
        print(f"Assistant: {error_message}")
    else:
        # 도구 호출이 있을 경우
        messages.append({"role": "assistant", "content": "", "toolCalls": tool_calls})
        tool_call = tool_calls[0]
        print(f"\nAssistant: {tool_call}\n")
        
        # Step 3. 함수 실행 — 응답 기반으로 실제 함수 호출
        tool_call_id = tool_call["id"]
        tool_name = tool_call["function"]["name"]
        arguments = tool_call["function"]["arguments"]
        results = process_tool_calls(tool_name, arguments)
        messages.append({"role": "tool", "content": str(results), "toolCallId": tool_call_id})
        print(f"Tool: {results}\n")
        
        # Step 4. 요청 — 함수 실행 결과 전달
        chat_response = chat_completions(
            messages = messages,
            seed = 0,
            topP = 0.8,
            topK = 0,
            maxTokens = 1024,
            temperature = 0.5,
            repeatPenalty = 1.1,
            stopBefore = [],
            includeAiFilters = True 
        )
        # Step 5. 응답 — 최종 답변 추출
        final_answer = chat_response.get("result").get("message").get("content")
        print(f'Assistant: {final_answer}')
        
except Exception as e:
    error_message = f"요청 처리 중 오류가 발생했습니다: {str(e)}"
    messages.append({"content": error_message, "role": "assistant"})
    print(f"Assistant: {error_message}")

다음은 위 코드 실행 시 출력 예시입니다. 이 출력은 사용자 요청이 Function calling과 사용자 정의 함수를 거쳐 최종 응답으로 생성되는 단계를 순차적으로 보여줍니다.

  • output sample 1
User: 네이버 그저께 주가

Assistant: {'id': 'call_abA5RsWViXcaCa7FCWg1eoDf', 'type': 'function', 'function': {'name': 'get_stock_data', 'arguments': {'ticker': '035420', 'date': '2025-04-06', 'result_type': 'price'}}}

Tool: [{'name': 'get_stock_data', 'response': {'date': '2025-04-06', 'price': np.float64(191800.0)}}]

Assistant: 네이버의 그저께 주가는 191,800원이었습니다.
  • output sample 2
User: 엔비디아 10주를 100불에 매도해줘

Assistant: {'id': 'call_Vy7hJQnTicsB1PFa4tscjl0W', 'type': 'function', 'function': {'name': 'order_stock', 'arguments': {'ticker': 'NVDA', 'action_type': '매도', 'shares': 10, 'order_type': '지정가', 'order_price': 100}}}

Tool: [{'name': 'order_stock', 'response': "NVDA 종목 10주 지정가로 '매도' 주문 완료"}]

Assistant: 사용자님께서 말씀하신 NVDA 종목 10주에 대한 지정가 매도 주문이 완료되었습니다.
  • output sample 3
User: 만원을 달러로 환전하면 얼마인가요

Assistant: {'id': 'call_b7ianfYh9jiEk1csGgWCZKiI', 'type': 'function', 'function': {'name': 'calculate_currency', 'arguments': {'from_currency': 'KRW', 'to_currency': 'USD', 'amount': 10000, 'date': '2025-04-08'}}}

Tool: [{'name': 'calculate_currency', 'response': '6.76 USD'}]

Assistant:  원(10,000 KRW)을 달러로 환전하면  6.76 USD입니다. (환율은 2025  4 8 기준입니다.)
  •  output sample 4
User: 오늘 날씨 어때?

Assistant: 죄송하지만, 입력하신 내용은 제가 처리할  있는 범위를 벗어났습니다. 주식 정보나 환율 계산과 관련된 요청으로 다시 시도해 주세요.

실전 활용 팁


이 섹션에서는 Function calling에서 복잡한 사용자 요청을 효과적으로 처리하는 방법을 예시와 함께 알아봅니다. 예를 들어, 특정 종목의 주가를 조회하면서 동시에 주식 주문을 처리하는 복잡한 멀티 쿼리 시나리오도 쉽게 해결할 수 있습니다. 

1. 병렬 도구 호출: 여러 도구를 동시에 실행하기

여러 도구를 동시에 호출한 뒤, 그 결과를 종합하여 사용자 요청에 응답할 수 있습니다. 복잡한 요청을 단계별로 실행할 때 유용합니다.

Quote
query = "YOUR_QUERY"
messages = [{"content": query, "role": "user"}]
print(f"User: {query}")

# Step 1. 요청 — 입력 및 함수 정의 전달
function_response = chat_completions(
    messages = messages,
    tools = tools
) 

# Step 2. 응답 — 호출할 함수 및 인수 추출
tool_calls = function_response.get("result", {}).get("message", {}).get("toolCalls", [])

try:
    if not tool_calls:
        # 도구 호출이 없을 경우
        error_message = "죄송하지만, 입력하신 내용은 제가 처리할 수 있는 범위를 벗어났습니다. 주식 정보나 환율 계산과 관련된 요청으로 다시 시도해 주세요."
        messages.append({"content": error_message, "role": "assistant"})
        print(f"Assistant: {error_message}")
    else:
        # 도구 호출이 있을 경우
        messages.append({"role": "assistant", "content": "", "toolCalls": tool_calls})
        print(f"\nAssistant: {tool_calls}\n")

        # Step 3. 함수 실행 — 응답 기반으로 실제 함수 호출
        results = []
        for tool_call in tool_calls:
            tool_call_id = tool_call["id"]
            tool_name = tool_call["function"]["name"]
            arguments = tool_call["function"]["arguments"]
            results = process_tool_calls(tool_name, arguments)
            messages.append({"role": "tool", "content": str(results), "toolCallId": tool_call_id})
            print(f"Tool: {results}\n")
        
        # Step 4. 요청 — 함수 실행 결과 전달
        chat_response = chat_completions(
            messages = messages,
            seed = 0,
            topP = 0.8,
            topK = 0,
            maxTokens = 1024,
            temperature = 0.5,
            repeatPenalty = 1.1,
            stopBefore = [],
            includeAiFilters = True 
        )
        # Step 5. 응답 — 최종 답변 추출
        final_answer = chat_response.get("result").get("message").get("content")
        print(f'Assistant: {final_answer}')

except Exception as e:
    error_message = f"요청 처리 중 오류가 발생했습니다: {str(e)}"
    messages.append({"content": error_message, "role": "assistant"})
    print(f"Assistant: {error_message}")

 

 
User: 지금 테슬라 주가 얼마야? 시장가로 20 매수 주문해줘.

Assistant: [{'id': 'call_eeYdvrLHG69sYFJgC95XBjCd', 'type': 'function', 'function': {'name': 'get_stock_data', 'arguments': {'ticker': 'TSLA', 'date': '2025-04-08', 'result_type': 'price'}}}, {'id': 'call_fsVYRYX5hGI9OvzObPe4gxqG', 'type': 'function', 'function': {'name': 'order_stock', 'arguments': {'ticker': 'TSLA', 'action_type': '매수', 'shares': 20, 'order_type': '시장가'}}}]

Tool: [{'name': 'get_stock_data', 'response': {'date': '2025-04-08', 'price': 233.2899932861328}}]

Tool: [{'name': 'order_stock', 'response': "TSLA 종목 20주 시장가로 '매수' 주문 완료"}]

Assistant: 현재(2025 4 8일) 테슬라(TSLA)의 주가는 **233.29** 달러입니다. 또한 요청하신 대로 시장가로 20주를 매수하는 주문을 완료했습니다. 추가적인 도움이 필요하시면 말씀해 주세요!
2. 도구 간 의존성 처리: 특정 도구의 출력 결과를 다른 도구의 입력으로 사용하기

한 도구의 출력이 다른 도구의 입력으로 사용되는 경우, 시스템 프롬프트와 큐(queue)를 활용하여 도구 간 의존성을 처리할 수 있습니다.

Function calling 호출 시 시스템 프롬프트에 의존성을 "@도구이름.출력키" 형식으로 명시하게끔 하여 각 도구가 필요한 데이터를 다른 도구의 결과에서 자동으로 참조하도록 설정합니다. 그리고 각 도구 호출은 큐로 관리하며, 의존성이 해결된 도구부터 순차적으로 실행해 결과를 축적하고, 의존성이 충족되지 않은 도구는 다시 큐에 삽입해 처리합니다. 결과적으로 모든 호출이 처리된 후 최종 응답을 생성하여 사용자에게 제공합니다. 

Quote
query = "YOUR_QUERY"
messages = [{"content": query, "role": "user"}]
print(f"User: {query}")

# 도구 간 의존성 처리를 위한 시스템 프롬프트 설정
system_prompt = {
    "content": (
        "여러 toolCalls를 사용할 때, 특정 tool의 입력 파라미터가 이전 tool의 결과에 의존한다면, \n"
        "**해당 값을 직접 입력하지 말고 반드시 아래 형식으로 표현해야 합니다:**\n"
        "'@tool_name.output_key'\n"
        "\n"
        "예를 들어 'calculate_currency'의 'amount'가 'get_stock_data'의 결과에 따라 결정된다면:\n"
        "    'amount': '@get_stock_data.result.price'\n"
        "\n"
        "**아직 값을 알 수 없는 파라미터가 있다면 무조건 `@` 형식으로 남겨두세요.**\n"
        "**절대 임의의 숫자나 더미 값을 넣지 마세요. 그것은 잘못된 파라미터입니다.**"
    ),
    "role": "system"
}

# 매핑 규칙 정의 (출력 키 → 입력 키)
mapping_rules = {
    "get_stock_data": {"price": "amount", "date": "date"},
    "calculate_currency": {}
}

# Step 1. 요청 — 입력 및 함수 정의 전달
function_response = chat_completions(
    messages = [system_prompt] + messages ,
    tools = tools
)

# Step 2. 응답 — 호출할 함수 및 인수 추출
tool_calls = function_response.get("result", {}).get("message", {}).get("toolCalls", [])
'''
tool_calls 값 예시(calculate_currency의 amount에 의존성 명시):
[
    {
        'id': '61b11dfa41ab48babfef90bd0f55bf08',
        'type': 'function',
        'function': {
            'name': 'get_stock_data',
            'arguments': {
                'ticker': 'TSLA',
                'date': '2024-12-05',
                'result_type': 'price'
            }
        }
    },
    {
        'id': '8b7fb02209d64a1d985c15d6d1d93006',
        'type': 'function',
        'function': {
            'name': 'calculate_currency',
            'arguments': {
                'from_currency': 'USD',
                'to_currency': 'KRW',
                'amount': '@get_stock_data.result.price',
                'date': '2024-12-05'
            }
        }
    }
]
'''
try:
    # 도구 호출이 없을 경우
    if not tool_calls:
        error_message = "죄송하지만, 입력하신 내용은 제가 처리할 수 있는 범위를 벗어났습니다. 주식 정보나 환율 계산과 관련된 요청으로 다시 시도해 주세요."
        messages.append({"content": error_message, "role": "assistant"})
        print(f"Assistant: {error_message}")

    # 도구 호출이 있을 경우  
    else:
        # 도구 호출 결과를 저장할 딕셔너리
        tool_results = {} 
        # BFS 큐로 사용할 대기열에 모든 도구 호출 추가
        queue = tool_calls[:]
        # 이미 처리된 도구를 추적하는 집합
        processed_tools = set()
        
        # 도구 호출 처리
        while queue:
            # 큐에서 도구 호출 하나를 꺼낸 뒤 이름과 파라미터 추출
            tool_call = queue.pop(0)
            tool_call_id = tool_call["id"]
            tool_name = tool_call["function"]["name"]
            arguments = tool_call["function"]["arguments"]
            
            # 이미 처리된 도구라면 건너뜀
            if tool_name in processed_tools:
                continue

            # 의존성 확인 및 처리
            dependency_resolved = True
            for arg_key, arg_value in arguments.items():
                if isinstance(arg_value, str) and arg_value.startswith("@"):
                    # 의존성을 가진 값 처리
                    dep_tool, dep_attr = arg_value[1:].split(".result.")

                    # 의존성 충족: 결과값으로 대체
                    if dep_tool in tool_results:
                        arguments[arg_key] = tool_results[dep_tool].get(dep_attr)

                    # 의존성 미충족: 큐로 다시 삽입
                    else:
                        dependency_resolved = False
                        break

            # 의존성이 충족된 경우 도구 호출 실행
            # Step 3. 함수 실행 — 응답 기반으로 실제 함수 호출
            if dependency_resolved:
                response = process_tool_calls(tool_name, arguments)

                # 결과 저장
                if isinstance(response, list) and response and isinstance(response[0], dict):
                    tool_results[tool_name] = response[0].get("response", {})
                elif isinstance(response, dict):
                    tool_results[tool_name] = response.get("response", {})
                else:
                    tool_results[tool_name] = {}

                messages.append({"role": "assistant", "content": "", "toolCalls": [tool_call]})
                messages.append({"role": "tool", "content": str(tool_results[tool_name]), "toolCallId": tool_call_id})

                print(f"Assistant: {tool_call}\n")
                print(f"Tool: {tool_results[tool_name]}\n")
                processed_tools.add(tool_name)

            # 의존성이 충족되지 않은 경우 다시 큐에 삽입 
            else:
                queue.append(tool_call)

        # Step 4. 요청 — 함수 실행 결과 전달
        chat_response = chat_completions(
            messages = messages,
            seed = 0,
            topP = 0.8,
            topK = 0,
            maxTokens = 1024,
            temperature = 0.5,
            repeatPenalty = 1.1,
            stopBefore = [],
            includeAiFilters = True 
        )
        # Step 5. 응답 — 최종 답변 추출
        final_answer = chat_response.get("result").get("message").get("content")
        print(f'Assistant: {final_answer}')

except Exception as e:
    error_message = f"요청 처리 중 오류가 발생했습니다: {str(e)}"
    messages.append({"content": error_message, "role": "assistant"})
    print(f"Assistant: {error_message}")

 

 

User: 오늘 테슬라 주가 알려주고 한화로 계산하면 얼마인지 계산해줘

Assistant: {'id': 'call_QqLOLiZYwgqG44mXXNP2ktHL', 'type': 'function', 'function': {'name': 'get_stock_data', 'arguments': {'ticker': 'TSLA', 'date': '2025-04-08', 'result_type': 'price'}}}

Tool: {'date': '2025-04-08', 'price': 233.2899932861328}

Assistant: {'id': 'call_Gc7gkcZUItMKF3n6sw3p6nw3', 'type': 'function', 'function': {'name': 'calculate_currency', 'arguments': {'from_currency': 'USD', 'to_currency': 'KRW', 'amount': 233.2899932861328, 'date': '2025-04-08'}}}

Tool: 346487.31 KRW

Assistant: 2025 4 08 기준으로 테슬라(TSLA)의 주가는 **233.29 USD**이며, 이를 한화로 환산하면  **346,487원**입니다.

마무리


CLOVA Studio의 Chat Completions v3 API를 활용해, 도구(Function)를 호출하고 자연스러운 대화 응답을 생성하는 방법을 살펴보았습니다. 이번 쿡북을 통해 Function calling의 작동 원리를 이해하고, 이를 활용해 자신만의 데이터 소스와 도구를 결합하여 AI 어시스턴트를 제작해 보시길 바랍니다!

 

 

image.png.c6bf7699242321672b3693ab44d64d1a.png

 

  • Like 1
링크 복사
다른 사이트에 공유하기

게시글 및 댓글을 작성하려면 로그인 해주세요.



로그인
×
×
  • Create New...