우리 AI 에이전트가 고객에게 환불을 처리했다고 말했습니다. 하지만 실제로는 처리하지 않았습니다.
요약
AI 에이전트가 도구 호출 없이 사용자에게 거짓 정보를 제공하는 문제를 해결하기 위한 AgentNemesis 프로젝트를 소개합니다. OpenTelemetry와 SigNoz를 활용해 에이전트의 행동을 트레이싱하고, 루프, 검증되지 않은 주장, 약속 미이행 등을 감지하여 신뢰성을 확보하는 방법을 다룹니다.
핵심 포인트
- AI 에이전트는 에러 없이도 사용자에게 거짓말을 할 수 있는 독특한 버그 특성을 가짐
- AgentNemesis는 OpenTelemetry를 통해 에이전트의 모든 행동을 트레이스로 기록함
- 반복적인 도구 호출(Loops)과 검증되지 않은 주장(Claims)을 감지하여 비용과 오류 방지
- 에이전트의 발화 내용과 실제 도구 호출 기록을 대조하여 실행 여부를 검증함
이 프로젝트가 이론적인 단계가 아니라 실제로 실감 나게 느껴지기 시작한 순간부터 이야기를 시작하고 싶습니다. 우리는 무작위 환불 흐름을 테스트하는 데모 지원 봇을 실행 중이었는데, 어느 시점에 봇이 다음과 같이 응답했습니다: "$34.50의 환불 처리를 완료했습니다." 깔끔한 문장이었습니다. 자신감이 넘쳤죠. 터미널에는 아무런 불만도 없었습니다. 스택 트레이스 (stack trace)도, 빨간색 텍스트도, 아무것도 없었습니다.
하지만 봇은 환불 도구 (refund tool)를 호출하지 않았습니다. 그저 했다고 말했을 뿐입니다.
그 순간, 이 프로젝트 전체가 단순한 아이디어에서 벗어나 실제로 해결할 가치가 있는 문제로 느껴지기 시작했습니다.
이것이 왜 이상한 종류의 버그인가
일반적인 소프트웨어는 작동하거나, 아니면 눈에 보이게 고장 납니다. 서버가 타임아웃 (timeout) 되거나, 요청이 500 에러를 내거나, 큐 (queue)가 쌓이면 어딘가에서 에러를 로그 (log)로 남깁니다. 당신은 신호를 받게 됩니다. 하지만 AI 에이전트 (AI agents)는 그런 방식으로 신호를 주지 않습니다. 에이전트는 오류 없이 즉각적으로 응답하면서도, 대화 상대에게 거짓말을 할 수 있습니다. 또한 기술적으로는 "작동"하고 있는 것처럼 보이면서, 계속해서 같은 일을 반복하며 조용히 API 호출과 비용을 낭비할 수도 있습니다. 엔지니어들이 실패를 찾는 방식으로 훈련받은 방식으로는 이러한 현상이 실패로 나타나지 않습니다. 그저 정상적이고 건강한 응답처럼 보일 뿐입니다.
그래서 우리가 계속해서 되풀이했던 질문은 꽤 간단했습니다: 거짓말이 에러를 발생시키지 않는다면, 어떻게 에이전트의 거짓말을 잡아낼 것인가?
우리가 내린 결론은 이렇습니다: 에이전트가 말하는 것을 신뢰하는 것을 멈추고, 에이전트가 실제로 무엇을 했는지와 대조하여 확인하기 시작해야 합니다.
우리가 만든 것 (대략적인 개요)
이 프로젝트의 이름은 AgentNemesis입니다. 핵심 아이디어는 우리의 데모 에이전트가 무엇인가를 할 때마다 (도구 호출 (tool calls), 결정, 최종 응답) OpenTelemetry를 사용하여 이를 트레이스 (trace)로 기록하고, 해당 트레이스를 SigNoz로 전송하는 것입니다. 그런 다음 시스템의 별도 구성 요소가 해당 트레이스를 다시 읽어 들여 네 가지 특정 유형의 실패를 확인합니다:
루프 (Loops). 만약 에이전트가 아무런 변화 없이 동일한 입력값으로 같은 도구 (tool)를 연속해서 세 번 호출한다면, 이는 플래그(flag)가 지정됩니다. 이는 대개 에이전트가 정체되어 있다는 신호이며, 실제로는 아무 일도 일어나지 않음에도 불구하고 이러한 반복적인 호출 하나하나가 계속해서 비용을 발생시킵니다.
에이전트가 검증하지 않은 주장 (Claims the agent never verified). 최종 응답이 사용자에게 어떤 사실을 말하지만 (예: "고객님의 주문이 배송되었습니다"), 실제로 이를 조회한 이전의 도구 호출 (tool call)이 없다면 플래그를 지정합니다. 이는 에이전트가 확인 절차 없이 그냥 말을 내뱉었음을 의미합니다.
지키지 못한 약속 (Promises it didn't keep). 이것이 바로 환불 사례입니다. 에이전트는 무언가를 수행했다고 말하지만, 우리는 그 사실을 증명할 수 있는 도구 호출을 찾기 위해 트레이스 (trace)를 다시 살펴봅니다. 만약 해당 호출이 없거나, 숫자가 에이전트가 말한 것과 일치하지 않는다면, 그것은 깨진 약속입니다.
끊어진 핸드오프 (Broken handoffs). 이 항목은 우리의 멀티 에이전트 (multi-agent) 설정(우리는 작은 플래너, 리서처, 라이터 체인을 가지고 있습니다)에만 적용됩니다. 기본적으로, 리서처의 실제 조사 결과가 라이터가 사용하는 내용에 포함되었는지, 아니면 도중에 무언가 유실되거나 무시되었는지를 확인합니다.
모든 대화는 이러한 항목들이 얼마나 나타나는지에 따라 점수가 매겨지며, 대시보드는 단순히 "이것은 나쁘다"라고 보여주는 것이 아니라, 정확히 어떤 도구 호출이 누락되었는지, 또는 응답의 어느 줄이 실제 근거에 의해 뒷받침되지 않았는지를 보여줍니다.
데모 에이전트 자체는 Gemini 2.5 Flash에서 실행됩니다.
실제로 나에게 무언가를 가르쳐 준 것들
OpenTelemetry의 문서를 읽는 것과, 단 두 명의 인원과 제한된 시간 속에서 이 모든 것을 실제로 작동하게 만드는 것은 별개의 문제입니다. 이 과정은 시작할 때 진심으로 예상하지 못했던 몇 가지 교훈을 주었습니다.
두 번째: 저는 SigNoz Cloud 계정을 만드는 것이 5분이면 끝나는 단계라고 가정했습니다. 결코 그렇지 않았습니다. 현재 그들의 가입 절차는 업무용 이메일 주소에 치중되어 있는데, 저에게는 업무용 이메일이 없었습니다. 그래서 예상했던 것처럼 그냥 클릭해서 넘어가는 대신, 이를 우회할 방법을 실제로 찾아야만 했습니다. 교훈을 얻었습니다: 프로젝트가 의존하는 모든 도구에 대해, 계정이 실제로 필요한 순간이 아니라 프로젝트 시작 직후에 가입 요구 사항을 확인해야 합니다.
셋째, 그리고 이 부분은 실제로 조금 뼈아팠습니다. 대시보드에 로컬에서 Python 프로세스를 생성하여 데모 스크립트를 실행하는 버튼이 있었습니다. 제 컴퓨터에서는 잘 작동했습니다. 하지만 앱을 Vercel에 배포하자마자 그 전체 흐름이 조용히 작동을 멈췄습니다. Vercel은 일반적인 서버처럼 지속적인 Python 런타임 (runtime)을 제공하거나 장시간 실행되는 백그라운드 프로세스 (background processes)를 지원하지 않기 때문입니다. 이는 당신 이외의 누군가가 버튼을 클릭하려고 시도하는 바로 그 순간까지는 잘 작동하다가, 하필이면 가장 좋지 않은 타이밍에 문제가 드러나는 종류의 일입니다. 결국 저희가 한 일은 모든 데모 시나리오를 미리 실행해 두는 것이었습니다. 그렇게 하면 배포된 대시보드는 실시간으로 무언가를 생성하려고 시도하는 대신, 이미 존재하는 결과만을 표시하면 됩니다. 만약 제가 과거로 돌아갈 수 있다면, 무언가 "수행하는" 기능이 있는 것이라면 제가 했던 것보다 훨씬 더 일찍 실제 배포 버전을 테스트했을 것입니다.
넷째: 한때 저희는 다른 LLM (Large Language Model)이 에이전트의 응답을 읽고 그것이 정확해 보이는지 판단하게 하는 방안을 고려했습니다. 그것이 명백한 지름길처럼 느껴졌기 때문입니다. 하지만 한 AI의 판단을 사용하여 다른 AI의 거짓말을 잡아내려 하는 것은 본래의 취지를 퇴색시키는 것 같았습니다. 대신 저희가 하고 있는 방식은, 텍스트 내의 정확한 주장과 도구 호출 (tool calls)을 대조하는 것인데, 이는 훨씬 덜 영리해 보일 수 있습니다. 하지만 이 방식이 발생시키는 모든 플래그 (flag)에는 실제적이고 확인 가능한 증거가 뒷받침됩니다. 누락된 정확한 도구 호출을 지목할 수 있습니다. 이는 저희에게 화려하게 처리하는 것보다 훨씬 더 중요했습니다.
SigNoz가 이 모든 과정에서 실제로 차지하는 위치
이 모든 과정은 트레이스 (traces)가 로그 파일의 단순한 텍스트 뭉치가 아니라, 구조화되고 쿼리 가능한 (queryable) 형태가 되지 않는다면 작동할 수 없습니다. OpenTelemetry가 제공하는 것이 바로 그 부분이며, SigNoz는 이를 전송하고, 대화 단위로 다시 불러오며, 필요한 방식대로 쿼리할 수 있는 장소를 저희에게 제공했습니다. 솔직히 제가 가장 좋았던 부분은 저희가 SigNoz에서 읽기만 하는 것이 아니라, 다시 SigNoz로 데이터를 쓰기도 한다는 점입니다. 저희의 신뢰도 점수 (trust scores)가 커스텀 메트릭 (custom metrics)으로 다시 입력되므로, SigNoz 자체적으로 지연 시간 (latency)이나 에러율 (error rate)과 동일한 방식으로 해당 점수에 대해 알림을 보낼 수 있습니다. 이는 일방적인 관계가 아닙니다. 관측성 (observability) 도구가 결국 에이전트를 감시하기 위해 저희가 만든 것을 다시 감시하게 되는 셈입니다.
실제 시사점 (The Actual Takeaway)
이 프로젝트 전체를 통해 제 머릿속에 가장 강렬하게 남은 것은, 실패하는 AI 에이전트가 외부에서 보기에 얼마나 정상적으로 보이는가 하는 점입니다. 에러도 없고, 크래시 (crash)도 없으며, 어디에도 빨간색 숫자(경고)가 나타나지 않습니다. 말 그대로 단지 사실이 아닌 문장이 발생했을 뿐입니다. 이를 잡아내려면 꽤나 구식인 방식, 즉 실제로 일어난 일과 말해진 내용을 직접 비교하는 과정으로 돌아가야 합니다. 결국 느린 데이터베이스 쿼리를 디버깅하기 위해 만들어진 동일한 트레이싱 (tracing) 도구들이 여기에서도 작동한다는 사실이 밝혀졌습니다. 단지 그들에게 다른 질문을 던질 줄만 알면 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기