GitHub 트렌딩 딥다이브 · 2026-06-24 · TrendShift Topics(RAG·온디바이스)

RCLI 딥다이브
— 클라우드도 API 키도 없이, 맥에서 100% 온디바이스로 도는 음성 AI 비서(STT→LLM→TTS + RAG)

RunanywhereAI/RCLI. macOS Apple Silicon에서 모든 추론(받아쓰기·LLM·음성합성·비전·임베딩)을 기기 안 Metal GPU로 실행하는 음성 AI CLI/TUI다. 마이크로 말하면 받아쓰고(STT) → 로컬 LLM이 답을 만들고 → 음성으로 읽어 주며(TTS), 동시에 내 문서를 근거로 답하는 로컬 RAG, 카메라·화면을 보는 VLM(비전), 그리고 "사파리 열어줘" 같은 40개 macOS 제어 액션까지 단일 C++17 바이너리에 담았다. 클라우드 전송·과금이 전혀 없고, 자체 GPU 엔진 'MetalRT'를 쓰되 구형 칩에선 오픈소스 llama.cpp로 자동 폴백한다. (저장소: RunanywhereAI/RCLI · C++17 약 28,500줄 · v0.3.7 · 라이선스 MIT · 스택 llama.cpp / sherpa-onnx / USearch / FTXUI · macOS 13+ Apple Silicon 전용 — TrendShift RAG 토픽, 스타 약 1,500)

목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석 (목소리가 답이 되어 돌아오기까지)
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 · 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

"맥에게 말을 걸면, 인터넷 없이 기기 안에서 듣고·생각하고·말하고·행동한다."

한 줄로

RCLI는 Siri의 편리함 + ChatGPT의 똑똑함을, 클라우드 0·API 키 0으로 맥 안에서만 돌리는 음성 비서다 — 받아쓰기(STT)·로컬 LLM·음성합성(TTS)·문서 RAG·카메라/화면 비전·앱 제어를 하나의 바이너리로.

보통의 음성 비서는 당신 목소리를 회사 서버로 보내 처리합니다(프라이버시·과금·인터넷 의존). RCLI는 그 모든 계산을 당신의 맥 GPU 안에서 끝냅니다. 받아쓰기 모델, 답을 만드는 LLM, 목소리를 합성하는 TTS, 문서를 찾아 주는 검색까지 전부 기기 안에 들어 있어 비행기 모드에서도 작동합니다. "사진 속에 뭐가 있어?"라고 물으면 카메라를 보고(VLM), "사파리 열어줘"라고 하면 실제로 앱을 엽니다(40개 macOS 액션).

용어
온디바이스(on-device) / STT / TTS / VLM / RAG
온디바이스는 계산을 클라우드가 아닌 사용자 기기에서 하는 것입니다. STT(Speech-to-Text)는 음성을 글자로(받아쓰기), TTS(Text-to-Speech)는 글자를 음성으로(읽어주기) 바꿉니다. VLM(Vision-Language Model)은 이미지+텍스트를 함께 이해하는 모델(카메라·화면 분석), RAG는 내 문서에서 근거를 찾아 답하게 하는 기법입니다. RCLI는 이 다섯을 전부 로컬로 묶었습니다.

2왜 주목받는가

"완전 로컬 프라이버시 + 자체 GPU 엔진(빠르다 주장) + 크래시 복구 같은 '실배포 디테일'."

완전 로컬 · 프라이버시
목소리도 문서도 기기 밖으로 나가지 않는다

모든 추론(STT·LLM·TTS·VLM·임베딩)이 Apple Silicon의 Metal GPU에서 돌아 클라우드 전송·API 키·과금이 전혀 없습니다. 받아쓰기 앱(MacWhisper 등)은 받아쓰기만, 클라우드 비서(Siri·Alexa·ChatGPT 음성)는 서버 의존이지만, RCLI는 "듣고→생각하고→도구 실행하고→말하는" 전체 루프를 오프라인으로 완성합니다.

성능 주장

자체 엔진 'MetalRT' — 빠름을 노린 독점 백엔드

