🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

AI 에이전트 개요 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 3. · 18 Views

AI 에이전트 개요 완벽 가이드

AI 에이전트의 기본 개념부터 5가지 워크플로 패턴까지, 프레임워크 없이 직접 구현하는 방법을 초급 개발자의 눈높이에서 설명합니다. LLM 기반 자동화 시스템의 핵심을 마스터할 수 있습니다.


목차

  1. AI_에이전트란_무엇인가
  2. 에이전트와_일반_챗봇의_차이
  3. 프레임워크_없이_만드는_이유
  4. 다섯가지_워크플로_패턴_소개
  5. 프롬프트_체이닝_라우팅_병렬처리
  6. 오케스트레이터_워커_평가_최적화
  7. 이_코스의_학습_로드맵

1. AI 에이전트란 무엇인가

어느 날 김개발 씨는 ChatGPT를 사용하다가 문득 궁금해졌습니다. "이 AI가 스스로 인터넷을 검색하고, 코드를 실행하고, 파일을 저장할 수 있다면 얼마나 좋을까?" 단순히 대화만 하는 것이 아니라, 실제로 무언가를 해내는 AI 말입니다.

AI 에이전트란 LLM이 단순히 텍스트를 생성하는 것을 넘어, 스스로 판단하고 도구를 사용하여 목표를 달성하는 시스템입니다. 마치 유능한 비서가 지시를 받으면 알아서 일정을 조율하고, 이메일을 보내고, 자료를 정리하는 것과 같습니다.

에이전트는 생각하고, 행동하고, 그 결과를 다시 생각에 반영하는 순환 구조를 가집니다.

다음 코드를 살펴봅시다.

# AI 에이전트의 기본 구조
import anthropic

client = anthropic.Anthropic()

def simple_agent(user_request):
    # 1. LLM에게 사용자 요청을 전달하고 계획 수립
    planning_response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": f"다음 요청을 수행할 계획을 세워주세요: {user_request}"}]
    )

    # 2. 계획에 따라 도구를 실행 (여기서는 간단히 출력)
    plan = planning_response.content[0].text
    print(f"수립된 계획: {plan}")

    # 3. 결과를 반환
    return plan

# 에이전트 실행
result = simple_agent("오늘 날씨를 확인하고 적절한 옷차림을 추천해줘")

김개발 씨는 입사 6개월 차 주니어 개발자입니다. 요즘 회사에서 AI를 활용한 업무 자동화 프로젝트가 한창인데, 선배들이 "에이전트"라는 단어를 자주 사용합니다.

처음에는 그냥 챗봇의 다른 이름인 줄 알았는데, 뭔가 다른 것 같습니다. 어느 날 점심시간, 박시니어 씨에게 조심스럽게 물었습니다.

"선배님, AI 에이전트가 정확히 뭔가요? 그냥 ChatGPT 같은 건가요?" 박시니어 씨가 웃으며 대답했습니다.

"좋은 질문이야. 비유를 들어볼게.

ChatGPT는 아주 똑똑한 백과사전 같아. 뭘 물어보면 잘 대답해주지.

근데 직접 뭔가를 해주진 않잖아?" 김개발 씨가 고개를 끄덕였습니다. "네, 맞아요.

코드를 알려주긴 하는데 직접 실행해주진 않죠." "그렇지. 반면에 에이전트는 유능한 비서 같아.

네가 '내일 부산 출장 준비해줘'라고 하면, 스스로 기차표를 검색하고, 예약하고, 숙소도 찾고, 일정표까지 만들어주는 거야. 단순히 정보를 알려주는 게 아니라 실제로 행동을 하는 거지." 이것이 바로 AI 에이전트의 핵심입니다.

LLM이 가진 추론 능력에 실제 세계와 상호작용할 수 있는 도구를 결합한 것입니다. 에이전트는 크게 세 가지 요소로 구성됩니다.

첫째는 두뇌 역할을 하는 LLM입니다. Claude나 GPT 같은 대형 언어 모델이 상황을 이해하고 다음에 무엇을 해야 할지 판단합니다.

둘째는 손과 발 역할을 하는 도구들입니다. 웹 검색, 파일 읽기/쓰기, 코드 실행, API 호출 등 실제로 무언가를 할 수 있는 기능들입니다.

셋째는 기억 역할을 하는 컨텍스트입니다. 이전에 무엇을 했고, 어떤 결과가 나왔는지 기억하여 다음 행동에 반영합니다.

위의 코드를 살펴보면, 아주 단순한 형태의 에이전트 구조를 볼 수 있습니다. 사용자의 요청이 들어오면 LLM이 먼저 계획을 세웁니다.

실제 에이전트에서는 이 계획에 따라 다양한 도구를 호출하고, 그 결과를 다시 LLM에게 전달하여 다음 행동을 결정합니다. 실제 현업에서 에이전트는 다양한 곳에서 활용됩니다.

