한국어
Week 1: 기초
02. Tool Calling

02. Tool Calling & 구조화된 출력

개요

이번 세션에서는 정규식 기반 파싱에서 Pydantic과 OpenAI Function Calling API를 사용한 구조화된 도구 호출로 발전합니다. 이를 통해 타입 안전성, 유효성 검사, 신뢰성을 얻을 수 있습니다.

왜 Function Calling인가?

정규식 파싱Function Calling
❌ 취약함✅ 견고함
❌ 타입 체크 없음✅ 완전한 타입 안전성
❌ 일관성 없음✅ 형식 보장
❌ 유지보수 어려움✅ 확장 용이

핵심 개념

도구 스키마를 위한 Pydantic

완전한 타입 안전성으로 도구 파라미터를 정의합니다:

from pydantic import BaseModel, Field
 
class CalculatorInput(BaseModel):
    """계산기 도구의 입력 스키마"""
    expression: str = Field(
        description="계산할 수학 표현식"
    )

OpenAI 형식으로 변환

OpenAI는 특정 JSON 스키마 형식을 기대합니다:

def pydantic_to_openai_function(model, name, description):
    return {
        "type": "function",
        "function": {
            "name": name,
            "description": description,
            "parameters": model.model_json_schema()
        }
    }

Function Calling 흐름

실습

노트북에서 다음을 수행합니다:

  1. Pydantic 스키마 정의 - Calculator, Search, Weather 도구
  2. OpenAI 형식으로 변환 - tools 배열 구축
  3. 도구 핸들러 구현 - 실제 실행 로직
  4. FunctionCallingAgent 구축 - 완전한 에이전트 클래스
  5. Tavily 통합 - 실제 웹 검색 기능

Tavily 통합

Tavily API 키가 있으면 실제 웹 검색이 가능합니다:

from tavily import TavilyClient
client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
results = client.search(query, max_results=5)

비교: 이전 vs 이후

이전 (정규식 파싱)

# 취약함 - 쉽게 깨짐
pattern = r"Action:\s*(\w+)\[(.+?)\]"
match = re.search(pattern, response)

이후 (Function Calling)

# 견고함 - 구조 보장
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto"
)
 
for tool_call in response.message.tool_calls:
    # 타입 안전, 검증된 인자
    args = json.loads(tool_call.function.arguments)

모범 사례

⚠️

팁: Function Calling을 사용하더라도 항상 도구 인자를 검증하세요. LLM도 실수할 수 있습니다.

  1. 설명적인 스키마 - 더 좋은 설명 = 더 좋은 도구 선택
  2. 에러 처리 - 도구 실행을 try/except로 감싸기
  3. 로깅 - 디버깅을 위해 모든 도구 호출 기록
  4. 타임아웃 - 외부 API는 멈출 수 있음

다음 단계

실제로 무언가를 만들 준비가 되셨나요? 주말 프로젝트에서 개인 리서치 어시스턴트를 만들어보세요!