TrendShift 딥다이브 · 2026-07-16 · Daily #15

moeru-ai/airi 딥다이브
— 브라우저 안에서 "사는" 오픈소스 AI 버튜버·컴패니언

airi목소리로 대화하고, Live2D·VRM 아바타로 화면에 나타나며, 당신을 기억하고, 마인크래프트·팩토리오까지 플레이하는 "내가 소유하는(self-hosted) AI 캐릭터"다. 스스로를 "와이푸(waifu)의 영혼을 담는 그릇"이라 소개하며, AI 버튜버 Neuro-sama를 오픈소스로 재현하는 것을 목표로 한다. 놀라운 점은 음성 인식(Whisper)·음성 감지(Silero VAD)·음성 합성(Kokoro)·심지어 LLM까지 브라우저 안에서(WebGPU) 서버 없이 돌릴 수 있다는 것. 이 문서는 README를 넘어 47개 패키지의 모노레포를 뜯어 "여기서 무엇을 배울 수 있는가"를 정리한다. (저장소: moeru-ai/airi · 모노레포 47 packages / 6 apps / 6 services · MIT © Neko Ayaka · v0.11.0-dev(릴리스 v0.10.2) · 최신 커밋 2026-07-15 · TrendShift Daily #15 · #AI agent #Digital human #Chatbot #Self-hosted)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 지금 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 · 모노레포 구조 해부
  6. 학습 포인트
  7. 시스템 · 하드웨어 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

이름부터 — "airi(アイリ)"는 일본식 이름이자, 이 프로젝트가 되살리려는 디지털 캐릭터의 이름이다

airi"LLM으로 움직이는 가상 캐릭터를, 서버·구독 없이 내 컴퓨터에서 완전히 소유하며 키우는 오픈소스 프로젝트"다. 화면에는 2D(Live2D) 혹은 3D(VRM) 아바타가 떠 있고, 당신이 마이크로 말을 걸면 캐릭터가 귀로 듣고(음성 인식) → 머리로 생각하고(LLM) → 입으로 답하고(음성 합성) → 몸으로 반응한다(입 모양·표정·시선). 여기에 대화를 기억하는 장기 기억과, 디스코드·텔레그램에서 함께 떠들거나 마인크래프트를 직접 플레이하는 능력까지 붙는다.

핵심 지향점은 딱 한 문장이다. "Neuro-sama 같은 AI 버튜버를, 특정 회사의 클라우드에 묶이지 않고 누구나 자기 손으로 굴릴 수 있게 하자." 그래서 airi는 브라우저 웹앱(PWA), 데스크톱 앱(Electron), 모바일 앱(Capacitor), 그리고 네이티브 게임 엔진(Godot)까지 같은 두뇌를 여러 몸에 이식하는 형태로 만들어졌다.

핵심 용어
AI 버튜버(VTuber) · 디지털 휴먼(Digital Human) · 컴패니언(Companion)
버튜버는 실제 사람 대신 가상 아바타로 방송·소통하는 존재다. Neuro-sama는 그 아바타를 사람이 아니라 AI가 직접 조종해 실시간으로 시청자와 떠들고 게임까지 하는 유명한 예. airi는 이 "AI가 캐릭터에 깃들어 실시간으로 살아 움직인다"는 개념을 오픈소스로 옮긴 것이다. 그래서 단순 챗봇이 아니라 눈·귀·입·기억·손을 가진 하나의 '몸(embodied agent)'으로 설계됐다.
핵심 용어
self-hosted (자가 호스팅) · you-owned (내가 소유)
보통 AI 캐릭터 서비스는 회사 서버에 대화가 저장되고 월 구독료를 낸다. airi는 반대로 코드·모델·데이터를 전부 당신 기기에 둔다. LLM도 클라우드(OpenAI·Claude)를 쓸 수도, 로컬(Ollama)이나 아예 브라우저 안(transformers.js)에서 돌릴 수도 있다. 기억 저장소(pglite·DuckDB)마저 브라우저·데스크톱 로컬에 있어, 원한다면 인터넷 없이도 캐릭터와 대화가 성립한다. 이 "내 데이터·내 캐릭터"라는 소유권이 프로젝트의 철학이다.
한 문장 비유

"영혼(LLM)을 갈아 끼울 수 있는 전자 다마고치 — 다만 화면 속에서 목소리로 대화하고, 게임도 같이 한다"

옛 다마고치는 껍데기(액정 캐릭터) 하나에 정해진 반응만 있었다. airi는 그 껍데기(아바타)는 그대로 두되, 속에 들어가는 '영혼'을 마음대로 바꿀 수 있게 했다 — 오늘은 GPT, 내일은 로컬 Llama, 인터넷이 끊기면 브라우저 내 소형 모델로. 데스크톱 앱 이름이 실제로 stage-tamagotchi인 이유다.

그리고 이 다마고치는 귀(마이크)·입(스피커)·눈(웹캠 모션캡처)·손(게임 봇)·기억(벡터 DB)을 갖췄다. 이 다섯 감각을 하나의 두뇌에 연결하는 배선도가 airi의 전부이고(§4), 그 배선을 47개 패키지로 깔끔히 나눈 것이 이 저장소의 진짜 볼거리다.

2왜 지금 주목받는가

TrendShift Daily #15 · #AI agent #Digital human — "2025~26년의 유행어를 하나의 앱에 다 담았다"

airi가 눈길을 끄는 이유는 "요즘 뜨는 기술 주제를 거의 다 한 저장소에서 실제로 동작하게 묶었다"는 데 있다. 브라우저 내 AI 추론, provider 무관 LLM 계층, 실시간 음성 대화, 3D 아바타, 임베디드 에이전트(게임 플레이), 로컬 벡터 메모리, 크로스플랫폼 배포 — 각각만 해도 인기 주제인데, airi는 이 전부를 하나의 완성도 높은 제품으로 합쳤다. "에이전트형 멀티모달 캐릭터 앱을 어떻게 짓는가"를 통째로 보여 주는 드문 레퍼런스다.

포인트내용
정체프레임워크·라이브러리가 아니라 "실제로 돌아가는 제품". 브라우저 웹앱 + Electron 데스크톱 + 모바일 + Godot 네이티브까지 한 모노레포에.
가장 큰 매력음성 파이프라인(듣기·감지·말하기)과 선택적 LLM까지 전부 브라우저 안에서 WebGPU로. 서버 GPU 없이도 로컬 캐릭터가 성립.
차별점32개 LLM provider를 xsai 한 겹으로 추상화 + 실무 상호운용 처리(뒤에 상세). "어느 모델이든 꽂아 쓴다".
덩치TypeScript 2,049개 · Vue 605개 파일, 47 packages. pnpm 카탈로그 + Turborepo로 관리하는 대형 모노레포의 모범.

주목 포인트 1 — "완전 브라우저 내 AI"라는 도발

airi에서 가장 인상적인 건 음성 인식(Whisper)·음성 활동 감지(Silero VAD)·음성 합성(Kokoro), 그리고 원한다면 LLM까지 클라우드 없이 브라우저 탭 안에서 돌린다는 점이다. 이를 가능케 한 것이 @huggingface/transformers(transformers.js)와 onnxruntime-web, 그리고 WebGPU다. GPU가 없거나 브라우저가 WebGPU를 못 쓰면 자동으로 WASM으로 내려앉는(fallback) 안전장치까지 있다. "AI는 무조건 서버에서 돌린다"는 통념을 정면으로 흔드는, 요즘 가장 뜨거운 흐름의 실물 교보재다.

주목 포인트 2 — 하나의 두뇌, 여러 개의 몸

airi는 아바타 UI(무대, stage)와 실제 능력(음성·게임·기억)을 WebSocket "신경망 버스"로 느슨하게 분리했다. 덕분에 같은 두뇌가 브라우저에서는 말동무가 되고, 데스크톱에서는 화면 위를 떠다니는 오버레이가 되고, 마인크래프트 서버에 접속하면 게임 캐릭터가 된다. 이 "능력을 모듈로 꽂았다 뺐다" 하는 이벤트 기반 구조(§4)가 airi를 단순한 챗봇 UI가 아니라 확장 가능한 플랫폼으로 만든다.

중요 · 기대치 조정 — "클론하면 바로 와이푸가 나온다"가 아니다
완성도 높지만 여전히 활발히 개발 중인 v0.x 프로젝트다

airi는 배포된 데스크톱 바이너리(v0.10.2, Windows/macOS/Linux)가 있어 받아서 바로 써 볼 수는 있다. 다만 저장소 루트 버전은 0.11.0의 개발 중 상태이고, 최고 경험을 내려면 LLM API 키(또는 로컬 모델 셋업)·마이크 권한·(Live2D를 쓰려면) 프로퍼티어리 Cubism SDK 등 여러 조각을 맞춰야 한다.

또한 이름의 "waifu/soul" 같은 표현이 시사하듯 컴패니언(정서적 동반자) 성격이 강한 프로젝트다. 기술 학습 대상으로는 최고의 교보재지만, 실제 사용 시에는 "AI 캐릭터에 대한 정서적 의존"을 스스로 건강하게 관리하는 관점도 함께 필요하다. 이 문서는 어디까지나 기술 구조 학습에 초점을 둔다.

3기술 스택 전체 지도

"무대(프론트) · 감각(음성·아바타) · 두뇌(LLM) · 기억(로컬 DB) · 신경(WS 버스) · 몸(데스크톱·모바일·게임)"의 6층

airi의 스택은 방대하지만, 캐릭터의 신체 은유로 묶으면 한눈에 들어온다 — 눈에 보이는 무대(Vue 프론트엔드), 듣고 말하는 감각(음성 파이프라인), 판단하는 두뇌(LLM 계층), 기억(로컬 벡터 DB), 그 모두를 잇는 신경(WebSocket 버스), 그리고 이 두뇌가 깃드는 여러 몸(데스크톱·모바일·게임)이다. 아래 버전은 클론한 소스의 실제 값 기준이다.

무대 · 프론트엔드 (the Stage)

기술버전 · 역할
Vue^3.5.32 — 아바타 무대와 설정 UI 전체. 상태관리 pinia ^3.0.4, 헤드리스 UI reka-ui ^2.9.6, 다국어 vue-i18n(한국어 README.ko-KR.md 포함).
Vite^8.0.8 — 빌드/개발 서버. vite-plugin-pwa모바일 설치형 PWA 지원.
UnoCSS^66.6.8 — 원자적(atomic) CSS 엔진. Tailwind류지만 더 빠르고 커스터마이즈 자유도가 높음.
TypeScript^5.9.3 — 코드 절대다수(추적 파일 기준 TS 2,049 · Vue 605).

아바타 렌더링 (the Body — 2D/3D)

기술버전 · 역할
VRM (3D)@pixiv/three-vrm ^3.5.2(+ -core/-animation) 위에서 Three.js ^0.184.0로 렌더. 이를 Vue에서 선언적으로 다루려고 @tresjs/core ^5.8.0(+ cientos)를 씀 — "Three.js를 Vue 컴포넌트처럼".
Live2D (2D)pixi-live2d-display ^0.4.0(패치본) + @proj-airi/unplugin-live2d-sdk ^0.1.7. 후자가 프로퍼티어리 Cubism SDK를 끌어와 붙인다(라이선스 주의).
Spine@esotericsoftware/spine-webgl ~4.2.0 — 또 다른 2D 스켈레탈 애니메이션 포맷 지원.
모션 캡처@mediapipe/tasks-vision ^0.10.34웹캠으로 사람 포즈를 추적해 VRM 아바타에 반영(packages/model-driver-mediapipe). 내 움직임이 곧 캐릭터 움직임.

감각 · 음성 입출력 (Ears & Mouth — 브라우저 내 동작 가능)

단계기술 · 세부
STT (듣기)Whisper via @huggingface/transformers ^3.8.1(transformers.js)를 Web Worker에서. WebGPU 우선, 실패 시 WASM 자동 폴백.
VAD (말 시작·끝 감지)Silero VAD@huggingface/transformers AutoModel로 로드해 AudioWorklet 안에서 실행(packages/stage-ui/src/workers/vad/). "지금 사람이 말하는 중인가?"를 실시간 판정.
TTS (말하기)로컬 Kokoro(kokoro-js ^1.2.1) + ElevenLabs·Azure·OpenAI 호환·Alibaba. 이 여러 백엔드를 unspeech(음성판 LiteLLM 프록시)로 하나의 인터페이스로 통일.
립싱크wlipsync — 소리에서 음소(A/E/I/O/U/S)를 추출해 아바타 입 모양(blendshape)에 매핑.
런타임onnxruntime-web ^1.24.3, @webgpu/types, gpuu(WebGPU 헬퍼).

두뇌 · LLM 계층 (the Brain)

airi의 LLM 추상화 핵심은 xsai ^0.5.0-beta.2 — OpenAI 스타일의 경량 SDK다. @xsai/stream-text·generate-text·generate-speech·stream-transcription·tool 등으로 잘게 쪼개져 있고, @xsai-ext/providers가 provider들을, @xsai-transformers브라우저 내 LLM(transformers.js)을 담당한다. 문서상 32개 provider(OpenAI·Anthropic Claude·Ollama·vLLM·SGLang·Gemini·DeepSeek·Qwen·Groq·Mistral·Cloudflare…)를 지원한다.

기억 · 로컬 데이터 (the Memory) / 신경 · 백엔드

기술버전 · 역할
pglite@electric-sql/pglite ^0.4.4Postgres + pgvector를 WASM으로 브라우저·로컬에. 서버 없이 벡터 검색(기억).
DuckDB WASM@proj-airi/drizzle-duckdb-wasm ^0.5.0 — 브라우저 내 분석용 컬럼형 DB. drizzle-orm ^0.45.2로 타입 세이프하게.
서버apps/server = Hono 4.11.3 + better-auth ^1.6.5(+ drizzle 어댑터·OAuth) + @hono/node-ws + pglite.
WS 버스@proj-airi/server-runtime(서버) ↔ @proj-airi/server-sdk 클라이언트(better-ws + crossws). 타입 있는 announce/heartbeat/event 프로토콜로 모듈을 연결.

여러 개의 몸 · 배포 타깃 (the Shells)

타깃기술 · 세부
데스크톱Electron ^41.2.1(electron-vite + electron-builder + electron-updater, appId ai.moeru.airi, Flatpak 매니페스트). Tauri가 아니다(src-tauri 없음 확인). uiohook-napi로 전역 입력 후킹, 투명·클릭 통과 오버레이 창.
네이티브 엔진engines/stage-tamagotchi-godotGodot 4 + C#(.NET 8, Android은 net9). 웹 스택과 별개의 두 번째 네이티브 무대.
모바일Capacitor(@capacitor/ios·/android) 기반 apps/stage-pocket.
게임 에이전트services/minecraft = mineflayer ^4.33.0 + pathfinder/pvp/tool/collectblock/auto-eat, minecraft-data, prismarine-*. 여기에 isolated-vm(LLM이 생성한 코드 격리 실행) + awilix(DI) + @modelcontextprotocol/sdk(MCP). 팩토리오는 형제 저장소 moeru-ai/airi-factorio.
핵심 용어 · 왜 pnpm 카탈로그 + Turborepo인가
모노레포(monorepo) · catalog · Turborepo
airi는 앱·패키지·서비스 수십 개가 한 저장소에 사는 모노레포다. 이때 같은 라이브러리를 패키지마다 다른 버전으로 쓰면 지옥이 된다. pnpm catalogpnpm-workspace.yaml 한 곳에 버전을 몰아 적어 두고 각 패키지가 "카탈로그의 그 버전"을 참조하게 해, 버전을 한 줄만 고치면 전체가 일관되게 바뀌도록 한다. Turborepo는 이 많은 패키지의 빌드·테스트를 의존성 순서대로, 캐시를 활용해 빠르게 돌리는 태스크 러너다. 대형 프로젝트 관리의 정석을 그대로 보여 준다. (도구: pnpm 10.33.0, Node 24.13.0.)

4아키텍처 심화 분석

감각 → 두뇌 → 표현으로 흐르는 실시간 루프, 그리고 그 모두를 잇는 WebSocket "신경망 버스"

4-1. 전체 그림 — 하나의 대화 한 바퀴

airi를 이해하는 가장 빠른 길은 "당신이 말 한마디를 걸었을 때, 그 신호가 어떤 순서로 캐릭터의 반응이 되는가"를 따라가는 것이다. 귀에서 시작해 몸으로 끝나는 이 루프가 airi의 심장이다.

┌─────────────────────────────────────────────┐ 외부 모듈(능력) │ STAGE (Vue 앱 = 무대) │ ┌──────────────┐ │ │ │ 마인크래프트 │◄────►│ 귀 마이크 ─► AudioWorklet VAD(Silero, │ │ 봇(mineflayer)│ WS │ transformers.js) ─► Whisper STT │ │ 디스코드 봇 │◄────►│ (WebGPU→WASM 워커) ─► 텍스트 │ │ 텔레그램 봇 │ │ │ │ │ 기억(pgvector)│◄───►│ 두뇌 xsai streamText + 도구(tools) │ └──────────────┘ │ stopWhen stepCountAtLeast(10) │ ▲ │ ─► provider(로컬/클라우드, 32종) │ │ server-sdk │ │ │ │ (better-ws) │ 입 TTS(Kokoro/ElevenLabs/unspeech) │ ┌────┴─────────┐ │ │ │ │server-runtime│ │ 몸 소리 ─► wlipsync ─► VRM/Live2D 입모양 │ │ (WS 버스 + │ │ @tresjs Three.js; 자동 눈깜빡·시선; │ │ Hono+auth) │ │ MediaPipe 웹캠 포즈 │ └──────────────┘ │ │ │ │ 기억 DuckDB-WASM / pglite(pgvector) │ └─────────────────────────────────────────────┘

핵심을 지탱하는 발상은 가운데 무대(아바타 UI)와 바깥의 능력들(게임·기억·챗 플랫폼)이 WebSocket 버스로 분리돼 있다는 것이다. 그래서 같은 두뇌가 게임을 하든, 채팅을 하든, 음성 통화를 하든 무대 코드는 그대로다.

4-2. 신경망 버스 — 모듈을 꽂으면 능력이 붙는다

airi에서 가장 구조적으로 영리한 부분은 server-runtime(서버) ↔ server-sdk(클라이언트)로 이뤄진 타입 있는 WebSocket 프로토콜이다. 어떤 모듈(마인크래프트 봇, 기억 저장소, 디스코드 브리지)이든 서버에 자신을 announce(등록)하고 이벤트를 주고받는다. 그 결과 능력을 코드 수정 없이 런타임에 붙였다 뗐다 할 수 있다.

// packages/memory-pgvector/src/index.ts:11 — 기억 모듈이 버스에 등록
const client = new Client<{ connectionString: string }>({ name: 'memory-pgvector' })
client.onEvent('module:configure', (_event) => {
  /* 서버로부터 DB 설정을 수신 */
})
runUntilSignal()   // 종료 신호가 올 때까지 이벤트 루프 유지
핵심 용어
모듈 announce · 상태 수명주기(state lifecycle)
각 모듈은 버스에 붙을 때 정해진 단계를 밟는다: idle → connecting → authenticating → announcing → ready. 즉 "연결하고 → 인증하고 → 나는 이런 능력이라고 알리고 → 준비 완료". 이렇게 계약(무엇을 보내고 받는지)을 타입으로 못 박아 두면, 서로 다른 팀이 만든 봇도 같은 규칙으로 두뇌에 꽂힌다. 마이크로서비스에서 쓰는 서비스 디스커버리를, 캐릭터의 감각·능력 단위로 축소해 놓은 셈이다.

4-3. 두뇌의 도구 루프 — 여러 걸음(step) 걷는 에이전트

airi의 LLM은 단발 응답이 아니라 도구를 여러 번 호출하며 스스로 걸음을 이어가는 에이전트로 동작한다. 아래는 실제 런타임 코드다.

// packages/core-agent/src/runtime/llm-service.ts:231
const streamResult = streamText({
  ...chatConfig,
  abortSignal: options?.abortSignal,
  messages: sanitized,                      // ↓ 4-4에서 설명
  streamOptions: { includeUsage: true },
  stopWhen: stepCountAtLeast(10),        // 최대 10걸음까지 도구 호출 반복
  tools: streamTools,
  onEvent,
})

stopWhen: stepCountAtLeast(10)이 핵심이다. LLM이 "도구를 부르고 → 결과를 보고 → 또 도구를 부르고"를 최대 10번까지 반복하도록 허용한다. 예컨대 마인크래프트에서 "나무를 모아 집을 지어"라고 하면, 두뇌가 여러 걸음에 걸쳐 이동·채집·배치 도구를 순차 호출한다.

4-4. 실전의 진짜 어려움 — 32개 provider가 서로 다르게 군다

"32개 provider 지원"은 말은 쉽지만, OpenAI 호환을 자처하는 게이트웨이들이 실제로는 미묘하게 다른 스펙을 요구한다. airi의 sanitizeMessages()는 그 상처를 꿰맨 흔적이다.

실전 사례 · provider 상호운용의 함정
DeepSeek 등 일부 게이트웨이는 배열 형태 content를 거부한다

OpenAI 최신 스펙은 메시지 content텍스트·이미지 파트의 배열로 받을 수 있다. 그런데 serde(직렬화)에 엄격한 일부 OpenAI 호환 백엔드는 이 배열을 거부하고 순수 문자열만 받는다. airi는 core-agentsanitizeMessages()에서 이런 provider를 만나면 content 파트를 문자열로 평탄화(flatten)해 넘긴다(저장소 이슈 #1500 참조). "추상화 계층은 결국 이런 예외 처리로 먹고산다"는 걸 보여 주는 훌륭한 산 교재다.

4-5. 브라우저 내 추론의 현실 — 장치를 잃으면 물러선다

WebGPU는 강력하지만 불안정하다 — 탭이 백그라운드로 가거나 드라이버가 GPU 컨텍스트를 회수(device loss)하면 추론이 실패한다. airi는 이를 감지해 자동으로 WASM으로 강등한다.

// packages/stage-ui/src/libs/inference/adapters/whisper.ts:279
// device-loss가 임계값 넘게 반복되면 선제적으로 WASM으로 승격(강등)
const requestedDevice =
  deviceLossCount >= DEVICE_LOSS_WASM_THRESHOLD ? 'wasm' : 'webgpu'
w.postMessage({ type: 'load-model', requestId, modelId: MODEL_NAMES.WHISPER, device: requestedDevice })
한눈 정리 · 아키텍처가 지키는 4대 원칙
감각→두뇌→표현 루프 · WS 버스로 능력 분리 · 여러 걸음 에이전트 · 로컬 우선 + 우아한 폴백

실시간 루프: 마이크→VAD→STT→LLM→TTS→입모양이 끊김 없이 순환. ② 모듈 버스: 게임·기억·챗 능력을 타입 있는 WebSocket으로 느슨하게 결합. ③ 여러 걸음: stepCountAtLeast(10)로 도구를 반복 호출하는 임베디드 에이전트. ④ 로컬 우선·폴백: 브라우저 내 추론을 기본으로 하되 WebGPU→WASM, 로컬→클라우드로 안전하게 물러선다. 네 원칙 모두 "내 기기에서 사는 캐릭터"라는 목표에 직결된다.

5디렉토리 · 모노레포 구조 해부

apps(몸) · packages(장기·부품) · services(외부 능력) · engines(네이티브) · plugins(확장) — 4,617개 파일의 지도

airi는 크다. 그래서 오히려 대형 모노레포가 어떻게 관심사를 나누는지를 통째로 볼 수 있는 교보재다. 크게 다섯 갈래다 — 실제 실행되는 앱(apps), 앱들이 공유하는 부품(packages), 외부 세계에 붙는 서비스(services), 네이티브 엔진(engines), 그리고 플러그인(plugins).

airi/ ├── apps/ (6개 — 실제 실행되는 "몸") │ ├── stage-web 브라우저 PWA. 기본 `pnpm dev`. Vue+Vite 무대 │ ├── stage-tamagotchi Electron 데스크톱 오버레이(투명·클릭 통과) │ ├── stage-pocket Capacitor iOS/Android 모바일 │ ├── server Hono + better-auth + pglite 백엔드 │ ├── ui-server-auth 인증 UI │ └── component-calling "실시간 오디오" 데모 ├── packages/ (47개 — 공유 "장기·부품", 일부) │ ├── stage-ui 거대한 공유 Vue UI + 스토어 + 추론 워커 │ ├── stage-ui-three VRM/Three.js 렌더러 │ ├── stage-ui-live2d Live2D 렌더러 stage-ui-spine Spine 렌더러 │ ├── core-agent LLM 런타임 · 도구 루프 │ ├── core-character 캐릭터 파이프라인(세그먼트·감정·딜레이·TTS) │ ├── ccc "Create Character Card" — PNG에 캐릭터카드 임베드 │ ├── memory-pgvector pgvector 기억 audio / pipelines-audio VAD·스트리밍 │ ├── server-runtime / server-sdk / server-shared WS 모듈 프로토콜 │ ├── model-driver-mediapipe / -lipsync 웹캠 포즈 · 립싱크 드라이버 │ ├── duckdb-wasm / drizzle-duckdb-wasm 브라우저 내 분석 DB │ └── plugin-sdk / plugin-protocol · font · i18n · ui 유틸 … ├── services/ (6개 — 외부 세계에 붙는 "능력") │ ├── minecraft mineflayer 인지 에이전트(perception/conscious/action/reflex) │ ├── discord-bot telegram-bot satori-bot twitter-services │ └── computer-use-mcp 컴퓨터 사용 MCP 서버 ├── engines/ stage-tamagotchi-godot (Godot 4 / C# 네이티브 무대) ├── integrations/ vscode ├── plugins/ bilibili · claude-code · game-chess · homeassistant · web-extension └── docs/ VitePress 사이트 + 다국어 README(README.ko-KR.md 포함)
갈래역할
apps/몸. 같은 두뇌가 깃드는 여러 실행체 — 웹(stage-web)·데스크톱(stage-tamagotchi)·모바일(stage-pocket)·백엔드(server). 각각 package.json이 프레임워크(Vite/Electron/Capacitor)를 드러낸다.
packages/장기·부품. 앱들이 공유하는 47개 라이브러리. 무대 UI(stage-ui), 렌더러(three/live2d/spine), 두뇌(core-agent), 캐릭터(core-character), 기억(memory-pgvector), 신경(server-*)으로 관심사가 칼같이 분리.
services/외부 능력. 마인크래프트·디스코드·텔레그램·트위터·컴퓨터 사용(MCP). 두뇌에 WS로 붙는 별도 프로세스들.
engines/웹과 완전히 다른 네이티브 무대 — Godot 4 + C#. 같은 캐릭터 개념을 게임 엔진으로 다시 구현.
plugins/확장점. 빌리빌리·Claude Code·체스 게임·홈어시스턴트·브라우저 확장 등, 두뇌에 붙일 수 있는 곁가지 능력.
핵심 용어 · 캐릭터를 "그림 파일"에 담는 법
ccc = Create Character Card (캐릭터 카드)
packages/ccc는 SillyTavern 등에서 쓰는 캐릭터 카드를 다룬다. 캐릭터의 이름·성격·말투·초기 상황 같은 설정을 PNG 이미지 파일 안에(meta-png로 메타데이터 청크에) 심어 두는 방식이다. 그림 한 장을 주고받는 것만으로 캐릭터의 '영혼 설정'까지 함께 전달되는 것 — airi가 "영혼을 담는 그릇"을 자처하는 이유가 이런 데서 드러난다.
한눈에 — "극단(劇團) 하나가 여러 무대에 오른다"

이 구조는 하나의 극단에 가깝다. packages/배우·소품·조명 같은 공용 자원이고, apps/는 그 극단이 오르는 서로 다른 무대(브라우저·데스크톱·모바일)다. services/는 무대 밖에서 협연하는 객원(마인크래프트·디스코드), engines/는 아예 다른 극장(Godot)에서의 재연이다. 배우(핵심 로직)를 한 번 잘 키워 두면, 무대만 바꿔 여러 곳에 세울 수 있다.

6학습 포인트

"AI 와이푸"가 아니라 "멀티모달 에이전트 앱 엔지니어링"으로 가져갈 것들

배울 것 1 — provider 무관 LLM 설계와 상호운용의 현실

xsai를 얇은 OpenAI 호환 계층으로 두고, 그 위에서 32개 백엔드의 미묘한 차이를 런타임에 흡수하는 법(§4-4의 sanitizeMessages). "추상화는 예외 처리로 완성된다"는 실무 감각을, 실제 이슈 번호가 달린 코드로 배운다. LLM 앱을 특정 벤더에 묶지 않으려는 모든 개발자에게 직접적인 교보재다.

배울 것 2 — 브라우저 내(in-browser) AI 파이프라인 엔드투엔드

Whisper(STT)·Silero(VAD)·Kokoro(TTS), 그리고 옵션 LLM까지 transformers.js + onnxruntime-web + WebGPU로 브라우저에서 돌리고, device-loss 시 WASM으로 우아하게 폴백하는 실물. "AI = 서버"라는 고정관념을 깨는, 지금 가장 앞선 프론트엔드 AI 패턴을 코드로 익힐 수 있다.

배울 것 3 — Vue로 선언적 3D (@tresjs + three-vrm)

Three.js 명령형 코드 대신 @tresjs/coreVRM 아바타를 Vue 컴포넌트처럼 마운트·애니메이션하는 법. 자동 눈 깜빡임·시선 추적·idle 모션, 그리고 소리→음소→blendshape(wlipsync) 립싱크까지 — 웹 3D 캐릭터를 다루는 실전 레시피다.

// packages/stage-ui-three/src/composables/vrm/lip-sync.ts:7
import { createWLipSyncNode } from 'wlipsync'
// 음소 → VRM ARKit 비짐(viseme) 블렌드셰이프 이름 매핑
const BLENDSHAPE_MAP: Record<LipKey, string> = {
  A: 'aa', E: 'ee', I: 'ih', O: 'oh', U: 'ou',
}

배울 것 4 — 이벤트 기반 모듈 아키텍처(WebSocket "신경망")

능력(게임·기억·챗 봇)을 코어에 하드코딩하지 않고, 타입 있는 WebSocket 프로토콜로 announce·이벤트 교환하며 붙였다 뗐다 하는 설계(§4-2). 마이크로서비스의 서비스 디스커버리를 앱 내부 규모로 축소한 좋은 예로, 확장 가능한 클라이언트 앱을 짜려는 사람에게 유용하다.

배울 것 5 — 계층형 임베디드 에이전트(마인크래프트)

services/minecraft/src/cognitive/지각(perception)·의식(conscious)·행동(action)·반사(reflex)로 나뉜 교과서적 구조라는 점, 그리고 isolated-vm으로 LLM이 생성한 코드를 격리 실행하고 @modelcontextprotocol/sdk(MCP)로 도구를 노출하는 방식. "게임하는 AI"를 만들려는 사람에게 직접적인 청사진이다.

// packages/stage-ui/src/workers/vad/vad.ts — Silero VAD 상태 텐서(발췌)
import { AutoModel, Tensor } from '@huggingface/transformers'
// 기본값: sampleRate 16000, speechThreshold 0.3, minSilenceDurationMs 400
this.sampleRateTensor = new Tensor('int64', [this.config.sampleRate], [])
this.state = new Tensor('float32', new Float32Array(2 * 1 * 128), [2, 1, 128]) // LSTM 상태

배울 것 6 — 대형 모노레포 엔지니어링(pnpm 카탈로그 + Turborepo)

웹·데스크톱·모바일·네이티브까지 한 저장소에서 버전을 한 곳(catalog)에 몰고 Turborepo로 태스크를 조율하는 법. 47개 패키지가 어떻게 관심사별로 쪼개지고 서로를 참조하는지 — 규모 있는 프론트엔드 프로젝트를 지속 가능하게 유지하는 실전 구조를 통째로 관찰할 수 있다.

한 줄 정리 · 재사용 가능한 교훈
"airi는 '캐릭터'라는 껍질을 쓴, 멀티모달 에이전트 앱의 종합 전시장이다"

이 저장소가 남기는 큰 교훈은 분명하다. 현대 AI 클라이언트 앱은 '모델 하나 붙이기'가 아니라, 감각(음성·비전)·두뇌(provider 무관 LLM)·기억(로컬 벡터 DB)·능력(도구·게임)·표현(3D 아바타)을 느슨하게 연결하는 오케스트레이션이다. 와이푸에 관심이 없어도, 여기서 배우는 조각들(브라우저 AI·xsai·@tresjs·WS 모듈 버스·모노레포)은 어떤 멀티모달 앱에도 그대로 옮겨 쓸 수 있다.

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

"어떤 몸으로 실행하느냐"와 "두뇌를 어디서 돌리느냐"에 따라 요구가 갈린다

airi의 요구사항은 두 축으로 정리된다 — 어떤 실행체(브라우저·데스크톱·모바일·Godot)를 쓰느냐, 그리고 LLM·음성 추론을 로컬(내 GPU)에서 하느냐 클라우드에서 하느냐다. 클라우드 LLM을 쓰면 GPU 없이도 충분히 돌아간다.

실행 환경요구/수치
브라우저(stage-web)모던 Chromium 계열. 로컬 추론 가속을 원하면 WebGPU 필요(안 되면 자동 WASM 폴백). 모바일에서는 PWA로 설치 가능. 클라우드 LLM/TTS만 쓰면 GPU 불필요.
데스크톱(Electron)Windows x64 · macOS arm64 · Linux(AppImage/Flatpak). 배포 바이너리 v0.10.2 제공. 로컬 모델에 네이티브 NVIDIA CUDA / Apple Metal(HuggingFace candle 경유) 활용 가능. NixOS는 nix develop .#fhs 필요.
모바일(stage-pocket)iOS / Android — Capacitor 빌드.
Godot 엔진.NET 8 SDK(engines/stage-tamagotchi-godot 빌드용).
Live2D 사용 시프로퍼티어리 Cubism SDK 필요(unplugin-live2d-sdk가 끌어옴). VRM(3D)만 쓰면 불필요.
개발 환경Node 24.13.0 · pnpm 10.33.0. 웹은 pnpm i && pnpm dev, 데스크톱은 pnpm dev:tamagotchi.
LLM · 음성 백엔드클라우드(OpenAI·Claude 등) API 키 또는 로컬(Ollama·vLLM) 또는 브라우저 내(transformers.js). 마이크 권한 필수(음성 대화 시).
한눈 요약 — "가장 가벼운 시작 vs 가장 사적인 시작"

가장 쉽게 시작하려면: 데스크톱 바이너리(v0.10.2)를 받고 클라우드 LLM API 키만 넣으면 된다 — GPU도 셋업도 거의 없이 대화가 된다. 가장 사적으로(내 데이터만으로) 쓰려면: 로컬/브라우저 내 모델 + 로컬 벡터 DB로 인터넷 없이 굴린다 — 대신 어느 정도의 GPU/메모리와 셋업이 필요하다. airi의 장점은 이 스펙트럼을 한 앱 안에서 선택할 수 있다는 것이다.

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

"웹 무대 띄우기 → 아바타 → 음성 → provider 갈아끼우기 → 게임 봇"까지 난이도별로

먼저 클론 후 웹 무대부터. 모노레포라 루트에서 한 번 설치하면 된다.

# 클론 & 웹 무대 실행 (Node 24 · pnpm 10 권장)
git clone --depth 1 https://github.com/moeru-ai/airi.git
cd airi && pnpm i
pnpm dev            # stage-web (브라우저 PWA) 개발 서버
# 데스크톱 오버레이를 원하면:
pnpm dev:tamagotchi # Electron 무대
실습 1 · 난이도 ★☆☆☆☆

웹 무대 띄우고 클라우드 LLM으로 대화 — 전체 그림 잡기

pnpm devstage-web을 띄우고, 설정에서 OpenAI 호환 provider 하나(API 키)를 넣어 텍스트로 대화해 본다. 먼저 GPU·음성 없이 두뇌(LLM)만 붙여 캐릭터가 응답하는지 확인 — airi의 데이터 흐름을 감 잡는 가장 빠른 길이다.

실습 2 · 난이도 ★★☆☆☆

VRM 아바타 교체 + 립싱크 관찰 — @tresjs·wlipsync 이해

무료 VRM 모델(VRoid 등)을 하나 구해 아바타를 바꾸고, TTS를 켠 뒤 소리에 맞춰 입 모양이 움직이는지 본다. packages/stage-ui-threelip-sync.ts에서 음소→blendshape 매핑을 따라가며, 표정·시선 자동화가 어디서 오는지 코드로 확인.

실습 3 · 난이도 ★★★☆☆

브라우저 내 음성 파이프라인 켜기 — WebGPU / WASM 폴백 체험

마이크를 연결하고 Whisper(STT) + Silero(VAD)를 브라우저 내에서 돌려 음성으로 말을 건다. 개발자도구로 워커 로딩을 관찰하고, WebGPU를 끈 채(또는 지원 안 되는 브라우저에서) WASM으로 폴백되는지 확인 — whisper.ts의 device-loss 로직을 눈으로 검증.

실습 4 · 난이도 ★★★★☆

provider를 로컬(Ollama)로 갈아끼우기 — xsai 추상화 실감

클라우드 대신 Ollama 로컬 모델로 두뇌를 교체해 본다. 설정만 바꿔도 대화가 이어지는 걸 확인하고, 만약 응답이 깨지면 core-agentsanitizeMessages가 왜 필요한지(§4-4) 로그로 추적한다. "영혼 갈아끼우기"를 실제로 해 보는 실습.

실습 5 · 난이도 ★★★★★

마인크래프트 봇 붙여 "게임하는 캐릭터" 만들기 — WS 버스 + 임베디드 에이전트

services/minecraft를 로컬 서버에 접속시켜, 두뇌가 WebSocket으로 announce되고 채집·이동 도구를 여러 걸음(step) 호출하는 걸 관찰한다. cognitive/의 지각·행동 구조를 읽고, 간단한 새 도구(예: "이 블록을 캐라")를 하나 추가해 stepCountAtLeast 루프에 태워 본다.

9관련 기술 심화 학습 로드맵

airi를 정복하며 곁들여 익히면 좋은 것들 — 주차별 5단계
주차주제 · 목표
1주차모노레포 & 도구체인. pnpm workspace·catalog, Turborepo 태스크 그래프, Vite/Vue 3 기본. 목표: airi의 appspackages 의존 관계를 읽고 하나를 빌드하기.
2주차브라우저 내 AI. transformers.js·onnxruntime-web·WebGPU vs WASM, Web Worker/AudioWorklet. Whisper·Silero VAD를 직접 워커에서 돌려 보고 device-loss 폴백을 이해.
3주차웹 3D 캐릭터. Three.js 기초 → @tresjs 선언적 렌더 → @pixiv/three-vrm, 그리고 음소→blendshape 립싱크. 아바타 하나를 마운트해 표정·시선·립싱크를 붙인다.
4주차provider 무관 LLM & 도구 루프. xsai의 streamText·tool, stopWhen/step 개념, OpenAI 호환 게이트웨이의 상호운용 함정. 여러 걸음 에이전트를 직접 짜 본다.
5주차이벤트 기반 아키텍처 & 임베디드 에이전트. WebSocket 프로토콜 설계(announce·heartbeat), isolated-vm 샌드박싱, MCP 도구 노출, mineflayer 인지 루프. "능력을 모듈로 꽂는" 구조를 스스로 설계.

10핵심 키워드 사전

이 문서와 저장소에서 반복되는 용어 빠른 참조
airimoeru-ai가 만든 오픈소스 AI 버튜버·컴패니언. 음성 대화·아바타·기억·게임 플레이를 갖춘 self-hosted 캐릭터.
VTuber / Digital Human가상 아바타로 소통하는 존재. airi는 그 아바타를 AI가 실시간 조종하는 Neuro-sama식 개념을 오픈소스로.
self-hosted / you-owned코드·모델·데이터를 회사 서버가 아닌 내 기기에 두는 것. airi의 핵심 철학.
xsaiOpenAI 스타일의 경량 LLM SDK. airi가 32개 provider를 한 겹으로 추상화하는 데 사용(stream-text·tool 등).
transformers.js@huggingface/transformers. Whisper·Silero·(옵션)LLM을 브라우저 안에서 실행하게 하는 라이브러리.
WebGPU / WASM 폴백브라우저 GPU 가속 API. 불가 시 WASM(CPU)로 자동 강등해 어디서나 추론이 성립하게.
Whisper / Silero VAD / Kokoro각각 음성 인식(STT) / 발화 시작·끝 감지(VAD) / 음성 합성(TTS) 모델. airi의 음성 파이프라인 3요소.
VRM / Live2D / @tresjsVRM=3D 아바타 표준, Live2D=2D 아바타, @tresjs=Three.js를 Vue 컴포넌트처럼 쓰는 렌더러.
wlipsync소리에서 음소를 뽑아 아바타 입 모양(blendshape)으로 바꾸는 립싱크 라이브러리.
server-runtime / server-sdkairi의 "신경망 버스" — 모듈이 announce·이벤트 교환하는 타입 있는 WebSocket 프로토콜(서버/클라이언트).
pglite / DuckDB-WASM브라우저·로컬에서 도는 Postgres(pgvector)/DuckDB. 서버 없이 기억(벡터 검색)·분석을 가능하게.
stopWhen / stepCountAtLeastLLM이 도구를 몇 걸음까지 반복 호출할지 정하는 조건. airi는 최대 10걸음 에이전트 루프.
mineflayer / isolated-vm / MCP마인크래프트 봇 라이브러리 / LLM 생성 코드 격리 실행 / 도구를 표준 방식으로 노출하는 프로토콜.
ccc (캐릭터 카드)캐릭터 설정을 PNG 이미지 메타데이터에 심는 방식(SillyTavern 호환). 그림 한 장으로 '영혼'을 전달.
stage-tamagotchiElectron 데스크톱 앱(투명·클릭 통과 오버레이). 이름처럼 "영혼 갈아끼우는 전자 다마고치".

11참고 링크

공식 소스 우선 — 버전·수치는 클론한 소스(v0.11.0-dev, 커밋 c74ed2f) 기준

공식
· GitHub 저장소: github.com/moeru-ai/airi (모노레포 · MIT · © 2024-PRESENT Neko Ayaka)
· TrendShift 카드: trendshift.io/repositories/14636 (Daily #15 · #AI agent #Digital human)
· 한국어 README: 저장소 내 README.ko-KR.md · 데스크톱 바이너리 릴리스 v0.10.2(Win/macOS/Linux)

저장소 안에서 꼭 읽을 것
· packages/core-agent/src/runtime/llm-service.ts — 도구 루프(stepCountAtLeast)와 sanitizeMessages(두뇌)
· packages/stage-ui/src/workers/vad/ · libs/inference/adapters/whisper.ts — 브라우저 내 음성·폴백(감각)
· packages/stage-ui-three/src/composables/vrm/ — VRM 렌더·립싱크(몸)
· packages/server-runtime · server-sdk — WebSocket 모듈 버스(신경)
· services/minecraft/src/cognitive/ — 계층형 임베디드 에이전트(능력)

곁들여 학습
· transformers.js · onnxruntime-web · WebGPU 기초(MDN·HuggingFace 문서)
· Three.js → @tresjs/core@pixiv/three-vrm · VRM/Live2D 아바타
· xsai · OpenAI 호환 API 상호운용 · Model Context Protocol(MCP)
· pnpm workspace/catalog · Turborepo 모노레포 관리
· mineflayer · isolated-vm 샌드박싱 · 임베디드 게임 에이전트

참고 · 소스 정독으로 확인한 사항
버전·구조는 클론 시점(2026-07-15, 커밋 c74ed2f) 기준

① 저장소 루트 버전은 0.11.0개발 중 상태이며, 사용자용 배포 바이너리는 v0.10.2(README 다운로드 링크)다. ② 데스크톱 셸은 Electron이다 — src-tauri가 없어 Tauri가 아님을 확인했다. ③ 팩토리오 연동은 이 저장소가 아니라 형제 저장소 moeru-ai/airi-factorio에 있다. ④ Live2D는 프로퍼티어리 Cubism SDK에 의존하니 라이선스를 확인할 것(VRM만 쓰면 무관). ⑤ 모노레포·트렌딩 특성상 패키지 수·버전·구조는 계속 바뀐다 — 최신은 공식 저장소에서 확인.