프롬프트 엔지니어링
프롬프트 패턴, Few-shot, CoT
프롬프트 엔지니어링
프롬프트 패턴, Few-shot, CoT
프롬프트가 곧 프로그래밍이다
LLM의 행동을 제어하는 가장 직접적이고 비용 효율적인 방법
프롬프트 구조
정의 · 실물 해부 · 조립과 흐름
프롬프트 구조
정의 · 실물 해부 · 흐름 — 프롬프트라는 구조물의 해부도
프롬프트 = LLM에 대한 유일한 인터페이스
사람이 모델에게 전달하는 입력 전체를 구조로 이해합니다 — 구조를 알아야 설계할 수 있습니다.
- 정의 — 자연어 입력의 총합
- 실물 해부 — Converse 요청 한 건
- 흐름 — 조립 → 추론 → 출력
- 설계 대상 — system과 user 메시지
같은 모델이라도 프롬프트 설계에 따라 결과가 갈립니다 — 코드 변경 없이 동작을 제어하는 가장 직접적인 수단입니다.
프롬프트의 정의
질문 한 줄이 아닌, 모델에게 전달되는 자연어 입력의 총합
프롬프트(Prompt) = 사람이 LLM에게 전달하는 자연어 입력의 총합. 시스템 지시어, 사용자 질문, 참고 문서, 대화 이력을 모두 포함합니다.
시스템 지시어역할 · 규칙
+
사용자 질문이번 요청
+
참고 문서검색 결과 · 자료
+
대화 이력이전 턴
=
프롬프트
"질문 한 줄"
— 흔히 프롬프트라 부르는 것은 네 요소 중 하나일 뿐, 모델은 항상 합계 전체를 받습니다
사용자에게 보이는 질문은 입력의 일부일 뿐입니다 — 총합 전체가 프롬프트이고, 그 전체가 설계의 대상입니다.
실물 해부 — Converse 요청 하나
실제 API 요청 한 건을 열어 본 네 칸 — 칸마다 다른 작성자와 설계 원칙
system
"당신은 AWS 솔루션스 아키텍트입니다. 추측하지 말고, 형식은 마크다운 표로…"
역할·규칙 — 사용자 비노출 (PART 2)
user
"이 아키텍처를 검토해 주세요: ALB → ECS → RDS…"
가변 입력 — 설계의 주 대상
assistant
"단일 AZ 구성이라 가용성 위험이 있습니다. 다음 대안을…" (이전 턴 응답)
멀티턴 맥락 · Few-shot 예시로 활용
inference
temperature: 0.2 · maxTokens: 1024
생성 방식 제어 — PART 5
네 칸 중 개발자가 직접 설계하는 것은 system과 user입니다 — assistant는 멀티턴 맥락 유지와 Few-shot 예시로 활용되고, inference는 PART 5에서 조절하는 손잡이입니다.
프롬프트 흐름
세 조각의 조립 → LLM 추론 → 형식을 갖춘 출력으로 이어지는 한 사이클
System Prompt설계는 PART 2
User Message가변 — 매 요청
Context다음 모듈
→
조립
LLM 추론 — genai-basics의 7단계
① 토큰화→… →
⑤ 확률 · ⑥ 샘플링
→⑦ 자기회귀
Temperature · Top-P가 ⑤·⑥에서 작용 — PART 5에서 조절
→
생성
Output
JSON · 마크다운 · 자연어
형식도 프롬프트로 제어 (PART 4)
System Prompt와 User Message만이 아닙니다 — Context와 추론 파라미터까지 포함한 전체 입력이 출력 품질을 결정합니다.
System Prompt 설계
Persona · Rules · Format — 모델 행동의 기본 틀
System Prompt
모든 대화에 적용되는 불변 지시어의 설계법
Persona + Rules + Format
역할을 부여하고, 규칙으로 경계를 긋고, 형식으로 출력을 고정합니다 — 가드레일의 첫 번째 방어선입니다.
- Persona — 역할·전문 분야·톤
- Rules — 금지 사항·범위 제한
- Format — 출력 구조 사전 정의
- 원칙 — 구체적일수록 좋다
"친절하게 답해줘"보다 "2문장 이내, 존댓말, JSON 형식"이 낫습니다 — 구체성이 System Prompt의 품질을 결정합니다.
System Prompt 3요소
역할을 부여하고, 규칙을 정하고, 출력 형식을 지정 — 이 3가지가 모델의 행동 틀
Persona (역할)
"당신은 시니어 백엔드 엔지니어입니다"
전문 분야, 톤, 관점을 정의
Rules (규칙)
"모르면 모른다고 답변"
금지 사항, 범위 제한, 응답 길이
Format (형식)
"JSON으로 응답, key는 영어"
출력 구조를 사전 정의
역할이 관점을, 규칙이 경계를, 형식이 출력 구조를 정합니다 — 3요소의 조합이 모델 행동의 기본 틀입니다.
System Prompt 예시
3요소를 조합한 실제 System Prompt
# Persona
당신은 AWS Solutions Architect입니다.
고객의 아키텍처 질문에 Well-Architected Framework 기반으로 답변합니다.
# Rules
- 모르는 내용은 "확인이 필요합니다"라고 답변
- 비용 관련 질문에 구체적 금액을 제시하지 않음
- 항상 대안을 2가지 이상 제시
# Format
- 마크다운으로 응답
- 추천 서비스는 | 서비스 | 이유 | 형태의 테이블
- 마지막에 "⚠️ 주의사항" 섹션 포함
- # Persona — Well-Architected 기반으로 답변하는 AWS Solutions Architect 역할 부여
- # Rules — 추측 금지("확인이 필요합니다") · 금액 제시 금지 · 대안 2가지 이상
- # Format — 마크다운 + 테이블로 출력 구조를 사전에 고정
- 세 섹션이 모든 대화에 공통 적용되는 불변 지시어
핵심 기법
Zero-shot · Few-shot · Chain of Thought · ReAct
핵심 기법
태스크 복잡도에 따라 단계적으로 올리는 기법의 사다리
Zero-shot → Few-shot → CoT → ReAct
가장 단순한 기법부터 시작해, 태스크가 복잡해질 때 한 단계씩 올립니다.
- Zero-shot — 지시만으로 수행
- Few-shot — 예시 3~5개로 패턴 학습
- Chain of Thought — 단계별 추론 생성
- ReAct — 추론 + 도구 사용 루프
기법은 대체가 아니라 복잡도에 따른 상승 사다리입니다 — 단순 태스크에 무거운 기법을 쓰면 토큰만 낭비됩니다.
기법의 진화
단순한 지시에서 구조화된 추론까지 — 태스크 복잡도에 따른 기법 상승 사다리
Zero-shot으로 시작해 부족하면 예시를, 그래도 부족하면 추론 과정을 더합니다 — ReAct는 에이전트의 기본 패턴이 되며, 루프 실행은 하네스 엔지니어링 모듈에서 깊이 다룹니다.
Zero-shot — 지시가 전부다
예시 없이 지시만으로 — 대상 · 형식 · 제약을 지시에 담는 것이 Zero-shot의 전부
모호한 지시
구체적 지시 — 대상 · 형식 · 제약
Zero-shot의 품질은 지시의 구체성이 결정합니다 — 대상·형식·제약 세 가지를 지시에 담고, 그래도 형식이 흔들리면 다음 단계(Few-shot)로 올립니다.
Few-shot 예시 설계
좋은 예시와 나쁜 예시의 차이 — 예시의 품질이 곧 출력의 품질
나쁜 예시
모호하고 일관성 없음
- 예시 수가 1개 (패턴 학습 불가)
- 입력-출력 형식이 매번 다름
- 에지 케이스를 커버하지 않음
- 예시가 너무 길어 토큰 낭비
나쁜 예시는 모델을 혼란스럽게 합니다. 형식이 불일치하면 모델이 어떤 형식을 따를지 추측해야 합니다.
좋은 예시
구체적이고 일관됨
- 예시 3~5개 (패턴 명확)
- 입력-출력 형식 완전 일관
- 정상 케이스 + 에지 케이스 포함
- 실제 프로덕션 데이터에서 추출
좋은 예시는 일관된 포맷을 보여주고, 에지 케이스도 포함합니다. 모델이 "이렇게 하면 된다"를 명확히 학습합니다.
예시의 품질이 곧 출력의 품질입니다 — 형식이 일관된 예시 3~5개를 실제 프로덕션 데이터에서 추출하는 것이 이상적입니다.
Few-shot 실물 — 예시는 assistant 턴으로
assistant 역할의 실전 용도 — user/assistant 쌍이 곧 예시
Few-shot은 별도 문법이 아니라 메시지 배열의 활용입니다 — 예시를 대화 이력처럼 넣으면 모델이 패턴을 따라갑니다.
{
"system": [{ "text": "상품 리뷰의 감성을 분류합니다. 형식: 감성|신뢰도" }],
"messages": [
{ "role": "user", "content": [{ "text": "배송 빠르고 좋아요" }] },
{ "role": "assistant", "content": [{ "text": "긍정|0.97" }] },
{ "role": "user", "content": [{ "text": "포장이 찢어져 왔어요" }] },
{ "role": "assistant", "content": [{ "text": "부정|0.94" }] },
{ "role": "user", "content": [{ "text": "생각보다 무겁네요" }] },
{ "role": "assistant", "content": [{ "text": "중립|0.81" }] },
{ "role": "user", "content": [{ "text": "재구매 의사 있어요" }] }
]
}
- 예시 3쌍 = user/assistant 턴 — 모델은 이 대화가 실제로 있었다고 보고 패턴을 이어갑니다
- 형식 완전 일관 + 에지 케이스 — 감성|신뢰도 형식 고정, 애매한 "중립" 케이스 포함
- 마지막 user만 실제 질문 — 모델은 학습된 패턴대로 "긍정|…" 형식으로 답합니다
Chain of Thought 효과
"단계별로 생각해" 한 줄을 추가하면 — 정확도가 극적으로 향상되는 원리
중간 과정이 없어 검증 불가
복잡한 문제에서 오답률 높음 → "Let's think step by step" 추가
중간 추론 과정을 명시적 생성
각 단계를 검증할 수 있음
빠르지만 부정확
단순 태스크에 적합 → 출력 토큰 증가 (추론 과정 포함)
느리지만 정확
비용 vs 정확도 판단 필요
CoT 실물 — 같은 질문, 다른 응답
"노트북 120만원 3대와 모니터 45만원 2대, 예산 500만원으로 되나요?"
직접 답변
+ "단계별로 계산해 주세요"
2. 모니터: 45만 × 2 = 90만
3. 합계: 360만 + 90만 = 450만 ≤ 500만
→ 예산 내입니다 (여유 50만원)
지시 한 줄("단계별로")이 추론 토큰을 생성하게 만들어 정확도를 끌어올립니다 — genai-basics에서 본 "더 오래 생각하면 더 정확하다"의 프롬프트 버전입니다.
Role Prompting — Persona를 기법으로
구체적 역할 부여로 활성화되는 도메인 지식과 어조
역할 없음
- "이 코드를 리뷰해줘"
- 일반적이고 피상적인 피드백
- 구체적 관점이 없음
- 도메인 맥락을 고려하지 않음
역할이 없으면 모델은 "일반적 AI 어시스턴트"로 동작합니다. 응답이 광범위하고 깊이가 부족합니다.
역할 부여
- "당신은 10년차 보안 엔지니어입니다. 이 코드를 OWASP 기준으로 리뷰해주세요"
- 보안 취약점에 집중한 구체적 피드백
- 심각도 분류(Critical/High/Medium) 포함
- 수정 방향까지 제안
구체적 역할(직함+경력+전문 분야)을 부여하면, 모델이 해당 도메인의 프레임워크와 용어를 활용하여 깊이 있는 응답을 생성합니다.
직함·경력·전문 분야를 갖춘 구체적 역할이 도메인 프레임워크와 용어를 활성화합니다 — "도와줘"와는 응답의 깊이가 다릅니다.
고급 기법
입력 구조화 · 구조화 출력 · Prompt Chaining · 네거티브 프롬프팅
고급 기법
프로덕션에서 반복 검증된 네 가지 — 목적은 하나, 출력의 예측 가능성
구조화 · 강제 · 분해 · 제약
입력을 태그로 구조화하고, 출력을 스키마로 강제하고, 작업을 단계로 나누고, 범위를 제약으로 좁힙니다.
- 입력 구조화 — XML 태그로 지시·자료 분리
- 구조화 출력 — JSON Schema로 형식 강제
- Prompt Chaining — 단계 분해 + 단계별 검증
- 네거티브 프롬프팅 — "하지 마"로 범위 축소
핵심 기법이 한 호출의 품질을 올린다면, 고급 기법은 작업 전체의 신뢰도를 올립니다 — 네 가지는 함께 조합해 적용할 수 있습니다.
입력 구조화 — XML 태그로 지시와 자료 분리
긴 자료와 지시가 섞이면 모델도 혼동 — 태그 경계가 곧 가드레일 (Anthropic 공식 권장)
System Prompt(역할·규칙, PART 2)를 설계했다면, User 메시지도 태그로 구조화합니다 — 프롬프트 인젝션 완화에도 유효합니다.
<instructions>
아래 회의록에서 결정 사항만 3개 추출해 주세요.
출력은 번호 목록으로 작성합니다.
</instructions>
<document>
{{meeting_notes}}
</document>
<example>
1. 배포 일정을 8월 1주로 확정
</example>
- 태그로 경계 선언 — 지시·자료·예시를 XML 태그로 분리, 모델이 역할 경계를 명확히 인식
- 긴 자료는 document 안에 — 지시가 자료 본문에 묻히지 않음, 자료 안의 "지시처럼 보이는 문장"도 무력화
- Claude 계열 특화 — XML 태그 인식에 최적화되어 있어 Anthropic 공식 가이드가 권장하는 방식
구조화 출력 예시
Strands SDK의 Structured Output — Pydantic 스키마로 출력을 강제
from strands import Agent
from pydantic import BaseModel
# ① 출력 구조를 Pydantic 스키마로 선언
class ReviewResult(BaseModel):
sentiment: str # "positive" | "negative" | "neutral"
confidence: float
summary: str
keywords: list[str]
agent = Agent(model=model, system_prompt="상품 리뷰를 분석합니다.")
# ② 스키마 준수 응답을 보장하는 파라미터
result = agent(
"이 제품 정말 좋아요! 배송도 빠르고 품질도 최고",
structured_output_model=ReviewResult,
)
# ③ 파싱 없이 타입이 보장된 객체로 바로 사용
print(result.structured_output)
# ReviewResult(sentiment='positive', confidence=0.95, ...)
- BaseModel — 출력 구조를 Pydantic 스키마로 선언
- structured_output_model — 스키마 준수 응답을 보장하는 파라미터
- result.structured_output — 파싱 없이 타입이 보장된 객체로 바로 사용, 파싱 실패 제거 → 다운스트림 자동화 연결
Prompt Chaining
복잡한 작업의 단계별 분해 — 작고 검증 가능한 단계들의 사슬
단일 프롬프트
한 번에 모든 것
- 한 번에 모든 것을 요구
- "문서 읽고, 요약하고, 번역하고, 이메일 작성해"
- 중간 실패 시 전체 재시작
- 디버깅 불가능
중간 단계가 보이지 않아 어디서 잘못됐는지 알 수 없습니다. 실패하면 전체를 처음부터 다시 실행해야 합니다.
Chaining
단계 분해 + 검증
- Step 1: 문서 요약 → 검증
- Step 2: 핵심 포인트 추출 → 검증
- Step 3: 이메일 초안 작성 → 검증
- 각 단계 독립 재시도 가능
각 단계의 출력이 다음 단계의 입력이 됩니다. 단계별로 검증하고, 실패한 단계만 독립적으로 재시도할 수 있습니다.
복잡한 작업일수록 쪼갭니다 — 작고 검증 가능한 단계의 사슬이 전체 신뢰도를 만듭니다.
Prompt Chaining 코드
요약 → 추출 → 작성 — 이전 단계의 출력이 다음 단계의 입력
from strands import Agent
# 단일 책임 프롬프트로 역할을 분리
summarizer = Agent(model=model, system_prompt="문서를 3문장으로 요약합니다.")
extractor = Agent(model=model, system_prompt="핵심 포인트를 3개 추출합니다.")
writer = Agent(model=model, system_prompt="고객 안내 이메일을 작성합니다.")
# ① Step 1 — 요약: 출력을 확인·검증할 수 있는 첫 번째 지점
summary = str(summarizer(doc))
# ② Step 2 — 이전 단계의 출력이 그대로 다음 단계의 입력
points = str(extractor(summary))
# ③ Step 3 — 실패하면 이 단계만 독립 재시도
email = str(writer(points))
- 단계 분해 — 요약·추출·작성을 단일 책임 프롬프트로 분리
- 출력 → 입력 연결 — 단계 사이가 곧 검증 지점
- 독립 재시도 — 실패한 단계만 다시 실행, 전체 재시작 불필요
네거티브 프롬프팅 — 범위를 좁히는 제약
하지 말아야 할 것을 명시 — System Prompt Rules의 패턴 확장
범위 제한
"범위 밖 질문은 거절"
다루는 주제의 경계를 선언
불확실성 규칙
"확실하지 않으면 모른다고 답변"
추측 대신 정직한 한계 선언
생성 금지 목록
"외부 URL을 생성하지 마라"
지어내기 쉬운 출력의 원천 차단
System Prompt의 Rules(PART 2)를 패턴으로 확장한 것입니다 — "하지 마"의 제약으로 범위를 좁히면 환각이 줄고 일관성이 올라갑니다.
추론 파라미터
Temperature · Top-P · Top-K · Max Tokens · Stop Sequences
추론 파라미터
무엇을 생성할지는 프롬프트가, 어떻게 생성할지는 파라미터가
품질은 프롬프트로, 생성 방식은 파라미터로
genai-basics에서 본 추론 파이프라인의 ⑤ 확률 · ⑥ 샘플링 · ⑦ 종료를 조절하는 손잡이 다섯 개입니다.
- Temperature — ⑤ 분포의 뾰족함
- Top-P — ⑥ 누적 확률 컷
- Top-K — ⑥ 상위 K개 컷
- Max Tokens — ⑦ 길이 상한
- Stop Sequences — ⑦ 중단 문자열
다섯 손잡이 중 네 개는 Converse inferenceConfig 기본 세트(temperature · topP · maxTokens · stopSequences)이고, Top-K는 모델 네이티브 파라미터입니다.
Temperature — 분포의 뾰족함
같은 후보, 다른 손잡이 — 낮으면 결정적, 높으면 다양 (분포 수치는 예시)
"이 구성의 주요 위험은 ___" 다음 토큰 후보
가용성 · 보안 · 비용 · 지연
범위 0~1 — Converse 스키마
태스크별 권장
추출 · 분류 · 코드 0
RAG 질의응답 0~0.3
요약 · 번역 0.2~0.5
대화 ≈0.7
창작 0.9~1.0
어느 쪽으로 돌릴지는 태스크가 정합니다 — 재현이 중요하면 0으로, 다양성이 중요하면 0.9 이상으로, 대화는 0.7 부근이 균형점입니다.
Top-P — 누적 확률 컷
확률 내림차순으로 쌓다가 누적 p에서 자르는 방식 — 남은 후보 안에서만 추첨 (수치는 예시)
확률 내림차순 정렬 후 누적 합산
topP = 0.9
범위 0~1 · 창작 프리셋 0.95
남은 후보 3개 중 확률 비율로 추첨
— 분포가 뾰족하면 후보가 줄고, 평탄하면 늘어나는 가변 컷
컷의 기준은 개수가 아니라 누적 확률입니다 — Temperature와 함께 조절하되, 둘을 동시에 극단으로 올리지 않는 것이 안전한 기본기입니다.
Top-K — 상위 K개 컷
확률과 무관하게 상위 K개만 남기는 고정 컷 — Top-P와의 차이는 자르는 기준 (수치는 예시)
같은 분포에 개수 컷 적용
topK = 2
1위 가용성 0.46
2위 보안 0.27
3위 비용 0.17
4위 지연 0.10
→
상위 2개 중 추첨
주의
Converse inferenceConfig 기본 세트(maxTokens · stopSequences · temperature · topP)에 Top-K는 없음 — additionalModelRequestFields로 전달하는 모델 네이티브 파라미터 (예: Anthropic top_k)
같은 "후보 자르기"라도 Top-K는 개수 고정, Top-P는 누적 확률 가변입니다 — Converse에서는 기본 세트가 아니라 additionalModelRequestFields로 전달합니다.
Max Tokens — 출력 길이 상한
상한에 닿으면 문장 중간이라도 끊김 — 출력 토큰 과금이므로 길이 상한이 곧 비용 상한
2. 지급 기한: 30일 이내
3. 위약금: 계약금의 10%
2. 지급 기한: 30일 이▍
─ 상한 도달 · 여기서 절단 ─
비용 관점
출력 토큰 × 단가 = 응답 비용
→
maxTokens = 응답 하나의 지출 상한선
응답의 stopReason이 "max_tokens"면 상한에 닿아 잘린 것입니다 — 필요 길이에 여유를 더해 상한을 잡되, 무한정 열어 두지 않는 것이 비용 안전장치입니다.
Stop Sequences — 중단 문자열
지정한 문자열이 생성 스트림에 등장하는 순간 즉시 종료 — 끝나는 지점을 예약하는 손잡이
생성 스트림
stopSequences: ["끝."]
1. 배상 한도: 5,000만원
→
2. 지급 기한: 30일 이내
→
끝.
즉시 종료
stopReason: "stop_sequence"
이 외에 참고할 점은…
추가 설명 …
✕ 생성되지 않음 — 불필요한 꼬리가 잘림
쓰임새
목록의 끝 표시
턴의 경계 강제
출력 형식 고정
모델이 스스로 멈추기를 기다리지 않고 끝나는 지점을 문자열로 예약합니다 — 목록의 끝, 턴의 경계처럼 출력 형식을 강제하는 데 유용합니다.
inferenceConfig — Bedrock에서 지정하기
Converse API 호출 한 번에 함께 들어가는 프롬프트와 파라미터
import boto3
client = boto3.client("bedrock-runtime", region_name="us-east-1")
response = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
system=[{"text": "계약서에서 금액 조항만 추출합니다."}],
messages=[{"role": "user", "content": [{"text": contract}]}],
# ① 기본 세트 4종은 inferenceConfig 하나에 모아서
inferenceConfig={
"temperature": 0, # ② 추출 태스크 — 재현 가능성 우선
"maxTokens": 1024, # ③ 출력 길이 상한 = 비용 상한
"stopSequences": ["끝."],
},
# ④ Top-K 등 기본 세트 밖 파라미터는 모델 네이티브 필드로
# additionalModelRequestFields={"top_k": 50},
)
print(response["output"]["message"]["content"][0]["text"])
- inferenceConfig — temperature · topP · maxTokens · stopSequences 기본 세트를 한 객체로 전달
- temperature 0 — 추출 태스크 권장, 같은 입력이면 항상 같은 출력
- maxTokens · stopSequences — 길이 상한(비용 상한)과 중단 문자열로 종료 지점을 이중으로 예약
- additionalModelRequestFields — Top-K처럼 기본 세트에 없는 모델 네이티브 파라미터의 전달 경로
다음 단계: 컨텍스트 엔지니어링
프롬프트와 파라미터만으로 부족할 때 — "무엇을 넣을 것인가"로 넓히는 시야
프롬프트는 시작일 뿐
프롬프트 기법을 마스터했다면, 다음은 "모델에 무엇을 보여줄 것인가"를 설계하는 컨텍스트 엔지니어링입니다 — 늘어난 프롬프트의 버전·비교·배포는 Prompt Management 모듈에서 다룹니다.
- RAG
- Memory
- Tool Results
- Compression
- Ordering
"어떻게 쓸까"의 다음 질문은 "무엇을 보여줄까"입니다 — 검색 결과·메모리·도구 결과까지 포함한 입력 전체의 설계로 이어집니다.
프롬프트 → 컨텍스트 → 하네스로 이어지는 엔지니어링의 첫 단계.