AI 코딩 에이전트가 세션마다 기억을 잃는 문제, 로컬 Rust 서비스 하나로 풀었다 — memnest

한 줄 요약
memnest는 localhost에서 도는 Rust 서비스 하나가 AI 코딩 에이전트의 기억을 대신 들고 있다가, 요청하는 에이전트에게 돌려주는 로컬 메모리 서비스입니다. 저장소와 툴 계약이 하나라서 도구를 바꿔도 에이전트가 아는 내용이 초기화되지 않습니다. MIT 라이선스이고, LLM API 호출은 전혀 없습니다.
어떤 불편에서 출발했나
에이전트와 함께 일해 보신 분이라면 익숙한 장면일 겁니다.
- 서비스가 어느 포트에서 도는지 매번 다시 설명
- 왜 하필 이 라이브러리를 골랐는지 매번 다시 설명
- 두 번이나 고쳤던 그 버그의 해결책을 또 다시 설명
하네스마다 반쪽짜리 메모리 기능이 붙어 있긴 하지만, 다른 도구로 넘어가는 순간 그대로 사라진다는 게 핵심 문제였습니다. 기억이 도구에 묶여 있으니 도구를 바꾸면 기억도 함께 날아가는 구조죠.
붙는 방식
메모리를 도구 바깥으로 꺼내서, 여러 클라이언트가 같은 저장소를 바라보게 했습니다.
| 클라이언트 | 연결 방식 | | --- | --- | | pi | 확장(extension) | | Claude Code, Codex | MCP + 프롬프트 훅 | | 그 외 MCP 클라이언트 | 동일 엔드포인트 |
설계에서 눈여겨볼 지점
1. LLM을 전혀 호출하지 않습니다
임베딩은 multilingual-e5-base로 로컬에서 돕니다. 제작자의 표현을 그대로 옮기면, *"내가 쓴 메모를 읽는 데 API 키가 필요한 메모리 시스템은 이상하다"*는 관점입니다. 개인 개발 맥락이 통째로 외부로 나가지 않는다는 점에서 프라이버시 측면의 이점이 분명합니다.
2. SQLite가 진실의 원본, 색인은 파생물
- SQLite = source of truth
- Tantivy BM25 색인, HNSW 벡터 색인 = 언제든 다시 만들 수 있는 파생물
인덱싱 작업은 레코드와 같은 트랜잭션에 기록되고, 두 색인이 모두 디스크에 안착한 뒤에야 삭제됩니다. 덕분에 중간에 끊긴 쓰기는 색인을 조용히 잃는 대신 재시작 때 다시 재생됩니다. 크래시 이후에 검색 결과가 슬그머니 비는 사고를 막는 설계입니다.
3. 색인이 두 개인 이유: 실패하는 방식이 다르다
이 부분이 개인적으로 가장 설득력 있었습니다.
- BM25: 포트 번호, 크레이트 이름 같은 정확한 토큰은 잘 찾지만 바꿔 말한 문장은 놓칩니다.
- 벡터 검색: 바꿔 말한 문장은 찾지만 정작 내가 입력한 문자열에서 멀어집니다.
어느 쪽이 필요한지는 질의 시점에만 알 수 있습니다. 그래서 쓰기 경로가 두 색인을 모두 부담하고, 결과는 RRF(k=60) 로 합친 뒤 MMR(lambda=0.5) 로 다시 정렬합니다.
4. 원문 그대로 보관, 요약 없음
- 일부러 저장한 기억(결정 · 선호 · 교정)
- 민감정보를 가린 대화 기록
이 둘을 분리해 보관하되, 어느 쪽도 LLM 요약을 거치지 않고 원문 그대로 남습니다. 요약 과정에서 디테일이 뭉개지는 걸 피한 선택입니다.
5. 자격증명은 검색 대상 밖으로
자격증명은 검색에서 아예 빠져 AES-256-GCM 금고에 들어가고, 자격증명처럼 생긴 텍스트는 쓰기 경로에서 미리 마스킹됩니다.
채택하지 않은 실험까지 공개
벤치마크 문서에 "안 쓰기로 한 것"도 그대로 적어둔 점이 인상적입니다.
- CJK 2~3글자 ngram 토크나이저: 고립 실험에서 부분어 어휘 재현율을 0.167 → 1.000으로 끌어올렸지만, 실제 46개 질의 픽스처에서는 개선이 없었고 색인 크기만 2.9배가 되어 껐습니다.
- Jina 교차 인코더 리랭커: 알려진 순위 오류 5건을 전부 고쳤지만, 모델 캐시 1.1GB와 웜 초기화 35초를 요구해 껐습니다.
벤치마크에서 좋아 보이는 수치가 실제 워크로드에서는 그대로 재현되지 않는다는, 검색 시스템의 전형적인 교훈이 잘 드러납니다.
아직 약한 지점: 후보 기각
제작자가 직접 밝힌 현재 최대 약점입니다. 한국어 픽스처 기준으로,
recall@1= 0.976 (찾아야 할 걸 찾는 능력은 충분)no-result정확도 = 0.200 (아무것도 반환하지 말아야 할 질의 5개 중 4개가 여전히 신뢰도 낮은 기억을 반환)
즉 "모른다"고 말하는 능력이 아직 부족합니다. 에이전트 메모리에서는 엉뚱한 기억을 자신 있게 꺼내는 쪽이 아무것도 안 꺼내는 쪽보다 위험할 수 있어서, 다음 개선 대상으로 지목된 상태입니다.
설치와 라이선스
- 라이선스: MIT
- 릴리스 바이너리: Linux x86_64 / aarch64
- 설치 스크립트: Windows, WSL
제작자는 "설계가 어디서 틀렸는지 알려주시면 반갑겠습니다" 라며 피드백을 요청하고 있습니다. 검색·랭킹이나 로컬 에이전트 인프라에 관심 있는 분이라면 벤치마크 문서부터 열어보시길 권합니다.