/AI & 자동화/LLM 에이전트 툴 사용 완전 정복: Function Calling부터 MCP까지
AI & 자동화LLM에이전트

LLM 에이전트 툴 사용 완전 정복: Function Calling부터 MCP까지

LLM 에이전트가 외부 세계와 상호작용하는 핵심 메커니즘인 툴 사용(Tool Use)을 완전히 해부합니다. OpenAI Function Calling, Anthropic Tool Use, 그리고 Model Context Protocol(MCP)까지 코드와 함께 비교합니다.

LLM 에이전트 툴 사용 완전 정복: Function Calling부터 MCP까지

LLM 에이전트 툴 사용 완전 정복: Function Calling부터 MCP까지

에이전트를 에이전트답게 만드는 것은 **툴 사용(Tool Use)**입니다. LLM이 단순히 텍스트를 생성하는 것을 넘어, 외부 API를 호출하고, 데이터베이스를 조회하고, 코드를 실행하게 만드는 메커니즘입니다.

툴 사용의 동작 원리

LLM은 텍스트만 입력받고 텍스트만 출력합니다. 툴 사용은 이 제약을 아래 흐름으로 우회합니다.

CODE
1. 사용자 메시지 + 툴 스펙 → LLM
2. LLM → "이 툴을 이 인자로 호출하라" (JSON 형태 출력)
3. 런타임이 실제 함수 실행
4. 실행 결과 → LLM에게 다시 전달
5. LLM → 최종 자연어 답변 생성

핵심은 LLM이 직접 함수를 실행하지 않는다는 점입니다. 런타임이 실행하고, 결과를 LLM에게 넘겨줍니다.

OpenAI Function Calling

Python
from openai import OpenAI
import json

client = OpenAI()

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "특정 종목의 현재 주가를 조회합니다",
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {
                        "type": "string",
                        "description": "주식 티커 (예: AAPL, TSLA)"
                    },
                    "currency": {
                        "type": "string",
                        "enum": ["USD", "KRW"]
                    }
                },
                "required": ["symbol"]
            }
        }
    }
]

def get_stock_price(symbol, currency="USD"):
    return {"symbol": symbol, "price": 192.5, "currency": currency}

def run_agent(user_message):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        msg = response.choices[0].message
        messages.append(msg)

        if msg.tool_calls is None:
            return msg.content

        for tc in msg.tool_calls:
            args = json.loads(tc.function.arguments)
            result = get_stock_price(**args)
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": json.dumps(result)
            })

Anthropic Tool Use

Claude의 툴 사용은 tool_use 콘텐츠 블록으로 호출하고, tool_result로 반환합니다.

Python
import anthropic, json

client = anthropic.Anthropic()

tools = [{
    "name": "search_docs",
    "description": "내부 문서 데이터베이스에서 관련 문서를 검색합니다",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "max_results": {"type": "integer", "default": 5}
        },
        "required": ["query"]
    }
}]

def search_docs(query, max_results=5):
    return [{"title": "API 인증 가이드", "content": "Bearer 토큰 방식을 사용합니다..."}]

messages = [{"role": "user", "content": "우리 API 인증 방식이 어떻게 돼?"}]

while True:
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )

    if response.stop_reason == "end_turn":
        text_block = next(b for b in response.content if b.type == "text")
        print(text_block.text)
        break

    messages.append({"role": "assistant", "content": response.content})

    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            result = search_docs(**block.input)
            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(result, ensure_ascii=False)
            })
    messages.append({"role": "user", "content": tool_results})

Model Context Protocol (MCP)

MCP는 Anthropic이 제안한 툴 표준화 프로토콜입니다. 개별 LLM SDK에 종속되지 않고, 서버-클라이언트 구조로 툴을 독립적으로 제공합니다.

Python
# MCP 서버 구현
from mcp.server import Server
import mcp.types as types

server = Server("my-tools-server")

@server.list_tools()
async def handle_list_tools():
    return [
        types.Tool(
            name="query_database",
            description="SQL 쿼리를 실행하고 결과를 반환합니다",
            inputSchema={
                "type": "object",
                "properties": {
                    "sql": {"type": "string", "description": "실행할 SELECT 쿼리"}
                },
                "required": ["sql"]
            }
        )
    ]

@server.call_tool()
async def handle_call_tool(name, arguments):
    if name == "query_database":
        results = execute_query(arguments["sql"])
        return [types.TextContent(type="text", text=str(results))]

MCP의 장점은 재사용성입니다. 한 번 만든 MCP 서버는 Claude Desktop, Claude Code, 자체 에이전트 등 어디서든 연결해 쓸 수 있습니다.

툴 설계 원칙

좋은 툴과 나쁜 툴의 차이는 description에 있습니다.

나쁜 예좋은 예
"데이터를 가져온다""주문 ID로 특정 주문의 상태, 금액, 배송 정보를 조회한다. 취소된 주문도 조회 가능하다."
매개변수 설명 없음각 매개변수의 타입, 허용 값, 기본값 명시

LLM은 description을 읽고 툴을 선택합니다. 설명이 부정확하면 잘못된 툴을 호출하거나 잘못된 인자를 넣습니다.

병렬 툴 호출

여러 툴을 순차 실행하면 느립니다. GPT-4o와 Claude 모두 병렬 툴 호출을 지원합니다.

Python
import asyncio

async def execute_tools_parallel(tool_calls):
    tasks = [dispatch_tool(tc.function.name, json.loads(tc.function.arguments))
             for tc in tool_calls]
    return await asyncio.gather(*tasks)

다음 편에서는 에이전트가 대화 맥락을 유지하고 장기 작업을 수행할 수 있게 하는 메모리 시스템 설계를 다룹니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Director·검토 · 사람 편집자·발행 · 2026년 5월 20일

댓글

불러오는 중...