XGEN 15일 무료 체험 — 설치 없이 브라우저에서 바로 시작하세요체험 신청
PlateerAI Labs
·Reading Time | 4 min
작성 | 유지수

회의 녹음 STT와 화자분리를 설계하며 판단이 네 번 바뀌었습니다

회의 녹음 파일을 올리면 화자별 텍스트로 바꿔 주는 기능을 설계하며 범위, 화자분리 모델 배치, 업로드 방식, 호출 순서에 대한 판단이 차례로 바뀐 과정을 정리합니다.

회의 녹음 STT와 화자분리를 설계하며 판단이 네 번 바뀌었습니다 — 커버 일러스트

편집자 노트 · B2B 도입 관점 — 회의록 자동화를 검토하는 고객이 먼저 묻는 것은 대개 "인식률이 몇 %인가"입니다. 이 기고는 도입 가능성이 모델 정확도보다 앞단에서 먼저 갈릴 수 있다는 점을 보여 줍니다. 수백 MB의 녹음 파일이 게이트웨이와 요청 시간 제한을 통과할 수 있는지, 화자분리 모델이 고객사의 GPU 관리 체계 안에 들어가는지, 폐쇄망에서 모델을 반입하고 로드할 수 있는지가 그것입니다.

편집자의 해석으로는, 이 글의 "판단이 네 번 바뀌었다"는 기록은 계획이 흔들린 이야기라기보다 코드를 쓰기 전에 고객 환경의 제약을 확인해 설계를 고친 과정에 가깝습니다. 유사한 프로젝트라면 요구사항 한 줄을 화면, 데이터 경로, 운영 주체로 다시 풀어 보는 단계를 PoC 범위 정의에 포함하기를 권합니다. 또한 글에 나온 처리 시간과 GPU 메모리 수치는 개발 서버에서 짧은 녹음 한 건으로 확인한 값이며, 긴 녹음 처리와 폐쇄망 로드, 회의실 음질에 따른 정확도는 아직 검증 전이라는 점도 함께 읽어 주시기 바랍니다.

회의 녹음 파일을 올리면 화자별 텍스트로 바꿔 주는 기능을 설계하고 있습니다. 10월 29일에 쓰기 시작한 작업계획서는 11월 2일까지 일곱 번 고쳐 썼고, 그사이 처음에 당연하다고 여긴 판단 네 가지가 모두 바뀌었습니다. 기능을 어디에 둘지, 화자분리 모델을 어디서 돌릴지, 파일을 어떻게 올릴지, 화자분리와 받아쓰기를 어떤 순서로 호출할지입니다.

이 글은 아직 구현을 마친 기록이 아니라 설계 단계의 기록입니다. 코드를 쓰기 전에 무엇을 확인했고, 그 확인이 판단을 어떻게 바꿨는지를 정리했습니다. 같은 기능을 폐쇄망이나 온프레미스 환경에 넣으려는 팀이라면 저희가 처음에 놓친 지점이 참고가 될 수 있을 것입니다.

처음에는 대화방 기능의 일부라고 생각했습니다

요구사항은 "STT 모델을 올렸으니 회의 녹음을 텍스트로 바꿀 수 있게 해 달라"는 한 줄이었습니다. 저희는 이것을 XGEN의 대화방(페르소나) 안에서 음성을 다루는 기능으로 이해했고, 첫 계획서도 그 전제로 썼습니다.

다시 확인해 보니 요청자가 원한 것은 전혀 다른 화면이었습니다. 대화와 상관없이, 회의가 끝난 뒤 녹음 파일을 올리면 자동으로 텍스트로 변환되는 독립 메뉴였습니다. 범위를 바로잡으면서 "지금 오디오를 텍스트로 바꿔 주는 화면이 이미 있는가"부터 조사했습니다. 받아쓰기 API는 있었지만 이를 호출하는 화면이 없었고, 그 API는 파일 전체를 메모리로 읽고 60초 안에 끝나야 했습니다. 관리자 화면의 [연결 테스트]는 모델 목록만 확인했고, 개인 설정 화면은 설정을 저장할 뿐이었습니다. 한 시간짜리 회의를 처리할 수 있는 경로는 어디에도 없었습니다.

