여러 AI 모델을 교차 검증에 쓸 때 나는 검증 결과 파일을 열어 이름부터 확인했다. 파일 이름에 검증사 이름이 들어 있으면 "아, 이건 그 벤더가 봤구나" 하고 넘어갔다. 그런데 실제로 그 요청을 받은 모델은 설정에 적힌 것과 다른 모델이었다. 화면에는 맞는 이름이 떠 있었는데, 그 이름으로 일한 건 다른 존재였다.

발견한 계기는 사소했다. 검증 결과가 이상하게 관대하다는 느낌이 들어 로그를 열어봤을 뿐이다. 그런데 그 안에 "요청한 모델을 인식하지 못해 다른 모델로 대체한다"는 문구가 반복해서 찍혀 있었다. 세어 보니 수십 번이었다. 그동안 특정 벤더가 꼼꼼히 검증했다고 믿었던 결과들이, 실은 훨씬 가벼운 모델이 조용히 대신 처리한 결과였다.

설정 파일엔 분명 그 이름이 적혀 있었다

사건은 설정 파일에 모델 이름을 적어 넣는 아주 평범한 순간에서 시작됐다. 특정 벤더의 상위 모델을 쓰겠다고 슬러그(모델을 호출할 때 쓰는 정확한 내부 이름, Slug)를 하나 지정했다. 이름 뒤에 "-preview"라는 흔한 접미사가 하나 붙어 있었는데, 그 슬러그는 실제로는 존재하지 않는 이름이었다. 정식 출시되며 접미사가 빠졌는데 설정에는 예전 이름이 남아 있던 것이다.

문제는 이 잘못된 이름을 호출기가 그냥 튕겨내지 않았다는 데 있다. 존재하지 않는 슬러그를 요청받은 시스템은 에러를 내는 대신 알아서 더 가벼운 대체 모델로 넘어갔다. 화면과 결과 파일에는 여전히 원래 요청한 이름이 표시됐다. 실제로 일한 건 다른 모델인데, 기록에는 내가 지정한 이름이 그대로 남았다. 겉모습과 실체가 갈라지는 순간이었다.

설정 파일에 적힌 모델 슬러그 이름과 실제로 응답을 처리한 대체 모델이 서로 다른 구조를 화살표로 표현한 다이어그램
직접 생성한 오리지널 다이어그램.

더 나쁜 건 이 잘못된 이름이 한 곳에만 있지 않았다는 점이다. 설정은 보통 여러 곳에 복사된다. 로컬 설정 파일, 팀 공유 설정, 연동 도구의 기본값까지. 오타 하나가 원본에서 복제될 때마다 같이 퍼졌다. 나중에 세어 보니 여러 파일, 여러 곳에 같은 잘못된 이름이 박혀 있었다. 뿌리 하나를 못 뽑으면 가지 전부에서 같은 문제가 반복된다.

이름이 맞다는 것과 그 이름으로 실행됐다는 것은 다른 말이다

이 사고를 겪고 나서야 두 문장을 구분하게 됐다. "설정에 그 이름이 적혀 있다"와 "그 이름의 모델이 실제로 그 일을 했다"는 완전히 다른 주장이다. 앞 문장은 파일을 열어 보면 바로 확인된다. 뒤 문장은 호출이 실제로 어떻게 처리됐는지를 봐야만 안다. 나는 오랫동안 앞 문장이 참이면 뒤 문장도 저절로 참이라고 믿었다. 아니었다.

비유하면 이렇다. 식당에 예약할 때 "김 셰프님으로 부탁드립니다"라고 이름을 남겼다고 해서, 그 이름이 영수증에 찍혀 나온다고 해서, 실제로 김 셰프가 주방에서 그 요리를 만들었다는 보장은 없다. 주방이 바쁘면 다른 요리사가 대신 만들고 영수증 양식은 그대로 두는 식당도 있을 수 있다. 손님은 영수증만 보고 "역시 김 셰프 솜씨네"라고 믿는다. 맛이 평소와 다르다는 걸 눈치채지 못하면 그 믿음은 계속 유지된다.

