패스노트
도메인 1. 에이전틱 아키텍처와 오케스트레이션

1.2오케스트레이션 패턴

예상 학습 시간 40

복잡한 작업은 하나의 거대한 프롬프트가 아니라 여러 LLM 호출의 조합으로 풀어야 합니다. 이 수업에서는 Anthropic이 정리한 표준 패턴 — 프롬프트 체이닝, 라우팅, 병렬화, 오케스트레이터-워커, 평가자-최적화자 — 의 구조와 선택 기준을 다룹니다.

워크플로와 에이전트의 구분

Anthropic의 「Building effective agents」는 에이전틱 시스템을 두 부류로 나눕니다. **워크플로(workflow)**는 LLM과 도구가 미리 정의된 코드 경로를 따라 조율되는 시스템이고, **에이전트(agent)**는 LLM이 스스로 과정과 도구 사용을 지휘하는 시스템입니다.

이 구분이 모든 오케스트레이션 논의의 출발점입니다. 시험에서도 "다음 시스템은 워크플로인가 에이전트인가"를 판별하는 문제가 반복해서 나옵니다. 판별 기준은 하나입니다. 다음 단계를 누가 정하는가? 코드가 정하면 워크플로, 모델이 정하면 에이전트입니다.

# 워크플로: 단계가 코드에 고정되어 있다
outline = llm("이 주제로 개요를 작성하라: " + topic)
draft   = llm("이 개요로 초안을 작성하라: " + outline)
final   = llm("이 초안을 다듬어라: " + draft)

# 에이전트: 모델이 다음 행동을 고른다
while not done:
    action = llm(history, tools=[search, write, review])
    done = execute(action)

Anthropic이 강조하는 원칙은 "가장 단순한 구성을 찾고, 필요할 때만 복잡성을 더하라"입니다. 단일 LLM 호출 + 검색(retrieval) + 좋은 프롬프트로 충분한 문제에 멀티 에이전트를 붙이는 것은 비용과 지연, 디버깅 난도만 키웁니다. 복잡한 오케스트레이션은 그 복잡성이 성능으로 명확히 보상될 때만 정당화됩니다.

프롬프트 체이닝과 라우팅

**프롬프트 체이닝(prompt chaining)**은 작업을 순차 단계로 쪼개, 앞 호출의 출력이 뒤 호출의 입력이 되게 하는 패턴입니다. 각 단계가 단순해지므로 개별 호출의 정확도가 올라갑니다. 단계 사이에 게이트(gate) — 프로그램적 검증 — 를 끼워 넣을 수 있다는 것이 큰 장점입니다.

outline = llm(f"다음 요구사항으로 문서 개요를 작성하라:\n{spec}")

# 게이트: 다음 단계로 가기 전 프로그램적 검증
if len(outline.split("\n")) < 3:
    raise GateFailed("개요가 3항목 미만입니다")

draft = llm(f"이 개요를 바탕으로 본문을 작성하라:\n{outline}")

체이닝이 맞는 상황: 작업이 자연스럽게 고정된 순서의 하위 작업으로 나뉘고, 정확도를 위해 지연 시간을 감수할 수 있을 때입니다.

**라우팅(routing)**은 입력을 먼저 분류한 뒤, 유형별로 특화된 프롬프트·모델·도구 구성으로 보내는 패턴입니다. 고객 문의를 "환불 / 기술 지원 / 일반 질문"으로 나눠 각각 다른 처리 경로에 태우는 것이 전형적인 예입니다.

라우팅의 핵심 이점은 관심사 분리입니다. 한 프롬프트에 모든 유형의 처리 규칙을 욱여넣으면 한 유형을 최적화할 때 다른 유형의 성능이 흔들립니다. 경로를 분리하면 각 프롬프트를 독립적으로 개선할 수 있습니다. 또 하나의 실무적 이점은 비용입니다. 쉬운 질문은 Haiku 같은 빠르고 저렴한 모델로, 어려운 질문만 상위 모델로 보내는 모델 라우팅이 가능합니다. 분류 자체는 작은 모델이나 임베딩 분류기로도 처리할 수 있습니다.

병렬화: 섹셔닝과 보팅

**병렬화(parallelization)**는 여러 LLM 호출을 동시에 실행하고 결과를 프로그램적으로 합치는 패턴입니다. 두 가지 변형이 있습니다.

섹셔닝(sectioning) — 독립적인 하위 작업으로 나눠 각각 병렬 실행합니다. 예: 문서 10개를 각각 요약한 뒤 합치기, 코드 리뷰를 보안·성능·정확성 관점으로 나눠 동시에 돌리기. 각 호출이 좁은 관심사에 집중하므로 품질이 올라가고, 벽시계 시간(wall-clock time)이 줄어듭니다.

보팅(voting) — 같은 작업을 여러 번 실행해 다수결이나 합집합으로 결과를 정합니다. 예: 취약점 탐지를 3회 돌려 2회 이상 지적된 것만 채택. 개별 호출의 변동성을 줄이고 신뢰도를 높입니다.

import asyncio

async def review(aspect: str, code: str) -> str:
    return await llm_async(f"{aspect} 관점에서만 이 코드를 리뷰하라:\n{code}")

results = await asyncio.gather(
    review("보안", code),
    review("성능", code),
    review("테스트 누락", code),
)
merged = merge_findings(results)  # 프로그램적 병합

