CPN 한국어 자습서 · 러닝패스 2 / 4 — Building with the Claude API
도구 사용
Tool schemas
도구 함수를 만들었으니, 2단계는 Claude가 그 도구를 이해하도록 JSON 스키마를 작성하는 일입니다. 맨 위 name·description으로 “이 도구가 무엇이고 언제 쓰는지”를 알리고, input_schema로 “어떤 인자를 받는지”를 기술합니다.
Stephen Grider · Anthropic 기술 스태프
도구 함수를 만들었으니, 이제 2단계로 넘어갑니다. JSON 스키마를 작성하는 단계입니다. 우리는 결국 이 설정 전체를 Claude에 보낼 텐데, Claude는 이것으로 사용할 수 있는 도구 함수들과, 그 함수에 넘겨야 하는 인자들을 이해합니다.
먼저 JSON 스키마가 정확히 무엇인지 짚겠습니다. 오른쪽에 보이는 객체 전체가 곧 JSON 스키마인 것은 아닙니다. 맨 위에는 name과 description이 있습니다. 그 아래에 input_schema 키가 있고, 거기에 할당된 딕셔너리, 바로 그 부분이 엄밀히 말해 JSON 스키마입니다.
JSON 스키마라는 개념은 언어 모델이나 도구 호출에 특별히 묶인 게 아닙니다. JSON 스키마는 데이터 검증 명세(data validation specification)입니다. 즉, 어떤 JSON 데이터든 검증하는 데 쓸 수 있는 규칙의 집합이죠. 언어 모델 커뮤니티가 어느 시점에 “도구 호출을 엮고 처리하기에 JSON 스키마가 아주 편리하다”고 판단해 채택한 결과입니다. 오래전부터 널리 쓰여 온 기술입니다.
이 객체 전체는 Claude에 어떤 도구가 있는지 알리는 데 쓰입니다. 도구의 name(예: get_weather)을 주고, description으로 그 도구가 무엇을 하는지, 언제 쓰는지, 어떤 데이터를 반환하는지를 알려 줍니다. 모범 사례는 설명을 3~4문장 정도로 충분히 쓰는 것입니다. 화면엔 “현재 날씨를 가져온다” 한 줄만 보이지만, 실제로는 훨씬 길게 쓰는 게 좋습니다.
그 아래 input_schema 키에 들어가는 것이 실제 JSON 스키마 명세입니다. 함수에 전달해야 하는 인자들을 기술하죠. 예를 들어 위치(location)만 받는 날씨 함수라면, input_schema에 location을 넣고, 타입은 문자열(string), 그리고 그 인자의 목적을 설명하는 description을 적습니다. 이 인자 설명도 3~4문장 정도로 써서, 이 인자가 무엇을 제어하고 함수 호출에 어떤 영향을 주는지 Claude가 정확히 이해하도록 돕습니다.
이 설정을 전부 손으로 쓰는 게 부담스럽게 느껴질 수 있는데, 거의 완벽한 스키마를 만들어 주는 작은 트릭이 있습니다. 먼저 에디터에서 도구 함수(우리의 get_current_datetime)를 찾아 복사합니다. 그리고 Claude.ai 창으로 가서 간단한 프롬프트를 씁니다 — “이 함수에 대해 도구 호출용으로 유효한 JSON 스키마 명세를 작성하라. 첨부 문서의 모범 사례를 따르라.” 그리고 도구 함수를 붙여 넣습니다.
여기가 진짜 트릭입니다. Anthropic API 문서의 User Guide 섹션에는 ‘도구 사용(tool use)’ 페이지가 통째로 있습니다. 좋은 설명과 나쁜 설명의 예, 여러 모범 사례가 잔뜩 들어 있죠. 그 페이지 텍스트를 전부 복사해 Claude 창에 첨부로 붙여 넣고 실행합니다. 그러면 Claude가 아주 탄탄한 JSON 스키마 명세로 응답합니다.
응답을 복사해 에디터로 가져와, 기존 get_current_datetime 함수 바로 아래에 붙여 넣습니다. 변수 이름은 get_current_datetime_schema로 둡니다. 제가 즐겨 쓰는 명명 규칙은, 함수 이름이 무엇이든 그에 대응하는 스키마는 같은 이름 + _schema로 두는 것입니다. 서로 짝을 맞추기 쉬워집니다.
마지막으로 한 가지. 셀 맨 위에 from anthropic.types import ToolParam을 추가하고, 이 ToolParam으로 딕셔너리 전체를 감쌉니다. ToolParam( 으로 열고 끝에서 ) 로 닫는 거죠. 이 ToolParam이 꼭 필요한 것은 아닙니다 — 없어도 코드는 동작합니다. 다만 나중에 이 스키마를 실제로 사용할 때 타입 에러가 나는 것을 막아 줍니다.
이 장에서 배우는 것What you'll learn
약 7분도구 사용 2단계 — Claude에 보낼 도구 스키마(JSON)를 작성
name·description + input_schema — 셋의 역할 구분
description은 무엇·언제·무엇 반환을 3~4문장으로
input_schema가 곧 JSON 스키마 — 인자(타입·설명·required)를 기술
스키마를 손으로 안 쓰는 트릭 — 함수 + 도구 문서를 Claude에 첨부
이름 규칙 함수명_schema + ToolParam(...)으로 타입 에러 예방
get_current_datetime. Claude가 호출할 때 이 이름을 지정.anthropic.types의 타입. 스키마 딕셔너리를 감싸면 나중에 타입 에러를 막아 준다(선택).도구 함수를 만들었으니 2단계입니다. 이 설정 전체를 Claude에 보내면, Claude는 어떤 도구가 있고 어떤 인자를 받는지 이해합니다. 객체 전체가 곧 “JSON 스키마”는 아닙니다 — 맨 위 name·description이 있고, input_schema 안쪽이 엄밀한 의미의 JSON 스키마입니다.
get_current_datetime.type:object + properties(각 인자의 타입·설명) + required(필수 인자 목록)로 함수가 받는 인자를 기술합니다.JSON 스키마는 언어 모델 전용이 아니라 데이터 검증 명세입니다 — 어떤 JSON이든 검증하는 규칙 집합이죠. 오래전부터 널리 쓰여 왔고, 모델 커뮤니티가 도구 호출 인자를 기술하기에 편리하다고 보고 채택했습니다.
위치만 받는 get_weather 함수를 예로 들면, 스키마의 각 부분이 함수와 어떻게 대응되는지 또렷합니다.
def get_weather(location): if not location.strip(): raise ValueError("location cannot be empty") url = "https://theweatherapi.example.com/current" params = { "query": location, "key": api_key, } response = requests.get(url, params=params) return response.json()["current"]
이 함수를 기술한 스키마입니다. input_schema의 properties.location이 함수 인자와 짝을 이루고, required에 필수 인자를 적습니다.
{
"name": "get_weather",
"description": "Retrieves current weather", # 실제로는 3~4문장으로
"input_schema": { # 여기 안쪽이 JSON 스키마
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location for which to get weather",
},
},
"required": ["location"],
},
}인자의 description도 3~4문장 정도로 써서, 이 인자가 무엇을 제어하고 호출에 어떤 영향을 주는지 Claude가 정확히 알게 합니다.
설정을 전부 손으로 쓰는 건 부담스럽습니다. 거의 완벽한 스키마를 얻는 트릭 — 함수 + 도구 사용 문서를 Claude.ai에 주고 스키마를 만들게 합니다.
# Claude.ai 창에 붙여 넣을 프롬프트 (+ 도구 함수 + 도구 문서 텍스트를 첨부) Write a valid JSON schema spec for the purposes of tool calling for this function. Follow the best practices listed in the attached documentation. # 1) 위 프롬프트 아래에 get_current_datetime 함수를 붙여 넣고 # 2) Anthropic API 문서의 "Tool use" 페이지 텍스트를 통째로 복사해 첨부로 추가 # Claude가 탄탄한 스키마를 만들어 줍니다.
받은 스키마를 에디터의 함수 바로 아래에 붙이고, 이름은 함수명_schema 규칙으로 둡니다. 끝으로 ToolParam으로 감싸 타입 에러를 예방합니다.
from anthropic.types import ToolParam get_current_datetime_schema = ToolParam({ "name": "get_current_datetime", "description": "Returns the current date and time formatted" " according to the specified format string.", "input_schema": { "type": "object", "properties": { "date_format": { "type": "string", "description": "A string specifying the format of the" " returned datetime. Uses Python's" " strftime directives.", "default": "%Y-%m-%d %H:%M:%S", }, }, "required": [], }, })
date_format은 default가 있어 호출 때 꼭 주지 않아도 됩니다. 그래서 required는 비워 둡니다. (강사 음성의 “tool program”은 실제로는 ToolParam입니다.)
아래 빌더로 각 부분을 켜고 끄며 스키마가 어떻게 바뀌는지 보세요. 그다음 퀴즈로 정리합니다.
구성 요소
오른쪽 JSON이 그대로 요청의 tools에 들어갑니다. name은 항상 필요하고, description과 인자 description은 Claude가 “언제·어떻게” 쓸지 판단하는 근거라 충실할수록 좋습니다.
name·description + input_schema — input_schema 안쪽이 진짜 JSON 스키마.description은 무엇·언제·무엇 반환을 3~4문장으로. 인자 설명도 길게.함수명_schema, ToolParam으로 감싼다.Q1도구 스키마에서 “엄밀히 말한 JSON 스키마”에 해당하는 부분은?
맨 위 name·description은 메타데이터이고, input_schema 안쪽이 인자를 검증·기술하는 JSON 스키마입니다.
Q2description에 대한 모범 사례는?
설명은 Claude가 언제 도구를 쓸지 판단하는 근거라 충실할수록 좋습니다. 인자 설명도 마찬가지.
Q3ToolParam(...)으로 감싸는 이유는?
ToolParam은 선택 사항입니다. 타입 정보를 붙여, 스키마를 사용할 때 발생할 수 있는 타입 에러를 예방합니다.
도구 정의(JSON 스키마)에 인자 후보를 넣어, 필수 항목과 타입이 맞는지 검사합니다.
// 도구 스키마 검사기 — 도구는 name·description·input_schema(JSON Schema)로 정의한다.
// 모델이 채워 보낸 인자 후보가 스키마에 맞는지 required·타입 기준으로 점검한다.
const weatherTool = {
name: "get_weather",
description: "도시의 현재 날씨를 조회한다.",
input_schema: {
type: "object",
properties: {
city: { type: "string" },
unit: { type: "string" }, // "celsius" | "fahrenheit"
},
required: ["city"],
},
};
function validate(tool, args) {
const schema = tool.input_schema;
const problems = [];
schema.required.forEach(function (key) {
if (!(key in args)) problems.push("필수 인자 누락: " + key);
});
Object.keys(args).forEach(function (key) {
const spec = schema.properties[key];
if (!spec) { problems.push("스키마에 없는 인자: " + key); return; }
if (spec.type === "string" && typeof args[key] !== "string") {
problems.push(key + " 는 string 이어야 하는데 " + typeof args[key] + " 입니다.");
}
});
return problems;
}
const cases = {
"통과": { city: "부산", unit: "celsius" },
"필수 누락": { unit: "celsius" },
"타입 불일치": { city: 12345 },
};
Object.keys(cases).forEach(function (label) {
const problems = validate(weatherTool, cases[label]);
console.log(label + " → " + (problems.length ? problems.join(" / ") : "스키마와 일치"));
});
스키마를 만들었으니, 이제 그것을 요청에 담아 Claude를 호출하고 돌아온 메시지 블록을 다뤄 봅니다. → 메시지 블록 다루기
전 코스는 계속 무료입니다. 등록하면 이 코스의 남은 76개 레슨을 끝까지 읽을 수 있습니다.
이미 등록하셨다면 그때 쓰신 이메일을 넣어 주세요.