지시를 늘릴수록 덜 지켜진다 — 에이전트가 실제로 따르는 스펙 쓰는 법
1. 이 글은 무엇에 관한 글인가?
Addy Osmani의 글 How to write a good spec for AI agents를 읽고 정리한 글입니다.
글은 저자가 받은 질문 하나에서 출발합니다.
"에이전트용 스펙을 잘 쓰라는 얘기는 많이 들었는데, 제대로 된 프레임워크는 아직 못 봤습니다."
이 질문이 정확합니다. "스펙을 잘 써라"는 조언은 어디에나 있는데, 무엇을 얼마나 쓰라는 것인지 를 말해주는 자료는 드뭅니다. 그리고 이 글의 답은 직관과 반대 방향입니다.
스펙을 크게 쓰면 안 됩니다. 컨텍스트 윈도우 한계와 모델의 어텐션 예산(attention budget) 이 가로막습니다.
컨텍스트 엔지니어링 글이 "규칙을 덜어내라" 였다면, 이 글은 그 바로 옆 칸입니다 — "그러면 남길 규칙은 무엇이고, 어떤 모양이어야 하는가." 덜어내기는 뺄셈이고, 스펙 쓰기는 무엇을 남길지 고르는 일 입니다.
2. 비전을 먼저, 디테일은 에이전트에게
글의 첫 번째 원칙은 순서에 관한 것입니다. 사람이 상세 스펙을 다 쓰고 시작하지 말라 는 겁니다.
❌ 사람이 50페이지 스펙 작성 → 에이전트에 투입
✅ 사람이 짧은 제품 브리프 작성 → 에이전트가 상세 스펙 초안 → 사람이 교정 → 실행이유가 실무적입니다. 부연(elaboration)은 모델이 잘하는 일 이고, 방향(direction)은 사람만 정할 수 있는 일 입니다. 둘을 섞어서 사람이 다 하면, 사람은 잘 못하는 일에 시간을 쓰고 모델은 잘하는 일을 못 씁니다.
글이 드는 예시 브리프는 이 정도로 짧습니다.
"사용자 계정과 영속 저장소를 가진 할 일 앱을 만든다."여기서 에이전트가 스키마·라우팅·에러 케이스·테스트 전략을 펼쳐내면, 사람은 그걸 읽고 틀린 곳만 고칩니다. 백지에서 쓰는 것보다 빠르고, 무엇보다 빠진 항목이 눈에 보입니다.
플랜 모드가 여기에 붙는 이유
글은 이 단계에서 Plan Mode(읽기 전용) 를 쓰라고 말합니다. 파일을 못 고치는 상태로 스펙을 다듬는 것.
이게 왜 중요하냐면, 스펙 교정과 코드 작성이 섞이면 교정이 끝나기 전에 코드가 생기기 때문입니다. 코드가 생기면 스펙을 고치는 비용이 갑자기 올라갑니다. 읽기 전용은 그 비용을 0으로 묶어두는 장치입니다.
그리고 다듬은 결과는 SPEC.md 같은 파일로 남깁니다. 대화가 아니라 파일이어야 하는 이유는 3절과 6절에서 계속 나옵니다.
3. 2,500개 에이전트 설정 파일이 말해주는 여섯 칸
글에서 가장 손에 잡히는 부분입니다. GitHub이 에이전트 설정 파일 2,500개 이상 을 분석한 결과, 좋은 파일에는 공통으로 여섯 개 영역이 있었다는 것.
| 영역 | 들어가야 하는 것 | 흔한 실패 |
|---|---|---|
| 명령어(Commands) | 플래그까지 포함한 실행 가능한 전체 명령 (pnpm test, pytest -v) | "테스트를 돌린다"로만 적혀 있음 |
| 테스트(Testing) | 프레임워크 · 테스트 위치 · 커버리지 기대치 | 어떤 러너인지 안 적혀 있음 |
| 프로젝트 구조 | 소스·테스트·문서가 각각 어디인지 | 에이전트가 파일을 엉뚱한 곳에 만든다 |
| 코드 스타일 | 실제 코드 예시 로 보여준 컨벤션 | 형용사로만 적혀 있음("깔끔하게") |
| Git 워크플로우 | 브랜치 명명 · 커밋 포맷 · PR 요건 | 매번 사람이 고쳐준다 |
| 경계(Boundaries) | 하드 제약 · 절대 건드리면 안 되는 것 | 아예 없다 |
여섯 칸 중 실무에서 제일 자주 비는 건 경계 입니다. 나머지 다섯은 "설명"이라 쓰다 보면 채워지는데, 경계는 사고를 겪어봐야 떠오르는 항목 이기 때문입니다.
글이 인용하는 한 문장이 이걸 요약합니다.
"절대 시크릿을 커밋하지 마라(Never commit secrets)" 가 가장 흔하게 등장한, 그리고 가장 도움이 된 제약이었다.
권장 골격
글이 제시하는 마크다운 구조는 이렇습니다.
# Project Spec: [이름]
## Objective
[명확한 목표 한 문장]
## Tech Stack
[구체적인 버전과 의존성]
## Commands
- Build: `npm run build`
- Test: `npm test`
## Project Structure
- `src/` – 애플리케이션 코드
- `tests/` – 유닛/통합 테스트
## Boundaries
- ✅ 항상: [안전한 행동]
- ⚠️ 먼저 물어볼 것: [영향이 큰 변경]
- 🚫 절대 금지: [하드 스톱]눈여겨볼 건 분량이 아니라 형태 입니다. 각 항목이 한 줄에 하나의 사실 이고, 형용사가 아니라 명령어·경로·이름 입니다. 모델이 지킬 수 있는 건 이 모양뿐입니다.
4. 지시의 저주 — 스펙이 커지면 오히려 안 지켜진다
이 글의 이론적 뼈대입니다. 학계에서 "지시의 저주(the curse of instructions)" 라 부르는 현상.
프롬프트 안의 지시·데이터가 늘어날수록, 각각의 요구사항을 지키는 비율이 눈에 띄게 떨어진다. GPT-4나 Claude 같은 모델도 동시에 많은 요구를 만족시키는 데 어려움을 겪는다.
읽고 나서 제일 오래 남은 문장입니다. 우리가 스펙을 늘리는 동기는 보통 "이것도 빠뜨리면 안 되니까" 인데, 그 동기가 만들어낸 문서가 앞서 적어둔 항목까지 같이 무너뜨립니다.
직관: 규칙을 20개 적으면 20개가 지켜진다
실제: 규칙을 20개 적으면 5개짜리 문서보다 개별 준수율이 떨어진다그래서 스펙 작성은 덧셈이 아니라 예산 배분 입니다. 새 규칙 하나를 넣는 건 공짜가 아니라, 기존 규칙들의 준수 확률을 조금씩 깎아서 사는 것 입니다. 이 관점이 덜어내는 컨텍스트 엔지니어링과 정확히 같은 지점에서 만납니다.
쪼개는 네 가지 방법
글이 제시하는 해법은 전부 "나누기"입니다.
| 방법 | 내용 |
|---|---|
| 컴포넌트별 분할 | 백엔드 스펙 · 프론트엔드 스펙을 나눠 맥락에 맞는 것만 넣는다 |
| 요약이 붙은 확장 목차 | 상세 절을 참조하는 압축 목차를 만들어 필요할 때만 펼친다 |
| 서브에이전트 / 스킬 | 도메인별 특화 에이전트가 스펙의 자기 몫만 들고 간다 |
| 순차 집중 | 프롬프트 하나에 작업 하나. 중간에 컨텍스트를 새로 간다 |
세 번째 항목이 스킬 거버넌스 글과 이어집니다. 거기서 서브에이전트는 "대부분 컨텍스트 윈도우를 지키려고 존재한다" 고 정리했는데, 이 글은 그 방어의 이론적 근거 를 대주는 셈입니다. 컨텍스트를 지키는 건 용량 문제가 아니라 준수율 문제 입니다.
병렬 에이전트에 붙은 단서
글은 독립적인 기능이라면 "하나는 코딩, 하나는 테스트, 하나는 리뷰" 로 동시에 돌리는 방식도 소개합니다. 다만 조건을 답니다 — 처음엔 2~3개로 제한하고, 작업 분리가 명확해야 하며, 공유 컨텍스트를 조율할 오케스트레이션이 필요하다는 것.
저는 이 단서가 본문보다 중요하다고 봤습니다. 병렬 에이전트는 컨텍스트를 나누는 장치인 동시에 충돌을 만드는 장치 입니다. 작업 경계가 흐린 상태로 늘리면, 지시의 저주를 피하려다 머지 충돌과 서로 덮어쓰기 를 삽니다.
5. 세 단계 경계 — ✅ / ⚠️ / 🚫
3절에서 가장 자주 빈다고 한 그 칸의 구체적인 모양입니다.
| 단계 | 의미 | 예시 |
|---|---|---|
| ✅ 항상 | 확인 없이 해야 하는 것 | "커밋 전에 항상 테스트를 돌린다" |
| ⚠️ 먼저 물어볼 것 | 되돌리기 비싼 것 | "DB 스키마를 고치기 전에 물어본다" |
| 🚫 절대 금지 | 예외 없는 하드 스톱 | "시크릿을 커밋하지 않는다" |
세 칸으로 나뉜 게 핵심입니다. 경계를 금지 목록 하나로만 쓰면 두 가지가 동시에 망가집니다.
금지만 있을 때: 애매한 것이 전부 "금지 아님"으로 흘러가 그냥 실행된다
금지만 있을 때: 반대로 조심시키려고 전부 금지에 넣으면 에이전트가 아무것도 못 한다⚠️ 칸은 "사람에게 되돌려주는 밸브" 입니다. 이 밸브가 없으면 모든 판단이 흑백이 되고, 실제 개발에서 중요한 결정은 대부분 회색이라 밸브 없는 스펙은 늘 둘 중 한쪽으로 고장 납니다.
자가 점검을 스펙 안에 심기
글은 경계 외에도 세 가지를 더 권합니다.
- 스펙 대조 검증 — 코드를 쓴 뒤 에이전트가 자기 결과물을 스펙 요구사항과 대조 하게 시킨다
- LLM-as-a-Judge — 주관적 판단이 필요한 항목에 심사용 모델을 둔다
- 적합성 테스트(conformance test) — 스펙에서 직접 도출한 테스트를 붙인다
세 번째가 가장 값이 큽니다. 스펙 문장이 테스트가 되면, 스펙은 읽히기를 바라는 문서 에서 안 지키면 빨간불이 켜지는 장치 로 바뀝니다. 코드 품질은 제약에 있다에서 정리한 "에이전트를 둘러싸는 것"이 바로 이 모양입니다.
6. 스펙은 살아 있는 산출물이다
글의 마지막 원칙입니다. 한 번 쓰고 끝나는 문서가 아니라는 것.
스펙은 공유된 진실의 원천(shared source of truth) 이 된다 — 프로젝트와 함께 진화하는 살아 있고 실행 가능한 산출물.
실천 항목은 이렇습니다.
| 항목 | 내용 |
|---|---|
| 마일스톤마다 테스트 | 스펙과 구현이 어긋난 걸 일찍 잡는다 |
| 스펙 갱신 | 요구사항이 빠졌던 걸 발견하면 문서를 고친다 (대화에서 때우지 않는다) |
| 스펙의 버전 관리 | 스펙 자체를 형상관리한다 |
| 에이전트 행동 로그 | 지시를 어떻게 오해했는지 역추적한다 |
| 컨텍스트 관리 도구 | 큰 스펙은 RAG·MCP·벡터 DB로 필요한 절만 꺼내 쓴다 |
마지막 항목이 4절의 해법과 같은 얘기입니다. 스펙이 커지는 걸 못 막는다면, 적어도 한꺼번에 들어가는 걸 막으라는 것.
모델 선택과 비용
글은 실무 항목도 하나 답니다 — 계획과 중요한 단계에는 좋은 모델을, 기계적인 부연에는 싼 모델을. 그리고 컨텍스트 크기를 적절히 조절하라고 덧붙입니다.
토큰이 많다고 결과가 좋아지지 않는다. 길이보다 컨텍스트의 품질이 중요하다.
Claude 모델 고르기에서 정리했던 것과 같은 결론입니다. 단계마다 필요한 게 다르고, 전 단계에 최고 모델을 쓰는 건 비용을 태우는 방식으로 게으른 것 입니다.
7. 안티패턴 — GitHub 연구가 꼽은 실패들
| 안티패턴 | 왜 실패하나 |
|---|---|
| 모호한 프롬프트 | "멋진 거 만들어줘"에는 붙잡을 앵커가 없다 |
| 요약 없는 초장문 컨텍스트 | 50페이지 문서 투하는 실패한다 (4절) |
| 사람 리뷰 건너뛰기 | 테스트 통과 = 정확함 이 아니다 |
| 프로토타이핑과 프로덕션을 뭉뚱그림 | 어디서 엄격해야 하는지 를 스펙에 적어야 한다 |
| 여섯 칸 중 일부 누락 | 빈 칸이 그대로 구멍이 된다 (3절) |
| 속도·비확정성·비용 리스크 무시 | 검증이 에이전트 속도를 따라가야 한다 |
네 번째가 특히 자주 보입니다. 같은 저장소 안에서도 버려질 프로토타입 과 1년 갈 코드 가 섞여 있는데, 스펙이 그 구분을 안 하면 에이전트는 둘 다 같은 강도로 처리합니다. 결과는 둘 다 나쁩니다 — 프로토타입은 과하게 만들어지고, 프로덕션 코드는 프로토타입 취급을 받습니다.
마지막 항목의 "검증이 속도를 따라가야 한다" 도 한 번 더 씹을 만합니다. 에이전트는 사람보다 빠르게 코드를 만들어내는데, 리뷰 속도는 그대로입니다. 그 격차가 벌어지면 검토되지 않은 코드의 재고 가 쌓이고, 그건 속도가 아니라 부채를 빨리 쌓는 것 입니다.
8. 이 저장소에 대입해보면 — 여섯 칸 중 네 칸이 비어 있다
읽기만 하면 남는 게 없으니 이 블로그 저장소의 CLAUDE.md를 3절의 여섯 칸에 대봤습니다.
| 영역 | 이 저장소의 현재 | 판정 |
|---|---|---|
| 명령어 | "나머지는 package.json scripts 참고"로 위임 + pnpm fetch:popular만 명시 | ⚠️ |
| 테스트 | 없음 — vitest인지 playwright인지, 어디 있는지 안 적혀 있다 | ❌ |
| 프로젝트 구조 | contents/blog/YYYY/MM/*.md 규약은 있음. src/ 배치는 없음 | ⚠️ |
| 코드 스타일 | 없음 | ❌ |
| Git 워크플로우 | 배포 경로(develop → master → gh-pages)는 상세함 | ✅ |
| 경계 | 없음 — ✅/⚠️/🚫 구분이 하나도 없다 | ❌ |
재보고 나서 흥미로웠던 건, 비어 있는 칸이 실제로 사고가 났던 칸과 겹친다 는 점입니다.
이 저장소에는 글 하나를 추가할 때마다 같이 고쳐야 하는 하드코딩된 테스트 기대값이 네 군데 있습니다(글 수, 카테고리 카운트, 최신 글 날짜, About 페이지 편수). CLAUDE.md에는 이게 한 줄도 없습니다. 테스트 칸이 비어 있으니 매번 빨간불로 배웁니다.
경계 칸도 마찬가지입니다. 이 저장소에는 명백한 🚫와 ⚠️가 이미 존재합니다.
🚫 `pnpm format`을 기존 글에 돌리지 말 것 — 표 정렬이 전부 바뀐다
🚫 `public/blog-assets/`를 커밋하지 말 것 — gitignore된 파생물이다
⚠️ `develop`에서 `pnpm fetch:popular`를 돌려 커밋하면 머지 때 충돌할 수 있다세 번째는 CLAUDE.md에 산문으로 적혀 있지만, ⚠️로 표시돼 있지 않습니다. 문단 속에 묻힌 경고와 ⚠️가 붙은 한 줄은 같은 정보가 아닙니다. 전자는 읽히길 기대하는 것이고, 후자는 분류된 것 입니다.
그래서 이 저장소에서 실제로 할 일은 이렇게 좁혀집니다.
- 경계 절을 만들고 이미 아는 🚫/⚠️를 옮긴다 — 새로 발견할 게 아니라, 이미 산문에 흩어져 있는 걸 분류 하는 일이다
- 테스트 칸을 채운다 — 러너·위치·그리고 "새 글 추가 시 같이 고칠 네 곳"
- 늘리지 않는다 — 4절이 있으니, 코드 스타일 칸은 실제로 사고가 난 뒤에 채운다
3번을 적어두는 게 중요합니다. 여섯 칸을 보면 여섯 칸을 다 채우고 싶어지는데, 그게 바로 이 글이 경고한 방향입니다. 빈 칸은 결함이 아니라 아직 비용을 치르지 않은 칸 일 수도 있습니다.
9. 오해하기 쉬운 지점
오해 1 — "스펙을 쓰라는 건 워터폴로 돌아가라는 뜻이다"
글의 주장은 반대입니다. 스펙은 한 번 확정하고 얼어붙는 문서 가 아니라 6절의 살아 있는 산출물 입니다. 그리고 초안은 사람이 아니라 에이전트가 씁니다(2절). 워터폴의 핵심은 "앞단계를 확정하고 넘어간다"인데, 여기서는 매 마일스톤마다 스펙으로 돌아옵니다.
오히려 이건 스펙을 코드처럼 다루자 는 얘기에 가깝습니다. 버전이 있고, 테스트가 붙고, 커밋으로 바뀌는 것.
오해 2 — "긴 컨텍스트 모델이 나오면 해결된다"
4절이 그 기대에 대한 답입니다. 지시의 저주는 용량 문제가 아니라 주의(attention) 문제 입니다. 창이 넓어져도 지시 20개를 동시에 지키는 문제 는 그대로 남습니다.
컨텍스트 윈도우: 얼마나 넣을 수 있는가 → 하드웨어/모델이 푼다
어텐션 예산: 얼마나 지켜지는가 → 넣는 사람이 푼다오해 3 — "여섯 칸을 다 채우면 좋은 스펙이다"
8절에서 걸린 지점입니다. 여섯 칸은 체크리스트가 아니라 진단 도구 입니다. 아무 일도 안 일어난 영역을 추측으로 채우면, 그건 4절이 말한 준수율을 깎는 지시 가 됩니다. 칸이 비었으면 왜 비었는지 를 먼저 보는 게 맞습니다 — 사고가 안 난 건지, 사고가 났는데 안 적은 건지.
오해 4 — "자가 검증을 붙였으니 사람 리뷰는 줄여도 된다"
안티패턴 목록이 직접 못박습니다. 테스트 통과 = 정확함이 아닙니다. 그리고 5절의 자가 점검은 전부 에이전트가 자기 작업을 자기 스펙에 대보는 것 이라, 스펙 자체가 틀렸을 때는 전부 통과합니다. 스펙이 틀렸는지는 스펙 안에서 알 수 없고, 이건 사람이 볼 수밖에 없는 자리입니다.
10. 정리
| 내용 | 왜 | |
|---|---|---|
| 1. 비전은 사람, 디테일은 에이전트 | 짧은 브리프 → 에이전트 초안 → 사람 교정 | 방향은 사람만, 부연은 모델이 잘한다 |
| 2. 여섯 칸으로 진단하라 | 명령어·테스트·구조·스타일·Git·경계 | 2,500개 파일에서 공통으로 나온 축 |
| 3. 경계는 세 단계로 | ✅ 항상 / ⚠️ 먼저 묻기 / 🚫 절대 금지 | ⚠️가 없으면 판단이 전부 흑백이 된다 |
| 4. 지시를 늘리면 준수율이 떨어진다 | 지시의 저주 | 새 규칙은 기존 규칙의 확률을 깎아서 산다 |
| 5. 그래서 쪼갠다 | 컴포넌트별 · 목차 · 서브에이전트 · 순차 | 컨텍스트 분리는 용량이 아니라 준수율 장치 |
| 6. 스펙 문장을 테스트로 | 적합성 테스트 · 스펙 대조 검증 | 읽히길 바라는 문서 → 빨간불이 켜지는 장치 |
| 7. 검증이 속도를 따라가야 한다 | 테스트 통과 ≠ 정확함 | 안 그러면 미검토 코드의 재고가 쌓인다 |
이 블로그에서 이어온 이야기와 겹쳐보면 자리가 분명해집니다.
- 제품 스펙 하네스 — 스펙을 만드는 절차 를 하네스로
- 컨텍스트 엔지니어링 — 규칙을 덜어낼 때 검증하라
- Claude 모델 고르기 — 단계마다 필요한 모델이 다르다
- 코드 품질은 제약에 있다 — 에이전트를 둘러싸는 것 으로 검증하라
- 스킬 거버넌스 — 그 규칙이 여러 사람 손을 타면 무엇이 필요한가
- 이번 글 — 그 규칙을 무슨 모양으로, 얼마나 적을 것인가
질문으로 돌아가면, "제대로 된 프레임워크"는 결국 여섯 칸과 세 단계 경계, 그리고 늘리지 않겠다는 규율 입니다. 앞의 둘은 목록이라 오늘 바로 쓸 수 있고, 어려운 건 세 번째입니다. 스펙은 쓸수록 길어지고 싶어지는 문서인데, 길어지는 순간 자기가 적어둔 것부터 지켜지지 않기 시작하기 때문입니다.
참고 문서
- Addy Osmani, How to write a good spec for AI agents
- GitHub, Spec-driven development · Spec Kit
- Anthropic, Effective context engineering for AI agents
- 이전 글 — 스킬 거버넌스 · 코드 품질은 제약에 있다 · 컨텍스트 엔지니어링