한 문장으로 이 프로젝트가 뭘 하는지부터.
Open Notebook = "흩어진 자료 → 검색·대화·요약·팟캐스트가 되는 개인 연구 노트북". 논문 PDF, 유튜브 영상, 녹음 파일, 웹페이지를 노트북 하나에 던져 넣으면, AI가 그 자료들을 읽고·쪼개고·색인해 둔다. 이후 "이 자료들 핵심만 정리해줘", "A와 B 주장이 어떻게 다른지 표로 만들어줘"처럼 물으면, 내가 넣은 자료에 근거해 답하고 출처(인용)를 붙여 준다.
NotebookLM은 편리하지만 자료를 전부 구글 클라우드에 올려야 하고, AI 모델도 구글 것만 쓴다. Open Notebook은 똑같은 "자료 모으고 → AI와 대화하고 → 팟캐스트 만들기"를, 내 컴퓨터/서버 안에서 한다.
그래서 민감한 사내 문서·미공개 연구도 외부로 한 줄 안 나가고, AI는 OpenAI든 Anthropic이든 내 노트북 위에서 도는 로컬 모델(Ollama)이든 골라 쓸 수 있다. "편의 vs 통제권"의 저울에서 통제권 쪽을 택한 도구다.
핵심 철학은 "내 데이터는 내 통제 아래(Privacy-First)"다. 자료도, 대화도, 임베딩(검색용 색인)도 전부 내가 띄운 SurrealDB와 디스크에 남는다. AI 공급자에게 보내는 내용조차 문맥(Context) 제어 기능으로 "어디까지 보낼지"를 항목별로 고를 수 있다.
TrendShift 일간 10위까지 올라온 이유 — 트렌딩의 배경.
2024년 구글 NotebookLM이 "내 자료로 대화 + 자동 팟캐스트"로 화제가 된 뒤, "같은 걸 내 서버에서, 내 모델로"를 원하는 수요가 컸다. Open Notebook은 그 빈자리를 정확히 노린다. 트렌딩 이유를 다섯으로 정리한다.
변호사·의료·연구·사내 보안 자료처럼 "외부 업로드 자체가 금지"인 경우가 많다. Open Notebook은 Docker로 내 서버에 띄우면 자료·임베딩·대화가 전부 로컬에 머문다. 여기에 Ollama·LM Studio로 LLM까지 로컬에 두면 인터넷 없이 100% 오프라인으로도 굴러간다.
NotebookLM은 구글 모델만 쓴다. Open Notebook은 esperanto 라이브러리 덕분에 OpenAI·Anthropic·Google·Groq·Mistral·DeepSeek·xAI·OpenRouter·Ollama 등 18종을 골라 끼운다. "요약은 싼 모델, 추론은 좋은 모델, 임베딩은 로컬"처럼 작업별로 모델을 섞어 비용을 깎을 수 있다.
NotebookLM의 대표 기능인 "두 진행자가 자료를 떠드는 팟캐스트"를, Open Notebook은 화자 1~4명 + 커스텀 프로필 + Episode Profile(에피소드 설계도)로 확장했다. 대본을 직접 손볼 수도 있어 "딥다이브 2인 대담" 한 가지에 갇히지 않는다.
NotebookLM은 공개 API가 없다. Open Notebook은 모든 기능을 FastAPI REST API로 노출한다(:5055/docs). 그래서 "매일 아침 새 논문을 자동으로 노트북에 넣고 요약 팟캐스트를 만들어 메일로 보내기" 같은 파이프라인을 스크립트로 짤 수 있다.
MCP(Model Context Protocol) 서버를 내장해, Claude Desktop이나 VS Code 같은 MCP 클라이언트에서 내 노트북·소스를 검색·활용할 수 있다. "연구 자료 창고"를 다른 AI 도구의 백엔드로도 쓰는 셈이다.
NotebookLM = 호텔 룸서비스 — 버튼만 누르면 다 가져다 주지만, 메뉴(모델)는 호텔이 정한 것만, 주방(서버)도 못 들여다본다.
Open Notebook = 내 집 주방 — 재료(모델)도 내가 고르고, 레시피(파이프라인)도 바꾸고, 남는 음식(데이터)도 전부 내 냉장고에 둔다. 대신 가스불은 내가 켜야 한다(직접 띄워 운영).
셀프호스팅은 설치·업데이트·DB 운영을 직접 떠안는다는 뜻이다. 또 README도 인정하듯 인용·출처 정밀도는 아직 NotebookLM보다 거칠고("Citations: 기본 수준, 개선 예정"), RAG 특성상 검색에서 엉뚱한 조각을 물어오면 답도 틀어진다. "트렌딩이라 완벽"이 아니라, RAG·벡터검색·멀티공급자·셀프호스팅 아키텍처를 통째로 공부하기 좋은 살아있는 교재로 보는 게 정확하다.
pyproject.toml · package.json · docker-compose · 소스 트리에서 뽑아낸 실제 구성.
Open Notebook은 ⓐ 백엔드(연구 두뇌) ⓑ 데이터 계층 ⓒ 프론트엔드 ⓓ 인프라 네 층으로 나뉜다. 특히 FastAPI 백엔드와 Next.js 프론트가 완전히 분리(디커플드)되어 REST로만 대화하는 게 설계의 큰 특징이다.
| 구성요소 | 무엇 | 역할 |
|---|---|---|
| Python 3.11~3.12 | 런타임 | 전체 백엔드 언어. 패키지 버전 1.9.0. |
| FastAPI + uvicorn | REST API 서버 | 포트 5055. notebooks·sources·chat·search·podcasts 등 20여 개 라우터. /docs 자동 문서. |
| LangChain 1.x + LangGraph 1.x | LLM 오케스트레이션 | ask·chat·transformation을 상태 그래프로 구성. 추론 흐름을 노드로 쪼갠다. |
| Esperanto | 공급자 추상화 | 같은 저자(lfnovo)가 만든 라이브러리. 18+ 공급자를 LLM/임베딩/STT/TTS 한 인터페이스로. |
| content-core | 콘텐츠 추출 | PDF·영상·오디오·웹·오피스 문서에서 텍스트를 뽑아내는 만능 인제스터. |
| podcast-creator | 팟캐스트 생성 | 멀티 화자 대본 작성 + TTS 합성 파이프라인. |
| tiktoken / ai-prompter | 토큰·프롬프트 | 토큰 계산(컨텍스트 예산) + 프롬프트 템플릿 관리. |
| 구성요소 | 무엇 | 역할 |
|---|---|---|
| SurrealDB v2 | 멀티모델 DB | 문서 + 그래프 + 벡터 + 전문검색(FTS)을 DB 하나로. 별도 벡터DB가 필요 없다. |
| RocksDB 스토리지 | 로컬 영구저장 | SurrealDB의 디스크 엔진. ./surreal_data 볼륨에 데이터 파일로. |
| surreal-commands | 비동기 커맨드 큐 | 임베딩·팟캐스트 같은 무거운 작업을 백그라운드 잡으로. DB가 큐 역할까지 겸한다. |
| langgraph-checkpoint-sqlite | 그래프 체크포인트 | LangGraph 대화 상태를 SQLite에 저장(멀티턴 이어가기). |
| 벡터 임베딩 | 의미 색인 | 자료를 조각내 임베딩 → 벡터로 저장. "뜻이 비슷한 문단"을 찾는 벡터검색의 토대. |
| 구성요소 | 무엇 | 역할 |
|---|---|---|
| Next.js 16 + React 19 | 웹 UI 프레임워크 | 최신 React 서버/클라이언트 컴포넌트. 백엔드와 REST로만 통신. |
| Radix UI + Tailwind 4 | shadcn 스타일 UI | 접근성 좋은 헤드리스 컴포넌트 + 유틸리티 CSS. components.json으로 shadcn 관리. |
| TanStack Query | 서버 상태 | API 응답 캐싱·동기화. 로딩/에러 상태를 자동 관리. |
| Zustand | 클라이언트 상태 | 가벼운 전역 상태 스토어. |
| react-hook-form + zod | 폼·검증 | 설정·자료 입력 폼과 타입 안전한 유효성 검사. |
| i18next + Monaco | 다국어·에디터 | 영어·포르투갈어·중국어·일본어·러시아어·벵골어 등 UI 다국어 + 코드/프롬프트 편집기. |
| 구성요소 | 무엇 | 역할 |
|---|---|---|
| Docker Compose | 2서비스 오케스트레이션 | surrealdb + open_notebook 컨테이너. docker compose up -d 한 줄. |
| supervisord | 멀티프로세스 관리 | 단일 이미지(Dockerfile.single) 안에서 API + UI + 워커를 한꺼번에 띄운다. |
| 암호화 키 | 비밀 보호 | OPEN_NOTEBOOK_ENCRYPTION_KEY로 DB에 저장되는 API 키들을 암호화. |
| 포트 3개 | 8502·5055·8000 | 웹 UI(8502) · REST API(5055) · SurrealDB(8000). |
AI 공급자는 저마다 API 모양이 다르다(OpenAI와 Anthropic은 요청 형식부터 다름). Open Notebook은 esperanto라는 공통 통역기(어댑터)를 두고, 위쪽 코드는 항상 같은 방식으로 "LLM에게 물어봐"만 호출한다. 그래서 설정에서 공급자만 바꾸면 코드 수정 없이 OpenAI → 로컬 Ollama로 갈아탈 수 있다. 18개 공급자 지원이 마법이 아니라 '추상화 설계'의 결과인 이유다.
자료 한 개가 "대화 가능한 지식"이 되기까지 — 데이터의 여정.
Open Notebook의 흐름은 크게 두 갈래다. ① 자료를 넣어 색인하는 적재 파이프라인(왼쪽), ② 질문을 받아 답을 짓는 질의 파이프라인(오른쪽). 가운데에 SurrealDB가 모든 걸 보관하고, 무거운 작업은 surreal-commands 백그라운드 워커가 떠맡는다.
가장 중요한 결정. 18개 공급자를 직접 if/else로 분기하면 코드가 지옥이 된다. 대신 esperanto가 LLM·임베딩·STT·TTS 네 종류의 공통 인터페이스를 정의하고, 각 공급자를 그 규격에 맞춰 끼운다. 위쪽 비즈니스 로직은 "어느 회사 모델인지" 전혀 모른 채 같은 메서드만 호출한다. 새 공급자가 나와도 어댑터 한 개만 추가하면 끝.
전형적인 RAG 스택은 "본문은 Postgres, 의미 벡터는 Pinecone, 검색은 Elasticsearch"처럼 DB를 3~4개 쓴다. Open Notebook은 SurrealDB 하나로 통합했다. 같은 DB 안에서 노트북 → 소스 → 노트 같은 관계(그래프)도 잇고, 벡터 유사도 검색도 하고, 전문검색(FTS)도 한다. 운영할 인프라가 줄고, "키워드 매칭(FTS) + 의미 매칭(벡터)"을 합친 하이브리드 검색을 한 쿼리로 짜기 쉬워진다.
채팅·질문응답·변환을 한 번의 LLM 호출로 끝내지 않고, "검색 → 컨텍스트 구성 → 생성 → 인용 부착" 같은 단계를 노드로 쪼갠 그래프로 만든다(graphs/chat.py, ask.py, transformation.py). 각 단계가 분리돼 있어 디버깅·교체·재시도가 쉽고, 대화 상태는 checkpoint로 저장돼 멀티턴이 자연스럽게 이어진다.
임베딩(자료가 크면 수천 조각)·팟캐스트(TTS 합성은 몇 분)는 사용자를 기다리게 하면 안 된다. Open Notebook은 commands/의 워커가 이런 작업을 백그라운드로 처리하고, 큐 저장소로 SurrealDB를 그대로 쓴다. 별도 Redis/Celery 없이 "DB가 큐"인 단순한 구조다.
프론트(Next.js)와 백엔드(FastAPI)가 완전히 분리돼 REST로만 만난다. 덕분에 웹 UI 없이도 API만으로 모든 걸 자동화할 수 있고(②번 트렌딩 이유), 나중에 모바일 앱·CLI를 붙여도 백엔드는 그대로다. docker-compose는 이 둘을 한 이미지로 묶되 supervisord가 내부에서 여러 프로세스로 띄운다.
실제 저장소 트리에서 "어디에 뭐가 있는지" 핵심만.
핵심 읽는 순서를 추천하면: api/routers/(입구가 뭐가 있나) → api/*_service.py(그게 뭘 부르나) → open_notebook/graphs/(AI가 어떻게 추론하나) → open_notebook/database/repository.py(SurrealDB를 어떻게 다루나) 순이다. 라우터는 얇고, 진짜 일은 service와 graphs에서 일어나는 계층 분리(layered) 구조가 또렷하게 보인다.
이 레포에서 "무엇을 배울 수 있는가" — 기술별 배울 것 + 실습 아이디어.
자료 추출 → 조각내기(청킹) → 임베딩 → 저장 → 하이브리드 검색 → 컨텍스트 구성 → 생성 → 인용. RAG의 모든 단계가 실제 코드로 들어 있다.
실습: graphs/ask.py를 따라가며 "질문이 들어오면 어떤 순서로 검색·생성되는지" 주석을 달아 보자. 검색 결과 조각 수(top-k)를 바꿔 답 품질이 어떻게 달라지는지 비교.
SurrealQL 문법, 벡터 유사도 함수, 전문검색 인덱스, 그래프 관계(노트북-소스-노트)를 한 DB에서 다루는 실전 예제다.
실습: docker compose로 띄운 SurrealDB(:8000)에 직접 접속해, 저장된 소스 테이블과 임베딩을 쿼리해 보자. "이 문단과 의미가 가까운 문단 5개"를 벡터검색으로 뽑아 보기.
"한 번 호출"이 아니라 노드 그래프로 추론을 설계하는 패턴. 체크포인트로 멀티턴 상태를 잇는 법까지.
실습: graphs/transformation.py를 본떠 "내 자료를 3줄로 요약하는" 커스텀 변환 노드를 추가해 보기.
라우터는 얇게, 로직은 service, 데이터는 repository로 분리하는 "현업에서 통하는" 백엔드 설계. 의존성 주입·Pydantic 모델 검증도 함께.
실습: :5055/docs(자동 생성 Swagger)로 모든 엔드포인트를 눌러 보고, 노트북 1개를 API만으로 만들어 보기.
"서버에서 온 데이터(Query 캐시)"와 "UI 상태(Zustand)"를 구분해 관리하는 모범 사례. Radix+Tailwind로 접근성 좋은 UI 구성.
실습: frontend/src에서 채팅 컴포넌트가 API 응답을 어떻게 캐싱·갱신하는지 추적해 보기.
"DB를 큐로 쓰는" 가벼운 백그라운드 처리, 그리고 18개 공급자를 한 인터페이스로 묶는 어댑터 설계 — 둘 다 다른 프로젝트에 바로 응용 가능한 패턴이다.
실습: commands/embedding_commands.py를 읽고, 무거운 작업이 어떻게 큐에 들어가 워커가 집어가는지 흐름을 그려 보기.
"내 노트북으로 돌아갈까?" — 구성에 따라 천차만별이다.
| 구성 | 필요 사양 | 비고 |
|---|---|---|
| 기본(클라우드 LLM) | Docker Desktop + RAM 2~4GB | OpenAI/Anthropic 등 API만 쓰면 내 PC는 가볍다. 추론은 공급자 서버가 함. |
| 로컬 LLM(Ollama) | RAM 16GB+ / GPU 권장 | 모델을 내 PC에서 돌리므로 무겁다. 7B급은 8~16GB, 더 큰 모델은 그 이상. |
| 디스크 | 자료 크기 + 임베딩 | PDF 본문 + 벡터 색인 + 팟캐스트 오디오가 쌓인다. 여유 있게. |
| 포트 | 8502 / 5055 / 8000 | 웹 UI · REST API · SurrealDB. 셋 다 비어 있어야 한다. |
| API 키 | 공급자별 키 | UI 설정에서 입력 → 암호화 키로 DB에 암호화 저장. Groq는 무료 티어 있음. |
처음엔 Groq 무료 티어나 OpenAI 키로 가볍게 띄워 감을 잡고, 프라이버시가 중요해지면 그때 Ollama로 LLM·임베딩을 로컬로 옮기면 된다. 도구가 둘 다 지원하니 설정만 바꾸면 전환된다.
읽기만 하면 안 남는다 — 손으로 해보는 난이도별 과제 6선.
docker-compose.yml 받아 OPEN_NOTEBOOK_ENCRYPTION_KEY만 바꾸고 docker compose up -d. localhost:8502 접속 → API 키 등록 → PDF 한 개 올려 "핵심 3가지 요약해줘" 질문 → 출처(인용)가 어떻게 붙는지 확인.
같은 자료로 팟캐스트 생성. 화자 수를 2명 → 3명으로 바꾸고, Episode Profile을 손봐 톤을 "진지한 다큐"와 "가벼운 잡담"으로 각각 뽑아 비교.
examples/docker-compose-ollama.yml로 LLM·임베딩을 전부 로컬로. 인터넷을 끊은 채 검색·채팅이 되는지 확인하며 "오프라인 RAG"를 체험.
:5055/docs를 참고해, 파이썬 httpx로 "노트북 생성 → URL 소스 추가 → 요약 요청"을 스크립트화. cron으로 매일 아침 새 자료를 자동 적재하게 만들기.
open_notebook/graphs/transformation.py와 domain/transformation.py를 본떠, "자료를 면접 예상질문 10개로 바꾸는" 새 변환을 추가. LangGraph 노드 + 프롬프트 템플릿 흐름을 직접 잇는다.
문서의 MCP Integration을 따라 Open Notebook을 MCP 서버로 등록. Claude Desktop에서 "내 노트북에서 X 관련 자료 찾아줘"가 동작하게 만들고, 검색 결과가 어떻게 전달되는지 관찰.
이 레포를 발판으로 "RAG 풀스택"을 익히는 6주 코스.
| 주차 | 주제 | 학습 내용 |
|---|---|---|
| 1주차 | RAG·임베딩 기초 | 임베딩·벡터검색·청킹 개념 잡기 + Open Notebook 띄워 자료 넣고 대화해 보며 체감. |
| 2주차 | SurrealDB 멀티모델 | SurrealQL 기본, 벡터 함수, FTS 인덱스, 그래프 관계. 저장된 데이터를 직접 쿼리. |
| 3주차 | LangChain / LangGraph | 그래프 오케스트레이션, 노드·엣지·상태, 체크포인트. graphs/ 코드 정독. |
| 4주차 | FastAPI 서비스 레이어 | router/service/repository 분리, Pydantic 검증, REST로 전 기능 자동화 스크립트 작성. |
| 5주차 | Next.js 16 · React 19 | 서버/클라이언트 컴포넌트, TanStack Query 캐싱, Zustand 상태, Radix+Tailwind UI. |
| 6주차 | 비동기·배포·운영 | surreal-commands 잡 큐, 팟캐스트 파이프라인, Docker+supervisord 배포, 보안(암호화 키·인증). |
한 번에 다 보려 하지 말고 "하나의 질문이 답이 되는 경로"만 끝까지 따라가 보라. 프론트의 채팅 입력 → api/routers/chat.py → chat_service.py → graphs/chat.py → 검색(SurrealDB) → Esperanto(LLM) → 응답. 이 한 줄기를 완전히 이해하면 나머지 기능은 같은 패턴의 반복임이 보인다.
이 프로젝트를 읽다 만나는 용어들 — 짧게 정리.
| 용어 | 뜻 |
|---|---|
| RAG | 검색 증강 생성. 내 자료에서 관련 부분을 찾아 그걸 근거로 AI가 답하는 방식. |
| 임베딩(Embedding) | 텍스트를 "뜻"을 담은 숫자 벡터로 바꾼 것. 의미가 비슷하면 벡터도 가깝다. |
| 벡터검색 | 키워드가 안 겹쳐도 "뜻이 가까운" 문단을 벡터 거리로 찾는 검색. |
| 하이브리드 검색 | 키워드 매칭(FTS)과 의미 매칭(벡터)을 합쳐 정확도를 올리는 검색. |
| SurrealDB | 문서+그래프+벡터+전문검색을 한 DB로 합친 멀티모델 데이터베이스. |
| LangGraph | LLM 추론을 노드 그래프(상태 머신)로 설계하는 LangChain 계열 프레임워크. |
| Esperanto | 18+ AI 공급자를 한 인터페이스로 묶는 추상화 라이브러리(같은 저자 제작). |
| content-core | PDF·영상·오디오·웹에서 본문 텍스트를 뽑아내는 콘텐츠 추출기. |
| surreal-commands | SurrealDB를 큐로 써서 무거운 작업을 백그라운드로 돌리는 비동기 잡 시스템. |
| Transformation | 자료를 요약·인사이트 등 다른 형태로 바꾸는 커스터마이즈 가능한 액션. |
| Episode Profile | 팟캐스트의 화자 수·톤·구성을 미리 정의해 둔 "에피소드 설계도". |
| MCP | Model Context Protocol. AI 에이전트가 외부 도구·데이터에 접근하는 표준 규약. |
| 셀프호스팅 | 클라우드 서비스 대신 내 서버/PC에 직접 띄워 운영하는 방식. |
| TanStack Query | 서버 데이터를 캐싱·동기화하는 React 라이브러리(구 React Query). |
| Zustand | 가볍고 단순한 React 전역 상태 관리 라이브러리. |
| supervisord | 한 컨테이너 안에서 여러 프로세스(API·UI·워커)를 띄워 관리하는 도구. |
더 깊이 파고들 때의 출발점.
| 자료 | 링크 |
|---|---|
| GitHub 저장소 | github.com/lfnovo/open-notebook |
| 공식 웹사이트 | open-notebook.ai |
| 공식 문서 | 저장소 docs/ · 0-START-HERE ~ 7-DEVELOPMENT |
| Esperanto(공급자 추상화) | github.com/lfnovo/esperanto |
| SurrealDB | surrealdb.com |
| LangGraph | langchain.com (LangGraph 문서) |
| Discord 커뮤니티 | 저장소 README의 Discord 초대 링크 |
| TrendShift 순위 | trendshift.io/repositories/14536 |