고객 서비스에서는 단순히 답변만 하는 것이 아니라 주문 조회, 환불 처리, 배송 추적까지 직접 수행합니다. 개발 분야에서는 코드를 분석하고, 버그를 찾아 수정하고, 테스트까지 실행합니다.

하지만 에이전트를 만들 때 주의할 점이 있습니다. LLM은 때때로 환각을 일으켜 잘못된 판단을 할 수 있습니다.

따라서 중요한 작업에서는 사람의 승인을 받는 단계를 넣거나, 되돌릴 수 없는 작업은 신중하게 처리해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다. "아, 그러니까 AI한테 뇌만 달아준 게 아니라 손발까지 달아준 거네요!" 정확합니다.

AI 에이전트는 생각하고 행동하는 AI 시스템의 새로운 패러다임입니다.

실전 팁

💡 - 에이전트 설계 시 LLM의 판단 오류에 대비한 안전장치를 반드시 마련하세요

  • 처음에는 간단한 도구 하나부터 시작해서 점진적으로 확장하는 것이 좋습니다
  • 에이전트의 모든 행동은 로깅하여 나중에 디버깅할 수 있게 해야 합니다

2. 에이전트와 일반 챗봇의 차이

김개발 씨는 회사에서 고객 문의를 처리하는 챗봇을 운영하고 있습니다. 그런데 최근 "에이전트로 업그레이드하자"는 이야기가 나왔습니다.

둘이 뭐가 다른 걸까요? 그냥 더 똑똑한 챗봇 아닌가요?

일반 챗봇은 질문에 대한 답변만 생성하는 반면, 에이전트는 목표 달성을 위해 스스로 계획을 세우고 도구를 사용합니다. 챗봇이 도서관의 안내 데스크라면, 에이전트는 직접 책을 찾아와서 필요한 부분을 복사해주는 사서와 같습니다.

가장 큰 차이는 자율성행동 능력입니다.

다음 코드를 살펴봅시다.

# 일반 챗봇 방식
def chatbot(user_message):
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": user_message}]
    )
    return response.content[0].text  # 단순히 텍스트만 반환

# 에이전트 방식
def agent(user_goal, tools):
    messages = [{"role": "user", "content": user_goal}]

    while True:  # 목표 달성까지 반복
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            tools=tools,  # 사용 가능한 도구 목록
            messages=messages
        )

        # 도구 호출이 필요하면 실행
        if response.stop_reason == "tool_use":
            tool_result = execute_tool(response)  # 도구 실행
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_result})
        else:
            return response.content[0].text  # 완료

김개발 씨의 팀에서 운영하는 챗봇은 꽤 똑똑합니다. 고객이 "반품하고 싶어요"라고 하면 반품 절차를 친절하게 안내해줍니다.

하지만 여기서 끝입니다. 고객은 안내받은 대로 직접 반품 신청 페이지에 들어가서 양식을 작성해야 합니다.

박시니어 씨가 화이트보드에 두 개의 그림을 그렸습니다. "왼쪽이 챗봇이야.

고객이 질문하면 답변하고, 또 질문하면 또 답변해. 항상 고객이 주도권을 가지고 있어.

수동적이지." 오른쪽 그림을 가리키며 계속했습니다. "이게 에이전트야.

고객이 '반품해줘'라고 하면, 스스로 주문 내역을 조회하고, 반품 가능한지 확인하고, 택배 예약까지 해버려. 능동적이야." 이 차이를 표로 정리하면 더 명확해집니다.

챗봇의 동작 방식은 질문-응답입니다. 한 번 답하면 끝입니다.

반면 에이전트는 목표-계획-실행-평가의 순환 구조로 동작합니다. 목표가 달성될 때까지 계속 시도합니다.

또 다른 중요한 차이는 상태 관리입니다. 일반 챗봇은 대화 맥락 정도만 기억합니다.

하지만 에이전트는 현재 진행 중인 작업의 상태, 이전 도구 호출의 결과, 남은 단계들을 모두 추적합니다. 위의 코드를 보면 이 차이가 명확하게 드러납니다.

챗봇 함수는 단순합니다. 메시지를 받아서 응답을 반환하고 끝입니다.

반면 에이전트 함수는 while 루프가 있습니다. 목표가 달성될 때까지 도구를 호출하고, 결과를 확인하고, 필요하면 다시 도구를 호출합니다.

실제로 이 차이가 어떤 영향을 미칠까요? 쇼핑몰 예시를 들어보겠습니다.

고객이 "지난달에 산 파란색 티셔츠 환불해줘"라고 했다고 가정해봅시다. 챗봇이라면 이렇게 답할 것입니다.

