들어가며
Design Doc 작성을 자동화하고 싶었다.
디자인 시안을 확인하고, 기획서를 읽고, 코드베이스를 파악해서 초안을 뽑아주는 것. 그게 /design-doc Command의 목표였다.
Command는 금방 만들었다. 문제는 그 다음이었다. Command가 호출할 Custom Agent를 어떻게 설계할 것인가.
두 번의 설계 전환과 여러 실패 끝에 현재 구조에 도달했다. 이 글은 그 여정이다.
1. 첫 번째 시도: Agent 중심 설계
처음엔 고정된 4개 Agent를 병렬로 호출하는 구조였다.
/design-doc 실행
↓
Main Agent가 4개 Agent 병렬 호출
├── code-researcher (코드베이스 분석)
├── doc-researcher (내부 문서 분석)
├── external-researcher (외부 도구 전부)
└── app-researcher (실제 앱 동작 확인)
↓
결과 조합 → Design Doc 초안
구조가 단순하고 역할이 명확해 보였다.
문제 1: 하나가 느리면 전체가 느리다
code-researcher가 Opus 모델로 실행되면서 전체가 지연됐다. 다른 Agent들은 이미 끝났는데 하나를 기다리고 있었다.
문제 2: 불필요한 리서치도 실행된다
입력에 포함되지 않은 소스도 조사하려 했다. 필요 없는 일을 하고 있었다.
문제 3: Agent 역할이 너무 넓다
external-researcher 하나가 디자인 도구, 문서 도구, 웹을 전부 처리해야 했다. 각 플랫폼의 특성이 다른데, 하나의 프롬프트에 다 담으려니 비대해졌다.
2. 전환: Task 중심 설계
Agent 단위가 아니라 Task 단위로 생각을 바꿨다.
입력: "A 기능 개선. 디자인: ..., 기획서: ..."
↓
Main Agent가 입력 분석 → 필요한 Task 도출
↓
Research Tasks (필요한 것만):
├── design-review
├── feature-spec
└── code-module-analysis
↓
Design Task → Write Task → 완료
핵심 변화:
- Task가 작고 구체적
- 필요한 Task만 선택적으로 실행
- Agent는 Task 수행을 위한 도구
3. external-researcher 분리
Task 중심으로 바꾸면서, external-researcher도 분리했다.
external-researcher (1개)
↓ 분리
design-researcher (디자인 도구)
docs-researcher (문서 도구)
web-researcher (웹)
분리 이유
각 소스의 특성이 다르다:
- 디자인 도구: 빠른 분석 vs 상세 분석 전략 필요
- 문서 도구: 인증 방식, 페이지 구조 파악 방식 다름
- 웹: MCP가 아닌 기본 도구 사용
실패 처리가 다르다:
- 디자인 도구 권한 없음 → 공유 설정 확인 요청
- 문서 도구 접근 불가 → 토큰 확인 요청
- 웹 타임아웃 → 다른 URL 시도
URL 패턴으로 쉽게 결정 가능:
- 디자인 도구 URL → design-researcher
- 문서 도구 URL → docs-researcher
- 그 외 → web-researcher
4. 상태 태그 패턴
분리하고 나니 새로운 문제가 생겼다. Agent가 실패했을 때 어떻게 알릴 것인가.
문제 상황
MCP 연결이 끊기거나 권한이 없을 때, Agent가 이렇게 반응했다:
“접근할 수 없습니다.”
그리고 끝. Command는 이게 재시도 가능한 건지, 포기해야 하는 건지 알 수 없었다. 모든 외부 연동에서 같은 문제가 있었다.
해결: 상태 태그
Agent가 결과물 최상단에 상태를 명시하게 했다:
[BLOCKED:mcp-disconnected]
## 분석 대상
- URL: https://...
## 실패 사유
MCP 연결이 끊어졌습니다. 연결 확인 후 재시도해주세요.
| 상태 | 설명 | Command 후처리 |
|---|---|---|
[SUCCESS] |
정상 완료 | 다음 단계 진행 |
[BLOCKED:reason] |
사용자 조건 필요 | 사용자에게 전달, 대기 |
[PARTIAL] |
부분 완료 | 결과 활용, 미완료 명시 |
[FAILED:reason] |
복구 불가 | 사용자에게 알림 |
Blocked 사유 코드: auth-error, permission-denied, invalid-input, mcp-disconnected
핵심 규칙: [BLOCKED:*]는 Agent가 임의로 스킵하지 않는다. 반드시 호출자에게 전달.
5. 책임 분리 원칙
상태 태그를 설계하면서 정리한 원칙이다. Agent는 “누가 호출하는지” 몰라야 한다.
| 구성 요소 | 책임 |
|---|---|
| Agent | Output 형식 정의, 실행 로직, Quality Gate, 상태 반환 |
| Command | 워크플로우 정의, Agent 호출 순서, 경로 지정, 결과 조합, 상태별 후처리 |
Agent가 하지 않는 것:
- 저장 경로 결정 (호출자가 지정)
- “Command”라는 개념 언급 (호출자 독립적)
- 다음 단계 결정 (상태만 반환)
이유:
- Agent는 Command가 호출할 수도, 사용자가 직접 호출할 수도, 다른 Agent가 호출할 수도 있다
- 호출자가 누구든 동일하게 동작해야 한다
6. 커뮤니티 리서치: 6-Section 구조
여기까지 만들고 나서 다른 사람들은 어떻게 하는지 궁금해졌다.
wshobson/agents(26k⭐), VoltAgent(6k⭐) 등을 조사했다. 공통된 구조가 있었다.
커뮤니티 6-Section
| 섹션 | 목적 |
|---|---|
| Role Definition | 에이전트 정체성/전문성 |
| Expertise Areas | 기술 스택 나열 |
| Workflow | 단계별 실행 절차 |
| Communication Protocol | 에이전트 간 통신 규약 |
| Output Format | 결과물 형식 |
| Quality Checklist | 완료 전 검증 항목 |
정리된 구조가 있다는 게 좋았다. 하지만 내 상황과 맞지 않는 부분도 있었다.
7. 6-Section에서 부족했던 것
입력 스펙이 없다
“이 Agent가 뭘 받아야 하는지”가 없다. URL만? URL + 질문? 분석 깊이 옵션?
실패 케이스가 없다
외부 서비스 연동 Agent에게 실패 처리는 필수다. MCP는 끊기고, API는 타임아웃 나고, 권한은 없다.
Quality Checklist는 “잘 됐을 때” 검증이다. “안 됐을 때” 대응이 없다.
Communication Protocol은 필요했다
반대로, 6-Section에 있는데 내 구조에 없는 것도 있었다.
지금 내 상태 태그는 단방향이다. Agent → Command로 상태 전달만 한다.
8. 최종 구조: 8-Section
6-Section을 참고하고, 내 경험을 더해서 정리한 구조다.
| 섹션 | 목적 | 비고 |
|---|---|---|
| YAML Frontmatter | name, description, tools, model | description이 자동 위임 판단에 사용됨 |
| 역할 정의 | 한 줄로 핵심만 | |
| 입력 | 필수/선택 파라미터 | 6-Section에 없음 |
| 실행 | 단계별 절차 | 도구가 많으면 전략 포함 |
| Output | 상태 태그 + 결과 템플릿 | 상태 태그 최상단 |
| Quality Gate | 자가 검증 체크리스트 | |
| 실패 시 | 상황별 상태 코드와 대응 | 6-Section에 없음 |
| 주의 사항 | 자주 하는 실수 방지 | 6-Section에 없음 |
6-Section과 비교
| 6-Section | 8-Section |
|---|---|
| Role Definition | 역할 정의 |
| Expertise Areas | ❌ (전문 Agent엔 불필요) |
| Workflow | 실행 |
| Communication Protocol | ❌ (개선 예정) |
| Output Format | Output (상태 태그 추가) |
| Quality Checklist | Quality Gate |
| ❌ | 입력 |
| ❌ | 실패 시 |
| ❌ | 주의 사항 |
9. 개선 포인트: Communication Protocol
아직 구현 안 한 게 하나 있다. Communication Protocol이다.
현재는 상태 태그로 단방향 반환만 한다:
Command → Agent → [SUCCESS] 결과
향후 구조화된 프로토콜을 추가하면, 더 유연한 통신이 가능해질 것이다:
- 상태 보고에 메타 정보 추가
- Agent 간 위임 요청
다음 개선 과제로 남겨둔다.
마무리
배운 것들:
-
Agent 중심보다 Task 중심: Agent 단위로 생각하면 역할이 비대해진다. Task 단위로 쪼개라.
-
범용보다 전문화: 플랫폼 특성이 다르면 분리하라.
-
상태 태그로 소통하라: Agent가 막히면 상태로 알려야 한다.
-
책임을 분리하라: Agent는 상태만 반환, 후처리는 호출자가.
-
입력과 실패를 설계하라: 6-Section엔 없지만, 외부 연동 Agent엔 필수다.
-
커뮤니티를 참고하되 맹신하지 마라: 내 상황에 맞게 조정하라.