Claude Code Max를 전 팀원이 표준 환경으로 쓰는 팀과, 프로젝트마다 AI 도구를 선택적으로 꺼내는 팀 사이에는 아키텍처 설계 단계부터 차이가 생긴다. 이 글은 멀티 에이전트 시스템을 실제로 구축할 때 어떤 구조로 에이전트를 연동하고, 어떤 기준으로 책임 경계를 나누는지를 엔지니어링 관점에서 정리한다.
전 팀원이 Claude Code Max를 표준 도구로 쓸 때 달라지는 것
AI 도구를 개인 생산성 도구로만 쓰면 지식이 개인에게 갇힌다. Claude Code Max를 팀 표준으로 세팅하면 프롬프트, MCP 도구 체인, 에이전트 명세가 코드베이스에 함께 버전 관리된다.
구체적으로 달라지는 점:
- 컨텍스트 공유: CLAUDE.md에 팀 공통 컨벤션과 도메인 용어를 정의해두면 모든 팀원의 세션이 같은 맥락에서 출발한다.
-
MCP 도구 체인 표준화:
mcp_servers설정을 리포지토리에 커밋해두면 팀원이 로컬에서 동일한 MCP 서버 목록을 사용한다. - 서브에이전트 재사용: 한 팀원이 만든 서브에이전트 프롬프트를 다른 팀원이 그대로 호출할 수 있어, 중복 개발이 줄어든다.
- TDD 자동화: Playwright MCP를 연결하면 E2E 테스트 시나리오 작성과 실행을 에이전트가 담당한다. 사람은 실패한 케이스만 리뷰한다.
팀 단위로 AI를 쓴다는 것은 "모두가 똑같이 쓴다"가 아니라, "공유 가능한 AI 인프라를 팀이 함께 유지 관리한다"에 가깝다.
멀티 에이전트 시스템을 설계할 때 어떤 원칙으로 분리하는가?
에이전트를 여러 개 연동할 때 가장 흔한 실수는 하나의 에이전트에 너무 많은 책임을 주는 것이다. 단일 LLM 호출로 "데이터 수집 → 분석 → 보고서 작성 → 슬랙 발송"을 한 번에 처리하려 하면, 중간 단계 오류가 전체 파이프라인을 무너뜨린다.
멀티 에이전트 아키텍처의 핵심 원칙은 단일 책임 + 명시적 인터페이스다.
각 에이전트는 하나의 작업만 수행하고, 입출력 스키마를 JSON으로 명시한다. 오케스트레이터 에이전트는 실행 순서와 에러 핸들링만 담당한다.
┌─────────────────────────────────────┐
│ Orchestrator Agent │
│ (실행 순서 결정 + 에러 핸들링) │
└──────┬──────────┬──────────┬────────┘
│ │ │
▼ ▼ ▼
Collector Analyzer Reporter
Agent Agent Agent
(데이터 수집) (분석·요약) (보고서 생성)
오케스트레이터가 서브에이전트를 호출할 때는 Claude의 서브에이전트 기능을 직접 활용할 수도 있고, 경량 태스크 큐(예: Celery, BullMQ)를 중간에 두어 비동기로 처리할 수도 있다. 동기 파이프라인이 필요한가, 비동기 병렬 처리가 필요한가에 따라 선택이 달라진다.
| 연동 방식 | 적합한 상황 | 주의할 점 |
|---|---|---|
| 직접 서브에이전트 호출 | 순차 의존성이 강한 파이프라인 | 컨텍스트 윈도우 누적 비용 |
| 메시지 큐 (BullMQ 등) | 병렬 처리 또는 재시도 필요 | 큐 인프라 운영 오버헤드 |
| HTTP API 호출 | 에이전트가 독립 서비스로 분리된 경우 | 네트워크 레이턴시, 인증 관리 |
| MCP 프로토콜 | 도구를 에이전트 간에 공유해야 할 때 | MCP 서버 별도 운영 필요 |
연구에서 운영까지 한 팀이 전 주기를 책임지는 아키텍처 설계법
R&D와 운영이 다른 팀이면 모델 연구 결과가 프로덕션에 반영되기까지 병목이 생긴다. 한 팀이 NLP 파인튜닝부터 에이전트 운영까지 맡을 때 아키텍처를 어떻게 구성할지가 실질적인 문제다.
Step 1 — 모델 레이어와 에이전트 레이어를 분리한다
파인튜닝된 모델을 에이전트 코드에 하드코딩하지 않는다. 모델 엔드포인트를 환경변수 또는 설정 파일로 주입한다.
# config.py
import os
MODEL_CONFIG = {
"base_model": os.getenv("BASE_MODEL", "claude-opus-4-5"),
"fine_tuned_endpoint": os.getenv("FINE_TUNED_ENDPOINT", None),
"temperature": float(os.getenv("MODEL_TEMPERATURE", "0.2")),
}
이렇게 하면 R&D 팀이 파인튜닝 모델을 교체할 때 에이전트 코드 수정 없이 환경변수만 변경하면 된다.
Step 2 — 에이전트 상태를 외부 저장소에 위임한다
에이전트 메모리를 프로세스 내부에 두면 재시작 시 컨텍스트가 사라진다. Redis나 Postgres에 세션 상태를 저장하고, 에이전트는 무상태(stateless)로 설계한다.
import redis
import json
r = redis.Redis(host="localhost", port=6379)
def save_agent_state(session_id: str, state: dict):
r.setex(f"agent:{session_id}", 3600, json.dumps(state))
def load_agent_state(session_id: str) -> dict:
raw = r.get(f"agent:{session_id}")
return json.loads(raw) if raw else {}
Step 3 — 오케스트레이터에 재시도 정책을 명시한다
서브에이전트가 실패할 때 오케스트레이터가 자동 재시도할 조건을 코드로 정의한다. 모호한 "에러 발생 시 재시도" 주석 대신, backoff 전략과 최대 시도 횟수를 명시한다.
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def call_sub_agent(agent_fn, payload):
return agent_fn(payload)
tenacity는 Python 재시도 라이브러리 중 가장 널리 쓰이는 선택지다. 실제 프로덕션에서 LLM API 호출은 간헐적 타임아웃이 발생하기 때문에 재시도 레이어가 없으면 운영 중 파이프라인이 의도치 않게 멈춘다.
Step 4 — 관측 가능성(observability)을 처음부터 설계에 포함한다
에이전트가 어떤 결정을 내렸는지 나중에 추적할 수 없으면 디버깅이 불가능하다. 각 에이전트 호출에 trace_id를 부여하고, 입력·출력·레이턴시를 로그로 기록한다.
import uuid
import time
import logging
logger = logging.getLogger(__name__)
def traced_agent_call(agent_fn, payload):
trace_id = str(uuid.uuid4())
start = time.time()
try:
result = agent_fn(payload)
logger.info({"trace_id": trace_id, "latency_ms": int((time.time()-start)*1000), "status": "ok"})
return result
except Exception as e:
logger.error({"trace_id": trace_id, "error": str(e), "status": "fail"})
raise
이 패턴을 모든 에이전트에 데코레이터로 적용하면 분산 트레이싱 없이도 기본적인 감사 로그를 확보할 수 있다. OpenTelemetry를 붙이면 더 정교한 추적이 가능하다.
오픈소스 공개가 기술 신뢰를 어떻게 증명하는가?
코드를 공개한다는 것은 숨길 것이 없다는 선언이다. TreeSoop이 운영하는 ai-news-mcp 등의 오픈소스 프로젝트는 MCP 서버를 어떻게 구현하는지 실제 코드 수준에서 확인할 수 있다. 코드를 먼저 보고 협업 여부를 판단하고 싶은 엔지니어라면 GitHub에서 직접 검토할 수 있다.
기술 신뢰는 포트폴리오 슬라이드보다 실행 가능한 코드가 더 빠르게 만든다. 오픈소스 기여 이력이 있는 팀에게 의존성을 맡기는 것이 리스크가 낮은 이유는 그 팀의 코드 스타일, 문서화 수준, 이슈 대응 방식을 사전에 확인할 수 있기 때문이다.
자주 묻는 질문
멀티 에이전트 시스템에서 오케스트레이터는 반드시 별도 에이전트로 분리해야 하는가?
반드시 그럴 필요는 없다. 파이프라인이 2~3단계로 단순하다면 오케스트레이터 로직을 메인 프로세스에 두어도 충분하다. 에이전트 수가 5개 이상이거나 조건 분기가 복잡해지면 그때 분리를 검토한다.
Claude Code Max의 MCP와 자체 API 호출 방식 중 어떤 것을 선택해야 하는가?
MCP는 도구 인터페이스를 표준화해 여러 에이전트가 같은 도구를 재사용할 때 유리하다. 단일 에이전트가 특정 API만 호출한다면 MCP 서버를 별도로 운영할 이유가 없다. 도구 공유 여부가 핵심 판단 기준이다.
온프레미스 배포와 클라우드 배포 중 에이전트 아키텍처 설계가 달라지는가?
에이전트 로직 자체는 동일하다. 달라지는 것은 모델 엔드포인트 주소와 스토리지 레이어다. 앞서 설명한 환경변수 주입 방식을 사용하면 배포 환경이 바뀌어도 코드 수정 없이 전환할 수 있다.
에이전트 파이프라인의 비용을 어떻게 예측하고 통제하는가?
LLM 호출 비용은 토큰 수에 비례한다. 각 에이전트 호출에 입력·출력 토큰을 로깅하고, 월별 예산 상한을 설정해 초과 시 알림을 보내는 모니터링 레이어를 추가한다. 오케스트레이터 단에서 불필요한 중간 결과를 컨텍스트에 누적하지 않는 것이 비용 통제의 기본이다.
에이전트 시스템 구축에 앞서 팀 내에서 먼저 검증해야 할 것은 무엇인가?
단일 에이전트로 가장 반복적인 업무 하나를 자동화하는 것부터 시작한다. 이 단계에서 입출력 스키마 설계, 에러 핸들링 패턴, 로깅 구조를 확정한 뒤 멀티 에이전트로 확장한다. 처음부터 복잡한 오케스트레이션을 설계하면 디버깅 지점이 너무 많아진다.
에이전트 아키텍처는 도구 선택보다 경계 설계가 먼저다. 어떤 LLM을 쓰든 에이전트의 책임 범위가 모호하면 운영 단계에서 반드시 문제가 생긴다. 구조를 먼저 설계하고, Claude Code Max 같은 AI-native 개발 환경을 팀 인프라로 편입하면 설계와 구현 사이의 간격이 좁아진다. 코드나 아키텍처에 대해 더 구체적인 논의가 필요하다면 GitHub이나 기술 문의 채널로 연락 주시면 된다.
더 보기: treesoop.com
Top comments (0)