개요

프롬프트 엔지니어링은 대규모 언어 모델(LLM)과 효과적으로 소통하는 핵심 기술입니다. 이번 포스트에서는 프롬프트의 기본 개념부터 인컨텍스트 학습, 시스템/사용자 프롬프트 구분, 그리고 컨텍스트 효율성까지 체계적으로 살펴보겠습니다.

1. 프롬프트 소개

1.1 프롬프트의 정의와 중요성

graph TB subgraph "Prompt Engineering Ecosystem" A[Prompt Engineering] --> B[Core Techniques] A --> C[Learning Paradigms] A --> D[Optimization Strategies] B --> B1[Prompt Structure] B --> B2[Context Management] B --> B3[Output Formatting] C --> C1[Zero-shot Learning] C --> C2[Few-shot Learning] C --> C3[Chain of Thought] C --> C4[In-Context Learning] D --> D1[Response Quality] D --> D2[Cost Optimization] D --> D3[Latency Reduction] D --> D4[Token Efficiency] subgraph "Prompt Components" E[System Prompt] F[User Prompt] G[Examples] H[Instructions] end B1 --> E B1 --> F C2 --> G B3 --> H subgraph "Application Domains" I[Text Generation] J[Code Generation] K[Analysis & Reasoning] L[Creative Tasks] end A --> I A --> J A --> K A --> L end style A fill:#ff9999 style C fill:#66b3ff style D fill:#99ff99 style B fill:#ffcc99

1.2 프롬프트의 기본 구조

class PromptStructure:
    """프롬프트 구조 설계 클래스"""
    
    def __init__(self):
        self.components = {
            "system_context": "",
            "task_instruction": "",
            "input_data": "",
            "examples": [],
            "output_format": "",
            "constraints": []
        }
    
    def build_prompt(self, task_type="general"):
        """작업 유형에 따른 프롬프트 구성"""
        
        prompt_templates = {
            "classification": self._build_classification_prompt,
            "generation": self._build_generation_prompt,
            "analysis": self._build_analysis_prompt,
            "extraction": self._build_extraction_prompt,
            "reasoning": self._build_reasoning_prompt
        }
        
        builder = prompt_templates.get(task_type, self._build_general_prompt)
        return builder()
    
    def _build_classification_prompt(self):
        """분류 작업용 프롬프트"""
        return f"""
{self.components['system_context']}

작업: 주어진 텍스트를 다음 카테고리 중 하나로 분류하세요.

분류 대상: {self.components['input_data']}

가능한 카테고리:
{self._format_categories()}

{self._format_examples()}

응답 형식:
{self.components['output_format']}

제약 조건:
{self._format_constraints()}
"""
    
    def _build_generation_prompt(self):
        """생성 작업용 프롬프트"""
        return f"""
{self.components['system_context']}

작업: {self.components['task_instruction']}

입력 정보:
{self.components['input_data']}

{self._format_examples()}

생성 요구사항:
- 톤: 전문적이고 명확한
- 길이: 200-500 단어
- 구조: 도입부, 본문, 결론

출력 형식:
{self.components['output_format']}
"""
    
    def add_few_shot_examples(self, examples):
        """퓨샷 예제 추가"""
        formatted_examples = []
        
        for i, example in enumerate(examples, 1):
            formatted_examples.append(f"""
예제 {i}:
입력: {example['input']}
출력: {example['output']}
""")
        
        self.components['examples'] = formatted_examples
    
    def optimize_for_context_length(self, max_tokens=4000):
        """컨텍스트 길이 최적화"""
        current_length = self._estimate_token_count()
        
        if current_length > max_tokens:
            # 예제 수 줄이기
            if len(self.components['examples']) > 3:
                self.components['examples'] = self.components['examples'][:3]
            
            # 긴 설명 요약
            if len(self.components['system_context']) > 500:
                self.components['system_context'] = self._summarize_context()
        
        return self._estimate_token_count()
    
    def _estimate_token_count(self):
        """토큰 수 추정 (대략적)"""
        full_prompt = self.build_prompt()
        # 대략 4 characters = 1 token
        return len(full_prompt) // 4

