에이전트가 200을 반환하고 거짓말한다. 신뢰하기 전에 확인하세요.

발행: (2026년 6월 11일 AM 03:05 GMT+9)
10 분 소요
원문: Dev.to

출처: Dev.to

성공 게이트는 시스템이 AI 에이전트의 주장된 성공을 받아들이기 전에 이를 검증합니다. SuccessGate는 세 가지 읽기 전용 검사를 수행합니다 — 스키마/계약, 실제 툴 호출 트레이스와 비교한 claim‑vs‑evidence, 그리고 선택적인 사후 조건 프로브 — 그리고 조용히 반환된 200 응답을 이유와 함께 명시적인 REJECTED 로 바꿉니다. 표준 라이브러리만 사용하는 파이썬 코드이며, API 키가 필요 없고, 어떤 동작도 수행하지 않으며, 한 줄 명령으로 실행할 수 있는 자체 테스트를 포함하고 있습니다.

아래는 제가 처음 겪은 실패 사례입니다. CRM 워크플로우 내의 에이전트가 인보이스에 대해 {"status": "sent", ...} 라고 보고했습니다. 정상 실행, 대시보드 초록색, 200 OK. 그런데 그 인보이스는 허용 목록에 없는 고객 ID로 전송되었습니다 — 모델이 완전히 확신하고 있던 근소한 환각이었습니다. 아무런 오류도, 예외도, 스택 트레이스도 발생하지 않았습니다. 우리는 며칠 뒤, 하위 단계에서 비싼 비용을 들여 이를 발견했습니다.

이것은 드문 버그가 아닙니다. 프로덕션 환경에서 에이전트가 기본적으로 겪는 실패 모드이며, 이제는 silent‑success drift 라는 이름이 붙었습니다. Cycles의 글에서는 이를 직설적으로 표현했습니다 — “200 OK Is the Most Dangerous Response in Production”: “가장 위험한 실패는 성공처럼 보인다.” 그리고 측정 결과도 이를 뒷받침합니다. Berkeley Function‑Calling Leaderboard (BFCL v3)는 정제된 벤치마크 프롬프트에서도 최첨단 모델이 구조적으로 잘못된 툴 호출을 2–5% 정도 발생시킨다고 보고합니다 — 노이즈가 많은 프로덕션 환경에서는 더 높습니다 (Future AGI). arXiv 논문 Agent Behavioral Contracts에서는 1,980개 세션 전체에서 계약을 적용한 에이전트가 세션당 5.2–6.8개의 부드러운 위반을 잡아냈으며, 계약을 적용하지 않은 베이스라인은 이를 전혀 놓쳤다고 합니다.

따라서 문제는 실패를 더 빨리 보는 방법이 아니라 에이전트가 실제로 달성하지 못한 성공을 받아들이지 않는 방법입니다.

TL;DR

  • 200 응답과 "status": "done"주장일 뿐, 증거가 아닙니다. 에이전트는 잘못된 작업을 수행하면서도, 혹은 아무 작업도 하지 않으면서도 두 값을 반환할 수 있습니다.
  • 관측성은 추적입니다: 호출이 있었는지 알려줄 뿐, 결과가 올바른지는 알려주지 못합니다. 이는 제어 문제입니다.
  • verify()는 성공을 받아들이기 전에 세 가지 검사를 수행합니다: (1) 스키마/계약 (형태, 타입, 열거형/허용 목록), (2) claim‑vs‑evidence (에이전트가 실제로 선언한 툴을 호출했는가?), (3) 선택적인 읽기 전용 사후 조건 프로브 (효과가 실제로 존재하는가?).
  • 순수 표준 라이브러리만 사용합니다; requests는 선택 사항이며 레벨‑3 프로브에만 필요합니다. 키도, 자금도, 블록체인도 없습니다.
  • 4개의 고정 테스트가 내장되어 있습니다: python success_gate.py. 에이전트도, 키도 필요 없습니다.
  • 이것은 게이트이며, 평가 스위트가 아닙니다. 제한 사항은 문서 하단에 있습니다.

