TL;DR — 혼자 AI로 증명사진 서비스를 굴립니다. 사진이 규격에 맞는지 보려면 "얼굴이 위아래로 얼마나 기울었나" 같은 값을 알아야 해요. 처음엔 얼굴 특징점 몇 개에서 각도를 역산해 추정했습니다. 그런데 이 추정값이 실제와 십몇 도씩 어긋났어요. 전용으로 재는 방법으로 바꾸자 오차가 2도대로 뚝 떨어졌고요. 문제는 그다음이었습니다. 아무 방법으로도 닿지 않는 값이 하나 남았어요 — 머리 정수리의 위치. 여기서 저는 그럴듯한 숫자를 지어내는 대신, 그 자리를 중립으로 비워 두기로 했습니다. 왜 그게 더 안전한 선택이었는지 적어 둡니다.


추정은 '조용히' 틀립니다

증명사진은 밀리미터의 세계예요. 얼굴이 사진 안에서 어느 높이에 있어야 하는지, 위아래로 얼마나 기울어도 되는지가 규격으로 딱 정해져 있습니다. 그래서 서비스는 매 사진마다 그 각도와 위치를 알아야 해요.

처음엔 편했습니다. 얼굴에서 눈·코·입 같은 특징점 몇 개를 이미 잡고 있었으니, 그 점들의 배치에서 "고개가 위로 몇 도 들렸는지"를 역산하면 되잖아요. 새로 뭘 붙일 필요도 없고, 계산 몇 줄이면 각도가 나옵니다.

그런데 이 값을 실제와 대 봤더니 십몇 도씩 벌어졌어요. 정면을 보고 찍은 사진인데도 "고개를 꽤 숙였다"고 나오는 식이었죠.

문제는 이게 조용히 틀린다는 겁니다. 추정값은 에러를 던지지 않아요. 그냥 숫자 하나를 내놓습니다. 12.4도. 아주 그럴듯하죠. 소수점까지 붙어 있으니 정밀해 보이기까지 합니다. 이 값을 믿고 "규격 미달"이라고 사용자에게 돌려보내면, 멀쩡한 사진이 반려됩니다. 사용자는 왜 반려됐는지도 모르고요.

그럴듯한 가짜 숫자가 위험한 이유가 여기 있어요. 그것은 틀렸다는 신호를 주지 않습니다. 비어 있으면 우리가 채우려 들지만, 그럴듯하게 채워져 있으면 우리는 검산조차 하지 않아요.

잴 수 있는 것은, 제대로 재세요

해법의 첫 절반은 단순했습니다. 각도를 특징점에서 역산하지 말고, 각도를 재라고 만들어진 방법으로 직접 재자. 바꾸고 나니 오차가 십몇 도에서 2도대로 떨어졌어요.

교훈을 좁혀 말하면 이렇습니다. 재라고 만들어지지 않은 도구에서 값을 짜내지 마라. 특징점은 "여기에 눈이 있다"를 잘 알려주는 도구지, "고개가 몇 도 기울었다"를 알려주는 도구가 아니었어요. 옆 동네에서 빌려 온 값은 편하지만, 그 편함의 대가를 사용자가 치릅니다.

여기까지는 흔한 엔지니어링 이야기예요. 제가 진짜 배운 건 나머지 절반이었습니다.

아무도 닿지 못하는 값이 하나 남았습니다

각도를 제대로 재게 됐어도, 값 하나가 계속 저를 괴롭혔어요. 머리 정수리의 위치.

증명사진 규격은 머리 꼭대기부터 턱까지의 길이를 봅니다. 그런데 얼굴을 인식하는 도구들은 하나같이 얼굴까지만 봐요. 눈, 코, 입, 눈썹, 턱선까지는 잡지만, 이마 위 머리카락과 정수리는 커버 범위 밖입니다. 경량으로 정수리를 직접 짚어 주는 방법이 있나 며칠을 뒤졌는데, 결론은 "없다"였어요.

