Recent Posts
Recent Comments
반응형
«   2025/11   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Archives
Today
Total
관리 메뉴

오늘도 공부

Claude Agent Skills Deep dive 본문

AI/Claude code

Claude Agent Skills Deep dive

행복한 수지아빠 2025. 10. 31. 10:03
반응형
 

Claude Agent Skills: A First Principles Deep Dive

Technical deep dive into Claude Agent Skills' prompt-based meta-tool architecture. Learn how context injection design, two-message patterns, LLM-based routin...

leehanchung.github.io

원문을 정리한 내용입니다. 

Claude의 Agent Skills 시스템은 프롬프트 기반 메타-툴 아키텍처를 통해 LLM의 능력을 확장하는 정교한 시스템입니다. 기존의 함수 호출이나 코드 실행과 달리, Skills는 프롬프트 확장과 컨텍스트 수정을 통해 작동합니다.

이 글에서는 Claude의 Agent Skills 시스템을 처음부터 끝까지 분석하고, 실제로 어떻게 활용할 수 있는지 풍부한 예제와 함께 살펴보겠습니다.

목차

  1. Claude Agent Skills 개요
  2. Skills 만들기: 기초부터
  3. Skills의 내부 아키텍처
  4. 실전 예제: PDF 스킬 실행 과정
  5. 한국어 환경에서의 활용 팁

Claude Agent Skills 개요

Skills란 무엇인가?

Skills는 실행 가능한 코드가 아닙니다. Python이나 JavaScript를 실행하지 않으며, HTTP 서버나 함수 호출이 뒤에서 일어나지 않습니다. Skills는 특수한 프롬프트 템플릿으로, 대화 컨텍스트에 도메인 특화 인스트럭션을 주입합니다.

Skills가 호출되면 두 가지가 변경됩니다:

  1. 대화 컨텍스트: 인스트럭션 프롬프트 주입
  2. 실행 컨텍스트: 도구 권한 변경, 모델 전환 등

기존 Tool과 Skills의 차이

측면 기존 Tool (Read, Bash 등) Skills

실행 방식 동기적, 직접 실행 프롬프트 확장
목적 특정 작업 수행 복잡한 워크플로우 가이드
반환 값 즉각적인 결과 컨텍스트 변경
예시 Read, Write, Bash docx, pdf, skill-creator
메시지 복잡도 단순 (3-4개) 복잡 (5-10개 이상)
토큰 오버헤드 최소 (~100 tokens) 상당함 (~1,500+ tokens)

Skills 선택 메커니즘

중요한 점은 Skills 선택에 알고리즘이 없다는 것입니다. 임베딩도, 분류기도, 패턴 매칭도 없습니다. Claude가 언어 이해를 통해 자연스럽게 선택합니다.

사용자가 요청을 보내면 Claude는 세 가지를 받습니다:

  1. 사용자 메시지
  2. 사용 가능한 도구들 (Read, Write, Bash 등)
  3. Skill 도구 (메타-툴)

Skill 도구의 설명에는 모든 사용 가능한 Skills의 name, description이 포함되어 있습니다. Claude는 이 리스트를 읽고 자연어 이해를 통해 사용자의 의도와 매칭합니다.

사용자: "내부 커뮤니케이션 문서를 작성해줘"
Claude: (내부 추론)
  - 사용자가 내부 문서 작성을 원함
  - Skills 목록 확인...
  - "internal-comms": 회사에서 선호하는 형식으로 내부 커뮤니케이션 작성
  - 일치함! Skill 도구를 command="internal-comms"로 호출

시각적 표현

┌─────────────────────────────────────────────────────────────┐
│  사용자 요청: "블로그 포스트를 워드 문서로 만들어줘"            │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
        ┌────────────────────────────────────┐
        │   Claude의 도구 목록 확인           │
        │   - Read, Write, Bash              │
        │   - Skill (메타-툴)                 │
        │     ├─ docx: 워드 문서 생성         │
        │     ├─ pdf: PDF 처리               │
        │     └─ xlsx: 스프레드시트           │
        └────────────────┬───────────────────┘
                         │
                         ▼
        ┌────────────────────────────────────┐
        │  Claude: "docx" skill 선택          │
        │  Skill 도구 호출: {command: "docx"}│
        └────────────────┬───────────────────┘
                         │
                         ▼
        ┌────────────────────────────────────┐
        │  Skill 시스템:                      │
        │  1. SKILL.md 로드                   │
        │  2. 프롬프트 확장                    │
        │  3. 컨텍스트 주입                    │
        │  4. 도구 권한 수정                   │
        └────────────────┬───────────────────┘
                         │
                         ▼
        ┌────────────────────────────────────┐
        │  Claude: 워드 문서 생성 전문가 모드  │
        │  python-docx 사용하여 문서 생성      │
        └────────────────────────────────────┘

Skills 만들기: 기초부터

Skills는 폴더 구조로 구성됩니다. 핵심은 SKILL.md 파일이고, 필요에 따라 스크립트, 참조 문서, 에셋을 추가할 수 있습니다.

기본 폴더 구조

my-skill/
├── SKILL.md           # 핵심 프롬프트와 인스트럭션
├── scripts/           # 실행 가능한 Python/Bash 스크립트
├── references/        # 컨텍스트에 로드할 문서
└── assets/            # 템플릿과 바이너리 파일

SKILL.md 작성하기

SKILL.md는 두 부분으로 구성됩니다:

