보안 카메라에게 "모르겠습니다"라고 말하도록 가르쳤더니, 유용성이 줄어들기는커녕 오히려 늘어났다
요약
보안 카메라 시스템의 오탐지를 줄이기 위해 시각-언어 모델(VLM)을 활용하여 맥락을 파악하는 프로젝트를 소개합니다. 모델이 불확실한 상황에서 추측(Hallucination)하지 않고 '모르겠다'고 답하도록 유도함으로써 알림의 유용성을 높이는 과정을 다룹니다.
핵심 포인트
- 단순 움직임 감지를 넘어 상황 맥락을 파악하는 VLM 기반 시스템 구축
- YOLOv8n과 Qwen-VL을 결합한 로컬-클라우드 하이브리드 아키텍처
- 모델의 환각 현상을 방지하기 위한 '불확실성' 처리의 중요성
- 사용자에게 유의미한 정보를 제공하여 알림 피로도 감소
해커톤을 위해 초인종 카메라 AI를 구축하던 4일 차쯤 되었을 때,
제 시스템이 저에게 거짓말을 하는 것을 발견했습니다. 악의적인 의도는 아니었습니다. 그저 우리 모두가 "모르겠다"라고 말하고 싶지 않을 때 그러는 것처럼, 시스템이 추측을 하고 있었을 뿐입니다. 그 문제를 해결하는 과정이 제작 과정 중 그 어떤 것보다 흥미로웠기에, 이 포스트는 주로 그 과정에 대해 다루며, 그 과정에서 겪은 정말 웃기거나 고통스러웠던 버그 이야기들을 함께 담았습니다.
아무도 해결하려고 하지 않았던 문제
시중에 나와 있는 모든 초인종 카메라는 한 가지 질문에 답합니다. 움직임이 있었는가?
그것은 잘못된 질문입니다. 밤 11시에 휴대폰이 울릴 때 사람이 실제로 답을 듣고 싶어 하는 올바른 질문은 _이것에 신경을 써야 하는가?_입니다. 카메라는 이에 답하지 못하며, 그래서 사람들은 확인도 하지 않고 알림을 밀어서 지워버리는 습관을 갖게 됩니다. 알림은 소음이 됩니다. 정작 소음이 아닌 상황이 닥쳤을 때는 이미 주의를 기울이는 것을 멈춘 상태가 됩니다.
그래서 이 프로젝트 — 저는 이를 Kenbunshoku (見聞色, 대략 "지각하는 기술"이라는 뜻으로, 상황이 명백해지기 전에 읽어내는 특정 무술 전통의 용어)라고 불렀습니다 — 는 빠져 있는 한 가지 계층인 _맥락 (context)_을 추가하려고 시도합니다. "무언가 움직였다"가 아니라, "배달 유니폼을 입은 사람이 택배를 들고 당신의 문 앞에 서 있다" 또는 "누군가 명확한 이유 없이 이례적인 시간에 입구 근처를 서성이고 있다"에 더 가까운 정보입니다.
아키텍처를 한마디로 요약하자면 다음과 같습니다: 로컬 YOLOv8n 탐지기 (detector)가 카메라 스트림을 감시하며 실제로 사람이 포함된 프레임만 전달합니다. 해당 프레임들은 클라우드 백엔드로 전송되며, 여기서 Qwen-VL (Alibaba Cloud의 시각-언어 모델 (vision-language model))을 호출하여 이미지에서 실제로 무슨 일이 일어나고 있는지 추론합니다. 경량 메모리 계층 (memory layer)은 이것이 반복되는 패턴인지 확인합니다. 그리고 추론 내용이 평이한 언어로 포함된 푸시 알림이 집주인의 휴대폰으로 전송됩니다. 이것이 시스템의 전부입니다. 시스템의 어떤 부분도 당신을 대신해 행동하지 않습니다. 잠금장치도, 경보기도, 누구에게 거는 전화도 없습니다. 시스템은 당신에게 정보를 알려줄 뿐입니다. 결정은 당신이 합니다.
마지막 문장은 보기보다 더 많은 역할을 하고 있으며, 이에 대해서는 나중에 다시 다루겠습니다.
여기 실제로 작동 중인 영상이 있습니다. 제작 가치라고는 전혀 없는 제 휴대폰으로 촬영한 것이며 — 실제 탐지(detection), 실제 Qwen-VL 분류(classification), 그리고 실제 기기에 도착하는 실제 푸시 알림(push notification)을 보여줍니다:
(영상미가 아니라 시스템을 판단해 주세요.)
모델이 했던 거짓말
초기에는 분류 프롬프트(classification prompt)가 단순히 Qwen-VL에게 프레임을 보고 다음 중 하나를 결정하도록 요청했습니다: 이 사람이 "익숙한(familiar)" 사람인가, "배달원 같은(delivery-like)" 사람인가, 아니면 "이상한(anomalous)" 사람인가?
저는 의도적으로 못생기고, 흐릿하며, 세부 정보가 없는 이미지 — 거의 실루엣만 보이는 이미지 — 를 사용하여 거부하거나 정직하게 "불분명함(unclear)"이라고 답하기를 기대하며 테스트했습니다. 하지만 결과는 다음과 같았습니다:
"익숙함(familiar)" — "...그들이 알려진 개인임을 시사함."
다시 한번 읽어보세요. 모델은 이 집에 사는 누구에 대한 참조 사진(reference photo)도 가지고 있지 않았습니다. 모델은 존재 이래로 이 "알려진 개인"을 본 적이 없습니다. 그것은 결코 알 수 없는 사실이었습니다. 그럼에도 불구하고 모델은 확신에 차 있고 구체적이며, 완전히 조작된 인지 주장을 내놓았습니다. 왜냐하면 제가 정체성을 묻는 듯한 형태의 질문을 던졌고, 모델은 그 공백이 존재함을 인정하는 대신 그럴듯하게 들리는 언어로 공백을 채우며 그에 맞춰 답변했기 때문입니다.
이것은 자세히 들여다보면, 회의에서 무지해 보이고 싶지 않아 하는 사람의 실패 모드(failure mode)와 정확히 일치합니다. 정보는 없지만, "확신에 찬 답변의 형태"를 만들어내기는 쉽습니다. 그리고 확신에 찬 형태의 답변은 "모르겠습니다"라는 답변보다 더 자주 보상을 받습니다 — 중요한 순간에 틀리기 직전까지 말입니다.
해결책은 더 큰 모델이나 더 긴 프롬프트 강의가 아니었습니다. 그것은 "익숙함(familiar)"이 무엇을 의미할 수 있는지 그 정의를 다시 내리는 것이었습니다:
"익숙함(familiar)"이란 방문이 예상대로이며 우려 사항이 낮아 보임(presents as)을 의미합니다 — 차분한 태도, 평범한 낮 시간의 접근, 특이한 물건 없음 — 즉, 당신이 그 사람의 신원을 알아보는 것이 아닙니다. 당신에게는 참조 사진(reference photos)이 없습니다.
그리고 실제 작업을 거의 다 수행한 또 하나의 문장입니다:
시각적 증거가 '익숙함(familiar)' 또는 '배달 관련(delivery-like)'을 명확하게 뒷받침하지 못한다면, 추측하기보다는 '비정상적(anomalous)'으로 선택하세요.
같은 흐릿한 테스트 이미지, 같은 모델, 새로운 프롬프트:
"비정상적(anomalous)" — "이미지가 너무 흐려서 명확한 행동, 휴대 물품 또는 맥락을 판단할 수 없어, 익숙함이나 배달 관련으로 분류하는 것이 불가능합니다."
이것은 더 나쁜 답변이 아닙니다. 이는 범주적으로 더 정직한 답변입니다. 모델은 자신이 가지고 있지 않은 기억을 꾸며내는 것(confabulating)에서 벗어나, 자신이 볼 수 있는 것의 한계를 정확하게 보고하는 것으로 바뀌었습니다. 홈 보안 시스템에게 있어서 '확신할 수 없으니 조심스럽게 판단한다'는 것은 어느 방향으로든 자신감 넘치는 잘못된 추측보다 훨씬 좋으며 — 단지 모델에게 그렇게 말할 권한을 주는 것만으로 가능했습니다.
"더 섬뜩하고, 더 비싼" 버전을 거부하며
만약 당신이 신원 인식을 위해 '익숙함'에 집착한다면, 다음 자연스러운 질문은 이것일 것입니다. 왜 직접 얼굴 매칭(face matching)을 하지 않는가? 임베딩(embeddings)을 저장하고, 알려진 방문객과 비교하여 실제 신원-신뢰도 점수(identity-confidence score)를 받아내는 것이 어떨까?
저는 그 질문에 대해 한동안 생각했고, 결론은 이렇습니다. 아니요. 의도적으로, 영구적으로, 게으름 때문이 아니라 원칙 때문에 말입니다.
그 이유는 다음과 같습니다. 당신의 문 앞에 오는 모든 사람에 대한 생체 인식과 유사한 데이터(biometric-adjacent data)를 저장하는 시스템은 그렇지 않은 시스템과는 근본적으로 다른 종류의 객체입니다 — 유출될 경우 위험도가 다르고, 윤리적 무게가 다르며, 관찰되는 사람들(그들 중 일부는 누구의 얼굴 인식 데이터베이스에도 동의하지 않았을 뿐더러, 해커톤 프로젝트에 대해서도 마찬가지)과의 관계 자체가 다릅니다. 그리고 결정적으로: 그것은 필요하지 않았습니다. 실제 제품의 요구 사항 — "매주 화요일마다 오는 같은 배달원 때문에 깨우지 마라" — 은 신원이 아닌 방문(visits) 패턴 매칭만으로 충분히 만족되는, 훨씬 저렴하고 훨씬 더 정직한 메커니즘을 통해 충족됩니다.
메모리 계층(memory layer)은 단지 다음과 같이 질문합니다: 이 카메라가 지난 2주 동안 동일한 요일, 유사한 시간에, 반복적으로 유사한 분류(classification)를 목격했는가? 만약 그렇다면, 그것은 "인식된 패턴(recognized pattern)"입니다. 여전히 로그에는 기록되지만, 다섯 번째 연속되는 화요일에 휴대폰이 울리는 대신 푸시 알림은 조용히 억제됩니다. 만약 패턴이 매칭되는 시간대라 할지라도 진정으로 인식되지 않은 이례적인 방문(anomalous visit)이 발생한다면, 이는 여전히 통과됩니다. 시스템은 패턴 여부와 상관없이 "이례적인(anomalous)" 상황에 대해서는 절대 침묵하지 않습니다.
이것은 추가 비용이 들지 않습니다. 임베딩(embeddings), 벡터 데이터베이스(vector database), 추가적인 모델 호출(model calls), 그리고 단 한 번의 실시간 분류(live classification)에 필요한 것 이상의 이미지 저장 공간도 필요하지 않습니다. 그저 SQLite 테이블과 적절한 SQL 쿼리 하나면 충분합니다. 그리고 이 시스템은 자신이 모르는 것을 안다고 주장하지 않습니다. "이 시간대는 일상적인 패턴이 있다"는 것은 진실이며, 검증 가능하고, 정직한 주장입니다. 반면 "나는 이 특정 인간을 알아본다"는 이 시스템이 할 권한이 있는 주장이 아니기에, 저는 시스템이 결코 그런 주장을 할 수 없도록 만들었습니다.
저렴함(Cheap)과 정직함(honest)은 두 번의 설계 결정에서 동일한 결과로 나타났습니다.
실제 기능으로서의 절제 (Restraint as the actual feature)
시스템은 결코 자율적인 행동을 취하지 않습니다. "드물게"가 아니라, 더 인상적인 데모가 될 수 있었던 상황에서도 제가 완화하기를 거부했던 엄격한 규칙으로서 "결코" 하지 않습니다. "이례적인" 상황이라고 해서 문을 자동으로 잠그거나, 누구에게 자동으로 전화를 걸거나, 어떤 종류의 제어 신호(control signal)를 보내는 일도 결코 없습니다. 그저 이유(reasoning)가 첨부된 알림을 결정권을 가진 인간에게 보낼 뿐입니다.
이를 "AI가 더 많은 것을 할 수 있었지만 우리가 억제했다"는 식의 한계로 읽기는 쉽습니다. 하지만 저는 그 반대라고 주장합니다. 절제(restraint)가 곧 설계입니다. 당신의 현관문을 지켜보며 가끔 틀리는 시스템(모든 시스템이 그렇습니다)이 용인될 수 있는 이유는, 틀렸을 때의 비용이 "비전 모델의 확신도가 73%였다는 이유로 시스템이 실제 문에 무언가 조치를 취하는 것"이 아니라 "약간 짜증 나는 알림"이기 때문입니다. 인간을 루프에 포함시키는 것(keeping a human in the loop)은 나중에 덧붙이는 기능이 아닙니다. 그것은 확신에 찬 목소리로 저지르는 실수들을 포함하여, 그 상류(upstream)에 있는 모든 것을 견딜 수 있게(survivable) 만드는 핵심 요소입니다.
diff(차이점)를 신뢰하지 않게 된 후에야 나타난 버그들
이 버그들은 단 하나도 빠짐없이 코드 리뷰(code review)를 통과했습니다. 화면상으로는 모두 괜찮아 보였습니다. 하지만 실제로는 전혀 괜찮지 않았습니다.
- 엠 대시(em dash) 하나가 푸시 알림(push notification)을 중단시켰습니다. 알림 제목에 스타일을 위해 일반적인 엠 대시를 사용했습니다. HTTP 헤더 값은 반드시 ASCII/latin-1이어야 합니다. 요청은 원인을 지목할 수 있는 방식으로 명확하게 실패하지 않았습니다. 그저 실제 알림이 처음으로 발송되려 할 때, 네트워킹 라이브러리 깊숙한 곳에서
UnicodeEncodeError를 던졌을 뿐입니다. 코드 자체는 전혀 잘못되어 보이지 않았습니다. - 모바일 OS가 모든 외부 네트워크 트래픽을 조용히 삼켜버렸습니다. 알림 클라이언트는 아무 곳에도 연결되지 않았고, 오류도 표시하지 않았으며, 문제가 있다는 신호도 주지 않았습니다. macOS의 앱 샌드박스(App Sandbox)가 소켓(socket)에 도달하기도 전에 권한(entitlement) 수준에서 모든 요청을 조용히 차단하고 있었기 때문입니다. Android는 이와 정반대의 문제를 가지고 있었습니다.
INTERNET권한이 선언되지 않아 똑같이 아무런 반응 없이 조용히 처리되었습니다. 정적 분석(Static analysis)은 두 경우 모두에 대해 아무런 지적을 하지 못했습니다. 실제 하드웨어에서 실제 앱을 실행했을 때만 이 문제들이 드러났습니다. - 카메라 루프가 과거를 재처리하느라 멈춰버렸습니다. 카메라를 손에, 그다음엔 펜에, 그다음엔 얼굴에 비추면 시스템은 계속해서 펜을 보고하고 있었습니다. 정확히 고장 난 것은 아니었습니다.
cv2.VideoCapture가 수 초가 걸리는 분류(classification) 왕복 시간(round-trip)이 프레임을 소진하는 속도보다 더 빠르게 들어오는 프레임을 버퍼링했기 때문입니다. 그래서 루프는 실시간 장면이 지나가는 동안 늘어나는 과거 프레임의 백로그(backlog)를 성실히 처리하고 있었습니다. 해결책은 가장 최신 프레임만 유지하고 이전의 모든 프레임은 조용히, 의도적으로 폐기하도록 하는 백그라운드 스레드(background thread)를 사용하는 것이었습니다. 이는 바로 이런 종류의 문제에 대한 표준적인 정답이지만, 자신의 카메라 앞에 자신의 손을 두고 실제로 발생하는 것을 목격한 후에야 비로소 명확해지는 해결책입니다. - 시스템이 더 신중해질수록 더 느려졌습니다. 단일 요청이 응답하기 전에 비전 모델(vision model)에 한 번, 푸시 서비스(push service)에 한 번, 총 두 번의 순차적인 네트워크 호출을 조용히 수행하고 있었으며, 두 호출 모두 타임아웃(timeout)이 설정되어 있지 않았습니다. 대부분의 경우에는 문제가 없었습니다.
가끔 두 홉(hop)이 동시에 느려지면서 타임아웃(timeout) 예산을 초과하는 경우가 발생했고, 시스템은 몇 초 늦게 실제로 계산해낸 진짜 분류(classification) 결과 대신 일반적인 "클라우드 접속 불가" 경고로 대체되어 버렸습니다.
이 중 어느 것도 생소한 것이 아닙니다. 이 모든 것들은 잘 알려진 범주의 버그(bug)이며, 잘 알려진 해결책이 있습니다. 이들의 공통점은 _코드를 읽는 것만으로는 아무것도 잘못되었다는 신호를 전혀 주지 않았다_는 점입니다. 이 중 그 어떤 것도 찾아낼 수 있는 유일한 방법은 실제 하드웨어에서, 실제 네트워크를 대상으로, 실제 시스템을 실행하고 그것이 내 눈앞에서 실패하는 것을 지켜보는 것뿐이었습니다.
재귀적인 부분
저는 대부분의 타이핑을 AI 페어 프로그래머(AI pair programmer)에게 맡기며 이 프로젝트를 구축했습니다. 작업 시작 3일 차가 되어서야 완전히 깨닫게 된 아이러니가 하나 있습니다. 저는 프로젝트 내내 한 AI 시스템에게 확신을 가지고 추측하는 것을 멈추고 불확실성을 인정하도록 가르치는 데 시간을 보냈습니다. 그러면서 동시에, 그 제안들이 얼마나 그럴듯하게 들리는지에 의존하기보다 현실에 근거하여 끊임없이 검증(grounding)되어야만 하는 다른 AI 시스템과 실시간으로 협업하고 있었던 것입니다. 컴파일(compile)이 된다고 해서 작동하는 코드는 아닙니다. 읽기 좋게 짜인 계획이라고 해서 실제 전화기, 실제 Alibaba Cloud 콘솔, 실제 서버를 대상으로 하는 실제 curl 명령어를 견뎌낼 수 있는 계획은 아닙니다.
인간이 작성한 부분과 AI가 작성한 부분을 막론하고, 전체 구축 과정을 관통하는 하나의 문장은 결국 동일했습니다. 자신의 확신이 아니라 현실에 근거하여 검증하라. 이 문장은 "익숙한" 환각(hallucination) 현상에 대한 완전한 해결책입니다. 위 목록에 있는 모든 버그에 대한 완전한 해결책이기도 합니다. 또한, 비전 모델(vision model)의 부착 여부와 상관없이 무언가를 출시하려는 모든 사람에게 아마도 훌륭한 조언이 될 것입니다.
Kenbunshoku는 Qwen Cloud와 함께하는 Global AI Hackathon Series를 위해 구축되었으며, 방문자 추론을 위해 Qwen-VL을 탑재한 Alibaba Cloud ECS에서 실행됩니다. 설계상으로는 카메라에 구애받지 않으며(Camera-agnostic), 원칙적으로는 인간 참여형(human-in-the-loop) 방식을 따릅니다. 그리고 — 이번 주 기준으로 — 자신이 모르는 것에 대해 조금 더 정직해졌습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기