Chapter 10 · System-Level Patterns for Production Readiness

에이전트가 사는 도시

『Agentic Architectural Patterns for Building Multi-Agent Systems』 10장 — Ali Arsanjani, Juan Pablo Bustos, Thomas Kurian

앞선 장들에서 우리는 에이전틱 AI의 구성 블록을 꼼꼼히 뜯어보고 조립했다. 기억과 추론을 갖춘 개별 에이전트를 설계했고, 복잡한 과업에서 협업하게 했고, 견고하고 책임 있게 만드는 해법을 마련했다. 사실상 유능하고 지적인 에이전트 행위자를 짓는 길을 닦은 셈이다. 이제 그들이 살고 활동할 맥락적 세계를 지어야 한다.

00

A strategic guide · architecture before implementation

전략 지도 — 에이전트의 마음에서 도시로

멀티 에이전트 시스템은 에이전트의 모음 이상이다. 여러모로 현대의 마이크로서비스 아키텍처를 닮았으나 결정적 차이가 하나 있다. 경직된 코드를 실행하는 정적 서비스 대신, 그 구성요소가 추론하고 목표를 좇으며 자율적으로 행동하는 에이전트라는 점이다.

효과적으로 협업하고 기업 등급 애플리케이션을 구동하려면 이 분산된 지능에는 조율과 정책 준수와 공유 인프라라는 완결된 단위가 필요하다. 그래서 초점이 에이전트 자신에서 그것을 감싸는 총체적 시스템 아키텍처로 옮겨간다.

이 장의 패턴들은 모든 기업 애플리케이션의 협상 불가한 요구에 답한다.

  • 서비스와 에이전트는 서로를 어떻게 동적으로 발견하는가
  • 자율 에이전트에 대한 보안·신원·접근 통제를 어떻게 강제하는가
  • 규제 준수 규칙을 실시간으로 어떻게 감시하고 집행하는가
  • 시스템은 외부 사건에 비동기적으로, 대규모로 어떻게 반응하는가
외부 요청 · 파트너 웹훅 EXTERNAL 보안 경계 · SECURITY PERIMETER API 게이트웨이 P3 · 에이전트 인증과 인가 애플리케이션 환경 · AGENTS 에이전트 A InventoryAgent 에이전트 B CustomsPaymentAgent 에이전트 C 공유 인프라 중앙 레지스트리 P1 · 발견과 디렉터리 “전화번호부” 메시지 버스 · 이벤트 스트림 P4 · 반응의 등뼈 “중추신경계” 거버넌스 서비스 P2 · 감독과 준수 정책 엔진 어느 에이전트에도 속하지 않는다 · 모든 에이전트가 안전하고 효율적으로 작동할 환경을 제공한다

〈그림 10.1〉 시스템 통합 아키텍처. 노란 선이 보안 경계이고, 아래 셋이 도시의 공용 기반시설이다.

얼마나 갖추고 시작해야 하는가

이 기초 패턴들 앞에서 흔히 나오는 질문이다. 답은 전적으로 에이전틱 AI 여정의 어디에 서 있느냐에 달렸다.

결정적이지도 않은 단일 에이전트를 위해 고가용성 도구 레지스트리를 구현하는 것은 과잉 설계다. 반대로 민감한 데이터를 다루는 멀티 에이전트 시스템을 견고한 인증과 규제 준수 없이 배포하는 것은 직무 유기다.

성숙도 단계역량가능해지는 패턴요약
3 · 에이전트 준비된 LLM기초 모델과 도구보안과 반응성에 대한 최초의 구상 — 기본 IAM(서비스 계정)과 단순 반응성(웹훅)어떤 에이전트를 배포하기 전에, 보안(IAM 통합)과 통신(이벤트 인프라)에 관한 기초적 결정이 플랫폼 설계의 일부가 되어야 한다.
4 · 단일 에이전트 시스템운영 등급의 단일 에이전트에이전트 인증과 인가 · 이벤트 기반 반응성 · 실시간 규제 준수 모니터링첫 에이전트가 운영에 들어가는 순간 보안은 협상 불가가 된다. 에이전트는 환경에 반응해야 하고, 민감한 과업을 다룬다면 준수 모니터링이 필수가 된다.
5 · 멀티 에이전트 시스템협업하는 에이전트 생태계도구·에이전트 레지스트리둘 이상의 에이전트가 동적으로 협업해야 하는 순간 레지스트리가 아키텍처의 주춧돌이 된다. 시스템 전체에 걸친 발견과 느슨한 결합을 가능하게 한다.

