왜 단일 Agent만으로는 부족한가: MAS 핵심 개념
2024~2025년 Agent가 실험실을 벗어나 프로덕션으로 진입했지만, 많은 팀이 곧 깨닫습니다. 모든 작업을 하나의 LLM Agent에 넣으면 규모 확장 시 시스템이 무너집니다. Google 내부 Agent Bake-Off 실험에 따르면 분산 멀티 Agent 아키텍처를 도입한 뒤 처리 시간이 1시간에서 10분으로 단축되었습니다(약 6배). AdaptOrch(2026)는 오케스트레이션 토폴로지 선택이 기반 모델보다 성능에 더 큰 영향을 미친다고 입증했으며, SWE-bench 등 벤치마크에서 12~23% 향상을 기록했습니다.
컨텍스트 윈도우 병목: 복잡한 작업의 중간 결과가 컨텍스트를 가득 채우면 이후 추론 품질이 급락합니다.
전문 역량 희석: 하나의 Agent가 검색·코딩·검수를 모두 맡으면 만능이지만 어느 것도 정밀하지 않습니다(jack-of-all-trades).
직렬 실행 비효율: 모든 하위 작업이 순차 실행되면 총 소요 시간이 각 단계의 합이 되어 병렬화가 불가능합니다.
단일 장애점(SPOF): 해당 Agent에 문제가 생기면 전체 플로우가 중단됩니다.
핵심 결론: 멀티 Agent 협업 아키텍처(MAS)는 위 문제를 해결하기 위해 존재합니다. 오케스트레이션 토폴로지 > 모델 선택입니다.
MAS 정의: Multi-Agent System은 여러 독립 AI Agent가 명확한 통신 프로토콜과 오케스트레이션 메커니즘으로 협업하여 단일 Agent가 효율적으로 처리하지 못하는 복잡한 작업을 완수하는 시스템입니다.
| 특성 | 설명 |
|---|---|
| 역할 전문화 | 검색·추론·생성·검증 등 하나의 명확한 하위 작업만 담당합니다 |
| 도구 접근 | 자신의 작업 완수에 필요한 특정 도구 세트를 보유합니다 |
| 상태 격리 | 자체 컨텍스트와 메모리를 유지하여 다른 Agent를 오염시키지 않습니다 |
| 교체 가능성 | 독립적으로 업그레이드·교체할 수 있으며 전체 시스템에 영향을 주지 않습니다 |
3가지 제어 모드:
| 모드 | 구조 | 장점 | 단점 |
|---|---|---|---|
| 중앙집중형(Centralized) | Orchestrator가 A/B/C를 일괄 스케줄링 | 감사 가능·제어 용이 | 단일 병목 |
| 분산형(Decentralized) | Agent 간 P2P 메시 네트워크 | 높은 탄력성·낮은 지연 | 디버깅 어려움·비결정성 |
| 계층형(Hierarchical) | 상위 Orchestrator → Team Lead → Worker | 제어성과 확장성 균형 | 설계 복잡도 중간 |
LangGraph vs CrewAI vs AutoGen: 프레임워크 비교와 선정 가이드
프레임워크를 올바르게 선택하면 자체 오케스트레이션·상태 관리 코드를 대폭 줄일 수 있습니다. 아래 표는 아키텍처 패러다임, 언어 지원, 학습 곡선, 상태 관리, HITL, 가시성, 프로덕션 준비도, 프로토타입 속도, Azure 통합, 전형적 시나리오를 다룹니다.
| 차원 | LangGraph | CrewAI | AutoGen(Microsoft) |
|---|---|---|---|
| 아키텍처 패러다임 | 상태 기계 그래프 | 역할 기반 팀 | 대화형 멀티 Agent |
| 프로그래밍 언어 | Python / JS·TS | Python | Python / .NET |
| 학습 곡선 | 가파름 | 완만함 | 중간 |
| 상태 관리 | 네이티브 지원 | 자체 구현 필요 | 제한적 지원 |
| Human-in-the-Loop | 네이티브 interrupt() | 자체 구현 필요 | 지원 |
| 가시성 | LangSmith(상용) | 제한적 | Azure Monitor |
| 프로덕션 준비도 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 빠른 프로토타입 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Azure 통합 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 적합 시나리오 | 복잡한 상태ful 워크플로 | 역할 기반 콘텐츠 파이프라인 | 대화형 협업·토론 |
선정 권장:
LangGraph 선택: 프로덕션급 신뢰성(금융·의료·컴플라이언스), 복잡한 상태 영속화, 정밀 HITL 제어, 조건 분기·루프의 정확한 표현이 필요할 때 적합합니다.
CrewAI 선택: 1~2일 내 아이디어 빠른 검증, 팀이「역할」로 Agent를 직관적으로 이해하는 경우, 콘텐츠 생성·리서치 리포트 등 역할 기반 시나리오에 적합합니다.
AutoGen 선택: Microsoft/Azure 기술 스택, Agent 다중 라운드 토론·반복 추론, 연구 또는 다양한 대화 모드 실험이 필요할 때 적합합니다.
오케스트레이션 토폴로지 선택이 기반 모델 선택보다 시스템 성능에 더 큰 영향을 미칩니다. 패턴과 프레임워크를 먼저 정하고 모델을 선택하세요.
6대 오케스트레이션 설계 패턴과 MCP+A2A 이중 통신 프로토콜
아래 6가지 패턴은 프로덕션 멀티 Agent 시나리오의 95% 이상을 커버합니다. 패턴 1 순차 파이프라인: Agent A의 출력이 B의 입력이 되며 엄격한 선형 실행입니다. 기사 작성·코드 리뷰 등 고정 플로우에 적합합니다.
from langgraph.graph import StateGraph, START, END
from typing import TypedDict
class PipelineState(TypedDict):
query: str
retrieved_docs: str
analysis: str
final_report: str
def retrieval_agent(state: PipelineState):
docs = search_knowledge_base(state["query"])
return {"retrieved_docs": docs}
def analysis_agent(state: PipelineState):
result = llm.invoke(f"다음 내용을 분석하세요: {state['retrieved_docs']}")
return {"analysis": result.content}
def writer_agent(state: PipelineState):
report = llm.invoke(f"분석 결과를 바탕으로 보고서를 작성하세요: {state['analysis']}")
return {"final_report": report.content}
builder = StateGraph(PipelineState)
builder.add_node("retriever", retrieval_agent)
builder.add_node("analyzer", analysis_agent)
builder.add_node("writer", writer_agent)
builder.add_edge(START, "retriever")
builder.add_edge("retriever", "analyzer")
builder.add_edge("analyzer", "writer")
builder.add_edge("writer", END)
pipeline = builder.compile()
패턴 2 병렬 팬아웃/팬인: 여러 Agent가 독립 하위 작업을 동시 처리하며 총 소요 시간은 max(T1…Tn)입니다. LangGraph Send API와 Annotated[list, operator.add] Reducer로 병렬 결과를 자동 집계합니다.
from langgraph.types import Send
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
import operator
class ResearchState(TypedDict):
query: str
research_results: Annotated[list, operator.add]
final_synthesis: str
def supervisor(state: ResearchState):
subtasks = [
{"query": state["query"], "source": "academic"},
{"query": state["query"], "source": "industry"},
{"query": state["query"], "source": "news"},
]
return [Send("research_worker", task) for task in subtasks]
def research_worker(state: dict):
result = search_by_source(state["query"], state["source"])
return {"research_results": [result]}
def synthesizer(state: ResearchState):
combined = "\n".join(state["research_results"])
synthesis = llm.invoke(f"다음 연구 결과를 종합하세요: {combined}")
return {"final_synthesis": synthesis.content}
builder = StateGraph(ResearchState)
builder.add_node("research_worker", research_worker)
builder.add_node("synthesizer", synthesizer)
builder.add_conditional_edges(START, supervisor, ["research_worker"])
builder.add_edge("research_worker", "synthesizer")
builder.add_edge("synthesizer", END)
graph = builder.compile()
패턴 3 계층형 Supervisor-Worker: Supervisor가 의도 인식과 라우팅을, Worker가 전문 하위 작업을 수행합니다. 키워드 패스트 패스 + LLM 정밀 라우팅 이중 최적화를 권장합니다.
KEYWORD_ROUTING = {
"코드": "code_agent", "code": "code_agent",
"검색": "search_agent", "조회": "search_agent",
"데이터": "data_agent",
}
def supervisor_with_fast_path(state):
query = state["query"].lower()
for keyword, agent_name in KEYWORD_ROUTING.items():
if keyword in query:
return {"next": agent_name}
routing_prompt = f"""
사용자 요청: {state['query']}
사용 가능 Agent: code_agent, search_agent, data_agent
가장 적합한 Agent 이름만 반환하세요.
"""
decision = llm.invoke(routing_prompt)
return {"next": decision.content.strip()}
패턴 4 군집 협업(Swarm): Agent가 P2P로 작업을 전달하며 중앙 조정자가 없고 종료 규칙으로 정지합니다. 프로덕션에서는 신중히 사용하며 하드 라운드 상한을 설정합니다. AutoGen GroupChat + max_round 예시입니다.
import autogen
reviewer_1 = autogen.AssistantAgent(
name="SecurityReviewer",
system_message="코드 보안 취약점에 집중하는 보안 전문가입니다."
)
reviewer_2 = autogen.AssistantAgent(
name="PerformanceReviewer",
system_message="코드 효율과 리소스 사용에 집중하는 성능 전문가입니다."
)
human_proxy = autogen.UserProxyAgent(
name="CodeAuthor",
human_input_mode="NEVER",
max_consecutive_auto_reply=2,
is_termination_msg=lambda x: "APPROVED" in x.get("content", "")
)
groupchat = autogen.GroupChat(
agents=[human_proxy, reviewer_1, reviewer_2],
messages=[],
max_round=6
)
manager = autogen.GroupChatManager(groupchat=groupchat)
패턴 5 블랙보드(Blackboard): 모든 Agent가 구조화된 공유 작업 공간을 사용하며 전제 조건 충족 시 능동적으로 읽고 씁니다. 시간 단위 비동기 작업과 이기종 서비스 협업에 적합합니다. 패턴 6 하이브리드(Hybrid): Intent 라우터 + Supervisor + 병렬 팬아웃 + 품질 보증 파이프라인을 조합하며 기업 콘텐츠 생성 시스템의 전형적 아키텍처입니다.
MCP + A2A 이중 프로토콜(Linux Foundation Agentic AI Foundation 거버넌스): MCP는 수직 계층으로 Agent ↔ 도구/DB/API 접근을 통일하고, A2A는 수평 계층으로 Agent ↔ Agent 작업 위임·역량 탐색을 표준화합니다.
from mcp.server import Server
from mcp.types import Tool, TextContent
app = Server("data-agent-mcp")
@app.list_tools()
async def list_tools():
return [
Tool(
name="query_customer_db",
description="고객 DB 조회, ID·이름·이메일로 검색 지원",
inputSchema={
"type": "object",
"properties": {
"field": {"type": "string", "enum": ["id", "name", "email"]},
"value": {"type": "string"}
},
"required": ["field", "value"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "query_customer_db":
result = db.query(arguments["field"], arguments["value"])
return [TextContent(type="text", text=str(result))]
A2A Agent Card(/.well-known/agent.json)로 역량을 선언하고, Orchestrator가 JSON-RPC 2.0으로 작업을 위임합니다.
import httpx
async def discover_and_delegate(agent_url: str, task: str):
card_response = await httpx.get(f"{agent_url}/.well-known/agent.json")
agent_card = card_response.json()
available_skills = [s["id"] for s in agent_card["skills"]]
if "web_research" not in available_skills:
raise ValueError(f"Agent {agent_card['name']}은 web_research 스킬을 지원하지 않습니다")
payload = {
"jsonrpc": "2.0",
"method": "message/send",
"id": "task-001",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": task}]
}
}
}
response = await httpx.post(agent_card["url"], json=payload)
return response.json()
관련 읽을거리: 도구 연동 세부 사항은 MCP Server 처음부터 개발하기를, 프로토콜 전략 관점은 MCP가 AI 시대 HTTP 프로토콜이 되는 이유를 참고하세요.
프로덕션급 멀티 Agent 시스템 6단계 Runbook
선정과 토폴로지 설계: 의사결정 트리로 오케스트레이션 패턴(파이프라인 / 팬아웃 / 계층 / 블랙보드 / 하이브리드)을 확정하고 Agent 수는 3~8개로 제한하여 과도한 엔지니어링을 피합니다.
상태 영속화: PostgresSaver로 체크포인트를 저장하여 프로세스 간 복구·중단 재개를 지원하고, 각 세션에 thread_id를 바인딩합니다.
Human-in-the-Loop: 고위험 작업은 interrupt()로 일시 정지 후 인간 확인을 기다리며, 컴플라이언스 업종에서 필수입니다.
서킷 브레이커와 재시도: 외부 Agent 호출에 CircuitBreaker를 래핑하고 실패 임계값 도달 시 OPEN 상태로 전환하여 연쇄 장애를 방지합니다.
토큰 예산: TokenBudgetManager를 배포하여 매 Agent 호출 전 잔여 예산을 확인하고 비용 폭주를 막습니다.
가시성 연동: OpenTelemetry traced_agent_call에 correlation_id를 부여하고 MONITORING_METRICS 지표를 추적하며, LLM-as-Judge로 출력 품질을 샘플링 평가합니다.
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.types import interrupt
with PostgresSaver.from_conn_string("postgresql://user:pass@localhost/agentdb") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "user-session-12345"}}
result = graph.invoke({"query": "Q2 실적 분석"}, config)
def high_risk_action_agent(state):
proposed_action = plan_action(state)
human_decision = interrupt({
"proposed_action": proposed_action,
"risk_level": "HIGH",
"message": "이 작업은 프로덕션 DB를 수정합니다. 실행을 확인해 주세요"
})
if human_decision["approved"]:
return execute_action(proposed_action)
return {"status": "cancelled", "reason": human_decision.get("reason")}
import time
from functools import wraps
class CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=60):
self.failure_count = 0
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.state = "CLOSED"
self.last_failure_time = None
def __call__(self, func):
@wraps(func)
async def wrapper(*args, **kwargs):
if self.state == "OPEN":
if time.time() - self.last_failure_time > self.recovery_timeout:
self.state = "HALF_OPEN"
else:
raise Exception("Circuit breaker OPEN - Agent 일시 사용 불가")
try:
result = await func(*args, **kwargs)
if self.state == "HALF_OPEN":
self.state = "CLOSED"
self.failure_count = 0
return result
except Exception:
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = "OPEN"
raise
return wrapper
class TokenBudgetManager:
def __init__(self, total_budget: int = 100_000):
self.total_budget = total_budget
self.used_tokens = 0
self.agent_usage = {}
def check_budget(self, agent_name: str, estimated_tokens: int) -> bool:
remaining = self.total_budget - self.used_tokens
if estimated_tokens > remaining:
raise BudgetExceededException(
f"Agent {agent_name}이 {estimated_tokens} tokens를 요청했으나 "
f"잔여 예산은 {remaining} tokens뿐입니다"
)
return True
def record_usage(self, agent_name: str, actual_tokens: int):
self.used_tokens += actual_tokens
self.agent_usage[agent_name] = self.agent_usage.get(agent_name, 0) + actual_tokens
가시성 하드 데이터, 4대 함정과 2026 트렌드
MAST 연구팀이 1642건의 멀티 Agent 실행 추적을 분석한 장애 분포는 다음과 같습니다.
| 장애 유형 | 비중 | 설명 |
|---|---|---|
| 시스템 설계 문제 | 41.77% | 단계 반복, 잘못된 도구 선택, 컨텍스트 오버플로, 종료 조건 부재 |
| Agent 간 불일치 | 36.94% | 인계 시 컨텍스트 손실, 환각이 다음 Agent의「사실」이 됨 |
| 작업 검증 실패 | 21.30% | 조기 종료, 불완전한 검증 |
57% vs 8%: 조직의 57%가 이미 프로덕션에서 Agent를 운영하지만 LLM 가시성 구현을 완료한 곳은 8%에 불과합니다. 많은 오류가 HTTP 200으로 반환되어 대시보드는 녹색이지만 출력은 틀립니다.
Google Bake-Off 6×: 분산 멀티 Agent 아키텍처가 처리 시간을 1시간에서 10분으로 줄였으며 하위 Agent를 독립 업그레이드할 수 있습니다.
AdaptOrch 12~23%: 올바른 오케스트레이션 토폴로지가 SWE-bench 등에서 12~23% 성능 향상을 가져오며, 단순 모델 교체보다 효과적입니다.
from opentelemetry import trace
import uuid
tracer = trace.get_tracer("multi-agent-system")
def traced_agent_call(agent_name: str, task: dict, correlation_id: str = None):
if not correlation_id:
correlation_id = str(uuid.uuid4())
with tracer.start_as_current_span(f"agent.{agent_name}") as span:
span.set_attribute("agent.name", agent_name)
span.set_attribute("correlation.id", correlation_id)
span.set_attribute("task.type", task.get("type", "unknown"))
try:
result = agent_registry[agent_name].run(task)
span.set_attribute("agent.tokens_used", result.get("tokens", 0))
span.set_attribute("agent.status", "success")
return result
except Exception as e:
span.set_attribute("agent.status", "error")
span.set_attribute("error.message", str(e))
raise
MONITORING_METRICS = {
"task_success_rate": "엔드투엔드 작업 완료율(목표: >85%)",
"e2e_latency_p95": "P95 엔드투엔드 지연(목표: <30s)",
"total_cost_per_task": "작업당 평균 토큰 비용",
"agent_error_rate": "Agent별 오류율(목표: <5%)",
"agent_retry_count": "재시도 횟수(높을수록 조사 필요)",
"tool_call_budget_usage": "도구 호출 횟수/예산 비율",
"output_quality_score": "출력 품질 점수",
"goal_alignment_score": "목표 정합성 점수",
"hallucination_rate": "환각 탐지율",
}
def evaluate_agent_output(original_task: str, agent_output: str) -> dict:
evaluation_prompt = f"""
원본 작업: {original_task}
Agent 출력: {agent_output}
작업 완료도, 정확성, 관련성, 환각 탐지 4개 차원으로 1~5점을 매기고
JSON으로 반환하세요: {{"completeness": x, "accuracy": x, "relevance": x,
"hallucination_detected": true/false, "comments": "..."}}
"""
evaluation = llm.invoke(evaluation_prompt)
return json.loads(evaluation.content)
4대 함정과 대응:
컨텍스트 오염: Agent A의 환각이 B/C로 전달되어 전체 체인이 잘못된 전제에 기반합니다. 대응: 각 인계 지점에서 validate_agent_output로 Schema·신뢰도를 검증합니다.
무한 루프: 재시도·도구 호출이 통제 불능이 되어 토큰 비용이 폭증합니다. 대응: MAX_ITERATIONS, MAX_TOOL_CALLS_PER_AGENT, MAX_TOTAL_TOKENS 하드 상한을 설정합니다.
과도한 엔지니어링: 단순 2단계 체인을 8개 Agent로 분해합니다. 대응: 순차 파이프라인부터 시작하고 프로덕션 최적 수는 3~8개입니다.
데모 격차: 내부 데모는 완벽하지만 엣지 입력에서 프로덕션 실패가 빈번합니다. 대응: ProductionGuardrails로 입력 길이·인젝션 탐지·PII 필터링을 수행합니다.
병렬 동기화: Send API 팬아웃 후 느린 분기가 완료되기 전 Supervisor가 재실행됩니다. 대응: LangGraph defer=True로 명시적 동기화 배리어를 생성합니다.
def validate_agent_output(output: dict, schema: dict) -> bool:
jsonschema.validate(output, schema)
if output.get("confidence_score", 1.0) < 0.7:
raise LowConfidenceError(f"Agent 출력 신뢰도 부족: {output['confidence_score']}")
required_fields = schema.get("required", [])
missing = [f for f in required_fields if not output.get(f)]
if missing:
raise MissingFieldsError(f"출력에 필수 필드 누락: {missing}")
return True
MAX_ITERATIONS = 10
MAX_TOOL_CALLS_PER_AGENT = 20
MAX_TOTAL_TOKENS = 50_000
class ProductionGuardrails:
def validate_input(self, user_input: str) -> str:
if len(user_input) > 10000:
raise InputTooLongError("입력이 10000자 제한을 초과했습니다")
injection_patterns = ["ignore previous instructions", "forget everything"]
for pattern in injection_patterns:
if pattern.lower() in user_input.lower():
raise PromptInjectionError("잠재적 프롬프트 인젝션 탐지")
return user_input.strip()
def validate_output(self, output: str) -> str:
output = self.pii_filter.redact(output)
if self.content_classifier.is_harmful(output):
raise HarmfulContentError("출력에 유해 콘텐츠 포함")
return output
builder.add_node("supervisor", supervisor_node, defer=True)
작업에 명확한 선형 의존 단계가 있나요?
├─ 예 → 하위 작업을 병렬 실행할 수 있나요?
│ ├─ 아니오 → 【순차 파이프라인】
│ └─ 예 → 【병렬 팬아웃 + 순차 파이프라인 하이브리드】
└─ 아니오 → 의사결정 권한을 가진 Agent가 있나요?
├─ 예 → 규모가 커서 하위 팀이 필요한가요?
│ ├─ 아니오 → 【Supervisor-Worker 계층 패턴】
│ └─ 예 → 【계층형(Supervisors of Supervisors)】
└─ 아니오 → 장시간 비동기 작업인가요?
├─ 예 → 【블랙보드 아키텍처】
└─ 아니오 → Agent 수가 ≤ 5인가요?
├─ 예 → 【Swarm(종료 조건 설정 필수)】
└─ 아니오 → 【계층 패턴으로 재분해 검토】
5가지 핵심 요약: ① 오케스트레이션 토폴로지 > 모델 선택; ② 순차 파이프라인부터 시작하고 근거가 있을 때 Agent를 추가; ③ MCP + A2A는 신규 프로젝트 표준 프로토콜; ④ 가시성은 선택이 아님(57% vs 8% 격차); ⑤ 프로덕션 Agent 수 3~8개가 최적입니다.
2026 트렌드: 연합 오케스트레이션(다팀 서브 오케스트레이터가 라우팅 정책 공유), 멀티모달 멀티 Agent(시각·오디오·텍스트 혼합 협업), 적응형 토폴로지 선택(AdaptOrch 방향), EU AI Act가 요구하는 완전한 의사결정 감사 체인입니다.
주의: 노트북에서 멀티 Agent 오케스트레이션을 실행하면 절전·메모리 부족·네트워크 지터로 세션이 끊깁니다. 저가 Linux VPS는 Xcode와 Apple Silicon 최적화 추론을 네이티브로 실행할 수 없습니다. 멀티 Agent 아키텍처는 2026년 AI 엔지니어링의 핵심 경쟁력이지만, 프로덕션에는 안정적인 호스트가 필요합니다.
7×24 멀티 Agent 오케스트레이션 상주, PostgresSaver 체크포인트 영속화, MCP Server와 Cursor / Claude Code 협업이 필요한 프로덕션 환경에서는 MESHLAUNCH Mac Mini 클라우드 대여가 일반적으로 더 나은 선택입니다. 전용 Apple Silicon, 일/주/월 단위 탄력 주문으로 LangGraph 워크플로와 로컬 벡터 검색의 안정 호스트가 되어, 오케스트레이션 자산을 특정 벤더에 묶이지 않는 팀 소유 이식 가능 역량으로 전환할 수 있습니다.
복잡한 상태 관리, HITL, 컴플라이언스 감사가 필요하면 LangGraph를 선택합니다. 1~2일 빠른 프로토타입과 역할 기반 콘텐츠 파이프라인에는 CrewAI가 적합합니다. Microsoft/Azure 스택과 다중 라운드 토론 협업에는 AutoGen을 권장합니다. 멀티 Agent 오케스트레이션 호스트는 대여 가격 페이지를 참고하세요.
MCP는 수직 계층으로 Agent가 도구·데이터베이스·API에 접근하는 방식을 통일합니다(한 번 작성, 어디서나 사용). A2A는 수평 계층으로 Agent Card와 JSON-RPC 2.0을 통해 Agent 간 작업 위임·역량 탐색을 구현합니다. 둘 다 Linux Foundation Agentic AI Foundation이 거버넌스하며, 신규 프로젝트는 이중 아키텍처를 바로 채택하는 것이 좋습니다.
최소한 PostgreSQL 체크포인트 영속화(PostgresSaver), OpenTelemetry 분산 추적, 토큰 예산·서킷 브레이커, 그리고 노트북 절전으로 장시간 세션이 끊기지 않도록 7×24 안정 호스트가 필요합니다. Mac Mini 베어메탈은 LangGraph 워크플로, MCP Server, 로컬 벡터 검색을 동시에 실행할 수 있습니다. 배포·네트워크 이슈는 고객 센터를 참고하세요.