메모리 개요
Kumiho가 표준 저장소인 이유, NoneMemory 런타임 바인딩, 그리고 메모리 백엔드 선택 방법을 설명합니다.
Revka의 메모리는 두 계층으로 나뉩니다. Rust 런타임 수준에서는 Memory 트레이트가 있으며, 유일하게 연결된 구현체는 NoneMemory — 아무것도 저장하지 않는 no-op입니다. 영속적인 크로스 세션 메모리는 모두 Kumiho에 위임됩니다. Kumiho는 Model Context Protocol(MCP)을 통해 접근하는 그래프 기반 인지 메모리 백엔드입니다. 이 페이지에서는 해당 분리 구조를 설명합니다: 트레이트와 그 필드, 런타임 바인딩이 no-op인 이유, [memory] 설정 섹션의 동작 방식, 그리고 컨텍스트에 어떤 내용이 노출될지를 결정하는 분류 및 감쇠 규칙을 다룹니다.
메모리가 실제로 어디에 저장되는지 이해하거나 로컬 백엔드를 설정해도 아무것도 지속되지 않는 이유를 파악하려면 이 페이지를 먼저 읽으세요. 사이드카를 설치하고 에이전트를 Kumiho에 연결하려면 Kumiho 설정과 Kumiho 그래프 메모리로 이동하세요.
Kumiho가 표준 저장소인 이유
섹션 제목: “Kumiho가 표준 저장소인 이유”상태 비저장 LLM 호출은 반환되는 순간 모든 내용을 잊습니다. Revka는 이 문제를 로컬 데이터베이스가 아닌 Kumiho로 해결합니다. Kumiho는 Neo4j 기반의 지식 그래프로, Kumiho 컨트롤 플레인(클라우드) 또는 자체 호스팅 커뮤니티 에디션에서 운영됩니다. Kumiho MCP는 모든 비내부 에이전트에 사이드카로 주입되며, 에이전트의 도구 루프 내에서 그래프를 읽고 쓰는 kumiho_memory_* 도구(kumiho_memory_engage, kumiho_memory_reflect 등)를 제공합니다.
이는 의도적인 아키텍처 선택입니다: 크로스 세션 연속성, 타입화된 출처 엣지를 통한 그래프 구조 기반 회상, 그리고 여러 에이전트가 읽고 쓸 수 있는 공유 기반이 모두 하나의 표준 장소에 존재합니다. Rust 런타임은 상태 비저장을 유지합니다. 에이전트 측 사용 패턴(응답 전 engage, 응답 후 reflect)에 대해서는 Kumiho 그래프 메모리를 참고하세요.
Memory 트레이트
섹션 제목: “Memory 트레이트”Memory는 모든 메모리 백엔드가 구현해야 하는 인터페이스를 정의하는 비동기 Rust 트레이트입니다. 이는 내부 확장 포인트로, 직접적인 사용자 인터페이스가 아니며, 향후 커스텀 백엔드가 시스템의 나머지 부분을 건드리지 않고 슬롯에 끼워 넣을 수 있도록 존재합니다. 메서드는 다음과 같습니다:
store, recall, get, list, forget, count, health_check, store_procedural, recall_namespaced, export, store_with_metadata, purge_namespace, purge_session.
선택적 메서드(recall_namespaced, export, store_with_metadata, purge_namespace, purge_session)에는 기본 구현이 제공되므로, 백엔드는 네이티브로 지원하는 것만 재정의하면 됩니다. store 계열은 다음을 받습니다:
| 필드 | 타입 | 의미 |
|---|---|---|
key | &str | 항목의 고유 식별자. |
content | &str | 저장할 텍스트 내용. |
category | MemoryCategory | Core, Daily, Conversation, 또는 Custom(String). |
session_id | Option<&str> | 항목을 특정 세션으로 범위 지정. |
namespace | Option<&str> | 에이전트/컨텍스트 간 항목을 격리(기본값: "default"). |
importance | Option<f64> | 우선 검색을 위한 0.0–1.0 값. |
superseded_by | Option<String> | 폐기된 항목을 대체 항목에 연결. |
since / until | Option<&str> | recall 및 export에 적용되는 RFC 3339 시간 범위. |
NoneMemory — 런타임 바인딩
섹션 제목: “NoneMemory — 런타임 바인딩”NoneMemory는 Revka 런타임에 연결된 유일한 구체적 Memory 구현체입니다. 모든 작업은 조용히 성공합니다: 저장은 폐기되고, 회상은 빈 결과를 반환합니다. 트레이트는 향후 백엔드 추가를 위해 존재하지만, 현재 런타임은 no-op으로 처리되며 영속성은 전적으로 에이전트 수준의 Kumiho MCP에 맡깁니다.
두 가지 백엔드 이름이 NoneMemory로 처리됩니다:
[memory]backend = "kumiho" # 권장 — Kumiho MCP가 영속성 처리[memory]backend = "none" # 명시적 no-op그 외 백엔드 이름(예: sqlite, qdrant, lucid, markdown)은 시작 시 거부되며 Kumiho 사용을 안내하는 오류가 발생합니다.
[memory] 설정 섹션
섹션 제목: “[memory] 설정 섹션”[memory]는 ~/.revka/config.toml에 위치하며, 백엔드 선택과 세션 내 동작을 제어합니다: 자동 저장, 위생/보존, 응답 캐싱, 네임스페이스 격리, 그리고 메모리 정책입니다. 대표적인 블록 예시:
[memory]backend = "kumiho" # 또는 "none"auto_save = true # 사용자 메시지 자동 저장hygiene_enabled = true # 오래된 항목 아카이브/삭제archive_after_days = 7 # 아카이브 전 대기 일수purge_after_days = 30 # 아카이브된 항목 삭제 전 대기 일수conversation_retention_days = 30 # 대화 행 보존 일수min_relevance_score = 0.4 # 임계값 미만 항목은 컨텍스트에서 제외default_namespace = "default"
# 응답 캐시 (선택 사항)response_cache_enabled = false # 기본값: 비활성화response_cache_ttl_minutes = 60 # 항목별 TTLresponse_cache_max_entries = 5000response_cache_hot_entries = 256 # 인메모리 LRU 티어 크기
# 스냅샷 내보내기 (백업용)snapshot_enabled = falsesnapshot_on_hygiene = falseauto_hydrate = true
# 감사 추적audit_enabled = falseaudit_retention_days = 30
[memory.policy]max_entries_per_namespace = 0 # 0 = 무제한max_entries_per_category = 0read_only_namespaces = []# retention_days_by_category = { core = 365, daily = 30 }| 키 | 타입 | 기본값 | 의미 |
|---|---|---|---|
backend | string | "none" | 런타임 백엔드; "kumiho" 또는 "none"만 허용. |
auto_save | bool | true | 매 턴 후 사용자 입력 자동 저장(어시스턴트 출력 제외). |
hygiene_enabled | bool | false | 오래된 항목 아카이브 후 삭제. |
archive_after_days | int | 7 | 항목이 아카이브되기까지의 일수. |
purge_after_days | int | 30 | 아카이브된 항목이 삭제되기까지의 일수. |
conversation_retention_days | int | 30 | 최대 대화 기록 보존 기간. |
min_relevance_score | float | 0.4 | 이 값 미만의 항목은 컨텍스트에서 제외. |
default_namespace | string | "default" | 네임스페이스를 지정하지 않은 항목의 기본 네임스페이스. |
response_cache_enabled | bool | false | LLM 응답 캐시 활성화. |
audit_enabled | bool | false | 메모리 감사 추적 활성화. |
audit_retention_days | int | 30 | 감사 보존 기간. |
백엔드 선택지
섹션 제목: “백엔드 선택지”“백엔드”를 설명하는 두 가지 표면이 있으며, 이 둘은 다릅니다 — 어느 쪽을 보고 있는지 정확히 파악하는 것이 중요합니다:
- 런타임 백엔드(이 섹션). Rust 런타임이
[memory].backend에서 허용하는 값:"kumiho"와"none"만 가능하며 둘 다NoneMemory로 처리됩니다. 그 외 값은 시작 시 거부됩니다. - 온보딩 마법사 선택지.
revka onboard의 메모리 단계에서는 더 친화적인 메뉴를 제공합니다 — Kumiho 클라우드, Kumiho 로컬 CE(자체 호스팅 커뮤니티 에디션), 또는 없음. 클라우드/CE 구분은[memory]가 아닌[kumiho]블록의mode = "cloud"또는mode = "local_ce"로 설정합니다.
요약하면: 영속성 결정은 Kumiho 클라우드 vs. Kumiho CE vs. 없음 — [memory].backend는 Kumiho 경로의 활성화 여부만 토글하며, [kumiho].mode가 어떤 Kumiho와 통신할지를 선택합니다.
MemoryCategory
섹션 제목: “MemoryCategory”MemoryCategory는 모든 항목을 태그하고 필터링합니다. 소문자 문자열로 직렬화되며 네 가지 변형이 있습니다:
| 카테고리 | 직렬화 값 | 의미 | 시간 감쇠 |
|---|---|---|---|
Core | "core" | 상시 유효한 장기 사실. | 면제 — 항상 전체 점수 유지. |
Daily | "daily" | 세션 로그. | 지수적 감쇠. |
Conversation | "conversation" | 컨텍스트 내 교환. | 지수적 감쇠. |
Custom(String) | 그 외 문자열 | 사용자 정의 레이블. | 지수적 감쇠. |
캡처 시 카테고리를 설정하거나(kumiho_memory_reflect의 type을 통해) CLI에서 필터링합니다:
revka memory list --category corerevka memory list --category daily시간 감쇠 점수
섹션 제목: “시간 감쇠 점수”회상 점수는 시간이 지남에 따라 낮아집니다. Revka는 항목의 경과 일수를 기반으로 메모리의 관련성 점수에 지수 감쇠를 적용하므로, 오래된 대화 내용은 자연스럽게 컨텍스트에서 사라지고 상시 유효한 사실은 유지됩니다. 공식:
score × 2^(-age_days / half_life_days)- 기본 반감기는 7일(
DEFAULT_HALF_LIFE_DAYS = 7.0)이며half_life_days로 설정할 수 있습니다.0이하 값은 기본값으로 대체됩니다. Core메모리는 감쇠하지 않습니다 — 항상 전체 점수를 유지합니다.- 점수가 없는 항목(
score: None)과 타임스탬프를 파싱할 수 없는 항목은 변경되지 않습니다.
실질적 의미: Conversation 또는 Daily 메모리의 관련성은 7일 후 절반으로, 14일 후 약 25%로 줄어들지만, Core 메모리는 면제됩니다. min_relevance_score와 결합하면, 감쇠가 오래된 메모리가 여전히 컨텍스트에 포함될지를 결정합니다.
메모리 항목 필드
섹션 제목: “메모리 항목 필드”MemoryEntry는 recall, get, list, export가 반환하는 구조화된 레코드이며, JSON API 응답과 revka memory get <key> 출력에서 확인할 수 있는 형태입니다.
| 필드 | 타입 | 의미 |
|---|---|---|
id | String | UUID. |
key | String | 사람이 읽을 수 있는 식별자. |
content | String | 저장된 텍스트. |
category | MemoryCategory | 분류(위 참고). |
timestamp | String | RFC 3339 생성 시각. |
session_id | Option<String> | 범위 지정 세션(있는 경우). |
score | Option<f64> | 시간 감쇠가 적용되는 관련성 0.0–1.0. |
namespace | String | 기본값은 "default". |
importance | Option<f64> | 0.0–1.0; 높을수록 회상 시 우선 노출. |
superseded_by | Option<String> | 대체 항목으로의 링크. |
자동 저장과 합성 필터링
섹션 제목: “자동 저장과 합성 필터링”auto_save = true일 때, 사용자가 말한 대화 입력은 매 턴 후 자동으로 저장됩니다. 저장 전에 Revka는 합성/노이즈 패턴을 필터링하여 머신 생성 아티팩트가 메모리 그래프를 오염시키지 않도록 합니다. 다음은 절대 저장되지 않습니다:
- 크론 작업 메시지 —
[cron:...] - 하트비트 작업 —
[Heartbeat Task...] - 증류된 메모리 청크 —
[distilled_...], 또는distilled_index_sig:를 포함하는 내용 - 빈 문자열
- 어시스턴트 자동 저장 키 —
assistant_resp,assistant_resp_*
증류된 청크 필터는 요약 아티팩트(메모리 항목처럼 보이지만 합성인)가 실제 메모리로 저장되는 것을 방지합니다. assistant_resp* 필터는 레거시 보호 장치입니다: 과거 어시스턴트 출력의 자동 저장은 신뢰할 수 없음으로 처리되며, 시스템 프롬프트에 다시 주입되지 않습니다. 따라서 모델이 과거 자신의 출력을 검증된 사실인 것처럼 받을 수 없습니다. 자동 저장은 사용자 입력만 대상으로 하며 — 어시스턴트 출력은 설계상 제외됩니다.