〈표 10.1〉 시스템 수준 패턴과 GenAI 성숙도 모델의 매핑

네 개의 기반시설

Perimeter

API 게이트웨이

시스템으로 들어오는 모든 요청의 단일하고 요새화된 진입점이다. 서명·만료·수신자 클레임·스코프를 검사하고 토큰 교체를 강제해, 안전하고 최소 권한인 에이전트 간 통신을 보장한다.

Backbone

메시지 버스 · 이벤트 스트림

비동기 통신의 중추신경계다. 에이전트는 대개 지속 소비자로 돌거나 장기 스트림 연결로 이벤트를 감지한다. 구독한 토픽에 새 이벤트가 오면 감지 구성요소가 촉발되어 즉시 추론 루프가 시작된다.

Directory

중앙 레지스트리

시스템의 “전화번호부”다. 발견 가능한 모든 에이전트와 도구가 여기에 자기 역량과 엔드포인트를 등록한다. 동적 발견이 가능해진다.

Oversight

거버넌스 서비스

에이전트 행동을 관찰하고 통치하는 전담 계층이다. 기업 표준을 맞추려면 행동 수준(예: 대출 승인), 행 수준(특정 레코드), 필드 수준(예: PII·PHI 차단)에서 제약을 강제해야 한다. 어떤 작업이 진행되기 전에 세밀한 준수를 보장한다.

넷이 한 줄로 엮인다 — 자동화된 공급망

P4 · 이벤트외부 물류 파트너의 웹훅 메시지가 메시지 버스의 shipping_events 토픽에 게시된다. 컨테이너가 항구에 도착했다는 사건이다.
P4 · 이벤트이 토픽을 구독한 InventoryAgent가 새 메시지에 촉발되어 움직인다. 목표는 컨테이너 내용물을 검증하고 재고를 갱신하는 것이다.
P3 · 인증적하목록을 얻으려면 ShippingAPI에 접근해야 한다. 먼저 서비스 계정 자격증명으로 IAM 시스템에 액세스 토큰을 요청한다.
P3 · 인가토큰을 제시하며 API를 호출한다. API 게이트웨이가 호출을 가로채 토큰을 검증하고 그 에이전트에게 read:manifest 권한이 있음을 확인한다.
P1 · 발견적하목록 처리 후 재무 부서에 알려야 한다고 판단한다. 레지스트리에 “관세 결제를 처리할 수 있는 에이전트를 찾아라”고 질의하고, CustomsPaymentAgent의 엔드포인트를 받는다.
P2 · 준수결제 개시 요청을 보낸다. ComplianceMonitor가 메시지 버스에서 이 이벤트를 가로채, 결제 금액을 정책 엔진과 대조하고 벤더가 승인 목록에 있는지 확인한 뒤 준수 확인 이벤트를 기록한다.
완료CustomsPaymentAgent가 검증된 요청을 받아 안전하게 과업을 완수한다.

Resiliency in action · 실패 경로

4단계에서 토큰이 만료됐다면 어떻게 되는가.

실패ShippingAPI401 Unauthorized로 호출을 거부한다.
복구 — 죽는 대신 에이전트의 내부 로직이 이 특정 오류 코드를 잡아낸다. 자동으로 IAM에 재인증해 새 토큰을 얻고 요청을 재시도한다.
결과 — 워크플로가 자동으로 재개된다. 시스템 수준의 보안 패턴과 에이전트 수준의 견고성이 맞물려 흔한 중단을 처리하는 모습이다.

도입은 단계적으로