RunAnywhere가 Apple Silicon 전용으로 만든 GPU 추론 엔진 MetalRT를 씁니다. 자사 블로그 기준 LLM 디코드 최대 550 tok/s, STT 실시간 대비 714배, 종단 음성 지연 sub-200ms를 주장합니다. M3 이상에서만 동작하고, M1/M2에서는 오픈소스 llama.cpp로 자동 폴백합니다. (단, 이 수치는 자사 출처이고 MetalRT 자체는 소스가 비공개인 dylib입니다 — 7번·아래 함정 참고.)

실배포 디테일
크래시를 알고, 스스로 폴백한다

MetalRT dylib이 일부 M3/M4에서 segfault 나는 걸 개발진이 알고 있어, 초기화 전에 breadcrumb 파일(~/.rcli/.metalrt_init_in_progress)을 남기고 SIGSEGV/SIGBUS 핸들러를 설치합니다. 그래서 다음 실행 때 "아, 지난번 MetalRT가 죽었구나" 하고 자동으로 llama.cpp로 폴백해 사용자가 크래시 루프에 갇히지 않습니다. 이런 디테일이 "장난감"이 아니라 실제 배포 제품임을 보여 줍니다.

기대치 조정 — 솔직한 현실
'100% 오픈소스'는 아니고, 맥 전용이며, 최근 정체

핵심 성능을 책임지는 MetalRT 엔진은 이 저장소에 소스가 없는 독점 dylib입니다(오픈된 건 llama.cpp 폴백 경로뿐). 벤치마크 수치도 자사 블로그 출처라 독립 검증 자료는 없습니다. macOS Apple Silicon 전용이라 윈도우·리눅스·인텔 맥에선 못 돕니다. 또 초기 급성장 뒤 마지막 커밋이 약 3개월 전이라 유지보수 활발도는 둔화된 상태입니다. 다만 학습 교본으로서의 코드 가치는 매우 큽니다.

3기술 스택 전체 지도

"순수 C++17 + CMake. UI는 SwiftUI가 아니라 터미널(FTXUI). 추론은 llama.cpp/sherpa-onnx, 벡터는 USearch."

레이어실제 사용 기술
언어 / 빌드C++17(67×.h, 39×.cpp) + macOS 브리지 Objective-C++(.mm 3개)/Cocoa(.m 1개). CMake 3.15+, -O3 + LTO, arm64 -mcpu=native
UIFTXUI v5 — 순수 터미널 TUI(푸시투토크·HW 모니터·모델 관리). SwiftUI 아님
LLM 추론llama.cpp(vendored, GGUF, GGML_METAL=ON, Flash Attention, KV 캐시) ② MetalRT(독점 dylib, MLX safetensors 4bit)
STT(받아쓰기)sherpa-onnx — 스트리밍 Zipformer(transducer) + 오프라인 Whisper base.en / Parakeet TDT 0.6B
TTS(음성합성)sherpa-onnx offline — Kokoro 82M(28 voices) / Piper(VITS) / Kitten
VAD(음성구간 검출)Silero VAD(silero_vad.onnx)
VLM(비전)llama.cpp libmtmd(멀티모달) — Qwen3 VL 2B / LFM2 VL 1.6B / SmolVLM 500M
임베딩 / 벡터llama.cpp 임베딩(기본 384차원, Snowflake arctic) + USearch v2.16.5(헤더온리 HNSW)
키워드 검색자체 구현 BM25Index(bm25_index.cpp)
문서 파싱PDF → poppler pdftotext, DOCX → word/document.xml unzip 파싱
macOS 제어AppleScript + 셸. CoreAudio/AVFoundation/AppKit/Metal 등 14개 프레임워크 링크
배포Homebrew tap + install.sh 원커맨드 + GitHub Releases prebuilt
용어
GGUF / llama.cpp / sherpa-onnx
llama.cpp는 C/C++로 LLM을 CPU·GPU에서 돌리는 대표 오픈소스 런타임이고, GGUF는 그 양자화(압축) 모델 파일 포맷입니다. GGML_METAL을 켜면 애플 GPU로 연산을 오프로드합니다. sherpa-onnx는 k2-fsa 팀의 온디바이스 음성 툴킷으로, ONNX 런타임으로 받아쓰기(STT)·합성(TTS)·음성검출(VAD)을 제공합니다 — RCLI의 "귀와 입"입니다.