이 글은 에이전트를 실행 후가 아니라 실행 전에 제어하는 작은 시리즈의 세 번째 조각입니다. 1부는 런어웨이 루프를 막는 사전 지출 한도 — 에이전트가 돈을 쓰지 못하게 함. 2부는 전송 전 트랜잭션 카나리 — 나쁜 트랜잭션을 보내지 못하게 함. 이번 글은 같은 사전 실행 레이어의 세 번째 포인트: 실제 존재하지 않는 성공을 받아들이지 않기. 지출, 전송, 수락 — 같은 아이디어, 세 단계.


당신의 대시보드는 추적합니다. 제어는 하지 못합니다.

제가 사용해 본 모든 에이전트 관측 도구는 같은 유용한 일을 합니다: 무슨 일이 있었는지 기록합니다. 스팬, 트레이스, 툴 호출 타임라인, 지연 시간, 200 반환 시 초록 체크마크 등. 이것을 비판하는 것이 아니라, 필요하기 때문에 사용합니다. 하지만 실제로 무엇을 알고 있는지를 살펴보세요.

  • 호출이 있었는지는 알지만, 그 호출이 올바른 일을 했는지는 모릅니다.

이 격차를 보여주는 설문 결과가 있습니다. 2026년 1,300명 이상의 AI 전문가를 대상으로 한 설문에서 **조직의 89%가 관측성을 갖추고 있지만, 실제로 각 단계에서 에이전트가 무엇을 하는지 검사할 수 있는 비율은 62%**에 불과했습니다 (Cycles). 추적은 거의 보편적이지만, 결과를 검증할 수 있는 능력은 전체의 3분의 1 수준에 머물러 있습니다. 바로 이 차이가 silent‑success drift 가 존재하는 지점입니다.

그리고 이 문제는 복합적으로 악화됩니다. 모두가 인용하는 산술은 실제입니다: 단계당 95% 정확도를 가정하면 10단계 워크플로우가 전체적으로 올바르게 동작할 확률은 약 60%에 불과하고, 85% 정확도에서는 약 20%에 불과합니다. 구조화된 출력은 큰 도움이 됩니다 — Agentmelt의 프로덕션 데이터에 따르면 **구조화된 출력 사용 시 작업 성공률이 95–99%**이며, 비구조화된 텍스트 파싱 시는 **70–85%**에 머물러 있습니다 (Agentmelt). 하지만 구조화된 출력이 해결하는 것은 형태일 뿐, 에이전트가 그 형태가 의미하는 작업을 실제로 수행했는지는 보장하지 못합니다. {"status": "updated"} 라는 완벽한 JSON을 반환했지만 update 를 전혀 호출하지 않은 에이전트는 정직한 에이전트와 동일하게 잘 형성된 결과를 만든 것입니다.

따라서 관측성, 구조화된 출력, 초록색 대시보드가 모두 갖춰져 있어도 거짓을 배포할 수 있습니다. 빠진 조각은 “에이전트가 끝났음”과 “우리가 받아들인다” 사이에 위치한 단계이며, 여기서 “증명해 보라”고 요구합니다.


해결책의 형태: 수락 전 게이트

한 문장으로 요약하면 다음과 같습니다. 에이전트의 결과를 성공으로 간주하기 전에 계약을 적용하고, 주장을 뒷받침하지 못하면 조용한 200 응답을 통과시키지 말고 REJECTED 로 표시한다.

세 가지 검사는 의도적으로 비대칭적이며, 결과가 거짓일 수 있는 세 가지 경우를 각각 잡아냅니다:

  1. 스키마 / 계약 검사
    • 출력이 성공 형태를 갖추었는가? 필수 필드 존재, 타입 일치, 허용된 값인지(예: target_id 허용 목록) 확인합니다. 이는 BFCL이 보고한 2–5%의 구조적 오류를 잡아내는 저비용 검사입니다. `cust
0 조회
Back to Blog

관련 글

더 보기 »

Eidentic 소개

Today we're releasing Eidentic, an open-source TypeScript SDK for building AI agents with self-improving memory and the production fundamentals built in — not b...

Typescript의 타입

Introdução Tipos são uma forma de definir a “forma” ou o contrato dos dados que estamos usando no código. Pensando em Javascript puro, ele é dinâmico: você pode...