class PromptValidator:
    """프롬프트 유효성 검증기"""
    
    def __init__(self):
        self.validation_rules = {
            "clarity": self._check_clarity,
            "specificity": self._check_specificity,
            "completeness": self._check_completeness,
            "consistency": self._check_consistency
        }
    
    def validate_prompt(self, prompt):
        """프롬프트 종합 검증"""
        validation_results = {}
        
        for rule_name, rule_func in self.validation_rules.items():
            validation_results[rule_name] = rule_func(prompt)
        
        # 전체 점수 계산
        overall_score = sum(result['score'] for result in validation_results.values()) / len(validation_results)
        
        return {
            "overall_score": overall_score,
            "detailed_results": validation_results,
            "recommendations": self._generate_recommendations(validation_results)
        }
    
    def _check_clarity(self, prompt):
        """명확성 검사"""
        clarity_indicators = {
            "has_clear_instruction": "수행해야 할" in prompt or "작업:" in prompt,
            "uses_simple_language": self._check_language_complexity(prompt),
            "avoids_ambiguity": self._check_ambiguous_terms(prompt),
            "has_examples": "예제" in prompt or "예시" in prompt
        }
        
        score = sum(clarity_indicators.values()) / len(clarity_indicators)
        
        return {
            "score": score,
            "indicators": clarity_indicators,
            "suggestions": self._generate_clarity_suggestions(clarity_indicators)
        }
    
    def _check_specificity(self, prompt):
        """구체성 검사"""
        specificity_indicators = {
            "has_output_format": "형식" in prompt or "포맷" in prompt,
            "defines_constraints": "제약" in prompt or "조건" in prompt,
            "specifies_length": any(word in prompt for word in ["글자", "단어", "문장", "단락"]),
            "provides_context": len(prompt.split('\n')) > 3
        }
        
        score = sum(specificity_indicators.values()) / len(specificity_indicators)
        
        return {
            "score": score,
            "indicators": specificity_indicators
        }

2. 인컨텍스트 학습: 제로샷과 퓨샷

2.1 제로샷 학습 (Zero-shot Learning)

class ZeroShotPrompting:
    """제로샷 프롬프팅 클래스"""
    
    def __init__(self, model):
        self.model = model
        self.zero_shot_templates = self._load_templates()
    
    def _load_templates(self):
        """제로샷 템플릿 로드"""
        return {
            "classification": """
다음 텍스트를 {categories} 중 하나로 분류해주세요.

텍스트: "{text}"

분류 결과: """,
            
            "sentiment_analysis": """
다음 텍스트의 감정을 분석해주세요.

텍스트: "{text}"

감정 (긍정/부정/중립): """,
            
            "summarization": """
다음 텍스트를 3문장으로 요약해주세요.

텍스트: "{text}"

요약: """,
            
            "question_answering": """
주어진 문맥을 바탕으로 질문에 답해주세요.

문맥: "{context}"
질문: "{question}"

답변: """,
            
            "translation": """
다음 텍스트를 {target_language}로 번역해주세요.

원문: "{text}"

번역: """
        }
    
    def classify_text(self, text, categories):
        """텍스트 분류 (제로샷)"""
        prompt = self.zero_shot_templates["classification"].format(
            text=text,
            categories=", ".join(categories)
        )
        
        response = self.model.generate(prompt, temperature=0.1)
        return self._parse_classification_response(response, categories)
    
    def analyze_sentiment(self, text):
        """감정 분석 (제로샷)"""
        prompt = self.zero_shot_templates["sentiment_analysis"].format(text=text)
        
        response = self.model.generate(prompt, temperature=0.1)
        return self._parse_sentiment_response(response)
    
    def zero_shot_reasoning(self, problem):
        """제로샷 추론"""
        reasoning_prompt = f"""
다음 문제를 단계별로 해결해주세요.

문제: {problem}

해결 과정:
1. 문제 이해:
2. 접근 방법:
3. 단계별 해결:
4. 최종 답안:
"""
        
        response = self.model.generate(reasoning_prompt, temperature=0.3)
        return self._parse_reasoning_response(response)
    
    def chain_of_thought_zero_shot(self, problem):
        """제로샷 사고 연쇄"""
        cot_prompt = f"""
{problem}

단계별로 생각해보겠습니다:
"""
        
        response = self.model.generate(cot_prompt, temperature=0.3)
        return response
    
    def _parse_classification_response(self, response, categories):
        """분류 응답 파싱"""
        response_lower = response.lower().strip()
        
        for category in categories:
            if category.lower() in response_lower:
                return {
                    "predicted_category": category,
                    "confidence": self._estimate_confidence(response),
                    "raw_response": response
                }
        
        return {
            "predicted_category": "Unknown",
            "confidence": 0.0,
            "raw_response": response
        }