4아키텍처 심화 분석 (목소리가 답이 되어 돌아오기까지)

"심장은 Orchestrator. STT/LLM/TTS 3개 스레드가 락프리 링버퍼로 이어지고, 말 끊기(barge-in)는 atomic 플래그로."

핵심은 orchestrator.cppOrchestrator 클래스입니다. 3개 동시 스레드(STT·LLM·TTS)가 락프리 RingBuffer + 미리 잡아 둔 MemoryPool(64MB)로 연결되고, 사용자가 응답 도중 끼어드는 barge-in을 atomic 플래그로 즉시 처리합니다.

[마이크] ─CoreAudio─► capture RingBuffer<float> (16kHz, ~10s) │ ┌───────▼──────────┐ stt_thread │ Silero VAD │ 음성 구간 검출 │ → STT(Zipformer │ 부분/최종 transcript ─► TUI │ 스트리밍/Whisper)│ └───────┬───────────┘ partial/final text │ (mutex+condvar 핸드오프) ┌───────▼─────────────────────────────┐ llm_thread │ (옵션) RAG: 질의 임베딩(384d) │ │ USearch HNSW ∥ BM25 → RRF 융합 ~4ms │ │ → top-K 청크를 프롬프트에 주입 │ ├──────────────────────────────────────┤ │ LLM 1차 패스 (시스템프롬프트+도구를 │ │ KV-cache로 캐싱, 유저 부분만 디코드) │ │ ↓ 모델별 native tool-call 파싱 │ │ tool? → ToolEngine → ActionRegistry │ │ → AppleScript/셸 (40 액션) │ │ → 결과로 LLM 2차 패스(continuation) │ │ 문장 단위 분할(SentenceDetector) │ └───────┬──────────────────────────────┘ 문장 큐 (barge-in 시 취소 체크) ┌───────▼────────┐ tts_thread │ TTS 더블버퍼 │ 다음 문장 합성하며 현재 재생 │ (Kokoro/Piper) │ └───────┬────────┘ ▼ playback RingBuffer<float>(24kHz) ─CoreAudio─► [스피커] barge-in: 재생 중 STT가 음성 감지 → atomic 플래그 set → LLM·TTS 즉시 중단, interrupted_response_ 저장("이어서" 기능용)

핵심 설계 패턴

① 백엔드 추상화 + 핫스왑: LlmBackend::{LLAMACPP, METALRT}를 런타임에 교체(switch_backend()). 파이프라인이 IDLE일 때 모델을 갈아끼웁니다. MetalRT가 죽으면 시그널 핸들러 + breadcrumb로 llama.cpp 폴백.

② 시스템 프롬프트 KV 캐싱: 시스템 프롬프트+도구 정의를 한 번 프리필해 두고, 유저 입력 부분만 디코드(generate_with_cached_prompt())해 지연을 줄입니다.

③ from-scratch 하이브리드 RAG: 벡터(USearch HNSW)와 키워드(BM25)를 RRF(score += 1/(60+rank))로 융합. 청크 텍스트는 mmap zero-copy로 읽고, 쿼리당 힙 할당이 0이 되도록 버퍼를 사전할당하는 최적화까지 들어 있습니다.

④ ModelProfile 추상화: 모델 패밀리(lfm2·qwen3 등)별로 채팅 템플릿과 tool-call 포맷이 달라서, 이를 자동 감지·분기하는 프로파일 레이어를 둡니다. 2-패스 tool calling(호출→실행→결과 주입→재생성)의 핵심.

5디렉토리 구조 해부

"기능별로 깔끔히 나뉜 src/ — pipeline(심장)·engines(추론)·rag·actions·audio·cli."