교차 검증의 전제는 서로 다른 벤더가 서로 다른 관점으로 같은 결과물을 본다는 데 있다. 이 전제가 성립하려면 "내가 요청한 벤더가 실제로 그 검증을 수행했다"는 사실이 확실해야 한다. 그런데 표시명은 요청 시점의 의도만 보여줄 뿐, 실행 시점의 사실을 보증하지 않는다. 요청과 실행 사이에 조용한 대체가 끼어들면, 검증 결과에는 여전히 원하던 벤더의 이름이 붙어 있지만 실제로는 그 벤더가 검증하지 않은 것이 된다. 겉으로는 두 벤더가 교차 확인한 것처럼 보이는데 실제로는 한 벤더 안에서 끝난 셈이다.

표시명이 배신하는 세 가지 길목

같은 상황을 몇 번 더 겪으며 표시명과 실체가 갈라지는 지점이 대체로 세 군데로 반복된다는 걸 알았다.

첫 번째는 이름이 비슷한 슬러그다. 정식 이름과 미리보기(프리뷰) 이름처럼 철자 몇 글자만 다른 슬러그가 흔하다. 정식판이 나온 뒤에도 예전 미리보기 이름이 문서나 설정에 남아 있는 경우가 많다. 둘 다 그럴듯해 보이니 사람 눈으로는 구분이 잘 안 된다.

두 번째는 설정이 여러 곳에 흩어져 있는 구조다. 같은 값이 로컬 설정·공유 설정·연동 도구 기본값처럼 여러 파일에 중복 저장되면, 하나를 고쳐도 나머지가 안 고쳐진 채 남는다. 겉으로는 "고쳤다"고 생각하지만 실제 호출은 여전히 안 고쳐진 사본을 타고 나간다.

세 번째가 제일 조용하다. 알 수 없는 이름을 만났을 때 시스템이 에러 대신 알아서 대체 모델로 넘어가는 동작이다. 이게 편의 기능처럼 보이지만 검증 맥락에서는 함정이다. 에러가 났다면 바로 알아챘을 텐데, 대체가 조용히 일어나면 화면상 아무 이상 신호가 없다. 결과가 나오고, 이름표도 맞고, 다 정상으로 보인다. 실은 그 결과를 만든 게 내가 생각한 모델이 아니었을 뿐이다.

수십 번, 로그에만 남아 있던 증거

이 문제를 잡아낸 방법은 특별하지 않았다. 검증 결과가 지나치게 후하다는 감이 먼저 왔고, 그다음 호출 로그를 처음부터 끝까지 훑었다. 검증 도구가 남기는 실행 로그 안에 "요청한 모델 이름을 인식하지 못해 기본 모델로 대체한다"는 문구가 반복돼 있었다. 하나둘이 아니라 수십 번이었다.

이 숫자가 의미하는 바는 이렇다. 그 잘못된 설정이 살아 있던 기간 동안 그 벤더로 보낸 요청 상당수가 실제로는 더 가벼운 대체 모델의 응답이었다는 뜻이다. 그런데 결과 파일이나 화면에는 원래 지정했던 벤더·모델 이름이 그대로 찍혀 있었다. 검증 통과 기록만 보면 "상위 모델이 확인했다"고 읽히지만, 로그를 보면 "대체 모델이 확인했다"가 진실이었다.

이름표가 달린 배지를 돋보기로 확대해 들여다보는 모습으로, 표시된 이름을 그대로 믿지 않고 자세히 검증해야 한다는 의미를 담은 이미지
표시명을 그냥 믿지 않고 돋보기를 들이대듯 자세히 들여다봐야 한다는 것을 상징하는 이미지.

