본문으로 건너뛰기

보고, 판단하고, 의심하는 향상된 Thinking 모드

· 약 8분
Seongwoo Kong
Seongwoo Kong
AI Specialist
Hyunchan Moon
Hyunchan Moon
AI Specialist

보고, 판단하고, 의심하는 향상된 Thinking 모드

작은 VLM에게 "알아서 깊게 생각해"라고 요청하는 것만으로는 일관된 판단을 기대하기 어렵습니다. 모델은 하나의 호출 안에서 여러 문제를 동시에 해결하려 하고, 애매한 증거를 오래 되짚다가 결론을 내리지 못할 수도 있습니다.

이번 향상된 Thinking 모드에서는 모델의 내부 추론에 모든 판단을 맡기는 대신, 사고의 흐름 자체를 역할과 구조로 설계했습니다. 기준을 먼저 세우고, 볼 영역을 고정한 뒤, 서로 다른 관점에서 판단하고, 마지막 결정은 코드가 담당하도록 파이프라인을 재구성했습니다.

핵심은 생각을 더 많이 시키는 것이 아니라, 보고, 판단하고, 의심해야 할 순서를 명확하게 만드는 것입니다.




1. 기존 Thinking 구조의 문제

기존 개발 버전은 incidents 블록에 포함된 여러 위험 상황을 한 번의 VLM 호출에서 동시에 판정했습니다.

구조는 단순하지만, 한 번의 호출에 서로 다른 문제를 모두 맡긴다는 점에서 두 가지 문제가 발생했습니다.

1) 한 번에 여러 문제를 동시에 판단

호출 한 번이 fall, smoke, fire를 동시에 판정합니다. 어떤 항목은 쉽게 판단할 수 있어도, 하나의 애매한 항목이 전체 Reasoning Budget을 차지할 수 있습니다.

2) 생각의 범위를 제한하기 어려움

Reasoning은 모델 내부에서 일어나는 블랙박스 과정입니다. 애플리케이션이 조절할 수 있는 값은 사실상 Budget 숫자 하나뿐이고, 모델이 어떤 기준으로 무엇을 반복해서 검토하는지는 통제하기 어렵습니다.

구분기존 구조
대상고정된 3종: fall / smoke / fire
판정 기준코드에 하드코딩
판단 근거남지 않음. 최종 bool만 반환
실패 시조용히 모든 결과가 False가 될 수 있음



2. 실제 Thinking trace가 보여준 한계

증기가 깔린 설비실에서 smoke를 판정하는 상황을 살펴보면, 모델이 "깊이 생각한다"는 것이 항상 새로운 근거를 찾는다는 의미는 아니라는 점을 확인할 수 있습니다.

Smoke 판정에 사용한 설비 장면

Qwen3.5VL-9B-Thinking Langfuse Trace


모델은 흰색 증기를 발견한 뒤, 증기인지 가스 누출인지 판단하기 위해 같은 규칙을 반복해서 읽었습니다. 그러나 반복 과정에서 새로운 시각 증거가 추가되지는 않았습니다.

"Wait, let's look closer."의 반복 — 새로운 시각 증거는 0개

이 trace에서 확인한 대표적인 문제는 다음과 같습니다.

증상의미
같은 규칙을 여러 번 다시 읽음새로운 정보가 없는 rumination
결론을 내리지 못하고 순환함생각을 끝내는 방법을 모름. 답변이 Budget이 끊기는 지점에 좌우됨
데이터셋에서는 다른 해석도 가능하다고 재검토함Prompt에 정의한 정책을 즉석에서 재해석
쉬운 항목은 짧게 끝나고 애매한 항목이 전체를 차지함하나의 문제가 Reasoning Budget을 독점

결국 소형 VLM에게 "알아서 깊게 생각해"라고 요청하는 것만으로는 충분하지 않습니다. 모델이 무엇을 먼저 확인하고, 언제 판단을 끝내며, 애매한 경우 어떻게 처리할지를 구조로 안내해야 합니다.




