S
STONI
AI
Agentic AI
AWS Bedrock
Design Patterns
ReAct
Reflection
Tool Use
Agent
LLM

Agentic AI 디자인 패턴 (Part 1): 기초 패턴과 실전 적용

Agentic AI 디자인 패턴 (Part 1): 기초 패턴과 실전 적용

GenAI vs Agentic AI: 무엇이 다른가?

생성형 AI(GenAI)의 등장은 AI 산업에 혁명을 가져왔지만, 단순히 텍스트나 이미지를 생성하는 것만으로는 복잡한 비즈니스 문제를 해결하기 어렵습니다. 여기서 Agentic AI가 등장합니다.

핵심 차이점

FeatureGen AIAgentic 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는 다음 세 가지 특성으로 정의됩니다:

  1. Asynchronous (비동기성)

    • 느슨하게 결합된 이벤트 기반 환경에서 작동
    • 여러 작업을 병렬로 처리 가능
    • 실시간 응답을 기다리지 않고 독립적으로 진행
  2. Autonomy (자율성)

    • 인간이나 외부 제어 없이 독립적으로 행동
    • 상황에 따라 자체적으로 판단하고 결정
    • 예기치 않은 상황에 적응하고 대응
  3. 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 패턴은 다음과 같은 순환 구조로 작동합니다:

  1. Reason: Foundation Model의 추론 능력을 사용하여 요청을 분석하고 논리적 단계로 분해
  2. Act: 필요한 도구(Action Groups)나 지식 베이스를 결정하고 API 호출 또는 데이터 쿼리 실행
  3. Observe: 실행 결과를 관찰하고 다음 단계 결정
  4. 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: 출력 평가 및 개선 방향 제시

적용 케이스

언제 사용해야 하는가:

  • 출력 품질이 중요한 경우 (예: 기술 문서, 코드 리뷰)
  • 복잡한 추론이 필요한 작업
  • 오류 가능성이 높은 작업

실제 사용 예시:

  1. 코드 생성 및 리뷰
# 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)
  1. 기술 문서 작성
  • 초안 생성 → 정확성 검증 → 명확성 개선 → 완성도 평가

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를 호출하여 학습 데이터 범위를 넘어서는 작업을 수행할 수 있게 합니다. 이는 거의 모든 프로덕션 에이전트에서 필수적인 패턴입니다.

작동 메커니즘

에이전트는 다음과 같은 방식으로 도구를 사용합니다:

  1. Tool Discovery: 사용 가능한 도구 목록과 각 도구의 기능 파악
  2. Tool Selection: 작업에 적합한 도구 선택
  3. Parameter Extraction: 도구 호출에 필요한 매개변수 추출
  4. Tool Invocation: 도구 실행 및 결과 수신
  5. 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를 활용한 구현 방법을 상세히 살펴볼 것입니다.

참고 자료

Clickable cat