Phase 2: 프롬프트 엔지니어링 | 예상 학습 시간: 30분
🎯 학습 목표
- 다단계 추론(Multi-step reasoning)이 필요한 상황을 식별할 수 있다
- Chain-of-Thought와 단계적 분해(Step Decomposition) 패턴을 실전에 적용할 수 있다
- 복잡한 작업을 서브태스크로 나누어 Claude에게 위임하는 워크플로를 설계할 수 있다
1. 왜 다단계 추론이 필요한가?
LLM은 단순 질의에는 강하지만, 복잡한 문제를 한 번에 처리하려 하면 품질이 급격히 떨어집니다. 이유는 두 가지입니다.
첫째, 생성 과정은 토큰을 왼쪽에서 오른쪽으로 순차 생성합니다. 한 번 생성된 토큰은 수정되지 않으므로, 초반 방향이 잘못되면 전체가 틀립니다.
둘째, 컨텍스트 안에 있는 중간 계산 결과가 모델의 “작업 메모리” 역할을 합니다. 단계별로 답을 명시하면 모델이 올바른 중간 상태를 참고할 수 있습니다.
비유: 암산으로 3자리 곱셈을 하는 것보다 종이에 풀어 쓰는 게 정확한 것과 같습니다.
2. 핵심 패턴 3가지
패턴 A: Chain-of-Thought (CoT)
모델이 답 전에 생각 과정을 출력하도록 유도합니다. Day 07에서 다뤘지만, 여기서는 명시적 단계 레이블을 붙이는 방법을 심화합니다.
prompt = """다음 코드의 버그를 찾아주세요.
코드:
def calculate_discount(price, discount_pct):
return price - price * discount_pct
calculate_discount(100, 20) # 기대값: 80, 실제값: -1900
단계별로 분석해주세요:
1단계) 함수가 의도한 동작 파악
2단계) 실제 계산 과정 추적
3단계) 버그 원인 특정
4단계) 수정 코드 제시
"""
레이블(1단계, 2단계)을 명시하면 모델이 각 단계를 건너뛰지 않습니다.
패턴 B: 작업 분해 (Task Decomposition)
복잡한 작업을 별도 API 호출로 분리합니다. 각 단계의 출력이 다음 단계의 입력이 됩니다.
import anthropic
client = anthropic.Anthropic()
def run(prompt: str) -> str:
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=[{"role": "user", "content": prompt}]
)
return msg.content[0].text
# 요구사항 문서 → 개발 태스크 분해 파이프라인
requirements = """
사용자가 CSV 파일을 업로드하면 자동으로 데이터를 정제하고
이상치를 탐지한 뒤, 요약 리포트를 이메일로 발송하는 시스템
"""
# Step 1: 핵심 컴포넌트 추출
components = run(f"""
다음 요구사항에서 독립적인 기능 컴포넌트를 목록으로 추출해주세요.
요구사항: {requirements}
형식: 번호 매긴 목록, 각 항목은 한 문장
""")
# Step 2: 각 컴포넌트를 개발 태스크로 변환
tasks = run(f"""
다음 컴포넌트 목록을 Jira 태스크 형식으로 변환해주세요.
각 태스크: 제목, 수락 기준 2개, 예상 공수(시간)
컴포넌트 목록:
{components}
""")
print(tasks)
패턴 C: 검토-수정 루프 (Critique-and-Revise)
모델에게 자신의 초안을 비판하고 개선하도록 요청합니다.
draft = run("""
Python으로 이진 탐색 함수를 작성해주세요.
정렬된 리스트에서 target 값을 찾아 인덱스를 반환합니다.
없으면 -1을 반환합니다.
""")
final = run(f"""
다음 코드를 검토하고 개선해주세요.
[초안 코드]
{draft}
검토 기준:
1. 엣지 케이스 처리 (빈 리스트, 단일 원소 등)
2. 시간/공간 복잡도
3. Pythonic한 스타일
4. 독스트링 완성도
개선된 버전을 제시해주세요.
""")
print(final)
3. 실전 예시: 코드 리뷰 파이프라인
다음은 세 패턴을 조합해 PR 코드 리뷰를 자동화하는 예시입니다.
import anthropic
client = anthropic.Anthropic()
def multi_step_code_review(code: str, language: str = "Python") -> dict:
"""3단계 코드 리뷰 파이프라인"""
def run(prompt: str) -> str:
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=[{"role": "user", "content": prompt}]
)
return msg.content[0].text
# Step 1: 코드 이해
summary = run(f"""
다음 {language} 코드가 무엇을 하는지 3문장으로 요약해주세요.
기술적 세부사항보다 비즈니스 목적 중심으로 설명해주세요.
```{language.lower()}
{code}
```
""")
# Step 2: 잠재적 문제 탐지
issues = run(f"""
다음 코드의 잠재적 문제를 찾아주세요.
코드 요약: {summary}
```{language.lower()}
{code}
```
아래 카테고리별로 분류해주세요:
- [버그] 실제 오류 가능성
- [보안] 취약점
- [성능] 비효율
- [가독성] 유지보수 어려움
문제가 없는 카테고리는 "없음"으로 표기하세요.
""")
# Step 3: 개선 우선순위 결정
priority = run(f"""
다음 코드 리뷰 결과를 바탕으로 수정 우선순위를 결정해주세요.
발견된 이슈:
{issues}
출력 형식:
1. [즉시 수정] ...
2. [다음 PR에서 수정] ...
3. [기술 부채로 등록] ...
""")
return {
"summary": summary,
"issues": issues,
"priority": priority
}
# 사용 예시
code = """
def get_user(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
result = db.execute(query)
return result[0]
"""
review = multi_step_code_review(code)
for step, content in review.items():
print(f"=== {step.upper()} ===")
print(content)
print()
💡 실무 팁: 각 단계 사이에 검증 로직을 추가하세요. 예를 들어 Step 1의 요약이 너무 짧으면 (
len(summary) < 50) 재시도하는 방어 코드를 넣으면 파이프라인 안정성이 높아집니다.
📝 핵심 요약
- 복잡한 문제 = 여러 단계로 분해 — 한 번의 프롬프트로 해결하려 하지 말 것
- 단계 레이블 명시 —
1단계,2단계등 레이블이 있으면 Claude가 단계를 건너뛰지 않음 - 중간 결과를 다음 프롬프트에 주입 — 각 API 호출 결과가 다음 입력의 컨텍스트가 됨
- 검토-수정 루프 — 모델 스스로 비판하게 하면 초안 품질이 크게 향상됨
- 단계별 분리의 부작용: API 호출 횟수 증가 → 비용/지연 증가, 트레이드오프를 인식할 것
🔗 참고 자료
⬅️ 이전: Day 10 — 코드 생성 및 리뷰 | 다음: Day 12 — 프롬프트 평가 및 개선 ➡️