실시간 음성 입력에서는 "말이 언제 끝났는가"를 판단하는 것이 핵심이었습니다(음성 AI는 '인식률'보다 운영 기준이 중요합니다). 녹음 파일은 끝이 정해져 있지만, 대신 길이가 문제였습니다. 같은 STT 모델을 쓰더라도 풀어야 할 문제가 달랐습니다.

화자분리만 따로 띄우면 GPU는 누가 정하나요

회의록은 누가 말했는지가 빠지면 쓰기 어렵습니다. 화자분리 모델은 크기가 작으니 별도 서비스로 하나 더 띄우면 간단하다고 생각했습니다.

그런데 고객 환경을 들여다보니 GPU를 쓰는 방식이 이미 정해져 있었습니다. XGEN의 모델 서버가 노드의 GPU를 맡고, 관리자는 인프라 화면의 로컬 모델 목록에서 LLM이나 STT 모델을 골라 로드하면서 어떤 GPU에 올릴지 지정합니다. 화자분리만 별도 서비스로 띄우면 GPU를 할당받을 방법이 없었고, 방법이 있더라도 관리자가 모르는 곳에서 GPU를 쓰는 모델이 하나 늘어납니다. 인터넷이 없는 폐쇄망이라 모델 파일도 사람이 직접 반입해야 합니다. 반입하는 방법과 로드하는 방법이 모델마다 다르면 운영자가 기억해야 할 절차가 늘어납니다.

그래서 화자분리도 다른 모델과 똑같이 다루기로 했습니다. 모델 서버의 모델 폴더에 파일을 올리면 로컬 목록에 나타나고, 관리자가 GPU를 골라 로드하고, 다른 서비스는 모델 서버의 API를 호출하기만 합니다. 10월 31일에는 모델 서버에 pyannote speaker-diarization-3.1 엔진이 들어왔습니다. 개발 서버에서 101초짜리 3인 회의를 넣자 3.0초 만에 화자 세 명을 나눴고, 배치 크기 1 기준 GPU 메모리는 1GB를 넘지 않았습니다. 처음 걱정한 것보다 가볍다는 점은 확인했지만, 가볍다고 해서 관리 체계 밖에 둘 이유는 없었습니다.

업로드는 당연히 될 줄 알았습니다

녹음 파일은 크기가 큽니다. 두 시간 회의면 수백 MB가 됩니다. 처음 구상은 파일을 한 번에 올리고 서버가 받아쓰기를 마칠 때까지 기다리는 구조였습니다.

요청이 거치는 경로를 따라가 보니 두 곳에서 문제가 드러났습니다. 하나는 API 게이트웨이가 요청 본문을 끝까지 받아 메모리에 올린 뒤 뒤쪽 서비스로 넘기는 구조라는 점이었습니다. 수백 MB짜리 요청 몇 건이 동시에 들어오면 게이트웨이의 메모리가 먼저 바닥납니다. 다른 하나는 일반 요청이 5분이면 끊긴다는 점이었습니다. 한 시간 녹음의 받아쓰기는 5분 안에 끝나지 않습니다.

그래서 업로드와 처리를 분리했습니다. 브라우저는 파일을 8MB 조각으로 잘라 두 개씩 올리고, 실패한 조각만 다시 보냅니다. 조각은 서버 디스크가 아니라 오브젝트 스토리지에 모읍니다. 백엔드가 여러 파드로 떠 있어서 조각마다 다른 파드에 도착할 수 있기 때문입니다. 마지막 조각이 올라가면 작업은 대기열에 들어가고, 화면은 3초마다 진행률만 조회합니다. 어느 파드가 작업을 맡을지는 데이터베이스의 조건부 UPDATE 한 줄로 정합니다. status가 아직 queued인 행만 running으로 바꾸고, 바뀐 행이 1개인 파드가 작업을 가져갑니다. 처리 중인 파드가 30초마다 남기는 생존 신호(heartbeat)가 5분 동안 끊기면 다른 파드가 작업을 다시 대기열로 돌립니다.

"파일 하나 올리는 기능"이 작업 상태 여섯 개와 재시도 규칙을 가진 작은 작업 시스템이 됐습니다. 처음 계획서에는 없던 내용인데, 계획서에서 가장 긴 절이 됐습니다.

한 번에 받을 수 있는데 나눠 받기로 했습니다

