확장 (Extensions)¶
요약¶
확장은 Agent2Agent(A2A) 프로토콜에 새로운 데이터, 요구 사항, 메서드 및 상태 머신을 추가하여 확장하는 수단입니다. 에이전트는 자신의 AgentCard
에서 확장에 대한 지원을 선언하며, 클라이언트는 에이전트에 요청하는 과정에서 확장이 제공하는 동작을 선택적으로 사용할 수 있습니다. 확장은 URI로 식별되며 해당 확장 사양에 의해 정의됩니다. 누구나 확장을 정의, 게시 및 구현할 수 있습니다.
소개¶
핵심 A2A 프로토콜은 에이전트 간의 통신을 가능하게 하는 견고한 기반입니다. 그러나 일부 도메인에서는 프로토콜의 일반적인 메서드가 제공하는 것보다 더 많은 추가 구조가 필요하다는 것이 분명합니다. 이러한 경우를 지원하기 위해 확장이 프로토콜에 추가되었습니다. 확장을 통해 에이전트와 클라이언트는 핵심 프로토콜 위에 계층화될 추가적인 사용자 지정 로직을 협상할 수 있습니다.
확장의 범위¶
확장을 사용하는 가능한 방법의 정확한 집합은 의도적으로 정의되지 않았습니다. 이는 현재 알려진 사용 사례를 넘어 A2A를 확장하는 기능을 용이하게 하기 위함입니다. 그러나 다음과 같은 일부 사용 사례는 명확하게 예측할 수 있습니다.
-
AgentCard
에 새로운 정보 노출. 확장은 요청/응답 흐름에 전혀 영향을 미치지 않을 수 있으며, 단순히AgentCard
를 통해 클라이언트에 추가적인 구조화된 정보를 전달하는 방법으로 사용될 수 있습니다. 이를 데이터 전용 확장이라고 합니다. 예를 들어, 확장은 에이전트의 GDPR 준수에 대한 구조화된 데이터를 해당AgentCard
에 추가할 수 있습니다. -
핵심 요청/응답 메시지에 추가적인 구조 및 상태 변경 요구 사항 오버레이. 예를 들어, 확장은 모든 메시지가 특정 스키마를 준수하는
DataPart
를 사용하도록 요구할 수 있습니다. 이러한 유형의 확장은 효과적으로 핵심 A2A 프로토콜에 대한 프로필 역할을 하여 허용되는 값의 범위를 좁힙니다. 이를 프로필 확장이라고 합니다. 예를 들어, 의료 확장은 환자 정보가 포함된 모든Message
부분이 암호화되어 FHIR 표준을 준수하는DataPart
내에 배치되도록 의무화할 수 있습니다. -
완전히 새로운 RPC 메서드 추가. 확장은 에이전트가 핵심 프로토콜 메서드 집합 이상을 구현하도록 정의할 수 있습니다. 이를 메서드 확장이라고 합니다. 예를 들어, '작업 기록' 확장은 이전 작업 목록을 검색하기 위해
tasks/search
RPC 메서드를 추가할 수 있습니다.
확장이 허용하지 않는 프로토콜 변경 사항도 일부 있습니다.
- 핵심 데이터 구조의 정의 변경. 프로토콜에서 정의한 데이터 구조에 새 필드를 추가하거나 필수 필드를 제거하는 것은 지원되지 않습니다. 확장은 핵심 데이터 구조에 있는
metadata
맵에 사용자 지정 속성을 배치해야 합니다. - 열거형 타입에 새 값 추가. 대신, 확장은 기존 열거형 값을 사용하고
metadata
필드에 추가적인 의미론적 의미를 주석으로 달아야 합니다.
이러한 제한 사항은 확장이 클라이언트와 에이전트가 수행하는 핵심 유형 유효성 검사를 깨뜨리는 것을 방지하기 위해 존재합니다.
아키텍처 개요¶
TODO: 구성 요소와 연결을 간략하게 설명하는 다이어그램.
확장 선언¶
에이전트는 AgentCapabilities
객체에 AgentExtension
객체를 포함시켜 자신의 AgentCard
에서 확장에 대한 지원을 선언합니다.
필드명 | 타입 | 필수 | 설명 |
---|---|---|---|
uri |
string |
예 | 확장의 URI입니다. 이는 확장 사양이 정의하는 임의의 식별자입니다. 확장 구현은 이 URI를 사용하여 활성화 시기를 식별하고, 클라이언트는 이를 사용하여 확장 호환성을 결정합니다. |
required |
boolean |
아니요 | 에이전트가 클라이언트에게 이 확장을 사용하도록 요구하는지 여부입니다. |
description |
string |
아니요 | 에이전트가 선언된 확장을 사용하는 방법에 대한 설명입니다. 확장의 전체 세부 정보는 확장 사양에 포함되어야 합니다. 이 필드는 에이전트와 확장 간의 연결을 설명하는 데 유용합니다. |
params |
object |
아니요 | 확장별 구성입니다. 이 필드에 배치할 예상 값(있는 경우)은 확장 사양에 의해 정의됩니다. 이 필드는 확장의 매개변수를 지정하거나 추가적인 에이전트별 데이터를 선언하는 데 사용할 수 있습니다. |
확장을 보여주는 AgentCard
예시:
{
"name": "매직 8볼",
"description": "당신의 미래를 알려줄 수 있는 에이전트... 아마도.",
"version": "0.1.0",
"url": "https://example.com/agents/eightball",
"capabilities": {
"streaming": true,
"extensions": [
{
"uri": "https://example.com/ext/konami-code/v1",
"description": "새로운 운세를 잠금 해제하기 위한 치트 코드 제공",
"required": false,
"params": {
"hints": [
"심즈가 급하게 추가 현금이 필요할 때",
"부인할 수도 있지만, 그 소들에 대한 증거는 이미 확보했습니다."
]
}
}
]
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "fortune",
"name": "점쟁이",
"description": "신비로운 매직 8볼에게 조언을 구하세요",
"tags": ["신비로운", "믿을 수 없는"]
}
]
}
필수 확장¶
확장은 추가 기능을 활성화하는 수단이지만, 일부 에이전트는 핵심 A2A 프로토콜로 표현할 수 있는 것보다 더 엄격한 요구 사항을 가질 것으로 예상됩니다. 예를 들어, 에이전트는 모든 수신 메시지가 작성자에 의해 암호화 서명되도록 요구할 수 있습니다. required
로 선언된 확장은 이러한 사용 사례를 지원하기 위한 것입니다.
AgentCard
가 필수 확장을 선언하면, 이는 확장의 일부 측면이 요청 구성 방식에 영향을 미친다는 신호를 클라이언트에게 보냅니다. 에이전트는 요청이 에이전트에 전달되는 방식에 직접적인 영향이 없으므로 데이터 전용 확장을 필수로 표시해서는 안 됩니다.
AgentCard
가 필수 확장을 선언하고 클라이언트가 해당 필수 확장의 활성화를 요청하지 않으면, 에이전트는 수신 요청을 거부하고 적절한 오류 코드를 반환해야 합니다.
클라이언트가 확장 활성화를 요청하지만 확장 정의 프로토콜을 따르지 않으면, 에이전트는 요청을 거부하고 적절한 유효성 검사 실패 메시지를 반환해야 합니다.
확장 사양¶
확장의 세부 정보는 사양에 의해 정의됩니다. 이 문서의 정확한 형식은 지정되지 않았지만, 최소한 다음을 포함해야 합니다.
-
확장 구현이 식별하고 응답해야 하는 특정 URI. 버전 관리 또는 사양 문서 위치 변경을 고려하여 여러 URI가 동일한 확장을 식별할 수 있습니다. 확장 작성자는 URL 확산을 피하기 위해 w3id와 같은 영구 식별자 서비스를 사용하는 것이 좋습니다.
-
AgentCard
에 노출된AgentExtension
객체의params
필드에 지정된 객체의 스키마 및 의미. -
클라이언트와 에이전트 간에 통신되는 추가 데이터 구조의 스키마.
-
요청/응답 흐름, 추가 엔드포인트 또는 확장을 구현하는 데 필요한 기타 로직에 대한 세부 정보.
확장 종속성¶
확장은 다른 확장에 의존할 수 있습니다. 이 종속성은 확장의 핵심 기능이 종속 항목 없이는 실행될 수 없는 경우 필수이거나, 다른 확장이 있을 때 일부 추가 기능이 활성화되는 경우 선택 사항일 수 있습니다. 확장 사양은 종속성과 해당 유형을 문서화해야 합니다.
종속성은 AgentExtension
객체가 아닌 확장 사양 내에서 선언됩니다. 확장 및 해당 확장의 사양에 나열된 모든 필수 종속성을 활성화하는 것은 클라이언트의 책임입니다.
확장 활성화¶
확장은 기본적으로 비활성 상태여야 합니다. 이는 확장 미인식 클라이언트가 확장이 제공하는 세부 정보와 데이터에 부담을 느끼지 않는 "기본값으로 기준선" 경험을 제공합니다. 대신, 클라이언트와 에이전트는 협상을 수행하여 요청에 대해 어떤 확장이 활성 상태인지 결정합니다. 이 협상은 클라이언트가 에이전트에 대한 HTTP 요청에 X-A2A-Extensions
헤더를 포함하여 시작됩니다. 이 헤더의 값은 클라이언트가 활성화하려는 확장 URI 목록이어야 합니다.
클라이언트는 모든 확장의 활성화를 요청할 수 있습니다. 에이전트는 요청에서 지원되는 확장을 식별하고 활성화를 수행할 책임이 있습니다. 에이전트에서 지원하지 않는 요청된 확장은 무시할 수 있습니다.
모든 확장이 활성화 가능한 것은 아닙니다. 데이터 전용 확장은 AgentCard를 통해 추가 정보를 제공하기 위해서만 존재합니다. 클라이언트는 여전히 이러한 확장의 활성화를 요청할 수 있습니다. 확장은 활성화 시 추가 로직을 수행하지 않으므로 요청에 영향을 미치지 않아야 합니다.
일부 확장에는 활성화를 위한 추가 전제 조건이 있을 수 있습니다. 예를 들어, 일부 민감한 확장에는 확장을 활성화할 수 있는 사람을 지정하는 해당 접근 제어 목록이 있을 수 있습니다. 요청된 확장 중 어떤 확장이 활성화되는지 결정하는 것은 에이전트에게 달려 있습니다.
클라이언트가 필수 종속성이 있는 확장의 활성화를 요청하는 경우, 해당 클라이언트는 해당 종속 확장의 활성화도 요청하고 해당 요구 사항을 준수해야 합니다. 클라이언트가 요청된 확장에 대한 모든 필수 종속성을 요청하지 않으면 서버는 적절한 오류와 함께 요청을 실패시킬 수 있습니다.
에이전트가 활성화된 모든 확장을 식별하면, 응답에는 활성화된 모든 확장을 식별하는 X-A2A-Extensions
헤더가 포함되어야 합니다.
확장 활성화를 보여주는 요청 예시:
POST /agents/eightball HTTP/1.1
Host: example.com
Content-Type: application/json
X-A2A-Extensions: https://example.com/ext/konami-code/v1
Content-Length: 519
{
"jsonrpc": "2.0",
"method": "message/send",
"id": "1",
"params": {
"message": {
"kind": "message",
"messageId": "1",
"role": "user",
"parts": [{"kind": "text", "text": "오 매직 8볼, 오늘 비가 올까요?"}]
},
"metadata": {
"https://example.com/ext/konami-code/v1/code": "motherlode"
}
}
}
그리고 활성화된 확장을 반영하는 해당 응답:
HTTP/1.1 200 OK
Content-Type: application/json
X-A2A-Extensions: https://example.com/ext/konami-code/v1
Content-Length: 338
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"kind": "message",
"messageId": "2",
"role": "agent",
"parts": [{"kind": "text", "text": "바로 그거예요!"}]
}
}
구현 고려 사항¶
A2A 프로토콜은 확장의 "무엇"을 정의하지만, 이 섹션에서는 확장 구현을 작성, 버전 관리 및 배포하기 위한 모범 사례인 "방법"에 대한 지침을 제공합니다.
버전 관리¶
확장 사양은 필연적으로 발전할 것입니다. 클라이언트와 에이전트가 호환되는 구현을 협상할 수 있도록 명확한 버전 관리 전략을 갖는 것이 중요합니다.
- 권장 사항: 확장의 URI를 기본 버전 식별자로 사용합니다.
https://example.com/ext/my-extension/v1
또는https://example.com/ext/my-extension/v2
와 같이 URI 경로에 직접 버전 번호를 포함하는 것이 좋습니다. - 호환성이 손상되는 변경: 확장의 로직, 데이터 구조 또는 필수 매개변수에 호환성이 손상되는 변경을 도입할 때는 새 URI를 반드시 사용해야 합니다. 이렇게 하면 모호성을 방지하고
/v1
을 지원하는 에이전트가/v2
요청을 잘못 처리하지 않도록 합니다. - 불일치 처리: 클라이언트가 에이전트가 지원하지 않는 확장 버전을 요청하는 경우(예: 클라이언트가
/v2
를 요청하지만 에이전트는/v1
만 지원), 에이전트는 해당 확장에 대한 활성화 요청을 무시해야 합니다(SHOULD). 클라이언트의 로직은 요청된 버전에 명시적으로 연결되어 있으므로 에이전트는 다른 버전으로 "대체"하려고 시도해서는 안 됩니다 (MUST NOT).
검색 가능성 및 게시¶
확장이 유용하려면 다른 개발자가 해당 사양을 찾고 사용 방법을 이해할 수 있어야 합니다.
- 사양 호스팅: 확장 사양 문서는 확장의 URI에서 호스팅되어야 합니다(SHOULD). 이렇게 하면 개발자가 식별자를 간단히 확인하여 설명서에 쉽게 액세스할 수 있습니다.
- 영구 식별자: 끊어진 링크 또는 변경되는 도메인 문제를 방지하기 위해 작성자는 확장 URI에 대해 w3id.org와 같은 영구 식별자 서비스를 사용하는 것이 좋습니다.
- 커뮤니티 레지스트리 (향후): 향후 A2A 커뮤니티는 사용 가능한 확장을 검색하고 찾아볼 수 있는 중앙 레지스트리를 구축할 수 있습니다.
패키징 및 재사용성¶
채택을 촉진하기 위해 확장 로직은 기존 A2A 클라이언트 및 서버 애플리케이션에 쉽게 통합할 수 있는 재사용 가능한 라이브러리로 패키징되어야 합니다.
-
배포: 확장 구현은 해당 언어 생태계에 대한 표준 패키지(예: Python용 PyPI 패키지, TypeScript/JavaScript용 npm 패키지)로 배포되어야 합니다.
-
간단한 통합: 목표는 개발자를 위한 거의 "플러그 앤 플레이" 경험이어야 합니다. 잘 설계된 확장 패키지를 사용하면 개발자가 최소한의 코드로 서버에 추가할 수 있어야 합니다. 예를 들면 다음과 같습니다.
# 가상 Python 서버 통합 from konami_code_extension import CheatCodeHandler from a2a.server import A2AServer, DefaultRequestHandler # 확장은 해당 로직을 처리하기 위해 요청 처리기에 연결됩니다. extension = CheatCodeHandler(description="") extension.add_cheat( code="motherlode", hint="심즈가 급하게 추가 현금이 필요할 때", ) extension.add_cheat( code="thereisnocowlevel", hint="부인할 수도 있지만, 그 소들에 대한 증거는 이미 확보했습니다.", ) request_handler = DefaultRequestHandler( agent_executor=MyAgentExecutor(extension), task_store=InMemoryTaskStore(), extensions=[extension] ) server = A2AServer(agent_card, request_handler) server.run()
보안¶
확장은 A2A 프로토콜의 핵심 동작을 수정하므로 새로운 보안 고려 사항을 도입합니다.
- 입력 유효성 검사: 확장에 의해 도입된 모든 새 데이터 필드, 매개변수 또는 메서드는 구현에 의해 엄격하게 유효성을 검사해야 합니다(MUST). 신뢰를 설정하기 위한 프로토콜 정의 수단이 없는 한 외부 당사자의 모든 확장 관련 데이터를 신뢰할 수 없는 입력으로 처리합니다.
required
확장의 범위:AgentCard
에서 확장을required: true
로 표시할 때 주의하십시오. 이렇게 하면 모든 클라이언트에 대한 하드 종속성이 생성됩니다. 에이전트의 핵심 기능 및 보안 상태에 기본적인 확장(예: 메시지 서명 확장)에만 이 기능을 사용하십시오.- 인증 및 권한 부여: 확장이 새 메서드를 추가하는 경우, 구현은 이러한 메서드가 핵심 A2A 메서드와 동일한 인증 및 권한 부여 검사를 받도록 반드시 보장해야 합니다. 확장은 에이전트의 기본 보안 제어를 우회하는 방법을 제공해서는 안 됩니다 (MUST NOT).