Chapter 0: 하네스 한눈에 보기
이 챕터는 책 전체의 핵심을 3분 안에 전달한다. Agent와 Skill의 기본 개념을 이미 알고 있다면, 여기서 하네스의 전체 그림을 파악하고 Part 2(Chapter 4)부터 바로 시작할 수 있다.
하네스 = 에이전트 팀 + 오케스트레이터 스킬
하네스의 핵심은 한 문장으로 요약된다:
전문 에이전트 팀을 구성하고, 오케스트레이터 스킬이 이들을 조율하여 복잡한 요청을 처리하는 구조.
사용자 요청
│
▼
┌─────────────────────────────────┐
│ 오케스트레이터 스킬 (SKILL.md) │ ← 누가, 언제, 어떤 순서로 일하는지 정의
│ │
│ Phase 1 → 에이전트 A → 산출물 │
│ Phase 2 → 에이전트 B → 산출물 │
│ Phase 3 → 에이전트 C → 검증 │
│ Phase 4 → ... → 결과물 │
└─────────────────────────────────┘
│
▼
최종 결과
에이전트는 “누가 하는가” — 전문가의 역할과 원칙을 정의한다. 스킬은 “어떻게 하는가” — 작업의 절차와 규칙을 정의한다. 오케스트레이터 스킬은 “어떤 순서로 하는가” — 에이전트 팀의 실행 흐름을 정의한다.
이 세 요소가 .claude/ 디렉토리 안에 마크다운 파일로 존재한다. 그것이 하네스의 전부다.
인포그래픽: 하네스 구성 요소 전체 맵
메타 스킬: “책을 집필해줘” 한마디면 끝
사용자가 하네스를 직접 설계할 필요는 없다. 하네스 메타 스킬(/harness)이 이 과정을 자동화한다.
“책 집필을 자동화하고 싶다”고 요청하면, 메타 스킬이:
- 도메인을 분석한다 (어떤 작업이 필요한가?)
- 에이전트 팀을 구성한다 (
.claude/agents/에 파일 생성) - 각 에이전트의 스킬을 만든다 (
.claude/skills/에 파일 생성) - 팀을 조율하는 오케스트레이터를 만든다
- 생성된 하네스를 검증한다
메타 스킬은 “스킬을 만드는 스킬”이다. 에이전트 팀 + 오케스트레이터라는 복잡한 구조를 한 번의 요청으로 자동 생성한다. 물론 자동 생성된 결과를 이해하고 커스터마이징하려면 각 파일의 구조를 알아야 한다 — 이것이 이 책에서 생성된 구조를 상세히 다루는 이유다.
인포그래픽: 메타 스킬이 하네스를 만드는 과정
메타 스킬의 실제 내용
아래는 실제로 사용되는 하네스 메타 스킬의 전체 내용이다. 3개의 파일로 구성된다.
디렉토리 구조
~/.claude/skills/harness/
├── SKILL.md # 메타 스킬 본체
└── references/
├── agent-design-patterns.md # 아키텍처 패턴 레퍼런스
└── team-examples.md # 팀 구성 예시
프로젝트별이 아니라 사용자의 홈 디렉토리(~/.claude/)에 위치한다. 어떤 프로젝트에서든 “책을 집필해줘”, “리서치 팀을 구성해줘”라고 요청하면 이 메타 스킬이 트리거되어 해당 도메인에 맞는 하네스를 자동 생성한다.
파일 1: SKILL.md (메타 스킬 본체)
---
name: harness
description: "하네스를 구성합니다. 전문 에이전트를 정의하며, 해당 에이전트가
사용할 스킬을 생성하는 메타 스킬. (1) '하네스 구성해줘',
'하네스 구축해줘' 요청 시, (2) '하네스 설계', '하네스 엔지니어링'
요청 시, (3) 새로운 도메인/프로젝트에 대한 하네스 기반 자동화
체계를 구축할 때, (4) 하네스 구성을 재구성하거나 확장할 때 사용."
---
# Harness — Agent Team & Skill Architect
도메인/프로젝트에 맞는 하네스를 구성하고, 각 에이전트의 역할을 정의하며,
에이전트가 사용할 스킬을 생성하는 메타 스킬.
**핵심 원칙: 에이전트 정의(`.claude/agents/`)와 스킬(`.claude/skills/`)을 생성한다.**
## 워크플로우
### Phase 1: 도메인 분석
1. 사용자 요청에서 도메인/프로젝트 파악
2. 핵심 작업 유형 식별 (생성, 검증, 편집, 분석 등)
3. 기존 에이전트/스킬 확인 (충돌/중복 방지)
### Phase 2: 팀 아키텍처 설계
1. 작업을 전문 영역으로 분해
2. 에이전트 팀 구조 결정 (아키텍처 패턴은 `references/agent-design-patterns.md` 참조)
- **파이프라인**: 순차 의존 작업
- **팬아웃/팬인**: 병렬 독립 작업
- **전문가 풀**: 상황별 선택 호출
- **생성-검증**: 생성 후 품질 검수
3. 에이전트 분리 기준 적용:
- 전문성이 다르면 분리
- 독립 실행 가능하면 분리
- 컨텍스트 부담이 크면 분리
- 재사용성이 높으면 분리
### Phase 3: 에이전트 정의 생성
각 에이전트를 `프로젝트/.claude/agents/{name}.md`에 정의:
```markdown
---
name: agent-name
description: "역할 설명. 트리거 키워드."
model: sonnet
---
# Agent Name — 역할 요약
당신은 [도메인]의 [역할] 전문가입니다.
## 핵심 역할
## 작업 원칙
## 출력 형식
## 협업
```
**에이전트 생성 원칙:**
- shared/ 규칙(기본 지침, 코딩 원칙 등)을 에이전트 작업 원칙에 반영
- "Always respond in Korean" 등 기본 지침을 포함
- 출력 형식은 구체적으로 (마크다운 예시 포함)
### Phase 4: 스킬 생성
각 에이전트가 사용할 스킬을 `프로젝트/.claude/skills/{name}/SKILL.md`에 생성.
**스킬 생성 원칙:**
- 에이전트 1개 ↔ 스킬 1~N개 (1:1 또는 1:다)
- 여러 에이전트가 공유하는 스킬도 가능
- 스킬은 "어떻게 하는가"를 담고, 에이전트는 "누가 하는가"를 담는다
- 레퍼런스가 크면 `references/` 하위에 분리
### Phase 5: 통합 스킬 (오케스트레이터)
팀 전체를 조율하는 상위 스킬 생성:
- 시나리오별 에이전트 구성 테이블
- Phase별 워크플로우 (병렬/순차)
- 에이전트 간 데이터 흐름
- 각 Phase의 **검증 기준** 명시
### Phase 6: 검증
- [ ] 모든 에이전트 파일이 올바른 위치에 있는지 확인
- [ ] frontmatter(name, description, model) 검증
- [ ] 에이전트의 description에 트리거 키워드가 포함되어 있는지 확인
- [ ] 에이전트 간 참조 일관성 확인
- [ ] 오케스트레이터 스킬에서 모든 에이전트가 참조되는지 확인
- [ ] 커맨드(`.claude/commands/`)가 생성되지 않았는지 확인
## 산출물 체크리스트
- [ ] `프로젝트/.claude/agents/` — 에이전트 정의 파일들
- [ ] `프로젝트/.claude/skills/` — 스킬 파일들 (SKILL.md + references/)
- [ ] 통합 오케스트레이터 스킬 1개
- [ ] `.claude/commands/` — 아무것도 생성하지 않음
- [ ] 기존 에이전트/스킬과 충돌 없음
## 참고
- 아키텍처 패턴: `references/agent-design-patterns.md`
- 팀 구성 예시: `references/team-examples.md`파일 2: references/agent-design-patterns.md (아키텍처 패턴)
메타 스킬이 Phase 2에서 팀 구조를 결정할 때 참조하는 패턴 레퍼런스다.
# Agent Team Design Patterns
## 에이전트 팀 아키텍처 유형
### 1. 파이프라인 (Pipeline)
순차적 작업 흐름. 이전 에이전트의 출력이 다음 에이전트의 입력.
```
[분석] → [설계] → [구현] → [검증]
```
예시: 소설 집필 — 세계관 → 캐릭터 → 플롯 → 집필 → 편집
### 2. 팬아웃/팬인 (Fan-out/Fan-in)
병렬 처리 후 결과 통합. 독립적 작업을 동시 수행.
```
┌→ [전문가A] ─┐
[분배] → ├→ [전문가B] ─┼→ [통합]
└→ [전문가C] ─┘
```
예시: 종합 리뷰 — 문체/과학/일관성 동시 검증 → 통합 보고
### 3. 전문가 풀 (Expert Pool)
상황에 따라 적절한 전문가를 선택 호출.
```
[라우터] → { 전문가A | 전문가B | 전문가C }
```
예시: 소설 도메인 — 세계관/캐릭터/플롯 중 필요한 전문가만 호출
### 4. 생성-검증 (Producer-Reviewer)
생성 에이전트와 검증 에이전트가 쌍으로 동작.
```
[생성] → [검증] → (문제시) → [생성] 재실행
```
예시: 웹툰 — artist 생성 → reviewer 검수 → 문제 패널 재생성
## 에이전트 분리 기준
| 기준 | 분리 | 통합 |
|------|------|------|
| 전문성 | 영역이 다르면 분리 | 영역이 겹치면 통합 |
| 병렬성 | 독립 실행 가능하면 분리 | 순차 종속이면 통합 고려 |
| 컨텍스트 | 컨텍스트 부담이 크면 분리 | 가볍고 빠르면 통합 |
| 재사용성 | 다른 팀에서도 쓰면 분리 | 이 팀에서만 쓰면 통합 고려 |
## 스킬 vs 에이전트 구분
| 구분 | 스킬 (Skill) | 에이전트 (Agent) |
|------|-------------|-----------------|
| 정의 | 절차적 지식 + 도구 번들 | 전문가 페르소나 + 행동 원칙 |
| 위치 | `.claude/skills/` | `.claude/agents/` |
| 트리거 | 사용자 요청 키워드 매칭 | Agent 도구로 명시적 호출 |
| 용도 | "어떻게 하는가" | "누가 하는가" |파일 3: references/team-examples.md (팀 구성 예시)
메타 스킬이 도메인별 팀 구성을 참고할 때 사용하는 예시 모음이다.
# Agent Team Examples
## 예시 1: SF 소설 집필 팀
| 에이전트 | 역할 | 스킬 |
|---------|------|------|
| worldbuilder | 세계관 구축 | world-setting |
| character-designer | 캐릭터 설계 | character-profile |
| plot-architect | 플롯 구조 | outline |
| prose-stylist | 문체 편집 | write-scene, review-chapter |
| science-consultant | 과학 검증 | science-check |
| continuity-manager | 일관성 검증 | consistency-check |
### 팀 아키텍처
```
Phase 1 (병렬): worldbuilder + character-designer + plot-architect
Phase 2 (순차): prose-stylist (집필)
Phase 3 (병렬): prose-stylist + science-consultant + continuity-manager (리뷰)
```
## 예시 2: 웹툰 제작 팀
| 에이전트 | 역할 | 스킬 |
|---------|------|------|
| webtoon-artist | 패널 이미지 생성 | generate-webtoon |
| webtoon-reviewer | 품질 검수 | review-webtoon, fix-webtoon-panel |
### 팀 아키텍처
```
Phase 1: webtoon-artist (패널 생성)
Phase 2: webtoon-reviewer (검수)
Phase 3: webtoon-artist (문제 패널 재생성)
```
## 예시 3: 리서치 팀
| 에이전트 | 역할 |
|---------|------|
| web-researcher | 웹 검색/수집 |
| analyst | 데이터 분석/종합 |
| report-writer | 보고서 작성 |이 3개 파일이 메타 스킬의 전부다. SKILL.md가 워크플로우(6단계)를 정의하고, references의 두 파일이 팀 설계 시 참조하는 패턴 사전과 예시 모음 역할을 한다. 메타 스킬은 이 레퍼런스를 읽고 도메인에 적합한 패턴과 팀 구조를 결정한다.
실제 동작 예시: 이 책이 만들어진 방법
이 책 자체가 하네스로 만들어졌다. “12챕터 기술서를 집필해줘”라는 요청 하나로, 5명의 에이전트가 협업하여 259페이지 PDF를 만들어냈다.
에이전트 팀
| 에이전트 | 역할 | 하는 일 |
|---|---|---|
book-planner |
기획자 | 목차와 챕터별 명세를 설계 |
chapter-writer |
집필자 | 명세에 따라 챕터를 작성 |
book-editor |
편집자 | 원고를 리뷰하고 이슈를 발견 |
infographic-creator |
디자이너 | 챕터별 SVG 인포그래픽 생성 |
book-publisher |
출판 담당 | PDF와 웹 뷰어를 빌드 |
오케스트레이터가 조율한 흐름
Phase 1: [book-planner] → outline.md (목차 설계)
│
Phase 2: [chapter-writer] → ch01.md ~ ch12.md (12챕터 집필)
│
Phase 3: [book-editor] → 리뷰 → CRITICAL 이슈?
│ ├─ Yes → [chapter-writer] 수정 → 재리뷰
│ └─ No → 승인
│
Phase 4: [infographic-creator] → 7개 SVG (병렬 생성)
│
Phase 5: [book-publisher] → PDF 259p + 웹 뷰어
에이전트들은 서로 직접 대화하지 않는다. 파일을 통해 통신한다. book-planner가 outline.md를 만들면, chapter-writer가 그 파일을 읽고 챕터를 쓴다. 오케스트레이터가 이 데이터 흐름을 관리한다.
파일 구조
.claude/
├── agents/ # 에이전트 정의 (5명)
│ ├── book-planner.md
│ ├── chapter-writer.md
│ ├── book-editor.md
│ ├── infographic-creator.md
│ └── book-publisher.md
└── skills/
└── book-writer/ # 오케스트레이터 스킬
└── SKILL.md
마크다운 파일 6개. 이것이 5명의 전문가 팀과 지휘자를 만들어낸 전부다.
인포그래픽: book-writer 하네스 전체 아키텍처
하네스의 핵심 아이디어 3가지
1. 복잡한 작업은 팀으로 나눈다. 한 에이전트에게 모든 것을 맡기면 역할 충돌, 컨텍스트 부족, 병렬 처리 불가의 벽에 부딪힌다. 전문성별로 에이전트를 나누면 각자 자기 역할에 집중할 수 있다.
2. 오케스트레이터가 팀을 지휘한다. 에이전트들이 있어도 누군가 순서를 정하고 결과를 전달해야 한다. 오케스트레이터 스킬이 Phase별 워크플로우를 정의하고, 에이전트 간 데이터 흐름을 관리한다.
3. 모든 것이 마크다운 파일이다. 에이전트 정의, 스킬 정의, 오케스트레이터 — 전부 .claude/ 안의 마크다운 파일이다. 코드 한 줄 없이 자연어로 팀을 구성한다. 이것이 하네스가 접근하기 쉬운 이유다.
이 책의 구성과 읽는 법
| Part | 내용 | 답하는 질문 |
|---|---|---|
| Part 1 (Ch01~02) | 핵심 개념 | 에이전트/스킬이 뭔가? 메타 스킬로 하네스를 어떻게 만드나? |
| Part 2 (Ch03~05) | 생성된 하네스의 구조 | 아키텍처 패턴은? 생성된 파일 구조는? 오케스트레이터는? |
| Part 3 (Ch06~08) | 실전 사례 3가지 | 실제 도메인에 어떻게 적용하나? |
| Part 4 (Ch09~11) | 운영과 확장 | 디버깅, 설계, 메타 스킬 커스터마이징은? |
추천 경로
- Agent/Skill 개념이 처음이라면: Chapter 1부터 순서대로 읽는다.
- 하네스가 처음이라면: Chapter 2(메타 스킬)를 읽고 직접 실행해본다. 그 후 Part 2로 간다.
- 생성된 구조를 이해하고 싶다면: Part 2(Chapter 3)부터 시작한다.
- 실전 사례가 궁금하다면: Part 3(Chapter 6)의 book-writer 하네스 분석부터 읽는다.
다음 챕터부터는 이 전체 그림을 구성하는 각 조각을 하나씩 다룬다. Chapter 1에서는 에이전트와 스킬의 기본 개념과 파일 구조를 살펴본다.
Chapter 1: Claude Code의 Agent와 Skill 이해하기
이 챕터에서 배울 것
- Claude Code의 확장 구조인
.claude/디렉토리가 어떻게 구성되는지 - Agent(에이전트)와 Skill(스킬)이 각각 무엇이며, 왜 분리되어 있는지
- 에이전트 파일과 스킬 파일의 물리적 위치와 구조
- frontmatter의 역할과 트리거 키워드가 동작하는 방식
- 실제 에이전트 파일과 스킬 파일을 읽고 구조를 파악하는 방법
본문
Claude Code는 어떻게 확장되는가
Claude Code는 터미널에서 동작하는 AI 코딩 어시스턴트다. 기본 상태로도 코드를 읽고, 수정하고, 실행할 수 있다. 하지만 프로젝트마다 필요한 전문성은 다르다. 코드 리뷰를 전문으로 하는 AI가 필요할 수도 있고, PDF 조판을 담당하는 AI가 필요할 수도 있다.
이런 확장은 프로젝트 루트의 .claude/ 디렉토리를 통해 이루어진다. 이 디렉토리 안에 마크다운 파일을 배치하면, Claude Code가 이를 읽어서 새로운 능력과 역할을 갖추게 된다.
.claude/
├── agents/ # 에이전트 정의 파일들
│ ├── book-planner.md
│ ├── chapter-writer.md
│ └── book-editor.md
├── skills/ # 스킬 정의 파일들
│ └── book-writer/
│ └── SKILL.md
└── settings.local.json
여기서 핵심적인 두 가지 개념이 등장한다: Agent와 Skill이다.
Agent: “누가 하는가”
에이전트(Agent)는 특정 전문성을 가진 페르소나(persona)다. 사람으로 비유하면 “직책”에 해당한다. 편집자, 기획자, 디자이너처럼 각자 다른 관점과 원칙을 가지고 일한다.
에이전트 파일은 다음 질문에 답한다:
- 이 AI는 누구인가? (역할 정의)
- 어떤 원칙을 따르는가? (행동 규범)
- 어떤 형식으로 결과를 내는가? (출력 규격)
- 누구와 협업하는가? (인터페이스)
에이전트 파일은 .claude/agents/ 디렉토리에 위치하며, 파일명은 {에이전트명}.md 형식이다.
에이전트는 행동의 주체를 정의한다. “무엇을 해야 하는지”보다 “어떤 관점에서 일하는지”에 초점을 맞춘다.
Skill: “어떻게 하는가”
스킬(Skill)은 구체적인 작업 절차를 담은 가이드다. 사람으로 비유하면 “업무 매뉴얼”에 해당한다. 여러 에이전트가 어떤 순서로 일하고, 어떤 도구를 쓰고, 어떤 결과물을 만들어야 하는지를 정의한다.
스킬 파일은 다음 질문에 답한다:
- 어떤 단계를 거쳐 작업하는가? (워크플로우)
- 각 단계에서 어떤 도구를 사용하는가? (도구 번들)
- 산출물은 어디에, 어떤 형식으로 저장하는가? (출력 규칙)
- 여러 에이전트를 어떤 순서로 호출하는가? (오케스트레이션)
스킬 파일은 .claude/skills/{스킬명}/SKILL.md 경로에 위치한다. 에이전트와 달리 디렉토리 단위로 관리되는데, 스킬에 필요한 참고 자료(references/)나 템플릿을 함께 묶기 위해서다.
스킬은 절차와 방법을 정의한다. “누가 하는지”보다 “어떤 순서로, 어떤 도구로 하는지”에 초점을 맞춘다.
Agent와 Skill의 관계
이 둘의 관계를 정리하면 다음과 같다:
| 구분 | Agent (에이전트) | Skill (스킬) |
|---|---|---|
| 비유 | 직책 (편집자, 기획자) | 업무 매뉴얼 (집필 프로세스) |
| 핵심 질문 | “누가 하는가?” | “어떻게 하는가?” |
| 정의 내용 | 페르소나, 원칙, 출력 형식 | 워크플로우, 도구, 산출물 규칙 |
| 파일 위치 | .claude/agents/*.md |
.claude/skills/*/SKILL.md |
| 단위 | 파일 1개 = 에이전트 1명 | 디렉토리 1개 = 스킬 1개 |
인포그래픽: Agent vs Skill 비교 다이어그램
왜 분리해야 할까? 하나의 스킬이 여러 에이전트를 조율할 수 있고, 하나의 에이전트가 여러 스킬에서 활용될 수 있기 때문이다. 예를 들어 chapter-writer 에이전트는 book-writer 스킬뿐 아니라, 미래에 만들 blog-writer 스킬에서도 재사용할 수 있다.
파일 구조: frontmatter와 본문
에이전트 파일과 스킬 파일은 모두 마크다운으로 작성되며, frontmatter(프론트매터)라는 메타데이터 영역을 가진다. frontmatter는 파일 최상단에 ---로 감싸진 YAML 블록이다.
frontmatter의 3가지 핵심 필드
---
name: chapter-writer
description: "책의 챕터를 집필하는 에이전트. '챕터 작성', '집필', 'write chapter' 요청 시 트리거."
model: opus
---name: 이 에이전트(또는 스킬)의 고유 식별자. 다른 파일에서 이 이름으로 참조한다.description: 역할 설명과 함께 트리거 키워드를 포함한다. Claude Code가 사용자의 요청을 이 설명과 매칭하여 적절한 에이전트/스킬을 활성화한다.model: 이 에이전트가 사용할 AI 모델을 지정한다.opus는 가장 강력한 모델로 복잡한 창작 작업에 적합하고,sonnet은 빠르고 효율적인 모델로 분석이나 검증 작업에 적합하다.
트리거 키워드의 역할
description 필드에 포함된 키워드는 단순한 설명이 아니다. 사용자가 Claude Code에게 요청할 때, 이 키워드와 매칭되는 에이전트나 스킬이 자동으로 선택된다.
# book-planner의 description
description: "책의 목차와 구조를 설계하는 에이전트. '목차 설계', '책 구조', 'book plan' 요청 시 트리거."사용자가 “목차 설계해줘”라고 입력하면, Claude Code는 이 description을 보고 book-planner 에이전트를 활성화한다. 따라서 트리거 키워드는 사용자가 실제로 사용할 만한 자연스러운 표현이어야 한다.
실습: 실제 에이전트 파일 읽어보기
이 책을 집필하는 데 사용된 실제 에이전트 파일을 살펴보자. 먼저 chapter-writer 에이전트다.
파일 위치: .claude/agents/chapter-writer.md
---
name: chapter-writer
description: "책의 챕터를 집필하는 에이전트. '챕터 작성', '집필', 'write chapter' 요청 시 트리거."
model: opus
---
# Chapter Writer — 챕터 집필 전문가
당신은 기술서적의 챕터를 집필하는 전문 작가입니다.
## 핵심 역할
1. **챕터 집필**: book-planner의 명세에 따라 본문 작성
2. **예제 코드 작성**: 따라할 수 있는 실습 코드 포함
3. **설명 문체**: 초보자도 이해할 수 있는 명확한 설명
4. **구조화**: 일관된 챕터 구조 유지
## 작업 원칙
- Always respond in Korean
- 예제 코드는 반드시 **실행 가능**해야 함
- "왜 이렇게 하는가"를 항상 설명
- 전문 용어 첫 등장 시 정의 포함
- 한 챕터에 하나의 핵심 주제만
- 마크다운으로 작성, 파일명: `chapters/ch{NN}-{slug}.md`
## 협업
- `book-planner`의 목차/명세를 입력으로 받음
- `book-editor`가 작성된 챕터를 리뷰
- 리뷰 피드백에 따라 수정 반영이 파일의 구조를 분석해보자:
frontmatter:
name으로 식별하고,description에 한국어/영어 트리거 키워드를 모두 포함했다.model: opus로 설정한 이유는 챕터 집필이 긴 맥락을 이해하고 창작하는 복잡한 작업이기 때문이다.제목과 역할 선언: “당신은 ~전문가입니다”로 시작하여 페르소나를 명확히 부여한다. Claude Code는 이 문장을 읽고 해당 역할에 맞는 어조와 관점을 유지한다.
핵심 역할: 이 에이전트가 무엇을 하는지 4가지로 정의한다. 번호를 매겨 우선순위를 암시한다.
작업 원칙: 모든 출력에 적용되는 규칙이다. “한 챕터에 하나의 핵심 주제만”처럼 구체적이고 검증 가능한 원칙이 좋다.
협업 섹션: 다른 에이전트와의 인터페이스를 정의한다. 입력은 누구에게서 받고, 출력은 누구에게 전달하는지 명시한다.
실습: 실제 스킬 파일 읽어보기
이제 이 에이전트들을 조율하는 book-writer 스킬을 살펴보자.
파일 위치: .claude/skills/book-writer/SKILL.md
---
name: book-writer
description: "책 집필 오케스트레이터. 에이전트 팀을 조율하여 책 한 권을 완성합니다.
'책 집필', '책 쓰기', 'write book' 요청 시 트리거."
---
# Book Writer — 집필 오케스트레이터
에이전트 팀(book-planner, chapter-writer, book-editor, infographic-creator,
book-publisher)을 조율하여 책 한 권을 완성하는 오케스트레이터 스킬.
## 에이전트 팀 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `book-planner` | 목차/구조 설계 | sonnet | 1 |
| `chapter-writer` | 챕터 집필 | opus | 2, 3 |
| `book-editor` | 원고 리뷰/편집 | sonnet | 3 |
| `infographic-creator` | SVG 인포그래픽 | sonnet | 4 |
| `book-publisher` | PDF + 웹 뷰어 | sonnet | 5 |
## 워크플로우
### Phase 1: 목차 설계
- **에이전트**: `book-planner`
- **입력**: 책 주제, 대상 독자, 요구사항
- **출력**: `book/outline.md`
- **검증**: 사용자가 목차를 확인하고 승인
### Phase 2: 챕터 집필
- **에이전트**: `chapter-writer`
- **입력**: `book/outline.md`의 챕터별 명세
- **출력**: `book/chapters/ch{NN}-{slug}.md`
- **검증**: 각 챕터 파일이 챕터 구조를 따르는지 확인
### Phase 3: 리뷰 루프
- **에이전트**: `book-editor` → `chapter-writer`
- **프로세스**: 리뷰 → 수정 → 재리뷰 → 승인
### Phase 4: 인포그래픽 생성
- **에이전트**: `infographic-creator`
- **출력**: `book/assets/infographic-ch{NN}-{slug}.svg`
### Phase 5: 출판
- **에이전트**: `book-publisher`
- **출력**: PDF + 웹 뷰어에이전트 파일과 비교하면 구조적 차이가 뚜렷하다:
frontmatter에
model이 없다: 스킬 자체는 특정 모델에 종속되지 않는다. 모델은 각 에이전트가 결정한다.에이전트 팀 구성 테이블: 어떤 에이전트를 어떤 Phase에서 사용하는지 한눈에 보여준다. 이것이 에이전트 파일에는 없는, 스킬만의 고유한 요소다.
Phase별 워크플로우: 각 단계의 입력, 출력, 검증 기준을 명시한다. 에이전트 파일이 “내가 누구인지”를 정의한다면, 스킬 파일은 “일의 흐름”을 정의한다.
산출물 경로 규칙:
book/chapters/ch{NN}-{slug}.md처럼 파일이 저장될 위치와 네이밍 규칙을 구체적으로 지정한다.
심화: 에이전트와 스킬, 왜 이렇게 나눴을까
“하나의 파일에 역할과 절차를 모두 쓰면 안 되나?”라고 생각할 수 있다. 물론 가능하다. 하지만 분리하면 얻는 이점이 있다.
1. 재사용성
chapter-writer 에이전트는 book-writer 스킬에서만 쓰이는 것이 아니다. 나중에 “블로그 글 작성” 스킬을 만들 때도 같은 에이전트를 호출할 수 있다. 역할 정의는 그대로 두고, 절차만 새로 만들면 된다.
2. 독립적 변경
편집자의 리뷰 기준을 바꾸고 싶다면 book-editor.md만 수정하면 된다. 워크플로우의 Phase 순서를 바꾸고 싶다면 SKILL.md만 수정하면 된다. 서로 영향을 주지 않는다.
3. 관심사 분리
에이전트 파일을 작성할 때는 “이 전문가가 어떤 사람인지”에만 집중하면 된다. 스킬 파일을 작성할 때는 “일의 순서가 어떻게 되는지”에만 집중하면 된다. 두 가지를 동시에 생각하지 않아도 되므로 설계가 명확해진다.
이 분리 원칙은 소프트웨어 설계의 기본 원칙과 같다. 인터페이스(에이전트)와 구현(스킬)을 분리하면 시스템이 유연해진다.
심화: model 선택의 기준
frontmatter의 model 필드는 비용과 품질 사이의 트레이드오프다. 이 책의 에이전트들은 다음과 같이 모델을 배정받았다:
| 에이전트 | 모델 | 선택 이유 |
|---|---|---|
book-planner |
sonnet | 목차 구조화는 분석적 작업. 빠른 모델로 충분 |
chapter-writer |
opus | 긴 본문 작성은 깊은 이해와 창작력 필요 |
book-editor |
sonnet | 체크리스트 기반 검증은 빠른 모델이 효율적 |
infographic-creator |
sonnet | SVG 코드 생성은 패턴 기반 작업 |
book-publisher |
sonnet | 변환/조판은 절차적 작업 |
일반적인 기준은 이렇다: - opus: 복잡한 추론, 긴 텍스트 생성, 미묘한 판단이 필요한 작업 - sonnet: 구조화된 작업, 분석, 검증, 코드 생성 등 패턴이 명확한 작업
비용이 제한적이라면, 모든 에이전트를 sonnet으로 시작하고 품질이 부족한 에이전트만 opus로 올리는 점진적 접근이 실용적이다.
정리
- Claude Code의 확장은
.claude/디렉토리의 마크다운 파일로 이루어진다. - Agent는 “누가 하는가”를 정의한다. 전문가 페르소나, 행동 원칙, 출력 형식을 담은 파일이며
.claude/agents/*.md에 위치한다. - Skill은 “어떻게 하는가”를 정의한다. 워크플로우, 도구 사용법, 산출물 규칙을 담은 파일이며
.claude/skills/*/SKILL.md에 위치한다. - frontmatter의
name,description,model세 필드가 에이전트/스킬의 식별, 트리거, 모델 선택을 결정한다. - 둘을 분리하면 재사용성, 독립적 변경, 관심사 분리라는 설계 이점을 얻는다.
다음 챕터 미리보기
- Chapter 2에서는 이 Agent와 Skill이 팀으로 묶일 때 어떤 일이 벌어지는지 다룬다. 단일 에이전트의 한계를 넘어, 여러 에이전트가 협업하는 하네스(harness)의 개념과, 이를 자동 생성하는 메타 스킬을 소개한다.
Chapter 2: 하네스와 메타 스킬
이 챕터에서 배울 것
- 단일 에이전트의 세 가지 한계: 컨텍스트 윈도우, 역할 충돌, 병렬 처리 불가
- 하네스(harness)가 무엇이고, 메타 스킬이 어떻게 하네스를 자동 생성하는지
- 메타 스킬의 6단계 워크플로우: 도메인 분석부터 검증까지
- 하네스의 3요소: 에이전트 정의, 스킬 정의, 통합 오케스트레이터
- 에이전트를 분리하는 4가지 기준: 전문성, 병렬성, 컨텍스트 부담, 재사용성
- 실전 예제: “기술 블로그 자동화” 하네스를 메타 스킬로 생성하는 전체 과정
- book-writer 하네스의 실제 구조와 데이터 흐름
본문
단일 에이전트의 한계
Chapter 1에서 에이전트와 스킬의 개념을 배웠다. 에이전트 하나와 스킬 하나만으로도 많은 일을 할 수 있다. 하지만 작업이 복잡해지면 벽에 부딪힌다.
책 한 권을 쓰는 상황을 생각해보자. 한 명의 에이전트에게 다음을 모두 맡긴다고 가정한다:
- 목차를 설계한다
- 챕터를 집필한다
- 작성한 내용을 스스로 리뷰한다
- 인포그래픽을 만든다
- PDF로 조판한다
이 접근에는 세 가지 근본적인 문제가 있다.
첫째, 컨텍스트 윈도우(context window) 한계. 컨텍스트 윈도우란 AI가 한 번에 읽고 기억할 수 있는 텍스트의 최대 크기다. 목차 설계 지침, 집필 원칙, 리뷰 체크리스트, SVG 생성 규칙, PDF 조판 설정을 모두 하나의 컨텍스트에 넣으면, 정작 중요한 본문 내용이 들어갈 자리가 줄어든다. 마치 책상 위에 다섯 과목의 교과서를 동시에 펼쳐놓고 공부하는 것과 같다.
둘째, 역할 충돌. 작가는 “표현을 풍부하게” 쓰려 하고, 편집자는 “불필요한 수식어를 삭제해라”고 한다. 한 에이전트에게 두 역할을 동시에 부여하면, 어떤 원칙을 따라야 할지 모호해진다. 글을 쓰면서 동시에 자기 글을 냉정하게 평가하기 어려운 것은 사람도 마찬가지다.
셋째, 병렬 처리 불가. 챕터 12개의 인포그래픽을 만들 때, 단일 에이전트는 하나씩 순서대로 처리해야 한다. 각 인포그래픽이 서로 독립적인데도 동시에 작업할 수 없다.
이 세 가지 문제를 한 줄로 요약하면 이렇다: 복잡한 작업은 한 명이 아니라 팀이 필요하다.
하네스란 무엇인가
하네스(harness)는 에이전트 팀과 오케스트레이터 스킬을 자동 생성하는 메타 스킬(meta-skill)이다. 메타 스킬이란 “스킬을 만드는 스킬”이라는 뜻이다.
사용자 입장에서 하네스와의 상호작용은 놀랍도록 단순하다:
사용자: "책 집필을 자동화하고 싶어. 하네스 구성해줘"
하네스: (도메인 분석 → 에이전트 설계 → 스킬 생성 → 오케스트레이터 조립 → 검증)
결과: .claude/ 안에 에이전트 팀 + 오케스트레이터 완성
이 한 번의 요청이 핵심이다. 사용자는 에이전트 정의 파일을 직접 작성하지 않는다. 스킬 파일을 하나하나 만들지 않는다. 오케스트레이터의 Phase를 설계하지 않는다. 메타 스킬이 이 모든 것을 자동으로 생성한다.
왜 “하네스”라는 이름일까? 하네스는 원래 여러 줄의 케이블이나 끈을 하나로 묶어 관리하는 장치를 뜻한다. 자동차의 와이어 하네스가 수십 개의 전선을 체계적으로 정리하듯, 이 하네스는 여러 에이전트와 스킬을 하나의 체계로 묶어준다.
메타 스킬이 중요한 이유는 진입 장벽을 낮추기 때문이다. 에이전트 정의, 스킬 정의, 오케스트레이터를 직접 작성하려면 이 책의 Part 2 전체를 이해해야 한다. 하지만 메타 스킬을 사용하면 “하네스 구성해줘”라는 한마디로 시작할 수 있다. 물론 자동 생성된 결과를 검토하고 미세 조정하려면 수동 구성의 원리를 알아야 한다 — 이것이 이 책이 존재하는 이유다.
메타 스킬의 6단계 워크플로우
메타 스킬(/harness)이 하네스를 생성할 때 거치는 6단계를 상세히 살펴보자.
메타 스킬의 위치
harness 메타 스킬은 다음 경로에 위치한다.
~/.claude/skills/harness/
├── SKILL.md # 메타 스킬 본체
└── references/
├── agent-design-patterns.md # 아키텍처 패턴 레퍼런스
└── team-examples.md # 팀 구성 예시
~/.claude/ 경로에 있다는 점에 주목하자. 프로젝트 레벨(.claude/)이 아니라 사용자의 홈 디렉토리(~/.claude/)에 위치한다. 이는 harness 메타 스킬이 특정 프로젝트에 종속되지 않는 범용 도구임을 의미한다. 어떤 프로젝트에서든 “하네스 구성해줘”라고 요청하면 동작한다.
메타 스킬의 frontmatter는 이렇게 생겼다.
---
name: harness
description: "하네스를 구성합니다. 전문 에이전트를 정의하며, 해당 에이전트가
사용할 스킬을 생성하는 메타 스킬. (1) '하네스 구성해줘',
'하네스 구축해줘' 요청 시, (2) '하네스 설계', '하네스 엔지니어링'
요청 시, (3) 새로운 도메인/프로젝트에 대한 하네스 기반 자동화
체계를 구축할 때, (4) 하네스 구성을 재구성하거나 확장할 때 사용."
---references 디렉토리의 두 파일은 메타 스킬이 팀 구조를 결정할 때 참조하는 지식이다. agent-design-patterns.md에는 4가지 아키텍처 패턴(Chapter 3에서 상세히 다룬다)이, team-examples.md에는 다양한 도메인의 팀 구성 예시가 담겨 있다.
Phase 1: 도메인 분석
사용자 요청 → [도메인/프로젝트 파악] → [핵심 작업 유형 식별] → [기존 에이전트/스킬 확인]
사용자가 “기술 블로그 자동화 하네스를 구성해줘”라고 요청하면, Phase 1에서 세 가지를 수행한다.
첫째, 도메인을 파악한다. “기술 블로그 자동화”라는 요청에서 도메인은 “기술 블로그”이고, 자동화 대상은 블로그 글의 기획부터 발행까지의 과정이다.
둘째, 핵심 작업 유형을 식별한다. 기술 블로그를 만들려면 어떤 종류의 작업이 필요한가? 주제 리서치, 아웃라인 작성, 본문 집필, 코드 예제 작성, 기술 검증, 편집, 발행 등이 있다. 이 단계에서 작업 유형을 “생성”, “검증”, “편집”, “분석” 같은 카테고리로 분류한다.
셋째, 기존 에이전트/스킬을 확인한다. 프로젝트에 이미 .claude/agents/나 .claude/skills/에 파일이 있는지 확인한다. 이미 존재하는 에이전트와 이름이 충돌하거나, 역할이 중복되는 것을 방지하기 위해서다.
왜 Phase 1이 중요한가? 잘못된 도메인 분석 위에 세운 팀 구조는 전부 다시 만들어야 한다. 도메인 분석이 정확해야 이후 Phase의 결과도 정확하다.
Phase 2: 팀 아키텍처 설계
[작업을 전문 영역으로 분해] → [아키텍처 패턴 선택] → [에이전트 분리 기준 적용]
Phase 1에서 식별한 작업 유형을 바탕으로 에이전트 팀의 구조를 결정한다. 메타 스킬은 references/agent-design-patterns.md를 참조하여 4가지 아키텍처 패턴 중 적합한 것을 선택한다.
- 파이프라인: 순차적으로 의존하는 작업 (A의 출력이 B의 입력)
- 팬아웃/팬인: 독립적인 작업을 병렬 처리한 후 결과 통합
- 전문가풀: 상황에 따라 적절한 전문가를 선택 호출
- 생성-검증: 생성 후 품질 검수, 문제 시 재생성
그리고 에이전트를 분리할지 통합할지를 4가지 기준으로 판단한다(이 기준은 이 챕터의 뒷부분에서 상세히 다룬다). 메타 스킬이 자동으로 판단하지만, 결과를 사용자에게 보여주고 확인을 받는다. 자동화가 판단을 대신해도 최종 승인은 사람의 몫이다.
Phase 3: 에이전트 정의 생성
[에이전트 파일 생성] → 프로젝트/.claude/agents/{name}.md
Phase 2에서 설계한 팀 구조를 기반으로, 각 에이전트의 정의 파일을 .claude/agents/ 디렉토리에 생성한다. 에이전트 파일은 Chapter 1에서 배운 구조를 따른다: frontmatter + 역할 선언 + 핵심 역할 + 작업 원칙 + 출력 형식 + 협업.
메타 스킬이 에이전트를 생성할 때 적용하는 원칙이 세 가지 있다.
첫째, 프로젝트 공유 설정을 반영한다. 기본 지침, 코딩 원칙 등이 있으면 에이전트의 작업 원칙에 이를 반영한다.
둘째, 출력 형식을 구체적으로 명시한다. “적절히 작성하라”가 아니라, 마크다운 예시를 포함하여 산출물의 형태를 명확히 보여준다.
셋째, 협업 섹션에서 다른 에이전트와의 관계를 정의한다. 누구에게서 입력을 받고, 누구에게 출력을 전달하는지를 명시한다. 이 정보가 없으면 에이전트는 팀 안에서 자기 위치를 모른다.
Phase 4: 스킬 생성
[스킬 파일 생성] → 프로젝트/.claude/skills/{name}/SKILL.md
각 에이전트가 사용할 스킬을 .claude/skills/ 디렉토리에 생성한다. 모든 에이전트가 반드시 별도 스킬 파일을 가져야 하는 것은 아니다. 에이전트 정의 안에 작업 절차가 충분히 담길 수 있으면 별도 스킬 없이도 동작한다. 작업 절차가 길거나, 참고 자료(references/)를 함께 관리해야 할 때 스킬로 분리한다.
스킬 생성의 핵심 원칙 네 가지:
| 원칙 | 설명 |
|---|---|
| 에이전트 1:N 스킬 | 하나의 에이전트가 여러 스킬을 가질 수 있다 |
| 공유 스킬 가능 | 여러 에이전트가 같은 스킬을 참조할 수 있다 |
| 역할 분리 | 스킬은 “어떻게 하는가”, 에이전트는 “누가 하는가” |
| 레퍼런스 분리 | 참고 자료가 크면 references/ 하위에 별도 파일로 관리 |
Phase 5: 통합 스킬 (오케스트레이터) 생성
[오케스트레이터 스킬 생성] → 프로젝트/.claude/skills/{팀명}/SKILL.md
팀 전체를 조율하는 상위 스킬을 생성한다. 오케스트레이터가 정의하는 것은 네 가지다.
- 에이전트 구성 테이블: 시나리오별로 어떤 에이전트가 참여하는지
- Phase별 워크플로우: 각 Phase의 입력, 출력, 실행 방식 (병렬/순차)
- 에이전트 간 데이터 흐름: 산출물이 파일로 어디에 저장되고, 다음 에이전트가 어디서 읽는지
- Phase별 검증 기준: 각 Phase가 끝날 때 충족해야 할 조건
오케스트레이터는 하네스의 “설계도”다. 이 파일 하나를 읽으면 팀의 전체 구조와 워크플로우를 파악할 수 있어야 한다.
Phase 6: 검증
Phase 1~5를 거쳐 파일들이 생성된 후, 마지막으로 6가지 항목을 검증한다.
검증 체크리스트:
- [ ] 모든 에이전트 파일이 올바른 위치에 있는가
- [ ] frontmatter(name, description, model)가 유효한가
- [ ] 에이전트의 description에 트리거 키워드가 포함되어 있는가
- [ ] 에이전트 간 참조가 일관성 있는가
- [ ] 오케스트레이터 스킬에서 모든 에이전트가 참조되는가
- [ ] .claude/commands/ 에 아무것도 생성되지 않았는가
파일 위치 검증: 위치가 틀리면 Claude Code가 인식하지 못한다. frontmatter 검증: name이 빠지면 에이전트가 로드되지 않는다. 트리거 키워드 검증: description에 트리거 키워드가 없으면 사용자가 에이전트를 호출할 방법이 없다. 참조 일관성 검증: 에이전트 A의 협업 섹션에서 “에이전트 B에게 전달”이라고 했는데, 에이전트 B가 존재하지 않으면 워크플로우가 끊긴다. 오케스트레이터 완전성 검증: 참조하지 않는 에이전트가 있으면 팀에서 호출되지 않는 “고아”가 된다. commands 미생성 검증: 메타 스킬이 “도움이 될 것 같아서” 커맨드까지 생성하는 과잉 행동을 방지한다.
결과적으로 하네스가 생성하는 산출물은 다음 세 가지다:
하네스의 산출물
├── 에이전트 정의 파일들 (.claude/agents/*.md)
├── 스킬 정의 파일들 (.claude/skills/*/SKILL.md)
└── 통합 오케스트레이터 (.claude/skills/{팀명}/SKILL.md)
인포그래픽: 메타 스킬이 하네스를 만드는 과정
하네스의 3요소
하네스를 구성하는 세 가지 요소를 정리하면 다음과 같다.
| 요소 | 역할 | 파일 위치 |
|---|---|---|
| 에이전트 정의 | 각 전문가의 페르소나와 원칙 | .claude/agents/{name}.md |
| 스킬 정의 | 각 에이전트의 작업 절차 | .claude/skills/{name}/SKILL.md |
| 통합 오케스트레이터 | 팀 전체의 실행 순서와 데이터 흐름 | .claude/skills/{팀명}/SKILL.md |
이 세 요소는 각각 Chapter 1에서 배운 Agent와 Skill의 확장이다. 차이점은 여러 에이전트가 하나의 오케스트레이터 아래 조율된다는 것이다.
각 요소를 하나씩 살펴보자.
요소 1: 에이전트 정의
에이전트 정의는 Chapter 1에서 본 것과 동일하다. 다만 팀으로 묶일 때는 협업 섹션이 중요해진다. 어떤 에이전트에게서 입력을 받고, 어떤 에이전트에게 출력을 전달하는지 명시해야 한다.
## 협업
- `book-planner`의 목차/명세를 입력으로 받음
- `book-editor`가 작성된 챕터를 리뷰
- 리뷰 피드백에 따라 수정 반영이 협업 정의가 없으면 에이전트는 자기 역할만 알고, 팀 내에서 자신의 위치를 모른다.
요소 2: 스킬 정의
개별 스킬은 에이전트가 참조하는 작업 절차다. 오케스트레이터와 구분하기 위해 개별 스킬이라 부르자. 예를 들어 book-editor 에이전트가 리뷰할 때 참조하는 체크리스트, infographic-creator가 SVG를 생성할 때 따르는 디자인 가이드 등이 여기에 해당한다.
모든 에이전트가 반드시 별도의 스킬 파일을 가져야 하는 것은 아니다. 에이전트 정의 파일 안에 작업 절차가 충분히 담길 수 있으면 별도 스킬 없이도 동작한다. 작업 절차가 길거나, 참고 자료(references/)를 함께 관리해야 할 때 스킬로 분리한다.
요소 3: 통합 오케스트레이터
오케스트레이터(orchestrator)는 팀 전체를 지휘하는 상위 스킬이다. 오케스트라의 지휘자가 각 악기 파트에 언제 연주하라고 신호를 보내듯, 오케스트레이터는 각 에이전트에게 언제, 어떤 순서로 작업하라고 지시한다.
오케스트레이터가 정의하는 것은 세 가지다:
- 에이전트 구성 테이블: 누가 팀에 있는지, 각자 어떤 Phase에서 활동하는지
- Phase별 워크플로우: 각 Phase의 입력, 출력, 검증 기준
- 에이전트 간 데이터 흐름: 산출물이 파일로 어디에 저장되고, 다음 에이전트가 어디서 읽는지
오케스트레이터 자체도 .claude/skills/ 아래의 SKILL.md 파일이다. 다른 스킬과 형식이 같지만, 여러 에이전트를 호출하는 워크플로우를 담고 있다는 점이 다르다.
인포그래픽: 하네스 구성 요소 전체 맵
에이전트 분리 기준 4가지
하네스를 설계할 때 가장 어려운 판단은 “이 작업을 별도 에이전트로 분리할 것인가, 기존 에이전트에 맡길 것인가”다. 메타 스킬이 Phase 2에서 이 판단을 자동으로 내리지만, 사용자가 결과를 검토하려면 기준을 알아야 한다. 다음 4가지 기준으로 판단한다.
기준 1: 전문성
영역이 다르면 분리한다.
목차 설계와 본문 집필은 서로 다른 전문성을 요구한다. 목차 설계는 전체 구조를 조감하는 분석적 사고가 필요하고, 본문 집필은 독자를 이끌어가는 서술 능력이 필요하다. 하나의 에이전트에게 “분석가이면서 작가”라는 이중 역할을 부여하면, 어느 쪽에도 깊이 집중하지 못한다.
반대로, 영역이 겹치면 통합을 고려한다. “문법 검사”와 “맞춤법 검사”는 전문성이 거의 같으므로 하나의 에이전트로 충분하다.
기준 2: 병렬성
독립적으로 실행 가능하면 분리한다.
12개 챕터의 인포그래픽을 만드는 작업은 챕터 간에 의존성이 없다. 챕터 3의 인포그래픽을 만들기 위해 챕터 1의 인포그래픽이 완성되어야 할 이유가 없다. 이런 경우 별도 에이전트로 분리하면 병렬 처리가 가능해진다.
반대로, 반드시 순서대로 처리해야 하는 작업은 분리해도 병렬 이점이 없으므로 통합을 고려한다.
기준 3: 컨텍스트 부담
컨텍스트 윈도우를 크게 차지하면 분리한다.
PDF 조판을 위해서는 CSS 스타일시트, 페이지 레이아웃 설정, 폰트 임베딩 규칙 등 방대한 참고 자료가 필요하다. 이 모든 것을 챕터 집필 에이전트의 컨텍스트에 함께 넣으면, 정작 집필에 쓸 공간이 줄어든다. 별도의 book-publisher 에이전트로 분리하면 각자 자기 작업에 필요한 컨텍스트만 가지면 된다.
기준 4: 재사용성
다른 팀에서도 활용할 수 있으면 분리한다.
chapter-writer 에이전트는 이 책의 집필뿐 아니라, 기술 블로그 작성, 교육 자료 제작 등 다른 하네스에서도 재사용할 수 있다. 범용적인 역할은 독립 에이전트로 분리해두면 미래의 다른 프로젝트에서 그대로 가져다 쓸 수 있다.
이 4가지 기준을 표로 정리하면 다음과 같다:
| 기준 | 분리 | 통합 |
|---|---|---|
| 전문성 | 영역이 다르면 분리 | 영역이 겹치면 통합 |
| 병렬성 | 독립 실행 가능하면 분리 | 순차 종속이면 통합 고려 |
| 컨텍스트 부담 | 참고 자료가 많으면 분리 | 가볍고 빠르면 통합 |
| 재사용성 | 다른 팀에서도 쓰면 분리 | 이 팀에서만 쓰면 통합 고려 |
4가지 기준 모두 충족할 필요는 없다. 하나라도 강하게 해당되면 분리를 고려하되, 에이전트 수가 너무 많아지면 오케스트레이터의 복잡도가 올라간다는 트레이드오프도 기억해야 한다.
실전: “기술 블로그 자동화” 하네스 생성
이제 harness 메타 스킬을 사용하여 실제로 하네스를 생성하는 전체 과정을 따라가 보자. 도메인은 “기술 블로그 자동화”다. 6단계 워크플로우가 실전에서 어떻게 동작하는지, Phase별로 살펴본다.
시작: 사용자 요청
사용자: 기술 블로그 자동화 하네스를 구성해줘.
주제 선정부터 블로그 글 발행까지 자동화하고 싶어.
코드 예제가 포함된 기술 글을 작성하는 거야.
이 한 마디로 메타 스킬이 트리거된다. “하네스 구성해줘”가 description의 트리거 키워드에 매칭되기 때문이다.
Phase 1 실행: 도메인 분석
메타 스킬이 요청을 분석한 결과:
도메인 분석 결과:
- 도메인: 기술 블로그
- 자동화 범위: 주제 선정 → 리서치 → 아웃라인 → 집필 → 코드 예제 → 기술 검증 → 편집 → 발행
- 핵심 작업 유형:
- 분석: 주제 리서치, 기술 트렌드 파악
- 설계: 아웃라인 구성, 글 구조 설계
- 생성: 본문 집필, 코드 예제 작성
- 검증: 기술 정확성 검증, 코드 실행 검증
- 편집: 가독성 개선, 문법 검수
- 기존 에이전트/스킬: 없음 (신규 프로젝트)
기존 에이전트가 없으므로 충돌 걱정이 없다. 기존 에이전트가 있었다면 여기서 충돌 가능성을 보고하고 대안을 제시했을 것이다.
Phase 2 실행: 팀 아키텍처 설계
작업 유형을 전문 영역으로 분해하고, 아키텍처 패턴을 선택한다.
팀 아키텍처 설계:
아키텍처 패턴: 파이프라인 + 생성-검증
- 파이프라인: 리서치 → 아웃라인 → 집필 → 편집 → 발행 (순차 의존)
- 생성-검증: 집필 → 기술 검증 → (문제시) 재집필 (품질 보장)
에이전트 분리 결정:
| 에이전트 후보 | 분리 근거 |
|-------------|----------|
| topic-researcher | 전문성: 리서치 ≠ 집필 |
| blog-writer | 전문성: 글쓰기에 집중 |
| code-crafter | 전문성: 코드 작성 ≠ 글쓰기, 컨텍스트: 언어별 컨벤션 |
| tech-reviewer | 역할 충돌 방지: 작성자 ≠ 검증자 |
| blog-editor | 전문성: 편집 ≠ 집필, 역할 충돌 방지 |
여기서 메타 스킬이 내린 핵심 판단 두 가지를 살펴보자.
첫째, blog-writer와 code-crafter를 분리했다. 하나의 에이전트가 글도 쓰고 코드도 작성할 수 있지만, 분리한 이유는 컨텍스트 부담이다. 기술 글의 코드 예제는 실행 가능해야 하고, 해당 언어의 관용적 스타일을 따라야 한다. 코드 컨벤션과 실행 환경 설정을 글쓰기 에이전트의 컨텍스트에 함께 넣으면 컨텍스트 오염 문제가 발생할 수 있다.
둘째, tech-reviewer를 blog-writer와 분리했다. 생성-검증 패턴의 핵심 원칙이다. 글을 쓴 에이전트가 자기 글의 기술적 정확성을 객관적으로 평가하기 어렵다. 검증자는 “이 설명이 기술적으로 맞는가?”만 판단하면 되므로, 역할을 분리하는 것이 품질에 유리하다.
메타 스킬은 이 설계 결과를 사용자에게 보여주고 확인을 받은 후 Phase 3으로 넘어간다.
Phase 3 실행: 에이전트 정의 생성
확정된 팀 구조를 기반으로 5개의 에이전트 파일을 생성한다.
.claude/agents/topic-researcher.md:
---
name: topic-researcher
description: "기술 블로그 주제 리서치 전문가. 트렌드 분석, 주제 선정,
참고 자료 수집을 담당합니다. '주제 리서치', '토픽 분석' 요청 시 트리거."
model: sonnet
---
# 주제 리서처 -- 기술 트렌드를 분석하고 블로그 주제를 제안합니다
당신은 기술 블로그의 주제 리서치를 담당하는 전문가입니다.
항상 한국어로 응답합니다.
## 핵심 역할
1. 기술 트렌드와 커뮤니티 관심사를 분석한다
2. 블로그 주제를 3~5개 제안하고 각각의 근거를 제시한다
3. 선정된 주제에 대한 참고 자료를 수집한다
4. 글의 아웃라인 초안을 작성한다
## 작업 원칙
- 제안하는 주제에 반드시 "왜 지금 이 주제인가"의 근거를 포함한다
- 참고 자료는 출처를 명시한다
- 독자 수준(초급/중급/고급)을 고려한 난이도 표시를 한다
## 출력 형식
리서치 결과를 `blog-output/research.md`에 저장한다.
## 협업
- **출력**: blog-writer에게 리서치 결과와 아웃라인 전달.claude/agents/blog-writer.md:
---
name: blog-writer
description: "기술 블로그 본문 집필 전문가. 리서치 결과를 바탕으로
독자 친화적인 기술 글을 작성합니다. '블로그 집필', '글쓰기' 요청 시 트리거."
model: opus
---
# 블로그 라이터 -- 독자 친화적인 기술 글을 작성합니다
당신은 기술 블로그의 본문을 집필하는 전문가입니다.
항상 한국어로 응답합니다.
## 핵심 역할
1. 리서치 결과와 아웃라인을 기반으로 본문을 작성한다
2. 기술 개념을 비유와 단계적 설명으로 풀어쓴다
3. 코드가 삽입될 위치를 표시하고 code-crafter에게 전달할 명세를 작성한다
## 작업 원칙
- "왜 이렇게 하는가"를 항상 설명한다
- 한 섹션에 하나의 개념만 다룬다
- 코드 예제가 필요한 곳에 `<!-- CODE: {설명} -->` 플레이스홀더를 삽입한다
## 출력 형식
블로그 글을 `blog-output/draft.md`에 저장한다.
## 협업
- **입력**: topic-researcher의 `blog-output/research.md`
- **출력**: code-crafter에게 코드 명세 전달, tech-reviewer가 기술 검증.claude/agents/code-crafter.md:
---
name: code-crafter
description: "기술 블로그 코드 예제 전문가. 실행 가능한 코드 예제와
테스트를 작성합니다. '코드 예제', '코드 작성' 요청 시 트리거."
model: opus
---
# 코드 크래프터 -- 실행 가능한 코드 예제를 작성합니다
당신은 기술 블로그에 포함될 코드 예제를 작성하는 전문가입니다.
항상 한국어로 응답합니다.
## 핵심 역할
1. blog-writer가 표시한 코드 플레이스홀더에 맞는 코드를 작성한다
2. 모든 코드는 독자가 복사하여 바로 실행할 수 있어야 한다
3. 필요시 간단한 테스트 코드를 포함한다
## 작업 원칙
- 코드에 한국어 주석으로 핵심 로직을 설명한다
- 외부 라이브러리 사용 시 설치 명령을 함께 제공한다
- 해당 언어의 관용적 스타일을 따른다
## 출력 형식
코드를 `blog-output/codes/` 디렉토리에 저장한다.
## 협업
- **입력**: blog-writer의 `blog-output/draft.md`에서 코드 플레이스홀더 확인
- **출력**: `blog-output/codes/` 에 코드 파일 저장, blog-writer가 본문에 삽입.claude/agents/tech-reviewer.md:
---
name: tech-reviewer
description: "기술 블로그 기술 검증 전문가. 기술적 정확성과 코드의
실행 가능성을 검증합니다. '기술 검증', '팩트 체크' 요청 시 트리거."
model: sonnet
---
# 기술 리뷰어 -- 기술적 정확성을 검증합니다
당신은 기술 블로그의 기술적 정확성을 검증하는 전문가입니다.
항상 한국어로 응답합니다.
## 핵심 역할
1. 본문의 기술 설명이 정확한지 검증한다
2. 코드 예제가 실행 가능하고 올바른 결과를 내는지 확인한다
3. 기술적 오류를 발견하면 구체적인 피드백을 작성한다
## 검증 기준
### CRITICAL (FAIL)
- 기술적으로 틀린 설명이 있다
- 코드에 구문 오류가 있다
- 보안 취약점이 있는 코드 예제다
### MAJOR (FAIL)
- 설명과 코드가 일치하지 않는다
- 코드의 에러 처리가 누락되어 실행 시 크래시가 예상된다
- 더 이상 사용하지 않는(deprecated) API를 사용한다
### MINOR (PASS -- 기록만)
- 더 효율적인 방법이 있다
- 주석이 부족하다
## 출력 형식
검증 결과를 `blog-output/review.md`에 저장한다.
## 작업 원칙
- 코드를 직접 수정하지 않는다. 피드백만 작성한다
- MINOR 이슈로 FAIL 판정하지 않는다.claude/agents/blog-editor.md:
---
name: blog-editor
description: "기술 블로그 편집 전문가. 가독성, 구조, 문법을 개선합니다.
'블로그 편집', '글 다듬기' 요청 시 트리거."
model: sonnet
---
# 블로그 에디터 -- 가독성과 구조를 개선합니다
당신은 기술 블로그의 편집을 담당하는 전문가입니다.
항상 한국어로 응답합니다.
## 핵심 역할
1. 문장의 가독성과 흐름을 개선한다
2. 전체 글의 구조가 논리적인지 검토한다
3. 맞춤법과 문법을 검수한다
4. 기술 용어의 일관성을 확인한다
## 작업 원칙
- 기술적 정확성은 tech-reviewer의 영역이다. 편집은 가독성에 집중한다
- 원본의 기술적 의미를 변경하지 않는다
## 출력 형식
편집 결과를 `blog-output/edited-draft.md`에 저장한다.
## 협업
- **입력**: tech-reviewer의 검증을 통과한 `blog-output/draft.md`
- **출력**: 최종 편집본 `blog-output/edited-draft.md`5개 에이전트의 모델 선택 근거를 정리하면 다음과 같다.
| 에이전트 | 모델 | 모델 선택 근거 |
|---|---|---|
topic-researcher |
sonnet | 리서치는 정보 수집이므로 sonnet으로 충분 |
blog-writer |
opus | 글쓰기는 창의성과 맥락 이해가 필요하므로 opus |
code-crafter |
opus | 코드 생성은 높은 품질이 필요하므로 opus |
tech-reviewer |
sonnet | 검증은 기준 대조이므로 sonnet으로 충분 |
blog-editor |
sonnet | 편집은 규칙 기반이므로 sonnet으로 충분 |
창의적 생성(집필, 코드)에는 opus, 규칙 기반 작업(리서치, 검증, 편집)에는 sonnet. 이것이 비용 대비 품질의 균형이다.
Phase 4 실행: 스킬 생성
이 예제에서는 개별 에이전트의 작업 절차가 에이전트 정의 안에 충분히 담겼으므로, 별도 스킬 파일 없이 오케스트레이터 스킬만 생성한다. 모든 에이전트가 반드시 별도 스킬을 가질 필요는 없다는 것을 기억하자.
만약 code-crafter가 여러 언어를 다루어 언어별 컨벤션 레퍼런스가 필요하다면, skills/code-crafter/SKILL.md와 skills/code-crafter/references/를 별도로 생성할 수 있다. 이 판단은 도메인의 복잡도에 따라 달라진다.
Phase 5 실행: 오케스트레이터 생성
.claude/skills/tech-blog/SKILL.md:
---
name: tech-blog
description: "기술 블로그 자동화 하네스. 주제 리서치부터 편집까지
자동화합니다. '기술 블로그', 'tech blog harness' 요청 시 트리거."
---
# 기술 블로그 오케스트레이터
주제 리서치부터 편집까지 기술 블로그 작성 전 과정을 자동화하는 하네스입니다.
## 에이전트 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `topic-researcher` | 주제 리서치, 아웃라인 | sonnet | 1 |
| `blog-writer` | 본문 집필 | opus | 2, 3 |
| `code-crafter` | 코드 예제 작성 | opus | 2 |
| `tech-reviewer` | 기술 검증 | sonnet | 3 |
| `blog-editor` | 편집, 교정 | sonnet | 4 |
## 산출물 디렉토리
blog-output/
├── research.md # Phase 1 산출물
├── draft.md # Phase 2 산출물
├── codes/ # Phase 2 산출물 (코드)
│ ├── example-01.py
│ └── example-02.py
├── review.md # Phase 3 산출물
└── edited-draft.md # Phase 4 산출물 (최종)
## 워크플로우
### Phase 1: 주제 리서치
- **에이전트**: `topic-researcher`
- **입력**: 사용자의 주제 요청 또는 "알아서 선정"
- **출력**: `blog-output/research.md` (주제, 근거, 참고 자료, 아웃라인)
- **검증**: 주제와 아웃라인을 사용자에게 보여주고 승인
- **완료 후**: 사용자 확인
### Phase 2: 집필 + 코드 작성
- **에이전트**: `blog-writer` → `code-crafter`
- **처리**:
1. `blog-writer`가 아웃라인 기반으로 본문을 작성한다
(코드 위치에 플레이스홀더 삽입)
2. `code-crafter`가 플레이스홀더에 맞는 코드를 작성한다
3. `blog-writer`가 코드를 본문에 삽입하여 완성한다
- **출력**: `blog-output/draft.md`, `blog-output/codes/`
- **검증**: 모든 플레이스홀더가 코드로 교체되었는지 확인
- **완료 후**: 초안을 사용자에게 보여주고 확인
### Phase 3: 기술 검증 루프 (생성-검증)
- **생성자**: `blog-writer` + `code-crafter`
- **검증자**: `tech-reviewer`
- **최대 반복**: 3회
- **루프 절차**:
1. `tech-reviewer`가 본문과 코드의 기술적 정확성을 검증
2. CRITICAL 또는 MAJOR 이슈가 있으면 FAIL
3. FAIL 시: 피드백을 blog-writer/code-crafter에게 전달하여 수정
4. 수정본을 다시 tech-reviewer가 검증
5. PASS가 나오거나 최대 반복에 도달할 때까지 반복
- **출력**: `blog-output/review.md`
- **루프 종료 조건**: CRITICAL 0개 AND MAJOR 0개
- **최대 반복 도달 시**: 남은 이슈를 사용자에게 에스컬레이션
### Phase 4: 편집
- **에이전트**: `blog-editor`
- **입력**: 기술 검증을 통과한 `blog-output/draft.md`
- **출력**: `blog-output/edited-draft.md`
- **검증**: 편집본을 사용자에게 보여주고 최종 확인
## 중요 규칙
- 각 Phase 완료 후 사용자에게 결과를 보여주고 다음 Phase 진행 여부를 확인한다
- tech-reviewer는 코드를 직접 수정하지 않는다. 피드백만 작성한다
- blog-editor는 기술적 정확성을 판단하지 않는다. 가독성에만 집중한다이 오케스트레이터에서 주목할 설계 판단 세 가지:
첫째, Phase 2에서 blog-writer와 code-crafter가 순차 협업한다. blog-writer가 먼저 플레이스홀더를 포함한 초안을 쓰고, code-crafter가 코드를 채우고, blog-writer가 코드를 본문에 삽입한다. 코드와 글이 분리 생성되기 때문에 각자 전문성에 집중할 수 있다.
둘째, Phase 3의 생성-검증 루프에서 생성자가 2명이다. 기술적 오류가 본문에 있으면 blog-writer가, 코드에 있으면 code-crafter가 수정한다. 검증자가 피드백에서 어느 에이전트에게 수정을 요청할지 명시한다.
셋째, 블로그 발행(publish) 단계는 포함하지 않았다. 사용자의 요청이 “주제 선정부터 블로그 글 발행까지”였지만, 발행은 플랫폼(GitHub Pages, Medium, 개인 블로그 등)에 따라 완전히 달라지므로 범용 에이전트로 만들기 어렵다. 메타 스킬이 이 판단을 내리고 사용자에게 알릴 수 있다.
Phase 6 실행: 검증
생성된 파일들을 검증 체크리스트로 확인한다.
검증 결과:
[PASS] 모든 에이전트 파일이 .claude/agents/ 에 위치함
- topic-researcher.md
- blog-writer.md
- code-crafter.md
- tech-reviewer.md
- blog-editor.md
[PASS] frontmatter 검증
- 모든 파일에 name, description, model 존재
- model 값이 sonnet 또는 opus로 유효
[PASS] 트리거 키워드 검증
- 모든 description에 트리거 키워드 포함
[PASS] 에이전트 간 참조 일관성
- blog-writer → code-crafter: code-crafter 존재 확인
- blog-writer → tech-reviewer: tech-reviewer 존재 확인
- tech-reviewer → blog-writer: blog-writer 존재 확인
[PASS] 오케스트레이터 완전성
- 5개 에이전트 모두 오케스트레이터에서 참조됨
[PASS] commands 미생성
- .claude/commands/ 에 새 파일 없음
6개 항목 모두 PASS. 하네스 생성이 완료되었다.
생성된 디렉토리 구조
프로젝트/
├── .claude/
│ ├── agents/
│ │ ├── topic-researcher.md
│ │ ├── blog-writer.md
│ │ ├── code-crafter.md
│ │ ├── tech-reviewer.md
│ │ └── blog-editor.md
│ └── skills/
│ └── tech-blog/
│ └── SKILL.md # 오케스트레이터
└── blog-output/ # (실행 시 생성될 산출물 디렉토리)
├── research.md
├── draft.md
├── codes/
├── review.md
└── edited-draft.md
생성된 하네스 사용하기
하네스가 생성되었으니, 이제 사용할 차례다. 사용자가 Claude Code에서 다음과 같이 요청한다.
사용자: 기술 블로그 하네스로 "Python의 패턴 매칭(match/case)" 주제로 글을 써줘
“기술 블로그”가 오케스트레이터의 트리거 키워드에 매칭되어 tech-blog 스킬이 활성화된다. 이후 오케스트레이터가 Phase 1부터 순서대로 실행한다.
topic-researcher가 Python 패턴 매칭에 대한 리서치와 아웃라인을 작성한다- 사용자가 아웃라인을 확인하고 승인한다
blog-writer가 본문을 쓰고,code-crafter가 코드 예제를 작성한다- 사용자가 초안을 확인한다
tech-reviewer가 기술 검증을 수행한다- 문제가 있으면 수정-재검증 루프가 돈다
blog-editor가 최종 편집을 한다- 사용자가 편집본을 최종 확인한다
각 Phase에서 사용자 확인을 받는다는 점이 중요하다. 자동화되었다고 해서 사람이 빠지는 것이 아니다. 사람은 “방향이 맞는지” 판단하고, 에이전트는 “실행”을 담당한다.
book-writer 하네스로 이 책이 만들어지는 과정도 본질적으로 동일하다. 다음 절에서 book-writer 하네스의 구조를 살펴보면, 같은 원리가 다른 도메인에 어떻게 적용되는지 확인할 수 있다.
실습: book-writer 하네스의 구조 살펴보기
이 책 자체가 하네스로 집필되고 있다. 이보다 좋은 예제는 없다. book-writer 하네스의 실제 구조를 살펴보자.
디렉토리 구조
프로젝트/
├── .claude/
│ ├── agents/ # 에이전트 정의
│ │ ├── book-planner.md # 목차 설계자
│ │ ├── chapter-writer.md # 챕터 집필자
│ │ ├── book-editor.md # 편집자
│ │ ├── infographic-creator.md # 인포그래픽 제작자
│ │ └── book-publisher.md # 출판 담당자
│ └── skills/
│ └── book-writer/ # 통합 오케스트레이터
│ └── SKILL.md
└── book/ # 산출물 디렉토리
├── outline.md # Phase 1 산출물
├── chapters/ # Phase 2 산출물
│ ├── ch01-agent-and-skill.md
│ ├── ch02-harness-concept.md
│ └── ...
├── assets/ # Phase 4 산출물
│ └── infographic-ch01-*.svg
└── output/ # Phase 5 산출물
├── pdf/
└── web/
이 구조에서 두 가지를 주목하자:
.claude/아래에 에이전트와 스킬이 분리되어 있다. 에이전트 5명은 각각 독립적인 마크다운 파일이고, 오케스트레이터는skills/book-writer/SKILL.md하나다.book/디렉토리가 산출물 저장소다. 에이전트 간 통신은 이 디렉토리의 파일을 통해 이루어진다.book-planner가outline.md를 만들면,chapter-writer가 그 파일을 읽고 챕터를 쓴다. 별도의 메시지 큐나 API가 아니라 파일 시스템이 에이전트 간 통신 채널이다.
에이전트 팀 구성
| 에이전트 | 역할 | 모델 | 활동 Phase |
|---|---|---|---|
book-planner |
목차/구조 설계 | sonnet | 1 |
chapter-writer |
챕터 집필 | opus | 2, 3 |
book-editor |
원고 리뷰/편집 | sonnet | 3 |
infographic-creator |
SVG 인포그래픽 | sonnet | 4 |
book-publisher |
PDF + 웹 뷰어 | sonnet | 5 |
왜 이렇게 분리했을까? 4가지 기준을 적용해보자:
- book-planner vs chapter-writer: 전문성이 다르다. 구조 설계 vs 본문 작성.
- chapter-writer vs book-editor: 역할 충돌 방지. 작가와 편집자는 정반대의 관점을 가져야 한다.
- infographic-creator: 병렬 처리 가능. 12개 챕터의 인포그래픽을 동시에 만들 수 있다.
- book-publisher: 컨텍스트 부담. PDF 조판 규칙은 집필과 무관한 대량의 참고 자료를 필요로 한다.
Phase별 워크플로우
이 오케스트레이터는 5개의 Phase를 순서대로 실행한다. 각 Phase의 실행 방식이 다르다는 점에 주목하자.
Phase 1 – 목차 설계 (순차)
[book-planner] → outline.md → 사용자 승인
book-planner가 목차를 만들고, 사용자가 확인한 후 다음으로 넘어간다. 목차가 확정되지 않으면 이후 모든 작업이 의미 없으므로 순차 실행이 필수다.
Phase 2 – 챕터 집필 (순차)
[chapter-writer] → ch01.md → ch02.md → ... → ch12.md
chapter-writer가 한 챕터씩 순서대로 집필한다. 앞 챕터의 내용을 뒤 챕터에서 참조하므로 순차 실행한다.
Phase 3 – 리뷰 루프 (생성-검증)
[book-editor] → 리뷰 → CRITICAL 이슈 발견?
├─ Yes → [chapter-writer] → 수정 → [book-editor] 재리뷰
└─ No → 승인
이 Phase가 가장 흥미롭다. 두 에이전트가 루프를 돈다. book-editor가 리뷰하고, 심각한 문제가 있으면 chapter-writer가 수정하고, 다시 book-editor가 리뷰한다. CRITICAL 이슈가 0개가 될 때까지 반복한다. 이것이 생성-검증(Producer-Reviewer) 패턴이다.
Phase 4 – 인포그래픽 생성 (병렬)
┌→ [infographic-creator] → ch01 SVG
├→ [infographic-creator] → ch02 SVG
├→ [infographic-creator] → ch03 SVG
└→ ...
각 챕터의 인포그래픽은 독립적이므로 병렬로 생성할 수 있다. 같은 에이전트를 여러 번 호출하되 입력만 다르다.
Phase 5 – 출판 (순차)
[book-publisher] → PDF + 웹 뷰어
모든 챕터와 인포그래픽이 완성된 후, 최종 산출물을 만든다.
에이전트 간 데이터 흐름
에이전트들은 서로 직접 대화하지 않는다. 대신 파일을 통해 간접적으로 통신한다.
book-planner ──(outline.md)──→ chapter-writer
chapter-writer ──(ch01.md)──→ book-editor
book-editor ──(리뷰 결과)──→ chapter-writer
chapter-writer ──(ch01.md, 완성)──→ infographic-creator
infographic-creator ──(SVG 파일)──→ book-publisher
chapter-writer ──(ch01.md, 완성)──→ book-publisher
모든 중간 산출물은 book/ 디렉토리 아래에 정해진 경로와 네이밍 규칙으로 저장된다. 이 규칙이 오케스트레이터 스킬에 명시되어 있으므로, 각 에이전트는 자신의 입력을 어디서 찾고 출력을 어디에 저장할지 알 수 있다.
기술 블로그 하네스와 비교하면, 도메인은 다르지만 구조는 동일하다. 에이전트 정의 + 오케스트레이터 + 파일 기반 통신. 이 패턴이 반복된다는 것이 하네스의 핵심이다.
심화: 하네스 설계의 핵심 원칙
하네스를 설계할 때 기억해야 할 원칙이 있다. 메타 스킬이 자동으로 이 원칙을 따르지만, 생성 결과를 검토하고 수정할 때 이 원칙을 알아야 한다.
1. 에이전트는 작게, 오케스트레이터는 명확하게
에이전트 하나가 너무 많은 역할을 맡으면 단일 에이전트의 한계로 돌아간다. 반대로 에이전트를 지나치게 잘게 쪼개면 오케스트레이터가 복잡해진다. book-writer 하네스의 에이전트 5명은 이 균형점을 찾은 결과다.
2. 파일 기반 통신
에이전트 간 데이터 전달은 파일 시스템을 통해 이루어진다. 오케스트레이터가 “이 파일을 읽고, 결과를 저 파일에 쓰라”고 지시한다. 파일 경로와 네이밍 규칙을 명확히 정의하는 것이 팀 운영의 핵심이다.
3. Phase 완료 후 검증
각 Phase가 끝나면 산출물이 기대 조건을 만족하는지 확인한다. 이 검증 없이 다음 Phase로 넘어가면, 잘못된 중간 결과 위에 작업이 쌓이게 된다. book-writer 하네스에서 “사용자 승인”이 반복적으로 등장하는 이유다.
4. 기존 파일을 절대 덮어쓰지 않는다
메타 스킬이 하네스를 생성할 때, 프로젝트에 이미 에이전트나 스킬이 존재할 수 있다. 이 경우 기존 파일을 덮어쓰지 않고, 이름 충돌은 도메인 접두어로 구분하고, 역할 중복은 기존 에이전트를 재사용한다. 자동화가 기존 작업을 파괴하는 것은 가장 위험한 실수다.
5. 메타 스킬은 뼈대를 세우고, 사용자가 살을 붙인다
메타 스킬이 생성한 파일은 출발점이지, 완성본이 아니다. 생성된 에이전트의 작업 원칙을 도메인에 맞게 수정하거나, 오케스트레이터의 검증 기준을 강화하는 것은 자연스러운 다음 단계다. 예를 들어, code-crafter의 코딩 원칙에 “모든 코드 예제는 Python 3.10+ 문법을 사용한다”를 추가하거나, tech-reviewer의 검증 기준에 “deprecated API 사용은 CRITICAL”로 격상하는 것이 가능하다. 구조를 이해해야 이런 커스터마이징이 가능하다 – 이것이 이 책이 Part 2에서 생성된 하네스의 구조를 상세히 다루는 이유다.
정리
- 단일 에이전트의 한계: 컨텍스트 윈도우 부족, 역할 충돌, 병렬 처리 불가. 복잡한 작업에는 팀이 필요하다.
- 하네스는 메타 스킬이 자동 생성한다: 사용자는 “하네스 구성해줘”라고 요청하면 된다. 에이전트 정의, 스킬, 오케스트레이터가 한 번에 만들어진다.
- 메타 스킬의 6단계 워크플로우: 도메인 분석 → 팀 아키텍처 설계 → 에이전트 생성 → 스킬 생성 → 오케스트레이터 생성 → 검증. 각 단계의 산출물이 다음 단계의 입력이 되는 파이프라인이다.
- 하네스의 3요소: 에이전트 정의(누가), 스킬 정의(어떻게), 통합 오케스트레이터(어떤 순서로).
- 에이전트 분리 기준 4가지: 전문성, 병렬성, 컨텍스트 부담, 재사용성.
- 에이전트 간 통신은 파일 기반: 산출물 파일이 곧 에이전트 간 메시지다.
- 검증 체크리스트 6항목: 파일 위치, frontmatter, 트리거 키워드, 참조 일관성, 오케스트레이터 완전성, commands 미생성.
- 메타 스킬은 뼈대를 세우고, 사용자가 살을 붙인다: 자동 생성 결과는 출발점이며, 도메인에 맞게 커스터마이징하는 것이 자연스러운 다음 단계다.
다음 챕터 미리보기
- Chapter 3에서는 에이전트 팀의 4가지 아키텍처 패턴 – 파이프라인, 팬아웃/팬인, 전문가풀, 생성-검증 – 을 다룬다. 이 챕터에서 살짝 엿본 이 패턴들을 체계적으로 정리하고, 도메인에 맞는 패턴을 선택하는 의사결정 트리를 배운다.
Chapter 3: 4가지 아키텍처 패턴
이 챕터에서 배울 것
- 에이전트 팀을 구성하는 4가지 기본 아키텍처 패턴의 구조와 특성
- 파이프라인: 순차 의존 작업을 처리하는 가장 단순한 패턴
- 팬아웃/팬인: 독립 작업을 병렬로 처리하고 결과를 통합하는 패턴
- 전문가풀: 라우터가 상황에 따라 적절한 전문가를 선택하는 패턴
- 생성-검증: 생성자와 검증자가 루프를 돌며 품질을 보장하는 패턴
- 도메인에 맞는 패턴을 선택하는 의사결정 기준
- 실전에서 여러 패턴을 조합하는 방법
본문
왜 패턴이 필요한가
Chapter 2에서 하네스의 개념을 배웠다. 에이전트 팀을 구성하고, 오케스트레이터가 이들을 조율한다는 것까지는 이해했다. 하지만 한 가지 질문이 남는다: 에이전트들을 어떤 구조로 연결할 것인가?
5명의 에이전트가 있을 때, 모두 순서대로 실행할 수도 있고, 동시에 실행할 수도 있고, 상황에 따라 다른 에이전트를 호출할 수도 있다. 이 “연결 방식”을 매번 처음부터 고민하는 것은 비효율적이다.
소프트웨어 설계에 디자인 패턴이 있듯, 에이전트 팀 설계에도 반복적으로 등장하는 구조가 있다. 이것이 아키텍처 패턴(architecture pattern)이다. 검증된 구조를 이름 붙여 정리해두면, 새로운 도메인을 만날 때 “이건 파이프라인이 맞겠다” 혹은 “여기는 팬아웃/팬인이 필요하다”고 빠르게 판단할 수 있다.
이 챕터에서 다루는 4가지 패턴은 다음과 같다:
| 패턴 | 핵심 구조 | 한 줄 요약 |
|---|---|---|
| 파이프라인 | A → B → C | 앞 단계의 출력이 뒷 단계의 입력 |
| 팬아웃/팬인 | 분배 → 병렬 처리 → 통합 | 독립 작업을 동시에 처리하고 결과를 모은다 |
| 전문가풀 | 라우터 → 전문가 선택 | 상황에 따라 적절한 전문가를 골라 호출한다 |
| 생성-검증 | 생성 → 검증 → (재생성) | 품질 기준을 만족할 때까지 반복한다 |
인포그래픽: 4가지 패턴 흐름도 + 선택 가이드
하나씩 살펴보자.
패턴 1: 파이프라인 (Pipeline)
구조
파이프라인(pipeline)은 가장 직관적인 패턴이다. 에이전트들이 정해진 순서대로 실행되며, 앞 에이전트의 산출물이 다음 에이전트의 입력이 된다.
[에이전트 A] → 산출물 → [에이전트 B] → 산출물 → [에이전트 C]
공장의 조립 라인과 같다. 부품을 만드는 사람, 조립하는 사람, 도장하는 사람이 각자 자기 공정만 담당하고, 완성된 결과를 다음 사람에게 넘긴다.
언제 사용하는가
파이프라인은 다음 조건을 만족할 때 적합하다:
- 작업 간 순차 의존성이 있다. B를 하려면 A의 결과가 반드시 필요하다.
- 각 단계의 전문성이 다르다. 같은 에이전트가 모든 단계를 처리하기 어렵다.
- 실행 순서가 고정되어 있다. 상황에 따라 순서가 바뀌지 않는다.
반대로, 작업들이 서로 독립적이라면 파이프라인은 비효율적이다. 동시에 할 수 있는 일을 굳이 줄 세울 이유가 없기 때문이다.
왜 이 패턴인가
파이프라인의 가장 큰 장점은 단순함이다. 오케스트레이터가 “1번 실행 → 2번 실행 → 3번 실행”이라고만 지시하면 된다. 디버깅도 쉽다. 문제가 생기면 어느 단계에서 잘못되었는지 산출물을 순서대로 추적하면 된다.
단점은 속도다. 모든 에이전트가 순차적으로 실행되므로, 전체 소요 시간은 각 단계의 합이다. 병렬화할 수 있는 부분이 있어도 파이프라인 구조에서는 활용할 수 없다.
실습: SF 소설 집필 파이프라인
SF 소설을 쓰는 하네스를 설계한다고 하자. 세계관 설정, 플롯 구성, 본문 집필의 세 단계가 필요하다. 세계관이 없으면 플롯을 짤 수 없고, 플롯이 없으면 본문을 쓸 수 없다. 전형적인 파이프라인이다.
에이전트 팀:
| 에이전트 | 역할 | 모델 |
|---|---|---|
worldbuilder |
SF 세계관 설계 | opus |
plot-architect |
플롯/장 구성 | opus |
prose-writer |
본문 집필 | opus |
워크플로우:
[worldbuilder] [plot-architect] [prose-writer]
│ │ │
▼ ▼ ▼
세계관 설정서 플롯 구성안 완성된 소설
(설정, 규칙, (장별 시놉시스, (본문 텍스트)
기술 체계) 인물 아크)
Phase 1: [worldbuilder] → world-setting.md
Phase 2: [plot-architect] → world-setting.md 읽기 → plot-outline.md
Phase 3: [prose-writer] → world-setting.md + plot-outline.md 읽기 → chapter-01.md ...
오케스트레이터 스킬의 핵심 부분은 이렇게 작성된다:
## 워크플로우
### Phase 1: 세계관 설계
- **에이전트**: `worldbuilder`
- **입력**: 사용자의 소설 컨셉 (시대, 분위기, 핵심 갈등)
- **출력**: `novel/world-setting.md`
- **검증**: 세계관 설정에 모순이 없는지 사용자 확인
### Phase 2: 플롯 구성
- **에이전트**: `plot-architect`
- **입력**: `novel/world-setting.md`
- **출력**: `novel/plot-outline.md`
- **검증**: 장별 시놉시스가 세계관 규칙과 일치하는지 확인
### Phase 3: 본문 집필
- **에이전트**: `prose-writer`
- **입력**: `novel/world-setting.md` + `novel/plot-outline.md`
- **출력**: `novel/chapters/ch{NN}.md`
- **검증**: 각 장이 플롯 구성안을 충실히 반영하는지 확인각 Phase의 검증 기준에 주목하자. “사용자 확인”, “세계관 규칙과 일치”, “플롯 구성안을 충실히 반영” — 이 검증이 없으면 앞 단계의 오류가 뒤로 전파되어 전체 소설의 품질이 무너진다. 파이프라인에서 단계별 검증은 선택이 아니라 필수다.
패턴 2: 팬아웃/팬인 (Fan-out/Fan-in)
구조
팬아웃/팬인(fan-out/fan-in)은 하나의 작업을 여러 하위 작업으로 분배(fan-out)하고, 각 결과를 다시 통합(fan-in)하는 패턴이다.
┌→ [에이전트 B1] → 결과 ─┐
[에이전트 A] ───┼→ [에이전트 B2] → 결과 ─┼→ [에이전트 C]
(분배) └→ [에이전트 B3] → 결과 ─┘ (통합)
신문사의 취재팀과 같다. 편집장이 “이 사건을 세 각도에서 취재하라”고 지시하면, 기자 3명이 각각 독립적으로 취재한다. 취재가 끝나면 편집장이 세 기사를 종합하여 하나의 보도로 만든다.
언제 사용하는가
팬아웃/팬인은 다음 조건을 만족할 때 적합하다:
- 독립적인 하위 작업으로 분할할 수 있다. 각 작업이 서로의 결과에 의존하지 않는다.
- 하위 작업의 수가 가변적이다. 3개일 수도, 10개일 수도 있다.
- 최종적으로 결과를 하나로 통합해야 한다.
반대로, 하위 작업 간에 의존성이 있다면 팬아웃/팬인은 적합하지 않다. “B2가 B1의 결과를 참조해야 한다”면, 그것은 파이프라인에 가깝다.
왜 이 패턴인가
팬아웃/팬인의 핵심 장점은 속도다. N개의 작업을 동시에 실행하면 전체 소요 시간은 가장 느린 작업 하나의 시간에 수렴한다. 12개 챕터의 인포그래픽을 만든다면, 순차 실행은 12배의 시간이 걸리지만 팬아웃은 1배에 가까운 시간만 걸린다.
단점은 통합의 어려움이다. 독립적으로 생성된 결과들 사이에 일관성이 깨질 수 있다. 기자 3명이 같은 사건을 취재했는데, 사실관계가 다르게 서술되어 있다면? 통합 에이전트가 이 불일치를 해결해야 한다.
실습: 웹툰 에피소드 동시 제작
웹툰 한 편을 제작하는 하네스를 생각해보자. 시나리오가 확정된 후, 한 에피소드의 세 장면을 동시에 작업할 수 있다. 각 장면은 독립적이지만, 최종적으로 하나의 에피소드로 통합되어야 한다.
에이전트 팀:
| 에이전트 | 역할 | 모델 |
|---|---|---|
scene-splitter |
에피소드를 장면 단위로 분할 | sonnet |
scene-artist |
개별 장면의 콘티/스크립트 작성 | opus |
episode-assembler |
장면들을 하나의 에피소드로 통합 | sonnet |
워크플로우:
Phase 1: [scene-splitter]
에피소드 시나리오 → 장면 3개로 분할
Phase 2: (팬아웃)
┌→ [scene-artist] → scene-01.md
├→ [scene-artist] → scene-02.md
└→ [scene-artist] → scene-03.md
Phase 3: [episode-assembler]
scene-01.md + scene-02.md + scene-03.md → episode-final.md
오케스트레이터 스킬에서 팬아웃/팬인 부분은 이렇게 명시한다:
### Phase 2: 장면별 콘티 작성 (팬아웃)
- **에이전트**: `scene-artist` (장면 수만큼 병렬 호출)
- **입력**: `webtoon/scenes/scene-{NN}-brief.md` (Phase 1의 분할 결과)
- **출력**: `webtoon/scenes/scene-{NN}-draft.md`
- **병렬 실행**: 각 장면은 독립적이므로 동시 실행
- **검증**: 각 장면이 시나리오의 해당 부분을 충실히 반영하는지 확인
### Phase 3: 에피소드 통합 (팬인)
- **에이전트**: `episode-assembler`
- **입력**: `webtoon/scenes/scene-*-draft.md` (모든 장면)
- **출력**: `webtoon/episodes/ep{NN}-final.md`
- **통합 기준**:
- 장면 간 캐릭터 외형/복장 일관성
- 대사 톤의 통일성
- 시간 순서의 논리적 연결
- **검증**: 통합된 에피소드를 처음부터 끝까지 읽었을 때 자연스러운지 확인통합 기준을 구체적으로 명시한 부분에 주목하자. “일관성 확인”이라고만 쓰면 모호하다. 무엇의 일관성인지 — 외형, 대사 톤, 시간 순서 — 를 구체적으로 나열해야 통합 에이전트가 실제로 검증할 수 있다.
패턴 3: 전문가풀 (Expert Pool)
구조
전문가풀(expert pool)은 라우터(router)가 입력을 분석하여 적절한 전문가를 선택하고 호출하는 패턴이다.
┌→ [전문가 A] ─┐
[라우터] ───────────┼→ [전문가 B] ─┼→ 결과
(입력 분석, └→ [전문가 C] ─┘
전문가 선택)
병원의 접수 데스크와 같다. 환자가 증상을 말하면, 접수원이 “내과로 가세요” 혹은 “정형외과로 가세요”라고 안내한다. 어떤 전문의가 배정될지는 환자의 상태에 따라 달라진다.
파이프라인이나 팬아웃/팬인과의 결정적 차이는 선택이다. 파이프라인은 모든 에이전트가 항상 실행된다. 팬아웃/팬인도 모든 하위 에이전트가 실행된다. 하지만 전문가풀에서는 입력에 따라 일부 에이전트만 실행된다.
언제 사용하는가
전문가풀은 다음 조건을 만족할 때 적합하다:
- 입력의 종류가 다양하고, 종류에 따라 필요한 전문성이 다르다.
- 모든 전문가를 매번 호출하는 것은 낭비다.
- 새로운 전문가를 추가해도 기존 구조가 변경되지 않아야 한다.
반대로, 모든 입력이 동일한 처리 과정을 거친다면 전문가풀은 불필요한 복잡성을 추가할 뿐이다.
왜 이 패턴인가
전문가풀의 핵심 장점은 확장성이다. 새로운 전문가가 필요하면 전문가 에이전트를 하나 추가하고, 라우터의 선택 기준에 한 줄만 추가하면 된다. 기존 전문가들의 정의를 수정할 필요가 없다.
또 다른 장점은 효율성이다. Python 코드를 분석하는데 Java 전문가를 호출할 필요가 없다. 필요한 전문가만 골라서 호출하므로 리소스를 절약한다.
단점은 라우터의 정확도에 전체 시스템의 품질이 좌우된다는 점이다. 라우터가 잘못된 전문가를 선택하면, 아무리 전문가가 뛰어나도 엉뚱한 결과가 나온다.
실습: 멀티 도메인 리서치 팀
기업의 리서치 요청을 처리하는 하네스를 설계해보자. 요청 내용에 따라 기술 분석, 시장 조사, 법률 검토 중 적절한 전문가에게 라우팅해야 한다.
에이전트 팀:
| 에이전트 | 역할 | 모델 |
|---|---|---|
research-router |
요청 분석 및 전문가 라우팅 | sonnet |
tech-analyst |
기술 동향/아키텍처 분석 | opus |
market-researcher |
시장 규모/경쟁사 조사 | opus |
legal-reviewer |
규제/컴플라이언스 검토 | opus |
report-writer |
분석 결과를 보고서로 정리 | sonnet |
워크플로우:
Phase 1: [research-router]
요청 분석 → 전문가 선택
Phase 2: (선택적 호출)
┌→ [tech-analyst] (기술 관련 요청일 때)
├→ [market-researcher] (시장 관련 요청일 때)
└→ [legal-reviewer] (법률 관련 요청일 때)
Phase 3: [report-writer]
분석 결과 → 최종 보고서
라우터 에이전트의 핵심은 선택 기준을 명확히 정의하는 것이다:
## 라우팅 규칙
요청을 분석하여 아래 기준에 따라 전문가를 선택한다.
복수 도메인에 걸치는 요청은 해당 전문가를 모두 호출한다.
| 키워드/패턴 | 전문가 | 예시 |
|------------|--------|------|
| 기술, API, 아키텍처, 성능, 스택 | `tech-analyst` | "Kafka vs RabbitMQ 비교" |
| 시장, 경쟁사, TAM, 점유율, 트렌드 | `market-researcher` | "국내 생성AI 시장 규모" |
| 규제, 법률, 컴플라이언스, 개인정보 | `legal-reviewer` | "EU AI Act 영향 분석" |
### 복합 요청 처리
"AI 기술로 금융 시장에 진출할 때의 규제 리스크"
→ `tech-analyst` + `market-researcher` + `legal-reviewer` 모두 호출라우팅 규칙을 키워드 기반으로 작성한 이유는, AI 에이전트가 이 규칙을 읽고 판단할 수 있어야 하기 때문이다. “알아서 판단해라”보다 “이 키워드가 포함되면 이 전문가를 선택해라”가 훨씬 안정적이다.
또한 “복수 도메인에 걸치는 요청은 해당 전문가를 모두 호출한다”는 규칙도 중요하다. 실무에서는 하나의 요청이 여러 영역에 걸치는 경우가 대부분이다. 이 경우 전문가풀은 팬아웃/팬인과 결합된다 — 선택된 복수의 전문가가 병렬로 실행되고, 결과가 보고서 작성자에게 통합된다.
패턴 4: 생성-검증 (Generate-Verify)
구조
생성-검증(generate-verify)은 생성자(producer)가 결과물을 만들고, 검증자(reviewer)가 품질을 평가하여, 기준을 통과하지 못하면 재생성을 요청하는 루프 패턴이다.
[생성자] → 산출물 → [검증자] → 통과? ─ Yes → 완료
│
No
│
▼
피드백 → [생성자] → (재시도)
출판사의 편집 과정과 같다. 작가가 원고를 쓰고, 편집자가 리뷰한다. 편집자가 “이 부분을 고치세요”라고 피드백하면 작가가 수정한다. 수정본을 다시 편집자가 확인한다. 편집자가 “OK”할 때까지 이 과정이 반복된다.
언제 사용하는가
생성-검증은 다음 조건을 만족할 때 적합하다:
- 품질 기준이 명확하고, 기준 충족 여부를 자동으로 판단할 수 있다.
- 한 번에 완벽한 결과를 기대하기 어렵고, 반복적 개선이 자연스러운 작업이다.
- 생성자와 검증자의 관점이 달라야 효과적이다 (작가 vs 편집자).
반대로, 검증 기준이 모호하거나 주관적이면 루프가 끝나지 않을 위험이 있다. “좋은 글인가?”는 모호하지만, “모든 CRITICAL 이슈가 해결되었는가?”는 명확하다.
왜 이 패턴인가
생성-검증의 핵심 장점은 품질 보장이다. 다른 세 패턴은 결과물이 기대에 미치지 못하면 사람이 직접 수정해야 한다. 생성-검증은 시스템 스스로가 품질을 개선하는 자기 교정(self-correction) 메커니즘을 내장한다.
또 다른 장점은 역할 분리다. Chapter 2에서 다룬 “역할 충돌” 문제를 해결한다. 글을 쓰면서 동시에 자기 글을 냉정하게 평가하기 어렵지만, 작성과 검증을 별개 에이전트에게 맡기면 각자 자기 역할에 충실할 수 있다.
단점은 무한 루프 위험이다. 검증자의 기준이 너무 엄격하거나, 생성자가 피드백을 제대로 반영하지 못하면 루프가 끝나지 않는다. 이를 방지하려면 최대 반복 횟수를 반드시 설정해야 한다.
실습: 기술 블로그 작성과 리뷰
기술 블로그 글을 작성하고 리뷰하는 하네스를 설계해보자.
에이전트 팀:
| 에이전트 | 역할 | 모델 |
|---|---|---|
blog-writer |
기술 블로그 초안 작성 | opus |
blog-reviewer |
기술 정확성과 가독성 검증 | sonnet |
워크플로우:
Phase 1: [blog-writer] → 초안 작성 → draft.md
Phase 2: 리뷰 루프 (최대 3회)
[blog-reviewer] → draft.md 리뷰 → review.md
│
├─ CRITICAL 이슈 0개 → 승인 → Phase 3으로
└─ CRITICAL 이슈 1개 이상 → [blog-writer] → 수정 → 재리뷰
Phase 3: 최종본 확정
이 패턴의 핵심은 리뷰 기준과 루프 종료 조건이다. 오케스트레이터에 다음과 같이 명시한다:
### Phase 2: 리뷰 루프
- **생성자**: `blog-writer`
- **검증자**: `blog-reviewer`
- **최대 반복**: 3회
- **루프 종료 조건**: CRITICAL 이슈 0개
- **리뷰 기준**:
- CRITICAL: 기술적 오류 (잘못된 코드, 틀린 설명)
- MAJOR: 구조적 문제 (논리 비약, 핵심 내용 누락)
- MINOR: 표현 개선 (문체, 용어 통일)
- **재생성 규칙**:
- CRITICAL, MAJOR 이슈만 수정 대상
- MINOR는 기록만 하고 수정하지 않음
- 수정 시 리뷰에서 지적된 부분만 변경 (나머지 유지)
- **최대 반복 도달 시**: CRITICAL이 남아 있으면 사용자에게 에스컬레이션세 가지 중요한 설계 결정이 여기에 담겨 있다:
첫째, 이슈 심각도 분류. CRITICAL, MAJOR, MINOR를 구분하지 않으면, 사소한 문체 문제 때문에 루프가 계속 돌 수 있다. 심각도를 나누고 “CRITICAL만 루프 조건에 포함”하면 루프가 적정 횟수에서 종료된다.
둘째, 최대 반복 횟수. 3회로 제한했다. 3번의 수정으로도 CRITICAL이 해결되지 않으면, 그것은 생성자의 능력 밖의 문제일 가능성이 높다. 이 경우 사람의 개입이 필요하므로 에스컬레이션한다.
셋째, 수정 범위 제한. “리뷰에서 지적된 부분만 변경”이라는 규칙이 없으면, 생성자가 수정 과정에서 다른 부분까지 건드려 새로운 문제를 만들 수 있다. 외과 수술처럼 지적된 부분만 정확히 수정해야 루프가 수렴한다.
심화: 패턴 선택 의사결정 트리
4가지 패턴을 배웠다. 실전에서는 “우리 도메인에 어떤 패턴이 맞는가?”를 빠르게 판단해야 한다. 다음 의사결정 트리를 따라가면 적절한 패턴을 선택할 수 있다.
작업을 분석한다
│
├─ Q1: 작업들 사이에 순서 의존성이 있는가?
│ │
│ ├─ Yes: 앞 작업의 결과가 없으면 뒤 작업을 시작할 수 없는가?
│ │ │
│ │ ├─ Yes → 파이프라인
│ │ └─ No → Q2로
│ │
│ └─ No → Q2로
│
├─ Q2: 동일한 작업을 여러 입력에 대해 독립적으로 수행하는가?
│ │
│ ├─ Yes → 팬아웃/팬인
│ └─ No → Q3로
│
├─ Q3: 입력의 종류에 따라 다른 처리가 필요한가?
│ │
│ ├─ Yes → 전문가풀
│ └─ No → Q4로
│
└─ Q4: 결과물의 품질을 자동으로 검증하고 개선해야 하는가?
│
├─ Yes → 생성-검증
└─ No → 파이프라인 (가장 단순한 패턴으로 시작)
이 트리는 출발점이지 정답은 아니다. 실전에서는 하나의 패턴만으로 충분한 경우가 드물다. 다음 섹션에서 다루는 패턴 조합이 더 현실적이다.
몇 가지 판단 기준을 표로 정리하면 다음과 같다:
| 질문 | 해당 패턴 |
|---|---|
| “A의 결과가 없으면 B를 시작할 수 없다” | 파이프라인 |
| “12개 항목을 같은 방식으로 처리한다” | 팬아웃/팬인 |
| “Python이면 A, Java이면 B를 호출한다” | 전문가풀 |
| “초안을 쓰고, 리뷰하고, 고치고, 다시 리뷰한다” | 생성-검증 |
심화: 패턴 조합 — 실전은 단일 패턴이 아니다
지금까지 4가지 패턴을 개별적으로 살펴봤다. 하지만 실전의 하네스는 대부분 여러 패턴이 Phase별로 혼합된 형태다. Chapter 2에서 본 book-writer 하네스가 좋은 예다.
Phase 1: 목차 설계 → 파이프라인의 첫 단계
Phase 2: 챕터 집필 → 파이프라인 (순차)
Phase 3: 리뷰 루프 → 생성-검증
Phase 4: 인포그래픽 생성 → 팬아웃/팬인
Phase 5: 출판 → 파이프라인의 마지막 단계
전체 구조는 파이프라인이지만, Phase 3에서 생성-검증이, Phase 4에서 팬아웃/팬인이 내포되어 있다. 이런 중첩 구조가 실전의 기본 형태다.
패턴을 조합할 때 기억해야 할 원칙이 세 가지 있다.
1. 큰 틀은 파이프라인으로 시작한다
대부분의 복합 작업은 전체적으로 “먼저 이것 → 다음 이것 → 그 다음 이것”이라는 순서가 있다. 이 큰 흐름을 파이프라인으로 잡고, 각 Phase 안에서 다른 패턴을 적용하는 것이 자연스럽다.
2. 한 Phase에 하나의 패턴만 적용한다
Phase 3에서 팬아웃/팬인과 생성-검증을 동시에 적용하면 오케스트레이터가 복잡해진다. 대신 Phase를 더 잘게 나누는 것이 낫다. Phase 3a에서 팬아웃/팬인, Phase 3b에서 생성-검증으로 분리하면 각 Phase가 단순해진다.
3. 패턴 조합의 흔한 유형을 알아둔다
자주 등장하는 조합을 정리하면 다음과 같다:
| 조합 | 구조 | 전형적 사례 |
|---|---|---|
| 파이프라인 + 생성-검증 | 순차 처리하되, 특정 단계에 리뷰 루프 | 책 집필, 코드 생성 |
| 파이프라인 + 팬아웃/팬인 | 순차 흐름 중간에 병렬 처리 | 배치 처리, 다국어 번역 |
| 전문가풀 + 생성-검증 | 전문가가 생성하고, 별도 에이전트가 검증 | 코드 생성 + 자동 테스트 |
| 팬아웃/팬인 + 생성-검증 | 병렬 생성 후 각각 검증 | 동시 리서치 + 팩트체크 |
실제 하네스를 설계할 때는 이렇게 접근하자:
- 전체 작업을 Phase로 나눈다
- 각 Phase에 적합한 단일 패턴을 선택한다
- Phase 간 연결은 파이프라인으로 묶는다
- 오케스트레이터에 Phase별 패턴을 명시한다
심화: 4가지 패턴 비교 총정리
마지막으로, 4가지 패턴의 핵심 특성을 한 번에 비교한다.
| 특성 | 파이프라인 | 팬아웃/팬인 | 전문가풀 | 생성-검증 |
|---|---|---|---|---|
| 데이터 흐름 | 순차 (직렬) | 분배 → 병렬 → 통합 | 라우팅 → 선택적 실행 | 순환 (루프) |
| 에이전트 실행 | 전부 순서대로 | 전부 동시에 | 선택된 것만 | 조건부 반복 |
| 핵심 장점 | 단순함, 추적 용이 | 속도 (병렬) | 확장성, 효율 | 품질 보장 |
| 핵심 단점 | 느림 | 통합 어려움 | 라우터 의존 | 무한 루프 위험 |
| 설계 핵심 | 단계별 검증 | 통합 기준 명시 | 라우팅 규칙 | 종료 조건 명확화 |
| 적합한 작업 | 순차 의존 | 독립 반복 | 다양한 입력 | 반복 개선 |
정리
- 아키텍처 패턴은 에이전트 팀의 “연결 방식”을 유형화한 것이다. 매번 처음부터 설계하는 대신, 검증된 구조를 선택한다.
- 파이프라인: A → B → C. 순차 의존 작업에 적합. 단순하지만 느리다. 단계별 검증이 핵심.
- 팬아웃/팬인: 분배 → 병렬 → 통합. 독립 작업에 적합. 빠르지만 통합이 어렵다. 통합 기준 명시가 핵심.
- 전문가풀: 라우터가 전문가를 선택. 다양한 입력에 적합. 확장성이 높지만 라우터 정확도에 의존한다. 라우팅 규칙 명확화가 핵심.
- 생성-검증: 생성 → 검증 → 재생성 루프. 품질 보장에 적합. 자기 교정이 가능하지만 무한 루프 위험. 종료 조건 설정이 핵심.
- 패턴 선택 의사결정 트리: 순서 의존 → 파이프라인, 독립 반복 → 팬아웃/팬인, 입력별 분기 → 전문가풀, 반복 개선 → 생성-검증.
- 실전은 조합: 큰 틀은 파이프라인, 각 Phase 안에서 다른 패턴을 적용하는 중첩 구조가 일반적이다.
다음 챕터 미리보기
- Chapter 4에서는 에이전트 정의 파일을 실제로 작성하는 방법을 다룬다. frontmatter의 각 필드를 어떻게 채우고, 본문의 역할/원칙/협업 섹션을 어떻게 설계하며, 좋은 에이전트 정의와 나쁜 에이전트 정의의 차이가 무엇인지를 구체적으로 배운다.
Chapter 4: 에이전트, 스킬, 오케스트레이터의 구조
이 챕터에서 배울 것
- 메타 스킬이 자동 생성하는 파일의 종류와 위치
- 에이전트 파일의 구조: frontmatter 3개 필드 + 본문 5개 섹션의 역할
- 스킬 파일의 구조: frontmatter + 워크플로우 + 도구 사용법 + 출력 규칙, 그리고 references/ 디렉토리
- 에이전트와 스킬의 관계: 1:N, N:1, 1:1 패턴과 선택 기준
- 생성된 파일에서 주로 수정하는 부분과 커스터마이징 방법
- 좋은 정의와 나쁜 정의의 차이, 그리고 커스터마이징 포인트
- description 트리거 키워드 설계의 4가지 원칙
- sonnet과 opus 모델을 작업 특성에 맞게 선택하는 기준
본문
메타 스킬이 생성하는 파일들
Chapter 2에서 메타 스킬(/harness)을 실행하면 에이전트 팀이 자동으로 생성된다고 배웠다. Chapter 3에서는 그 팀이 취하는 4가지 아키텍처 패턴을 살펴보았다. 이제 메타 스킬이 실제로 만들어낸 파일들을 열어볼 차례다.
메타 스킬이 “기술 블로그 자동화” 하네스를 생성했다고 하자. .claude/ 디렉토리를 열어보면 다음과 같은 구조가 나타난다.
.claude/
├── agents/ # 에이전트 정의 파일들
│ ├── blog-planner.md
│ ├── blog-writer.md
│ ├── blog-editor.md
│ └── seo-optimizer.md
└── skills/ # 스킬 정의 파일들
├── blog-planning/
│ └── SKILL.md
├── blog-writing/
│ ├── SKILL.md
│ └── references/
│ └── style-guide.md
├── blog-editing/
│ └── SKILL.md
└── blog-orchestrator/ # 오케스트레이터 (스킬의 한 종류)
└── SKILL.md
생성되는 파일은 크게 세 종류다.
| 파일 종류 | 위치 | 역할 |
|---|---|---|
| 에이전트 정의 | .claude/agents/{이름}.md |
“누가 하는가” — 전문가 페르소나와 행동 원칙 |
| 스킬 정의 | .claude/skills/{이름}/SKILL.md |
“어떻게 하는가” — 작업 절차와 도구 사용법 |
| 오케스트레이터 | .claude/skills/{이름}/SKILL.md |
“어떤 순서로 하는가” — 에이전트 간 실행 순서와 데이터 흐름 |
오케스트레이터도 형식상 스킬 파일이다. 다만 단일 에이전트의 절차가 아니라 에이전트 팀 전체의 실행 계획을 담고 있다는 점이 다르다. 오케스트레이터의 상세 구조는 Chapter 5에서 다룬다.
메타 스킬은 도메인을 분석하여 필요한 에이전트 수, 각 에이전트의 역할, 스킬 분배, 아키텍처 패턴까지 자동으로 결정한다. 하지만 자동 생성된 파일이 모든 상황에 완벽할 수는 없다. 이 챕터에서는 각 파일의 구조를 이해하여, 어디를 읽고 어디를 수정해야 하는지 판단할 수 있게 하는 것이 목표다.
에이전트 파일의 구조
메타 스킬이 생성한 code-reviewer 에이전트 파일을 열어보자.
---
name: code-reviewer
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review', 'PR 리뷰', '코드 검토' 요청 시 트리거."
model: sonnet
---
# Code Reviewer — 코드 리뷰 전문가
당신은 소프트웨어 프로젝트의 코드 품질을 검증하는 전문 리뷰어입니다.
## 핵심 역할
1. **코드 품질 검증**: 가독성, 유지보수성, 성능 관점에서 코드 검토
2. **버그 탐지**: 논리 오류, 엣지 케이스 누락, 잠재적 런타임 에러 식별
3. **개선 제안**: 리팩토링 방향, 디자인 패턴 적용, 테스트 보완 제안
4. **보안 점검**: SQL 인젝션, XSS, 인증/인가 누락 등 보안 취약점 검사
## 작업 원칙
- Always respond in Korean
- 심각도를 3단계로 분류: CRITICAL / WARNING / SUGGESTION
- 문제 지적 시 반드시 **구체적인 수정 코드**를 함께 제시
- 좋은 부분도 언급하여 균형 잡힌 리뷰 유지
- 추측이나 가정을 하지 않음 — 확인이 필요하면 질문
- 한 번에 하나의 파일 또는 PR 단위로 리뷰
- 코딩 스타일보다 **로직과 설계**에 집중
## 출력 형식
리뷰 결과는 다음 형식을 따릅니다:
```markdown
## 리뷰: {파일명 또는 PR 제목}
### 총평
- 코드 품질: {상/중/하}
- 주요 이슈: {count}개
### 상세 리뷰
#### [CRITICAL] {위치 — 파일:라인}
- 문제: {설명}
- 수정 전: `{기존 코드}`
- 수정 후: `{제안 코드}`
#### [WARNING] {위치}
- 문제: {설명}
- 제안: {개선 방향}
### 잘된 점
- {긍정적 피드백}
```
## 협업
- 개발자 에이전트가 작성한 코드를 입력으로 받음
- 리뷰 결과를 개발자 에이전트에게 반환하여 수정 요청
- CRITICAL 이슈가 있으면 수정본을 재리뷰
- CRITICAL 이슈가 0개일 때 승인에이전트 파일은 한 장의 이력서와 같다. 이력서에 이름, 직무 요약, 핵심 역량이 담기듯, 에이전트 파일에는 식별 정보, 역할 정의, 행동 지침이 담긴다. 파일을 읽는 법을 두 영역으로 나누어 살펴보자.
frontmatter: 에이전트의 신분증
파일 상단의 ---로 감싸진 YAML 블록이 frontmatter다. Claude Code가 에이전트를 식별하고 라우팅하는 데 사용하는 메타데이터다.
---
name: code-reviewer
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review', 'PR 리뷰', '코드 검토' 요청 시 트리거."
model: sonnet
---세 개의 필드가 각각 하나의 질문에 답한다.
| 필드 | 질문 | 예시 |
|---|---|---|
name |
이 에이전트의 ID는? | code-reviewer |
description |
언제 이 에이전트를 호출하는가? | 역할 설명 + 트리거 키워드 |
model |
어떤 수준의 AI로 실행하는가? | sonnet 또는 opus |
name 은 에이전트의 고유 식별자다. kebab-case(code-reviewer, blog-planner)로 작성하며, 파일명과 일치시키는 것이 관례다. name: code-reviewer이면 파일명은 code-reviewer.md다. 메타 스킬은 이 관례를 자동으로 따른다.
description 은 두 가지 역할을 동시에 수행한다. 첫째, 이 에이전트가 무엇을 하는지 한 문장으로 설명한다. 둘째, 사용자가 어떤 표현을 입력할 때 이 에이전트가 활성화되는지 트리거 키워드를 명시한다. Claude Code는 사용자의 요청을 각 에이전트의 description과 매칭한다. 사용자가 “코드 리뷰해줘”라고 입력하면, description에 “코드 리뷰”가 포함된 에이전트가 선택된다. description은 단순한 설명이 아니라 검색 인덱스처럼 기능한다. 트리거 키워드 설계의 상세 전략은 심화 섹션에서 다룬다.
model 은 이 에이전트가 사용할 AI 모델을 지정한다. 현재 주요 선택지는 sonnet(빠르고 비용 효율적)과 opus(느리지만 강력)다. 모델 선택 기준은 심화 섹션에서 상세히 다룬다.
본문: 에이전트의 행동 지침
frontmatter 아래의 본문은 에이전트가 실제로 일할 때 참조하는 행동 지침이다. 다섯 가지 핵심 섹션으로 구성된다.
섹션 1: 역할 선언. 본문은 제목과 역할 선언 문장으로 시작한다.
# Code Reviewer — 코드 리뷰 전문가
당신은 소프트웨어 프로젝트의 코드 품질을 검증하는 전문 리뷰어입니다.“당신은 ~입니다” 문장이 에이전트의 페르소나(persona)를 설정한다. “전문 리뷰어”라고 선언하면, 이후의 모든 출력에서 리뷰어의 관점을 유지한다. 역할 선언은 구체적으로, 한 문장으로, “당신”을 주어로 작성한다. “전문가”보다 “코드 품질을 검증하는 전문 리뷰어”가 범위를 더 명확히 한정한다.
섹션 2: 핵심 역할. 이 에이전트가 수행하는 구체적인 업무를 나열한다.
## 핵심 역할
1. **코드 품질 검증**: 가독성, 유지보수성, 성능 관점에서 코드 검토
2. **버그 탐지**: 논리 오류, 엣지 케이스 누락, 잠재적 런타임 에러 식별
3. **개선 제안**: 리팩토링 방향, 디자인 패턴 적용, 테스트 보완 제안
4. **보안 점검**: SQL 인젝션, XSS, 인증/인가 누락 등 보안 취약점 검사번호는 우선순위를 암시한다. 1번이 가장 핵심적인 역할이다. 3~5개로 제한하는 것이 좋다. 6개 이상 나열해야 한다면 에이전트를 분리하라는 신호다. 각 항목은 “명사: 설명” 형태로, 볼드 처리된 명사가 역할의 이름이 되고 뒤의 설명이 범위를 한정한다.
섹션 3: 작업 원칙. 모든 출력에 적용되는 행동 규칙이다.
핵심 역할이 “무엇을 하는가”라면, 작업 원칙은 “어떤 기준으로 하는가”다. 좋은 작업 원칙은 구체적이고 검증 가능하다. “꼼꼼하게 리뷰”가 아니라 “심각도를 CRITICAL/WARNING/SUGGESTION 3단계로 분류”처럼 쓴다. 5~8개가 적당하다.
섹션 4: 출력 형식. 에이전트의 산출물이 일정한 형태를 가져야 할 때 정의한다. 다른 에이전트가 이 출력을 파싱해서 사용하거나, 사용자가 일관된 형태를 기대할 때 필요하다. 출력 형태가 매번 달라져도 되는 자유 형식 작업에서는 생략할 수 있다.
섹션 5: 협업. 팀의 일원으로 동작할 때, 다른 에이전트와의 관계를 정의한다. 세 가지를 명시한다: 누구에게서 무엇을 받는가(입력), 누구에게 무엇을 전달하는가(출력), 언제 끝나는가(종료 조건). 단독으로 사용되는 에이전트라면 생략해도 되지만, 하네스의 일부로 동작하는 에이전트라면 반드시 포함해야 한다.
이 다섯 섹션의 구조를 표로 정리하면 다음과 같다.
| 섹션 | 역할 | 핵심 질문 |
|---|---|---|
| 역할 선언 | 페르소나 설정 | “이 에이전트는 누구인가?” |
| 핵심 역할 | 업무 범위 한정 | “무엇을 하는가?” |
| 작업 원칙 | 행동 기준 설정 | “어떤 기준으로 하는가?” |
| 출력 형식 | 산출물 규격화 | “결과를 어떤 형태로 내는가?” |
| 협업 | 팀 내 위치 정의 | “누구와 어떻게 소통하는가?” |
에이전트 파일은 길 필요가 없다. 위 예시도 40줄 남짓이다. 핵심만 명확하게 담으면 된다.
스킬 파일의 구조
에이전트가 “누구인가”를 정의한다면, 스킬은 “어떤 절차로 일하는가”를 정의한다. 에이전트 파일이 사람의 이력서라면, 스킬 파일은 업무 매뉴얼이다.
메타 스킬이 생성한 code-review 스킬 파일을 열어보자.
.claude/skills/
└── code-review/ # 스킬 디렉토리
├── SKILL.md # 스킬 정의 본체
└── references/ # 참고자료 (선택)
├── checklist.md
└── severity-guide.md
에이전트와 달리 스킬은 디렉토리 단위로 관리된다. 스킬에는 워크플로우 외에도 체크리스트, 템플릿, 예시 파일 같은 참고자료가 필요할 수 있기 때문이다. 이들을 하나의 디렉토리에 묶으면 스킬 단위로 이동하거나 재사용하기 쉽다.
스킬 파일의 4개 섹션
스킬 파일(SKILL.md)은 크게 4개 섹션으로 구성된다.
---
name: code-review
description: "코드 리뷰 스킬. PR의 코드를 분석하고 리뷰 코멘트를 생성합니다.
'코드 리뷰', 'code review', 'PR 리뷰' 요청 시 트리거."
---
# 1. 개요 (Overview)
이 스킬이 무엇을 하는지 한 문단 요약.
# 2. 워크플로우 (Workflow)
Phase별 작업 절차. 입력 → 처리 → 출력 → 검증.
# 3. 도구 사용법 (Tool Usage)
각 Phase에서 사용하는 Claude Code 도구와 사용 규칙.
# 4. 출력 규칙 (Output Rules)
산출물의 형식, 저장 위치, 네이밍 규칙.각 섹션을 하나씩 살펴보자.
frontmatter. 에이전트와 동일한 형식이지만, model 필드가 없다. 왜 없는가? 스킬은 절차를 정의할 뿐, 어떤 모델로 실행할지는 스킬을 호출하는 에이전트가 결정하기 때문이다. 같은 “코드 리뷰” 스킬을 opus 에이전트가 실행할 수도 있고 sonnet 에이전트가 실행할 수도 있다. 절차는 같지만 실행 모델은 다를 수 있다.
워크플로우. 스킬의 핵심이다. “무엇을 어떤 순서로 하는가”를 Phase 단위로 정의한다. 각 Phase에는 반드시 4가지를 명시한다.
| 항목 | 역할 | 예시 |
|---|---|---|
| 입력 | 이 Phase가 시작되려면 무엇이 필요한가 | PR 번호, diff 내용 |
| 처리 | 입력을 어떻게 가공하는가 | diff를 파싱하여 이슈 식별 |
| 출력 | 이 Phase가 끝나면 무엇이 생기는가 | 이슈 목록, 리뷰 코멘트 |
| 검증 | 출력이 올바른지 어떻게 확인하는가 | 모든 파일이 분석되었는지 |
이 4가지 중 하나라도 빠지면 스킬은 불완전하다. 특히 검증이 빠지기 쉬운데, 검증이 없으면 세 가지 문제가 발생한다. 첫째, 무음 실패 — Phase 1에서 빈 결과가 나와도 Phase 2가 그대로 진행된다. 둘째, 오류 누적 — 불완전한 중간 결과가 다음 Phase로 전달되어 최종 결과가 왜곡된다. 셋째, 디버깅 불가 — 최종 결과가 이상할 때 어느 Phase에서 문제가 발생했는지 추적할 수 없다.
실제 워크플로우 예시를 보자.
## 워크플로우
### Phase 1: 변경 파일 수집
- **입력**: PR 번호 또는 브랜치명
- **처리**: `gh pr diff` 또는 `git diff`로 변경된 파일 목록과 diff 수집
- **출력**: 변경 파일 목록 + diff 내용
- **검증**: diff가 비어있지 않은지 확인
### Phase 2: 코드 분석
- **입력**: Phase 1의 diff + 원본 파일
- **처리**:
1. 변경된 파일별로 Read 도구로 전체 내용을 읽는다
2. `references/checklist.md` 의 항목에 따라 이슈를 식별한다
3. 각 이슈에 `references/severity-guide.md` 기준으로 심각도를 부여한다
- **출력**: 파일별 이슈 목록 (심각도, 위치, 설명, 개선 제안)
- **검증**: 모든 변경 파일이 분석되었는지, 각 이슈에 심각도가 부여되었는지 확인도구 사용법. Claude Code는 파일 읽기, 검색, 편집, 터미널 명령 실행 등 여러 도구를 가지고 있다. 같은 작업을 여러 방법으로 수행할 수 있는데, 스킬 파일에서 도구를 지정하면 일관된 방식으로 작업이 수행되고, 결과의 예측 가능성이 높아진다.
출력 규칙. 스킬의 최종 산출물이 어떤 형식이어야 하고, 어디에 저장되는지를 정의한다. 출력 규칙이 없으면 같은 스킬을 실행할 때마다 형식이 달라진다.
references/ 디렉토리 활용
스킬의 워크플로우를 작성하다 보면 참고자료가 길어지는 경우가 있다. 코드 리뷰 체크리스트가 100줄이 넘거나, 심각도 분류 기준이 별도 문서 분량이 되는 경우다. 이런 참고자료를 SKILL.md 안에 모두 넣으면 두 가지 문제가 생긴다.
- 가독성 저하: 워크플로우의 흐름 사이에 100줄짜리 체크리스트가 끼면 전체 구조를 파악하기 어렵다.
- 컨텍스트 낭비: 특정 Phase에서만 필요한 참고자료가 전체 실행 내내 컨텍스트를 차지한다.
해결책은 references/ 디렉토리로 분리하고, SKILL.md에서 필요할 때만 참조하는 것이다.
## 워크플로우
### Phase 2: 코드 분석
- `references/checklist.md` 의 체크리스트에 따라 코드를 분석한다
- 심각도는 `references/severity-guide.md` 의 기준을 따른다이렇게 하면 SKILL.md의 가독성이 유지되고, 체크리스트만 업데이트하고 싶을 때 SKILL.md를 건드리지 않아도 된다.
모든 참고자료를 분리할 필요는 없다. 다음 기준으로 판단한다.
| 기준 | references/로 분리 | SKILL.md에 유지 |
|---|---|---|
| 분량 | 20줄 이상 | 20줄 미만 |
| 변경 빈도 | 자주 업데이트됨 | 거의 바뀌지 않음 |
| 사용 범위 | 특정 Phase에서만 사용 | 전체 워크플로우에 걸쳐 사용 |
| 공유 가능성 | 다른 스킬에서도 재사용 | 이 스킬에서만 사용 |
참고자료의 위치는 두 곳이 가능하다. 프로젝트 수준(references/ — 프로젝트 루트)은 모든 에이전트와 스킬이 참조하는 전역 가이드라인이다. 스킬 수준(.claude/skills/{스킬명}/references/)은 해당 스킬에서만 사용하는 참고자료다. 여러 스킬이 참조하는 코딩 원칙은 프로젝트 수준에, 코드 리뷰 체크리스트처럼 특정 스킬 전용인 자료는 스킬 수준에 둔다.
에이전트와 스킬의 관계
에이전트와 스킬은 반드시 1:1로 대응하지 않는다. 세 가지 관계 패턴이 가능하다.
1 에이전트 : N 스킬
가장 흔한 구조다. 하나의 에이전트가 상황에 따라 여러 스킬을 선택하여 실행한다.
code-reviewer (에이전트)
├── code-review (스킬) — 일반 코드 리뷰
├── security-audit (스킬) — 보안 취약점 중심 리뷰
└── performance-review (스킬) — 성능 병목 중심 리뷰
사용자가 “코드 리뷰해줘”라고 하면 code-review 스킬을, “보안 취약점 검토해줘”라고 하면 security-audit 스킬을 사용한다. 에이전트의 전문성은 동일(코드를 분석하는 능력)하지만, 절차가 다르기 때문에 스킬을 나눈 것이다.
N 에이전트 : 1 스킬 (공유 스킬)
여러 에이전트가 하나의 스킬을 공유하는 구조다.
backend-dev (에이전트) ─┐
frontend-dev (에이전트) ─┼── code-review (공유 스킬)
devops-engineer (에이전트)─┘
세 에이전트 모두 PR을 리뷰할 수 있고, 리뷰 절차는 동일하다. 차이는 관점이다. 백엔드 개발자는 API 설계를, 프론트엔드 개발자는 UI 로직을 중점적으로 본다. 이 관점 차이는 에이전트 파일에 정의되어 있으므로, 절차(스킬)는 공유해도 된다.
공유 스킬을 설계할 때의 핵심 원칙은 절차는 일반적으로, 관점은 에이전트에게 위임하는 것이다. 스킬에 “API 설계를 중점적으로 본다”라고 쓰면 공유가 불가능해진다. 대신 “변경된 파일을 에이전트의 전문 분야 관점에서 분석한다”처럼 일반적으로 작성한다.
1 에이전트 : 1 스킬
에이전트마다 절차도 다르고 관점도 다른 경우다. 가장 단순하지만, 에이전트와 스킬이 1:1로 묶이면 재사용성이 떨어진다.
관계 선택 기준
어떤 관계를 선택할지 다음 질문으로 판단한다.
| 질문 | 답이 “예”이면 |
|---|---|
| 같은 에이전트가 상황에 따라 다른 절차를 따르는가? | 1 에이전트 : N 스킬 |
| 다른 에이전트가 동일한 절차를 따르는가? | N 에이전트 : 1 스킬 |
| 에이전트마다 절차도 다르고 관점도 다른가? | 1 에이전트 : 1 스킬 |
메타 스킬이 생성한 하네스는 보통 1:1 관계로 시작한다. 이것이 가장 단순하고 이해하기 쉬운 구조이기 때문이다. 하네스를 운영하면서 “이 에이전트에게 다른 절차도 필요하구나” 또는 “이 절차는 여러 에이전트가 공유할 수 있겠구나”라는 판단이 서면 그때 관계를 확장하면 된다.
커스터마이징 가이드
메타 스킬이 생성한 파일은 초안이다. 도메인을 분석하여 합리적인 구조를 만들어내지만, 실제 운영 과정에서 조정이 필요한 부분이 생긴다. 커스터마이징의 핵심은 “전체를 다시 쓰는 것”이 아니라 “특정 부분만 정밀하게 수정하는 것”이다.
주로 수정하는 부분은 다음 세 가지다.
1. 작업 원칙 추가/수정
가장 빈번한 커스터마이징이다. 메타 스킬은 범용적인 작업 원칙을 생성하지만, 팀이나 프로젝트의 고유한 규칙은 사람이 추가해야 한다.
## 작업 원칙
- Always respond in Korean
- 심각도를 3단계로 분류: CRITICAL / WARNING / SUGGESTION
- 문제 지적 시 반드시 구체적인 수정 코드를 함께 제시
+ - 사내 코딩 컨벤션(Kotlin Style Guide v2.1)을 기준으로 판단
+ - 레거시 코드의 경우 대규모 리팩토링을 제안하지 않음
+ - PR의 변경 범위를 넘어서는 이슈는 별도 이슈로 분리하여 제안작업 원칙을 추가할 때의 기준: 추가하려는 원칙이 구체적이고 검증 가능한지 자문한다. “더 꼼꼼하게 리뷰”는 추상적이라 효과가 없다. “사내 코딩 컨벤션을 기준으로 판단”은 구체적이며 결과를 검증할 수 있다.
2. 출력 형식 커스터마이징
에이전트의 산출물이 다음 에이전트나 외부 시스템에 전달되어야 할 때, 출력 형식을 조정한다.
예를 들어, 리뷰 결과를 GitHub PR 코멘트로 게시해야 한다면, 마크다운 형식을 GitHub이 잘 렌더링하는 구조로 맞추는 것이 합리적이다. 또는 Jira 티켓과 연동해야 한다면, 이슈별로 고유 ID를 부여하는 출력 형식이 필요할 수 있다.
출력 형식을 수정할 때 주의할 점은, 해당 에이전트의 산출물을 다음 에이전트가 어떻게 파싱하는지 확인하는 것이다. 오케스트레이터의 워크플로우에서 다음 Phase의 입력이 이 출력에 의존한다면, 형식을 바꿀 때 다음 Phase의 입력 기대치도 함께 수정해야 한다.
3. references/ 추가
프로젝트 고유의 참고자료를 스킬에 추가하는 것이다. 메타 스킬은 범용적인 references만 생성하지만, 실제 프로젝트에는 고유한 가이드라인이 있다.
.claude/skills/code-review/references/
├── checklist.md # 메타 스킬이 생성한 범용 체크리스트
├── severity-guide.md # 메타 스킬이 생성한 심각도 기준
+ ├── team-conventions.md # 팀 코딩 컨벤션 (직접 추가)
+ └── security-policy.md # 사내 보안 정책 (직접 추가)
references를 추가한 후에는 SKILL.md의 워크플로우에서 해당 파일을 참조하도록 수정해야 한다.
### Phase 2: 코드 분석
- `references/checklist.md` 의 체크리스트에 따라 코드를 분석한다
- 심각도는 `references/severity-guide.md` 의 기준을 따른다
+ - 코딩 스타일은 `references/team-conventions.md` 를 기준으로 판단한다
+ - 보안 관련 이슈는 `references/security-policy.md` 의 정책을 적용한다커스터마이징의 일반 원칙을 정리하면 다음과 같다.
| 원칙 | 설명 |
|---|---|
| 최소 수정 | 전체를 다시 쓰지 않는다. 필요한 부분만 수정한다. |
| 연쇄 확인 | 한 파일을 수정하면, 그 파일을 참조하는 다른 파일도 확인한다. |
| 원본 보존 | 메타 스킬이 생성한 구조(섹션 순서, 네이밍 관례)는 유지한다. |
| 점진적 개선 | 한 번에 많이 바꾸지 않는다. 하나씩 바꾸고, 결과를 확인하고, 다시 바꾼다. |
심화: 좋은 정의 vs 나쁜 정의
같은 역할의 에이전트를 두 가지 방식으로 작성해보겠다. 차이를 비교하면서 좋은 정의의 조건을 정리하자.
나쁜 에이전트 정의
---
name: reviewer
description: "리뷰 에이전트"
model: opus
---
# Reviewer
리뷰를 잘 해주세요.
## 역할
- 코드를 리뷰합니다
- 문제를 찾아줍니다
- 개선점을 알려줍니다
## 원칙
- 꼼꼼하게 리뷰해주세요
- 친절하게 설명해주세요
- 빠짐없이 확인해주세요좋은 에이전트 정의
---
name: code-reviewer
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review', 'PR 리뷰', '코드 검토' 요청 시 트리거."
model: sonnet
---
# Code Reviewer — 코드 리뷰 전문가
당신은 소프트웨어 프로젝트의 코드 품질을 검증하는 전문 리뷰어입니다.
## 핵심 역할
1. **코드 품질 검증**: 가독성, 유지보수성, 성능 관점에서 코드 검토
2. **버그 탐지**: 논리 오류, 엣지 케이스 누락, 잠재적 런타임 에러 식별
3. **개선 제안**: 리팩토링 방향, 디자인 패턴 적용, 테스트 보완 제안
4. **보안 점검**: SQL 인젝션, XSS, 인증/인가 누락 등 보안 취약점 검사
## 작업 원칙
- Always respond in Korean
- 심각도를 3단계로 분류: CRITICAL / WARNING / SUGGESTION
- 문제 지적 시 반드시 **구체적인 수정 코드**를 함께 제시
- 좋은 부분도 언급하여 균형 잡힌 리뷰 유지
- 추측이나 가정을 하지 않음 — 확인이 필요하면 질문
- 코딩 스타일보다 **로직과 설계**에 집중차이점 분석
| 항목 | 나쁜 정의 | 좋은 정의 | 왜 중요한가 |
|---|---|---|---|
| name | reviewer |
code-reviewer |
범위가 모호하면 잘못된 상황에서 호출된다 |
| description | 트리거 키워드 없음 | 한/영 키워드 4개 | 키워드 없으면 사용자 요청에 매칭되지 않는다 |
| model | opus |
sonnet |
분석 작업에 opus는 비용 낭비다 |
| 역할 선언 | “리뷰를 잘 해주세요” | “코드 품질을 검증하는 전문 리뷰어” | 페르소나가 모호하면 관점이 흔들린다 |
| 핵심 역할 | “코드를 리뷰합니다” | “가독성, 유지보수성, 성능 관점에서 검토” | 검증 가능한 구체적 범위가 필요하다 |
| 작업 원칙 | “꼼꼼하게 리뷰해주세요” | “심각도 3단계 분류” | 추상적 지시는 행동을 바꾸지 못한다 |
| 출력 형식 | 없음 | 구조화된 템플릿 | 형식 없으면 매번 다른 형태가 나온다 |
| 협업 | 없음 | 입력/출력/종료 조건 명시 | 팀에서 제 역할을 못 한다 |
나쁜 정의의 핵심 문제는 추상성이다. “잘 해주세요”, “꼼꼼하게”, “친절하게”는 사람이 들어도 어떻게 행동해야 할지 모호하다. AI도 마찬가지다. 구체적이고 검증 가능한 지시가 일관된 품질을 만든다.
좋은 정의의 조건을 정리하면 다음과 같다.
- name이 역할을 드러낸다 — 파일명만 봐도 무슨 에이전트인지 안다
- description에 트리거 키워드가 있다 — 사용자의 자연스러운 표현과 매칭된다
- model이 작업 특성에 맞다 — 비용과 품질의 균형
- 역할 선언이 구체적이다 — “당신은 ~하는 전문가입니다”로 범위를 한정한다
- 핵심 역할이 3~5개로 제한된다 — 집중할 수 있는 범위
- 작업 원칙이 검증 가능하다 — “잘 하세요”가 아니라 “3단계로 분류”
- 출력 형식이 정의되어 있다 — 일관된 산출물 보장
- 협업 관계가 명시되어 있다 — 팀 내 위치와 종료 조건
메타 스킬이 생성한 에이전트 정의를 검토할 때, 이 8가지 조건으로 점검하면 커스터마이징이 필요한 부분을 빠르게 찾아낼 수 있다.
심화: description 트리거 키워드 설계 원칙
description 필드는 에이전트의 “검색 가능성”을 결정한다. 사용자가 어떤 표현으로 요청하든 올바른 에이전트가 선택되게 하려면, 키워드 설계에 4가지 원칙을 적용한다.
원칙 1: 사용자의 언어로 쓴다
개발자가 “코드 리뷰해줘”라고 하지 “소스코드 정적 분석을 수행해줘”라고 하지 않는다. 트리거 키워드는 사용자가 실제로 입력할 표현이어야 한다.
# 나쁜 예 — 전문 용어 위주
description: "소스코드 정적 분석 및 동적 검증 에이전트. '정적 분석', 'static analysis' 요청 시 트리거."
# 좋은 예 — 사용자 표현 위주
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review', 'PR 리뷰', '코드 검토' 요청 시 트리거."원칙 2: 한국어와 영어를 모두 포함한다
개발자는 한국어와 영어를 섞어 쓴다. 두 언어의 키워드를 모두 포함해야 트리거 누락을 방지한다.
description: "... '코드 리뷰', 'code review', 'PR 리뷰' ..."원칙 3: 동의어와 유사 표현을 포함한다
같은 의도를 다른 단어로 표현할 수 있다. 주요 동의어를 커버하되, 핵심 키워드 3~5개로 제한한다. 너무 많으면 관련 없는 요청에도 매칭될 수 있다.
# "리뷰"와 "검토"는 같은 의도
description: "... '코드 리뷰', '코드 검토', 'code review' ..."원칙 4: 역할 설명 문장 자체에도 키워드를 녹인다
트리거 키워드 목록뿐 아니라, 앞의 역할 설명 문장에도 핵심 단어를 포함시킨다. Claude Code는 description 전체를 매칭에 사용하기 때문이다.
# 역할 설명에 "코드 리뷰"가 이미 포함됨
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review', 'PR 리뷰' 요청 시 트리거."공통 패턴을 정리하면: “{역할 동사}하는 에이전트. ‘{한국어 키워드}’, ‘{영어 키워드}’ 요청 시 트리거.” 이 패턴을 따르면 일관성 있는 description을 작성할 수 있다.
메타 스킬은 이 원칙을 대체로 잘 따르지만, 프로젝트 고유의 용어(사내 약어, 팀 용어 등)는 사람이 추가해야 한다. 예를 들어 팀에서 코드 리뷰를 “CR”이라고 부른다면, 트리거 키워드에 ’CR’을 추가하는 것이 합리적이다.
심화: model 선택 가이드
모델 선택은 비용과 품질 사이의 트레이드오프다. 잘못된 선택은 불필요한 비용 증가 또는 품질 저하로 이어진다.
sonnet vs opus 판단 표
| 작업 특성 | sonnet | opus |
|---|---|---|
| 구조화된 분석 (체크리스트 기반) | O | |
| 패턴 기반 코드 생성 | O | |
| 데이터 변환/포맷팅 | O | |
| 짧은 텍스트 생성 (요약, 설명) | O | |
| 긴 텍스트 창작 (챕터, 보고서) | O | |
| 복잡한 추론 (다단계 논리) | O | |
| 미묘한 판단 (뉘앙스, 맥락) | O | |
| 여러 제약 조건 동시 만족 | O |
한 문장으로 요약하면: “정해진 틀에 따라 처리하는 작업은 sonnet, 틀 자체를 만들어야 하는 작업은 opus.”
실전 적용 예시: book-writer 하네스의 모델 배정
이 책의 에이전트 팀에서 왜 chapter-writer만 opus이고 나머지는 sonnet인지 살펴보자.
| 에이전트 | 모델 | 이유 |
|---|---|---|
book-planner |
sonnet | 목차 구조화는 분석적 작업. 주어진 주제를 분류하고 순서를 정하면 된다 |
chapter-writer |
opus | 12~18페이지의 본문을 일관된 문체로 작성해야 한다. 개념 설명, 비유, 예제를 유기적으로 엮는 창작 작업이다 |
book-editor |
sonnet | 체크리스트 기반 검증이다. “정확한가? 완성도는? 일관성은?”을 항목별로 확인한다 |
infographic-creator |
sonnet | SVG 코드 생성은 패턴 기반이다. 박스, 화살표, 텍스트의 조합이다 |
book-publisher |
sonnet | PDF/웹 변환은 절차적 작업이다. 정해진 규칙에 따라 처리한다 |
비용 최적화 전략
모델 선택에 확신이 없다면, 다음 전략을 추천한다.
- 모든 에이전트를 sonnet으로 시작한다
- 결과 품질이 부족한 에이전트만 opus로 올린다
- opus로 올린 후에도 개선이 미미하면 sonnet으로 돌린다 — 이 경우 문제는 모델이 아니라 에이전트 정의 자체에 있다
세 번째 포인트가 중요하다. 품질 문제의 원인이 항상 모델 성능인 것은 아니다. 핵심 역할이 모호하거나, 작업 원칙이 부족하거나, 출력 형식이 불명확한 경우 opus로 올려도 개선되지 않는다. 모델을 바꾸기 전에 에이전트 정의를 먼저 점검하라.
정리
- 메타 스킬은 세 종류의 파일을 생성한다: 에이전트 정의(
.claude/agents/), 스킬 정의(.claude/skills/), 오케스트레이터(스킬의 한 종류). - 에이전트 파일은 frontmatter(name, description, model)와 본문(역할 선언, 핵심 역할, 작업 원칙, 출력 형식, 협업) 두 영역으로 구성된다.
- 스킬 파일은 4개 섹션으로 구성된다: frontmatter, 워크플로우, 도구 사용법, 출력 규칙.
model필드가 없다 — 실행 모델은 에이전트가 결정한다. - 워크플로우의 각 Phase에는 입력, 처리, 출력, 검증 4가지를 반드시 명시한다. 검증이 없으면 무음 실패, 오류 누적, 디버깅 불가 문제가 발생한다.
- 에이전트와 스킬의 관계는 1:N, N:1, 1:1 모두 가능하다. 절차가 다르면 스킬을 나누고, 관점이 다르면 에이전트를 나눈다.
- 긴 참고자료는
references/디렉토리로 분리한다. 20줄 이상, 변경 빈도 높음, 특정 Phase 전용, 다른 스킬에서 재사용 가능 — 네 가지 기준으로 판단한다. - 트리거 키워드는 사용자의 언어로, 한국어/영어 모두 포함하되 3~5개로 제한한다.
- 모델 선택: 정해진 틀에 따라 처리하는 작업은 sonnet, 틀 자체를 만드는 작업은 opus. 확신이 없으면 sonnet으로 시작하여 점진적으로 올린다. 모델을 바꾸기 전에 에이전트 정의를 먼저 점검하라.
- 좋은 정의의 핵심은 구체성과 검증 가능성이다. “잘 해주세요”가 아니라 “심각도를 3단계로 분류”처럼 쓴다.
- 커스터마이징은 작업 원칙 추가, 출력 형식 조정, references/ 추가 세 가지가 주요 수정 포인트다. 최소 수정, 연쇄 확인, 원본 보존, 점진적 개선의 원칙을 따른다.
다음 챕터 미리보기
- Chapter 5에서는 에이전트 팀 전체를 엮는 오케스트레이터 스킬의 구조를 다룬다. 에이전트 구성 테이블, Phase별 워크플로우, 파일 기반 통신, “각 Phase 완료 후 사용자 확인” 패턴을 배운다. 이 챕터에서 살펴본 에이전트와 스킬이 오케스트레이터에 의해 하나의 팀으로 조율되는 과정을 확인한다.
Chapter 5: 오케스트레이터와 팀 운영
이 챕터에서 배울 것
- 오케스트레이터 스킬이 무엇이며, 일반 스킬과 어떻게 다른지
- 메타 스킬이 생성한 오케스트레이터 파일의 전체 구조를 읽는 법
- 에이전트 구성 테이블에서 팀의 큰 그림을 10초 안에 파악하는 법
- Phase별 워크플로우에서 입력/출력의 연쇄와 검증의 2레벨을 이해하는 법
- 파일 기반 통신의 3가지 규칙: 위치 고정, 형식 통일, 메타 정보 포함
- “각 Phase 완료 후 사용자 확인” 패턴이 왜 필수적인지
- 오케스트레이터 설계에서 흔히 발생하는 4가지 실수와 대처법
본문
오케스트레이터란 무엇인가
Chapter 4에서 에이전트와 스킬의 구조를 살펴보았다. 에이전트는 “누가 하는가”를, 스킬은 “어떻게 하는가”를 정의한다. 하지만 에이전트와 스킬이 각각 존재하는 것만으로는 팀이 되지 않는다. 축구에서 공격수, 미드필더, 수비수가 있어도 감독이 포메이션과 작전을 지시하지 않으면 조직적인 플레이가 나오지 않는다.
오케스트레이터(orchestrator)는 이 감독의 역할을 한다. 에이전트 팀의 실행 순서, 데이터 흐름, 의사결정 분기를 정의하는 스킬이다.
일반 스킬과 오케스트레이터 스킬의 차이를 정리하면 다음과 같다.
| 항목 | 일반 스킬 | 오케스트레이터 스킬 |
|---|---|---|
| 실행 주체 | 단일 에이전트 | 여러 에이전트를 순서대로 호출 |
| 워크플로우 | 한 에이전트 내의 작업 절차 | 에이전트 간의 실행 순서와 데이터 전달 |
| 산출물 | 하나의 결과물 | 여러 에이전트의 산출물이 누적되어 최종 결과 |
| Phase 개념 | “이 에이전트가 무엇을 하는가” | “어떤 에이전트가, 언제, 무엇을 받아서, 무엇을 내놓는가” |
일반 스킬이 “한 사람의 업무 매뉴얼”이라면, 오케스트레이터는 “팀 전체의 작전 계획서”다.
왜 오케스트레이터가 별도로 필요할까? 에이전트 정의에 “다음에 에이전트 B를 호출하라”고 쓸 수도 있지 않은가? 가능은 하지만, 세 가지 문제가 생긴다.
- 결합도가 높아진다: 에이전트 A가 에이전트 B의 존재를 직접 알아야 한다. B를 C로 교체하면 A도 수정해야 한다.
- 전체 흐름이 보이지 않는다: 5개 에이전트 파일을 모두 열어야 전체 워크플로우를 파악할 수 있다.
- 재사용이 어렵다: 같은 에이전트를 다른 팀에서 쓰려면 협업 섹션을 매번 수정해야 한다.
오케스트레이터가 있으면 에이전트는 자기 역할에만 집중하고, 팀 구조는 오케스트레이터 한 파일에서 관리된다. 에이전트 교체, 순서 변경, 팀 확장이 모두 오케스트레이터 수정만으로 가능해진다.
메타 스킬(/harness)로 하네스를 생성하면, 이 오케스트레이터가 자동으로 만들어진다. 생성된 .claude/skills/{하네스명}/SKILL.md 파일을 열어보면, 에이전트 팀 구성부터 Phase별 워크플로우까지 완성된 형태로 나온다. 이 챕터에서는 그 생성된 구조를 하나씩 분해하여 이해한다.
인포그래픽: 오케스트레이터 실행 흐름도
오케스트레이터 스킬의 전체 구조
오케스트레이터 스킬 파일은 일반 스킬과 동일하게 .claude/skills/{스킬명}/SKILL.md에 위치한다. 파일 형식도 같다. 다만, 포함하는 정보의 범위가 다르다.
메타 스킬이 생성한 오케스트레이터 파일을 열어보면 다음과 같은 구조가 나온다.
---
name: {오케스트레이터-이름}
description: "{역할 설명}. '{트리거1}', '{트리거2}' 요청 시 트리거."
---
# {타이틀} — {한 줄 설명}
{오케스트레이터의 목적 한 문단 요약}
## 에이전트 팀 구성
(에이전트 구성 테이블)
## 디렉토리 구조
(산출물 저장 위치 계획)
## 워크플로우
(Phase별 실행 순서, 데이터 흐름, 검증 기준)
## 실행 방법
(실제로 어떻게 실행하는지)일반 스킬에는 없고 오케스트레이터에만 있는 섹션이 두 개다: 에이전트 팀 구성과 디렉토리 구조. 이 두 섹션이 오케스트레이터의 핵심이다. 하나씩 살펴보자.
에이전트 구성 테이블
오케스트레이터의 첫 번째 섹션은 에이전트 팀 구성 테이블이다. 이 테이블은 팀 전체를 한눈에 보여준다.
## 에이전트 팀 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `code-reviewer` | 코드 리뷰 | sonnet | 1, 4 |
| `test-writer` | 테스트 코드 작성 | sonnet | 2 |
| `code-fixer` | 코드 수정 | sonnet | 3 |테이블의 네 컬럼은 각각 다음 질문에 답한다.
| 컬럼 | 질문 |
|---|---|
| 에이전트 | 누가 하는가? |
| 역할 | 무엇을 하는가? |
| 모델 | 어떤 수준으로 하는가? |
| Phase | 언제 하는가? |
이 테이블이 왜 중요한가? 오케스트레이터를 처음 읽는 사람이 전체 팀 구조를 10초 안에 파악할 수 있기 때문이다. 워크플로우의 상세 내용은 뒤에 나오지만, 테이블만으로도 “3명의 에이전트가 4개 Phase로 동작하는구나”라는 큰 그림이 보인다.
테이블 읽는 법
테이블에서 읽어내야 할 핵심 정보는 네 가지다.
첫째, 팀 규모와 역할 분담. 에이전트가 몇 명이고, 각각 무엇을 담당하는지 파악한다. 역할이 겹치는 에이전트가 있다면 설계를 재검토할 필요가 있다.
둘째, 모델 선택의 의도. 대부분의 에이전트는 sonnet을 사용한다. 특정 에이전트만 opus를 사용한다면, 그 에이전트의 작업이 더 높은 추론 능력이나 긴 텍스트 생성을 필요로 한다는 의미다. 예를 들어 book-writer 하네스에서는 chapter-writer만 opus를 사용한다. 긴 텍스트 창작이 필요한 유일한 에이전트이기 때문이다.
셋째, Phase 흐름. Phase 컬럼의 숫자를 따라가면 전체 실행 순서가 보인다. 숫자가 순차적이면 파이프라인 구조, 같은 Phase에 여러 에이전트가 배치되면 병렬 실행을 암시한다.
넷째, 재등장하는 에이전트. 한 에이전트가 여러 Phase에 등장하면(예: code-reviewer가 Phase 1, 4에 모두 참여), 생성-검증 루프를 암시한다. Phase 1에서 초기 리뷰를 하고, Phase 4에서 수정본을 재리뷰하는 패턴이다.
실제 book-writer 하네스의 에이전트 구성 테이블을 보자.
## 에이전트 팀 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `book-planner` | 목차/구조 설계 | sonnet | 1 |
| `chapter-writer` | 챕터 집필 | opus | 2, 3 |
| `book-editor` | 원고 리뷰/편집 | sonnet | 3 |
| `infographic-creator` | SVG 인포그래픽 | sonnet | 4 |
| `book-publisher` | PDF + 웹 뷰어 | sonnet | 5 |이 테이블에서 읽어낼 수 있는 정보:
- 5명의 에이전트가 5개 Phase로 동작한다.
chapter-writer만 opus를 사용한다. 긴 텍스트 창작이 필요한 유일한 에이전트이기 때문이다.- Phase 3에 두 에이전트가 참여한다. 이것은 리뷰 루프(생성-검증 패턴)를 암시한다.
- Phase 1 → 2 → 3 → 4 → 5 순서로 파이프라인 구조다.
테이블 하나에 이만큼의 정보가 담긴다. 메타 스킬이 생성한 오케스트레이터를 처음 열었을 때, 이 테이블부터 읽으면 전체 그림이 빠르게 잡힌다.
테이블의 규칙
에이전트 이름은 백틱으로 감싼다. 코드로 취급되는 식별자임을 시각적으로 표시하기 위해서다. 이 이름은 .claude/agents/ 디렉토리의 파일명과 일치해야 한다. code-reviewer라고 썼으면 .claude/agents/code-reviewer.md 파일이 존재해야 한다.
Phase 컬럼에는 숫자를 쓴다. “리뷰 단계”가 아니라 “Phase 1”로 쓴다. 워크플로우 섹션과 정확히 대응되어야 하기 때문이다.
한 에이전트가 여러 Phase에 등장할 수 있다. 이 경우 Phase 컬럼에 “1, 4”처럼 콤마로 나열한다.
역할은 한 줄로 쓴다. 상세한 역할 정의는 에이전트 파일에 있다. 테이블에서는 이 에이전트가 이 팀에서 어떤 포지션인지만 알 수 있으면 된다.
디렉토리 구조와 파일 기반 통신
오케스트레이터의 두 번째 핵심 섹션은 디렉토리 구조다. 에이전트들은 메모리를 공유하지 않는다. 에이전트 A가 파일을 생성하면, 에이전트 B가 그 파일을 읽어서 작업한다. 이것이 파일 기반 통신이다.
왜 파일인가? Claude Code의 에이전트 호출 구조에서는 각 에이전트가 독립적인 세션으로 실행된다. 한 에이전트의 컨텍스트(대화 내역, 분석 결과 등)는 다른 에이전트에게 자동으로 전달되지 않는다. 에이전트 간에 정보를 전달할 수 있는 유일한 채널은 파일 시스템이다.
메타 스킬이 생성한 오케스트레이터를 열어보면, 디렉토리 구조가 다음과 같이 정의되어 있다.
## 디렉토리 구조
quality-reports/
├── reviews/ # Phase 1: 코드 리뷰 결과
│ └── review-{대상}.md
├── tests/ # Phase 2: 테스트 코드
│ └── test_{대상}.py
├── fixes/ # Phase 3: 수정 사항
│ └── fix-{대상}.md
└── summary/ # 최종 요약
└── quality-report.md이 디렉토리 구조는 에이전트 간의 통신 계약(contract)이다. “Phase 1의 산출물은 reviews/review-{대상}.md에 저장한다”는 약속이 있으면, Phase 2의 에이전트는 정확히 어디를 읽어야 하는지 안다.
디렉토리 구조 설계의 3가지 원칙
메타 스킬이 디렉토리 구조를 생성할 때 따르는 원칙이 있다. 커스터마이징할 때도 이 원칙을 유지해야 한다.
원칙 1: Phase별 디렉토리를 만든다. 하나의 Phase가 하나의 디렉토리에 산출물을 저장한다. Phase가 같은 디렉토리에 쓰면 산출물이 뒤섞인다. 이 분리가 있으면 “reviews/에 있는 파일은 리뷰 결과, tests/에 있는 파일은 테스트 코드”라는 것이 파일 시스템만 보고도 명확하다.
원칙 2: 파일명에 패턴을 정한다. review-{대상}.md, test_{대상}.py처럼 네이밍 규칙을 명시한다. 에이전트가 이 패턴을 따르면, 다른 에이전트가 Glob 도구로 해당 패턴의 파일을 쉽게 찾을 수 있다. 파일명 패턴이 없으면 에이전트 A는 review-result.md라고 저장하고, 에이전트 B는 reviews/auth-review.md를 찾으려 한다. 파일을 못 찾아서 실패하거나, 엉뚱한 파일을 읽게 된다.
원칙 3: 최종 산출물과 중간 산출물을 분리한다. 사용자에게 전달되는 최종 결과물과 에이전트 간 통신용 중간 파일을 구분한다. 위 예시에서 summary/quality-report.md는 최종 산출물이고, reviews/와 fixes/는 중간 산출물이다. 이 분리가 있으면 사용자는 summary/만 보면 되고, 디버깅이 필요할 때만 중간 산출물을 확인한다.
이 원칙들이 지켜지면 한 가지 부수적인 이점도 생긴다: 점진적 재실행이 가능해진다. Phase 2가 실패했을 때 Phase 1부터 다시 시작할 필요가 없다. reviews/ 디렉토리에 Phase 1의 산출물이 온전히 남아 있으므로, Phase 2만 재실행하면 된다.
파일 기반 통신의 3가지 규칙
디렉토리 구조가 잡혔으면, 에이전트가 파일을 주고받을 때 따라야 할 규칙이 있다.
규칙 1: 산출물 파일의 위치와 이름을 고정한다. 오케스트레이터에서 각 Phase의 출력을 명시할 때, 정확한 파일 경로를 지정한다.
# 나쁜 예 — 위치가 모호
- **출력**: 리뷰 결과 파일
# 좋은 예 — 위치가 명확
- **출력**: `reviews/review-{대상}.md`규칙 2: 파일 형식을 통일한다. 중간 산출물은 가능하면 마크다운으로 통일한다. 이유는 두 가지다.
- AI가 가장 잘 읽고 쓰는 형식이다. Claude Code는 마크다운을 네이티브하게 이해한다. JSON이나 YAML보다 자연스럽게 구조화된 정보를 담을 수 있다.
- 사람도 읽을 수 있다. 디버깅할 때 중간 산출물을 열어봐야 하는데, 마크다운이면 별도 도구 없이 바로 읽을 수 있다.
물론 예외는 있다. 테스트 코드는 .py나 .ts로, 설정 파일은 .json으로 저장해야 한다. “에이전트 간 통신을 위한 중간 산출물”은 마크다운, “프로젝트의 실제 코드”는 해당 언어의 파일 형식을 사용한다.
규칙 3: 산출물에 메타 정보를 포함한다. 에이전트 B가 에이전트 A의 산출물을 읽을 때, 그 파일이 어떤 맥락에서 생성되었는지 알아야 한다. 산출물 파일의 상단에 메타 정보를 포함하면 이 문제가 해결된다.
# 코드 리뷰: auth-service
- 리뷰 대상: src/auth/token.py, src/auth/session.py
- 리뷰 일시: 2026-03-15
- 리뷰어: code-reviewer (sonnet)
## 요약
- CRITICAL: 1개
- WARNING: 3개
- SUGGESTION: 2개
## 상세 리뷰
...이 메타 정보가 있으면 에이전트 B는 “어떤 파일을 대상으로 한 리뷰인지”, “어떤 에이전트가 작성한 건지” 즉시 파악할 수 있다. 또한 사람이 디버깅할 때도 유용하다.
Phase별 워크플로우
오케스트레이터의 핵심은 워크플로우다. 에이전트 구성 테이블이 “누가 참여하는가”를 보여준다면, 워크플로우는 “어떤 순서로, 무엇을 주고받으며, 어떻게 검증하는가”를 정의한다.
메타 스킬이 생성한 오케스트레이터의 워크플로우를 열어보면, 각 Phase는 다음과 같은 형식으로 되어 있다.
### Phase 1: 코드 리뷰
- **에이전트**: `code-reviewer`
- **입력**: 리뷰 대상 코드 (파일 경로 또는 PR 번호)
- **처리**: `code-review` 스킬의 워크플로우에 따라 코드 분석
- **출력**: `reviews/review-{대상}.md`
- **검증**: 리뷰 결과에 심각도별 이슈가 분류되어 있는지 확인일반 스킬의 Phase와 구조는 동일하다. 입력, 처리, 출력, 검증의 4가지를 명시한다. 다만 오케스트레이터의 Phase에는 한 가지가 추가된다: 에이전트 지정. 일반 스킬에서는 해당 스킬을 호출한 에이전트가 모든 Phase를 수행하지만, 오케스트레이터에서는 Phase마다 다른 에이전트가 실행될 수 있으므로, 어떤 에이전트가 이 Phase를 담당하는지 명시해야 한다.
입력과 출력의 연쇄
오케스트레이터에서 가장 중요한 설계 원칙은 “앞 Phase의 출력이 다음 Phase의 입력”이라는 것이다.
Phase 1 출력: reviews/review-auth.md
↓
Phase 2 입력: reviews/review-auth.md ← 동일한 파일
↓
Phase 2 출력: tests/test_auth.py
↓
Phase 3 입력: reviews/review-auth.md + tests/test_auth.py ← 누적
이 연쇄가 끊기면 워크플로우가 멈춘다. Phase 2가 reviews/review-auth.md를 입력으로 기대하는데, Phase 1이 review_auth_result.txt로 저장했다면? Phase 2는 입력을 찾지 못한다.
따라서 메타 스킬이 생성한 워크플로우를 확인할 때는 모든 Phase의 입력/출력이 디렉토리 구조와 일치하는지 반드시 점검해야 한다. 이것은 마치 함수의 반환 타입이 다음 함수의 매개변수 타입과 맞아야 하는 것과 같다. 타입이 안 맞으면 컴파일 에러가 나듯, 파일 경로가 안 맞으면 워크플로우가 실패한다.
검증의 2레벨
Chapter 4에서 스킬의 Phase마다 검증 기준을 넣어야 한다고 배웠다. 오케스트레이터에서는 검증이 두 가지 레벨로 작동한다.
레벨 1: 에이전트 수준 검증. 개별 에이전트가 자기 산출물을 스스로 점검한다. 이것은 해당 에이전트의 스킬에 정의된 검증 기준이다. 예를 들어 코드 리뷰어가 “모든 변경 파일이 분석되었는지” 확인하는 것이다.
레벨 2: 오케스트레이터 수준 검증. Phase 간 전환 시점에서 오케스트레이터가 추가로 점검한다. 이것은 에이전트 간의 인터페이스가 올바른지 확인하는 것이다. 예를 들어 “Phase 1의 산출물 파일이 실제로 존재하는지”, “파일 형식이 다음 Phase가 기대하는 구조인지” 확인한다.
### Phase 1: 코드 리뷰
- **에이전트**: `code-reviewer`
- ...
- **검증**:
- [에이전트 수준] 모든 변경 파일이 분석되었는지
- [오케스트레이터 수준] `reviews/review-{대상}.md` 파일이 생성되었는지실제 오케스트레이터에서 반드시 이렇게 두 레벨을 구분하여 태깅할 필요는 없다. 다만 오케스트레이터를 읽거나 수정할 때 “에이전트 자체의 품질 검증”과 “Phase 간 연결 검증”을 모두 고려하고 있는지 점검해야 한다.
“각 Phase 완료 후 사용자 확인” 패턴
메타 스킬이 생성한 오케스트레이터에는 반드시 포함되는 패턴이 있다. 각 Phase가 완료될 때마다 사용자에게 확인을 받는 것이다.
## 실행 방법
Phase 1: code-reviewer → reviews/ 생성 → **사용자 확인**
Phase 2: test-writer → tests/ 생성 → **사용자 확인**
Phase 3: code-fixer → fixes/ 생성 → **사용자 확인**
Phase 4: 최종 요약 → summary/ 생성 → **사용자 확인**왜 매번 확인을 받아야 할까? 자동으로 Phase 1 → 2 → 3 → 4를 쭉 실행하면 더 효율적이지 않은가? 세 가지 이유가 있다.
이유 1: 오류의 증폭을 방지한다
Phase 1에서 리뷰가 잘못되면, Phase 2의 테스트 코드도 잘못된 리뷰를 기반으로 작성된다. Phase 3의 수정도 잘못된 방향으로 진행된다. 최종 보고서를 보고 “처음부터 잘못되었구나”라고 발견하면, 모든 Phase를 처음부터 다시 해야 한다.
Phase 1 완료 후 사용자가 리뷰 결과를 확인하면, 잘못된 방향을 즉시 교정할 수 있다. “이 부분은 의도한 설계니까 이슈에서 빼줘”라고 피드백하면, Phase 2부터는 올바른 기반 위에서 진행된다.
이유 2: AI의 판단을 사람이 검증한다
AI는 코드를 분석하고 이슈를 찾지만, 도메인 맥락은 사람이 더 잘 안다. “이 코드가 복잡한 건 성능 최적화 때문”이라는 배경 지식은 AI에게 없을 수 있다. 사용자 확인은 AI의 분석에 도메인 지식을 주입하는 기회다.
이유 3: 비용을 통제한다
에이전트 호출에는 API 비용이 발생한다. Phase 1 결과가 불만족스러우면 Phase 2 이후를 실행할 필요가 없다. Phase 1만 재실행하면 된다. 자동 실행이면 불필요한 Phase까지 모두 실행되어 비용이 낭비된다.
사용자 확인이 오케스트레이터에 명시되는 방식
메타 스킬이 생성한 오케스트레이터에서는 사용자 확인이 두 곳에 명시된다. 워크플로우의 각 Phase에 구체적인 확인 내용이 들어가고:
### Phase 1: 코드 리뷰
- **에이전트**: `code-reviewer`
- **입력**: 리뷰 대상 코드
- **출력**: `reviews/review-{대상}.md`
- **검증**: 리뷰 결과 파일이 존재하고, 심각도별 이슈가 분류되어 있는지
- **사용자 확인**: 리뷰 결과를 사용자에게 보여주고, 수정/보완 요청을 반영한 후 다음 Phase로 진행실행 방법 섹션에 전체 원칙이 일괄 명시된다:
## 실행 방법
각 Phase 완료 후 사용자 확인을 받고 다음 Phase로 진행.
사용자가 재작업을 요청하면 해당 Phase를 재실행한다.이 두 곳을 모두 확인해야 한다. Phase별 검증 섹션에서는 해당 Phase의 구체적인 확인 내용을, 실행 방법 섹션에서는 전체 원칙을 파악한다.
예제: “코드 품질 관리” 오케스트레이터
지금까지 설명한 개념을 실제 오케스트레이터에서 확인하자. 다음은 메타 스킬이 생성한 “코드 품질 관리” 오케스트레이터의 완성된 모습이다. .claude/skills/code-quality/SKILL.md에 위치한다.
---
name: code-quality
description: "코드 품질 관리 오케스트레이터. 에이전트 팀을 조율하여 코드 리뷰, 테스트, 수정을 수행합니다.
'코드 품질', 'code quality', '품질 관리' 요청 시 트리거."
---
# Code Quality — 코드 품질 관리 오케스트레이터
에이전트 팀(code-reviewer, test-writer, code-fixer)을 조율하여
코드 변경 사항의 품질을 종합적으로 관리하는 오케스트레이터 스킬.
## 에이전트 팀 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `code-reviewer` | 코드 리뷰 | sonnet | 1, 4 |
| `test-writer` | 테스트 코드 작성 | sonnet | 2 |
| `code-fixer` | 코드 수정 | sonnet | 3 |
## 디렉토리 구조
quality-reports/
├── reviews/ # Phase 1, 4: 코드 리뷰 결과
│ ├── review-{대상}.md
│ └── re-review-{대상}.md
├── tests/ # Phase 2: 테스트 코드
│ └── test_{대상}.py
├── fixes/ # Phase 3: 수정 보고서
│ └── fix-{대상}.md
└── summary/ # Phase 5: 최종 보고서
└── quality-report.md
## 워크플로우
### Phase 1: 코드 리뷰
- **에이전트**: `code-reviewer`
- **입력**: 리뷰 대상 코드 (파일 경로 목록 또는 PR 번호)
- **처리**: `code-review` 스킬의 워크플로우에 따라 코드 분석 및 이슈 식별
- **출력**: `quality-reports/reviews/review-{대상}.md`
- **검증**: 리뷰 파일 생성 확인, 모든 대상 파일 분석 확인, 심각도 부여 확인
- **사용자 확인**: 리뷰 결과를 보여주고 이슈 목록에 동의하는지 확인
### Phase 2: 테스트 코드 작성
- **에이전트**: `test-writer`
- **입력**: `quality-reports/reviews/review-{대상}.md`
- **처리**: CRITICAL/WARNING 이슈에 대한 재현 테스트 작성, 실행하여 Red 상태 확인
- **출력**: `quality-reports/tests/test_{대상}.py`
- **검증**: 테스트 파일 생성 확인, CRITICAL 이슈 테스트 포함 확인, Red 상태 확인
- **사용자 확인**: 테스트 코드와 실행 결과 확인
### Phase 3: 코드 수정
- **에이전트**: `code-fixer`
- **입력**: `quality-reports/reviews/review-{대상}.md` + `quality-reports/tests/test_{대상}.py`
- **처리**: CRITICAL 이슈부터 순서대로 수정, 수정마다 테스트 실행
- **출력**: 수정된 소스 코드 + `quality-reports/fixes/fix-{대상}.md`
- **검증**: CRITICAL 이슈 전체 수정 확인, 테스트 Green 확인, 기존 테스트 통과 확인
- **사용자 확인**: 수정된 코드와 테스트 결과 확인
### Phase 4: 재리뷰
- **에이전트**: `code-reviewer`
- **입력**: 수정된 소스 코드 + `quality-reports/fixes/fix-{대상}.md`
- **처리**: 수정된 코드에 대해 재리뷰
- **출력**: `quality-reports/reviews/re-review-{대상}.md`
- **분기**: CRITICAL 0개 → Phase 5 / CRITICAL 존재 → Phase 3 반복
- **사용자 확인**: 재리뷰 결과 확인, 추가 수정 또는 완료 판단
### Phase 5: 최종 보고서
- **에이전트**: (오케스트레이터)
- **입력**: 전체 산출물 (`quality-reports/` 하위 전체)
- **처리**: 이슈 발견/수정/잔여 현황을 종합
- **출력**: `quality-reports/summary/quality-report.md`
- **검증**: 모든 Phase 산출물이 보고서에 반영되었는지 확인
## 실행 방법
오케스트레이터(사용자 또는 메인 Claude)가 각 Phase를 순서대로 실행:
Phase 1: Agent tool → code-reviewer → 리뷰 생성 → 사용자 확인
Phase 2: Agent tool → test-writer → 테스트 작성 → 사용자 확인
Phase 3: Agent tool → code-fixer → 코드 수정 → 사용자 확인
Phase 4: Agent tool → code-reviewer → 재리뷰 → CRITICAL 0개? → Phase 5 / Phase 3 반복
Phase 5: 최종 보고서 생성 → 사용자 확인
각 Phase 완료 후 사용자 확인을 받고 다음 Phase로 진행.
사용자가 재작업을 요청하면 해당 Phase를 재실행한다.
CRITICAL 이슈가 0개가 될 때까지 Phase 3 ↔ Phase 4를 반복한다. (최대 2회)
2회 반복 후에도 CRITICAL이 남아 있으면 사용자에게 판단을 요청한다.이 오케스트레이터의 전체 하네스 구조는 다음과 같다.
.claude/
├── agents/
│ ├── code-reviewer.md
│ ├── test-writer.md
│ └── code-fixer.md
└── skills/
├── code-review/
│ ├── SKILL.md
│ └── references/
│ ├── checklist.md
│ └── severity-guide.md
└── code-quality/ ← 오케스트레이터
└── SKILL.md
이 구조에서 주목할 점을 짚어보자.
에이전트 3명, 스킬 1개, 오케스트레이터 1개. 사용자가 “코드 품질 관리해줘”라고 요청하면, code-quality 오케스트레이터가 트리거되고, Phase 1부터 순서대로 적절한 에이전트를 호출하며 진행한다.
Phase 4에 분기가 있다. CRITICAL 이슈가 남아있으면 Phase 3으로 돌아간다. 이것이 Chapter 3에서 배운 생성-검증 패턴이다. 코드 수정(생성)과 코드 리뷰(검증)가 루프를 돌며 품질 기준을 만족할 때까지 반복한다. 단, 최대 2회로 제한하여 무한 루프를 방지한다.
Phase 5는 별도 에이전트 없이 오케스트레이터가 직접 수행한다. 최종 보고서 생성은 기존 산출물을 취합하는 단순 작업이므로, 전문 에이전트를 할당할 필요가 없다. 모든 Phase에 반드시 에이전트를 배정해야 하는 것은 아니다.
Phase 2에서 TDD의 Red 단계를 활용한다. 테스트가 현재 코드에서 실패하는지(Red) 확인하는 것은, 테스트가 실제로 이슈를 검출하는지 검증하는 방법이다. 이미 통과하는 테스트는 이슈를 재현하지 못하는 것이므로 의미가 없다.
심화: 오케스트레이터와 아키텍처 패턴의 관계
Chapter 3에서 4가지 아키텍처 패턴을 배웠다. 오케스트레이터의 워크플로우는 이 패턴들의 구체적인 구현이다. 메타 스킬이 생성한 오케스트레이터를 열어보면, 워크플로우 안에 어떤 패턴이 사용되었는지 식별할 수 있다.
파이프라인이 오케스트레이터가 되면
Phase 1 (A) → Phase 2 (B) → Phase 3 (C) → Phase 4 (D)
가장 단순한 형태다. 에이전트 A의 산출물이 B로, B의 산출물이 C로 순차 전달된다. 코드 품질 관리 오케스트레이터의 Phase 1 → 2 → 3 경로가 이것이다.
생성-검증이 오케스트레이터가 되면
Phase N (생성자) → Phase N+1 (검증자) → 기준 미달? → Phase N 반복
→ 기준 충족? → 다음 Phase
루프가 들어간다. Phase 3(code-fixer) → Phase 4(code-reviewer) → 다시 Phase 3의 경로가 이것이다. 오케스트레이터에서 생성-검증 패턴을 구현할 때 가장 중요한 것은 분기 조건과 종료 조건을 명시하는 것이다.
패턴을 조합하면
실전의 오케스트레이터는 대부분 여러 패턴의 조합이다. 코드 품질 관리 오케스트레이터는 파이프라인(Phase 1→2→3)과 생성-검증(Phase 3↔︎4)의 조합이다.
[파이프라인] [생성-검증 루프]
Phase 1 → Phase 2 → Phase 3 ↔ Phase 4 → Phase 5
book-writer 오케스트레이터도 마찬가지다. Phase 1→2→3→4→5는 파이프라인이지만, Phase 3 안에서 editor와 writer가 생성-검증 루프를 돈다.
패턴을 먼저 선택하고 오케스트레이터를 만드는 것이 아니다. 메타 스킬이 도메인의 워크플로우를 분석하여 자연스럽게 패턴을 선택한다. 패턴의 이름을 아는 것은 “지금 내가 보고 있는 것이 무엇인지” 인식하기 위해서다. 인식하면 해당 패턴에서 주의할 점(예: 생성-검증의 종료 조건)을 놓치지 않게 된다.
심화: 오케스트레이터 설계 시 흔한 실수
메타 스킬이 생성한 오케스트레이터를 커스터마이징하거나, 직접 수정할 때 자주 발생하는 실수를 정리한다.
실수 1: Phase를 너무 세분화한다
# 나쁜 예 — 8개 Phase
Phase 1: PR 정보 수집
Phase 2: diff 추출
Phase 3: 파일별 분류
Phase 4: 코드 분석
Phase 5: 이슈 분류
Phase 6: 테스트 작성
Phase 7: 코드 수정
Phase 8: 최종 보고서Phase 1~5는 모두 “코드 리뷰” 단계다. 이것은 code-review 스킬 내부의 워크플로우여야 한다. 오케스트레이터의 Phase는 에이전트 전환이 일어나는 단위다. 같은 에이전트가 연속으로 실행되는 Phase는 하나로 합쳐야 한다.
# 좋은 예 — 5개 Phase
Phase 1: 코드 리뷰 (code-reviewer)
Phase 2: 테스트 작성 (test-writer)
Phase 3: 코드 수정 (code-fixer)
Phase 4: 재리뷰 (code-reviewer)
Phase 5: 최종 보고서판단 기준: “이 Phase와 다음 Phase의 에이전트가 같은가?” 같다면 하나로 합쳐라. 세부 절차는 해당 에이전트의 스킬에 정의한다.
실수 2: 에이전트 간 의존성이 implicit하다
# 나쁜 예 — 입력이 모호
### Phase 2: 테스트 작성
- **입력**: 리뷰 결과
- **출력**: 테스트 코드“리뷰 결과”가 어디 있는 파일인지 명시되지 않았다. 에이전트가 매번 다른 위치에서 파일을 찾으려 할 수 있다.
# 좋은 예 — 입력이 명시적
### Phase 2: 테스트 작성
- **입력**: `quality-reports/reviews/review-{대상}.md`
- **출력**: `quality-reports/tests/test_{대상}.py`정확한 파일 경로를 쓴다. 모호성이 사라지고, 에이전트가 정확히 어디를 읽어야 하는지 안다.
실수 3: 종료 조건이 없는 루프
# 나쁜 예 — 종료 조건 없음
### Phase 4: 재리뷰
- CRITICAL 이슈가 있으면 Phase 3으로 돌아감CRITICAL이 계속 나오면 무한 루프에 빠진다. 반드시 최대 반복 횟수를 정하거나, 대체 종료 조건을 둔다.
# 좋은 예 — 종료 조건 있음
### Phase 4: 재리뷰
- **분기**:
- CRITICAL 0개 → Phase 5
- CRITICAL 존재 + 반복 횟수 2회 미만 → Phase 3 반복
- CRITICAL 존재 + 반복 횟수 2회 이상 → 미해결 이슈로 기록하고 Phase 5 진행이렇게 하면 최대 2회 루프 후에는 반드시 Phase 5로 진행한다. 미해결 이슈는 최종 보고서에 명시하여 사용자가 직접 판단할 수 있게 한다.
실수 4: 사용자 확인 없이 전체 자동 실행
# 나쁜 예 — 사용자 확인 없음
## 실행 방법
Phase 1 → Phase 2 → Phase 3 → Phase 4 → Phase 5를 자동으로 실행Phase 1의 리뷰가 잘못되면 이후 모든 Phase가 헛수고가 된다. 앞서 설명한 대로, 매 Phase 완료 후 사용자 확인은 필수다. 오류의 증폭을 막고, 비용을 통제하고, 도메인 지식을 주입할 수 있는 유일한 시점이다.
오케스트레이터 체크리스트
메타 스킬이 생성한 오케스트레이터를 검토하거나, 수정한 후 다음 체크리스트로 점검한다.
에이전트 팀 구성: - [ ] 모든 에이전트의 .claude/agents/{이름}.md 파일이 존재하는가? - [ ] 에이전트 구성 테이블의 이름이 파일명과 일치하는가? - [ ] 각 에이전트의 모델 선택이 작업 특성에 맞는가?
디렉토리 구조: - [ ] 모든 Phase의 산출물 저장 위치가 디렉토리 구조에 포함되어 있는가? - [ ] 파일명 패턴이 명확한가? (다른 에이전트가 Glob으로 찾을 수 있는가?) - [ ] 최종 산출물과 중간 산출물이 구분되어 있는가?
워크플로우: - [ ] 모든 Phase에 에이전트, 입력, 처리, 출력, 검증이 명시되어 있는가? - [ ] 앞 Phase의 출력 경로와 다음 Phase의 입력 경로가 일치하는가? - [ ] 루프가 있다면 종료 조건이 명시되어 있는가? - [ ] 각 Phase에 사용자 확인이 포함되어 있는가?
실행: - [ ] 실행 방법 섹션에 전체 흐름이 한눈에 보이는가? - [ ] Phase 재실행 방법이 설명되어 있는가?
정리
- 오케스트레이터는 에이전트 팀의 실행 순서, 데이터 흐름, 의사결정 분기를 정의하는 스킬이다. 일반 스킬이 “한 사람의 업무 매뉴얼”이라면, 오케스트레이터는 “팀의 작전 계획서”다.
- 에이전트 구성 테이블은 팀 전체를 한눈에 보여준다. 에이전트, 역할, 모델, Phase의 4컬럼으로 팀의 큰 그림을 10초 안에 파악할 수 있다.
- 디렉토리 구조는 에이전트 간의 통신 계약이다. Phase별 디렉토리, 파일명 패턴, 최종/중간 산출물 분리의 3가지 원칙을 따른다.
- 파일 기반 통신은 에이전트 간 정보 전달의 유일한 채널이다. 위치 고정, 형식 통일, 메타 정보 포함의 3가지 규칙을 따른다.
- 워크플로우의 각 Phase에는 에이전트, 입력, 처리, 출력, 검증을 명시한다. 앞 Phase의 출력 경로와 다음 Phase의 입력 경로가 반드시 일치해야 한다. 검증은 에이전트 수준과 오케스트레이터 수준의 2레벨로 작동한다.
- 각 Phase 완료 후 사용자 확인은 필수 패턴이다. 오류 증폭 방지, AI 판단의 검증, 비용 통제를 위해 반드시 포함한다.
- 루프가 있는 워크플로우에는 종료 조건을 반드시 명시한다. 최대 반복 횟수를 정하여 무한 루프를 방지한다.
- 오케스트레이터의 워크플로우는 Chapter 3의 아키텍처 패턴(파이프라인, 생성-검증 등)의 구체적인 구현이다. 실전에서는 여러 패턴이 조합된다.
다음 챕터 미리보기
- Chapter 6에서는 이 책 자체를 만든 book-writer 하네스의 전체 구조를 해부한다. 5명의 에이전트, 5개 Phase의 워크플로우, 파이프라인과 생성-검증 패턴의 조합을 실제 파일을 열어보며 분석한다. 이 챕터에서 배운 오케스트레이터 구조가 실전에서 어떻게 적용되는지 확인하는 챕터다.
Chapter 6: 사례 1 — 책 집필 하네스 (파이프라인 + 생성-검증)
이 챕터에서 배울 것
- book-writer 하네스의 전체 구조와 5명의 에이전트가 어떻게 협업하는지
- 파이프라인 패턴(Phase 1→2→4→5)과 생성-검증 패턴(Phase 3)이 하나의 하네스에서 어떻게 조합되는지
- 각 에이전트 정의 파일의 핵심 설계 결정과 그 이유
- 오케스트레이터 스킬(SKILL.md)이 에이전트 간 데이터 흐름을 어떻게 관리하는지
- 산출물 디렉토리 구조와 파일 네이밍 규칙의 설계 원칙
- book-writer 하네스를 처음부터 재현하며 구축하는 과정
본문
이 책은 어떻게 만들어졌는가
이 챕터는 메타적이다. 지금 읽고 있는 이 책 자체가 book-writer 하네스로 만들어졌다. Chapter 1의 개념 설명도, Chapter 3의 패턴 분석도, 지금 이 문장도 — 모두 5명의 에이전트가 협업한 결과물이다.
book-planner가 목차를 설계했고, chapter-writer가 본문을 집필했고, book-editor가 리뷰했고, infographic-creator가 다이어그램을 그렸고, book-publisher가 PDF와 웹 뷰어로 변환한다. 이 과정을 조율한 것이 book-writer 오케스트레이터 스킬이다.
이 챕터에서는 이 하네스의 전체 구조를 해부한다. Chapter 3에서 배운 패턴이 실전에서 어떻게 조합되는지, Part 2에서 배운 에이전트/스킬/오케스트레이터 작성법이 실제로 어떻게 적용되었는지를 하나씩 확인한다.
인포그래픽: book-writer 하네스 전체 아키텍처
book-writer 하네스 전체 구조
에이전트 팀 구성
book-writer 하네스는 5명의 에이전트로 구성된다.
| 에이전트 | 역할 | 모델 | Phase |
|---|---|---|---|
book-planner |
목차/구조 설계 | sonnet | 1 |
chapter-writer |
챕터 집필 | opus | 2, 3 |
book-editor |
원고 리뷰/편집 | sonnet | 3 |
infographic-creator |
SVG 인포그래픽 | sonnet | 4 |
book-publisher |
PDF + 웹 뷰어 | sonnet | 5 |
이 구성에서 눈여겨볼 점이 세 가지 있다.
첫째, opus는 chapter-writer에만 사용한다. 5명 중 4명이 sonnet이고, opus는 집필 에이전트 하나뿐이다. 이유는 명확하다 — 집필은 가장 높은 창의성과 맥락 이해를 요구하는 작업이다. 목차 설계, 리뷰, SVG 생성, 조판은 규칙 기반 작업이므로 sonnet으로 충분하다. Chapter 4에서 배운 “비용 대비 품질” 원칙이 여기에 적용된다.
둘째, chapter-writer는 두 개 Phase에 걸쳐 참여한다. Phase 2에서 초안을 쓰고, Phase 3에서 편집자의 피드백을 받아 수정한다. 하나의 에이전트가 여러 Phase에 참여하는 것은 자연스럽다 — 글을 쓴 사람이 수정도 하는 것이 당연하기 때문이다.
셋째, 에이전트 분리 기준이 명확하다. Chapter 2에서 배운 4가지 기준을 대입해보면:
| 기준 | 적용 |
|---|---|
| 전문성 | 기획자, 작가, 편집자, 디자이너, 출판 기술자 — 각자 전문 영역이 다르다 |
| 병렬성 | infographic-creator는 챕터별로 병렬 실행할 수 있다 |
| 컨텍스트 부담 | 집필 원칙과 리뷰 체크리스트를 하나의 컨텍스트에 넣으면 과부하 |
| 재사용성 | book-editor는 다른 글쓰기 하네스에서도 재사용 가능 |
5명이라는 수가 임의적인 것이 아니라, 각 기준에 의해 자연스럽게 도출된 결과다.
디렉토리 구조
프로젝트/
├── .claude/
│ ├── agents/
│ │ ├── book-planner.md
│ │ ├── chapter-writer.md
│ │ ├── book-editor.md
│ │ ├── infographic-creator.md
│ │ └── book-publisher.md
│ └── skills/
│ └── book-writer/
│ └── SKILL.md # 오케스트레이터
├── book/
│ ├── outline.md # Phase 1 산출물
│ ├── chapters/ # Phase 2~3 산출물
│ │ ├── ch01-agent-and-skill.md
│ │ ├── ch02-harness-concept.md
│ │ └── ...
│ ├── assets/ # Phase 4 산출물
│ │ ├── infographic-ch01-agent-vs-skill.svg
│ │ └── ...
│ └── output/ # Phase 5 산출물
│ ├── pdf/
│ │ └── harness-engineering-guide.pdf
│ └── web/
│ └── index.html
이 구조에서 주목할 점은 Phase별로 산출물 위치가 분리되어 있다는 것이다. outline.md는 Phase 1, chapters/는 Phase 2~3, assets/는 Phase 4, output/는 Phase 5의 결과물이 저장된다. 이렇게 하면 어떤 Phase에서 문제가 생겼을 때, 해당 디렉토리만 확인하면 된다.
파일 네이밍에도 규칙이 있다:
| 산출물 | 네이밍 규칙 | 예시 |
|---|---|---|
| 목차 | outline.md (단일 파일) |
book/outline.md |
| 챕터 | ch{NN}-{slug}.md |
ch07-case-book-writing.md |
| 인포그래픽 | infographic-ch{NN}-{slug}.svg |
infographic-ch07-book-writer-architecture.svg |
{책-제목}.pdf |
harness-engineering-guide.pdf |
|
| 웹 뷰어 | index.html |
output/web/index.html |
{NN}은 두 자리 숫자로 챕터 번호를, {slug}는 하이픈으로 구분된 영문 키워드를 사용한다. 이 규칙 덕분에 파일을 정렬하면 자연스럽게 챕터 순서가 된다.
Phase 1~5 워크플로우 상세 분석
전체 흐름
Phase 1 Phase 2 Phase 3 Phase 4 Phase 5
[planner] → [writer] → [editor↔writer] → [infographic] → [publisher]
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
outline.md ch{NN}.md 수정된 ch{NN}.md SVG 파일들 PDF + 웹
(초안) (승인된 원고)
큰 틀은 파이프라인이다. Phase 1의 출력이 Phase 2의 입력이 되고, Phase 2의 출력이 Phase 3의 입력이 되는 식으로 순차적으로 흐른다. 하지만 Phase 3 내부에는 생성-검증 루프가 내포되어 있다. Chapter 3에서 다룬 “패턴 조합”의 전형적인 사례다.
각 Phase를 상세히 분석하자.
Phase 1: 목차 설계 (파이프라인)
### Phase 1: 목차 설계
- **에이전트**: `book-planner`
- **입력**: 책 주제, 대상 독자, 요구사항
- **출력**: `book/outline.md` (목차 + 챕터별 명세)
- **검증**: 사용자가 목차를 확인하고 승인Phase 1은 전체 파이프라인의 첫 단계다. book-planner가 책의 전체 설계도를 만든다.
이 Phase에서 가장 중요한 것은 출력의 구체성이다. outline.md가 단순히 “Chapter 1: 소개”라고만 적혀 있으면, 뒤이어 집필하는 chapter-writer가 무엇을 어떻게 써야 할지 모른다. 실제 outline.md에는 각 챕터의 목표, 핵심 내용, 예제, 분량이 구체적으로 명시된다.
#### Chapter 6: 사례 1 — 책 집필 하네스 (파이프라인 + 생성-검증)
- 목표: 이 책을 만든 book-writer 하네스의 전체 구조를 이해하고,
복합 패턴 설계를 할 수 있다
- 핵심 내용:
- book-writer 하네스 전체 구조 분석
- 5명의 에이전트: book-planner, chapter-writer, book-editor, ...
- Phase 1~5 워크플로우 상세 분석
- ...
- 예제: book-writer 하네스를 처음부터 재현하며 구축
- 분량: 16~18페이지이것이 chapter-writer에게 전달되는 “작업 지시서”다. 목표가 무엇이고, 어떤 내용을 다뤄야 하고, 어떤 예제가 필요하고, 몇 페이지를 써야 하는지가 명시되어 있다. 뒤에서 살펴볼 book-planner 에이전트의 출력 형식이 이 구조를 강제한다.
검증 방법은 사용자 확인이다. 목차 품질은 주관적 판단이 필요하기 때문에, AI가 자동으로 검증하기보다 사람이 확인하는 것이 적절하다. 이것이 “각 Phase 완료 후 사용자 확인을 받고 다음 Phase로 진행”이라는 원칙의 첫 적용이다.
Phase 2: 챕터 집필 (파이프라인)
### Phase 2: 챕터 집필
- **에이전트**: `chapter-writer`
- **입력**: `book/outline.md`의 챕터별 명세
- **출력**: `book/chapters/ch{NN}-{slug}.md`
- **방식**: 한 챕터씩 순차 집필
- **검증**: 각 챕터 파일이 챕터 구조를 따르는지 확인Phase 2는 파이프라인의 핵심 단계다. chapter-writer가 outline.md의 명세를 읽고 챕터를 하나씩 집필한다.
“한 챕터씩 순차 집필”이라는 방식에 의문이 들 수 있다. 각 챕터가 독립적이라면 팬아웃/팬인으로 병렬 집필할 수도 있지 않은가? 이론적으로는 가능하지만, 실전에서는 세 가지 이유로 순차가 낫다.
첫째, 챕터 간 참조. Chapter 7이 “Chapter 3에서 배운 패턴”을 언급하려면, Chapter 3의 내용을 알아야 한다. 앞 챕터의 내용이 뒤 챕터에 영향을 미치므로 완전한 독립이 아니다.
둘째, 용어 일관성. “하네스”, “오케스트레이터”, “에이전트” 같은 핵심 용어의 정의와 사용법이 챕터 간에 일관되어야 한다. 병렬로 작성하면 같은 개념을 다른 용어로 설명할 위험이 있다.
셋째, 난이도 곡선. 기술서적은 점진적으로 난이도를 높여가야 한다. 순차 집필이면 앞 챕터의 수준을 확인하면서 다음 챕터의 난이도를 조절할 수 있다.
검증은 구조적 검증이다. 챕터가 chapter-writer의 정의에 명시된 구조(이 챕터에서 배울 것 → 본문 → 정리 → 다음 챕터 미리보기)를 따르는지 확인한다. 내용의 정확성은 Phase 3에서 검증한다.
Phase 3: 리뷰 루프 (생성-검증)
### Phase 3: 리뷰 루프 (생성-검증)
- **에이전트**: `book-editor` → `chapter-writer`
- **입력**: 완성된 챕터
- **프로세스**:
1. `book-editor`가 챕터 리뷰
2. CRITICAL 이슈가 있으면 `chapter-writer`에게 수정 요청
3. 수정본을 `book-editor`가 재리뷰
4. CRITICAL 이슈 0개일 때 승인
- **검증**: 모든 챕터가 편집자 승인을 받음Phase 3은 이 하네스의 핵심이다. 파이프라인 안에 생성-검증 패턴이 내포된 지점이다.
흐름을 도식화하면 이렇다:
[chapter-writer]가 ch01.md 작성 (Phase 2)
│
▼
[book-editor]가 ch01.md 리뷰
│
├─ CRITICAL 0개 → 승인 → ch02로 이동
│
└─ CRITICAL 1개 이상
│
▼
피드백 전달 → [chapter-writer]가 ch01.md 수정
│
▼
[book-editor]가 수정본 재리뷰
│
├─ CRITICAL 0개 → 승인
└─ CRITICAL 1개 이상 → 재수정 (반복)
Chapter 3의 생성-검증 패턴에서 배운 세 가지 설계 결정이 모두 적용되어 있다.
심각도 분류. book-editor는 이슈를 CRITICAL, WARNING, SUGGESTION으로 분류한다. 루프 종료 조건은 “CRITICAL 이슈 0개”다. 문체나 표현의 소소한 개선(SUGGESTION)은 루프를 돌릴 이유가 되지 않는다.
역할 분리. chapter-writer(opus)는 창의적 집필에 집중하고, book-editor(sonnet)는 냉정한 평가에 집중한다. 같은 에이전트가 쓰면서 동시에 리뷰하는 것보다 역할이 분리되어야 품질이 높아진다. Chapter 2에서 다룬 “역할 충돌” 문제의 해법이다.
루프 종료 보장. 오케스트레이터에 최대 반복 횟수를 설정할 수 있다. 3번의 수정으로도 CRITICAL이 해결되지 않으면, 사용자에게 에스컬레이션한다.
Phase 4: 인포그래픽 생성 (파이프라인, 잠재적 팬아웃)
### Phase 4: 인포그래픽 생성
- **에이전트**: `infographic-creator`
- **입력**: 각 챕터에서 시각화가 필요한 개념
- **출력**: `book/assets/infographic-ch{NN}-{slug}.svg`
- **방식**: 챕터별 병렬 생성 가능
- **검증**: SVG 파일이 유효하고 챕터에서 참조됨Phase 4는 파이프라인의 한 단계이면서, 내부적으로는 팬아웃/팬인이 가능한 구조다. 각 챕터의 인포그래픽은 서로 독립적이므로 동시에 생성할 수 있다.
“챕터별 병렬 생성 가능”이라는 문구에 주목하자. “가능”이라고 한 것은, 병렬이 필수는 아니기 때문이다. Agent tool의 동시 호출 수에 따라 순차로 진행할 수도 있고, 여러 개를 동시에 생성할 수도 있다. 오케스트레이터가 상황에 따라 유연하게 결정할 수 있는 여지를 남긴 것이다.
검증은 두 가지다: SVG 파일이 유효한 형식인지(파싱 가능한지), 해당 SVG가 챕터 본문에서 실제로 참조되는지. 인포그래픽을 만들어놓고 아무 챕터에서도 언급하지 않으면, 그 인포그래픽은 독자에게 도달하지 못한다.
Phase 5: 출판 (파이프라인)
### Phase 5: 출판
- **에이전트**: `book-publisher`
- **입력**: 완성된 챕터들 + SVG 에셋
- **출력**:
- `book/output/pdf/harness-engineering-guide.pdf`
- `book/output/web/index.html`
- **검증**: PDF가 정상 생성되고 웹 뷰어에서 페이지 넘김 동작Phase 5는 파이프라인의 마지막 단계다. 앞선 4개 Phase의 모든 산출물을 모아 최종 결과물로 변환한다.
이 Phase에서 book-publisher가 받는 입력은 두 종류다: book/chapters/ 디렉토리의 마크다운 파일들과, book/assets/ 디렉토리의 SVG 파일들. 서로 다른 Phase의 산출물이 하나의 Phase에서 통합된다. 이것이 파이프라인에서 “분기 후 합류”가 일어나는 지점이다.
검증도 두 종류다: PDF가 정상 생성되었는지(파일이 존재하고 열리는지), 웹 뷰어가 동작하는지(페이지 넘김이 되는지). 기술적 검증이므로 자동화할 수 있다.
파이프라인과 생성-검증의 조합 분석
전체 워크플로우에서 패턴이 어떻게 조합되는지 정리하자.
Phase 1: 목차 설계 → 파이프라인 (순차)
Phase 2: 챕터 집필 → 파이프라인 (순차)
Phase 3: 리뷰 루프 → 생성-검증 (루프)
Phase 4: 인포그래픽 생성 → 파이프라인 (잠재적 팬아웃)
Phase 5: 출판 → 파이프라인 (순차)
큰 틀은 Phase 1 → 2 → 3 → 4 → 5라는 파이프라인이다. 각 Phase는 앞 Phase의 산출물에 의존한다. Phase 2는 outline.md가 없으면 시작할 수 없고, Phase 5는 챕터와 SVG가 없으면 시작할 수 없다.
이 파이프라인 안에서 Phase 3이 생성-검증 패턴으로 동작한다. 파이프라인의 직선적 흐름 중간에 루프가 삽입된 구조다. Phase 2에서 넘어온 초안이 Phase 3의 루프를 통과하면, 비로소 Phase 4로 넘어간다.
Chapter 3에서 배운 “큰 틀은 파이프라인으로, 각 Phase 안에서 다른 패턴을 적용”하는 원칙이 그대로 적용된 것이다.
왜 이런 조합이 필요한가? 각 패턴의 장점을 조합하기 위해서다:
| 패턴 | 이 하네스에서의 역할 |
|---|---|
| 파이프라인 | Phase 간 순서와 데이터 흐름을 보장 |
| 생성-검증 | 원고 품질을 자동으로 개선 |
파이프라인만으로는 품질 보장이 안 되고, 생성-검증만으로는 전체 워크플로우를 관리할 수 없다. 두 패턴의 결합이 “순서도 보장하고 품질도 보장하는” 하네스를 만든다.
각 에이전트의 정의 파일 해부
이제 5명의 에이전트 정의 파일을 하나씩 분석한다. Chapter 4에서 배운 에이전트 파일의 구조(frontmatter + 핵심 역할 + 작업 원칙 + 출력 형식 + 협업)가 실제로 어떻게 적용되었는지 확인하자.
book-planner: 목차/구조 설계 전문가
---
name: book-planner
description: "책의 목차와 구조를 설계하는 에이전트.
'목차 설계', '책 구조', 'book plan' 요청 시 트리거."
model: sonnet
---모델 선택: sonnet. 목차 설계는 정해진 형식에 맞춰 구조화하는 작업이다. 창의적 표현보다는 논리적 구성력이 핵심이므로 sonnet이 적합하다.
핵심 역할 4가지를 보자:
- 독자 분석: 대상 독자의 수준과 기대를 파악
- 목차 설계: 논리적 흐름을 가진 챕터 구조 설계
- 챕터 명세: 각 챕터의 목표, 핵심 내용, 예상 분량 정의
- 학습 경로: 초보자가 따라갈 수 있는 점진적 난이도 구성
역할이 “무엇을 분석하라”가 아니라 “무엇을 만들어라”로 서술되어 있다. “독자 분석”의 결과물, “목차 설계”의 결과물이 명확하다. Chapter 4에서 배운 “행동 가능한 역할 서술” 원칙이 적용된 것이다.
작업 원칙에서 주목할 것은 “예제 중심(Hands-on) 구조를 우선”이라는 항목이다. 이 원칙 하나가 전체 책의 성격을 결정한다. book-planner가 이 원칙을 따르기 때문에, outline.md의 모든 챕터에 “예제” 항목이 포함된다.
출력 형식이 마크다운 템플릿으로 명시되어 있다는 점도 중요하다. 챕터 명세에 “목표”, “핵심 내용”, “예제”, “분량”이 반드시 포함되도록 강제한다. 이 형식 덕분에 chapter-writer가 받는 입력의 품질이 일정하게 유지된다.
chapter-writer: 챕터 집필 전문가
---
name: chapter-writer
description: "책의 챕터를 집필하는 에이전트.
'챕터 작성', '집필', 'write chapter' 요청 시 트리거."
model: opus
---모델 선택: opus. 유일하게 opus를 사용하는 에이전트다. 집필은 복잡한 개념을 쉽게 설명하고, 비유를 만들고, 예제를 구성하는 창의적 작업이다. 이 부분에서 비용을 아끼면 책 전체의 품질이 떨어진다.
핵심 설계 결정은 챕터 구조의 명시다:
## 챕터 구조
# Chapter {N}: {제목}
## 이 챕터에서 배울 것
- bullet points
## 본문
### 개념 설명
### 실습: {예제 제목}
### 심화: {고급 주제}
## 정리
- 핵심 요약 (3-5줄)
## 다음 챕터 미리보기
- 다음에 배울 내용 한 줄 소개이 구조가 에이전트 정의에 명시되어 있기 때문에, 12개 챕터 모두 동일한 패턴을 따른다. “이 챕터에서 배울 것”으로 시작하고, “다음 챕터 미리보기”로 끝나는 일관성이 독자 경험을 높인다.
작업 원칙에서 “왜 이렇게 하는가를 항상 설명”이라는 항목이 눈에 띈다. 기술서적에서 가장 흔한 실수가 “무엇(what)”만 설명하고 “왜(why)”를 빠뜨리는 것이다. 이 원칙이 있기 때문에 chapter-writer는 모든 설계 결정에 대해 이유를 설명한다. 지금 이 문장처럼.
협업 섹션에서는 입출력 관계가 명확하다:
book-planner의 목차/명세를 입력으로 받음book-editor가 작성된 챕터를 리뷰- 리뷰 피드백에 따라 수정 반영
이 세 줄이 Phase 2~3의 데이터 흐름을 에이전트 관점에서 정의한다.
book-editor: 원고 리뷰/편집 전문가
---
name: book-editor
description: "원고를 리뷰하고 편집하는 에이전트.
'원고 리뷰', '편집', 'review chapter' 요청 시 트리거."
model: sonnet
---모델 선택: sonnet. 리뷰는 체크리스트 기반의 구조화된 평가 작업이다. 창의적 판단보다 기준에 따른 일관된 검증이 중요하므로 sonnet이 적합하다.
이 에이전트의 핵심은 심각도 분류 체계다:
## 작업 원칙
- 심각도 분류: CRITICAL / WARNING / SUGGESTION
- 구체적인 수정 제안 포함 (추상적 피드백 금지)
- 좋은 부분도 언급 (균형 잡힌 리뷰)
- 독자 관점에서 리뷰 (저자 관점 아님)세 가지 원칙이 Phase 3의 생성-검증 루프를 작동하게 만든다:
- 심각도 분류: CRITICAL만 루프 조건에 포함되므로, 사소한 SUGGESTION 때문에 루프가 끝없이 도는 것을 방지한다.
- 구체적 수정 제안: “이 부분이 좀 어색합니다”가 아니라 “이 문단의 비유를 X로 바꾸세요”처럼 actionable한 피드백을 준다. chapter-writer가 피드백을 즉시 반영할 수 있다.
- 독자 관점: 저자(chapter-writer)의 의도가 아니라, 독자가 이해할 수 있는지를 기준으로 평가한다. 역할 분리의 핵심이다.
출력 형식도 리뷰 결과 템플릿으로 명시되어 있다:
## 리뷰: Chapter {N} — {제목}
### 총평
- 완성도: {상/중/하}
- 주요 이슈: {count}개
### 상세 리뷰
#### [CRITICAL] {위치}
- 문제: {설명}
- 제안: {구체적 수정안}
#### [WARNING] {위치}
- 문제: {설명}
- 제안: {수정 방향}
#### [SUGGESTION] {위치}
- 제안: {개선 아이디어}
### 잘된 점
- {긍정적 피드백}이 형식이 있기 때문에 오케스트레이터가 “CRITICAL 이슈가 0개인가?”를 기계적으로 판단할 수 있다. 리뷰 결과가 자유 서술이었다면, 루프 종료 여부를 자동으로 결정하기 어려웠을 것이다.
infographic-creator: 인포그래픽 생성 전문가
---
name: infographic-creator
description: "인포그래픽과 다이어그램을 SVG로 생성하는 에이전트.
'인포그래픽', '다이어그램', 'SVG 생성' 요청 시 트리거."
model: sonnet
---모델 선택: sonnet. SVG 생성은 XML 구조를 정해진 규칙대로 조합하는 작업이다. 시각적 레이아웃 감각보다 규칙 준수가 중요하므로 sonnet이 적합하다.
이 에이전트의 특징은 구체적인 스타일 규칙이 작업 원칙에 포함되어 있다는 점이다:
## 작업 원칙
- SVG 형식으로 생성 (브라우저/PDF 모두 호환)
- 색상 팔레트: 깔끔한 파스텔 톤 (접근성 고려)
- 폰트: sans-serif 계열
- 파일명: assets/infographic-ch{NN}-{slug}.svg
- 한 SVG에 하나의 개념만 표현
- 텍스트는 최소화, 시각적 표현 우선“파스텔 톤”, “sans-serif”, “하나의 개념만” — 이런 구체적 규칙이 없으면, 챕터마다 인포그래픽 스타일이 달라진다. 에이전트 정의에서 시각적 일관성을 강제하는 것이다.
협업 섹션도 명확하다: book-planner에게서 시각화 대상을 받고, chapter-writer의 본문에서 참조 위치를 확인하고, 결과를 book-publisher에게 전달한다. 3개의 다른 에이전트와 연결되어 있다.
book-publisher: PDF 조판 + 웹 뷰어 전문가
---
name: book-publisher
description: "PDF 조판과 웹 뷰어를 구현하는 에이전트.
'PDF 생성', '웹 뷰어', 'publish' 요청 시 트리거."
model: sonnet
---모델 선택: sonnet. 마크다운 → PDF/HTML 변환은 도구 호출과 설정 작업이다. pandoc이나 weasyprint 같은 도구를 정확히 다루는 것이 핵심이므로 sonnet이 적합하다.
이 에이전트의 특징은 두 가지 출력 포맷을 담당한다는 점이다:
## 출력 형식
### PDF
- `output/pdf/harness-engineering-guide.pdf`
- 표지, 목차, 본문, 부록 포함
### 웹 뷰어
- `output/web/index.html` — 메인 페이지
- 챕터별 페이지 네비게이션
- 반응형 디자인하나의 에이전트가 PDF와 웹 뷰어 두 가지를 모두 담당한다. “출판 기술”이라는 전문성이 동일하고, 입력(마크다운 + SVG)도 동일하기 때문이다. 만약 PDF와 웹 뷰어의 요구사항이 크게 달라진다면, 그때 에이전트를 분리해도 늦지 않다.
오케스트레이터 스킬 해부
5명의 에이전트를 조율하는 오케스트레이터 스킬을 분석하자. .claude/skills/book-writer/SKILL.md 파일이다.
frontmatter
---
name: book-writer
description: "책 집필 오케스트레이터. 에이전트 팀을 조율하여 책 한 권을 완성합니다.
'책 집필', '책 쓰기', 'write book' 요청 시 트리거."
---description에 “오케스트레이터”라는 역할과 “에이전트 팀을 조율”이라는 핵심 기능이 명시되어 있다. 트리거 키워드는 “책 집필”, “책 쓰기”, “write book” — 다양한 표현을 커버한다.
에이전트 팀 테이블
## 에이전트 팀 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `book-planner` | 목차/구조 설계 | sonnet | 1 |
| `chapter-writer` | 챕터 집필 | opus | 2, 3 |
| `book-editor` | 원고 리뷰/편집 | sonnet | 3 |
| `infographic-creator` | SVG 인포그래픽 | sonnet | 4 |
| `book-publisher` | PDF + 웹 뷰어 | sonnet | 5 |이 테이블이 오케스트레이터의 조감도다. 5명의 에이전트가 누구이고, 무엇을 하고, 어떤 모델을 쓰고, 어느 Phase에 참여하는지를 한눈에 볼 수 있다. Chapter 5에서 배운 “에이전트 구성 테이블 작성법”의 실전 적용이다.
특히 Phase 열을 보면, chapter-writer가 Phase 2와 3에 모두 참여하는 것이 즉시 보인다. 에이전트와 Phase의 매핑이 1:1이 아닌 경우를 테이블로 명시한 것이다.
워크플로우 섹션
오케스트레이터의 워크플로우 섹션에서 각 Phase는 동일한 구조를 따른다:
- 에이전트: 어떤 에이전트가 실행되는가
- 입력: 무엇을 읽는가
- 출력: 무엇을 만드는가
- 검증: 어떻게 확인하는가
이 4항목 구조가 Chapter 5에서 배운 “입력, 처리, 출력, 검증” 원칙의 오케스트레이터 버전이다. Phase 3에는 추가로 프로세스 항목이 있어 생성-검증 루프의 흐름을 명시한다.
실행 방법
## 실행 방법
오케스트레이터(사용자 또는 메인 Claude)가 각 Phase를 순서대로 실행:
Phase 1: Agent tool → book-planner → outline.md 생성 → 사용자 승인
Phase 2: Agent tool → chapter-writer → 챕터 1개씩 순차 집필
Phase 3: Agent tool → book-editor → 리뷰 → chapter-writer → 수정 (반복)
Phase 4: Agent tool → infographic-creator → SVG 생성
Phase 5: Agent tool → book-publisher → PDF + 웹 뷰어
각 Phase 완료 후 사용자 확인을 받고 다음 Phase로 진행.마지막 한 줄이 핵심이다: “각 Phase 완료 후 사용자 확인을 받고 다음 Phase로 진행.” 완전 자동화가 아니라, 사람이 체크포인트를 관리한다. 12개 챕터의 집필은 몇 시간이 걸리는 작업이다. 중간에 방향이 틀어지면 전체를 다시 해야 하므로, Phase마다 확인하는 것이 합리적이다.
실습: book-writer 하네스를 처음부터 재현하기
지금까지 분석한 내용을 바탕으로, book-writer 하네스를 처음부터 구축하는 과정을 따라가보자. 실제로 하네스를 만드는 7단계를 순서대로 진행한다.
Step 1: 도메인 분석
책 집필이라는 도메인을 분석한다.
도메인: 기술서적 집필
작업 유형: 기획 → 집필 → 리뷰 → 시각화 → 출판
순서 의존성: 있음 (목차 → 본문 → 리뷰 → 인포그래픽 → 최종본)
병렬 가능: 인포그래픽 생성 (챕터별 독립)
품질 보장: 필요 (리뷰 루프)
Chapter 3의 패턴 선택 의사결정 트리를 적용하면:
- Q1: 작업 간 순서 의존성이 있는가? → Yes → 파이프라인
- 추가: 특정 단계에서 반복적 품질 개선이 필요한가? → Yes → 생성-검증 내포
결론: 파이프라인 + 생성-검증 조합.
Step 2: 에이전트 식별
도메인의 전문 영역을 분해한다.
1. 목차 기획 → 기획 전문가 필요
2. 본문 집필 → 작가 필요
3. 원고 리뷰 → 편집자 필요 (작가와 분리 — 역할 충돌 방지)
4. 인포그래픽 → 시각 디자이너 필요
5. PDF/웹 변환 → 출판 기술자 필요
5명의 에이전트가 도출된다. 4가지 분리 기준을 적용하여 검증한다:
- 기획자와 작가를 합칠 수 있나? → 전문성이 다르고, 컨텍스트가 과부하됨 → 분리 유지
- 편집자와 작가를 합칠 수 있나? → 역할 충돌이 심함 → 분리 유지
- 디자이너와 출판 기술자를 합칠 수 있나? → 전문 도구가 다름 (SVG vs pandoc) → 분리 유지
Step 3: 에이전트 정의 파일 작성
5개의 에이전트 파일을 .claude/agents/에 생성한다. 각 파일의 작성 원칙:
book-planner.md
├── model: sonnet (구조화 작업)
├── 핵심 역할: 독자 분석, 목차 설계, 챕터 명세, 학습 경로
├── 작업 원칙: 예제 중심, 점진적 난이도
├── 출력 형식: 목차 마크다운 템플릿 (목표/내용/예제/분량)
└── 협업: chapter-writer에게 명세 전달
chapter-writer.md
├── model: opus (창의적 작업)
├── 핵심 역할: 챕터 집필, 예제 작성, 구조화
├── 작업 원칙: "왜"를 설명, 전문 용어 정의, 실행 가능한 코드
├── 출력 형식: 챕터 구조 템플릿 (배울 것/본문/정리/미리보기)
└── 협업: planner에게서 입력, editor에게 리뷰 받음
book-editor.md
├── model: sonnet (구조화된 평가)
├── 핵심 역할: 품질 검증, 가독성, 코드 정확성, 일관성
├── 작업 원칙: CRITICAL/WARNING/SUGGESTION 분류, 구체적 수정안
├── 출력 형식: 리뷰 결과 템플릿 (총평/상세/잘된 점)
└── 협업: writer의 원고 리뷰, 수정 요청
infographic-creator.md
├── model: sonnet (규칙 기반 생성)
├── 핵심 역할: 아키텍처 다이어그램, 프로세스 플로우
├── 작업 원칙: SVG 형식, 파스텔 톤, 하나의 개념
├── 출력 형식: SVG 파일
└── 협업: planner/writer에게서 입력, publisher에게 전달
book-publisher.md
├── model: sonnet (도구 기반 변환)
├── 핵심 역할: PDF 조판, 웹 뷰어, 에셋 통합
├── 작업 원칙: A4 사이즈, 반응형, 구문 강조
├── 출력 형식: PDF + HTML
└── 협업: writer의 마크다운 + infographic의 SVG 통합
Step 4: 디렉토리 구조 설계
산출물이 저장될 위치를 미리 계획한다.
book/
├── outline.md # Phase 1: 목차
├── chapters/ # Phase 2~3: 챕터
├── assets/ # Phase 4: 인포그래픽
└── output/ # Phase 5: 최종본
├── pdf/
└── web/
설계 원칙:
- Phase별 분리: 어떤 Phase의 산출물인지 디렉토리만 보고 알 수 있다
- 네이밍 규칙 통일:
ch{NN}-{slug}패턴으로 정렬과 참조가 쉽다 - 입출력 경로 명시: 에이전트가 어디서 읽고 어디에 쓰는지 모호함이 없다
Step 5: 오케스트레이터 스킬 작성
.claude/skills/book-writer/SKILL.md를 작성한다. 핵심은 세 가지다:
- 에이전트 팀 테이블: 5명의 에이전트, 역할, 모델, Phase 매핑
- Phase별 워크플로우: 각 Phase의 에이전트/입력/출력/검증
- 실행 방법: Agent tool로 어떤 순서로 호출하는지
특히 Phase 3의 생성-검증 루프를 오케스트레이터에 명시하는 것이 핵심이다:
### Phase 3: 리뷰 루프 (생성-검증)
- **에이전트**: `book-editor` → `chapter-writer`
- **프로세스**:
1. `book-editor`가 챕터 리뷰
2. CRITICAL 이슈가 있으면 `chapter-writer`에게 수정 요청
3. 수정본을 `book-editor`가 재리뷰
4. CRITICAL 이슈 0개일 때 승인루프 종료 조건(“CRITICAL 이슈 0개”)이 오케스트레이터 수준에서 명시되어야, 메인 Claude가 언제 루프를 멈출지 판단할 수 있다.
Step 6: 검증
완성된 하네스를 검증한다. Chapter 5에서 다룬 오케스트레이터 검증 체크리스트를 적용한다:
Step 7: 실행
Phase 1부터 순서대로 실행한다.
사용자: "책 집필 시작해줘"
→ book-writer 스킬 트리거
→ Phase 1: book-planner 호출 → outline.md 생성
→ 사용자 확인: "목차 괜찮습니다"
→ Phase 2: chapter-writer 호출 → ch01.md 생성
→ Phase 3: book-editor 호출 → ch01 리뷰 → 수정 → 승인
→ Phase 2~3 반복 (ch02, ch03, ...)
→ Phase 4: infographic-creator 호출 → SVG 생성
→ Phase 5: book-publisher 호출 → PDF + 웹 뷰어 생성
실제로 이 책이 이 과정을 거쳐 만들어졌다.
심화: 설계 결정의 대안과 트레이드오프
book-writer 하네스의 현재 설계가 유일한 정답은 아니다. 다른 선택지와 그 트레이드오프를 살펴보자.
대안 1: 에이전트 수 줄이기
“편집자 없이 작가가 스스로 리뷰하면 안 되나?”
가능하다. chapter-writer에게 “작성 후 스스로 리뷰하라”는 원칙을 추가하면 에이전트 수를 4명으로 줄일 수 있다. 하지만 Chapter 2에서 다뤘듯, 역할 충돌 문제가 발생한다. 글을 쓴 에이전트가 자기 글의 문제를 발견하기 어렵다. 같은 컨텍스트에서 “창의적으로 써라”와 “냉정하게 평가해라”를 동시에 기대하면, 둘 다 중간 수준이 된다.
트레이드오프: 에이전트 수 감소 vs 품질 저하. book-writer 하네스는 품질을 선택했다.
대안 2: 챕터 병렬 집필
“12개 챕터를 동시에 쓰면 빠르지 않나?”
이론적으로는 가능하다. 하지만 앞서 분석했듯, 챕터 간 참조, 용어 일관성, 난이도 곡선 문제가 있다. 병렬로 쓰면 “Chapter 3에서 배운 것처럼”이라는 참조를 쓸 수 없고, 같은 개념을 “오케스트레이터”와 “조율자”라는 다른 용어로 설명하는 불일치가 발생할 수 있다.
트레이드오프: 속도 vs 일관성. book-writer 하네스는 일관성을 선택했다.
대안 3: 리뷰 없는 파이프라인
“Phase 3을 생략하고 바로 인포그래픽으로 넘어가면?”
이 경우 파이프라인만으로 하네스가 구성된다. 단순하고 빠르다. 하지만 chapter-writer가 한 번에 완벽한 챕터를 쓸 가능성은 낮다. 기술적 오류, 논리 비약, 핵심 내용 누락 같은 문제가 최종 PDF에 그대로 남게 된다.
트레이드오프: 속도 vs 품질 보장. book-writer 하네스는 품질 보장을 선택했다.
이 세 가지 대안에서 공통적으로 드러나는 원칙이 있다: 복합 패턴은 복잡하지만, 그 복잡성에는 이유가 있다. 파이프라인만으로 충분한 도메인이라면 생성-검증을 추가할 필요가 없다. 하지만 책 집필처럼 품질이 핵심인 도메인에서는, 생성-검증 루프를 추가하는 복잡성의 대가가 품질 향상으로 돌아온다.
심화: 메타적 관점 — 이 챕터는 어떻게 작성되었는가
이 챕터 자체가 book-writer 하네스의 작동 결과물이라는 점을 잊지 말자. 이 챕터가 만들어진 과정을 복기하면:
Phase 1: book-planner가 outline.md에 Chapter 6의 명세를 작성했다. “목표: 이 책을 만든 book-writer 하네스의 전체 구조를 이해하고, 복합 패턴 설계를 할 수 있다”, “분량: 16~18페이지”.
Phase 2: chapter-writer(지금 이 글을 쓰고 있는 에이전트)가 outline.md의 명세를 읽고, 챕터 구조(배울 것 → 본문 → 정리 → 미리보기)에 맞춰 집필했다.
Phase 3: book-editor가 이 원고를 리뷰했다. “CRITICAL: Phase 3의 생성-검증 루프 설명이 Chapter 3의 패턴 설명과 중복됨 — 이 하네스에 특화된 분석으로 차별화 필요”, “WARNING: 대안 분석 섹션의 트레이드오프가 추상적 — 구체적 수치나 예시 추가 권장” 같은 피드백이 나올 수 있다. chapter-writer가 피드백을 반영하여 수정하고, book-editor가 재리뷰하여 승인한다.
이 순환 구조가 메타적으로 흥미로운 점이다: 이 챕터는 자신이 설명하는 프로세스에 의해 만들어졌다. Chapter 6이 book-writer 하네스를 분석하는 동시에, book-writer 하네스가 Chapter 7을 만든다. 마치 컴파일러가 자기 자신을 컴파일하는 셀프 호스팅(self-hosting)과 같다.
이런 자기 참조가 가능한 이유는, 하네스의 구조가 도메인 독립적이기 때문이다. 에이전트 팀, 오케스트레이터, 파이프라인, 생성-검증 — 이 구조는 “책 집필”이라는 도메인에 종속되지 않는다. 같은 구조로 코드 생성 하네스를 만들 수도 있고, 리서치 팀 하네스를 만들 수도 있다. Chapter 7과 9에서 확인하게 될 것이다.
정리
- book-writer 하네스는 5명의 에이전트(book-planner, chapter-writer, book-editor, infographic-creator, book-publisher)로 구성된다.
- 모델 선택: 창의적 작업(집필)만 opus, 나머지 4명은 sonnet. 비용 대비 품질 최적화.
- 전체 구조는 파이프라인(Phase 1→2→3→4→5)이되, Phase 3에 생성-검증 루프가 내포되어 있다.
- 생성-검증의 핵심 설계: CRITICAL/WARNING/SUGGESTION 심각도 분류, CRITICAL 0개가 루프 종료 조건, 역할 분리(writer vs editor).
- 오케스트레이터 스킬이 에이전트 팀 테이블, Phase별 워크플로우, 실행 방법을 한 파일에 정의한다.
- 산출물 디렉토리는 Phase별로 분리되고, 파일 네이밍은
ch{NN}-{slug}패턴을 따른다. - 설계 대안을 검토하면 현재 구조의 트레이드오프가 명확해진다: 에이전트 수 vs 품질, 병렬 vs 일관성, 단순함 vs 품질 보장.
- 이 책 자체가 이 하네스의 산출물이라는 메타적 구조가 하네스의 범용성을 증명한다.
다음 챕터 미리보기
- Chapter 7에서는 팬아웃/팬인 패턴이 주연인 리서치 팀 하네스를 설계한다. 병렬로 조사하고 결과를 통합하는 구조가 book-writer의 순차 파이프라인과 어떻게 다른지, 동시 실행과 결과 통합의 설계 포인트를 배운다.
Chapter 7: 사례 2 — 리서치 팀 하네스 (팬아웃/팬인)
이 챕터에서 배울 것
- 리서치 도메인의 특성 분석: 왜 병렬 처리가 자연스러운가
- 팬아웃/팬인 패턴을 실전에 적용하는 구체적 설계 과정
- 3명의 리서처 + 1명의 분석가 + 1명의 보고서 작성자로 구성된 하네스 구축
- 팬아웃 시 작업을 분배하는 전략: 무엇을 기준으로 나누는가
- 팬인 시 결과를 통합하는 전략: 충돌 해결과 우선순위 설정
- 병렬과 순차를 적절히 조합하는 하이브리드 워크플로우 설계
본문
왜 리서치는 팬아웃/팬인인가
Chapter 3에서 팬아웃/팬인 패턴을 배웠다. 독립적인 하위 작업으로 분할할 수 있고, 최종적으로 결과를 하나로 통합해야 하는 도메인에 적합하다고 했다. 리서치는 이 패턴의 가장 자연스러운 적용 대상이다.
실제 리서치팀이 일하는 방식을 떠올려보자. 팀장이 “생성AI의 엔터프라이즈 도입 현황을 조사해주세요”라는 요청을 받으면, 보통 이렇게 진행한다:
- 팀장이 조사 주제를 하위 관점으로 분해한다 (기술, 시장, 사례)
- 팀원 3명이 각자 맡은 관점에서 동시에 조사한다
- 조사 결과를 모아서 하나의 분석 보고서로 통합한다
핵심은 2번이다. 기술 동향을 조사하는 동안 시장 분석을 기다릴 이유가 없다. 각 조사는 독립적이다. 기술 리서처가 “시장 리서처의 결과가 나올 때까지 기다려야 합니다”라고 말하는 일은 없다.
이것이 리서치가 팬아웃/팬인에 딱 맞는 이유다:
| 팬아웃/팬인 조건 | 리서치에서의 해당 사항 |
|---|---|
| 독립적인 하위 작업으로 분할 가능 | 관점별 조사는 서로 의존하지 않음 |
| 하위 작업의 수가 가변적 | 주제에 따라 조사 관점이 3개일 수도, 5개일 수도 있음 |
| 결과를 하나로 통합해야 함 | 개별 조사 결과를 종합 보고서로 합쳐야 함 |
반면, 리서치의 전체 흐름은 순차적이다. 조사 주제를 분해하지 않고 바로 조사할 수는 없고, 조사 결과를 통합하지 않고 보고서를 쓸 수는 없다. 따라서 전체 구조는 파이프라인이고, 중간에 팬아웃/팬인이 내포된 하이브리드 구조가 된다:
[주제 분해] → (팬아웃) [리서처 A] ─┐
(팬아웃) [리서처 B] ─┼→ [분석가] → [보고서 작성자]
(팬아웃) [리서처 C] ─┘
(팬인)
Chapter 3에서 다룬 패턴 조합 원칙 — “큰 틀은 파이프라인으로 시작하고, 각 Phase 안에서 다른 패턴을 적용한다” — 의 전형적인 예다.
인포그래픽: 팬아웃/팬인 데이터 흐름도
도메인 분석: 리서치 작업의 구조
하네스를 설계하기 전에 리서치 작업의 구조를 분석해야 한다. “어떤 에이전트가 필요한가”를 먼저 물으면 안 된다. “어떤 작업이 있고, 각 작업의 특성이 무엇인가”를 먼저 물어야 한다. 에이전트는 작업에서 파생되는 것이지, 그 반대가 아니다.
리서치 작업을 단계별로 분해하면 다음과 같다:
단계 1: 주제 분해
리서치 요청을 분석하여 조사할 하위 관점을 도출한다. “생성AI의 엔터프라이즈 도입 현황”이라는 요청을 받으면:
- 기술 관점: 어떤 기술이 사용되는가, 성능과 한계는?
- 시장 관점: 시장 규모, 성장률, 주요 플레이어는?
- 사례 관점: 실제 도입 기업의 성과와 교훈은?
이 단계의 특성: 순차적. 분해 없이 조사를 시작할 수 없다. 또한 분해 결과가 뒤 단계의 작업 수를 결정한다.
단계 2: 관점별 조사
각 관점에 대해 독립적으로 조사한다. 웹 검색, 데이터 수집, 1차 정리를 수행한다.
이 단계의 특성: 병렬 가능. 각 조사는 서로의 결과에 의존하지 않는다. 이 단계가 팬아웃의 대상이다.
단계 3: 결과 통합 분석
개별 조사 결과를 모아서 교차 분석한다. 기술 동향과 시장 트렌드 사이의 상관관계, 사례에서 발견된 패턴, 관점 간 모순되는 정보를 식별한다.
이 단계의 특성: 순차적. 모든 조사 결과가 있어야 교차 분석이 가능하다. 이 단계가 팬인이다.
단계 4: 보고서 작성
분석 결과를 구조화된 보고서로 작성한다. 요약, 상세 분석, 시사점, 권장 사항을 포함한다.
이 단계의 특성: 순차적. 분석이 끝나야 보고서를 쓸 수 있다.
이 분석에서 자연스럽게 에이전트 구성이 도출된다:
| 단계 | 작업 | 에이전트 | 모델 |
|---|---|---|---|
| 주제 분해 | 요청 분석, 관점 도출 | 오케스트레이터(스킬) | — |
| 관점별 조사 | 웹 검색, 데이터 수집, 1차 정리 | 리서처 x3 | sonnet |
| 결과 통합 | 교차 분석, 모순 식별, 패턴 발견 | 분석가 | opus |
| 보고서 작성 | 구조화된 보고서 생성 | 보고서 작성자 | opus |
왜 리서처는 sonnet이고, 분석가와 보고서 작성자는 opus인가? 리서처의 작업은 정보 수집과 정리다. 검색 결과를 읽고 핵심을 추출하는 작업은 sonnet으로 충분하다. 반면, 분석가는 여러 관점의 정보를 교차 분석하고 인사이트를 도출해야 한다. 보고서 작성자는 긴 문서를 구조적이고 논리적으로 작성해야 한다. 이런 고차원 추론과 긴 출력이 필요한 작업에는 opus가 적합하다.
에이전트 설계
도메인 분석에서 도출된 에이전트를 정의 파일로 구체화한다. 각 에이전트의 파일은 .claude/agents/ 디렉토리에 위치한다.
리서처 에이전트
3명의 리서처는 같은 에이전트 정의를 공유한다. 에이전트를 3개 만드는 것이 아니다. 하나의 리서처 에이전트를 정의하고, 팬아웃 시 서로 다른 입력(관점)을 넣어 3번 호출하는 것이다.
왜 에이전트를 분리하지 않는가? 세 리서처의 전문성은 동일하기 때문이다. 모두 “웹 검색으로 정보를 수집하고 구조화하는” 역할이다. 다른 것은 입력(조사 관점)뿐이다. Chapter 4에서 배운 에이전트 분리 기준 — 전문성이 다를 때 분리한다 — 에 따르면, 이 경우는 분리하지 않는 것이 맞다.
---
name: researcher
description: "리서처. 특정 관점에서 웹 검색과 데이터 수집을 수행하고,
구조화된 조사 결과를 작성합니다.
'리서치', 'research', '조사', '검색' 요청 시 트리거."
model: sonnet
---
# Researcher — 리서치 전문가
당신은 주어진 관점에서 철저하게 조사하는 리서치 전문가입니다.
## 핵심 역할
1. **웹 검색**: 주어진 관점에 관련된 정보를 웹에서 검색하고 수집
2. **데이터 정리**: 수집된 정보를 구조화하고 핵심을 추출
3. **출처 관리**: 모든 정보에 출처(URL, 발행일)를 명시
4. **신뢰도 평가**: 수집된 정보의 신뢰도를 평가하고 표시
## 작업 원칙
- Always respond in Korean
- 사실과 의견을 구분한다
- 최신 정보를 우선한다 (1년 이내 자료 우선)
- 하나의 출처에만 의존하지 않는다 (최소 3개 출처 교차 확인)
- 확인되지 않은 정보는 "미확인" 태그를 붙인다
## 출력 형식
조사 결과는 다음 구조로 작성한다:
### {관점명} 조사 결과
- **조사 범위**: 어떤 범위를 조사했는지
- **핵심 발견**: 주요 사실 3~5개 (번호 매김)
- **상세 내용**: 각 발견에 대한 상세 설명
- **출처 목록**: [번호] 출처명, URL, 발행일
- **신뢰도 평가**: 높음/중간/낮음 + 근거
## 협업
- 오케스트레이터로부터 조사 관점과 핵심 질문을 입력받음
- 조사 결과를 파일로 저장하여 분석가 에이전트에게 전달이 에이전트 정의에서 주목할 점이 있다.
출처 관리와 신뢰도 평가를 명시한 이유. 리서치 결과의 품질은 정보의 정확성에 달려 있다. AI가 검색 결과를 요약할 때 출처 없이 서술하면, 나중에 분석가가 사실 관계를 확인할 방법이 없다. 출처를 반드시 명시하도록 원칙에 넣으면, 분석가가 모순된 정보를 발견했을 때 원본을 추적할 수 있다.
“미확인” 태그. AI는 때때로 확실하지 않은 정보를 확정적으로 서술한다. “미확인 정보에는 태그를 붙여라”는 원칙이 이 문제를 완화한다. 분석가는 미확인 태그가 붙은 정보를 별도로 검증하거나, 보고서에서 제외할 수 있다.
분석가 에이전트
---
name: research-analyst
description: "리서치 분석가. 여러 관점의 조사 결과를 교차 분석하고
인사이트를 도출합니다.
'분석', 'analyze', '교차 분석', '통합 분석' 요청 시 트리거."
model: opus
---
# Research Analyst — 리서치 분석가
당신은 다양한 관점의 조사 결과를 종합하여 인사이트를 도출하는 분석 전문가입니다.
## 핵심 역할
1. **교차 분석**: 여러 관점의 조사 결과에서 공통점과 차이점을 식별
2. **모순 식별**: 관점 간 모순되는 정보를 발견하고 해결 방안을 제시
3. **패턴 발견**: 개별 조사에서는 보이지 않는 전체적 패턴과 트렌드를 식별
4. **인사이트 도출**: 데이터에 기반한 핵심 시사점을 정리
## 작업 원칙
- Always respond in Korean
- 개별 조사 결과를 그대로 나열하지 않는다 — 반드시 교차 분석의 부가가치를 만든다
- 모순된 정보는 삭제하지 않고, 양쪽 관점을 모두 제시한 뒤 판단을 명시한다
- 인사이트는 근거 없이 주장하지 않는다 — 반드시 조사 결과의 데이터에 기반한다
- 분석의 한계를 명시한다 (데이터 부족, 편향 가능성 등)
## 출력 형식
분석 결과는 다음 구조로 작성한다:
### 통합 분석 결과
- **핵심 인사이트**: 3~5개의 주요 발견 (중요도순)
- **교차 분석**: 관점 간 상관관계와 시너지
- **모순 사항**: 관점 간 불일치 + 해결/판단
- **정보 공백**: 추가 조사가 필요한 영역
- **분석 한계**: 데이터나 방법론의 제약
## 협업
- 리서처 에이전트들의 조사 결과 파일을 입력으로 받음
- 분석 결과를 파일로 저장하여 보고서 작성자 에이전트에게 전달분석가 에이전트의 핵심은 “부가가치”다. 조사 결과를 단순히 합치는 것은 분석이 아니다. 개별 조사에서는 보이지 않던 것을 발견하는 것이 분석가의 존재 이유다. “개별 조사 결과를 그대로 나열하지 않는다”는 원칙이 이 점을 강제한다.
보고서 작성자 에이전트
---
name: report-writer
description: "보고서 작성자. 분석 결과를 구조화된 보고서로 작성합니다.
'보고서', 'report', '작성' 요청 시 트리거."
model: opus
---
# Report Writer — 보고서 작성 전문가
당신은 분석 결과를 명확하고 구조화된 보고서로 변환하는 전문가입니다.
## 핵심 역할
1. **구조 설계**: 보고서의 전체 구조(목차)를 독자 관점에서 설계
2. **본문 작성**: 분석 결과를 논리적이고 읽기 쉬운 문체로 작성
3. **시각화 제안**: 데이터를 효과적으로 전달할 표/차트를 설계
4. **권장 사항 작성**: 분석에 기반한 구체적이고 실행 가능한 권장 사항을 제시
## 작업 원칙
- Always respond in Korean
- 독자가 전문가가 아닐 수 있다 — 전문 용어에는 간단한 설명을 덧붙인다
- 요약 → 상세의 순서로 작성한다 (바쁜 독자는 요약만 읽을 수 있어야 한다)
- 모든 주장에는 데이터 근거를 표시한다 (분석 결과의 어느 부분에 기반하는지)
- 보고서 분량은 사용자가 지정하지 않으면 A4 5~10페이지 수준으로 작성한다
## 출력 형식
### {주제} 리서치 보고서
1. **요약 (Executive Summary)**: 핵심 발견과 권장 사항 1페이지 요약
2. **배경**: 조사 배경과 목적
3. **분석 결과**: 주제별 상세 분석 (표, 비교 포함)
4. **시사점**: 분석에서 도출된 의미
5. **권장 사항**: 구체적이고 실행 가능한 행동 제안
6. **부록**: 출처 목록, 조사 방법론, 용어 정의
## 협업
- 분석가 에이전트의 통합 분석 결과를 입력으로 받음
- 최종 보고서를 파일로 저장보고서 작성자에서 가장 중요한 원칙은 “요약 → 상세” 구조다. 보고서를 읽는 사람은 보통 바쁘다. 10페이지 보고서를 처음부터 끝까지 읽는 사람은 드물다. 첫 페이지의 Executive Summary만으로 핵심을 파악할 수 있어야 한다. 상세 내용은 관심 있는 사람만 읽으면 된다.
오케스트레이터 스킬 설계
에이전트가 정의되었으면, 이들을 조율하는 오케스트레이터 스킬을 설계한다. 오케스트레이터는 .claude/skills/research-team/SKILL.md에 위치한다.
전체 구조
.claude/
├── agents/
│ ├── researcher.md # 리서처 (3번 병렬 호출)
│ ├── research-analyst.md # 분석가
│ └── report-writer.md # 보고서 작성자
└── skills/
└── research-team/
├── SKILL.md # 오케스트레이터 스킬
└── references/
└── report-template.md # 보고서 템플릿
산출물은 다음 디렉토리에 저장된다:
research/
├── brief.md # Phase 1: 주제 분해 결과
├── findings/ # Phase 2: 리서처별 조사 결과
│ ├── perspective-01.md
│ ├── perspective-02.md
│ └── perspective-03.md
├── analysis.md # Phase 3: 통합 분석 결과
└── report.md # Phase 4: 최종 보고서
왜 산출물 디렉토리를 이렇게 설계하는가? 두 가지 원칙이 있다.
첫째, Phase별로 산출물이 구분된다. brief.md는 Phase 1, findings/는 Phase 2, analysis.md는 Phase 3, report.md는 Phase 4의 산출물이다. 문제가 생겼을 때 어느 Phase의 결과물에 이슈가 있는지 파일만 보고 특정할 수 있다.
둘째, 팬아웃 결과는 디렉토리로 묶는다. 리서처 3명의 결과물은 findings/ 디렉토리에 모인다. perspective-01.md, perspective-02.md, perspective-03.md로 번호를 매기면 몇 명이 조사했는지, 어떤 결과물이 누락되었는지 한눈에 파악할 수 있다.
오케스트레이터 스킬 전체 코드
이제 오케스트레이터 스킬의 전체 코드를 작성한다. 코드가 길지만, 각 Phase를 별도 섹션으로 분리했으므로 순서대로 읽으면 된다.
---
name: research-team
description: "리서치 팀 오케스트레이터. 리서치 요청을 분석하고,
3명의 리서처로 병렬 조사한 뒤 분석가가 통합 분석하여
보고서를 생성합니다.
'리서치 팀', 'research team', '종합 조사' 요청 시 트리거."
---
# Research Team — 리서치 팀 오케스트레이터
리서치 요청을 받아 주제를 분해하고, 병렬로 조사한 뒤,
결과를 통합 분석하여 구조화된 보고서를 생성하는 워크플로우.
## 에이전트 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `researcher` | 관점별 웹 검색 및 조사 | sonnet | 2 (x3 병렬) |
| `research-analyst` | 교차 분석 및 인사이트 도출 | opus | 3 |
| `report-writer` | 최종 보고서 작성 | opus | 4 |
## 워크플로우
### Phase 1: 주제 분해 (오케스트레이터 직접 수행)
- **입력**: 사용자의 리서치 요청
- **처리**:
1. 리서치 요청을 분석하여 핵심 질문을 도출한다
2. 핵심 질문을 3개의 독립적인 조사 관점으로 분해한다
3. 각 관점별로 조사 범위와 핵심 질문을 정리한다
- **출력**: `research/brief.md`
- 원본 요청
- 핵심 질문
- 관점별 조사 지시서 (관점명, 조사 범위, 핵심 질문 3~5개)
- **검증**:
- 관점들이 서로 겹치지 않는지 확인
- 모든 관점을 합하면 원본 요청을 충분히 커버하는지 확인
- 각 관점이 독립적으로 조사 가능한지 확인
- **사용자 확인**: 분해 결과를 사용자에게 보여주고 승인을 받는다
### Phase 2: 관점별 조사 (팬아웃)
- **에이전트**: `researcher` (관점 수만큼 병렬 호출)
- **입력**: `research/brief.md`의 관점별 조사 지시서
- **처리**:
1. 각 리서처에게 하나의 관점과 핵심 질문을 전달한다
2. 리서처는 웹 검색으로 정보를 수집하고 구조화한다
3. 각 리서처는 독립적으로 작업한다 — 다른 리서처의 결과를 참조하지 않는다
- **출력**: `research/findings/perspective-{NN}.md` (관점별 1개)
- **병렬 실행 규칙**:
- 각 리서처는 서브 에이전트로 호출한다
- 모든 리서처가 완료될 때까지 Phase 3으로 진행하지 않는다
- 한 리서처가 실패하면, 해당 관점만 재시도한다 (다른 결과는 유지)
- **검증**:
- 모든 관점에 대해 조사 결과 파일이 생성되었는지 확인
- 각 파일에 핵심 발견, 출처 목록, 신뢰도 평가가 포함되었는지 확인
- 출처가 최소 3개 이상인지 확인
### Phase 3: 통합 분석 (팬인)
- **에이전트**: `research-analyst`
- **입력**: `research/findings/perspective-*.md` (모든 조사 결과)
- **처리**:
1. 모든 조사 결과를 읽는다
2. 관점 간 공통점과 차이점을 식별한다
3. 모순되는 정보를 발견하면 양쪽 근거를 비교하여 판단한다
4. 개별 조사에서 보이지 않는 전체적 패턴을 도출한다
5. 추가 조사가 필요한 정보 공백을 식별한다
- **출력**: `research/analysis.md`
- **검증**:
- 모든 관점의 핵심 발견이 분석에 반영되었는지 확인
- 모순 사항이 식별되고 판단이 내려졌는지 확인
- 인사이트에 근거 데이터가 명시되었는지 확인
- **사용자 확인**: 분석 결과를 사용자에게 보여주고 승인을 받는다
### Phase 4: 보고서 작성
- **에이전트**: `report-writer`
- **입력**: `research/analysis.md` + `research/findings/perspective-*.md`
- **처리**:
1. `references/report-template.md`의 구조를 참고하여 보고서를 작성한다
2. 분석 결과의 인사이트를 중심으로 서술한다
3. 필요한 곳에 표를 사용하여 비교/정리한다
4. Executive Summary를 마지막에 작성한다 (전체 내용 파악 후 요약)
- **출력**: `research/report.md`
- **검증**:
- Executive Summary가 보고서의 핵심을 정확히 반영하는지 확인
- 모든 주장에 근거가 표시되었는지 확인
- 권장 사항이 구체적이고 실행 가능한지 확인
- **사용자 확인**: 최종 보고서를 사용자에게 보여주고 수정 요청을 받는다이 오케스트레이터에서 주목해야 할 설계 결정이 여러 가지 있다. 하나씩 풀어보자.
팬아웃 시 작업 분배 전략
Phase 2에서 3명의 리서처에게 작업을 분배한다. “분배”라고 하면 단순해 보이지만, 실제로는 세 가지 질문에 답해야 한다.
질문 1: 무엇을 기준으로 나누는가?
작업을 분배하는 기준은 도메인에 따라 다르다. 리서치에서는 관점(perspective)으로 나눈다.
| 분배 기준 | 예시 | 적합한 도메인 |
|---|---|---|
| 관점 (perspective) | 기술/시장/사례 | 리서치, 분석 |
| 항목 (item) | 챕터 1/챕터 2/챕터 3 | 배치 처리, 번역 |
| 영역 (region) | 북미/유럽/아시아 | 지역별 조사 |
| 레이어 (layer) | UI/API/DB | 시스템 분석 |
리서치에서 “관점”으로 나누는 이유는, 같은 주제를 서로 다른 렌즈로 보는 것이 리서치의 본질이기 때문이다. “항목”으로 나누면(예: 기업 A 조사/기업 B 조사/기업 C 조사) 각 조사가 파편화되어 전체 그림을 놓칠 수 있다.
질문 2: 관점이 겹치면 어떻게 하는가?
“기술 관점”으로 조사하다 보면 시장 데이터를 만나고, “시장 관점”으로 조사하다 보면 기술 트렌드를 만난다. 관점이 완전히 분리되는 경우는 드물다. 이 겹침을 어떻게 처리할 것인가?
두 가지 전략이 있다:
전략 A: 엄격한 경계. 각 리서처에게 “이 관점에 해당하는 정보만 수집하라”고 지시한다. 기술 리서처가 시장 데이터를 만나면 무시한다.
전략 B: 유연한 경계 (권장). 각 리서처에게 “이 관점이 주(主)이지만, 다른 관점에 유용한 정보를 만나면 별도 섹션에 메모하라”고 지시한다.
전략 B가 더 낫다. 엄격한 경계를 두면 관점 사이의 빈틈에 있는 중요한 정보를 놓칠 수 있다. 유연한 경계를 두면, 분석가가 팬인 단계에서 이 “부산물 정보”를 활용하여 더 풍부한 교차 분석을 할 수 있다.
이 전략을 리서처 에이전트의 출력 형식에 반영하면 다음과 같다:
## 출력 형식
### {관점명} 조사 결과
#### 핵심 발견 (주 관점)
- [발견 1] ...
- [발견 2] ...
#### 관련 정보 (부 관점)
- [기술 관점 관련] ...
- [사례 관점 관련] ...
#### 출처 목록
- [1] ...“관련 정보” 섹션이 바로 유연한 경계의 구현이다. 리서처는 자기 관점에 집중하되, 다른 관점에 유용한 정보를 만나면 별도로 기록한다.
질문 3: 리서처의 수를 어떻게 결정하는가?
오케스트레이터가 주제를 분해할 때, 관점의 수가 결정된다. 3개로 고정할 필요는 없다. 주제에 따라 2개일 수도, 5개일 수도 있다.
하지만 실용적 상한선이 있다. Claude Code에서 서브 에이전트를 동시에 너무 많이 호출하면 컨텍스트 관리가 복잡해지고, 팬인 단계에서 분석가가 처리해야 할 정보량이 과도해진다.
권장하는 범위:
| 관점 수 | 판단 |
|---|---|
| 2개 | 주제가 단순하거나, 관점이 명확히 양분되는 경우 |
| 3개 | 대부분의 리서치에 적합한 균형점 |
| 4~5개 | 복합적인 주제. 분석가의 부담이 커짐 |
| 6개 이상 | 주제를 더 상위로 묶거나, 2단계 팬아웃을 고려 |
3개가 기본값인 이유는 경험적이다. 대부분의 비즈니스 리서치는 “기술/시장/규제”, “내부/경쟁사/고객”, “현재/단기/장기” 같은 3축 분해가 자연스럽다. 이 책의 예제에서도 3개를 기본으로 사용한다.
팬인 시 결과 통합 전략
팬아웃보다 어려운 것이 팬인이다. 독립적으로 수집된 정보를 하나로 통합할 때, 세 가지 문제가 발생한다.
문제 1: 정보 충돌
기술 리서처는 “GPT-4의 엔터프라이즈 도입률이 35%”라고 했는데, 시장 리서처는 “47%”라고 했다. 어느 숫자가 맞는가?
해결 전략: 출처 기반 판단.
분석가는 양쪽의 출처를 비교한다. 조사 기관의 신뢰도, 조사 시점, 표본 크기, “도입”의 정의 차이 등을 검토한다. 이것이 리서처에게 “출처를 반드시 명시하라”고 한 이유다. 출처 없이 숫자만 있으면 어느 쪽이 더 신뢰할 수 있는지 판단할 근거가 없다.
분석가 에이전트의 출력에서 이 충돌은 다음과 같이 기록된다:
### 모순 사항
#### [M1] GPT-4 엔터프라이즈 도입률 수치 불일치
- **관점 A (기술)**: 35% — 출처: Gartner 2025 보고서 (n=500, 2025.01)
- **관점 B (시장)**: 47% — 출처: McKinsey 설문 (n=1200, 2024.11)
- **차이 원인**: Gartner는 "프로덕션 배포"를 기준, McKinsey는 "파일럿 포함"을 기준
- **판단**: 정의 차이에 의한 불일치. "프로덕션 배포 기준 약 35%, 파일럿 포함 시 47%"로 병기모순을 “해결”하는 것이 아니라 양쪽을 모두 제시하고 차이의 원인을 설명하는 것이 핵심이다. 하나를 임의로 선택하면 정보가 왜곡된다.
문제 2: 정보 중복
세 리서처가 모두 “OpenAI의 엔터프라이즈 요금제 출시”를 언급했다. 세 번 반복해서 보고서에 넣을 것인가?
해결 전략: 중복 제거 + 관점별 해석 보존.
같은 사실이라도 관점에 따라 해석이 다를 수 있다. 기술 리서처는 “기술적 기능 확장”으로, 시장 리서처는 “시장 전략 변화”로, 사례 리서처는 “기업 도입 사례의 촉매”로 해석했을 수 있다. 사실은 한 번만 서술하되, 각 관점의 해석은 보존한다.
### 교차 분석
#### OpenAI 엔터프라이즈 요금제 (3개 관점에서 공통 언급)
- **사실**: 2024년 8월 OpenAI Enterprise 요금제 출시
- **기술 관점**: 데이터 프라이버시, 무제한 컨텍스트 등 기술적 차별화
- **시장 관점**: B2B 시장 공식 진출, 기존 SaaS 업체와의 경쟁 구도 변화
- **사례 관점**: 출시 후 6개월 내 Fortune 500 기업 80% 도입 (출처: [7])이렇게 하면 중복은 제거하면서, 각 관점의 고유한 해석은 살린다.
문제 3: 정보 공백
기술과 시장은 충분히 조사되었는데, 사례 조사에서 최근 실패 사례를 찾지 못했다. 성공 사례만으로 보고서를 쓰면 편향된다.
해결 전략: 공백의 명시적 식별.
분석가는 “어떤 정보가 있는가”만이 아니라 “어떤 정보가 없는가”도 보고한다. 이것이 분석가의 출력 형식에 “정보 공백” 섹션을 넣은 이유다.
### 정보 공백
1. **실패 사례 부족**: 도입 후 중단/철회한 사례가 발견되지 않음.
생존자 편향(survivorship bias) 가능성. 추가 조사 권장.
2. **비용 데이터 부족**: ROI 수치를 공개한 기업이 2건에 불과.
비용 효과 분석의 일반화에 한계.보고서 작성자는 이 정보 공백을 보고서의 “분석 한계” 섹션에 반영한다. 공백을 무시하고 쓰면 보고서의 신뢰도가 떨어지지만, 공백을 명시하면 오히려 보고서의 전문성이 높아진다.
병렬과 순차의 적절한 조합
리서치 팀 하네스의 전체 워크플로우를 다시 보자:
Phase 1 (순차): 주제 분해
↓
Phase 2 (병렬): 관점별 조사 ← 팬아웃
↓
Phase 3 (순차): 통합 분석 ← 팬인
↓
Phase 4 (순차): 보고서 작성
4개 Phase 중 병렬인 것은 Phase 2뿐이다. 나머지는 모두 순차적이다. 이것이 현실적인 패턴이다. “팬아웃/팬인 하네스”라고 해서 모든 것이 병렬인 것이 아니다. 병렬 처리가 가능한 한 구간을 팬아웃/팬인으로 설계하고, 나머지는 파이프라인으로 잇는다.
이 구조가 효과적인 이유를 시간 관점에서 보자:
순차 실행 (파이프라인만 사용):
[Phase 1: 5분] → [조사A: 10분] → [조사B: 10분] → [조사C: 10분]
→ [Phase 3: 15분] → [Phase 4: 20분]
= 총 70분
하이브리드 (팬아웃/팬인 적용):
[Phase 1: 5분] → [조사A: 10분]
[조사B: 10분] ← 동시 실행
[조사C: 10분]
→ [Phase 3: 15분] → [Phase 4: 20분]
= 총 50분
병렬화로 20분(약 29%)을 절약했다. 리서처가 많아질수록 절약 효과는 커진다. 5개 관점이면 순차는 50분 추가되지만, 병렬은 가장 느린 리서처의 시간만 추가된다.
하지만 “병렬이 좋으니까 Phase 3과 Phase 4도 병렬로 하면 안 되는가?”라고 물을 수 있다. 안 된다. 분석 없이 보고서를 쓸 수 없기 때문이다. 의존성이 있는 작업을 억지로 병렬화하면 품질이 무너진다.
병렬과 순차를 판단하는 기준은 단순하다:
| 판단 질문 | 답 | 실행 방식 |
|---|---|---|
| A의 결과 없이 B를 시작할 수 있는가? | Yes | 병렬 가능 |
| A의 결과 없이 B를 시작할 수 있는가? | No | 순차 필수 |
| A와 B가 같은 리소스를 수정하는가? | Yes | 순차 (충돌 방지) |
리서치 하네스에서 이 기준을 적용하면: - 리서처 A와 리서처 B: 서로의 결과 불필요 → 병렬 - 리서처와 분석가: 분석가는 조사 결과 필요 → 순차 - 분석가와 보고서 작성자: 보고서는 분석 결과 필요 → 순차
실습: 리서치 팀 하네스 구축
지금까지 설계한 내용을 실제 파일 구조로 구현한다. 이 섹션의 코드를 따라하면 동작하는 리서치 팀 하네스가 완성된다.
Step 1: 디렉토리 구조 생성
# 에이전트 디렉토리 (이미 있으면 생략)
mkdir -p .claude/agents
# 스킬 디렉토리
mkdir -p .claude/skills/research-team/references
# 산출물 디렉토리
mkdir -p research/findingsStep 2: 에이전트 파일 작성
세 개의 에이전트 파일을 앞서 설계한 대로 작성한다.
.claude/agents/researcher.md — 리서처 에이전트 (앞의 설계 그대로)
.claude/agents/research-analyst.md — 분석가 에이전트 (앞의 설계 그대로)
.claude/agents/report-writer.md — 보고서 작성자 에이전트 (앞의 설계 그대로)
Step 3: 보고서 템플릿 작성
.claude/skills/research-team/references/report-template.md:
# {주제} 리서치 보고서
> 작성일: {날짜}
> 조사 기간: {시작일} ~ {종료일}
> 조사 관점: {관점 목록}
---
## 1. Executive Summary
{보고서 전체의 핵심을 1페이지 내로 요약.
바쁜 독자가 이 섹션만 읽어도 핵심을 파악할 수 있어야 한다.}
### 핵심 발견
1. {가장 중요한 발견}
2. {두 번째 발견}
3. {세 번째 발견}
### 핵심 권장 사항
1. {가장 중요한 행동 제안}
2. {두 번째 제안}
---
## 2. 배경
### 조사 배경
{왜 이 리서치를 수행했는가}
### 조사 목적
{이 리서치를 통해 답하려는 질문}
### 조사 방법론
{어떤 방법으로 조사했는가 — 웹 검색, 보고서 분석 등}
---
## 3. 분석 결과
### 3.1 {관점 1 제목}
{상세 분석 내용}
### 3.2 {관점 2 제목}
{상세 분석 내용}
### 3.3 {관점 3 제목}
{상세 분석 내용}
### 3.4 교차 분석
{관점 간 상관관계, 공통 패턴, 모순 사항}
---
## 4. 시사점
{분석 결과에서 도출된 의미. "그래서 이것이 왜 중요한가?"}
---
## 5. 권장 사항
| 우선순위 | 권장 사항 | 기대 효과 | 근거 |
|---------|----------|----------|------|
| 1 | {행동 제안} | {기대 효과} | {섹션 3.X 참조} |
| 2 | {행동 제안} | {기대 효과} | {섹션 3.X 참조} |
| 3 | {행동 제안} | {기대 효과} | {섹션 3.X 참조} |
---
## 6. 부록
### 출처 목록
{모든 참고 자료의 목록}
### 조사 방법론 상세
{조사 과정의 상세 설명}
### 용어 정의
{보고서에 사용된 전문 용어의 정의}
### 분석 한계
{데이터 부족, 편향 가능성 등 한계점 명시}Step 4: 오케스트레이터 스킬 작성
.claude/skills/research-team/SKILL.md — 앞서 설계한 오케스트레이터 스킬의 전체 코드를 그대로 작성한다.
Step 5: 실행
모든 파일이 준비되었으면, 다음과 같이 실행한다:
사용자: "리서치 팀, 생성AI의 엔터프라이즈 도입 현황을 조사해줘"
오케스트레이터가 활성화되면서 Phase 1부터 순서대로 진행된다:
- Phase 1: 주제를 “기술 동향”, “시장 분석”, “도입 사례”로 분해 →
research/brief.md생성 → 사용자 확인 - Phase 2: 3명의 리서처가 각 관점에서 병렬 조사 →
research/findings/perspective-01.md~perspective-03.md생성 - Phase 3: 분석가가 3개 결과를 통합 분석 →
research/analysis.md생성 → 사용자 확인 - Phase 4: 보고서 작성자가 최종 보고서 작성 →
research/report.md생성 → 사용자 확인
심화: 서브 에이전트 호출과 팬아웃 구현
Claude Code에서 팬아웃을 구현하는 메커니즘은 서브 에이전트(SubAgent) 호출이다. 오케스트레이터가 여러 에이전트를 “동시에” 호출할 때, Claude Code의 내장 서브 에이전트 기능을 사용한다.
오케스트레이터 스킬에서 팬아웃을 명시하는 방법은 다음과 같다:
### Phase 2: 관점별 조사 (팬아웃)
- **에이전트**: `researcher` (관점 수만큼 병렬 호출)
- **실행 방식**: 각 관점에 대해 서브 에이전트를 생성하여 병렬 실행
- **서브 에이전트별 입력**:
- 서브 에이전트 1: `research/brief.md`의 관점 1 섹션
- 서브 에이전트 2: `research/brief.md`의 관점 2 섹션
- 서브 에이전트 3: `research/brief.md`의 관점 3 섹션
- **완료 조건**: 모든 서브 에이전트가 결과 파일을 생성할 때까지 대기여기서 중요한 점은, Claude Code의 서브 에이전트는 파일 시스템을 통해 통신한다는 것이다. 서브 에이전트 간에 직접 메시지를 주고받는 것이 아니라, 각 서브 에이전트가 지정된 경로에 파일을 생성하고, 다음 Phase의 에이전트가 그 파일을 읽는 방식이다.
이것이 산출물 디렉토리 설계가 중요한 이유다. 파일 경로가 곧 에이전트 간의 통신 프로토콜이다. research/findings/perspective-{NN}.md라는 네이밍 규칙이, 분석가 에이전트가 “어떤 파일을 읽어야 하는지”를 알려주는 계약(contract)이 된다.
팬아웃 실패 처리
팬아웃에서는 일부 서브 에이전트가 실패할 수 있다. 리서처 B가 웹 검색 결과를 제대로 수집하지 못했다면? 두 가지 전략이 있다:
전략 A: 전체 재시도. 모든 리서처를 다시 실행한다. 단순하지만 비효율적이다. 성공한 리서처 A, C의 작업이 낭비된다.
전략 B: 부분 재시도 (권장). 실패한 리서처 B만 재시도한다. A와 C의 결과는 보존한다.
이 전략을 오케스트레이터에 명시한다:
- **실패 처리**:
- 결과 파일이 생성되지 않은 관점을 식별한다
- 해당 관점에 대해서만 `researcher`를 재호출한다
- 재시도는 최대 2회까지 허용한다
- 2회 재시도 후에도 실패하면, 해당 관점을 "조사 실패"로 표시하고
나머지 결과로 Phase 3를 진행한다
- Phase 3의 분석가에게 누락된 관점을 알린다“2회 재시도 후에도 실패하면 나머지로 진행한다”는 규칙이 중요하다. 하나의 관점 조사가 계속 실패한다고 해서 전체 리서치를 포기할 이유는 없다. 3개 관점 중 2개로도 유용한 보고서를 작성할 수 있다. 단, 분석가에게 누락된 관점을 명시적으로 알려야 한다. 그래야 분석가가 “이 보고서는 기술 관점이 빠져 있다”는 한계를 인식하고 기록할 수 있다.
심화: 팬아웃 결과의 품질 편차
팬아웃의 숨겨진 문제 중 하나는 품질 편차다. 같은 리서처 에이전트를 3번 호출해도, 결과의 품질이 균일하지 않을 수 있다.
리서처 A는 출처 5개를 찾아 상세한 조사 결과를 작성했는데, 리서처 C는 출처 1개로 빈약한 결과를 냈다고 하자. 이 상태로 팬인하면 분석가가 불균형한 정보를 바탕으로 분석하게 된다.
이 문제에 대한 해결책은 팬아웃과 팬인 사이에 품질 검증 단계를 넣는 것이다:
Phase 2: 팬아웃 (조사)
↓
Phase 2.5: 품질 검증 (각 결과의 최소 기준 충족 여부 확인)
↓
Phase 3: 팬인 (통합 분석)
오케스트레이터에서 Phase 2의 검증 항목이 바로 이 역할을 한다:
- **검증**:
- 모든 관점에 대해 조사 결과 파일이 생성되었는지 확인
- 각 파일에 핵심 발견, 출처 목록, 신뢰도 평가가 포함되었는지 확인
- 출처가 최소 3개 이상인지 확인“출처가 최소 3개 이상”이 핵심이다. 이 검증을 통과하지 못한 관점은 재조사 대상이 된다. 재조사 없이 넘어가면 분석의 기반이 불균형해지고, 결과적으로 보고서의 신뢰도가 떨어진다.
심화: 통합 기준을 명확히 하는 법
Chapter 3에서 팬아웃/팬인의 핵심 설계 포인트가 “통합 기준 명시”라고 배웠다. 리서치 하네스에서 이 통합 기준을 어떻게 구체화하는지 살펴보자.
분석가 에이전트에게 “결과를 통합하라”고만 하면 매번 다른 방식으로 통합한다. 한 번은 관점별로 나열하고, 한 번은 시간순으로 정리하고, 한 번은 중요도순으로 배열한다. 통합 기준을 구체적으로 명시해야 일관된 결과가 나온다.
리서치 하네스의 통합 기준을 정리하면 다음과 같다:
| 통합 항목 | 기준 | 처리 방법 |
|---|---|---|
| 동일 사실 | 2개 이상 관점에서 언급 | 한 번만 서술, 각 관점의 해석을 병기 |
| 충돌 정보 | 같은 주제에 대해 수치/결론이 다름 | 양쪽 출처 비교, 차이 원인 분석, 판단 명시 |
| 고유 정보 | 한 관점에서만 발견됨 | 해당 관점의 고유 기여로 유지 |
| 미확인 정보 | 리서처가 “미확인” 태그를 붙임 | 다른 관점의 결과로 교차 검증 시도 |
| 정보 공백 | 조사했으나 정보를 찾지 못함 | 공백 목록에 명시, 추가 조사 필요성 기록 |
이 기준 테이블을 오케스트레이터 스킬의 Phase 3에 직접 포함시키거나, references/merge-criteria.md로 분리하여 참조할 수 있다. 기준이 5줄 이내면 오케스트레이터에 직접 넣고, 그 이상이면 분리하는 것이 좋다.
심화: 리서치 하네스의 확장
기본 구성(3 리서처 + 1 분석가 + 1 보고서 작성자)을 다양한 방향으로 확장할 수 있다.
확장 1: 팩트체크 에이전트 추가
보고서의 신뢰도를 높이려면, 보고서 작성 후 팩트체크를 수행하는 에이전트를 추가할 수 있다. 이것은 Chapter 3의 “생성-검증” 패턴과의 조합이다.
Phase 1 → Phase 2 (팬아웃) → Phase 3 (팬인) → Phase 4 → Phase 5 (검증 루프)
Phase 5: 팩트체크
- **에이전트**: `fact-checker`
- 보고서의 주요 주장을 출처와 대조 검증
- CRITICAL 오류가 있으면 보고서 작성자에게 수정 요청 → 재검증
이 확장이 유용한 경우: 보고서가 외부에 공개되거나, 의사결정의 근거 자료로 사용될 때. 내부 참고용이라면 팩트체크 없이도 충분하다. 모든 확장이 항상 필요한 것은 아니다. 도메인과 용도에 맞게 판단해야 한다.
확장 2: 전문가풀과의 결합
리서치 요청의 도메인이 다양하다면, 리서처를 범용으로 두는 대신 도메인별 전문 리서처를 두고 라우팅할 수 있다.
Phase 1: 주제 분해
↓
Phase 1.5: 관점별 전문 리서처 선택 (전문가풀)
↓
Phase 2: 전문 리서처 병렬 조사 (팬아웃)
↓
Phase 3 ~ Phase 4: (동일)
예를 들어, “기술 관점”이면 tech-researcher를, “법률 관점”이면 legal-researcher를 선택한다. 각 전문 리서처는 해당 도메인의 검색 키워드, 참고 소스, 분석 관점에 특화되어 있다.
확장 3: 반복 심화 조사
1차 보고서를 보고 사용자가 “시장 규모 부분을 더 깊이 조사해줘”라고 요청하면, 해당 관점만 심화 조사를 수행할 수 있다.
Phase 5: 심화 조사
- 사용자가 지정한 관점에 대해 리서처를 재호출
- 1차 조사 결과를 입력으로 제공 → "이미 아는 것 외에 추가 조사"
- 심화 결과를 기존 분석에 병합
- 보고서 업데이트
이 확장은 리서치의 반복적 특성을 반영한다. 실제 리서치는 한 번에 끝나지 않는다. 1차 결과를 보고 “여기를 더 파보자”라고 방향을 수정하는 것이 자연스러운 흐름이다.
전체 하네스 아키텍처 정리
리서치 팀 하네스의 전체 구조를 정리한다.
사용자 요청
│
▼
[오케스트레이터: research-team 스킬]
│
├─ Phase 1: 주제 분해 (오케스트레이터 직접 수행)
│ └─ 출력: research/brief.md
│ └─ 사용자 확인
│
├─ Phase 2: 관점별 조사 (팬아웃)
│ ├─ [researcher] → research/findings/perspective-01.md
│ ├─ [researcher] → research/findings/perspective-02.md
│ └─ [researcher] → research/findings/perspective-03.md
│ └─ 검증: 파일 생성, 출처 3개 이상
│
├─ Phase 3: 통합 분석 (팬인)
│ └─ [research-analyst] → research/analysis.md
│ └─ 사용자 확인
│
└─ Phase 4: 보고서 작성
└─ [report-writer] → research/report.md
└─ 사용자 확인
파일 흐름:
brief.md ──→ perspective-01.md ──┐
perspective-02.md ──┼──→ analysis.md ──→ report.md
perspective-03.md ──┘
각 화살표가 파일 시스템을 통한 에이전트 간 통신이다. 왼쪽 에이전트가 파일을 쓰고, 오른쪽 에이전트가 읽는다. 이 흐름이 곧 하네스의 데이터 파이프라인이다.
정리
- 리서치는 팬아웃/팬인의 자연스러운 적용 대상이다. 관점별 조사가 독립적이고, 최종적으로 통합이 필요한 구조가 팬아웃/팬인과 정확히 일치한다.
- 전체 구조는 파이프라인 + 팬아웃/팬인의 하이브리드다. 큰 틀은 파이프라인(주제 분해 → 조사 → 분석 → 보고서)이고, 조사 단계에서 팬아웃/팬인이 내포된다.
- 팬아웃 작업 분배의 핵심은 “독립적인 관점으로의 분해”다. 관점이 겹치더라도 유연한 경계를 두어 부산물 정보를 보존한다.
- 팬인 결과 통합의 3대 과제: 정보 충돌(출처 기반 판단), 정보 중복(사실 통합 + 해석 보존), 정보 공백(명시적 식별).
- 같은 에이전트를 여러 번 호출하는 것과 에이전트를 여러 개 만드는 것은 다르다. 전문성이 동일하면 하나의 에이전트를 서로 다른 입력으로 호출한다.
- 파일 시스템이 에이전트 간 통신 프로토콜이다. 산출물 디렉토리 구조와 파일 네이밍이 곧 통신 계약이다.
- 품질 검증은 팬아웃과 팬인 사이에 넣는다. 최소 품질 기준(출처 3개 이상 등)을 충족하지 못한 결과는 재조사한다.
다음 챕터 미리보기
- Chapter 7에서는 세 번째 사례로 코드 생성 하네스를 구축한다. 전문가풀 패턴으로 Python, Java, Kotlin 전문가를 라우팅하고, 생성-검증 패턴으로 자동 테스트와 린트를 거쳐 코드 품질을 보장하는 구조를 설계한다. 전문가풀과 생성-검증의 조합이 어떻게 시너지를 내는지를 배운다.
Chapter 8: 사례 3 — 코드 생성 하네스 (전문가풀 + 생성-검증)
이 챕터에서 배울 것
- 다중 언어/프레임워크 코드 생성 시나리오에서 전문가풀 패턴이 왜 자연스러운 선택인지
- 라우터 역할의 오케스트레이터가 요청을 분석하고 적절한 전문가를 선택하는 구조
- Python, Java, Kotlin 전문가 에이전트를 각 언어의 관용적 스타일에 맞게 설계하는 방법
- 생성된 코드를 자동 검증(테스트 실행, 린트)하는 생성-검증 루프 구현
- 검증 실패 시 피드백 기반 재생성 루프의 종료 조건 설계
- 전문가풀 확장: 새 언어 전문가를 추가할 때 기존 구조를 변경하지 않는 설계 원칙
본문
문제 상황: “이 로직을 Python, Java, Kotlin으로 만들어줘”
개발팀에서 이런 요청이 온다고 하자.
“사용자 인증 토큰을 검증하는 유틸리티를 만들어줘. 백엔드 서비스는 Python, Java, Kotlin 세 언어로 운영되고 있어. 각 언어의 관용적 스타일로 작성하고, 테스트도 포함해줘.”
하나의 에이전트가 세 언어를 모두 처리할 수 있을까? 물론 가능하다. 하지만 문제가 있다.
첫째, 컨텍스트 오염. 하나의 에이전트가 Python 코드를 생성한 직후 Kotlin 코드를 생성하면, Python의 관습이 Kotlin 코드에 스며들 수 있다. snake_case가 Kotlin 코드에 등장하거나, Kotlin의 data class를 쓰지 않고 일반 클래스로 작성하는 식이다.
둘째, 프롬프트 비대화. 세 언어의 코딩 컨벤션, 프레임워크 사용법, 테스트 도구 설정을 하나의 에이전트에 모두 담으면 프롬프트가 비대해진다. 컨텍스트 윈도우를 낭비하고, 에이전트가 정작 중요한 지시를 놓칠 확률이 높아진다.
셋째, 확장 비용. 나중에 Go나 TypeScript 전문가를 추가하려면? 하나의 에이전트 파일을 계속 수정해야 하고, 수정할 때마다 기존 언어 처리에 영향을 줄 위험이 있다.
이 문제를 해결하는 패턴이 전문가풀(expert pool)이다. Chapter 3에서 배운 것처럼, 라우터가 요청을 분석하여 적절한 전문가를 선택하고 호출한다. 그리고 생성된 코드의 품질을 보장하기 위해 생성-검증(generate-verify) 루프를 결합한다.
이 챕터에서는 이 두 패턴을 조합하여 실제로 동작하는 코드 생성 하네스를 구축한다.
전체 아키텍처 설계
에이전트 팀 구성
먼저 필요한 역할을 식별하자.
| 에이전트 | 역할 | 모델 | 근거 |
|---|---|---|---|
code-router |
요청 분석, 언어 식별, 전문가 라우팅 | sonnet | 라우팅은 판단만 하면 되므로 빠르고 저렴한 모델 |
python-expert |
Python 코드 + 테스트 생성 | opus | 코드 생성은 높은 품질이 필요 |
java-expert |
Java 코드 + 테스트 생성 | opus | 동일 |
kotlin-expert |
Kotlin 코드 + 테스트 생성 | opus | 동일 |
code-reviewer |
생성된 코드의 품질 검증 | sonnet | 검증은 기준 대조이므로 sonnet으로 충분 |
왜 5개의 에이전트인가?
- 라우터와 전문가를 분리하는 이유: 라우터는 “어떤 전문가를 호출할지” 판단하는 역할이고, 전문가는 “코드를 생성하는” 역할이다. 두 역할을 합치면 라우터가 직접 코드를 생성하게 되어, 전문가풀의 확장성이 사라진다.
- 전문가를 언어별로 분리하는 이유: 각 에이전트가 해당 언어의 컨벤션, 프레임워크, 테스트 도구만 알면 된다. 컨텍스트가 집중되어 품질이 올라간다.
- 리뷰어를 전문가와 분리하는 이유: Chapter 3의 생성-검증 패턴에서 배운 “역할 분리” 원칙이다. 코드를 생성한 에이전트가 자기 코드를 객관적으로 평가하기 어렵다.
워크플로우 개요
Phase 1: [code-router]
요청 분석 → 대상 언어 식별 → 전문가 선택
Phase 2: (전문가풀 — 선택적 호출)
┌→ [python-expert] → Python 코드 + 테스트
├→ [java-expert] → Java 코드 + 테스트
└→ [kotlin-expert] → Kotlin 코드 + 테스트
Phase 3: 검증 루프 (언어별, 최대 3회)
[code-reviewer] → 코드 검증
│
├─ PASS → Phase 4로
└─ FAIL → 피드백 → 해당 전문가 재생성 → 재검증
Phase 4: 최종 산출물 정리
이 구조에서 Phase 1~2가 전문가풀 패턴이고, Phase 2~3이 생성-검증 패턴이다. 두 패턴이 자연스럽게 연결된다: 전문가가 코드를 생성(Phase 2)하고, 리뷰어가 검증(Phase 3)하며, 실패 시 해당 전문가에게 다시 돌아간다.
디렉토리 구조 설계
하네스의 에이전트와 스킬이 어디에 위치하고, 산출물은 어디에 저장되는지부터 정한다.
.claude/
├── agents/
│ ├── code-router.md
│ ├── python-expert.md
│ ├── java-expert.md
│ ├── kotlin-expert.md
│ └── code-reviewer.md
└── skills/
└── code-generation/
├── SKILL.md # 오케스트레이터 스킬
└── references/
├── python-conventions.md
├── java-conventions.md
└── kotlin-conventions.md
codegen-output/ # 산출물 디렉토리
├── request.md # 원본 요청
├── routing-result.md # 라우팅 결과
├── python/
│ ├── token_validator.py
│ ├── test_token_validator.py
│ └── review.md
├── java/
│ ├── TokenValidator.java
│ ├── TokenValidatorTest.java
│ └── review.md
└── kotlin/
├── TokenValidator.kt
├── TokenValidatorTest.kt
└── review.md
산출물을 언어별 하위 디렉토리로 분리한 이유는, 각 전문가가 자기 디렉토리만 읽고 쓰면 되기 때문이다. 전문가 간 산출물 충돌이 발생하지 않는다.
라우터 에이전트 설계
라우터는 전문가풀 패턴의 핵심이다. 요청을 분석하여 어떤 전문가를 호출할지 결정한다.
에이전트 정의: code-router.md
---
name: code-router
description: "코드 생성 요청을 분석하여 적절한 언어 전문가를 선택하는 라우터.
'코드 생성', 'code generation', '코드 작성' 요청 시 트리거."
model: sonnet
---
# 코드 생성 라우터 — 요청을 분석하고 전문가를 선택합니다
당신은 코드 생성 요청을 분석하여 적절한 언어 전문가에게
라우팅하는 역할을 담당합니다.
## 핵심 역할
1. 사용자의 코드 생성 요청에서 대상 언어를 식별한다
2. 요청의 핵심 요구사항을 구조화한다
3. 적절한 전문가를 선택하고 작업 지시를 생성한다
## 라우팅 규칙
요청을 분석하여 아래 기준에 따라 전문가를 선택한다.
복수 언어가 필요한 요청은 해당 전문가를 모두 선택한다.
| 키워드/패턴 | 전문가 | 비고 |
|------------|--------|------|
| python, django, flask, fastapi, pytest | `python-expert` | Python 생태계 |
| java, spring, maven, gradle, junit | `java-expert` | Java 생태계 |
| kotlin, ktor, kotest, coroutine | `kotlin-expert` | Kotlin 생태계 |
### 언어가 명시되지 않은 경우
- 프레임워크나 라이브러리 이름으로 추론한다
- 추론이 불가능하면 사용자에게 질문한다
- "모든 언어로" 요청하면 등록된 전문가 전체를 선택한다
## 출력 형식
분석 결과를 `codegen-output/routing-result.md`에 저장한다.
```markdown
# 라우팅 결과
## 요청 요약
- 기능: {기능 설명}
- 입력/출력: {입력과 출력 명세}
- 제약사항: {성능, 보안 등 제약}
## 선택된 전문가
- [ ] python-expert
- [ ] java-expert
- [ ] kotlin-expert
## 전문가별 작업 지시
### python-expert
{Python 관점의 구체적 작업 지시}
### java-expert
{Java 관점의 구체적 작업 지시}작업 원칙
- 라우팅만 한다. 코드를 직접 생성하지 않는다
- 모호한 요청은 추측하지 말고 사용자에게 질문한다
- 전문가별 작업 지시는 해당 언어의 관점에서 구체적으로 작성한다
라우터 설계에서 주목할 점이 세 가지 있다.
**첫째, 라우팅 규칙을 테이블로 명시했다.** "알아서 판단해라"가 아니라, 키워드와 전문가의 매핑을 명확히 정의했다. 이렇게 해야 라우팅 결과가 예측 가능하다.
**둘째, 모호한 경우의 처리 규칙을 정했다.** 언어가 명시되지 않으면 프레임워크로 추론하고, 그래도 불확실하면 사용자에게 질문한다. "추측하지 말고 질문하라"는 원칙이 라우터에서 특히 중요하다. 잘못된 전문가를 선택하면 이후 모든 작업이 헛수고가 된다.
**셋째, 전문가별 작업 지시를 생성한다.** 라우터는 단순히 "Python 전문가를 호출해라"로 끝나지 않는다. "JWT 토큰을 검증하는 함수를 만들어라. `pyjwt` 라이브러리를 사용하고, 만료 시간 검증을 포함해라"처럼, 해당 언어 관점에서 구체화된 지시를 만든다. 이 지시가 전문가 에이전트의 입력이 된다.
---
### 전문가 에이전트 설계
전문가 에이전트는 자기 언어에 대해 깊이 있는 코드를 생성한다. 세 언어의 전문가를 하나씩 설계하자.
#### Python 전문가: `python-expert.md`
```markdown
---
name: python-expert
description: "Python 코드 생성 전문가. Python, Django, Flask, FastAPI,
pytest 관련 코드 생성 요청을 처리합니다."
model: opus
---
# Python 전문가 — 관용적 Python 코드를 생성합니다
당신은 Python 코드 생성을 담당하는 전문가입니다.
## 핵심 역할
1. 라우터의 작업 지시를 기반으로 Python 코드를 생성한다
2. 해당 코드의 pytest 기반 테스트를 함께 생성한다
3. PEP8과 Black 포매팅을 준수한다
## 코딩 원칙
- **type hints 필수**: 모든 함수에 타입 힌트를 작성한다
- **dataclass 활용**: 구조화된 데이터는 `dataclass`로 정의한다
- **comprehension 우선**: 단순 루프보다 list/dict comprehension을 사용한다
- **함수형 스타일**: `map`, `filter` 또는 PyFunctional을 활용한다
- **docstring**: 공개 함수에 Google style docstring을 작성한다
## 테스트 원칙
- pytest를 사용한다
- 정상 케이스, 경계 케이스, 에러 케이스를 각각 작성한다
- mock이 필요하면 `unittest.mock`을 사용한다
- 테스트 함수명은 `test_{기능}_{시나리오}_{기대결과}` 형식
## 출력 규칙
- 코드 파일: `codegen-output/python/{모듈명}.py`
- 테스트 파일: `codegen-output/python/test_{모듈명}.py`
- snake_case 네이밍
## 협업
- **입력**: `codegen-output/routing-result.md`의 python-expert 작업 지시
- **출력**: `codegen-output/python/` 디렉토리에 코드와 테스트 저장
Java 전문가: java-expert.md
---
name: java-expert
description: "Java 코드 생성 전문가. Java, Spring, Maven, Gradle,
JUnit 관련 코드 생성 요청을 처리합니다."
model: opus
---
# Java 전문가 — 관용적 Java 코드를 생성합니다
당신은 Java 코드 생성을 담당하는 전문가입니다.
## 핵심 역할
1. 라우터의 작업 지시를 기반으로 Java 코드를 생성한다
2. 해당 코드의 JUnit 5 기반 테스트를 함께 생성한다
3. Effective Java의 모범 사례를 따른다
## 코딩 원칙
- **record 활용**: 데이터 캐리어는 `record`로 정의한다 (Java 16+)
- **Streams API**: 컬렉션 처리에 Streams를 사용한다
- **final 선호**: 변경되지 않는 변수는 `final`로 선언한다
- **인터페이스 우선**: 구현체보다 인터페이스에 의존한다
- **Optional 활용**: null 반환 대신 `Optional`을 사용한다
## 테스트 원칙
- JUnit 5를 사용한다
- `@DisplayName`으로 테스트 의도를 명시한다
- Mockito로 의존성을 모킹한다
- 정상, 경계, 예외 케이스를 구분하여 작성한다
## 출력 규칙
- 코드 파일: `codegen-output/java/{ClassName}.java`
- 테스트 파일: `codegen-output/java/{ClassName}Test.java`
- PascalCase 클래스명, camelCase 메서드명
## 협업
- **입력**: `codegen-output/routing-result.md`의 java-expert 작업 지시
- **출력**: `codegen-output/java/` 디렉토리에 코드와 테스트 저장Kotlin 전문가: kotlin-expert.md
---
name: kotlin-expert
description: "Kotlin 코드 생성 전문가. Kotlin, Ktor, Kotest, Coroutine
관련 코드 생성 요청을 처리합니다."
model: opus
---
# Kotlin 전문가 — 관용적 Kotlin 코드를 생성합니다
당신은 Kotlin 코드 생성을 담당하는 전문가입니다.
## 핵심 역할
1. 라우터의 작업 지시를 기반으로 Kotlin 코드를 생성한다
2. 해당 코드의 JUnit 5 기반 테스트를 함께 생성한다
3. Kotlin의 관용적 표현(idiomatic Kotlin)을 적극 활용한다
## 코딩 원칙
- **val 우선**: `var`는 꼭 필요한 경우에만 사용한다
- **data class 활용**: 데이터 홀더는 `data class`로 정의한다
- **sealed class**: 제한된 타입 계층은 `sealed class`로 표현한다
- **확장 함수**: 유틸리티 로직은 확장 함수로 작성한다
- **스코프 함수**: `let`, `run`, `apply`, `also`를 적절히 활용한다
- **null 안전성**: `!!` 대신 `?.`, `?:`, `let` 조합을 사용한다
## 테스트 원칙
- JUnit 5를 사용한다 (Kotest도 가능)
- MockK로 의존성을 모킹한다
- `@DisplayName`으로 테스트 의도를 한국어로 명시한다
- 정상, 경계, 예외 케이스를 구분하여 작성한다
## 출력 규칙
- 코드 파일: `codegen-output/kotlin/{ClassName}.kt`
- 테스트 파일: `codegen-output/kotlin/{ClassName}Test.kt`
- PascalCase 클래스명, camelCase 함수명
## 협업
- **입력**: `codegen-output/routing-result.md`의 kotlin-expert 작업 지시
- **출력**: `codegen-output/kotlin/` 디렉토리에 코드와 테스트 저장세 전문가의 공통점과 차이점
세 에이전트의 구조를 비교해보면 패턴이 보인다.
| 섹션 | 공통 | 언어별 차이 |
|---|---|---|
| 핵심 역할 | 코드 생성 + 테스트 생성 | 없음 |
| 코딩 원칙 | 없음 | 각 언어의 관용적 스타일 |
| 테스트 원칙 | 정상/경계/예외 구분 | 프레임워크 (pytest, JUnit, MockK) |
| 출력 규칙 | 디렉토리 구조 동일 | 파일 확장자, 네이밍 컨벤션 |
구조는 동일하고 내용만 다르다. 이것이 전문가풀의 장점이다. 새 전문가를 추가할 때 기존 에이전트 파일을 복사하고, 코딩 원칙과 테스트 프레임워크만 바꾸면 된다. 전문가 간의 인터페이스(입력 형식, 출력 위치)는 동일하므로, 라우터나 리뷰어를 수정할 필요가 없다.
왜 이렇게 하는가? 개방-폐쇄 원칙(Open-Closed Principle)과 같은 논리다. 전문가풀은 “새 전문가 추가(확장)에는 열려 있고, 기존 구조 변경(수정)에는 닫혀 있다.” 전문가 에이전트 파일 하나를 추가하고, 라우터의 라우팅 테이블에 한 줄만 추가하면 된다.
코드 리뷰어 에이전트 설계
코드 리뷰어는 생성-검증 루프의 “검증자” 역할이다. 전문가가 생성한 코드를 평가하고, 기준을 통과하지 못하면 피드백을 반환한다.
에이전트 정의: code-reviewer.md
---
name: code-reviewer
description: "생성된 코드의 품질을 검증하는 리뷰어.
코드 리뷰, 검증, 품질 확인 요청 시 트리거."
model: sonnet
---
# 코드 리뷰어 — 생성된 코드의 품질을 검증합니다
당신은 코드 생성 전문가가 작성한 코드의 품질을 검증하는
리뷰어입니다. 코드를 생성하지 않습니다. 평가만 합니다.
## 핵심 역할
1. 생성된 코드가 요청 명세를 충족하는지 확인한다
2. 코드의 구조적/기능적 문제를 식별한다
3. 테스트의 커버리지와 품질을 평가한다
4. 검증 결과를 PASS/FAIL과 함께 피드백으로 작성한다
## 검증 기준
### CRITICAL (FAIL 판정)
- 요청한 기능이 구현되지 않았다
- 컴파일/구문 오류가 있다
- 명백한 런타임 에러가 예상된다
- 테스트가 없거나, 핵심 기능의 테스트가 누락되었다
- 보안 취약점이 있다 (하드코딩된 비밀키, SQL 인젝션 등)
### MAJOR (FAIL 판정)
- 해당 언어의 관용적 스타일을 심각하게 위반한다
- 에러 처리가 누락되었다
- 테스트가 정상 케이스만 다루고 경계/에러 케이스가 없다
- 성능상 명백한 문제가 있다
### MINOR (PASS — 기록만)
- 네이밍 개선 여지가 있다
- 주석이 부족하다
- 더 간결한 표현이 가능하다
## 출력 형식
검증 결과를 `codegen-output/{언어}/review.md`에 저장한다.
```markdown
# 코드 리뷰 결과
## 판정: {PASS 또는 FAIL}
## 리뷰 대상: {파일 목록}
## 시도: {N}차 / 최대 3차
### CRITICAL 이슈
- [ ] {파일:라인} {설명}
### MAJOR 이슈
- [ ] {파일:라인} {설명}
### MINOR 이슈 (참고)
- {파일:라인} {설명}
### 피드백 요약
{FAIL인 경우, 전문가가 수정해야 할 내용을 구체적으로 명시}작업 원칙
- 코드를 직접 수정하지 않는다. 피드백만 작성한다
- 검증 기준을 엄격히 적용한다. 기분에 따라 판정을 바꾸지 않는다
- MINOR 이슈로 FAIL 판정하지 않는다
- 피드백은 전문가가 바로 수정할 수 있을 만큼 구체적으로 작성한다
리뷰어 설계에서 가장 중요한 부분은 **이슈 심각도 분류**와 **FAIL 판정 기준**이다.
왜 심각도를 나누는가? Chapter 3에서 다뤘듯이, 심각도를 구분하지 않으면 사소한 네이밍 문제 때문에 루프가 계속 도는 사태가 발생한다. CRITICAL과 MAJOR만 FAIL 조건에 포함하고, MINOR는 기록만 한다. 이렇게 해야 루프가 적정 횟수에서 종료된다.
또 하나 주목할 점: "코드를 직접 수정하지 않는다"는 원칙이다. 리뷰어가 코드를 수정하기 시작하면 역할 경계가 무너진다. 리뷰어는 **문제를 발견하고 피드백하는 것**까지만 담당하고, 수정은 전문가에게 맡긴다.
---
### 오케스트레이터 스킬 설계
에이전트 팀을 정의했으니, 이들을 조율하는 오케스트레이터 스킬을 작성하자.
#### 스킬 정의: `code-generation/SKILL.md`
```markdown
---
name: code-generation
description: "다중 언어 코드 생성 하네스. 전문가풀 패턴으로 언어별
전문가를 라우팅하고, 생성-검증 루프로 품질을 보장합니다.
'코드 생성 하네스', 'code generation harness' 요청 시 트리거."
---
# 코드 생성 하네스 오케스트레이터
다중 언어 코드 생성을 자동화하는 하네스입니다.
전문가풀 패턴으로 적절한 언어 전문가를 선택하고,
생성-검증 루프로 코드 품질을 보장합니다.
## 에이전트 구성
| 에이전트 | 역할 | 모델 | Phase |
|---------|------|------|-------|
| `code-router` | 요청 분석, 전문가 라우팅 | sonnet | 1 |
| `python-expert` | Python 코드 + 테스트 생성 | opus | 2, 3 |
| `java-expert` | Java 코드 + 테스트 생성 | opus | 2, 3 |
| `kotlin-expert` | Kotlin 코드 + 테스트 생성 | opus | 2, 3 |
| `code-reviewer` | 코드 품질 검증 | sonnet | 3 |
## 산출물 디렉토리
codegen-output/ ├── request.md ├── routing-result.md ├── python/ ├── java/ └── kotlin/
## 워크플로우
### Phase 1: 요청 분석과 라우팅
- **에이전트**: `code-router`
- **입력**: 사용자의 코드 생성 요청
- **처리**:
1. 요청에서 대상 언어, 기능 명세, 제약사항을 추출한다
2. 라우팅 규칙에 따라 전문가를 선택한다
3. 전문가별 작업 지시를 작성한다
- **출력**: `codegen-output/routing-result.md`
- **검증**: 선택된 전문가가 1명 이상인지 확인
- **완료 후**: 라우팅 결과를 사용자에게 보여주고 확인을 받는다
### Phase 2: 코드 생성 (전문가풀)
- **에이전트**: Phase 1에서 선택된 전문가만 호출
- **입력**: `codegen-output/routing-result.md`의 해당 전문가 작업 지시
- **처리**: 각 전문가가 자기 언어의 코드와 테스트를 생성한다
- **출력**: `codegen-output/{언어}/` 디렉토리에 코드와 테스트 파일
- **실행 방식**: 선택된 전문가를 순차 호출
(Claude Code의 서브 에이전트는 순차 실행이므로)
- **검증**: 각 언어의 코드 파일과 테스트 파일이 모두 생성되었는지 확인
### Phase 3: 검증 루프 (생성-검증)
- **생성자**: Phase 2에서 호출된 전문가
- **검증자**: `code-reviewer`
- **최대 반복**: 3회 (언어별 독립 카운트)
- **루프 절차**:
1. `code-reviewer`가 생성된 코드를 검증한다
2. CRITICAL 또는 MAJOR 이슈가 있으면 FAIL
3. FAIL 시: 리뷰 피드백을 해당 전문가에게 전달하여 수정 요청
4. 수정된 코드를 다시 `code-reviewer`가 검증한다
5. PASS가 나오거나 최대 반복에 도달할 때까지 반복
- **루프 종료 조건**: CRITICAL 0개 AND MAJOR 0개
- **최대 반복 도달 시**: 남은 이슈를 사용자에게 에스컬레이션
- **출력**: `codegen-output/{언어}/review.md`
### Phase 4: 최종 정리
- 모든 언어의 코드가 PASS되면, 최종 산출물 목록을 사용자에게 보고한다
- 각 언어별 생성된 파일, 리뷰 결과, 반복 횟수를 요약한다
## 중요 규칙
- 각 Phase 완료 후 사용자에게 결과를 보여주고 다음 Phase 진행 여부를 확인한다
- 전문가 에이전트는 자기 언어 디렉토리만 읽고 쓴다
- 리뷰어는 코드를 수정하지 않는다. 피드백만 작성한다
- 새 전문가를 추가할 때는 에이전트 파일 생성 + 라우터 테이블 추가만 하면 된다
오케스트레이터 설계에서 핵심적인 결정 세 가지를 짚어보자.
첫째, Phase 3의 검증 루프가 언어별로 독립이다. Python 코드가 PASS되었는데 Java 코드가 FAIL이면, Java 전문가만 수정-재검증 루프를 돈다. Python 전문가는 다시 호출되지 않는다. 이미 통과한 코드를 다시 건드리지 않는 것이 효율적이다.
둘째, “각 Phase 완료 후 사용자 확인”을 명시했다. 이것은 Chapter 5에서 강조한 패턴이다. 자동화가 아무리 좋아도, 사람의 확인 없이 다음 단계로 넘어가면 잘못된 방향으로 계속 진행될 위험이 있다. 특히 Phase 1의 라우팅 결과를 확인하는 것이 중요하다. 라우터가 잘못된 전문가를 선택했는데 이를 확인하지 않으면, 이후 모든 작업이 헛수고가 된다.
셋째, 새 전문가 추가 규칙을 문서화했다. “에이전트 파일 생성 + 라우터 테이블 추가만 하면 된다”는 것을 명시함으로써, 하네스 유지보수자가 확장 방법을 바로 파악할 수 있다.
실전 예제: JWT 토큰 검증기 생성
이제 설계한 하네스를 실제로 가동해보자. “JWT 토큰을 검증하는 유틸리티를 Python, Java, Kotlin으로 만들어줘”라는 요청을 처리하는 전체 과정을 따라간다.
Phase 1: 라우팅 결과
code-router가 요청을 분석하여 다음과 같은 라우팅 결과를 생성한다.
codegen-output/routing-result.md:
# 라우팅 결과
## 요청 요약
- 기능: JWT 토큰 검증 유틸리티
- 입력: JWT 토큰 문자열, 비밀키
- 출력: 검증 결과 (유효/만료/무효) + 디코딩된 페이로드
- 제약사항: 만료 시간 검증 필수, 서명 검증 필수
## 선택된 전문가
- [x] python-expert
- [x] java-expert
- [x] kotlin-expert
## 전문가별 작업 지시
### python-expert
- `pyjwt` 라이브러리를 사용하여 JWT 검증 함수를 구현한다
- 검증 결과를 dataclass로 정의한다
- 만료, 서명 불일치, 잘못된 형식 각각에 대한 예외 처리를 구현한다
- pytest로 정상/만료/무효 토큰 케이스를 테스트한다
### java-expert
- `java-jwt` (auth0) 라이브러리를 사용하여 JWT 검증 클래스를 구현한다
- 검증 결과를 record로 정의한다
- 예외 계층을 설계하여 만료, 서명 불일치, 형식 오류를 구분한다
- JUnit 5로 정상/만료/무효 토큰 케이스를 테스트한다
### kotlin-expert
- `java-jwt` (auth0) 라이브러리를 사용하여 JWT 검증 함수를 구현한다
- 검증 결과를 sealed class + data class로 정의한다
- Result 타입과 확장 함수를 활용한다
- JUnit 5로 정상/만료/무효 토큰 케이스를 테스트한다라우터가 각 전문가에게 해당 언어의 관용적 도구를 지정한 점에 주목하자. Python은 pyjwt, Java와 Kotlin은 java-jwt를 사용하도록 지시한다. Kotlin에는 sealed class와 Result 타입을 활용하라는 지시가 추가되었다. 같은 기능이지만, 언어의 특성에 맞게 구현 방향이 다르다.
Phase 2: 전문가별 코드 생성
각 전문가가 코드와 테스트를 생성한다. 핵심 코드만 살펴보자.
Python — codegen-output/python/token_validator.py:
from dataclasses import dataclass
from datetime import datetime, timezone
from enum import Enum
from typing import Any
import jwt
class ValidationStatus(Enum):
VALID = "valid"
EXPIRED = "expired"
INVALID_SIGNATURE = "invalid_signature"
MALFORMED = "malformed"
@dataclass(frozen=True)
class ValidationResult:
"""JWT 토큰 검증 결과."""
status: ValidationStatus
payload: dict[str, Any] | None = None
error_message: str | None = None
@property
def is_valid(self) -> bool:
return self.status == ValidationStatus.VALID
def validate_token(token: str, secret_key: str, algorithms: list[str] | None = None) -> ValidationResult:
"""JWT 토큰을 검증하고 결과를 반환한다.
Args:
token: 검증할 JWT 토큰 문자열.
secret_key: 서명 검증에 사용할 비밀키.
algorithms: 허용할 알고리즘 목록. 기본값은 ["HS256"].
Returns:
ValidationResult: 검증 결과와 디코딩된 페이로드.
"""
if algorithms is None:
algorithms = ["HS256"]
try:
payload = jwt.decode(token, secret_key, algorithms=algorithms)
return ValidationResult(status=ValidationStatus.VALID, payload=payload)
except jwt.ExpiredSignatureError:
return ValidationResult(
status=ValidationStatus.EXPIRED,
error_message="토큰이 만료되었습니다",
)
except jwt.InvalidSignatureError:
return ValidationResult(
status=ValidationStatus.INVALID_SIGNATURE,
error_message="서명이 유효하지 않습니다",
)
except jwt.DecodeError:
return ValidationResult(
status=ValidationStatus.MALFORMED,
error_message="토큰 형식이 올바르지 않습니다",
)Python — codegen-output/python/test_token_validator.py:
from datetime import datetime, timedelta, timezone
import jwt
import pytest
from token_validator import ValidationResult, ValidationStatus, validate_token
SECRET_KEY = "test-secret-key"
def _create_token(payload: dict, secret: str = SECRET_KEY, algorithm: str = "HS256") -> str:
"""테스트용 JWT 토큰을 생성한다."""
return jwt.encode(payload, secret, algorithm=algorithm)
class TestValidateToken:
"""validate_token 함수 테스트."""
def test_valid_token_returns_valid_status(self) -> None:
"""유효한 토큰이면 VALID 상태와 페이로드를 반환한다."""
payload = {
"sub": "user-123",
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
}
token = _create_token(payload)
result = validate_token(token, SECRET_KEY)
assert result.is_valid
assert result.status == ValidationStatus.VALID
assert result.payload is not None
assert result.payload["sub"] == "user-123"
def test_expired_token_returns_expired_status(self) -> None:
"""만료된 토큰이면 EXPIRED 상태를 반환한다."""
payload = {
"sub": "user-123",
"exp": datetime.now(tz=timezone.utc) - timedelta(hours=1),
}
token = _create_token(payload)
result = validate_token(token, SECRET_KEY)
assert not result.is_valid
assert result.status == ValidationStatus.EXPIRED
assert result.payload is None
assert "만료" in result.error_message
def test_invalid_signature_returns_invalid_signature_status(self) -> None:
"""서명이 다른 키로 생성된 토큰이면 INVALID_SIGNATURE 상태를 반환한다."""
payload = {
"sub": "user-123",
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
}
token = _create_token(payload, secret="wrong-secret-key")
result = validate_token(token, SECRET_KEY)
assert not result.is_valid
assert result.status == ValidationStatus.INVALID_SIGNATURE
def test_malformed_token_returns_malformed_status(self) -> None:
"""형식이 잘못된 문자열이면 MALFORMED 상태를 반환한다."""
result = validate_token("not-a-jwt-token", SECRET_KEY)
assert not result.is_valid
assert result.status == ValidationStatus.MALFORMED
def test_valid_result_has_no_error_message(self) -> None:
"""유효한 토큰의 결과에는 에러 메시지가 없다."""
payload = {
"sub": "user-123",
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
}
token = _create_token(payload)
result = validate_token(token, SECRET_KEY)
assert result.error_message is NonePython 코드에서 눈여겨볼 점: - @dataclass(frozen=True)로 불변 결과 객체를 정의했다 - Enum으로 상태를 정의하여 문자열 비교 대신 타입 안전한 비교를 사용한다 - 예외를 삼키지 않고, 각 예외 유형별로 명확한 상태를 반환한다 - 테스트가 정상, 만료, 서명 불일치, 형식 오류 4가지 시나리오를 모두 커버한다
Java — codegen-output/java/TokenValidator.java:
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Map;
import java.util.Optional;
public final class TokenValidator {
public enum Status {
VALID, EXPIRED, INVALID_SIGNATURE, MALFORMED
}
public record ValidationResult(
Status status,
Optional<Map<String, Object>> payload,
Optional<String> errorMessage
) {
public boolean isValid() {
return status == Status.VALID;
}
public static ValidationResult valid(Map<String, Object> payload) {
return new ValidationResult(Status.VALID, Optional.of(payload), Optional.empty());
}
public static ValidationResult failure(Status status, String errorMessage) {
return new ValidationResult(status, Optional.empty(), Optional.of(errorMessage));
}
}
private final Algorithm algorithm;
public TokenValidator(String secretKey) {
this.algorithm = Algorithm.HMAC256(secretKey);
}
public ValidationResult validate(String token) {
try {
final DecodedJWT decoded = JWT.require(algorithm).build().verify(token);
final Map<String, Object> payload = decoded.getClaims().entrySet().stream()
.collect(java.util.stream.Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().asString()
));
return ValidationResult.valid(payload);
} catch (TokenExpiredException e) {
return ValidationResult.failure(Status.EXPIRED, "토큰이 만료되었습니다");
} catch (SignatureVerificationException e) {
return ValidationResult.failure(Status.INVALID_SIGNATURE, "서명이 유효하지 않습니다");
} catch (JWTDecodeException e) {
return ValidationResult.failure(Status.MALFORMED, "토큰 형식이 올바르지 않습니다");
}
}
}Java 코드에서 눈여겨볼 점: - record로 결과 객체를 정의했다 (Java 16+ 관용) - Optional로 null을 대체했다 - final 키워드를 적극 사용했다 - 팩토리 메서드 valid(), failure()로 생성을 캡슐화했다 - Streams API로 클레임을 Map으로 변환했다
Kotlin — codegen-output/kotlin/TokenValidator.kt:
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTDecodeException
import com.auth0.jwt.exceptions.SignatureVerificationException
import com.auth0.jwt.exceptions.TokenExpiredException
sealed class ValidationResult {
data class Valid(val payload: Map<String, Any>) : ValidationResult()
data class Expired(val message: String = "토큰이 만료되었습니다") : ValidationResult()
data class InvalidSignature(val message: String = "서명이 유효하지 않습니다") : ValidationResult()
data class Malformed(val message: String = "토큰 형식이 올바르지 않습니다") : ValidationResult()
val isValid: Boolean
get() = this is Valid
}
fun ValidationResult.payloadOrNull(): Map<String, Any>? = when (this) {
is ValidationResult.Valid -> payload
else -> null
}
fun ValidationResult.errorMessageOrNull(): String? = when (this) {
is ValidationResult.Valid -> null
is ValidationResult.Expired -> message
is ValidationResult.InvalidSignature -> message
is ValidationResult.Malformed -> message
}
class TokenValidator(secretKey: String) {
private val algorithm: Algorithm = Algorithm.HMAC256(secretKey)
fun validate(token: String): ValidationResult {
return runCatching {
val decoded = JWT.require(algorithm).build().verify(token)
val payload = decoded.claims
.mapValues { (_, claim) -> claim.asString() }
ValidationResult.Valid(payload)
}.getOrElse { error ->
when (error) {
is TokenExpiredException -> ValidationResult.Expired()
is SignatureVerificationException -> ValidationResult.InvalidSignature()
is JWTDecodeException -> ValidationResult.Malformed()
else -> throw error
}
}
}
}Kotlin 코드에서 눈여겨볼 점: - sealed class로 검증 결과의 타입 계층을 정의했다. when 식에서 컴파일러가 모든 케이스를 검사해준다 - data class로 각 결과 타입의 동등성 비교와 복사를 자동 지원한다 - 확장 함수 payloadOrNull(), errorMessageOrNull()로 결과를 안전하게 추출한다 - runCatching으로 예외를 함수형으로 처리했다 - val만 사용하고 var는 없다
세 언어의 비교: 같은 기능, 다른 관용구
같은 JWT 검증 로직이 세 언어에서 어떻게 다르게 표현되는지 비교해보자.
| 설계 요소 | Python | Java | Kotlin |
|---|---|---|---|
| 결과 타입 | @dataclass + Enum |
record + enum |
sealed class + data class |
| null 처리 | None + \| 타입 |
Optional |
? + 확장 함수 |
| 불변성 | frozen=True |
final + record |
val |
| 에러 처리 | try/except |
try/catch |
runCatching |
| 네이밍 | snake_case |
camelCase |
camelCase |
이것이 전문가를 분리하는 이유다. 하나의 에이전트가 세 가지 스타일을 동시에 유지하는 것보다, 각 전문가가 자기 언어에 집중하는 것이 훨씬 품질이 높다.
생성-검증 루프 상세 설계
Phase 3의 검증 루프를 더 자세히 살펴보자.
루프 동작 흐름
[1차 시도]
전문가가 코드 생성 → code-reviewer가 검증
│
├─ PASS → 완료
└─ FAIL → 피드백 반환
│
▼
[2차 시도]
전문가가 피드백 기반으로 수정 → code-reviewer가 재검증
│
├─ PASS → 완료
└─ FAIL → 피드백 반환
│
▼
[3차 시도]
전문가가 피드백 기반으로 수정 → code-reviewer가 재검증
│
├─ PASS → 완료
└─ FAIL → 사용자에게 에스컬레이션
피드백 전달 메커니즘
리뷰어가 FAIL을 판정하면, review.md에 구체적인 피드백이 담긴다. 이 파일이 전문가에게 전달되는 “수정 요청서”다.
Phase 2에서 보여준 코드는 리뷰와 수정이 완료된 최종본이다. 여기서는 리뷰 과정을 재현하기 위해, 초안 시점의 코드를 기준으로 살펴보자. 예를 들어, Python 코드에 대해 리뷰어가 다음과 같은 피드백을 남겼다고 하자.
codegen-output/python/review.md (1차 리뷰 — FAIL):
# 코드 리뷰 결과
## 판정: FAIL
## 리뷰 대상: token_validator.py, test_token_validator.py
## 시도: 1차 / 최대 3차
### CRITICAL 이슈
- [ ] token_validator.py:42 — algorithms 파라미터의 기본값이
mutable list이다. 함수 호출 간에 공유되어 예기치 않은
동작이 발생할 수 있다.
### MAJOR 이슈
- [ ] test_token_validator.py — 커스텀 알고리즘(RS256 등)을
지정한 경우의 테스트가 누락되었다.
### MINOR 이슈 (참고)
- token_validator.py:15 — ValidationStatus의 값을
대문자로 통일하면 가독성이 향상될 수 있다.
### 피드백 요약
1. validate_token의 algorithms 기본값을 None으로 변경하고,
함수 내부에서 ["HS256"]을 할당하세요.
2. 커스텀 알고리즘 테스트를 추가하세요.이 피드백을 받은 python-expert는 지적된 부분만 수정한다.
# 수정 전
def validate_token(token: str, secret_key: str, algorithms: list[str] = ["HS256"]) -> ValidationResult:
# 수정 후
def validate_token(token: str, secret_key: str, algorithms: list[str] | None = None) -> ValidationResult:
if algorithms is None:
algorithms = ["HS256"]그리고 누락된 테스트를 추가한다.
def test_custom_algorithm_is_accepted(self) -> None:
"""커스텀 알고리즘을 지정하면 해당 알고리즘으로 검증한다."""
payload = {
"sub": "user-123",
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
result = validate_token(token, SECRET_KEY, algorithms=["HS256"])
assert result.is_valid수정 후 code-reviewer가 다시 검증한다.
codegen-output/python/review.md (2차 리뷰 — PASS):
# 코드 리뷰 결과
## 판정: PASS
## 리뷰 대상: token_validator.py, test_token_validator.py
## 시도: 2차 / 최대 3차
### CRITICAL 이슈
(없음)
### MAJOR 이슈
(없음)
### MINOR 이슈 (참고)
- token_validator.py:15 — ValidationStatus의 값을
대문자로 통일하면 가독성이 향상될 수 있다.
### 피드백 요약
모든 CRITICAL, MAJOR 이슈가 해결되었습니다. PASS.MINOR 이슈는 남아 있지만 PASS다. MINOR는 루프 종료 조건에 포함되지 않기 때문이다.
재생성 시 핵심 규칙
검증 루프가 수렴하려면 재생성 규칙이 명확해야 한다.
규칙 1: 지적된 부분만 수정한다. 피드백에 없는 부분을 “개선”하려고 건드리면, 새로운 문제가 발생할 수 있다. 외과 수술처럼, 문제가 있는 곳만 정확히 절개하고 봉합해야 루프가 수렴한다.
규칙 2: 수정 사항을 명시적으로 기록한다. 전문가가 무엇을 어떻게 수정했는지를 기록하면, 리뷰어가 해당 부분만 집중적으로 재검증할 수 있다. 전체 코드를 처음부터 다시 리뷰하는 것보다 효율적이다.
규칙 3: 3회 시도 후에도 FAIL이면 에스컬레이션한다. 무한 루프를 방지하는 안전장치다. 3회 시도로 해결되지 않는 문제는, AI 에이전트의 능력 밖일 가능성이 높다. 사람의 판단이 필요한 시점이다.
자동 검증 강화: 테스트 실행과 린트
지금까지의 리뷰어는 코드를 읽고 판단하는 방식이다. 여기에 자동 검증 도구를 결합하면 검증의 정확도가 올라간다.
검증 도구 통합
오케스트레이터 스킬에 자동 검증 단계를 추가한다.
### Phase 3 상세: 검증 루프
#### Step 1: 자동 검증 (도구 기반)
각 언어별로 다음 검증을 자동 실행한다.
**Python:**
- 구문 검증: `python -m py_compile {파일}`
- 린트: `ruff check {파일}`
- 포매팅: `black --check {파일}`
- 테스트: `pytest {테스트파일} -v`
**Java:**
- 구문 검증: `javac {파일}`
- 린트: (컴파일 경고 확인)
- 테스트: `java -jar junit-platform-console-standalone.jar --select-class {클래스}`
**Kotlin:**
- 구문 검증: `kotlinc {파일} -include-runtime`
- 린트: `ktlint {파일}`
- 테스트: JUnit 5로 실행
#### Step 2: AI 리뷰 (code-reviewer)
자동 검증을 통과한 코드에 대해 code-reviewer가 리뷰한다.
- 자동 검증 결과를 리뷰의 입력으로 포함한다
- 자동 검증에서 발견하지 못하는 설계적/논리적 문제를 집중 검토한다
#### 검증 순서의 이유
자동 검증을 먼저 하는 이유: 구문 오류나 포매팅 문제를 AI가 판단하게 하는 것은
낭비다. 도구가 정확하게 잡을 수 있는 문제는 도구에 맡기고,
AI 리뷰어는 도구가 잡지 못하는 고수준 문제에 집중하게 한다.왜 자동 검증과 AI 리뷰를 분리하는가?
역할 분리의 원칙이다. 구문 오류, 포매팅 위반, 테스트 실패는 도구가 100% 정확하게 잡는다. 이런 문제를 AI에게 맡기면 가끔 놓칠 수 있고, 컨텍스트 윈도우도 낭비된다. 반대로 “이 설계가 확장 가능한가”, “이 에러 처리가 충분한가” 같은 판단은 도구로 자동화할 수 없다. 각각이 잘하는 것에 집중하게 하는 것이 효율적이다.
자동 검증 실패 시 처리
자동 검증에서 실패하면 AI 리뷰 없이 바로 전문가에게 돌려보낸다.
자동 검증 실패 (예: 테스트 FAIL)
→ 실패 로그를 전문가에게 전달
→ 전문가가 수정
→ 다시 자동 검증
→ 자동 검증 PASS
→ AI 리뷰 (code-reviewer)
자동 검증이 통과하지 못한 코드를 AI 리뷰어에게 보내는 것은 비효율적이다. 컴파일이 안 되는 코드를 설계 관점에서 리뷰하는 것은 의미가 없다.
전문가풀 확장: Go 전문가 추가하기
전문가풀 패턴의 진가는 확장할 때 드러난다. 팀에서 Go 서비스를 새로 시작하여, Go 전문가를 추가해야 한다고 하자.
변경이 필요한 파일
| 작업 | 파일 | 변경 내용 |
|---|---|---|
| 에이전트 추가 | .claude/agents/go-expert.md |
새 파일 생성 |
| 라우터 테이블 추가 | .claude/agents/code-router.md |
라우팅 규칙에 1줄 추가 |
| 컨벤션 참고자료 추가 | .claude/skills/code-generation/references/go-conventions.md |
새 파일 생성 |
| 자동 검증 추가 | code-generation/SKILL.md |
Go 검증 도구 추가 |
변경이 필요하지 않은 파일
| 파일 | 이유 |
|---|---|
python-expert.md |
Go와 무관 |
java-expert.md |
Go와 무관 |
kotlin-expert.md |
Go와 무관 |
code-reviewer.md |
언어 무관한 범용 기준으로 리뷰 |
| 기존 references/ | 기존 언어 컨벤션은 변경 불필요 |
기존 전문가 에이전트를 전혀 수정하지 않는다. 리뷰어도 수정하지 않는다. 열려 있는 확장, 닫혀 있는 수정이다.
Go 전문가 에이전트
---
name: go-expert
description: "Go 코드 생성 전문가. Go, Gin, Echo, goroutine
관련 코드 생성 요청을 처리합니다."
model: opus
---
# Go 전문가 — 관용적 Go 코드를 생성합니다
당신은 Go 코드 생성을 담당하는 전문가입니다.
## 핵심 역할
1. 라우터의 작업 지시를 기반으로 Go 코드를 생성한다
2. 해당 코드의 testing 패키지 기반 테스트를 함께 생성한다
3. Go의 관용적 스타일(idiomatic Go)을 따른다
## 코딩 원칙
- **에러는 값이다**: panic 대신 error 반환을 사용한다
- **인터페이스 활용**: 작은 인터페이스를 정의하고 구현한다
- **goroutine 안전**: 공유 상태에 mutex 또는 채널을 사용한다
- **명시적 에러 처리**: `if err != nil` 패턴을 따른다
- **간결한 네이밍**: Go 컨벤션에 따라 짧은 이름을 사용한다
## 테스트 원칙
- 표준 testing 패키지를 사용한다
- 테이블 주도 테스트(table-driven tests)를 작성한다
- testify를 보조적으로 사용할 수 있다
## 출력 규칙
- 코드 파일: `codegen-output/go/{package_name}.go`
- 테스트 파일: `codegen-output/go/{package_name}_test.go`
- snake_case 파일명, CamelCase 내보내기 함수명
## 협업
- **입력**: `codegen-output/routing-result.md`의 go-expert 작업 지시
- **출력**: `codegen-output/go/` 디렉토리에 코드와 테스트 저장라우터 테이블에 1줄 추가
| 키워드/패턴 | 전문가 | 비고 |
|------------|--------|------|
| python, django, flask, fastapi, pytest | `python-expert` | Python 생태계 |
| java, spring, maven, gradle, junit | `java-expert` | Java 생태계 |
| kotlin, ktor, kotest, coroutine | `kotlin-expert` | Kotlin 생태계 |
| go, golang, gin, echo, goroutine | `go-expert` | Go 생태계 | ← 추가이것이 전부다. 기존의 Python, Java, Kotlin 전문가는 한 글자도 수정하지 않았다. 리뷰어도 수정하지 않았다. 오케스트레이터의 워크플로우 로직도 변하지 않는다. “선택된 전문가를 호출한다”는 규칙이 이미 전문가 수와 무관하게 동작하기 때문이다.
설계 판단의 근거 정리
이 챕터에서 내린 설계 판단들을 “왜?”와 함께 정리한다.
왜 라우터와 전문가를 분리하는가?
하나의 에이전트가 라우팅과 코드 생성을 모두 하면, 새 언어를 추가할 때 그 에이전트의 프롬프트가 점점 비대해진다. 라우터는 “판단만” 하고, 전문가는 “생성만” 한다. 역할을 분리하면 각 에이전트가 단순해지고, 개별적으로 개선할 수 있다.
왜 리뷰어를 sonnet으로 하는가?
리뷰어는 “기준에 맞는가”를 판정하는 역할이다. 새로운 코드를 창의적으로 생성하는 것이 아니라, 기존 기준과 대조하는 작업이다. 이런 대조 작업은 sonnet으로 충분하다. opus를 사용하면 비용만 증가하고 품질 차이는 미미하다.
왜 검증 루프를 언어별로 독립 운영하는가?
Python이 2차에서 PASS되고 Java가 3차에서 PASS되면, 전체 루프가 종료된다. 만약 루프를 통합 운영하면, Python이 이미 PASS인데 Java의 재검증 때문에 Python도 다시 검증받게 되어 비효율적이다.
왜 자동 검증을 AI 리뷰 전에 하는가?
컴파일 오류나 테스트 실패는 도구가 즉시 잡는다. AI에게 이런 명확한 문제를 판단하게 하면 컨텍스트 윈도우를 낭비하고, 가끔 놓칠 수도 있다. 자동 검증을 통과한 코드만 AI에게 보내면, AI는 도구가 잡지 못하는 설계와 논리 문제에 집중할 수 있다.
왜 MINOR 이슈로 FAIL하지 않는가?
MINOR 이슈(네이밍, 주석)까지 FAIL 조건에 넣으면, 수정할 때 새로운 MINOR가 생기고, 다시 FAIL하고, 또 수정하면 또 새로운 MINOR가 발생하는 무한 루프에 빠진다. MINOR는 “기록은 하되 통과시키는” 전략이 루프 수렴에 필수적이다.
전체 흐름 요약
이 챕터에서 구축한 코드 생성 하네스의 전체 데이터 흐름을 정리한다.
사용자 요청
│
▼
[Phase 1: code-router]
│ 요청 분석 → 언어 식별 → 전문가 선택
│ 산출물: routing-result.md
▼
사용자 확인
│
▼
[Phase 2: 전문가풀]
├→ [python-expert] → python/*.py
├→ [java-expert] → java/*.java
└→ [kotlin-expert] → kotlin/*.kt
│
▼
[Phase 3: 검증 루프] (언어별 독립, 최대 3회)
│
├─ Step 1: 자동 검증 (컴파일, 린트, 테스트)
│ ├─ FAIL → 전문가에게 피드백 → 수정 → 다시 Step 1
│ └─ PASS → Step 2로
│
└─ Step 2: AI 리뷰 (code-reviewer)
├─ FAIL → 전문가에게 피드백 → 수정 → 다시 Step 1
└─ PASS → 완료
│
▼
[Phase 4: 최종 정리]
산출물 목록, 리뷰 결과, 반복 횟수 보고
│
▼
사용자에게 최종 보고
이 흐름에는 두 가지 패턴이 결합되어 있다.
- 전문가풀: Phase 1에서 라우터가 전문가를 선택하고, Phase 2에서 선택된 전문가만 실행한다.
- 생성-검증: Phase 2~3에서 전문가가 생성하고, 리뷰어가 검증하며, 실패 시 전문가가 재생성한다.
두 패턴은 자연스럽게 연결된다. 전문가풀이 “누가 생성하는가”를 결정하고, 생성-검증이 “생성된 결과가 충분한가”를 보장한다.
정리
- 전문가풀 + 생성-검증 조합은 다중 도메인 코드 생성에 자연스럽게 적합하다. 전문가풀이 입력별 전문가를 선택하고, 생성-검증이 품질을 보장한다.
- 라우터는 판단만 한다. 라우팅 규칙을 키워드-전문가 테이블로 명시하면 예측 가능한 라우팅이 된다. 모호한 요청은 추측하지 말고 사용자에게 질문한다.
- 전문가는 자기 언어에 집중한다. 에이전트 간 컨텍스트 오염을 방지하고, 각 언어의 관용적 스타일을 깊이 있게 반영할 수 있다.
- 리뷰어는 생성하지 않고 검증만 한다. 역할 분리가 생성-검증 루프의 핵심이다. 이슈 심각도를 분류하고, CRITICAL/MAJOR만 FAIL 조건에 포함하여 루프 수렴을 보장한다.
- 자동 검증과 AI 리뷰를 분리한다. 도구가 잡을 수 있는 문제는 도구에 맡기고, AI는 도구가 잡지 못하는 고수준 문제에 집중한다.
- 전문가풀은 확장에 열려 있다. 새 전문가를 추가할 때 에이전트 파일 1개 생성 + 라우터 테이블 1줄 추가로 끝난다. 기존 전문가, 리뷰어, 오케스트레이터를 수정하지 않는다.
- 검증 루프의 최대 반복 횟수는 필수다. 없으면 무한 루프 위험. 3회가 지나도 해결되지 않으면 사람에게 에스컬레이션한다.
다음 챕터 미리보기
- Chapter 10에서는 이 책에서 설계한 하네스들을 직접 만들지 않고도, harness 메타 스킬을 사용하여 자동 생성하는 방법을 다룬다. “코드 생성 하네스를 구성해줘”라고 말하면 에이전트 파일, 스킬 파일, 디렉토리 구조가 자동으로 생성되는 프로세스를 배운다.
Chapter 9: 디버깅과 개선
이 챕터에서 배울 것
- 하네스 운영 중 자주 발생하는 세 가지 문제 패턴: 산출물 불일치, 무한 루프, 컨텍스트 초과
- 에이전트의
description트리거 키워드가 미스매치될 때 원인을 추적하고 수정하는 방법 - 오케스트레이터 Phase가 실패했을 때 복구하는 전략
- 에이전트를 언제 분리하고 언제 통합해야 하는지 판단하는 기준
- 모델 선택(sonnet vs opus)과 컨텍스트 절약을 통한 성능 최적화
- 반복 실행 시 결과 품질을 안정화하는 전략
- 실패하는 하네스를 단계별로 디버깅하여 수정하는 실전 시나리오
본문
하네스는 한 번에 완성되지 않는다
Chapter 2에서 harness 메타 스킬로 하네스를 자동 생성하는 법을 배웠다. 하지만 생성된 하네스가 처음부터 완벽하게 동작하는 경우는 드물다. 에이전트가 잘못된 형식으로 산출물을 만들거나, 오케스트레이터가 엉뚱한 에이전트를 호출하거나, 검증 루프가 끝나지 않는 상황이 발생한다.
이는 하네스만의 문제가 아니다. 소프트웨어 개발에서도 설계와 구현 사이에는 항상 간극이 있다. 코드를 작성하고 테스트하고 디버깅하며 개선하는 것처럼, 하네스도 동일한 과정을 거친다. 차이점이 있다면, 하네스의 “버그”는 프롬프트의 모호성, 에이전트 간 계약 위반, LLM 특유의 비결정성에서 비롯된다는 것이다.
이 챕터에서는 하네스 운영 중 가장 빈번하게 마주치는 문제를 유형별로 분류하고, 각각의 진단법과 해결 전략을 다룬다.
흔한 문제 패턴 3가지
하네스 디버깅 경험을 축적하다 보면, 문제의 대부분이 세 가지 유형으로 수렴한다는 것을 알게 된다.
유형 1: 에이전트 간 산출물 불일치
가장 흔한 문제다. 에이전트 A가 생성한 산출물의 형식을 에이전트 B가 기대하는 형식과 다르게 만드는 경우.
전형적인 증상: - 다음 Phase의 에이전트가 “입력 파일을 찾을 수 없다”고 보고 - 파일은 존재하지만 에이전트가 파싱에 실패하여 엉뚱한 결과를 산출 - 동일한 정보가 에이전트마다 다른 이름, 다른 구조로 표현됨
발생 원인:
산출물 형식이 구체적으로 명시되지 않았기 때문이다. “리뷰 결과를 마크다운으로 작성하라”는 지시는 모호하다. 에이전트는 자기 나름의 합리적인 형식을 선택하고, 이것이 다음 에이전트의 기대와 어긋난다.
해결 전략:
에이전트 간 산출물은 계약(contract)이다. 계약에는 다음 세 가지가 반드시 포함되어야 한다.
- 파일 경로: 어디에 저장하는가 (예:
output/review-ch01.md) - 파일 형식: 어떤 구조로 작성하는가 (마크다운 헤딩 구조, JSON 스키마 등)
- 필수 필드: 반드시 포함해야 하는 정보는 무엇인가
## 출력 형식
리뷰 결과를 `output/review-ch{NN}.md`에 저장한다.
### 필수 구조
# 리뷰: {챕터 제목}
## 요약 판정
- 판정: {PASS | REVISION_NEEDED}
- CRITICAL 이슈 수: {N}개
- MINOR 이슈 수: {N}개
## CRITICAL 이슈
### 이슈 1: {제목}
- 위치: {섹션명}
- 문제: {구체적 설명}
- 제안: {수정 방향}
## MINOR 이슈
(동일 구조)위처럼 산출물의 구체적인 템플릿을 에이전트 정의나 스킬에 명시하면, 다음 에이전트가 안정적으로 파싱할 수 있다. Chapter 5에서 배운 “출력 규칙 섹션”이 바로 이 역할을 한다.
핵심 원칙: 산출물 형식은 생산자가 아니라 소비자 기준으로 설계하라. 다음 에이전트가 어떤 정보를 어떤 형식으로 필요로 하는지를 먼저 정하고, 그에 맞게 이전 에이전트의 출력 규칙을 작성한다.
유형 2: 무한 루프
생성-검증 패턴에서 발생한다. 리뷰어가 계속 FAIL을 주고, 생성자가 계속 수정하지만, 리뷰어의 기준을 영원히 충족하지 못하는 상황.
전형적인 증상: - 검증 루프가 3회, 5회, 10회를 넘겨도 종료되지 않음 - 수정된 버전이 이전 버전과 본질적으로 같음 (같은 피드백이 반복) - 한 이슈를 고치면 다른 이슈가 생겨서 전체 이슈 수가 줄지 않음
발생 원인:
세 가지 중 하나다.
- 리뷰어의 기준이 생성자의 능력 밖이다. 리뷰어가 opus 수준의 품질을 요구하는데 생성자가 sonnet이면, 생성자는 영원히 기준을 만족시킬 수 없다.
- 리뷰 피드백이 실행 불가능하다. “더 자연스럽게 써라”, “품질을 높여라”처럼 구체적이지 않은 피드백은 생성자가 해석할 수 없다.
- 종료 조건이 없다. “CRITICAL 이슈가 0개일 때 통과”라는 기준은 있지만, “최대 3회 시도 후 사용자에게 판단을 위임”하는 탈출 조건이 없다.
해결 전략:
## 검증 루프 규칙
1. 최대 반복 횟수: **3회**
2. 3회 시도 후에도 CRITICAL 이슈가 남아있으면:
- 남은 이슈 목록과 수정 시도 이력을 사용자에게 보고
- 사용자가 수동 개입하거나, 수용 가능한 수준으로 기준을 조정
3. 리뷰 피드백은 반드시 **구체적인 수정 지시**를 포함해야 한다:
- BAD: "문장이 어색합니다"
- GOOD: "'~하는 것이다' 종결어미가 3회 연속 반복됩니다.
두 번째와 세 번째를 다른 종결어미로 변경하세요"무한 루프 방지의 핵심은 최대 반복 횟수와 탈출 조건을 반드시 명시하는 것이다. 소프트웨어의 while 루프에 종료 조건이 필수인 것과 같은 이유다.
유형 3: 컨텍스트 초과
에이전트가 처리해야 할 입력 텍스트가 모델의 컨텍스트 윈도우를 초과하는 문제.
전형적인 증상: - 에이전트가 입력의 앞부분만 처리하고 뒷부분을 무시 - 앞에서 지시한 규칙이 긴 입력 처리 중 “잊혀지는” 현상 - 산출물의 후반부 품질이 전반부보다 현저히 떨어짐
발생 원인:
하네스에서 컨텍스트 초과가 발생하는 경로는 두 가지다.
- 입력 누적: 이전 Phase의 모든 산출물을 한꺼번에 읽어야 하는 에이전트. 예를 들어, 12챕터의 책 전체를 한 번에 리뷰하는 편집자 에이전트.
- 프롬프트 비대화: 에이전트 정의 + 스킬 지시문 + 참고 자료(references)가 합쳐져 컨텍스트의 상당 부분을 차지하는 경우.
해결 전략:
# 컨텍스트 절약 방법
1. 입력 분할: 전체를 한 번에 처리하지 말고 단위별로 나눈다
- BAD: 12챕터 전체를 한 번에 리뷰
- GOOD: 챕터 1개씩 순차 리뷰
2. 산출물 요약 전달: 원본 대신 요약본을 다음 에이전트에게 전달
- BAD: 리서치 원문 전체를 분석 에이전트에게 전달
- GOOD: 리서치 에이전트가 핵심 요약을 생성하여 전달
3. references 최적화: 참조 자료를 필요한 부분만 발췌
- BAD: 200줄짜리 코딩 컨벤션 전체를 references에 포함
- GOOD: 해당 에이전트에 관련된 규칙 30줄만 발췌하여 포함
Chapter 5에서 배운 “파일 기반 통신” 원칙이 여기서 빛을 발한다. 에이전트 간 통신이 파일 기반이므로, 파일의 크기와 형식을 통제하여 컨텍스트 사용량을 관리할 수 있다.
트리거 키워드 미스매치 디버깅
에이전트의 description 필드에 적힌 트리거 키워드는, Claude Code가 어떤 에이전트를 활성화할지 결정하는 핵심 메커니즘이다. 오케스트레이터가 “리뷰를 수행해줘”라고 지시했는데 엉뚱한 에이전트가 호출되거나, 아무 에이전트도 호출되지 않는다면 트리거 키워드가 원인일 가능성이 높다.
증상과 진단
트리거 미스매치는 두 가지 형태로 나타난다.
형태 1: 호출 누락 — 원하는 에이전트가 호출되지 않음.
진단 절차: 1. 오케스트레이터의 호출 지시문에 사용된 단어를 확인한다 2. 해당 에이전트의 description 필드를 확인한다 3. 둘 사이에 단어 수준의 일치가 있는지 비교한다
# 오케스트레이터의 지시: "코드 품질을 점검해줘"
# 에이전트 description: "'코드 리뷰', 'code review' 요청 시 트리거"
# 문제: "점검"과 "리뷰"가 일치하지 않음이 경우 오케스트레이터의 호출 지시를 수정하거나, 에이전트의 description에 “점검”을 추가하면 된다. 어느 쪽을 수정할까? 에이전트의 description을 확장하는 것이 낫다. 이유는 오케스트레이터의 지시를 수정하면 자연스러운 표현이 제한되지만, description에 동의어를 추가하면 다양한 표현에 대응할 수 있기 때문이다.
# 수정 후
description: "코드 리뷰를 수행하는 에이전트. '코드 리뷰', 'code review',
'코드 점검', 'PR 리뷰', '품질 검토' 요청 시 트리거."형태 2: 잘못된 호출 — 의도하지 않은 에이전트가 호출됨.
진단 절차: 1. 호출된 에이전트의 description에 현재 요청과 겹치는 키워드가 있는지 확인한다 2. 의도한 에이전트와 호출된 에이전트 사이에 description이 겹치는 부분을 찾는다
# 의도: python-expert를 호출하고 싶음
# 결과: code-reviewer가 호출됨
# 원인: 둘 다 description에 "코드"라는 단어가 포함되어 있음
# python-expert: "Python 코드를 생성하는 전문가"
# code-reviewer: "코드 품질을 검증하는 리뷰어"해결법은 description의 차별화다. 각 에이전트의 트리거 키워드가 겹치지 않도록 고유한 키워드를 배정한다.
# 수정 후
python-expert: "'Python 생성', 'Python 작성', 'py 코드' 요청 시 트리거"
code-reviewer: "'코드 리뷰', '코드 검증', 'PR 리뷰' 요청 시 트리거"트리거 키워드 설계 원칙
트리거 미스매치를 사전에 방지하려면 다음 원칙을 따른다.
- 에이전트당 고유 키워드 최소 2개: 하나만 있으면 동의어 대응이 안 되고, 너무 많으면 다른 에이전트와 겹칠 수 있다
- 동사 + 목적어 조합: “리뷰”보다 “코드 리뷰”가 구체적이다. “생성”보다 “Python 생성”이 다른 에이전트와 구별된다
- 한국어 + 영어 병기: 오케스트레이터가 어떤 언어로 호출할지 예측할 수 없으므로 양쪽 모두 포함한다
- 전체 에이전트 키워드를 테이블로 관리: 에이전트를 추가할 때마다 기존 키워드와 겹치지 않는지 확인한다
| 에이전트 | 트리거 키워드 | 금지 키워드 (겹침 방지) |
|---------|-------------|---------------------|
| python-expert | Python 생성, Python 작성, py 코드 | 코드 (너무 일반적) |
| java-expert | Java 생성, Java 작성, 자바 코드 | 코드 (너무 일반적) |
| code-reviewer | 코드 리뷰, 코드 검증, PR 리뷰 | 코드 생성 (전문가와 겹침) |Phase 실패 시 복구 전략
오케스트레이터가 Phase를 순차 실행하는 도중 한 Phase가 실패하면 어떻게 할 것인가? 소프트웨어의 예외 처리와 마찬가지로, 사전에 복구 전략을 설계해두어야 한다.
실패 유형 분류
Phase 실패는 세 가지 유형으로 나뉜다.
유형 A: 산출물 미생성 — 에이전트가 실행되었으나 기대하는 파일이 생성되지 않음.
원인: 에이전트가 지시를 이해하지 못했거나, 파일 경로를 잘못 사용함. 복구: 해당 Phase를 동일 에이전트로 재실행한다. 재실행 시 “이전 시도에서 {파일명}이 생성되지 않았다”는 컨텍스트를 추가한다.
유형 B: 산출물 품질 미달 — 파일은 생성되었으나 다음 Phase의 요구 수준에 미치지 못함.
원인: 에이전트의 능력 한계, 또는 지시가 불충분함. 복구: 두 가지 선택지가 있다. 1. 프롬프트 보강 후 재실행: 에이전트 정의나 스킬에 더 구체적인 지시를 추가 2. 모델 업그레이드: sonnet으로 시도했다면 opus로 변경
유형 C: 중간 Phase 실패 — Phase 3이 실패했을 때, Phase 1~2의 산출물은 정상.
이것이 가장 흔한 상황이다. 핵심은 정상 산출물을 보존하고 실패한 Phase만 재실행하는 것이다.
Phase 1: [완료] → outline.md 정상 ✓
Phase 2: [완료] → ch01~ch12.md 정상 ✓
Phase 3: [실패] → 리뷰 루프에서 무한 반복 ✗
Phase 4: [미실행]
Phase 5: [미실행]
이 경우 Phase 1~2는 다시 실행할 필요가 없다. Phase 3의 문제를 진단하고 수정한 후 Phase 3부터 재개한다.
복구를 위한 설계 원칙
Phase 실패 시 효율적으로 복구하려면, 오케스트레이터 설계 단계에서 다음 원칙을 적용해야 한다.
원칙 1: 각 Phase의 산출물은 파일로 영속화한다.
Phase 간 데이터를 대화 컨텍스트에만 의존하면, 실패 시 이전 Phase부터 다시 시작해야 한다. 파일로 저장하면 실패한 Phase만 재실행하면 된다. Chapter 5에서 배운 “파일 기반 통신”이 디버깅에서도 중요한 이유다.
원칙 2: Phase 완료 체크포인트를 둔다.
각 Phase 완료 시 상태 파일을 업데이트하여, 어디까지 진행되었는지 기록한다.
# progress.md — 진행 상태
## Phase 1: 목차 설계
- 상태: 완료
- 산출물: outline.md
- 완료 시각: {YYYY-MM-DD} 14:30
## Phase 2: 챕터 집필
- 상태: 완료
- 산출물: ch01.md ~ ch12.md
- 완료 시각: {YYYY-MM-DD} 16:45
## Phase 3: 리뷰 루프
- 상태: 실패 (3회 시도 후 중단)
- 잔여 이슈: ch07 CRITICAL 2건
- 마지막 시도: {YYYY-MM-DD} 17:20이 파일이 있으면 새로운 세션에서도 “Phase 3부터 재개”할 수 있다. 하네스를 여러 세션에 걸쳐 운영할 때 특히 유용하다.
원칙 3: 사용자 개입 지점을 명시한다.
Chapter 6에서 “각 Phase 완료 후 사용자 확인” 패턴을 배웠다. 이것은 디버깅 관점에서도 중요하다. 사용자가 각 Phase의 산출물을 확인하면, 문제가 어느 Phase에서 시작되었는지 빠르게 특정할 수 있다.
에이전트 분리와 통합 판단
하네스를 운영하다 보면 두 가지 반대 방향의 필요가 생긴다. “이 에이전트의 역할이 너무 넓어서 쪼개야 할 것 같다”는 분리 필요, 그리고 “이 두 에이전트는 항상 같이 호출되니 합치는 게 낫겠다”는 통합 필요.
Chapter 2에서 에이전트 분리 기준 4가지(전문성, 병렬성, 컨텍스트 부담, 재사용성)를 배웠다. 여기서는 운영 중 관찰되는 신호를 기준으로 분리/통합을 판단하는 실전 가이드를 다룬다.
분리가 필요한 신호
신호 1: 하나의 에이전트가 모순되는 피드백을 받는다.
예를 들어, “코드 생성 + 테스트 생성” 에이전트가 있다고 하자. 리뷰어가 “프로덕션 코드의 추상화 수준을 높여라”고 피드백하면 코드가 복잡해지고, 동시에 “테스트는 단순하게 유지하라”고 피드백하면 테스트 작성이 어려워진다. 두 역할의 최적화 방향이 충돌한다.
이 경우 code-generator와 test-writer로 분리하면, 각 에이전트가 자기 역할에 집중할 수 있다.
신호 2: 에이전트의 프롬프트가 계속 비대해진다.
에이전트 정의 파일이 점점 길어진다면, 여러 역할이 하나에 응축되었다는 신호다. 경험적으로, 에이전트 정의가 150줄을 넘으면 역할 분리를 검토할 시점이다.
신호 3: 에이전트 실행 시간이 과도하게 길다.
하나의 에이전트가 처리하는 작업량이 많아 실행 시간이 매우 길다면, 작업을 분할하여 두 에이전트로 나누는 것이 효율적이다. 특히 팬아웃 패턴을 적용하여 병렬 처리가 가능한 경우.
통합이 필요한 신호
신호 1: 두 에이전트가 항상 연속으로 호출되고, 중간 산출물이 의미 없다.
에이전트 A의 산출물이 오직 에이전트 B에게만 전달되고, 다른 곳에서는 사용되지 않는다면, A와 B는 사실상 하나의 작업을 불필요하게 쪼갠 것이다. 합치면 에이전트 간 통신 오버헤드가 사라진다.
신호 2: 에이전트 간 산출물 불일치가 반복적으로 발생한다.
두 에이전트 사이의 “계약”을 아무리 정교하게 해도 불일치가 계속 발생한다면, 두 작업을 하나의 컨텍스트 안에서 처리하는 것이 더 안정적일 수 있다.
신호 3: 두 에이전트의 컨텍스트가 거의 동일하다.
A와 B가 동일한 참고 자료와 거의 같은 프롬프트를 사용한다면, 분리로 인한 이점이 없다. 오히려 중복 컨텍스트 로딩이 발생하여 비효율적이다.
판단 체크리스트
분리와 통합 중 어느 방향이 맞는지 확인하는 체크리스트다.
## 분리 체크리스트 (3개 이상 해당하면 분리 검토)
- [ ] 에이전트 정의가 150줄을 넘는다
- [ ] 모순되는 최적화 방향의 피드백을 받는다
- [ ] 에이전트 실행 시간이 다른 에이전트 대비 3배 이상 길다
- [ ] 에이전트가 다루는 도메인 지식이 2개 이상이다
- [ ] 에이전트를 다른 하네스에서 재사용하려면 절반 이상 수정해야 한다
## 통합 체크리스트 (3개 이상 해당하면 통합 검토)
- [ ] 두 에이전트가 항상 연속으로 호출된다
- [ ] 중간 산출물이 디버깅 외 용도로 사용되지 않는다
- [ ] 두 에이전트의 프롬프트가 70% 이상 겹친다
- [ ] 산출물 형식 불일치가 반복된다
- [ ] 통합해도 에이전트 정의가 100줄 이하로 유지된다분리와 통합은 트레이드오프다. 분리하면 전문성과 재사용성이 올라가지만 통신 비용이 증가하고, 통합하면 통신 비용은 줄지만 유연성이 떨어진다. 기본값은 현재 상태를 유지하고, 위의 신호가 관찰될 때만 변경하는 것이 안전하다.
성능 최적화
하네스의 성능은 두 축으로 측정된다: 비용(토큰 소비량)과 품질(산출물의 정확성). 이 둘은 대부분 트레이드오프 관계에 있으므로, 적절한 균형점을 찾는 것이 최적화의 목표다.
모델 선택: sonnet vs opus
Chapter 4에서 모델 선택의 기본 원칙을 배웠다. 여기서는 운영 경험을 바탕으로 한 실전 가이드를 추가한다.
sonnet이 적합한 작업: - 구조화된 판단: 체크리스트 대조, 형식 검증, 라우팅 결정 - 변환 작업: 형식 변환, 구조 재배치, 요약 생성 - 규칙 기반 생성: 템플릿을 채우는 작업, 정해진 규칙에 따른 코드 생성
opus가 필요한 작업: - 창의적 생성: 긴 글 작성, 복잡한 설계, 독창적 해결책 도출 - 복잡한 추론: 여러 조건을 동시에 고려해야 하는 의사결정 - 미묘한 판단: 뉘앙스가 중요한 텍스트 편집, 모호한 요구사항 해석
실전 팁: sonnet부터 시작하고, 품질이 부족할 때만 opus로 올린다.
이유는 단순하다. sonnet으로 80점짜리 결과를 빠르고 저렴하게 얻을 수 있는 작업에 opus를 투입하면, 85점을 얻기 위해 비용이 수배 증가한다. 반면 opus가 아니면 50점밖에 안 나오는 작업이 있다. 모든 에이전트를 opus로 설정하는 것은 모든 나사를 금으로 만드는 것과 같다.
book-writer 하네스의 사례를 보자. 5명의 에이전트 중 opus는 chapter-writer 하나뿐이다. 목차 설계(book-planner), 리뷰(book-editor), SVG 생성(infographic-creator), 출판(book-publisher)은 모두 sonnet으로 충분하다. 가장 높은 창의성을 요구하는 집필만 opus를 사용한다.
컨텍스트 절약 기법
컨텍스트를 절약하면 비용이 줄고, 에이전트가 핵심 지시에 더 집중할 수 있어 품질도 올라간다.
기법 1: references 계층화
모든 참고 자료를 하나의 references 디렉토리에 넣지 말고, 에이전트별로 필요한 자료만 선별적으로 참조하도록 구성한다.
.claude/skills/code-generation/
├── SKILL.md
└── references/
├── shared/ # 공통 참조 (최소한만)
│ └── output-format.md
├── python/ # python-expert만 참조
│ └── conventions.md
├── java/ # java-expert만 참조
│ └── conventions.md
└── kotlin/ # kotlin-expert만 참조
└── conventions.md
기법 2: 산출물 요약 패턴
이전 Phase의 산출물을 다음 에이전트에게 원본 그대로 전달하는 대신, 핵심만 요약하여 전달한다.
# 오케스트레이터의 Phase 2 → Phase 3 전달 지시
Phase 2 산출물을 Phase 3 에이전트에게 전달할 때:
- 원본 파일 전체를 읽지 않는다
- `output/summary.md`(Phase 2에서 생성)만 읽는다
- 상세가 필요하면 해당 섹션의 파일만 선택적으로 읽는다기법 3: 에이전트 정의 간결화
에이전트 정의에 불필요한 설명이 포함되어 있지 않은지 점검한다. “당신은 전문가입니다. 항상 최선을 다하세요. 정확하게 작업해주세요.” 같은 문구는 성능에 기여하지 않으면서 토큰을 소비한다. 구체적인 행동 지침만 남기고 제거한다.
반복 실행 결과의 품질 안정화
LLM의 고유한 특성 중 하나는 비결정성이다. 같은 프롬프트, 같은 입력으로 두 번 실행하면 다른 결과가 나온다. 하네스에서 이 비결정성은 “어제는 잘 되었는데 오늘은 안 된다”는 형태로 나타난다.
완전한 결정성을 달성하는 것은 불가능하다. 하지만 품질의 하한선을 올리는 전략은 존재한다.
전략 1: 출력 형식을 엄격하게 제약한다
자유도가 높을수록 변동성이 크다. “적절한 형식으로 작성하라”는 지시는 실행할 때마다 다른 형식을 만들어낸다. 반면 구체적인 템플릿을 제공하면 형식적 변동이 사라지고, 내용의 변동만 남는다.
## 출력 형식 (엄격)
아래 구조를 정확히 따른다. 섹션을 생략하거나 순서를 변경하지 않는다.
### {함수명}
**시그니처:**
```{언어}
{함수 시그니처}파라미터: | 이름 | 타입 | 설명 | |—–|——|——| | … | … | … |
반환값: {타입} — {설명}
예외: {발생 가능한 예외와 조건}
#### 전략 2: 검증 기준을 정량화한다
"품질이 높아야 한다"는 정성적 기준은 실행마다 해석이 달라진다. 정량적 기준을 설정하면 검증 결과가 안정된다.
```markdown
## 검증 기준
1. 코드 커버리지: 테스트가 주요 분기를 80% 이상 커버
2. 문서화: 모든 public 함수에 docstring 존재
3. 네이밍: 언어별 네이밍 컨벤션 준수율 100%
4. 에러 처리: 외부 의존성 호출에 예외 처리 존재
“좋은 코드인가?”보다 “이 4가지를 모두 만족하는가?”가 일관된 판단을 가능하게 한다.
전략 3: few-shot 예시를 제공한다
원하는 결과물의 예시를 하나 이상 포함하면, 출력의 스타일과 수준이 예시에 수렴한다. 이 책의 chapter-writer 에이전트가 일관된 문체를 유지하는 이유 중 하나는, 이미 작성된 챕터가 암묵적인 few-shot 예시 역할을 하기 때문이다.
## 예시
아래는 올바른 출력의 예시이다. 이 형식과 수준을 따른다.
### 예시: validate_token 함수 (Python)
(구체적인 예시 코드와 테스트 코드)전략 4: 핵심 규칙에 강조 표시를 한다
프롬프트가 길어지면 LLM이 모든 지시를 동일한 비중으로 처리하지 않을 수 있다. 절대 위반해서는 안 되는 규칙에는 강조를 추가한다.
## 작업 원칙
- 변수명은 camelCase를 사용한다
- 함수는 단일 책임 원칙을 따른다
- **[CRITICAL] 외부 라이브러리는 절대 추가하지 않는다. 표준 라이브러리만 사용한다.**
- **[CRITICAL] 기존 테스트를 수정하지 않는다. 새 테스트만 추가한다.**[CRITICAL] 태그가 모든 경우에 효과적이라고 보장할 수는 없지만, 규칙 간 우선순위를 명시하면 위반 확률이 줄어든다.
실습: 실패하는 하네스를 단계별로 디버깅하기
이 절에서는 실제로 문제가 발생한 하네스를 단계별로 진단하고 수정하는 시나리오를 따라간다. 가상의 “기술 블로그 자동화” 하네스를 사용한다.
시나리오 설정
다음과 같은 하네스가 있다고 하자.
# 기술 블로그 자동화 하네스
## 에이전트 팀
| 에이전트 | 역할 | 모델 |
|---------|------|------|
| topic-researcher | 주제 리서치 | sonnet |
| blog-writer | 블로그 글 작성 | opus |
| seo-optimizer | SEO 최적화 | sonnet |
## 워크플로우
Phase 1: topic-researcher → 주제 분석 결과 → output/research.md
Phase 2: blog-writer → 블로그 초안 → output/draft.md
Phase 3: seo-optimizer → SEO 최적화 → output/final.md이 하네스를 실행하자 세 가지 문제가 연쇄적으로 발생한다.
문제 1: topic-researcher가 호출되지 않음
오케스트레이터가 “블로그 주제를 조사해줘”라고 지시했는데, topic-researcher가 호출되지 않고 blog-writer가 호출되었다.
진단:
에이전트 description을 확인한다.
# topic-researcher
description: "기술 트렌드를 분석하는 리서처. '기술 트렌드', 'tech trend' 요청 시 트리거."
# blog-writer
description: "블로그 글을 작성하는 작가. '블로그', 'blog', '글 작성' 요청 시 트리거."문제가 보인다. 오케스트레이터의 지시에는 “블로그 주제를 조사”라는 표현이 있다. “블로그”라는 키워드가 blog-writer의 트리거에 해당하여, topic-researcher 대신 blog-writer가 호출된 것이다. 한편 topic-researcher의 트리거에는 “조사”, “리서치”, “주제 분석” 같은 키워드가 없다.
수정:
두 가지를 동시에 수정한다.
# topic-researcher — 트리거 키워드 확장
description: "기술 트렌드를 분석하는 리서처. '주제 조사', '주제 분석', '리서치',
'기술 트렌드', 'topic research' 요청 시 트리거."
# blog-writer — 트리거를 더 구체적으로
description: "블로그 글을 작성하는 작가. '블로그 작성', '블로그 집필',
'초안 작성', 'write blog' 요청 시 트리거."blog-writer에서 단독 “블로그”를 제거하고 “블로그 작성”으로 구체화한 것이 핵심이다. 이렇게 하면 “블로그 주제를 조사”라는 표현이 blog-writer를 트리거하지 않는다.
문제 2: blog-writer가 research.md를 무시함
Phase 1을 수정한 후 다시 실행하니, topic-researcher가 정상적으로 output/research.md를 생성했다. 그런데 Phase 2의 blog-writer가 이 파일의 내용을 전혀 반영하지 않고, 자체적으로 주제를 선정하여 글을 작성했다.
진단:
blog-writer의 에이전트 정의와 오케스트레이터의 Phase 2 지시를 확인한다.
# blog-writer 에이전트 정의 (발췌)
## 핵심 역할
1. 기술 블로그 글을 작성한다
2. 독자의 흥미를 끄는 도입부를 구성한다
3. 코드 예제를 포함한다
# 오케스트레이터 Phase 2 지시
Phase 2: blog-writer에게 블로그 초안을 작성하도록 한다.문제는 Phase 2의 지시에 입력 파일에 대한 언급이 없다는 것이다. blog-writer는 output/research.md의 존재를 모르므로, 자기 판단으로 글을 작성한 것이다. 에이전트 탓이 아니라 오케스트레이터의 지시가 불충분하다.
수정:
오케스트레이터의 Phase 2 지시를 보강한다.
### Phase 2: 블로그 작성
- **에이전트**: blog-writer
- **입력**: `output/research.md` (Phase 1 산출물)
- **지시**: "output/research.md의 분석 결과를 기반으로 블로그 초안을 작성하라.
research.md의 '추천 주제'와 '핵심 키워드'를 반드시 반영한다."
- **출력**: `output/draft.md`
- **검증**: draft.md가 research.md의 추천 주제를 다루고 있는지 확인입력 파일의 경로뿐 아니라, 어떤 정보를 어떻게 활용해야 하는지까지 명시하는 것이 포인트다.
문제 3: seo-optimizer가 원문을 과도하게 변경
Phase 2 수정 후 다시 실행하니, blog-writer가 research.md를 반영하여 좋은 초안을 생성했다. 그런데 Phase 3에서 seo-optimizer가 SEO 키워드를 삽입하면서 원문의 자연스러운 문체를 망가뜨렸다. 결과물이 키워드 스터핑처럼 보인다.
진단:
seo-optimizer의 에이전트 정의를 확인한다.
# seo-optimizer 에이전트 정의 (발췌)
## 핵심 역할
1. SEO 키워드를 분석하고 삽입한다
2. 메타 디스크립션을 생성한다
3. 제목 태그를 최적화한다
## 작업 원칙
- 핵심 키워드를 본문에 5회 이상 포함시킨다
- 부제목(H2, H3)에 키워드를 배치한다“5회 이상”이라는 규칙이 문제다. 이 규칙이 원문의 품질보다 우선하여, 에이전트가 부자연스럽게라도 키워드를 반복 삽입한 것이다.
수정:
SEO 최적화의 범위를 제한하고, 원문 보존 원칙을 추가한다.
## 작업 원칙
- **[CRITICAL] 원문의 문체와 논리 흐름을 보존한다.
내용 변경은 최소화하고, SEO 요소는 비파괴적으로 추가한다.**
- 키워드 삽입은 자연스러운 위치에만 (제목, 소제목, 첫 문단, 마지막 문단)
- 키워드 빈도 목표: 전체 본문의 1~2% (강제 삽입 금지)
- 메타 디스크립션, alt 텍스트 등 본문 외 요소를 우선 최적화“5회 이상”이라는 정량 규칙을 “1~2% 비율”로 완화하고, 원문 보존을 CRITICAL 규칙으로 격상한 것이 핵심이다.
디버깅 결과 요약
세 가지 문제와 해결 방법을 정리하면 다음과 같다.
| 문제 | 유형 | 원인 | 해결 |
|---|---|---|---|
| researcher 미호출 | 트리거 미스매치 | description 키워드 겹침 | 키워드 차별화 |
| research.md 무시 | 산출물 불일치 | 오케스트레이터의 입력 지시 누락 | Phase별 입력/출력 명시 |
| 원문 품질 파괴 | 에이전트 과잉 동작 | 작업 원칙의 우선순위 부재 | CRITICAL 규칙으로 범위 제한 |
이 시나리오에서 보듯, 하네스 디버깅은 한 번에 모든 문제를 해결하는 것이 아니라, 앞의 문제부터 순서대로 해결하며 다음 문제를 드러내는 과정이다. 소프트웨어 디버깅과 동일한 접근이다.
디버깅 원칙 정리
이 챕터에서 다룬 내용을 세 가지 원칙으로 압축한다.
원칙 1: 관찰 → 가설 → 검증 → 수정
소프트웨어 디버깅과 동일한 사이클을 따른다. 증상을 관찰하고, 원인에 대한 가설을 세우고, 가설을 검증하고, 수정한다. 하네스에서 “관찰”은 산출물 파일을 읽는 것이고, “검증”은 수정 후 해당 Phase만 재실행하는 것이다.
원칙 2: 한 번에 하나만 수정한다
여러 문제가 동시에 보여도, 한 번에 하나씩만 수정한다. 여러 변수를 동시에 바꾸면 어떤 수정이 효과를 냈는지 알 수 없다. TDD에서 “한 번에 하나의 테스트만” 원칙과 같다.
원칙 3: 수정 이력을 기록한다
어떤 문제에 어떤 수정을 적용했는지 기록한다. 하네스는 반복적으로 실행되므로, 과거에 해결한 문제가 다시 발생할 수 있다. 기록이 있으면 빠르게 대응할 수 있다.
# debugging-log.md
## {YYYY-MM-DD}: topic-researcher 호출 실패
- 증상: blog-writer가 대신 호출됨
- 원인: "블로그" 키워드가 blog-writer 트리거에 해당
- 수정: topic-researcher 트리거에 "주제 조사" 추가, blog-writer 트리거를 "블로그 작성"으로 구체화
- 결과: 정상 호출 확인정리
- 하네스의 문제는 대부분 산출물 불일치, 무한 루프, 컨텍스트 초과 세 가지 유형으로 수렴한다
- 산출물 불일치는 에이전트 간 계약(파일 경로, 형식, 필수 필드)을 구체적으로 명시하여 방지한다
- 무한 루프는 최대 반복 횟수와 사용자 개입 탈출 조건을 반드시 설정하여 방지한다
- 트리거 키워드는 에이전트 간 겹치지 않는 고유 키워드를 배정하고, 동사+목적어 조합으로 구체화한다
- Phase 실패 시 파일 기반 산출물과 진행 상태 파일 덕분에 실패한 Phase만 재실행할 수 있다
- 에이전트 분리/통합은 관찰되는 신호(프롬프트 비대화, 산출물 반복 불일치 등)를 기준으로 판단한다
- 성능 최적화는 sonnet 우선, opus는 필요할 때만 원칙과 컨텍스트 절약 기법을 조합한다
- 품질 안정화는 출력 템플릿 제약, 정량적 검증 기준, few-shot 예시로 하한선을 올린다
다음 챕터 미리보기
- Chapter 10에서는 지금까지 배운 모든 내용을 종합하여, 독자 자신의 도메인에 맞는 하네스를 처음부터 설계하는 워크시트를 제공한다
Chapter 10: 나만의 하네스 설계하기
이 챕터에서 배울 것
- 자신의 도메인을 분석하여 하네스가 필요한지 판단하는 체크리스트
- 작업 유형을 식별하고 전문 영역을 분해하는 방법
- Chapter 3의 아키텍처 패턴 선택 의사결정 트리를 종합적으로 적용하는 방법
- 에이전트 분리 기준 4가지를 실전에 재적용하는 방법
- 에이전트 1개부터 시작하여 점진적으로 확장하는 전략
- 빈칸을 채워가며 하네스를 설계하는 워크시트 사용법
- 완성된 하네스가 올바른지 자가 검증하는 최종 체크리스트
본문
이 챕터의 위치
Chapter 1에서 Agent와 Skill의 개념을 배웠다. Chapter 2~3에서 하네스의 구조와 아키텍처 패턴을 익혔다. Chapter 4~5에서 생성된 하네스의 구조를 이해했다. Chapter 6~8에서 세 가지 실전 사례를 분석했다. Chapter 2에서 메타 스킬로 자동 생성하는 법을, Chapter 9에서 디버깅하는 법을 배웠다.
이 모든 지식을 하나로 엮는 것이 이 챕터의 목적이다. “내 도메인에서 하네스를 만들려면 어디서부터 시작해야 하는가?”라는 질문에 답한다.
이 챕터는 설명보다 도구에 가깝다. 워크시트를 채우고, 체크리스트를 확인하고, 의사결정 트리를 따라가면 — 챕터를 다 읽었을 때 하네스의 초안이 손에 있다.
인포그래픽: 하네스 설계 전체 프로세스 요약
Step 1: 도메인 분석 — 하네스가 필요한가?
하네스를 설계하기 전에, 먼저 하네스가 정말 필요한지 판단해야 한다. Chapter 2에서 배웠듯이, 단일 에이전트로 충분한 작업에 하네스를 적용하면 오히려 복잡성만 늘어난다.
하네스 필요성 판단 체크리스트
아래 항목 중 3개 이상에 해당하면 하네스를 고려할 만하다.
| # | 질문 | 해당 여부 |
|---|---|---|
| 1 | 하나의 작업을 완료하려면 서로 다른 전문성이 2가지 이상 필요한가? | [ ] |
| 2 | 작업 단계 중 병렬로 처리할 수 있는 독립적인 부분이 있는가? | [ ] |
| 3 | 하나의 프롬프트에 모든 지시를 담으면 컨텍스트 윈도우가 부족해지는가? | [ ] |
| 4 | 생성된 결과물을 다른 관점에서 검증해야 품질이 보장되는가? | [ ] |
| 5 | 이 작업을 반복적으로 수행해야 하는가 (일회성이 아닌가)? | [ ] |
| 6 | 사람이 이 작업을 할 때 2명 이상의 역할 분담이 자연스러운가? | [ ] |
| 7 | 입력의 종류에 따라 처리 방식이 달라지는 분기가 있는가? | [ ] |
1~2개만 해당하면: 단일 에이전트 + 잘 작성된 스킬 하나로 충분하다. 하네스는 과잉 설계다.
3~4개 해당하면: 하네스가 도움이 된다. 에이전트 2~3개 규모로 시작하자.
5개 이상 해당하면: 하네스가 거의 필수다. 본격적으로 설계에 들어가자.
사례로 판단해보기
사례 A: 블로그 글 작성 “기술 블로그 글을 써줘”라는 요청. 전문성은 하나(글쓰기), 병렬 작업 없음, 컨텍스트 충분, 검증이 선택적, 일회성일 수 있음. 해당 항목: 0~1개. 하네스 불필요.
사례 B: 기술 블로그 자동화 시스템 “매주 3개 주제로 블로그 글을 쓰고, 리뷰하고, SEO 최적화하고, 발행해줘”라는 요청. 전문성: 글쓰기, 리뷰, SEO, 발행 (4가지). 주제별 병렬 가능. 컨텍스트에 모든 규칙 담기 어려움. 리뷰 검증 필요. 매주 반복. 해당 항목: 5개 이상. 하네스 필요.
이 차이를 만드는 핵심은 작업의 복잡도와 반복성이다.
Step 2: 작업 유형 식별과 전문 영역 분해
하네스가 필요하다고 판단했다면, 다음 단계는 어떤 작업들이 필요한지 식별하고, 어떤 전문성이 필요한지 분해하는 것이다.
작업 목록 작성법
자신의 도메인에서 최종 결과물이 나오기까지의 전체 과정을 적어보자. 이때 중요한 원칙은 사람이 하는 것처럼 단계를 나누는 것이다.
예를 들어 “기술 문서 번역 시스템”을 만든다고 하자.
1. 원문을 분석하여 기술 용어를 추출한다
2. 용어집을 기반으로 일관된 번역어를 결정한다
3. 본문을 번역한다
4. 번역 품질을 검수한다 (용어 일관성, 문맥 정확도)
5. 최종 포맷(마크다운, PDF)으로 변환한다
전문 영역 분해
각 작업이 요구하는 전문성을 파악한다. 핵심 질문: “이 작업을 잘 하려면 어떤 지식과 원칙이 필요한가?”
| 작업 | 필요한 전문성 | 필요한 원칙/지식 |
|---|---|---|
| 용어 추출 | 기술 도메인 이해 | 기술 용어 사전, 도메인 분류 기준 |
| 용어 번역어 결정 | 번역학 + 기술 도메인 | 기존 용어집, 번역 컨벤션 |
| 본문 번역 | 번역학 + 문장력 | 번역 원칙, 문체 가이드 |
| 품질 검수 | 편집/교정 | 품질 체크리스트, 오역 패턴 |
| 포맷 변환 | 문서 조판 | 템플릿, 포맷 규칙 |
이렇게 나열하면 자연스럽게 에이전트 후보가 보인다. “용어 추출”과 “용어 번역어 결정”은 같은 전문성(기술 용어 + 번역)을 공유하므로 하나로 묶을 수 있다. “본문 번역”은 별도의 집중이 필요하다. “품질 검수”는 번역자와 다른 관점이므로 분리한다.
Step 3: 에이전트 분리 기준 재점검
Chapter 2에서 배운 4가지 분리 기준을 다시 꺼내자. 이 책의 모든 사례에서 반복적으로 적용된 기준이다.
4가지 기준
| 기준 | 질문 | 분리 신호 |
|---|---|---|
| 전문성 | 이 두 작업이 요구하는 전문 지식이 다른가? | 작가와 편집자, 개발자와 테스터 |
| 병렬성 | 이 작업들을 동시에 처리할 수 있는가? | 챕터별 집필, 언어별 코드 생성 |
| 컨텍스트 부담 | 두 작업의 지시를 한 프롬프트에 담으면 과부하인가? | 코딩 컨벤션 3종 + 리뷰 체크리스트 |
| 재사용성 | 이 에이전트를 다른 하네스에서도 쓸 수 있는가? | 범용 리뷰어, 범용 포매터 |
적용 방법
Step 2에서 식별한 작업 목록의 각 쌍(pair)에 대해 4가지 기준을 적용한다.
작업 A와 작업 B를 같은 에이전트에 넣을 것인가?
전문성이 같은가? → 같으면 합치는 방향
병렬 처리가 필요한가? → 병렬이 필요하면 분리
컨텍스트가 과부하인가? → 과부하면 분리
재사용 가능한가? → 재사용하려면 분리
4가지 중 하나라도 “분리”를 가리키면 분리하는 것이 안전하다. 합칠 이유(전문성이 같음)보다 분리할 이유(병렬, 컨텍스트, 재사용)가 하나라도 있으면 분리한다.
흔한 실수: 과도한 분리
반대 방향의 실수도 있다. 에이전트를 너무 잘게 쪼개면 오케스트레이터의 복잡도가 급격히 올라간다.
분리가 과한 신호: - 에이전트 A의 출력이 에이전트 B의 입력과 1:1로 대응하고, B의 출력이 다시 C의 입력과 1:1로 대응한다. 세 에이전트가 사실상 하나의 작업을 세 토막으로 나눈 것이다. - 에이전트가 5줄짜리 프롬프트로 정의된다. 분리할 만큼의 전문성이 없다는 뜻이다. - 에이전트 간 통신이 에이전트 자체의 작업량보다 많다. 오버헤드가 작업을 초과한다.
이런 경우 합치는 것이 낫다. 3~7개가 적정 범위다. 이 책의 사례들을 보면 — book-writer 5개, 리서치 팀 5개, 코드 생성 5개 — 모두 이 범위 안에 있다.
Step 4: 아키텍처 패턴 선택
에이전트 후보를 확정했다면, 이들을 어떤 구조로 연결할지 결정해야 한다. Chapter 3에서 배운 4가지 패턴의 의사결정 트리를 종합적으로 적용한다.
종합 의사결정 트리
다음 질문을 순서대로 따라가자.
Q1. 작업들 사이에 순서 의존성이 있는가?
│
├─ 전부 순차 의존 → 파이프라인
│
├─ 일부 순차, 일부 독립 → Q2로
│
└─ 대부분 독립 → Q2로
Q2. 독립적인 작업들을 동시에 처리하고 결과를 합칠 필요가 있는가?
│
├─ 예 → 팬아웃/팬인 (+ 순차 부분은 파이프라인)
│
└─ 아니오 → Q3으로
Q3. 입력의 종류에 따라 다른 전문가를 호출해야 하는가?
│
├─ 예 → 전문가풀 (+ 라우터 설계 필수)
│
└─ 아니오 → Q4로
Q4. 생성된 결과물의 품질 검증이 필요하고, 기준 미달 시 재작업해야 하는가?
│
├─ 예 → 생성-검증 루프
│
└─ 아니오 → 파이프라인 (가장 단순한 구조로 시작)
패턴은 조합된다
이 의사결정 트리에서 하나의 답만 나오는 경우는 드물다. 실전에서는 Phase별로 다른 패턴이 적용된다.
| 사례 | Phase 1 | Phase 2 | Phase 3 | Phase 4 |
|---|---|---|---|---|
| 책 집필 (Ch7) | 파이프라인 | 파이프라인 | 생성-검증 | 파이프라인 |
| 리서치 팀 (Ch8) | 파이프라인 | 팬아웃/팬인 | 파이프라인 | — |
| 코드 생성 (Ch9) | 전문가풀 | 전문가풀 | 생성-검증 | 파이프라인 |
각 Phase에서 “이 단계의 작업 특성에 맞는 패턴은 무엇인가?”를 독립적으로 판단한다.
패턴 선택 요약표
| 패턴 | 핵심 조건 | 전형적 Phase |
|---|---|---|
| 파이프라인 | A의 출력이 B의 입력 | 초기 분석, 최종 정리 |
| 팬아웃/팬인 | 독립 작업 동시 처리 + 통합 | 데이터 수집, 챕터별 작업 |
| 전문가풀 | 입력 종류에 따라 다른 전문가 | 라우팅, 언어/도메인별 처리 |
| 생성-검증 | 품질 기준 미달 시 재작업 | 콘텐츠 생성 후 리뷰 |
Step 5: 점진적 구축 전략
하네스 설계의 가장 큰 실수는 처음부터 완성형을 만들려는 것이다. 에이전트 5개, 복잡한 루프, 정교한 라우팅을 한 번에 구축하면 디버깅이 불가능해진다.
원칙: 에이전트 1개에서 시작한다
가장 핵심적인 에이전트 하나만 먼저 만들고, 그것이 제대로 동작하는지 확인한다. 그 다음 에이전트를 하나 추가하고, 둘 사이의 데이터 흐름을 확인한다. 이 과정을 반복한다.
4단계 확장 로드맵
1단계: 핵심 에이전트 1개
하네스의 목적을 가장 직접적으로 수행하는 에이전트 하나를 만든다. 책 집필이면 chapter-writer, 코드 생성이면 python-expert(언어 하나만).
이 단계에서 확인할 것: - 에이전트가 원하는 품질의 결과물을 생성하는가? - 프롬프트의 원칙이 실제로 반영되는가? - 출력 형식이 일관적인가?
2단계: 검증자 추가 (에이전트 2개)
핵심 에이전트의 결과물을 검증하는 에이전트를 추가한다. 이것이 가장 기본적인 생성-검증 구조다.
이 단계에서 확인할 것: - 검증자의 피드백이 구체적인가? - 피드백을 반영한 수정이 실제로 품질을 올리는가? - 루프가 3회 이내에 수렴하는가?
3단계: 분업 확대 (에이전트 3~5개)
나머지 에이전트를 추가한다. 각 에이전트가 추가될 때마다 오케스트레이터의 Phase를 함께 업데이트한다.
이 단계에서 확인할 것: - 에이전트 간 산출물 형식이 호환되는가? - 오케스트레이터의 Phase 순서가 논리적인가? - 각 Phase의 검증 기준이 명확한가?
4단계: 자동화 완성
모든 에이전트가 동작하면, 오케스트레이터 스킬을 정리하고 사용자 확인 포인트를 배치한다.
이 단계에서 확인할 것: - 전체 워크플로우를 처음부터 끝까지 한 번 돌릴 수 있는가? - 사용자 확인 없이 잘못된 방향으로 진행되는 구간이 없는가? - 에이전트 추가/제거가 다른 에이전트에 영향을 주지 않는가?
각 단계에서 커밋한다
점진적 구축의 핵심은 각 단계가 동작하는 상태를 유지하는 것이다. 1단계에서 에이전트 1개가 동작하면 커밋한다. 2단계에서 검증 루프가 동작하면 커밋한다. 3단계에서 가 추가될 때마다 커밋한다. 문제가 생기면 마지막 동작 상태로 돌아갈 수 있어야 한다.
Step 6: 하네스 설계 워크시트
여기까지의 단계를 하나의 워크시트로 정리했다. 빈칸을 채우면 하네스의 설계 초안이 완성된다.
워크시트 섹션 1: 도메인 정의
■ 하네스 이름: ___________________________________
■ 한 줄 설명: ___________________________________
■ 최종 산출물: ___________________________________
(예: 마크다운 문서, 코드 파일, 보고서 PDF)
■ 하네스 필요성 판단 (해당 항목에 체크):
[ ] 서로 다른 전문성 2가지 이상 필요
[ ] 병렬 처리 가능한 독립 작업 존재
[ ] 단일 프롬프트로 모든 지시 담기 어려움
[ ] 다른 관점에서의 검증 필요
[ ] 반복적으로 수행하는 작업
[ ] 사람이 해도 2명 이상 역할 분담
[ ] 입력 종류에 따라 처리 방식 분기
→ 체크 수: ___개 → 하네스 필요 여부: [ ] 필요 / [ ] 불필요
워크시트 섹션 2: 작업 분해
■ 전체 작업 흐름 (최종 산출물까지의 단계):
1. _________________________________________________
2. _________________________________________________
3. _________________________________________________
4. _________________________________________________
5. _________________________________________________
(필요시 추가)
■ 각 작업의 전문 영역:
| 작업 | 필요한 전문성 | 필요한 지식/원칙 |
|------|-------------|----------------|
| 1. | | |
| 2. | | |
| 3. | | |
| 4. | | |
| 5. | | |
워크시트 섹션 3: 에이전트 설계
■ 에이전트 분리 판단:
| 작업 쌍 | 전문성 | 병렬성 | 컨텍스트 | 재사용 | 판정 |
|---------|--------|--------|---------|--------|------|
| 1 vs 2 | 같/다 | 요/불 | 과/적 | 가/불 | 합/분 |
| 2 vs 3 | 같/다 | 요/불 | 과/적 | 가/불 | 합/분 |
| 3 vs 4 | 같/다 | 요/불 | 과/적 | 가/불 | 합/분 |
| ... | | | | | |
■ 확정된 에이전트 팀:
| 에이전트 이름 | 역할 | 모델 | 담당 작업 |
|-------------|------|------|----------|
| | | sonnet / opus | |
| | | sonnet / opus | |
| | | sonnet / opus | |
| | | sonnet / opus | |
| | | sonnet / opus | |
■ 모델 선택 근거:
- opus를 쓰는 에이전트: _________ (이유: __________________)
- sonnet을 쓰는 에이전트: ________ (이유: __________________)
워크시트 섹션 4: 아키텍처 패턴
■ 의사결정 트리 결과:
Q1. 작업 간 순서 의존성:
[ ] 전부 순차 → 파이프라인
[ ] 일부 순차 + 일부 독립 → 혼합
[ ] 대부분 독립 → 팬아웃/팬인
Q2. 독립 작업 동시 처리 필요:
[ ] 예 → 팬아웃/팬인 포함
[ ] 아니오
Q3. 입력 종류별 전문가 분기:
[ ] 예 → 전문가풀 포함
[ ] 아니오
Q4. 품질 검증 + 재작업 루프:
[ ] 예 → 생성-검증 포함
[ ] 아니오
■ Phase별 패턴 배정:
| Phase | 작업 내용 | 패턴 | 에이전트 |
|-------|---------|------|---------|
| 1 | | | |
| 2 | | | |
| 3 | | | |
| 4 | | | |
(필요시 추가)
워크시트 섹션 5: 데이터 흐름과 산출물
■ 산출물 디렉토리 구조:
{프로젝트}/
├── .claude/
│ ├── agents/
│ │ ├── __________________.md
│ │ ├── __________________.md
│ │ └── __________________.md
│ └── skills/
│ └── __________________/
│ ├── SKILL.md
│ └── references/
│ └── __________________.md
└── {산출물 디렉토리명}/
├── __________________ (Phase 1 산출물)
├── __________________ (Phase 2 산출물)
└── __________________ (Phase 3 산출물)
■ 에이전트 간 데이터 흐름:
[___________] → {산출물: ___________} → [___________]
→ {산출물: ___________} → [___________]
■ 각 Phase의 검증 기준:
| Phase | 검증 기준 | 실패 시 행동 |
|-------|---------|------------|
| 1 | | |
| 2 | | |
| 3 | | |
■ 생성-검증 루프 (해당 시):
- 생성자: _________________
- 검증자: _________________
- 최대 반복: ___회
- FAIL 조건: ___________________
- 최대 반복 도달 시: ___________________
워크시트 섹션 6: 점진적 구축 계획
■ 1단계 (에이전트 1개):
- 먼저 만들 에이전트: _________________
- 확인할 것: _________________________
■ 2단계 (에이전트 2개):
- 추가할 에이전트: _________________
- 확인할 것: _________________________
■ 3단계 (에이전트 3~5개):
- 추가할 에이전트들: _________________
- 확인할 것: _________________________
■ 4단계 (자동화 완성):
- 오케스트레이터 정리 사항: _________________
- 사용자 확인 포인트: _________________
Step 7: 워크시트 적용 예시 — “기술 문서 번역 시스템”
빈 워크시트가 어떻게 채워지는지 하나의 예시를 통해 보여주겠다. 실제로 빈칸을 채우는 과정을 따라가자.
섹션 1: 도메인 정의 (채운 예시)
■ 하네스 이름: doc-translator
■ 한 줄 설명: 기술 문서를 용어 일관성을 유지하며 한영/영한 번역하는 하네스
■ 최종 산출물: 번역된 마크다운 문서 + 용어집
■ 하네스 필요성 판단:
[x] 서로 다른 전문성 2가지 이상 필요 (용어 관리, 번역, 검수)
[ ] 병렬 처리 가능한 독립 작업 존재
[x] 단일 프롬프트로 모든 지시 담기 어려움
[x] 다른 관점에서의 검증 필요 (번역자 ≠ 검수자)
[x] 반복적으로 수행하는 작업
[x] 사람이 해도 2명 이상 역할 분담
[ ] 입력 종류에 따라 처리 방식 분기
→ 체크 수: 5개 → 하네스 필요 여부: [x] 필요
섹션 3: 에이전트 설계 (채운 예시)
■ 확정된 에이전트 팀:
| 에이전트 이름 | 역할 | 모델 | 담당 작업 |
|-------------|------|------|----------|
| term-analyst | 기술 용어 추출 + 번역어 결정 | sonnet | 1, 2 |
| doc-translator | 본문 번역 | opus | 3 |
| translation-reviewer | 번역 품질 검수 | sonnet | 4 |
■ 모델 선택 근거:
- opus: doc-translator (번역은 문맥 이해와 문장력이 필요한 창의적 작업)
- sonnet: term-analyst (용어 매칭은 규칙 기반), translation-reviewer (체크리스트 대조)
섹션 4: 아키텍처 패턴 (채운 예시)
■ Phase별 패턴 배정:
| Phase | 작업 내용 | 패턴 | 에이전트 |
|-------|---------|------|---------|
| 1 | 용어 추출 + 번역어 결정 | 파이프라인 | term-analyst |
| 2 | 본문 번역 | 파이프라인 | doc-translator |
| 3 | 품질 검수 + 수정 | 생성-검증 | doc-translator + translation-reviewer |
Phase 1의 용어집이 Phase 2의 입력이 되므로 파이프라인이다. Phase 3은 검수자가 피드백하고 번역자가 수정하는 생성-검증 루프다.
에이전트 3개, Phase 3개. 단순하지만 충분하다. 이것이 첫 번째 버전이다.
만약 나중에 문서가 10개 챕터로 구성되어 있고 챕터별 병렬 번역이 필요해지면, Phase 2에 팬아웃/팬인을 도입한다. 하지만 그 필요가 실제로 생길 때 추가하는 것이지, 처음부터 설계하지 않는다.
Step 8: 최종 자가 검증 체크리스트
워크시트를 모두 채웠다면, 마지막으로 설계가 올바른지 검증한다. 아래 체크리스트의 모든 항목을 통과해야 한다.
A. 에이전트 설계 검증
| # | 검증 항목 | 통과 |
|---|---|---|
| A1 | 각 에이전트의 역할이 한 문장으로 설명 가능한가? | [ ] |
| A2 | 두 에이전트의 역할이 중복되지 않는가? | [ ] |
| A3 | 에이전트가 3~7개 범위 안에 있는가? (2개 이하면 하네스 불필요, 8개 이상이면 과도한 분리) | [ ] |
| A4 | 각 에이전트의 model 선택에 명확한 근거가 있는가? (opus: 창의적 생성, sonnet: 규칙 기반 판단) | [ ] |
| A5 | 어떤 에이전트도 “만능”이 아닌가? (모든 작업을 하나가 담당하지 않는가) | [ ] |
B. 아키텍처 검증
| # | 검증 항목 | 통과 |
|---|---|---|
| B1 | 각 Phase에 적용된 패턴이 해당 작업의 특성과 맞는가? | [ ] |
| B2 | 생성-검증 루프가 있다면, 최대 반복 횟수가 설정되어 있는가? | [ ] |
| B3 | 생성-검증 루프의 FAIL 조건이 구체적인가? (“품질 미달”이 아니라 “CRITICAL 이슈 1개 이상”) | [ ] |
| B4 | 팬아웃/팬인이 있다면, 통합 기준이 명시되어 있는가? | [ ] |
| B5 | 전문가풀이 있다면, 라우팅 규칙이 키워드 기반으로 명시되어 있는가? | [ ] |
C. 데이터 흐름 검증
| # | 검증 항목 | 통과 |
|---|---|---|
| C1 | 모든 에이전트의 입력과 출력이 명시되어 있는가? | [ ] |
| C2 | 에이전트 A의 출력 형식이 에이전트 B의 입력 기대와 일치하는가? | [ ] |
| C3 | 산출물 파일의 저장 경로가 충돌하지 않는가? | [ ] |
| C4 | 각 Phase 완료 후 사용자 확인 포인트가 있는가? | [ ] |
| C5 | 에이전트 간 통신이 파일 기반으로 이루어지는가? (직접 호출이 아닌 산출물 전달) | [ ] |
D. 운영 검증
| # | 검증 항목 | 통과 |
|---|---|---|
| D1 | 새 에이전트를 추가할 때 기존 에이전트를 수정하지 않아도 되는가? | [ ] |
| D2 | 점진적 구축 계획이 있는가? (1단계부터 시작) | [ ] |
| D3 | 에이전트 하나가 실패해도 전체 하네스가 멈추지 않는 복구 전략이 있는가? | [ ] |
| D4 | Chapter 7의 디버깅 기법을 적용할 수 있는 구조인가? (Phase별 산출물 추적 가능) | [ ] |
통과하지 못한 항목이 있다면
각 항목의 해결 방향:
- A3 미통과 (에이전트 수): 에이전트가 적으면 분리 기준을 다시 적용하고, 너무 많으면 유사 역할을 통합한다.
- B2 미통과 (최대 반복 미설정): 3회를 기본값으로 설정한다. Chapter 7에서 다뤘듯이, 3회가 비용과 품질의 적절한 균형이다.
- B3 미통과 (FAIL 조건 모호): 이슈를 CRITICAL, MAJOR, MINOR로 분류하고, CRITICAL과 MAJOR만 FAIL 조건에 넣는다.
- C2 미통과 (형식 불일치): 에이전트 A의 출력 규칙과 에이전트 B의 입력 기대를 나란히 놓고, 필드명과 구조가 일치하는지 확인한다.
- C4 미통과 (사용자 확인 없음): 최소한 Phase 1 완료 후와 최종 Phase 전에 사용자 확인을 넣는다.
- D1 미통과 (확장성 부족): 에이전트 추가가 다른 에이전트의 수정을 요구한다면, 오케스트레이터의 구조를 “선택된 에이전트를 호출한다” 같은 간접 참조 방식으로 변경한다.
전체 프로세스 요약
이 챕터에서 다룬 하네스 설계 전체 과정을 한눈에 정리한다.
[Step 1] 하네스가 필요한가?
│ 필요성 판단 체크리스트 (7항목 중 3개 이상)
│
▼
[Step 2] 어떤 작업이 필요한가?
│ 작업 목록 작성 + 전문 영역 분해
│
▼
[Step 3] 에이전트를 어떻게 나누는가?
│ 분리 기준 4가지: 전문성, 병렬성, 컨텍스트, 재사용성
│
▼
[Step 4] 어떤 구조로 연결하는가?
│ 의사결정 트리 → Phase별 패턴 배정
│
▼
[Step 5] 어떤 순서로 만드는가?
│ 에이전트 1개 → 검증자 추가 → 분업 확대 → 자동화 완성
│
▼
[Step 6] 워크시트로 구체화한다
│ 6개 섹션 빈칸 채우기
│
▼
[Step 7] 예시를 참고하여 적용한다
│
▼
[Step 8] 자가 검증 체크리스트로 확인한다
│ A(에이전트) + B(아키텍처) + C(데이터) + D(운영)
│ 모든 항목 통과 → 구축 시작
│
▼
[구축 시작]
점진적 구축 계획에 따라 1단계부터 실행
마무리: 하네스는 도구이지 목적이 아니다
이 책을 통해 하네스의 개념, 패턴, 작성법, 실전 사례, 자동 생성, 디버깅, 그리고 직접 설계하는 방법까지 배웠다. 마지막으로 한 가지를 강조하고 싶다.
하네스는 도구다. 문제를 해결하기 위한 수단이지, 만드는 것 자체가 목적이 아니다.
단일 에이전트와 스킬 하나로 충분하다면, 하네스를 만들지 마라. 에이전트 2개면 되는데 5개를 만들지 마라. 파이프라인이면 되는데 전문가풀을 쓰지 마라.
이 판단을 도와주는 것이 이 챕터의 체크리스트와 워크시트다. Step 1의 필요성 판단에서 “불필요”가 나왔다면, 그것이 올바른 답이다. 하네스를 만들지 않는 것도 좋은 설계 결정이다.
반대로, 하네스가 필요한 상황이라면 — 이 책이 제공한 프레임워크를 따라 설계하고, 점진적으로 구축하고, 체크리스트로 검증하자. Chapter 1에서 시작한 여정이 여기서 완성된다.
이제 당신의 도메인에 워크시트를 펼칠 차례다.
정리
- 하네스 필요성은 먼저 판단한다. 7가지 질문 중 3개 이상에 해당할 때만 하네스를 고려한다. 과잉 설계를 방지하는 첫 번째 관문이다.
- 작업을 먼저 나열하고, 에이전트는 나중에 도출한다. “에이전트를 몇 개 만들까”가 아니라 “어떤 작업이 필요한가”에서 시작한다. 작업의 전문 영역이 자연스럽게 에이전트 경계를 만든다.
- 분리 기준 4가지(전문성, 병렬성, 컨텍스트, 재사용성)를 매번 적용한다. 하나라도 “분리”를 가리키면 분리한다. 합칠 이유보다 분리할 이유가 우선한다.
- 패턴은 Phase별로 독립 선택한다. 하나의 하네스에 하나의 패턴만 쓸 필요 없다. 각 Phase의 작업 특성에 맞는 패턴을 각각 적용한다.
- 에이전트 1개에서 시작하여 점진적으로 확장한다. 처음부터 완성형을 만들지 않는다. 각 단계에서 동작을 확인하고 커밋한다. 문제가 생기면 마지막 동작 상태로 돌아간다.
- 워크시트는 설계를 구체화하는 도구다. 6개 섹션을 채우면 하네스의 초안이 완성된다. 예시를 참고하되, 자신의 도메인에 맞게 변형한다.
- 자가 검증 체크리스트로 설계를 마무리한다. 에이전트(A), 아키텍처(B), 데이터 흐름(C), 운영(D) 4개 영역의 모든 항목을 통과해야 구축을 시작한다.
- 하네스를 만들지 않는 것도 좋은 설계 결정이다. 도구는 문제를 해결하기 위해 존재한다. 문제가 단순하면 단순한 해결책이 최선이다.
부록 안내
부록에서는 실전에서 바로 사용할 수 있는 참고 자료를 제공한다:
- Appendix A: 에이전트 정의 템플릿 — 빈 템플릿과 작성 가이드
- Appendix B: 스킬 정의 템플릿 — 빈 템플릿과 작성 가이드
- Appendix C: 아키텍처 패턴 치트시트 — 4가지 패턴의 한 장 요약
- Appendix D: 용어집 — 하네스, 에이전트, 스킬, 오케스트레이터 등 핵심 용어 정의
Chapter 11: 메타 스킬 커스터마이징
이 챕터에서 배울 것
- harness 메타 스킬의 파일 구조와 설치 위치, 각 파일의 역할
- references/ 디렉토리의 레퍼런스 파일을 수정하여 메타 스킬의 생성 결과를 바꾸는 방법
- 기존 에이전트/스킬과 새 하네스가 충돌하지 않도록 방지하는 전략 (이름 충돌, 역할 중복, 디렉토리 충돌)
- 기존 하네스에 에이전트를 추가/제거하여 재구성하고, 다른 도메인으로 확장하는 방법
- 수동 구성과 메타 스킬 자동 생성의 차이를 이해하고 상황에 맞게 선택하는 기준
- 메타 스킬을 효과적으로 활용하기 위한 실전 팁 3가지
- 팀/조직 전체에서 공유하는 표준 템플릿을 만들어 일관된 하네스를 생성하는 방법
본문
Chapter 10에서 harness 메타 스킬로 하네스를 자동 생성하는 과정을 배웠다. 6단계 워크플로우가 도메인 분석부터 검증까지 자동으로 수행한다는 것을 확인했다. 하지만 메타 스킬이 생성하는 결과는 출발점이지 완성본이 아니다.
“메타 스킬은 뼈대를 세우고, 사용자가 살을 붙인다.” Chapter 10에서 이 원칙을 언급했다. 이 챕터에서는 그 살을 붙이는 구체적인 방법을 다룬다. 메타 스킬 자체를 수정하여 자신의 팀과 조직에 맞게 확장하는 것이다.
메타 스킬 파일의 구조
메타 스킬을 커스터마이징하려면 먼저 그 구조를 정확히 알아야 한다. harness 메타 스킬은 다음 경로에 위치한다.
~/.claude/skills/harness/
├── SKILL.md # 메타 스킬 본체
└── references/
├── agent-design-patterns.md # 아키텍처 패턴 레퍼런스
└── team-examples.md # 팀 구성 예시
세 파일의 역할을 하나씩 살펴보자.
SKILL.md — 메타 스킬의 본체
SKILL.md는 메타 스킬의 핵심이다. 이 파일이 정의하는 것은 네 가지다.
- frontmatter:
name,description으로 스킬의 이름과 트리거 키워드를 정의한다 - 6단계 워크플로우: 도메인 분석 → 팀 설계 → 에이전트 생성 → 스킬 생성 → 오케스트레이터 생성 → 검증
- 생성 원칙: 에이전트 파일의 구조, frontmatter 형식, 출력 형식 규칙
- 검증 체크리스트: Phase 6에서 수행하는 6항목 검증
SKILL.md를 수정하면 메타 스킬의 동작 자체가 바뀐다. 예를 들어 Phase 6의 검증 항목을 추가하거나, 에이전트 파일의 필수 섹션을 변경할 수 있다. 하지만 SKILL.md의 수정은 신중해야 한다. 워크플로우의 핵심 구조를 함부로 바꾸면 생성 결과의 품질이 떨어질 수 있다.
권장: SKILL.md는 가능한 한 그대로 유지하고, references/ 파일을 수정하여 생성 결과를 조절하는 것이 안전하다.
agent-design-patterns.md — 패턴 레퍼런스
이 파일에는 Chapter 3에서 배운 4가지 아키텍처 패턴의 요약이 담겨 있다.
- 파이프라인, 팬아웃/팬인, 전문가풀, 생성-검증
- 각 패턴의 적용 조건
- 에이전트 분리 기준 4가지
메타 스킬이 Phase 2(팀 아키텍처 설계)에서 이 파일을 참조하여 도메인에 적합한 패턴을 선택한다. 이 파일을 수정하면 메타 스킬이 어떤 패턴을 선택하는지에 영향을 줄 수 있다.
team-examples.md — 팀 구성 예시
이 파일에는 다양한 도메인의 팀 구성 예시가 포함되어 있다. SF 소설 팀, 웹툰 팀, 리서치 팀 등의 구성 사례다.
메타 스킬이 Phase 2에서 에이전트를 분리하고 역할을 정의할 때 이 예시를 참조한다. 여기에 자신의 도메인에 맞는 예시를 추가하면, 메타 스킬이 그 예시를 참고하여 더 적합한 팀 구조를 생성한다.
파일 위치의 의미
~/.claude/ 경로에 있다는 것은 이 메타 스킬이 사용자 레벨의 범용 도구임을 의미한다. 프로젝트 레벨(.claude/)이 아니므로, 어떤 프로젝트에서든 “하네스 구성해줘”라고 요청하면 동작한다.
이 위치는 커스터마이징의 관점에서 중요한 의미를 가진다. ~/.claude/skills/harness/를 수정하면 이후 생성하는 모든 하네스에 영향을 준다. 특정 프로젝트에만 적용하고 싶은 변경이라면 메타 스킬을 수정하는 것이 아니라, 생성된 결과물을 프로젝트 레벨에서 직접 수정하는 것이 맞다.
references/ 커스터마이징
메타 스킬 커스터마이징의 핵심은 references/ 디렉토리에 있다. SKILL.md를 건드리지 않고도 생성 결과를 크게 바꿀 수 있다.
agent-design-patterns.md 수정
이 파일을 수정하는 대표적인 시나리오 두 가지가 있다.
시나리오 1: 새로운 패턴 추가
4가지 기본 패턴 외에 팀에서 자주 사용하는 패턴이 있다면 추가할 수 있다. 예를 들어 “단계적 승인 패턴”이 있다고 하자. 각 Phase의 산출물을 관리자가 승인해야 다음 Phase로 넘어가는 구조다.
### 패턴 5: 단계적 승인 (Staged Approval)
- 적용 조건: 각 단계의 산출물이 조직의 승인 프로세스를 거쳐야 할 때
- 구조: 파이프라인과 유사하지만, 각 Phase 사이에 승인 게이트가 삽입됨
- 에이전트: 생성 에이전트 + 승인 검토 에이전트
- 적합한 도메인: 규제 산업 문서, 법률 문서, 공식 보고서이 패턴을 추가하면 메타 스킬이 Phase 2에서 “이 도메인에는 단계적 승인이 필요한가?”를 추가로 판단한다.
시나리오 2: 에이전트 분리 기준 조정
기본 분리 기준은 전문성, 병렬성, 컨텍스트 부담, 재사용성 4가지다. 팀에서 추가 기준이 필요하면 여기에 명시한다.
### 추가 분리 기준: 보안 등급
- 민감한 데이터를 다루는 에이전트는 별도로 분리한다
- 보안 등급이 다른 작업은 같은 에이전트에 넣지 않는다
- 예: 고객 개인정보를 다루는 에이전트와 외부 API를 호출하는 에이전트를 분리team-examples.md 수정
이 파일의 수정이 가장 효과적이고 안전한 커스터마이징 방법이다. 메타 스킬은 새 하네스를 생성할 때 기존 예시를 참고하므로, 자신의 도메인과 비슷한 예시를 추가하면 생성 품질이 올라간다.
### 예시: 데이터 파이프라인 팀
- 도메인: 데이터 수집 → 정제 → 분석 → 리포트 자동화
- 패턴: 파이프라인 + 생성-검증
- 에이전트 구성:
| 에이전트 | 역할 | 모델 |
|---------|------|------|
| data-collector | 데이터 소스에서 원시 데이터 수집 | sonnet |
| data-cleaner | 데이터 정제, 이상치 제거 | sonnet |
| data-analyst | 통계 분석, 인사이트 도출 | opus |
| report-writer | 분석 결과를 보고서로 작성 | opus |
| report-reviewer | 보고서 정확성과 일관성 검증 | sonnet |
- 모델 선택 근거:
- opus: 분석과 글쓰기에 창의성과 깊은 문맥 이해 필요
- sonnet: 수집, 정제, 검증은 규칙 기반 작업이 예시를 추가한 후 “데이터 분석 보고서 하네스를 구성해줘”라고 요청하면, 메타 스킬이 이 예시를 참고하여 더 적합한 팀 구조를 생성한다.
수정 시 주의사항
references/ 파일을 수정할 때 지켜야 할 원칙이 있다.
- 기존 내용을 삭제하지 않는다. 추가만 한다. 기본 패턴과 예시는 메타 스킬의 범용성을 보장하는 기반이다.
- 형식을 일관되게 유지한다. 기존 예시의 마크다운 구조(헤딩 레벨, 테이블 형식)를 따른다. 메타 스킬이 이 형식을 기대하기 때문이다.
- 실제 경험에 기반한 예시를 추가한다. 이론적인 예시보다, 실제로 구축하여 동작을 확인한 팀 구성이 훨씬 유용하다.
기존 하네스와의 충돌 방지
프로젝트에 이미 에이전트나 스킬이 존재할 때, 메타 스킬로 새 하네스를 생성하면 충돌이 발생할 수 있다. Chapter 10에서 세 가지 충돌 유형을 소개했다. 여기서는 각 유형의 구체적인 방지 전략을 심화한다.
이름 충돌 — 네이밍 컨벤션으로 해결
기존에 code-reviewer.md가 있는데 새 하네스에서도 코드 리뷰 에이전트가 필요한 경우.
방지 전략: 도메인 접두어 네이밍 컨벤션을 정한다.
기존: code-reviewer.md
새로: blog-code-reviewer.md (도메인: blog)
pipeline-code-reviewer.md (도메인: pipeline)
네이밍 컨벤션을 팀에서 합의하면 이후 충돌을 원천 차단할 수 있다. 권장 형식은 {도메인}-{역할}.md다.
이 컨벤션을 team-examples.md에 명시해두면, 메타 스킬이 에이전트를 생성할 때 자동으로 접두어를 붙인다.
### 네이밍 규칙
- 에이전트: {도메인}-{역할}.md (예: blog-writer.md, pipeline-analyst.md)
- 스킬 디렉토리: {도메인}-{스킬명}/ (예: blog-writing/, pipeline-analysis/)
- 오케스트레이터: {도메인}/ (예: tech-blog/, data-pipeline/)역할 중복 — 재사용 vs 신규 생성 판단
기존 에이전트가 새 하네스에서 필요한 역할을 이미 수행하고 있는 경우.
판단 기준:
| 조건 | 판정 | 이유 |
|---|---|---|
| 기존 에이전트의 역할이 새 하네스의 요구와 90% 이상 일치 | 재사용 | 중복 에이전트는 유지보수 부담 |
| 역할은 비슷하지만 작업 원칙이나 출력 형식이 크게 다르다 | 신규 생성 | 한 에이전트에 두 가지 원칙을 넣으면 혼란 |
| 기존 에이전트가 다른 하네스의 오케스트레이터에서 참조 중이다 | 재사용 + 확장 | 기존 정의를 수정하면 기존 하네스에 영향 |
세 번째 경우가 가장 까다롭다. 기존 에이전트를 수정하면 이미 동작 중인 하네스가 영향을 받는다. 이때는 기존 에이전트를 그대로 유지하고, 새 하네스의 오케스트레이터에서 해당 에이전트를 참조하되 추가 지시는 오케스트레이터의 Phase 설명에 넣는 방식이 안전하다.
디렉토리 충돌 — 스킬 경로 분리
기존에 .claude/skills/blog-writer/가 있는데, 새 하네스도 같은 디렉토리를 사용하려는 경우.
방지 전략: 스킬 디렉토리에 도메인 네임스페이스를 적용한다.
.claude/skills/
├── blog-writer/ # 기존 (범용 블로그 스킬)
│ └── SKILL.md
├── tech-blog-writer/ # 새 하네스 (기술 블로그 전용)
│ ├── SKILL.md
│ └── references/
└── tech-blog/ # 오케스트레이터
└── SKILL.md
디렉토리 이름이 다르면 Claude Code가 별도의 스킬로 인식한다. 기존 스킬의 기능을 확장하고 싶다면 새 디렉토리에서 기존 스킬의 내용을 포함하되, 추가 레퍼런스를 references/에 넣는 방식으로 구성한다.
충돌 방지 종합 원칙
세 가지 충돌 유형에 공통되는 핵심 원칙이 하나 있다.
메타 스킬은 기존 파일을 절대 덮어쓰지 않는다. 충돌이 감지되면 사용자에게 알리고, 대안(이름 변경, 재사용, 디렉토리 분리)을 제시한다. 자동화가 기존 작업을 파괴하는 것은 가장 위험한 실수다.
이 원칙이 지켜지려면 Phase 1(도메인 분석)의 “기존 에이전트/스킬 확인” 단계가 제대로 동작해야 한다. 메타 스킬이 .claude/agents/와 .claude/skills/를 스캔하여 기존 파일 목록을 파악하고, 충돌 가능성을 미리 보고하는 것이다.
하네스 재구성과 확장
메타 스킬은 새 하네스를 생성하는 것뿐 아니라, 기존 하네스를 수정하거나 다른 도메인에 응용하는 데도 활용할 수 있다.
재구성: 에이전트 추가
기존 하네스에 에이전트를 추가하는 시나리오다.
사용자: 기술 블로그 하네스에 SEO 최적화 에이전트를 추가해줘
메타 스킬이 수행하는 작업은 세 가지다.
- 기존 하네스를 분석한다.
.claude/agents/와.claude/skills/tech-blog/SKILL.md를 읽어 현재 팀 구성과 워크플로우를 파악한다. - 새 에이전트 파일을 생성한다.
.claude/agents/blog-seo-optimizer.md를 생성한다. 기존 에이전트 파일은 수정하지 않는다. - 오케스트레이터를 업데이트한다. 에이전트 구성 테이블에 새 에이전트를 추가하고, 적절한 Phase에 배치한다. 기존 Phase의 구조는 가능한 한 유지한다.
핵심은 기존 에이전트를 수정하지 않는다는 원칙이다. Chapter 8의 코드 생성 하네스에서 Go 전문가를 추가할 때 기존 Python 전문가나 Java 전문가를 수정하지 않았던 것과 같은 원칙이다. 새 에이전트는 새 파일로 추가하고, 오케스트레이터만 업데이트한다.
재구성: 에이전트 제거
반대로 에이전트를 제거하는 경우도 있다.
사용자: 기술 블로그 하네스에서 코드 예제 에이전트를 제거해줘.
이 블로그는 코드가 필요 없는 개념 설명 위주야.
이 경우 수행할 작업:
code-crafter.md파일을 삭제한다 (또는 이름을 변경하여 비활성화한다).- 오케스트레이터에서 code-crafter를 참조하는 모든 부분을 제거한다.
blog-writer의 협업 섹션에서 code-crafter 관련 내용을 수정한다.- Phase 2의 “코드 플레이스홀더” 관련 절차를 제거한다.
에이전트 제거는 추가보다 더 주의가 필요하다. 제거된 에이전트를 참조하는 모든 곳을 찾아 수정해야 한다. 하나라도 놓치면 오케스트레이터가 존재하지 않는 에이전트를 호출하려는 오류가 발생한다.
권장 절차:
- 제거 대상 에이전트의 이름으로 모든
.claude/파일을 검색한다 - 참조하는 파일 목록을 확인한다
- 각 파일에서 해당 참조를 제거하거나 수정한다
- 에이전트 파일을 삭제한다
- 오케스트레이터의 Phase 구조가 여전히 논리적인지 확인한다
확장: 다른 도메인에 응용
기존 하네스의 구조를 참고하여 완전히 다른 도메인의 하네스를 만들 수 있다.
사용자: 기술 블로그 하네스와 비슷한 구조로 마케팅 뉴스레터 하네스를 구성해줘
이때 메타 스킬은 기존 하네스를 “템플릿”으로 활용한다.
| 기술 블로그 에이전트 | 마케팅 뉴스레터 에이전트 | 역할 변환 |
|---|---|---|
| topic-researcher | trend-researcher | 기술 트렌드 → 마케팅 트렌드 |
| blog-writer | newsletter-writer | 기술 글 → 마케팅 카피 |
| code-crafter | (불필요) | 코드 예제 → 해당 없음 |
| tech-reviewer | marketing-reviewer | 기술 정확성 → 마케팅 메시지 일관성 |
| blog-editor | newsletter-editor | 기술 글 편집 → 뉴스레터 편집 |
아키텍처 패턴(파이프라인 + 생성-검증)은 그대로 재사용할 수 있다. 리서치 → 작성 → 검증 → 편집의 순차 흐름은 도메인이 바뀌어도 유효하기 때문이다. 달라지는 것은 각 에이전트의 전문성과 작업 원칙이다.
이것이 하네스 아키텍처의 강점이다. 에이전트의 역할은 도메인에 종속되지만, 에이전트 간의 구조적 관계는 도메인을 넘어 재사용 가능하다.
수동 구성과 메타 스킬의 비교
어떤 상황에서 메타 스킬을 사용하고, 어떤 상황에서 수동으로 구성해야 하는가? 아래 비교 테이블로 판단 기준을 정리한다.
| 항목 | 수동 구성 | 메타 스킬 |
|---|---|---|
| 도메인 분석 | 사용자가 직접 분석 | 메타 스킬이 분석, 사용자가 확인 |
| 팀 설계 | 사용자가 패턴 선택, 분리 기준 적용 | 메타 스킬이 제안, 사용자가 확인 |
| 파일 생성 | 에이전트/스킬 파일을 하나씩 작성 | 한 번에 모든 파일 생성 |
| 형식 일관성 | 사용자가 템플릿을 참고하며 유지 | 메타 스킬이 자동으로 보장 |
| 검증 | 사용자가 직접 체크리스트 확인 | Phase 6에서 자동 검증 |
| 소요 시간 | 에이전트 수 x 작성 시간 | 요청 1회 + 확인 수 회 |
| 세밀한 제어 | 모든 세부사항을 직접 결정 | 메타 스킬의 판단에 의존 후 수정 |
| 학습 효과 | 구조를 깊이 이해하게 됨 | 빠르게 시작하지만 구조 이해가 얕을 수 있음 |
메타 스킬이 유리한 경우
- 새 하네스를 처음 만들 때: 빈 캔버스에서 시작하는 것보다 뼈대가 있는 상태에서 수정하는 것이 빠르다.
- 3개 이상의 에이전트가 필요할 때: 에이전트가 많아질수록 수동 작성의 형식 불일치 위험이 높아진다.
- 팀원 간 일관성이 필요할 때: 같은 메타 스킬을 사용하면 팀원마다 다른 형식으로 작성하는 문제를 방지한다.
수동 구성이 유리한 경우
- 에이전트가 1~2개일 때: 메타 스킬의 6단계 워크플로우가 과잉이다.
- 매우 특수한 도메인일 때: 메타 스킬의 references/에 유사 예시가 없어 생성 품질이 낮을 수 있다.
- 기존 하네스를 미세 조정할 때: 에이전트 하나의 작업 원칙을 3줄 수정하는 데 메타 스킬을 호출할 필요는 없다.
권장: 메타 스킬로 시작하고, 수동으로 다듬는다
대부분의 경우 최선의 전략은 두 가지를 조합하는 것이다.
- 메타 스킬로 하네스의 뼈대를 생성한다
- 생성된 파일을 열어 도메인에 맞게 수정한다
- 에이전트의 작업 원칙, 출력 형식, 검증 기준을 구체화한다
- 오케스트레이터의 Phase 순서와 검증 조건을 세밀히 조정한다
이 조합이 효과적인 이유는 Part 2에서 수동 구성을 먼저 배운 덕분이다. 구조를 이해해야 자동 생성 결과를 검토하고 수정할 수 있다. 구조를 모르면 메타 스킬이 내린 판단이 적절한지 판단할 수 없다.
메타 스킬 활용의 팁
Chapter 10에서 소개한 세 가지 팁을 더 구체적으로 확장한다.
팁 1: 요청을 구체적으로 하라
메타 스킬의 Phase 1(도메인 분석)이 정확하려면 입력이 구체적이어야 한다.
# 나쁜 요청
"블로그 하네스 만들어줘"
# 보통 요청
"기술 블로그 자동화 하네스를 구성해줘"
# 좋은 요청
"기술 블로그 자동화 하네스를 구성해줘.
주제 선정부터 편집까지 자동화하고 싶어.
코드 예제가 포함된 기술 글을 작성하는 거야.
대상 독자는 중급 개발자야.
주 1회 발행 기준이고, Python과 TypeScript 코드를 다뤄."
좋은 요청에 포함된 정보는 다섯 가지다.
| 정보 | 역할 |
|---|---|
| 도메인: 기술 블로그 | Phase 1의 도메인 식별 |
| 범위: 주제 선정 ~ 편집 | 에이전트 팀의 범위 결정 |
| 특성: 코드 예제 포함 | code-crafter 같은 전문 에이전트 필요성 판단 |
| 독자: 중급 개발자 | 에이전트의 작업 원칙에 반영 |
| 주기/기술: 주 1회, Python/TypeScript | 구체적인 컨벤션과 레퍼런스 범위 결정 |
정보가 많을수록 메타 스킬의 추측 범위가 좁아지고, 생성 결과의 정확도가 올라간다.
팁 2: Phase 2 결과를 꼼꼼히 검토하라
Phase 2(팀 아키텍처 설계)는 메타 스킬이 가장 큰 판단을 내리는 곳이다. 여기서 결정된 에이전트 구성과 패턴이 이후 모든 Phase의 기반이 된다.
Phase 2 결과를 검토할 때 확인해야 할 질문 목록:
- 에이전트 수가 적절한가? 3~7개가 적정 범위다. 2개 이하면 하네스가 불필요하고, 8개 이상이면 과도한 분리다.
- 분리 근거가 납득되는가? 각 에이전트의 분리 이유가 전문성, 병렬성, 컨텍스트 부담, 재사용성 중 하나 이상에 해당해야 한다.
- 빠진 역할은 없는가? 요청에서 언급한 작업 중 에이전트가 배정되지 않은 것이 있는지 확인한다.
- 선택된 패턴이 적합한가? Chapter 3의 의사결정 트리를 머릿속으로 따라가보고, 메타 스킬의 선택이 일치하는지 확인한다.
- 모델 선택이 합리적인가? 창의적 생성에는 opus, 규칙 기반 판단에는 sonnet이 적용되었는지 확인한다.
Phase 2에서 문제를 발견하면 즉시 피드백한다. “에이전트가 너무 많다”, “이 두 에이전트는 하나로 합쳐도 될 것 같다”, “검증 에이전트가 빠져 있다” 같은 구체적인 피드백이 좋다. 메타 스킬은 피드백을 반영하여 Phase 2를 다시 실행한다.
팁 3: 생성 후 커스터마이징하라
메타 스킬이 생성한 결과물에서 가장 자주 수정하게 되는 부분 세 가지:
첫째, 에이전트의 작업 원칙을 구체화한다.
메타 스킬이 생성하는 작업 원칙은 도메인의 일반적인 수준이다. “한 섹션에 하나의 개념만 다룬다”는 좋은 원칙이지만, 실제 블로그에는 “코드 블록 앞에 반드시 실행 환경 정보를 명시한다”, “외부 링크는 최소 3개 이상 포함한다” 같은 도메인 고유의 원칙이 필요하다.
둘째, 검증 기준을 강화한다.
메타 스킬이 생성하는 검증 기준(CRITICAL, MAJOR, MINOR 분류)은 범용적이다. 여기에 팀의 품질 기준을 반영해야 한다. 예를 들어 “deprecated API 사용은 CRITICAL” 또는 “500자 미만의 섹션은 MAJOR”를 추가할 수 있다.
셋째, 산출물의 출력 형식을 정밀하게 정의한다.
에이전트 간 산출물은 계약이다. Chapter 9에서 배운 것처럼, 파일 경로, 파일 형식, 필수 필드를 구체적으로 명시해야 다음 에이전트가 안정적으로 파싱할 수 있다. 메타 스킬이 생성하는 출력 형식은 기본적인 수준이므로, 실제 운영에 맞게 세부 구조를 추가한다.
심화: 조직 표준 템플릿 만들기
지금까지는 개인이 메타 스킬을 커스터마이징하는 방법을 다뤘다. 이 섹션에서는 팀이나 조직 전체에서 일관된 하네스를 생성하기 위한 표준 템플릿을 만드는 방법을 다룬다.
왜 조직 표준이 필요한가
팀원 5명이 각자 메타 스킬을 커스터마이징하면, 5가지 다른 스타일의 하네스가 만들어진다. 에이전트 네이밍 규칙, 출력 형식, 검증 기준이 모두 다르다. 한 사람이 만든 하네스를 다른 사람이 수정하거나 확장해야 할 때, 구조를 이해하는 데 시간이 걸린다.
조직 표준 템플릿은 이 문제를 해결한다. 메타 스킬의 references/ 파일을 팀에서 합의한 내용으로 통일하고, 모든 팀원이 같은 references/를 사용하면 생성되는 하네스의 형식과 품질이 일관된다.
표준 템플릿 구성 요소
조직 표준 템플릿에 포함해야 할 항목은 네 가지다.
1. 네이밍 컨벤션
## 네이밍 규칙
### 에이전트
- 형식: {도메인}-{역할}.md
- 예: blog-writer.md, pipeline-analyst.md, api-tester.md
- 금지: 한글 파일명, 공백 포함, 대문자
### 스킬 디렉토리
- 형식: {도메인}-{스킬명}/
- 예: blog-writing/, pipeline-analysis/
### 오케스트레이터
- 형식: {도메인}/SKILL.md
- 예: tech-blog/SKILL.md, data-pipeline/SKILL.md
### 산출물 디렉토리
- 형식: {도메인}-output/
- 예: blog-output/, pipeline-output/2. 에이전트 필수 섹션
## 에이전트 필수 섹션
모든 에이전트 파일에 반드시 포함해야 할 섹션:
1. frontmatter (name, description, model)
2. 역할 선언 (한 문장으로)
3. 핵심 역할 (번호 목록, 3~5개)
4. 작업 원칙 (번호 또는 불릿 목록)
5. 출력 형식 (파일 경로 + 마크다운 구조 예시)
6. 협업 (입력 소스와 출력 대상 명시)3. 검증 기준 분류 체계
## 검증 기준 분류
모든 검증 에이전트는 다음 분류를 사용한다:
### CRITICAL (FAIL — 즉시 수정)
- 사실과 다른 정보
- 보안 취약점
- 실행 불가능한 코드
### MAJOR (FAIL — 수정 권장)
- 요구사항 미충족
- 형식 불일치
- 일관성 위반
### MINOR (PASS — 기록만)
- 스타일 개선 제안
- 선택적 최적화4. 도메인별 팀 구성 예시
팀에서 실제로 운영 중인 하네스를 예시로 등록한다. 이론적인 예시보다 실전 경험에 기반한 예시가 훨씬 유용하다.
표준 템플릿 배포 방법
조직 표준 템플릿을 팀원에게 배포하는 방법은 세 가지다.
방법 1: Git 저장소로 관리
~/.claude/skills/harness/references/ 디렉토리를 Git으로 관리한다. 팀원이 저장소를 클론하여 자신의 ~/.claude/skills/harness/references/에 배치한다.
# 표준 템플릿 저장소
harness-templates/
├── agent-design-patterns.md # 팀 커스텀 패턴 포함
└── team-examples.md # 팀 실전 예시 포함
팀원이 표준 템플릿을 업데이트할 때는 저장소에서 pull한다. 변경 이력이 Git으로 추적되므로, 누가 어떤 변경을 했는지 확인할 수 있다.
방법 2: 셋업 스크립트
새 팀원이 합류하면 실행하는 셋업 스크립트에 references/ 복사를 포함한다.
#!/bin/bash
# 하네스 메타 스킬 표준 템플릿 설치
HARNESS_DIR="$HOME/.claude/skills/harness"
TEMPLATE_REPO="https://github.com/your-org/harness-templates.git"
mkdir -p "$HARNESS_DIR/references"
git clone "$TEMPLATE_REPO" /tmp/harness-templates
cp /tmp/harness-templates/*.md "$HARNESS_DIR/references/"
echo "하네스 표준 템플릿 설치 완료"방법 3: 문서로 공유
가장 단순한 방법이다. Confluence, Notion 같은 문서 도구에 표준 템플릿의 내용을 기록하고, 팀원이 직접 복사하여 적용한다. Git 관리보다 진입 장벽이 낮지만, 버전 관리가 어렵다.
표준 템플릿 유지보수
표준 템플릿은 한 번 만들고 끝나는 것이 아니다. 팀의 경험이 쌓이면서 지속적으로 업데이트해야 한다.
업데이트해야 할 시점:
- 새로운 도메인의 하네스를 성공적으로 구축했을 때 → team-examples.md에 사례 추가
- 반복적으로 같은 문제가 발생할 때 → 검증 기준이나 작업 원칙에 해당 규칙 추가
- 팀의 기술 스택이 바뀌었을 때 → 코딩 컨벤션이나 도구 설정 업데이트
- 새로운 패턴이 유효함을 확인했을 때 → agent-design-patterns.md에 패턴 추가
핵심은 실전에서 검증된 것만 표준에 넣는다는 원칙이다. 이론적으로 좋아 보이지만 실제로 검증되지 않은 패턴이나 예시를 표준에 넣으면, 오히려 생성 품질을 떨어뜨릴 수 있다.
정리
- 메타 스킬의 커스터마이징은 references/ 파일 수정부터 시작한다. SKILL.md(본체)는 가능한 한 유지하고, agent-design-patterns.md와 team-examples.md를 수정하여 생성 결과를 조절한다. 기존 내용을 삭제하지 않고 추가하는 것이 원칙이다.
- 이름 충돌, 역할 중복, 디렉토리 충돌 — 세 가지 충돌 유형에 대한 방지 전략이 있다. 도메인 접두어 네이밍 컨벤션, 재사용 vs 신규 생성 판단 기준, 디렉토리 네임스페이스 분리로 해결한다. 핵심 원칙: 메타 스킬은 기존 파일을 절대 덮어쓰지 않는다.
- 하네스 재구성(에이전트 추가/제거)은 기존 파일을 건드리지 않는 방향으로 진행한다. 새 에이전트는 새 파일로 추가하고, 제거 시에는 참조하는 모든 곳을 확인한 후 정리한다.
- 기존 하네스의 구조는 다른 도메인에 재사용할 수 있다. 에이전트의 역할은 도메인에 종속되지만, 아키텍처 패턴과 에이전트 간의 구조적 관계는 도메인을 넘어 재사용 가능하다.
- 메타 스킬과 수동 구성은 상호 보완적이다. 메타 스킬로 뼈대를 생성하고, 수동으로 도메인에 맞게 다듬는 조합이 대부분의 상황에서 최선이다.
- 세 가지 팁: 구체적 요청, Phase 2 검토, 생성 후 커스터마이징. 특히 Phase 2(팀 설계)의 결과를 꼼꼼히 검토하는 것이 생성 품질을 결정한다.
- 조직 표준 템플릿으로 팀 전체의 하네스 품질을 통일할 수 있다. 네이밍 컨벤션, 필수 섹션, 검증 기준, 팀 구성 예시를 표준화하고 Git으로 관리하면, 누가 만들어도 일관된 구조의 하네스가 생성된다.
- 메타 스킬은 뼈대를 세우고, 사용자가 살을 붙인다. 이것이 이 책 전체를 관통하는 원칙이다. 자동화는 반복 작업을 줄여주지만, 도메인에 대한 깊은 이해와 판단은 사람의 몫이다.
부록 안내
이 챕터로 본문이 마무리된다. Chapter 0에서 하네스의 전체 그림을 살펴본 것으로 시작하여, Part 1에서 핵심 개념을, Part 2에서 구조를, Part 3에서 실전 사례를, Part 4에서 운영과 확장을 다뤘다.
부록에서는 실전에서 바로 사용할 수 있는 참고 자료를 제공한다:
- Appendix A: 에이전트 정의 템플릿 — frontmatter부터 협업 섹션까지의 빈 템플릿과 각 섹션의 작성 가이드. 새 에이전트를 만들 때 이 템플릿을 복사하여 빈칸을 채우면 된다.
- Appendix B: 스킬 정의 템플릿 — SKILL.md의 빈 템플릿과 references/ 구성 가이드. 오케스트레이터 스킬과 개별 에이전트 스킬 양쪽의 템플릿을 포함한다.
- Appendix C: 아키텍처 패턴 치트시트 — 파이프라인, 팬아웃/팬인, 전문가풀, 생성-검증 4가지 패턴의 한 장 요약. 패턴 선택 의사결정 트리, 각 패턴의 적용 조건과 주의사항을 빠르게 참조할 수 있다.
- Appendix D: 용어집 — 하네스, 에이전트, 스킬, 오케스트레이터, 메타 스킬, 아키텍처 패턴 등 이 책에서 사용한 핵심 용어의 정의를 모아놓았다.