에이전트 운영 회고 (5/7) — 보안 정책이 delegation을 깨뜨린 사례

핵심 요약 — 이 글이 전달하는 것

  • intersection rule: sub-agent의 effective toolset은 부모의 toolset과 교집합으로 결정된다. 권한 상승을 막는 보안 규칙이지만, 부모를 가볍게 만들면 sub가 무력화된다.
  • delegation의 전제 조건: 부모가 sub에게 위임하려는 도구를 자기도 보유해야 한다. 그렇지 않으면 sub의 effective tools가 0이 되고, 모델은 빈 schema 위에서 그럴듯한 답을 합성(환각)한다.
  • L0 vs L1: 구조적 강제(L0, toolset 제거)와 행동 규율(L1, 시스템 프롬프트)의 트레이드오프. sub delegation이 존재하는 한 L0 toolset 축소는 안전한 최적화 수단이 아니다.
  • 토큰 최적화 경로: 위임 그래프에서는 "부모 도구 축소"가 아니라 "호출 빈도 제어 + schema 캐싱 + 행동 규율"이 올바른 레이어다.

배경 — 토큰 최적화 시도의 실패

Hermes에서 토큰 폭주 이슈가 있었다. 메인 에이전트가 매 호출마다 무거운 schema를 통째로 싣고 나가는 구조였다. OpenClaw 쪽은 보안과 자기개선 루프가 어느 정도 자리를 잡은 상태였고, 이번 이슈는 Hermes에 국한된다.

초기 대응안은 단순했다. platform_toolsets.discord를 17개에서 10개로 축소. discord, skill, delegate_task처럼 메인이 직접 쓰는 도구만 남기고 browser/terminal/web 같은 무거운 toolset은 제거. 무거운 작업은 sub-agent에게 위임하면 되니 sub만 보유하면 된다는 판단이었다. 이 설계안은 작동하지 않았다. 아래는 그 이유와, 같은 구조를 가진 시스템에서 반복되지 않도록 하기 위한 정리다.

증상 — 환각이 도구 축소 직후 발생

축소 직후 GitHub PR 조회 요청 경로에서 두 가지 이상 신호가 동시에 관측됐다.

  1. sub-agent가 PR #110, PR #109를 "조회 결과"로 반환. 실제 해당 저장소의 최근 PR 번호는 12000번대였다.
  2. sub-agent의 tool call 로그가 비어 있었다. 도구를 호출한 흔적 없이 PR 정보를 생성.

두 번째 신호가 결정적이었다. tool 호출 없이 결과가 나온다는 건 모델이 학습 분포에서 값을 합성했다는 뜻이다. 도구 축소 직후 발생이라는 시간적 근접성이 인과 추정을 뒷받침했다.

작동 원리 — intersection rule

원인은 tools/delegate_tool.py:311-313이다.

if toolsets:
    # Intersect with parent — subagent must not gain tools the parent lacks
    child_toolsets = _strip_blocked_tools([t for t in toolsets if t in parent_toolsets])

주석 그대로 동작한다: sub-agent는 부모가 보유하지 않은 toolset을 새로 획득할 수 없다. parent_toolsets는 같은 파일 상단에서 부모의 활성 toolset으로부터 도출된다.

이 규칙의 설계 의도는 명확하다 — 권한 상승 방지. sub가 부모보다 넓은 권한을 가질 수 있다면 "메인 에이전트를 제약한다"는 개념 자체가 성립하지 않는다.

충돌 구조 — 두 정책의 양립 불가능성

정책 요구
intersection rule (보안) sub ⊆ parent. 부모가 가진 것의 부분집합만 sub가 보유 가능.
운영 의도 (토큰 최적화) parent를 가볍게, 무거운 일은 sub가. 즉 sub ⊋ parent 혹은 sub ⊅ parent.

두 정책이 수학적으로 양립하지 않는다. 부모의 toolset을 17 → 10으로 줄인 순간 sub가 요청한 browser/terminal toolset이 부모 집합 밖이 되어 교집합에서 제외된다. sub의 effective tools = 0.

환각 발생 메커니즘

effective tools = 0일 때 LLM의 반응은 두 경로다. 1. "도구 없음"을 명시적으로 거부 응답. 2. 빈 schema 위에서 학습 분포의 prior로 결과를 합성.

중요한 점: intersection rule이 toolset을 비우는 과정에서 sub에게 "도구가 박탈되었다"는 명시 신호가 전달되지 않는다. sub 입장에서는 애초부터 비어 있는 schema를 받는 것과 구분되지 않는다. 거부 응답을 택하려면 별도의 행동 규율(시스템 프롬프트 수준)이 필요하다. 그 규율이 부재한 상태에서 모델은 경로 2를 택했다. 결과가 PR #110, #109였다.

요약하면: 보안 규칙은 정확히 작동했고, 그 정확한 작동의 부산물이 환각이었다.

