메뉴
HN
Hacker News 55일 전

로컬 LLM을 위한 영구 기억 계층, Mnemo

IMP
7/10
핵심 요약

대화가 끝나면 모든 기억을 잃는 LLM의 한계를 극복하기 위해 개발된 로컬 우선(local-first) AI 메모리 계층입니다. SQLite와 petgraph를 활용해 오프라인 환경에서도 지식 그래프를 구축하고, 50ms 미만의 속도로 관련 문맥을 자동 추출하여 프롬프트에 주입합니다. 클라우드 없이 단일 바이너리로 작동하며, OpenAI, Anthropic, Ollama 등 다양한 환경과 호환된다는 것이 특징입니다.

번역된 본문

Mnemo: 모든 LLM을 위한 로컬 우선 AI 메모리 계층

주요 기능: 영구적인 지식 그래프 구축, 개체명 추출, 시맨틱 검색 기능을 제공하며 클라우드 연결이 필요하지 않습니다.

Mnemo란 무엇인가?

대부분의 LLM은 대화가 끝나는 순간 모든 것을 잊어버립니다. Mnemo는 이 문제를 해결합니다.

Mnemo는 사용자가 입력하는 모든 대화를 모니터링하는 사이드카 서비스(sidecar service)입니다. LLM을 활용해 명명된 개체와 관계를 추출하고, SQLite에 영구적인 지식 그래프를 구축하며, 50ms 이내에 관련 컨텍스트를 미래의 프롬프트에 자동으로 주입합니다. Ollama(완전한 로컬 및 무료), OpenAI, Anthropic 또는 OpenAI 호환 API와 함께 작동하며, 단일 정적 바이너리로 제공되어 클라우드 의존성이 전혀 없습니다.

작동 방식

사용자 애플리케이션
│
▼
POST /ingest ──► 개체 추출(LLM) ──► 지식 그래프(SQLite + petgraph)
│
POST /retrieve ◄── 점수 책정 + 순위 지정 ◄── 그래프 탐색 + 전체 텍스트 검색
│
▼
context_prompt ──► LLM 프롬프트에 주입
  1. 데이터 저장 (/ingest): 원시 텍스트(대화, 문서, 메모 등)를 POST 방식으로 전송합니다.
  2. 개체 추출: Mnemo는 구성된 LLM으로 텍스트를 전송하여 개체(사람, 도구, 장소, 개념)와 그 관계를 추출합니다. 개체는 이름+유형으로 중복 제거되고, 별칭이 병합되며, 모든 것이 SQLite에 기록됩니다. 메모리 내 petgraph는 원자적으로 업데이트됩니다.
  3. 데이터 검색 (/retrieve): Mnemo는 6단계 파이프라인(전체 텍스트 청크 검색 → 개체 이름 검색 → 그래프 확장(BFS) → 관계 필터링 → 점수 책정 및 순위 지정 → context_prompt 문자열 조립)을 실행합니다. 이렇게 생성된 context_prompt를 LLM의 시스템 프롬프트에 주입하면 과거 대화를 기억하는 LLM이 완성됩니다.

빠른 시작 가이드

방법 A — Docker + Ollama (완전 무료, 권장)

git clone https://github.com/zaydmulani09/mnemo
cd mnemo
docker compose up -d

# 첫 실행 시 llama3 모델 다운로드(약 4GB)
docker exec mnemo-ollama ollama pull llama3

# 시스템 상태 확인
curl http://localhost:8080/health

방법 B — 바이너리 실행 (Ollama 또는 OpenAI 별도 실행 필요)

cargo install --path crates/mnemo-api

# Ollama 사용 시
export MNEMO_LLM_BASE_URL=http://localhost:11434/v1
mnemo-api

# OpenAI 사용 시
export MNEMO_LLM_BASE_URL=https://api.openai.com/v1
export MNEMO_LLM_API_KEY=sk-...
export MNEMO_LLM_MODEL=gpt-4o-mini
export MNEMO_LLM_PROVIDER=openai
mnemo-api

방법 C — Python SDK

pip install mnemo-sdk
from mnemo import MnemoClient

client = MnemoClient() # 기본 서버 주소: http://localhost:8080

# 기억 저장
client.ingest("Rust로 vecdb라는 벡터 데이터베이스를 만들고 있어.")

# 다음 LLM 프롬프트에 주입할 컨텍스트 가져오기
print(client.get_context("내가 지금 무슨 작업을 하고 있지?"))

API 참조

