nashsu/llm_wiki. Andrej Karpathy가 던진 "LLM Wiki" 아이디어를 Tauri v2 + React 19 + Rust로 풀스택 구현한 첫 본격 데스크톱 앱이다. 전통 RAG(NotebookLM, ChatGPT 파일 업로드)는 질문할 때마다 원문 조각을 다시 검색해 매번 지식을 처음부터 짜맞춘다. llm_wiki는 반대로 문서를 넣는 순간(인제스트) LLM이 위키를 컴파일한다 — 엔티티·개념 페이지를 만들고, [[위키링크]]로 교차 연결하고, 모순을 표시한다. 그래서 지식이 매번 휘발되지 않고 디스크에 쌓이며 복리(compounding)로 자라는 영속 아티팩트가 된다. 위키 폴더는 그대로 Obsidian 보관함으로 열리고, 하이브리드 검색(키워드+벡터 RRF 융합)·지식 그래프(Louvain 커뮤니티)·MCP 서버까지 갖췄다. (저장소: nashsu/llm_wiki · TypeScript ~71,400줄 + Rust ~12,400줄 · v0.4.26 · 라이선스 단독개발 · 스택 Tauri v2 / React 19 / LanceDB — TrendShift RAG·문서처리 토픽 트렌딩)
"문서를 넣어 두면, LLM이 알아서 상호 연결된 마크다운 위키를 만들고 계속 고쳐 준다."
도서관에 자료를 갖다주면, 사서가 그때그때 "어디서 찾아 읽으세요"라고 안내만 하는 게 보통의 RAG입니다. llm_wiki의 사서는 다릅니다 — 자료가 들어올 때마다 직접 항목 카드를 쓰고(엔티티 페이지), 관련 카드끼리 실로 연결하고([[위키링크]]), 앞 자료와 모순되면 메모를 붙입니다. 그래서 나중에 질문하면 원문 더미를 다시 뒤지는 게 아니라 이미 정리된 위키를 읽고 답합니다. 자료가 쌓일수록 위키도 촘촘해지는, "복리로 자라는 지식"이 핵심입니다.
"출처가 분명한 트렌딩(Karpathy 패턴) + RAG의 한계를 정조준한 발상 + 학습가치 높은 스택."
Andrej Karpathy가 공개한 llm-wiki.md 메모(질문마다 재검색하는 RAG 대신, LLM이 영속 위키를 증분 구축·유지하자는 방법론)를 본격 데스크톱 앱으로 옮긴 첫 프로젝트입니다. 원본 메모 전문이 저장소에 llm-wiki.md로 포함돼 있어 "왜 이렇게 만들었는가"의 1차 출처가 명확합니다.
NotebookLM·ChatGPT 파일 업로드·OpenKB 같은 전통 RAG는 질문마다 원문 청크를 다시 검색해 매번 답을 재합성합니다(같은 작업을 반복). llm_wiki는 인제스트 때 2단계 사고(분석→생성)로 위키를 만들어 두므로, 다음 문서가 들어오면 기존 위키에 연결·모순 표시까지 합니다. 지식이 누적되는 영속 아티팩트라는 점이 결정적 차별점입니다. 게다가 위키 폴더는 .obsidian/이 자동 생성돼 그대로 Obsidian 보관함으로 열립니다 — Obsidian은 사람이 직접 쓰는 도구지만, 여기선 LLM이 유지보수를 맡고 사람은 큐레이션·질문만 합니다.
키워드 검색과 벡터 의미검색을 RRF(상호순위융합)로 합치는 하이브리드 검색(README 벤치마크상 recall 58.2%→71.4%), 링크 위상으로 지식 클러스터를 찾는 Louvain 커뮤니티 탐지, "뜻밖의 연결/지식 공백"을 짚어 주는 Graph Insights까지 — 경쟁 노트앱이 거의 제공하지 않는 지식그래프 분석을 갖췄습니다.
모든 데이터가 로컬 디스크에 저장되고, 벡터DB(LanceDB)도 온디바이스 임베디드입니다. LLM은 OpenAI/Anthropic/Google 같은 클라우드부터 로컬 Ollama까지 자유 선택 — 클라우드 키 없이도 완전 로컬로 돌릴 수 있습니다.
사실상 단독 개발(스타 수십 개 수준, 이슈/PR 거의 없음)이라 커뮤니티 성숙도는 초기입니다. 또한 GitHub 웹에 보이는 README가 구버전으로 캐시돼 있어(벡터검색·MinerU 미언급) 실제 기능과 다를 수 있습니다 — 이 문서는 클론한 v0.4.26 실제 소스 기준입니다. 다만 코드 깊이·기능 완성도·릴리스 속도(2.5개월 만에 v0.1→v0.4.26)는 "초기 장난감"이 결코 아닙니다.
"Rust 백엔드(Tauri) + React 프론트엔드 + 임베디드 벡터DB + MCP 서버 + Chrome 확장 — 데스크톱 풀스택의 교과서적 조합."
src-tauri/, 약 12,400줄)| 기술 | 역할 / 메모 |
|---|---|
| Tauri v2 | macOS/Windows/Linux 네이티브 셸. Rust 백엔드 + 웹 프론트엔드를 IPC로 연결(Electron보다 경량) |
| lancedb 0.27 + arrow 57 | 임베디드 벡터DB. 코사인 ANN 검색. DB 경로 {project}/.llm-wiki/lancedb |
| pdfium-render / calamine / docx-rs / zip | PDF·XLSX·DOCX·PPTX 문서 파서(번들 pdfium 바이너리 포함) |
| tiny_http | 로컬 HTTP 서버 2개 — API(:19828) + Clip(:19827, 확장 연동) |
| tokio + which | claude/codex CLI를 자식 프로세스로 띄워 stdout 스트리밍(에이전트 연동) |
| notify + walkdir | raw/sources/ 폴더 자동 감시(추가·수정·삭제 감지) |
| sha2 / md-5 | 인제스트 중복제거 해시(변경 없는 파일은 재처리 스킵) |
src/, 약 71,400줄)| 기술 | 역할 / 메모 |
|---|---|
| React 19 + TS 5.7 + Vite 8 | UI 코어. 빌드 포트 1420 고정 |
| shadcn/ui + Tailwind v4 | 컴포넌트·스타일 시스템 |
| Zustand 5 | 상태관리(wiki·chat·review·research·activity 스토어) |
| Milkdown 7 | ProseMirror 기반 위키 WYSIWYG 에디터(+수식 플러그인) |
| sigma 3 + graphology | 지식그래프 시각화 + ForceAtlas2 레이아웃 + Louvain 커뮤니티 |
| react-markdown + KaTeX + mermaid | 마크다운·수식·다이어그램 렌더링 |
| i18next | 다국어(영/중, README는 영·중·일·한 4종) |
| Vitest 4 + fast-check | 단위 + property-based 테스트(품질관리가 탄탄) |
| 구성요소 | 역할 / 메모 |
|---|---|
MCP 서버(mcp-server/) | 별도 npm 패키지. 로컬 API를 7개 MCP 툴로 노출 → Claude Code/Codex가 위키를 도구로 사용 |
| Chrome 확장(MV3) | Readability.js(본문 추출) + Turndown.js(HTML→MD)로 웹페이지를 위키에 클립 |
| LLM 프로바이더 | OpenAI / Anthropic / Google / Ollama / Custom(Azure·DeepSeek·Kimi·xAI 등 호환 게이트웨이). 스트리밍 SSE 파싱, <think> 추론 블록 표시 |
| 웹검색 / 고급 파싱 | Tavily / SerpApi / SearXNG(딥리서치), MinerU(선택, PDF 클라우드 파싱) |
"불변 원본(raw) → 2단계 CoT 인제스트 → LLM 소유 위키(wiki) → 벡터·그래프 색인 → 5단계 쿼리 파이프라인."
핵심 설계는 Karpathy의 "원본은 건드리지 않고, LLM이 위키를 따로 유지한다"를 충실히 따르되, 단일 인제스트를 2단계 사고(Chain-of-Thought)로 쪼개고 벡터·그래프·리뷰·딥리서치를 얹은 것입니다.
① 2단계 CoT 인제스트(ingest.ts): 원본을 (1) 구조화 분석 → (2) 위키 파일 생성, 두 번의 LLM 호출로 분리해 품질을 높입니다. SHA256 증분 캐시로 변경 없는 파일은 토큰을 아끼려 건너뛰고, 영속 인제스트 큐는 직렬 처리·디스크 영속·앱 재시작 생존·3회 자동 재시도를 보장합니다.
② 하이브리드 검색의 실제 구현(search.rs): BM25 라이브러리 없이 토큰 가중 스코어링을 직접 짭니다. 영어는 split+stopword 제거, 중국어 등 CJK는 bigram(2글자)+단일글자로 토큰화. 벡터 검색이 켜지면 RRF(1/(k+rank))로 키워드 순위와 벡터 순위를 융합합니다.
③ 4-신호 관련성 모델(graph-relevance.ts): 페이지 간 관련도를 Direct link ×3.0, Source overlap ×4.0(같은 raw 원본 공유 — sources[] frontmatter), Adamic-Adar ×1.5, Type affinity ×1.0의 가중합으로 계산합니다. 같은 출처에서 파생된 페이지를 가장 강하게 묶는 게 특징입니다.
④ panic_guard로 파서 격리: 릴리스 프로파일이 panic = "unwind"이고, Tauri 커맨드 경계에서 서드파티 파서(pdfium 등)의 패닉을 잡아 파일 하나가 깨져도 앱 전체가 죽지 않게 합니다.
"코드 구조(src·src-tauri·mcp-server·extension)와, 런타임에 생성되는 위키 프로젝트 구조는 별개다."
| 경로 | 역할 |
|---|---|
| src/ | React 프론트엔드. components/(chat·graph·search·settings·review·editor 등), lib/(핵심 로직 90+ 모듈), stores/(Zustand), commands/(Tauri invoke 래퍼) |
| src/lib/*.ts | ingest.ts·search.ts·deep-research.ts·graph-relevance.ts·graph-insights.ts·embedding.ts·llm-providers.ts·lint.ts — 인제스트·검색·그래프·임베딩·프로바이더·린트의 심장 |
| src-tauri/ | Rust 백엔드. api_server.rs·clip_server.rs(HTTP), commands/(search·vectorstore·file_sync·claude_cli·codex_cli), panic_guard.rs, pdfium/(번들 바이너리) |
| mcp-server/ | 별도 MCP npm 패키지(index.ts·api-client.ts + 테스트) |
| extension/ | Chrome MV3 확장(manifest.json·popup.*·Readability.js·Turndown.js) |
| llm-wiki.md | Karpathy 원본 패턴 메모 전문 — 방법론의 출처 |
| README(_CN/_JA/_KO) | 4개 언어 README |
"Tauri 데스크톱·하이브리드 검색·임베디드 벡터DB·그래프 알고리즘·멀티 LLM 추상화가 한 레포에 모여 있다."
배울 것: Rust 백엔드 + 웹 프론트엔드를 IPC(커맨드 패턴)로 잇는 법, panic = "unwind" + 가드로 서드파티 크래시 격리, capabilities 기반 권한, 멀티 타깃 번들(.dmg/.msi/.deb/.AppImage). Electron 대비 경량 네이티브를 배우기 좋은 실전 예제.
실습: Tauri로 "파일을 드롭하면 Rust가 해시를 계산해 프론트로 돌려주는" 미니 앱 만들기. invoke로 커맨드를 호출하고 결과를 React 상태에 반영해 보기.
배울 것: 라이브러리 없이 토큰 가중 스코어링을 짜고, 키워드 순위와 벡터 순위를 RRF로 융합하는 법. CJK bigram 토큰화의 필요성. "index.md 우선" 전략이 중간 규모(~100 소스)에서 통한다는 Karpathy의 주장과 그 한계를 코드로 확인.
실습: 두 검색기(키워드/벡터)의 결과 리스트를 받아 score += 1/(60+rank)로 합쳐 재정렬하는 RRF 함수를 직접 구현. 한쪽만 잘 맞는 질의에서 융합이 어떻게 도움이 되는지 관찰.
배울 것: Arrow 스키마로 FixedSizeList<Float32> 벡터를 저장하고, 청크 단위 업서트·코사인 ANN·compaction을 다루는 법. 별도 벡터 서버(Pinecone 등) 없이 온디바이스로 RAG 인프라를 구성하는 경험.
실습: LanceDB(또는 Chroma)로 문장 100개를 임베딩해 저장하고, 질의 문장과 코사인 유사도가 높은 top-5를 뽑아 보기.
배울 것: Adamic-Adar(공유 이웃 가중), Louvain 커뮤니티 탐지(모듈러리티 최적화로 클러스터 발견), 고아·브리지 노드 탐지를 graphology + ForceAtlas2 시각화와 함께. "지식 그래프"가 마케팅 용어가 아니라 실제 알고리즘임을 체득.
실습: 내 노트들을 노드로, 링크를 엣지로 만들어 graphology에 넣고 Louvain으로 커뮤니티를 칠해 보기. 어떤 노트가 "다리(bridge)" 역할인지 찾기.
배울 것: 하나의 인터페이스로 OpenAI/Anthropic/Google/Ollama의 스트리밍 차이(SSE 파싱·헤더·vision 콘텐츠 블록 변환)를 흡수하는 어댑터 패턴. OLLAMA_ORIGINS 같은 현실 함정 주석이 교육적입니다.
실습: OpenAI와 Ollama 두 백엔드를 같은 chat(messages) 인터페이스 뒤에 숨기고, 설정값만 바꿔 스트리밍 응답을 받아 보기.
배울 것: 마크다운 + YAML frontmatter를 단일 진실원으로 쓰고 Obsidian과 공존시키는 법, 소스 삭제 시 참조 무결성을 지키는 캐스케이드 삭제, 그리고 로컬 REST API를 MCP 툴로 래핑해 에이전트가 쓰게 하는 법.
실습: @modelcontextprotocol/sdk로 "내 메모 폴더를 검색하는" MCP 툴 1개를 만들어 Claude Code에 붙여 보기.
"앱 자체는 가볍다(Tauri). 실질 부담은 '어떤 LLM을 쓰느냐'에 달렸다 — 클라우드면 가볍고, 로컬 Ollama면 모델 메모리가 지배적."
| 항목 | 요구사항 / 메모 |
|---|---|
| OS | macOS(Apple Silicon+Intel) · Windows(.msi) · Linux(.deb/.AppImage). Tauri v2 네이티브 |
| 빌드 전제 | Node.js 20+ + Rust 1.70+. MCP 서버 Node ≥20 |
| RAM | README에 명시 수치 없음. Tauri라 Electron보다 가벼움. 로컬 Ollama 모델 사용 시 해당 모델의 RAM/VRAM(예: 7B≈8GB+)이 지배적 |
| LLM(택1) | 클라우드 키(OpenAI/Anthropic/Google) 또는 로컬 Ollama(키 불필요) |
| 벡터검색(선택) | OpenAI 호환 /v1/embeddings 엔드포인트 |
| 웹검색(선택) | Tavily/SerpApi 키 또는 자체 SearXNG 인스턴스 |
| 포트 | 로컬 2개 — 19828(API) · 19827(Clip 확장) |
클라우드 비용·키 없이 체험하려면 Ollama로 로컬 모델(예: llama3.1)을 띄우고 llm_wiki의 LLM 프로바이더를 Ollama로 지정하면 됩니다. 벡터검색·웹검색은 전부 선택이라 꺼 두면 됩니다 — 그러면 완전 오프라인·무키로 위키 자동생성을 체험할 수 있습니다.
"체험 → 비교 → 그래프 분석 → MCP 연동 → 미니 LLM Wiki 만들기."
앱을 받아 프로젝트를 만들고(템플릿 택1), Ollama를 LLM으로 지정한 뒤 PDF·MD 문서 3개를 import. Activity 패널에서 엔티티·개념 페이지가 생기고 [[링크]]로 연결되는 과정을 관찰.
목표: "인제스트=위키 컴파일"을 체감. Graph 탭에서 페이지들이 어떻게 이어졌는지 보기.
같은 문서 묶음을 NotebookLM(또는 ChatGPT 파일 업로드)에도 넣고, "이 주제와 저 주제가 어떻게 연결되나?" 같은 교차 질문을 양쪽에 던져 답을 비교. 위키 방식이 연결·모순을 더 잘 잡는지 확인.
목표: "매번 재검색"과 "미리 합성된 위키"의 차이를 실제 답변 품질로 체감.
파이썬으로 키워드 검색(간단 토큰 매칭)과 벡터 검색(임베딩 코사인)을 각각 만들고, 둘의 결과를 1/(60+rank) RRF로 융합해 재정렬. 한쪽만으로는 놓치는 질의를 융합이 어떻게 건지는지 측정.
목표: llm_wiki search.rs의 핵심 아이디어를 작은 코드로 재현. CJK bigram 토큰화도 추가해 보기.
앱의 로컬 API(:19828)를 호출하는 MCP 툴을 직접 작성(또는 동봉된 mcp-server 분석)해, Claude Code에서 "내 위키에서 X를 찾아 줘"가 동작하게 연결. 입력 스키마·에러 코드까지 갖추기.
목표: 로컬 앱을 에이전트 도구로 노출하는 MCP 패턴을 손에 익히기.
문서 → (분석)→(엔티티/개념 MD 생성) 2단계 인제스트 + frontmatter sources[] + 간단한 그래프(노드/엣지)를 갖춘 CLI를 직접 조립. SHA256 캐시로 변경분만 재처리하는 부분까지 넣으면 llm_wiki의 뼈대가 거의 완성됩니다.
목표: "원본 불변 + LLM 소유 위키"라는 핵심 패턴을 내 것으로 만들기. Obsidian으로 결과 폴더를 열어 보기.
"RAG 기초에서 출발해 벡터DB·하이브리드 검색·지식그래프·Tauri 데스크톱까지, llm_wiki를 길잡이 삼아."
| 주차 | 주제 | 핵심 학습 + llm_wiki 연결점 |
|---|---|---|
| 1주 | RAG와 임베딩 기초 | 청킹·임베딩·코사인 검색의 기본, "retrieve-and-answer"의 한계 → llm-wiki.md 메모 정독 |
| 2주 | 벡터DB + 하이브리드 검색 | LanceDB/Chroma, BM25 vs 벡터, RRF 융합, CJK 토큰화 → search.rs·embedding.ts |
| 3주 | 지식 그래프 | graphology, Adamic-Adar, Louvain 커뮤니티, ForceAtlas2 → graph-relevance.ts·graph-insights.ts |
| 4주 | Tauri 데스크톱 + 멀티 LLM | Rust↔웹 IPC, panic 격리, 프로바이더 어댑터 → src-tauri/·llm-providers.ts |
| 5주 | MCP + 로컬-퍼스트 | MCP 서버 작성, 마크다운+frontmatter 데이터모델, 캐스케이드 삭제 → mcp-server/·ingest.ts |
이 로드맵은 "현대 RAG의 한계 → 그 다음 세대 아이디어"를 한 줄로 꿴 코스입니다. llm_wiki는 RAG·벡터검색·지식그래프·데스크톱 앱이라는 네 갈래를 한 저장소에서 동시에 보여 주는 드문 교재라, "AI 지식관리 도구를 어떻게 만드는가"를 통째로 익히기에 알맞습니다.
"이 문서와 저장소에서 반복되는 RAG·검색·그래프·데스크톱 용어를 한곳에."
| 용어 | 의미 |
|---|---|
| LLM Wiki 패턴 | 질의마다 재검색하는 RAG 대신, LLM이 인제스트 시점에 영속 위키를 증분 구축·유지하는 Karpathy의 방법론 |
| 2-Step CoT Ingest | 원본을 (분석)→(위키 생성) 두 LLM 호출로 나눠 품질을 높이는 인제스트 방식 |
| RRF (상호순위융합) | 여러 검색 순위를 1/(k+rank) 합으로 합치는 하이브리드 랭킹 기법(k는 보통 60) |
| 하이브리드 검색 | 키워드(정확 매칭)+벡터(의미 매칭) 검색을 합쳐 recall을 끌어올리는 전략 |
| 4-신호 관련성 | Direct link/Source overlap/Adamic-Adar/Type affinity 가중합으로 페이지 관련도 계산 |
| Adamic-Adar | 두 노드가 공유하는 이웃을 (이웃 차수 역로그로) 가중해 링크 가능성을 추정하는 그래프 지표 |
| Louvain 커뮤니티 | 링크 위상만으로 지식 클러스터를 자동 발견하는 모듈러리티 최적화 알고리즘 |
| Source overlap | 같은 raw 원본에서 파생된 페이지를 묶는 출처 추적(sources[] frontmatter, 관련도 가중치 최고) |
| LanceDB | Rust 임베디드 벡터DB. Arrow FixedSizeList<Float32>로 임베딩 저장, 온디바이스 ANN |
| CJK bigram 토큰화 | 공백 없는 한중일 문자열을 2글자 단위로 쪼개 검색 토큰을 만드는 기법 |
| Graph Insights | 그래프 구조로 "뜻밖의 연결(다른 커뮤니티 간 엣지)"과 "지식 공백(고아·브리지 노드)"을 자동 도출 |
| Tauri v2 / panic_guard | Rust+웹 데스크톱 프레임워크. 커맨드 경계에서 파서 패닉을 에러로 격리 |
| MCP (Model Context Protocol) | 로컬 기능을 표준 "툴"로 노출해 Claude Code 같은 에이전트가 호출하게 하는 프로토콜 |
| frontmatter | 마크다운 상단의 YAML 메타데이터(type·title·sources 등). 위키의 구조·관계를 담는 그릇 |