Phase 1
기초를 지킨다
에이전트 인증과 인가 운영에 들어가는 맨 첫 에이전트(4단계)에 보안은 무엇보다 중요하다. 첫날부터 기업 IAM 시스템과 통합하라. 에이전트를 일급 서비스 신원으로 다뤄야 한다.
Phase 2
반응성과 감독
이벤트 기반 반응성 · 실시간 규제 준수 모니터링 시스템이 더 결정적인 과업을 맡게 되면 확장성을 위해 이벤트 버스로 구성요소를 분리하라. 민감 데이터·PII·금융 거래가 얽힌 모든 워크플로에는 준수 모니터링을 도입한다.
Phase 3
생태계를 키운다
도구·에이전트 레지스트리 진정한 멀티 에이전트 시스템(5단계)으로 넘어갈 준비가 됐을 때, 복잡성을 관리하고 에이전트 간 동적 협업을 가능하게 하려면 레지스트리가 필요하다.

〈표 10.2〉 시스템 수준 패턴의 단계별 도입

P1

Discovery · the yellow pages

도구·에이전트 레지스트리 — 도시의 전화번호부

P1

Tool and Agent Registry

도구·에이전트 레지스트리

LV 5발견

문제의 배경

에이전틱 생태계가 자라면 전문 에이전트와 가용 도구의 수가 빠르게 늘어난다. 에이전트들이 서로의 기능을 미리 아는 정적이고 하드코딩된 방식은 부서지기 쉽고 유지가 불가능해진다.

맥락

느슨한 결합을 촉진하고 시스템이 진화하도록 하려는 모든 멀티 에이전트 또는 도구 중심 시스템에 근본적이다. 에이전트가 설계 시점에 명시적으로 프로그래밍되지 않은 역량을 동적으로 발견하고 활용하게 하는 기반이다.

문제

새 도구와 에이전트가 끊임없이 추가되는 크고 진화하는 시스템에서, 에이전트가 과업 완수에 필요한 역량을 갖춘 올바른 도구나 다른 에이전트를 어떻게 찾을 것인가.

해법 — 세 단계

  • 등록 — 각 도구와 에이전트가 get_supplier_quote 같은 역량 이름, 무엇을 하는지에 대한 자연어 설명, 입출력 스키마, 네트워크 엔드포인트를 등록한다.
  • 발견 — 역량이 필요하면 하드코딩된 호출 대신 레지스트리에 질의한다. 이름으로 찾을 수도 있고, 더 강력하게는 의미로 찾을 수도 있다(예: 항공편을 예약할 수 있는 도구를 찾아라).
  • 호출 — 레지스트리가 일치하는 서비스와 엔드포인트 목록을 돌려준다. 요청한 에이전트가 이 정보로 서비스를 직접 호출한다.

이 패턴은 역량에 대한 지식을 그 구현으로부터 효과적으로 분리한다.

사례 — 동적 조달 시스템

ProcurementAgent가 특정 부품의 가격 견적을 받아야 한다. 회사에는 우대 벤더용 내부 API와 공개 사이트용 웹 스크래핑 도구 등 여러 방법이 있다.

01등록PreferredVendorAPIToolWebScrapingQuoteTool이 각각 get_quote 역량을 광고하며 레지스트리에 자신을 등록한다
02발견 — “부품 #XYZ의 최저가를 구하라”는 과업을 받는다. LLM에 계획을 세우게 하고, 레지스트리에 질의한다. get_quote 역량을 가진 모든 도구를 찾아라
03호출 — 레지스트리가 두 도구의 엔드포인트를 돌려준다. 에이전트의 추론 로직이 둘 다 병렬로 호출해 최저가를 찾기로 결정하고, 레지스트리가 제공한 스키마에 맞춰 각각 요청을 구성해 실행한다

다음 달에 InternationalVendorAPITool이 추가되어도 ProcurementAgent는 한 줄도 고칠 필요가 없다. 새 도구가 등록되는 즉시 에이전트가 그것을 발견해 자동으로 쓴다.

