Tool Use와 함수 호출 — AI가 외부 세계와 연결되는 방법

…

한줄 요약

Function Calling은 LLM이 “이 함수를 호출해야겠다”고 스스로 판단하고 JSON 형식의 호출 신호를 출력하는 기술로, 에이전트가 실제 세계와 상호작용하는 핵심 메커니즘이다.


Function Calling이란

2023년 6월 OpenAI가 GPT-4에 도입하면서 널리 알려진 개념이다. LLM은 텍스트를 생성하는 대신, 미리 정의된 함수 목록 중 어떤 것을 호출할지를 JSON으로 출력한다.

기존 LLM 출력:

"메트포르민과 와파린의 상호작용은 혈당 저하 효과 증가입니다."

Function Calling 출력:

{
  "name": "check_drug_interaction",
  "arguments": {
    "drug_a": "metformin",
    "drug_b": "warfarin"
  }
}

LLM이 직접 답하지 않고, 답을 얻기 위한 함수 호출을 지시한다.


JSON Schema로 Tool 정의하기

Claude Tool Use API에서 도구는 JSON Schema로 정의한다.

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "search_drug_interaction",
        "description": "두 약물 간의 임상적 상호작용을 확인한다. "
                       "결과는 상호작용 심각도(major/moderate/minor)와 "
                       "권장 조치를 포함한다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "drug_a": {
                    "type": "string",
                    "description": "첫 번째 약물명 (성분명 또는 상품명)"
                },
                "drug_b": {
                    "type": "string",
                    "description": "두 번째 약물명 (성분명 또는 상품명)"
                }
            },
            "required": ["drug_a", "drug_b"]
        }
    },
    {
        "name": "lookup_guideline",
        "description": "ADA, ACC/AHA, KDA 등의 최신 의료 가이드라인을 검색한다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "society": {
                    "type": "string",
                    "enum": ["ADA", "ACC", "KDA", "KDIGO"],
                    "description": "검색할 학회 가이드라인"
                }
            },
            "required": ["query"]
        }
    },
    {
        "name": "calculate_dose",
        "description": "환자 체중, 신기능, 연령을 고려한 적정 약물 용량을 계산한다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "drug": {"type": "string"},
                "weight_kg": {"type": "number"},
                "egfr": {"type": "number", "description": "eGFR (mL/min/1.73m²)"},
                "age": {"type": "integer"}
            },
            "required": ["drug", "weight_kg", "egfr"]
        }
    }
]

Claude Tool Use API 실전 예시

def run_medical_agent(patient_query: str):
    messages = [{"role": "user", "content": patient_query}]

    while True:
        response = client.messages.create(
            model="claude-opus-4-5",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

        # 도구 호출이 없으면 최종 답변
        if response.stop_reason == "end_turn":
            return response.content[0].text

        # 도구 호출 처리
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                result = execute_tool(block.name, block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(result)
                })

        # 결과를 메시지에 추가하고 루프 계속
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": tool_results})


def execute_tool(name: str, inputs: dict) -> dict:
    """실제 도구 실행 함수 — 각 도구를 라우팅한다."""
    if name == "search_drug_interaction":
        return db.query_interaction(inputs["drug_a"], inputs["drug_b"])
    elif name == "lookup_guideline":
        return guideline_search(inputs["query"], inputs.get("society"))
    elif name == "calculate_dose":
        return dose_calculator(**inputs)
    else:
        return {"error": f"Unknown tool: {name}"}

안전한 Tool 설계 원칙

의료 환경에서 도구를 설계할 때 반드시 지켜야 할 원칙이 있다.

Read-only vs Write 구분:

# 안전 (읽기 전용)
"lookup_guideline"       # DB 조회만
"search_drug_interaction" # 조회만
"calculate_dose"          # 계산만

# 주의 필요 (쓰기)
"create_prescription"     # EMR에 처방 기록
"send_order"              # 원무팀에 지시 전송
"update_patient_record"   # 환자 기록 수정

쓰기 도구에는 반드시 human-in-the-loop 승인 단계를 추가해야 한다.

def create_prescription(drug: str, dose: str, patient_id: str) -> dict:
    # 직접 실행 금지 — 항상 초안으로 반환
    draft = {
        "status": "draft",
        "requires_physician_approval": True,
        "drug": drug,
        "dose": dose,
        "patient_id": patient_id
    }
    return draft  # 의사가 검토 후 별도 확정 버튼으로 실행

핵심 정리

  • Function Calling은 LLM이 텍스트 대신 구조화된 함수 호출 신호를 출력하는 기법이다
  • JSON Schema로 도구를 정의하면 LLM이 파라미터를 정확하게 채워 호출한다
  • Claude Tool Use API는 stop_reason: "tool_use" 신호로 도구 호출 요청을 전달한다
  • 의료 도구는 read-only를 기본으로 하고, 쓰기 작업에는 의사 승인 단계가 필수다
  • 도구 설명(description)의 품질이 LLM의 올바른 도구 선택을 결정한다

관련 글