클로드는 똑똑하지만 우리 회사 재고가 몇 개인지는 모릅니다. 실시간 데이터나 사내 시스템의 정보는 클로드의 지식 밖에 있죠. 이 간극을 메우는 것이 툴 사용(tool use, function calling)입니다. 클로드가 "이 질문에 답하려면 재고 조회 함수를 이 인수로 호출해야 해"라고 판단하면, 내 코드가 그 함수를 실행해 결과를 돌려주는 방식입니다.
전체 흐름
1. 나 → 클로드: 질문 + 사용할 수 있는 툴 목록
2. 클로드 → 나: "check_stock 툴을 sku='GB-CUP-01'로 호출해 줘" (stop_reason: tool_use)
3. 나: 실제로 함수 실행 → 결과: 재고 37개
4. 나 → 클로드: 툴 실행 결과 전달 (tool_result)
5. 클로드 → 나: "현재 GB-CUP-01 재고는 37개입니다." (최종 답변)
클로드는 결정만 하고, 실행은 내 코드가 합니다. 이 점이 보안상으로도 중요합니다. 어떤 함수를 실제로 실행할지는 끝까지 내가 통제합니다.
1단계. 툴 정의하기
툴은 이름, 설명, 입력 형식(JSON Schema)으로 정의합니다.
tools = [
{
"name": "check_stock",
"description": "상품 코드(SKU)로 현재 창고 재고 수량을 조회한다. "
"고객이 재고, 품절 여부, 구매 가능 여부를 물을 때 사용한다.",
"input_schema": {
"type": "object",
"properties": {
"sku": {"type": "string", "description": "상품 코드, 예: GB-CUP-01"}
},
"required": ["sku"],
},
}
]
설명(description)이 가장 중요합니다. 클로드는 이 설명을 읽고 언제 이 툴을 쓸지 판단합니다. "무엇을 하는지"와 함께 "언제 써야 하는지"를 적어 주세요.
2단계. 직접 루프 작성하기
툴 사용 흐름을 이해하기 위해 먼저 직접 작성해 봅니다.
import anthropic
client = anthropic.Anthropic()
STOCK = {"GB-CUP-01": 37, "GB-BAG-02": 0}
def check_stock(sku: str) -> str:
if sku not in STOCK:
return f"{sku}: 존재하지 않는 상품 코드"
return f"{sku}: 재고 {STOCK[sku]}개"
messages = [{"role": "user", "content": "GB-BAG-02 지금 살 수 있나요?"}]
while True:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break
results = []
for block in response.content:
if block.type == "tool_use" and block.name == "check_stock":
output = check_stock(**block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
messages.append({"role": "user", "content": results})
print("".join(b.text for b in response.content if b.type == "text"))
결과로 "GB-BAG-02는 현재 재고가 없어 구매가 어렵습니다. 재입고 알림을 신청해 보세요." 같은 답이 나옵니다.
코드의 핵심 포인트
stop_reason == "tool_use"이면 클로드가 툴 호출을 원하는 것입니다.- 클로드의 응답 전체(
response.content)를 대화에 그대로 추가해야 합니다. - 툴 결과는
tool_use_id를 맞춰 user 메시지로 돌려줍니다. - 툴 호출이 여러 개면 결과도 한 번의 user 메시지에 모두 담아 보냅니다.
3단계. SDK 툴 러너로 간단히
파이썬 SDK에는 이 루프를 대신 돌려 주는 툴 러너(tool runner) 헬퍼가 있습니다. 함수에 데코레이터를 붙이면 툴 정의와 실행 루프를 SDK가 처리합니다. 구체적인 사용법은 SDK 버전에 따라 다를 수 있으니 공식 문서의 예제를 확인하세요. 흐름을 이해한 뒤에 쓰면 디버깅이 훨씬 쉽습니다.
실무에서 주의할 점
- 입력값 검증: 클로드가 넘긴 인수를 그대로 DB 쿼리에 넣지 마세요. 형식과 범위를 검증합니다.
- 오류는 숨기지 말고 돌려주기: 실패하면
is_error: true와 함께 오류 내용을 돌려주면 클로드가 상황을 설명하거나 다른 방법을 시도합니다. - 위험한 툴은 확인 단계: 결제, 삭제, 메일 발송처럼 되돌릴 수 없는 툴은 실행 전에 사람의 확인을 받도록 설계합니다.
- 툴 결과의 내용도 검증: 툴이 외부 웹페이지나 문서를 가져온다면, 그 안에 AI를 속이려는 지시문이 있을 수 있음을 염두에 두세요.
- 반복 횟수 제한: 루프가 끝나지 않는 상황에 대비해 최대 반복 횟수를 둡니다.
기억할 것 세 가지
- 툴 사용은 클로드가 호출할 함수와 인수를 결정하고, 실행은 내 코드가 하는 구조입니다.
- 툴 설명에 "무엇을, 언제" 쓰는지 명확히 적고, 결과는 tool_use_id를 맞춰 돌려줍니다.
- 입력 검증, 오류 반환, 위험 작업 확인 단계, 반복 제한을 갖추세요.
AI에게 손발을 달아 줄 때
툴 사용을 처음 이해했을 때 든 생각은 "AI에게 손발을 달아 주는 것"이었습니다. 동시에 그 손발이 할 수 있는 일을 내가 정확히 정해야 한다는 책임도 느꼈습니다. 처음에는 읽기 전용 툴(조회)만 만들어 보고, 쓰기 툴(수정·발송)은 확인 단계를 충분히 갖춘 뒤에 추가하는 것을 권합니다.
출처·참고 링크