여기서 유혹이 옵니다. 그냥 추정하면 되잖아? 얼굴 아래 절반은 정확히 아니까, 위 절반도 대칭이라고 치고 접어 올리면 정수리가 대충 나올 거야. 아니면 평균 두상 비율을 곱해서 채워 넣든지.

실제로 이런 대칭·비율 추정은 어느 정도 맞습니다. 하지만 어느 정도가 문제예요. 사람마다 이마 높이도, 머리 볼륨도, 헤어스타일도 다릅니다. 볼륨 있는 머리를 한 사람에게 평균 비율을 곱하면 정수리를 실제보다 낮게 잡아요. 그러면 사진은 규격 안에 있는데 서비스는 "머리가 잘렸다"고 우기게 됩니다. 다시, 조용히 틀리는 숫자예요.

그래서 저는 그 값을 지어내지 않기로 했습니다

정확히는 이렇게 했어요. 잴 수 있는 부분(얼굴)은 실측으로 쓰고, 닿지 않는 부분(정수리)은 한쪽으로 편향된 추정을 밀어 넣지 않고 중립으로 비워 뒀습니다. 확신할 수 없는 자리에 확신 있는 척하는 숫자를 앉히지 않은 거예요.

이건 항복처럼 보여요. "정수리를 못 잰다"를 인정하는 거니까요. 그런데 제품 관점에서는 정반대였습니다.

  • 그럴듯한 가짜 값은 자신 있게 틀립니다. 그리고 그 자신감이 사용자에게 그대로 전달돼요. "당신 사진은 규격 미달입니다" — 확신에 찬 오판.
  • 정직한 '모름'은 판단을 유보합니다. 애매한 자리에서 사용자를 함부로 막지 않아요. 확실히 아는 것으로만 문을 여닫습니다.

혼자 굴리는 서비스에서 신뢰는 유일한 자산이에요. 사용자는 제가 밤새 뭘 고쳤는지 몰라요. 자기 사진이 정당하게 처리됐는지 아닌지로만 저를 판단합니다. 한 번의 자신만만한 오판이, 열 번의 정직한 유보보다 신뢰를 크게 깎습니다.

시스템도 "모른다"고 말할 줄 알아야 합니다

돌아보면 이번 일은 두 문장으로 줄어요.

  1. 잴 수 있는 것은, 그것을 재라고 만들어진 도구로 제대로 재라. 옆에서 빌려 온 추정으로 때우지 마라.
  2. 잴 수 없는 것은, 지어내지 마라. 그럴듯한 가짜보다 정직한 '모름'이 안전하다.

사람은 "모르겠어요"라고 말하는 걸 배우는 데 오래 걸립니다. 시스템도 마찬가지예요. 우리는 코드가 항상 답을 내놓길 바라죠. 빈칸이 있으면 불안하니까요. 그런데 어떤 빈칸은 채우는 게 아니라 지키는 겁니다. 모른다는 걸 아는 것도 하나의 정보고, 그 정보를 버리고 그럴듯한 숫자로 덮으면 시스템은 겉만 매끈해지고 속은 거짓말을 하게 됩니다.

증명사진 한 장에서 배운 이야기지만, AI로 뭔가를 자동으로 판정하게 만드는 사람이라면 어디서든 마주칠 갈림길이라고 생각해요. 당신의 시스템은 모를 때 모른다고 말합니까, 아니면 그럴듯한 숫자로 덮습니까?

여러분은 어느 쪽인가요. 저는 요즘, 코드가 자신 있게 내놓는 숫자를 볼 때마다 한 번 더 묻습니다 — 이거 진짜 잰 값이야, 아니면 지어낸 값이야?


혼자 AI 에이전트들과 작은 사진 서비스를 만들며 남기는 빌더 노트입니다. 잘 맞은 판단도, 헛짚은 판단도 그대로 적어 둡니다.