모델 서버의 받아쓰기 API는 화자분리 결과까지 붙여서 한 번에 돌려주는 형식도 지원합니다. 채팅에 녹음을 첨부하는 기능이 이미 이 형식을 쓰고 있었습니다. 이 형식을 쓰면 호출 한 번으로 끝나니 처음에는 그쪽으로 기울었습니다.

결국 호출을 두 단계로 나눴습니다. 먼저 전체 녹음을 화자분리에 한 번 보내 "몇 초부터 몇 초까지 누가 말했다"는 구간을 받고, 그 구간을 기준으로 잘라 받아쓰기를 여러 번 호출합니다. 이유는 세 가지였습니다.

첫째, 화자분리는 반드시 전체 파일로 한 번에 돌려야 합니다. 잘라서 돌리면 조각마다 화자 번호가 새로 매겨져 앞 조각의 화자1과 뒤 조각의 화자1이 같은 사람이라는 보장이 없습니다. 둘째, 받아쓰기는 잘라서 호출해야 합니다. 저희가 쓰는 Qwen3-ASR 모델은 한 번 호출에 다룰 수 있는 길이에 한계가 있고, 서버 쪽 자동 분할에만 맡겼을 때 긴 녹음에서 같은 문장이 반복되는 현상이 있었습니다. 그래서 한 화자의 구간이 1분을 넘으면 그 안의 조용한 지점에서 다시 나누고, 화자분리를 끈 경우에는 5분마다 자르되 경계 앞뒤 5초 안에서 가장 조용한 지점을 찾아 말이 중간에 잘리지 않게 합니다. 셋째, 나눠서 호출하면 단위마다 진행률을 올리고, 실패한 단위만 다시 시도하고, 중간에 취소할 수 있습니다. 두 시간짜리 녹음을 한 요청에 담으면 이 셋을 모두 포기해야 하고, 요청 시간 제한에 걸릴 위험도 그대로 남습니다.

한 번에 받는 형식은 버리지 않고 결과를 비교하는 기준으로 남겨 두었습니다. 화자 구간별로 받아쓴 결과가 더 나쁘다면 이 판단은 다시 바뀔 수 있습니다.

화자1을 홍길동으로 바꾸는 일은 이름표만 바꾸면 됐습니다

화자분리 모델은 사람 이름을 알지 못합니다. 결과는 SPEAKER_00, SPEAKER_01 같은 라벨로 나오고, 화면에는 처음 말한 순서대로 화자1, 화자2로 보여 줍니다. 사용자가 "화자1은 홍길동"이라고 지정하면 그 이름으로 바뀌어야 합니다.

처음에는 이름을 바꾸면 결과 파일을 다시 쓰는 방식을 떠올렸습니다. 대신 결과 파일은 손대지 않고, 라벨과 이름의 대응표만 데이터베이스에 따로 저장하기로 했습니다. 결과를 보여 주거나 txt로 내려받을 때만 대응표를 적용합니다. 받아쓰기를 다시 돌리지 않아도 되고, 이름을 잘못 붙였을 때 원래 라벨로 언제든 되돌릴 수 있습니다. 누가 누구인지 판단하기 쉽도록 화자마다 앞쪽 발언 세 개를 함께 보여 줍니다. 두 화자에게 같은 이름을 붙이면 한 사람으로 합쳐서 보여 줍니다. 화자분리 모델이 한 사람을 두 화자로 나누는 경우에 대비한 것입니다.

아직 정하지 못한 것들

설계 단계의 글이라 남은 과제가 많습니다. 두 시간 녹음을 화자분리에 한 번에 보냈을 때 모델 서버 쪽 요청 시간 제한 안에 끝나는지는 아직 확인하지 못했습니다. 끝나지 않는다면 처리할 수 있는 녹음 길이 상한을 낮춰야 합니다. 화자분리 모델의 하위 모델들이 인터넷 없이 로컬 경로만으로 로드되는지도 폐쇄망에서 직접 로드해 봐야 압니다. 개발 서버에는 외부망이 열려 있어 이 문제가 드러나지 않았을 수 있습니다. 회의실 녹음의 품질에 따라 정확도가 얼마나 달라지는지도 아직 측정하지 못했습니다. 그래서 결과 화면과 내려받는 파일 머리에 "자동 변환 — 검토 필요"를 붙이기로 했습니다.

