Google ADK 1.31로 5분 만에 코디네이터 + 서브 에이전트 멀티 에이전트 만들기

Lavelle Hatcher Jr·2026년 4월 24일
post-thumbnail

2026년 4월 22일, Google Cloud Next 2026 키노트에서 구글이 Gemini Enterprise Agent Platform을 공개했어요. Vertex AI의 후속 격으로, Agent Studio, Agent Garden, Agent Development Kit (ADK), Agent Gateway를 한 스택에 모아둔 구조입니다. Python 패키지 google-adk는 4월 21일에 1.31.1이 PyPI에 올라왔고요.

이 글에서는 ADK 1.31로 "요청을 받는 코디네이터"가 "날씨 담당 서브 에이전트"랑 "인사 담당 서브 에이전트"에게 작업을 넘기는 그래프형 멀티 에이전트를 5분 안에 돌려볼게요.

※ 공개 정보를 바탕으로 한 개인 정리입니다. 각 기업의 공식 입장이 아닙니다.

전제

  • Python 3.10 이상 (google-adk 1.31.1의 요구사항: Python>=3.10)
  • Google AI Studio API 키 또는 Vertex AI 프로젝트
  • OS는 Linux/macOS/Windows 아무거나. GPU는 필요 없어요 (추론은 Gemini API 쪽에서).

하드웨어 가이드

로컬에서 추론하지 않기 때문에 개발 머신 스펙 요구가 거의 없어요.

  • CPU: 2코어 이상이면 충분
  • RAM: 4GB 이상
  • 디스크: venv 포함 1GB 미만
  • 네트워크: Gemini API랑 양방향 통신 가능한 회선

로컬 LLM으로 바꾸고 싶으면 LiteLLM 프로바이더 경유로 Ollama에 꽂을 수 있는데, 그 얘기는 다른 글로 뺄게요.

1단계: 설치

가상환경 띄우고 설치. 공식 문서 그대로예요.

python3 -m venv .venv
source .venv/bin/activate        # 윈도우는 .venv\Scripts\activate
pip install google-adk==1.31.1

버전 확인 한번 해두면 좋아요.

pip show google-adk | head -n 2
# Name: google-adk
# Version: 1.31.1

4월 주간 릴리스 타고 1.31대로 오면서 Agent Studio UI와 Python 패키지 쪽 동작이 많이 맞아떨어졌어요. adk web 체감이 꽤 안정됐습니다.

2단계: API 키 설정

ADK는 기본적으로 Gemini API를 호출해요. 프로젝트 디렉토리의 .env에 적어두면 알아서 읽어갑니다.

# .env
GOOGLE_API_KEY="AIza...(AI Studio에서 발급한 키)"
GOOGLE_GENAI_USE_VERTEXAI=FALSE

Vertex AI 쓸 거면 GOOGLE_GENAI_USE_VERTEXAI=TRUE로 바꾸고 GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION을 추가하면 돼요.

3단계: 디렉토리 구조

ADK는 "에이전트 하나 = 디렉토리 하나" 규약이 꽤 엄격한 편이에요. 여기 어긋나면 CLI가 조용히 실패합니다.

trip_team/
├── __init__.py
├── agent.py
└── .env

__init__.py는 한 줄만 있으면 끝.

# trip_team/__init__.py
from . import agent

이 한 줄이 빠지면 adk run trip_team이 "root_agent를 못 찾겠다"고 튑니다. 여기서 10~20분 날리는 사람이 많아요. adk create trip_team으로 스캐폴딩하면 자동으로 채워줘요.

4단계: 먼저 싱글 에이전트로 돌려보기

분기 넣기 전에 단일 에이전트로 동작하는지 확인해요.

# trip_team/agent.py
from google.adk.agents import Agent

def get_weather(city: str) -> dict:
    """Return a fake weather report for a city.

    Args:
        city: The city name, e.g. "Seoul".

    Returns:
        A dict with temperature in Celsius and a short condition string.
    """
    table = {
        "Seoul": {"temp_c": 17, "condition": "cloudy"},
        "Busan": {"temp_c": 20, "condition": "sunny"},
        "Jeju": {"temp_c": 22, "condition": "windy"},
    }
    return table.get(city, {"temp_c": 20, "condition": "unknown"})

root_agent = Agent(
    model="gemini-flash-latest",
    name="root_agent",
    description="Answers travel questions using live tools.",
    instruction=(
        "당신은 여행 어시스턴트예요. 도시 이름이 들어오면"
        " get_weather 툴로 날씨를 조회해서 짧게 정리해 답변하세요."
    ),
    tools=[get_weather],
)

실행은 trip_team/상위 디렉토리에서 때려야 해요. 여기가 또 다른 함정이고, cd trip_team && adk run . 식으로 에이전트 디렉토리에 들어가서 실행하면 인식 안 돼요.

adk run trip_team

대화 모드에서 제주 날씨 어때? 같이 물어보면 툴 호출 로그랑 최종 응답이 쭉 나올 거예요.

5단계: 서브 에이전트를 묶는 코디네이터

여기서부터가 핵심이에요. 두 전문 에이전트를 sub_agents로 묶고, 라우팅은 Coordinator가 책임지게 만들어요. ADK의 LlmAgentsub_agents를 넘기면 transferToAgent 함수 호출로 자동 위임하는 AutoFlow가 켜져요.

agent.py를 이렇게 바꿔요.

# trip_team/agent.py
from google.adk.agents import LlmAgent

def get_weather(city: str) -> dict:
    """Return a fake weather report for a city."""
    table = {
        "Seoul": {"temp_c": 17, "condition": "cloudy"},
        "Busan": {"temp_c": 20, "condition": "sunny"},
        "Jeju": {"temp_c": 22, "condition": "windy"},
    }
    return table.get(city, {"temp_c": 20, "condition": "unknown"})

