
당신의 AI 에이전트가 실제로 무엇을 했는지 어떻게 검증할 것인가?
요약
AI 에이전트의 동작을 검증하는 것이 왜 어려운지 분석하고, 단순한 자기 보고부터 실행 추적까지 검증의 수준을 6단계로 분류하여 설명합니다. 에이전트가 생성한 보고서의 신뢰성 문제와 실제 실행 데이터 간의 간극을 다룹니다.
핵심 포인트
- 에이전트의 자기 보고(Self-report)는 모델 편향으로 인해 신뢰할 수 없음
- 단순 API 호출 증명과 작업의 유효성 검증은 별개의 문제임
- 검증을 위해서는 실행 경로와 구조화된 로그(Execution trace)가 필요함
- 핵심 시스템 수준의 엄격한 테스트와 증거 기반 검증이 요구됨
짧은 답변을 드리자면, 일반적으로는 불가능합니다. 당신은 특정 수준의 증명(proof)을 통해 특정 주장(claim)만을 검증할 수 있으며, 필요한 수준은 에이전트가 틀렸을 때 어떤 일이 발생하는지에 따라 달라집니다.
이것이 회피하는 것처럼 들릴 수도 있겠지만, 그렇지 않습니다. 이것이 바로 이 질문이 그토록 혼란스러운 조언들을 만들어내는 이유입니다. "에이전트가 무엇을 했는지 검증하라"는 말은 여섯 가지 서로 다른 질문을 하나로 묶어버린 것이며, 대부분의 도구들은 여섯 가지 모두에 답하는 것처럼 들리면서 실제로는 그중 하나에만 답합니다. 서명된 영수증은 API 호출이 발생했음을 증명합니다. 하지만 그 호출이 허용된 것이었는지에 대해서는 아무것도 말해주지 않습니다. 관측성 대시보드(observability dashboard)는 실행 경로(execution path)를 보여줍니다. 하지만 그 작업이 유효한 것으로 간주되어야 하는지에 대해서는 아무것도 말해주지 않습니다.
저는 사이버 및 우주 분야의 검증(verification)과 자격 부여(qualification)를 전문으로 하는 핵심 시스템(critical systems)을 테스트하며 생계를 유지하고 있습니다. 그 세계에서는 누군가가 작동한다고 말한다고 해서 아무것도 출시되지 않습니다. 모든 요구사항(requirement)에는 테스트가 있고, 모든 테스트에는 통과 기준(pass criterion)이 있으며, 모든 결과에는 증거(evidence)가 남습니다. 증거가 첨부되지 않은 주장은 이름이 있습니다. 바로 부적합(non-conformity)입니다.
그런 다음 저는 우리가 AI 에이전트를 어떻게 배포하는지 살펴보았습니다. 그리고 우리는 어떤 핵심 시스템에서도 거부했을 바로 그 행동, 즉 에이전트가 스스로 업무를 수행했다고 인증하는 보고서를 직접 작성하도록 허용하고 있다는 사실을 깨달았습니다.
그래서 제가 사용하는 사다리를 소개합니다. 답변하는 질문의 순서에 따라 정렬된 6단계입니다. 그리고 사람들이 단계로 착각하지만 실제로는 단계가 아닌 두 가지도 포함되어 있습니다.
사전 공개: 저는 이 분야에서 오픈 소스(open-source) 도구를 유지 관리하고 있습니다. 이 도구는 1단계에서 3단계 사이에 위치하며, 저는 그것이 어디에서 멈추는지 정확히 말씀드릴 것입니다.
V0 — 자기 보고 (Self-report)
질문: 에이전트는 자신이 무엇을 했다고 말하는가?
{ "status": "success", "message": "Invoice sent." }
증명하는 것: 아무것도 없음.
이것은 수사적인 표현이 아닙니다. 에이전트는 동일한 모델을 사용하여 동일한 컨텍스트(context) 내에서 작업과 그 작업에 대한 보고서를 모두 생성합니다. 자기 평가(self-evaluation)에 대한 연구는 이로 인해 발생하는 편향(bias)에 이름을 붙였습니다. 모델은 다른 모델의 출력보다 자신의 출력을 체계적으로 더 높게 평가합니다. 에이전트에게 성공했는지 묻는 것은, 반대 심문(cross-examination) 없이 증인에게 자기 자신에 대해 증언하도록 요청하는 것과 같습니다.
충분한 경우: 그 결과로 실제 아무 일도 일어나지 않을 때입니다. 도구 (tools)를 사용하는 에이전트에게 그런 경우는 결코 없습니다.
V1 — 실행 추적 (Execution trace)
질문: 실제로 어떤 호출 시퀀스 (sequence of calls)가 실행되었는가?
구조화된 스팬 (Structured spans): 어떤 도구인지, 어떤 인자 (arguments)를 사용했는지, 언제 실행되었는지, 무엇이 반환되었는지, 그리고 오류 (error)가 발생했는지 여부. OpenTelemetry의 GenAI 시맨틱 컨벤션 (semantic conventions)이 이를 다루고 있으며, 상관관계 ID (correlation ID)가 포함된 모든 구조화된 로그도 마찬가지입니다.
증명하는 것: 호출이 발생했다는 사실, 해당 인자들을 사용했다는 사실, 그리고 어떻게 종료되었는지.
증명하지 못하는 것: 해당 호출이 허용되었는지 여부, 또는 그것이 어떤 효과를 냈는지 여부.
비용: 이미 추적 (traces)을 내보내고 있다면 낮음.
V1이 사람들이 놓치는 부분 중 이미 잡아내고 있는 한 가지는 바로 도구 호출이 실패했음에도 에이전트가 성공했다고 보고하는 경우입니다. 오류는 스팬 상태 (span status)에 바로 나타나 있습니다. 만약 당신의 보고서에 이것이 드러나지 않는다면, 그것은 탐지 (detection)의 문제가 아니라 보고 (reporting)의 공백입니다. 증거는 이미 당신의 저장소에 있었습니다.
V2 — 증거 (Evidence)
질문: 나를 의심하는 사람 앞에 내놓을 수 있는 결과물 (artifact)을 보유하고 있는가?
메시지 ID (Message-ID). 파일의 SHA-256 해시값. 생성된 레코드의 ID. 서명된 요청/응답 페이로드 (request/response payload). 추가만 가능한 로그 항목 (append-only log entry).
증명하는 것: 특정하고 검증 가능한 결과물 (artifact)이 해당 동작에 부착되어 있다는 사실.
증명하지 못하는 것: 의도한 효과가 대상 시스템에 존재하는지 여부. 영수증은 전송 계층 (transport-layer)의 증거입니다. 영수증 계층을 구축하는 벤더들은 자신들의 문서에 이 점을 명확히 명시하고 있지만, 사용자들은 그것이 슬라이드에 도달할 때쯤이면 이를 잊어버립니다.
충분한 경우: 분쟁, 재구성 (reconstruction), 부인 방지 (non-repudiation).
V3 — 권한 부여 (Authorization)
질문: 이 동작이 허용되었는가?
여기에는 실행 과정에서 생성되는 것이 아닌 다른 것이 필요합니다. 즉, 에이전트가 무엇을 할 수 있는지 실행 _전_에 작성된 명세서 (specification)입니다. 허용된 도구. 임계값 (Thresholds). 필수 후속 조치. 예산. 에스컬레이션 (Escalation) 조건. 그런 다음 관찰된 추적 (trace)을 이 명세서와 대조하여 확인합니다.
증명하는 것: 관찰된 각 동작이 선언된 위임 사항 (mandate)을 준수하는지 또는 준수하지 않는지 여부.
증명하지 못하는 것: 해당 동작이 실제로 효과를 만들어냈는지 여부.
비용 (Cost): 낮음. 작업 내용은 코드를 작성하는 것이 아니라 명세 (specification)를 작성하는 것입니다.
이 단계는 시장에서 끊임없이 이야기되지만 가장 적게 구현되는 단계입니다. 이는 "작업 계약 (task contract)", "정책 (policy)", "수락 기준 (acceptance criteria)", "완료 정의 (define done)" 등의 이름으로 나타납니다. 모두가 이를 부르지만, 정작 파일 형식 (file format)을 제공하는 사람은 거의 없습니다. 그리고 이것 없이는 그 아래 단계들은 무용지물입니다. 아무도 승인하지 않은 동작에 대한 완벽한 실행 추적 (execution trace)은 그저 잘 기록된 사고 (incident)일 뿐입니다.
자격 검증 (qualification) 관점에서 보자면: 비교 대상이 될 요구 사항 (requirement) 없이는 실행의 증거는 가치가 없습니다. 이것은 철학이 아니라, V-모델 (V-model)에 왼쪽 부분이 존재하는 이유 그 자체입니다.
agent: refund-bot-v3
allowed_tools: [read_order, issue_refund, notify_customer, escalate_to_human]
...
V4 — 독립적 결과 검증 (Independent outcome verification)
질문: 의도한 변경이 실제로 일어났는가?
에이전트에게 묻지 마세요. 직접 가서 확인하세요. 데이터베이스를 쿼리 (query)하세요. 보낸 편지함 (Sent folder)을 검색하세요. API를 호출하여 레코드가 존재하는지 확인하세요. 결정적으로, 동작에 사용된 것과는 다른 경로를 사용해야 합니다. 만약 쓰기 (write) 작업과 확인 (check) 작업이 동일한 클라이언트 (client)를 통해 이루어진다면, 두 작업은 동일한 실패 모드 (failure modes)를 공유하게 됩니다.
증명하는 것: 기록 시스템 (system of record)에 결과가 반영되었는지 여부.
증명하지 못하는 것: 그것이 옳은 일이었는지 여부.
비용 (Cost): 높음. 각 작업 유형별로 검증기 (verifier)가 필요하며, 이를 유지 관리해야 합니다.
이 단계는 "호출이 200을 반환했다"와 "효과가 존재한다" 사이의 간극을 메우는 유일한 단계입니다. 추적 (trace)으로는 이를 수행할 수 없습니다. 추적은 요청이 전송되고 응답이 돌아왔다는 것을 기록할 뿐, 행 (row)이 실제로 저장되었는지는 기록하지 않습니다. 만약 당신의 에이전트가 돈을 옮기거나, 고객에게 무언가를 보내거나, 되돌릴 수 없는 어떤 동작을 수행한다면, 이 단계는 선택이 아닌 필수입니다.
V5 — 보존된 불변량 (Preserved invariants)
질문: 유지되어야 했던 것이 여전히 유지되고 있는가?
이 단계는 거의 아무도 구현하지 않으며, 모두가 불평하는 실패를 잡아내는 단계입니다. 즉, 에이전트가 할당된 범위 (scope) 내에 머물렀음에도 불구하고 여전히 무언가를 망가뜨리는 경우를 잡아냅니다.
본능적으로는 에이전트가 해서는 안 될 행동들을 적어 내려가게 됩니다. '인증(auth)을 건드리지 말 것', '응답 형태(response shape)를 변경하지 말 것', '스키마(schema)를 수정하지 말 것'과 같은 식입니다. 그리고 무언가 새로운 문제가 발생할 때마다 이 목록은 계속 늘어나며 결코 끝나지 않습니다. 금지된 행동의 집합은 무한하기 때문입니다. 당신은 여집합(complement)을 열거하고 있는 것이며, 유용한 집합의 여집합은 경계가 없습니다.
자격 검증(Qualification)은 그 반대로 동작합니다. 금지된 것을 열거하는 것이 아니라, 반드시 참으로 유지되어야 하는 불변량(invariants)을 단언(assert)하고 사후에 이를 확인하는 것입니다. 예를 들어, "parse()의 null 처리 수정"은 "인증을 변경하지 말 것"이 되지 않습니다. 대신 다음과 같이 변합니다: "null 입력 시 에러를 반환할 것", "공개 시그니처(public signature)는 변경되지 않을 것", "기존의 모든 호출자(caller) 테스트가 여전히 통과할 것". 이것은 유한한(finite) 단언(assertion)의 집합이며, 실행 가능하고, 당신이 미처 금지할 생각을 못 했던 행동들까지 포괄합니다.
유한함이 철저함(exhaustive)을 이깁니다. 이것이 핵심 비결입니다.
레벨(levels)이 아닌 두 가지 요소
이 주제에 대해 제가 본 두 가지 AI 생성 분류 체계(taxonomies)와 여러 벤더의 포스트들은 모두 이 부분을 틀리고 있습니다. 이 부분은 이름을 명시할 만큼 중요합니다.
무결성(Integrity)은 속성이지, 레벨이 아니다
로그 서명(signing), 해시 체이닝(chaining hashes), 추가 전용 저장소(append-only storage), 타임스탬프 증명(timestamp attestation) 등. 제가 읽은 모든 분류 체계는 "암호화된 감사 추적(cryptographic audit trail)"을 가장 높은 수준의 보증 단계인 최상위 레벨에 배치합니다.
하지만 그것은 레벨이 아닙니다. 로그에 서명하는 것은 무슨 일이 일어났는지에 대해 새로운 정보를 전혀 알려주지 않습니다. 그것은 단지 기록이 사후에 변경되지 않았음을 알려줄 뿐입니다. 서명된 V1 트레이스(trace)는 여전히 V1 트레이스입니다. 그것은 호출이 발생했음을 변조 방지(tamper-evident) 방식으로 증명할 뿐입니다. 무결성은 직교(orthogonal)합니다. 즉, 당신이 어느 레벨에 있든 그 레벨을 강화할 뿐이며, 증거에 대한 이의가 제기될 때 정확히 필요한 요소입니다. 무결성을 추가한다고 해서 사다리의 위 단계로 올라가는 것은 아닙니다.
두 번째 모델은 강력한 오라클(strong oracle)이 아니라 약한 오라클(weak oracle)이다
한 분류 체계에서는 "다른 AI를 검증자로 사용하기"를 레벨 7에, "독립적인 결과 검증(independent outcome verification)"을 레벨 4에 배치했습니다. 이는 앞뒤가 바뀐 것입니다.
중요한 축은 작업을 수행한 대상으로부터 오라클(oracle)이 얼마나 독립적인가입니다: 에이전트 자신(가치 없음) → 두 번째 모델(상관관계가 있는 사각지대, 동일한 학습 데이터, 유사한 실패 모드) → 결정론적 스크립트(deterministic script) → 기록 시스템(system of record)에 대한 직접적인 관찰. 요약이 충실한지 여부와 같이 결정론적인 오라클이 없는 질문에는 LLM 판사(LLM judge)가 유용합니다. 하지만 데이터베이스를 직접 확인하는 것보다 더 높은 순위를 차지할 수는 없습니다.
도구들이 실제로 위치하는 곳
| 기능 | 레벨 |
|---|---|
| LLM 관측성 플랫폼 (traces, spans, dashboards) | V1 |
| ... |
마지막 행이 중요합니다. 에이전트가 '누구'인지 검증하는 것과 에이전트가 '무엇을 했는지' 검증하는 것은 서로 다른 문제이며, 현재의 담론은 이 둘을 끊임없이 혼용하고 있습니다. 둘 다 필요합니다. 하나를 사면 다른 하나도 얻을 수 있다고 생각하는 것은, 결국 검증되지 않은 행동에 감사 가능한(auditable) 신원만을 연결하게 되는 결과를 초래합니다.
검증기를 검증하라
어떤 레벨을 선택하든, 모든 상황에 적용되는 하나의 규칙이 있습니다: 검증기에 당신이 틀렸다고 알고 있는 결과를 입력하고, 그것이 해당 결과를 거부하는지 확인하십시오. 테스트되지 않은 검증기는 증명이 아니라 믿음일 뿐입니다.
제가 직접 출시했다가 나중에 수정해야 했던, 제 도구에서 발생한 두 가지 실패 사례가 있습니다.
검증기가 자신이 검증하고 있는 대상을 신뢰했습니다. 저의 에스컬레이션(escalation) 체크 항목인
침묵을 성공으로 간주함. 도구 이름(tool name)이 없는 도구 호출(tool call)이 허용 목록(allowlist) 체크를 조용히 통과했습니다. 이는 속성 하나를 누락하는 것만으로도 어떠한 호출이라도 의무 사항을 우회할 수 있음을 의미합니다. 이제 규칙은 이름을 지정할 수 없는 도구는 허용될 수 없다는 것입니다. 검증할 수 없는 호출은 '빈 칸'이 아니라 '결함(finding)'입니다.
두 버그는 공통된 형태를 공유하며, 이는 주의 깊게 살펴봐야 할 부분입니다: 검증기가 아무것도 볼 수 없었기 때문에 깨끗한 실행이라고 보고한 것입니다. 볼 것이 없었기 때문이 아닙니다. 결함의 부재(absence of findings)와 부재의 결함(finding of absence)은 같은 결과가 아니며, 대부분의 검증기(verifier)는 이 둘을 혼동합니다.
그러므로 검증기를 신뢰하기 전에 스스로의 검증기를 공격하십시오. 당신이 나쁘다고 알고 있는 실행 데이터를 검증기에 입력해 보십시오. 만약 결과가 '그린(pass)'으로 나온다면, 당신은 검증기를 만든 것이 아니라 형식적인 절차(formality)를 만든 것입니다.
선택 방법
사용 가능한 것이 아니라, 당신이 감수해야 할 위험에 따라 선택하십시오:
- 되돌릴 수 없는 일이 발생하지 않음 → V1으로 충분합니다.
- 에이전트의 행동에 대해 다른 누군가(고객, 감사인, 규제 기관 등)가 책임을 져야 함 → V3가 최소 기준입니다. 선언된 요구 사항이 없는 트레이스(trace)는 감사 추적(audit trail)이 아닙니다. 그것은 마케팅 수사가 가미된 로그 파일일 뿐입니다.
- 금전, 또는 되돌릴 수 없는 그 어떤 것 → 독립적인 오라클(oracle)을 포함한 V4.
- 중요하게 생각하는 시스템에 대한 광범위한 자율성 → V5.
- 증거에 대해 논쟁이 발생할 가능성이 있음 → 선택한 어떤 수준에든 무결성(integrity)을 추가하십시오.
저는 V1부터 V3까지를 다루는 Apache-2.0 Python 패키지인 Alfred를 개발했습니다. 이 패키지는 에이전트의 OpenTelemetry GenAI 스팬(span)을 읽고, 이를 YAML에 선언된 의무 사항과 대조하며, 모든 문장이 트레이스 이벤트 ID(trace event ID)에 고정된 일일 요약(daily digest)을 계산합니다. 도구 호출 실패는 에이전트가 그에 대해 무엇을 말했든 상관없이 별도의 라인에 나타납니다.
이것은 V4를 수행하는 것이 아닙니다. 데이터베이스가 아니라 트레이스(traces)를 읽는 것이며, 현재 V5를 수행하지도 않습니다. 여러분이 운영 환경(production)에서 이를 직접 발견하게 하기보다 차라리 여기에 명시해 두는 편이 낫겠습니다.
만약 여러분이 운영 환경에서 에이전트(agents)를 검증하고 있다면, 여러분이 어느 단계에서 멈췄는지, 그리고 그 이유는 무엇인지 진심으로 알고 싶습니다. 그 부분이야말로 아무도 공개하지 않는 영역이기 때문입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기