3. 설계 철학: 사고의 흐름을 구조로 만든다

향상된 Thinking 모드는 다음 세 가지 원칙을 중심으로 설계했습니다.

원칙내용
1. 한 호출 = 한 문제작고 명확한 과업으로 분리해 각 호출에서는 별도의 Reasoning이 필요하지 않도록 합니다. 모든 호출은 enable_thinking: false인 Instruct 모델을 사용합니다.
2. 사고의 흐름 = 구조기준 수립 → 시선 고정 → 판단 → 반증의 흐름을 Node 순서로 안내합니다.
3. 결정은 코드가 담당최종 알람 여부는 LLM의 단일 출력이 아니라 결정론적 Gate가 판단합니다.

새 아키텍처는 시나리오를 먼저 규칙으로 정리하고, 서로 다른 역할의 Voter가 독립적으로 판단하도록 구성됩니다.

  • 두 Voter는 병렬·독립적으로 실행되며 서로의 출력을 볼 수 없습니다.
  • 모든 호출은 enable_thinking: false인 Instruct 방식으로 실행합니다.
  • 하나의 호출에는 하나의 판단 문제만 전달합니다.
  • 최종 알람은 두 Voter가 모두 Positive일 때만 발생합니다.

이 구조에서 LLM은 모든 것을 한 번에 결정하지 않습니다. 각 단계가 자신의 역할에 집중하고, 코드가 단계 사이의 연결과 최종 결정을 통제합니다.




4. 핵심 장치: "지금 여기를 보고 있어"

판단하기 전에 모델이 어디를 보고 있는지부터 근거로 출력하도록 만들었습니다. 이를 담당하는 역할이 focus_locator입니다.

focus_locator는 판정을 내리는 역할이 아니라, 관찰 대상과 위치를 제안하는 역할만 합니다. 이후 vote_context는 전체 프레임과 Locator가 지정한 영역의 Crop을 함께 보고, vote_skeptic은 Locator의 설명을 참고하지 않고 전체 프레임만으로 독립 검증합니다.

장치효과
근거 선언무엇이 어디에 보이는지를 판단 전에 텍스트와 좌표로 출력합니다.
시선 고정vote_context는 전체 프레임과 해당 영역의 20% Margin Crop을 함께 봅니다.
오염 방지vote_skeptic은 Crop 없이 전체 프레임만 보므로 Locator가 틀려도 판정이 오염되지 않습니다.

왜 성능에 도움이 되는가

  • 8B급 VLM은 이미지 전체의 인상으로 판단하기 쉽습니다. 명시된 영역의 증거를 먼저 제공하면 판단을 해당 근거에 정박(grounding)할 수 있습니다.
  • 20% Margin Crop은 대상을 확대하면서도 주변 맥락을 유지합니다. 대상의 일부만 보고 오판하는 문제를 줄이기 위한 장치입니다.
  • 어디를 보았는지가 텍스트로 남기 때문에, 오판이 발생했을 때 시선이 잘못되었는지 판단이 잘못되었는지 구분할 수 있습니다.



5. 실패한 trace를 구조로 해결하기

기존 Thinking trace에서 나타난 문제를 새로운 Pipeline의 역할과 Gate로 대응했습니다.

기존 trace의 실패새 구조의 대응
판정 중 규칙을 다시 협상함규칙을 판정 전에 scenario_rule_builder로 확정합니다.
“정말 smoke인가?”라는 내면 독백이 반복됨skeptic voter라는 독립 역할로 반증 과정을 제도화합니다.
애매한 상태에서 True/False를 억지로 선택함Voter가 uncertain을 반환할 수 있고, Gate가 알람을 차단합니다.
하나의 문제가 Budget을 독점함한 호출 = 한 문제 원칙으로 호출을 분리합니다.