class FewShotPrompting:
    """퓨샷 프롬프팅 클래스"""
    
    def __init__(self, model):
        self.model = model
        self.example_database = {}
    
    def add_examples(self, task_type, examples):
        """예제 데이터베이스에 추가"""
        if task_type not in self.example_database:
            self.example_database[task_type] = []
        
        self.example_database[task_type].extend(examples)
    
    def few_shot_classify(self, text, task_type, num_examples=3):
        """퓨샷 분류"""
        examples = self._select_best_examples(task_type, text, num_examples)
        
        prompt = self._build_few_shot_prompt(
            task_type="classification",
            examples=examples,
            input_text=text
        )
        
        response = self.model.generate(prompt, temperature=0.1)
        return response
    
    def _build_few_shot_prompt(self, task_type, examples, input_text):
        """퓨샷 프롬프트 구성"""
        prompt_parts = [
            "다음은 텍스트 분류 작업의 예제들입니다:\n"
        ]
        
        # 예제 추가
        for i, example in enumerate(examples, 1):
            prompt_parts.append(f"""
예제 {i}:
입력: {example['input']}
출력: {example['output']}
""")
        
        # 실제 작업
        prompt_parts.append(f"""
이제 다음 텍스트를 분류해주세요:
입력: {input_text}
출력: """)
        
        return "\n".join(prompt_parts)
    
    def _select_best_examples(self, task_type, input_text, num_examples):
        """가장 적합한 예제 선택"""
        available_examples = self.example_database.get(task_type, [])
        
        if len(available_examples) <= num_examples:
            return available_examples
        
        # 유사도 기반 예제 선택
        similarities = []
        for example in available_examples:
            similarity = self._calculate_similarity(input_text, example['input'])
            similarities.append((similarity, example))
        
        # 유사도 순으로 정렬
        similarities.sort(key=lambda x: x[0], reverse=True)
        
        return [example for _, example in similarities[:num_examples]]
    
    def _calculate_similarity(self, text1, text2):
        """텍스트 유사도 계산 (간단한 자카드 유사도)"""
        words1 = set(text1.lower().split())
        words2 = set(text2.lower().split())
        
        intersection = words1.intersection(words2)
        union = words1.union(words2)
        
        return len(intersection) / len(union) if union else 0.0
    
    def dynamic_few_shot(self, input_text, task_type, max_examples=5):
        """동적 퓨샷 학습"""
        # 초기에는 적은 예제로 시작
        for num_examples in range(1, max_examples + 1):
            examples = self._select_best_examples(task_type, input_text, num_examples)
            
            prompt = self._build_few_shot_prompt(task_type, examples, input_text)
            response = self.model.generate(prompt, temperature=0.1)
            
            # 응답 품질 평가
            confidence = self._evaluate_response_confidence(response)
            
            if confidence > 0.8:  # 충분히 확신하는 경우
                return {
                    "response": response,
                    "num_examples_used": num_examples,
                    "confidence": confidence
                }
        
        # 최대 예제 수를 사용한 결과 반환
        return {
            "response": response,
            "num_examples_used": max_examples,
            "confidence": confidence
        }