경로역할 (LOC)
src/cli/(~7,100) 명령 디스패치 + TUI 앱/대시보드. 명령: listen·ask·rag·vlm·camera·screen·models·metalrt
src/engines/(~4,400) stt·llm·tts·vad·vlm·embedding + metalrt_{loader,engine,stt,tts} + model_profile
src/api/(~3,500) rcli_api.cpp — C ABI 인터페이스(rcli_create/init/...). 정적 라이브러리 librcli의 외부 창구
src/pipeline/(~3,000) orchestrator(심장) + sentence_detector + text_sanitizer + wake_word_detector
src/actions/(~2,100) 40개 macOS 액션: notes·reminders·messages·app_control·window·files·clipboard·media·web·browser + applescript_executor + action_registry
src/rag/(~1,800) hybrid_retriever + vector_index(USearch) + bm25_index + document_processor + index_builder + embedding_cache
src/models/(~1,450) LLM/STT/TTS/VLM 모델 카탈로그(URL·크기·우선순위)
src/audio/(~1,390) audio_io(CoreAudio) + camera_capture.mm + screen_capture.mm + mic_permission.mm + rcli_overlay.m
src/core/(~1,010) memory_pool · ring_buffer · hardware_profile · types · personality · log
src/tools/(~300) tool_engine + tool_defs
루트CMakeLists.txt·install.sh·Formula/rcli.rb(Homebrew)·scripts/{setup,download_models,setup_metalrt}.sh·CLAUDE.md
비유

이 폴더 구조는 한 사람의 "감각 기관"을 코드로 나눈 것 같습니다 — audio(귀·눈), engines(뇌의 언어 영역), rag(기억 도서관), actions(손), 그리고 이 모두를 지휘하는 pipeline/orchestrator(중추신경)입니다. "음성 비서를 만든다"는 막연한 목표가 어떤 부품으로 분해되는지 한눈에 보여 주는 좋은 지도입니다.

6학습 포인트 (기술별 — 배울 것 + 실습 아이디어)

"온디바이스 음성 풀스택·C++ LLM 추론·from-scratch RAG·tool calling·Apple 플랫폼 통합이 한 레포에."

① 온디바이스 음성 풀스택

배울 것: VAD→STT→LLM→TTS를 직접 엮는 법. 락프리 RingBuffer + 멀티스레드 핸드오프(mutex/condvar/atomic), 더블버퍼 TTS로 지연 숨기기, barge-in 인터럽트 설계. "실시간 음성 루프"가 왜 어려운지를 코드로 체득.

실습: 마이크 입력을 링버퍼에 쌓고, 별도 스레드에서 일정 구간씩 꺼내 처리하는 생산자-소비자 구조를 작은 프로그램으로 구현.

② C++로 LLM 추론 다루기

배울 것: llama.cpp C API 직접 호출, GGUF 로딩, n_gpu_layers/Flash Attention/KV-cache 튜닝, 토크나이즈/디토크나이즈, 시스템 프롬프트 KV 캐싱. "Ollama가 내부에서 뭘 하는가"를 한 겹 아래에서 보기.

실습: llama.cpp를 빌드해 작은 GGUF 모델을 로드하고, 같은 프롬프트를 n_gpu_layers 값만 바꿔 가며 토큰/초를 측정.

③ RAG 내부를 from-scratch로

배울 것: HNSW 벡터검색(USearch) + BM25 + RRF 융합을 라이브러리 조립이 아니라 직접. mmap zero-copy 청크 스토어, 쿼리당 무할당 최적화, 시맨틱 청킹(64~512 토큰, 오버랩 50). "RAG는 마법이 아니라 자료구조"임을 이해.

실습: 문서를 청크로 쪼개 임베딩→HNSW 색인하고, 같은 질의를 BM25 결과와 RRF로 합쳐 답 근거를 뽑아 보기.

④ LLM tool calling 엔지니어링

배울 것: 모델별 네이티브 tool-call 포맷 파싱, 2-패스(호출→실행→결과 주입→재생성), KV 캐시를 깨지 않으려 도구 힌트를 유저 턴에 주입하는 트릭. "에이전트가 실제로 손을 쓰는" 메커니즘.

실습: 작은 로컬 모델에 "도구 목록(JSON)"을 주고, 모델이 호출을 출력하면 파싱해 실제 함수를 실행한 뒤 결과를 다시 모델에 넣는 루프를 구현.

⑤ Apple 플랫폼 통합 + 프로덕션 견고성

