Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

스킬

스킬(Agent Skills)은 모델이 따라야 할 지침과 참고 자료·스크립트를 하나의 폴더로 묶어 두고, 작업에 필요할 때만 불러오는 방법입니다. 프롬프트(지시)·문서(자료)·도구(스크립트)를 재사용 가능한 한 단위로 패키징한다는 점에서, 앞의 세 방법을 조합하는 상위 계층의 맥락 조정 방법입니다.

스킬의 핵심은 **단계적 공개(progressive disclosure)**입니다.

  1. 평소에는 각 스킬의 이름과 설명(메타데이터)만 시스템 프롬프트에 노출합니다.

  2. 모델이 "이 작업엔 이 스킬이 필요하다"고 판단하면, 그때 해당 스킬의 전체 지침(본문)을 컨텍스트에 불러옵니다.

  3. 더 깊은 자료(추가 파일)는 정말 필요할 때만 읽습니다.

이렇게 하면 도구·지식이 아무리 많아도 컨텍스트 창에는 "지금 필요한 것"만 들어오므로, 앞서 본 컨텍스트 비용·품질 문제를 자연스럽게 줄일 수 있습니다.

1스킬의 구조 (SKILL.md)

스킬은 SKILL.md 파일 하나를 담은 폴더입니다. SKILL.mdnamedescription을 담은 YAML 프런트매터로 시작하고, 그 아래에 전체 지침을 적습니다(필요하면 스크립트·참고 자료 파일을 같은 폴더에 더 둘 수 있습니다).

이 실습에 필요한 패키지를 설치합니다.

!uv pip install httpx

스킬 두 개를 폴더로 만듭니다. 프런트매터의 description이 "언제 이 스킬을 쓰는지"를 알려 주는, 단계적 공개의 1단계 정보입니다.

%%writefile skills/summary_3_bullets/SKILL.md
---
name: summary-3-bullets
description: 사용자가 글이나 문단을 요약해 달라고 할 때 사용합니다.
---
요약은 정확히 3개의 불릿(- )으로 작성합니다.
각 불릿은 한 문장으로 핵심만 담고, 불릿 외의 머리말·맺음말은 쓰지 않습니다.
%%writefile skills/email_polite/SKILL.md
---
name: email-polite
description: 사용자가 이메일 초안 작성을 요청할 때 사용합니다.
---
정중한 한국어 비즈니스 이메일 형식으로 작성합니다: 인사 → 본문 → 맺음말 → 서명.

2스킬 카탈로그 만들기 (1단계 메타데이터)

SKILL.md의 프런트매터만 읽어 **카탈로그(이름 + 설명)**를 만듭니다. 본문은 아직 읽지 않습니다 — 이것이 단계적 공개의 출발점입니다.

import glob
import pathlib

def parse_skill(path):
    text = pathlib.Path(path).read_text(encoding="utf-8")
    _, frontmatter, body = text.split("---", 2)  # 프런트매터와 본문 분리
    meta = dict(line.split(":", 1) for line in frontmatter.strip().splitlines())
    return {
        "name": meta["name"].strip(),
        "description": meta["description"].strip(),
        "body": body.strip(),
    }

skills = {s["name"]: s for s in (parse_skill(p) for p in sorted(glob.glob("skills/*/SKILL.md")))}
catalog = "\n".join(f"- {s['name']}: {s['description']}" for s in skills.values())
print(catalog)

3스킬 선택과 로드 (2단계 본문 공개)

이제 두 번의 모델 호출로 단계적 공개를 구현합니다.

  1. 선택: 카탈로그(메타데이터)만 보여 주고, 요청에 가장 맞는 스킬 이름을 고르게 합니다(없으면 NONE).

  2. 실행: 선택된 스킬의 본문 지침을 그때 로드해 시스템 메시지에 넣고 작업을 수행합니다.

import os
import httpx

OLLAMA_API_URL = f"{os.getenv('OLLAMA_HOST', 'http://localhost:11434')}/api/chat"
MODEL_NAME = "qwen3:latest"

def chat(messages):
    payload = {"model": MODEL_NAME, "messages": messages, "stream": False, "think": False}
    response = httpx.post(OLLAMA_API_URL, json=payload, timeout=120)
    response.raise_for_status()
    return response.json()["message"]["content"].strip()

def select_skill(request):
    # 1단계: 메타데이터(카탈로그)만 보고 스킬 선택
    system = (
        "아래 스킬 목록에서 사용자 요청에 가장 적합한 스킬의 name 하나만 정확히 출력하라. "
        "적합한 것이 없으면 NONE. 다른 말은 출력하지 마라.\n" + catalog
    )
    out = chat([{"role": "system", "content": system}, {"role": "user", "content": request}])
    return next((name for name in skills if name in out), None)

def run_with_skills(request):
    name = select_skill(request)
    if name:
        # 2단계: 선택된 스킬의 본문을 그때 로드해 지침으로 주입
        print(f"-> 선택된 스킬: {name} (본문을 컨텍스트에 로드)")
        system = "다음 지침을 반드시 따르라.\n" + skills[name]["body"]
        return chat([{"role": "system", "content": system}, {"role": "user", "content": request}])
    print("-> 적합한 스킬 없음 (일반 응답)")
    return chat([{"role": "user", "content": request}])

질문 = "다음 내용을 요약해줘: 트랜스포머는 어텐션 기반 아키텍처로 병렬 처리가 가능하고 장거리 의존성을 잘 포착하며, 사전훈련 후 미세조정으로 다양한 작업에 쓰인다."
print(run_with_skills(질문))

summary-3-bullets 스킬이 선택되어 본문 지침이 로드되고, 응답이 3개의 불릿으로 나옵니다. 이메일 작성을 요청하면 email-polite가, 스킬과 무관한 질문(예: 단순 계산)에는 NONE이 선택됩니다. 중요한 점은 선택 단계에서는 본문을 전혀 보지 않았다는 것입니다 — 모델은 짧은 설명만으로 어떤 스킬이 필요한지 판단했고, 전체 지침은 실행 단계에서야 컨텍스트에 들어왔습니다.

4정리

스킬은 프롬프트·문서·도구를 재사용 가능한 패키지로 묶고, 필요할 때만 불러오는 맥락 조정 방법입니다. 단계적 공개 덕분에 보유한 능력이 늘어나도 컨텍스트 창에는 그 순간 필요한 지침만 올라오므로, 컨텍스트를 가볍고 정확하게 유지할 수 있습니다. 이로써 컨텍스트 엔지니어링의 네 가지 방법 — 프롬프트(지시), 문서(지식), 도구(연동), 스킬(패키징) — 을 모두 살펴보았습니다.