weather_agent = LlmAgent(
    name="weather_agent",
    model="gemini-flash-latest",
    description="Looks up current weather for a given city.",
    instruction=(
        "당신은 날씨 전담 서브 에이전트예요."
        " 도시 이름이 들어오면 get_weather를 한 번만 호출해서"
        " 한 문장으로 정리해 돌려주세요."
    ),
    tools=[get_weather],
)

greeter_agent = LlmAgent(
    name="greeter_agent",
    model="gemini-flash-latest",
    description="Greets the user and confirms what they want to plan.",
    instruction=(
        "당신은 여행의 초입을 정리하는 서브 에이전트예요."
        " 인사와 목적지/일정 확인만 담당해요."
    ),
)

root_agent = LlmAgent(
    name="coordinator",
    model="gemini-flash-latest",
    description="Routes the user request to the right specialist.",
    instruction=(
        "당신은 여행 코디네이터예요."
        " 인사나 일정 정리가 필요하면 greeter_agent에,"
        " 날씨 조회는 weather_agent에 위임하세요."
        " 직접 툴을 호출하지 마세요."
    ),
    sub_agents=[greeter_agent, weather_agent],
)

sub_agents=[...]를 넘기면 각 서브 에이전트의 description이 LLM한테 "이걸 누구한테 넘겨야 하는지"에 대한 힌트로 보여요. description을 대충 쓰면 라우팅이 무너져요. 제목처럼 쓰지 말고 "무엇을 받아서 무엇을 돌려주는지" 한 문장으로 쓰는 게 포인트.

6단계: Web UI로 흐름 확인

adk web을 띄우면 어떤 서브 에이전트로 넘어갔는지 스텝 단위로 보여요. 디버깅이 많이 편해져요.

adk web --port 8000

http://localhost:8000에 들어가면 에이전트 셀렉터에 trip_team이 보여요. 거기서 안녕하세요, 제주 갈 예정인데 날씨 알려주세요 같이 날려보면 인사 → 위임 → 날씨 호출 → 최종 답변 순서가 화면에 나와요.

7단계: 프로그램에서 직접 부르기

나중에 Slack Bot이나 사내 툴에 붙일 때는 Runner를 직접 씁니다. run_async가 기본 API예요.

# run_trip_team.py
import asyncio
from google.adk.runners import InMemoryRunner
from google.genai import types as genai_types
from trip_team.agent import root_agent

async def main() -> None:
    runner = InMemoryRunner(agent=root_agent)
    session = await runner.session_service.create_session(
        app_name=runner.app_name, user_id="user-1"
    )

    user_message = genai_types.Content(
        role="user",
        parts=[genai_types.Part(text="안녕하세요, 제주 날씨 알려주세요")],
    )

    async for event in runner.run_async(
        user_id="user-1",
        session_id=session.id,
        new_message=user_message,
    ):
        if event.content and event.content.parts:
            for part in event.content.parts:
                if part.text:
                    print(f"[{event.author}] {part.text}")

if __name__ == "__main__":
    asyncio.run(main())

InMemoryRunner는 세션을 내부적으로 들고 있어서 상주 서버가 아니면 이 정도로 충분해요. 프로덕션 서버에서는 RunnerDatabaseSessionService 같은 걸 꽂아서 세션을 영속화하시면 됩니다.

자주 걸리는 함정

30분 날릴 만한 포인트만 모았어요.

  • __init__.pyfrom . import agent 꼭 쓰기: 이거 없으면 adk run이 조용히 실패해요. adk create로 만들면 자동으로 들어가요.
  • CLI는 에이전트 상위 디렉토리에서 실행: adk run trip_team은 OK, cd trip_team && adk run .은 NG.
  • sub_agents를 넘긴 Coordinator에 직접 툴 붙이지 않기: AutoFlow 위임이랑 툴 호출이 충돌해서 라우팅이 불안정해져요. 코디네이터는 "분류만" 하는 역할로.
  • gemini-flash-latest 에일리어스: 공식 샘플도 이걸 쓰고 있어요. 버전 고정이 필요 없으면 이대로 가고, 필요하면 gemini-2.5-flash 같은 구체 버전으로 바꿔요.
  • adk web은 개발용: 공식 문서에 프로덕션 용도가 아니라고 명시돼 있어요. 실서비스는 adk api_server나 FastAPI에서 Runner를 직접 부르는 형태로 전환하세요.

정리

  • ADK 1.31.1 + sub_agents면 10분 안에 코디네이터 + 전문 에이전트 그래프가 돌아가요.
  • Gemini Enterprise Agent Platform의 코어가 이 ADK라서, 개인 검증으로 짠 에이전트가 사내 배포로 이어붙이기 쉬운 구조가 됐어요.
  • 함정의 80%는 "디렉토리 규약", "__init__.py 한 줄", "코디네이터에 툴 안 붙이기 + description 안 대충 쓰기"에서 나와요.
  • 모델은 gemini-flash-latest 에일리어스로 시작하고, 프로덕션 직전에 구체 버전으로 고정.
  • Gemini Enterprise Agent Platform은 GA 직후라 디테일이 주 단위로 움직일 수 있다는 전제로 운영 설계하는 게 안전해요.

참고

  • Introducing Gemini Enterprise Agent Platform (Google Cloud Blog)
  • google/adk-python (GitHub)
  • google-adk 1.31.1 (PyPI)
  • Multi-agent systems - ADK docs
profile
시스템 엔지니어 및 제품 개발자

0개의 댓글