배울 것: Objective-C++ 브리지로 마이크 권한·카메라·화면 캡처, AppleScript로 시스템 제어, 그리고 시그널 핸들러 기반 크래시 복구·breadcrumb 폴백·CMake LTO/dead_strip·Homebrew 패키징. "데모"와 "배포 제품"의 차이를 만드는 디테일.

실습: macOS에서 AppleScript 한 줄(tell application "Safari" to activate)을 C++ system()이나 NSAppleScript로 실행해 보기.

7하드웨어 · 시스템 요구사항

"macOS 13+ · Apple Silicon 필수. MetalRT는 M3+, 그 외엔 llama.cpp 폴백. 기본 모델 묶음 약 1GB."

항목요구사항 / 메모
OSmacOS 13+. 윈도우·리눅스·인텔 맥 불가
Apple Silicon 필수(arm64 아니면 설치 즉시 실패). MetalRT GPU 엔진은 M3 이상, M1/M2는 자동 llama.cpp 폴백
디스크/모델기본 rcli setup ~1GB(LFM2 1.2B 731MB + Whisper + Piper + Silero VAD + 임베딩). MetalRT ~0.9GB, 둘 다 ~1.9GB. VLM은 온디맨드
RAM명시 수치 없음. 1.2B Q4 모델 + KV 캐시(기본 ctx 4096) 기준 통합메모리 8GB면 동작 가능 추정(레포에 수치 미기재)
인터넷최초 모델 다운로드 시에만. 이후 추론은 완전 오프라인
운용 팁
"내 칩이 M1/M2면 MetalRT는 기대하지 말 것"

MetalRT의 화려한 속도 수치는 M3 이상 이야기입니다. M1/M2 사용자는 자동으로 llama.cpp 경로로 떨어지므로(여전히 잘 동작) "벤치마크만큼 빠르지 않다"고 실망하지 마세요. 먼저 rcli setup에서 엔진을 선택하고, rcli metalrt로 내 칩에서 실제 동작하는지 점검하는 게 안전합니다.

8직접 해볼 수 있는 실습 과제

"설치·대화 → 문서 RAG → 비전 → 액션 추가 → 미니 음성 루프 만들기."

과제 1난이도 ★☆☆☆☆ · 입문

설치하고 말 걸어 보기

brew tap RunanywhereAI/rcli ...brew install rclircli setup으로 모델을 받고, rcli TUI에서 스페이스(푸시투토크)로 질문. 답이 음성으로 돌아오고, rcli ask "open Safari"로 앱이 열리는지 확인.

목표: "오프라인 음성 비서"를 체감. 비행기 모드에서도 동작하는지 시험.

과제 2난이도 ★★☆☆☆ · 초급

내 문서로 RAG 질의

rcli rag ingest ~/Documents/notes로 폴더를 색인하고, rcli ask --rag ~/Library/RCLI/index "내 노트에서 X 알려줘"로 근거 기반 답을 받기. 같은 질문을 RAG 없이도 물어 차이를 비교.

목표: 로컬 RAG가 "근거 있는 답"을 어떻게 만드는지 체감. 색인 폴더 안을 열어 청크가 어떻게 저장됐는지 보기.

과제 3난이도 ★★★☆☆ · 중급

카메라·화면 비전(VLM) 써 보기

rcli vlm photo.jpg "이 사진에 뭐가 있어?" 또는 TUI에서 V(카메라)·S(화면)로 실시간 분석. VLM 모델이 온디맨드로 받아져 로컬에서 이미지+텍스트를 함께 추론하는 과정을 관찰.

목표: "멀티모달 추론이 로컬에서 된다"를 체감. 응답 지연이 텍스트 대비 어떤지 비교.

과제 4난이도 ★★★★☆ · 중상

41번째 macOS 액션 추가하기

src/actions/의 기존 액션(예: notes·reminders)을 본떠 새 액션(예: "스포티파이 다음 곡")을 만들고 action_registry에 등록. AppleScript 한 줄과 도구 정의(JSON 스키마)를 연결해 음성으로 호출되게.

목표: tool calling + 액션 레지스트리 구조를 손으로 이해. 실제 오픈소스 기여 후보.

과제 5난이도 ★★★★★ · 고급

'미니 음성 루프' 처음부터 만들기