구현 예시 · Python
# --- 1. 중앙 도구 레지스트리 정의 ---
class ToolRegistry:
    def __init__(self):
        # 레지스트리는 도구를 역량으로 색인해 저장한다
        self.registry = {}

    def register_tool(self, capability, name, description, endpoint, schema):
        self.registry.setdefault(capability, []).append({
            "name": name, "description": description,
            "endpoint": endpoint, "schema": schema
        })

    def discover(self, capability):
        """역량으로 도구를 발견한다."""
        return self.registry.get(capability, [])

GLOBAL_REGISTRY = ToolRegistry()
GLOBAL_REGISTRY.register_tool("get_quote", "PreferredVendorAPITool", ...)
GLOBAL_REGISTRY.register_tool("get_quote", "WebScrapingQuoteTool", ...)

# --- 4. 에이전트 구현 ---
procurement_agent = ProcurementAgent(registry=GLOBAL_REGISTRY)
procurement_agent.get_best_price("Part #XYZ")

장점

  • 모듈성과 확장성 — 고도로 모듈적이고 확장 가능한 아키텍처를 촉진한다. 기존 에이전트의 코드를 한 줄도 바꾸지 않고 시스템에 새 역량을 더할 수 있다.
  • 회복력 — 특정 도구나 에이전트 인스턴스가 죽으면 레지스트리가 대안을 제공해 시스템이 장애를 우회하게 한다.

단점

  • 단일 실패 지점 — 레지스트리 자체가 단일 실패 지점이 될 수 있다. 고가용성과 회복력을 갖추도록 설계해야 한다.
  • 부담 — 발견을 위한 네트워크 홉이 하나 더 붙어 약간의 지연이 생긴다. 레지스트리 자체도 유지·관리해야 한다.

구현 지침

단순한 경우라면 공유 데이터베이스나 잘 관리된 JSON 파일로도 레지스트리 노릇을 할 수 있다. 기업 시스템에는 Consul이나 etcd 같은 전용 서비스 디스커버리 도구가 더 견고하다. 레지스트리 성공의 열쇠는 역량을 서술하는 잘 정의되고 풍부한 메타데이터 스키마다.

P2

Governance · adjudication before action

실시간 규제 준수 모니터링 — 사후 탐지가 아니라 사전 차단

P2

Real-Time Compliance Monitoring

실시간 규제 준수 모니터링

LV 4거버넌스

문제의 배경

금융·의료·법률처럼 규제받는 산업에서 에이전틱 시스템은 “블랙박스”일 수 없다. 그 행동은 감사 가능해야 하고 외부 규제와 내부 정책을 엄격히 지켜야 한다.

맥락

민감 데이터를 다루거나, 판돈 큰 거래를 실행하거나, GDPR·HIPAA·금융 준수 규칙 같은 규제가 지배하는 영역에서 작동하는 모든 에이전틱 시스템에 필수다.

문제

자율 에이전트의 행동이 복잡하고 동적인 규칙 집합을 지속적으로 준수하도록, 그래서 사후에 탐지하는 것이 아니라 위반이 일어나기 전에 막도록 어떻게 보장할 것인가.

해법 — 네 단계

  • 중앙 정책 엔진 — 모든 규칙과 규제를 OPA(Open Policy Agent) 같은 정책 엔진으로 기계가 읽을 수 있는 형식으로 정의한다.
  • 이벤트 가로채기 — 모니터가 시스템 전역 이벤트 버스를 구독하거나 결정적 행동의 관문 노릇을 한다. 모든 유의미한 이벤트(데이터 요청, 외부와의 통신 등)를 검사한다.
  • 실시간 판정 — 이벤트마다 정책 엔진에 질의해 표준 인가를 넘어서는 맥락 인지적 제약을 검증한다. 인가(AuthZ)가 에이전트가 자원에 접근할 수 있는지(권한)를 본다면, 준수 모니터는 현재 상태에 근거해 접근해도 되는지를 본다.
  • 집행 — 준수하면 진행시킨다. 정책을 위반하면 행동을 차단하고 준수 위반을 기록하며 사람 감독자에게 경보를 보낼 수 있다.

The distinction

할 수 있는가 대 해도 되는가

