사유고 개발로그 · 1화
종이책 사진에 물어보는 서재: 글자·그림 검색 두 갈래로 세웠다
종이책 사진을 물어볼 수 있는 서재로 바꾸려고, 글자 검색과 그림 검색 두 갈래로 엔진을 세웠다.
종이책을 휴대폰으로 찍어 두는 습관이 있었다. 문제는 찍어 둔 뒤였다. 어디선가 읽은 문장이 떠올라도 그게 어느 책 몇 쪽이었는지 찾으려면 사진 수백 장을 넘겨야 했다. 찍기만 하고 다시 꺼내 쓰지 못하는 책이 쌓여 갔다.
그래서 원하는 것은 단순했다. 질문을 던지면 답이 오고, 그 답이 책의 어느 문장에서 나왔는지, 원본 사진으로는 어느 쪽인지 같이 보여 주는 것. 이 프로젝트는 처음에 ’책 RAG’라는 이름으로 시작했고, 사유고라는 이름은 나중에 붙였다.
검색을 두 갈래로 나눴다
7월 2일 저장소에 처음 올린 뼈대는 두 갈래 검색이다. 글자 검색은 사진을 OCR로 읽은 본문을 bge-m3로 임베딩해 FAISS로 찾는다. 대부분의 질문은 여기서 해결된다.
그런데 OCR은 그림을 읽지 못한다. 뇌 해부도, 도표, 그래프가 있는 쪽은 글자만으로는 찾을 수 없었다. 그래서 페이지 사진 자체를 Qwen3-VL 임베딩으로 색인하는 두 번째 갈래를 따로 두었다. “해마가 그려진 그림”처럼 물으면 그 그림이 있는 쪽을 이미지로 찾아온다.
언어 모델은 이렇게 찾은 근거 안에서만 답을 쓰게 했다. 답에는 근거 번호가 붙고, 번호를 누르면 출처 페이지와 원본 스캔이 열린다. 책에 없는 말을 지어내는 것보다 “근거가 없다”고 답하는 편이 낫다고 봤다.
화면은 NotebookLM처럼 책마다 채팅과 자료를 나란히 두는 한 페이지 앱으로 만들었다. 드래그한 주장을 웹에서 교차 검증하는 팩트 검증은 이미 돌리던 Hermes 에이전트에 맡겼다.
저장소 첫날의 커밋 열다섯 개
저장소를 만든 첫날에만 커밋이 열다섯 개 쌓였다. 뼈대를 올린 직후 바로 심각한 문제가 하나 나왔다. 인덱스를 모으는 쪽과 전체 검색이 실제로 등록된 책 목록을 기준으로 삼지 않아, 지운 책이 검색에 섞이거나 새 책이 빠질 수 있었다. 등록 목록을 유일한 기준으로 바꾸고, 서버 상태·책 목록·유효한 ID·고아 데이터 걸러내기·질문 응답을 확인하는 스모크 테스트 다섯 개를 만들었다.
그다음은 버티는 힘이었다. 다운로드 폴더에 있던 원본 자료가 지워져도 서재가 무너지지 않게 앱 안에 사본을 두고 자동으로 맞췄고, 사본 교체는 중간에 끊겨도 깨지지 않도록 원자적으로 바꿨다. 답이 다 만들어질 때까지 기다리지 않도록 스트리밍으로 흘려보내고, 새 책을 넣을 때 전체를 다시 임베딩하지 않도록 책마다 캐시를 뒀다. 대화 기록은 서버에 저장하고, 브라우저 저장소는 화면을 빨리 띄우는 사본으로만 썼다.
그렇게 13권으로 시작한 서재가 지금은 책 587권에 영상과 논문까지 들어간 도서관이 됐다.
배운 것
그날 가장 잘한 일은 기능이 아니라 “진짜는 어디에 있는가”를 정한 것이었다. 등록 목록이 기준이고, 서버에 저장된 것이 진실이고, 브라우저에 있는 것은 사본이다. 이 원칙은 그 뒤로 책이 수백 권으로 늘고 자동화가 붙을 때마다 다시 꺼내 쓰게 된다.
사유고 개발로그 · 전 11화
- 1화종이책 사진에 물어보는 서재: 글자·그림 검색 두 갈래로 세웠다
- 2화저자 토론 기능을 붙였다: GPT가 저자 연기를 거부했다
- 3화학습 루프를 만들었다: 증거 없이 완료되는 구멍이 나왔다
- 4화저자 인터뷰와 대목 연결 기능을 붙였다: 결함 5개를 먼저 고쳤다
- 5화책 587권 자동 등록: 파일은 왔는데 페이지가 빠져 있었다
- 6화AI 강의 품질을 쟀다: 모델이 쓴 인용은 문구가 바뀌고 쪽수가 틀렸다
- 7화600권 완독 코스·마인드맵을 배치로 미리 만들기 시작했다
- 8화배치 사용량 문지기: 5시간 한도 80%에서 쉬고 주간 90%에서 멈춘다
- 9화사유고2는 책 795권을 원문 10분의 1 크기 지도로 바꿨다: 답하는 서재에서 늘어놓는 서재로
- 10화투자 책 50권만으로 노트 2,094개짜리 지식 연결망이 나왔다: 795권으로 키우기 전에 고민할 것
- 11화사유고 촬영 자동화를 맥북 프로에서 맥북 에어로 옮겨 같은 작업을 이어 갔다: 바꾼 코드는 두 줄이었다