Skip to main content

좋은 Skill은 지침이 친절하다고 해서만 안정적으로 작동하지 않는다. 진짜 차이는 어디에서 생기느냐 하면, 에이전트가 생각해야 할 일과 그냥 실행해야 할 일을 제대로 나눴는지에서 생긴다. 문장을 다듬고, 상황을 해석하고, 우선순위를 정하는 일은 모델이 잘한다. 하지만 점수를 계산하고, 날짜를 더하고, CSV 컬럼을 검사하고, 출력 포맷이 규칙에 맞는지 확인하는 일은 코드가 훨씬 잘한다. 에이전트가 자꾸 비슷한 작업에서 다른 답을 내놓는 이유도 대개 여기 있다. 모델에게 맡기면 안 되는 일을 모델에게 맡겼기 때문이다.12

이번 장의 목표는 단순하다. 자연어 지침과 스크립트의 경계를 선명하게 만드는 것이다. 한마디로 요약하면 이렇다. 판단은 모델에게, 확정은 코드에게 맡겨라. 이 선이 분명해질수록 Skill은 덜 흔들리고, 더 재사용 가능해진다.

Skill과 스크립트

모델이 잘하는 일과 코드가 잘하는 일은 다르다

AI 에이전트는 사람처럼 설명을 이해하고, 애매한 요구를 구조화하고, 문맥에 맞는 표현을 고르는 데 강하다. 그래서 보고서 초안을 잡고, 이메일의 톤을 조정하고, 리서치 질문을 분해하고, 사용자 요청의 숨은 의도를 파악하는 데는 자연어 지침이 매우 강력하다.

하지만 같은 에이전트에게 "총점 100점 기준으로 가중치를 적용해 최종 점수를 계산해라", "날짜 형식이 모두 ISO 8601인지 검사해라", "필수 컬럼이 없으면 실패로 처리해라", "JSON 스키마에 맞지 않으면 다시 생성하게 해라" 같은 일을 맡기면 이야기가 달라진다. 이런 일은 창의성이 아니라 정확성이 중요하다. 확률적으로 그럴듯한 답이 아니라, 항상 같은 입력에 같은 결과를 내야 한다.13

이 차이를 놓치면 Skill이 이상해진다. 글은 자연스러운데 숫자가 틀리고, 형식은 그럴듯한데 필수 필드가 빠지고, CSV 분석은 했다는데 컬럼 이름 하나 잘못 읽어서 전체 해석이 어긋난다. 겉으로는 "거의 맞는 것"처럼 보이지만, 실무에서는 바로 사고가 난다.

그래서 Skill 설계자는 늘 이런 질문을 던져야 한다.

이 단계에서 필요한 것은 해석인가, 계산인가. 판단인가, 검증인가. 제안인가, 확정인가.

질문이 달라지면 구현도 달라진다.

자연어 지침만으로 충분한 작업은 어디까지인가

자연어 지침만으로 충분한 작업은 보통 정답이 하나로 고정되지 않는 일이다. 예를 들어 회의록을 요약하면서 핵심 의사결정을 먼저 배치하는 일, 독자 수준에 맞춰 설명의 난이도를 조정하는 일, 회사 톤에 맞게 이메일을 부드럽게 바꾸는 일은 코드로 묶기보다 지침으로 설명하는 편이 낫다. 이런 일은 맥락이 중요하고, 약간의 변주가 오히려 품질을 높인다.

반대로 아래와 같은 징후가 보이면 자연어만으로 버티기 어렵다.

  • 결과가 매번 같아야 한다.

  • 수식이나 규칙이 명확하다.

  • 파일, 운영체제, 외부 도구와 상호작용해야 한다.

  • 실패 여부를 기계적으로 판정할 수 있다.

  • 길거나 복잡한 명령을 반복 실행해야 한다.

예를 들어 채용 후보자 평가 Skill을 만든다고 해 보자. 면접 메모를 읽고 강점과 우려 사항을 정리하는 일은 자연어 지침이 잘한다. 하지만 평가표의 각 항목 점수에 가중치를 적용해 총점을 산출하고, 최소 통과 기준을 넘는지 판단하고, 누락된 평가 항목이 있는지 검사하는 일은 스크립트가 맡아야 한다. 모델이 이 계산까지 하게 하면, 한 명은 84점인데 합격, 다른 한 명은 86점인데 불합격 같은 황당한 장면이 벌어질 수 있다.

