5. 서버 시작하기

5. 서버 시작하기

이제 Agent Card와 Agent Executor가 있으니, A2A 서버를 설정하고 시작할 수 있어요. A2A 서버를 설정하기 위해 Python SDK는 라우트 팩토리와 헬퍼 함수(create_agent_card_routes, create_jsonrpc_routes, create_rest_routes)를 제공해요. 라우트 팩토리를 사용해 A2A 서버의 서비스용 라우트를 만들어요. 이 라우트들은 Starlette와 FastAPI 같은 인기 프레임워크에 기본적으로 연결할 수 있어서, 인증, 로깅, 기타 기능을 더 잘 제어할 수 있어요. 이 튜토리얼에서는 Uvicorn과 함께 Starlette를 사용할게요.

출처: 문서

본문

Helloworld의 서버 설정

__main__.py를 다시 보면서 서버가 어떻게 초기화되고 시작되는지 살펴볼게요.

import uvicorn

from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import (
    create_agent_card_routes,
    create_jsonrpc_routes,
)
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import (
    AgentCapabilities,
    AgentCard,
    AgentInterface,
    AgentSkill,
)
from agent_executor import (
    HelloWorldAgentExecutor,  # type: ignore[import-untyped]
)
from starlette.applications import Starlette

if __name__ == '__main__':
    # Defines the abilities or functions that agent can perform.
    skill = AgentSkill(
        id='echo_bot',
        name='Echo Bot',
        description='An example agent that acknowledges client request and responds with a "Hello World" message.',
        input_modes=['text/plain'],
        output_modes=['text/plain'],
        tags=['a2a', 'echo-example'],
        examples=['hi', 'how are you'],
    )
    # Defines an optional additional skill for the agent that is not visible in the public card.
    extended_skill = AgentSkill(
        id='echo_bot_super_mode',
        name='Echo Bot (Super Mode)',
        description='An extended version of Echo Bot that responds with extra enthusiasm!',
        tags=['a2a', 'echo-example', 'extended'],
        examples=['super hi', 'give me a super hello'],
    )

    # Define a public-facing agent card that allows clients to discover your agent's capabilities.
    public_agent_card = AgentCard(
        # Basic identity information of A2A server
        name='Hello World Agent',  # Identity
        description='Just a hello world agent',
        version='0.0.1',
        # Default Media Types for the agent's interactions
        default_input_modes=['text/plain'],  # Supported media types
        default_output_modes=['text/plain'],
        # Supported A2A features (like streaming or extended config)
        capabilities=AgentCapabilities(streaming=True, extended_agent_card=True),
        # Ordered list of endpoints and protocols where the service can be reached
        supported_interfaces=[
            AgentInterface(
                protocol_binding='JSONRPC',
                url='http://127.0.0.1:9999',
                protocol_version='1.0',
            )
        ],
        # The list of AgentSkill objects that this agent offers
        skills=[skill],
        # Optional attributes (omitted here for simplicity):
        # icon_url                         -> A URL to an icon representing the agent
    )

    # Defines the authenticated extended agent card with
    # extended skills that are visible only to authenticated users
    extended_agent_card = AgentCard(
        name='Hello World Agent - Extended Edition',
        description='The full-featured hello world agent for authenticated users.',
        version='0.0.2',
        default_input_modes=['text/plain'],
        default_output_modes=['text/plain'],
        capabilities=AgentCapabilities(streaming=True, extended_agent_card=True),
        supported_interfaces=[
            AgentInterface(
                protocol_binding='JSONRPC',
                url='http://127.0.0.1:9999',
                protocol_version='1.0',
            )
        ],
        skills=[
            skill,
            extended_skill,
        ],  # Both skills for the extended card
    )
    # The RequestHandler processes incoming requests and manages tasks
    request_handler = DefaultRequestHandler(
        # Agent executor handles the execution of the client requests
        agent_executor=HelloWorldAgentExecutor(),
        # The task_store is used to store and manage tasks
        task_store=InMemoryTaskStore(),
        # Public agent card for unauthenticated users
        agent_card=public_agent_card,
        # Extended agent card for authenticated users
        extended_agent_card=extended_agent_card,
    )
    # Creating the routes for the A2A server
    # These routes handle the incoming requests from the clients
    # and the outgoing responses to the clients
    routes = []

    # Create routes for the agent card
    routes.extend(create_agent_card_routes(public_agent_card))

    # Create routes for the JSONRPC protocol
    # Alternatively, you can choose GRPC or HTTP_JSON as protocol bindings
    # based on your requirements
    routes.extend(create_jsonrpc_routes(request_handler, '/'))

    # Create a web app with the defined routes
    # Here we are using Starlette, a lightweight ASGI web framework to serve the agent
    # Alternatively, you can choose FastAPI or other ASGI frameworks
    app = Starlette(routes=routes)

    # Run the app
    # Uvicorn is a production-ready ASGI HTTP server
    uvicorn.run(app, host='127.0.0.1', port=9999)

