작업 생명주기와 비동기 협업
빠른 응답보다 중요한 것
기업 업무에서 에이전트 협업은 항상 몇 초 안에 끝나지 않는다. 고객 환불 승인, 공급업체 견적 비교, 보안 예외 검토, 월말 정산 자료 생성처럼 여러 시스템과 사람을 거치는 일은 수 시간 또는 수일이 걸릴 수 있다. 이때 중요한 것은 에이전트가 한 번 답을 잘하는 능력만이 아니다. 일이 어디까지 진행됐는지, 누구의 입력을 기다리는지, 중간 산출물이 무엇인지, 실패했다면 왜 실패했는지를 끊기지 않고 추적하는 능력이 더 중요하다.
A2A에서 이 역할을 맡는 기본 단위가 Task다. Task는 단순한 요청 ID가 아니다. 하나의 업무를 추적하는 실행 맥락이다. 클라이언트가 원격 에이전트에게 일을 맡기면, 원격 에이전트는 아주 단순한 상호작용에는 바로 Message로 답할 수도 있고, 추적이 필요한 일에는 Task를 만들어 장기 작업으로 관리할 수도 있다. Task가 만들어진 뒤에는 클라이언트가 같은 Task를 기준으로 상태를 조회하고, 추가 메시지를 보내고, 산출물을 받고, 필요하면 취소를 요청한다.
이 장에서는 Task를 기술 객체가 아니라 "업무 티켓"으로 이해하자. 티켓에는 담당자, 현재 상태, 요청 내역, 중간 기록, 결과물, 종료 사유가 남는다. A2A의 Task도 같은 문제를 에이전트 간 협업에 맞게 표현한다.
AI 생성 이미지
상태 전이를 업무 언어로 읽기
A2A의 Task 상태는 실행 엔진의 내부 로그가 아니라, 협업 당사자가 공유해야 하는 업무 신호다. 상태를 올바르게 해석해야 클라이언트 에이전트, 원격 에이전트, 사용자, 운영 시스템이 같은 상황을 보고 같은 결정을 내릴 수 있다.
대표적인 흐름은 다음과 같다.
클라이언트가 요청 메시지를 보낸다.
원격 에이전트가 요청을 받아 Task를 만든다.
Task가 제출 또는 실행 상태로 이동한다.
처리 중 추가 정보, 승인, 인증이 필요하면 잠시 멈춘 상태가 된다.
필요한 입력이나 인증이 해결되면 같은 Task에서 작업을 이어 간다.
성공, 실패, 취소, 거절 중 하나로 종료된다.
이를 업무 관점에서 풀어보면 다음과 같다.
제출됨(submitted): 일이 접수됐다. 아직 실제 처리가 시작되지 않았을 수 있다. 큐에 들어갔거나 담당 에이전트가 처리 순서를 정하는 단계다.
진행 중(working): 원격 에이전트가 실제로 작업하고 있다. 외부 도구를 호출하거나, 다른 에이전트에게 일부 업무를 위임하거나, 중간 산출물을 만들 수 있다.
입력 필요(input-required): 실패가 아니라 의도적인 멈춤이다. 정보가 부족하거나, 사용자의 확인이 필요하거나, 관리자 승인이 필요하다는 뜻이다.
인증 필요(auth-required): 작업을 계속하려면 추가 인증이나 권한 부여가 필요하다는 뜻이다. 예를 들어 특정 업무 시스템에 접근하기 위한 위임 동의나 토큰 갱신이 필요한 경우가 여기에 가깝다.
완료(completed): 작업이 성공적으로 끝났고 최종 산출물을 확인할 수 있다.
실패(failed): 작업을 끝낼 수 없었다. 시스템 오류, 데이터 불일치, 외부 API 실패, 처리 중 발견된 제약 같은 이유를 함께 전달해야 한다.
취소(canceled): 요청자나 권한 있는 중간 시스템이 작업 중단을 요청했다. 예산 초과, 사용자 철회, 중복 요청 감지 같은 이유가 있을 수 있다.
거절(rejected): 원격 에이전트가 애초에 수행할 수 없거나 수행하지 않기로 판단했다. 권한 부족, 정책 위반, 지원하지 않는 업무 유형, 잘못된 입력 형식이 대표적이다.
여기서 가장 자주 오해되는 상태가 입력 필요다. input-required는 오류 코드가 아니다. 기업 업무에서는 사람이 중간에 판단해야 하는 지점이 많다. 예를 들어 구매 에이전트가 5천만 원 이상의 계약 초안을 만들었다면, 바로 발주하지 않고 승인권자의 확인을 요구해야 한다. 이때 Task는 실패하지 않는다. 다만 "이 결정을 기다리는 중"이라는 상태가 된다.
auth-required도 비슷하게 볼 수 있다. 이것은 "업무 자체가 잘못됐다"는 뜻이라기보다, 작업을 계속하려면 인증이나 권한 부여 절차가 먼저 필요하다는 신호다. 사용자가 필요한 권한을 부여하면 원격 에이전트는 같은 Task의 맥락 안에서 작업을 이어 갈 수 있다.
반대로 failed와 rejected는 구분해야 한다. 실패는 해보려 했지만 끝내지 못한 경우다. 거절은 시작하지 않거나 계속하지 않기로 판단한 경우다. 예를 들어 회계 에이전트가 세금 계산서를 검증하다가 외부 국세 시스템 장애로 중단되면 실패에 가깝다. 그러나 요청자가 접근 권한이 없는 법인의 세금 자료를 요청했다면 거절에 가깝다.
장기 작업에서 스트리밍이 필요한 이유
장기 작업을 단순 조회 방식으로만 관리하면 클라이언트는 계속 "끝났나요?"라고 물어야 한다. 짧은 작업에서는 괜찮지만, 오래 걸리는 작업에서는 비효율적이다. 진행 상황도 늦게 알게 되고, 중간 산출물을 즉시 활용하기 어렵다.
A2A는 이런 문제를 줄이기 위해 스트리밍 방식을 지원한다. 공식 가이드에서는 서버가 스트리밍 능력을 제공할 경우 Agent Card의 capabilities.streaming 값으로 이를 알리고, 클라이언트가 SendStreamingMessage 또는 기존 Task에 대한 구독 방식으로 진행 이벤트를 받을 수 있다고 설명한다.1
스트리밍의 대표적인 전송 방식은 Server-Sent Events(SSE)다. SSE는 서버가 HTTP 연결을 열어 둔 채 클라이언트에게 이벤트를 계속 보내는 방식이다. 웹소켓처럼 양방향 통신을 전제로 하지 않고, 서버에서 클라이언트로 진행 상황을 흘려보내는 데 적합하다.
A2A 스트림에서 중요한 이벤트는 크게 두 종류로 볼 수 있다.
상태 업데이트(TaskStatusUpdateEvent): Task가 제출됨, 진행 중, 입력 필요, 인증 필요, 완료, 실패 같은 상태로 바뀌었음을 알린다. 에이전트가 중간 메시지를 함께 전달할 수도 있다.
산출물 업데이트(TaskArtifactUpdateEvent): 보고서 일부, 분석 결과 일부, 파일 조각, 구조화 데이터 일부처럼 Artifact가 새로 생기거나 갱신됐음을 알린다. 큰 결과물을 조각으로 보내기 위해 append, lastChunk 같은 정보를 함께 쓰기도 한다.
예를 들어 시장 조사 에이전트가 "한국, 일본, 미국의 2026년 전기차 보조금 정책 비교 보고서"를 작성한다고 하자. 이 작업은 여러 출처 조사, 표 생성, 요약 작성, 검증을 거친다. 스트리밍이 없다면 사용자는 최종 보고서가 나올 때까지 기다려야 한다. 스트리밍이 있으면 다음과 같은 진행을 받을 수 있다.
Task submitted: 요청 접수
Task working: 한국 정책 조사 중
Artifact update: 한국 정책 요약 초안 생성
Task working: 일본 정책 조사 중
Artifact update: 비교 표 1차 생성
Task input-required: 미국 연방 정책과 주별 정책 중 어느 범위를 포함할지 확인 필요이 흐름에서 중요한 점은 중간 메시지가 단순한 친절한 알림이 아니라는 것이다. 중간 산출물은 다른 에이전트가 이어서 사용할 수 있는 Artifact가 될 수 있고, 입력 필요 상태는 사람의 결정을 공식적으로 기다리는 업무 상태가 된다.
한 가지 더 기억할 점이 있다. 스트림은 Task가 완료, 실패, 취소, 거절 같은 최종 상태에 도달하면 닫힌다. 또한 input-required나 auth-required처럼 작업이 사람의 입력이나 인증을 기다리는 상태가 되어도 스트림이 일단 닫힐 수 있다.1 이것은 Task가 사라졌다는 뜻이 아니다. 지금은 더 진행하려면 클라이언트 쪽의 다음 행동이 필요하다는 뜻이다.
연결이 끊겨도 작업은 계속되어야 한다
스트리밍은 실시간성에 강하지만 한계가 있다. 클라이언트와 서버 사이의 연결이 항상 유지된다는 보장은 없다. 브라우저가 닫힐 수 있고, 네트워크가 끊길 수 있으며, 게이트웨이가 연결을 종료할 수도 있다. 수일이 걸리는 작업을 하나의 열린 연결에만 의존하는 것은 위험하다.
그래서 A2A는 장기 실행 작업을 위해 재구독과 푸시 알림 구조를 함께 다룬다. 스트림이 끊겼지만 Task가 아직 종료되지 않았다면 클라이언트는 SubscribeToTask 같은 구독 흐름으로 해당 Task의 이후 업데이트를 다시 받을 수 있다. 또한 서버가 푸시 알림 기능을 지원하면 Agent Card의 capabilities.pushNotifications로 이를 알리고, 클라이언트가 제공한 HTTPS 웹훅 URL로 중요한 상태 변화를 알려 줄 수 있다.1
웹훅은 서버가 클라이언트의 특정 URL을 호출해 이벤트를 전달하는 방식이다. 클라이언트가 계속 연결을 붙잡고 있지 않아도 된다. 예를 들어 결산 분석 Task가 밤새 실행되는 경우를 보자.
재무 에이전트가 분석 Task를 시작한다.
클라이언트는 푸시 알림을 받을 웹훅 URL과 필요한 인증 정보를 함께 등록한다.
연결은 종료된다.
원격 에이전트는 배치 분석, 검증, 보고서 생성을 계속한다.
Task가 입력 필요, 인증 필요, 완료 같은 중요한 상태가 되면 원격 에이전트가 웹훅으로 알림을 보낸다.
클라이언트는 알림을 검증한 뒤, 알림에 포함된 Task 식별 정보로 최신 Task를 조회한다.
A2A의 푸시 알림 본문은 스트리밍에서 쓰는 형식과 맞춰 Task, Message, 상태 업데이트, Artifact 업데이트 중 하나를 담을 수 있다.1 다만 실무에서는 웹훅 알림 자체에 모든 결과를 싣기보다 "상태가 바뀌었으니 와서 확인하라"는 신호로 쓰는 편이 안전한 경우가 많다. 알림에는 Task ID, 상태, 이벤트 종류, 상관관계 ID 같은 식별 정보를 담고, 실제 상세 내용과 산출물은 GetTask 같은 조회 흐름으로 가져오는 구조가 더 관리하기 쉽다.
이 방식은 보안과 운영에도 유리하다. 대용량 파일을 웹훅 본문에 싣지 않아도 되고, 클라이언트가 현재 권한으로 다시 조회하게 만들 수 있다. 알림 유실이나 중복 수신이 발생해도 Task의 현재 상태를 기준으로 복구할 수 있다. 물론 웹훅을 받을 때는 토큰, 서명, mTLS, 허용된 발신자 검증 같은 방식으로 알림의 진위를 확인해야 한다. 푸시 알림은 편리하지만, 아무 URL에나 서버가 요청을 보내거나 아무 요청이나 믿고 처리해서는 안 된다.
휴먼 인 더 루프를 Task 안에 넣기
휴먼 인 더 루프(Human in the Loop)는 자동화 흐름 중간에 사람이 판단하거나 승인하는 단계를 뜻한다. A2A에서 사람의 개입은 별도의 예외 흐름으로 밀려나면 안 된다. 기업 업무에서는 사람의 승인이 정상 절차인 경우가 많기 때문이다.
예를 들어 법무 검토 에이전트가 계약서 초안을 점검한다고 하자. 다음과 같은 상황에서는 사람의 판단이 필요하다.
표준 계약서와 다른 면책 조항이 발견됐다.
고객사가 요구한 손해배상 한도가 내부 기준을 넘었다.
특정 국가의 개인정보 이전 조항이 불명확하다.
계약 금액이 자동 승인 한도를 초과했다.
이때 원격 에이전트는 Task를 실패로 끝내기보다 입력 필요 상태로 전환하고, 무엇을 확인해야 하는지 Message로 설명해야 한다. 클라이언트는 이 메시지를 사용자, 승인권자, 또는 상위 워크플로 시스템에 전달한다. 사람이 답하면 클라이언트는 같은 Task에 추가 메시지를 보내 작업을 재개한다.
중요한 것은 같은 Task를 유지하는 것이다. 새 요청으로 다시 시작하면 이전 판단 근거, 중간 산출물, 승인 요청 내역이 분리된다. 그러면 감사 추적이 어려워지고, 에이전트가 같은 일을 반복할 수 있다. 반대로 같은 Task 안에서 입력 대기와 재개가 이뤄지면 "어떤 근거로 멈췄고, 누가 무엇을 승인했으며, 이후 어떤 결과가 나왔는지"를 하나의 흐름으로 남길 수 있다.
인증이 필요한 경우도 비슷하다. 업무 시스템 접근 권한이 만료됐거나, 사용자의 위임 동의가 더 필요하다면 Task를 곧바로 실패로 끝내기보다 auth-required로 멈추는 편이 자연스럽다. 이후 인증 절차가 끝나면 클라이언트는 같은 Task의 맥락에서 처리를 이어 갈 수 있다. 다만 인증 세부 절차는 조직의 보안 정책과 구현 방식에 따라 달라질 수 있으므로, 어떤 정보를 Task 메시지에 담고 어떤 정보는 별도 보안 채널로 처리할지 분명히 정해야 한다.
다만 입력 대기 상태를 무한히 방치해서는 안 된다. 사람이 답하지 않는 Task가 계속 쌓이면 운영 부담이 커진다. 따라서 실무 구현에서는 다음 정책이 필요하다.
입력 대기 또는 인증 대기 상태의 만료 시간
승인자 부재 시 대체 승인 경로
민감 업무의 자동 승인 금지 규칙
시간 초과 시 실패, 취소, 에스컬레이션 중 어떤 상태로 전환할지에 대한 기준
승인 메시지와 승인자의 신원을 감사 로그에 남기는 방식
A2A는 이런 조직 정책 자체를 대신 정하지 않는다. 대신 Task, Message, 상태 업데이트라는 공통 구조 안에 사람의 입력 단계를 표현할 수 있게 한다.
최종 상태 이후에는 새 일을 이어 붙이지 않는다
Task에는 끝이 있어야 한다. 완료, 실패, 취소, 거절 같은 상태는 일반적으로 최종 상태다. 최종 상태에 도달한 Task는 더 이상 진행 중인 업무가 아니다. 공식 명세에서도 최종 상태의 Task에 추가 메시지를 보내는 동작은 허용되지 않으며, 이 경우 UnsupportedOperationError 같은 오류로 처리될 수 있다.2
이 제약은 불편해 보일 수 있지만 중요하다. 완료된 Task에 계속 새 메시지를 붙일 수 있다면, 같은 Task의 의미가 흐려진다. "완료된 보고서"에 다시 "그럼 이번에는 다른 지역도 조사해 줘"라는 메시지를 붙이면, 원래 Task의 완료 시점과 결과가 불명확해진다. 실패한 Task에 임의의 새 요청을 붙이면 장애 분석도 어려워진다.
따라서 클라이언트는 최종 상태를 확인한 뒤 다음 원칙을 따라야 한다.
완료된 결과에 대한 후속 질문이 기존 결과 해석이라면 새 Task가 아니라 별도 대화나 조회로 처리할 수 있는지 검토한다.
새로운 업무 범위가 생겼다면 새 Task를 만든다.
이전 Task의 결과를 바탕으로 정교화하거나 후속 작업을 해야 한다면 같은
contextId안에서 새 Task를 시작하고, 필요하면referenceTaskIds로 이전 Task를 참조한다.3실패한 작업을 재시도할 때도 기존 Task를 되살리기보다 새 Task를 만들고, 이전 Task ID를 참조 관계로 남기는 편이 안전하다.
취소된 Task에 다시 입력을 보내지 않는다. 사용자가 재개를 원하면 새 요청으로 시작한다.
거절된 Task는 거절 사유를 먼저 해결한 뒤 다시 요청한다.
오류 처리도 명확해야 한다. 클라이언트는 추가 메시지가 거부됐을 때 이를 일반 실패로만 표시하지 말고, "이미 종료된 작업이므로 새 작업을 시작해야 한다"는 식으로 사용자에게 설명해야 한다. 개발자 관점에서는 TaskNotFoundError, UnsupportedOperationError, ContentTypeNotSupportedError 같은 오류를 구분해 처리해야 한다. 그래야 사용자는 권한 문제인지, 종료된 작업인지, 입력 형식 문제인지 이해할 수 있다.
비동기 협업의 설계 기준
A2A의 비동기 협업을 잘 구현하려면 단순히 상태 값을 저장하는 것으로는 부족하다. 상태 전이는 운영 가능한 정책과 함께 설계되어야 한다.
첫째, 모든 Task에는 명확한 소유자와 권한이 있어야 한다. 누가 Task를 조회할 수 있는지, 누가 취소할 수 있는지, 누가 추가 입력을 보낼 수 있는지 정해야 한다.
둘째, 상태 변경은 기록되어야 한다. 언제 제출됐고, 언제 진행 중이 됐으며, 언제 입력이나 인증을 기다렸고, 누가 승인했는지 남겨야 한다. 이는 디버깅뿐 아니라 감사와 책임 분리에 필요하다.
셋째, 중간 산출물과 최종 산출물을 구분해야 한다. 스트리밍으로 전달된 초안은 나중에 수정될 수 있다. 반면 완료 상태의 Artifact는 재사용 가능한 결과물로 취급될 수 있다.
넷째, 재시도는 신중해야 한다. 네트워크 오류 때문에 같은 요청을 다시 보냈는데 실제로는 원격 에이전트가 이미 결제, 발주, 메일 발송 같은 부수 효과를 수행했을 수 있다. 장기 작업에서는 멱등성, 즉 같은 요청이 여러 번 들어와도 중복 실행되지 않도록 하는 설계가 필요하다.
다섯째, 스트리밍과 푸시 알림은 서로 대체재가 아니라 보완재다. 사용자가 화면을 보고 있는 동안에는 SSE로 실시간 진행 상황을 보여 줄 수 있다. 사용자가 떠난 뒤에도 중요한 변화는 웹훅으로 전달할 수 있다. 그리고 언제든 Task 조회를 통해 현재 상태를 복구할 수 있어야 한다.
결국 엔터프라이즈 에이전트 협업의 핵심은 "오래 걸리는 일을 잊지 않는 것"이다. A2A의 Task 생명주기는 이 문제를 해결하기 위한 공통 언어다. 빠른 응답은 좋은 사용자 경험을 만든다. 그러나 추적 가능한 비동기 작업은 실제 업무 자동화를 가능하게 한다.
참고
1Streaming and Asynchronous Operations for Long-Running Tasks
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.