쉽게 말하면 자연어 지침은 "어떻게 생각할지"를 가르치고, 스크립트는 "어떻게 확정할지"를 고정한다.

언제 Python, Bash, JavaScript를 붙여야 하는가

스크립트를 붙여야 한다고 해서 언어를 아무렇게나 고르면 안 된다. 언어 선택은 취향보다 작업 성격이 먼저다.

Python은 데이터 처리와 검증에 가장 무난하다. CSV, Excel, JSON, 로그 파일, 통계 계산, 텍스트 파싱, 간단한 시각화처럼 "파일을 읽고 가공하고 결과를 구조화해 내보내는 일"에 강하다. 숫자 계산이나 데이터 정제가 들어가면 대개 Python이 가장 먼저 후보로 올라온다.1

Bash는 운영체제 명령을 조합하는 데 좋다. 파일 존재 여부를 확인하고, 특정 디렉터리를 순회하고, 여러 CLI 도구를 순서대로 실행하고, 빌드·검사·배포 전 검증 같은 작업을 짧게 엮을 때 유리하다. 다만 Bash는 데이터 구조를 다루는 데는 불편하므로, 복잡한 로직까지 억지로 넣기 시작하면 금세 읽기 어려워진다. 명령을 묶는 접착제 정도로 생각하는 편이 좋다.1

JavaScript는 프론트엔드 자산 처리, Node 기반 도구 연동, 기존 JS 생태계 활용이 필요할 때 강하다. 예를 들어 ESLint나 Prettier 같은 Node 도구를 호출하거나, 웹 관련 변환 로직을 실행하거나, 프로젝트가 이미 TypeScript 중심으로 움직일 때 자연스럽다. Deno나 Bun처럼 스크립트 단위 의존성 선언이 쉬운 런타임을 활용하면 가벼운 자동화에도 잘 맞는다.1

실무적으로는 이렇게 판단하면 편하다.

Python은 계산과 정리에, Bash는 실행 연결에, JavaScript는 웹 도구 생태계 연동에 강하다.

여기서 중요한 포인트가 하나 더 있다. 간단한 단발성 명령은 굳이 scripts/에 넣지 않아도 된다. 예를 들어 특정 포매터를 한 번 돌리는 일처럼 명령이 짧고 명확하다면 npx eslint@9 --fix . 같은 형태를 SKILL.md에 직접 적어 둘 수 있다. 하지만 명령이 길어지고, 옵션이 많아지고, 실패 처리까지 필요해지면 그때는 스크립트로 옮기는 편이 더 안정적이다.1

즉, 기준은 멋이 아니라 실패 가능성이다. 한 번에 맞히기 어려운 명령이라면 이미 스크립트 후보라고 봐도 된다.

점수 계산, 포맷 검증, 변환 로직은 왜 코드로 고정해야 하는가

Skill이 자주 흔들리는 지점은 대개 세 종류다. 계산, 검증, 변환이다.

계산은 말 그대로 숫자를 다루는 일이다. 합계, 평균, 가중치, 비율, 단위 환산, 날짜 차이, 순위 산정 같은 일은 코드가 맡아야 한다. 모델은 계산 과정을 설명하는 데는 능숙하지만, 계산 자체를 항상 맞게 하는 기계는 아니다. 특히 입력이 길어지고, 예외 조건이 많아질수록 작은 오류가 큰 결과 차이로 이어진다.13

검증은 규칙 일치 여부를 확인하는 일이다. 예를 들어 "제목은 60자 이하", "필수 필드는 title, summary, sources", "날짜는 YYYY-MM-DD 형식", "JSON 출력은 지정한 스키마와 일치", "브랜드 금지어 포함 시 실패" 같은 규칙은 자연어로 권고하는 순간 무너질 가능성이 커진다. 이때는 스크립트가 결과물을 검사하고, 통과와 실패를 명확히 반환하게 해야 한다.

