6. Multi-Agent 오케스트레이션

단일 Agent로 해결하기 어려운 복잡한 작업은 여러 Agent를 협력시켜 처리합니다. 각 Agent가 전문 역할을 맡고, Orchestrator가 전체 흐름을 조율하는 방식입니다. LangGraph, AutoGen, CrewAI 같은 프레임워크가 이 패턴을 지원합니다.

1. 왜 Multi-Agent인가?

Single Agent의 한계

단일 LLM 호출의 Context Window는 제한적입니다(200K 토큰). 복잡한 작업은 이 한계를 초과하거나, 한 모델이 모든 역할을 잘하기 어렵습니다.
Multi-Agent의 장점 세 가지:
병렬 처리 — 서로 독립된 서브태스크를 동시에 실행
전문화 — 코드 작성 Agent, 리뷰 Agent, 테스트 Agent로 역할 분리
검증 — 한 Agent 결과를 다른 Agent가 검토 (Critic 패턴)

2. 두 가지 협력 패턴

패턴 1: Orchestrator-Worker (중앙 집중형)
Orchestrator Agent
전체 계획 수립, 서브태스크 분배, 결과 통합
↙ ↓ ↘
Research Agent
|
Code Agent
|
Review Agent
패턴 2: Pipeline (순차형)
Planner
Executor
Critic
Output
이전 Agent 결과를 다음 Agent에 전달 — 순서 의존 작업에 적합

3. 패턴 비교 — 언제 뭘 쓰나

패턴구조장점단점적합한 경우
Orchestrator-Worker 중앙 Orchestrator가 Worker를 지시 병렬 처리, 동적 태스크 분배 Orchestrator가 병목, 복잡한 조율 로직 독립 서브태스크가 많은 경우
Pipeline A → B → C 순차 처리 단순, 예측 가능, 디버깅 쉬움 순차라 느림, 앞 단계 실패 시 전체 실패 순서 의존 작업 (계획 → 실행 → 검토)
Debate/Critic 여러 Agent가 동일 문제를 독립 분석 후 합산 편향 줄임, 품질 향상 비용 N배 증가 고중요도 의사결정, 코드 리뷰
LangGraph — 상태 기반 그래프 (Python)
from langgraph.graph import StateGraph, END
from typing import TypedDict

class AgentState(TypedDict):
    task: str
    research: str
    code: str
    review: str

def research_node(state):
    result = research_agent.run(state["task"])
    return {"research": result}

def code_node(state):
    result = code_agent.run(
        state["task"], state["research"])
    return {"code": result}

def review_node(state):
    result = review_agent.run(state["code"])
    return {"review": result}

# 그래프 정의
graph = StateGraph(AgentState)
graph.add_node("research", research_node)
graph.add_node("code",     code_node)
graph.add_node("review",   review_node)

graph.set_entry_point("research")
graph.add_edge("research", "code")
graph.add_edge("code", "review")
graph.add_edge("review", END)

app = graph.compile()
Java — Orchestrator 패턴 구현
public class OrchestratorAgent {
    private final List<WorkerAgent> workers;
    private final LLMClient llm;

    public String run(String task) {
        // 1. Orchestrator가 서브태스크 계획
        List<SubTask> plan = planSubTasks(task);

        // 2. 독립 태스크는 병렬 실행
        List<CompletableFuture<String>> futures =
            plan.stream()
                .map(sub -> CompletableFuture
                    .supplyAsync(() -> dispatch(sub)))
                .toList();

        // 3. 모든 결과 수집
        List<String> results = futures.stream()
            .map(CompletableFuture::join)
            .toList();

        // 4. 결과 통합
        return synthesize(task, results);
    }

    private String dispatch(SubTask sub) {
        return workers.stream()
            .filter(w -> w.canHandle(sub.getType()))
            .findFirst()
            .orElseThrow()
            .execute(sub);
    }
}

4. Agent 간 통신 — 상태 공유 방법

상태 전달 방식 3가지

① 메시지 패싱: 이전 Agent의 결과를 다음 Agent의 입력으로 직접 전달. 구현 간단, LangGraph 기본 방식.
② 공유 메모리(KV Store): Redis나 인메모리 Map에 상태를 저장하고 Agent들이 공유. 병렬 실행 시 적합.
③ 이벤트 큐: Kafka/RabbitMQ 같은 메시지 브로커를 통해 비동기 통신. 대용량, 내결함성 필요 시. 쿠팡처럼 트래픽이 높은 환경에서는 Redis 기반 상태 공유 + 비동기 이벤트 큐 조합이 현실적입니다.

5. 면접 대비 핵심 Q&A

Q1. "Multi-Agent 시스템의 가장 큰 운영 난관은 무엇인가요?"

세 가지입니다. 첫째, 디버깅 어려움입니다. 어느 Agent에서 오류가 났는지 추적하려면 각 Agent 입출력을 전부 로깅해야 합니다(Langfuse 같은 AI Observability 툴이 필요). 둘째, 비용 폭발입니다. Agent 수 × LLM 호출 수만큼 비용이 곱해집니다. 각 Worker에 토큰 예산을 설정해야 합니다. 셋째, 부분 실패 처리입니다. Worker 하나가 실패해도 전체 파이프라인이 멈추지 않도록 fallback과 재시도 로직이 필요합니다.

Q2. "LangChain과 LangGraph의 차이는?"

LangChain은 단일 체인(Chain) 또는 단일 Agent 실행에 적합한 프레임워크입니다. LangGraph는 LangChain 팀이 만든 그래프 기반 프레임워크로, 사이클(루프)과 조건 분기가 있는 복잡한 Multi-Agent 워크플로우를 정의할 수 있습니다. "A 결과가 기준 미달이면 다시 A 실행" 같은 루프는 LangGraph의 조건 엣지로 표현합니다. 단순한 RAG 챗봇 → LangChain, 검토-재시도-승인 같은 복잡한 흐름 → LangGraph로 구분합니다.

핵심 한 줄

Multi-Agent = 역할 분리 + 병렬 실행 + 결과 통합. Orchestrator-Worker(병렬)와 Pipeline(순차) 두 패턴을 이해하고, 비용·디버깅·부분 실패 세 가지 운영 과제를 답할 수 있으면 된다.