Claude API의 가장 강력한 기능 중 하나는 Tool Use(툴 사용)입니다.
이를 통해 Claude는 외부 API 호출, 데이터베이스 조회, 계산 수행 등 사전 정의된 함수를 실행할 수 있습니다.
이번 가이드에서는 Tool Use의 개념부터 실전 구현까지, Claude를 진정한 AI 에이전트로 변신시키는 방법을 단계별로 알아보겠습니다.

Tool Use란?
Tool Use(또는 Function Calling)는 Claude가 필요에 따라 외부 함수나 API를 호출할 수 있도록 하는 기능입니다.
기본 개념
일반적인 Claude 사용:
사용자: "샌프란시스코 날씨 알려줘"
Claude: "죄송하지만 실시간 날씨 정보에 접근할 수 없습니다..."
Tool Use를 사용한 Claude:
사용자: "샌프란시스코 날씨 알려줘"
Claude: [get_weather 함수 호출] → API에서 날씨 정보 가져옴
Claude: "샌프란시스코는 현재 15도이며 맑은 날씨입니다."
Tool의 두 가지 유형
1. Client Tools (클라이언트 도구)
- 개발자가 직접 구현한 함수
- 사용자 시스템에서 실행
- 예: 데이터베이스 조회, API 호출, 파일 읽기
2. Server Tools (서버 도구)
- Anthropic 서버에서 자동 실행
- 구현 불필요
- 예: Web Search (웹 검색), Web Fetch (웹페이지 가져오기)
이 글에서는 Client Tools 구현에 집중합니다.
Tool Use 작동 원리
Tool Use는 4단계로 작동합니다:
1. [개발자] → Claude에게 사용 가능한 도구 목록 제공
2. [Claude] → 사용자 질문 분석 후 필요한 도구 선택 및 파라미터 생성
3. [개발자] → 선택된 도구 실행 후 결과 반환
4. [Claude] → 도구 결과를 바탕으로 최종 답변 생성
첫 번째 Tool 구현
1단계: 도구 정의
도구는 다음 3가지 요소로 정의됩니다:
tool = {
"name": "get_weather", # 도구 이름 (함수명처럼 작성)
"description": "현재 날씨 조회", # Claude가 이해할 수 있는 설명
"input_schema": { # JSON Schema로 파라미터 정의
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "도시명, 예: Seoul, KR"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "온도 단위"
}
},
"required": ["location"] # 필수 파라미터
}
}
2단계: Claude에게 도구 전달
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
],
messages=[
{"role": "user", "content": "What's the weather in Seoul?"}
]
)
print(response)
3단계: Claude의 응답 처리
Claude는 다음과 같이 응답합니다:
{
"id": "msg_01Aq9w938a90dw8q",
"model": "claude-opus-4-6",
"stop_reason": "tool_use", # 도구 사용을 원한다는 신호
"content": [
{
"type": "text",
"text": "I'll check the weather in Seoul for you."
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9", # 도구 호출 ID
"name": "get_weather",
"input": {
"location": "Seoul, KR",
"unit": "celsius"
}
}
]
}
중요: stop_reason이 "tool_use"이면 Claude가 도구 실행을 원합니다!
4단계: 도구 실행 및 결과 반환
import requests
def get_weather(location, unit="celsius"):
"""실제 날씨 API 호출 함수"""
# 여기서는 예시를 위해 하드코딩
# 실제로는 OpenWeatherMap 등의 API 호출
return f"15 degrees {unit}"
# Claude의 응답에서 tool_use 추출
tool_use = None
for block in response.content:
if block.type == "tool_use":
tool_use = block
break
# 도구 실행
result = get_weather(
location=tool_use.input["location"],
unit=tool_use.input.get("unit", "celsius")
)
# Claude에게 결과 반환
final_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=[...], # 동일한 도구 정의
messages=[
{"role": "user", "content": "What's the weather in Seoul?"},
{
"role": "assistant",
"content": response.content # Claude의 이전 응답
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id, # 매칭되는 ID
"content": result # 도구 실행 결과
}
]
}
]
)
print(final_response.content[0].text)
# 출력: "The current weather in Seoul is 15 degrees Celsius."
실전 예제
예제 1: 계산기 도구
복잡한 수학 계산을 정확하게 수행:
import anthropic
import math
client = anthropic.Anthropic()
# 계산기 도구 정의
calculator_tool = {
"name": "calculator",
"description": "수학 계산 수행. 지원 연산: add, subtract, multiply, divide, sqrt, power",
"input_schema": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": ["add", "subtract", "multiply", "divide", "sqrt", "power"],
"description": "수행할 연산"
},
"a": {
"type": "number",
"description": "첫 번째 숫자"
},
"b": {
"type": "number",
"description": "두 번째 숫자 (sqrt는 불필요)"
}
},
"required": ["operation", "a"]
}
}
def calculator(operation, a, b=None):
"""계산 실행 함수"""
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
return a / b
elif operation == "sqrt":
return math.sqrt(a)
elif operation == "power":
return a ** b
def process_tool_call(user_message):
"""도구 호출 처리 전체 로직"""
# 1. 초기 요청
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[calculator_tool],
messages=[{"role": "user", "content": user_message}]
)
# 2. Tool use 확인
if response.stop_reason != "tool_use":
return response.content[0].text
# 3. 도구 실행
tool_use = next(block for block in response.content if block.type == "tool_use")
result = calculator(
operation=tool_use.input["operation"],
a=tool_use.input["a"],
b=tool_use.input.get("b")
)
# 4. 결과 반환
final_response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[calculator_tool],
messages=[
{"role": "user", "content": user_message},
{"role": "assistant", "content": response.content},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(result)
}
]
}
]
)
return final_response.content[0].text
# 사용 예시
print(process_tool_call("123.45 곱하기 678.90은 얼마인가요?"))
# 출력: "123.45 곱하기 678.90은 83,810.055입니다."
예제 2: 데이터베이스 조회 도구
사용자 정보를 데이터베이스에서 조회:
import anthropic
import sqlite3
client = anthropic.Anthropic()
# 데이터베이스 초기화 (예시)
def init_db():
conn = sqlite3.connect('users.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS users
(id INTEGER PRIMARY KEY, name TEXT, email TEXT, age INTEGER)''')
c.execute("INSERT OR IGNORE INTO users VALUES (1, 'Alice', 'alice@example.com', 30)")
c.execute("INSERT OR IGNORE INTO users VALUES (2, 'Bob', 'bob@example.com', 25)")
conn.commit()
conn.close()
init_db()
# 데이터베이스 조회 도구
db_query_tool = {
"name": "query_user",
"description": "사용자 ID로 사용자 정보 조회",
"input_schema": {
"type": "object",
"properties": {
"user_id": {
"type": "integer",
"description": "조회할 사용자 ID"
}
},
"required": ["user_id"]
}
}
def query_user(user_id):
"""데이터베이스에서 사용자 조회"""
conn = sqlite3.connect('users.db')
c = conn.cursor()
c.execute("SELECT * FROM users WHERE id = ?", (user_id,))
result = c.fetchone()
conn.close()
if result:
return f"ID: {result[0]}, 이름: {result[1]}, 이메일: {result[2]}, 나이: {result[3]}"
else:
return "사용자를 찾을 수 없습니다."
# 전체 대화 처리
conversation = []
def chat_with_db(user_message):
conversation.append({"role": "user", "content": user_message})
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[db_query_tool],
messages=conversation
)
# Tool use 처리
if response.stop_reason == "tool_use":
conversation.append({"role": "assistant", "content": response.content})
for block in response.content:
if block.type == "tool_use":
result = query_user(user_id=block.input["user_id"])
conversation.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": block.id,
"content": result
}]
})
# 최종 응답 생성
final_response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[db_query_tool],
messages=conversation
)
return final_response.content[0].text
return response.content[0].text
# 사용 예시
print(chat_with_db("사용자 ID 1번의 정보를 알려주세요."))
# 출력: "사용자 ID 1번은 Alice이며, 이메일은 alice@example.com, 나이는 30세입니다."
예제 3: 여러 도구 사용 (병렬 호출)
Claude는 독립적인 작업을 병렬로 처리할 수 있습니다:
import anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "특정 도시의 날씨 조회",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
},
{
"name": "get_time",
"description": "특정 시간대의 현재 시간 조회",
"input_schema": {
"type": "object",
"properties": {
"timezone": {"type": "string"}
},
"required": ["timezone"]
}
}
]
def get_weather(location):
# 실제로는 API 호출
return f"{location}의 날씨: 맑음, 15도"
def get_time(timezone):
# 실제로는 시간 계산
return f"{timezone} 시간: 오후 3:00"
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=tools,
messages=[{
"role": "user",
"content": "뉴욕의 날씨와 현재 시간을 알려주세요."
}]
)
# 모든 tool_use 추출
tool_uses = [block for block in response.content if block.type == "tool_use"]
# 모든 도구를 실행하고 결과 수집
tool_results = []
for tool_use in tool_uses:
if tool_use.name == "get_weather":
result = get_weather(tool_use.input["location"])
elif tool_use.name == "get_time":
result = get_time(tool_use.input["timezone"])
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": result
})
# 모든 결과를 한 번에 반환
final_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "뉴욕의 날씨와 현재 시간을 알려주세요."},
{"role": "assistant", "content": response.content},
{"role": "user", "content": tool_results}
]
)
print(final_response.content[0].text)
# 출력: "뉴욕은 현재 맑은 날씨에 15도이며, 현지 시간은 오후 3:00입니다."
고급 패턴
1. 순차적 도구 호출
하나의 도구 결과를 다음 도구의 입력으로 사용:
tools = [
{
"name": "get_user_location",
"description": "사용자의 현재 위치 조회 (IP 기반)",
"input_schema": {
"type": "object",
"properties": {} # 파라미터 없음
}
},
{
"name": "get_weather",
"description": "특정 위치의 날씨 조회",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
]
# 사용자: "내 위치의 날씨는?"
# Claude: get_user_location 호출 → 결과: "Seoul, KR"
# Claude: get_weather(location="Seoul, KR") 호출 → 결과: "15도"
# Claude: "서울은 현재 15도입니다."
2. 에러 처리
도구 실행 실패 시 Claude에게 에러 전달:
try:
result = get_weather(location=tool_use.input["location"])
except Exception as e:
# 에러를 Claude에게 전달
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": f"Error: {str(e)}",
"is_error": True # 에러 플래그
})
Claude는 에러를 이해하고 사용자에게 적절히 설명합니다:
"죄송합니다. 날씨 정보를 가져오는 중 오류가 발생했습니다.
잠시 후 다시 시도해주세요."
3. Tool Choice 제어
Claude의 도구 사용을 제어:
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=[...],
tool_choice={
"type": "tool",
"name": "get_weather" # 반드시 get_weather 사용
},
messages=[...]
)
Tool Choice 옵션:
{"type": "auto"}(기본값): Claude가 자동 판단{"type": "any"}: 반드시 어떤 도구든 사용{"type": "tool", "name": "도구명"}: 특정 도구만 사용
4. Strict Tool Use (스키마 검증 보장)
프로덕션 환경에서 도구 파라미터 검증 보장:
tools = [
{
"name": "create_user",
"description": "신규 사용자 생성",
"input_schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name", "age"]
},
"strict": True # 스키마 검증 강제
}
]
strict: true를 사용하면 Claude가 반드시 스키마를 정확히 따릅니다.
Best Practics
1. 명확한 도구 설명 작성
# ❌ 나쁜 예
"description": "Get weather"
# ✅ 좋은 예
"description": "Get the current weather conditions including temperature, humidity, and precipitation for a specified location. Returns data in real-time from weather APIs."
2. 파라미터 설명 상세화
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA or Seoul, South Korea. Use the format 'City, Country' for international locations."
}
}
3. 도구 개수 제한
- 권장: 5-10개 이하
- 최대: 20개 (성능 저하 가능)
너무 많은 도구는 Claude의 선택을 어렵게 만듭니다.
4. 도구 결과는 간결하게
# ❌ 너무 장황한 결과
result = """
날씨 정보:
==========
온도: 15도
습도: 60%
강수량: 0mm
풍속: 3m/s
...
(100줄 이상)
"""
# ✅ 간결한 결과
result = "Temperature: 15°C, Humidity: 60%, Clear sky"
5. 도구 실행 타임아웃 설정
import requests
from requests.exceptions import Timeout
def call_external_api(url):
try:
response = requests.get(url, timeout=5) # 5초 타임아웃
return response.json()
except Timeout:
return "API 응답 시간 초과"

자주 묻는 질문 (FAQ)
Q1. Tool Use는 어떤 모델에서 사용 가능한가요?
A: 모든 Claude 모델(Opus, Sonnet, Haiku)에서 지원됩니다. 단, 모델별 성능 차이가 있습니다:
- Opus 4.6/4.5: 복잡한 도구 체인 및 추론에 최적
- Sonnet 4.5: 대부분의 도구 사용에 충분, 가성비 최고
- Haiku 4.5: 간단한 도구 호출에 적합, 가장 빠름
Q2. 도구 비용은 얼마나 추가되나요?
A: 도구 정의는 추가 입력 토큰으로 계산됩니다:
| 모델 | tool_choice: auto |
tool_choice: any |
|---|---|---|
| Opus 4.6 | +346 토큰 | +313 토큰 |
| Sonnet 4.5 | +346 토큰 | +313 토큰 |
| Haiku 4.5 | +346 토큰 | +313 토큰 |
예시 (Sonnet 4.5):
- 도구 정의: 346 토큰 ($0.001)
- 사용자 질문: 20 토큰 ($0.00006)
- 도구 응답: 50 토큰 출력 ($0.00075)
- 총 비용: ~$0.002 (약 3원)
Q3. 여러 도구를 동시에 호출할 수 있나요?
A: 네! Claude는 독립적인 작업을 병렬로 처리할 수 있습니다 (Parallel Tool Use). 예를 들어 "뉴욕 날씨와 시간"을 물으면 두 도구를 동시에 호출합니다.
Q4. 도구가 실패하면 어떻게 되나요?
A: is_error: true 플래그와 에러 메시지를 Claude에게 전달하면, Claude가 사용자에게 적절히 설명합니다:
{
"type": "tool_result",
"tool_use_id": "toolu_123",
"content": "API rate limit exceeded",
"is_error": True
}
Q5. Tool Use와 Structured Outputs의 차이는?
A:
| 기능 | Tool Use | Structured Outputs |
|---|---|---|
| 목적 | 외부 함수 실행 | JSON 형식 응답 생성 |
| 실행 주체 | 개발자 시스템 | Claude |
| 사용 사례 | API 호출, DB 조회 | 데이터 추출, 폼 작성 |
함께 사용 가능: Tool Use로 데이터를 가져오고, Structured Outputs로 정리된 JSON 반환!
Q6. Claude가 도구를 사용하지 않으면?
A: 다음을 확인하세요:
- 도구 설명이 명확한가? - 모호한 설명은 Claude가 이해 못함
- 파라미터가 적절한가? - required 파라미터 확인
- 질문이 도구와 관련있는가? - "안녕하세요"는 도구 불필요
- tool_choice 설정 확인 -
{"type": "any"}로 강제 가능
디버깅 팁: 시스템 프롬프트에 추가
system="도구를 최대한 활용하여 정확한 답변을 제공하세요."
실전 활용 시나리오
시나리오 1: 고객 지원 봇
tools = [
{"name": "query_order_status", "description": "주문 상태 조회"},
{"name": "update_shipping_address", "description": "배송지 변경"},
{"name": "request_refund", "description": "환불 요청"},
{"name": "search_faq", "description": "FAQ 검색"}
]
시나리오 2: 데이터 분석 에이전트
tools = [
{"name": "query_database", "description": "SQL 쿼리 실행"},
{"name": "generate_chart", "description": "차트 생성"},
{"name": "calculate_statistics", "description": "통계 계산"},
{"name": "export_report", "description": "보고서 내보내기"}
]
시나리오 3: 스마트 홈 제어
tools = [
{"name": "control_lights", "description": "조명 제어"},
{"name": "set_temperature", "description": "온도 설정"},
{"name": "check_security", "description": "보안 상태 확인"},
{"name": "play_music", "description": "음악 재생"}
]
결론 - Tool Use로 Claude를 진정한 AI 에이전트로
Tool Use는 Claude를 단순한 대화형 AI에서 실제 작업을 수행하는 에이전트로 진화시킵니다.
핵심 요약:
- 도구 정의: name, description, input_schema
- stop_reason 확인:
"tool_use"면 도구 실행 필요 - 결과 반환: tool_result로 도구 실행 결과 전달
- 에러 처리: is_error 플래그 활용
- 병렬 처리: 여러 도구를 동시에 실행 가능
다음 단계:
이제 Part 1 (Claude API 기초)을 완료했습니다! Part 2에서는 Claude Code를 다룹니다:
- 6편: Claude Code 설치 및 시작하기
- 7편: 핵심 명령어 & 슬래시 커맨드
- 8편: VS Code 연동
📌 관련 글:
🔗 참고 자료:
Sources:
'개발&프로그래밍' 카테고리의 다른 글
| [Claude] Claude Code 핵심 명령어 & 슬래시 커맨드 총정리 (0) | 2026.02.11 |
|---|---|
| [Claude] Claude Code 설치 및 시작하기 (Mac/Windows/Linux) (0) | 2026.02.10 |
| [Claude] Claude API 요금제 & 비용 최적화 전략 (프롬프트 캐싱 활용법) (0) | 2026.02.10 |
| [Claude] Claude API Python SDK 사용법 완벽 가이드 (0) | 2026.02.09 |
| [Claude] Claude API 모델 비교 - Opus vs Sonnet vs Haiku 선택 가이드 (1) | 2026.02.09 |
댓글