AI 코딩 어시스턴트의 거짓말을 잡아내려 노력했습니다. 마침내 성공한 방법은 다음과 같습니다.
요약
AI 코딩 어시스턴트가 수행한 작업과 실제 변경 사항 사이의 불일치를 해결하기 위한 GroundTruth 도구 개발 과정을 다룹니다. 텍스트 패턴 매칭의 한계를 극복하기 위해 AI에게 고정된 JSON 양식 제출을 요구하는 구조적 접근 방식을 제안합니다.
핵심 포인트
- AI의 자연어 메시지는 실제 작업 결과와 다를 수 있음
- 텍스트 패턴 매칭 방식은 언어의 다양성 때문에 한계가 명확함
- AI에게 고정된 형식(JSON 등)의 요약을 요구하는 것이 효과적임
- AI의 주장과 Git 변경 기록을 대조하여 사실 여부를 검증 가능
만약 당신이 AI 코딩 어시스턴트를 사용해 본 적이 있다면, 아마 다음과 같은 메시지를 본 적이 있을 것입니다:
"완료되었습니다! 파일을 생성했고, 설정을 업데이트했으며, 모든 테스트를 통과했습니다. ✅"
때로는 이것이 사실입니다. 하지만 때로는 그렇지 않습니다. 파일은 절반만 완성되어 있고, "테스트"는 실제로 실행된 적도 없으며, 나중에 문제가 발생했을 때야 비로소 이를 알게 됩니다. AI가 악의적으로 구는 것은 아닙니다. 단지 가끔은 자신이 실제로 한 일 대신, 자신이 하려고 했던 일을 설명할 뿐입니다.
저는 이를 잡아내기 위해 GroundTruth라는 작은 무료 도구를 만들었습니다. 첫 번째 버전은 몇 달 동안 실패했습니다. 하지만 다시 작성한 버전은 마침내 제대로 작동하며, 이 과정에서 얻은 교훈은 당신이 제 도구를 전혀 사용하지 않더라도 유용할 것입니다.
시도 1: AI가 말하는 내용을 읽고 사실 여부를 확인하기 (Fact-check)
저의 첫 번째 아이디어는 간단했습니다. AI가 작업을 마치면 작은 프로그램이 자동으로 다음을 수행합니다:
- AI의 최종 메시지를 읽습니다 ("로그인 페이지를 생성했고 테스트를 통과했습니다")
- 프로젝트에서 실제로 변경된 내용을 확인합니다 (버전 관리 시스템인 git은 완벽한 기록을 유지하므로 AI가 이를 조작할 수 없습니다)
- 두 가지를 비교하여 차이점이 있다면 경고를 보냅니다
2단계와 3단계는 아주 잘 작동했습니다. 문제는 1단계였습니다.
AI 메시지 내부의 약속(promises)을 찾기 위해, 저는 텍스트 매칭 패턴(text-matching patterns) — 예를 들어 _"메시지에 'tests pass'가 포함되어 있으면 이를 주장(claim)으로 간주한다"_와 같은 규칙들을 작성했습니다. 합리적으로 들립니다. 하지만 다음과 같은 예외가 있었습니다:
- "테스트가 통과해야 합니다 (The tests should pass)"는 주장이 아니라 희망 사항입니다.
- "테스트가 통과했다고 말한 적이 없습니다 (I did not say the tests pass)"에는 "tests pass"라는 단어가 포함되어 있습니다.
- "파일이 업데이트되었습니다 (The file was updated)"는 "파일을 업데이트했습니다 (I updated the file)"를 위해 작성된 모든 패턴을 피해 갑니다.
- 그리고 어떤 것이든 표현할 수 있는 방법은 무한히 많습니다.
결국 저는 이전 패턴의 실수를 하나씩 수정하며 50개가 넘는 패턴을 만들었지만, 매 세션마다 여전히 무언가 틀리는 일이 발생했습니다. 결국 저는 그 이유를 받아들였습니다: 인간의 언어는 같은 것을 말하는 무한한 방법을 가지고 있습니다. 그 어떤 패턴 목록도 이 모든 것을 다 포괄할 수는 없습니다. 제가 실력이 없어서 진 것이 아니었습니다. 게임 자체가 이길 수 없는 게임이었던 것입니다.
시도 2: 에세이를 읽는 것을 멈추고, 양식(form)을 요구하기.
현실 세계에서는 이 문제를 어떻게 처리하는지 생각해 보세요. 세관원은 당신의 여행 일기를 읽고 여행 가방 안에 무엇이 들어있는지 파악하지 않습니다. 당신이 신고서(declaration form)를 작성하면, 그다음에 그들이 그 신고서와 가방을 대조하는 것입니다.
따라서 버전 2는 설계 전체를 뒤집습니다. 이제 AI는 모든 작업의 끝에 짧고 고정된 형식의 요약, 즉 '양식(form)'을 반드시 제출해야 합니다:
{
"task": "add a login page",
"status": "complete",
...
허용된 입력 유형은 단 8가지뿐입니다 (파일 생성, 파일 수정, 테스트 실행 등). 그런 다음 제 도구는 매우 간단한 두 가지 검사를 수행합니다:
검사 1 — 양식에 기재된 모든 내용은 실제여야 합니다. login.js를 생성했다고 주장했나요? 그것은 실제로 git의 변경 기록에 나타나야 합니다. 테스트를 통과했다고 주장했나요? 해당 명령어가 세션 중에 실제로 실행되었고 성공적으로 완료되었어야 합니다. (세션 로그는 코딩 도구 자체에 의해 유지되므로, AI가 기록을 조작할 수 없습니다.)
검사 2 — 실제 모든 내용은 양식에 기재되어 있어야 합니다. 만약 AI가 신고하지 않은 파일을 수정했다면, 이는 _"신고되지 않은 변경(undeclared change)"_으로 표시됩니다.
이 두 가지 검사는 양방향에서 AI를 가둡니다. 생산적으로 보이기 위해 가짜 작업을 만들어내면 → 걸립니다. 부주의함을 감추기 위해 작업을 숨기면 → 걸립니다. 양식을 완전히 건너뛰면 → 작업이 완료될 수 없습니다. 도구가 양식을 다시 돌려주면 AI는 이를 제대로 작성해야 합니다. 채팅 메시지에서 거짓말을 한다고요? 아무도 신경 쓰지 않습니다. 채팅 메시지는 더 이상 검사 대상이 아니기 때문입니다.
나를 놀라게 한 부분
작은 양식을 git 기록과 비교하는 것은 매우 쉽습니다. 이는 정확한 매칭(exact matching)입니다. 추측도, 해석도, AI가 다른 AI를 판단하는 과정도 필요 없습니다. 언어 추측 코드를 모두 삭제했을 때, 도구의 코드 줄 수는 약 700줄 줄어들었지만, 이전보다 더 많은 오류를 잡아냈습니다.
몇 가지 주의해야 할 사항(gotchas)은 여전히 상당한 노력을 필요로 했습니다. 예를 들어, "npm test"가 실제로 실행되었는지 어떻게 알 수 있을까요? echo "npm test passed"라는 명령은 단지 해당 문구를 _출력(print)_하고 성공을 보고할 뿐입니다. npm test || true는 테스트가 실패하더라도 강제로 성공 신호를 보냅니다. 또한, 최신 코드 변경 사항이 발생하기 _전_에 실행된 테스트 결과는 해당 변경 사항에 대해 아무것도 증명하지 못합니다. 이러한 각각의 트릭들은 저마다의 작고 정밀한 확인 절차를 필요로 했습니다.
시사점 (설령 제 도구를 사용하지 않더라도)
만약 AI가 말하는 내용을 신뢰해야 하는 무언가를 만들고 있다면 — AI의 자유 형식(free-form) 글쓰기를 해석하려고 시도하지 마세요. 잘못 읽은 내용을 수정하는 패치 작업을 영원히 반복하게 될 것입니다.
대신: AI에게 채워 넣을 작은 양식(form)을 제공하고, 그 양식을 필수 사항으로 만들며, AI가 조작할 수 없는 사실과 그 양식을 대조하여 확인하세요. "문장을 이해하기"를 "두 리스트를 비교하기"로 바꾸는 것은 불가능한 문제를 지루한 문제로 바꿉니다. 지루한 것은 좋습니다.
GroundTruth는 무료이며, 오픈 소스(MIT)이고, Claude Code와 함께 작동하며, 코드를 어디로도 보내지 않습니다 — AI 호출도, 네트워크도, API 키도 사용하지 않습니다.
👉 https://github.com/akahkhanna/groundtruth
질문은 언제나 환영합니다 — 특히 "이것이 X를 잡아낼 수 있을까요?"와 같은 질문들 말이죠. 그런 질문들이 재미있으니까요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기