주제와 구독
주제와 구독 (Topic and Subscription)
런타임이 메시지를 전달하는 방식은 두 가지예요. 직접 메시징(direct messaging) 과 브로드캐스트(broadcast) 입니다. 직접 메시징은 1:1 방식이라 발신자가 수신자의 에이전트 ID를 반드시 제공해야 해요. 반면 브로드캐스트는 1:N 방식이라 발신자가 수신자의 에이전트 ID를 제공하지 않아요. 이번 글에서는 브로드캐스트의 핵심 개념인 토픽(topic) 과 구독(subscription) 을 자세히 살펴볼게요.
많은 시나리오가 브로드캐스트에 적합해요. 예를 들어 이벤트 기반 워크플로에서는 에이전트가 항상 누가 자신의 메시지를 처리할지 알지 못하고, 서로 의존성이 없는 에이전트로 워크플로가 구성될 수 있어요.
토픽 (Topic)
토픽은 브로드캐스트 메시지의 범위를 정의해요. 본질적으로 에이전트 런타임은 브로드캐스트 API를 통해 발행·구독(publish-subscribe) 모델을 구현해요. 메시지를 발행할 때는 토픽을 반드시 지정해야 해요. 토픽은 에이전트 ID에 대한 간접(indirection)일 뿐이에요.
토픽은 두 가지 구성 요소로 이뤄져요: 토픽 타입(topic type) 과 토픽 소스(topic source).
Topic = (Topic Type, Topic Source)
에이전트 ID처럼 두 구성 요소가 있는데, 토픽 타입은 보통 애플리케이션 코드가 정의해서 그 토픽이 담당할 메시지의 타입을 표시해요. 예를 들어 GitHub 에이전트가 새 이슈에 대한 메시지를 발행할 때 토픽 타입으로 "GitHub_Issues"를 쓸 수 있어요.
토픽 소스는 토픽 타입 안에서 토픽을 고유하게 식별하는 식별자예요. 보통 애플리케이션 데이터로 정의돼요. 예를 들어 GitHub 에이전트가 "github.com/{repo_name}/issues/{issue_number}"를 토픽 소스로 써서 토픽을 고유하게 식별할 수 있어요. 토픽 소스는 발행자가 메시지의 범위를 제한하고 silo를 만들 수 있게 해 줘요.
토픽 ID는 문자열로 변환되거나 문자열에서 변환될 수 있는데, 그 문자열의 형식은 다음과 같아요:
Topic_Type/Topic_Source
타입은 UTF8이고 영문자(a-z)·숫자(0-9)·밑줄(_)만 포함할 때 유효해요. 유효한 식별자는 숫자로 시작할 수 없고 공백을 포함할 수 없어요. 소스는 UTF8이고 ASCII 32(공백)에서 126(~) 사이의 문자만 포함할 때 유효해요.
구독 (Subscription)
구독은 토픽을 에이전트 ID에 매핑해요. 에이전트 런타임은 구독을 추적하고 그것을 사용해 에이전트에게 메시지를 전달해요.
토픽에 구독이 없으면 그 토픽에 발행된 메시지는 어떤 에이전트에게도 전달되지 않아요. 토픽에 구독이 여러 개면 메시지는 모든 구독을 따라 각 수신 에이전트에게 정확히 한 번씩 전달돼요. 애플리케이션은 에이전트 런타임의 API로 구독을 추가하거나 제거할 수 있어요.
타입 기반 구독 (Type-based Subscription)
타입 기반 구독은 토픽 타입을 에이전트 타입(【에이전트 ID】 참고)에 매핑해요. 정확한 토픽 소스와 에이전트 키를 알지 못해도, 토픽에서 에이전트 ID로의 무한 매핑을 선언해요. 그 메커니즘은 단순해요. 타입 기반 구독의 토픽 타입과 일치하는 아무 토픽이나, 구독의 에이전트 타입과 토픽 소스의 값으로 지정된 에이전트 키를 가진 에이전트 ID로 매핑돼요. Python API에서는 autogen_core.components.TypeSubscription을 사용해요.
Type-Based Subscription = Topic Type --> Agent Type
일반적으로 타입 기반 구독은 구독을 선언하는 선호되는 방식이에요. 이식 가능하고 데이터에 독립적이어서, 개발자가 특정 에이전트 ID에 의존하는 애플리케이션 코드를 쓸 필요가 없어요.
타입 기반 구독의 시나리오
정확한 토픽이나 에이전트 ID가 데이터에 의존적일 때 타입 기반 구독은 많은 시나리오에 적용될 수 있어요. 시나리오는 두 가지 고려 사항으로 나눌 수 있어요: (1) 단일 테넌트인지 멀티 테넌트인지, (2) 테넌트당 단일 토픽인지 여러 토픽인지. 테넌트(tenant)는 보통 특정 사용자 세션이나 특정 요청을 처리하는 에이전트 집합을 가리켜요.
단일 테넌트, 단일 토픽
이 시나리오에서는 전체 애플리케이션에 테넌트 하나와 토픽 하나만 있어요. 가장 단순한 시나리오로, 커맨드라인 도구나 단일 사용자 애플리케이션 같은 많은 경우에 쓸 수 있어요.
이 시나리오에 타입 기반 구독을 적용하려면, 각 에이전트 타입마다 타입 기반 구독을 하나씩 만들고 모든 타입 기반 구독에 같은 토픽 타입을 사용해요. 발행할 때는 항상 같은 토픽, 즉 같은 토픽 타입과 토픽 소스를 사용해요.
예를 들어 "triage_agent", "coder_agent", "reviewer_agent" 세 가지 에이전트 타입이 있고 토픽 타입이 "default"라면, 다음 타입 기반 구독을 만들어요:
# Type-based Subscriptions for single-tenant, single topic scenario
TypeSubscription(topic_type="default", agent_type="triage_agent")
TypeSubscription(topic_type="default", agent_type="coder_agent")
TypeSubscription(topic_type="default", agent_type="reviewer_agent")
위 타입 기반 구독으로 모든 메시지에 같은 토픽 소스 "default"를 사용해요. 그래서 토픽은 항상 ("default", "default")예요. 이 토픽에 발행된 메시지는 위 모든 타입의 모든 에이전트에게 전달돼요. 구체적으로는 다음 에이전트 ID로 보내져요:
# The agent IDs created based on the topic source
AgentID("triage_agent", "default")
AgentID("coder_agent", "default")
AgentID("reviewer_agent", "default")
그 ID의 에이전트가 없으면 런타임이 만들어요.
단일 테넌트, 여러 토픽
이 시나리오에서는 테넌트가 하나뿐인데, 어떤 에이전트가 어떤 토픽을 처리하는지 제어하고 싶어요. silo를 만들고 서로 다른 에이전트가 서로 다른 토픽 처리에 전문화되기를 원할 때 유용해요.
이 시나리오에 타입 기반 구독을 적용하려면, 각 에이전트 타입마다 타입 기반 구독을 하나씩 만들되 서로 다른 토픽 타입을 사용해요. 여러 에이전트 타입이 같은 토픽을 공유하기를 원하면 같은 토픽 타입을 여러 에이전트 타입에 매핑할 수 있어요. 토픽 소스는 발행할 때 여전히 모든 메시지에 같은 값을 사용해요.
위 예시를 같은 에이전트 타입으로 계속해서, 다음 타입 기반 구독을 만들어요:
# Type-based Subscriptions for single-tenant, multiple topics scenario
TypeSubscription(topic_type="triage", agent_type="triage_agent")
TypeSubscription(topic_type="coding", agent_type="coder_agent")
TypeSubscription(topic_type="coding", agent_type="reviewer_agent")
위 타입 기반 구독으로, ("triage", "default") 토픽에 발행된 모든 메시지는 "triage_agent" 타입의 에이전트에게 전달되고, ("coding", "default") 토픽에 발행된 모든 메시지는 "coder_agent"와 "reviewer_agent" 타입의 에이전트에게 전달돼요.
멀티 테넌트 시나리오
단일 테넌트 시나리오에서 토픽 소스는 항상 같은 값(예: "default")이에요 — 애플리케이션 코드에 하드코딩돼 있죠. 멀티 테넌트 시나리오로 넘어가면 토픽 소스가 데이터에 의존적이 돼요.
참고: 멀티 테넌트 시나리오에 있다는 좋은 신호는 같은 에이전트 타입의 인스턴스가 여러 개 필요하다는 것이다. 예를 들어 개인 데이터를 격리하기 위해 서로 다른 사용자 세션을 서로 다른 에이전트 인스턴스가 처리하게 하고 싶거나, 무거운 워크로드를 같은 에이전트 타입의 여러 인스턴스에 분산해서 동시에 처리하게 하고 싶을 수 있다.
위 예시를 계속해서, 특정 GitHub 이슈를 처리하는 전용 에이전트 인스턴스를 만들고 싶다면, 토픽 소스를 그 이슈의 고유 식별자로 설정해야 해요.
예를 들어 "triage_agent" 에이전트 타입에 대한 타입 기반 구독이 하나 있다고 해 볼게요:
TypeSubscription(topic_type="github_issues", agent_type="triage_agent")
("github_issues", "github.com/microsoft/autogen/issues/1") 토픽에 메시지가 발행되면, 런타임은 그 메시지를 ("triage_agent", "github.com/microsoft/autogen/issues/1") ID의 에이전트에게 전달해요. ("github_issues", "github.com/microsoft/autogen/issues/9") 토픽에 메시지가 발행되면, 런타임은 그 메시지를 ("triage_agent", "github.com/microsoft/autogen/issues/9") ID의 에이전트에게 전달해요.
에이전트 ID가 데이터에 의존적이고, 런타임은 그 에이전트가 없으면 새 인스턴스를 만들어요. 테넌트당 여러 토픽을 지원하려면, 단일 테넌트·여러 토픽 시나리오처럼 서로 다른 토픽 타입을 사용하면 돼요.
더 알아보기 (Learn more)
- 대화 - 메시지와 통신 — 직접 메시징과 브로드캐스트 사용법
- 에이전트 정체성과 수명주기
- Hand-off 설계 패턴 — pub-sub 기반 멀티에이전트 예시