애플리케이션에서 도구 호출 처리
API 응답에서 finish_reason이 tool_calls인지 확인하고, 함수 이름과 인수를 추출한 다음 해당 Python 함수를 실행하고 결과를 모델에 다시 전달합니다.
애플리케이션에서 도구 호출 처리은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
도구 호출 응답 객체
모델이 함수를 호출하기로 결정하면 API 응답의 메시지 객체에 tool_calls 목록이 포함됩니다. 각 도구 호출에는 고유한 id, 호출할 function.name, 모델이 전달하려는 인수의 JSON 문자열인 function.arguments가 있습니다. 이를 파싱하고 함수를 실행하는 것은 애플리케이션 코드의 책임입니다.
from openai import OpenAI
import json
client = OpenAI()
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'What is the weather in Paris?'}],
tools=tools # defined previously
)
message = response.choices[0].message
if response.choices[0].finish_reason == 'tool_calls':
for tool_call in message.tool_calls:
print('Call ID:', tool_call.id)
print('Function name:', tool_call.function.name)
print('Arguments (JSON string):', tool_call.function.arguments)함수 인수 파싱하기
function.arguments 필드는 Python dict가 아니라 JSON으로 인코딩된 문자열입니다. json.loads()를 사용하여 파싱해야 합니다. 모델이 스키마 안내를 따르더라도 가끔 잘못된 JSON을 생성하므로 항상 try/except로 감싸고 적절히 처리하세요.
import json
def parse_tool_call(tool_call) -> dict:
'''Parse a tool call's arguments from JSON string to dict.'''
try:
args = json.loads(tool_call.function.arguments)
return args
except json.JSONDecodeError as e:
print(f'Failed to parse arguments for {tool_call.function.name}: {e}')
print(f'Raw arguments: {tool_call.function.arguments}')
return {}
# Usage
tool_call = message.tool_calls[0]
args = parse_tool_call(tool_call)
print('Parsed args:', args) # {'location': 'Paris', 'unit': 'celsius'}올바른 함수로 전달하기
function.name을 사용하여 올바른 Python 함수로 전달하세요. 깔끔한 방식은 함수를 이름과 호출 가능한 객체의 매핑인 사전에 저장하는 것입니다. 이렇게 하면 취약한 if/elif 연쇄를 피할 수 있고 나중에 새 도구를 쉽게 추가할 수 있습니다.
def get_current_weather(location: str, unit: str = 'celsius') -> str:
# Real implementation calls a weather API
return f'{location}: 18{chr(176)}C, partly cloudy'
def create_calendar_event(title: str, start_time: str, duration_minutes: int, **kwargs) -> str:
return f'Event created: {title} at {start_time} for {duration_minutes} minutes'
# Tool registry: maps function names to callables
TOOL_REGISTRY = {
'get_current_weather': get_current_weather,
'create_calendar_event': create_calendar_event
}
def execute_tool_call(tool_call) -> str:
name = tool_call.function.name
args = parse_tool_call(tool_call)
if name not in TOOL_REGISTRY:
return f'Unknown function: {name}'
try:
result = TOOL_REGISTRY[name](**args)
return str(result)
except Exception as e:
return f'Function {name} raised an error: {str(e)}'결과를 모델에 다시 보내기
함수를 실행한 후에는 후속 API 호출을 통해 결과를 모델에 다시 보내야 합니다. 도구 호출을 포함한 어시스턴트의 메시지를 대화에 추가한 다음, role='tool', tool_call_id, 함수 결과를 콘텐츠로 포함하는 새 메시지를 추가하세요. 그런 다음 API를 다시 호출합니다.
def run_tool_call_loop(messages: list, tools: list) -> str:
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
message = response.choices[0].message
messages.append(message) # Add assistant's tool_calls message
# Execute all tool calls and collect results
for tool_call in (message.tool_calls or []):
result = execute_tool_call(tool_call)
# Add each tool result as a 'tool' role message
messages.append({
'role': 'tool',
'tool_call_id': tool_call.id,
'content': result
})
# Second API call with results appended
final_response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
return final_response.choices[0].message.content전체 대화 한 차례
완전한 도구 호출 상호작용은 대화 기록에서 네 개의 메시지로 구성됩니다. 사용자의 메시지, 도구 호출을 요청하는 어시스턴트의 메시지, 도구 결과 메시지, 결과를 반영한 어시스턴트의 최종 응답입니다. 이 구조를 이해하는 것은 여러 차례에 걸쳐 도구를 사용하는 어시스턴트를 구축하는 데 필수적입니다.
# The full message history for a tool-calling conversation:
conversation = [
{'role': 'user', 'content': 'What is the weather in Tokyo?'},
# Model requests a tool call (added by run_tool_call_loop)
# {'role': 'assistant', 'content': None, 'tool_calls': [...]},
# Application sends tool result back
# {'role': 'tool', 'tool_call_id': 'call_abc123', 'content': 'Tokyo: 22C, sunny'},
# Model produces final human-readable response
# {'role': 'assistant', 'content': 'The weather in Tokyo is 22 degrees Celsius and sunny.'}
]
final_answer = run_tool_call_loop(
[{'role': 'user', 'content': 'What is the weather in Tokyo?'}],
tools
)
print(final_answer)도구가 호출되지 않는 경우 처리하기
모델이 도구를 호출하지 않고 직접 답변하는 경우가 있습니다. 이때 finish_reason은 'tool_calls'가 아니라 'stop'입니다. 도구 호출을 처리하기 전에 항상 이 경우인지 확인하세요. 견고한 구현은 두 분기를 모두 깔끔하게 처리합니다.
def smart_complete(user_message: str) -> str:
messages = [{'role': 'user', 'content': user_message}]
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
choice = response.choices[0]
if choice.finish_reason == 'stop':
# Model answered directly without calling a tool
return choice.message.content
elif choice.finish_reason == 'tool_calls':
# Process tool calls
messages.append(choice.message)
for tc in choice.message.tool_calls:
result = execute_tool_call(tc)
messages.append({'role': 'tool', 'tool_call_id': tc.id, 'content': result})
# Get final answer
final = client.chat.completions.create(model='gpt-4o', messages=messages)
return final.choices[0].message.content
return 'Unexpected finish reason: ' + choice.finish_reason실행 전에 인수 검증하기
모델이 비즈니스 로직 검증에 실패하는 인수를 전달하는 경우가 있습니다. 예를 들어 음수 기간, 유효하지 않은 이메일, 과거 날짜 등이 있습니다. 실제 함수를 호출하기 전에 인수를 검증하고, 검증에 실패하면 설명이 포함된 오류 문자열을 반환하세요. 그러면 모델이 다음 차례에 인수를 수정할 수 있습니다.
from pydantic import BaseModel, ValidationError
from datetime import datetime
class CreateEventArgs(BaseModel):
title: str
start_time: str # ISO 8601
duration_minutes: int
def safe_create_event(tool_call) -> str:
try:
raw_args = json.loads(tool_call.function.arguments)
validated = CreateEventArgs(**raw_args)
# Additional business rule
event_time = datetime.fromisoformat(validated.start_time)
if event_time < datetime.now():
return 'Error: start_time must be in the future.'
return create_calendar_event(**validated.dict())
except ValidationError as e:
return f'Invalid arguments: {e}'도구 호출 상호작용 기록하기
디버깅과 분석을 위해 도구 호출 상호작용을 항상 기록하세요. 함수 이름, 인수, 결과, 실행 시간을 기록합니다. 이 데이터는 어떤 도구가 가장 자주 호출되는지, 어떤 도구가 실패하는지, 모델이 어떤 인수 패턴을 생성하는지 파악하는 데 도움이 되며, 스키마와 함수 구현을 개선하는 데 매우 중요합니다.
import time
import logging
logger = logging.getLogger('tool_calls')
def logged_execute(tool_call) -> str:
name = tool_call.function.name
args_str = tool_call.function.arguments
start = time.time()
result = execute_tool_call(tool_call)
elapsed = time.time() - start
logger.info(
'Tool call executed',
extra={
'function': name,
'arguments': args_str,
'result_length': len(result),
'elapsed_ms': round(elapsed * 1000)
}
)
return result도구 호출 보안 고려 사항
검증 없이 모델 출력에 따라 임의의 함수를 실행하지 마세요. TOOL_REGISTRY에는 정확한 함수 이름만 허용 목록으로 등록하고, 모든 인수를 검증하며, 작업을 실행하기 전에 권한을 확인하세요. 모델은 신뢰할 수 없는 호출자입니다. 전달 로직이 지나치게 허술하면 악의적인 프롬프트가 파괴적인 함수를 호출하려고 시도할 수 있습니다.
- TOOL_REGISTRY에 명시적으로 등록된 함수만 허용합니다
- 실행 전에 Pydantic으로 입력을 검증합니다
- 쓰기 및 삭제 작업에는 권한을 요구합니다
풍부한 구조화 결과 반환하기
도구 결과가 일반 문자열일 필요는 없습니다. JSON 형식의 데이터, 표 또는 요약을 반환할 수 있습니다. 구조화된 데이터를 JSON으로 반환하면 모델이 최종 답변에서 특정 필드를 파싱하고 참조할 수 있습니다. 결과가 큰 경우 모든 원시 데이터를 컨텍스트에 그대로 넣기보다 핵심 사실이 담긴 요약을 반환하세요.
def get_order_status(order_id: str) -> str:
# Fetch from real database
order = {'id': order_id, 'status': 'shipped', 'estimated_delivery': '2024-03-15', 'carrier': 'FedEx', 'tracking': 'FX123456'}
# Return concise summary, not raw DB record
return (
f'Order {order_id}: Status={order["status"]}, '
f'Estimated delivery: {order["estimated_delivery"]}, '
f'Carrier: {order["carrier"]}, Tracking: {order["tracking"]}'
)여러 차례에 걸친 도구 사용 대화
강력한 방식 중 하나는 모델이 여러 사용자의 메시지에 걸쳐 도구를 호출하며 컨텍스트를 쌓아 가는 여러 차례의 대화입니다. 모델이 이전 답변을 참조하고 불필요하게 도구를 다시 호출하지 않도록 과거의 도구 호출과 결과를 포함한 전체 대화 기록을 항상 유지하세요.
빠른 확인
애플리케이션에서 도구 호출을 처리하는 방법에 대한 이해도를 테스트해 보세요.
레슨 요약
이 레슨에서는 다음을 배웠습니다. 도구 호출 인수는 json.loads()로 파싱해야 하는 JSON 문자열로 전달됩니다. 또한 TOOL_REGISTRY 사전은 함수 이름을 호출 가능한 객체에 매핑하여 깔끔하게 전달합니다. 그리고 결과는 일치하는 tool_call_id가 포함된 role='tool' 메시지로 모델에 돌아갑니다. 다음으로는 모델이 병렬 함수 호출을 사용하여 여러 함수를 동시에 호출하는 경우를 처리하는 방법을 알아봅니다.
자주 묻는 질문
“애플리케이션에서 도구 호출 처리” 강의는 무료인가요?
네 — “애플리케이션에서 도구 호출 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“애플리케이션에서 도구 호출 처리”에서 뭘 배우나요?
API 응답에서 finish_reason이 tool_calls인지 확인하고, 함수 이름과 인수를 추출한 다음 해당 Python 함수를 실행하고 결과를 모델에 다시 전달합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“애플리케이션에서 도구 호출 처리” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- API용 함수 스키마 정의
- 애플리케이션에서 도구 호출 처리
- 병렬 함수 호출
- 자연어 데이터베이스 인터페이스 구축