녹음 원본은 처리가 끝나면 바로 지우고 결과만 남깁니다. 회의 내용은 민감한 정보일 수 있어서 받아쓴 본문은 로그에 남기지 않고, 결과는 암호화해 저장하며 올린 사람만 볼 수 있게 했습니다.

정리하면

처음 판단 바뀐 판단 계기
대화방 기능의 일부 녹음 파일을 올리는 독립 화면 요구사항 재확인, 기존 화면 조사
화자분리 모델은 별도 서비스로 다른 모델처럼 로컬 목록에서 로드하고 관리자가 GPU 지정 GPU 관리 방식, 폐쇄망 반입 절차
파일을 한 번에 올리고 응답을 기다림 8MB 조각 업로드 + 대기열 작업 + 진행률 조회 게이트웨이 메모리 적재 구조, 5분 요청 제한, 여러 파드
화자분리와 받아쓰기를 한 번에 받음 화자분리 1회 → 구간별 받아쓰기 화자 번호 일관성, 호출당 길이 한계, 진행률·재시도·취소

네 번 모두 판단을 바꾼 것은 새로운 아이디어가 아니라 이미 있는 구조를 확인한 일이었습니다. 요청이 거치는 게이트웨이, GPU를 나눠 주는 방식, 백엔드 파드 수처럼 기능 설명에는 나오지 않는 것들입니다. 같은 기능을 검토하는 팀이라면 모델 정확도를 재기 전에 녹음 파일 하나가 브라우저에서 모델까지 가는 길부터 따라가 보기를 권합니다. 저희가 다시 그린 부분은 대부분 그 길 위에 있었습니다.


편집자 해석 · 회의록 자동화를 도입하려는 팀을 위한 점검 항목

이 기고에서 판단을 바꾼 계기는 모두 기능 설명에는 드러나지 않는 구조였습니다. 고객 환경에 같은 기능을 넣으려 한다면, 모델을 비교하기 전에 다음 네 가지를 먼저 확인해 두는 편이 안전합니다.

  1. 요구 범위 — 대화 중에 음성을 다루는 기능인지, 회의가 끝난 뒤 녹음을 올려 일괄 처리하는 화면인지, 결과를 누가 어디서 확인하는지
  2. 인프라 경로 — 게이트웨이가 요청 본문을 어떻게 받는지, 요청 시간 제한은 얼마인지, 백엔드가 여러 인스턴스일 때 업로드 조각과 작업 상태를 어디에 두는지
  3. 모델 운영 — 화자분리·STT 모델을 기존 모델 관리 화면에서 같은 방식으로 반입·로드하고 GPU를 지정할 수 있는지, 폐쇄망에서 외부 접속 없이 로드되는지
  4. 결과 신뢰와 보안 — 자동 변환 결과에 검토 필요 표시를 하는지, 화자 이름 지정을 되돌릴 수 있는지, 원본 삭제·결과 암호화·열람 권한·로그 미기록 원칙이 정해져 있는지

PoC 수용 기준도 조용한 환경의 짧은 샘플보다 실제 회의실 녹음으로 잡는 것이 현실적입니다. 길이·참석 인원·음질이 다른 녹음으로 화자 구분 오류, 전체 처리 시간, 실패한 단위의 재시도와 취소 동작을 함께 측정하고, 결과 품질은 "사람이 회의록을 정리하는 시간이 얼마나 줄었는가"로 보는 편이 도입 판단에 더 가깝습니다. 자동 변환 결과는 사람이 검토하는 것을 전제로 하며, 정확도 수치는 고객 녹음으로 실측하기 전까지 약속할 수 있는 값이 아닙니다.

회의록 자동화의 가치는 모델이 얼마나 잘 받아쓰는가만으로 정해지지 않습니다. 고객의 인프라와 보안 정책 안에서 긴 녹음을 끝까지 처리하고, 사람이 결과를 검토하고 고칠 수 있는가가 함께 정해져야 합니다. 이 글은 그 질문을 코드보다 먼저 확인한 기록으로 읽을 수 있습니다.

#STT#화자분리#음성 인식#회의록#폐쇄망#XGEN
블로그 목록으로