Agent Skills eval 운영법: 스킬이 좋아졌는지 감으로 보지 않는 방법
Agent Skill을 만들다 보면 이런 일이 자주 생긴다. 설명을 조금 고쳤더니 더 잘 호출되는 것 같다. 실행 순서를 바꿨더니 빨라진 것 같다. 그런데 며칠 뒤 다른 요청에서는 스킬이 아예 발동하지 않거나, 필요한 명령을 건너뛰거나, 임시 파일을 이상한 곳에 남긴다. 감으로는 개선인지 회귀인지 판단하기 어렵다.
OpenAI의 'Testing Agent Skills Systematically with Evals'는 이 문제를 eval로 다루는 방법을 설명한다. 핵심은 단순하다. prompt, captured run, artifacts, checks, score를 하나의 루프로 묶는다. 이 글은 Codex 기반 스킬뿐 아니라 사내 AI 에이전트 지침, MCP 작업 절차, 운영 runbook에도 적용할 수 있는 실무 방식을 정리한다.
먼저 성공을 정의한다
스킬을 쓰기 전에 '성공'을 측정 가능한 말로 바꿔야 한다. 좋은 분류는 네 가지다. Outcome goal, process goal, style goal, efficiency goal이다.
Outcome goal은 결과가 만들어졌는지 본다. 예를 들어 Vite React demo app을 만드는 스킬이라면 package.json이 있는지, npm run dev가 뜨는지 확인한다. Process goal은 의도한 절차를 따랐는지 본다. npm install을 실제로 실행했는지, Tailwind 설정 전에 프로젝트를 만들었는지 같은 항목이다. Style goal은 팀 컨벤션을 봐야 한다. TypeScript component만 썼는지, CSS module을 만들지 않았는지, 파일 구조가 맞는지 확인한다. Efficiency goal은 불필요한 command 반복, 과도한 token 사용, 같은 오류의 반복 재시도를 본다.
처음부터 완벽한 rubric을 만들 필요는 없다. 반드시 지켜야 하는 5~10개만 고른다. eval은 법전이 아니라 회귀를 빨리 잡는 안전망이다.
트리거 테스트가 중요하다
Skill은 SKILL.md의 name과 description에 크게 의존한다. 그래서 내용이 좋아도 trigger가 애매하면 스킬이 필요한 상황에서 불리지 않는다. 반대로 description이 너무 넓으면 기존 앱에 Tailwind를 추가하라는 요청에서도 새 demo app을 scaffold할 수 있다.
작은 prompt set을 만들자. 10~20개면 충분하다. 각 row에는 id, should_trigger, prompt를 둔다. 예를 들어 Create a demo app named devday-demo using the setup skill은 true, Add Tailwind styling to my existing React app은 false다. 직접 스킬명을 부르는 explicit invocation, 스킬명을 말하지 않는 implicit invocation, 약간의 도메인 noise가 섞인 contextual invocation, 발동하면 안 되는 negative control을 섞는다.
이 데이터셋은 시간이 지날수록 좋아진다. 실제 업무에서 스킬이 잘못 발동한 요청이나 놓친 요청을 한 줄씩 추가하면 된다. prompt set은 스킬 운영의 사고 기록이기도 하다.
deterministic grader부터 만든다
모든 것을 LLM judge에게 맡기면 eval도 흔들린다. 먼저 deterministic check를 만든다. Codex의 --json 실행처럼 structured event를 남길 수 있다면 command execution event를 파싱해 npm install 실행 여부를 확인한다. 파일 생성 여부, exit code, 특정 config 값, 금지 파일 생성 여부도 자동으로 볼 수 있다.
예를 들어 demo app 스킬이면 다음 정도를 확인한다.
package.json존재src/components/Header.tsx존재src/components/Card.tsx존재npm install실행 이벤트 존재- Tailwind import가
src/index.css에 존재 - 새 프로젝트가 요청한 이름으로 생성됨
이런 체크는 실패했을 때 설명이 쉽다. JSONL trace를 열어 실제 어떤 명령을 실행했는지 보면 된다. 회귀 원인도 찾기 쉽다.
qualitative check는 구조화한다
파일 존재만으로는 품질을 평가할 수 없다. component 구조가 지저분하거나, Tailwind 대신 inline style을 남발하거나, instruction이 요구한 최소 UI를 만들지 않았을 수 있다. 이때는 model-assisted grading을 쓰되, output schema를 고정한다.
예를 들어 overall_pass, score, checks, violations, recommended_fix 같은 JSON schema를 둔다. grader prompt에는 'read-only로 결과물을 검토하고, 없는 요구사항을 상상하지 말라'고 쓴다. 점수만 받지 말고 어떤 체크가 실패했는지 배열로 받아야 다음 개선으로 이어진다.
중요한 것은 deterministic check와 qualitative check를 섞는 것이다. 전자는 빠르고 재현 가능하다. 후자는 사람 리뷰어의 판단에 가까운 영역을 본다. 둘 중 하나만 있으면 blind spot이 생긴다.
CI에 넣을 때의 기준
스킬 eval은 매 PR마다 전체를 돌릴 필요가 없다. 작은 smoke set은 PR에서 돌리고, 긴 prompt set은 nightly나 release 전에 돌리는 식이 현실적이다. 특히 agent run은 비용과 시간이 들기 때문에 trigger eval, deterministic artifact check, rubric grading을 단계적으로 나눠야 한다.
결과 저장도 중요하다. prompt, skill version, model, sandbox setting, command trace, artifact path, score를 같이 남긴다. 모델이 바뀌면 결과도 바뀔 수 있으므로 version 정보를 빼면 비교가 어렵다. 실패 케이스는 단순 로그가 아니라 다음 prompt set 후보가 된다.
스킬 개선 루프
좋은 운영 방식은 짧다. 실패를 발견한다. 실패 prompt를 dataset에 추가한다. 스킬 설명이나 절차를 고친다. eval을 다시 돌린다. 기존 통과 케이스가 깨지지 않았는지 본다. 이 과정을 반복한다.
여기서 주의할 점은 스킬을 너무 똑똑하게 만들려 하지 않는 것이다. 스킬은 특정 workflow를 안정적으로 수행하는 작은 패키지다. 범위를 넓히면 trigger도 흐려지고 eval도 어려워진다. setup skill, deploy skill, migration skill처럼 목적을 작게 나누는 편이 낫다.
실행 체크리스트
- 스킬별 outcome/process/style/efficiency goal을 5~10개로 제한한다.
- explicit, implicit, contextual, negative prompt를 포함한 10~20개 dataset을 만든다.
--jsontrace나 동등한 event log를 저장한다.- 파일 존재, 명령 실행, config 값은 deterministic check로 본다.
- 구조와 스타일은 JSON schema가 있는 rubric grader로 평가한다.
- prompt, model, skill version, sandbox setting, score를 같이 저장한다.
- PR에는 smoke eval, nightly에는 full eval을 돌린다.
- 실제 실패 사례를 dataset에 추가해 회귀 방지 자산으로 만든다.