┌─────────────────────────────────────┐
│ 1. YAML Frontmatter (메타데이터)     │ ← 설정
│ ---                                 │
│ name: skill-name                    │
│ description: 간단한 설명             │
│ allowed-tools: "Bash, Read"         │
│ version: 1.0.0                      │
│ ---                                 │
├─────────────────────────────────────┤
│ 2. Markdown 콘텐츠 (인스트럭션)       │ ← Claude를 위한 프롬프트
│                                     │
│ 목적 설명                            │
│ 상세 인스트럭션                       │
│ 예제와 가이드라인                     │
│ 단계별 절차                          │
└─────────────────────────────────────┘

실전 예제 1: 한국어 기술 블로그 작성 스킬

한국 개발자를 위한 기술 블로그 작성 스킬을 만들어봅시다.

---
name: korean-tech-blog
description: 한국어 기술 블로그 포스트를 작성합니다. 벨로그, 티스토리, 미디엄 등에 적합한 형식으로 작성하며, 코드 하이라이팅과 이미지를 포함합니다.
allowed-tools: "Read,Write,Bash"
version: 1.0.0
---

# 한국어 기술 블로그 작성 스킬

당신은 한국 개발자 커뮤니티에서 인정받는 기술 블로거입니다.

## 작성 원칙

1. **명확한 구조**: 도입 → 본문 → 결론 → 참고자료
2. **코드 품질**: 
   - 주석은 한글로
   - 변수명은 영어로 (camelCase 또는 snake_case)
   - 실행 가능한 예제 제공
3. **독자 배려**:
   - 전문 용어에 한글 번역 병기
   - 초보자도 이해할 수 있는 설명
   - 실무에 바로 적용 가능한 팁

## 작성 워크플로우

### 1단계: 주제 분석
- 타겟 독자 파악 (주니어/시니어/팀 리더)
- 핵심 메시지 정의
- SEO 키워드 선정

### 2단계: 구조 설계
```markdown
# [매력적인 제목]

## TL;DR (3줄 요약)
- 핵심 1
- 핵심 2
- 핵심 3

## 들어가며
[문제 상황 제시]

## 본문
### 개념 설명
### 실전 예제
### 주의사항

## 마치며
[배운 점 정리 + 다음 단계 제안]

## 참고자료

3단계: 코드 예제 작성

# ✅ 좋은 예제
def calculate_total_price(items: list[dict]) -> int:
    """
    장바구니 아이템들의 총 가격을 계산합니다.
    
    Args:
        items: 상품 정보 리스트 (각 아이템은 'price'와 'quantity' 키를 포함)
    
    Returns:
        총 가격 (원 단위)
    """
    return sum(item['price'] * item['quantity'] for item in items)

# 사용 예시
cart_items = [
    {'name': '노트북', 'price': 1500000, 'quantity': 1},
    {'name': '마우스', 'price': 50000, 'quantity': 2}
]
total = calculate_total_price(cart_items)
print(f"총 결제 금액: {total:,}원")  # 출력: 총 결제 금액: 1,600,000원

4단계: 이미지 및 다이어그램

  • Mermaid 다이어그램 활용
  • 스크린샷은 한글 UI로
  • 코드 실행 결과 캡처

5단계: 검토 및 최적화

  • [ ] 오타 확인
  • [ ] 코드 실행 테스트
  • [ ] 링크 유효성 검사
  • [ ] SEO 메타 태그 확인

출력 형식

마크다운 파일로 저장하며, 다음 메타데이터를 포함합니다:

---
title: "제목"
date: 2025-10-31
categories: [카테고리1, 카테고리2]
tags: [태그1, 태그2, 태그3]
author: "작성자명"
description: "SEO를 위한 설명 (150자 이내)"
---

에러 처리

  • 코드 예제가 실행되지 않으면 주석으로 표시하고 대안 제시
  • 이미지 로드 실패 시 텍스트 설명으로 대체
  • 링크가 깨졌다면 Wayback Machine 확인

예시

입력

"Next.js App Router와 Server Actions에 대해 블로그 작성"

출력

완전한 기술 블로그 포스트 (2,000-3,000자, 코드 예제 3개 이상 포함)

### 실전 예제 2: 한국 회사 내부 문서 작성 스킬

한국 기업 문화에 맞는 내부 문서 작성 스킬입니다.

```yaml
---
name: korean-internal-docs
description: 한국 회사의 내부 문서를 작성합니다. 보고서, 기획서, 회의록 등을 한국 기업 문화에 맞게 작성합니다.
allowed-tools: "Read,Write"
version: 1.0.0
---

# 한국 회사 내부 문서 작성 스킬

당신은 한국 대기업과 스타트업에서 10년 경력의 전략기획팀 출신입니다.

## 문서 유형별 템플릿