sherpa-onnx(STT/TTS/VAD) + llama.cpp(LLM)를 직접 묶어, 마이크→받아쓰기→LLM→음성합성의 작은 루프를 C++로 조립. 링버퍼 핸드오프와 barge-in(말 끊기) 취소 플래그까지 넣으면 RCLI 뼈대가 거의 완성됩니다.

목표: "듣고→생각하고→말하는" 실시간 파이프라인을 내 것으로. 지연을 줄이는 더블버퍼링을 실험.

9관련 기술 심화 학습 로드맵 (5주 플랜)

"C++ 오디오에서 출발해 STT/TTS·로컬 LLM·RAG·tool calling까지, RCLI를 길잡이 삼아."

주차주제핵심 학습 + RCLI 연결점
1주실시간 오디오 + 동시성CoreAudio 콜백, 락프리 링버퍼, 생산자-소비자, atomic → core/ring_buffer·audio/audio_io
2주STT/TTS/VAD (sherpa-onnx)Zipformer transducer, Silero VAD, Kokoro/Piper TTS, 더블버퍼 → engines/{stt,tts,vad}
3주로컬 LLM (llama.cpp)GGUF·Metal 오프로드·KV 캐시·토크나이저·시스템프롬프트 캐싱 → engines/llm·model_profile
4주온디바이스 RAGHNSW(USearch)·BM25·RRF·시맨틱 청킹·mmap → rag/{hybrid_retriever,vector_index,bm25_index}
5주tool calling + Apple 통합2-패스 호출, AppleScript 액션, 시그널 핸들러 복구, Homebrew → tools/·actions/·pipeline/orchestrator
비유

이 로드맵은 "음성 비서를 부품 단위로 분해해 다시 조립하는" 코스입니다. RCLI는 "온디바이스 AI"라는 추상적 유행어를 실제 C++ 코드(오디오·추론·검색·도구)로 풀어 보여 주는 드문 교재라, 시스템 프로그래밍과 AI 추론을 동시에 익히려는 사람에게 알맞습니다.

10핵심 키워드 사전

"이 문서와 저장소에서 반복되는 음성·추론·검색 용어를 한곳에."

용어의미
온디바이스(on-device)클라우드가 아닌 사용자 기기에서 추론을 수행. 프라이버시·오프라인·무과금
MetalRTRunAnywhere의 Apple Silicon 전용 독점 GPU 추론 엔진(소스 비공개 dylib). M3+에서 동작
llama.cpp / GGML / GGUF오픈소스 LLM 추론 백엔드 / 텐서 연산 라이브러리 / 양자화 모델 포맷
sherpa-onnxk2-fsa의 온디바이스 음성 툴킷. ONNX로 STT/TTS/VAD 제공
Zipformer (transducer)스트리밍 STT 모델. encoder+decoder+joiner 3-ONNX의 RNN-T 구조
Silero VADVoice Activity Detection. 무음/잡음 구간을 걸러 STT를 효율화
Kokoro / Piper(VITS)신경망 TTS 모델. Kokoro 82M은 28개 음색, 더블버퍼 합성
VLM / libmtmdVision-Language Model / llama.cpp 멀티모달 모듈. 이미지+텍스트 추론
RAG(하이브리드)벡터(의미)+BM25(키워드) 검색을 합쳐 문서 근거 답변 생성
RRF (상호순위융합)두 랭킹을 1/(k+rank) 합으로 융합(k=60). 스케일이 다른 검색 결과 결합 표준
USearch (HNSW)헤더온리 근사 최근접이웃 벡터 인덱스. mmap 로드로 빠른 쿼리
BM25고전 키워드 랭킹 함수(TF-IDF 계열). 정확한 용어 매칭에 강함
barge-inTTS 응답 재생 중 사용자가 말을 끊으면 atomic 플래그로 즉시 중단하고 재청취
KV cache continuation시스템 프롬프트·도구 정의를 한 번 프리필해 재사용, 유저 입력만 디코드 → 지연 단축
tool calling(2-패스)모델이 도구 호출을 출력 → 실행 → 결과 주입 → 재생성. 에이전트가 "손을 쓰는" 메커니즘

11참고 링크