모든 엔드포인트는 application/json 형식을 받고 반환합니다. 기본 URL: http://localhost:8080

  • GET /health: 서버, DB, LLM 상태를 확인합니다.
  • POST /ingest: 텍스트를 저장하고 개체를 추출합니다.
  • POST /retrieve: 순위가 지정된 메모리 컨텍스트를 검색합니다.
  • GET /entities: 개체 목록을 페이지네이션하여 조회합니다.
  • GET /entities/:id: UUID로 특정 개체를 조회합니다.
  • DELETE /entities/:id: 특정 개체 및 연관 데이터를 삭제합니다.
  • GET /entities/:id/neighbors: 지식 그래프 내 이웃 노드를 조회합니다.
  • GET /chunks: 메모리 청크 목록을 페이지네이션하여 조회합니다.
  • GET /chunks/:id: UUID로 특정 메모리 청크를 조회합니다.
  • DELETE /chunks/:id: 특정 메모리 청크를 삭제합니다.
  • POST /search: 개체 및 청크에 대한 전체 텍스트 검색을 수행합니다.
  • DELETE /wipe: 헤더(X-Confirm-Wipe: true) 확인 시 모든 메모리를 영구 삭제합니다.
  • GET /stats: 개체/청크/그래프 수 및 가동 시간(uptime) 통계를 제공합니다.

주요 요청/응답 데이터 구조:

// 데이터 저장 요청 (IngestRequest)
{
  "content": "string", // 필수 — 저장할 텍스트
  "source": "string", // 필수 — 출처(예: "chat", "email", "cli")
  "session_id": "string|null", // 선택 — 관련 청크를 그룹화하는 세션 ID
  "metadata": {} // 선택 — 임의의 JSON 데이터
}

