[개발기] SQLite 하나로 터미널에이전트 이전 대화 검색하기 - 한국어 형태소 분석을 왜 해야하나

116.126.***.***
12

이 글은 seCall — AI 에이전트 대화 세션을 수집·검색하는 CLI 도구 — 의 기능 개발기입니다. 바이브코딩 테스트 프로젝트의 일환으로 만들었으니 세부적인 코드는 모르고 알고 싶지도 않습니다. 몰라도 됩니다. 알면 다칩니다 다만 시행착오 끝에 적용한 기능에 사용된 기술과 도입 이유를 풀어보고 싶어서 쓰는 글입니다.

문제: AI 대화가 너무 많다

하루에 수십 개씩 대화가 쌓입니다. "지난주에 BM25 관련해서 뭐라고 했더라?" 같은 순간이 매일 옵니다. 그런데 Claude Code는 ~/.claude 에 JSONL로, ChatGPT는 export ZIP으로, 코덱스는 또 ~/.codex 아래에 어딘가에... 각자 다른 형식으로 흩어져 있습니다. 그리고 대화는 FIFO라 순식간에 과거의 대화는 밀려 올라가서 찾기가 힘들어 집니다(AI들은 말도 참 길게 합니다) 또 세션이 한번 끊어지면 이전 대화가 어떤 세션에 있었는지도 찾을 수도 없습니다. 그래서 resume.md에 마지막 세션을 기록해 놓기도 했습니다. 😇

원하는 건 단순합니다: 한 곳에 모아서, 한국어로 검색하고 싶다. 여유 시간에 프로젝트를 복기할 수 있도록 어딘가에 정리가 되어있으면 좋겠다.

왜 SQLite인가

검색 엔진 하면 Elasticsearch가 먼저 떠오르고, 벡터DB도 크로마DB등 오픈소스지만 쟁쟁한 도구가 많습니다, 하지만 개인이 사용하는 도구에 JVM 기반 서비스를 띄우는 건 과하다고 생각했습니다. 그래서 가볍게 가자고 생각했습니다. 개인 일기장 만드는데 postgresql을 쓸 수 있지만, 엄청나게 과한거니까요.

SQLite를 선택한 이유:

  • 설치할 게 없다. 파일 하나가 곧 데이터베이스(혼자 쓰기엔 충분)

  • 메타데이터와 검색 인덱스가 한 곳에. 에이전트, 프로젝트, 날짜 필터링과 전문검색을 한 쿼리로

  • FTS5라는 전문검색 엔진이 내장되어 있다. BM25 랭킹까지 지원

이 정도만 해도 안 쓸 이유는 없습니다.

FTS5란?

Full-Text Search 5 — SQLite에 내장된 전문검색 확장입니다.

일반 LIKE '%검색어%'는 테이블 전체를 훑어야 하지만, FTS5는 역색인(inverted index)을 미리 만들어놓습니다. 문서마다 어떤 단어가 몇 번 나오는지 기록해두고, 검색할 때 그 인덱스만 찾아보는 방식입니다. 수천 개 대화에서도 밀리초 단위로 결과가 나옵니다.

거기에 BM25 랭킹도 내장입니다. 검색어가 문서에 몇 번 나오는지, 전체 문서 중 얼마나 드문 단어인지를 고려해서 관련도 순으로 정렬해줍니다. 구글 검색이 쓰는 것과 같은 계열의 알고리즘입니다

문제: FTS5는 한국어를 모른다

여기서 벽에 부딪힙니다. 이전에 QMD(파이썬 스크립트 + BM25를 사용해 옵시디언에 클로드코드 세션(대화)를 파싱해서 옵시디언 볼트에 정리?해주는 프로젝트입니다. 비슷한 프로젝트 중에 아마 제일 유명할 겁니다)를 제미나이 버전으로 재구현 해보면서 포기했던 부분도 이 부분이구요. 굳이 토크나이저까지 공부해가면서 해야하나 라는 생각에 포기했었는데, 마침 우리 앙드레 카파시 선생님(오픈AI 창업멤버 -> 테슬라 인공지능 총괄자)께서 위키에 화두를 하나 던지셔서 재 도전해보게 되어 깃헙스타 50에 빛나는(?) 초인기,초대형 프로젝트인 seCall이 탄생하게 된 계기가 되었습니다

FTS5의 기본 토크나이저는 공백과 구두점으로 단어를 나눕니다. 영어는 이걸로 충분하지만 한국어는 아닙니다.

어떤 문제냐면

"임베딩 모델을 최적화했습니다" 라고 저장되어있으면 FTS5는 영어식으로 "임베딩" "모델을" "최적화했습니다" 라고 나누어서 이 상태에서 "모델"을 검색하게 되면 "모델을"과 매칭이 안됩니다. "최적화"도 마찬가지입니다. 한국어(CJK동일)에 적용하면 무쓸모가 되는겁니다. 그래서 한국어는 형태소 분석(단어를 의미 단위로 쪼개는 작업)이 따로 필요합니다.

형태소 분석하면 "임베딩" "모델" "최적화" 로 분리되기 때문에 이제 "모델"로 검색하면 검색이 됩니다.

해법: Rust에서 먼저 쪼개고 넣기