변환은 입력을 다른 형태로 바꾸는 일이다. CSV를 JSON으로, 회의록 원문을 표준 템플릿 필드로, 로그 파일을 요약 가능한 구조로, 마크다운을 특정 CMS 포맷으로 바꾸는 일이다. 이런 작업은 겉보기에 단순하지만 실제로는 사소한 형식 차이 때문에 자주 망가진다. 그래서 변환 규칙은 지침이 아니라 코드에 고정하는 편이 낫다.

예를 들어 사내 보고서 Skill이 있다고 해 보자. 모델은 인터뷰 메모와 수치 자료를 읽고 핵심 메시지를 뽑는다. 하지만 다음 단계는 코드가 받는 편이 좋다.

1. 모델: 리스크, 기회, 다음 액션을 추출한다.
2. 스크립트: 누락 필드가 없는지 검사한다.
3. 스크립트: 점수 계산과 우선순위 정렬을 수행한다.
4. 모델: 계산 결과를 바탕으로 임원용 문장으로 다듬는다.
5. 스크립트: 최종 JSON/표/문서 포맷이 규격에 맞는지 다시 검증한다.

이 구조가 좋은 이유는 분명하다. 모델은 해석과 서술에 집중하고, 코드는 실수를 허용하면 안 되는 구간을 잠근다. 한마디로 스크립트는 에이전트의 자유를 빼앗는 장치가 아니라, 에이전트의 신뢰도를 올리는 안전레일이다.

좋은 스크립트는 도구처럼 설계해야 한다

많은 사람이 스크립트를 "에이전트가 알아서 읽고 적당히 써 주는 코드"로 생각한다. 하지만 실제로는 반대다. 좋은 스크립트는 에이전트가 상상력을 발휘할 여지를 줄인다. 입력이 무엇인지, 출력이 무엇인지, 실패하면 어떻게 되는지까지 분명한 작은 도구처럼 설계해야 한다.13

핵심은 인터페이스다. 사람이 직접 쓰는 스크립트는 감으로 써도 어떻게든 돌아갈 때가 있지만, 에이전트가 쓰는 스크립트는 감에 의존하면 바로 흔들린다. 에이전트는 터미널에서 TTY 프롬프트에 답하지 못하므로, 실행 중간에 "계속하시겠습니까?" 같은 대화형 입력을 요구하면 그냥 멈춰 버린다. 그래서 입력은 반드시 명령행 인수, 환경 변수, 표준 입력 가운데 하나로 받아야 한다.1

또한 --help가 중요하다. 사람에게 도움말은 친절함의 문제지만, 에이전트에게는 인터페이스 학습 그 자체다. 어떤 플래그가 있는지, 필수 인수가 무엇인지, 예제가 어떻게 되는지가 짧고 명확하게 드러나야 한다.1

좋은 예는 이런 식이다.

python3 scripts/score_candidates.py --input candidates.csv --output scores.json

이 명령만 보고도 에이전트는 입력 파일, 출력 파일, 스크립트 역할을 짐작할 수 있다. 반대로 python3 scripts/run.py처럼 모호한 이름과 숨겨진 동작을 가진 스크립트는 사람도 싫어하지만, 에이전트는 더 싫어한다.

입력·출력 계약을 명문화하라

Skill에 스크립트를 붙일 때 가장 중요한 문서는 의외로 코드가 아니라 계약서다. 여기서 계약서란 "이 스크립트는 무엇을 받고 무엇을 돌려주는가"를 뜻한다.

입력 계약부터 보자. 최소한 다음이 정리되어 있어야 한다.

  • 어떤 인수가 필수인가

  • 경로, 문자열, 숫자, enum 중 무엇을 받는가

  • stdin을 쓰는가, 파일을 읽는가

  • 잘못된 입력이 오면 무엇을 에러로 보는가

출력 계약도 마찬가지다. 에이전트가 결과를 다음 단계에 넘겨야 하므로, 출력은 가급적 JSON, CSV, TSV처럼 구조화된 형식이 좋다. 사람이 읽기 좋다고 공백 정렬 표를 찍어 내면 에이전트는 다시 해석해야 한다. 그 한 번의 재해석이 불안정성을 만든다.1

