G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현 G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건) G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST) G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직 G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트 G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트 G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트 G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트 G-10: core/push_notify.py + routers/push.py + PushSubscription 모델 G-11: approvals 다중승인 (위임/서명/기한초과/마감연장) G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh 하네스: guardia-orchestrator 확장기능 Phase 반영 봇명령어: /sr /status /license /bulk 슬래시 명령어 추가 설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
308 lines
11 KiB
Markdown
308 lines
11 KiB
Markdown
# 스킬 테스트 & 반복 개선 가이드
|
|
|
|
하네스에서 생성한 스킬의 품질을 검증하고 반복적으로 개선하는 방법론. SKILL.md Phase 6의 보충 레퍼런스.
|
|
|
|
---
|
|
|
|
## 목차
|
|
|
|
1. [테스트 프레임워크 개요](#1-테스트-프레임워크-개요)
|
|
2. [테스트 프롬프트 작성법](#2-테스트-프롬프트-작성법)
|
|
3. [실행 테스트: With-skill vs Baseline](#3-실행-테스트-with-skill-vs-baseline)
|
|
4. [정량적 평가: Assertion 기반 채점](#4-정량적-평가-assertion-기반-채점)
|
|
5. [전문 에이전트 활용](#5-전문-에이전트-활용)
|
|
6. [반복 개선 루프](#6-반복-개선-루프)
|
|
7. [Description 트리거 검증](#7-description-트리거-검증)
|
|
8. [워크스페이스 구조](#8-워크스페이스-구조)
|
|
|
|
---
|
|
|
|
## 1. 테스트 프레임워크 개요
|
|
|
|
스킬 품질 검증은 **정성적 평가**와 **정량적 평가**의 조합이다.
|
|
|
|
| 평가 유형 | 방법 | 적합한 스킬 |
|
|
|----------|------|-----------|
|
|
| **정성적** | 사용자가 산출물을 직접 리뷰 | 문체, 디자인, 창작물 등 주관적 품질 |
|
|
| **정량적** | assertion 기반 자동 채점 | 파일 생성, 데이터 추출, 코드 생성 등 객관적 검증 가능 |
|
|
|
|
핵심 루프: **작성 → 테스트 실행 → 평가 → 개선 → 재테스트**
|
|
|
|
---
|
|
|
|
## 2. 테스트 프롬프트 작성법
|
|
|
|
### 원칙
|
|
|
|
테스트 프롬프트는 **실제 사용자가 입력할 법한 구체적이고 자연스러운 문장**이어야 한다. 추상적이거나 인공적인 프롬프트는 테스트 가치가 낮다.
|
|
|
|
### 나쁜 예
|
|
|
|
```
|
|
"PDF를 처리하라"
|
|
"데이터를 추출하라"
|
|
"차트를 생성하라"
|
|
```
|
|
|
|
### 좋은 예
|
|
|
|
```
|
|
"다운로드 폴더에 있는 'Q4_매출_최종_v2.xlsx'에서 C열(매출)과 D열(비용)을
|
|
사용해서 이익률(%) 열을 추가해줘. 그리고 이익률 기준으로 내림차순 정렬."
|
|
```
|
|
|
|
```
|
|
"이 PDF에서 3페이지 표를 추출해서 CSV로 변환해줘. 표 헤더가 2줄로
|
|
되어 있어서 첫 번째 줄은 카테고리, 두 번째 줄이 실제 열 이름이야."
|
|
```
|
|
|
|
### 프롬프트 다양성
|
|
|
|
- **공식적 / 캐주얼** 톤 혼합
|
|
- **명시적 / 암시적** 의도 혼합 (파일 형식을 직접 말하는 경우 vs 맥락으로 추론해야 하는 경우)
|
|
- **단순 / 복잡** 작업 혼합
|
|
- 일부는 약어, 오타, 캐주얼한 표현 포함
|
|
|
|
### 커버리지
|
|
|
|
2~3개 프롬프트로 시작하되, 다음을 커버하도록 설계:
|
|
- 핵심 사용 사례 1개
|
|
- 엣지 케이스 1개
|
|
- (선택) 복합 작업 1개
|
|
|
|
---
|
|
|
|
## 3. 실행 테스트: With-skill vs Baseline
|
|
|
|
### 3-1. 비교 실행 구조
|
|
|
|
각 테스트 프롬프트에 대해 두 개의 서브에이전트를 **동시에** 스폰한다:
|
|
|
|
**With-skill 실행:**
|
|
```
|
|
프롬프트: "{테스트 프롬프트}"
|
|
스킬 경로: {스킬 경로}
|
|
출력 경로: _workspace/iteration-N/eval-{id}/with_skill/outputs/
|
|
```
|
|
|
|
**Baseline 실행:**
|
|
```
|
|
프롬프트: "{테스트 프롬프트}" (동일)
|
|
스킬: 없음
|
|
출력 경로: _workspace/iteration-N/eval-{id}/without_skill/outputs/
|
|
```
|
|
|
|
### 3-2. Baseline 선택
|
|
|
|
| 상황 | Baseline |
|
|
|------|----------|
|
|
| 새 스킬 생성 | 스킬 없이 같은 프롬프트 실행 |
|
|
| 기존 스킬 개선 | 수정 전 스킬 버전 (스냅샷 보존) |
|
|
|
|
### 3-3. 타이밍 데이터 캡처
|
|
|
|
서브에이전트 완료 알림에서 `total_tokens`와 `duration_ms`를 **즉시** 저장한다. 이 데이터는 알림 시점에만 접근 가능하고 이후 복구할 수 없다.
|
|
|
|
```json
|
|
{
|
|
"total_tokens": 84852,
|
|
"duration_ms": 23332,
|
|
"total_duration_seconds": 23.3
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 정량적 평가: Assertion 기반 채점
|
|
|
|
### 4-1. Assertion 작성
|
|
|
|
산출물이 객관적으로 검증 가능한 경우, 자동 채점을 위한 assertion을 정의한다.
|
|
|
|
**좋은 assertion:**
|
|
- 객관적으로 참/거짓 판별 가능
|
|
- 서술적인 이름으로 결과만 봐도 무엇을 검사하는지 명확
|
|
- 스킬의 핵심 가치를 검증
|
|
|
|
**나쁜 assertion:**
|
|
- 스킬 유무와 무관하게 항상 통과하는 것 (예: "출력이 존재한다")
|
|
- 주관적 판단이 필요한 것 (예: "잘 작성되었다")
|
|
|
|
### 4-2. 프로그래밍 가능한 검증
|
|
|
|
assertion이 코드로 검증 가능하면 스크립트로 작성한다. 눈으로 확인하는 것보다 빠르고 신뢰성 있으며, iteration마다 재사용 가능.
|
|
|
|
### 4-3. Non-discriminating assertion 주의
|
|
|
|
"두 구성 모두에서 100% 통과"하는 assertion은 스킬의 차별적 가치를 측정하지 못한다. 이런 assertion을 발견하면 제거하거나, 더 도전적인 assertion으로 교체한다.
|
|
|
|
### 4-4. 채점 결과 스키마
|
|
|
|
```json
|
|
{
|
|
"expectations": [
|
|
{
|
|
"text": "이익률 열이 추가됨",
|
|
"passed": true,
|
|
"evidence": "E열에 'profit_margin_pct' 열 확인"
|
|
},
|
|
{
|
|
"text": "이익률 기준 내림차순 정렬",
|
|
"passed": false,
|
|
"evidence": "정렬 없이 원본 순서 유지됨"
|
|
}
|
|
],
|
|
"summary": {
|
|
"passed": 1,
|
|
"failed": 1,
|
|
"total": 2,
|
|
"pass_rate": 0.50
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 전문 에이전트 활용
|
|
|
|
테스트/평가 과정에서 전문 역할의 에이전트를 활용하면 품질이 향상된다.
|
|
|
|
### 5-1. Grader (채점자)
|
|
|
|
assertion 기반 채점을 수행하고, 산출물에서 검증 가능한 주장(claim)을 추출하여 교차 검증한다.
|
|
|
|
**역할:**
|
|
- assertion별 통과/실패 판정 + 근거 제시
|
|
- 산출물에서 사실적 주장을 추출하고 검증
|
|
- eval 자체의 품질에 대한 피드백 (assertion이 너무 쉽거나 모호한 경우 제안)
|
|
|
|
### 5-2. Comparator (블라인드 비교자)
|
|
|
|
두 산출물을 A/B로 익명화하여, 어떤 것이 스킬을 사용한 결과인지 모르는 상태에서 품질을 판정한다.
|
|
|
|
**활용 시점:** "새 버전이 정말 더 나은가?"를 엄밀하게 확인하고 싶을 때. 일반적인 반복 개선에서는 생략 가능.
|
|
|
|
**판정 기준:**
|
|
- 내용: 정확성, 완성도
|
|
- 구조: 조직화, 포맷팅, 사용성
|
|
- 종합 점수
|
|
|
|
### 5-3. Analyzer (분석자)
|
|
|
|
벤치마크 데이터에서 통계적 패턴을 분석한다:
|
|
- Non-discriminating assertion (두 구성 모두 통과 → 차별력 없음)
|
|
- 고분산 eval (결과가 실행마다 크게 달라짐 → 불안정)
|
|
- 시간/토큰 트레이드오프 (스킬이 품질은 높이지만 비용도 높이는 경우)
|
|
|
|
---
|
|
|
|
## 6. 반복 개선 루프
|
|
|
|
### 6-1. 피드백 수집
|
|
|
|
사용자에게 산출물을 보여주고 피드백을 받는다. 빈 피드백은 "이상 없음"으로 해석한다.
|
|
|
|
### 6-2. 개선 원칙
|
|
|
|
1. **피드백을 일반화하라** — 테스트 예시에만 맞는 좁은 수정은 오버피팅이다. 원리 수준에서 수정한다.
|
|
2. **무게를 벌지 않는 것은 제거하라** — 트랜스크립트를 읽고, 스킬이 에이전트에게 비생산적인 작업을 시키고 있다면 해당 부분을 삭제한다.
|
|
3. **Why를 설명하라** — 사용자의 피드백이 간결하더라도, 왜 그것이 중요한지 이해하고 그 이해를 스킬에 반영한다.
|
|
4. **반복 작업은 번들링하라** — 모든 테스트 실행에서 동일한 헬퍼 스크립트가 생성되면, `scripts/`에 미리 포함한다.
|
|
|
|
### 6-3. 반복 절차
|
|
|
|
```
|
|
1. 스킬 수정
|
|
2. 새 iteration-N+1/ 디렉토리에 모든 테스트 케이스 재실행
|
|
3. 사용자에게 결과 제시 (이전 iteration과 비교)
|
|
4. 피드백 수집
|
|
5. 다시 수정 → 반복
|
|
```
|
|
|
|
**종료 조건:**
|
|
- 사용자가 만족
|
|
- 피드백이 모두 비어 있음 (모든 산출물 이상 없음)
|
|
- 의미 있는 개선이 더 이상 없음
|
|
|
|
### 6-4. 초안 → 재검토 패턴
|
|
|
|
스킬 수정 시, 초안을 작성한 후 **새로운 시각으로 다시 읽고** 개선한다. 한 번에 완벽하게 쓰려 하지 말고, 초안-검토 사이클을 거친다.
|
|
|
|
---
|
|
|
|
## 7. Description 트리거 검증
|
|
|
|
### 7-1. 트리거 Eval 쿼리 작성
|
|
|
|
20개의 eval 쿼리를 작성한다 — should-trigger 10개 + should-NOT-trigger 10개.
|
|
|
|
**쿼리 품질 기준:**
|
|
- 실제 사용자가 입력할 법한 구체적이고 자연스러운 문장
|
|
- 파일 경로, 개인적 맥락, 열 이름, 회사명 등 구체적 디테일 포함
|
|
- 길이, 톤, 형식 다양하게 혼합
|
|
- 명확한 정답보다 **경계 케이스(edge case)**에 집중
|
|
|
|
**Should-trigger 쿼리 (8~10개):**
|
|
- 다양한 표현의 같은 의도 (공식적/캐주얼)
|
|
- 스킬/파일 유형을 명시적으로 말하지 않지만 분명히 필요한 경우
|
|
- 비주류 사용 사례
|
|
- 다른 스킬과 경쟁하지만 이 스킬이 이겨야 하는 경우
|
|
|
|
**Should-NOT-trigger 쿼리 (8~10개):**
|
|
- **Near-miss가 핵심** — 키워드가 유사하지만 다른 도구/스킬이 적합한 쿼리
|
|
- 명백히 무관한 쿼리("피보나치 함수 작성")는 테스트 가치 없음
|
|
- 인접 도메인, 모호한 표현, 키워드 겹침 but 맥락이 다른 경우
|
|
|
|
### 7-2. 기존 스킬 충돌 검증
|
|
|
|
새 스킬의 description이 기존 스킬의 트리거 영역과 겹치지 않는지 확인한다:
|
|
|
|
1. 기존 스킬 목록의 description을 수집
|
|
2. 새 스킬의 should-trigger 쿼리가 기존 스킬을 잘못 트리거하지 않는지 확인
|
|
3. 충돌 발견 시 description의 경계 조건을 더 명확히 기술
|
|
|
|
### 7-3. 자동 최적화 (선택적 고급 기능)
|
|
|
|
description 최적화가 필요한 경우:
|
|
|
|
1. 20개 eval 쿼리를 Train(60%) / Test(40%) split
|
|
2. 현재 description으로 트리거 정확도 측정
|
|
3. 실패 케이스를 분석하여 개선된 description 생성
|
|
4. Test set 기준으로 best description 선택 (Train set 기준이 아님 — 과적합 방지)
|
|
5. 최대 5회 반복
|
|
|
|
> 이 과정은 `claude -p`를 사용하는 자동화 스크립트로 수행한다. 토큰 비용이 높으므로 스킬이 충분히 안정화된 후 최종 단계에서 실행한다.
|
|
|
|
---
|
|
|
|
## 8. 워크스페이스 구조
|
|
|
|
테스트/평가 결과를 체계적으로 관리하는 디렉토리 구조:
|
|
|
|
```
|
|
{skill-name}-workspace/
|
|
├── iteration-1/
|
|
│ ├── eval-descriptive-name-1/
|
|
│ │ ├── eval_metadata.json
|
|
│ │ ├── with_skill/
|
|
│ │ │ ├── outputs/
|
|
│ │ │ ├── timing.json
|
|
│ │ │ └── grading.json
|
|
│ │ └── without_skill/
|
|
│ │ ├── outputs/
|
|
│ │ ├── timing.json
|
|
│ │ └── grading.json
|
|
│ ├── eval-descriptive-name-2/
|
|
│ │ └── ...
|
|
│ └── benchmark.json
|
|
├── iteration-2/
|
|
│ └── ...
|
|
└── evals/
|
|
└── evals.json
|
|
```
|
|
|
|
**규칙:**
|
|
- eval 디렉토리는 숫자가 아닌 **서술적 이름** 사용 (예: `eval-multi-page-table-extraction`)
|
|
- 각 iteration은 독립 디렉토리에 보존 (이전 iteration 덮어쓰기 금지)
|
|
- `_workspace/`는 삭제하지 않음 — 사후 검증 및 감사 추적용
|