[세컨드브레인 개발기] 7. 전사가 깨진 이유.
지난 편의 마지막에서, 전사가 전사대로 싸움을 준비하고 있다고 했는데, 그 싸움의 상대는 소리가 아니었습니다. 회의 녹음을 글로 바꾸는 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들이 나오는 편에서.
'공부 > 인공지능' 카테고리의 다른 글
| [세컨드브레인 개발기] 9. 매주 월요일 아침, 논문이 온다. (0) | 2026.08.11 |
|---|---|
| [세컨드브레인 개발기] 8. 단체 메일은 조용히. (0) | 2026.08.06 |
| [세컨드브레인 개발기] 6. 소리가 줄어드는 녹음. (0) | 2026.08.05 |
| [세컨드브레인 개발기] 5. 끊기지 않는 유입. (0) | 2026.08.03 |
| [세컨드브레인 개발기] 4. 위키가 영어로 쓰여 있었다 — 4,382개 중 482개 (0) | 2026.08.02 |