// 컨텍스트 검색 요청 (RetrievalQuery)
{
  "text": "string", // 필수 — 쿼리 텍스트
  "session_id": "string|null", // 선택 — 특정 세션으로 필터링
  "max_chunks": 10, // 기본값 10
  "max_entities": 20, // 기본값 20
  "min_conf": 0.5 // 최소 신뢰도 임계값
}
원문 보기
원문 보기 (영어)
mnemo Local-first AI memory layer for any LLM. Persistent knowledge graph, entity extraction, semantic retrieval — no cloud required. What is mnemo? Most LLMs forget everything the moment a conversation ends. mnemo fixes that. mnemo is a sidecar service that watches every conversation you feed it, extracts named entities and relationships using an LLM, builds a persistent knowledge graph in SQLite, and injects relevant context back into future prompts — automatically, in under 50ms. It works with Ollama (fully local, free), OpenAI, Anthropic, or any OpenAI-compatible API. It ships as a single static binary with zero cloud dependency. How it works your app │ ▼ POST /ingest ──► entity extraction (LLM) ──► knowledge graph (SQLite + petgraph) │ POST /retrieve ◄── scoring + ranking ◄── graph traversal + full-text search │ ▼ context_prompt ──► inject into your LLM prompt You POST raw text to /ingest (a conversation turn, a document, a note). mnemo sends it to your configured LLM and extracts entities (people, tools, places, concepts) and the relationships between them. Entities are deduplicated by name+type, aliases are merged, and everything is written to SQLite. The in-memory petgraph is updated atomically. On POST /retrieve , mnemo runs a 6-stage pipeline: full-text chunk search → entity name search → graph expansion (BFS over the knowledge graph) → relation filter → score+rank → assemble a context_prompt string. You inject context_prompt into your LLM's system prompt. Done. Quickstart Path A — Docker + Ollama (fully free, recommended) git clone https://github.com/zaydmulani09/mnemo cd mnemo docker compose up -d # Pull the llama3 model the first time (~4 GB) docker exec mnemo-ollama ollama pull llama3 # Verify everything is healthy curl http://localhost:8080/health Path B — Binary (Ollama or OpenAI running separately) cargo install --path crates/mnemo-api # With Ollama export MNEMO_LLM_BASE_URL=http://localhost:11434/v1 mnemo-api # With OpenAI export MNEMO_LLM_BASE_URL=https://api.openai.com/v1 export MNEMO_LLM_API_KEY=sk-... export MNEMO_LLM_MODEL=gpt-4o-mini export MNEMO_LLM_PROVIDER=openai mnemo-api Path C — Python SDK pip install mnemo-sdk from mnemo import MnemoClient client = MnemoClient () # server at http://localhost:8080 # Store a memory client . ingest ( "I'm building a Rust vector database called vecdb" ) # Get context for injection into your next LLM prompt print ( client . get_context ( "what am I working on?" )) API Reference All endpoints accept and return application/json . Base URL: http://localhost:8080 . Method Path Description Request body Response GET /health Server + DB + LLM status — HealthResponse POST /ingest Store text, extract entities IngestRequest IngestResponse POST /retrieve Retrieve ranked memory context RetrievalQuery RetrievalResult GET /entities List entities (paginated) ?limit&offset Entity[] GET /entities/:id Get entity by UUID — Entity DELETE /entities/:id Delete entity (cascades) — {"deleted":true} GET /entities/:id/neighbors Knowledge graph neighbors ?depth (max 5) GraphNode[] GET /chunks List memory chunks (paginated) ?limit&offset&session_id MemoryChunk[] GET /chunks/:id Get chunk by UUID — MemoryChunk DELETE /chunks/:id Delete chunk — {"deleted":true} POST /search Full-text search entities + chunks {"query","limit"} {"entities","chunks"} DELETE /wipe Delete all memory (irreversible) header: X-Confirm-Wipe: true {"wiped":true} GET /stats Entity/chunk/graph counts + uptime — StatsResponse Key request/response types: // IngestRequest { "content" : " string " , // required — text to store "source" : " string " , // required — e.g. "chat", "email", "cli" "session_id" : " string|null " , // optional — group related chunks "metadata" : {} // optional — arbitrary JSON } // RetrievalQuery { "text" : " string " , // required — query text "session_id" : " string|null " , // optional — filter by session "max_chunks" : 10 , // default 10 "max_entities" : 20 , // default 20 "min_confidence" : 0.5 , // default 0.5 "include_graph" : true , // default true — expand via knowledge graph "graph_depth" : 2 // default 2 — BFS depth for graph expansion } Full endpoint documentation with curl examples: docs/api.md Configuration Environment variables Variable Default Description MNEMO_DB_PATH mnemo.db SQLite database file path MNEMO_PORT 8080 API server port MNEMO_LLM_BASE_URL http://localhost:11434/v1 OpenAI-compatible LLM base URL MNEMO_LLM_MODEL llama3 Model name for entity extraction MNEMO_LLM_API_KEY ollama API key (any value works for Ollama) MNEMO_LLM_PROVIDER ollama Provider type: ollama , openai , anthropic , custom TOML config file Pass --config path/to/config.toml to mnemo-api . See mnemo.example.toml : db_path = " mnemo.db " port = 8080 [ llm ] provider = " ollama " base_url = " http://localhost:11434/v1 " model = " llama3 " api_key = " ollama " timeout_secs = 30 max_retries = 3 max_tokens = 2048 temperature = 0.1 Environment variables take precedence over TOML values. The active config source is reported in GET /health → config_source . CLI Install: cargo install --path crates/mnemo-cli Usage: # Store a memory mnemo ingest " I use Neovim and prefer dark mode " # Retrieve relevant context mnemo search " what editor do I use? " # List all extracted entities mnemo entities # Show entity detail + graph neighbors mnemo entity < uuid > --neighbors # List memory chunks mnemo chunks # Server health mnemo health # Memory statistics mnemo stats # Delete everything (prompts for confirmation) mnemo wipe # Skip confirmation prompt mnemo wipe --yes # Point at a non-default server mnemo --server http://192.168.1.10:8080 stats Python SDK Install: pip install mnemo-sdk See sdk/python/README.md for the full API reference. Async example: import asyncio from mnemo import AsyncMnemoClient async def main (): async with AsyncMnemoClient () as client : await client . ingest ( "Alice is a principal engineer at Stripe working on payment infrastructure." , session_id = "session-001" , ) context = await client . get_context ( "what does Alice work on?" , session_id = "session-001" , ) print ( context ) asyncio . run ( main ()) A working standalone example: examples/basic_usage.py Architecture Four Rust crates wired together: Crate Type Role mnemo-core lib Entity extraction, graph ops, retrieval engine, DB layer mnemo-api bin Axum REST API — thin handler layer over mnemo-core mnemo-cli bin CLI tool using blocking reqwest against the API mnemo-bench bin Performance benchmarks (12 suites) Full architecture documentation: docs/architecture.md Performance Benchmarked on Apple M2, SQLite WAL mode, in-memory petgraph. Debug build numbers — release build ( --release ) is 3–5× faster. Operation Avg latency Throughput Entity insert (SQLite) ~0.12 ms ~8,300 ops/s Entity lookup by ID ~0.08 ms ~12,500 ops/s Chunk insert ~0.14 ms ~7,100 ops/s Full-text chunk search ~0.28 ms ~3,500 ops/s Graph neighbor (depth=1) ~0.21 ms ~4,700 ops/s Graph neighbor (depth=2) ~0.89 ms ~1,100 ops/s Full retrieval pipeline ~4.2 ms ~238 ops/s Run cargo run -p mnemo-bench to benchmark on your hardware. Testing Rust cargo test --workspace # run all 122 tests make coverage # HTML coverage report (requires cargo-llvm-cov) make coverage-summary # summary to stdout Python SDK cd sdk/python && pytest tests/ -v Benchmarks cargo run -p mnemo-bench # all 12 benchmarks cargo run -p mnemo-bench -- --filter graph # graph benchmarks only cargo run -p mnemo-bench -- --json out.json # save results to JSON Current test counts: 122 Rust tests · 21 Python tests · 12 benchmarks Contributing PRs welcome. Please run make fmt && make lint before submitting. Open an issue first for large changes. See CONTRIBUTING.md for full setup instructions, code style guide, and how to add a new LLM provider. License MIT — see LICENSE