지난 편의 마지막에서, 전사가 전사대로 싸움을 준비하고 있다고 했는데, 그 싸움의 상대는 소리가 아니었다. 회의 녹음을 글로 바꾸는 brain-transcribe 라는 작업이, 죽어 있었다. 녹음기는 소리를 받는 법을 고쳤는데, 정작 그 소리를 받아야 할 다음 관문이 넘어져 있었다. 그달 중반의 기록에는, numpy 와 numba 의 충돌이라는 진단 한 줄이 남아 있다. 버전 두 개가 싸운 흔적을, 하나씩 보자.
전사가 하는 일은 단순한데, 16k 모노 wav 를 받아서 텍스트로 바꾸는 것 하나다. 그 일을 하는 도구는 mlx-whisper 인데, large-v3-turbo 라는 모델을 맥의 통합 메모리 위에서 도는 애플 실리콘 전용 음성 인식이다. 만들어진 텍스트는 회의록 폴더에 전사 문서로 떨어지고, 15분 주기의 정리 작업이 그 문서를 이어받아 한 줄 요약과 핵심, 안건, 결정, 실행 항목으로 나누어 구조화한 뒤, 정리본으로 같은 폴더에 다시 넣는다.
전사가 왜 맥에 살고 있었는지도 짚어야 하는데, 서버에는 큰 음성 모델을 올릴 자리가 없었다. GB10 은 vLLM 이 통합 메모리를 거의 다 점유하고 있었고, 그 vLLM 자체가 텍스트 전용이라 소리를 들을 수 없었다. 소리를 글로 바꾸는 일은 그래서 맥의 MLX 가 적소였고, 음성은 맥에서 텍스트는 서버에서, 역할이 저절로 나뉘어 있었다.
열 분마다 도는 작업
전사는 launchd 가 띄우는 작업이었는데, 로그인과 함께 떠서 열 분마다 잠깐씩 깨어난다. 새 wav 가 있으면 받고, 없으면 조용히 잠든다. 할 일이 없을 때 아무것도 하지 않는 일이라, 죽어 있어도 스스로 말하지 않는다. 녹음기는 파일명에 시각을 박아 두니, 전사는 파일을 보는 것만으로 언제 녹음인지 안다. 정리 작업도 같은 폴더를 보고, 전사가 남긴 문서를 찾아 이어받는다. 열한 개가 된 파이프라인 가운데, 열 분 주기로 도는 작업은 이 전사 하나였다.
전사가 불리는 길은 둘이었는데, 하나는 열 분마다 launchd 가 부르는 길이고, 다른 하나는 녹음기가 파일을 떨구는 순간 직접 부르는 길이었다. 어느 쪽이든, 전사가 쓰는 파이썬은 같은 것이어야 했다. 앞 단계가 죽으면 뒤 단계는 그저 기다리는, 계단을 내려가는 방식이었다. 계단의 한 칸이 빠지면, 아래 칸들은 영영 기다린다. 지난 편에서 알림 하나가 죽어 전사가 시작되지 않던 것도, 같은 모양의 고장이었다.
녹음(wav) → 전사(mlx-whisper) → 전사 문서 → 정리(서버 LLM) → 정리된 회의록

numpy 와 numba 가 싸웠다
그 계단이, 전사에서 끊겼다. 진단은 의존성 충돌이었는데, base 파이썬에 올라간 numpy 2.4 와 numba 가 서로 맞지 않았고, 그 사이에 끼어 있던 mlx-whisper 가 깨졌다. 기록에는 'numpy 2.4 ↔ numba 충돌로 mlx-whisper 깨짐'이라는 한 줄만 남아 있는데, 어느 함수에서 어떤 에러로 죽었는지는 적지 않아서, 문제가 부딪힌 정확한 지점은 그 한 줄 너머로 알 수 없다.
의존성 충돌은 둘이 싸우는 것처럼 보이지만, 실은 셋이 얽힌 싸움이다. 전사가 numba 를 끌어오고, numba 는 자기와 맞는 numpy 를 요구하는데, base 에는 그 요구와 다른 numpy 2.4 가 이미 앉아 있었다. numba 가 왜 그 자리에 있었는지조차 기록에는 없고, mlx-whisper 가 끌고 온 것이라고만 짐작할 뿐이다. numpy 는 버전마다 동작이 조금씩 달라지고, numba 처럼 기계어까지 내려가는 도구일수록 그 차이에 민감해서, 둘의 시차가 어느 날 갑자기 싸움이 됐다. 녹음기는 소리로 죽었는데, 전사는 소리와 무관한 버전 싸움으로 죽었다. 같은 계단에서, 전혀 다른 병이 두 번 났다.

