Phase 3: API 활용 | 예상 학습 시간: 30분
🎯 학습 목표
- Client tool과 Server tool의 실행 위치 차이를 설명하고, 상황에 맞게 선택할 수 있다
input_schema와tool_choice를 사용해 Claude의 도구 호출 방식을 설계할 수 있다tool_use→ 실행 →tool_result로 이어지는 전체 루프를 Python 코드로 구현할 수 있다
1. Tool Use란 무엇인가 — Client Tool vs Server Tool
Tool Use(Function Calling)는 Claude가 스스로 답할 수 없는 질문에 부딪혀 외부 함수나 API를 “호출"하도록 만드는 기능입니다. 정확히 말하면 Claude가 직접 코드를 실행하는 것이 아니라, “이 도구를 이런 입력으로 불러달라"는 구조화된 요청(JSON)을 반환할 뿐입니다. 실제 실행은 도구의 종류에 따라 둘 중 한 곳에서 일어납니다.
| 구분 | 실행 위치 | 예시 | 흐름 |
|---|---|---|---|
| Client tool | 내 애플리케이션 서버 | 사용자가 직접 정의한 함수, bash, text_editor | Claude가 tool_use 반환 → 내가 실행 → tool_result를 다시 전송 |
| Server tool | Anthropic 인프라 | web_search, web_fetch, code_execution | Claude가 호출부터 실행까지 처리 → 결과가 같은 응답에 포함 |
즉 “직접 만든 함수"는 항상 client tool이고, Anthropic이 스키마와 실행 환경을 모두 제공하는 몇 가지 도구만 server tool입니다. 이 강의에서는 실무에서 가장 많이 쓰는 client tool, 즉 사용자 정의 함수 연동에 집중합니다.
전체 흐름은 다음과 같은 반복 루프(agentic loop)입니다.
- 사용자가 질문을 보낸다
- Claude가
tools에 정의된 함수 중 필요한 것을 판단해stop_reason: "tool_use"와 함께tool_use블록을 반환한다 - 내 애플리케이션이 해당 함수를 실제로 실행한다
- 실행 결과를
tool_result블록으로 담아 다시 Claude에게 보낸다 - Claude가 결과를 바탕으로 최종 답변을 생성한다
이 루프는 한 번에 끝나지 않을 수도 있습니다. 복잡한 작업이라면 Claude가 도구를 여러 번 연쇄적으로 호출하기도 합니다.
2. Tool 정의하기 — input_schema와 tool_choice
도구는 요청의 tools 파라미터에 배열로 전달하며, 각 도구는 세 가지 핵심 필드로 구성됩니다.
- name:
^[a-zA-Z0-9_-]{1,64}$정규식을 만족하는 이름 - description: 도구가 무엇을 하는지, 언제 써야 하는지, 각 파라미터가 무엇을 의미하는지 최소 3~4문장으로 상세히 설명 — 이 항목의 품질이 도구 선택 정확도에 가장 큰 영향을 줍니다
- input_schema: 입력 파라미터를 정의하는 JSON Schema 객체
tools = [
{
"name": "get_weather",
"description": (
"지정한 도시의 현재 날씨 정보를 반환한다. "
"실시간 기온, 습도, 날씨 상태를 알려줄 때 사용하고, "
"미래 예보나 과거 날씨는 지원하지 않는다."
),
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "도시와 국가, 예: 'Seoul, South Korea'",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "온도 단위 (기본값: celsius)",
},
},
"required": ["location"],
},
}
]
Claude가 도구를 호출할지 여부는 tool_choice로 제어합니다.
| 값 | 동작 |
|---|---|
auto (기본값) | Claude가 상황에 맞게 스스로 판단 |
any | 반드시 도구 중 하나를 호출하되, 어떤 도구인지는 자유 |
{"type": "tool", "name": "..."} | 지정한 도구를 강제로 호출 |
none | 도구를 전혀 사용하지 않음 |
any나 특정 tool을 강제하면 Claude는 자연어 설명 없이 곧바로 tool_use 블록만 반환합니다. 도구 호출과 함께 자연스러운 설명도 원한다면 tool_choice는 auto로 두고, 시스템 프롬프트나 사용자 메시지에 “get_weather 도구를 사용해서 답해줘"처럼 명시적으로 지시하는 편이 낫습니다. 또한 strict: true를 도구 정의에 추가하면 Claude가 반환하는 입력이 스키마를 정확히 준수하도록 강제할 수 있어, 파싱 에러를 크게 줄일 수 있습니다.
3. 실습: 전체 Tool Use 루프 구현하기
실제로 함수를 실행하고 결과를 돌려주는 전체 루프를 구현해 보겠습니다. 핵심은 tool_use 블록의 id를 그대로 tool_result의 tool_use_id에 담아 매칭시키는 것입니다.
import anthropic
client = anthropic.Anthropic()
def get_weather(location: str, unit: str = "celsius") -> str:
# 실제로는 외부 날씨 API를 호출하는 부분
return f"{location}의 현재 기온은 22{unit[0].upper()}이고 맑음입니다."
messages = [{"role": "user", "content": "서울 날씨 어때?"}]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = get_weather(**block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({"role": "user", "content": tool_results})
final = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(final.content[0].text)
함수 실행 중 에러가 발생하면 tool_result에 "is_error": true를 추가해 Claude에게 실패를 알릴 수 있습니다. 이렇게 하면 Claude가 무작정 같은 결과를 다시 요청하지 않고, 다른 파라미터로 재시도하거나 사용자에게 상황을 설명하는 등 적절히 대응합니다.
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": "오류: 알 수 없는 도시명입니다.",
"is_error": True,
})
Claude가 한 응답 안에서 여러 도구를 동시에 호출하는 경우(parallel tool use)도 흔합니다. 이때는 response.content를 순회하며 tool_use 타입인 블록을 모두 처리한 뒤, 각각의 tool_result를 하나의 user 메시지에 함께 담아 보내야 합니다. 하나라도 빠뜨리면 다음 요청에서 400 에러가 발생하므로, 반환된 tool_use 블록 수와 보내는 tool_result 수가 항상 일치해야 합니다.
📝 핵심 요약
- Client tool은 내 애플리케이션이 실행하고 결과를
tool_result로 돌려줘야 하며, server tool(web_search등)은 Anthropic 인프라에서 실행되어 같은 응답에 결과가 포함된다 - 도구 정의의 핵심은
description이며, 무엇을 하는지·언제 쓰는지·파라미터 의미를 최소 3~4문장으로 상세히 적을수록 선택 정확도가 올라간다 tool_choice는auto/any/특정tool/none네 가지이며, 강제 호출 시 Claude는 자연어 설명 없이 곧바로 도구를 호출한다tool_use블록의id는 반드시tool_result의tool_use_id로 그대로 매칭해서 돌려줘야 하고, 병렬 호출 시에는 모든 호출에 대한 결과를 빠짐없이 보내야 한다- 실행 실패는
is_error: true로 알려주면 Claude가 재시도나 사용자 안내 등 스스로 적절히 대응한다
🔗 참고 자료
⬅️ 이전: Day 15 — Streaming 응답 처리 | 다음: Day 17 — Vision API ➡️