에이전트가 200 OK를 반환하며 거짓말을 할 때: 신뢰하기 전에 검증하세요
요약
AI 에이전트가 잘못된 작업을 수행하고도 200 OK 응답을 반환하는 '침묵하는 성공 드리프트' 문제를 해결하기 위한 Success Gate를 소개합니다. 스키마 검증, 도구 호출 추적, 사후 조건 조사를 통해 에이전트의 주장이 실제 증거와 일치하는지 검증합니다.
핵심 포인트
- 에이전트의 200 OK 응답은 성공의 증거가 아닌 단순한 주장일 수 있음
- 침묵하는 성공 드리프트(silent-success drift)는 프로덕션 환경의 주요 실패 모드
- Success Gate는 스키마, 도구 호출 추적, 사후 조건 조사를 통해 검증 수행
- 관측성을 넘어 에이전트의 실행 결과에 대한 제어(control)가 필요함
Success Gate는 시스템이 수락하기 전에 AI 에이전트가 주장하는 성공 여부를 검증합니다. SuccessGate는 세 가지 읽기 전용(read-only) 체크 — 스키마/계약(schema/contract), 실제 도구 호출 추적(tool-call trace)에 대한 주장 대 증거(claim-vs-evidence) 비교, 그리고 선택적인 사후 조건 조사(post-condition probe) — 를 실행하며, 침묵하는 200 응답을 명시적인 REJECTED와 그 이유로 전환합니다. 이는 표준 라이브러리(stdlib) Python으로 구현되어 API 키가 필요 없으며, 데이터를 이동시키지 않고, 한 번의 명령으로 실행 가능한 셀프 테스트와 함께 제공됩니다.
제가 이 일을 시작하게 된 실패 사례는 다음과 같습니다. CRM 워크플로우의 한 에이전트가 송장에 대해 {"status": "sent", ...}라고 보고했습니다. 깔끔한 실행. 녹색 대시보드. 200 OK. 하지만 송장은 우리의 허용 목록(allow-list)에 없는 고객 ID로 전송되었습니다. 모델이 완전히 확신하고 있었던, 아찔한 환각(hallucination) 사례였습니다. 아무것도 충돌하지 않았습니다. 예외(exception)도, 스택 트레이스(stack trace)도 없었습니다. 우리는 며칠 뒤, 하류(downstream) 단계에서 아주 비싼 대가를 치르고 나서야 이를 발견했습니다.
이것은 드문 버그가 아닙니다. 프로덕션 환경에서 에이전트들이 보이는 기본 실패 모드이며, 이제는 이름도 생겼습니다: 침묵하는 성공 드리프트 (silent-success drift). Cycles의 글은 이를 직설적으로 표현했습니다 — "200 OK는 프로덕션에서 가장 위험한 응답이다": "가장 위험한 실패는 성공처럼 보인다." 그리고 측정 데이터가 이를 뒷받침합니다. Berkeley Function-Calling Leaderboard (BFCL v3)에 따르면, 최첨단 모델(frontier-model)조차 깨끗한 벤치마크 프롬프트에서 **구조적으로 유효하지 않은 도구 호출(structurally invalid tool calls)이 25%**에 달하며, 노이즈가 많은 프로덕션 환경에서는 이보다 더 높습니다 (via Future AGI). arXiv 논문 Agent Behavioral Contracts는 1,980개의 세션에 걸쳐, 계약된 에이전트들이 계약되지 않은 베이스라인 모델들이 완전히 놓친 **세션당 5.26.8개의 소프트 위반(soft violations)**을 잡아냈다고 보고합니다.
따라서 질문은 _어떻게 하면 실패를 더 빨리 발견할 것인가_가 아닙니다. 핵심은 에이전트가 실제로 달성하지 못한 성공을 어떻게 하면 수락하지 않을 것인가입니다.
요약 (TL;DR)
- 200 OK 응답과
"status": "done"은 주장(claims)일 뿐, 증거(proof)가 아닙니다. 에이전트는 잘못된 작업을 수행하면서도 이 두 가지를 반환하거나, 혹은 아무것도 반환하지 않을 수 있습니다. - 관측성 (Observability)은 _추적 (tracking)_입니다. 호출이 발생했다는 사실을 알려줄 뿐, 그 결과가 올바른지는 알려줄 수 없습니다. 그것은 _제어 (control)_의 문제입니다.
verify()는 성공을 수락하기 전에 세 가지 검사를 실행합니다: (1) 스키마/계약 (형태, 타입, 열거형/허용 목록), (2) 주장 대 증거 (에이전트가 사용했다고 주장하는 도구를 실제로 호출했는가?), (3) 선택적 읽기 전용 사후 조건 조사 (효과가 실제로 존재하는가?).- 표준 라이브러리(Stdlib)만 사용합니다;
requests는 선택 사항이며 레벨 3 조사에만 사용됩니다. 키(key), 자금(funds), 블록체인은 포함되지 않습니다. - 4개의 피스처(fixtures)에 대한 내장 자체 테스트를 제공합니다:
python success_gate.py. 에이전트나 키가 필요 없습니다. - 이것은 게이트(gate)이지, 평가 스위트(eval suite)가 아닙니다. 하단에 제한 사항이 있습니다.
이 글은 에이전트가 실행한 후가 아니라, 실행하기 전에 제어하는 방법에 관한 짧은 시리즈의 세 번째 글입니다. 첫 번째 글은 폭주하는 루프를 위한 엄격한 실행 전 지출 한도 설정 — 에이전트가 돈을 쓰지 못하게 하는 법이었습니다. 두 번째 글은 전송 전 트랜잭션 카나리 (canary) — 잘못된 트랜잭션을 보내지 못하게 하는 법이었습니다. 이번 글은 동일한 실행 전 계층(pre-execution layer)에 대한 세 번째 지점입니다: 실제가 아닌 성공을 수락하지 마십시오. 지출(spend), 전송(send), 수락(accept) — 같은 아이디어이며, 세 군데의 지점을 다룹니다.
대시보드는 추적할 뿐, 제어하지 않습니다.
제가 사용해 본 모든 에이전트 관측성 (agent-observability) 도구들은 동일하게 유용한 일을 수행합니다. 바로 무슨 일이 일어났는지 기록하는 것입니다. 스팬 (Spans), 트레이스 (traces), 도구 호출의 타임라인, 지연 시간 (latency), 그리고 실행이 200을 반환할 때 나타나는 초록색 체크 표시 같은 것들 말이죠. 이를 비난하는 것이 아닙니다. 이런 도구들은 반드시 필요합니다. 하지만 _그 도구들이 실제로 무엇을 알고 있는지_를 보십시오.
그 도구들은 호출이 이루어졌다는 사실은 압니다. 하지만 그 호출이 올바른 일을 수행했는지는 알지 못합니다.
이 간극을 포착하는 설문조사 결과가 있습니다. 1,300명 이상의 AI 전문가를 대상으로 한 2026년 조사에 따르면 89%의 조직은 관측 가능성(observability)을 갖추고 있지만, 실제로 에이전트가 각 단계에서 무엇을 수행했는지 검사할 수 있는 곳은 62%에 불과합니다 (Cycles). 추적(Tracking)은 거의 보편적입니다. 하지만 결과를 확인하는 능력은 해당 분야의 3분의 1 정도 뒤처져 있습니다. 이 차이가 바로 조용한 성공 드리프트(silent-success drift)가 존재하는 지점입니다.
그리고 이것은 복리처럼 쌓입니다. 모두가 인용하는 산술적 계산은 실제입니다: 단계별 정확도가 95%일 경우, 10단계 워크플로우는 겨우 약 60%의 확률로 올바르게 작동하며; 85%일 경우, 약 20%에 불과합니다. 구조화된 출력(structured output)은 많은 도움을 줍니다 — Agentmelt의 프로덕션 데이터에 따르면 **구조화된 출력을 사용할 때 액션 성공률이 95–99%인 반면, 비정형 텍스트를 파싱할 때는 70–85%**입니다 (Agentmelt). 하지만 구조화된 출력이 무엇을 고쳐주는지 주목하십시오: 그것은 _모양(shape)_만을 보장합니다. 에이전트가 update를 호출한 적이 없더라도 완벽하게 형성된 {"status": "updated"}는 정직한 결과만큼이나 잘 형성되어 있습니다.
따라서 관측 가능성, 구조화된 출력, 그리고 녹색 대시보드를 가지고 있어도 거짓말을 배포할 수 있습니다. 빠진 조각은 '에이전트 완료'와 '우리가 이를 수용한다' 사이에 위치하여
- 체크 1 — 스키마 / 계약 (schema / contract). 출력 형식이 성공의 형태를 갖추고 있는가? 필수 필드가 존재하고, 올바른 타입이며,
target_id와 같은 항목에 대한 **허용 목록 (allow-list)**을 포함하여 허용된 집합 내의 값인가? 이는 BFCL의 2~5%를 잡아내는 저렴한 방법으로, 잘못된 형식의 JSON, 누락된 필드, 허용되지 않은 ID 등을 찾아냅니다.cust_9999로 청구하려다 실패한 사례는 여기서 걸러집니다. - 체크 2 — 주장 대 증거 (claim vs evidence). 에이전트가 말한 대로 수행했는가? 실제 도구 호출 추적 (tool-call trace)을 따라가 보십시오. 결과는 `
단 한 번의 호출로, 당신이 현재 에이전트의 말을 신뢰하고 있는 바로 그 지점에서 검증하십시오. 당신은 이미 에이전트에게 필요한 네 가지 요소를 갖추고 있습니다: 에이전트의 구조화된 결과 (structured result), 당신의 계약 (contract), 프레임워크가 기록한 도구 호출 추적 (tool-call trace), 그리고 (선택 사항인) 읽기 전용 프로브 (read-only probe)입니다.
gate = verify(
result=agent_result, # 에이전트가 반환한 것
contract=my_contract, # 여기서 '실제 성공'이 의미하는 것
...
raise는 역방향의 '돌이킬 수 없는 지점 (point of no return)'입니다. 만약 게이트 (gate)가 거부하면, "완료 처리 (mark done)" 코드는 절대 실행되지 않습니다. 사유 목록 (reasons list)은 로그에 표시되는 내용입니다. 따라서 새벽 3시에 무언가가 거부되었을 때, 단순히 빨간색 숫자만 보는 것이 아니라 "'updated'라고 주장하지만 'update_record'를 호출하지 않음"과 같이 왜 거부되었는지를 알 수 있습니다.
계약 (contract)이 게임의 핵심이며, 이는 당신이 직접 작성하는 부분입니다. required는 형태를 정의합니다. enums는 허용 목록 (allow-lists)이 존재하는 곳으로, 가장 유용한 필드입니다. 왜냐하면 "에이전트가 임의로 만들어낸 ID"가 제가 목격하는 가장 흔한 드리프트 (drift)이기 때문입니다. claim_requires_action은 각 주장 동사 (claim verb)를 이를 뒷받침해야 하는 도구 (tool)에 매핑합니다. 당신을 괴롭혔던 워크플로우 하나부터 시작하여 점차 확장해 나가십시오.
실행하기 (Run it)
python success_gate.py
계정, 키, 네트워크가 필요 없습니다. 처음 두 가지 체크는 순수 표준 라이브러리 (stdlib)를 사용합니다. 셀프 테스트의 레벨 3 프로브 (level-3 probe)는 False를 반환하는 로컬 스텁 (stub)이므로, 서버를 구축하지 않고도 잘못된 효과에 의한 거부를 확인할 수 있습니다. pip install requests는 당신의 통합 환경에서 선택적 프로브가 실제 읽기 전용 GET 요청을 수행하기를 원하는 경우에만 설치하십시오.
출력 (Output)
SuccessGate self-test - no agent, no key, offline
--- fixture 1: valid - created, with a real create_record call ---
...
여기서 결정론적 (deterministic)인 것은 숫자가 아니라 판결 (verdicts)입니다. Fixture 1은 ACCEPTED입니다. 즉, 스키마 (schema)가 유효하며 created 주장이 실제 create_record 호출에 의해 뒷받침됩니다. Fixture 2, 3, 4는 각각 세 가지 다른 이유로 REJECTED 처리됩니다: 깨진 JSON, 일치하는 도구 호출이 없는 주장, 그리고 계약의 허용 목록과 프로브 모두가 거부하는 효과입니다. 세 가지 서로 다른 거짓말, 세 가지 서로 다른 포착, 그 중 어느 것도 조용한 200 OK가 아닙니다.
이것이 아닌 것 (What this is not)
이 기술의 범위를 벗어나서 여러분이 이를 맹신하게 만들기보다는, 차라리 과소평가하는 편을 택하겠습니다. 잘못된 확신을 주는 게이트는 게이트가 없는 것보다 더 나쁩니다.
- 이것은 평가 (evals)나 테스트를 대체하는 것이 아닙니다. SuccessGate는 한 번에 하나의 결과에 대해 작동하는 런타임 (runtime) 게이트입니다. 이는 에이전트가 전체적으로 우수한지를 알려주지 않으며, 데이터셋 전체의 품질을 측정하지도 않고, 프롬프트 변경이 성능 저하를 일으켰는지 알려주는 오프라인 평가 (offline eval) 스위트를 대체하지도 않습니다. 둘 다 실행하십시오. 이들은 서로 다른 질문에 답합니다.
- 명시적인 계약 (contract) 없이는 '의미론적으로는 맞지만 바람직하지 않은' 경우를 잡아낼 수 없습니다. 만약 에이전트가 올바른 레코드를 잘못된 비즈니스 결정(법적으로는 문제가 없으나 어리석은 행동)으로 업데이트했는데, 여러분의 계약에 이를 금지하는 규칙이 인코딩되어 있지 않다면, 게이트는 이를 통과시킵니다. 게이트의 성능은 여러분이 작성한 계약의 수준과 정확히 일치합니다. 빈 계약은 아무것도 검증하지 못합니다.
- 레벨 3 조사 (level-3 probe)는 효과를 확인할 수 있는 읽기 전용 (read-only) 방식이 필요합니다. "송장이 발송되었는가"는 질문할 수 있는 읽기 엔드포인트 (read endpoint)가 있어야만 검증 가능합니다. 읽기 피드백이 없는 효과(발송 후 잊어버리는 방식의 부수 효과(side effects), 쿼리할 수 없는 제3자 작업 등)의 경우, 체크 3은 단순히 적용되지 않으며, 여러분은 체크 1과 2에 의존하게 됩니다.
- 자가 테스트 (self-test)는 메커니즘 데모이지, 벤치마크 (benchmark)가 아닙니다. 네 가지 피스처 (fixtures)는 각 체크가 어떻게 실행되는지를 보여줍니다. 이는 실제 에이전트가 얼마나 자주 이탈하는지를 측정하는 것이 아닙니다. 그에 대해서는 상단의 arXiv 및 BFCL 수치를 참조하십시오. 그것들은 실제 연구 결과이며, 제가 직접 만든 네 가지 사례와는 다릅니다.
이 중 그 어느 것도 핵심 주장(core claim)을 훼손하지 않습니다. 에이전트가 성공이라고 주장하는 결과를 수락하기 전에 계약을 거치게 하는 것은, cust_9999를 게이트에서 잡아내느냐 아니면 일주일 뒤 하류 (downstream) 단계에서 발견하느냐의 차이입니다.
내가 여전히 고민 중인 한 가지 질문
그 명확한 경계선은 계약(contract)이 확인할 수 있는 효과와 오직 인간만이 판단할 수 있는 효과 사이에 있습니다. target_id in allow_list는 명확합니다. 기계가 확인할 수 있으며 논쟁의 여지가 없습니다. 하지만 "이 인보이스(invoice)가 정확한가"는 그렇지 않습니다. 적어도 명확하지는 않습니다. 금액, 품목(line items), 세금, 그리고 고객의 실제 의도 같은 것들 말입니다. 저는 "정확함"의 더 많은 부분을 사후 조건(post-conditions)으로 인코딩해 왔습니다. 즉, 레코드를 다시 읽어와서 합계가 참조하는 주문과 일치하는지 단언(assert)하는 방식입니다. 이 방식은 단언(assertion) 자체에 판단이 필요해지기 전까지는 효과적입니다. 여러분은 어디에서 선을 긋습니까? 여러분의 팀은 "인보이스가 올바르다"라는 것을 사람이 눈으로 확인하는 대신, 어떻게 기계가 확인할 수 있는 사후 조건(post-condition)으로 인코딩합니까? 만약 여러분이 허용 목록(allow-list)이나 다시 읽기(read-back)보다 더 멀리 그 경계를 밀어붙여 본 경험이 있다면, 어떻게 했는지 정말 알고 싶습니다. 댓글로 남겨주세요.
이 글은 에이전트를 위한 실행 전 제어(pre-execution control)에 관한 시리즈의 세 번째 파트입니다. 에이전트가 과도하게 지출하게 두지 말고, 잘못된 트랜잭션(transaction)을 전송하게 두지 마십시오. 그리고 에이전트가 달성하지도 못한 성공을 그대로 받아들이지 마십시오.
AI의 도움을 받아 작성되었으며 사람이 검토 및 편집했습니다. 이 포스트의 코드는 게시 전에 실행되었습니다. 위의 출력 블록은 실제 실행 결과(2026-06-08)입니다. 외부 수치들 — BFCL v3의 25% 유효하지 않은 도구 호출(Future AGI 제공), Agentmelt의 구조화된 액션 대비 비구조화된 액션의 성공률 9599% 대 7085%, arXiv 2602.22302의 수치(1,980 세션, 세션당 5.26.8회의 소프트 위반, 200개 시나리오), 그리고 Cycles의 89%/62% 설문 조사 분할 — 는 해당 출처에서 보고된 대로이며, 인용하기 전에 원문을 확인하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기