"환불을 원하시는군요. 주문번호를 알려주시면 환불 절차를 안내해드리겠습니다." 고객은 주문번호를 찾아야 합니다.

에이전트라면 다릅니다. 먼저 고객 정보로 주문 내역을 조회합니다.

지난달 구매한 파란색 티셔츠를 찾아냅니다. 환불 정책에 맞는지 확인합니다.

문제없으면 환불 처리를 진행하고 "주문번호 12345의 파란색 티셔츠 환불이 완료되었습니다. 3일 내로 카드 취소됩니다"라고 답합니다.

물론 에이전트가 항상 좋은 것은 아닙니다. 에이전트는 더 많은 리소스를 사용하고, 설계와 테스트가 복잡하며, 잘못된 판단을 할 위험도 있습니다.

단순한 FAQ 응답이 목적이라면 챗봇으로 충분합니다. 김개발 씨가 정리했습니다.

"그러니까 단순 안내는 챗봇, 실제 업무 처리는 에이전트네요?" 박시니어 씨가 엄지를 치켜세웠습니다. "정확해.

목적에 맞게 선택하면 돼."

실전 팁

💡 - 단순 정보 제공만 필요하다면 챗봇이 더 효율적입니다

  • 에이전트 도입 시 반드시 사람의 승인이 필요한 작업 범위를 정의하세요
  • 챗봇에서 에이전트로 전환할 때는 점진적으로 기능을 추가하는 것이 안전합니다

3. 프레임워크 없이 만드는 이유

김개발 씨가 LangChain, AutoGen 같은 에이전트 프레임워크를 검토하고 있었습니다. 그런데 박시니어 씨가 의외의 조언을 했습니다.

"일단 프레임워크 없이 직접 만들어봐. 그래야 진짜 이해할 수 있어."

에이전트 프레임워크는 편리하지만, 처음 배울 때는 블랙박스가 되어 핵심 원리를 이해하기 어렵게 만듭니다. 마치 자동차 운전을 배울 때 자동 주차 기능만 쓰면 실제 주차 원리를 모르는 것과 같습니다.

직접 구현해보면 에이전트의 동작 원리를 완벽히 이해하고, 문제가 생겼을 때 정확히 어디를 고쳐야 하는지 알 수 있습니다.

다음 코드를 살펴봅시다.

# 프레임워크 없이 구현하는 간단한 도구 시스템
def create_tool(name, description, func):
    """도구를 정의하는 함수"""
    return {
        "name": name,
        "description": description,
        "input_schema": {"type": "object", "properties": {}},
        "execute": func
    }

# 계산기 도구 예시
calculator = create_tool(
    name="calculator",
    description="수학 계산을 수행합니다",
    func=lambda expr: str(eval(expr))  # 실제로는 보안 처리 필요
)

# 도구 실행기
def run_tool(tool, input_data):
    print(f"도구 실행: {tool['name']}")
    result = tool["execute"](input_data)
    print(f"결과: {result}")
    return result

# 사용 예시
result = run_tool(calculator, "15 * 24 + 100")

김개발 씨는 당장 LangChain 튜토리얼을 따라해보고 싶었습니다. 몇 줄의 코드만으로 에이전트가 뚝딱 만들어지는 게 너무 매력적이었거든요.

그런데 왜 선배는 직접 만들어보라고 하는 걸까요? 박시니어 씨가 경험담을 들려주었습니다.

"나도 처음에 LangChain으로 시작했어. 근데 에이전트가 이상하게 동작할 때 어디가 문제인지 전혀 몰랐어.

프레임워크 안에서 뭐가 어떻게 돌아가는지 이해를 못 했거든." 이것은 많은 개발자들이 겪는 문제입니다. 프레임워크의 추상화는 양날의 검입니다.

복잡한 것을 쉽게 만들어주지만, 동시에 핵심을 가려버립니다. 직접 구현하면 얻는 첫 번째 장점은 완전한 이해입니다.

LLM이 도구를 어떻게 선택하는지, 도구 실행 결과를 어떻게 처리하는지, 루프는 언제 종료되는지 모든 것을 명확히 알게 됩니다. 두 번째 장점은 디버깅 능력입니다.

에이전트가 예상대로 동작하지 않을 때, 어느 단계에서 문제가 생겼는지 바로 찾아낼 수 있습니다. 프레임워크를 쓰면 "어딘가 내부에서 뭔가 잘못됐는데..." 수준에서 멈추기 쉽습니다.

세 번째는 자유로운 커스터마이징입니다. 프레임워크는 정해진 방식대로 동작합니다.

특별한 요구사항이 있을 때 프레임워크를 우회하거나 수정하는 것은 매우 어렵습니다. 직접 만든 코드는 원하는 대로 바꿀 수 있습니다.