### 1. 주간 업무 보고서
```markdown
# 주간 업무 보고서 (YYYY.MM.DD - YYYY.MM.DD)

**보고자**: [이름] [직급]  
**보고일**: YYYY년 MM월 DD일

## 1. 주요 성과
### 완료 업무
- [업무명] - [성과 지표] ([목표 대비 달성률])
  - 상세 내용

### 진행 중 업무
- [업무명] - 진행률 [00]%
  - 예상 완료일: YYYY.MM.DD

## 2. 이슈 및 리스크
| 이슈 | 심각도 | 대응 방안 | 담당자 |
|------|--------|-----------|--------|
|      | 상/중/하|          |        |

## 3. 차주 계획
- [ ] [업무명] (예정일: MM.DD)

## 4. 건의사항
[필요한 지원, 의사결정 요청 사항 등]

2. 사업 기획서

# [사업명] 사업 기획서

## Executive Summary (요약)
**추진 배경**: [2-3줄]
**목표**: [정량적 목표 명시]
**예상 효과**: [매출, 사용자, KPI 등]

## 1. 시장 분석
### 1.1 시장 현황
- 시장 규모: [금액]원 (YoY [증감률]%)
- 주요 플레이어: [경쟁사 나열]

### 1.2 고객 분석
**타겟 고객**: [페르소나 정의]
**고객 니즈**: 
1. [니즈 1]
2. [니즈 2]

## 2. 사업 내용
### 2.1 서비스 개요
[한 문장 설명]

### 2.2 핵심 기능
| 기능 | 설명 | 차별점 |
|------|------|--------|
|      |      |        |

### 2.3 비즈니스 모델
- **수익 모델**: [구독/광고/중개 수수료 등]
- **가격 정책**: [정책 설명]

## 3. 실행 계획
### 3.1 마일스톤
| 시기 | 목표 | 산출물 |
|------|------|--------|
| 1Q   |      |        |
| 2Q   |      |        |

### 3.2 조직 및 인력
- PM: [0]명
- 개발: [0]명
- 디자인: [0]명

## 4. 재무 계획
### 4.1 투자 예산
| 항목 | 금액(만원) | 비율 |
|------|-----------|------|
| 인건비 |          | 00%  |
| 개발비 |          | 00%  |
| 마케팅 |         | 00%  |
| **합계** |       | 100% |

### 4.2 손익 예측
- **BEP 도달 시점**: [분기]
- **1년차 예상 매출**: [금액]원

## 5. 리스크 관리
| 리스크 | 발생 가능성 | 영향도 | 대응 방안 |
|--------|------------|--------|----------|
|        | 상/중/하    | 상/중/하|          |

## 6. 결론 및 제안
[의사결정 요청 사항]

3. 회의록

# [회의명] 회의록

**일시**: YYYY년 MM월 DD일 (요일) HH:MM - HH:MM  
**장소**: [회의실명 / Zoom 링크]  
**참석자**: 
- [부서] [이름] [직급] (주관)
- [부서] [이름] [직급]

**불참자**: [이름 (불참 사유)]

## 안건
1. [안건 1]
2. [안건 2]

## 논의 내용

### 안건 1: [제목]
**논의 사항**:
- [참석자]: [의견 요약]
- [참석자]: [의견 요약]

**결정 사항**:
- ✅ [결정된 내용]
- ✅ [결정된 내용]

**Action Items**:
| 담당자 | 업무 | 기한 | 상태 |
|--------|------|------|------|
| [이름] |      | MM.DD| 진행중 |

### 안건 2: [제목]
[동일한 구조 반복]

## Next Steps
- [ ] [담당자] [업무] (기한: MM.DD)
- [ ] [담당자] [업무] (기한: MM.DD)

## 차기 회의
**일시**: YYYY년 MM월 DD일 (요일) HH:MM  
**안건**: 
1. [안건]
2. [안건]

---
**작성자**: [이름]  
**작성일**: YYYY.MM.DD  
**배포**: [메일링 리스트 / Slack 채널]

한국 기업 문화 반영 포인트

호칭 및 존댓말

  • 직급 사용: "김 과장님", "이 팀장님"
  • 존댓말 일관성 유지
  • 보고 대상에 따라 높임말 수준 조정

수치 표현

  • 한국 단위 사용: 만원, 억원
  • 퍼센트보다 "배수" 선호 (예: 2배 증가)
  • 전년 대비 (YoY), 전월 대비 (MoM) 명시

시각 자료

  • 표와 그래프 적극 활용
  • 색상: 빨강(나쁨/위험), 파랑(좋음/안정)
  • 볼드와 이탤릭 강조

의사결정 스타일

  • 찬반 의견 명확히 구분
  • 리스크 사전 명시
  • 대안 2-3가지 제시

자동 검증 항목

  • [ ] 날짜 형식: YYYY.MM.DD 또는 YYYY년 MM월 DD일
  • [ ] 금액 단위: 만원, 억원, 천만원 등
  • [ ] 담당자/기한 명시
  • [ ] 핵심 내용 볼드 처리
  • [ ] 표 정렬 확인
### 프롬프트 콘텐츠 작성 모범 사례

```markdown
## 추천 구조

---
# Frontmatter
---

# [간략한 목적 문장 - 1-2문장]

## 개요
[이 스킬이 하는 일, 언제 사용하는지, 무엇을 제공하는지]

## 사전 요구사항
[필요한 도구, 파일, 컨텍스트]

## 인스트럭션

### 1단계: [첫 번째 액션]
[명령형 인스트럭션]
[필요시 예제]

### 2단계: [다음 액션]
[명령형 인스트럭션]

### 3단계: [최종 액션]
[명령형 인스트럭션]

## 출력 형식
[결과를 어떻게 구조화할지]

## 에러 처리
[문제 발생 시 대응 방법]

## 예제
[구체적인 사용 예제]

## 리소스
[scripts/, references/, assets/ 참조]

모범 사례:

  • 5,000 단어 이하 유지 (~800줄)
  • 명령형 언어 사용 ("코드를 분석하라" ✅ / "코드를 분석해야 합니다" ❌)
  • 외부 파일 참조로 상세 내용 분리
  • {baseDir} 사용, 절대 경로 하드코딩 금지
❌ Read /home/user/project/config.json
✅ Read {baseDir}/config.json

리소스 번들링

Skills는 SKILL.md만으로도 작동하지만, 추가 리소스를 번들링하면 훨씬 강력해집니다.

1. scripts/ 디렉토리

실행 가능한 Python/Bash 스크립트를 저장합니다.

예제: 한글 텍스트 전처리 스크립트

scripts/preprocess_korean.py:

#!/usr/bin/env python3
"""
한글 텍스트 전처리 스크립트
- 띄어쓰기 정규화
- 특수문자 제거
- 중복 공백 제거
"""
import re
import sys