class InContextLearningOptimizer:
    """인컨텍스트 학습 최적화기"""
    
    def __init__(self, model):
        self.model = model
        self.performance_cache = {}
    
    def optimize_example_selection(self, task_data, validation_data):
        """예제 선택 최적화"""
        optimization_results = {}
        
        strategies = {
            "random": self._random_selection,
            "similarity": self._similarity_based_selection,
            "diversity": self._diversity_based_selection,
            "difficulty": self._difficulty_based_selection,
            "performance": self._performance_based_selection
        }
        
        for strategy_name, strategy_func in strategies.items():
            selected_examples = strategy_func(task_data, num_examples=5)
            
            # 검증 데이터로 성능 평가
            performance = self._evaluate_examples(selected_examples, validation_data)
            
            optimization_results[strategy_name] = {
                "examples": selected_examples,
                "performance": performance
            }
        
        # 최적 전략 선택
        best_strategy = max(optimization_results.items(), 
                          key=lambda x: x[1]['performance']['accuracy'])
        
        return {
            "best_strategy": best_strategy[0],
            "best_examples": best_strategy[1]['examples'],
            "all_results": optimization_results
        }
    
    def _diversity_based_selection(self, task_data, num_examples):
        """다양성 기반 예제 선택"""
        selected = []
        remaining = task_data.copy()
        
        # 첫 번째 예제는 랜덤 선택
        first_example = random.choice(remaining)
        selected.append(first_example)
        remaining.remove(first_example)
        
        # 나머지 예제들은 다양성을 고려하여 선택
        for _ in range(num_examples - 1):
            if not remaining:
                break
            
            max_diversity = -1
            best_candidate = None
            
            for candidate in remaining:
                # 이미 선택된 예제들과의 다양성 계산
                diversity_score = self._calculate_diversity(candidate, selected)
                
                if diversity_score > max_diversity:
                    max_diversity = diversity_score
                    best_candidate = candidate
            
            if best_candidate:
                selected.append(best_candidate)
                remaining.remove(best_candidate)
        
        return selected
    
    def _calculate_diversity(self, candidate, selected_examples):
        """예제 다양성 계산"""
        if not selected_examples:
            return 1.0
        
        similarities = []
        for selected in selected_examples:
            similarity = self._calculate_similarity(
                candidate['input'], 
                selected['input']
            )
            similarities.append(similarity)
        
        # 평균 유사도가 낮을수록 다양성이 높음
        avg_similarity = sum(similarities) / len(similarities)
        return 1 - avg_similarity

3. 시스템 프롬프트와 사용자 프롬프트

3.1 시스템 프롬프트 설계

class SystemPromptDesigner:
    """시스템 프롬프트 설계기"""
    
    def __init__(self):
        self.system_prompt_templates = {
            "assistant": self._create_assistant_prompt,
            "analyst": self._create_analyst_prompt,
            "teacher": self._create_teacher_prompt,
            "translator": self._create_translator_prompt,
            "coder": self._create_coder_prompt
        }
    
    def create_system_prompt(self, role, domain=None, constraints=None):
        """역할별 시스템 프롬프트 생성"""
        base_prompt = self.system_prompt_templates.get(role, self._create_generic_prompt)()
        
        # 도메인 특화 지식 추가
        if domain:
            domain_expertise = self._add_domain_expertise(domain)
            base_prompt += f"\n\n도메인 전문성:\n{domain_expertise}"
        
        # 제약 조건 추가
        if constraints:
            constraint_text = self._format_constraints(constraints)
            base_prompt += f"\n\n제약 조건:\n{constraint_text}"
        
        return base_prompt
    
    def _create_assistant_prompt(self):
        """일반 어시스턴트 프롬프트"""
        return """
당신은 도움이 되고 정확한 AI 어시스턴트입니다.

핵심 원칙:
- 정확하고 사실에 기반한 정보를 제공합니다
- 불확실한 내용은 명시적으로 표현합니다  
- 사용자의 요청을 주의 깊게 이해하고 맞춤형 응답을 제공합니다
- 윤리적이고 안전한 가이드라인을 준수합니다

응답 스타일:
- 명확하고 구조적인 설명
- 적절한 예시와 구체적인 정보 포함
- 전문적이면서도 접근하기 쉬운 톤 유지
"""
    
    def _create_analyst_prompt(self):
        """분석가 프롬프트"""
        return """
당신은 데이터와 정보를 체계적으로 분석하는 전문 분석가입니다.

분석 접근법:
- 주어진 데이터를 객관적으로 검토합니다
- 패턴, 트렌드, 이상 징후를 식별합니다
- 근거 기반의 결론을 도출합니다
- 불확실성과 한계점을 명시합니다

분석 결과 제시:
- 핵심 발견사항을 우선 제시
- 지지 증거와 데이터 포함
- 대안적 해석 가능성 고려
- 실행 가능한 인사이트 제공
"""
    
    def _create_teacher_prompt(self):
        """교사 프롬프트"""
        return """
당신은 학습자의 이해를 돕는 전문 교육자입니다.

교육 철학:
- 학습자의 현재 수준을 파악하여 맞춤형 설명 제공
- 복잡한 개념을 단계적으로 분해하여 설명
- 실제 예시와 비유를 통한 이해 촉진
- 능동적 학습을 격려하는 질문 제시

교수법:
- 기초 개념부터 점진적으로 발전
- 다양한 학습 스타일 고려
- 즉각적인 피드백과 격려 제공
- 실습과 적용 기회 창출
"""
    
    def _add_domain_expertise(self, domain):
        """도메인 전문성 추가"""
        domain_knowledge = {
            "healthcare": """
의료 분야 전문 지식:
- 의학 용어와 절차에 대한 정확한 이해
- 환자 안전과 프라이버시 최우선 고려
- 의료 가이드라인과 모범 사례 준수
- 의료 조언은 정보 제공 목적으로만 제한
""",
            "finance": """
금융 분야 전문 지식:
- 금융 상품과 시장 메커니즘 이해
- 리스크 관리와 규제 준수 중시
- 투자 조언의 한계와 위험성 명시
- 개인 재정 정보 보호 우선
""",
            "technology": """
기술 분야 전문 지식:
- 최신 기술 트렌드와 발전 동향 파악
- 기술적 구현과 아키텍처 이해
- 보안과 프라이버시 고려사항 포함
- 실무 적용 가능한 솔루션 제시
""",
            "legal": """
법률 분야 전문 지식:
- 법률 원칙과 절차에 대한 이해
- 관할권과 법률 변화 고려
- 법률 조언의 한계 명시
- 전문 법률 상담 권장
"""
        }
        
        return domain_knowledge.get(domain, "일반적인 전문 지식을 바탕으로 답변합니다.")

