Skip to content

fix(ai): STT 모델을 whisper-large → nova-2 로 교체 + 발음 임계치 재보정 - #255

Merged
i3months merged 1 commit into
devfrom
fix/stt-model-nova2
Sep 27, 2026
Merged

i3months merged 1 commit into
devfrom
fix/stt-model-nova2

Conversation

@i3months

Copy link
Copy Markdown
Member

왜

"STT 계속 써도 괜찮냐"는 질문에 답하려고 운영에 실제로 올라온 음성 3종을 30회 돌려
재시도 없이 단발 성공률을 쟀다. 결과가 좋지 않았다.

whisper-large: 30회 중 7회(23%)가 20초 read 타임아웃. 그것도 균일하지 않고 파일별로 갈렸다.

오디오 단발 실패
A 6/10 (60%)
B 1/10 (10%)
C 0/10 (0%)

크기와 무관했다. 특정 오디오에서 Deepgram 쪽 whisper 가 간헐적으로 멎는다.

#244 의 재시도 3회가 이걸 대부분 흡수하고 있었다(= 지금 운영이 안 죽는 이유). 하지만

  • 0.6³ ≈ 최악 오디오는 5번에 1번꼴로 사용자에게 실패가 그대로 보인다
  • 실패할 때마다 20초씩 더 기다린다. 3회 전부 실패면 61초를 기다리고 실패한다

"재시도가 겨우 막아주는" 상태지 안정적인 상태가 아니다.

모델 비교 (각 6회, 동일 오디오·동일 설정)

모델 성공 응답 시간
whisper-large 13/18 1.4 ~ 6.9s
nova-2 18/18 1.5 ~ 3.5s
nova-3 18/18 1.1 ~ 1.8s

별도로 nova-2 를 28회 더 돌려 28/28 확인.

nova-3 를 쓰지 않은 이유

가장 빠르지만 없는 말을 지어낸다. 질문 오디오에 없는 "아 네. 질문 지레인데?" 를
붙였고, 영문 철자가 깨졌다(imbeded, readis). 면접 답변을 채점하는 서비스에서
환각 전사는 가장 나쁜 실패다 — 사용자가 하지 않은 말로 감점될 수 있다.

한국어 품질은 whisper ≈ nova-2 로 실사용 차이가 없었다. 유일한 차이는 기술 영문 처리로,
whisper 는 원문 유지(Revalidation Event), nova-2 는 한글화(리밸리데이션 이벤트)한다.
임베딩·채점 모두 한국어 본문 기준이라 문제되지 않는다고 판단했다.

같이 처리한 부작용 2개

모델 교체는 한 줄이지만 딸린 게 둘 있었다.

① keywords 힌트 경로가 깨어난다. deepgram.py 에 if hint and model.startswith("nova")
분기가 있었다 — whisper 는 이 파라미터에 400 을 내서 지금까지 잠들어 있던 코드다.
nova-2 로 바꾸면 처음으로 실제 요청에 실린다. 운영 키로 직접 호출해 200 + 전사 결과 동일
(부작용 없음)을 확인하고, 힌트가 nova 에서만 실리는 것을 테스트로 고정했다.

② pronunciation_accuracy 분포가 달라진다. 이 값은 STT 신뢰도 근사라 모델마다 스케일이
다르다.
Core 의 DeliveryFeedback.PRONUNCIATION_LOW = 0.85 를 실측으로 재보정했다:

중앙값 p10 0.85 미만
whisper-large (운영 77건) 0.841 — 44건 (57%)
nova-2 (실제 답변 26건) 0.976 0.909 0건

whisper 시절 0.85 는 이미 무의미했다 — 답변의 57% 를 '발음 불분명'으로 찍고 있었으니
신호가 아니라 노이즈였다. nova-2 에서 그대로 두면 이번엔 영영 안 울린다.
0.93 → 하위 15%(4/26) 만 짚는다.

⚠️ 리뷰 포인트: 이 0.93 은 26건짜리 근거다. #247 의 외부 호출 로그가 2주쯤 쌓이면
실제 분포로 다시 볼 값이다. 지금은 "57% 오검출"보다 나은 쪽으로 옮기는 게 목적.

