프롬프트 엔지니어링 완전 정복
프롬프트 엔지니어링 고급 기법
목차
Safety Filters (안전 필터)
Google Cloud Vertex AI Safety Filters
차단 사유
안전하지 않은 프롬프트에 대해서는 다음과 같은 응답이 제공됩니다:
- PROHIBITED_CONTENT: 금지된 콘텐츠(일반적으로 아동 성적 학대 콘텐츠)가 포함되어 신고되었으므로 프롬프트가 차단되었습니다.
- BLOCKED_REASON_UNSPECIFIED: 프롬프트 차단 이유가 지정되지 않았습니다.
- OTHER: 다른 모든 이유
유해 카테고리
콘텐츠 필터는 다음과 같은 유해 카테고리를 기준으로 콘텐츠를 평가합니다:
유해 카테고리 | 정의 |
---|---|
증오심 표현 | ID 또는 보호 속성을 대상으로 하는 부정적이거나 유해한 댓글 |
괴롭힘 | 다른 사람을 대상으로 위협하거나 협박하거나 괴롭히거나 모욕하는 댓글 |
음란물 | 성행위 또는 기타 외설적인 콘텐츠에 대한 참조가 포함 |
위험한 콘텐츠 | 유해한 상품, 서비스, 활동 홍보 및 이에 대한 액세스 지원 |
가드레일 종류
- BLOCK_LOW_AND_ABOVE: 확률 점수 또는 심각도 점수가 LOW, MEDIUM 또는 HIGH인 경우 차단
- BLOCK_MEDIUM_AND_ABOVE: 확률 점수 또는 심각도 점수가 MEDIUM 또는 HIGH인 경우 차단 (gemini-2.0-flash-001 및 이후 모델의 기본값)
- BLOCK_ONLY_HIGH: 확률 점수 또는 심각도 점수가 HIGH인 경우 차단
- HARM_BLOCK_THRESHOLD_UNSPECIFIED: 기본 기준점을 사용하여 차단
- OFF: 자동 대답 차단이 없으며 메타데이터가 반환되지 않음 (gemini-2.0-flash-001 및 이후 모델의 기본값)
- BLOCK_NONE: 자동 대답 차단을 삭제하고 반환된 점수로 자체 콘텐츠 가이드라인 구성 가능
이외에도 인용필터(기존 콘텐츠가 길게 복제될 가능성을 낮춤), 시민의식 필터(정치 선거 및 후보자를 언급하거나 이와 관련된 프롬프트를 감지하고 차단)가 있습니다.
목적
- 프롬프트를 대충 써도 그 프롬프트를 바탕으로 프레임워크를 적용한 프롬프트를 생성하여 답변의 질을 높이도록 하는 것
- 다양한 형식으로 인풋을 받을 수 있도록 하는 것
참고: Gemini LangChain Cheatsheet
설정
import os
from dotenv import load_dotenv
load_dotenv()
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
DEFAULT_MODEL = "gemini-2.0-flash"
CREATIVE_MODEL = "gemini-2.0-flash"
REASONING_MODEL = "gemini-2.0-flash"
# 가드레일 (안전 필터)
SAFETY_FILTERS = {
"HARM_CATEGORY_HARASSMENT": "OFF",
"HARM_CATEGORY_HATE_SPEECH": "OFF",
"HARM_CATEGORY_SEXUALLY_EXPLICIT": "OFF",
"HARM_CATEGORY_DANGEROUS_CONTENT": "OFF"
}
1. 프롬프트 프레임워크
CO-STAR 프레임워크
CO-STAR는 Context, Objective, Style, Tone, Audience, Response Format의 약자로, 포괄적인 프롬프트 설계를 위한 프레임워크입니다.
COSTAR_TEMPLATE = """
## Context (맥락)
{context}
## Objective (목표)
{objective}
## Style (스타일)
{style}
## Tone (톤)
{tone}
## Audience (대상)
{audience}
## Response Format (응답 형식)
{response_format}
"""
costar_prompt = COSTAR_TEMPLATE.format(
context="사용자가 복잡한 논리적 추론 문제를 해결하려고 합니다.",
objective="단계별 사고 과정을 통해 정확한 답변을 도출하는 것",
style="논리적이고 체계적인",
tone="객관적이고 분석적인",
audience="문제 해결을 원하는 사용자",
response_format="""
## 문제 해결 과정
### 1단계: 문제 이해
[문제의 핵심 요소 파악]
### 2단계: 정보 정리
[주어진 정보와 필요한 정보 정리]
### 3단계: 해결 방안 수립
[적용할 수 있는 공식이나 방법론]
### 4단계: 계산 과정
[단계별 계산 과정]
### 5단계: 답변 검증
[답변의 타당성 확인]
### 최종 답변
[최종 결과]
"""
)
AUTOMAT 프레임워크
AUTOMAT는 Act As, User Persona, Targeted Action, Output, Mode, Atypical Case, Topic Whitelist의 약자로, 더 구체적인 역할 정의에 초점을 맞춘 프레임워크입니다.
AUTOMAT_TEMPLATE = """
## Act As (행동)
{act_as}
## User Persona (사용자 페르소나)
{user_persona}
## Targeted Action (목표 행동)
{targeted_action}
## Output (출력)
{output}
## Mode (모드)
{mode}
## Atypical Case (비정상적인 경우)
{atypical_case}
## Topic Whitelist (토픽 화이트리스트)
{topic_whitelist}
"""
automat_prompt = AUTOMAT_TEMPLATE.format(
act_as="전문적인 코드 분석가",
user_persona="개발자가 복잡한 코드의 동작을 이해하고 싶어합니다",
targeted_action="코드의 실행 과정을 단계별로 추적하여 분석",
output="코드 실행 흐름과 각 단계별 상태 변화",
mode="코드 라인별 분석 → 변수 상태 추적 → 실행 흐름 시뮬레이션",
atypical_case="빈 입력이나 잘못된 형식의 코드가 주어진 경우",
topic_whitelist="프로그래밍, 코드 분석, 알고리즘"
)
LangChain 통합
from config import GOOGLE_API_KEY, DEFAULT_MODEL
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.prompts import PromptTemplate
# LLM 클라이언트 초기화
llm_client = ChatGoogleGenerativeAI(
google_api_key=GOOGLE_API_KEY,
model=DEFAULT_MODEL,
temperature=0,
max_tokens=None,
timeout=None,
max_retries=3
)
# 프롬프트 템플릿 생성
template = """
당신은 모바일 UI/UX 에 대한 QA 전문가입니다.
다음 모바일 화면을 분석하여 {} 관점에서 평가해주세요:
화면:
{image}
예외:
출력 예시:
"""
prompt = PromptTemplate(
input_variables=["code", "analysis_type"],
template=template
)
### 체인(Chain) 활용
from langchain.chains import LLMChain
# 기본 체인 생성
chain = LLMChain(llm=llm_client, prompt=prompt)
# 체인 실행
result = chain.run({
"analysis_type": "사용성",
"image": "모바일 화면 이미지"
})
고급 프롬프트 패턴
Chain-of-Thought 추론
기본 CoT 예제
def chain_of_thought_example():
"""Chain-of-Thought 추론 예제"""
print("\n=== Chain-of-Thought 추론 예제 ===")
# 기본 Chain-of-Thought 예제
cot_prompt = """
다음 문제를 단계별로 생각하면서 해결해주세요:
문제: 한 상자에 사과 5개, 오렌지 3개가 있습니다.
사과 2개와 오렌지 1개를 먹었다면, 남은 과일은 몇 개인가요?
단계별 해결 과정:
1) 처음 과일 개수: 사과 5개 + 오렌지 3개 = 총 8개
2) 먹은 과일 개수: 사과 2개 + 오렌지 1개 = 총 3개
3) 남은 과일 개수: 8개 - 3개 = 5개
따라서 남은 과일은 5개입니다.
이제 다음 문제를 같은 방식으로 해결해주세요:
문제: 한 교실에 학생 30명이 있습니다.
오늘 결석한 학생이 3명이고, 전학온 학생이 2명이라면,
현재 교실에 있는 학생은 몇 명인가요?
단계별 해결 과정:
"""
model = genai.GenerativeModel(
model_name=DEFAULT_MODEL,
safety_settings=SAFETY_FILTERS
)
response = model.generate_content(cot_prompt)
print(response.text)
고급 CoT + 프레임워크 조합
def advanced_chain_of_thought_example():
"""고급 Chain-of-Thought 예제 (프레임워크 활용)"""
# CO-STAR 프레임워크와 Chain-of-Thought 조합
costar_cot_prompt = COSTAR_TEMPLATE.format(
context="사용자가 복잡한 논리적 추론 문제를 해결하려고 합니다.",
objective="단계별 사고 과정을 통해 정확한 답변을 도출하는 것",
style="논리적이고 체계적인",
tone="객관적이고 분석적인",
audience="문제 해결을 원하는 사용자",
response_format="""
## 문제 해결 과정
### 1단계: 문제 이해
[문제의 핵심 요소 파악]
### 2단계: 정보 정리
[주어진 정보와 필요한 정보 정리]
### 3단계: 해결 방안 수립
[적용할 수 있는 공식이나 방법론]
### 4단계: 계산 과정
[단계별 계산 과정]
### 5단계: 답변 검증
[답변의 타당성 확인]
### 최종 답변
[최종 결과]
"""
)
complex_problem = """
문제:
A 회사는 월 매출이 100만원이고, 매월 10%씩 증가합니다.
B 회사는 월 매출이 80만원이고, 매월 15%씩 증가합니다.
몇 개월 후에 B 회사의 매출이 A 회사를 추월할까요?
"""
cot_instruction = """
다음 단계별로 해결해주세요:
1. 각 회사의 매출 증가 패턴 분석
2. 수학적 모델링 (지수 함수)
3. 방정식 설정 및 해결
4. 결과 검증
"""
full_prompt = f"{costar_cot_prompt}\n{cot_instruction}\n\n{complex_problem}"
Few-shot Learning 예제
def few_shot_learning_example():
"""Few-shot Learning 예제"""
few_shot_prompt = """
다음은 감정 분석 예제입니다:
예시 1:
입력: "오늘 날씨가 정말 좋네요!"
출력: 긍정적 (95% 신뢰도)
키워드: 좋네요
예시 2:
입력: "교통이 너무 복잡해서 짜증나요."
출력: 부정적 (90% 신뢰도)
키워드: 복잡해서, 짜증나요
예시 3:
입력: "오늘 점심은 샐러드를 먹었습니다."
출력: 중립적 (85% 신뢰도)
키워드: 점심, 샐러드
이제 다음 텍스트를 같은 형식으로 분석해주세요:
입력: "새로 산 책이 정말 흥미로워서 밤새 읽었어요!"
출력:
"""
## 📚 추가로 알아볼 내용
### 1. 고급 프롬프트 패턴들
**Tree of Thoughts (ToT):**
```python
tot_prompt = ChatPromptTemplate.from_template("""
문제: {problem}
다음 단계로 이 문제를 해결하겠습니다:
1단계: 3가지 다른 접근 방법 생각하기
접근법 A: [첫 번째 방법]
접근법 B: [두 번째 방법]
접근법 C: [세 번째 방법]
2단계: 각 접근법의 장단점 평가
접근법 A 평가: [장점/단점]
접근법 B 평가: [장점/단점]
접근법 C 평가: [장점/단점]
3단계: 최적 접근법 선택 및 실행
선택한 방법: [이유와 함께]
실행 과정: [단계별 진행]
최종 답변:
""")
Role-Based Prompting:
def create_expert_prompt(domain, task, context=""):
expert_roles = {
"medical": "당신은 20년 경력의 의사입니다.",
"legal": "당신은 법무법인의 시니어 변호사입니다.",
"technical": "당신은 소프트웨어 아키텍트입니다.",
"creative": "당신은 수상 경력이 있는 크리에이티브 디렉터입니다."
}
return ChatPromptTemplate.from_template(f"""
{expert_roles.get(domain, "당신은 해당 분야의 전문가입니다.")}
배경: {context}
과제: {task}
전문가적 관점에서 다음을 고려하여 답변해주세요:
1. 업계 모범 사례
2. 잠재적 위험 요소
3. 실용적 구현 방안
4. 대안적 접근법
답변:
""")
Persona-Driven Prompting:
personas = {
"beginner": {
"characteristics": "프로그래밍을 처음 배우는 학생",
"communication_style": "간단하고 이해하기 쉬운 언어 사용",
"needs": "기본 개념과 실습 예제"
},
"expert": {
"characteristics": "10년 이상의 개발 경험",
"communication_style": "기술적 용어와 고급 패턴 활용",
"needs": "최적화와 아키텍처 관점"
},
"manager": {
"characteristics": "기술 팀을 이끄는 관리자",
"communication_style": "비즈니스 가치와 연결된 설명",
"needs": "ROI와 팀 효율성 중심"
}
}
def adapt_prompt_for_persona(base_prompt, persona_type):
persona = personas.get(persona_type, personas["beginner"])
return ChatPromptTemplate.from_template(f"""
대상: {persona["characteristics"]}
소통 방식: {persona["communication_style"]}
중점 사항: {persona["needs"]}
{base_prompt}
위의 대상에게 맞춰 적절한 수준과 방식으로 답변해주세요.
""")
2. 동적 프롬프트 생성
Context-Aware Prompting:
class DynamicPromptGenerator:
def __init__(self):
self.context_analyzers = {
"complexity": self._analyze_complexity,
"domain": self._detect_domain,
"intent": self._classify_intent
}
def generate_adaptive_prompt(self, user_input, context=None):
# 사용자 입력 분석
analysis = {}
for analyzer_name, analyzer_func in self.context_analyzers.items():
analysis[analyzer_name] = analyzer_func(user_input, context)
# 분석 결과에 따른 프롬프트 구성
prompt_components = self._select_prompt_components(analysis)
return self._build_prompt(prompt_components, user_input)
def _analyze_complexity(self, text, context):
complexity_indicators = {
"simple": ["뭐야", "설명", "간단히"],
"medium": ["어떻게", "방법", "과정"],
"complex": ["분석", "비교", "평가", "최적화"]
}
for level, indicators in complexity_indicators.items():
if any(indicator in text for indicator in indicators):
return level
return "medium"
def _build_prompt(self, components, user_input):
return ChatPromptTemplate.from_template(f"""
{components['system_instruction']}
{components['context_setting']}
사용자 질문: {user_input}
{components['output_format']}
""")
3. 프롬프트 최적화 기법
Prompt Optimization through Iteration:
class PromptOptimizer:
def __init__(self, base_prompt, evaluation_criteria):
self.base_prompt = base_prompt
self.criteria = evaluation_criteria
self.optimization_history = []
def optimize_prompt(self, test_cases, iterations=5):
current_prompt = self.base_prompt
best_score = 0
for i in range(iterations):
# 현재 프롬프트로 테스트
scores = self._evaluate_prompt(current_prompt, test_cases)
avg_score = sum(scores) / len(scores)
print(f"Iteration {i+1}: Average Score = {avg_score:.3f}")
if avg_score > best_score:
best_score = avg_score
best_prompt = current_prompt
# 프롬프트 개선
current_prompt = self._improve_prompt(current_prompt, scores, test_cases)
self.optimization_history.append({
'iteration': i+1,
'prompt': current_prompt,
'score': avg_score
})
return best_prompt, best_score
def _improve_prompt(self, prompt, scores, test_cases):
# 낮은 점수를 받은 테스트 케이스 분석
low_performers = [(case, score) for case, score in zip(test_cases, scores) if score < 0.7]
if not low_performers:
return prompt
# 개선 제안 생성
improvement_prompt = ChatPromptTemplate.from_template("""
현재 프롬프트: {current_prompt}
문제가 있는 테스트 케이스들:
{problem_cases}
이 프롬프트를 개선하여 더 나은 결과를 얻을 수 있도록 수정해주세요.
개선 포인트를 명확히 하고 수정된 프롬프트를 제공해주세요.
""")
# LLM을 사용한 자동 개선
improved = improvement_prompt.format(
current_prompt=prompt.template,
problem_cases=str(low_performers[:3]) # 상위 3개만
)
# 실제로는 LLM 호출하여 개선된 프롬프트 받음
return prompt # 단순화된 반환
4. 멀티모달 프롬프트 엔지니어링
Vision-Language Prompting:
def create_vision_prompt(task_type, image_context=""):
vision_prompts = {
"analysis": """
이미지를 자세히 분석하고 다음 항목들을 설명해주세요:
1. 주요 객체와 그 위치
2. 색상과 조명 상태
3. 전체적인 분위기나 맥락
4. 특이사항이나 주목할 점
{image_context}
""",
"comparison": """
제공된 이미지들을 비교 분석하여 다음을 설명해주세요:
1. 유사점과 차이점
2. 각각의 특징
3. 품질이나 조건 비교
4. 추천 사항 (해당되는 경우)
{image_context}
""",
"troubleshooting": """
이미지에서 문제나 이상 징후를 찾아 다음과 같이 분석해주세요:
1. 발견된 문제점
2. 가능한 원인
3. 해결 방안
4. 예방 조치
{image_context}
"""
}
return vision_prompts.get(task_type, vision_prompts["analysis"]).format(
image_context=image_context
)
🔍 학습하면서 알게 된 점
1. 프롬프트 길이와 성능의 관계
def analyze_prompt_length_impact():
"""프롬프트 길이가 성능에 미치는 영향 분석"""
length_categories = {
"short": {"range": "50-150 tokens", "pros": "빠름, 비용 효율", "cons": "컨텍스트 부족"},
"medium": {"range": "150-500 tokens", "pros": "균형잡힌 성능", "cons": "중간 정도 비용"},
"long": {"range": "500-1000+ tokens", "pros": "풍부한 컨텍스트", "cons": "느림, 고비용"}
}
# 실제 경험상 최적점
optimal_ranges = {
"qa": "200-400 tokens",
"analysis": "300-600 tokens",
"creative": "150-800 tokens",
"coding": "100-300 tokens"
}
return length_categories, optimal_ranges
2. 문화적 컨텍스트와 언어 모델
cultural_adaptations = {
"korean": {
"honorifics": "존댓말 사용이 성능에 영향",
"context_style": "고맥락 문화 - 암시적 정보 선호",
"examples": "한국 문화에 맞는 예시 사용 필요"
},
"western": {
"directness": "직접적이고 명확한 지시 선호",
"context_style": "저맥락 문화 - 명시적 정보 선호",
"examples": "서구 문화권 예시 효과적"
}
}
def localize_prompt(prompt, culture="korean"):
"""문화적 맥락에 맞는 프롬프트 조정"""
adaptations = cultural_adaptations.get(culture, cultural_adaptations["korean"])
if culture == "korean":
# 존댓말 추가, 예의 표현 포함
return f"안녕하세요. {prompt} 정중히 답변 부탁드립니다."
else:
return f"Please {prompt.lower()}"
3. Safety Filter와 프롬프트 설계
def design_safety_aware_prompts():
"""안전 필터를 고려한 프롬프트 설계"""
safe_patterns = {
"constructive": ["도움이 되는", "건설적인", "유익한"],
"educational": ["학습을 위한", "교육적인", "이해를 돕는"],
"professional": ["전문적인", "업무에 도움이 되는"]
}
avoid_patterns = {
"harmful": ["해로운", "위험한", "부정적인"],
"biased": ["편견이 있는", "차별적인"],
"inappropriate": ["부적절한", "선정적인"]
}
return {
"recommendation": "긍정적이고 교육적인 표현 사용",
"safe_patterns": safe_patterns,
"avoid_patterns": avoid_patterns
}
4. 토큰 효율성 최적화
def optimize_token_usage():
"""토큰 사용량 최적화 전략"""
strategies = {
"abbreviations": {
"before": "Please provide a comprehensive analysis",
"after": "Analyze:",
"savings": "60% token reduction"
},
"structured_format": {
"before": "나열하여 설명해주세요",
"after": "Format: 1. ... 2. ... 3. ...",
"savings": "30% token reduction"
},
"context_pruning": {
"technique": "불필요한 예시와 설명 제거",
"savings": "40% token reduction"
}
}
return strategies
# 실제 적용 예시
def create_token_efficient_prompt(verbose_prompt):
"""장황한 프롬프트를 효율적으로 압축"""
# 핵심 지시사항 추출
core_instructions = extract_core_instructions(verbose_prompt)
# 간결한 형태로 재구성
efficient_prompt = ChatPromptTemplate.from_template("""
Task: {task}
Context: {context}
Output: {output_format}
""")
return efficient_prompt
5. 실시간 프롬프트 적응
class AdaptivePromptSystem:
def __init__(self):
self.performance_history = {}
self.adaptation_rules = self._load_adaptation_rules()
def adapt_prompt_realtime(self, base_prompt, user_feedback, context):
"""실시간 사용자 피드백 기반 프롬프트 적응"""
# 사용자 피드백 분석
feedback_analysis = self._analyze_feedback(user_feedback)
# 컨텍스트 기반 조정
context_adjustments = self._get_context_adjustments(context)
# 프롬프트 수정
adapted_prompt = self._apply_adaptations(
base_prompt,
feedback_analysis,
context_adjustments
)
# 성능 기록 업데이트
self._update_performance_history(adapted_prompt, user_feedback)
return adapted_prompt
def _analyze_feedback(self, feedback):
"""피드백 패턴 분석"""
patterns = {
"too_verbose": ["너무 길어", "간단히", "요약"],
"too_simple": ["더 자세히", "구체적으로", "예시"],
"off_topic": ["관련 없는", "다른 얘기", "주제 벗어남"]
}
for pattern_type, indicators in patterns.items():
if any(indicator in feedback for indicator in indicators):
return pattern_type
return "satisfactory"
6. 프롬프트 버전 관리
class PromptVersionManager:
def __init__(self):
self.versions = {}
self.performance_metrics = {}
def create_version(self, prompt_id, prompt_content, metadata=None):
"""프롬프트 버전 생성"""
version_id = f"{prompt_id}_v{len(self.versions.get(prompt_id, [])) + 1}"
if prompt_id not in self.versions:
self.versions[prompt_id] = []
version_data = {
"id": version_id,
"content": prompt_content,
"created_at": datetime.now(),
"metadata": metadata or {},
"status": "active"
}
self.versions[prompt_id].append(version_data)
return version_id
def rollback_to_version(self, prompt_id, version_number):
"""특정 버전으로 롤백"""
versions = self.versions.get(prompt_id, [])
if version_number <= len(versions):
target_version = versions[version_number - 1]
target_version["status"] = "active"
# 다른 버전들 비활성화
for v in versions:
if v != target_version:
v["status"] = "inactive"
return target_version
raise ValueError(f"Version {version_number} not found")
def compare_versions(self, prompt_id, version_a, version_b, test_cases):
"""버전 간 성능 비교"""
results = {}
for version_num in [version_a, version_b]:
version = self.get_version(prompt_id, version_num)
scores = self._evaluate_version(version, test_cases)
results[f"v{version_num}"] = {
"average_score": sum(scores) / len(scores),
"scores": scores
}
return results
이러한 고급 프롬프트 엔지니어링 기법들을 통해 더욱 효과적이고 적응적인 AI 시스템을 구축할 수 있습니다.