297 lines
7.2 KiB
Markdown
297 lines
7.2 KiB
Markdown
---
|
|
id: ai-skills-patterns
|
|
title: AI Skills — 재사용 가능 Instruction + Tools
|
|
category: Coding
|
|
status: draft
|
|
source_trust_level: B
|
|
verification_status: conceptual
|
|
created_at: 2026-05-09
|
|
updated_at: 2026-05-09
|
|
tags: [ai, skills, anthropic, vibe-coding]
|
|
tech_stack: { language: "Markdown / TS", applicable_to: ["Backend"] }
|
|
applied_in: []
|
|
aliases: [Skills, Anthropic Skills, Claude Skills, instruction packs, agent capabilities]
|
|
---
|
|
|
|
# AI Skills
|
|
|
|
> 재사용 instruction + scripts 묶음. **Filesystem-based**, 한 번 정의 → 여러 사용. Anthropic Skills, Claude Skills, custom agent capabilities.
|
|
|
|
## 📖 핵심 개념
|
|
- SKILL.md: 사용 instruction.
|
|
- Scripts: supporting code (`scripts/`).
|
|
- References: 추가 context files.
|
|
- Auto-trigger: 관련 시 자동 inject.
|
|
|
|
## 💻 코드 패턴
|
|
|
|
### Skill folder
|
|
```
|
|
.claude/skills/
|
|
└── code-review/
|
|
├── SKILL.md
|
|
├── scripts/
|
|
│ ├── analyze.ts
|
|
│ └── format-report.ts
|
|
└── references/
|
|
├── style-guide.md
|
|
└── checklist.md
|
|
```
|
|
|
|
### SKILL.md 형식
|
|
```markdown
|
|
---
|
|
name: code-review
|
|
description: Review TypeScript / React PRs against team style guide
|
|
---
|
|
|
|
# Code Review
|
|
|
|
You're a senior engineer reviewing a PR.
|
|
|
|
## Process
|
|
1. Read changed files
|
|
2. Run `scripts/analyze.ts` for static issues
|
|
3. Check against `references/style-guide.md`
|
|
4. Output review in `references/checklist.md` format
|
|
|
|
## Rules
|
|
- Severity: must-fix / suggestion / nit
|
|
- Quote line numbers
|
|
- Suggest specific fix
|
|
|
|
## Tools
|
|
- Bash, Read, Grep
|
|
- `bun run scripts/analyze.ts <file>` for AST analysis
|
|
```
|
|
|
|
### Skill discovery (auto-trigger)
|
|
```
|
|
Description matched → auto-inject into agent context.
|
|
|
|
User: "Review this PR"
|
|
→ Agent matches "code-review" skill
|
|
→ Loads SKILL.md + relevant references
|
|
```
|
|
|
|
### 자체 skill system
|
|
```ts
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import matter from 'gray-matter';
|
|
|
|
interface Skill {
|
|
name: string;
|
|
description: string;
|
|
content: string;
|
|
scriptsDir: string;
|
|
}
|
|
|
|
class SkillLoader {
|
|
private skills: Skill[] = [];
|
|
|
|
constructor(dir: string) {
|
|
for (const name of fs.readdirSync(dir)) {
|
|
const skillDir = path.join(dir, name);
|
|
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
if (fs.existsSync(skillFile)) {
|
|
const { data, content } = matter(fs.readFileSync(skillFile, 'utf8'));
|
|
this.skills.push({
|
|
name: data.name ?? name,
|
|
description: data.description ?? '',
|
|
content,
|
|
scriptsDir: path.join(skillDir, 'scripts'),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async findRelevant(userQuery: string, llm: LLM): Promise<Skill[]> {
|
|
// LLM 가 description 기반 선택
|
|
const r = await llm.complete({
|
|
system: `Given a user query, return JSON of skill names that are relevant.
|
|
Skills:
|
|
${this.skills.map(s => `- ${s.name}: ${s.description}`).join('\n')}
|
|
|
|
Output: { "relevant": ["name1", "name2"] }`,
|
|
user: userQuery,
|
|
response_format: { type: 'json_object' },
|
|
});
|
|
|
|
const { relevant } = JSON.parse(r);
|
|
return this.skills.filter(s => relevant.includes(s.name));
|
|
}
|
|
}
|
|
```
|
|
|
|
### Inject into agent
|
|
```ts
|
|
async function chat(userMsg: string) {
|
|
const relevantSkills = await skillLoader.findRelevant(userMsg, llm);
|
|
|
|
const skillSection = relevantSkills.length > 0 ? `
|
|
## Available Skills
|
|
|
|
${relevantSkills.map(s => `### ${s.name}\n${s.content}`).join('\n\n')}
|
|
` : '';
|
|
|
|
const system = `You are a helpful assistant.${skillSection}`;
|
|
|
|
return await agent.run({ system, userMsg });
|
|
}
|
|
```
|
|
|
|
### Skills + tools (script execution)
|
|
```markdown
|
|
# SKILL.md
|
|
## Tools
|
|
- `bash scripts/run-tests.sh` — runs project tests
|
|
- `node scripts/analyze.js <file>` — AST analysis
|
|
```
|
|
|
|
```ts
|
|
// Agent 가 Bash tool 으로 script 실행
|
|
const result = await agent.callTool('bash', {
|
|
command: `node ${skill.scriptsDir}/analyze.js ${file}`,
|
|
});
|
|
```
|
|
|
|
### Skill versioning
|
|
```
|
|
.claude/skills/code-review/v2/
|
|
.claude/skills/code-review/v1/
|
|
|
|
// SKILL.md 안 version 명시
|
|
```
|
|
|
|
### Skill testing
|
|
```ts
|
|
test('code-review skill produces severity labels', async () => {
|
|
const result = await runSkill('code-review', { input: samplePR });
|
|
expect(result).toMatch(/must-fix|suggestion|nit/);
|
|
});
|
|
```
|
|
|
|
### Skill marketplace (개념)
|
|
```
|
|
공유 skill repo (npm 처럼).
|
|
재사용 + community + version.
|
|
|
|
claude-skills.com 같은 곳 — OSS.
|
|
```
|
|
|
|
### 좋은 skill 패턴
|
|
```
|
|
1. Single responsibility — 한 task.
|
|
2. Self-contained — 외부 의존 최소.
|
|
3. Self-describing — description 풍부.
|
|
4. Verifiable — 결과 검증 가능.
|
|
5. Tool-aware — 어떤 tool 필요 명시.
|
|
```
|
|
|
|
### 안 좋은 skill 패턴
|
|
```
|
|
1. 너무 generic ("be helpful" — 의미 없음).
|
|
2. Description 빈약 — 매칭 안 됨.
|
|
3. Scripts 외부 API 의존 — 실패 가능.
|
|
4. Multi-purpose god skill — 분리.
|
|
5. Implicit tool — 사용자 모름.
|
|
```
|
|
|
|
### Skill vs Tool vs Prompt
|
|
```
|
|
Tool: 한 함수 — read_file, execute_sql.
|
|
Skill: 여러 step + instruction — 사용자가 task 보고 사용.
|
|
Prompt: 단순 template — placeholder.
|
|
|
|
Skill = Tool + instruction + ranking.
|
|
```
|
|
|
|
### Personality / persona via skill
|
|
```markdown
|
|
# SKILL.md
|
|
---
|
|
name: socratic-tutor
|
|
description: Teach by asking guiding questions, never give direct answers
|
|
---
|
|
|
|
You are a Socratic tutor. Ask questions to guide the student to understanding.
|
|
Never give the answer directly.
|
|
Encourage exploration and reasoning.
|
|
```
|
|
|
|
→ Agent 가 user query 가 학습 관련 시 자동 적용.
|
|
|
|
### Composability
|
|
```
|
|
Multiple skills 동시:
|
|
- code-review + security-audit + perf-check
|
|
|
|
각 skill 의 instruction 가 합쳐짐.
|
|
Conflict 시 higher-priority 선언.
|
|
```
|
|
|
|
### Use case
|
|
```
|
|
- Code review
|
|
- Document analysis
|
|
- Customer support (tone, knowledge)
|
|
- Data analysis (SQL)
|
|
- Translation (language pair, style)
|
|
- Email composition (tone, brevity)
|
|
- Technical writing
|
|
- Test generation
|
|
```
|
|
|
|
### Implementation 종류
|
|
```
|
|
Anthropic Claude: .claude/skills/ (CLI / Desktop).
|
|
Cursor: .cursorrules / .cursor/.
|
|
GitHub Copilot: custom instructions in IDE.
|
|
자체 agent: 위 SkillLoader pattern.
|
|
```
|
|
|
|
### Description 매칭 정확도
|
|
```
|
|
Bad: description: "useful tool"
|
|
Good: description: "Review TypeScript PRs against team style guide. Trigger on phrases like 'review this PR' or 'check this code change'."
|
|
```
|
|
|
|
→ LLM 가 description 으로 선택. 명확.
|
|
|
|
### Limit (token cost)
|
|
```
|
|
모든 skill 의 SKILL.md 매번 inject = 큰 cost.
|
|
→ Lazy load — 필요 시만.
|
|
→ 또는 skill 가 작게 (200-500 token).
|
|
```
|
|
|
|
## 🤔 의사결정 기준
|
|
| 상황 | 추천 |
|
|
|---|---|
|
|
| 자주 쓰는 task | Skill |
|
|
| 1회성 | Prompt |
|
|
| Tool + flow | Skill (with scripts) |
|
|
| 단순 helper | Tool 만 |
|
|
| Persona | Skill |
|
|
| Domain knowledge | RAG + skill |
|
|
|
|
## ❌ 안티패턴
|
|
- **모든 거 skill 화**: overload.
|
|
- **Description 빈약**: 매칭 X.
|
|
- **Scripts 안 test**: 깨짐.
|
|
- **External API in skill**: failure.
|
|
- **Token 무관 — 전부 inject**: 비용.
|
|
- **Versioning 없음**: skill 변경 시 깨짐.
|
|
|
|
## 🤖 LLM 활용 힌트
|
|
- SKILL.md + scripts + references 표준.
|
|
- LLM 가 description 으로 매칭.
|
|
- 작게 + composable.
|
|
- Anthropic Claude + 자체 agent 둘 다 사용.
|
|
|
|
## 🔗 관련 문서
|
|
- [[AI_LangGraph_Agent_Frameworks]]
|
|
- [[AI_MCP_Server_Building]]
|
|
- [[AI_Agentic_Patterns]]
|