[실무 강의] AI에 행동 능력 부여! ChatGPT 함수 호출(Function Calling)로 실시간 웹 API 연동하기 완벽 마스터 튜토리얼

1. 학습 목표: AI가 단순 답변을 넘어 ‘행동’하게 만드는 기술

2026년 현재, 단순히 텍스트를 생성하는 AI의 시대는 지났습니다. 이제는 AI가 직접 외부 시스템과 상호작용하고, 실시간 데이터를 조회하며, 사용자의 요청에 따라 실제 작업을 수행하는 ‘AI 에이전트’의 시대입니다. 이번 강의에서는 OpenAI의 함수 호출(Function Calling) 기능을 활용하여, ChatGPT가 실시간 웹 API(날씨 정보)를 직접 호출하고 그 결과를 바탕으로 답변하는 구조를 설계하고 구현하는 법을 배웁니다.

이 과정을 마치면 여러분은 AI 모델에 ‘손과 발’을 달아주는 원리를 이해하게 되며, 이를 응용해 사내 데이터베이스 조회, 이메일 발송, 스마트홈 제어 등 무궁무진한 기능을 AI에 통합할 수 있게 됩니다.

2. 사전 준비 사항

본 실습을 원활하게 진행하기 위해 아래의 환경을 권장하며, 필수 라이브러리를 미리 설치해 주시기 바랍니다.

2.1 개발 환경 구성

  • 운영체제(OS): Windows 11, macOS Sequoia, 또는 Ubuntu 24.04 이상
  • 코드 에디터: Visual Studio Code (VS Code) 최신 버전
  • 파이썬 버전: Python 3.11 이상 (안정적인 비동기 처리를 위해 권장)

2.2 필수 라이브러리 설치

터미널(Terminal) 또는 명령 프롬프트(CMD)를 열고 아래 명령어를 입력하여 필요한 패키지를 설치합니다.

pip install openai requests python-dotenv

2.3 API 키 준비

  • OpenAI API Key: OpenAI 플랫폼에서 발급받은 API 키가 필요합니다.
  • OpenWeatherMap API Key: 실시간 날씨 데이터를 가져오기 위해 OpenWeatherMap에서 무료 API 키를 발급받으세요.

3. 단계별 실습 과정

Step 1: 환경 변수 설정 (.env)

보안을 위해 API 키를 소스 코드에 직접 노출하지 않고 환경 변수 파일로 관리합니다. 프로젝트 루트 폴더에 .env 파일을 생성하고 다음과 같이 작성합니다.

OPENAI_API_KEY=your_openai_api_key_here
WEATHER_API_KEY=your_weather_api_key_here

Step 2: 외부 API 연동 함수 정의

먼저 AI가 호출하게 될 실제 파이썬 함수를 작성합니다. 이 함수는 위도와 경도 또는 도시 이름을 받아 실시간 날씨를 반환합니다.

import requests
import os
from dotenv import load_dotenv

load_dotenv()

def get_current_weather(location, unit="metric"):
    """지정된 지역의 현재 날씨 정보를 가져옵니다."""
    api_key = os.getenv("WEATHER_API_KEY")
    base_url = "https://api.openweathermap.org/data/2.5/weather"
    
    params = {
        "q": location,
        "appid": api_key,
        "units": unit,
        "lang": "kr"
    }
    
    response = requests.get(base_url, params=params)
    if response.status_code == 200:
        data = response.json()
        weather_desc = data['weather'][0]['description']
        temp = data['main']['temp']
        return f"{location}의 현재 날씨는 {weather_desc}이며, 기온은 {temp}도입니다."
    else:
        return "날씨 정보를 가져오는 데 실패했습니다."

Step 3: ChatGPT에게 함수 정보 전달 (Tools 정의)

AI 모델은 우리가 만든 함수가 무엇인지 모릅니다. 따라서 JSON Schema 형태의 명세서를 작성하여 AI에게 어떤 상황에 이 함수를 써야 하는지 알려주어야 합니다.

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "특정 지역의 현재 날씨 정보를 조회합니다.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "도시 이름 (예: 서울, 도쿄)",
                    },
                    "unit": {"type": "string", "enum": ["metric", "imperial"]},
                },
                "required": ["location"],
            },
        },
    }
]

Step 4: 함수 호출 로직 구현

이제 핵심 로직을 작성합니다. 이 로직은 [사용자 질문 -> 모델 판단 -> 함수 실행 -> 결과 전달 -> 최종 답변]의 흐름을 가집니다.

from openai import OpenAI
import json

client = OpenAI()

