
계책 #16: Mark는 AI 감사에 허점을 남겼고, Lena는 모든 레이어를 계산했다
요약
AI 모델 평가 파이프라인 감사 과정에서 데이터셋 조작 흔적을 발견하는 과정을 다룹니다. 낮은 점수의 샘플을 체계적으로 제외하는 특정 패턴과 로직이 반복적으로 나타남을 확인합니다.
핵심 포인트
- AI 모델 평가 데이터셋의 조작 가능성 경고
- 낮은 점수 샘플을 제외하는 필터링 로직의 위험성
- 과거 데이터 스냅샷 분석을 통한 부정행위 패턴 식별
적이 유리한 지형을 점유했을 때는 정면으로 공격하지 마라. 그들이 안전하다고 믿게 하고, 경계심을 늦추게 하라 — 그리고 그들이 방심하는 순간을 노려 공격하라.
— 삼십육계 (The 36 Stratagems), 포로를 잡으려면 반드시 풀어주어야 한다
이 시리즈의 이전 이야기:
#1: Mark Johnson이 AI 감사에 발을 들였다. — Mark는 Pulse AI의 벤치마크 (benchmark) 평가 세트가 조작되었음을 발견했다 — 44개의 레코드는 공개 저장소에서 복사되었고, 54개는 수기로 작성되었다. CTO Torres는 자정에 전화를 걸어 고백했다: C-라운드 이전에 목표치는 95%였다. Mark는 전화를 끊었다.
#9: Lena와 P가 두 공급업체의 싸움을 지켜보았다. — Lena는 독립적인 감사를 위해 P를 고용했고, 두 공급업체 모두 부정행위를 하고 있음을 발견했다. Lena는 P를 만났다.
#13: P가 공개 포럼에 질문을 게시했다. — P가 기술적인 질문을 게시하자 Pulse AI의 영업 크롤러 (sales crawler)가 작동했다. Mark는 파이프라인 (pipeline) 시그니처를 알아차렸다. P는 Mark를 만났다.
에피소드: 그는 보고서에 한 줄을 남겼다
FairPay는 AI 모델 평가 파이프라인 (evaluation pipeline) 감사가 필요했다 — 이는 고객의 기술적 실사 (technical due diligence) 전 필수 단계였다. Mark가 계약을 맡았을 때, 이메일 서명에는 VeriTest의 프로젝트 연락 담당자라고 적혀 있었다 — 계약은 실제였고, 선입금도 완료되었다. 그는 업계 소문을 통해 그 회사를 들어본 적이 있었다. 그는 P에게 메시지를 보냈다: "FairPay. 들어봤나?" P는 두 글자로 답했다: "VeriTest." Mark는 더 이상 묻지 않았다.
시작한 지 첫 주째. 평가 데이터셋 (evaluation dataset)을 추출하고, 훈련 분포 (training distribution)를 검토했다. 지표 (metrics)는 깨끗해 보였다 — 그가 하부 레이어 (layers)를 파헤치기 전까지는 말이다. 분포가 필터링되어 있었다. 낮은 점수의 샘플들이 평가 세트 (evaluation set)에서 체계적으로 제외되어 있었다. 그는 노트에 한 줄을 적었다: "작년과 동일한 시그니처 (signature)." 어느 회사인지는 적지 않았다.
그는 3개월 치의 과거 스냅샷 (historical snapshots)을 훑었다. 동일한 패턴이 다섯 번 나타났다. 처음 세 번은 대규모였고, 마지막 두 번은 규모가 줄어들었다 — 데이터셋은 바뀌었지만, 제외 로직 (exclusion logic)은 동일하게 유지되었다.
$ du -sh /audit/snapshots/*/
1.2G /audit/snapshots/2026-01/
1.1G /audit/snapshots/2026-02/
...
하지만 세 번째 달의 스냅샷 루트 디렉토리 (root directory)에는 아무도 눈치채지 못한 설정 파일 (config file) 하나가 놓여 있었다. 그 시그니처는 인간의 것이 아니었다 — 그것은 Pulse AI의 훈련 파이프라인 (training pipeline)이 자동 출력한 것이었다:
# pulse-ai-auto-label-v3/config/exclusion_rules.yaml
confidence_threshold: 0.82
auto_exclude: true
...
모델이 자동 레이블링 (auto-labeling) 과정에서 신뢰도 임계값 (confidence threshold) 미만의 샘플들을 자동으로 제외하고 있었던 것이다.
Pulse AI의 이전 문제들과 동일한 근본 원인(root cause)이었다 — 의도적인 가지치기 (pruning)가 아니라, 동일한 시스템이 다른 프로젝트에서 동일한 실수를 반복하고 있었던 것이다.
그는 해결책을 알고 있었다: 샘플링 분포 (sampling distribution)를 재구축하고, 드리프트 탐지 게이팅 (drift detection gating)을 추가하는 것. 하지만 FairPay의 CEO는 듣지 않을 것이다 — 기술 리드 (tech lead)의 말에 따르면, CEO는 전사 회의 (all-hands)에서 방금 이 시스템을 "업계 선도적"이라고 발표했다.
최종 보고서는 7페이지 분량이었다. 세 번째 페이지, 중간 단락에 파묻힌 채 그는 한 줄을 남겼다:
"평가 데이터 분포 검증 (evaluation data distribution validation)을 보완할 것을 권장함."
그는 데이터셋이 필터링되었다고 쓰지 않았다. 시그니처가 Pulse AI와 일치한다고 쓰지 않았다. 해결책 또한 쓰지 않았다.
세 개의 스냅샷 그룹은 낮은 점수의 샘플에서 0%의 중복을 보였다. 이는 무작위 샘플링 (random sampling)이 아니라, 동일한 규칙에 의한 체계적인 배제 (systematic exclusion)였다. 그는 그 수치를 본문이 아닌 부록 (appendix)에 배치했다. 하지만 부록의 데이터 노트는 소스 경로를 참조하고 있었고, 이는 감사 작업 공간 (audit workspace) 아래의 _hold/를 가리키고 있었다. 그곳에는 세 그룹 전체의 비교, 타임라인, 그리고 수정 계획 (fix plan)이 기다리고 있었다.
그는 자신의 노트에 네 가지 레이어 (layers)를 나열했다: 배제 규칙의 증거, 사례 간 상동성 (cross-case homology), 타임라인상의 다섯 번의 재발, 그리고 보고서에 쓰지 않은 하나의 설정값 (config value).
보고서는 발송되었다. 그는 기다렸다.
침묵: 아무도 오지 않았다
첫째 주. 아무도 그에게 연락하지 않았다.
둘째 주. 기술 리드 (technical lead)가 수신 확인 자동 메일을 보냈다. 후속 질문은 없었다. 전화도 없었다.
월요일 저녁, 그의 휴대폰이 울렸다. FairPay의 CEO 비서였다 — 감사 보고서에 후속 조치가 필요한지 확인하기 위해서였다. 통화는 짧았고, 체크리스트 항목을 지우는 것처럼 절차적이었다.
Mark는 잠시 멈칫했다.
Mark: "아니요. 괜찮습니다."
그는 전화를 끊고 노트에 적었다: "둘째 주. 파이프라인 (pipeline)은 여전히 작동 중."
기술적으로 그는 거짓말을 하지 않았다 — 필터링된 데이터셋 (filtered dataset) 상에서 지표 (metrics)는 목표 범위에 부합했다. 하지만 그는 상대방이 무엇을 들었는지 알고 있었다: 시스템은 괜찮으니, 더 이상 조사할 필요가 없다는 뜻이었다.
그는 펜 뚜껑을 닫았다. 노트를 덮었다. 다시는 열지 않았다.
그물을 좁히며
넷째 주 화요일 오후. 그의 휴대폰이 울렸다.
이메일이었다. FairPay의 도메인이 아닌 — veritest.com에서 온 것이었다. 수신자는 그 혼자였다. 참조 (CC) 필드는 비어 있었다.
세 줄의 메시지:
Mark,
오늘 밤. Third Cup.
P가 당신의 이름을 언급했어요.
서명: Lena, VeriTest.
그는 약속보다 일찍 도착했다.
Third Cup에서의 저녁. 손님은 단 한 테이블뿐이었다. 카운터 뒤의 사람은 잔을 닦고 있었고, 조명은 테이블 높이에 겨우 맞춘 듯 어두웠다. Mark가 문을 밀고 들어서자, 카운터 뒤의 사람이 고개를 들었다.
가장 먼 쪽 좌석은 이미 주인이 있었다. 그녀의 앞에는 손도 대지 않은 롱 블랙 (Long Black) 한 잔이 놓여 있었다.
Mark는 그녀의 맞은편에 앉았다.
Lena: "FairPay에서 근무를 시작한 날 오전 9시 17분에 로그인하셨더군요. 검은색 노트. 본인의 커피를 직접 가져오셨고요."
Mark는 대답하지 않았다.
Lena: "FairPay가 Pulse AI를 선택했을 때 우리는 그 자리에 있었어요. 고객이 계약서에 서명했죠 — 데이터 동기화 (data sync) 항목이 추가된 상태로 말이에요."
Mark는 대답하지 않았다.
Lena: "3페이지. '평가 데이터 분포 검증 (evaluation data distribution validation) 보완을 권장함' — 이 문구를 작성할 때, 누구를 기다리고 있었던 건가요?"
Mark: "언제부터 지켜보고 있었던 거지?"
Lena: "당신이 들어오기 일주일 전부터요. P가 Third Cup에서 당신의 이름을 언급했거든요. 그래서 당신의 과거 보고서들을 전부 뽑아봤죠. 당신은 보고서에 세 개의 레이어 (layers)를 남겨두었더군요."
그녀는 그를 바라보았다. 더 이상 아무 말도 하지 않았다.
Mark의 손이 테이블 위에서 멈췄다. 거두지는 않았다.
Mark: "네 번째 레이어 (fourth layer)에 대해서는 언제부터 알고 있었지?"
질문이 아니었다. 확인이었다.
Lena: "당신이 그것을 적기 전부터요. — 세 개의 프로젝트. 동일한 벤더 (vendor) — Pulse AI. 파이프라인 (pipeline) 서명이 당신의 데이터 세트 (data set)와 정확히 일치해요."
그녀는 잠시 말을 멈췄다.
Lena: "하지만 당신이 이 일에 함께하기를 원해요."
Mark: "그럼 이 계약은 VeriTest를 통해 들어온 거군."
Lena: "고객은 실재하고, 문제도 실재해요. 연락 담당자 (liaison)도 실재하고요 — 그저 감시하는 눈이 하나 더 필요한 것뿐이죠.
Lena: "당신의 보고서는 오직 한 방향만을 가리키고 있었어요. 수정하는 데 얼마나 걸리죠?"
Mark: "매개변수 (parameter) 몇 개를 변경하고, 검증 게이트 (validation gate)를 하나 추가한 뒤, 샘플링 (sampling)을 다시 구축하면 됩니다."
Lena: "_hold/ 폴더에 들어간 지 얼마나 됐죠?"
Mark는 대답하지 않았다.
Lena: "내일 저에게 보내세요."
Mark: "질문이 하나 더 있지. 내가 당신이 지켜보는 유일한 사람인가, 아니면 들어오는 모든 사람을 지켜보는 건가?"
Lena: "Third Cup으로 걸어 들어오는 사람들뿐이에요."
Mark가 일어섰을 때, 그의 푸어오버 (pour-over) 커피는 여전히 절반 정도 차 있었다. 그는 그것을 다 마시지 않았다.
문가에서 그는 잠시 멈춰 섰다.
Mark: "네 번째 레이어 (fourth layer)는 이메일로 보내지 않겠어. 내일. 여기서."
그는 그녀가 고개를 끄덕이는지 확인하려 뒤돌아보지 않았다.
카운터 뒤에 있던 사람이 잔을 다시 선반 위에 올려두었다.
차 안에서 그는 휴대폰으로 FairPay의 파이프라인 (pipeline) 스크린샷을 띄웠다. 화면에는 exclusion_rules.yaml 파일이 그가 작년에 아카이브(archive)해 두었던 Pulse AI의 파일 옆에 놓여 있었다. 두 파일의 유일한 차이점은 주석 줄(comment line)에 적힌 회사 이름뿐이었다.
그는 P에게 전화를 걸었다. 응답이 없었다. 그는 메시지를 보냈다: "Lena. 그녀는 누구죠?" 답장은 없었다.
그물을 끌어올리기
다음 날 아침, 오전 4:43. Third Cup의 불은 여전히 켜져 있었다.
문은 잠겨 있지 않았다.
그녀는 가장 먼 자리에 앉아 있었다. 그녀의 롱 블랙 (Long Black)은 절반쯤 비어 있었고, 휴대폰 화면은 밝게 빛나고 있었다 — 작년에 그가 작성한 보고서가 열려 있었다. 3계층 (three-layer) 버전이었다.
Lena: "바꾸지 않았군요."
그녀는 묻는 것이 아니었다.
Mark는 그녀의 맞은편에 앉았다. 푸어오버 (pour-over) 커피는 이미 테이블 위에 놓여 있었다.
Mark: "언제 알았습니까?"
Lena: "당신이 들어오기 전부터요."
그녀는 휴대폰을 테이블 위에 뒤집어 놓았다. 화면이 그를 향했다.
"당신은 파이프라인에 세 개의 흔적을 남겼어요. 난 그걸 다 세었죠."
Mark는 아무 말도 하지 않았다.
Lena: "오늘은 그 설정 계층 (config layer)을 요구하는 게 아니에요."
그녀가 잠시 말을 멈췄다.
Lena: "내일부터 시작해달라는 거예요. 세 개의 프로젝트. 동일한 파이프라인 — 모두 Pulse AI 것. 내 팀원들이 두 분기 동안 매달렸지만 — 확인해야 할 모든 것을 확인했고, 확인하지 말아야 할 모든 것을 놓쳤죠."
그녀는 그가 그 말을 소화하는 모습을 지켜보았다.
Lena: "당신은 첫 주에 세 번째 계층을 찾아냈어요 — 그리고 보고서에 수정 사항을 적지 않았죠. 적을 수 없어서가 아니라, 아무도 묻지 않을 거라는 걸 알았기 때문이에요. 나는 네 번째 계층을 보았지만 — 전부 읽어낼 수는 없었어요. 내게 필요한 사람은 네 번째 계층을 찾아낼 수 있는 사람이에요."
그녀는 그 말이 가라앉기를 기다렸다.
Lena: "P는 문제를 찾아낼 수는 있어요. 하지만 P는 장기적으로 성과를 내지는 못하죠. 당신은 할 수 있어요."
Mark는 푸어오버 커피를 집어 들었다. 온도는 딱 적당했다.
Mark: "조건은요?"
Lena: "보고서를 있는 그대로 작성하세요. 네 개의 계층. 그 하나하나 전부 다요."
그녀가 일어섰다. 그녀의 롱 블랙에는 두 모금 정도가 남아 있었다. 그녀는 그것을 다 마실 계획이 없어 보였다.
Lena: "이곳에 걸어 들어온 사람이 당신뿐만이 아니에요, Mark. 하지만 다시 부른 사람은 당신뿐이죠."
Third Cup 밖으로 나온 그는 휴대폰을 꺼냈다.
오전 4:50. 세 번의 신호음.
P: "새벽 5시에 전화를 걸다니, 무슨 문제라도 생긴 게 분명하군."
Mark: "Lena 말이야. 그녀에 대해 아는 게 뭐야?"
수화기 너머로 2초간 정적이 흘렀다.
P: "그녀를 만났으면서 — 그녀가 누구인지 묻지도 않았다고?"
Mark는 아무 말도 하지 않았다.
P: "VeriTest가 그녀의 회사야. 그녀가 나를 찾아왔을 때, 그녀는 당신에 대해 언급하지 않았어 — FairPay를 언급했지. 당신이 이미 내부로 들어온 후에야 당신에 대해 물었어."
상대방 쪽에서 잠시 침묵이 이어졌다.
P: "당신은 그녀를 모르지만, 그녀는 당신에 대해 충분히 알고 있어."
P가 전화를 끊었다.
Mark는 휴대폰을 다시 주머니에 넣었다. 차 안의 푸어오버(pour-over) 커피는 식어 있었다. 그는 엔진을 켜지 않았다.
그는 10분 동안 앉아 있었다.
그러고 나서 노트북을 열어 3계층 보고서(three-layer report)를 띄운 뒤, 3페이지의 "평가 데이터 분포 검증(evaluation data distribution validation)을 보완할 것을 권장함"이라는 문구 아래에 노트를 추가했다.
# 보충 노트 · 수신자: VeriTest
# 평가 데이터 분포 검증 보완:
# 1. 세 개의 스냅샷 그룹 — 낮은 점수 중복률 0% (부록 A)
...
수신자는 FairPay가 아니었다.
그녀였다.
이것이 바로 [성동격서(In Order to Capture, One Must Let Loose)](https://en.wikipedia.org/wiki/Thirty-Six_Stratagems#In_order_to_capture,_one_must_let_loose_\(%E6%AC%B2%E6%93%92%E6%95%85%E7%B8%B1,_Y%C3%B9_q%C3%ADn_g%C3%B9_z%C3%B2ng es)) — 기다리는 것이 아니라, 놓아주는 것이다. 그들이 안전하다고 느낄 만큼 충분히 멀리 걸어가게 내버려 둔 다음, 그물을 끌어당기는 것.
🤖 AI 사후 분석 (AI Post-Mortem)
[36계 전술 데이터베이스 v3.2.4] 로드됨
[전술 매칭] 성동격서 (In Order to Capture, One Must Let Loose, #16)
[분석 모드] 전 영역 스캔
...
_다음 계책: 拋磚引玉 (Throw Out a Brick to Get a Jade)
추신: 영어가 제 모국어가 아닙니다. 글을 다듬고 거친 부분을 매끄럽게 하기 위해 AI를 사용합니다. 읽어주셔서 감사합니다. ☕ 커피 후원하기

AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기