Tool Use 는 실제로 무엇을 하는가
"모델이 도구를 호출한다"는 표현은 오해를 부릅니다. 실제로는 모델이 아무것도 실행하지 않습니다. 모델은 "이 함수를 이 인자로 실행해 달라"는 요청을 텍스트(정확히는 구조화된 JSON)로 만들어낼 뿐이고, 그걸 실제로 실행하는 건 여러분이 짠 코드입니다. 이 구분을 헷갈리면 에이전트가 왜 가끔 없는 함수를 부르거나 이상한 인자를 넣는지 이해할 수 없습니다.
tools 파라미터는 프롬프트다
API에 tools 배열을 넘기면 내부적으로 무슨 일이 일어날까요. 마법은 없습니다. 여러분이 정의한 도구 스키마가 시스템 프롬프트 어딘가에 특수한 형식으로 삽입되고, 모델은 학습 과정에서 이 형식을 인식하도록 훈련되어 있을 뿐입니다.
tools = [
{
"name": "get_weather",
"description": "주어진 도시의 현재 날씨를 조회한다.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "도시 이름, 예: 서울"}
},
"required": ["city"]
}
}
]description을 대충 쓰면 모델도 대충 씁니다. "날씨 조회"라고만 쓰면 모델이 도쿄와 토쿄, 서울과 Seoul을 구분 못 하고 엉뚱한 값을 넣는 일이 실제로 생깁니다. 저는 도구 설명에 예시 입력을 하나씩 넣어 두는 편인데, 그게 프롬프트 엔지니어링치고 비용 대비 효과가 제일 좋았습니다.
응답이 돌아오는 모양
도구가 필요하다고 판단하면 모델은 텍스트 대신 이런 콘텐츠 블록을 반환합니다.
{
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"city": "서울"}
}
]
}여기서 중요한 건 stop_reason입니다. 이 값이 tool_use면 모델은 "나는 아직 할 말이 안 끝났고, 이 도구 결과를 받아야 이어갈 수 있다"고 말하는 겁니다. end_turn이면 도구 없이 답이 나온 겁니다. 에이전트 루프는 사실상 이 stop_reason 하나를 보고 분기하는 게 전부입니다 — 이 단순함이 5장에서 루프 코드가 짧아지는 이유입니다.
모델은 스키마를 어길 수 있다
required: ["city"]라고 선언해도, 모델이 city 없이 도구를 부르는 경우가 실제로 있습니다. 특히 프롬프트가 복잡해지거나 대화가 길어질수록 빈도가 올라갑니다. input_schema는 모델에게 주는 힌트이지, 코드 레벨의 타입 보장이 아닙니다. 실제 실행 코드에서는 반드시 별도로 검증해야 합니다.
def execute_tool(name: str, input: dict) -> str:
if name == "get_weather":
city = input.get("city")
if not city:
return "오류: city 파라미터가 없습니다. 다시 요청하세요."
return get_weather(city)
return f"오류: 알 수 없는 도구 {name}"여기서 눈여겨볼 부분은 오류를 예외로 던지지 않고 문자열로 돌려준다는 점입니다. 에이전트 루프에서 도구 실행이 실패했을 때 프로그램을 죽이면 안 됩니다 — 그 실패 메시지 자체를 모델에게 다시 보여줘서 스스로 정정하게 하는 게 에이전트 패턴의 핵심입니다. 사람이라면 실수를 지적받고 고치듯, 모델도 "city가 없다"는 오류 메시지를 보면 대개 다음 턴에 제대로 채워 넣습니다.
병렬 도구 호출
최신 모델은 한 번의 응답에 도구 호출을 여러 개 담아 보낼 수 있습니다. content 배열에 tool_use 블록이 두 개 이상 들어 있는 경우입니다. 이걸 순차로 처리할지 병렬로 처리할지는 여러분의 실행 코드가 정합니다 — API가 정해 주지 않습니다. 서로 의존관계가 없는 조회성 도구(날씨 조회, 재고 확인 등)라면 병렬 실행이 지연시간을 크게 줄여 줍니다. 반대로 한 도구의 결과가 다음 도구의 입력이 되어야 하는 상황이라면 애초에 모델이 그렇게 병렬로 부르지 않도록 도구 설명에서 순서를 암시해 주는 게 낫습니다.