Google Developers Blog가 2026년 5월 12일 공개한 ADK 장기 실행 에이전트 튜토리얼은 최근 에이전트 개발 흐름에서 꽤 중요한 분기점입니다. 지금까지 많은 예제는 짧은 대화형 챗봇에 머물렀습니다. 사용자가 질문하고, 모델이 답하고, 컨텍스트를 대화 히스토리에 붙이는 구조입니다. 문제는 실제 회사 업무가 그렇게 끝나지 않는다는 점입니다.
신입 사원 온보딩은 며칠 또는 몇 주가 걸립니다. 계약서 서명을 기다리고, IT 계정 생성을 기다리고, 노트북 배송을 기다립니다. 인보이스 분쟁, 영업 후속 연락, 보안 승인, 법무 검토도 마찬가지입니다. 대부분의 시간은 모델이 생각하는 시간이 아니라 외부 이벤트를 기다리는 idle time입니다. Google의 ADK 예제는 이 idle time을 정면으로 다룹니다. 핵심은 더 큰 컨텍스트 창이 아니라 durable state machine, persistent session, event-driven resume입니다.
일반적인 챗봇 구조는 모든 사용자 메시지와 모델 응답을 계속 이어 붙인 뒤 다음 호출에 다시 넣습니다. 5분짜리 Q&A에서는 괜찮습니다. 하지만 2주짜리 온보딩 흐름에서는 세 가지 문제가 생깁니다.
첫째, 컨텍스트 오염입니다. 오래된 툴 결과, 중복 지시문, 이미 끝난 단계의 대화가 섞이면서 모델이 현재 단계를 헷갈립니다. 둘째, 토큰 비용이 커집니다. 매번 전체 대화 기록을 다시 넣으면 실제 판단에 필요 없는 과거 정보 때문에 비용이 늘어납니다. 셋째, idle time 이후의 hallucination입니다. 에이전트가 3일 뒤 재개될 때 긴 히스토리를 보고 승인되지 않은 일을 승인된 것처럼 착각할 수 있습니다.
Google의 튜토리얼은 이 문제를 신입 사원 온보딩 예제로 풉니다. START, WELCOME_SENT, DOCUMENTS_SIGNED, IT_PROVISIONED, HARDWARE_DELIVERED, COMPLETED 같은 명시적 상태를 두고 에이전트가 대화 기록이 아니라 현재 상태를 기준으로 움직이게 합니다.
가장 중요한 설계는 상태를 자연어 기억에 맡기지 않는 것입니다. 예제에서는 current_step, new_hire_details, pending_signals 같은 값을 session state에 저장합니다. 시스템 지시문은 매 실행 시 이 값을 읽습니다. 현재 단계가 WELCOME_SENT라면 에이전트는 문서 서명을 기다린다고 말하고 다른 도구를 호출하지 않습니다. DOCUMENTS_SIGNED가 되면 IT provisioning sub-agent에 위임합니다.
이 구조의 장점은 단순합니다. 모델이 추측할 여지가 줄어듭니다. 상태 전이는 도구 호출 또는 webhook에서 명시적으로 일어납니다. send_welcome_packet 도구가 성공하면 current_step을 WELCOME_SENT로 바꾸고 pending_signals에 document_signed를 넣습니다. 서버가 그 직후 죽어도 상태는 이미 저장되어 있어야 합니다. 재시작 후 에이전트는 대화 전체를 복기하지 않고 current_step만 보고 이어갑니다.
실무에서는 이 방식이 특히 중요합니다. 결제 승인, 환불 처리, 채용 프로세스, 고객 지원 escalation처럼 단계가 틀리면 사고가 나는 업무는 모델의 기억에 맡기면 안 됩니다. 상태는 데이터베이스에, 판단은 모델에, 전이는 도구와 이벤트에 맡기는 분리가 필요합니다.
Google 예제는 ADK의 DatabaseSessionService를 사용해 세션을 SQLite에 저장하고, 운영 환경에서는 Cloud SQL 같은 영속 저장소로 바꿀 수 있다고 설명합니다. 컨테이너 환경에서는 Cloud Run처럼 scale-to-zero가 일어날 수 있습니다. 메모리 세션이면 idle time 동안 프로세스가 내려갔을 때 업무가 사라집니다. 그래서 세션 저장소가 workflow의 생명줄이 됩니다.
두 번째 축은 event-driven resumption입니다. 문서 서명이 완료됐는지 계속 polling하지 않습니다. 외부 시스템이 webhook을 호출하면 resume handler가 세션을 hydrate하고 state_delta로 current_step을 DOCUMENTS_SIGNED로 바꾼 뒤 runner.run_async를 실행합니다. 이때 모델은 다음 호출에서 이미 바뀐 상태를 봅니다. 오래된 대화 히스토리에서 추측하지 않습니다.
이 패턴은 비용과 안정성 양쪽에서 유리합니다. idle time 동안 실행 중인 thread를 붙잡지 않아도 됩니다. 외부 이벤트가 올 때만 컨테이너가 깨어납니다. 무엇보다 재개 지점이 명시적이라 장애 분석이 쉬워집니다.
첫 번째 실수는 상태를 JSON blob 하나에 대충 넣는 것입니다. 처음에는 편하지만 시간이 지나면 어떤 값이 workflow 단계인지, 어떤 값이 보조 정보인지 구분하기 어렵습니다. 최소한 current_step, actor, pending_signal, last_transition_at, retry_count, error_state는 분리하는 편이 좋습니다.
두 번째 실수는 webhook을 단순 메시지 입력처럼 다루는 것입니다. webhook은 사용자 채팅이 아니라 상태 전이 이벤트입니다. 서명 완료, 결제 실패, 배송 완료처럼 검증 가능한 외부 사실이어야 합니다. 서명 완료 webhook이 오면 먼저 서명 서비스의 signature나 event id를 검증하고, idempotency key로 중복 처리를 막아야 합니다.
세 번째 실수는 sub-agent 위임을 프롬프트로만 처리하는 것입니다. IT provisioning, HR 안내, 보안 승인처럼 책임이 다른 작업은 별도 도구와 권한으로 분리해야 합니다. 한 agent prompt 안에 모든 권한을 몰아넣으면 장애 때 원인 추적이 어렵고, 권한도 과하게 넓어집니다.
ADK 장기 실행 에이전트 예제의 의미는 챗봇을 더 똑똑하게 만드는 데 있지 않습니다. 에이전트를 회사 업무 프로세스 안에 넣으려면 기억, 상태, 이벤트, 권한을 명시적으로 설계해야 한다는 데 있습니다. 이걸 하지 않으면 모델이 좋아져도 운영은 계속 데모 수준에 머뭅니다.