“에이전트 X는 레코드를 읽을 권한이 있다. 그런데 이 특정 연구 목적에 대해 유효한 사용자 동의를 갖고 있는가?
인가는 앞의 물음에, 준수 모니터는 뒤의 물음에 답한다.

사례 — HIPAA를 지키는 의료 에이전트

ResearchQueryAgent가 임상 연구를 위해 특정 조건에 맞는 환자 기록을 찾는 과업을 받았다.

01행동 — 에이전트가 환자 #12345의 환자 데이터베이스 접근을 시도한다
02가로채기HIPAAComplianceAgent가 이 데이터 접근 요청을 가로챈다
03판정 — 요청의 맥락으로 정책 엔진을 확인한다.
규칙 — 환자 기록은 “임상 연구”에 대한 명시적이고 감사 가능한 동의가 파일에 있을 때만 접근할 수 있다.
확인 — 동의 데이터베이스를 조회하니 환자 #12345는 “청구 목적”에만 동의했다
04집행 — 정책 엔진이 DENY를 반환한다. HIPAAComplianceAgentDB 질의를 차단해 HIPAA 위반을 막는다. 거부된 시도를 기록하고 검토를 위한 경보를 올린다
구현 예시 · Python
# --- 모의 데이터베이스 / 서비스 ---
PATIENT_CONSENT_DB = {
    "Patient-12345": ["billing"],
    "Patient-67890": ["billing", "clinical_research"]
}

def policy_engine_check(action: str, resource_id: str, consent_types: list) -> bool:
    """행동이 준수하는지 확인한다. ALLOW면 True, DENY면 False."""
    if action == "clinical_research_query":
        return "clinical_research" in consent_types
    return True

class HIPAAComplianceAgent:
    """준수 에이전트·모니터 노릇을 한다.
    행동을 가로채 정책 엔진과 대조한다."""

    def intercept(self, agent_name: str, action: str, patient_id: str) -> dict:
        """행동을 가로채고 정책을 확인해 결정을 집행한다."""
        consents = PATIENT_CONSENT_DB.get(patient_id, [])
        allowed  = policy_engine_check(action, patient_id, consents)

        if not allowed:
            return {"decision": "DENY",
                    "reason": f"No consent for {action} on {patient_id}"}
        return {"decision": "ALLOW"}

장점

  • 신뢰와 안전 — 신뢰를 쌓고 시스템이 안전하고 합법적으로 작동하게 하는 데 필수다. 모든 행동에 대한 감사 가능한 추적을 제공한다.
  • 동적 거버넌스에이전트를 재배포하지 않고 중앙 엔진에서 정책을 갱신할 수 있어, 새 규제에 시스템이 빠르게 적응한다.

단점

  • 성능 부담 — 모든 행동을 정책 엔진과 대조하면 지연이 붙는다. 민감하거나 결정적인 작업에 신중히 적용해야 한다.
  • 복잡도 — 별도의 정책 엔진을 세우고 유지해야 하며, 세심하게 다듬은 규칙 집합이 필요하다.

구현 지침

Rego(OPA용) 같은 표준 정책 언어를 쓰기를 강력히 권한다. 효율을 위해 모든 행동을 다 확인할 필요는 없다. 데이터 저장소 접근, 외부 API, 사용자와의 통신처럼 결정적 상호작용에 정책 “길목(choke point)”을 만드는 데 집중하라.

P3

Security · the non-negotiable

에이전트 인증과 인가 — 너는 누구이며 무엇을 해도 되는가

준수 모니터링이 어떤 행동이 허용되는가를 통치한다면, 그 규칙은 흔히 누가 그 행동을 하는가에 근거한다. 이 확인이 안전하려면 시스템이 에이전트의 자칭 신원을 그냥 믿어서는 안 된다. 검증 가능하게 증명할 수 있어야 한다.

P3

Agent Authentication and Authorization

에이전트 인증과 인가

LV 4보안

문제의 배경

에이전트가 시스템·사용자·조직을 대신해 자율적으로 행동할 수 있게 되면 보안이 무엇보다 중요해진다. 보안되지 않은 에이전트는 취약점 정도가 아니라 애플리케이션에 대한 실존적 위험이다. 민감 데이터를 유출하거나, 사기 거래를 실행하거나, 시스템 전체에 피해를 주도록 조작될 수 있다.