실전에서는 stdout과 stderr를 분리하는 습관이 특히 중요하다. 구조화된 결과 데이터는 stdout으로 보내고, 진행 로그나 경고는 stderr로 보내야 한다. 그래야 에이전트가 결과를 깨끗하게 파싱하면서도, 실패 원인은 따로 볼 수 있다.1

예를 들어 출력 계약을 이렇게 고정할 수 있다.

{
  "status": "success",
  "data": {
    "total_score": 86,
    "passed": true,
    "missing_fields": []
  },
  "error": null
}

혹은 실패 시에는 이렇게 돌려줄 수 있다.

{
  "status": "error",
  "data": null,
  "error": {
    "code": "MISSING_COLUMN",
    "message": "Required column 'interview_score' not found"
  }
}

이런 계약은 에이전트에게 엄청난 도움을 준다. "아, 망했구나"가 아니라 "어떤 이유로 실패했는지"를 바로 이해할 수 있기 때문이다. 모호한 실패보다 좋은 실패가 더 낫다. 좋은 실패는 다음 행동을 결정할 수 있게 해 준다.

실패 처리는 친절함이 아니라 실행 설계다

에이전트는 완벽하지 않다. 잘못된 파일을 넘길 수도 있고, 없는 경로를 참조할 수도 있고, 외부 도구가 설치돼 있다고 착각할 수도 있다. 그러니 스크립트는 "정상 입력만 들어온다"는 가정 위에 서 있으면 안 된다.13

여기서 중요한 설계 원칙이 몇 가지 있다.

첫째, 애매하면 추측하지 말고 거절해야 한다. 입력 형식이 불분명한데 적당히 보정해 버리면, 에이전트는 잘못된 성공을 학습한다. 그보다 "--format은 json, csv, table 중 하나여야 합니다"처럼 분명히 실패시키는 편이 낫다.1

둘째, 재시도를 고려해 멱등성(idempotency)을 높여야 한다. 에이전트는 같은 명령을 다시 실행할 수 있다. 이때 "이미 존재하면 생성 실패"보다 "없으면 생성, 있으면 갱신 또는 건너뛰기"가 더 안전하다.1

셋째, 파괴적 작업에는 --dry-run이나 --confirm을 두는 편이 좋다. 삭제, 발송, 예약, 배포처럼 되돌리기 어려운 일은 먼저 시뮬레이션하고, 인간 승인 뒤에 실제 실행하도록 설계하는 것이 안전하다.1

넷째, 종료 코드를 의미 있게 써야 한다. 모든 실패를 exit code 1로 뭉개면 에이전트는 이유를 구분하기 어렵다. 인수 오류, 파일 없음, 인증 실패, 검증 실패가 다르다면 종료 코드나 구조화된 에러 코드도 다르게 주는 편이 좋다.1

결국 실패 처리는 예외 상황 대처가 아니라, 에이전트와 스크립트가 대화하는 방식이다.

실행 범위는 넓을수록 좋은 것이 아니다

스크립트를 붙이는 순간 Skill은 더 강력해지지만, 동시에 더 위험해진다. 파일을 읽고 쓰고, 셸 명령을 실행하고, 네트워크에 접근하고, 외부 도구를 설치할 수 있다면 생산성도 커지지만 사고 반경도 커진다. 그래서 스크립트 설계는 기능 설계와 동시에 권한 설계여야 한다.24

기본 원칙은 최소 권한이다. 이 Skill이 정말 Bash가 필요한가, 파일 쓰기가 필요한가, 네트워크 접근이 필요한가를 먼저 따져야 한다. 예를 들어 읽기 전용 분석 Skill이라면 결과는 콘솔이나 구조화된 출력으로만 반환하고, 원본 파일 수정은 금지하는 편이 낫다. 반대로 보고서 생성 Skill이라면 특정 출력 디렉터리에만 쓰기를 허용하는 식으로 범위를 좁혀야 한다.4

Claude Code 계열에서는 allowed-tools로 Skill이 주로 쓰는 도구를 제한할 수 있다. 이 기능은 완전한 보안 장치라기보다, "이 Skill은 어디까지 움직여도 되는가"를 미리 설정하는 운영 장치에 가깝다. 예를 들어 검증 전용 Skill이라면 읽기와 검색, 제한된 Bash 정도만 허용하고, 네트워크 호출이나 임의 파일 수정은 막는 식이다.4