병렬화를 쓸 때 주의할 점은 병합 단계의 설계입니다. 결과를 단순 연결하면 중복과 모순이 그대로 남습니다. 중복 제거 규칙을 코드로 두거나, 병합 전용 LLM 호출을 마지막에 한 번 두는 것이 일반적입니다. 시험 함정: 섹셔닝은 하위 작업이 서로 독립적일 때만 성립합니다. 앞 결과가 뒤 작업에 필요하면 체이닝이지 병렬화가 아닙니다.

오케스트레이터-워커와 평가자-최적화자

**오케스트레이터-워커(orchestrator-workers)**는 중앙 LLM이 작업을 동적으로 분해해 워커 LLM들에게 위임하고, 결과를 종합하는 패턴입니다. 섹셔닝과의 결정적 차이는 하위 작업이 미리 정의되지 않고 오케스트레이터가 입력을 보고 정한다는 점입니다. "이 버그를 고치려면 어떤 파일들을 수정해야 하는가"처럼 필요한 하위 작업의 수와 내용이 입력마다 달라지는 문제에 적합합니다.

plan = orchestrator_llm(f"이 이슈를 해결하기 위한 하위 작업 목록을 JSON으로: {issue}")
results = await asyncio.gather(*[
    worker_llm(task) for task in plan["subtasks"]  # 개수는 실행 시점에 결정
])
answer = orchestrator_llm(f"하위 결과를 종합하라: {results}")

**평가자-최적화자(evaluator-optimizer)**는 한 LLM이 생성하고 다른 LLM이 평가 기준에 따라 피드백을 주는 루프입니다. 번역 품질 개선, 문서 다듬기처럼 명확한 평가 기준이 있고 반복 개선이 실제로 가치를 더하는 작업에 씁니다. 평가자가 "통과"를 선언하거나 반복 상한에 도달하면 종료합니다.

패턴 선택 기준을 한 줄씩 정리하면:

패턴쓰는 조건
체이닝고정 순서의 단계, 단계 간 게이트 필요
라우팅입력 유형이 뚜렷이 나뉨
섹셔닝독립 하위 작업의 병렬 처리
보팅신뢰도·변동성 관리
오케스트레이터-워커하위 작업을 미리 알 수 없음
평가자-최적화자명확한 평가 기준 + 반복 개선 여지

시험에서는 시나리오를 주고 알맞은 패턴을 고르게 합니다. "하위 작업의 개수를 미리 알 수 있는가"와 "단계 순서가 고정인가"라는 두 질문으로 대부분 판별됩니다.

시험 함정

  • 섹셔닝과 오케스트레이터-워커의 구분 — 하위 작업이 미리 정의되면 섹셔닝, 실행 시점에 모델이 정하면 오케스트레이터-워커입니다.
  • 체이닝과 병렬화의 구분 — 앞 단계 출력이 뒤 단계 입력이면 체이닝입니다. 병렬화는 하위 작업이 독립적일 때만 성립합니다.
  • "복잡한 문제에는 무조건 멀티 에이전트"라는 선택지 — Anthropic의 원칙은 가장 단순한 구성에서 시작해 필요할 때만 복잡성을 더하는 것입니다.
  • 평가자-최적화자를 아무 작업에나 권하는 오답 — 명확한 평가 기준이 없으면 루프가 수렴하지 않고 비용만 늘어납니다.
  • 라우팅의 분류기를 반드시 대형 모델로 해야 한다는 오답 — 분류는 소형 모델이나 임베딩 분류기로 충분한 경우가 많습니다.

실습 시나리오

실제 시험과 같은 형식의 시나리오 문제입니다.

법률 문서 500건에서 각각 핵심 조항을 추출한 뒤 하나의 보고서로 합치려 합니다. 문서들은 서로 독립적입니다. 가장 적합한 패턴은 무엇입니까?

빌드 연습 · 라우팅 + 병렬화 파이프라인 구축

60
  1. 1.분류 프롬프트 작성

    고객 문의를 환불/기술/일반 세 유형으로 분류하는 프롬프트를 작성하고 JSON으로 응답받습니다.

    기대 결과 · 분류 결과가 {"route": "refund"} 형태로 안정적으로 반환됩니다.

  2. 2.경로별 특화 프롬프트 작성

    세 유형 각각에 다른 시스템 프롬프트와 도구 구성을 정의합니다.

    기대 결과 · 환불 경로에만 주문 조회 도구가 연결되는 등 경로별 차이가 드러납니다.

  3. 3.모델 라우팅 추가

    일반 질문은 Haiku, 나머지는 Sonnet으로 보내도록 분기합니다.

    기대 결과 · 경로별로 다른 model 파라미터가 로그에 기록됩니다.

  4. 4.보팅 검증 추가

    환불 승인 판단만 3회 병렬 실행해 2/3 이상 동의 시 승인하게 만듭니다.

    기대 결과 · 세 호출의 개별 판정과 최종 다수결 결과가 함께 출력됩니다.

  5. 5.실패 사례 분석

    오분류되는 입력을 5개 찾아 분류 프롬프트에 경계 사례 예시를 추가합니다.

    기대 결과 · 수정 후 같은 입력이 올바르게 라우팅됩니다.

출처 및 더 읽기