def run_conversation(user_prompt):
    # 1. 모델에게 질문과 사용 가능한 도구 목록을 전달
    messages = [{"role": "user", "content": user_prompt}]
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )
    
    response_message = response.choices[0].message
    tool_calls = response_message.tool_calls

    # 2. 모델이 함수 호출이 필요하다고 판단했는지 확인
    if tool_calls:
        # 사용 가능한 함수 매핑
        available_functions = {
            "get_current_weather": get_current_weather,
        }
        
        messages.append(response_message) # 모델의 요청을 대화 내역에 추가

        # 3. 모델이 요청한 모든 함수를 순차적으로 실행
        for tool_call in tool_calls:
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            
            function_response = function_to_call(
                location=function_args.get("location"),
                unit=function_args.get("unit", "metric"),
            )
            
            # 4. 함수 실행 결과를 다시 모델에게 전달
            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )
        
        # 5. 모델이 정보를 취합하여 최종 답변 생성
        second_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
        )
        return second_response.choices[0].message.content
    
    return response_message.content

4. 결과 확인

작성한 코드를 실행하여 AI가 실제로 외부 API 데이터를 활용하는지 테스트합니다.

# 테스트 실행
if __name__ == "__main__":
    user_input = "지금 서울 날씨 어때? 그리고 거기 어울리는 옷차림도 추천해줘."
    result = run_conversation(user_input)
    print(f"AI 답변: {result}")

예상 출력: “현재 서울의 날씨는 맑음이며 기온은 22도입니다. 선선한 날씨이므로 가벼운 셔츠나 얇은 가디건을 걸치시는 것을 추천합니다.”

위 결과에서 알 수 있듯이, AI는 학습 데이터에 없는 ‘현재 실시간 날씨’를 API를 통해 파악한 뒤, 그 데이터를 기반으로 옷차림 추천이라는 지능적인 추론까지 수행하게 됩니다.

5. 실무 응용 팁 및 주의 사항

5.1 보안 및 유효성 검사

AI가 생성한 함수 인자값(arguments)은 항상 정확하지 않을 수 있습니다. 함수 내부에서 입력값에 대한 유효성 검사(Validation)를 반드시 수행해야 하며, 데이터베이스 삭제나 송금과 같은 민감한 작업은 반드시 사용자의 최종 승인 단계를 거치도록 설계해야 합니다.

5.2 토큰 소모 관리

함수 호출 과정에서 대화 내역(Messages)이 길어지면 토큰 소모가 늘어납니다. 불필요하게 큰 API 응답 결과는 요약하여 모델에게 전달하는 것이 비용 절감과 성능 향상에 도움이 됩니다.

5.3 다중 함수 호출(Parallel Function Calling)

최신 모델(GPT-4o 등)은 한 번의 답변에서 여러 개의 함수를 동시에 호출할 수 있습니다. 예를 들어 “서울과 뉴욕 날씨 둘 다 알려줘”라고 하면, 모델은 get_current_weather를 두 번 호출하도록 요청합니다. 위 실습 코드의 for tool_call in tool_calls: 루프가 이를 처리하는 핵심 로직입니다.

6. 마치며

함수 호출(Function Calling)은 AI를 단순한 챗봇에서 강력한 비즈니스 도구로 변모시키는 핵심 기술입니다. 오늘 배운 내용을 바탕으로 여러분의 업무 환경에 있는 다양한 API와 연동해 보세요. 데이터 분석, 자동 보고서 생성, 고객 응대 자동화 등 그 활용 가능성은 무궁무진합니다.

댓글 남기기


Fatal error: Uncaught ErrorException: md5_file(/hosting/apdldk/html/wp-content/litespeed/css/22f7f341f3ce7bc27932b62b5577a586.css.tmp): Failed to open stream: No such file or directory in /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php:148 Stack trace: #0 [internal function]: litespeed_exception_handler() #1 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php(148): md5_file() #2 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(845): LiteSpeed\Optimizer->serve() #3 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(338): LiteSpeed\Optimize->_build_hash_url() #4 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(265): LiteSpeed\Optimize->_optimize() #5 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(226): LiteSpeed\Optimize->_finalize() #6 /hosting/apdldk/html/wp-includes/class-wp-hook.php(341): LiteSpeed\Optimize->finalize() #7 /hosting/apdldk/html/wp-includes/plugin.php(205): WP_Hook->apply_filters() #8 /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/core.cls.php(464): apply_filters() #9 [internal function]: LiteSpeed\Core->send_headers_force() #10 /hosting/apdldk/html/wp-includes/functions.php(5481): ob_end_flush() #11 /hosting/apdldk/html/wp-includes/class-wp-hook.php(341): wp_ob_end_flush_all() #12 /hosting/apdldk/html/wp-includes/class-wp-hook.php(365): WP_Hook->apply_filters() #13 /hosting/apdldk/html/wp-includes/plugin.php(522): WP_Hook->do_action() #14 /hosting/apdldk/html/wp-includes/load.php(1308): do_action() #15 [internal function]: shutdown_action_hook() #16 {main} thrown in /hosting/apdldk/html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php on line 148