따라서 에이전트에 의미 있는 과업을 맡기기 전에 두 가지 근본 물음에 암호학적 확실성으로 답할 수 있어야 한다. 이 에이전트는 누구인가(인증), 그리고 이 에이전트는 무엇을 해도 되는가(인가).

해법 — 두 축

에이전틱 시스템을 견고한 IAM(신원·접근 관리) 프레임워크와 통합해, 에이전트를 사용자나 서비스처럼 디지털 신원을 가진 일급 시민으로 다룬다.

  • 인증 · 신원 확인 — 배포될 때 각 에이전트에 고유하고 검증 가능한 자격증명을 발급한다. 대개 짧은 수명의 암호학적 토큰(예: JWT)을 생성할 수 있는 서비스 계정이다. 에이전트가 시스템의 다른 부분에 보내는 모든 요청은 자기 토큰으로 서명돼야 하고, 받는 서비스가 그 토큰을 검증해 신원을 확인한다.
  • 인가 · 권한 집행 — 인증된 뒤에는 무엇이 허용되는지 확인해야 한다. RBAC(역할 기반 접근 통제)로 에이전트에 역할(billing_analyst, read_only_reporter 등)을 배정하고, 권한은 개별 에이전트가 아니라 역할에 부여한다. 요청이 오면 자원 서버가 그 역할이 해당 행동에 필요한 권한을 갖는지 확인한다.

High-security enhancements

최대한의 무결성이 요구되는 환경에서는 표준 OAuth 2.0 클라이언트 자격증명 흐름회전하는 JWKS로 검증되는 서명된 JWT를 결합하는 경우가 많다. 나아가 상호 TLS(mTLS)를 강제해 전송 계층에서 클라이언트 에이전트와 서버 양쪽을 인증함으로써, 토큰 가로채기를 막고 종단 간 신뢰를 보장할 수 있다.

사례 — 여러 부서의 분석 시스템

중앙의 CustomerDataAgent가 주 고객 데이터베이스를 지킨다. SalesAgentMarketingAgent도 있다.

01인증SalesAgent가 고객의 구매 이력을 얻으려 한다. 서비스 계정으로 JWT를 생성해 요청 헤더에 넣는다. CustomerDataAgent의 API 게이트웨이가 토큰 서명을 검증해 요청이 정당하게 SalesAgent에서 왔음을 확인한다
02인가 — 신원을 확인한 게이트웨이가 역할 sales_role을 확인한다. 접근 통제 목록을 보니 이 역할은 purchase_historycontact_info 필드를 읽을 수 있다
03제한 — 반면 MarketingAgent(marketing_role)는 익명화·집계된 데이터만 읽을 수 있다. SalesAgent가 결제 정보 같은 제한 필드에 접근하려 하면 인가 확인이 실패하고 403 Forbidden으로 거부된다
구현 예시 · Python
ROLE_PERMISSIONS = {
    "sales_role":     ["read_purchase_history", "read_contact_info"],
    "marketing_role": ["read_aggregated_data"]
}

class APIGateway:
    def handle(self, token: str, action: str):
        # 1) 인증 — 토큰 서명과 만료를 검증한다
        claims = self.validate_jwt(token)
        if not claims:
            return {"status": 401, "error": "Unauthorized"}

        # 2) 인가 — 역할에 그 권한이 있는지 확인한다
        role = claims["role"]
        if action not in ROLE_PERMISSIONS.get(role, []):
            return {"status": 403, "error": "Forbidden"}

        return self.forward_to_service(claims, action)

장점

  • 보안 — 사칭을 막고 최소 권한 원칙을 보장해, 에이전트가 반드시 필요한 행동만 하게 한다.
  • 감사 가능성어느 에이전트가 언제 어떤 행동을 했는지 명확하고 감사 가능한 로그를 만든다.

