
Google ADK의 오케스트레이션 패턴 비교: 멀티 에이전트(Multi-Agent) vs 워크플로우 기반 루프(Workflow-Based
요약
Google ADK를 활용하여 동적 멀티 에이전트 라우팅과 순차적 워크플로우 루프라는 두 가지 오케스트레이션 패턴을 비교 분석합니다. 수학식 파서를 예시로 사용하여 각 아키텍처의 제어 흐름과 설계 차이점을 실무적으로 탐구합니다.
핵심 포인트
- 동적 멀티 에이전트: LLM이 도구를 사용하여 제어권을 동적으로 결정하는 계층적 구조
- 순차적 워크플로우: 사전에 정의된 노드 시퀀스를 따라 실행되는 구조적 설정
- Google ADK 기반의 실무적인 에이전트 설계 패턴 비교
- 수학식 파싱 사례를 통한 아키텍처별 제어 전달 흐름 검증
Google Skills Lab GENAI106을 기반으로 한 구조적(structured) 라우팅과 동적(dynamic) 에이전트 라우팅에 대한 실무 연구입니다.
서론 (Introduction)
에이전트형 AI (agentic AI)가 성숙해짐에 따라, 개발자들은 중요한 설계 결정에 직면하게 됩니다: 에이전트는 작업을 어떻게 오케스트레이션 (orchestrate) 해야 하는가?
이 글에서는 **Google Agent Development Kit (ADK)**에서 제공하는 두 가지 주요 오케스트레이션 (orchestration) 아키텍처를 탐구합니다:
- 동적 멀티 에이전트 라우팅 (Dynamic Multi-Agent Routing): LLM 에이전트가 주입된 도구 (tools)를 사용하여 제어권을 누구에게 전달할지 동적으로 결정하는 계층적 설정입니다.
- 순차적 워크플로우 루프 (Sequential Workflow Loops,
LoopAgent): 공유된 세션 상태 (session state)를 사용하여 실행이 사전에 정의된 노드 (nodes) 시퀀스를 따라 흐르는 구조적 설정입니다.
이 패턴들을 비교하기 위해, 우리는 수학식 파서 (parser)를 구축했습니다. ((12 + 8) * 5) - (10 / 2) + (4 * 6) - (50 / 5)와 같은 식을 해결하려면 adder, substracter, multiplier, divider라는 네 명의 전문가를 조정해야 합니다.
이 연구는 skills.google 플랫폼의 코드 랩 GENAI106: Build Multi-Agent Systems with ADK를 수정 및 확장한 것입니다.
아키텍처 1: 동적 멀티 에이전트 라우팅 (parent_and_subagents)
동적 멀티 에이전트 패턴에서는 중앙의 steering 코디네이터 (coordinator)가 사용자 입력을 받고, 수학적 우선순위에 따라 전문가 서브 에이전트 (sub-agents)에게 작업을 위임합니다.

graph TD
User([User Expression]) --> Steering[steering coordinator]
Steering -->|transfer_to_agent| Adder[adder specialist]
...
제어 전달 흐름 (The Control Transfer Flow)
steering이 식을 전문가(예:adder)에게 라우팅하면 제어권이 전달됩니다.- 전문가가 식의 해당 부분을 단순화하는 작업을 마치면, 제어권을 다시 부모에게 전달합니다:
# adk_multiagent_systems/parent_and_subagents/agent.py
# adder 지시사항:
# "덧셈을 완료하면, 'transfer_to_agent' 도구를 사용하여 제어권을 'steering' 에이전트에게 다시 전달하세요."
- 장점 (Pros): 매우 유연합니다. LLM이 최적의 경로를 동적으로 결정하고 재귀적으로 위임합니다.
- 단점 (Cons): 지속적인 피어 투 피어 (peer-to-peer) 라우팅 호출로 인해 지연 시간 (latency)이 높습니다.
아키텍처 2: 구조화된 워크플로우 루프 (workflow_agents)
워크플로우 패턴에서는 **LoopAgent**가 고정되고 미리 정의된 루프 (adder ➔ substracter ➔ multiplier ➔ divider) 내에서 실행을 순차적으로 조정하며, 공유 키 (shared key)를 통해 상태 업데이트를 전달합니다.

graph TD
User([User Expression]) --> WSteering[workflow_steering coordinator]
WSteering -->|transfer_to_agent| Loop[calculator_loop LoopAgent]
...
공유 세션 상태 (The Shared Session State)
워크플로우 에이전트들은 값을 직접 반환하는 대신, 커스텀 도구를 사용하여 세션 상태 (session state) 내의 공유 키 (expression)를 읽고 업데이트합니다:
def update_expression(tool_context: ToolContext, expression: str):
tool_context.state['expression'] = expression
return {"status": "success"}
전문가 에이전트가 수식(expression)이 단일 숫자로 축소되었음을 감지하고 ADK 내장 도구인 exit_loop를 호출하면 루프가 종료됩니다.
기술적 과제 및 값진 교훈
계산기를 LoopAgent 워크플로우로 전환할 때, 우리는 세 가지 주요 과제에 직면했습니다:
1. 도구 루프 재귀 문제 (The Tool Loop Recurrence Issue)
문제점: LLM 에이전트는 텍스트를 출력할 때까지 단일 턴(turn) 내에서 루프(loop)를 돌며 도구 호출(tool calls)을 생성합니다. { expression? }을 포함하는 시스템 지침(system instruction)이 해당 턴 동안 정적으로 유지되기 때문에, LLM은 동일한 값으로 update_expression을 재귀적으로 계속 호출했습니다.
해결책: 상태를 업데이트한 직후에 턴을 종료하도록 지침을 수정했습니다:
"'update_expression' 도구를 호출한 후에는 업데이트된 식을 텍스트로 출력하고 턴을 종료하십시오. 도구를 다시 호출하지 마십시오."
2. 고정된 시퀀스에서의 연산자 우선순위 (Operator Precedence in Fixed Sequences)
문제점: 루프 에이전트(loop agent)는 전문가(specialists)를 엄격한 순서대로 실행합니다. 만약 adder가 substracter보다 먼저 실행된다면, 100 - 5 + 24 - 10과 같은 식은 5 + 24 = 29를 먼저 잘못 계산하여 100 - 29 - 10 = 61이라는 결과(정답은 109)를 도출하게 됩니다.
해결책: adder가 연산 순서를 준수하도록 지침을 내렸습니다:
"뺄셈이 바로 앞에 나오는 경우 덧셈을 수행하지 마십시오 (예: '100 - 5 + 24'에서 마이너스 부호가 5에 속하므로 5 + 24를 더해서는 안 됩니다)."
3. 우아한 루프 종료 (Graceful Loop Termination)
문제점: exit_loop()를 호출하면 skip_summarization = True로 설정되어 실행이 즉시 종료됩니다. 만약 에이전트가 결과를 먼저 출력하지 않으면 세션이 조용히 닫혀버립니다.
해결책: 문제를 해결하는 에이전트가 exit_loop를 호출하기 전에 최종 결과를 출력하도록 지시합니다:
"식이 단일 숫자로 축약되면 최종 결과를 명확하게 출력하고 (예: 'El resultado es X') 'exit_loop' 도구를 호출하십시오."
계층적 중첩 하위 에이전트 시연: zero_division_guard
심층적인 에이전트 계층 구조와 오류 경계 처리(error boundary handling)를 보여주기 위해, divider 전문가 아래에 중첩된 검증 가드(zero_division_guard)를 추가했습니다.

graph TD
Divider[divider] -->|transfer_to_agent| Guard[zero_division_guard]
Guard -->|Validation Failed| Error[Abort & Exit]
...
어떤 나눗셈을 수행하기 전에, divider는 transfer_to_agent를 사용하여 zero_division_guard에 권한을 위임합니다. 가드(Guard)는 제수(divisor, 분모)를 확인합니다:
- 제수가 0으로 평가되는 경우 (예:
10 / 0), 실행을 중단하고 경고를 출력합니다. - 안전한 경우, 계산을 완료하기 위해 제어권을 다시
divider로 전달합니다.
통합 테스트 트레이스 (Multi-Agent):
Running: .venv/bin/adk run adk_multiagent_systems/parent_and_subagents "Please evaluate 10 / 0"
[zero_division_guard]: Error: División por cero detectada. Operación cancelada.
[divider]: Error: División por cero detectada. Operación cancelada.
...
통합 테스트 트레이스 (Workflow):
Running: .venv/bin/adk run adk_multiagent_systems/workflow_agents "Please evaluate 10 / 0"
[zero_division_guard]: Error: División por cero detectada. Operación cancelada.
결론
Google ADK는 동적인 멀티 에이전트 (Multi-Agent) 아키텍처와 결정론적인 워크플로우 (Workflow) 시퀀스 모두를 위한 강력한 프리미티브 (Primitives)를 제공합니다.
- 작업이 매우 동적이고, 예측 불가능하게 분기되며, 대화형 유연성(conversational flexibility)의 이점을 얻을 수 있는 경우에는 **멀티 에이전트 라우팅 (Multi-Agent Routing)**을 사용하세요.
- 신뢰성, 고정된 시퀀싱 (sequencing), 그리고 상태 기반 진행 (state-based progression)이 가장 중요한 구조화된 다단계 파이프라인의 경우에는 **워크플로우 루프 (Workflow Loops)**를 사용하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기