k
korAI
고급 전체
🔥 고급2026-06-256~8분

멀티 에이전트 환경에서 안전한 Tool 실행: 격리·타임아웃·감사 로그 설계

에이전트가 코드 실행·파일 쓰기·외부 API 호출을 병렬로 수행할 때 발생하는 경쟁 조건과 무한 루프를 차단하는 실전 아키텍처를 다룬다.

multi-agenttool-safetyreliability

멀티 에이전트 Tool 실행의 실패 모드

단일 에이전트도 위험하지만 멀티 에이전트는 실패가 연쇄된다. 대표적 패턴은 다음 세 가지다.

  1. 무한 tool 루프: 에이전트 A가 에이전트 B를 호출하고, B가 다시 A의 tool을 호출하는 순환. 실제 사례에서 3분 안에 API 비용이 $40 초과했다.
  2. 경쟁 쓰기: 두 에이전트가 동일 파일·DB 레코드를 동시에 수정해 데이터 손상.
  3. 탈출 없는 재시도: tool 오류 시 에이전트가 자체 판단으로 무제한 재시도.

격리 레이어 설계

안전한 멀티 에이전트 시스템은 Orchestrator → Tool Gateway → Executor 3계층으로 분리한다.

  • Orchestrator: Claude API 호출 및 tool_use 블록 파싱만 담당. 실제 IO 없음.
  • Tool Gateway: 허용 tool 목록 화이트리스트, 호출 횟수 한도(예: 세션당 50회), 중복 호출 디바운스.
  • Executor: 샌드박스(Docker/subprocess)에서 실행, 타임아웃 강제.

아래는 Gateway 레이어에서 타임아웃과 호출 한도를 강제하는 예시다.

import anthropic
import asyncio
from collections import defaultdict

client = anthropic.Anthropic()

class ToolGateway:
    def __init__(self, max_calls: int = 50, timeout_sec: float = 10.0):
        self.max_calls = max_calls
        self.timeout_sec = timeout_sec
        self.call_count: dict[str, int] = defaultdict(int)

    async def execute(self, session_id: str, tool_name: str, tool_input: dict) -> dict:
        self.call_count[session_id] += 1
        if self.call_count[session_id] > self.max_calls:
            raise RuntimeError(f"[{session_id}] tool 호출 한도 초과: {self.max_calls}회")
        try:
            result = await asyncio.wait_for(
                self._run_tool(tool_name, tool_input),
                timeout=self.timeout_sec
            )
            return {"status": "ok", "result": result}
        except asyncio.TimeoutError:
            return {"status": "error", "reason": f"{tool_name} timeout after {self.timeout_sec}s"}

    async def _run_tool(self, name: str, inputs: dict) -> str:
        # 실제 tool 로직 (파일 읽기, API 호출 등)
        await asyncio.sleep(0.1)  # placeholder
        return f"{name} 실행 완료"

gateway = ToolGateway(max_calls=50, timeout_sec=10.0)

Orchestrator는 tool_use 블록을 받으면 Gateway를 통해서만 실행하고, Gateway 응답을 tool_result로 반환한다. Claude API를 직접 재호출하는 로직은 Orchestrator에만 존재해야 한다.

감사 로그와 조기 종료 조건

감사 로그는 최소한 다음 필드를 포함해야 한다: session_id, tool_name, input_hash, duration_ms, status, agent_depth. agent_depth가 5를 초과하면 강제 종료한다.

수치 기준선 (실험 기반)

  • tool 타임아웃: 10초 (LLM 기반 tool은 30초)
  • 세션당 최대 tool 호출: 50회
  • 최대 에이전트 중첩 깊이: 5
  • 에러율 > 30% 시 자동 circuit break

운영 체크리스트

  • [ ] 모든 tool 실행이 Gateway를 경유하는지 코드 리뷰로 확인
  • [ ] agent_depth 카운터를 context 객체로 하위 에이전트에 전달
  • [ ] tool 호출 로그를 세션 단위로 집계해 비용 이상 감지 알람 설정
  • [ ] 타임아웃 에러는 재시도 없이 tool_result로 에이전트에 반환 (재시도는 에이전트가 판단)
  • [ ] 동일 input_hash의 tool이 1분 내 3회 이상 호출되면 순환 감지로 종료