스트리밍과 비동기 연산
스트리밍과 비동기 연산
Agent2Agent(A2A) 프로토콜은 즉시 완료되지 않을 수 있는 태스크를 처리하도록 명시적으로 설계됐어요. 많은 AI 기반 연산은 종종 오래 실행되고, 여러 단계를 거치고, 점진적 결과를 만들거나, 인간의 개입이 필요해요. A2A는 이러한 비동기 상호작용을 관리하는 메커니즘을 제공해서, 클라이언트가 계속 연결되어 있든 좀 더 단절된 방식으로 동작하든 효과적으로 업데이트를 받도록 보장해요.
출처: 문서
본문
Server-Sent Events(SSE) 스트리밍
점진적 결과를 만드는 태스크(긴 문서 생성이나 미디어 스트리밍처럼)나 지속적인 상태 업데이트를 제공하는 태스크를 위해 A2A는 Server-Sent Events(SSE)를 쓰는 실시간 통신을 지원해요. 이 접근 방식은 클라이언트가 A2A 서버와 활성 HTTP 연결을 유지할 수 있을 때 이상적이에요. 다음 핵심 기능들이 A2A 프로토콜에서 SSE 스트리밍이 어떻게 구현·관리되는지 설명해요.
- 서버 역량(Server Capability): A2A 서버는 Agent Card에서
capabilities.streaming: true를 설정해 스트리밍 지원을 나타내야 해요. - 스트림 시작(Initiating a Stream): 클라이언트는
SendStreamingMessageRPC 메서드로 초기 메시지(예: 프롬프트나 명령)를 보내면서 동시에 그 태스크의 업데이트를 구독해요. - 서버 응답과 연결(Server Response and Connection): 구독이 성공하면 서버는 HTTP 200 OK 상태와
Content-Type: text/event-stream으로 응답해요. 이 HTTP 연결은 서버가 클라이언트에 이벤트를 푸시할 수 있도록 열린 채로 유지돼요. - 이벤트 구조와 유형(Event Structure and Types): 서버는 이 스트림으로 이벤트를 보내요. 각 이벤트의
data필드는 JSON-RPC 2.0 Response 객체, 일반적으로SendStreamingMessageResponse를 담아요.SendStreamingMessageResponse의result필드에는 다음이 포함돼요.Task: 작업의 현재 상태를 나타내요.TaskStatusUpdateEvent: 태스크 수명주기 상태의 변화를 전달해요(예:working에서input-required또는completed로). 에이전트의 중간 메시지도 제공해요.TaskArtifactUpdateEvent: 태스크가 생성한 새 아티팩트나 업데이트된 아티팩트를 전달해요.append,lastChunk같은 필드로 큰 파일이나 데이터 구조를 청크로 스트리밍하는 데 쓰여요.
- 스트림 종료(Stream Termination): 태스크가 종료 또는 중단 상태(예:
COMPLETED,FAILED,CANCELED,REJECTED,INPUT_REQUIRED)에 도달하면 서버는 스트림을 닫고 더 이상 업데이트를 보내지 않아요. - 재구독(Resubscription): 태스크가 여전히 활성 상태인데 클라이언트의 SSE 연결이 조기 끊기면, 클라이언트는
SubscribeToTaskRPC 메서드를 사용해 스트림에 다시 연결할 수 있어요.
스트리밍을 언제 쓸까
SSE 스트리밍은 다음에 가장 적합해요.
- 장기 실행 태스크의 실시간 진행 모니터링.
- 큰 결과(아티팩트)를 점진적으로 받기.
- 즉각적인 피드백이나 부분 응답이 유익한 대화형·대화식 교환.
- 에이전트로부터 낮은 지연의 업데이트가 필요한 애플리케이션.
프로토콜 스펙 참조
자세한 구조는 프로토콜 스펙을 참고하세요.
연결 끊김 시나리오를 위한 푸시 알림
매우 오래 실행되는 태스크(예: 몇 분, 몇 시간, 심지어 며칠)의 경우나 클라이언트가 지속 연결을 유지할 수 없거나 선호하지 않는 경우(모바일 클라이언트나 서버리스 함수처럼), A2A는 푸시 알림을 사용한 비동기 업데이트를 지원해요. 이는 중요한 태스크 업데이트가 발생할 때 A2A 서버가 클라이언트가 제공한 웹훅을 적극적으로 알릴 수 있게 해요. 다음 핵심 기능들이 A2A 프로토콜에서 푸시 알림이 어떻게 구현·관리되는지 설명해요.
- 서버 역량(Server Capability): A2A 서버는 Agent Card에서
capabilities.pushNotifications: true를 설정해 이 기능 지원을 나타내야 해요. - 구성(Configuration): 클라이언트는 서버에
TaskPushNotificationConfig를 제공해요. 이 구성은 다음 중 하나로 제공돼요.- 초기
SendMessage또는SendStreamingMessage요청 안에서, 또는 - 별도로 기존 태스크에
CreateTaskPushNotificationConfigRPC 메서드를 사용해.TaskPushNotificationConfig는url(HTTPS 웹훅 URL), 선택적token(클라이언트 측 검증용), 선택적authentication세부사항(A2A 서버가 웹훅에 인증하기 위함)을 포함해요.
- 초기
- 알림 트리거(Notification Trigger): A2A 서버는 언제 푸시 알림을 보낼지 결정해요. 대개 태스크가 중요한 상태 변화(예: 종료 상태,
input-required,auth-required)에 도달했을 때죠. - 알림 페이로드(Notification Payload): A2A 프로토콜은 HTTP 본문 페이로드를 스트리밍 연산에 쓰는 형식과 일치하는
StreamResponse객체로 정의해요. 페이로드는task,message,statusUpdate,artifactUpdate중 하나를 포함해요. 상세 구조는 Push Notification Payload를 참고하세요. - 클라이언트 조치(Client Action): 푸시 알림을 받으면(그리고 그 진위를 성공적으로 검증하고 나면) 클라이언트는 대개 알림의
taskId로GetTaskRPC 메서드를 사용해 새 아티팩트를 포함한 완전하고 업데이트된Task객체를 가져와요.
푸시 알림을 언제 쓸까
푸시 알림은 다음에 이상적이에요.
- 완료까지 몇 분, 몇 시간, 며칠이 걸릴 수 있는 매우 오래 실행되는 태스크.
- 지속 연결을 유지할 수 없거나 선호하지 않는 클라이언트(모바일 앱이나 서버리스 함수처럼).
- 연속 업데이트보다는 중요한 상태 변화만 통지받으면 되는 시나리오.
프로토콜 스펙 참조
자세한 구조는 프로토콜 스펙을 참고하세요.
클라이언트 측 푸시 알림 서비스
TaskPushNotificationConfig.url에 지정된 url은 클라이언트 측 푸시 알림 서비스를 가리켜요. 이 서비스는 A2A 서버로부터 HTTP POST 알림을 받는 역할을 해요. 그 책임에는 들어오는 알림 인증, 관련성 검증, 알림 또는 그 콘텐츠를 적절한 클라이언트 애플리케이션 로직이나 시스템에 중계하는 것이 포함돼요.
푸시 알림의 보안 고려사항
푸시 알림은 비동기적이고 서버가 시작하는 아웃바운드 성격 때문에 보안이 가장 중요해요. A2A 서버(알림을 보내는 쪽)와 클라이언트 웹훅 수신자 모두 중요한 책임이 있어요.
A2A 서버 보안(클라이언트 웹훅으로 알림을 보낼 때)
- 웹훅 URL 검증(Webhook URL Validation): 서버는 클라이언트가 제공한 URL을 맹목적으로 신뢰하고 POST 요청을 보내면 안 돼요. 악성 클라이언트는 내부 서비스나 무관한 제3자 시스템을 가리키는 URL을 제공해서 SSRF(Server-Side Request Forgery) 공격을 유발하거나 DDoS(분산 서비스 거부) 증폭기 역할을 할 수 있어요.
- 완화 전략(Mitigation strategies): 신뢰 도메인 허용 목록, 소유권 검증(예: 챌린지-응답 메커니즘), 네트워크 제어(예: 이그레스 방화벽).
- 클라이언트 웹훅에 인증하기(Authenticating to the Client's Webhook): A2A 서버는
TaskPushNotificationConfig.authentication에 지정된 스킴에 따라 클라이언트 웹훅 URL에 반드시 자신을 인증해야 해요. 일반적인 스킴에는 Bearer 토큰(OAuth 2.0), API 키, HMAC 서명, 상호 TLS(mTLS)가 있어요.
클라이언트 웹훅 수신자 보안(A2A 서버에서 알림을 받을 때)
- A2A 서버 인증하기(Authenticating the A2A Server): 웹훅 엔드포인트는 들어오는 알림 요청의 진위를 엄격히 검증해서 합법적인 A2A 서버에서 왔는지, 사칭자가 아닌지 확인해야 해요.
- 검증 방법(Verification methods): 서명/토큰 검증(예: A2A 서버의 신뢰할 수 있는 공개 키에 대한 JWT 서명, HMAC 서명, API 키 검증). 또한
TaskPushNotificationConfig.token이 제공되면 이를 검증해요. - 리플레이 공격 방지(Preventing Replay Attacks):
- 타임스탬프: 알림은 타임스탬프를 포함해야 해요. 웹훅은 너무 오래된 알림은 거부해야 해요.
- 논스/고유 ID: 중요한 알림에는 고유한 일회용 식별자(예: JWT의
jti클레임이나 이벤트 ID)를 사용해 중복 알림 처리를 방지하는 것을 고려해요.
- 안전한 키 관리와 순환(Secure Key Management and Rotation): 특히 암호화 키에 대해 정기적 키 순환을 포함한 안전한 키 관리 관행을 구현해요. JWKS(JSON Web Key Set) 같은 프로토콜이 비대칭 키의 키 순환을 용이하게 해요.
예시 비대칭 키 흐름(JWT + JWKS)
- 클라이언트가
authentication.scheme: "Bearer"를 지정하고 JWT에 대한 예상issuer나audience를 명시하는TaskPushNotificationConfig를 만들어요. - A2A 서버가 알림을 보낼 때:
- 비밀 키로 서명한 JWT를 생성해요. JWT는
iss(발급자),aud(수신자),iat(발급 시각),exp(만료),jti(JWT ID),taskId같은 클레임을 포함해요. - JWT 헤더가 서명 알고리즘과 키 ID(
kid)를 나타내요. - A2A 서버는 JWKS 엔드포인트를 통해 공개 키를 제공해요.
- 비밀 키로 서명한 JWT를 생성해요. JWT는
- 클라이언트 웹훅이 알림을 받으면:
- Authorization 헤더에서 JWT를 추출해요.
- JWT 헤더의
kid(키 ID)를 검사해요. - A2A 서버의 JWKS 엔드포인트에서 해당 공개 키를 가져와요(키 캐싱 권장).
- 공개 키로 JWT 서명을 검증해요.
- 클레임(
iss,aud,iat,exp,jti)을 검증해요. TaskPushNotificationConfig.token이 제공되면 검사해요.
이 포괄적이고 계층화된 푸시 알림 보안 접근은 메시지가 진위성 있고 무결하며 적시에 도착하도록 보장해서, 보내는 A2A 서버와 받는 클라이언트 웹훅 인프라를 모두 보호해요.
더 알아보기 (Learn more)
- 푸시 알림과 스트리밍의 상태 기반 상호작용 기초는 핵심 개념(Key Concepts)을 확인하세요.
- 에이전트 카드에서 스트리밍 역량을 선언하는 방법은 에이전트 발견(Agent Discovery) 문서를 읽어 보세요.
- 스펙의 정확한 요구사항은 A2A 스펙(specification)을 참고하세요.