또한 실행 환경은 샌드박스를 전제로 생각해야 한다. Microsoft의 예시도 파일 기반 스크립트 실행을 시연하면서, 실제 운영에서는 컨테이너나 격리 환경, CPU·메모리·시간 제한, 허용 스크립트 목록, 구조화된 로그가 필요하다고 분명히 경고한다.2 이 말은 아주 중요하다. 스크립트를 붙였다고 해서 곧바로 "믿을 수 있는 자동화"가 되는 것이 아니다. 실행 환경이 통제되어야 비로소 운영 가능한 자동화가 된다.

샌드박스, 타임아웃, 승인 단계를 어떻게 설계할까

실전에서는 세 겹으로 생각하면 편하다.

첫 번째는 어디서 실행되는가다. 가능하면 로컬 전체가 아니라 격리된 작업 디렉터리나 컨테이너 안에서 실행하게 해야 한다. 그래야 실수로 다른 프로젝트 파일을 건드리는 사고를 줄일 수 있다.2

두 번째는 얼마나 오래, 얼마나 많이 실행되는가다. 무한 루프, 대용량 출력, 메모리 폭주, 네트워크 지연은 에이전트의 세션 전체를 망가뜨릴 수 있다. 그래서 벽시계 기준 실행 시간 제한, CPU·메모리 제한, 출력 크기 제한이 필요하다. 특히 에이전트 도구 체인은 출력이 너무 길면 자동으로 잘릴 수 있으므로, 스크립트는 기본적으로 요약된 결과를 내고 필요할 때 상세 플래그를 받는 방식이 좋다.12

세 번째는 언제 사람에게 물어볼 것인가다. 파일 삭제, 외부 발송, 데이터베이스 쓰기, 캘린더 예약, 결제, 프로덕션 배포처럼 상태를 바꾸는 작업은 자동 실행보다 승인 단계를 앞세워야 한다. 최근의 에이전트 환경들도 중요한 행동 전에 사용자 확인을 요구하는 방향으로 설계되고 있다.5 Skill에서도 같은 원칙을 따라야 한다. 절차는 에이전트가 기억하되, 책임은 사람에게 남겨야 한다.

SKILL.md에는 스크립트를 어떻게 적어야 하는가

좋은 스크립트가 있어도 SKILL.md에서 연결을 흐리게 쓰면 소용이 없다. 에이전트는 스크립트가 존재한다는 사실, 언제 실행해야 하는지, 무엇을 기대해야 하는지를 SKILL.md에서 배운다.1

따라서 SKILL.md에는 적어도 세 가지가 들어가야 한다.

첫째, 사용 가능한 스크립트 목록이다. 파일명만 던지지 말고, 각 스크립트가 하는 일을 짧게 설명해야 한다.

둘째, 실행 조건이다. 어떤 상황에서 어떤 스크립트를 먼저 돌리는지 단계 안에 녹여야 한다. "CSV를 분석하기 전에 반드시 scripts/validate_csv.py를 실행해 필수 컬럼과 날짜 형식을 검사하라"처럼 써야 한다.

셋째, 기대 결과다. 성공하면 무엇이 출력되고, 실패하면 어떻게 대응해야 하는지 적어야 한다. "검증 실패 시 원본 분석을 진행하지 말고, 오류를 사용자에게 요약해 수정 요청하라" 같은 문장이 바로 그 역할을 한다.

예를 들면 이런 흐름이 좋다.

## Available scripts

- `scripts/validate_csv.py` — 입력 CSV의 필수 컬럼, 날짜 형식, 결측치 비율을 검사한다.
- `scripts/score_candidates.py` — 평가표에 가중치를 적용해 총점과 통과 여부를 계산한다.
- `scripts/check_output.py` — 최종 JSON 출력이 스키마와 회사 규칙을 만족하는지 검증한다.

## Workflow

