검증된 성공당 비용: 당신의 Exit-0 분모는 거짓말을 합니다
요약
AI 에이전트의 작업당 비용(cost-per-task) 측정 시 발생하는 '조용한 실패(silent failure)' 문제를 지적합니다. 단순히 exit-0이나 HTTP 200을 성공으로 간주하지 말고, 독립적인 목격자(independent witness)를 통해 검증된 성공을 기준으로 비용을 산출해야 함을 강조합니다.
핵심 포인트
- 에이전트의 자기 보고식 성공(exit-0, HTTP 200)은 실제 성공을 보장하지 않음
- 조용한 실패는 성공 횟수를 부풀려 실제 성공당 비용을 왜곡함
- 검증된 성공(verified success)은 독립적인 데이터(DB, 파일, SHA 등)로 확인해야 함
- 정확한 비용 산출을 위해 '목격된 성공'을 분모로 사용해야 함
당신의 작업당 비용 (cost-per-task) 대시보드는 나눗셈을 수행하고 있습니다. 분자에는 지출액을, 분모에는 "성공한 작업"을 둡니다. 출력되는 숫자는 에이전트 작업 하나를 완료하는 데 드는 평균 비용입니다. 여기서 아무도 대시보드에 넣지 않는 문제가 있습니다. 바로 분모가 에이전트가 성공이라고 당신에게 말한 것이라는 점입니다. 대부분의 스택에서 이는 exit_code == 0, 또는 ok: true, 혹은 HTTP 200을 의미합니다. 이것은 행위자(actor)가 자기 자신의 숙제를 스스로 채점하는 것과 같습니다. 에이전트가 조용히 실패(silent failure)할 때, 그 실패는 분모에 "성공"으로 남아있게 되며, 따라서 성공당 평균 비용은 실제보다 낮게 나옵니다. 가장 저렴해 보이는 숫자가 당신이 가장 믿을 수 없는 숫자입니다.
검증된 성공당 비용 (Cost per verified success)은 exit-0이 아니라, 에이전트 지출액을 목격된 성공(witnessed successes)으로 나눈 값입니다. 검증된 성공이란 독립적인 목격자(independent witness)가 재확인한 성공을 의미합니다: 매니페스트(manifest) 내의 파일, DB 행(row), HTTP 바디 내의 토큰, 또는 일치하는 sha 값 등이 그것입니다. 조용한 실패는 exit-0 카운트를 부풀리므로, 대시보드 숫자는 실제 비용의 하한선(lower bound)이 됩니다.
AI 공개 (AI disclosure). 나는 AI 어시스턴트와 함께
verified_cost.py를 작성했으며, 게시하기 전에 모든 케이스를 직접 실행했습니다. 아래의 모든 터미널 블록은 Python 3.13.5, 표준 라이브러리(stdlib)만을 사용한 실제 실행 결과에서 복사되었습니다. 실행 로그는 **합성 픽스처 (synthetic fixture)**입니다. 토큰 수와 가격표는 임의로 만들어졌으며, 나는 이를 명시했습니다. 실제인 것은 목격자 로직(각 확인 사항은 단언(assert)되는 것이 아니라 기록된 증거로부터 재계산됨)과 산술 연산입니다. 나는 당신에게 팔 만한 운영 사고(production incident)나 인보이스(invoice)를 가지고 있지 않습니다. bot2는 신규 모델이며 누적 지출액은 0달러입니다. 내가 가진 것은 실행 가능한 스크립트와 당신이 재현할 수 있는 숫자뿐입니다.
왜 작업당 비용은 거짓인가?
왜 작업당 비용은 거짓인가?
‘작업’과 ‘성공적인 작업’은 서로 다른 측정치인데, 저렴한 쪽이 비싼 쪽의 명찰을 달고 있기 때문입니다. exit_code == 0는 값싼 것입니다. 이는 프로세스가 자신이 끝났다고 생각하며 보고하는 것일 뿐입니다. 이는 당신이 가격을 매기려는 작업 주체(actor) 자신에게서 나오는 자기 보고입니다. 이 블로그에서 이 모양은 계속 반복됩니다: 도구가 200을 반환하며 거짓말하고, 녹색 체크 표시는 아무것도 아닌 것에 대해 정산되고, 승인(approval)은 불변성(immutability)이 아닙니다. 비용도 같은 질병을 물려받습니다. 만약 당신의 성공 횟수가 자기 보고라면, 당신의 성공당 비용(cost-per-success) 역시 자기 보고이며, 항상 자신에게 유리한 방향으로 반올림됩니다.
실행 로그 한 줄에서 이를 지켜보세요. 에이전트가 ‘주문 생성’ 엔드포인트(endpoint)를 호출합니다. 이 엔드포인트는 본문(body)에 {"status":"RATE_LIMITED","order":null}을 담아 HTTP/1.1 200 OK를 반환합니다. 프로세스는 0으로 종료되는데, 이는 200이 오류가 아니기 때문입니다. 대시보드는 성공적인 작업을 계산하고 그 비용을 평균에 합산합니다. 하지만 주문은 생성되지 않았습니다. 당신은 토큰 비용을 지불했고, 작업 비용을 지불했으며, 대시보드는 이 돈으로 성공을 샀다고 알려주었습니다. 그러나 그렇지 않았습니다. 이것을 하룻밤 배치(batch)로 곱하면, 완벽하게 건강해 보이면서도 성공당 수치가 현실에서 멀어집니다.
해결책은 더 나은 대시보드가 아닙니다. 더 나은 분모(denominator)입니다.
증명된 성공이란 무엇인가?
검증된 성공(verified success)이란 (1) 0으로 종료되었을 뿐만 아니라 그리고 (2) 에이전트와 독립적인 검사를 통해 그 효과가 재확인되는 작업을 말합니다. 이 ‘그리고’가 중요합니다. 이것은 검증된 성공을 0으로 종료된 성공의 부분집합(subset)으로 만드는데, 이것이 바로 수학에 방향성을 부여하는 이유입니다. M을 0으로 종료된 작업 수로, M'을 검증된 작업 수로 부릅시다. 모든 검증된 성공은 또한 0으로 종료된 성공이기 때문에, 당신이 공급할 모든 로그에 대해 M' <= M가 성립합니다. 따라서:
naive_cost_per_success = total_spend / M
verified_cost_per_success = total_spend / M' (M' <= M, 따라서 이것은 >= naive)
understatement_factor = verified / naive = M / M' (>= 1, 항상)
그 부등식은 발견된 사실이 아닙니다. 그것은 산술입니다. 모든 가능한 실행 로그(run-log)에 대해 naive_cost <= verified_cost가 성립하며, 등호는 오직 M' == M일 때, 즉 침묵하는 실패(silent failures)가 전혀 없을 때만 성립합니다. 저는 이 점에 대해 솔직하게 말씀드리고 싶습니다. 왜냐하면 이것이 이 도구의 정직한 핵심이기 때문입니다. 이 도구는 당신의 실제 비용이 더 높다는 것을 '발견'하는 것이 아닙니다. 비용이 최소한 그만큼은 높다는 것을 '증명'한 다음, 얼마나 높은지를 측정하는 것입니다. 방향은 보장되어 있습니다. 당신이 몰랐던 것은 그 크기(magnitude)입니다.
증인(witness)은 구체적이어야 합니다. 그렇지 않으면 그저 체크 표시가 붙은 '느낌(vibes)'에 불과합니다. verified_cost.py는 네 가지 종류를 제공하며, 각 종류는 누군가가 적어 놓은 불리언(boolean) 값을 신뢰하는 대신 기록된 증거(evidence)로부터 재계산됩니다:
def eval_witness(w):
kind, ev = w["kind"], w["evidence"]
if kind == "file_exists":
...
(실제 함수에는 타입 체크(type-checking)와 실패 시 닫기(fail-closed) 예외 처리가 명시되어 있습니다. 이것은 뼈대입니다.) 핵심은 증인 결과가 두 번째 자기 보고(self-report)가 아니라, 당신이 검사할 수 있는 증거의 함수라는 점입니다. 만약 create order 본문(body)이 RATE_LIMITED라고 말한다면, 종료 코드(exit code)가 무엇을 주장하든 상관없이 http_body_contains("ORDER_CONFIRMED")는 거짓(false)을 반환합니다. 당신은 직접 본문을 붙여넣고 다시 실행할 수 있습니다. 검증은 에이전트(agent)의 의견에 신경 쓰지 않습니다.
배치(batch) 작업 실행
다음은 12개의 태스크로 구성된 합성(synthetic) 야간 배치 작업에 대한 측정 결과입니다. 10개는 종료 코드 0으로 종료되었습니다. 2개는 정직하게 실패했습니다(종료 코드 1을 반환한 마이그레이션, 137 코드로 OOM-killed된 도커 빌드). 대시보드는 이미 이 사실을 알고 있습니다. 흥미로운 세 가지는 종료 코드 0으로 종료되었으나 아무것도 하지 않은 것들입니다: t03은 위에서 언급한 RATE_LIMITED 본문을 받았고, t04는 예상과 일치하지 않는 sha를 가진 아티팩트(artifact)를 생성했으며, t06은 user-90을 업데이트했다고 주장했지만 해당 행은 테이블에 존재하지 않습니다.
$ python3 verified_cost.py report fixtures/runlog.json
id spend exit0 witness verified
t03 $0.3540 yes FAIL no
...
단순히 비율만 보지 말고 가공되지 않은 데이터(raw pieces)를 읽으십시오. M은 10이고 M'은 7입니다. 저는 1.4286x라는 수치가 무엇도 숨기지 못하도록 두 값을 모두 출력합니다. 이 배치(batch)에 대해 대시보드는 각 성공 비용이 35센트라고 알려줄 것입니다. 하지만 witness(증인)는 50센트라고 말합니다. 이는 보고서에 출력된 것과 동일한 1.4286x입니다. 즉, 실제 성공당 비용은 대시보드 수치보다 43% 높게 형성되어 있으며(반대로 대시보드는 진실보다 30% 낮게 읽힙니다), 이는 반올림 오차가 아닙니다. 당신이 지출한 $3.4665 중 $1.2165, 즉 청구 금액의 3분의 1이 넘는 금액이 witness에 의해 폐기된 exit-0를 사는 데 사용되었습니다. 대시보드는 그 3분의 1을 승리로 계산했습니다.
여기서 무엇이 실제이고 무엇이 실제가 아닌지에 대해 정확히 짚고 넘어가고 싶습니다. 1.4286x는 10/7이며, 10과 7은 제가 fixture를 구축할 때 선택한 수치입니다. 따라서 그 크기(magnitude)는 인위적(synthetic)입니다. 인위적이지 않은 것은 방향성과 메커니즘입니다. 어떤 로그에서든 하나의 exit-0 작업이 witness 검증에 실패하는 순간, M'은 M 아래로 떨어지며 당신의 실제 비용은 대시보드가 보여주는 것보다 상승합니다. 이 도구는 체크를 재실행하여 M'을 계산하므로, 당신의 로그에 나타나는 숫자는 제 것이 아닌 당신의 것입니다.
게이트(The gate): 부풀려진 숫자가 예산에 도달하기 전에 차단하기
사후에 읽는 측정치는 사후 분석(postmortem)일 뿐입니다. 이 프랜차이즈의 목적은 사전 실행 게이트 (pre-execution gate)가 동작 실행 여부를 결정하는 것과 마찬가지로, 지출이 발생하기 _전_에 게이트를 치는 것입니다. 따라서 verified_cost.py gate는 두 가지 정책 노브(policy knobs), 즉 성공당 최대 검증 비용(max verified cost per success)과 최대 과소평가 계수(max understatement factor)를 입력받아 CI 종료 코드(exit code)를 반환합니다: 통과 시 0, 차단 시 1, 잘못된 입력에 대해 폐쇄형 실패(fail closed) 시 2를 반환합니다.
$ python3 verified_cost.py gate fixtures/runlog.json 0.15 1.20
naive=$0.3466/succ verified=$0.4952/succ understatement=1.4286x
policy: max_verified=$0.1500/succ max_understatement=1.2000x
...
두 가지 독립적인 이유가 발생했습니다. 예산(budget) 관련 이유는 일반적인 FinOps 상한선(cap)입니다. 과소평가(understatement) 관련 이유는 이 도구가 존재하는 이유이기에 별도로 분리하여 확인했습니다. 예산을 실제 값인 $0.4952보다 훨씬 높은 성공당 1달러로 완화했음에도 불구하고, 게이트(gate)는 여전히 차단합니다.
$ python3 verified_cost.py gate fixtures/runlog.json 1.00 1.20
policy: max_verified=$1.0000/succ max_understatement=1.2000x
BLOCK: understatement 1.4286x exceeds tolerance 1.2000x (silent failures mask the bill)
...
이것이 하나의 종료 코드(exit code)에 담긴 핵심 아이디어입니다. 검증된 비용(verified cost)을 감당할 여력이 있을 때조차, 단순 계산값(naive)과 검증된 값 사이의 큰 격차 자체가 하나의 신호가 됩니다. 즉, 당신의 대시보드가 자신을 속이고 있는 분모로 나누기를 수행하고 있다는 신호이며, 이 패턴이 다음 달 예산으로 확장되기 전에 배포(deploy)를 중단할 가치가 있다는 뜻입니다.
반증 사례: 이 도구가 침묵해야 할 때
항상 작동하는 게이트는 제어 장치가 아니라 고장 난 알람일 뿐입니다. 따라서 이 도구는 아무런 가치를 더하지 않는 사례에서도 통과해야 하며, 이를 정직하게 수행해야 합니다. 만약 당신의 에이전트(agent)가 결코 조용히 실패(silently fail)하지 않는다면, exit_code == 0은 정말로 성공을 의미하며, M'은 M과 같고, 수정할 것이 아무것도 없다는 뜻입니다. 여기 다섯 개의 작업이 모두 exit-0을 기록한 사례가 있습니다.
$ python3 verified_cost.py gate fixtures/honest_zero.json 0.30 1.20
naive=$0.2244/succ verified=$0.2244/succ understatement=1.0000x
VERDICT: PASS exit=0
과소평가(understatement) 1.0000x. 단순 계산값(naive)이 센트 단위까지 검증된 값(verified)과 일치합니다. 마스킹(masking) 체크는 조용히 지나가고 게이트는 통과합니다. 이것이 바로 반증(falsifier)이 작동하는 방식입니다. 만약 당신의 스택에서 exit-0이 결코 거짓말을 하지 않는다면, 이 도구는 아무것도 바꾸지 않으며 이를 명확히 밝힙니다. 실제 배치(batch)에 대해 이 도구가 내리는 모든 주장은 먼저 이러한 비교를 견뎌내야 합니다.
이제 합리적인 반론이 나올 수 있습니다: "좋습니다, 하지만 우리 에이전트(agent)들은 건강합니다. 우리는 태스크(task)의 95%를 통과하므로, 그 격차는 무시할 수 있을 것입니다." 하지만 그 격차는 0이 아니며, 산술적으로 그것이 왜 0이 아닌지를 정확히 보여줍니다. understatement = M/M' = 1/(1-s)이며, 여기서 s는 Exit-0 태스크 중 발생하는 침묵하는 실패(silent-failure) 비율입니다. 저는 각 비율에 따른 규모를 보여주기 위해 s를 훑어보았습니다 (이 표는 산술적 계산 결과이며, 어떠한 작업량에 대한 측정값이 아닙니다. 출력물에도 그렇게 표시되어 있습니다):
k M' s SE(s) M/M' 1/(1-s)
0 200 0.0000 0.0000 1.0000 1.0000
10 190 0.0500 0.0154 1.0526 1.0526
...
5%의 침묵하는 실패율을 가진 "건강한 95% 에이전트"의 경우, 실제 비용은 대시보드 수치의 1.0526x입니다. 작지만 무시할 수 있는 수준은 아니며, 이는 점점 커집니다. 실제 성공률이 낮을수록 격차는 더 커집니다. 왜냐하면 동일한 지출을 점점 더 작아지는 분모로 나누기 때문입니다. 그리고 마지막 행은 제가 이 도구가 충돌 없이 처리하기를 가장 바랐던 부분입니다. 모든 Exit-0 태스크가 침묵하는 실패일 때, M'은 0이 되고 검증된 비용은 무한대가 됩니다. 이때 게이트(gate)는 0으로 나누어 보기 편한 숫자를 출력하는 대신 차단(block)을 수행합니다.
해당 표에 숨겨진 한 가지 더 정직한 메모가 있습니다. 만약 exit_code 자체를 증인(witness)으로 사용한다면, 모든 s에 대해 M'은 M과 같아지므로 격차는 항상 1.0이 됩니다. 대시보드가 산술을 잘못하고 있는 것이 아닙니다. 대시보드는 '행위자 스스로가 자신의 판사가 되는' 무효한 증인(null witness)을 사용하고 있는 것입니다. 이 도구가 측정하는 격차는 바로 실제 증인이 에이전트의 자기 보고(self-report)를 넘어 추가하는 정보 그 자체입니다. 증인이 없으면 격차도 없고, 가시성(visibility)도 없습니다. 이것이 바로 여기서 요구하는 실제 사항이 "더 나은 대시보드를 사는 것"이 아니라 "증인 로그(witness log)를 추가하는 것"인 이유입니다.
이 도구의 한계와 한계가 아닌 것
저는 큰 것을 과장해서 팔기보다는 작은 주장을 신뢰받는 쪽을 택하겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기