45 min to read
프로덕션 AI 에이전트의 6가지 황금 원칙 완벽 가이드! ✨
ChatGPT처럼 똑똑한 AI 에이전트 만들기! 실전 코드와 비밀 노하우 대공개
안녕하세요, AI 도파민 중독자 Welnai입니다! 🤖💫
오늘은 정말정말 흥미진진한 주제를 가져왔어요! 프로덕션 AI 에이전트 구축하기! 😍
여러분도 ChatGPT나 Claude 같은 똑똑한 AI를 보면서 “나도 이런 거 만들어보고 싶다!”라고 생각해보신 적 있으시죠? 하지만 막상 시작해보면… “어? 왜 내 AI는 이렇게 멍청하지?” 하게 되는 거예요! 😅
그런 여러분을 위해 App.build의 Arseni Kravchenko가 공개한 6가지 황금 원칙을 완전 분해해서 가져왔어요! 이 원칙들만 제대로 따라하면 여러분도 프로덕션급 AI 에이전트를 만들 수 있답니다! 🌟
🎯 AI 에이전트 아키텍처 전체 그림
먼저 전체적인 그림부터 보여드릴게요!
복잡해 보이지만, 하나씩 뜯어보면 정말 간단해요! 각 원칙들이 어떻게 연결되는지 알아보죠! 🚀
🌟 원칙 1: 시스템 프롬프트에 투자하라!
“좋은 프롬프트가 좋은 에이전트를 만든다!” ✨
이건 정말 기본 중의 기본이에요! 많은 개발자들이 프롬프트를 대충 쓰고 “왜 AI가 말을 안 듣지?”하는데, 사실 프롬프트가 문제인 경우가 90%예요!
❌ 나쁜 프롬프트 예시:
# 이러면 안 돼요! 😱
bad_prompt = "너는 도우미야. 도와줘."
✅ 좋은 프롬프트 예시:
class SystemPromptBuilder:
def __init__(self):
self.prompt_template = """
당신은 전문적인 AI 어시스턴트입니다.
## 역할 정의
- 사용자의 질문에 정확하고 도움이 되는 답변을 제공합니다
- 불확실한 정보는 명시적으로 언급합니다
- 단계별로 논리적인 사고 과정을 보여줍니다
## 응답 형식
1. 먼저 질문을 분석합니다
2. 필요한 도구를 식별합니다
3. 단계별로 해결책을 제시합니다
4. 최종 답변을 명확히 요약합니다
## 제약사항
- 개인정보는 절대 요청하지 않습니다
- 불법적이거나 해로운 내용은 거부합니다
- 확실하지 않을 때는 "잘 모르겠습니다"라고 말합니다
"""
def build_contextual_prompt(self, user_context: dict) -> str:
"""사용자 컨텍스트에 따른 맞춤 프롬프트 생성"""
context_info = f"""
## 현재 사용자 컨텍스트
- 전문 분야: {user_context.get('expertise', '일반')}
- 선호 상세도: {user_context.get('detail_level', '중간')}
- 이전 대화 주제: {user_context.get('previous_topics', [])}
"""
return self.prompt_template + context_info
# 사용법
prompt_builder = SystemPromptBuilder()
contextual_prompt = prompt_builder.build_contextual_prompt({
'expertise': 'AI/ML 개발자',
'detail_level': '높음',
'previous_topics': ['neural networks', 'transformers']
})
🔧 원칙 2: 컨텍스트를 똑똑하게 분할하라!
“필요한 정보만 주자! 너무 많으면 오히려 독!” 🧠
LLM은 컨텍스트가 너무 많으면 오히려 헷갈려해요. 필요한 정보만 동적으로 로딩하는 게 핵심!
구체적인 구현:
from typing import List, Dict, Optional
from dataclasses import dataclass
import tiktoken
@dataclass
class ContextChunk:
content: str
relevance_score: float
chunk_type: str
metadata: Dict
class SmartContextManager:
def __init__(self, max_tokens: int = 8000):
self.max_tokens = max_tokens
self.encoder = tiktoken.encoding_for_model("gpt-4")
self.context_retrievers = {
'code': self._retrieve_code_context,
'docs': self._retrieve_doc_context,
'history': self._retrieve_chat_history
}
def build_context(self, query: str, context_types: List[str]) -> str:
"""동적으로 최적화된 컨텍스트 구성"""
chunks = []
# 각 타입별로 관련 컨텍스트 수집
for context_type in context_types:
if context_type in self.context_retrievers:
type_chunks = self.context_retrievers[context_type](query)
chunks.extend(type_chunks)
# 관련성 점수로 정렬
chunks.sort(key=lambda x: x.relevance_score, reverse=True)
# 토큰 제한 내에서 최적 조합 선택
optimized_context = self._optimize_for_token_limit(chunks)
return self._format_context(optimized_context)
def _retrieve_code_context(self, query: str) -> List[ContextChunk]:
"""코드 관련 컨텍스트 검색"""
# 벡터 검색 또는 키워드 매칭으로 관련 코드 조각 찾기
relevant_code = self._search_codebase(query)
return [
ContextChunk(
content=code['content'],
relevance_score=code['score'],
chunk_type='code',
metadata={'file_path': code['path'], 'language': code['lang']}
)
for code in relevant_code
]
def _optimize_for_token_limit(self, chunks: List[ContextChunk]) -> List[ContextChunk]:
"""토큰 제한에 맞춰 최적 컨텍스트 선택"""
selected = []
total_tokens = 0
for chunk in chunks:
chunk_tokens = len(self.encoder.encode(chunk.content))
if total_tokens + chunk_tokens <= self.max_tokens:
selected.append(chunk)
total_tokens += chunk_tokens
else:
break
return selected
# 사용 예시
context_manager = SmartContextManager()
optimized_context = context_manager.build_context(
query="파이썬으로 REST API 만들기",
context_types=['code', 'docs']
)
🛠️ 원칙 3: 도구를 신중하게 설계하라!
“단순하고 명확한 도구가 최고!” ⚡
AI 에이전트의 도구는 사람이 사용하는 도구와 달라요. 명확하고 간단해야 해요!
🎯 좋은 도구 설계 원칙:
- 10개 이하의 도구만 제공
- 1-3개의 엄격한 타입 파라미터
- 멱등성(idempotency) 보장
- 명확한 입출력 정의
from typing import Union, Optional, List
from pydantic import BaseModel, Field
from abc import ABC, abstractmethod
class ToolResult(BaseModel):
success: bool
data: Optional[Union[str, dict, list]]
error_message: Optional[str] = None
execution_time: float
class BaseTool(ABC):
"""AI 에이전트 도구 기본 클래스"""
@property
@abstractmethod
def name(self) -> str:
pass
@property
@abstractmethod
def description(self) -> str:
pass
@abstractmethod
def execute(self, **kwargs) -> ToolResult:
pass
class WebSearchTool(BaseTool):
"""웹 검색 도구 - 간단하고 명확!"""
name = "web_search"
description = "키워드로 웹을 검색하여 최신 정보를 가져옵니다. 최대 5개 결과 반환."
def execute(self, query: str, max_results: int = 3) -> ToolResult:
"""
Args:
query: 검색할 키워드 (필수)
max_results: 최대 결과 수 (1-5, 기본값: 3)
"""
if not query or not isinstance(query, str):
return ToolResult(
success=False,
data=None,
error_message="검색 키워드가 필요합니다"
)
try:
# 실제 검색 로직
results = self._perform_search(query, max_results)
return ToolResult(
success=True,
data={
'query': query,
'results': results,
'count': len(results)
},
execution_time=0.5
)
except Exception as e:
return ToolResult(
success=False,
data=None,
error_message=f"검색 중 오류 발생: {str(e)}"
)
class CalculatorTool(BaseTool):
"""계산기 도구 - 멱등성 보장!"""
name = "calculator"
description = "수학 계산을 수행합니다. 동일한 입력에는 항상 동일한 결과를 반환."
def execute(self, expression: str) -> ToolResult:
"""
Args:
expression: 계산식 (예: "2 + 2", "sqrt(16)")
"""
import math
import ast
import operator
# 안전한 수학 연산만 허용
allowed_operations = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
}
try:
# 표현식 파싱 및 계산
result = self._safe_eval(expression, allowed_operations)
return ToolResult(
success=True,
data={
'expression': expression,
'result': result
},
execution_time=0.001
)
except Exception as e:
return ToolResult(
success=False,
data=None,
error_message=f"계산 오류: {str(e)}"
)
class ToolManager:
"""도구 관리자 - 10개 이하 원칙 준수!"""
def __init__(self):
self.tools: Dict[str, BaseTool] = {}
self.max_tools = 10
def register_tool(self, tool: BaseTool) -> bool:
"""도구 등록 - 최대 개수 제한"""
if len(self.tools) >= self.max_tools:
print(f"⚠️ 최대 도구 개수({self.max_tools})를 초과했습니다!")
return False
self.tools[tool.name] = tool
print(f"✅ 도구 '{tool.name}' 등록 완료!")
return True
def execute_tool(self, tool_name: str, **kwargs) -> ToolResult:
"""도구 실행"""
if tool_name not in self.tools:
return ToolResult(
success=False,
data=None,
error_message=f"도구 '{tool_name}'를 찾을 수 없습니다"
)
return self.tools[tool_name].execute(**kwargs)
# 사용 예시
tool_manager = ToolManager()
tool_manager.register_tool(WebSearchTool())
tool_manager.register_tool(CalculatorTool())
# 실행
search_result = tool_manager.execute_tool("web_search", query="AI agents 2025")
calc_result = tool_manager.execute_tool("calculator", expression="2 + 2 * 3")
🔄 원칙 4: 피드백 루프를 설계하라!
“창의적인 Actor + 까칠한 Critic = 완벽한 조합!” 🎭
이게 정말 핵심이에요! AI가 뭔가를 생성하면, 다른 AI가 검증하는 구조!
창의적 생성] B --> C[Response Draft] C --> D[Critic Agent
엄격한 검증] D --> E{검증 결과} E -->|통과| F[Final Response] E -->|실패| G[Feedback] G --> H[개선 지시] H --> B F --> I[사용자] I --> J[사용자 피드백] J --> K[성능 로그] K --> L[시스템 개선] L --> A end style B fill:#e3f2fd style D fill:#ffebee style E fill:#fff3e0
구체적인 구현:
from enum import Enum
from typing import Any, Dict, List
import json
from datetime import datetime
class ValidationResult(Enum):
PASS = "pass"
FAIL_RETRY = "fail_retry"
FAIL_ABORT = "fail_abort"
class ActorCriticAgent:
"""Actor-Critic 패턴 구현"""
def __init__(self, max_iterations: int = 3):
self.max_iterations = max_iterations
self.feedback_history: List[Dict] = []
def generate_with_feedback(self, user_request: str, domain: str = "general") -> Dict[str, Any]:
"""피드백 루프를 통한 응답 생성"""
for iteration in range(self.max_iterations):
print(f"🎭 Actor-Critic 반복 {iteration + 1}/{self.max_iterations}")
# Actor: 창의적 생성
response = self._actor_generate(user_request, self.feedback_history)
# Critic: 엄격한 검증
validation = self._critic_validate(response, domain)
if validation.result == ValidationResult.PASS:
print("✅ 검증 통과! 최종 응답 생성")
return {
'success': True,
'response': response,
'iterations': iteration + 1,
'feedback_history': self.feedback_history
}
elif validation.result == ValidationResult.FAIL_ABORT:
print("❌ 치명적 오류 - 작업 중단")
return {
'success': False,
'error': validation.feedback,
'iterations': iteration + 1
}
# FAIL_RETRY: 피드백 기록하고 재시도
self.feedback_history.append({
'iteration': iteration + 1,
'feedback': validation.feedback,
'timestamp': datetime.now().isoformat()
})
print(f"🔄 피드백: {validation.feedback}")
# 최대 반복 초과
return {
'success': False,
'error': f"최대 반복 횟수({self.max_iterations}) 초과",
'last_response': response,
'feedback_history': self.feedback_history
}
def _actor_generate(self, request: str, feedback_history: List[Dict]) -> str:
"""Actor: 창의적 응답 생성"""
# 이전 피드백을 반영한 프롬프트 구성
feedback_context = ""
if feedback_history:
recent_feedback = feedback_history[-1]['feedback']
feedback_context = f"""
이전 시도에서 받은 피드백:
{recent_feedback}
이 피드백을 반영하여 개선된 답변을 생성해주세요.
"""
actor_prompt = f"""
당신은 창의적이고 도움이 되는 AI 어시스턴트입니다.
사용자 요청: {request}
{feedback_context}
요청사항:
1. 사용자의 질문에 정확하고 상세한 답변을 제공하세요
2. 실용적이고 실행 가능한 해결책을 제시하세요
3. 필요하면 단계별 가이드를 포함하세요
"""
# 실제로는 LLM API 호출
return f"[Actor 생성] {request}에 대한 창의적 응답..."
def _critic_validate(self, response: str, domain: str) -> 'CriticValidation':
"""Critic: 엄격한 검증"""
domain_validators = {
'code': self._validate_code_response,
'medical': self._validate_medical_response,
'financial': self._validate_financial_response,
'general': self._validate_general_response
}
validator = domain_validators.get(domain, self._validate_general_response)
return validator(response)
def _validate_general_response(self, response: str) -> 'CriticValidation':
"""일반적인 응답 검증"""
# 기본 품질 체크
checks = {
'length_check': len(response) > 50, # 너무 짧지 않은가?
'relevance_check': self._check_relevance(response),
'safety_check': self._check_safety(response),
'completeness_check': self._check_completeness(response)
}
failed_checks = [check for check, passed in checks.items() if not passed]
if not failed_checks:
return CriticValidation(
result=ValidationResult.PASS,
feedback="모든 검증을 통과했습니다.",
score=0.9
)
# 심각한 문제가 있으면 중단
critical_failures = ['safety_check']
if any(check in critical_failures for check in failed_checks):
return CriticValidation(
result=ValidationResult.FAIL_ABORT,
feedback=f"치명적 오류 발견: {failed_checks}",
score=0.0
)
# 개선 가능한 문제면 재시도
return CriticValidation(
result=ValidationResult.FAIL_RETRY,
feedback=f"다음 항목을 개선해주세요: {failed_checks}",
score=0.3
)
class CriticValidation:
def __init__(self, result: ValidationResult, feedback: str, score: float):
self.result = result
self.feedback = feedback
self.score = score
# 사용 예시
agent = ActorCriticAgent(max_iterations=3)
result = agent.generate_with_feedback(
user_request="파이썬으로 웹 스크래핑하는 법 알려줘",
domain="code"
)
print(json.dumps(result, indent=2, ensure_ascii=False))
📊 원칙 5: LLM 기반 오류 분석을 구축하라!
“AI가 AI의 실수를 분석한다니! 메타버스급 발상!” 🤯
이게 정말 혁신적이에요! AI 에이전트의 로그를 다른 AI가 분석해서 개선점을 찾는 거예요!
import logging
import json
from typing import List, Dict, Any
from dataclasses import dataclass
from datetime import datetime, timedelta
@dataclass
class ExecutionLog:
timestamp: datetime
user_request: str
agent_response: str
tool_calls: List[Dict]
success: bool
error_message: str = None
execution_time: float = 0.0
context_used: Dict = None
class LLMErrorAnalyzer:
"""LLM 기반 오류 분석 시스템"""
def __init__(self):
self.execution_logs: List[ExecutionLog] = []
self.analysis_results: List[Dict] = []
def log_execution(self, log: ExecutionLog):
"""실행 로그 기록"""
self.execution_logs.append(log)
# 로그가 100개를 넘으면 분석 트리거
if len(self.execution_logs) % 100 == 0:
self.analyze_recent_patterns()
def analyze_recent_patterns(self, days: int = 7) -> Dict[str, Any]:
"""최근 패턴 분석"""
# 최근 N일 로그 필터링
cutoff_date = datetime.now() - timedelta(days=days)
recent_logs = [
log for log in self.execution_logs
if log.timestamp >= cutoff_date
]
if not recent_logs:
return {'message': '분석할 로그가 없습니다'}
# 실패 케이스 분석
failures = [log for log in recent_logs if not log.success]
success_rate = (len(recent_logs) - len(failures)) / len(recent_logs)
print(f"📊 최근 {days}일 성공률: {success_rate:.2%}")
if failures:
failure_analysis = self._analyze_failures(failures)
self._generate_improvement_suggestions(failure_analysis)
return {
'success_rate': success_rate,
'total_logs': len(recent_logs),
'failures': len(failures),
'failure_patterns': failure_analysis,
'timestamp': datetime.now().isoformat()
}
return {
'success_rate': success_rate,
'message': '모든 실행이 성공했습니다! 🎉'
}
def _analyze_failures(self, failures: List[ExecutionLog]) -> Dict[str, Any]:
"""실패 케이스 패턴 분석"""
# 오류 유형별 분류
error_categories = {}
tool_failure_patterns = {}
context_issues = []
for log in failures:
# 오류 메시지 분류
error_type = self._categorize_error(log.error_message)
error_categories[error_type] = error_categories.get(error_type, 0) + 1
# 도구 실패 패턴 분석
failed_tools = [
tool['name'] for tool in log.tool_calls
if not tool.get('success', True)
]
for tool in failed_tools:
if tool not in tool_failure_patterns:
tool_failure_patterns[tool] = []
tool_failure_patterns[tool].append({
'request': log.user_request,
'error': log.error_message
})
# 컨텍스트 관련 이슈 식별
if self._is_context_issue(log):
context_issues.append({
'request': log.user_request,
'context_size': len(str(log.context_used)) if log.context_used else 0
})
return {
'error_categories': error_categories,
'tool_failures': tool_failure_patterns,
'context_issues': context_issues
}
def _generate_improvement_suggestions(self, analysis: Dict[str, Any]) -> List[str]:
"""개선 제안 생성"""
suggestions = []
# LLM에게 분석 결과 전달하여 제안 생성
analysis_prompt = f"""
다음 AI 에이전트 실행 분석 결과를 보고 구체적인 개선 제안을 해주세요:
오류 카테고리: {analysis['error_categories']}
도구 실패 패턴: {analysis['tool_failures']}
컨텍스트 이슈: {len(analysis['context_issues'])}개
각 문제에 대해 구체적이고 실행 가능한 개선안을 제시해주세요.
"""
# 실제로는 LLM API 호출
llm_suggestions = [
"시스템 프롬프트에서 도구 사용 지침을 더 명확히 하세요",
"실패한 도구들의 오류 처리 로직을 개선하세요",
"컨텍스트 크기를 동적으로 조절하는 로직을 추가하세요",
"사용자 질문 유형별로 전용 처리 파이프라인을 구축하세요"
]
suggestions.extend(llm_suggestions)
print("🔍 AI 분석 결과 - 개선 제안:")
for i, suggestion in enumerate(suggestions, 1):
print(f" {i}. {suggestion}")
# 제안사항을 시스템에 자동 적용
self._apply_suggestions(suggestions)
return suggestions
def _apply_suggestions(self, suggestions: List[str]):
"""제안사항 자동 적용"""
print("🔄 자동 개선 적용 중...")
# 실제 시스템 설정 업데이트
improvements_applied = []
for suggestion in suggestions:
if "컨텍스트" in suggestion:
# 컨텍스트 관리 개선
improvements_applied.append("컨텍스트 동적 조절 활성화")
if "프롬프트" in suggestion:
# 프롬프트 템플릿 업데이트
improvements_applied.append("시스템 프롬프트 개선")
if "도구" in suggestion:
# 도구 오류 처리 강화
improvements_applied.append("도구 오류 복구 로직 추가")
print(f"✅ 적용된 개선사항: {improvements_applied}")
# 실제 사용 예시
analyzer = LLMErrorAnalyzer()
# 실행 로그 기록
analyzer.log_execution(ExecutionLog(
timestamp=datetime.now(),
user_request="파이썬 코드 리뷰해줘",
agent_response="코드 분석 실패",
tool_calls=[{'name': 'code_analyzer', 'success': False}],
success=False,
error_message="코드 분석 도구 연결 실패",
execution_time=2.5
))
# 패턴 분석
analysis = analyzer.analyze_recent_patterns(days=1)
🐛 원칙 6: 문제적 행동을 시스템 이슈로 인식하라!
“AI가 말을 안 듣는다고? 시스템을 먼저 의심하자!” 🕵️
AI가 이상하게 행동할 때 “모델이 바보야!”라고 하기 전에, 시스템 설계를 먼저 점검해보세요!
시스템 디버거 구현:
from enum import Enum
from typing import Dict, List, Optional, Any
import re
class IssueType(Enum):
TOOL_ACCESS = "tool_access"
CONTEXT_QUALITY = "context_quality"
PROMPT_CLARITY = "prompt_clarity"
CONSTRAINT_CONFLICT = "constraint_conflict"
PERMISSION_ISSUE = "permission_issue"
class SystemDebugger:
"""AI 에이전트 시스템 디버거"""
def __init__(self):
self.debug_rules = {
IssueType.TOOL_ACCESS: self._check_tool_access,
IssueType.CONTEXT_QUALITY: self._check_context_quality,
IssueType.PROMPT_CLARITY: self._check_prompt_clarity,
IssueType.CONSTRAINT_CONFLICT: self._check_constraints,
IssueType.PERMISSION_ISSUE: self._check_permissions
}
def diagnose_behavior(self,
agent_response: str,
expected_behavior: str,
system_config: Dict[str, Any]) -> Dict[str, Any]:
"""AI 행동 이상 진단"""
print("🕵️ AI 행동 분석 시작...")
# 이상 행동 패턴 식별
anomaly_patterns = self._identify_anomaly_patterns(agent_response)
# 각 이슈 유형별 검사
diagnoses = {}
for issue_type, checker in self.debug_rules.items():
diagnosis = checker(agent_response, system_config)
if diagnosis['severity'] > 0:
diagnoses[issue_type.value] = diagnosis
# 종합 분석 및 해결 제안
comprehensive_analysis = self._generate_solutions(diagnoses, anomaly_patterns)
return {
'anomaly_patterns': anomaly_patterns,
'detailed_diagnoses': diagnoses,
'recommended_actions': comprehensive_analysis['actions'],
'severity_score': comprehensive_analysis['max_severity'],
'auto_fixable': comprehensive_analysis['auto_fixable']
}
def _identify_anomaly_patterns(self, response: str) -> List[str]:
"""이상 행동 패턴 식별"""
patterns = []
# 일반적인 문제 패턴들
anomaly_indicators = {
r"할 수 없습니다|불가능합니다": "기능 제한 표시",
r"모르겠습니다|잘 모르겠어요": "지식 부족 표시",
r"오류|에러|실패": "실행 오류 표시",
r"접근.*권한|권한.*없음": "권한 문제 표시",
r"도구.*사용.*못|도구.*없음": "도구 접근 문제",
r"컨텍스트.*부족|정보.*부족": "컨텍스트 문제"
}
for pattern, description in anomaly_indicators.items():
if re.search(pattern, response, re.IGNORECASE):
patterns.append(description)
return patterns
def _check_tool_access(self, response: str, config: Dict) -> Dict[str, Any]:
"""도구 접근성 검사"""
available_tools = config.get('tools', [])
# 응답에서 도구 사용 시도 흔적 찾기
tool_mentions = re.findall(r'도구|tool|기능', response, re.IGNORECASE)
severity = 0
issues = []
if tool_mentions and len(available_tools) == 0:
severity = 3 # High
issues.append("도구가 필요한 작업인데 사용 가능한 도구가 없음")
elif len(available_tools) > 10:
severity = 2 # Medium
issues.append(f"너무 많은 도구({len(available_tools)})로 인한 선택 혼란")
# 도구별 기능 명확성 검사
unclear_tools = [
tool for tool in available_tools
if not tool.get('description') or len(tool.get('description', '')) < 20
]
if unclear_tools:
severity = max(severity, 2)
issues.append(f"설명이 불분명한 도구들: {[t.get('name') for t in unclear_tools]}")
return {
'severity': severity,
'issues': issues,
'suggested_fixes': self._suggest_tool_fixes(issues)
}
def _check_context_quality(self, response: str, config: Dict) -> Dict[str, Any]:
"""컨텍스트 품질 검사"""
context_info = config.get('context', {})
severity = 0
issues = []
# 컨텍스트 크기 검사
context_size = len(str(context_info))
if context_size == 0:
severity = 3
issues.append("컨텍스트가 전혀 제공되지 않음")
elif context_size > 50000: # 너무 큰 컨텍스트
severity = 2
issues.append(f"컨텍스트가 너무 큼 ({context_size} chars)")
# 컨텍스트 관련성 검사
if "정보.*부족" in response or "더 많은.*정보" in response:
severity = max(severity, 2)
issues.append("필요한 정보가 컨텍스트에 부족함")
return {
'severity': severity,
'issues': issues,
'suggested_fixes': self._suggest_context_fixes(issues)
}
def _check_prompt_clarity(self, response: str, config: Dict) -> Dict[str, Any]:
"""프롬프트 명확성 검사"""
system_prompt = config.get('system_prompt', '')
severity = 0
issues = []
# 프롬프트 기본 검사
if len(system_prompt) < 100:
severity = 3
issues.append("시스템 프롬프트가 너무 짧음")
# 모호한 지시사항 검사
ambiguous_phrases = ['적절히', '잘', '좋게', '알아서']
ambiguous_found = [phrase for phrase in ambiguous_phrases if phrase in system_prompt]
if ambiguous_found:
severity = max(severity, 2)
issues.append(f"모호한 지시사항 발견: {ambiguous_found}")
# 역할 정의 검사
if '역할' not in system_prompt and '당신은' not in system_prompt:
severity = max(severity, 2)
issues.append("AI의 역할이 명확히 정의되지 않음")
return {
'severity': severity,
'issues': issues,
'suggested_fixes': self._suggest_prompt_fixes(issues)
}
def _suggest_tool_fixes(self, issues: List[str]) -> List[str]:
"""도구 관련 수정 제안"""
fixes = []
for issue in issues:
if "사용 가능한 도구가 없음" in issue:
fixes.append("필요한 도구들을 등록하고 명확한 설명 추가")
elif "너무 많은 도구" in issue:
fixes.append("도구 개수를 10개 이하로 줄이고 핵심 기능만 유지")
elif "설명이 불분명한 도구" in issue:
fixes.append("각 도구에 상세하고 명확한 설명 추가")
return fixes
def auto_fix_system(self, diagnosis: Dict[str, Any]) -> Dict[str, Any]:
"""자동 시스템 수정"""
print("🔧 자동 수정 시작...")
applied_fixes = []
failed_fixes = []
for issue_type, details in diagnosis['detailed_diagnoses'].items():
if details['severity'] >= 2: # Medium 이상만 자동 수정
try:
fix_result = self._apply_auto_fix(issue_type, details)
if fix_result:
applied_fixes.append(f"{issue_type}: {fix_result}")
else:
failed_fixes.append(issue_type)
except Exception as e:
failed_fixes.append(f"{issue_type}: {str(e)}")
return {
'applied_fixes': applied_fixes,
'failed_fixes': failed_fixes,
'manual_intervention_needed': len(failed_fixes) > 0
}
# 사용 예시
debugger = SystemDebugger()
# 문제 상황 시뮬레이션
problematic_response = "죄송하지만 해당 작업을 수행할 도구가 없어서 도움을 드릴 수 없습니다."
system_config = {
'tools': [], # 도구가 없음!
'system_prompt': "도와줘", # 너무 짧은 프롬프트!
'context': {}
}
# 진단 실행
diagnosis = debugger.diagnose_behavior(
agent_response=problematic_response,
expected_behavior="사용자 질문에 도움이 되는 답변",
system_config=system_config
)
print("🔍 진단 결과:")
print(json.dumps(diagnosis, indent=2, ensure_ascii=False))
# 자동 수정 시도
fix_results = debugger.auto_fix_system(diagnosis)
print("\n🔧 수정 결과:")
print(json.dumps(fix_results, indent=2, ensure_ascii=False))
🌟 실제 프로덕션 사례: 종합 구현
이제 모든 원칙을 통합한 완전한 프로덕션 AI 에이전트를 만들어보겠어요!
from typing import Dict, List, Any, Optional
from dataclasses import dataclass, field
import asyncio
import json
from datetime import datetime
@dataclass
class ProductionAgent:
"""프로덕션급 AI 에이전트"""
name: str
max_iterations: int = 3
tools: Dict[str, BaseTool] = field(default_factory=dict)
context_manager: Optional[SmartContextManager] = None
error_analyzer: Optional[LLMErrorAnalyzer] = None
system_debugger: Optional[SystemDebugger] = None
def __post_init__(self):
"""초기화"""
self.context_manager = SmartContextManager()
self.error_analyzer = LLMErrorAnalyzer()
self.system_debugger = SystemDebugger()
self.actor_critic = ActorCriticAgent(self.max_iterations)
# 기본 도구들 등록
self._register_default_tools()
def _register_default_tools(self):
"""기본 도구 등록"""
default_tools = [
WebSearchTool(),
CalculatorTool(),
# 다른 필수 도구들...
]
for tool in default_tools:
if len(self.tools) < 10: # 최대 10개 제한
self.tools[tool.name] = tool
async def process_request(self, user_request: str, context_types: List[str] = None) -> Dict[str, Any]:
"""사용자 요청 처리 - 모든 원칙 적용"""
start_time = datetime.now()
try:
# 1. 스마트 컨텍스트 구성 (원칙 2)
if context_types:
optimized_context = self.context_manager.build_context(
query=user_request,
context_types=context_types
)
else:
optimized_context = ""
# 2. Actor-Critic으로 응답 생성 (원칙 4)
generation_result = self.actor_critic.generate_with_feedback(
user_request=user_request,
domain="general"
)
if not generation_result['success']:
# 3. 시스템 디버깅 (원칙 6)
await self._handle_generation_failure(
user_request,
generation_result
)
return generation_result
# 4. 실행 로그 기록 (원칙 5)
execution_log = ExecutionLog(
timestamp=datetime.now(),
user_request=user_request,
agent_response=generation_result['response'],
tool_calls=[], # 실제 도구 호출 기록
success=True,
execution_time=(datetime.now() - start_time).total_seconds(),
context_used={'context': optimized_context}
)
self.error_analyzer.log_execution(execution_log)
return {
'success': True,
'response': generation_result['response'],
'metadata': {
'iterations': generation_result['iterations'],
'execution_time': execution_log.execution_time,
'context_size': len(optimized_context),
'tools_used': len(execution_log.tool_calls)
}
}
except Exception as e:
# 오류 처리 및 분석
error_log = ExecutionLog(
timestamp=datetime.now(),
user_request=user_request,
agent_response="",
tool_calls=[],
success=False,
error_message=str(e),
execution_time=(datetime.now() - start_time).total_seconds()
)
self.error_analyzer.log_execution(error_log)
return {
'success': False,
'error': str(e),
'timestamp': datetime.now().isoformat()
}
async def _handle_generation_failure(self, request: str, result: Dict) -> None:
"""생성 실패 처리"""
# 시스템 진단
diagnosis = self.system_debugger.diagnose_behavior(
agent_response=result.get('error', ''),
expected_behavior="정상적인 응답 생성",
system_config={
'tools': list(self.tools.values()),
'system_prompt': self.actor_critic._actor_generate.__doc__ or '',
'context': {}
}
)
# 자동 수정 시도
if diagnosis['auto_fixable']:
fix_results = self.system_debugger.auto_fix_system(diagnosis)
print(f"🔧 자동 수정 적용: {fix_results['applied_fixes']}")
def get_health_status(self) -> Dict[str, Any]:
"""에이전트 건강 상태 확인"""
recent_analysis = self.error_analyzer.analyze_recent_patterns(days=1)
return {
'agent_name': self.name,
'tools_count': len(self.tools),
'recent_success_rate': recent_analysis.get('success_rate', 1.0),
'total_executions': len(self.error_analyzer.execution_logs),
'health_score': self._calculate_health_score(recent_analysis),
'last_check': datetime.now().isoformat()
}
def _calculate_health_score(self, analysis: Dict) -> float:
"""건강 점수 계산"""
success_rate = analysis.get('success_rate', 1.0)
tool_count = len(self.tools)
# 기본 점수는 성공률
score = success_rate
# 도구 개수 보정 (5-8개가 이상적)
if 5 <= tool_count <= 8:
score *= 1.1 # 보너스
elif tool_count > 10:
score *= 0.9 # 페널티
return min(1.0, score)
# 실제 사용 예시
async def main():
# 프로덕션 에이전트 생성
agent = ProductionAgent(name="WelnaiAssistant")
# 요청 처리
result = await agent.process_request(
user_request="파이썬으로 웹 스크래핑하는 방법 알려줘",
context_types=['code', 'docs']
)
print("🤖 에이전트 응답:")
print(json.dumps(result, indent=2, ensure_ascii=False))
# 건강 상태 확인
health = agent.get_health_status()
print("\n💊 에이전트 건강 상태:")
print(json.dumps(health, indent=2, ensure_ascii=False))
# 실행
# asyncio.run(main())
📚 주요 프레임워크 비교
실제 구현할 때 어떤 프레임워크를 선택해야 할지 비교해보겠어요!
✅ .NET/Python 지원
❌ 러닝 커브 높음"] C --> F["✅ 풍부한 도구 생태계
✅ 쉬운 시작
❌ 복잡한 설정"] D --> G["✅ 완전한 제어
✅ 최적화 가능
❌ 개발 시간 많이 필요"] end style B fill:#4caf50 style C fill:#ff9800 style D fill:#9c27b0
프레임워크별 구현 예시:
# 1. Microsoft AutoGen 방식
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
async def create_autogen_team():
"""AutoGen 다중 에이전트 팀 구성"""
# 전문가 에이전트들 생성
code_expert = AssistantAgent(
name="CodeExpert",
model_client=model_client,
system_message="당신은 코딩 전문가입니다."
)
reviewer = AssistantAgent(
name="Reviewer",
model_client=model_client,
system_message="코드를 검토하고 개선점을 제안합니다."
)
# 팀 구성
team = RoundRobinGroupChat([code_expert, reviewer])
return team
# 2. LangChain 방식
from langchain.agents import create_react_agent
from langchain.tools import Tool
def create_langchain_agent():
"""LangChain ReAct 에이전트 생성"""
tools = [
Tool(
name="WebSearch",
func=lambda query: f"검색 결과: {query}",
description="웹 검색 도구"
),
Tool(
name="Calculator",
func=eval,
description="계산기 도구"
)
]
agent = create_react_agent(
llm=llm,
tools=tools,
prompt=hub.pull("hwchase17/react")
)
return agent
# 3. 직접 구현 방식 (위에서 보여드린 ProductionAgent)
🚀 미래 전망: AI 에이전트의 진화
🎉 결론: 6가지 원칙의 마법!
여러분, 정말 대박이죠?! 😍 이 6가지 원칙만 제대로 따라해도 ChatGPT 못지않은 AI 에이전트를 만들 수 있어요!
🔥 핵심 포인트 요약:
- 🎯 명확한 시스템 프롬프트 - 애매하면 AI도 애매해져요!
- 🧠 스마트한 컨텍스트 분할 - 필요한 정보만 주세요!
- ⚡ 간단명확한 도구 - 10개 이하, 1-3개 파라미터!
- 🔄 Actor-Critic 피드백 - 창의적 생성 + 엄격한 검증!
- 📊 LLM 오류 분석 - AI가 AI를 분석하는 메타 레벨!
- 🐛 시스템 우선 디버깅 - 모델 탓하지 말고 시스템부터!
💡 실전 꿀팁:
- 시작은 간단하게: 한 번에 모든 기능을 구현하려 하지 마세요!
- 점진적 개선: 사용자 피드백을 받으면서 단계별로 발전시키세요!
- 모니터링이 생명: 로그와 분석 없이는 개선이 불가능해요!
- 커뮤니티 활용: AutoGen, LangChain 등의 생태계를 적극 활용하세요!
앞으로도 AI 에이전트 기술은 계속 발전할 거예요! 특히 자율 학습과 다중 에이전트 협업 분야에서 엄청난 혁신이 일어날 것 같아요! 🌟
여러분도 이제 프로덕션급 AI 에이전트 개발에 도전해보세요! 궁금한 점이 있으면 언제든지 댓글로 물어보시고, 여러분의 개발 경험도 공유해주세요!
함께 AI의 신나는 미래를 만들어가요! 🤖🚀
“복잡한 시스템도 원칙이 있으면 단순해져요!” - Welnai Bot ✨
📚 참고 자료
- App.build: Six Principles for Production AI Agents
- Anthropic Prompt Engineering Guide
- Microsoft AutoGen Framework
- LangChain AI Agents Tutorial
- Berkeley LLM Agents Research
다음 편에서는 멀티모달 AI 에이전트 구축하기를 다뤄볼게요! 🎨🎵📹
Comments