Skip to content

필사 모드: AI 에이전트는 프로덕션에서 어떻게 실패하는가 — 14가지 실패 모드, 그리고 재시도가 안전하지 않은 이유

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며 — 프로덕션 에이전트의 진짜 질문 세 가지

데모에서 잘 도는 에이전트를 프로덕션에 올리면 질문이 바뀝니다. "이게 되나?"에서 "이게 왜 안 됐고, 얼마를 태웠고, 다시 시도해도 되나?"로요. 이 글은 그 세 질문에 순서대로 답합니다.

먼저 결론부터. 실패는 대부분 모델이 아니라 시스템 설계에서 납니다. UC 버클리 연구진이 멀티 에이전트 시스템 실행 트레이스 1642건을 분류한 결과, 실패의 44.2%가 시스템 설계 이슈였고 32.3%가 에이전트 간 어긋남, 23.5%가 태스크 검증 실패였습니다. 그리고 가장 흔한 실패 모드 두 개는 단계 반복(15.7%)과 종료 조건 미인지(12.4%) — 합치면 전체의 28.1%입니다. 이 둘은 그냥 "실패"가 아닙니다. 에이전트가 같은 일을 반복하고 멈출 줄 모른다는 뜻이고, 그건 토큰 청구서인 동시에 부작용이 두 번 일어난다는 뜻입니다.

여기서 세 번째 질문이 나옵니다. 비결정적 호출자(LLM)가 진짜 부작용(결제, 메일 발송, 티켓 생성)을 굴릴 때, 재시도는 안전한가? 답은 "당신이 직접 안전하게 만들지 않으면 아니다"입니다. 에이전트가 도구를 부르는 표준 프로토콜인 MCP에는 멱등성을 선언하는 힌트는 있지만 멱등성을 보장하는 메커니즘이 없습니다. 그리고 이 문제의 업계 표준이라 할 IETF의 Idempotency-Key 헤더 드래프트는 2020년에 시작해서 아직 RFC가 아닙니다 — 2026년 4월에 만료된 상태입니다.

에이전트는 실제로 어디서 실패하는가 — MAST의 14가지 모드

가장 인용할 만한 자료는 MAST(Multi-Agent System Failure Taxonomy)입니다. UC 버클리와 Intesa Sanpaolo 연구진(Cemri, Pan, Yang 등, arXiv:2503.13657)이 NeurIPS 2025 Datasets & Benchmarks 트랙에 낸 논문으로, 멀티 에이전트 시스템 실패를 경험적으로 분류한 첫 시도입니다.

방법론부터 봅시다. 연구진은 5개 오픈소스 프레임워크의 트레이스 150여 건(한 건당 평균 1만 5천 줄이 넘습니다)을 근거 이론(Grounded Theory)으로 분석해 분류 체계를 만들었고, 전문 어노테이터 6명이 참여했습니다. 어노테이터 3명이 트레이스 15건을 독립적으로 라벨링해 어노테이터 간 일치도 카파 0.88을 확보한 뒤, 그 정의를 기준으로 OpenAI o1 기반 LLM-as-a-judge 파이프라인을 만들어 전체 1642건을 라벨링했습니다.

분류 결과는 이렇습니다. 괄호 안은 전체 1642건 대비 각 모드의 출현 비율입니다.

[범주 1] 시스템 설계 이슈 (System Design Issues)          44.2%
  1.1 태스크 명세 위반    (Disobey Task Specification)      11.8%
  1.2 역할 명세 위반      (Disobey Role Specification)       1.50%
  1.3 단계 반복          (Step Repetition)                 15.7%   <- 최다
  1.4 대화 히스토리 상실  (Loss of Conversation History)     2.80%
  1.5 종료 조건 미인지    (Unaware of Termination Conditions) 12.4%

