2편에서 바이브로 작은 앱을 올렸다면, 곧 이런 벽이 옵니다. 채팅이 길어지고, 에이전트가 예전에 한 말을 잊고, “고친다”며 다른 파일을 부수고, 리뷰 없이 Accept All 한 코드가 프로덕션에 못 갑니다.
핵심 한 줄: 에이전트 엔지니어링의 첫 단계는 더 긴 프롬프트가 아니라 역할을 나누고, 핸드오프를 계약으로 고정하는 것입니다.
이 글은 「코딩은 대화다」 3편입니다. 1편(도구 고르기) · 2편(바이브 코딩) 다음에, 멀티에이전트로 올라갑니다.
왜 한 채팅으로는 부족해지나
바이브 코딩(한 에이전트·코드를 거의 안 봄)은 프로토타입에 강합니다. 하지만 일이 커지면 한 컨텍스트에 연구·구현·검증이 뒤섞입니다.
| 증상 | 한 에이전트일 때 | 역할 분리 후 |
|---|---|---|
| 컨텍스트 폭발 | 검색 로그가 본 대화를 잠식 | Research가 요약만 넘김 |
| 범위 팽창 | “顺便으로” 인증·DB까지 추가 | Implement의 out-of-scope에 명시 |
| 품질 착각 | 스스로 “완료” 선언 | Review/Fact-check가 게이트 |
| 재현 불가 | 같은 프롬프트에 다른 결과 | 입·출력 스키마로 고정 |
Martin Fowler가 말한 agentic programming(LLM이 쓰더라도 사람이 구조를 돌봄)으로 가려면, 도구 UI만 Agent로 바꾸는 게 아니라 일의 조직도가 필요합니다.
에이전트 엔지니어링 = 역할 + 계약 + 게이트
PapaCoder Labs 스펙은 에이전트를 “거대한 만능 프롬프트”가 아니라 직무 카드로 정의합니다 (specs/11-agent-architecture.md 요지):
- Goal — 한 가지 책임
- Inputs / Outputs — 다음 에이전트가 파싱할 구조화된 산출물
- Prompt — 버전된 프롬프트 파일
- Tools — 쓸 수 있는 MCP/도구 (최소 권한)
- Retry / Quality — 실패 시 행동과 점수 게이트
에디토리얼 팀은 실제로 EiC → Research → Outline → Writer → Humanizer → Review → Fact Check → SEO → Publisher(초안만)처럼 DAG로 움직입니다. 사람은 마지막에 Publish합니다.
Rendering diagram…
핵심은 화살표입니다. 무엇을 넘기는지가 다음 역할의 전부입니다.
핸드오프는 문장이 아니라 계약
느슨한 핸드오프 예:
“로그인 알아봤어. 대충 NextAuth 쓰면 될 듯.”
계약형 핸드오프 예:
{
"from": "research",
"to": "implement",
"goal": "Add email/password admin login only",
"decisions": [
"Use existing Better Auth email/password",
"No OAuth in this slice"
],
"constraints": [
"Do not touch public signup",
"Do not add new tables beyond what schema already has"
],
"outOfScope": ["SSO", "passkeys", "mobile app"],
"acceptance": [
"Admin can sign in with ADMIN_EMAIL/PASSWORD",
"Non-admin redirected to login"
],
"sources": ["specs/09-api-design.md §auth"]
}
받는 쪽 규칙: 스키마가 깨지면 구현하지 말고 STOP을 반환합니다. 이게 멀티에이전트의 90%입니다.
실습: 미니 뉴스룸 3역할 (Cursor / 아무 Agent UI)
목표: 레포에 짧은 기술 노트 초안을 넣되, 한 채팅에 몰지 않습니다. 세 번의 Agent 세션(또는 서브에이전트)으로 나눕니다.
역할 카드 A — Research (읽기 위주)
You are ResearchAgent.
Goal: Produce ResearchBrief JSON only. Do not edit product code.
Inputs: topic string from the user.
Output schema:
{
"topic": string,
"keyFacts": string[],
"sources": [{"url": string, "title": string}],
"uncertainties": string[],
"outOfScope": string[]
}
Rules:
- At least 2 real URLs you opened or that exist in-repo docs
- No implementation advice beyond naming libraries
- If sources conflict, list under uncertainties
Return JSON only.
역할 카드 B — Implement
You are ImplementAgent.
Goal: Apply the smallest code/docs change that satisfies acceptance.
Inputs: the ResearchBrief JSON + Outline (sections list).
Rules:
- Read ResearchBrief first; if required fields missing → reply STOP with what's missing
- Do not expand outOfScope
- Prefer editing existing files over new frameworks
- End with: files changed, how to verify, residual risks
역할 카드 C — Review
You are ReviewAgent.
Goal: Gate the change. Do not implement fixes unless asked.
Check:
1) acceptance items from the brief
2) no secrets committed
3) scope creep vs outOfScope
4) claims that need citations
Output:
{
"pass": boolean,
"blockingIssues": string[],
"nits": string[],
"rewriteInstructions": string[]
}
If pass=false, Implement must re-run with rewriteInstructions only.
진행 순서 (복사)
- 새 채팅에 Research 카드 + 토픽:
예: "Next.js App Router에서 loading.tsx가 하는 일" - 나온 JSON을 저장 (
research-brief.json). - 새 채팅에 Implement 카드 + 그 JSON 첨부.
- 새 채팅에 Review 카드 + diff/요약 첨부.
pass=false면 Implement만 재실행 — Research를 섞지 않기.
처음 멀티에이전트를 돌릴 때, 같은 창에서 역할을 바꿔 가며 쓰다가 Research가 파일을 수정해 버린 적이 있습니다. 그다음부터는 채팅을 나누거나, 도구 권한을 읽기 전용으로 막는 쪽을 먼저 합니다.
도구별 힌트 (2026-08-02)
Claude Code subagents
공식 문서상 서브에이전트는 별도 컨텍스트에서 일하고 요약만 메인으로 돌려줍니다. Explore(읽기)·Plan·general-purpose 등이 내장되어 있고, 커스텀은 .claude/agents/에 Markdown+YAML로 둡니다 (Subagents).
“검색 로그가 본 대화를 잠식할 때” 쓰라는 안내와, 이 글의 Research 분리와 같은 결입니다.
Cursor
Cursor에서도 Task/서브에이전트·별도 채팅으로 역할을 분리할 수 있습니다. 중요한 건 UI 이름보다 입력·출력 계약을 파일로 남기는 것입니다 (research-brief.json, review.json). PapaCoder처럼 agents/editorial/*.md + packages/agents/prompts/에 카드와 프롬프트를 버전 관리하는 방식이 장기적으로 이깁니다.
실패 모드 (멀티에이전트 특유)
| 실패 | 증상 | 완화 |
|---|---|---|
| 계약 없음 | 다음 에이전트가 산문만 받음 | JSON/스키마 강제 |
| 역할 오염 | Research가 코드 수정 | 도구 allowlist / 새 채팅 |
| 게이트 없음 | Review 없이 merge | pass 필드 + 사람 확인 |
| 무한 핑퐁 | Review↔Implement 루프 | max 2 retries 후 사람 |
| 병렬 충돌 | 두 에이전트가 같은 파일 | 파일 소유권 파티션 |
| 환각 출처 | 없는 URL | Fact-check 역할 또는 링크 검증 |
언제 4편(하네스)으로 넘어가나
역할과 핸드오프만으로도 체감이 큽니다. 그래도 이런 요구가 생기면 하네스 엔지니어링이 필요합니다.
- 샌드박스·네트워크·시크릿 주입을 프롬프트가 아니라 런타임이 강제
- 테스트/린트를 에이전트가 “했다고 말함”이 아니라 CI가 검증
- 같은 작업을 여러 번 돌려 점수화
루프·그래프(5–6편)는 그 위의 제어 구조입니다.
Cursor에서 오늘
- 위 Research / Implement / Review 카드를
prompts/또는 메모에 저장 - 토픽 하나로 세 채팅을 실제로 돌려 보기
pass=false를 한 번은 의도적으로 만들어 보기- 성공한
research-brief.json을 레포에 커밋할지는 팀 규칙에 맡기기 (시크릿 없게)
다음 편 — 「코딩은 대화다」
- 도구·요금
- 바이브 코딩 → 배포
- 지금 글 — 멀티에이전트
- 하네스 엔지니어링
- 루프 엔지니어링
- 그래프 엔지니어링
- PapaCoder 실전 사례
FAQ
Q. 에이전트를 많이 만들수록 좋나요?
A. 아니요. 책임 경계가 생기는 지점만 자릅니다. 입문은 3개(Research/Implement/Review)면 충분합니다.
Q. 바이브는 버리나요?
A. 버립니다기보다 배치합니다. throwaway는 바이브, 유지할 코드는 역할+게이트.
Q. PapaCoder는 이걸 쓰나요?
A. 에디토리얼/개발 모두 에이전트 카드와 파이프라인으로 나눕니다. 사람은 Publish 등 고위험 게이트를 잡습니다.
참고 출처
- PapaCoder — Agent Architecture (spec 11)
- Claude Code — Subagents
- Martin Fowler — Vibe Coding (agentic vs vibe)
- PapaCoder editorial workflow
마무리
멀티에이전트는 “AI를 여러 개 켠다”가 아니라 조직을 작게 복제하는 일입니다. 역할·계약·게이트만 있으면, 2편의 바이브 근육 위에 품질을 쌓을 수 있습니다.
앞으로는 모델 선택보다 누가 멈추게 할 권한이 있는지가 더 자주 물어질 겁니다. 4편에서는 그 권한을 프롬프트 밖—하네스—에 심는 법을 다룹니다.