위 코드를 보면 도구 시스템의 본질이 드러납니다. 도구란 결국 이름, 설명, 실행 함수의 조합입니다.

프레임워크가 복잡하게 포장해놨을 뿐, 핵심은 이렇게 단순합니다. 물론 프레임워크가 나쁜 것은 아닙니다.

프로덕션 환경에서는 검증된 프레임워크를 사용하는 것이 안전하고 효율적입니다. 하지만 배우는 단계에서는 직접 구현해보는 것이 훨씬 가치 있습니다.

비유하자면, 처음 요리를 배울 때 밀키트로 시작하면 편하지만 요리 원리를 모릅니다. 재료 손질부터 직접 해봐야 나중에 레시피를 변형하거나 새로운 요리를 만들 수 있습니다.

Anthropic에서도 이 점을 강조합니다. 공식 문서에서 "에이전트를 가장 간단한 형태로 시작하고, 필요할 때만 복잡성을 추가하라"고 권장합니다.

프레임워크는 그 복잡성 중 하나입니다. 김개발 씨가 결심했습니다.

"알겠어요. 일단 바닥부터 만들어볼게요." 박시니어 씨가 미소 지었습니다.

"그게 나중에 큰 자산이 될 거야. 원리를 아는 개발자와 모르는 개발자는 문제 앞에서 완전히 다르거든."

실전 팁

💡 - 처음에는 가장 단순한 형태로 구현하고, 점차 기능을 추가하세요

  • 프레임워크를 사용하더라도 내부 동작 원리를 파악하려고 노력하세요
  • 직접 구현한 경험은 프레임워크를 더 효과적으로 사용하는 데 도움이 됩니다

4. 다섯가지 워크플로 패턴 소개

김개발 씨가 본격적으로 에이전트를 설계하려 하자, 박시니어 씨가 화이트보드에 다섯 가지 패턴을 그리기 시작했습니다. "에이전트 설계의 핵심은 이 다섯 가지 패턴이야.

레고 블록처럼 조합해서 쓸 수 있어."

에이전트 워크플로에는 다섯 가지 핵심 패턴이 있습니다. 프롬프트 체이닝, 라우팅, 병렬 처리, 오케스트레이터-워커, 평가자-최적화기입니다.

마치 요리에 볶기, 굽기, 찌기 등의 기본 조리법이 있듯이, 에이전트에도 이런 기본 패턴들이 있습니다. 각 패턴의 특성을 이해하면 상황에 맞는 최적의 구조를 설계할 수 있습니다.

다음 코드를 살펴봅시다.

# 5가지 워크플로 패턴 개요
workflow_patterns = {
    "prompt_chaining": {
        "설명": "여러 단계를 순차적으로 연결",
        "사용_시점": "복잡한 작업을 단계별로 분해할 때",
        "예시": "문서 요약 → 핵심 추출 → 보고서 생성"
    },
    "routing": {
        "설명": "입력에 따라 적절한 처리 경로 선택",
        "사용_시점": "다양한 유형의 요청을 처리할 때",
        "예시": "고객 문의 → 기술/환불/배송 담당자 분배"
    },
    "parallelization": {
        "설명": "여러 작업을 동시에 처리",
        "사용_시점": "독립적인 작업을 빠르게 처리할 때",
        "예시": "코드 리뷰 + 보안 검사 + 성능 분석 동시 실행"
    },
    "orchestrator_worker": {
        "설명": "중앙 지휘자가 작업을 분배하고 조율",
        "사용_시점": "복잡한 프로젝트를 여러 팀이 협업할 때",
        "예시": "프로젝트 매니저가 디자인/개발/QA팀 조율"
    },
    "evaluator_optimizer": {
        "설명": "결과를 평가하고 개선을 반복",
        "사용_시점": "품질이 중요한 창작/최적화 작업",
        "예시": "글쓰기 → 검토 → 수정 반복"
    }
}

for pattern, info in workflow_patterns.items():
    print(f"\n{pattern}: {info['설명']}")

김개발 씨는 화이트보드 앞에 섰습니다. 박시니어 씨가 그린 다섯 개의 도형이 보입니다.

각각 화살표로 연결되어 있거나, 분기하거나, 병렬로 나열되어 있습니다. "복잡해 보이지?

근데 하나씩 보면 별거 아니야." 박시니어 씨가 첫 번째 패턴을 가리켰습니다. 첫 번째는 프롬프트 체이닝입니다.

가장 직관적인 패턴입니다. A 작업의 결과가 B 작업의 입력이 되고, B의 결과가 C의 입력이 되는 식입니다.

마치 공장의 컨베이어 벨트와 같습니다. 원재료가 들어가서 여러 공정을 거쳐 완제품이 나옵니다.

두 번째는 라우팅입니다. 입력의 종류에 따라 다른 경로로 보내는 것입니다.

