03
제품 — 무엇을 만드는가
이 문서에서
정의 v0.2
먼저 우리 셋이 매일 쓰는 기기를 만들고, 검증되면 소량으로 판다. 책상과 거실을 하나의 기기로 잡되, 1세대는 책상에서 시작한다. 팀의 하드웨어 경험은 취미 수준이므로, 하드웨어에서 가장 어려운 문제는 사고 우리는 프로토콜과 HAX에 힘을 쓴다.
이것이다.
- 에이전트용 I/O 주변장치. 마이크 어레이 + 스피커 + LED 링 + 물리 뮤트.
- 프로토콜이 열린 소켓. 어떤 에이전트든 어댑터 하나로 붙는다.
- 맥락을 나르는 통로. 기억은 사용자의 에이전트에 있고, 기기는 세션·맥락 핸들만 넘긴다.
- 인터넷을 모르는 기기. 사용자의 브리지하고만 말한다. 계정도, 클라우드도, 서비스 종료도 없다.
- 책상 30 cm부터 거실 3 m까지, 음악 재생 중에도 말이 통하는 far-field.
- 타이밍(700 ms 이전 반응)과 회복(구체적 되묻기)을 기기 차원에서 책임진다.
- 누가 말했는지 안다. 방향은 기기가, 정체는 브리지가.
이것이 아니다.
- 또 하나의 브랜드 어시스턴트. 기기에 성격을 심지 않는다.
- 기억을 소유하는 사일로.
- Matter 허브. IoT는 Home Assistant에 위임하고 MCP로 제어한다.
- 배터리 기기. 1세대는 USB-C 유선.
- 스마트폰 대체. 시각이 필요한 출력은 근처 화면으로 넘긴다.
두 장면
책상, 회의 직후. "방금 회의 정리해서 노션에 넣고, 액션 아이템은 각자한테 슬랙으로 보내줘." 기기는 300 ms 안에 짧은 확인음과 LED 변화로 "들었다"를 알리고, 회의 녹취의 맥락 핸들과 함께 요청을 업무 에이전트 — OpenClaw든 Claude Code든 — 에 넘긴다. 작업이 2분 걸리면 기기는 "작업 중" 상태를 주변 채널(LED)로만 조용히 보이다가, 끝나면 한 호흡으로 보고한다. 결과 문서는 화면에서 본다. 기기는 USB-C로 맥에 꽂혀 있고, 무선 칩이 없다.
거실, 귀가 직후. "불 켜고, 내일 첫 일정만 알려줘." 조명은 Home Assistant가 로컬에서 즉시 켠다. 클라우드가 죽어도 된다. 일정은 캘린더 에이전트가 답한다. 두 에이전트가 관여했지만 사용자는 누가 답했는지를 LED 색 하나로 안다. 잘못 라우팅됐으면 "아니, 회사 캘린더" 한마디로 고친다. 아이가 같은 기기에 말을 걸면 반말로 답하고 결제는 막는다. 기기는 집 안 네트워크에서 브리지만 찾고, 밖으로 나가는 주소를 모른다.
핵심 루프
웨이크 (기기, 로컬)
→ 턴 감지 (브리지, semantic VAD)
→ 라우팅 (어느 에이전트가 답하나 — 화자·맥락·웨이크워드)
→ 스트리밍
→ 한 호흡 응답
│
└ 긴 작업이면 위임 → 세션 닫음 → LED로 진행 표시 → 말 걸어도 되는 순간에 보고
아키텍처 — 얇은 기기, 두꺼운 브리지
┌──────────────────────────┐ 디바이스 프로토콜 ┌──────────────────────────┐ ┌────────────────────────┐
│ 기기 (얇게) │ ◀──────────────────▶ │ 브리지 (두껍게) │ ─────▶ │ 업무 에이전트 │
│ ESP32-S3 + XMOS XVF3800 │ 오디오 · 이벤트 · 상태 │ 홈서버 / PC · Python │ │ OpenClaw · Hermes · │
│ │ USB 또는 LAN 전용 │ │ │ Claude Code │
│ · 마이크 4 · AEC · 빔포밍 │ │ · 턴 감지 (Smart Turn) │ ─────▶ │ 비서 에이전트 │
│ · DoA │ │ · STT · TTS (한국어) │ │ 캘린더 · 메일 · 자체 │
│ · 웨이크워드 · 로컬 VAD │ │ · 화자 태깅 │ ─────▶ │ Realtime 음성 모델 (선택) │
│ · 스피커 · LED 링 │ │ · 라우터 │ │ gpt-realtime · Gemini │
│ · 물리 뮤트 │ │ · 세션 · 맥락 핸들 │ └────────────────────────┘
│ │ │ · 긴 작업 추적 · 보고 │ ═════▶ ┌────────────────────────┐
│ 인터넷을 모른다 │ │ · 에이전트 어댑터 │ MCP │ Home Assistant → IoT │
└──────────────────────────┘ │ (OpenAI 호환 · MCP) │ │ Matter · SmartThings │
│ Pipecat / LiveKit 위에 │ └────────────────────────┘
└──────────────────────────┘
인터페이스는 세 개다. 기기↔브리지의 디바이스 프로토콜은 우리가 정의한다. 브리지↔에이전트의 어댑터는 기존 표준(OpenAI 호환 chat/Realtime, MCP, A2A)을 재사용한다. 브리지↔홈의 HA MCP(/api/mcp/assist)는 이미 존재한다. 직접 만들 것은 첫 번째뿐이고, 그것이 제품이다.
디바이스 프로토콜이 담아야 할 것
프로토콜은 전송과 분리한다. USB로 가든 LAN으로 가든 같은 규약이다.
- 오디오. 양방향 스트림(16 kHz PCM 또는 Opus). 재생 신호를 AEC 레퍼런스로 같은 클록에 동기.
- 이벤트.
wake,vad_start/end,mute,button,doa(화자 방향, 도 단위). - 상태. 대기·듣기·생각·말하기·음소거 + 응답 주체(어느 에이전트) + 백그라운드 작업 중. LED 어휘의 근거. 상태 어휘와 색은 에이전트가 아니라 기기가 소유한다.
- 위임과 보고. 긴 작업을 넘기고 세션을 닫았다가, 완료 알림을 말 걸어도 되는 순간에 받는 비동기 경로. HA의 60초 타임아웃이 못 하는 것.
- 맥락 핸들. 방금 오간 대화, 회의 녹취, 현재 방, 지금 화자 같은 맥락을 기기가 저장하지 않고 참조로 에이전트에 넘기는 방식.
- 전송. (a) USB-C: USB Audio Class로 마이크·스피커, HID 또는 벌크 채널로 이벤트·상태. (b) LAN 전용: WebSocket, 사설망 주소만, 브리지는 mDNS로 발견, OTA도 브리지를 통해서만. 펌웨어에 클라우드 종단점이 없다는 것을 코드로 공개한다.
기존 생태계와 단절되지 않도록, 브리지 쪽에 ESPHome 네이티브 API와 xiaozhi WebSocket 어댑터를 처음부터 둔다. 남의 기기도 우리 브리지에 붙고, 우리 기기도 남의 브리지에 붙을 수 있어야 "소켓"이라는 말이 성립한다.
공간과 화자 — 마이크 여러 개와 푸리에 변환
친구와의 논의에서 두 아이디어가 나왔다. 여러 사람이 말할 때 푸리에 변환으로 발화자를 분리·태깅할 수 있겠다는 것, 그리고 마이크 3개면 발화자 위치와 잡음 제거를 더 잘할 수 있겠다는 것. 둘 다 방향이 맞고 업계가 가는 길과 일치한다. 경계를 정리해 둔다.
푸리에 변환은 답이 아니라 판이다. 사람마다 기본 주파수와 배음, 포먼트가 달라 스펙트럼에서 "다른 사람"이 보인다. 현대 음성 처리의 거의 모든 단계가 STFT로 시간-주파수 평면에 올린 뒤 작동한다. 그러나 두 사람이 동시에 말하면 스펙트럼이 같은 대역에서 겹치고, 음역이 비슷하면 어느 성분이 누구 것인지 스펙트럼만으로는 정할 수 없다. 실제 시스템은 그 위에 둘 중 하나를 얹는다. 공간 정보 — 마이크가 여러 개면 각 주파수 성분이 어느 방향에서 왔는지(마이크 간 위상차)를 알아 방향별로 나눌 수 있다 — 또는 학습된 화자 모델 — 짧은 발화에서 목소리 지문(speaker embedding)을 뽑아 등록된 사람 중 누구인지 맞춘다. 전자를 source separation / beamforming, 후자를 speaker diarization(누가 언제) / verification(그 사람이 맞나)이라 부르고, 좋은 시스템은 둘을 섞는다.
마이크는 3개가 최소, 4개가 정석이다. 마이크 2개는 도착 시간 차이가 하나뿐이라 좌우 각도만 나오고 앞뒤를 구분 못 한다. 평면에서 방향을 확정하려면 일직선상에 있지 않은 3개가 최소이고, Echo Dot 5세대가 실제로 3개를 삼각형으로 쓴다. 4개를 정사각형으로 놓으면 360° 모든 방향에서 성능이 대칭이 되고 하나가 스피커 진동에 오염돼도 여유가 생겨서, XMOS XVF3800이 66 mm 정사각 4개를 기준으로 잡았다. 3과 4의 차이는 원리가 아니라 대칭성과 여유다.
위치 파악은 잡음 제거의 전제다. 마이크 N개를 단순히 더하는 방식은 무작위 잡음에 대해 10·log₁₀(N) dB만 좋아진다. 3개면 4.8 dB, 4개면 6 dB. 진짜 이득은 방향을 알고 난 뒤, 화자 방향은 살리고 TV나 식기세척기 방향에 널(null)을 놓는 적응형 빔포밍(MVDR, GSC 계열)에서 나오며, 특정 방향 잡음을 15~20 dB씩 깎는다. 두 아이디어가 한 문장에 묶인 것은 우연이 아니다.
제약 둘. 마이크 간격이 파장의 절반보다 넓어지는 주파수부터 방향이 여러 개로 보이는 공간 앨리어싱이 생긴다. 66 mm면 약 2.6 kHz 위부터인데, 음성의 방향 정보는 대부분 그 아래에서 뽑는다. 그리고 빔포밍은 마이크들의 감도와 위상이 서로 맞아야 널이 파이므로, 어레이용으로 매칭된 부품(Infineon IM69D130: 감도 ±1 dB, 위상 ±2° 보증)을 써야 한다. 취미용 I2S 마이크 셋을 사다 붙이면 방향은 대충 나와도 널은 안 파인다.
이 기기에서의 배치. 기기(XVF3800)가 방향별로 소리를 나누고 "지금 2시 방향에서 누가 말한다"까지 알려준다. 이건 이미 칩이 해주는 일이라 만들지 않는다. 브리지가 그 발화의 화자 임베딩을 뽑아 "그건 아내다"로 태깅한다. 이건 우리가 만든다. 태깅이 되면 가족 구성원별 존대·권한·연결 에이전트가 한 번에 풀린다. 이 아이디어는 음향 기능이 아니라 HAX 기능으로 볼 때 가치가 가장 크다.
프라이버시의 물성
화자 인식은 프라이버시 민감도가 확 올라가는 기능이다. 목소리 등록은 생체정보이고 개인정보보호법상 민감정보다. 우리 구조에서는 임베딩이 기기에도 클라우드에도 없고 사용자의 브리지에만 있다. "가족의 목소리는 집 밖으로 나가지 않는다"는 문장이 그냥 성립한다.
확인 가능한 것들로 프라이버시를 구성한다.
- 마이크 전원을 끊는 물리 스위치. 펌웨어가 아니라 전원선.
- 마이크 전원선에 직접 물린 LED. 펌웨어가 거짓말할 수 없다.
- 공개된 펌웨어. 클라우드 종단점이 없음을 코드로.
- USB 전용 버전에는 무선 칩이 없다. 패킷을 뜰 필요도 없다.
- 등록은 명시적으로, 인식 결과는 기기에 저장하지 않고 세션 핸들로만.
- 음성으로도 끌 수 있고, 꺼짐이 보이고, 꺼짐이 무엇을 뜻하는지 설명된다. 게스트 모드가 있다.