class UserPromptOptimizer:
    """사용자 프롬프트 최적화기"""
    
    def __init__(self):
        self.optimization_strategies = {
            "clarity": self._improve_clarity,
            "specificity": self._add_specificity,
            "context": self._enrich_context,
            "structure": self._improve_structure
        }
    
    def optimize_user_prompt(self, original_prompt, optimization_goals=None):
        """사용자 프롬프트 최적화"""
        if optimization_goals is None:
            optimization_goals = ["clarity", "specificity", "context"]
        
        optimized_prompt = original_prompt
        optimization_log = []
        
        for goal in optimization_goals:
            if goal in self.optimization_strategies:
                optimizer_func = self.optimization_strategies[goal]
                optimized_prompt, changes = optimizer_func(optimized_prompt)
                optimization_log.append({
                    "goal": goal,
                    "changes": changes
                })
        
        return {
            "original": original_prompt,
            "optimized": optimized_prompt,
            "optimization_log": optimization_log,
            "improvement_score": self._calculate_improvement_score(original_prompt, optimized_prompt)
        }
    
    def _improve_clarity(self, prompt):
        """명확성 개선"""
        improvements = []
        optimized = prompt
        
        # 모호한 표현 식별 및 개선
        ambiguous_patterns = {
            "이것": "구체적인 대상",
            "좀": "",
            "약간": "정확한 정도",
            "대충": "자세히",
            "뭔가": "구체적인 내용"
        }
        
        for ambiguous, replacement in ambiguous_patterns.items():
            if ambiguous in optimized:
                if replacement:
                    optimized = optimized.replace(ambiguous, replacement)
                    improvements.append(f"'{ambiguous}'를 '{replacement}'로 명확화")
                else:
                    optimized = optimized.replace(ambiguous, "")
                    improvements.append(f"불필요한 '{ambiguous}' 제거")
        
        # 질문 형태로 변환
        if not optimized.endswith("?") and not any(word in optimized for word in ["해주세요", "부탁드립니다", "알려주세요"]):
            optimized += "해주세요."
            improvements.append("명확한 요청 형태로 변환")
        
        return optimized, improvements
    
    def _add_specificity(self, prompt):
        """구체성 추가"""
        improvements = []
        optimized = prompt
        
        # 출력 형식 지정 추가
        if "형식" not in optimized and "포맷" not in optimized:
            format_addition = "\n\n출력 형식: 명확하고 구조화된 답변으로 제공해주세요."
            optimized += format_addition
            improvements.append("출력 형식 지정 추가")
        
        # 길이 제한 추가 (필요시)
        if len(optimized.split()) > 10 and "길이" not in optimized:
            length_guideline = " 간결하면서도 포괄적인 답변으로"
            optimized = optimized.replace("해주세요", length_guideline + " 해주세요")
            improvements.append("답변 길이 가이드라인 추가")
        
        return optimized, improvements
    
    def _enrich_context(self, prompt):
        """컨텍스트 강화"""
        improvements = []
        optimized = prompt
        
        # 목적 명시
        if "목적" not in optimized and "이유" not in optimized:
            context_addition = "\n\n이 정보가 필요한 목적: "
            optimized = context_addition + optimized
            improvements.append("목적 명시 섹션 추가")
        
        # 대상 청중 명시
        if "대상" not in optimized and len(optimized.split()) > 15:
            audience_note = " (일반인도 이해할 수 있도록)"
            optimized = optimized.replace("해주세요", audience_note + " 해주세요")
            improvements.append("대상 청중 명시")
        
        return optimized, improvements