대응 — L0 포기, L1 전환

선택지는 둘이었다.

  • A. intersection rule 우회 패치: sub가 부모를 넘어서는 toolset을 가질 수 있도록 교집합 로직을 제거/완화. 보안 모델 붕괴.
  • B. L0 구조 강제 포기, L1로 전환: 부모 toolset을 원복하고 행동 규율을 시스템 프롬프트에 삽입.

B를 채택. 근거는 "권한 상승 방지"가 "토큰 절감"보다 상위 요구라는 판단이었다.

L0 vs L1 비교

층위 메커니즘 강제력 비용
L0 toolset 자체를 시스템에서 제거 LLM이 어길 수 없음 (구조적) delegation과 양립 불가
L1 시스템 프롬프트에 행동 규율 prepend LLM이 어길 수 있음 (확률적) delegation 유지 가능

재설계 적용 내용

  1. platform_toolsets.discord 17개 전체 복구.
  2. SOUL.md 행동 규율 섹션 전면 개편:
  3. 구조적 제약이 해제되었음을 명시.
  4. 메인이 sub 응답을 수용하기 전에 거치는 self-check 단계를 박음.
  5. "환각을 막는 마지막 방어선은 모델 자신"임을 선언적으로 기재.
  6. 이전 설정은 재설계 시점 백업으로 보존 (롤백 경로 확보).

검증 — 동일 요청 재실행 결과

복구 후 같은 종류의 PR 조회 요청 재실행.

  • 메인 에이전트 호출: delegate_task ×1, skill_view ×2.
  • sub-agent effective tools: 두 자릿수 복구. browser 계열 정상 활용.
  • 반환 PR 번호: #12497, #12495, #12494 (NousResearch/hermes-agent로 추정되는 저장소 기준).
  • 직전 시점 실제 데이터와 일치. #110, #109 환각 소거.

적용 가능한 패턴

이 사례에서 추출되는 재사용 가능한 원칙들:

  1. Delegation graph에서 부모 toolset은 "상한선"이다. 부모를 가볍게 만드는 것은 sub의 능력 상한을 낮추는 것과 같다. 토큰 절감 효과와 역비례.
  2. 보안 규칙과 운영 의도의 양립성은 설계 시점에 검증해야 한다. 둘 다 합리적이어도 조합이 non-viable일 수 있다. intersection rule × 부모 경량화가 그 사례.
  3. L0 구조 강제는 단일 에이전트 구성에만 안전하게 적용 가능하다. delegation graph가 들어가는 순간 L1으로 내려와야 한다.
  4. 토큰 최적화의 올바른 레이어: (a) 호출 빈도 제어 (Token Guard 등 실시간 감시), (b) schema 캐싱, (c) 행동 규율을 통한 불필요 호출 차단. 부모 toolset 축소는 이 목록에 없다.
  5. Empty-schema 환각 방지에는 명시적 거부 규율이 필요하다. 빈 tool set을 마주한 모델이 거부를 선택하도록 하는 행동 규율은 L1에서 별도로 설계되어야 한다.

한계와 열린 질문

L1 전환은 구조가 보장하던 것모델이 지켜야 하는 것으로 이동시킨다. self-check 4단계를 시스템 프롬프트에 박아도 모델이 일부 호출에서 절차를 건너뛸 확률은 0이 아니다. 현재 관측 단계에서 열려 있는 질문들:

  • 동일 패턴 환각의 재발 빈도는?
  • sub-agent가 빈 결과를 마주했을 때 거부 응답을 안정적으로 생성하는가?
  • 메인의 self-check가 실제 호출에서 발동하는 비율은?

이 질문들은 로그 표본이 축적되기 전에는 답할 수 없다. "해결됨"이 아니라 "조건부 작동 중"이 현재 상태다.

적용 범위

  • 적용 가능: Claude Code 계열 + 자체 delegation 프레임워크 + intersection-style security policy를 가진 멀티에이전트 시스템.
  • 적용 제한: L0 toolset 축소를 이미 사용 중인 단일 에이전트 구성은 이 사례의 대상이 아니다. delegation graph가 없으면 교집합이 문제를 일으키지 않는다.
  • 일반화 가능 원칙: 권한 경계 규칙(intersection, sandboxing, capability scoping 등)을 가진 모든 multi-agent 시스템에서, 부모의 capability 축소는 자식 능력의 상한 축소로 직결된다는 점.

시리즈 전체 안내: 시리즈 목차

댓글

이 블로그의 인기 게시물

"LLM 핵심 학습 (1/6) — 기본: 토큰화·임베딩·어텐션·위치 인코딩"

"LLM 핵심 학습 (2/6) — 파인튜닝: LoRA·QLoRA·증류·Adapter"

"ML 기초 학습 (1/9) — 머신러닝과 sklearn: 학습의 좌표계"