설정 경로 확인 (#248 의 교훈)

#246 이 코드 기본값만 고쳐서 compose/.env 에 가려 무효였던 사고가 있었다. 같은 실수를
피하려고 먼저 확인했다:

  • docker-compose.yml → - DEEPGRAM_MODEL passthrough 만 (기본값 없음) ✅
  • 운영 .env → DEEPGRAM_MODEL 없음, 실행 중 컨테이너 printenv 에도 없음 ✅

→ settings.py 기본값이 그대로 적용된다. 재배포만 하면 반영된다.

ai/.env.example 에는 DEEPGRAM_MODEL=whisper-large 가 살아있는 값으로 있어서 같이 고쳤다
(그대로 두면 로컬 개발자와 신규 배포가 계속 whisper 를 쓴다).

변경

  • settings.py · deepgram.py — deepgram_model 기본값 whisper-large → nova-2
    • provider 클래스 기본값도 같이 맞췄다. settings 만 바꿨더니 두 곳이 어긋났고 테스트가 그걸 잡았다
  • DeliveryFeedback.java — PRONUNCIATION_LOW 0.85 → 0.93 (근거 주석 포함)
  • .env.example · ai/.env.example — nova-2 + "모델 바꾸면 임계치 재보정" 경고
  • ai/CLAUDE.md §8 — 측정치·판단 근거 기록
  • 테스트 3개 — 기본값이 nova-2 인지(Settings.model_fields 기준 = 운영이 실제 쓰는 값),
    nova 에서 힌트가 실리는지, whisper 에서 안 실리는지

검증

  • AI pytest 419 passed / black clean / flake8 clean
  • Backend ./gradlew test BUILD SUCCESSFUL
  • 운영 키로 Deepgram 실호출 비교 (성공률·응답시간·전사 품질·keywords 부작용)

배포 후 볼 것

[n/N] 재시도 로그(#244)에서 [2/3] 이상이 사라졌는지. whisper 시절엔 꾸준히 찍혔다.

"계속 써도 괜찮냐"는 질문에 답하려고 운영 음성 3종을 30회 돌려 재시도 없이
측정했다. whisper-large 는 **23%(7/30)가 20초 read 타임아웃**이었고 파일별
편차가 컸다 — 60% / 10% / 0% 로, 크기와 무관하다.

재시도 3회가 대부분 흡수하지만 최악 오디오는 5번에 1번꼴로 사용자에게 실패가
보이고, 실패할 때마다 20초씩 더 기다린다(3회 전부 실패 시 61초). "재시도가 겨우
막아주는" 상태지 안정적인 상태가 아니다.

모델 비교(각 6회):
  whisper-large  13/18 성공  1.4~6.9s
  nova-2         18/18 성공  1.5~3.5s
  nova-3         18/18 성공  1.1~1.8s

nova-3 는 가장 빠르지만 없는 말을 지어내고("아 네. 질문 지레인데?") imbeded·
readis 처럼 영문 철자가 깨져 제외했다. 한국어 품질은 whisper ≈ nova-2 로,
whisper 가 기술 영문을 원문 유지(Revalidation Event)하는 반면 nova-2 는
한글화(리밸리데이션 이벤트)하는 차이 정도다.

부작용 2개를 같이 처리했다:

1) keywords 힌트 경로가 켜진다. Whisper 는 400 이라 잠들어 있던 코드다.
   운영 키로 실제 호출해 200·전사 동일(부작용 없음)을 확인하고 테스트로 고정.

2) pronunciation_accuracy 는 STT 신뢰도라 모델마다 분포가 다르다.
   PRONUNCIATION_LOW 0.85 → 0.93 재보정. 실측 근거:
     whisper-large 운영 77건 — 중앙 0.841, 0.85 미만 44건(57%) → 이미 무의미
     nova-2 실제 답변 26건 — 중앙 0.976, p10 0.909, 0.93 기준 15%(4/26)
   그냥 두면 이 신호가 영영 안 울린다.

provider 클래스 기본값도 같이 맞췄다 — settings 만 바꿨더니 두 곳이 어긋났고
테스트가 그걸 잡았다.
@i3months
i3months merged commit e2a8c85 into dev Sep 27, 2026
5 checks passed
i3months added a commit to i3months/stackup that referenced this pull request Oct 6, 2026
Team-StackUp#255 에서 nova-2 로 바꾸며 `keywords` 힌트 경로가 깨어났다. 그때는 "운영 키로
호출해 200 + 전사 동일"을 보고 안전하다고 적었는데, **비교 1회로는 '효과 없음'과
'비결정성'을 구분할 수 없었다.** 제대로 측정했다.

같은 오디오(101/466.webm)로 힌트 유/무 5회씩:

  힌트 없음      297자 x4, 285자 x1
  질문전체 힌트   297자 x4, 285자 x1

**두 조건의 출력 분포가 동일하다.** 차이처럼 보이던 것은 힌트가 아니라 nova-2
자체의 비결정성이었다. 단어 하나 + 강도(`백오프:10`)로 줄여도, 영어 단어
(`jitter:10`)로 바꿔도 같았다 — 한국어에서 Deepgram keyword boosting 은
동작하지 않는다. (`keyterm` 은 nova-2 에서 400: "only supported for Nova-3".)

그래서 params["keywords"] 를 뺀다. 효과가 없는데

  · 매 호출마다 질문 본문 200자를 외부로 보내고
  · Deepgram 이 언젠가 이 값을 반영하기 시작하면 답변 전사가 질문 어휘 쪽으로
    끌려간다 — 채점하는 서비스에서 그건 사용자가 하지 않은 말로 감점되는 것이다
    (nova-3 를 환각 때문에 뺀 것과 같은 이유)

hint 인자 자체는 SttProvider 공통 인터페이스라 남겨 둔다.

덤으로 알게 된 것: **nova-2 는 비결정적이다.** 같은 파일 10회 중 2회가 답변
마지막 문장("여기까지 하겠습니다.")을 빠뜨렸다. 재전사가 다른 결과를 내는 것은
버그가 아니라 이 성질 때문이고, 실패하지 않았어도 재전사가 도움이 될 수 있다는
뜻이다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant