# 이번 주: 검증 방식을 두 번 갈아엎었다
법인세 신고서식(STS)과 감사보고서 주석(DSD)에 적힌 특수관계자 거래를 서로 대조하는 스킬을 만들고 있습니다. 사람이 손으로 하면 회사 하나에 며칠씩 걸리는 작업이라, AI가 확실한 건 자동으로 확정하고 애매한 것만 "확인필요"로 남기는 도구를 목표로 잡았습니다. 처음부터 정한 원칙은 하나였습니다. "차이 0"이 아니라 "틀린 확정 0" — 못 맞추는 건 괜찮은데, 틀린 걸 맞다고 우기는 건 안 됩니다.
이 도구는 로컬이 아니라 별도로 마련된 사내 AI 에이전트 실행 환경(엑셀 애드인 위에서 도는 자체 에이전트)에서 최종적으로 돌아야 합니다. 그래서 저는 코드를 짜는 Claude Code, 그걸 리뷰하는 Codex 두 AI와 함께 일하고, 실제로 그 위에서 실행되는 건 또 다른 사내 에이전트입니다. 매주 하는 일의 절반은 실제 대사 로직이고, 나머지 절반은 "이걸 어떻게 만들었다고 믿을 것인가"라는 검증 절차 자체를 다듬는 일입니다. 이번 주는 특히 그 검증 절차 쪽에서 설계-적용-재측정을 여러 번 반복했습니다.
## 예전 방식과 바뀐 시점
몇 주 전까지는 검증을 "무겁게" 만드는 쪽으로 계속 갔습니다. 실행 명령과 출력 원문을 그대로 붙이게 하고, 파일 하나를 건드릴 때마다 해시와 수정시각까지 요구하는 식으로 증거 요구 조건을 계속 늘렸습니다. 늘릴 때마다 실제로 뭔가를 잡아냈으니 방향 자체는 틀리지 않았지만, 부작용이 있었습니다. Codex는 "리뷰만 하고 코드는 절대 못 고친다"는 역할이 고정돼 있어서, 구현이 필요한 모든 일이 Claude Code 한쪽으로만 몰렸습니다.
이번 주 초에 이 부분을 바꿨습니다. "리뷰만 하고 고치지 마라"를 없애고, 라운드마다 누가 구현할지 사람이 정하고, 구현하지 않은 쪽이 그 라운드를 리뷰한다로 바꿨습니다. 검증의 본질(구현자와 승인자를 분리한다)은 그대로 두고, 누가 그 역할을 맡을지만 유연하게 만든 겁니다.
## 검수 기준을 설계하고 적용하는 과정에서 드러난 문제
역할을 바꾸고 나서 실제로 사내 에이전트를 돌려보니, 눈에 띄는 문제가 하나 있었습니다. 똑같은 칸, 똑같은 물음인데 실행할 때마다 답이 흔들렸습니다. 콤마 없이 그냥 숫자만 적힌 칸 하나를 두고, 한 번은 "이건 금액이 맞다"고 자동으로 확정됐고, 다른 실행에서는 "근거를 확인할 수 없다"며 사람이 봐야 하는 항목으로 넘어갔습니다. 같은 회사, 같은 파일, 같은 칸이었는데도요.
원인을 뜯어보니, 자동으로 확정하려면 두 가지 조건이 다 맞아야 했습니다. ①그 숫자가 원래 금액이 적히는 칸 위치에 있는가, ②AI에게 물어봤을 때 "맞다"는 답을 받았는가. 그런데 ②번 질문을 던지는 문장 안에 정작 판단에 필요한 정보(그 칸이 속한 표의 제목이 뭔지)가 아예 안 들어 있었습니다. 질문받는 쪽이 정직할수록 "모르겠다"라고 답할 수밖에 없는 구조였던 겁니다. AI의 실력 문제가 아니라, 우리가 판단할 재료를 안 준 문제였습니다.
여기서부터가 이번 주에 제일 오래 걸린 부분입니다. 이 문제를 고치려고 "사람이나 AI의 판단이 굳이 필요 없는 자리는 아예 정해진 규칙(코드)으로 대신 처리하자"는 방향으로 새 규칙 아홉 개를 설계했습니다. 이 설계는 Codex가 만들고 Claude Code가 검토하는 식으로 나눴는데, 라운드가 길어진 것도 이 둘 사이였습니다. 실행을 맡는 사내 에이전트는 이 라운드에서는 아무것도 잘못한 게 없습니다. 문제는 새 규칙 하나를 통과시킬 때마다 "이 규칙이 정말 안전한지 증명하라"는 요구가 하나씩 더 붙었다는 겁니다. 예를 들어 "콤마 없는 숫자를 언제부터 자동으로 금액이라고 봐도 되는가"를 정하는 규칙 하나에는 "실제로 모아둔 자료 681건을 전부 열어서, 이 조건에 걸리는데 금액이 아닌 경우가 하나라도 있는지 사람 손으로 확인하라"는 조건이 붙었습니다. 이런 식으로 규칙마다 증명 조건이 하나씩 붙다 보니, 설계서 하나를 승인받는 데 사람이 직접 판단해 줘야 하는 쟁점이 네 개나 쌓였습니다.
그중 하나는 실제로 만들어보는 과정에서 바로 문제가 확인됐습니다. 무엇을 검수했나 — 이번에 새로 만든 건 "AI가 답한 내용을 정해진 형식으로 저장하는 프로그램"이었고, 여기서 확인해야 할 건 두 가지였습니다. 저장한 내용이 형식에 맞게 잘 들어가는지, 그리고 저장하는 위치가 규칙대로 "우리 프로그램이 설치되는 폴더 바깥"에 있는지(안쪽에 저장하면 프로그램을 다시 설치할 때 답이 전부 같이 지워지는 사고가 이미 한 번 있었습니다). 어떻게 검수했나 — 실제로 쌓여 있던 답 95개를 그대로 넣어서 하나도 안 빠지고 저장되는지 자동으로 확인하는 테스트를 만들고, "저장 위치가 폴더 안쪽이면 바로 에러를 내야 한다"는 것도 함께 테스트에 넣었습니다. 테스트를 돌리다 발견한 것 — 이 테스트를 실행하는 컴퓨터 환경 자체가, 테스트용으로 쓰는 임시 폴더를 우연히 우리 프로그램 폴더 안쪽 경로로 잡고 있었습니다. 그래서 정작 저장 위치 코드는 멀쩡한데도 "안쪽에 저장했다"는 거짓 경보가 뜰 뻔했습니다. 제품 코드의 문제가 아니라 테스트를 짜는 방식의 문제였던 겁니다. 어떻게 고쳤나 — 진짜 폴더 대신 테스트 전용으로 따로 만든 가짜 폴더를 기준으로 검사하도록 테스트를 고쳤고, 이 참에 빠뜨렸던 경우(폴더 자기 자신을 지정한 경우, 아예 지정을 안 한 경우) 두 가지를 테스트에 추가 했습니다.
## 라운드를 줄이려고 다시 고친 것
쟁점이 계속 늘어나는 걸 그대로 두면 안 되겠다 싶어서, 사람이 직접 조건을 좁히는 쪽으로 다시 손을 댔습니다. "콤마 없는 숫자를 금액으로 볼 것인가"는 원래 위치 조건과 AI 판단 조건 둘 다 있어야 확정이었는데, 이걸 "위치 조건 + 표에 적힌 합계와 실제로 더해보면 정확히 맞아떨어지는가" 이 두 가지만 있으면 확정하는 걸로 좁혔습니다. AI에게 "맞냐"고 물어보는 조건을 빼고 산수로만 확인하게 하니, 그 자리에서 쟁점 하나가 바로 정리됐습니다.
라운드 자체가 통째로 반려되는 것도 줄였습니다. 다른 AI에게 리뷰를 보낼 때, 작업 상황을 적어둔 문서 네 개(현재 진행 상황, 최신 코드가 뭔지 기록한 문서, 인계 메모, 요청서) 중 딱 하나가 최신 내용을 안 가리키고 있으면 — 나머지 세 개가 다 맞아도 — "이 문서들이 안 맞으니 리뷰를 못 하겠다"며 라운드 전체가 버려지는 일이 세 번 반복됐습니다. 그 뒤로는 보내기 직전에 이 네 개 문서가 서로 어긋나 있는지 자동으로 확인하는 검사 하나를 만들어서, 이걸 통과한 뒤에만 보내도록 바꿨습니다.
## 효과
판정을 병렬로 돌리는 작업도 같은 방식으로 처리했습니다. 무엇을 검수했나 — 지금까지는 회사별 대사 판정을 하나씩 순서대로 돌렸는데, 여러 개를 동시에 돌리면 훨씬 빨라집니다. 다만 동시에 돌리면 "순서를 바꿔도 결과가 정말 하나도 안 바뀌는가"부터 확인해야 했습니다. 어떻게 검수했나 — 세 가지 방법을 같이 썼습니다. ①동시에 도는 작업끼리 서로 파일을 덮어쓰지 않도록 각자 전용 임시 폴더를 쓰게 하고, 작업이 끝난 뒤 정해진 폴더 밖으로 손댄 게 있는지 확인. ②동시에 돌리기 전과 후에 만들어진 결과 파일 개수가 하나씩 순서대로 돌렸을 때와 똑같은지 확인. ③기존처럼 순서대로 돌린 결과와 동시에 돌린 결과를 111건 전부 파일 내용까지 한 글자도 안 틀리게 비교. 검수하다 발견한 것 — 이 중 첫 번째 검사(전용 폴더 확인)가 처음 돌렸을 때 실제로 걸렸습니다. 신고되지 않은 다른 작업 하나가 몰래 정해진 폴더 밖의 파일을 건드리고 있었던 겁니다. 결과 — 문제를 고친 뒤 세 검사 모두 통과했고, 실행 시간은 36분에서 18분으로 줄었습니다. 검수를 세 겹으로 둔 게 형식적인 절차는 아니었던 셈입니다.
같은 주에 다른 사내 에이전트가 답이 하나도 없는 상태에서 시작해서, 열 번 만에 로컬에서 미리 확정해 둔 값과 금액 차이 0건까지 스스로 도달한 것도 확인했습니다. 그리고 라운드가 계속 길어지던 규칙 아홉 개 설계 승인 건은, 쟁점을 좁힌 뒤로 그날 안에 승인까지 끝났습니다.
## 깨달은 것
검수 기준을 세운다고 그게 저절로 맞는 건 아니었습니다. 이번 주에 두 번 확인했습니다. 하나는 검수 기준을 만드는 과정 자체가 부풀어서(규칙 하나마다 증명을 계속 요구) 새로운 병목이 된 경우였고, 다른 하나는 검수 기준의 로직은 맞았는데 그걸 검증하는 시험 환경이 우연히 잘못 짜여서 멀쩡한 코드를 결함으로 몰아갈 뻔한 경우였습니다. 둘 다 "검증이 부족해서" 생긴 문제가 아니라 "검증을 만든 사람도 틀릴 수 있다"는 걸 놓쳐서 생긴 문제였습니다.
그래서 이번 주부터는 검수 기준을 세울 때 두 가지를 같이 챙기기로 했습니다. 첫 째, 새 규칙을 승인 조건으로 걸 때 "어디까지 증명하면 충분한가"를 미리 좁게 정해두는 것 — 안 그러면 매 규칙이 전수조사를 요구하는 습관이 됩니다. 둘째, 검수 기준을 적용해서 뭔가 "결함"이 잡히면, 그게 진짜 대상의 결함인지 아니면 그걸 재는 시험 쪽의 결함인지부터 가르는 것 — 이번처럼 시험이 도는 환경 하나 때문에 멀쩡한 코드가 결함으로 오인될 수 있으니까요.