class PromptChaining:
    """프롬프트 체이닝 시스템"""
    
    def __init__(self, model):
        self.model = model
        self.chain_history = []
    
    def execute_chain(self, initial_prompt, chain_steps):
        """프롬프트 체인 실행"""
        current_context = initial_prompt
        results = []
        
        for step_num, step_config in enumerate(chain_steps, 1):
            step_prompt = self._build_step_prompt(
                current_context, 
                step_config, 
                step_num
            )
            
            response = self.model.generate(
                step_prompt,
                temperature=step_config.get('temperature', 0.3)
            )
            
            # 결과 저장
            step_result = {
                "step": step_num,
                "prompt": step_prompt,
                "response": response,
                "config": step_config
            }
            results.append(step_result)
            
            # 다음 단계를 위한 컨텍스트 업데이트
            current_context = self._update_context(
                current_context, 
                response, 
                step_config
            )
        
        return {
            "final_result": results[-1]["response"],
            "chain_results": results,
            "execution_summary": self._generate_execution_summary(results)
        }
    
    def _build_step_prompt(self, context, step_config, step_num):
        """단계별 프롬프트 구성"""
        step_instruction = step_config['instruction']
        
        if step_num == 1:
            return f"{context}\n\n{step_instruction}"
        else:
            return f"""
이전 단계의 결과를 바탕으로 다음 작업을 수행하세요:

이전 컨텍스트: {context}

현재 작업: {step_instruction}
"""
    
    def create_analysis_chain(self, data, analysis_type="comprehensive"):
        """분석 체인 생성"""
        chain_templates = {
            "comprehensive": [
                {
                    "instruction": "주어진 데이터의 핵심 특성과 패턴을 식별하세요.",
                    "temperature": 0.2
                },
                {
                    "instruction": "식별된 패턴의 원인과 의미를 분석하세요.",
                    "temperature": 0.3
                },
                {
                    "instruction": "분석 결과를 바탕으로 실행 가능한 인사이트와 권장사항을 제시하세요.",
                    "temperature": 0.4
                }
            ],
            "problem_solving": [
                {
                    "instruction": "문제의 핵심 요소와 제약 조건을 명확히 정의하세요.",
                    "temperature": 0.1
                },
                {
                    "instruction": "가능한 해결 방안들을 브레인스토밍하고 각각의 장단점을 평가하세요.",
                    "temperature": 0.5
                },
                {
                    "instruction": "최적의 해결책을 선택하고 구체적인 실행 계획을 수립하세요.",
                    "temperature": 0.3
                }
            ]
        }
        
        return chain_templates.get(analysis_type, chain_templates["comprehensive"])

4. 컨텍스트 길이와 컨텍스트 효율성

4.1 컨텍스트 길이 관리

