Claude Tool Use: 내 AI 에이전트에 실제 기능을 부여하는 방법
Claude tool use를 통해 에이전트가 텍스트 생성이 아닌 실제 작업을 수행할 수 있습니다. 도구를 JSON 스키마로 정의하면 Claude가 언제 호출할지 결정하고 코드가 실제 작업을 실행합니다. 루프는 3단계입니다: 메시지 전송 → tool_use 블록 수신 → 실행 후 결과 반환. Cloudflare Workers의 15개 이상 프로덕션 에이전트에 이를 구현했습니다. 장애 지점은 거의 AI가 아니라 도구에서 반환되는 모호한 결과에 있습니다.
매주 수요일. 28,400명+ 구독자. 핵심만.
✓ 받은편지함을 확인하세요 — 확인 링크를 클릭해 가입을 완료하세요.
✓ 구독이 완료되었습니다!
✓ 이미 목록에 있습니다.
목차
2026년 7월 업데이트.
TL;DR: Claude tool use를 통해 에이전트가 텍스트 생성이 아닌 실제 작업을 수행할 수 있습니다. 도구를 JSON 스키마로 정의하면 Claude가 언제 호출할지 결정하고 코드가 실제 작업을 실행합니다. 루프는 3단계입니다: 메시지 전송 → tool_use 블록 수신 → 실행 후 결과 반환. Cloudflare Workers의 15개 이상 프로덕션 에이전트에 이를 구현했습니다. 장애 지점은 거의 AI가 아니라 도구에서 반환되는 모호한 결과에 있습니다.
[운영자 관점] 컨설팅 브랜드와 텍사스주 플루거빌의 피클볼 시설인 Pickleland에서 30개 이상의 프로덕션 AI 에이전트를 운영합니다. 절반 정도가 tool use를 사용합니다 — 모델이 코드에서 정의한 함수를 호출할 수 있게 하는 Claude API 기능입니다. 프로덕션에서 구현하고 반복하며 수렴한 패턴을 소개합니다.
Tool use가 에이전트의 능력을 바꾸는 이유
도구 없이 에이전트는 텍스트만 생성할 수 있습니다. 요약, 초안 작성, 분류에는 유용하지만 대부분의 비즈니스 자동화가 실제로 필요로 하는 것은 아닙니다. 비즈니스 자동화는 정보 조회, 데이터베이스 쓰기, API 호출, 메시지 전송이 필요합니다.
Tool use는 Claude에게 이러한 접근 권한을 부여하는 방법입니다. JSON 스키마로 도구 세트를 정의합니다. Claude가 스키마를 읽고 어떤 도구를 어떤 인수로 호출할지 결정하여 구조화된 tool_use 콘텐츠 블록을 반환합니다. 코드가 실제 함수를 실행합니다. Claude가 결과를 받아 다음에 할 일을 결정합니다 — 다른 도구를 호출하거나 최종 텍스트 응답을 생성하는 것을 포함합니다.
핵심: Claude가 언제 그리고 도구를 호출할지 여부를 결정합니다. 능력을 정의하는 것은 당신입니다. 모델이 사용 시점을 추론합니다.
API 흐름 작동 방식
Tool use 루프에는 3단계가 있습니다. 모델이 수행하는 도구 호출 수에 따라 이 루프를 한 번 또는 여러 번 실행합니다.
1단계: 정의된 도구와 함께 메시지 전송
const response = await anthropic.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 1024,
tools: [
{
name: "check_court_availability",
description:
"Check if a court is available at a given date, time, and duration",
input_schema: {
type: "object",
properties: {
date: {
type: "string",
description: "Date in YYYY-MM-DD format",
},
time: {
type: "string",
description: "Start time in HH:MM format (24h)",
},
duration_minutes: {
type: "number",
description: "Duration of the booking in minutes",
},
},
required: ["date", "time", "duration_minutes"],
},
},
],
messages: [
{
role: "user",
content: "Is a court available tomorrow at 2pm for 90 minutes?",
},
],
});2단계: Claude가 도구를 호출하려는지 확인
if (response.stop_reason === "tool_use") {
const toolUseBlock = response.content.find(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
if (!toolUseBlock) throw new Error("Expected tool_use block");
// Run your actual function
const toolResult = await checkCourtAvailability(
toolUseBlock.input as CourtAvailabilityInput
);
// Step 3: Return the result to Claude
const finalResponse = await anthropic.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 1024,
tools: [
/* same tools as before */
],
messages: [
{
role: "user",
content: "Is a court available tomorrow at 2pm for 90 minutes?",
},
{ role: "assistant", content: response.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolUseBlock.id,
content: JSON.stringify(toolResult),
},
],
},
],
});
// finalResponse.content now has the text answer
}이것이 전체 패턴입니다. 도구 호출당 3번의 API 상호작용: 도구 정의 → tool_use 블록 수신 → 결과 반환.
실제 예시: Pickleland 가용성 확인기
Pickleland는 피클볼 시설입니다. Facebook Messenger, 댓글, 챗봇으로 예약 문의를 받습니다. 질문은 거의 항상 “토요일 오후 3시에 여시나요?” 또는 “8인 그룹용 코트를 예약할 수 있나요?”의 변형입니다.
가용성 확인 에이전트는 정형화된 응답 대신 tool use를 사용하여 실시간으로 실제 예약 시스템을 조회합니다.
전체 에이전트를 보여드립니다 — 간소화되었지만 프로덕션에 충실합니다:
// workers/availability-checker.ts
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic();
const AVAILABILITY_TOOLS: Anthropic.Tool[] = [
{
name: "check_availability",
description:
"Check court availability for a date, time, and group size. Returns available courts and their prices.",
input_schema: {
type: "object",
properties: {
date: { type: "string", description: "YYYY-MM-DD" },
start_time: { type: "string", description: "HH:MM (24h)" },
duration_minutes: { type: "number" },
players: { type: "number", description: "Number of players" },
},
required: ["date", "start_time", "duration_minutes"],
},
},
{
name: "get_pricing",
description:
"Get current pricing for court rentals and open play sessions",
input_schema: {
type: "object",
properties: {
session_type: {
type: "string",
enum: ["court_rental", "open_play", "clinics"],
},
},
required: ["session_type"],
},
},
];
export async function handleInquiry(
userMessage: string,
env: Env
): Promise<string> {
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: userMessage },
];
// Agentic loop — keep going until stop_reason is "end_turn"
while (true) {
const response = await anthropic.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 512,
system:
"You are the booking assistant for Pickleland, a pickleball facility in Pflugerville, TX. " +
"Use the tools to look up real availability and pricing. Never make up availability or prices. " +
"If the customer wants to book, direct them to pickleland.com/book.",
tools: AVAILABILITY_TOOLS,
messages,
});
// Push the assistant's response into message history
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason === "end_turn") {
const textBlock = response.content.find(
(b): b is Anthropic.TextBlock => b.type === "text"
);
return (
textBlock?.text ??
"I wasn't able to answer that — please call us directly."
);
}
if (response.stop_reason === "tool_use") {
// Process ALL tool calls in this response (Claude can request multiple at once)
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type !== "tool_use") continue;
let result: unknown;
switch (block.name) {
case "check_availability":
result = await checkAvailability(
block.input as AvailabilityInput,
env
);
break;
case "get_pricing":
result = await getPricing(block.input as PricingInput, env);
break;
default:
result = { error: `Unknown tool: ${block.name}` };
}
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result),
});
}
// Return all tool results in a single user message
messages.push({ role: "user", content: toolResults });
}
}
}여기서 두 가지를 강조하고 싶습니다.
에이전트 루프. stop_reason === "end_turn"이 될 때까지 계속합니다. Claude가 check_availability를 호출하고 가격도 필요하다고 판단하여 get_pricing을 호출한 다음 최종 답변을 생성할 수 있습니다 — 이는 하나의 사용자 메시지에 대한 세 번의 API 호출입니다. 루프는 특별한 로직 없이 이를 처리합니다.
턴당 여러 도구 호출. Claude는 단일 응답에서 여러 tool_use 블록을 반환할 수 있습니다. 모두 처리하고 단일 user 메시지로 모든 결과를 반환합니다. 하나씩 처리하여 개별적으로 반환하면 대화 흐름이 끊기고 토큰을 낭비합니다.
실제 예시: 리드 조사 에이전트
컨설팅 브랜드에서는 대화 전에 인바운드 리드를 풍부하게 만드는 조사 에이전트를 사용합니다. 누군가 연락 양식을 작성하면 에이전트가 회사를 조사하고 통화 전에 알아야 할 내용을 추출합니다.
이 도구 정의에는 쓰기 도구가 포함됩니다 — 패턴이 흥미로워지는 부분입니다:
const RESEARCH_TOOLS: Anthropic.Tool[] = [
{
name: "search_company",
description: "Search for information about a company",
input_schema: {
type: "object",
properties: {
company_name: { type: "string" },
website: { type: "string", description: "Company website if known" },
},
required: ["company_name"],
},
},
{
name: "save_research",
description:
"Save the completed research summary to Airtable. Call this when all research is complete.",
input_schema: {
type: "object",
properties: {
company_summary: { type: "string" },
estimated_size: {
type: "string",
enum: ["1-10", "11-50", "51-200", "200+"],
},
likely_use_case: { type: "string" },
priority: { type: "string", enum: ["high", "medium", "low"] },
notes: { type: "string" },
},
required: [
"company_summary",
"estimated_size",
"likely_use_case",
"priority",
],
},
},
];save_research는 쓰기 도구라고 부릅니다 — 정보를 가져오는 것이 아니라 Claude의 출력을 구조화된 형태로 데이터베이스에 커밋하는 것이 목적입니다. 텍스트 응답에서 JSON을 파싱하는 대신 이 패턴을 사용합니다. Claude는 조사가 완료되면 알고 올바르게 타입이 지정된 필드로 save_research를 호출합니다. 파서를 작성할 필요가 없습니다.
이것이 tool use의 가장 깔끔한 적용입니다: 원하는 정확한 스키마로 “최종 액션” 도구를 정의하면 Claude가 도구 호출을 통해 구조화된 출력을 제공합니다. 텍스트 파싱 없음, 정규식 없음, 자유 텍스트 출력의 JSONSchema 검증 없음.
하나의 도구 vs. 여러 개
Tool use를 시작할 때의 본능은 모든 것을 처리하는 거대한 도구를 만드는 것입니다. 이를 저항하세요. 작고 집중된 도구가 세 가지 이유로 더 좋습니다:
-
Claude는 작은 도구에 대해 더 잘 추론합니다. 가용성을 반환하는
get_court_status라는 도구가mode매개변수를 받고 내부적으로 분기하는manage_facility보다 모델이 처리하기 더 쉽습니다. -
작은 도구는 테스트하기 더 쉽습니다. 각 도구는 LLM과 독립적으로 단위 테스트할 수 있는 TypeScript 함수입니다. 그래야 합니다 — 도구 버그는 라이브 대화에서 디버그하기 어렵습니다.
-
Claude는 작은 도구를 병렬화할 수 있습니다. 두 도구가 서로 의존하지 않는 경우 Claude는 같은 응답에서 호출하고 병렬로 처리할 수 있습니다. 이는 도구가 진정으로 독립적인 경우에만 작동합니다.
예외: 많은 공유 내부 상태에 접근해야 하는 도구. 함수가 동일한 데이터 소스에서 10개의 변수가 필요하면 각각 별도로 데이터베이스에 접근하는 10개의 도구보다 더 풍부한 스키마를 가진 하나의 도구가 낫습니다.
경험 법칙: 서로 다른 기능당 하나의 도구로 시작합니다. 모든 요청에서 함께 호출하는 것을 볼 때만 도구를 병합합니다.
비용 영향
Tool use는 토큰을 추가합니다. 각 도구 정의는 시스템 프롬프트 컨텍스트에 들어갑니다. 각 tool_use 및 tool_result 블록은 대화 기록의 토큰을 소비합니다. 멀티턴 에이전트 루프에서는 이것이 빠르게 쌓입니다.
Pickleland 가용성 확인기의 경우 일반적인 대화는 총 3-4번의 API 호출(초기 메시지 + 1-2번의 도구 호출 + 최종 답변)을 실행하며 각각 600-900개의 토큰을 처리합니다. Haiku 가격 기준으로 요청당 $0.001 미만입니다. AI 에이전트 비용 계산 게시물에서 설명한 것처럼 Haiku는 잘 정의된 도구 호출 작업을 안정적으로 처리하며 동일한 토큰 양에 대해 Sonnet보다 10배 저렴합니다.
리드 조사 에이전트는 Sonnet에서 실행됩니다. 왜냐하면 판단 결정 — 리드 우선순위 지정, 적합성 추정 — 은 Haiku가 오픈 입력에서 안정적으로 제공하는 것보다 더 많은 추론 능력이 필요하기 때문입니다. 드물게 실행되므로(하루에 수천 번이 아닌 주에 몇 번) 계산이 여전히 작동합니다. 모델 선택은 개인 선호도가 아닌 작업 복잡성을 따릅니다.
아무도 이야기하지 않는 장애 지점
프로덕션 tool use에서 가장 일반적으로 보이는 장애 지점은 Claude가 잘못된 도구를 호출하는 것이 아닙니다. Claude가 명확하게 추론할 수 없는 것을 도구가 반환하는 것입니다.
도구가 40개 필드를 가진 원시 데이터베이스 객체를 반환하면 Claude는 어떤 필드가 중요한지 혼란스러워합니다. 도구가 예외를 발생시키면(도구 결과가 아닌 Worker 충돌로 나타남) 루프가 조용히 끊깁니다. 도구가 “결과 없음”을 의미할 때 null을 반환하면 Claude는 재시도할지 포기할지 모릅니다.
도구 결과에 대한 세 가지 규칙:
간결하고 명시적인 결과 반환. { available: true, courts: ["Court 3", "Court 5"], price_per_hour: 20 } — 전체 데이터베이스 행이 아닙니다.
도구 함수 내에서 오류를 포착하고 구조화된 결과로 반환. { error: "booking system timeout", retry: true } — Worker를 충돌시키는 발생된 예외가 아닙니다.
“결과 없음”을 명시적으로 만들기. { available: false, next_available: "2026-07-23T14:00:00Z" } — 컨텍스트 없는 null이나 빈 배열이 아닙니다.
Claude는 모호한 반환 값보다 명확한 신호에 대해 훨씬 더 잘 추론합니다. 프로덕션에서 tool use를 디버그하는 데 소비한 모든 시간은 모델의 추론이 아닌 불명확한 결과에 관한 것이었습니다.
운영자의 결론
Tool use는 Claude를 텍스트 생성기에서 운영자로 변환하는 기능입니다. 명확한 입력 스키마로 집중된 도구를 정의합니다. 모델에 대한 단일 응답에서 모든 tool_use 블록을 처리합니다. stop_reason === "end_turn"이 될 때까지 에이전트 루프를 실행합니다. 도구 함수에서 깨끗하고 간결한 결과를 반환합니다 — 원시 데이터 객체, 발생된 예외, 모호한 null이 아닙니다.
모델이 추론을 담당합니다. 코드가 실제 작업을 담당합니다. 이 두 가지 역할을 명확하게 분리하면 도구를 추가해도 아키텍처가 유지 가능합니다.
첫 번째 tool use 에이전트를 구축하는 경우 위의 가용성 확인기 패턴으로 시작하세요 — 하나의 도구, 하나의 목적, 하나의 에이전트 루프. 그것을 배포합니다. 그런 다음 두 번째 도구를 추가합니다.
관련: 30개 이상의 프로덕션 에이전트를 실행하는 데 사용하는 에이전트 스택 · Haiku vs Sonnet: 에이전트 작업의 비용 계산 · 이벤트 트리거 vs 예약 에이전트: 어떤 패턴이 어떤 작업에 맞는지
Tool use 에이전트를 구축하다 막혔나요? 연락하기 — 운영팀을 위한 프로덕션 에이전트 아키텍처를 설계하고 구축합니다.
FAQ
Claude tool use는 모든 모델에서 작동합니까?
예 — tool use는 모든 현재 Claude 모델에서 지원됩니다. Claude Haiku는 명확한 스키마로 잘 정의된 도구를 안정적으로 처리하며 대용량 작업 유형에 가장 저렴한 옵션입니다. Sonnet은 더 모호하거나 개방형 도구 호출 결정을 더 잘 처리합니다. Haiku로 시작하고 출력 품질이 부족하면 업그레이드합니다.
Claude tool use와 OpenAI 함수 호출의 차이점은 무엇입니까?
기계적으로 동일합니다. OpenAI가 “function calling”을 만들었고 Anthropic은 “tool use”라고 부릅니다. 두 경우 모두: JSON 스키마를 정의하고 모델이 구조화된 호출을 반환하며 코드가 함수를 실행합니다. API 형태는 다르지만 개념은 같습니다.
Claude가 단일 응답에서 여러 도구를 호출할 수 있습니까?
예. Claude는 단일 assistant 응답에서 여러 tool_use 블록을 반환할 수 있습니다. 모두 처리하고 단일 user 메시지에 모든 결과를 반환합니다. 위의 Pickleland 예시에서 에이전트 루프 패턴을 참조하세요 — response.content의 for 루프가 이를 올바르게 처리합니다.
에이전트당 몇 개의 도구를 정의해야 합니까?
에이전트당 8-10개 미만으로 유지합니다. 그 이상에서는 Claude가 첫 번째 시도에서 잘못된 도구를 선택하는 경우가 있어 수정 루프에서 토큰을 낭비합니다. 10개 이상의 기능이 필요한 경우 모든 것을 아는 하나의 에이전트를 구축하는 대신 전문화된 도구 세트를 가진 여러 에이전트로 나눕니다.
구조화된 출력을 위해 tool use를 사용해야 합니까?
예 — save_research 쓰기 도구 패턴은 Claude에게 텍스트 블록에서 JSON을 반환하도록 요청한 다음 파싱하는 것보다 깔끔합니다. 원하는 정확한 스키마로 “최종 액션” 도구를 정의합니다. Claude가 완료되면 올바르게 타입이 지정된 필드로 호출합니다. 파서가 필요 없습니다.
매주 수요일. 28,400명+ 구독자. 핵심만.
✓ 받은편지함을 확인하세요 — 확인 링크를 클릭해 가입을 완료하세요.
✓ 구독이 완료되었습니다!
✓ 이미 목록에 있습니다.
관련 게시물
인간 감독이 포함된 AI 에이전트: 승인 게이트를 구축할 때와 그렇지 않을 때
2026년 업데이트. 프로덕션 AI 에이전트에 인간 승인 단계가 필요한 시점을 결정하는 데 사용하는 의사결정 프레임워크 — 그리고 게이트를 추가하면 오히려 채택을 조용히 죽이는 경우.
AI Agents2026년 비즈니스를 위한 Claude 대 ChatGPT: 운영자의 솔직한 평가
2026년 업데이트. 저는 Claude에서 30개 이상의 프로덕션 AI 에이전트를 운영합니다. 비즈니스를 위한 Claude vs ChatGPT에 대한 솔직한 비교 — 각각 어디서 이기고, 어디서 실패하며, 스택에 맞는 것을 어떻게 선택하는지.
AI AgentsCourtlines를 만든 방법: Claude로 개발한 클럽 관리 SaaS
라켓 스포츠 클럽과 스튜디오를 위한 운영 체제 Courtlines의 뒷이야기 — 왜 만들었는지, 무엇을 하는지, 그리고 Claude를 주력 엔지니어링 파트너로 삼아 한 명의 운영자가 어떻게 완전한 멀티 테넌트 SaaS를 출시할 수 있었는지.
AI 플레이북을 받아보세요
매주 수요일. 28,400명+ 구독자. 핵심만.
받은편지함을 확인하세요.
확인 이메일을 보냈습니다 — 링크를 클릭해 구독을 완료하세요. 1분 안에 보이지 않으면 스팸함을 확인하세요.
구독이 완료되었습니다.
환영합니다 — 다음 호가 곧 받은편지함에 도착합니다.
이미 목록에 있습니다 — 매주 수요일에 확인하세요.