콜센터의 ARS 시스템을 생각하면 됩니다. "기술 문의는 1번, 결제 문의는 2번을 눌러주세요." 각 번호마다 전문 상담원이 있듯이, 라우팅은 요청을 가장 적합한 처리기로 보냅니다.

세 번째는 병렬 처리입니다. 독립적인 작업들을 동시에 실행합니다.

식당에서 셰프가 스테이크를 굽는 동안 보조 요리사가 샐러드를 준비하는 것과 같습니다. 서로 기다릴 필요가 없는 작업은 동시에 하는 게 효율적입니다.

네 번째는 오케스트레이터-워커입니다. 이름 그대로 오케스트라의 지휘자와 연주자 관계입니다.

지휘자가 전체 곡의 흐름을 이해하고, 각 파트에 언제 어떻게 연주할지 지시합니다. 복잡한 프로젝트에서 여러 하위 작업을 조율할 때 유용합니다.

다섯 번째는 평가자-최적화기입니다. 결과물을 만들고, 검토하고, 더 나은 버전을 만드는 순환 구조입니다.

작가가 글을 쓰고, 편집자가 피드백을 주고, 다시 수정하는 과정과 같습니다. 김개발 씨가 질문했습니다.

"이 패턴들을 섞어서 쓸 수도 있나요?" "물론이지. 실제로 대부분의 에이전트는 여러 패턴을 조합해서 만들어.

예를 들어 오케스트레이터가 작업을 분배하는데, 각 워커가 체이닝으로 동작하고, 일부는 병렬로 실행하는 식이야." 이 다섯 가지 패턴을 이해하면 어떤 복잡한 에이전트도 설계할 수 있습니다. 마치 레고 블록으로 어떤 모양이든 만들 수 있는 것처럼요.

다음 섹션부터 각 패턴을 하나씩 자세히 살펴보겠습니다.

실전 팁

💡 - 처음에는 가장 단순한 체이닝 패턴부터 시작하세요

  • 패턴 선택 기준은 작업의 특성입니다: 순차적인가, 병렬 가능한가, 반복 개선이 필요한가
  • 실제 에이전트는 보통 여러 패턴을 조합하여 구성됩니다

5. 프롬프트 체이닝 라우팅 병렬처리

이제 본격적으로 각 패턴을 구현해볼 시간입니다. 김개발 씨가 노트북을 열고 코드를 작성하기 시작했습니다.

첫 번째로 살펴볼 세 가지 패턴은 가장 기본적이면서도 자주 사용되는 것들입니다.

프롬프트 체이닝은 여러 LLM 호출을 순차적으로 연결합니다. 각 단계의 출력이 다음 단계의 입력이 됩니다.

라우팅은 입력을 분석하여 적절한 처리 경로를 선택합니다. 병렬 처리는 독립적인 작업들을 동시에 실행하여 전체 처리 시간을 단축합니다.

이 세 패턴은 가장 기본적이면서도 실무에서 가장 많이 사용됩니다.

다음 코드를 살펴봅시다.

import asyncio

# 1. 프롬프트 체이닝: 순차 처리
def prompt_chaining(text):
    # 1단계: 텍스트 요약
    summary = call_llm(f"다음 글을 한 문장으로 요약해주세요: {text}")
    # 2단계: 핵심 키워드 추출
    keywords = call_llm(f"다음 요약에서 핵심 키워드 3개를 추출하세요: {summary}")
    # 3단계: 최종 보고서 생성
    report = call_llm(f"키워드 {keywords}를 바탕으로 짧은 보고서를 작성하세요")
    return report

# 2. 라우팅: 입력 유형별 분기
def routing(user_input):
    # 입력 분류
    category = call_llm(f"다음 문의를 분류하세요 (기술/환불/배송): {user_input}")

    handlers = {
        "기술": handle_tech_support,
        "환불": handle_refund,
        "배송": handle_shipping
    }
    return handlers.get(category.strip(), handle_general)(user_input)

# 3. 병렬 처리: 동시 실행
async def parallel_processing(code):
    tasks = [
        asyncio.create_task(call_llm_async(f"코드 리뷰: {code}")),
        asyncio.create_task(call_llm_async(f"보안 검사: {code}")),
        asyncio.create_task(call_llm_async(f"성능 분석: {code}"))
    ]
    results = await asyncio.gather(*tasks)  # 동시 실행
    return {"review": results[0], "security": results[1], "performance": results[2]}

박시니어 씨가 김개발 씨 옆에 앉아 코드를 함께 살펴봅니다. "자, 첫 번째 패턴인 프롬프트 체이닝부터 보자." 프롬프트 체이닝은 직관적입니다.

위 코드에서 보듯이, 먼저 텍스트를 요약합니다. 그 요약 결과를 가지고 키워드를 추출합니다.

