본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 22. 06:33

실시간 데스크톱 AI 콜라보 파일럿 구축하기: 어려운 부분들

요약

실시간 데스크톱 AI 어시스턴트 구축 과정에서 겪은 엔지니어링적 도전 과제를 다룹니다. macOS와 Windows의 시스템 오디오 캡처 방식 차이와 지연 시간(Latency) 최소화를 위한 STT 및 LLM 스트리밍 전략을 분석합니다.

핵심 포인트

  • macOS는 ScreenCaptureKit, Windows는 WASAPI loopback을 사용하여 시스템 오디오를 캡처함
  • 실시간성을 위해 STT와 LLM 모두 스트리밍 방식 적용이 필수적임
  • 보안과 관리를 위해 모델 키와 프롬프트는 클라이언트가 아닌 서버에서 관리함
  • 지연 시간 단축을 위해 간결한 답변을 유도하는 시스템 프롬프트 설계가 중요함

반년 전, 저는 간단한 질문을 던졌습니다. 온라인 통화 중에 상대방이 아직 말하고 있는 동안, 화면에 짧고 핵심적인 힌트가 몇 초 만에 나타날 수 있을까? 나중에 작성하는 기록(transcript)이 아니라, 그 순간의 도움말 같은 것이요.

그 결과물은 데스크톱 어시스턴트(macOS + Windows)입니다. 아래는 무엇이 어려웠는지, 그리고 어떤 해결책이 작동했는지에 대한 솔직한 분석입니다. 마케팅 내용은 제외하고 순수 엔지니어링 관점만 다룹니다.

아키텍처를 한 문단으로 설명하자면:
장치(on the device)에는 오디오 캡처와 얇은 UI 오버레이 두 가지 요소만 존재합니다. 모든 '두뇌'(provider keys, prompts, model selection)는 서버에 있습니다. 클라이언트는 짧게 유지되는 세션별 토큰을 받아 오디오를 스트리밍하고, 서버는 전사된 내용(transcript)과 생성된 답변을 반환합니다. 저는 이 분할 방식을 '보안 연극' 때문이 아니라, 그렇지 않으면 키와 프롬프트가 바이너리에 포함되어야 했고 — 둘 다 즉시 유출되기 때문에 선택했습니다.

어려운 부분 #1: 마이크가 아닌 시스템 오디오 캡처
마이크는 사용자 본인만 녹음합니다. 필요한 것은 상대방의 오디오, 즉 시스템 출력(system output)입니다. 그리고 여기서 플랫폼별 어려움이 시작됩니다:

macOS. 오랫동안 네이티브 '시스템 오디오 가져오기' API가 없었습니다. 고전적인 경로는 가상 오디오 장치(BlackHole/Soundflower 스타일)였거나, 최근 버전에서는 프로세스의 오디오를 전달할 수 있는 ScreenCaptureKit을 사용해야 했습니다. ScreenCaptureKit이 가장 좋은 옵션으로 판명되었습니다. 사용자에게 설치할 커널 확장(kernel extensions)이 필요 없었기 때문입니다.
Windows. WASAPI loopback 기능이 문제를 해결해 줍니다. 가상 케이블 없이 출력 장치로 가는 모든 것을 가져올 수 있습니다.

핵심은 다음과 같습니다: '시스템 오디오 캡처'는 하나의 기능이 아니라 두 OS를 위한 두 가지 다른 서브 시스템이며, 초기의 대부분 버그는 오디오 자체의 문제가 아니라 권한 및 장치 선택에 관한 것이었습니다.

어려운 부분 #2: 지연 시간 (Latency)이 전부다
6초 늦게 도착하는 힌트는 쓸모가 없습니다. 이미 대화는 다음 단계로 넘어갔기 때문입니다. 지연 시간 예산 (Latency budget)은 세 부분으로 나뉩니다:

  1. STT (음성 → 텍스트). 스트리밍 (Streaming) 방식만 가능합니다. "문구가 끝난 후 인식"하는 배치 (Batch) 방식은 즉시 1~2초를 추가합니다. 핵심 지표는 "벤치마크 상의 전체 정확도"가 아니라, 도메인 어휘가 포함된 대상 언어에서의 스트리밍 지연 시간과 품질이었습니다.
  2. LLM (텍스트 → 답변). 토큰 스트리밍 (Token streaming)은 필수입니다. 첫 번째 토큰이 거의 즉시 나타나야 하며, 그렇지 않으면 시스템이 멈춘 것처럼 느껴집니다. 또한 간결함을 위한 공격적인 시스템 프롬프트 (System prompt)가 필요합니다. 답변이 길어지면 소리 내어 읽는 것이 불가능하기 때문입니다.
  3. 네트워크 (Network). 서버 및 제공업체까지의 RTT (Round-Trip Time). 연결을 활성 상태 (Warm)로 유지하고 문구마다 소켓 (Socket)을 새로 열지 않는 것이 도움이 됩니다.
    주요 교훈: 전체 응답 시간이 아니라, 첫 번째 유용한 토큰까지의 시간 (Time-to-first-useful-token)을 최적화해야 합니다.

어려운 부분 #3: 마지막 문장이 아닌 대화 문맥 (Dialog context)
모델에 마지막 문장만 입력하면 답변을 놓치게 됩니다. 실제 질문은 종종 3~4회차의 대화에 걸쳐 퍼져 있습니다. 따라서 서버는 대화의 슬라이딩 윈도우 (Sliding window)를 유지하며, 일관성 있고 역할 태그 (Role-tagged)가 지정된 문맥을 프롬프트 (Prompt)에 전달합니다. 이와 별개로, 단축키로 트리거되는 스크린샷 분석을 도입했습니다. 화면에 있는 코드나 다이어그램은 음성만으로는 전달할 수 없는 정보를 모델에게 제공합니다.

어려운 부분 #4: 화면 캡처에서 제외되는 오버레이 (Overlay)
기술적으로 재미있는 부분입니다. 힌트 창은 사용자에게는 보여야 하지만, 화면 공유나 녹화에는 나타나지 않아야 합니다. macOS에서는 윈도우 레벨 (Window level)과 캡처 제외 플래그 (sharingType)로 이 문제를 해결하며, Windows에서는 윈도우 어피니티 (WDA_EXCLUDEFROMCAPTURE)를 사용합니다. 주의할 점은, 화상 회의 앱이 화면을 캡처하는 방식(Composited vs. Raw)에 따라 동작이 달라지기 때문에 "OS × 통화 플랫폼" 테스트 매트릭스 (Test matrix)가 필요했습니다.

어려운 부분 #5: 개인정보 보호와 신뢰
앱이 통화 내용을 듣기 시작하면, 즉각적인 질문은 "데이터는 어떻게 되는가?"입니다. 제가 내린 결정은 다음과 같습니다:

API 키와 프롬프트(prompts)는 서버에만 존재하며, 클라이언트에는 어떠한 비밀 정보도 남기지 않았습니다.
세션마다 유효 기간이 짧은 토큰을 사용하여 지속적인 토큰(persistent token) 대신 사용했습니다.
오디오 캡처(audio capture)와 화면 분석(screen analysis)은 사용자의 명시적인 동작이 있을 때만 수행하며, 백그라운드에서

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0