[범주 2] 에이전트 간 어긋남 (Inter-Agent Misalignment)     32.3%
  2.1 대화 리셋          (Conversation Reset)               2.20%
  2.2 확인 질문 실패      (Fail to Ask for Clarification)    6.80%
  2.3 태스크 탈선        (Task Derailment)                  7.40%
  2.4 정보 은닉          (Information Withholding)          0.80%
  2.5 타 에이전트 입력 무시 (Ignored Other Agent's Input)     1.90%
  2.6 추론-행동 불일치    (Reasoning-Action Mismatch)        13.2%

[범주 3] 태스크 검증 (Task Verification)                  23.5%
  3.1 조기 종료          (Premature Termination)            6.20%
  3.2 검증 없음/불완전    (No or Incomplete Verification)    8.20%
  3.3 잘못된 검증        (Incorrect Verification)           9.10%

숫자가 맞아떨어지는지 확인해 두면 좋습니다. 11.8 + 1.5 + 15.7 + 2.8 + 12.4 = 44.2, 2.2 + 6.8 + 7.4 + 0.8 + 1.9 + 13.2 = 32.3, 6.2 + 8.2 + 9.1 = 23.5. 세 범주를 더하면 정확히 100%입니다.

여기서 한 가지 경고. 이 논문을 요약한 2차 자료 중에는 "42%가 명세 문제, 37%가 조율 붕괴, 21%가 검증 부실"이라고 적은 것들이 돌아다니는데, 세 숫자 모두 논문에 없습니다. 범주 이름도 다릅니다 — 논문의 첫 범주는 "명세 이슈"가 아니라 "시스템 설계 이슈"입니다(초기 버전에서 이름이 바뀐 흔적으로 보입니다). 인용하실 거면 논문 Figure 1을 직접 보시길 권합니다.

기저 실패율도 새겨둘 만합니다. 논문이 평가한 7개 SOTA 오픈소스 시스템의 실패율은 41%에서 86.7% 사이였습니다. 가장 나빴던 건 AppWorld의 Test-C(86.7% 실패), 가장 나았던 건 AG2의 OlympiadBench(41% 실패)였습니다. 프로덕션에 올리는 물건의 기준선이 이렇다는 뜻입니다.

각 실패 범주는 무엇을 청구하는가

먼저 정직하게 말해 둘 것이 있습니다. 모드별로 "이 실패는 얼마"라고 적은 공개 수치는 없습니다. MAST는 출현 빈도를 셌지 비용을 재지 않았고, 제가 찾은 어떤 1차 자료도 실패 모드별 금액을 공개하지 않았습니다. 그러니 여기서 숫자를 지어내는 대신, 각 범주가 청구하는 비용의 종류를 구분하겠습니다. 이 구분이 실무에서는 금액보다 쓸모 있습니다 — 종류가 다르면 대응이 다르기 때문입니다.

범주 1(시스템 설계, 44.2%)은 토큰으로 청구됩니다. 단계 반복(15.7%)과 종료 조건 미인지(12.4%)가 이 범주의 절반 이상을 차지하는데, 둘 다 증상이 "에이전트가 계속 돈다"입니다. 루프 한 바퀴마다 컨텍스트 전체가 다시 모델에 들어가므로 비용은 선형이 아니라 그보다 가파르게 붙습니다. 이 범주의 좋은 점은 가장 싸게 잡힌다는 것입니다 — 턴 수 상한, 예산 상한, 반복 감지는 모델을 건드리지 않고도 넣을 수 있습니다.

범주 2(에이전트 간 어긋남, 32.3%)는 잘못된 부작용으로 청구됩니다. 이 범주의 최다 모드는 추론-행동 불일치(13.2%)로, 논문의 정의대로라면 에이전트의 추론과 실제 행동이 어긋나는 경우입니다. 이건 토큰 문제가 아닙니다. 에이전트가 "A를 하겠다"고 말하고 B를 실행하면, 청구서는 B가 건드린 시스템에 남습니다. 태스크 탈선(7.40%)도 같은 성격입니다.

범주 3(태스크 검증, 23.5%)은 조용히 틀린 산출물로 청구됩니다. 검증 없음/불완전(8.20%)과 잘못된 검증(9.10%)을 합치면 17.3%인데, 이 둘의 공통점은 실패가 실패로 보이지 않는다는 것입니다. 논문이 든 예가 인상적입니다 — ChatDev가 만든 체스 프로그램이 피상적인 테스트는 통과했다는 것이죠. 이 범주가 가장 늦게 발견되고, 그래서 대체로 가장 비쌉니다.

정리하면 이렇습니다.

범주 1 (44.2%)  ->  토큰 청구서       ->  가장 싸게 잡힘 (상한·감지)
범주 2 (32.3%)  ->  잘못된 부작용     ->  멱등성·권한으로 방어
범주 3 (23.5%)  ->  조용히 틀린 결과  ->  가장 늦게 발견, 가장 비쌈

왜 재시도가 안전하지 않은가

이제 핵심입니다. 범주 1의 두 최다 모드(반복·미종료)와 범주 2의 최다 모드(추론-행동 불일치)를 겹쳐 놓으면, 하나의 문장이 나옵니다. 비결정적 호출자가 실제 부작용을 일으키는 도구를 반복해서 부른다.

전통적인 분산 시스템에서 이건 낯선 문제가 아닙니다. 네트워크가 끊기면 클라이언트는 요청이 처리됐는지 모르고, 재시도하면 중복이 생깁니다. 그래서 우리는 멱등성 키를 씁니다. 그런데 에이전트에는 문제가 하나 더 있습니다 — 전통적 클라이언트는 재시도할지를 코드가 결정하지만, 에이전트는 모델이 결정합니다. 모델은 도구가 실패했다고 판단하면(혹은 실패했다고 오판하면) 그냥 다시 부릅니다. 재시도 정책이 프롬프트 안에 있는 셈이고, 그건 정책이 아니라 확률입니다.

여기서 아주 중요한 구분이 하나 있습니다. 재시도가 위험한 건 도구가 실패했을 때만이 아닙니다. 도구가 성공했는데 응답이 유실됐을 때가 더 위험합니다. 이때 모델이 보는 건 "결과 없음"이고, 모델의 합리적 행동은 재시도입니다. 그리고 부작용은 이미 일어났습니다.

MCP는 멱등성을 보장해 주는가 — 힌트는 있고 메커니즘은 없다

그럼 에이전트가 도구를 부르는 표준 프로토콜인 MCP는 이 문제를 어떻게 다룰까요. 현재 최신 스펙 리비전(2025-11-25)의 스키마를 직접 열어 보면 답이 명확합니다.

MCP에는 도구 애노테이션이 있고, 그중 하나가 멱등성 힌트입니다. 스키마의 정의를 그대로 옮기면, 참이면 "같은 인자로 도구를 반복 호출해도 환경에 추가적인 영향이 없다"는 뜻입니다. 네 가지 힌트의 기본값은 이렇습니다.

readOnlyHint      기본값 false   (도구가 환경을 수정한다고 가정)
destructiveHint   기본값 true    (수정이 파괴적이라고 가정)
idempotentHint    기본값 false   (반복 호출에 추가 영향이 있다고 가정)
openWorldHint     기본값 true    (외부 세계와 상호작용한다고 가정)

기본값이 전부 비관적인 쪽으로 잡혀 있다는 데 주목할 만합니다. 애노테이션이 없으면 모든 도구는 파괴적이고 멱등하지 않은 쓰기 작업으로 취급해야 한다는 뜻입니다. 이건 좋은 설계입니다.

그런데 스펙은 이 힌트들에 대해 이렇게 못 박습니다(스키마 주석 원문의 번역입니다).

ToolAnnotations의 모든 속성은 힌트다. 이것들이 도구 동작을 충실하게 기술한다는 보장은 없다(title 같은 서술적 속성을 포함해서). 클라이언트는 신뢰할 수 없는 서버로부터 받은 ToolAnnotations에 근거해 도구 사용을 결정해서는 안 된다.

여기서 진짜 문제가 드러납니다. 2573줄짜리 스키마 전체에서 idempotentHint선언되는 그 한 곳에만 등장합니다. 그리고 "retry"라는 단어는 스키마에 한 번도 나오지 않습니다. 멱등성 키도, 요청 중복 제거 메커니즘도, 재시도 시맨틱도 없습니다.

즉 MCP는 멱등성에 대해 어휘는 주지만 도구는 주지 않습니다. 서버가 "나는 멱등해요"라고 주장할 수는 있는데, 그 주장은 (a) 강제되지 않고 (b) 신뢰할 수 없는 서버에서 오면 믿지 말라고 스펙이 직접 경고하며 (c) 멱등하지 않은 도구를 재시도 안전하게 만들 방법은 프로토콜에 아예 없습니다.

트랜스포트 계층에 재전송이 있지 않냐고 물을 수 있습니다. Streamable HTTP 스펙에는 재개(resumability)와 재전송(redelivery)이 있습니다 — 서버가 SSE 이벤트에 id를 붙이고, 클라이언트가 끊긴 뒤 Last-Event-ID 헤더로 GET을 보내면 서버가 그 지점 이후 메시지를 재생할 수 있습니다. 하지만 이건 서버에서 클라이언트로 가는 메시지를 끊어진 그 스트림에 한해 재생하는 것이고(스펙은 다른 스트림의 메시지를 재생해서는 안 된다고 명시합니다), 스트림 내 커서일 뿐입니다. 클라이언트가 보낸 도구 호출을 중복 제거해 주는 장치가 아닙니다. MCP 스펙 자체의 방향성에 대해서는 MCP가 세션을 걷어낸다 — 스테이트리스 코어 읽기 편에서 따로 다룹니다.

그럼 업계 표준은 어디까지 왔나 — 5년 반째 드래프트

"그냥 멱등성 키 쓰면 되잖아"가 자연스러운 반응입니다. 맞습니다. 그런데 놀랍게도 멱등성 키에는 표준이 없습니다.

IETF HTTPAPI 워킹그룹의 Idempotency-Key HTTP 헤더 드래프트 이력을 데이터트래커에서 직접 확인하면 이렇습니다.

draft-idempotency-header-00                  2020-11-17  (개인 드래프트)
draft-ietf-httpapi-idempotency-key-header-00 2021-07-01  (WG 채택)
                                        -01  2022-05-08
                                        -02  2022-11-09
                                        -03  2023-07-04
                                        -04  2023-11-16
                                        -05  2024-05-27
                                        -06  2025-02-24
                                        -07  2025-10-15  (최신)

현재 상태: Expired (2026-04-18 만료)
IESG 상태: "I-D Exists" — IESG가 처리를 시작한 적 없음

2020년 11월에 시작해 8번 개정됐고, 최신 개정판은 2025년 10월에 올라와 인터넷 드래프트의 6개월 수명 규칙대로 2026년 4월 18일에 만료됐습니다. IESG 상태는 "I-D Exists" — 데이터트래커의 설명 그대로 "IESG가 이 드래프트 처리를 시작하지 않았거나, 출판 없이 처리를 중단했음"입니다. 5년 반 넘게 RFC가 되지 못했습니다.

그래서 현실에서 "멱등성 키"는 표준이 아니라 관행입니다. 그 관행을 가장 잘 문서화한 곳이 Stripe이고, 실제로 위 IETF 드래프트가 성문화하려던 것도 대체로 이 관행입니다. Stripe 문서에서 확인되는 동작은 이렇습니다.

  • 주어진 멱등성 키에 대해 첫 요청의 상태 코드와 응답 본문을 저장하고, 성공이든 실패든 저장한다.
  • 같은 키로 오는 후속 요청은 같은 결과를 돌려준다 — 500 에러까지 그대로 재생한다.
  • 멱등성 계층은 들어온 파라미터를 원 요청과 비교해서, 다르면 에러를 낸다.
  • 키는 최소 24시간이 지나면 정리(prune)될 수 있고, 정리된 뒤 같은 키를 재사용하면 새 요청이 생성된다.
  • 결과는 엔드포인트 실행이 시작된 뒤에만 저장된다. 파라미터 검증 실패나 동시 실행 충돌은 저장되지 않으므로 재시도할 수 있다.

에이전트 관점에서 두 줄이 특히 아픕니다. 하나는 500까지 재생한다는 것 — 멱등 재시도는 "다시 시도"가 아니라 "원래 결과를 다시 보여주기"입니다. 모델이 실패를 보고 재시도하면 실패를 다시 봅니다. 이건 버그가 아니라 설계이고, 모델이 이걸 이해하지 못하면 무한 루프에 빠집니다(그리고 그게 바로 실패 모드 1.3 단계 반복입니다). 다른 하나는 24시간입니다. 며칠에 걸쳐 도는 장기 실행 에이전트가 어제의 키로 재시도하면, 그건 재시도가 아니라 새 부작용입니다.

에이전트 비용을 어떻게 재는가 — OTel에는 비용 지표가 없다

이제 관측 가능성입니다. 표준을 따르고 싶다면 OpenTelemetry의 GenAI 시맨틱 컨벤션을 보게 되는데, 현재 상태를 정확히 알고 시작하는 게 좋습니다.

첫째, GenAI 컨벤션은 이사했습니다. 원래 open-telemetry/semantic-conventions 저장소의 docs/gen-ai에 있었지만, 지금 그 경로의 파일들은 "이 페이지는 이동했으며 더 이상 이 저장소에서 관리되지 않습니다"라는 안내만 남아 있습니다. 새 집은 open-telemetry/semantic-conventions-genai입니다.

둘째, 그 새 저장소는 2026년 5월 5일에 만들어졌고, 아직 릴리스가 하나도 없습니다. (본체 시맨틱 컨벤션의 최신 릴리스는 v1.43.0, 2026년 7월 3일입니다.) 그리고 에이전트 스팬 문서와 MCP 문서 모두 문서 상태가 "Development"입니다. 개발이 멈춘 건 아닙니다 — 마지막 푸시가 이틀 전입니다. 다만 당신이 "표준"이라 부르며 대시보드를 세우는 그 물건은 아직 릴리스된 적 없는 개발 중 스펙이라는 뜻입니다.

셋째, 그리고 이게 실무에서 제일 중요한데 — 비용 지표가 없습니다. GenAI 시맨틱 컨벤션의 메트릭 문서와 속성 레지스트리 전체를 cost, price, usd, dollar로 검색하면 결과가 0건입니다. 정의된 메트릭은 이게 전부입니다.

gen_ai.client.token.usage
gen_ai.client.operation.duration
gen_ai.client.operation.time_to_first_chunk
gen_ai.client.operation.time_per_output_chunk
gen_ai.server.request.duration
gen_ai.server.time_to_first_token
gen_ai.server.time_per_output_token

표준은 토큰을 줍니다. 돈은 당신 몫입니다. 토큰을 금액으로 바꾸려면 모델별 단가표가 필요하고, 그 표는 벤더가 바꿉니다. 벤더들의 비용 대시보드가 저마다 독자 규격이고 서로 숫자가 안 맞는 이유가 여기 있습니다.

토큰을 그냥 더하면 왜 틀리는가

비용을 직접 계산하기로 했다면, 반드시 알아야 할 함정이 하나 있습니다. 속성 레지스트리에 정의된 토큰 속성은 다섯 개입니다.

gen_ai.usage.input_tokens
gen_ai.usage.output_tokens
gen_ai.usage.cache_creation.input_tokens
gen_ai.usage.cache_read.input_tokens
gen_ai.usage.reasoning.output_tokens

문제는 이것들이 평평하지 않고 중첩되어 있다는 점입니다. 레지스트리의 주석이 명시합니다 — 캐시 생성 토큰과 캐시 읽기 토큰은 gen_ai.usage.input_tokens에 포함되어야 하고(SHOULD), 입력 토큰은 캐시된 토큰을 포함해 모든 종류의 입력 토큰을 포함해야 합니다. 추론 토큰도 마찬가지로 gen_ai.usage.output_tokens에 포함되어야 합니다.

그래서 이런 계산은 틀립니다.

잘못된 계산:
  비용 = input_tokens x 입력단가 + output_tokens x 출력단가

왜 틀리나:
  input_tokens 안에 cache_read.input_tokens 가 이미 들어 있음
  캐시 읽기는 신규 입력보다 싸게 과금됨 (그게 캐시를 쓰는 이유)
  -> 캐시가 잘 들을수록, 당신의 계산은 실제보다 비싸게 나옴

올바른 방향:
  신규입력 = input_tokens - cache_read - cache_creation
  비용 = 신규입력 x 입력단가
       + cache_read x 캐시읽기단가
       + cache_creation x 캐시쓰기단가
       + output_tokens x 출력단가
  (단가는 벤더·모델마다 다르므로 여기에 숫자를 적지 않습니다)

에이전트에서 이 오차는 작지 않습니다. 에이전트 루프는 매 턴 같은 시스템 프롬프트와 도구 정의를 다시 보내므로 캐시 적중률이 구조적으로 높고, 그래서 input_tokens 중 캐시 읽기 비중이 큽니다. 순진하게 더하면 캐싱이 잘 될수록 장부상 비용이 부풀려집니다. 캐싱의 비용 효과를 대시보드에서 확인하려다 정반대 결론에 도달할 수 있습니다.

한 겹 더 있습니다. 위 다섯 속성은 스팬 속성이고, 메트릭 gen_ai.client.token.usage의 차원인 gen_ai.token.type의 well-known 값은 inputoutput 둘뿐입니다. 즉 집계된 메트릭만 보고서는 캐시된 토큰과 신규 토큰을 구분할 수 없습니다. 정확한 비용을 내려면 스팬 단위로 내려가야 합니다. (커스텀 값을 쓸 수는 있지만, 그 순간 표준이 아니게 됩니다.)

무엇을 계측해야 하는가 — 그리고 옵트인 함정

도구 호출 계측은 execute_tool 스팬으로 합니다. 스팬 이름은 execute_tool 뒤에 도구 이름을 붙이는 형태이고, 속성은 이렇습니다.

gen_ai.operation.name        Required            (Development)
gen_ai.tool.name             Required            (Development)
error.type                   Recommended         (Stable)
gen_ai.agent.name            Conditionally Req.  (Development)
gen_ai.tool.call.id          Recommended         (Development)
gen_ai.tool.description      Recommended         (Development)
gen_ai.tool.type             Recommended         (Development)
gen_ai.tool.call.arguments   Opt-In              (Development)   <- 기본 미수집
gen_ai.tool.call.result      Opt-In              (Development)   <- 기본 미수집

마지막 두 줄이 함정입니다. 에이전트가 무슨 인자로 도구를 불렀고 무엇을 돌려받았는지는 "Opt-In" — 즉 기본적으로 수집되지 않습니다. 그럴 만한 이유가 있습니다(개인정보와 저장 비용). 하지만 결과적으로, 에이전트가 왜 엉뚱한 짓을 했는지 디버깅하는 데 정확히 필요한 그 두 필드가 기본으로 꺼져 있습니다. 범주 2(추론-행동 불일치)를 추적하려면 이걸 켜야 하고, 켜는 순간 트레이스에 민감정보가 들어올 수 있습니다. 공짜 점심이 아닙니다 — 샘플링·마스킹과 함께 의식적으로 결정해야 하는 트레이드오프입니다.

MCP를 쓴다면 하나 더 알아야 합니다. MCP 시맨틱 컨벤션 문서는 HTTP 트레이스 컨텍스트 전파가 HTTP 요청만 덮고 요청/응답 스트림 안에서 오가는 개별 메시지는 덮지 못한다고 지적합니다. 그래서 계측은 MCP 요청의 params._meta 주머니에 컨텍스트를 주입해야 하고(SEP-414가 traceparent, tracestate, baggage 키의 처리를 정의합니다), 수신 측이 그걸 원격 부모로 씁니다. 이걸 안 하면 에이전트 트레이스가 MCP 경계에서 끊깁니다. 로깅·트레이싱 일반론은 LLM 로그와 트레이싱 편을 참고하세요.

고치면 실제로 나아지는가 — 정직한 개입 결과

여기가 이 글에서 가장 정직해야 할 부분입니다. MAST 논문은 분류만 하고 끝내지 않고, 분류를 근거로 실제 개입을 해 봤습니다. 결과(논문 Table 5)는 이렇습니다.

AG2 / GSM-Plus (GPT-4)      기준선 84.75 +- 1.94 | 프롬프트 개선 89.75 +- 1.44 | 토폴로지 변경 85.50 +- 1.18
AG2 / GSM-Plus (GPT-4o)     기준선 84.25 +- 1.86 | 프롬프트 개선 89.00 +- 1.38 | 토폴로지 변경 88.83 +- 1.51
ChatDev / ProgramDev-v0     기준선 25.0          | 프롬프트 개선 34.4          | 토폴로지 변경 40.6
ChatDev / HumanEval         기준선 89.6          | 프롬프트 개선 90.3          | 토폴로지 변경 91.5

널리 인용되는 "+9.4%"와 "+15.6%"가 여기서 나옵니다. ChatDev의 ProgramDev-v0에서 25.0 → 34.4이 +9.4, 25.0 → 40.6이 +15.6입니다. 퍼센트가 아니라 퍼센트 포인트입니다.

그런데 이 숫자를 인용할 거라면 반드시 함께 말해야 할 것이 있습니다.

첫째, ProgramDev-v0는 32개 태스크입니다. 32개에 대한 25.0%는 8개, 34.4%는 11개, 40.6%는 13개입니다(계산이 정확히 맞아떨어집니다). 즉 화제의 "+9.4%p"는 태스크 3개, "+15.6%p"는 태스크 5개를 더 통과했다는 뜻입니다. 작은 표본입니다.

둘째, 최선의 개입 이후에도 성공률은 40.6%입니다. 다시 말해 여전히 약 59%가 실패합니다. 논문의 표현을 그대로 옮기면 "초기 단계의 개입이 성능 향상으로 이어지긴 하지만, 모든 실패 모드가 해소되지는 않으며 태스크 완료율은 여전히 낮아, 더 실질적인 개선이 필요함을 시사한다"입니다.

셋째, 효과가 보편적이지 않습니다. AG2에서 토폴로지 변경은 GPT-4에서 윌콕슨 검정 p값 0.4로 통계적으로 유의하지 않았고, 같은 변경이 GPT-4o에서는 p값 0.03으로 유의했습니다. 논문의 결론은 "이 전략들은 보편적이지 않으며, 그 효과는 기저 LLM 같은 요인에 따라 달라진다"입니다.

넷째, 방향성은 있습니다. 논문은 두 시스템 모두에서 토폴로지 기반 변경이 프롬프트 기반 변경보다 효과적이었다고 보고합니다. 그리고 저자들은 견고한 신뢰성에는 "고립된 수정 이상"이 필요하며 "근본적인 MAS 재설계"를 향해야 한다고 못 박습니다.

마지막으로 이 자료 자체의 한계. 1642건 중 대부분은 저자들이 만든 o1 기반 LLM 어노테이터가 라벨링했습니다. 사람이 검증한 건 훨씬 적은 부분집합입니다(카파 0.88은 트레이스 15건에 대한 어노테이터 3명의 일치도입니다). 저자들 스스로 "MAST가 모든 잠재적 실패 패턴을 포괄한다고 주장하지 않는다"고 적었습니다. 이건 결정적 지도가 아니라, 지금까지 나온 것 중 가장 경험적인 지도입니다.

그래서, 무엇을 해야 하나 — 결정 규칙

위 자료들에서 곧장 따라 나오는 규칙입니다.

1. 도구를 부작용 기준으로 먼저 분류하라. MCP 기본값이 이미 정답을 알려 줍니다 — 애노테이션이 없으면 파괴적·비멱등으로 취급합니다. 읽기 전용 도구와 쓰기 도구를 섞어 놓고 재시도 정책을 하나로 가져가지 마세요.

2. 멱등성은 당신 계층에서 구현하라. MCP의 idempotentHint는 힌트지 보장이 아니고, 신뢰할 수 없는 서버의 애노테이션은 믿지 말라고 스펙이 직접 말합니다. IETF 표준도 없습니다. 그러니 부작용을 일으키는 도구는 당신의 서버 쪽에서 키를 받아 첫 결과를 저장하고 재생하십시오. Stripe의 관행이 검증된 참고 구현입니다 — 결과(에러 포함)를 저장하고, 파라미터 지문을 비교하고, 보존 기간을 명시하는 것까지.

3. 키를 모델이 만들게 하지 마라. 재시도를 결정하는 주체가 비결정적이므로, 멱등성 키는 결정적인 곳 — 오케스트레이터의 스텝 ID나 태스크 ID — 에서 파생시켜야 합니다. 모델이 매번 새 키를 지어내면 멱등성 키는 장식입니다.

4. 상한을 예산으로 걸어라. 실패의 28.1%가 반복과 미종료라면, 턴 상한과 토큰 예산은 최적화가 아니라 차단기입니다. 가장 흔한 실패 범주를 가장 싸게 막는 방법입니다.

5. 비용은 스팬에서 계산하라. 메트릭만으로는 캐시 토큰을 분리할 수 없습니다. 그리고 토큰을 그냥 더하지 마세요 — 캐시 읽기는 이미 input_tokens 안에 있습니다.

6. 인자와 결과 수집을 의식적으로 결정하라. 기본은 꺼짐입니다. 켜지 않으면 범주 2를 디버깅할 수 없고, 켜면 민감정보가 트레이스에 들어옵니다. 샘플링과 마스킹을 함께 설계하십시오.

언제 이 모든 걸 하지 말아야 하나

정직한 반대편입니다. 위의 대부분은 에이전트가 진짜 부작용을 굴릴 때만 값을 합니다.

  • 읽기 전용 에이전트라면 멱등성 인프라는 과잉입니다. 검색·요약·분석만 하는 에이전트에서 중복 호출은 돈만 더 쓸 뿐 상태를 망가뜨리지 않습니다. 상한만 걸고 넘어가세요.
  • 사람이 모든 쓰기를 승인한다면 재시도 위험은 대부분 사라집니다. 승인 게이트는 멱등성 계층보다 싸게 구현되고, 초기 단계에서는 대체로 더 낫습니다.
  • 워크플로로 충분하다면 에이전트를 쓰지 마세요. MAST의 실패 대부분은 시스템 설계 이슈이고, 그건 "결정을 모델에게 넘긴 만큼" 생깁니다. 경로가 정해져 있다면 코드로 짜세요 — 효과적인 AI 에이전트 만들기 편에서 다룬 워크플로/에이전트 구분이 여기서 그대로 유효합니다.
  • 단일 에이전트로 되면 멀티 에이전트로 가지 마세요. MAST 실패의 32.3%는 에이전트 사이에서 났습니다. 에이전트를 하나 더 붙이는 순간 그 32.3% 표면적을 새로 삽니다.

마치며

정리하면 이렇습니다. 에이전트 실패는 모델의 실패가 아니라 대체로 시스템 설계의 실패입니다(MAST 기준 44.2%). 가장 흔한 두 모드는 반복과 미종료이고(합쳐서 28.1%), 이 둘은 토큰을 태우는 동시에 부작용을 중복시킵니다. 그리고 그 중복을 막아 줄 프로토콜 차원의 장치는 없습니다 — MCP는 멱등성 힌트만 주고, IETF의 멱등성 키 표준은 5년 반째 드래프트이며 지금 만료 상태입니다. 관측 가능성 쪽도 비슷합니다 — OTel GenAI 컨벤션은 릴리스도 없는 개발 중 스펙이고, 비용 지표가 아예 없으며, 디버깅에 필요한 인자·결과는 기본으로 꺼져 있습니다.

이 목록은 비관하라는 뜻이 아니라, 어디를 당신이 직접 메워야 하는지의 지도입니다. 표준이 채워 줄 거라 기대하고 비워 둔 칸이 바로 프로덕션에서 청구서가 날아오는 칸입니다.

그리고 마지막으로, 개입 결과를 다시 봅시다. 최선의 구조적 개입 뒤에도 코드 생성 성공률은 25.0%에서 40.6%였습니다 — 여전히 절반 넘게 실패합니다. 프로덕션 에이전트를 운영한다는 건 실패를 없애는 일이 아니라, 실패의 비용을 아는 일에 가깝습니다. 어떤 실패가 토큰만 태우고, 어떤 실패가 상태를 망가뜨리고, 어떤 실패가 조용히 틀린 답을 내보내는지. 그 셋을 구분하는 순간부터가 운영입니다. 에이전트를 무엇으로 어떻게 측정할지의 문제는 시뮬레이션된 고객은 절대 떠나지 않는다 편에서, 에이전트를 격리해 굴리는 문제는 Lambda 마이크로VM 에이전트 샌드박스 편에서 이어집니다.

참고 자료

현재 단락 (1/155)

데모에서 잘 도는 에이전트를 프로덕션에 올리면 질문이 바뀝니다. "이게 되나?"에서 "이게 왜 안 됐고, 얼마를 태웠고, 다시 시도해도 되나?"로요. 이 글은 그 세 질문에 순서대...

작성 글자: 0원문 글자: 13,339작성 단락: 0/155