그 키워드로 최종 보고서를 만듭니다. 각 단계가 이전 단계의 결과를 사용합니다.

이 패턴의 장점은 복잡한 작업을 단순한 단계로 분해할 수 있다는 것입니다. LLM에게 한 번에 "긴 글을 읽고 요약하고 키워드 뽑고 보고서 만들어"라고 하면 품질이 떨어질 수 있습니다.

하지만 단계별로 나누면 각 단계에서 높은 품질을 유지할 수 있습니다. "여기서 중요한 건 게이트야." 박시니어 씨가 덧붙였습니다.

"각 단계 사이에 품질 검증 로직을 넣을 수 있어. 요약이 너무 길면 다시 하라고 시키거나, 키워드가 이상하면 재생성하는 식으로." 두 번째 패턴인 라우팅을 보겠습니다.

고객 문의가 들어오면 먼저 어떤 종류인지 분류합니다. 기술 문의면 기술 담당자에게, 환불 문의면 환불 담당자에게 보냅니다.

각 담당자는 해당 분야에 특화된 프롬프트와 도구를 가지고 있습니다. 라우팅의 핵심은 전문화입니다.

하나의 만능 에이전트보다, 각 영역에 특화된 여러 에이전트가 협력하는 것이 더 좋은 결과를 냅니다. 마치 종합병원에서 내과, 외과, 피부과가 나뉘어 있는 것처럼요.

세 번째 패턴인 병렬 처리는 성능과 관련이 깊습니다. 위 코드에서 코드 리뷰, 보안 검사, 성능 분석은 서로 독립적입니다.

순차적으로 실행하면 3배의 시간이 걸리지만, 병렬로 실행하면 가장 오래 걸리는 것 하나의 시간만 소요됩니다. 김개발 씨가 궁금해했습니다.

"병렬 처리할 때 결과를 어떻게 합치나요?" "좋은 질문이야. 두 가지 방식이 있어.

섹셔닝은 각 결과를 그대로 합치는 거야. 코드 리뷰, 보안, 성능 결과를 각각 별도 섹션으로 보여주는 식이지.

보팅은 여러 결과 중 다수결로 선택하거나, 가중 평균을 내는 거야. 콘텐츠 분류 같은 데 많이 써." 실무에서 이 세 패턴은 자주 조합됩니다.

예를 들어 고객 문의 시스템에서 라우팅으로 문의 유형을 분류하고, 각 유형별 처리기가 체이닝으로 동작하며, 여러 검증 작업은 병렬로 실행할 수 있습니다. 김개발 씨가 고개를 끄덕였습니다.

"기본 패턴이지만 조합하면 정말 다양한 걸 만들 수 있겠네요."

실전 팁

💡 - 체이닝에서는 각 단계 사이에 검증 로직(게이트)을 넣으면 품질이 향상됩니다

  • 라우팅의 분류 정확도가 전체 시스템 품질을 좌우하므로 분류 프롬프트에 신경 쓰세요
  • 병렬 처리는 독립적인 작업에만 적용하고, 의존성이 있으면 체이닝을 사용하세요

6. 오케스트레이터 워커 평가 최적화

기본 패턴 세 가지를 익힌 김개발 씨에게 박시니어 씨가 더 고급 패턴을 소개합니다. "이 두 패턴은 좀 더 복잡한 상황에서 빛을 발해.

특히 큰 프로젝트나 품질이 중요한 작업에서."

오케스트레이터-워커 패턴은 중앙 지휘자가 전체 작업을 파악하고 여러 워커에게 하위 작업을 분배한 뒤 결과를 조합합니다. 평가자-최적화기 패턴은 결과물을 생성하고, 별도의 평가자가 검토한 뒤, 피드백을 반영하여 개선하는 과정을 반복합니다.

두 패턴 모두 복잡하거나 품질이 중요한 작업에 적합합니다.

다음 코드를 살펴봅시다.

# 1. 오케스트레이터-워커 패턴
def orchestrator_worker(complex_task):
    # 오케스트레이터: 작업 분석 및 분해
    subtasks = call_llm(f"""
    다음 작업을 하위 작업으로 분해하세요:
    {complex_task}
    JSON 형식으로 반환: {{"tasks": ["task1", "task2", ...]}}
    """)

    # 워커들에게 작업 분배 및 실행
    results = []
    for task in subtasks["tasks"]:
        result = call_llm(f"다음 작업을 수행하세요: {task}")
        results.append({"task": task, "result": result})

    # 오케스트레이터: 결과 종합
    final = call_llm(f"다음 결과들을 종합하여 최종 결과를 만드세요: {results}")
    return final

