에이전트 도구를 JSON Schema로 정의하는 방법, 파라미터 타입 설계, required/optional 구분, 그리고 description 품질이 에이전트 성능에 미치는 영향을 실전 예제와 함께 설명합니다.
🎯 학습 목표
이 강을 마치면 다음을 할 수 있습니다.
- Anthropic Tool Use API가 요구하는 JSON Schema 구조를 정확히 이해하고 작성할 수 있습니다.
string·number·array·object·enum등 주요 타입을 상황에 맞게 선택할 수 있습니다.required와 선택적 파라미터를 설계 원칙에 따라 구분할 수 있습니다.- description 품질이 에이전트 성능에 직접 영향을 준다는 것을 이해하고, 좋은 description을 작성할 수 있습니다.
🏗️ 도구 스키마의 기본 구조
이 섹션에서는 Anthropic Tool Use API가 도구를 어떤 형식으로 받는지 살펴보겠습니다.
2강에서 우리는 이미 도구 정의를 사용해 봤습니다. 이제 그 구조를 하나씩 해부해 보겠습니다. Anthropic API의 도구 정의는 세 개의 필드로 이루어집니다.
tool_definition = {
"name": "search_web", # 도구 식별자 (snake_case 권장)
"description": "...", # LLM이 읽고 도구 선택을 결정하는 설명
"input_schema": { # JSON Schema 형식의 파라미터 정의
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "검색할 질의문"
}
},
"required": ["query"] # 필수 파라미터 목록
}
}
name은 LLM이 도구를 호출할 때 사용하는 식별자입니다. 공백 없이 영문 소문자와 밑줄(_)을 사용하는 snake_case를 권장합니다. LLM이 이름만 보고도 도구 용도를 어느 정도 추측할 수 있도록 동사+명사 형태로 지으면 좋습니다. 예: search_web, read_file, send_email.
description은 세 필드 중 에이전트 성능에 가장 큰 영향을 주는 부분입니다. LLM은 이 텍스트를 읽고 언제 이 도구를 사용할지, 어떤 인수를 넘길지 판단합니다. 뒤에서 description 작성 원칙을 자세히 다룹니다.
input_schema는 JSON Schema 명세를 따르는 파라미터 정의입니다. Anthropic API는 type: "object"를 루트로 하는 JSON Schema를 받습니다. properties 안에 각 파라미터를 정의하고, required 배열에 필수 파라미터 이름을 나열합니다.
🔠 파라미터 타입 시스템
이 섹션에서는 JSON Schema에서 사용할 수 있는 주요 타입을 살펴보겠습니다.
JSON Schema는 string, number, integer, boolean, array, object, null 등의 기본 타입을 지원합니다. 각 타입에는 추가 검증 키워드를 붙여 더 구체적으로 정의할 수 있습니다.
{
"input_schema": {
"type": "object",
"properties": {
# 1. 문자열 — 길이 제한과 패턴 적용 가능
"query": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "검색 질의문. 1자 이상 200자 이하."
},
# 2. 정수 — 범위 제한
"max_results": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"description": "반환할 최대 결과 수 (1~50)"
},
# 3. 열거형 — 허용 값 목록 지정
"language": {
"type": "string",
"enum": ["ko", "en", "ja", "zh"],
"description": "검색 언어 코드"
},
# 4. 배열 — 요소 타입 지정
"tags": {
"type": "array",
"items": {"type": "string"},
"maxItems": 10,
"description": "필터링할 태그 목록 (최대 10개)"
},
# 5. 중첩 객체 — 구조화된 입력
"date_range": {
"type": "object",
"properties": {
"start": {
"type": "string",
"description": "시작일 (YYYY-MM-DD 형식)"
},
"end": {
"type": "string",
"description": "종료일 (YYYY-MM-DD 형식)"
}
},
"required": ["start"],
"description": "검색 날짜 범위"
},
# 6. 불리언
"include_images": {
"type": "boolean",
"description": "이미지 결과 포함 여부 (기본값: false)"
}
},
"required": ["query"]
}
}
몇 가지 실전 팁이 있습니다. enum은 LLM이 임의 값을 넣는 것을 방지하는 강력한 도구입니다. 파라미터가 특정 값 집합 중 하나여야 한다면 반드시 enum을 사용하세요. 예를 들어 정렬 방향은 "enum": ["asc", "desc"]로 제한하면 LLM이 "ascending"이나 "내림차순"을 출력하는 것을 막을 수 있습니다. number와 integer는 다릅니다. number는 부동소수점을 포함하고 integer는 정수만 허용합니다. 페이지 번호, 개수처럼 소수가 의미 없는 파라미터는 integer를 사용하세요. 날짜와 시간은 format: "date", format: "date-time"을 명시할 수 있지만, Anthropic API는 이 format을 강제 검증하지 않습니다. description에 형식을 직접 명시하는 것이 더 확실합니다.
📋 required vs optional — 설계 원칙
이 섹션에서는 파라미터를 필수와 선택으로 나누는 원칙을 살펴보겠습니다.
required 배열에 포함된 파라미터는 LLM이 반드시 값을 제공해야 합니다. 빠지면 도구 호출 자체가 실패합니다. required에 없는 파라미터는 선택적이며, LLM이 필요하다고 판단할 때만 포함합니다.
어떤 파라미터를 required로 설정해야 할까요? 판단 기준은 명확합니다. 해당 파라미터 없이는 도구가 의미 있는 결과를 반환할 수 없다면 required입니다. 검색 도구에서 query(무엇을 검색할지)가 없으면 검색 자체가 불가능하므로 required입니다. 반면 max_results는 기본값으로 10을 사용할 수 있으므로 optional입니다.
선택적 파라미터에는 반드시 description에 기본값을 명시하세요. LLM은 이 정보를 바탕으로 파라미터를 포함할지 결정합니다.
{
"name": "send_email",
"description": "이메일을 발송합니다.",
"input_schema": {
"type": "object",
"properties": {
"to": {
"type": "string",
"description": "수신자 이메일 주소" # required
},
"subject": {
"type": "string",
"description": "이메일 제목" # required
},
"body": {
"type": "string",
"description": "이메일 본문" # required
},
"cc": {
"type": "array",
"items": {"type": "string"},
"description": "참조 수신자 목록 (선택, 기본값: 없음)" # optional
},
"priority": {
"type": "string",
"enum": ["normal", "high", "urgent"],
"description": "발송 우선순위 (선택, 기본값: 'normal')" # optional
}
},
"required": ["to", "subject", "body"]
}
}
required 파라미터가 너무 많으면 LLM이 도구를 호출할 때 필요한 정보가 없어 실패하거나 값을 추측해서 넣는 경우가 생깁니다. 반대로 너무 적으면 도구 호출 결과가 예측 불가능해집니다. 핵심 입력 2~4개만 required로 설정하고, 나머지는 기본값이 있는 optional로 설계하는 것이 일반적으로 좋은 균형입니다.
✍️ description 품질이 에이전트 성능을 결정한다
이 섹션에서는 이 강의 가장 중요한 주제인 description 작성 품질을 살펴보겠습니다.
많은 개발자가 도구를 처음 정의할 때 description을 대충 작성합니다. 하지만 실제로 에이전트 품질의 가장 큰 변수 중 하나가 바로 description입니다. LLM은 description을 읽고 세 가지를 판단합니다. 첫째, 지금 상황에서 이 도구를 써야 하는가? 둘째, 각 파라미터에 어떤 값을 넣어야 하는가? 셋째, 도구 결과를 어떻게 해석해야 하는가? 이 세 가지 판단 중 하나라도 엇나가면 에이전트가 원하지 않는 방향으로 동작합니다.
좋은 도구 description과 나쁜 도구 description을 비교해 보겠습니다.
# ❌ 나쁜 예 — 너무 짧고 모호함
{
"name": "get_data",
"description": "데이터를 가져옵니다.",
"input_schema": {
"type": "object",
"properties": {
"id": {"type": "string", "description": "ID"}
},
"required": ["id"]
}
}
# ✅ 좋은 예 — 사용 조건·반환값·한계·예시가 명확
{
"name": "get_product",
"description": (
"상품 ID로 단일 상품 정보를 조회합니다. "
"반환값: 상품명·가격·재고수량·카테고리. "
"존재하지 않는 ID는 null을 반환합니다. "
"여러 상품을 조회할 때는 이 도구를 반복 호출하지 말고 get_products_bulk를 사용하세요."
),
"input_schema": {
"type": "object",
"properties": {
"product_id": {
"type": "string",
"description": (
"상품 고유 ID. 영문 대문자와 숫자로 구성된 8자리 코드. "
"예: 'PRD00123'"
)
}
},
"required": ["product_id"]
}
}
좋은 description에는 네 가지 요소가 들어갑니다. 언제 사용하는가(사용 조건), 무엇을 반환하는가(반환값 설명), 어떤 한계가 있는가(오류 케이스, 제약사항), 다른 도구와 어떻게 다른가(유사 도구 비교)입니다. 특히 유사한 도구가 여러 개 있을 때는 각 도구의 description에서 서로의 차이를 명확히 설명해야 LLM이 올바른 도구를 선택합니다.
파라미터 description도 소홀히 하면 안 됩니다. 파라미터 설명에는 허용 형식("YYYY-MM-DD 형식")과 예시 값("예: 'PRD00123'")을 포함하는 것이 좋습니다. 추상적인 설명보다 구체적인 예시 하나가 훨씬 효과적입니다.
💻 실전 도구 스키마 예제 모음
이 섹션에서는 실제 에이전트에서 자주 쓰이는 도구 스키마를 예제로 살펴보겠습니다.
# 실전 도구 스키마 모음
TOOLS = [
# 1. 파일 읽기 도구
{
"name": "read_file",
"description": (
"로컬 파일 시스템에서 텍스트 파일을 읽습니다. "
"이진 파일(이미지·PDF 등)은 지원하지 않습니다. "
"파일이 없으면 오류 메시지를 반환합니다."
),
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "읽을 파일의 절대 경로 또는 상대 경로. 예: '/home/user/data.txt'"
},
"encoding": {
"type": "string",
"enum": ["utf-8", "utf-16", "latin-1"],
"description": "파일 인코딩 (선택, 기본값: 'utf-8')"
},
"max_lines": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "읽을 최대 줄 수 (선택, 기본값: 1000줄). 대용량 파일 처리 시 설정 권장."
}
},
"required": ["path"]
}
},
# 2. 데이터베이스 조회 도구
{
"name": "query_database",
"description": (
"읽기 전용 SQL 쿼리를 실행하고 결과를 JSON 배열로 반환합니다. "
"SELECT 문만 허용하며 INSERT·UPDATE·DELETE는 실행되지 않습니다. "
"결과는 최대 100행으로 제한됩니다. 더 많은 결과가 필요하면 LIMIT/OFFSET을 사용하세요."
),
"input_schema": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "실행할 SELECT SQL 문. 예: 'SELECT id, name FROM users WHERE active = true LIMIT 10'"
},
"params": {
"type": "array",
"items": {},
"description": "SQL 파라미터 바인딩 값 목록 (선택). SQL 인젝션 방지를 위해 값은 직접 삽입하지 말고 이 파라미터 사용."
}
},
"required": ["sql"]
}
},
# 3. HTTP 요청 도구
{
"name": "http_get",
"description": (
"외부 URL에 HTTP GET 요청을 보내고 응답 본문을 반환합니다. "
"JSON 응답은 자동으로 파싱됩니다. "
"타임아웃은 10초이며, 인증이 필요한 내부 API에는 사용하지 마세요."
),
"input_schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "요청할 URL. https:// 로 시작해야 합니다. 예: 'https://api.example.com/data'"
},
"headers": {
"type": "object",
"description": "추가 HTTP 헤더 (선택). 예: {'Accept': 'application/json'}"
}
},
"required": ["url"]
}
}
]
세 도구 모두 공통점이 있습니다. description에서 도구가 할 수 없는 것(제약)을 명시하고, 유사 도구와의 차이를 안내하며, 파라미터 description에 구체적인 예시값을 포함합니다. 이 세 가지를 지키는 것만으로도 에이전트의 도구 선택 정확도가 눈에 띄게 높아집니다.
⚠️ 자주 하는 실수와 해결법
이 섹션에서는 도구 스키마를 설계할 때 가장 자주 발생하는 실수를 살펴보겠습니다.
실수 1: name이 너무 모호하거나 중복됨. get_data, process, run처럼 너무 일반적인 이름은 LLM이 도구를 구분하기 어렵게 만듭니다. get_user_profile, process_payment, run_sql_query처럼 구체적인 이름을 사용하세요. 도구가 많아질수록 이름의 명확성이 더 중요해집니다.
실수 2: description에 사용 조건 누락. "정보를 가져옵니다"처럼 무엇을 하는지만 적고 언제 써야 하는지를 빠뜨리는 경우입니다. 비슷한 도구가 두 개 이상 있을 때 LLM은 둘 중 어떤 것을 써야 할지 추측에 의존하게 됩니다. 사용 조건과 유사 도구와의 차이를 반드시 description에 포함하세요.
실수 3: 모든 파라미터를 required로 설정. 선택적인 파라미터도 모두 required로 설정하면 LLM이 도구를 호출할 때마다 불필요한 값을 억지로 채워야 합니다. 이는 환각(hallucination)을 유발합니다. 기본값이 존재하는 파라미터는 optional로 설계하세요.
실수 4: 중첩 객체 남발. 파라미터를 지나치게 깊은 중첩 객체로 구조화하면 LLM이 올바른 JSON을 생성하기 어려워집니다. 2단계 중첩(object 안의 object)을 넘기지 않는 것을 권장합니다. 더 복잡한 구조가 필요하다면 도구를 더 작게 분리하는 것을 먼저 고려하세요.
실수 5: 날짜·시간 형식 미명시. "type": "string"만 쓰고 날짜 형식을 설명하지 않으면 LLM이 "2025년 1월", "2025/01/15", "Jan 15 2025" 등 다양한 형식을 사용해 파싱 오류가 발생합니다. description에 "YYYY-MM-DD 형식"처럼 정확한 형식을 명시하세요.
📝 핵심 요약 + 다음 강 예고
이 강에서 배운 내용을 정리하겠습니다.
| 개념 | 핵심 내용 |
|---|---|
| 스키마 기본 구조 | name·description·input_schema(type·properties·required) |
| 주요 타입 | string·integer·boolean·array·object·enum — 상황에 맞게 선택 |
| required 원칙 | 없으면 도구가 실패하는 파라미터만 required, 나머지는 optional에 기본값 명시 |
| description 4요소 | 사용 조건·반환값·제약·유사 도구와의 차이 |
| 흔한 실수 | 모호한 이름, 사용 조건 누락, 전부 required, 깊은 중첩, 날짜 형식 미명시 |
이제 좋은 도구 스키마를 설계할 수 있게 됐습니다. 하지만 스키마를 아무리 잘 만들어도 에이전트가 실제로 도구를 올바르게 호출하고 결과를 처리하는 루프가 없으면 소용없습니다. 다음 강인 4강 「도구 실행 루프 구현」에서는 여러 도구를 포함하는 에이전트 루프를 완성하고, 도구 실행 결과를 에이전트 컨텍스트에 안전하게 통합하는 방법을 자세히 다룹니다.
📚 참고 자료
관련 주제
- 도구 스키마 설계
- JSON Schema
- input_schema
- required optional 파라미터
- description 품질
- Tool Use
- AI 기술
- AI 기술 강의
- LLM 에이전트 설계와 구현 20강
- NUGUNA
- 누구나
📚 시리즈 전체 공유
LLM 에이전트 설계와 구현 20강
이 강의가 속한 시리즈는 총 20강(수강생 전용 보너스 · 1~3강 무료)입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.
댓글
불러오는 중...