고친 방법은 간단했다. 잘못된 슬러그를 정확한 이름으로 전부 바꾸고, 실제로 그 이름이 응답하는지 살아있는 호출로 한 번 더 확인했다. 파일을 몇 개 고쳤다고 끝내지 않고, 진짜 그 모델이 응답 코드를 정상으로 돌려주는지까지 실측했다. 표시명을 고치는 것과 그 표시명이 실제로 작동하는지 확인하는 것, 이 둘도 서로 다른 일이었다.

표시명 대신 무엇을 봐야 하나

이 사건 이후로 표시명을 완전히 안 믿지는 않되, 표시명만으로 끝내지 않는 습관을 들였다. 표시명이 참인지 확인할 수 있는 실제 호출 근거는 몇 가지로 정리된다.

확인 대상 믿으면 안 되는 것 대신 봐야 하는 것
어떤 모델이 검증했나 결과 파일·화면에 표시된 이름 실행 로그에 남은 실제 호출 모델 값
요청이 성공했나 에러가 안 났다는 사실 대체·폴백 발생 여부를 알리는 로그 문구
설정이 다 고쳐졌나 원본 설정 파일 하나만 확인 실제로 쓰이는 모든 사본·미러 파일 전수 확인
지금도 맞게 동작하나 과거에 한 번 확인했다는 기록 지금 시점에 다시 실행해 본 결과(재현 가능한 호출)
두 벤더가 정말 다른가 결과 파일 이름에 벤더명이 들어 있다는 것 각 결과가 서로 다른 실행 로그·응답 근거에서 나왔는지

핵심은 한 문장으로 줄일 수 있다. 판정은 자기 보고가 아니라 실행 증거로 내린다. 모델 스스로 "저는 A입니다"라고 말하는 것도, 설정 파일에 A라고 적혀 있는 것도 자기 보고에 가깝다. 진짜 증거는 그 요청이 실제로 어떤 응답 경로를 탔는지 보여주는 로그, 혹은 지금 다시 호출해서 확인한 결과다.

이건 작성자와 다른 벤더가 검증해야 한다는 원칙과 맞닿아 있다. 그 원칙이 성립하려면 "정말 다른 벤더가 봤다"는 사실 자체가 참이어야 하는데, 표시명만 믿으면 그 전제가 조용히 무너질 수 있다. 벤더를 나누는 규칙을 아무리 잘 세워도, 그 규칙이 가리키는 이름이 실제 호출과 일치하는지 별도로 확인하지 않으면 규칙은 종이 위에서만 유효하다.

설정에 적힌 표시명만 확인하는 경로와 실행 로그로 실제 호출 모델을 확인하는 경로를 나란히 비교한 다이어그램
직접 생성한 오리지널 다이어그램.

재발 방지 체크리스트

  • 모델 슬러그를 설정에 적을 때, 자동완성이나 기억이 아니라 공식 목록에서 정확한 철자를 복사했는가.
  • 같은 설정값이 저장된 모든 사본·미러 파일을 한 번에 나열하고 전부 확인했는가(원본 하나만 고치고 끝내지 않았는가).
  • 모델 이름을 인식 못 했을 때 조용히 다른 모델로 넘어가는지, 아니면 명확한 에러를 내는지 알고 있는가.
  • 검증 결과를 신뢰하기 전에 실행 로그에서 "대체·폴백·인식 실패" 같은 문구를 검색해 봤는가.
  • 결과 파일 이름에 벤더명이 들어 있다는 것과 실제로 그 벤더가 호출됐다는 것을 같은 것으로 취급하지 않았는가.
  • 중요한 설정 변경 뒤에는 문서 수정에서 끝내지 않고, 실제로 살아있는 호출 한 번으로 재확인했는가.

표시명은 의도를 보여줄 뿐 사실을 증명하지 않는다. 설정 파일에 원하는 이름을 적어 넣는 일과 그 이름의 모델이 실제로 응답하는 일 사이에는, 조용히 대체가 끼어들 틈이 늘 있다. 다음에 검증 결과를 볼 때는 파일 이름부터 안심하지 말고 로그부터 열어 보길 권한다.