class ContextManager:
    """컨텍스트 관리자"""
    
    def __init__(self, model_context_limit=4096):
        self.context_limit = model_context_limit
        self.tokenizer = self._load_tokenizer()
        self.compression_strategies = {
            "summarization": self._summarize_content,
            "extraction": self._extract_key_information,
            "hierarchical": self._hierarchical_compression,
            "selective": self._selective_retention
        }
    
    def manage_context(self, content, strategy="adaptive"):
        """컨텍스트 관리 실행"""
        current_tokens = self._count_tokens(content)
        
        if current_tokens <= self.context_limit:
            return {
                "status": "no_compression_needed",
                "content": content,
                "original_tokens": current_tokens,
                "final_tokens": current_tokens
            }
        
        if strategy == "adaptive":
            strategy = self._select_optimal_strategy(content)
        
        compression_func = self.compression_strategies.get(strategy)
        if not compression_func:
            raise ValueError(f"Unknown compression strategy: {strategy}")
        
        compressed_content = compression_func(content)
        final_tokens = self._count_tokens(compressed_content)
        
        return {
            "status": "compressed",
            "content": compressed_content,
            "strategy_used": strategy,
            "original_tokens": current_tokens,
            "final_tokens": final_tokens,
            "compression_ratio": final_tokens / current_tokens
        }
    
    def _summarize_content(self, content):
        """내용 요약"""
        if len(content) < 1000:
            return content
        
        # 섹션별로 분할
        sections = self._split_into_sections(content)
        summarized_sections = []
        
        for section in sections:
            if len(section) > 200:
                summary = self._generate_section_summary(section)
                summarized_sections.append(summary)
            else:
                summarized_sections.append(section)
        
        return "\n\n".join(summarized_sections)
    
    def _extract_key_information(self, content):
        """핵심 정보 추출"""
        extraction_patterns = {
            "facts": r'(?:사실|팩트|정보)[::]\s*(.+)',
            "numbers": r'\d+(?:\.\d+)?(?:[%%]|\s*(?:개|명|건|회|번|시간|분|초))',
            "entities": r'[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*',
            "dates": r'\d{4}[-./]\d{1,2}[-./]\d{1,2}|\d{1,2}[-./]\d{1,2}[-./]\d{4}',
            "keywords": self._extract_keywords
        }
        
        extracted_info = {}
        
        for category, pattern in extraction_patterns.items():
            if category == "keywords":
                extracted_info[category] = pattern(content)
            else:
                matches = re.findall(pattern, content, re.IGNORECASE)
                extracted_info[category] = matches
        
        # 추출된 정보를 구조화된 형태로 재구성
        structured_content = self._structure_extracted_info(extracted_info)
        return structured_content
    
    def _hierarchical_compression(self, content):
        """계층적 압축"""
        hierarchy_levels = [
            ("high_priority", ["결론", "요약", "핵심", "중요"]),
            ("medium_priority", ["분석", "설명", "방법", "과정"]),
            ("low_priority", ["배경", "부가", "참고", "예시"])
        ]
        
        compressed_sections = {}
        
        for priority, keywords in hierarchy_levels:
            sections = self._find_sections_by_keywords(content, keywords)
            
            if priority == "high_priority":
                # 높은 우선순위는 전체 유지
                compressed_sections[priority] = sections
            elif priority == "medium_priority":
                # 중간 우선순위는 요약
                compressed_sections[priority] = [
                    self._summarize_section(section) for section in sections
                ]
            else:
                # 낮은 우선순위는 키포인트만 추출
                compressed_sections[priority] = [
                    self._extract_keypoints(section) for section in sections
                ]
        
        # 우선순위 순으로 재구성
        final_content = []
        for priority in ["high_priority", "medium_priority", "low_priority"]:
            if compressed_sections[priority]:
                final_content.extend(compressed_sections[priority])
        
        return "\n\n".join(final_content)
    
    def optimize_context_efficiency(self, prompts_history):
        """컨텍스트 효율성 최적화"""
        optimization_results = {}
        
        # 중복 정보 제거
        deduplicated = self._remove_duplicate_information(prompts_history)
        optimization_results["deduplication"] = {
            "original_length": len(prompts_history),
            "optimized_length": len(deduplicated),
            "reduction": 1 - len(deduplicated) / len(prompts_history)
        }
        
        # 정보 우선순위 재정렬
        prioritized = self._prioritize_information(deduplicated)
        optimization_results["prioritization"] = prioritized
        
        # 컨텍스트 윈도우 슬라이딩
        windowed = self._apply_sliding_window(prioritized)
        optimization_results["windowing"] = windowed
        
        return optimization_results