# 2. 평가자-최적화기 패턴
def evaluator_optimizer(task, max_iterations=3):
    # 초기 결과물 생성
    content = call_llm(f"다음 작업을 수행하세요: {task}")

    for i in range(max_iterations):
        # 평가자: 결과물 평가
        evaluation = call_llm(f"""
        다음 결과물을 평가하세요:
        {content}
        개선이 필요하면 구체적인 피드백을, 충분하면 'APPROVED'를 반환하세요.
        """)

        if "APPROVED" in evaluation:
            break  # 품질 충족, 반복 종료

        # 최적화: 피드백 반영하여 개선
        content = call_llm(f"피드백을 반영하여 개선하세요:\n피드백: {evaluation}\n원본: {content}")

    return content

박시니어 씨가 새로운 예시를 들었습니다. "영화 제작을 생각해봐.

감독이 있고, 촬영팀, 조명팀, 음향팀이 있잖아. 감독이 전체 비전을 가지고 각 팀에 지시를 내리고, 결과물을 모아서 하나의 영화를 만들어.

이게 오케스트레이터-워커 패턴이야." 코드를 보면 구조가 명확합니다. 오케스트레이터가 먼저 복잡한 작업을 분석합니다.

"웹사이트를 만들어달라"는 요청을 받으면, "1. 디자인 설계, 2.

프론트엔드 개발, 3. 백엔드 개발, 4.

테스트"로 분해합니다. 그 다음 각 하위 작업을 워커에게 할당합니다.

워커는 자신의 작업만 집중해서 수행합니다. 디자인 워커는 디자인만, 프론트엔드 워커는 프론트엔드만 처리합니다.

마지막으로 오케스트레이터가 모든 결과를 모아서 종합합니다. 각 파트가 잘 맞는지 확인하고, 필요하면 조정 지시를 내립니다.

이 패턴의 강점은 동적인 작업 분해입니다. 미리 정해진 워크플로가 아니라, 입력에 따라 필요한 작업을 그때그때 결정합니다.

프로젝트마다 필요한 작업이 다를 때 유연하게 대응할 수 있습니다. 평가자-최적화기 패턴은 다른 상황에서 빛을 발합니다.

박시니어 씨가 설명했습니다. "글을 쓸 때 한 번에 완벽한 글이 나오진 않잖아.

초고를 쓰고, 검토하고, 수정하고, 다시 검토하고. 이 과정을 거쳐야 좋은 글이 나와." 코드를 보면, 먼저 LLM이 결과물을 생성합니다.

그 다음 별도의 평가 프롬프트로 결과물을 검토합니다. 평가자는 "이 부분이 부족하다", "여기를 더 보완하라" 같은 구체적인 피드백을 줍니다.

이 피드백을 반영하여 개선된 버전을 만듭니다. 그리고 다시 평가합니다.

이 과정을 품질이 충족될 때까지 반복합니다. 중요한 것은 종료 조건입니다.

위 코드에서는 두 가지 종료 조건이 있습니다. 평가자가 "APPROVED"를 반환하거나, 최대 반복 횟수에 도달하면 종료합니다.

무한 루프를 방지하기 위해 반드시 최대 횟수를 설정해야 합니다. 김개발 씨가 정리했습니다.

"오케스트레이터-워커는 복잡한 프로젝트를 나눠서 처리할 때, 평가-최적화는 품질이 중요한 창작 작업에 쓰는 거군요?" 박시니어 씨가 고개를 끄덕였습니다. "정확해.

그리고 이 두 패턴도 조합할 수 있어. 오케스트레이터가 작업을 분배하고, 각 워커가 평가-최적화 루프로 동작하는 식으로."

실전 팁

💡 - 오케스트레이터의 작업 분해 능력이 전체 품질을 좌우하므로, 분해 프롬프트를 잘 설계하세요

  • 평가-최적화에서 평가자와 생성자는 서로 다른 관점을 가지도록 프롬프트를 설계하세요
  • 평가-최적화는 반드시 최대 반복 횟수를 설정하여 무한 루프를 방지하세요

7. 이 코스의 학습 로드맵

모든 패턴을 살펴본 김개발 씨가 마지막으로 물었습니다. "선배님, 이제 어떻게 공부를 진행하면 좋을까요?

어디서부터 시작해야 할지 막막해요." 박시니어 씨가 학습 로드맵을 그려주었습니다.

이 코스는 프레임워크 없이 순수 Python으로 AI 에이전트를 구현하는 과정입니다. 기초 개념 이해 → 기본 패턴 구현 → 고급 패턴 구현 → 실전 프로젝트 순서로 진행됩니다.

각 단계를 충실히 따라가면 에이전트의 동작 원리를 완벽히 이해하고, 직접 설계하고 구현할 수 있는 능력을 갖추게 됩니다.

다음 코드를 살펴봅시다.