def preprocess_korean_text(text: str) -> str:
    """한글 텍스트를 전처리합니다."""
    # 중복 공백 제거
    text = re.sub(r'\s+', ' ', text)
    
    # 특수문자 제거 (한글, 영문, 숫자, 기본 문장부호만 유지)
    text = re.sub(r'[^가-힣a-zA-Z0-9\s.,!?]', '', text)
    
    # 양쪽 공백 제거
    text = text.strip()
    
    return text

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python preprocess_korean.py <input_file>")
        sys.exit(1)
    
    input_file = sys.argv[1]
    output_file = input_file.replace('.txt', '_processed.txt')
    
    with open(input_file, 'r', encoding='utf-8') as f:
        text = f.read()
    
    processed = preprocess_korean_text(text)
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(processed)
    
    print(f"전처리 완료: {output_file}")

SKILL.md에서 참조:

## 한글 텍스트 전처리

한글 텍스트를 정제하려면 전처리 스크립트를 실행하세요:

```bash
python {baseDir}/scripts/preprocess_korean.py input.txt

스크립트는 다음을 수행합니다:

  • 중복 공백 제거
  • 특수문자 필터링
  • 정규화된 텍스트 출력
### 2. references/ 디렉토리

Claude가 컨텍스트로 로드할 문서를 저장합니다.

**예제: 한국어 작문 가이드**

`references/korean_writing_guide.md`:
```markdown
# 한국어 기술 문서 작성 가이드

## 1. 문장 구조

### 능동태 vs 피동태
- ✅ "개발자가 API를 호출한다"
- ❌ "API가 개발자에 의해 호출된다"

### 간결함
- ✅ "이 함수는 데이터를 변환한다"
- ❌ "이 함수는 데이터를 변환하는 기능을 수행한다"

## 2. 전문 용어

### 번역 원칙
| 영어 | 한국어 | 사용 예 |
|------|--------|---------|
| Authentication | 인증 | 사용자 인증 |
| Authorization | 인가/권한 부여 | 접근 권한 확인 |
| Cache | 캐시 | 캐시 무효화 |
| Deploy | 배포 | 프로덕션 배포 |
| API | API (번역 안 함) | REST API |

### 병기 원칙
첫 등장 시 병기: "컨테이너(Container)"
이후 한글 단독 사용: "컨테이너를 실행한다"

## 3. 코드 주석

### Python
```python
def calculate_discount(price: int, rate: float) -> int:
    """
    할인가를 계산합니다.
    
    Args:
        price: 원가 (원 단위)
        rate: 할인율 (0.0 ~ 1.0)
    
    Returns:
        할인가 (원 단위, 소수점 버림)
    """
    return int(price * (1 - rate))

JavaScript

/**
 * 사용자 데이터를 검증합니다.
 * @param {Object} user - 사용자 객체
 * @param {string} user.name - 이름
 * @param {string} user.email - 이메일
 * @returns {boolean} 검증 통과 여부
 */
function validateUser(user) {
    return user.name && user.email;
}

4. 오류 메시지

원칙

  1. 무엇이 잘못되었는지 명확히
  2. 어떻게 해결할 수 있는지 제시
  3. 기술적 상세 정보 포함 (개발자용)

예시

❌ "오류가 발생했습니다" ✅ "데이터베이스 연결 실패: 호스트 'db.example.com'에 연결할 수 없습니다. 네트워크 연결을 확인하세요."

❌ "잘못된 입력" ✅ "이메일 형식이 올바르지 않습니다. 예: user@example.com"

SKILL.md에서 참조:
```markdown
## 작문 가이드 로드

한국어 기술 문서 작성 시 다음 가이드를 참고하세요:

Read {baseDir}/references/korean_writing_guide.md

가이드를 숙지한 후 문서를 작성하세요.

3. assets/ 디렉토리

템플릿과 바이너리 파일을 저장합니다. Claude는 경로만 참조하고 내용을 로드하지 않습니다.

예제: 한국어 README 템플릿

assets/readme_template_ko.md:

# {{PROJECT_NAME}}

{{PROJECT_DESCRIPTION}}

