프롬프트 설계의 기본기: 무엇·어디·왜·검증(How to verify)
Claude Code에서 프롬프트는 "명령문"이 아니라 작업 계약서에 가깝습니다. 무엇을 바꿀지(What)뿐 아니라, 어디를 기준으로 할지(Where), 왜 이게 필요한지(Why), 그리고 어떻게 합격/실패를 판정할지(How to verify)를 함께 넣을수록 결과가 안정적으로 좋아집니다.
특히 에이전트 코딩은 "그럴듯한 답"이 아니라 검증 가능한 결과물에 강합니다. 요구사항이 검증 가능해지는 순간, Claude Code는 탐색·수정·테스트·커밋을 하나의 루프로 굴리기 쉬워지고, 당신은 그 루프의 품질을 관리하는 사람이 됩니다.
프롬프트는 '대화'가 아니라 '스펙'이다
프롬프트를 잘 쓰는 가장 확실한 방법은, 프롬프트를 문장력 문제가 아니라 스펙(사양) 문제로 보는 것입니다. 좋은 스펙에는 보통 다음 요소가 들어갑니다.
모델에게 달성 목표(목표)와 수행 지시(요청 사항)를 주고, 지켜야 할 경계(제약조건)와 참고해야 할 재료(컨텍스트)를 명시하며, 결과를 받는 형태(응답 형식)까지 정합니다.1 또한 프롬프트는 한 번에 완성되는 마법 주문이 아니라, 목표/예상 결과를 정의하고 체계적으로 테스트하며 반복 개선하는 과정으로 다뤄야 합니다.1
이 관점으로 바꾸면, "프롬프트를 더 길게 써야 하나?" 같은 질문은 사라집니다. 대신 "이 프롬프트는 합격 조건이 정의되어 있나?"를 먼저 보게 됩니다.
4요소 프레임: 무엇·어디·왜·검증
이 챕터에서는 프롬프트를 아래 4요소로 쪼개어 작성합니다.
무엇(What): 바꾸려는 결과를 한 문장으로 고정
'무엇'은 작업의 출력물을 고정합니다. "버그를 고쳐줘"가 아니라, "어떤 조건에서 무엇이 어떻게 바뀌어야 하는지"로 적습니다.
예를 들어 "로그인 버그 수정"은 너무 큽니다. 반면 "만료된 토큰이면 401을 받고 로그인 화면으로 리다이렉트되며, 무한 재시도가 없어야 한다"는 확인 가능한 결과를 말합니다.
여기서 팁은 하나입니다. 무엇을 쓰기 어렵다면, 먼저 실패 증상을 적고 그 반대 상태를 '무엇'으로 바꾸세요.
어디(Where): 범위를 줄여 '추측'을 제거
Claude Code는 컨텍스트를 정확히 주면 강해지고, 컨텍스트가 넓거나 애매하면 추측이 늘어납니다. '어디'는 바로 그 추측을 줄이는 장치입니다.
기준 파일(엔트리포인트): "여기에서 결정이 내려진다"
영향 파일(호출부/소비부): "여기에서 그 결정이 쓰인다"
4장에서 다룬 @참조는 '어디'를 가장 빠르게 지정하는 방법입니다. 이 챕터에서는 조작법을 반복하지 않고, 원칙만 기억합시다. 파일을 멘션하는 목적은 '읽어라'가 아니라 '범위를 고정하라'입니다.
왜(Why): 우선순위와 트레이드오프를 모델에 알려준다
에이전트 코딩에서 "왜"는 단순한 배경설명이 아닙니다. 결정 기준(우선순위)을 주는 정보입니다.
예를 들어 리팩터링은 항상 선택이 필요합니다. 성능을 우선할지, 가독성을 우선할지, 리스크를 최소화할지. 당신은 머릿속에 기준이 있지만, 프롬프트에 쓰지 않으면 모델은 그 기준을 추측해야 합니다.
'왜'를 한두 문장으로 적어두면, 모델은 같은 '무엇'을 달성하더라도 더 적합한 방법을 선택합니다.
검증(How to verify): "성공"을 테스트로 바꿔 적는다
Claude Code가 폭발적으로 좋아지는 구간은 여기입니다. 검증 기준이 곧 작업의 레일이 됩니다.
검증은 대체로 세 가지 형태로 적으면 충분합니다.
첫째, 실행 커맨드입니다. 예를 들어 pnpm test, pytest -q, go test ./...처럼 당신의 프로젝트에서 통과해야 하는 명령을 적습니다.
둘째, 자동 검증(린트/포맷/타입체크)입니다. "코딩 스타일 맞춰줘"보다 "ruff/eslint/prettier/mypy를 통과"가 더 강합니다.
셋째, 수동 체크리스트(짧게)입니다. UI나 재현이 필요한 버그는 테스트만으로 충분치 않을 수 있으니, "브라우저에서 A→B→C를 하면 D가 보여야 한다"를 2~3줄로 씁니다.
이 검증 기준은 프롬프트 엔지니어링에서도 핵심으로 강조됩니다. 목표와 예상 결과를 정의하고, 이를 체계적으로 테스트하며 반복 개선하라고 권합니다.1
제약조건을 먼저 적는 습관: '해야 할 것'보다 '하면 안 되는 것'
제약조건은 모델을 제한하는 게 아니라, 결과를 가드레일 안으로 몰아넣는 장치입니다. 프롬프트가 넓거나 모호하면 모델은 길어지거나, 산만해지거나, 원치 않는 디테일을 채웁니다. 따라서 반드시 "해야 할 것"과 "하면 안 되는 것"을 명시하는 편이 좋습니다.2
제약조건을 쓸 때는 다음 감각이 중요합니다.
'짧게'가 아니라 '측정 가능하게' 쓰는 것입니다. "간단히"보다 "3문장 이하"가 낫고, "깔끔하게"보다 "함수 시그니처 변경 금지"가 낫습니다. 주관적 수식어는 피하고 객관적 제약으로 바꾸라는 체크리스트는 현업에서도 반복됩니다.1
그리고 제약조건은 많을수록 좋은 게 아닙니다. 너무 많은 제약은 일부가 무시될 위험이 있으니, 정말 중요한 것부터 적으라고 권합니다.2
패턴 참조: '설명'보다 '본보기'가 빠르다
Claude Code는 기존 코드베이스의 패턴을 잘 따라 합니다. 문제는 그 패턴을 "말로" 설명하려면 길어진다는 겁니다.
이때는 두 가지 방법이 있습니다.
첫째, 예시를 준다(퓨샷)입니다. "이런 형태로 결과를 내"를 1~2개 보여주면, 모델은 설명보다 빠르게 패턴을 복제합니다.1
둘째, 템플릿을 만든다입니다. 프롬프트 패턴을 재사용 가능한 템플릿으로 관리하면, 매번 새로 쓰는 대신 슬롯(변수)만 바꿔 넣게 됩니다.4
결국 좋은 프롬프트는 '한 번 잘 쓰는 기술'이 아니라, '재사용 가능한 구조'를 만들어 팀/프로젝트에 쌓아가는 습관입니다.
'모르면 질문하기'를 규칙으로 박아두기
실전에서 가장 흔한 실패는 "모델이 모르는 걸 아는 척하고 밀어붙이는 것"입니다. 이를 줄이려면, 프롬프트에 불확실할 때의 동작을 명시하세요.
예를 들어 "정보가 부족하면 먼저 확인 질문을 3개 이하로 해라"처럼요. 시스템 메시지 설계 가이드에서도, 애매하거나 범위를 벗어나거나 정보가 부족할 때 무엇을 할지(폴백 동작)를 명시하라고 권합니다.3
Claude Code에서도 이 규칙은 강력합니다. 확인 질문이 한 번만 잘 들어와도, 불필요한 수정/되돌리기가 크게 줄어듭니다.
Claude Code용 프롬프트 템플릿 3종
아래 템플릿은 길어 보이지만, 익숙해지면 대부분의 칸을 짧게 채우게 됩니다. 핵심은 검증 섹션을 비워두지 않는 것입니다.
버그 수정 템플릿
# What
[재현 조건]에서 [현재 동작]이 발생한다. 이를 [기대 동작]으로 고쳐라.
# Where (context scope)
- 엔트리포인트: @path/to/fileA
- 관련 로직/호출부: @path/to/fileB
- 로그/에러 메시지: ```
...붙여넣기...Why
이 버그는 [사용자 영향/장애/보안/매출] 때문에 우선순위가 높다.
Constraints
MUST: 기존 공개 API(함수 시그니처/엔드포인트) 변경 금지
MUST: 새 테스트 1개 이상 추가(또는 기존 테스트 수정)
MUST NOT: 임시로 try/catch로 삼키는 방식의 해결
How to verify
재현 스텝: A → B → C를 하면 D가 나와야 한다.
자동 테스트:
...실행 시 통과해야 한다.품질 체크:
...lint/format/typecheck...통과해야 한다.
Output format
먼저 원인 가설 2~3개를 짧게 제시
실제 수정은 작은 단위로 진행
마지막에 변경 파일 목록과 검증 결과를 요약
## 리팩터링 템플릿(행동 보존)
```md
# What
@path/to/target 에서 [냄새/중복/복잡도]를 줄여라.
외부 동작은 동일해야 한다(behavior-preserving).
# Where
- 대상: @path/to/target
- 호출부 1~2곳: @path/to/caller1, @path/to/caller2
# Why
유지보수 비용을 낮추기 위해서다. 특히 [온보딩/버그 빈도/성능 병목] 때문에 우선한다.
# Constraints
- MUST: 퍼블릭 인터페이스 변경 금지
- MUST: 함수 길이/복잡도 기준을 [예: 40줄 이하/분기 줄이기]로 맞추기
- MUST NOT: 리팩터링과 무관한 스타일 변경 대량 포함(불필요한 diff 금지)
# How to verify
- 기존 테스트 전체 통과: `...`
- 리팩터링 전후 결과가 같은지 확인할 스모크 체크 2개:
- ...
- ...
# Output format
- 리팩터링 계획(단계) → 실행 → 검증 결과 순서로 보고기능 추가 템플릿(작은 PR)
# What
[사용자 스토리]
- As a ...
- I want ...
- So that ...
# Where
- 관련 기능 위치: @...
- 라우팅/엔드포인트: @...
- UI 컴포넌트(있다면): @...
# Why
이 기능은 [업무 흐름/사용자 불편/요구사항]을 해결한다.
# Constraints
- MUST: 변경 범위를 작은 PR로 제한(필요하면 단계적 구현 제안)
- MUST: 에러 케이스 처리(입력 검증/권한/네트워크 실패)
- MUST: 문서/README/릴리즈 노트 중 필요한 것 업데이트
# How to verify
- 테스트 추가 또는 갱신: `...`
- 수동 시나리오 2개:
- 정상 흐름: ...
- 실패 흐름: ...
# Output format
- 구현 옵션 2개 비교(간단히) 후 추천안 1개
- 커밋 메시지 초안 1개 포함나쁜 프롬프트를 고치는 3단계
현장에서 가장 흔한 원문은 이런 형태입니다.
"이거 느린데 최적화해줘."
이 문장은 Claude Code에게 너무 많은 결정을 떠넘깁니다. 아래 3단계로 바꿔보세요.
첫째, '무엇'을 수치로 고정합니다. 예를 들어 "검색 API p95가 900ms인데 300ms 이하로"처럼요.
둘째, '어디'를 고정합니다. 엔드포인트 핸들러, 쿼리 빌더, 캐시 계층 중 무엇을 볼지 파일을 멘션합니다.
셋째, '검증'을 씁니다. 벤치마크 명령, 로컬 재현 방법, 회귀 방지를 위한 테스트(또는 최소한의 측정 스크립트)를 적습니다.
이 3가지를 넣는 순간, "최적화해줘"는 더 이상 추상적인 부탁이 아니라, 합격/불합격이 갈리는 작업이 됩니다.
프롬프트를 '테스트 가능한 자산'으로 만들기
좋은 프롬프트는 재사용될수록 가치가 커집니다. 그래서 프롬프트를 개인의 요령이 아니라 팀의 자산으로 만들려면, 프롬프트도 테스트 대상이 되어야 합니다.
LLM 앱 테스트는 보통 "정답 문자열 일치"가 아니라, 데이터셋(테스트 케이스)과 실행 러너, 그리고 출력 평가자(스코어링/임계값)로 회귀를 막는 방식으로 접근합니다.5 이 관점은 Claude Code를 쓰는 개발 흐름에도 그대로 적용됩니다.
당장 할 수 있는 최소 단위는 간단합니다. 당신이 자주 시키는 작업(버그 티켓 변환, 특정 모듈 리팩터, 문서 업데이트)을 템플릿으로 저장하고, "좋은 결과/나쁜 결과" 예시를 2~3개 모아두세요. 다음부터는 프롬프트를 바꿀 때마다 그 예시로 다시 돌려보고, 이전보다 나빠지면 되돌리는 식으로 관리하면 됩니다.
참고
1프롬프트 작성 전략 개요 | Google Cloud Vertex AI 문서
2Defining Constraints and Requirements for Effective Prompts | CodeSignal Learn
3System message design for Azure OpenAI (advanced prompt engineering) | Microsoft Learn
4Prompt Patterns Cheat-Sheet | Field Guide to AI
5LLM Testing: A Practical Guide to Automated Testing for LLM Applications | Langfuse Blog
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.