단점

  • 인프라 복잡도 — 서비스 계정, 토큰 발급, 정책 정의를 포함해 제대로 된 IAM 시스템을 세우고 관리해야 한다. 운영 부담이 는다.
  • 개발 부담 — 에이전트 개발자가 코드에서 토큰 처리와 관리를 올바로 구현해야 한다.

구현 지침 — 세 가지

1. 바퀴를 다시 발명하지 말라. 자체 인증·인가 프로토콜을 구현하는 것은 흔한 안티패턴이며 보안 사고로 이어지는 경우가 많다. 검증된 표준을 쓰라. 현대의 업계 표준은 인가에 OAuth 2.0, 인증에 OIDC다.

2. M2M 흐름을 이해하라. 에이전트는 자동화된 서비스라 비밀번호를 입력할 사람이 없다. 이 시나리오에 맞는 OAuth 2.0 흐름은 클라이언트 자격증명 흐름이다.

  • 설정 — 에이전트를 중앙 인가 서버(Okta, Microsoft Entra ID, Google IAM 등)에 클라이언트로 등록하고 client_idclient_secret을 받는다
  • 토큰 요청 — 보호된 자원에 접근할 때 이 둘을 인가 서버의 토큰 엔드포인트에 제시한다
  • 토큰 발급 — 서버가 자격증명을 검증하고 짧은 수명의 액세스 토큰(대개 JWT)을 발급한다
  • API 호출 — 에이전트가 이 토큰을 요청의 Authorization 헤더에 넣는다
  • 검증 — 자원 서버(또는 앞단의 API 게이트웨이)가 토큰의 진정성과 만료를 검증하고, 토큰에 딸린 스코프로 그 행동을 인가한다

3. API 게이트웨이로 집행을 중앙화하라. 모든 에이전트가 각자 토큰 검증 로직을 구현하는 대신 게이트웨이에 몰아라. 게이트웨이가 들어오는 모든 요청을 가로채고, JWT를 검증하고, 초기 인가를 수행하고, 신원과 권한을 붙여 하류 서비스로 넘긴다. 개별 에이전트의 코드가 극적으로 단순해진다. 받은 요청이 이미 인증·인가됐다고 믿을 수 있기 때문이다.

참고 자료

  • OAuth 2.0 — 개념 개관과 공식 명세 링크는 https://oauth.net/
  • RFC 6749 — 깊은 기술적 이해를 위한 OAuth 2.0 인가 프레임워크 공식 명세
  • JWT 디버거 — 토큰을 붙여 넣어 페이로드를 디코드하고 서명을 검증한다. https://www.jwt.io/
  • IdP 문서 — 가장 실용적인 안내는 선택한 신원 제공자(Okta, Auth0, Microsoft Entra ID, Google Cloud IAM)의 문서에서 온다
  • 비밀 관리client_idclient_secret은 극히 민감한 자격증명이다. 애플리케이션에 하드코딩해서는 결코 안 된다. HashiCorp Vault, AWS Secrets Manager, Google Secret Manager 같은 전용 도구로 저장하고 런타임에 안전하게 가져와야 한다
P4

Reactivity · invert the flow

이벤트 기반 반응성 — 묻지 말고 기다려라

P4

Event-Driven Reactivity

이벤트 기반 반응성

LV 4확장성

문제의 배경

에이전트는 바깥세상에서 벌어지는 일에 거의 실시간으로 반응해야 하는 경우가 많다. 새 이메일이 오고, 주가가 바뀌고, 새 파일이 올라온다. 갱신을 확인하려고 끊임없이 소스를 폴링하는 것은 비효율적이고 확장성이 나쁘다.

문제

끊임없는 폴링에 자원을 낭비하지 않으면서, 에이전틱 시스템이 외부·내부 트리거에 어떻게 효율적으로 반응할 것인가.

해법 — 흐름을 뒤집는다