class ContextEfficiencyAnalyzer:
    """컨텍스트 효율성 분석기"""
    
    def __init__(self):
        self.efficiency_metrics = [
            "information_density",
            "relevance_score", 
            "redundancy_rate",
            "compression_potential"
        ]
    
    def analyze_efficiency(self, context_data):
        """컨텍스트 효율성 분석"""
        analysis_results = {}
        
        for metric in self.efficiency_metrics:
            analyzer_func = getattr(self, f"_calculate_{metric}")
            analysis_results[metric] = analyzer_func(context_data)
        
        # 종합 효율성 점수
        overall_efficiency = self._calculate_overall_efficiency(analysis_results)
        
        return {
            "efficiency_score": overall_efficiency,
            "detailed_metrics": analysis_results,
            "recommendations": self._generate_efficiency_recommendations(analysis_results)
        }
    
    def _calculate_information_density(self, context_data):
        """정보 밀도 계산"""
        total_tokens = len(context_data.split())
        unique_concepts = len(set(self._extract_concepts(context_data)))
        
        density = unique_concepts / total_tokens if total_tokens > 0 else 0
        
        return {
            "density_score": density,
            "total_tokens": total_tokens,
            "unique_concepts": unique_concepts,
            "interpretation": self._interpret_density_score(density)
        }
    
    def _calculate_relevance_score(self, context_data):
        """관련성 점수 계산"""
        # 키워드 빈도 분석
        keywords = self._extract_keywords(context_data)
        keyword_frequency = {}
        
        for keyword in keywords:
            keyword_frequency[keyword] = context_data.lower().count(keyword.lower())
        
        # 관련성 점수 계산 (주요 키워드의 분포 기반)
        if not keyword_frequency:
            return {"relevance_score": 0, "keywords": []}
        
        top_keywords = sorted(keyword_frequency.items(), key=lambda x: x[1], reverse=True)[:10]
        total_mentions = sum(freq for _, freq in top_keywords)
        
        # 상위 키워드가 전체에서 차지하는 비율
        relevance_score = total_mentions / len(context_data.split())
        
        return {
            "relevance_score": relevance_score,
            "top_keywords": top_keywords,
            "total_mentions": total_mentions
        }
    
    def adaptive_context_optimization(self, context_history, current_task):
        """적응적 컨텍스트 최적화"""
        # 현재 작업과의 관련성 분석
        relevance_scores = []
        for context_item in context_history:
            relevance = self._calculate_task_relevance(context_item, current_task)
            relevance_scores.append((context_item, relevance))
        
        # 관련성 순으로 정렬
        relevance_scores.sort(key=lambda x: x[1], reverse=True)
        
        # 동적 컨텍스트 윈도우 크기 결정
        optimal_window_size = self._determine_optimal_window_size(
            relevance_scores, 
            current_task
        )
        
        # 최적화된 컨텍스트 구성
        optimized_context = []
        current_tokens = 0
        max_tokens = optimal_window_size
        
        for context_item, relevance in relevance_scores:
            item_tokens = len(context_item.split())
            
            if current_tokens + item_tokens <= max_tokens:
                optimized_context.append(context_item)
                current_tokens += item_tokens
            elif relevance > 0.8:  # 매우 관련성이 높은 경우 압축하여 포함
                compressed_item = self._compress_high_relevance_item(context_item)
                compressed_tokens = len(compressed_item.split())
                
                if current_tokens + compressed_tokens <= max_tokens:
                    optimized_context.append(compressed_item)
                    current_tokens += compressed_tokens
        
        return {
            "optimized_context": optimized_context,
            "tokens_used": current_tokens,
            "optimization_ratio": current_tokens / sum(len(item.split()) for item in context_history)
        }

결론

프롬프트 엔지니어링과 인컨텍스트 학습은 LLM의 성능을 극대화하는 핵심 기술입니다.

핵심 인사이트:

  • 구조화된 접근: 체계적인 프롬프트 설계가 일관된 고품질 결과를 보장
  • 적응적 학습: 제로샷과 퓨샷 학습의 적절한 조합으로 효율성 극대화
  • 컨텍스트 최적화: 한정된 컨텍스트 윈도우에서 정보 밀도와 관련성 최적화
  • 반복적 개선: 지속적인 프롬프트 평가와 개선을 통한 성능 향상

다음 포스트에서는 프롬프트 엔지니어링의 실전 모범 사례를 상세히 살펴보겠습니다.


시리즈 연결:

참고 자료: