Agentic AI 디자인 패턴 (Part 1): 기초 패턴과 실전 적용
Agentic AI 디자인 패턴 (Part 1): 기초 패턴과 실전 적용
GenAI vs Agentic AI: 무엇이 다른가?
생성형 AI(GenAI)의 등장은 AI 산업에 혁명을 가져왔지만, 단순히 텍스트나 이미지를 생성하는 것만으로는 복잡한 비즈니스 문제를 해결하기 어렵습니다. 여기서 Agentic AI가 등장합니다.
핵심 차이점
| Feature | Gen AI | Agentic AI |
|---|---|---|
| 작동 방식 | 프롬프트에 즉각 응답 | 목표 지향적 다단계 실행 |
| 자율성 | 인간의 명령에 의존적 | 자율적 계획 및 실행 |
| 상호작용 | 단일 입력 → 단일 출력 | 환경과 지속적 상호작용 |
| 도구 사용 | 제한적 | 외부 도구/API 적극 활용 |
| 메모리 | 대화 컨텍스트만 유지 | 상태 추적 및 장기 메모리 |
| 의사결정 | 반응적(Reactive) | 능동적(Proactive) |
실제 사례로 이해하기
GenAI 시나리오:
사용자: "이번 분기 매출 보고서를 작성해줘"
GenAI: [보고서 텍스트 생성]
→ 실제 데이터 없이 일반적인 템플릿만 제공
Agentic AI 시나리오:
사용자: "이번 분기 매출 보고서를 작성해줘"
Agentic AI:
1. 데이터베이스에서 실제 매출 데이터 조회 (Tool Use)
2. 전년 동기 대비 분석 수행 (Reasoning)
3. 트렌드 시각화 생성 (Tool Use)
4. 인사이트 도출 및 보고서 작성 (Reasoning + Acting)
5. 최종 검토 및 개선 (Reflection)
→ 실제 데이터 기반의 구체적이고 실행 가능한 보고서 제공
Agentic AI의 세 가지 핵심 원칙
AWS Prescriptive Guidance에 따르면, Agentic AI는 다음 세 가지 특성으로 정의됩니다:
-
Asynchronous (비동기성)
- 느슨하게 결합된 이벤트 기반 환경에서 작동
- 여러 작업을 병렬로 처리 가능
- 실시간 응답을 기다리지 않고 독립적으로 진행
-
Autonomy (자율성)
- 인간이나 외부 제어 없이 독립적으로 행동
- 상황에 따라 자체적으로 판단하고 결정
- 예기치 않은 상황에 적응하고 대응
-
Agency (주체성)
- 명확한 목표를 가지고 행동
- 환경에 실질적인 영향을 미칠 수 있음
- 결과에 대한 책임을 가진 의사결정
이러한 특성들이 전통적인 결정론적 자동화와 Agentic AI를 구분하는 핵심 요소입니다.
왜 Agentic AI가 중요한가?
Agentic AI는 단순히 프롬프트에 응답하는 수준을 넘어, 복잡한 작업을 자율적으로 계획하고 실행하는 지능형 시스템입니다. 이 시리즈에서는 프로덕션 환경에서 검증된 Agentic AI 디자인 패턴들을 깊이 있게 다루며, 각 패턴의 특징과 실제 적용 사례를 AWS 서비스와 함께 살펴봅니다.
Agentic Patterns의 핵심 원칙
AWS Prescriptive Guidance에 따르면, 모든 Agentic AI 시스템은 세 가지 기본 원칙을 따릅니다:
- Asynchronous (비동기성): 에이전트는 느슨하게 결합된 이벤트 기반 환경에서 작동합니다
- Autonomy (자율성): 에이전트는 인간이나 외부 제어 없이 독립적으로 행동합니다
- Agency (주체성): 에이전트는 목표 지향적이며 환경에 영향을 미칠 수 있습니다
이러한 원칙들은 전통적인 결정론적 자동화와 Agentic AI를 구분하는 핵심 요소입니다.
1. ReAct Pattern: Reasoning과 Acting의 결합
패턴 개요
ReAct(Reason + Act) 패턴은 Amazon Bedrock Agents의 기본 오케스트레이션 전략으로, 에이전트가 사고(Reasoning)와 행동(Acting)을 반복적으로 수행하며 문제를 해결하는 방식입니다.
작동 메커니즘
ReAct 패턴은 다음과 같은 순환 구조로 작동합니다:
- Reason: Foundation Model의 추론 능력을 사용하여 요청을 분석하고 논리적 단계로 분해
- Act: 필요한 도구(Action Groups)나 지식 베이스를 결정하고 API 호출 또는 데이터 쿼리 실행
- Observe: 실행 결과를 관찰하고 다음 단계 결정
- Iterate: 작업이 완료될 때까지 반복
# ReAct 패턴의 개념적 구조
while not task_completed:
# Reasoning Phase
thought = llm.reason(current_state, goal)
# Acting Phase
action = select_tool(thought)
observation = execute_action(action)
# Update State
current_state = update(current_state, observation)
적용 케이스
언제 사용해야 하는가:
- 다단계 작업이 필요한 경우 (예: 데이터 수집 → 분석 → 보고서 생성)
- 외부 API나 데이터베이스와의 상호작용이 필요한 경우
- 실행 중 동적으로 다음 단계를 결정해야 하는 경우
실제 사용 예시:
- 고객 지원 시스템: 문의 분석 → 관련 문서 검색 → 답변 생성 → 티켓 업데이트
- 데이터 분석 파이프라인: 데이터 소스 식별 → 데이터 추출 → 변환 → 시각화
AWS 구현
Amazon Bedrock Agents는 ReAct 패턴을 기본으로 제공합니다:
import boto3
bedrock_agent = boto3.client('bedrock-agent-runtime')
response = bedrock_agent.invoke_agent(
agentId='AGENT_ID',
agentAliasId='AGENT_ALIAS_ID',
sessionId='session-123',
inputText='분기별 매출 보고서를 생성해주세요'
)
# 에이전트는 자동으로:
# 1. 데이터베이스에서 매출 데이터 조회 (Act)
# 2. 데이터 분석 및 트렌드 파악 (Reason)
# 3. 시각화 도구 호출 (Act)
# 4. 보고서 생성 (Reason + Act)
트레이드오프
장점:
- 투명성: 각 단계의 추론 과정을 추적 가능
- 적응성: 중간 결과에 따라 계획 조정 가능
- 일관성: 예측 가능한 워크플로우
단점:
- 레이턴시: 각 단계마다 LLM 호출이 필요하여 응답 시간 증가
- 비용: 토큰 사용량이 많아 운영 비용 상승
- 순차성: 병렬 처리가 필요한 작업에는 비효율적
2. Reflection Pattern: 자기 개선 메커니즘
패턴 개요
Reflection 패턴은 에이전트가 자신의 출력을 평가하고 개선하는 자기 피드백 루프를 구현합니다. 이는 인간이 작업을 검토하고 수정하는 과정을 모방한 것입니다.
작동 메커니즘
def reflection_loop(task, max_iterations=3):
output = generate_initial_output(task)
for i in range(max_iterations):
# Self-Critique
critique = llm.evaluate(output, task)
if critique.is_satisfactory():
break
# Self-Improvement
output = llm.refine(output, critique)
return output
Reflection 패턴은 두 가지 역할을 분리합니다:
- Generator: 초기 출력 생성
- Reflector: 출력 평가 및 개선 방향 제시
적용 케이스
언제 사용해야 하는가:
- 출력 품질이 중요한 경우 (예: 기술 문서, 코드 리뷰)
- 복잡한 추론이 필요한 작업
- 오류 가능성이 높은 작업
실제 사용 예시:
- 코드 생성 및 리뷰
# Initial Generation
code = generate_code(requirements)
# Reflection Loop
for _ in range(3):
issues = analyze_code(code) # 보안, 성능, 가독성 검토
if not issues:
break
code = improve_code(code, issues)
- 기술 문서 작성
- 초안 생성 → 정확성 검증 → 명확성 개선 → 완성도 평가
AWS 구현
Amazon Bedrock의 Converse API를 활용한 구현:
import boto3
bedrock = boto3.client('bedrock-runtime')
def generate_with_reflection(prompt, model_id):
# Generation Phase
response = bedrock.converse(
modelId=model_id,
messages=[{
'role': 'user',
'content': [{'text': prompt}]
}]
)
initial_output = response['output']['message']['content'][0]['text']
# Reflection Phase
reflection_prompt = f"""
다음 출력을 평가하고 개선점을 제시하세요:
출력: {initial_output}
평가 기준:
- 정확성
- 완전성
- 명확성
"""
critique = bedrock.converse(
modelId=model_id,
messages=[{
'role': 'user',
'content': [{'text': reflection_prompt}]
}]
)
# Refinement Phase
if needs_improvement(critique):
refined_output = refine_output(initial_output, critique)
return refined_output
return initial_output
트레이드오프
장점:
- 품질 향상: 반복적 개선으로 출력 품질 대폭 향상
- 오류 감소: 자기 검증을 통한 실수 최소화
- 인간 개입 감소: 자동화된 품질 관리
단점:
- 계산 비용: 여러 번의 LLM 호출로 인한 비용 증가
- 레이턴시: 반복 횟수에 비례한 응답 시간 증가
- 수렴 보장 없음: 항상 개선되는 것은 아님
3. Tool Use Pattern: 외부 능력 통합
패턴 개요
Tool Use 패턴은 에이전트가 외부 도구와 API를 호출하여 학습 데이터 범위를 넘어서는 작업을 수행할 수 있게 합니다. 이는 거의 모든 프로덕션 에이전트에서 필수적인 패턴입니다.
작동 메커니즘
에이전트는 다음과 같은 방식으로 도구를 사용합니다:
- Tool Discovery: 사용 가능한 도구 목록과 각 도구의 기능 파악
- Tool Selection: 작업에 적합한 도구 선택
- Parameter Extraction: 도구 호출에 필요한 매개변수 추출
- Tool Invocation: 도구 실행 및 결과 수신
- Result Integration: 결과를 컨텍스트에 통합하여 다음 단계 결정
적용 케이스
필수 사용 케이스:
- 실시간 데이터 조회 (날씨, 주가, 뉴스)
- 데이터베이스 작업 (CRUD 연산)
- 외부 API 통합 (결제, 이메일, SMS)
- 코드 실행 (계산, 데이터 분석)
실제 사용 예시:
# Tool Definition
tools = [
{
"name": "get_weather",
"description": "현재 날씨 정보를 조회합니다",
"parameters": {
"location": "string",
"unit": "celsius|fahrenheit"
}
},
{
"name": "search_database",
"description": "데이터베이스에서 정보를 검색합니다",
"parameters": {
"query": "string",
"table": "string"
}
}
]
# Agent decides which tool to use
user_query = "서울의 현재 날씨는?"
selected_tool = agent.select_tool(user_query, tools)
# -> "get_weather"
result = execute_tool(selected_tool, {"location": "Seoul", "unit": "celsius"})
AWS 구현
Amazon Bedrock Agents의 Action Groups를 통한 구현:
# Lambda Function for Tool Execution
def lambda_handler(event, context):
action_group = event['actionGroup']
function = event['function']
parameters = event.get('parameters', [])
if function == 'get_weather':
location = next(p['value'] for p in parameters if p['name'] == 'location')
weather_data = fetch_weather(location)
return {
'response': {
'actionGroup': action_group,
'function': function,
'functionResponse': {
'responseBody': {
'TEXT': {
'body': json.dumps(weather_data)
}
}
}
}
}
Action Group 정의:
{
"actionGroupName": "WeatherTools",
"actionGroupExecutor": {
"lambda": "arn:aws:lambda:region:account:function:weather-tool"
},
"apiSchema": {
"payload": {
"openapi": "3.0.0",
"info": {
"title": "Weather API",
"version": "1.0.0"
},
"paths": {
"/weather": {
"get": {
"description": "Get current weather",
"parameters": [
{
"name": "location",
"in": "query",
"required": true,
"schema": {"type": "string"}
}
]
}
}
}
}
}
}
도구 선택 전략
단일 도구 vs 다중 도구:
# 단일 도구 호출
result = agent.use_tool("calculator", {"expression": "123 * 456"})
# 도구 체이닝
search_results = agent.use_tool("web_search", {"query": "AWS Lambda pricing"})
summary = agent.use_tool("summarizer", {"text": search_results})
translation = agent.use_tool("translator", {"text": summary, "target": "ko"})
트레이드오프
장점:
- 확장성: 새로운 도구 추가로 기능 확장 용이
- 정확성: 실시간 데이터와 전문 시스템 활용
- 유연성: 다양한 외부 서비스 통합 가능
단점:
- 복잡성: 도구 관리 및 오류 처리 필요
- 의존성: 외부 서비스 장애 시 영향
- 보안: API 키 관리 및 권한 제어 필요
패턴 선택 가이드
실제 프로젝트에서 어떤 패턴을 선택할지 결정하는 프레임워크:
의사결정 트리
1. 워크플로우가 예측 가능한가?
YES → Sequential Pattern (Part 2에서 다룸)
NO → 2번으로
2. 품질이 속도보다 중요한가?
YES → Reflection Pattern 추가
NO → 직접 실행 최적화
3. 외부 데이터나 도구가 필요한가?
YES → Tool Use Pattern (필수)
NO → Basic Reasoning Pattern
4. 작업이 진정으로 복잡한가?
YES → Multi-Agent Pattern (Part 3에서 다룸)
NO → Single Agent + Tool Use로 시작
패턴 조합 예시
실제 프로덕션 시스템은 여러 패턴을 조합합니다:
고객 지원 에이전트:
- ReAct (기본 오케스트레이션)
- Tool Use (티켓 시스템, 지식 베이스)
- Reflection (답변 품질 검증)
코드 생성 에이전트:
- ReAct (요구사항 분석 → 설계 → 구현)
- Tool Use (코드 실행, 테스트 실행)
- Reflection (코드 리뷰 및 개선)
성능 최적화 전략
1. 캐싱 전략
from functools import lru_cache
@lru_cache(maxsize=1000)
def cached_tool_call(tool_name, params_hash):
return execute_tool(tool_name, params_hash)
2. 병렬 도구 호출
import asyncio
async def parallel_tool_execution(tools):
tasks = [execute_tool_async(tool) for tool in tools]
results = await asyncio.gather(*tasks)
return results
3. 조기 종료 조건
def reflection_with_early_exit(output, quality_threshold=0.9):
for i in range(max_iterations):
quality_score = evaluate_quality(output)
if quality_score >= quality_threshold:
return output # 조기 종료
output = refine(output)
return output
모니터링 및 관찰성
프로덕션 환경에서는 다음 메트릭을 추적해야 합니다:
metrics = {
"pattern_type": "ReAct",
"iterations": 3,
"tools_used": ["database", "calculator"],
"total_tokens": 1500,
"latency_ms": 2300,
"success": True,
"quality_score": 0.92
}
# CloudWatch에 메트릭 전송
cloudwatch.put_metric_data(
Namespace='AgenticAI',
MetricData=[
{
'MetricName': 'PatternLatency',
'Value': metrics['latency_ms'],
'Unit': 'Milliseconds',
'Dimensions': [
{'Name': 'Pattern', 'Value': metrics['pattern_type']}
]
}
]
)
다음 편 예고
Part 2에서는 더 복잡한 오케스트레이션 패턴을 다룹니다:
- Planning Pattern: 복잡한 작업을 하위 작업으로 분해
- Routing Pattern: 전문화된 에이전트로 작업 라우팅
- Human-in-the-Loop Pattern: 인간 검토 및 승인 통합
이러한 패턴들은 엔터프라이즈급 애플리케이션에서 필수적이며, AWS Step Functions와 Amazon EventBridge를 활용한 구현 방법을 상세히 살펴볼 것입니다.