# 학습 로드맵: 순차적으로 진행하세요
learning_path = [
    {
        "단계": "1. 기초 다지기",
        "목표": "LLM API 호출과 기본 개념 이해",
        "실습": ["API 연결 설정", "간단한 프롬프트 실행", "응답 파싱"]
    },
    {
        "단계": "2. 도구 시스템 구축",
        "목표": "에이전트가 사용할 도구 정의와 실행",
        "실습": ["도구 스키마 정의", "도구 실행 함수", "LLM과 도구 연결"]
    },
    {
        "단계": "3. 기본 패턴 구현",
        "목표": "체이닝, 라우팅, 병렬 처리 패턴 마스터",
        "실습": ["문서 처리 파이프라인", "고객 문의 라우터", "다중 분석기"]
    },
    {
        "단계": "4. 고급 패턴 구현",
        "목표": "오케스트레이터-워커, 평가-최적화 패턴",
        "실습": ["프로젝트 관리 에이전트", "콘텐츠 생성 에이전트"]
    },
    {
        "단계": "5. 실전 프로젝트",
        "목표": "여러 패턴을 조합한 완성형 에이전트",
        "실습": ["코딩 어시스턴트", "연구 에이전트", "업무 자동화 봇"]
    }
]

for step in learning_path:
    print(f"\n{step['단계']}: {step['목표']}")

박시니어 씨가 커피를 한 잔 내려왔습니다. "자, 이제 어떻게 공부할지 정리해볼까?" 첫 번째 단계는 기초 다지기입니다.

아무리 복잡한 에이전트도 결국 LLM API 호출의 조합입니다. API를 자유롭게 다룰 수 있어야 합니다.

Claude API 문서를 읽고, 여러 가지 프롬프트를 실험해보고, 응답을 원하는 형태로 파싱하는 연습을 하세요. 두 번째 단계는 도구 시스템 구축입니다.

에이전트의 핵심은 도구입니다. 도구를 어떻게 정의하고, LLM이 어떻게 도구를 선택하며, 실행 결과를 어떻게 처리하는지 이해해야 합니다.

간단한 계산기, 웹 검색, 파일 읽기 같은 도구를 직접 만들어보세요. 세 번째 단계는 기본 패턴 구현입니다.

앞에서 배운 체이닝, 라우팅, 병렬 처리를 직접 구현해봅니다. 문서를 요약하고 번역하는 파이프라인, 고객 문의를 분류하는 라우터, 여러 관점에서 동시에 분석하는 시스템을 만들어보세요.

네 번째 단계는 고급 패턴 구현입니다. 오케스트레이터-워커와 평가-최적화 패턴은 더 복잡하지만, 그만큼 강력합니다.

복잡한 프로젝트를 자동으로 분해하는 시스템, 글을 쓰고 스스로 개선하는 시스템을 구현해보세요. 마지막 다섯 번째 단계는 실전 프로젝트입니다.

지금까지 배운 모든 것을 조합하여 실제로 유용한 에이전트를 만듭니다. 코딩을 도와주는 어시스턴트, 정보를 조사하고 보고서를 작성하는 연구 에이전트, 반복 업무를 자동화하는 봇 등을 만들어볼 수 있습니다.

김개발 씨가 물었습니다. "각 단계에 얼마나 시간을 써야 할까요?" "사람마다 다르지만, 중요한 건 깊이야.

빨리 넘어가는 것보다 각 단계를 확실히 이해하는 게 중요해. 특히 기초와 도구 시스템은 꼼꼼히 해야 해.

거기가 부실하면 나중에 전부 흔들려." 한 가지 팁을 더하자면, 작게 시작하고 점진적으로 확장하세요. 처음부터 대단한 에이전트를 만들려고 하지 마세요.

가장 단순한 형태로 시작해서 조금씩 기능을 추가하는 것이 훨씬 효과적입니다. 그리고 반드시 코드를 직접 작성하세요.

읽기만 하면 안 됩니다. 에러를 만나고, 디버깅하고, 해결하는 과정에서 진짜 실력이 늘어납니다.

김개발 씨가 노트에 로드맵을 적으며 말했습니다. "감사합니다, 선배님.

오늘 정말 많이 배웠어요. 이제 어디서부터 시작해야 할지 알겠어요." 박시니어 씨가 미소 지었습니다.

"에이전트는 앞으로 더 중요해질 거야. 지금 기초를 잘 다져놓으면 나중에 큰 힘이 될 거야.

화이팅!"

실전 팁

💡 - 각 단계를 넘어가기 전에 해당 단계의 개념을 확실히 이해했는지 점검하세요

  • 공식 문서와 예제 코드를 반복해서 읽고 직접 실행해보세요
  • 학습 내용을 블로그나 노트에 정리하면 이해도가 훨씬 높아집니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#AI-Agent#LLM#Workflow-Pattern#Prompt-Engineering#Python,AI,LLM

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.