이렇게 하면 모델의 내부 추론을 길게 만드는 대신, 판단에 필요한 검토 과정을 시스템의 관찰 가능한 단계로 바꿀 수 있습니다.




6. Before / After

구분기존 (develop)신규 (thinking_instruct)
대상고정된 3종임의의 시나리오: 침입, 배회, 유출 등
판정VLM 1회에서 동시 판정역할을 분리한 4회 호출, 호출당 1개 문제
Reasoning모델 내부에서 수행되어 통제하기 어려움Instruct 기반 구조가 흐름을 정의
최종 결정모델 출력 그대로 사용결정론적 AND Gate
판단 근거별도 기록 없음Voter별 투표와 이유를 모두 기록
판정 기준코드에 하드코딩시나리오별로 동적 생성

변경의 핵심은 호출 횟수를 늘리는 데 있지 않습니다. 판단 기준, 관찰 영역, 긍정과 반증의 역할, 최종 결정을 각각 분리해 실패 지점을 추적할 수 있게 만든 데 있습니다.




7. 시나리오를 더 유연하게 확장하기

기존 구조에서는 LLM이 판단 범위를 벗어나기 쉬웠기 때문에 탐지 대상을 연기·화재·쓰러짐 세 가지로 고정할 수밖에 없었습니다.

새 구조에서는 사용자가 incidents 블록을 직접 수정해도, 먼저 rule guide가 판정 기준을 정리합니다. Voter는 생성된 기준에 따라서만 판단합니다.

예를 들어 다음과 같은 요구사항을 입력할 수 있습니다.

  • “연기 발생” → 검은 연기 탐지
  • “화재 발생” → 영역의 대부분을 차지하는 큰 불꽃 탐지

수정된 문구는 그대로 Rule Guide로 생성되고, 이후 각 Voter는 해당 기준을 사용합니다. 따라서 새로운 시나리오를 추가할 때마다 Router나 판정 코드를 수정할 필요가 줄어듭니다.




8. 성능 결과

Precision 0.8273: 오탐 억제

SINGLE 평가에서 신규 구조는 Precision을 크게 높였습니다.

구분F1AccuracyPrecisionRecall
Before0.80730.95360.73160.9006
After0.80420.95180.82730.7823

Precision은 0.7316에서 0.8273으로 0.0957p 상승했습니다. 반면 Recall은 0.9006에서 0.7823으로 낮아졌습니다. 두 Voter가 모두 Positive여야 알람이 발생하는 AND Gate가 오탐을 억제하는 대신, 일부 실제 사례를 보수적으로 차단한 결과입니다.

카테고리별 성능

CategoryBefore PrecisionBefore RecallBefore F1After PrecisionAfter RecallAfter F1
연기·불꽃1.00000.97140.98551.00001.00001.0000
화재0.72880.86000.78900.80850.76000.7835
쓰러짐0.53190.86210.65790.72220.66100.6903

연기·불꽃은 모든 지표가 1.0000에 도달했고, 화재는 Precision이 0.8085로 향상되었습니다. 특히 화재 오탐을 9건으로 억제하면서 운영 환경에서 불필요한 알람을 줄이는 효과를 확인했습니다.

위와 같은 쓰러짐 사례에서는 사람이 바닥에 수평으로 누워 있는지, 단순히 웅크리거나 앉은 자세는 아닌지, 직접적인 시각 증거가 충분한지를 단계적으로 확인합니다.

반대로 붉은 빛이 보이는 장면에서는 조명이나 반사광을 실제 화염으로 단정하지 않습니다. 야간 환경, 광원, 화염 형태, 연소 단서와 연기 동반 여부를 함께 검토한 뒤 명확한 근거가 없으면 alert: false를 반환합니다.




한 줄 요약

8B에게 깊은 생각을 시키는 대신, 사고가 흘러야 할 길을 우리가 먼저 놓았습니다 — 기준을 세우고, 시선을 고정하고, 판단하고, 의심하도록.