리스팅은 존재하지 않았지만, 예약 링크는 작동했다
요약
AI로 생성된 완벽한 형태의 가짜 데이터(위조품)가 기존의 자동화된 검증 시스템을 어떻게 무력화하는지 경고합니다. 데이터의 형식이 올바른 것(well-formed)과 실제 사실과 일치하는 것(truthful) 사이의 간극을 분석합니다.
핵심 포인트
- AI 생성 데이터는 단순한 오류가 아닌 정교한 위조품일 수 있음
- 형식적 유효성(Schema/Type) 검증만으로는 데이터의 진위 여부를 판단할 수 없음
- 참조 대상(Referent)이 없는 데이터는 기존의 감사 방식으로 해결 불가능
- 데이터 파이프라인 설계 시 '형태가 올바른 거짓 데이터'에 대한 대비 필요
그 숙소는 그럴듯한 이름을 가지고 있었습니다. 별점, 가격, 깔끔하게 정리된 설명 문구, 유효한 LodgingBusiness 구조화 데이터 (structured data), 그리고 초록색 "Verified" (인증됨) 배지까지 갖추고 있었습니다. 또한 누군가 클릭하여 방을 예약하면 수수료를 지급하는 방식인, 작동하는 제휴 링크 (affiliate link)와 연결된 Book Now (지금 예약) 버튼도 있었습니다.
그 숙소는 존재하지 않았습니다. "폐업"한 것도, "이름이 바뀐" 것도 아니었습니다. 애초에 실재하지 않았던 것입니다. AI의 도움을 받아 빠르게 구축된 무언가가 이름, 설명, 별점, 편의시설 등을 통째로 생성해냈고, 이를 실제 결제 망 (payment rail)으로 연결해 두었습니다.
이런 사례는 혼자가 아니었습니다. 이들과 같은 부류가 무더기로 있었는데, 그 정체가 드러나는 지점은 거의 우스꽝스러울 정도였습니다. 서로 다른 도시에 있는 수십 개의 별개 "호텔"들이 모두 동일한 제휴 링크를 공유하고 있었습니다. 이름도 다르고 설명도 달랐지만, 목적지 URL은 하나였습니다. 모든 그림에 똑같은 서명을 남기는 위조범과 같았습니다.
그중 어느 것도 고장 난 것은 없었습니다. 바로 이 점이 깊이 생각해 볼 만한 부분입니다. 제가 던질 수 있는 모든 자동화된 검사(automated check)를 통과했습니다. 유효한 타입 (types), 유효한 스키마 (schema). 404 오류도, 빌드 오류 (build errors)도, 린트 경고 (lint warnings)도 없었습니다. 검증기 (validator)는 그것들이 잘 형성되었다 (well-formed)고 확인해주었으며, 그 '잘 형성되었다'는 사실 자체가 완벽한 위장술이었습니다.
'틀림'은 묘사 대상인 실제 대상이 존재함을 암시한다
저는 지난 몇 주 동안 틀린 데이터를 수정하는 데 시간을 보냈습니다. 오래되어 쓸모없어진 사실, 잘못된 도시로 등록된 엔티티 (entity), 페이지에 반영되지 않은 수정된 값 같은 것들 말입니다. '틀림'은 이미 해결된 종류의 문제입니다. '틀림'은 정답이 존재하며, 저장된 값이 그 정답과 일치하지 않음을 의미합니다. 당신은 감사 (audit)를 수행하고, 출처와 비교하며, 이를 조정 (reconcile)합니다.
이번 사례는 달랐고, 왜 그런지 깨닫는 데 잠시 시간이 걸렸습니다. 조작된 것을 출처와 대조하여 조정할 수는 없습니다. 왜냐하면 참조 대상 (referent)이 없기 때문입니다. 해당 행 (row)은 실제 대상을 잘못 묘사하고 있는 것이 아닙니다. 그것은 아무것도 존재하지 않는 상태를 확신에 차서 묘사하고 있습니다. 확인할 사실이 없는 이유는 검증할 대상 자체가 없기 때문입니다.
첫 번째 재구성(reframe)은 이렇습니다: AI가 생성한 시드 데이터는 다듬어야 할 초안이 아닙니다. 탐지해야 하는 위조품입니다. 그리고 그것의 정의적인 속성은 '검증한다'는 것입니다. 우리가 쌓아온 모든 직관은 형태가 잘못된 데이터(malformed data)를 위험한 데이터로 간주합니다. 왜냐하면 형태가 잘못된 데이터가 시스템을 망가뜨리는 것이기 때문입니다. 하지만 형태가 잘못된 데이터는 스스로 드러납니다. 진정으로 위험한 기록은 완벽하게 형태가 갖춰져 있으면서도 완전히 거짓인 기록입니다. 왜냐하면 여러분의 파이프라인에는 데이터를 구문 분석(parse)하는 행을 하는 로우(row)를 의심하도록 설계된 것이 아무것도 없기 때문입니다.
저는 그것들을 삭제했습니다. 위조품은 리팩토링하지 않습니다.
같은 문제의 더 조용한 버전
가짜 목록들은 시끄러운 사례였습니다. 그 아래에는 훨씬 더 광범위하게 퍼져나간, 더 조용한 사례가 있었고, 이것이 실제로 제가 생각하는 방식을 바꾼 부분입니다.
실제 목록들에는 '정책(policy)' 필드가 있었습니다. 이 작은 데이터 조각은 특정 부동산이 현장에서 어떤 것을 허용할 수 있는지 여부를 기록했습니다. 대부분의 경우, 그것들은 한 번도 확인된 적이 없었습니다. 그 필드는 비어 있었습니다.
페이지가 빈 필드에 대해 렌더링한 것은 다음과 같았습니다: 녹색 '확인됨(Verified)' 배지. 편의 시설 그리드에서 '예(Yes)'. 해당 것이 허용된다고 주장하는 구조화된 데이터 한 줄. 크롤러가 상호작용하는 부분이 로드되기 전에 읽는 서버 렌더링 복사본에 담긴 자신감 있는 문장들.
아무도 이러한 것들을 주장하기로 결정하지 않았습니다. 나쁜 행위자(bad actor)도, 나쁜 데이터도 없었습니다. 코드베이스 전반에 걸쳐 정신적으로 반복되는 단 하나의 코드가 있었습니다. 대략 다음과 같이 읽었습니다: 만약 이 값이 누락되었다면, 그것을 참으로 간주하라. 기본값(default). ?? true 또는 다른 네 개의 파일에 있는 사촌 격의 구문이었습니다.
그것이 두 번째 재구성이며, 제가 신입 엔지니어에게 새겨줄 내용입니다: 기본값은 주장이다. 알려지지 않은 것을 유리한 값으로 채울 때, 당신은 도움이 되고 있는 것이 아니며 비워두는 것도 아닙니다. 당신은 자신이 가지고 있지 않은 사실을 단언하고 있는 것입니다. 빈 필드는 사용자에게 가는 과정에서 비어있지 않았습니다. 그것은 조용히 약속(promise)으로 승격되었습니다.
부재가 '예'로 렌더링되었다는 것.
누락된 값은
한 곳에서 이를 발견하자 모든 곳에서 발견할 수 있었고, 그 모든 것들은 동일한 근본 원인(root cause)으로 거슬러 올라갔습니다. 데이터 모델(data model)에 세 가지 상태가 필요했으나 두 가지 상태만 존재했던 것입니다.
true가 있었고, false가 있었으며, null이 있었습니다. 하지만 null은 그 자체로 하나의 상태가 아니었습니다. 그것은 _해결되어야 할 입력값(input to be resolved)_이었고, 모든 계층(layer)이 이를 동일하게 낙관적인 방식으로 해결했습니다. 카드는 그것을 '예'로 강제했습니다. 배지는 그것을 '예'로 강제했습니다. 구조화된 데이터(structured data)는 그것을 '예'로 강제했습니다. 크롤러(crawler)가 읽는 프리렌더링된(prerendered) 복사본도 그것을 '예'로 강제했습니다. 하나의 누락된 사실이 네 개의 확신에 찬 단언(assertion)이 되었고, 그 중 어느 것도 정직한 답변을 표현할 방법이 없었습니다.
정직한 답변을 사용할 수 없었기 때문입니다. "미확인(Unverified)"은 시스템이 보유할 수 있는 값이 아니었습니다. 그리고 "모른다"를 표현할 수 없는 시스템은 자신이 모르는 것에 대해 침묵하지 않습니다. 대신 범위 내에서 가장 그럴듯한 값을 찾아내어 확정 지어 버립니다.
해결책은 영리한 것이 아니었습니다. 누락된 값을 추가하는 것이었습니다.
- _미확인(unconfirmed)_을 위한 실제적이고 명시적인 상태 추가 — 추론되는 것이 아니라 저장되는 방식.
- 두 가지 방식 대신 세 가지 방식의 렌더링: 예(Yes), 아니오(No), 그리고 미확인(Unconfirmed). 미확인 상태는 고유의 차분한 스타일을 갖습니다. 확정된 '예'의 초록색을 사용하지 않으며, 똑같이 중요한 점은 확정된 '아니오'의 빨간색도 사용하지 않는다는 것입니다. "확인하지 않았음"은 "허용되지 않음"과는 다른 주장이며, 이 둘을 하나로 합치는 것은 반대 방향을 향한 일종의 거짓말입니다.
- 모든 계층이 해당 상태를 지나쳐 기본값(default)으로 넘어가기보다, 그 상태를 따르도록(defer) 교육함. 카드, 배지, 구조화된 데이터, 크롤러가 읽는 정적 복사본 — 이 네 가지 모두가 이제 네 개의 독립적인 낙관적 추측 대신, 함께 "미확인"이라고 말하거나 혹은 아무 말도 하지 않습니다.
- 긍정적인 주장은 실제 확정된 값 뒤에 배치하여, 시스템이 실제로 뒷받침하는 근거가 있을 때만 어떤 사실이 참이라고 단언하도록 함.
모델에게 어깨를 으쓱할 방법을 주어라
이 교훈은 특정 분야나 특정 사이트를 넘어 일반화됩니다. 이는 시스템이 완전히 뒷받침할 수 없는 사실을 보유하고 있는 모든 곳에 적용됩니다. 그리고 검증된 사람이 입력하는 데이터보다 초기 데이터가 생성되는 비중이 높아짐에 따라, 이러한 현상은 점점 더 보편화되고 있습니다.
우리는 시스템의 정직함을 거짓 진술의 부재 (absence) — 즉 버그가 없고, 오래된 행(row)이 없으며, 깨끗한 감사(audit) 결과 — 로 생각하는 경향이 있습니다. 하지만 모든 감사를 통과하더라도 여전히 거짓을 말하는 시스템이 존재할 수 있습니다. 왜냐하면 거짓은 데이터 안에 있는 것이 아니라, 기본값(defaults)에 있기 때문입니다. 그것은 당신이 결코 가져본 적 없는 값에 어떤 일이 일어나는가에 달려 있습니다.
진정한 정직함이란 "알 수 없음 (unknown)"이 일급 객체 (first-class thing)로서 존재 (presence) 하는 것입니다. 즉, 저장할 수 있는 값, 렌더링할 수 있는 상태, 그리고 구조화된 데이터 (structured data)가 내리기를 거부할 수 있도록 허용된 주장이어야 합니다. 만약 당신의 모델이 제공하는 유일한 옵션이 '예'와 '아니오'뿐이라면, 지식의 모든 공백은 당신을 기분 좋게 만드는 쪽으로 조용히 채워지게 됩니다. 그리고 그 기울기의 극단적인 끝은 존재하지 않는 호텔인데 예약 버튼은 작동하는 상황입니다.
모델에게 "모르겠습니다"라고 말할 수 있는 명시적인 방법을 부여하십시오. 그렇지 않으면 모델은 모든 것에 고개를 끄덕일 것이며, 누군가 방을 감사하여 그중 절반이 동일한 위조범에 의해 그려졌다는 사실을 발견하기 전까지는 어디서 문제가 생겼는지 알 수 없을 것입니다.
추가 읽을거리 — 인접한 실패 모드들: 왜 AI 도구들이 운영 사이트에서 확신에 찬 침묵의 오류를 생성하는가, 그리고 왜 폴백 체인 (fallback chain)은 설계상 누락된 데이터를 숨기는가. 이 포스트는 두 사례 모두의 하위 계층에 대한 내용입니다: 즉, 왜 애초에 그 공백이 거짓으로 채워지는가에 대한 이야기입니다.
원문은 tedagentic.com에 게시되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기