1. 입력 파일을 받으면 먼저 `python3 scripts/validate_csv.py --input "$FILE"`를 실행한다.
2. 검증이 실패하면 분석을 중단하고 오류를 요약한다.
3. 검증이 통과하면 후보별 핵심 강점과 리스크를 분석한다.
4. 점수 계산이 필요하면 `python3 scripts/score_candidates.py --input "$FILE"`를 실행한다.
5. 최종 결과를 생성한 뒤 `python3 scripts/check_output.py --input result.json`으로 포맷을 검사한다.

이 정도만 되어도 에이전트는 "생각할 일"과 "실행할 일"을 꽤 잘 구분한다.

스크립트가 많아질수록 더 잘게 쪼개야 한다

초보자가 자주 빠지는 함정은 만능 스크립트다. run_all.py, process_everything.sh, smart_helper.js 같은 이름의 거대한 스크립트 하나로 모든 일을 처리하려고 한다. 처음에는 편해 보이지만, 금방 문제를 만든다. 입력 계약이 흐려지고, 실패 지점이 많아지고, 에이전트가 어떤 기능을 언제 써야 하는지 알기 어려워진다.13

훨씬 좋은 방식은 한 스크립트에 한 책임만 두는 것이다. 검증, 변환, 계산, 내보내기를 나누면 에이전트도 순서를 배우기 쉽고, 테스트도 쉬워진다. 무엇보다 실패했을 때 원인을 빠르게 좁힐 수 있다.

예를 들어 데이터 분석 Skill이라면 아래처럼 나누는 편이 낫다.

scripts/
├── validate_input.py
├── normalize_units.py
├── calculate_metrics.py
└── verify_output.py

이 구조에서는 "입력이 잘못됐는지", "단위 변환이 문제인지", "계산식이 틀렸는지", "최종 형식이 깨졌는지"를 단계별로 확인할 수 있다. 거대한 스크립트 하나보다 훨씬 디버깅이 쉽다. 에이전트에게도 이 구조가 더 친절하다. 사람보다 더 친절해야 한다는 점이 오히려 핵심이다.

결국 Skill의 안정성은 경계 설계에서 나온다

Skill에 스크립트를 붙인다는 말은 단순히 자동화 코드를 넣는다는 뜻이 아니다. 그보다 더 중요한 일은 경계를 설계하는 것이다. 어디까지는 모델이 해석하고, 어디부터는 코드가 확정하는지, 어떤 입력은 허용하고 어떤 입력은 거절하는지, 어떤 실패는 재시도하고 어떤 실패는 사람에게 올리는지, 어떤 도구는 허용하고 어떤 도구는 막는지를 정하는 일이다.124

이 경계가 모호하면 Skill은 똑똑해 보여도 믿기 어렵다. 반대로 이 경계가 선명하면 Skill은 화려하지 않아도 오래 간다. 실무에서 필요한 것은 대개 후자다. 놀라운 한 번보다, 흔들리지 않는 백 번이 더 값지기 때문이다.

그래서 좋은 Skill 설계자는 스크립트를 많이 쓰는 사람이 아니다. 모델이 해야 할 일과 코드가 해야 할 일을 정확히 구분하는 사람이다. 문장을 쓰는 능력만으로는 일하는 AI를 만들 수 없다. 절차를 나누고, 계약을 적고, 실패를 설계하고, 실행 범위를 좁히는 기술까지 들어가야 비로소 "프롬프트를 넘어서는 Skill"이 된다.

다음 장부터는 이런 원칙이 문서 작성, 리서치, 데이터 분석, 코딩 같은 실제 Skill 패턴 안에서 어떻게 구현되는지 더 구체적으로 보게 될 것이다. 그때부터 독자는 단순히 스킬의 구조를 아는 사람이 아니라, 일의 어느 부분을 코드로 잠가야 하는지 감각적으로 판단하는 설계자가 되기 시작한다.

참고

1Using scripts in skills - Agent Skills

2Agent Skills | Microsoft Learn

3Equipping agents for the real world with Agent Skills

4Claude를 skills로 확장하기 - Claude Code Docs

5Introducing ChatGPT agent: bridging research and action

책 목록

AI 에이전트 스킬 설계: 프롬프트를 넘어, 일하는 AI를 만드는 실행 지식의 기술

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기