[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Korean](https://img.shields.io/badge/language-한국어-red.svg)](README.ko.md)

## 📋 목차

- [소개](#소개)
- [주요 기능](#주요-기능)
- [설치](#설치)
- [사용법](#사용법)
- [API 문서](#api-문서)
- [기여하기](#기여하기)
- [라이선스](#라이선스)

## 소개

{{INTRODUCTION}}

## 주요 기능

- ✨ **{{FEATURE_1}}**: {{FEATURE_1_DESC}}
- 🚀 **{{FEATURE_2}}**: {{FEATURE_2_DESC}}
- 🔒 **{{FEATURE_3}}**: {{FEATURE_3_DESC}}

## 설치

### 요구사항

- Node.js >= 18.0.0
- npm >= 9.0.0

### 설치 방법

```bash
# npm
npm install {{PACKAGE_NAME}}

# yarn
yarn add {{PACKAGE_NAME}}

# pnpm
pnpm add {{PACKAGE_NAME}}

사용법

기본 사용

import { {{MAIN_CLASS}} } from '{{PACKAGE_NAME}}';

const instance = new {{MAIN_CLASS}}({
  apiKey: 'your-api-key',
  baseURL: 'https://api.example.com'
});

// 예제 사용
const result = await instance.{{METHOD_NAME}}(params);
console.log(result);

고급 사용

{{ADVANCED_USAGE}}

API 문서

자세한 API 문서는 docs.example.com을 참조하세요.

기여하기

기여를 환영합니다! 다음 절차를 따라주세요:

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

라이선스

MIT License - 자세한 내용은 LICENSE 파일을 참조하세요.

연락처

  • 이메일: {{EMAIL}}
  • 이슈 트래커: {{ISSUE_URL}}
SKILL.md에서 참조:
```markdown
## README 생성

한국어 README를 생성하려면 템플릿을 사용하세요:

```bash
# 템플릿 복사
cp {baseDir}/assets/readme_template_ko.md ./README.ko.md

# 플레이스홀더 채우기
# {{PROJECT_NAME}}, {{PROJECT_DESCRIPTION}} 등을 실제 값으로 대체

템플릿에는 다음 플레이스홀더가 있습니다:

  • {{PROJECT_NAME}}: 프로젝트 이름
  • {{PROJECT_DESCRIPTION}}: 한 줄 설명
  • {{FEATURE_1}}, {{FEATURE_2}}, {{FEATURE_3}}: 주요 기능
  • {{PACKAGE_NAME}}: npm 패키지 이름
### references/ vs assets/ 구분

| 측면 | references/ | assets/ |
|------|-------------|---------|
| 내용 | 텍스트 문서 (md, txt, json) | 템플릿, 이미지, 바이너리 |
| 로드 방식 | Read 도구로 컨텍스트에 로드 | 경로만 참조, 로드하지 않음 |
| 토큰 소비 | 많음 (전체 내용 로드) | 없음 (경로만) |
| 용도 | 가이드라인, 패턴, 스키마 | HTML/CSS 템플릿, 이미지, 폰트 |
| 예시 | `writing_guide.md` (10KB) | `template.html` (50KB) |

**핵심**: 
- **references/**는 Claude가 **읽어야 하는** 내용
- **assets/**는 Claude가 **사용하는** 파일 (읽지 않음)

---

## 일반적인 Skill 패턴

### 패턴 1: 스크립트 자동화

복잡한 작업을 Python/Bash 스크립트로 오프로드합니다.

```markdown
## 한글 맞춤법 검사

맞춤법 검사를 실행하세요:

```bash
python {baseDir}/scripts/spell_check_korean.py --input "$USER_FILE" --output report.json

생성된 report.json을 파싱하여 결과를 제시하세요.

**필요한 도구**:
```yaml
allowed-tools: "Bash(python {baseDir}/scripts/*:*), Read, Write"

패턴 2: Read - Process - Write

파일 변환과 데이터 처리에 유용합니다.

## 처리 워크플로우

1. Read 도구로 입력 파일 읽기
2. 형식에 따라 콘텐츠 파싱
3. 사양에 따라 데이터 변환
4. Write 도구로 출력 작성
5. 요약과 함께 완료 보고

필요한 도구:

allowed-tools: "Read, Write"

패턴 3: Search - Analyze - Report

코드베이스 분석과 패턴 탐지에 사용합니다.

## 분석 프로세스

1. Grep으로 관련 코드 패턴 검색
2. 매칭된 각 파일 읽기
3. 취약점 분석
4. 구조화된 보고서 생성

필요한 도구:

allowed-tools: "Grep, Read"

패턴 4: 명령 체인 실행

의존성이 있는 다단계 작업에 사용합니다.

## 분석 파이프라인 실행:

```bash
npm install && npm run lint && npm test

각 단계의 결과를 보고하세요.

**필요한 도구**:
```yaml
allowed-tools: "Bash(npm install:*), Bash(npm run:*), Read"

고급 패턴: 마법사 스타일 다단계 워크플로우

복잡한 설정 프로세스를 단계별로 안내합니다.

## 워크플로우

### 1단계: 초기 설정
1. 사용자에게 프로젝트 유형 질문
2. 사전 요구사항 존재 확인
3. 기본 설정 생성

**다음 단계로 진행하기 전에 사용자 확인을 기다리세요.**

### 2단계: 설정
1. 설정 옵션 제시
2. 사용자에게 설정 선택 요청
3. 설정 파일 생성

**다음 단계로 진행하기 전에 사용자 확인을 기다리세요.**

### 3단계: 초기화
1. 초기화 스크립트 실행
2. 설정 성공 확인
3. 결과 보고

Skills의 내부 아키텍처

이제 Skills가 실제로 어떻게 작동하는지 내부를 살펴보겠습니다.

Skill 객체 설계

일반 도구 (Read, Bash, Write)는 즉각적인 결과를 반환합니다. Skills는 다르게 작동합니다.

기능 일반 Tool Skill Tool

본질 직접 액션 실행 프롬프트 주입 + 컨텍스트 수정
메시지 역할 assistant → tool_use<br>user → tool_result assistant → tool_use<br>user → tool_result<br>user → skill prompt (주입!)
복잡도 단순 (3-4 메시지) 복잡 (5-10+ 메시지)
컨텍스트 정적 동적 (턴마다 수정)
지속성 도구 상호작용만 도구 상호작용 + 스킬 프롬프트
토큰 오버헤드 최소 (~100 tokens) 상당함 (~1,500+ tokens)

Skill 메타-툴 구조

Skill = {
  name: "Skill", // 도구 이름: "Skill" (고정)
  inputSchema: {
    command: string // 예: "pdf", "skill-creator", "korean-tech-blog"
  },
  outputSchema: {
    success: boolean,
    commandName: string
  },
  // 🔑 핵심: 스킬 리스트 동적 생성
  prompt: async () => generateSkillsList(),
  
  // 검증 및 실행
  validateInput: async (input, context) => { /* 5가지 에러 코드 */ },
  checkPermissions: async (input, context) => { /* allow/deny/ask */ },
  call: async *(input, context) => { /* 메시지 + 컨텍스트 수정자 반환 */ }
}

Skill 도구의 prompt 필드는 동적입니다. 고정된 문자열이 아니라 런타임에 모든 사용 가능한 Skills를 집계하여 설명을 생성합니다.

async function generateSkillsList() {
  let allSkills = await getAllSkills();
  let {
    modeCommands: modeSkills,
    limitedRegularCommands: regularSkills
  } = categorizeSkills(allSkills);
  
  let modeSection = formatModeSkills(modeSkills);
  let regularSection = formatRegularSkills(regularSkills);
  
  return `스킬 실행

<skills_instructions>
사용자가 작업을 요청하면, 아래 사용 가능한 스킬 중 작업을 더 효과적으로 완료할 수 있는 것이 있는지 확인하세요.

스킬 사용 방법:
- 스킬 이름만으로 이 도구를 호출 (인자 없음)
- 스킬을 호출하면 "<command-message>"{name}" 스킬 로딩 중</command-message>"이 표시됩니다
- 스킬의 프롬프트가 확장되어 작업 완료 방법에 대한 상세 인스트럭션을 제공합니다

예시:
- \`command: "pdf"\` - pdf 스킬 호출
- \`command: "korean-tech-blog"\` - 한국어 기술 블로그 스킬 호출
</skills_instructions>

<available_skills>
${modeSection}${regularSection}
</available_skills>
`;
}

API 요청 구조

{
  "model": "claude-sonnet-4-5-20250929",
  "system": "당신은 Anthropic의 공식 CLI인 Claude Code입니다...",
  "messages": [
    {"role": "user", "content": "한국어 기술 블로그 작성 도와줘"},
    // ... 대화 기록
  ],
  "tools": [
    {
      "name": "Skill",
      "description": "스킬 실행...\n\n<available_skills>\n\"korean-tech-blog\": 한국어 기술 블로그 포스트를 작성합니다...\n\"docx\": 워드 문서 생성...\n</available_skills>",
      "input_schema": {
        "type": "object",
        "properties": {
          "command": {
            "type": "string",
            "description": "스킬 이름 (인자 없음)"
          }
        }
      }
    },
    {
      "name": "Bash",
      "description": "bash 명령 실행...",
      // ...
    },
    {
      "name": "Read",
      // ...
    }
  ]
}

핵심 포인트:

  • <available_skills> 섹션은 Skill 도구의 설명 내에 있습니다
  • 각 API 요청마다 동적으로 재생성됩니다
  • 토큰 예산 제한: 기본 15,000자

Skill 대화 및 실행 컨텍스트 주입

Skills는 시스템 메시지가 아닌 role: "user" 메시지를 사용합니다. 왜일까요?

시스템 메시지:

  • 전체 대화에 걸쳐 지속되는 글로벌 컨텍스트
  • 모든 후속 턴에 영향
  • 사용자 인스트럭션보다 높은 우선순위

Skills는 임시적, 범위가 제한된 동작이 필요합니다:

  • pdf 스킬은 PDF 작업에만 영향
  • 스킬 완료 후 일반 대화로 복귀
  • 잔여 행동 수정 없음

isMeta 플래그: 투명성과 명확성

Skills 실행 시 두 개의 별도 사용자 메시지가 주입됩니다:

  1. 메타데이터 메시지 (isMeta: false - 기본값)
    • 사용자에게 표시
    • 상태 표시기
    • 50-200자 정도
<command-message>"pdf" 스킬 로딩 중</command-message>
<command-name>pdf</command-name>
<command-args>report.pdf</command-args>
  1. 스킬 프롬프트 메시지 (isMeta: true)
    • UI에서 숨김, Claude에게 전송
    • 500-5,000 단어
    • 전체 인스트럭션 세트
당신은 PDF 처리 전문가입니다.

PDF 문서에서 텍스트를 추출하는 것이 당신의 작업입니다.

## 프로세스
1. PDF 파일 존재 확인
2. pdftotext 명령으로 텍스트 추출
3. 출력 파일 읽기
4. 추출된 텍스트를 사용자에게 제시

## 사용 가능한 도구
- Bash(pdftotext:*) - pdftotext 명령 실행
- Read - 추출된 텍스트 읽기
- Write - 필요시 결과 저장

Base directory: /path/to/skill
User arguments: report.pdf

왜 두 개의 메시지인가?

한 개의 메시지로는:

  • isMeta: false → 수천 단어의 AI 인스트럭션이 사용자 채팅에 표시됨 (UI 혼잡)
  • isMeta: true → 스킬 활성화에 대한 투명성 없음

두 개의 메시지로:

  • 메시지 1 (isMeta: false) → 사용자 대상 투명성
  • 메시지 2 (isMeta: true) → Claude 대상 상세 인스트럭션

측면 메타데이터 메시지 스킬 프롬프트 메시지

대상 사람 사용자 Claude (AI)
목적 상태/투명성 인스트럭션/가이드
길이 ~50-200자 ~500-5,000 단어
형식 구조화된 XML 자연어 마크다운
가시성 표시되어야 함 숨겨져야 함
내용 "무엇이 일어나는가?" "어떻게 하는가?"

실전 예제: PDF 스킬 실행 과정

사용자가 "report.pdf에서 텍스트 추출해줘"라고 말했을 때 무슨 일이 일어나는지 전체 라이프사이클을 살펴봅시다.

Phase 1: Discovery & Loading (시작 시)

Claude Code가 시작되면 스킬을 스캔합니다:

async function getAllCommands() {
  // 모든 소스에서 병렬 로드
  let [userCommands, skillsAndPlugins, pluginCommands, builtins] =
    await Promise.all([
      loadUserCommands(), // ~/.claude/commands/
      loadSkills(), // .claude/skills/ + plugins
      loadPluginCommands(), // Plugin-defined commands
      getBuiltinCommands() // Hardcoded commands
    ]);

  return [...userCommands, ...skillsAndPlugins, ...pluginCommands, ...builtins]
    .filter(cmd => cmd.isEnabled());
}

pdf 스킬의 경우:

{
  type: "prompt",
  name: "pdf",
  description: "PDF 문서에서 텍스트 추출 (plugin:document-tools)",
  whenToUse: "사용자가 PDF 파일에서 텍스트를 추출하거나 처리하려 할 때",
  allowedTools: ["Bash(pdftotext:*)", "Read", "Write"],
  model: undefined, // 세션 모델 사용
  isSkill: true,
  promptContent: "당신은 PDF 처리 전문가입니다...",
  // ... 기타 필드
}

Phase 2: Turn 1 - 사용자 요청 & 스킬 선택

사용자: "report.pdf에서 텍스트 추출해줘"

Claude 내부 추론 (가상):

- 사용자가 "report.pdf에서 텍스트 추출"을 원함
- 이것은 PDF 처리 작업
- 사용 가능한 스킬 확인...
- "pdf": PDF 문서에서 텍스트 추출 - 사용자가 PDF 파일에서 텍스트를 추출하려 할 때
- 일치함! Skill 도구를 command="pdf"로 호출

Claude 응답:

{
  "type": "tool_use",
  "id": "toolu_123abc",
  "name": "Skill",
  "input": {
    "command": "pdf"
  }
}

Phase 3: Skill Tool 실행

Skill 도구가 실행됩니다.

Step 1: 검증

async validateInput({ command }, context) {
  let skillName = command.trim();
  
  // 에러 1: 비어있음
  if (!skillName) return { result: false, errorCode: 1 };
  
  // 에러 2: 알 수 없는 스킬
  const allSkills = await getAllSkills();
  if (!skillExists(skillName, allSkills)) {
    return { result: false, errorCode: 2 };
  }
  
  // 에러 3: 로드할 수 없음
  const skill = getSkill(skillName, allSkills);
  if (!skill) return { result: false, errorCode: 3 };
  
  // 에러 4: 모델 호출 비활성화
  if (skill.disableModelInvocation) {
    return { result: false, errorCode: 4 };
  }
  
  // 에러 5: 프롬프트 기반이 아님
  if (skill.type !== "prompt") {
    return { result: false, errorCode: 5 };
  }
  
  return { result: true };
}

pdf 스킬은 모든 검증 통과 ✓

Step 2: 권한 확인

async checkPermissions({ command }, context) {
  const skillName = command.trim();
  
  // 거부 규칙 확인
  // 허용 규칙 확인
  // ...
  
  // 기본: 사용자에게 질문
  return { 
    behavior: "ask", 
    message: `스킬 실행: ${skillName}` 
  };
}

사용자에게 프롬프트: "스킬 실행: pdf?" 사용자 승인 ✓

Step 3: 스킬 파일 로드 및 실행 컨텍스트 수정 생성

async *call({ command }, context) {
  const skill = getSkill(command);
  
  // 스킬 프롬프트 로드
  const promptContent = await skill.getPromptForCommand("", context);
  
  // 메타데이터 생성
  const metadata = `<command-message>"${skill.name}" 스킬 로딩 중</command-message>
<command-name>${skill.name}</command-name>`;
  
  // 메시지 생성
  const messages = [
    { type: "user", content: metadata }, // 사용자에게 표시
    { type: "user", content: promptContent, isMeta: true }, // 숨김, Claude에게 전송
  ];
  
  // 설정 추출
  const allowedTools = skill.allowedTools || [];
  const modelOverride = skill.model;
  
  // 🔑 결과 반환 + 실행 컨텍스트 수정자
  yield {
    type: "result",
    data: { success: true, commandName: command },
    newMessages: messages,
    contextModifier(context) {
      let modified = context;
      
      // 허용된 도구 주입
      if (allowedTools.length > 0) {
        modified = injectAllowedTools(context, allowedTools);
      }
      
      // 모델 오버라이드
      if (modelOverride) {
        modified.options.mainLoopModel = modelOverride;
      }
      
      return modified;
    }
  };
}

Phase 4: API 전송 (Turn 1 완료)

{
  "model": "claude-sonnet-4-5-20250929",
  "messages": [
    {
      "role": "user",
      "content": "report.pdf에서 텍스트 추출해줘"
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_123abc",
          "name": "Skill",
          "input": { "command": "pdf" }
        }
      ]
    },
    {
      "role": "user",
      "content": "<command-message>\"pdf\" 스킬 로딩 중</command-message>\n<command-name>pdf</command-name>"
      // isMeta: false (기본값) - 사용자에게 표시
    },
    {
      "role": "user",
      "content": "당신은 PDF 처리 전문가입니다...\n\n## 프로세스\n1. PDF 존재 확인\n2. pdftotext 실행...",
      "isMeta": true // UI에서 숨김, API로 전송
    },
    {
      "role": "user",
      "content": {
        "type": "command_permissions",
        "allowedTools": ["Bash(pdftotext:*)", "Read", "Write"],
        "model": undefined
      }
    }
  ]
}

Phase 5: Bash Tool 실행 (스킬 컨텍스트로!)

Claude가 API 응답을 받습니다. 스킬 프롬프트가 Claude의 동작을 변환했습니다:

Claude의 추론:

report.pdf에서 텍스트를 추출하겠습니다.

[pdf 스킬의 인스트럭션을 따름]
1. report.pdf 존재 확인
2. pdftotext 명령으로 텍스트 추출
3. 출력 파일 읽기
4. 추출된 텍스트를 사용자에게 제시

Claude가 Bash 도구 사용 (사전 승인됨, 사용자 프롬프트 불필요):

{
  "type": "tool_use",
  "id": "toolu_456def",
  "name": "Bash",
  "input": {
    "command": "pdftotext report.pdf output.txt",
    "description": "pdftotext를 사용하여 PDF에서 텍스트 추출"
  }
}

Bash 도구가 성공적으로 실행되어 결과를 반환합니다. Claude는 Read 도구로 출력 파일을 읽고 추출된 텍스트를 사용자에게 제시합니다.


한국어 환경에서의 활용 팁

1. 한글 인코딩 처리

Skills에서 한글을 다룰 때는 항상 UTF-8 인코딩을 명시하세요:

# ✅ 올바른 방법
with open('report.txt', 'r', encoding='utf-8') as f:
    content = f.read()

# ❌ 잘못된 방법 (Windows에서 CP949 오류 발생)
with open('report.txt', 'r') as f:
    content = f.read()

2. 한국어 토크나이저

한글 텍스트 처리 시 KoNLPy 같은 한국어 특화 라이브러리 사용을 권장하세요:

from konlpy.tag import Okt

okt = Okt()
tokens = okt.morphs("한국어 자연어 처리를 위한 라이브러리")
# ['한국어', '자연어', '처리', '를', '위한', '라이브러리']

3. 날짜 형식

한국 표준 날짜 형식을 사용하세요:

from datetime import datetime

# ✅ 한국 형식
date_kr = datetime.now().strftime('%Y년 %m월 %d일')
# "2025년 10월 31일"

# ✅ 파일명용
date_file = datetime.now().strftime('%Y%m%d')
# "20251031"

# ❌ 미국 형식 (한국에서 혼란)
date_us = datetime.now().strftime('%m/%d/%Y')
# "10/31/2025"

4. 숫자 포맷

한국식 숫자 표기 (만, 억 단위):

def format_korean_number(num: int) -> str:
    """한국식 숫자 표기"""
    if num >= 100_000_000:  # 억
        eok = num // 100_000_000
        man = (num % 100_000_000) // 10_000
        if man > 0:
            return f"{eok}억 {man}만"
        return f"{eok}억"
    elif num >= 10_000:  # 만
        man = num // 10_000
        return f"{man}만"
    else:
        return f"{num:,}"

# 예제
print(format_korean_number(150_000_000))  # "1억 5000만"
print(format_korean_number(50_000))       # "5만"
print(format_korean_number(1_234))        # "1,234"

5. 한글 문서 템플릿

회사 문서는 항상 표준 템플릿을 사용하세요:

# 보고서 제목

**작성자**: [이름] [부서] [직급]  
**작성일**: YYYY년 MM월 DD일  
**보고 대상**: [이름] [직급]

---

## 요약 (Executive Summary)
[3-5줄로 핵심 내용 요약]

## 1. 배경
### 1.1 목적
### 1.2 범위

## 2. 현황 분석
### 2.1 데이터 분석
### 2.2 시사점

## 3. 제안 사항
### 3.1 옵션 A
### 3.2 옵션 B (권장)

## 4. 실행 계획
| 단계 | 기간 | 담당자 | 산출물 |
|------|------|--------|--------|
|      |      |        |        |

## 5. 예상 효과
- **정량적 효과**: [매출, 비용 절감 등]
- **정성적 효과**: [브랜드, 만족도 등]

## 6. 리스크 및 대응 방안
| 리스크 | 영향도 | 대응 방안 |
|--------|--------|----------|
|        | 상/중/하|          |

---

**첨부 자료**:
- [파일명1.xlsx]
- [파일명2.pdf]

6. 한글 폰트 처리 (PDF/이미지 생성 시)

한글을 포함한 PDF나 이미지를 생성할 때는 한글 폰트를 명시하세요:

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

# 한글 폰트 등록
pdfmetrics.registerFont(TTFont('NanumGothic', 'NanumGothic.ttf'))

# PDF 생성
c = canvas.Canvas("report_ko.pdf")
c.setFont('NanumGothic', 12)
c.drawString(100, 750, "한글이 포함된 보고서")
c.save()

결론: 정신 모델 요약

Claude Code의 Skills는 메타-툴 아키텍처를 통해 작동하는 프롬프트 기반 컨텍스트 수정자입니다.

핵심 요점

  1. Skills는 프롬프트 템플릿이지 실행 코드가 아닙니다
  2. Skill 도구는 개별 스킬을 관리하는 메타-툴입니다 (시스템 프롬프트가 아님)
  3. Skills는 대화 컨텍스트를 수정합니다 (인스트럭션 프롬프트 주입)
  4. Skills는 실행 컨텍스트를 수정합니다 (도구 권한, 모델 선택 변경)
  5. 선택은 LLM 추론을 통해 이루어집니다 (알고리즘 매칭 없음)
  6. 도구 권한은 실행 컨텍스트 수정을 통해 스킬 실행 범위로 제한됩니다
  7. Skills는 호출당 두 개의 사용자 메시지를 주입합니다
    • 하나는 사용자 표시용 메타데이터
    • 다른 하나는 API로 전송되는 숨겨진 인스트럭션

우아한 설계

실행 코드가 아닌 프롬프트로 특수 지식을 처리하고, 컨텍스트 수정을 통해 동작을 변경함으로써, Claude Code는 기존 함수 호출로는 달성하기 어려운 유연성, 안전성, 조합성을 달성합니다.


참고 자료

반응형