폴링의 비효율을 없애려면 통신의 흐름을 뒤집어야 한다. 중앙 메시지 버스 또는 이벤트 스트림이 매개하는 이벤트 기반 아키텍처 위에 시스템을 짓는다. 세 부품이 맞물린다.

  • 이벤트 생산자 — 이벤트를 만드는 시스템(신규 가입을 처리하는 웹서버, IoT 센서 등). 사건을 서술하는 작고 자족적인 메시지(예: {"event_type":"new_user","user_id":"123"})를 버스의 특정 토픽에 게시한다.
  • 메시지 버스 — Apache Kafka, RabbitMQ, Google Cloud Pub/Sub 같은 전용 인프라. 생산자의 메시지를 받아 관심 있는 소비자에게 라우팅한다.
  • 이벤트 소비자(에이전트) — 관심 있는 토픽을 구독한다. 메시지가 게시되는 즉시 버스가 그들에게 밀어 넣는다. 이 푸시 기반 모델이 에이전트의 감지–계획–행동 루프를 촉발한다.

The inversion

에이전트가 묻지 않는다

에이전트가 “새로운 게 있나?”라고 묻지 않는다.
시스템이 에이전트에게 “여기 새로운 게 있다”고 말한다.

회복력을 위한 세 가지 운영 통제

  • 백프레셔 — 이벤트의 홍수가 에이전트의 속도 제한을 압도하지 않도록 기제를 마련해야 한다.
  • 데드레터 큐(DLQ) — 에이전트를 죽게 만드는 기형 이벤트를 붙잡도록 설정해, “독이 든 알약”이 큐 전체를 막는 일을 막는다.
  • 멱등성 — 에이전트의 행동은 멱등하게 설계돼야 한다. 분산 시스템에서 흔히 일어나듯 버스가 이벤트를 재전달해도 같은 행동을 두 번 실행하지 않게(예: 고객에게 이중 청구) 하기 위해서다.

사례 — 자동화된 고객 지원 시스템

사용자가 새 티켓을 제출하면 시스템이 이벤트 버스로 여러 독립 프로세스를 즉시 촉발한다. 이 “푸시” 모델 덕에 TriageAgentArchivingServiceDB를 폴링할 필요 없이 실시간으로 반응한다.

01생산자 — 사용자가 웹 양식으로 새 지원 티켓을 제출한다. 웹서버가 Kafka의 new_tickets 토픽에 메시지를 게시한다
02메시지 버스 — Kafka가 메시지를 받고 이 토픽을 구독한 서비스가 임을 확인한다
03소비자 ATriageAgent가 이벤트를 받아 즉시 촉발된다. 티켓 내용을 읽고 LLM으로 우선순위와 범주(“청구”, “긴급”)를 분류한 뒤, 보강된 새 이벤트를 triaged_tickets 토픽에 게시한다
04소비자 BArchivingService도 원본 이벤트를 받아, 분석용 장기 데이터 웨어하우스에 원시 티켓 사본을 즉시 기록한다

TriageAgent데이터베이스를 폴링할 필요가 없었다. 이벤트에 의해 즉각 활성화됐고, 그래서 시스템 전체가 매우 반응적이 된다.

장점

  • 확장성과 결합 해체 — 고도로 확장 가능하고 분리된 시스템을 만든다. 생산자는 소비자가 누구인지 알 필요가 없고 그 반대도 마찬가지다. 생산자를 바꾸지 않고 소비 에이전트를 더 붙일 수 있다.
  • 반응성 — 사건이 일어나는 대로 에이전트가 촉발되므로 시스템이 매우 반응적이고 거의 실시간으로 작동한다.

단점

  • 복잡도 — 메시지 버스를 배포하고 관리하는 운영 복잡성이 생긴다. 비동기 프로그래밍은 단순한 요청–응답 모델보다 디버깅이 어려울 수 있다.
  • 전달 보장 — 메시지 전달 보장(예: “최소 한 번” 전달)을 다루고 잠재적 메시지 실패를 관리하도록 버스를 올바로 설정해야 한다.

구현 지침

생산자와 소비자가 시간이 지나도 안정적으로 소통하도록 이벤트 페이로드의 명확하고 버전이 매겨진 스키마를 정의하라(예: Avro나 Protobuf). Kafka 같은 해법을 자체 호스팅하기 전에, 운영 부담을 줄이는 관리형 서비스(Google Pub/Sub, Amazon SQS·SNS)로 시작하라.