FTS5 자체에 한국어 분석기를 끼워넣는 건 어떤식으로든 C언어로 확장을 새로 짜야 해서 번거롭습니다. 대신 더 실용적인 방법을 썼습니다:

  1. 대화를 저장할 때: Rust에서 한국어 형태소 분석 → 분석된 단어들을 공백으로 이어붙여서 FTS5에 저장

  2. 검색할 때: 검색어도 같은 형태소 분석기를 통과시킨 뒤 FTS5에 질의

저장과 검색 양쪽에서 같은 분석기를 거치니, FTS5 입장에서는 이미 깔끔하게 정리된 단어들만 다루면 됩니다.이 패턴을 Pre-Tokenization이라고 부릅니다. 검색엔진 앞단에서 미리 토큰화해놓는 방식입니다.(이런식으로 오브젝트들을 레이어링, 파이프라인, 워크플로우 같은 개념을 적용해 두면 바이브코딩 퀄리티가 좋아집니다)

한국어 형태소 분석기: Lindera

그리고 진짜 토크나이져가 필요한 레이어에서는 오픈소스의 바다를 헤매다. 형태소 분석기로 Lindera를 선택했습니다.

  • MeCab 기반의 한국어 사전(ko-dic)을 바이너리에 통째로 포함

  • 추가 다운로드나 외부 서비스 없이 즉시 동작

  • Rust 네이티브라 빌드 한방에 끝

트레이드오프는 바이너리 크기가 ~80MB 늘어난다는 점. 하지만 개인 프로젝트에서 이 정도는 수용 가능 하다고 생각했습니다. 대안으로 Kiwi(한국어 특화 분석기)도 옵션으로 넣어뒀습니다. 키위가 분석 품질이 더 좋다는 평가가 있다는 얘기를 나중에 알아서 옵션이 되었습니다. 실제 큰 차이는 없는 것 같긴합니다.

품사 필터링: 의미 있는 단어만 남기기

형태소 분석기가 뱉어내는 모든 조각을 인덱싱하면 오히려 검색이 부정확해집니다.

"임베딩 모델을 최적화했습니다"

전체 형태소 → 임베딩 / 모델 / 을 / 최적화 / 하 / 았 / 습니다

"을", "하", "았", "습니다"는 검색에 쓸모가 없습니다. 그래서 의미를 가진 품사만 골라서 보존합니다:

  • 명사 (모델, 최적화, 검색, SQLite)

  • 동사/형용사 (구현하다, 빠르다)

  • 외국어 (embedding, vector, BM25)

조사, 어미, 접미사는 전부 버립니다. 1글자짜리 토큰도 노이즈가 되므로 제거합니다.

결과: "임베딩" "모델" "최적화" — 검색에 필요한 핵심만 남습니다. 최대한 노이즈를 배제하기 위해 명사, 동사/형용사, 외국어로 레이어링을 한겁니다. 벡터디비까지 가면 청크 품질이 결국 컨텍스트의 품질이 됩니다. 최대한 그리고 가능한 노이즈를 줄여야 합니다. (그리고 더 최근 트랜드는 대화 원문, RAG할 문서 그대로 DB에 넣고 거기서 형태소를 분리하거나 압축, 정리하는 레이어링을 하는 방식을 사용합니다. 노이즈가 얼마나 생기던 알고리즘을 바꿔서 리인덱싱 할 수 있는 장점이 있습니다)

sqlite-vec는 왜 안 썼나

원래 계획은 FTS5(텍스트 검색) + sqlite-vec(벡터 검색)을 SQLite 안에서 모두 해결하는 것이었습니다. (모두들 그러고 있으니까요!) 그런데 sqlite-vec가 제 맥에서 C 컴파일 에러가 났습니다. 아직 알파 버전(0.1)이라 플랫폼 호환성이 불안정했습니다.

결국 벡터 쪽은 다른 방식으로 풀었는데, 이건 관심있으신 분들이 계시면 텍스트 매칭만으로는 검색이 어려운 "의미가 비슷한 대화"를 찾기 위해 벡터 검색을 어떤식으로 구현했는지 썰(?)을 한번 풀어보겠습니다.

핵심은 외부 서비스 없이, SQLite 하나에 한국어 전문검색을 얹는 것이었습니다. Pre-Tokenization이라는 우회로를 쓰면 FTS5가 한국어를 모른다는 문제를 깔끔하게 넘길 수 있습니다.

기술

역할

선택 이유

SQLite FTS5

전문검색 + BM25 랭킹

제로 인프라, 단일 파일 DB

Lindera (ko-dic)

한국어 형태소 분석

Rust 네이티브, 외부 의존성 없음

Pre-Tokenization

FTS5에 한국어 지원 추가

C 확장 없이 실용적으로 해결

품사 필터링

검색 정밀도 향상

조사/어미 노이즈 제거

본 포스트는 안(no)바이브 작성입니다. 안심하고 읽으셔도 됩니다 😁 맨땅에 헤딩하는게 에이전틱 개발이 아닙니다. 경험을 통해 쌓아올린 인간지능의 도메인지식과 마구를 쓴 인공지능의 지치지 않는 정확한 작업의 이인삼각, 대환장콜라보입니다.

로그인한 회원만 댓글 등록이 가능합니다.

개발한당

KR | ID | EN
  • IDR
  • KOR
8.34 -0.01

2026.07.10 KEB 하나은행 고시회차 1218회

다가오는 한인 행사일정

  • 등록 된 일정이 없어요!