하나씩 풀어볼게요.

DefaultRequestHandler:

  • SDK는 DefaultRequestHandler를 제공해요. 이 핸들러는 여러분의 AgentExecutor 구현(HelloWorldAgentExecutor), TaskStore(InMemoryTaskStore), 그리고 공개·확장 AgentCard 객체를 받아요.
  • 들어오는 A2A RPC 호출을 실행기의 적절한 메서드(예: execute 또는 cancel)로 라우팅해요.
  • TaskStore는 DefaultRequestHandler가 태스크의 수명주기를 관리하는 데 사용해요. 특히 상태를 가진 상호작용, 스트리밍, 재구독에 필요하죠. 실행기가 단순해도 핸들러는 태스크 저장소가 필요해요.
  • agent_card는 요청을 처리할 때 에이전트의 선언된 역량을 검증할 수 있도록 핸들러에 전달돼요. 예를 들어 스트리밍이나 푸시 알림이 지원되는지 처리 전에 확인해요.
  • extended_agent_card는 인증된 클라이언트에게 GetExtendedAgentCard RPC 메서드로 서빙할 수 있도록 전달돼요.

create_agent_card_routes와 create_jsonrpc_routes:

  • create_agent_card_routes(public_agent_card)는 공개 발견을 위해 /.well-known/agent-card.json 엔드포인트에 Agent Card를 노출하는 Starlette 라우트를 반환해요.
  • create_jsonrpc_routes(request_handler, '/')는 들어오는 모든 A2A JSON-RPC 메서드 호출을 request_handler에 위임해 처리하는 Starlette 라우트를 반환해요.
  • 이 라우트 목록들은 결합되어 표준 Starlette 애플리케이션에 전달돼요.

uvicorn.run(app, ...):

  • 구성된 Starlette 앱은 uvicorn.run()으로 실행되어 에이전트를 HTTP로 접근 가능하게 해요.
  • host='127.0.0.1'은 서버를 로컬 머신에서만 접근 가능하게 해요.
  • port=9999는 리슨할 포트를 지정해요. 이는 AgentCard의 supported_interfaces에 정의된 엔드포인트와 일치해요.

Helloworld 서버 실행하기

터미널에서 a2a-samples 디렉터리로 이동하고(아직 거기에 없다면) 가상 환경이 활성화되어 있는지 확인해요. Helloworld 서버를 실행하려면:

# from the a2a-samples directory
python samples/python/agents/helloworld/__main__.py

서버가 실행 중임을 나타내는 다음과 유사한 출력이 보여야 해요:

INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:9999 (Press CTRL+C to quit)

여러분의 A2A Helloworld 에이전트가 이제 실행되어 요청을 기다리고 있어요! 다음 단계에서는 그와 상호작용해 볼게요.

더 알아보기 (Learn more)