바닥은 낮추지 않았다
가장 쉬운 해결책은 base 의 numpy 를 내려놓는 것이었다. 2.4 에서 2.1 쯤으로, numba 가 좋아하는 버전으로. 내려놓을까 싶을 만큼 유혹은 컸다. 그런데 base 는 전사만의 바닥이 아니었다. scipy 를 쓰는 다른 작업들도 같은 바닥 위에 얹혀 있었고, numpy 를 내리는 순간 그 작업들이 먼저 흔들릴 테니, 도구 하나 때문에 바닥을 낮추면 바닥 위의 모든 것이 그 대가를 치르는 구조였다.
그래서 전용 환경 brain-whisper 를 만들었는데, conda 는 파이썬부터 의존성까지 한 방에 관리하는 도구라 전사처럼 얽힌 것을 가둬두기 알맞았다. 환경 하나를 통째로 떼어 내고, mlx-whisper 0.4.3 과 numpy 2.1.3, numba 0.65.1 을 그 안에 함께 심었다. 서로 맞는 버전끼리만 산다. base 는 numpy 2.4 를 그대로 두었고, 버전 두 개가 싸우던 문제는 둘을 다른 방으로 나눠 보내는 것으로 끝났다. 환경을 나눠 쓰는 법, 그게 이번에 배운 가장 쓸모있는 교훈이었다.
brain-whisper (전용 방) base (그대로)
mlx-whisper 0.4.3 numpy 2.4
numpy 2.1.3
numba 0.65.1
이 규칙은, 실패를 한 번 겪은 뒤에야 세워졌다. 전사가 필요한 버전은 전사 방 안에서만 정하고, base 를 건드리는 일은 없다. 지금 보면 당연한 규칙인데, 그날은 그 당연함에 도달하는 데 시간이 걸렸다.

경로 하나
바꿔야 할 것은 딱 두 곳이었다. 전사 스크립트를 부르는 launchd 설정과, 녹음기의 전사 트리거. 둘 다 전용 환경의 파이썬을 가리키게 하면 되는, 단순한 교체였다. 문제의 크기에 비해 바꾼 것은 작았는데, 그 작은 경로 하나가 전사를 다시 파이프라인에 이어 붙였다.
고치고 나서 전체 체인을 다시 검증했다. 메뉴앱의 녹음에서 시작해, 전사와 정리를 거쳐 한 줄 요약과 핵심, 안건, 결정, 실행 항목이 갖춰진 회의록이 회의록 폴더에 떨어지는 것까지, 한 번의 흐름으로 확인됐다. 그 문서를 열어 본 순간, 비로소 전사가 살아났다는 걸 알았다. 계단이 다시 이어졌다.
이번 사건이 남긴 것은 하나다. 도구 하나 때문에 바닥을 낮추지 말 것. 바닥을 낮추면 그 위의 모든 것이 함께 내려앉고, 내려앉은 일들은 그때까지는 아무도 모른다. 격리 쪽이 번거로워 보였지만, 번거로움이 나중에 되갚는 편이었다. 환경 하나가 전사를 죽였고, 환경 하나가 전사를 살렸다. 그때의 선택이 맞았다고, 지금도 생각한다.
전사는 이걸로 끝이 아니었다. 나중에 이 워크로드는 맥의 MLX 를 떠나, gpugeant 의 L40 에 올린 Whisper large-v3 와 pyannote 화자분리 서버로 이관된다. gpugeant 는 L40 을 세 대 가진 x86 박스인데, 그중 한 장을 통째로 음성에 줄 수 있는 여유가 있었다. 회의록에 누가 말했는지가 붙는, 그 이야기는 GPU 들이 나오는 편에서.
'공부 > 인공지능' 카테고리의 다른 글
| 소리가 줄어드는 녹음. (0) | 2026.08.05 |
|---|---|
| 끊기지 않는 유입. (0) | 2026.08.03 |
| 위키가 영어로 쓰여 있었다 — 4,382개 중 482개 (1) | 2026.08.02 |
| 20k 문서를 실제로 읽어들이기 — 로더 지옥 (0) | 2026.08.02 |
| 개인 세컨드브레인을 RAG 없이 시작한 이유 (1) | 2026.08.02 |