|
| 1 | +# AIMemory Architecture |
| 2 | + |
| 3 | +> mcp-memory-server 내부 구조와 설계 결정을 설명하는 기술 문서 |
| 4 | +
|
| 5 | +## 시스템 개요 |
| 6 | + |
| 7 | +AIMemory는 AI 어시스턴트에 **영구적이고 자기 관리되는 기억**을 부여하는 MCP 서버입니다. |
| 8 | + |
| 9 | +기존 `.md` 파일 기반 기억의 두 가지 한계를 해결합니다: |
| 10 | + |
| 11 | +1. **수동 검색 문제** — `.md`에 적어둬도 AI가 매번 확인하지 않음 |
| 12 | +2. **토큰 낭비 문제** — 전체 파일을 context에 넣으면 불필요한 내용까지 포함 |
| 13 | + |
| 14 | +## 아키텍처 다이어그램 |
| 15 | + |
| 16 | +``` |
| 17 | +┌──────────────────────────────────────────────────────┐ |
| 18 | +│ MCP Client │ |
| 19 | +│ (Claude Desktop / Claude Code) │ |
| 20 | +└──────────────────────┬───────────────────────────────┘ |
| 21 | + │ stdio (JSON-RPC) |
| 22 | +┌──────────────────────▼───────────────────────────────┐ |
| 23 | +│ FastMCP Server (12 tools) │ |
| 24 | +│ src/aimemory/mcp/server.py │ |
| 25 | +├──────────────────────────────────────────────────────┤ |
| 26 | +│ MemoryBridge (orchestrator) │ |
| 27 | +│ src/aimemory/mcp/bridge.py │ |
| 28 | +├─────────┬───────────┬───────────┬────────────────────┤ |
| 29 | +│ Decision│ Retrieval │ Storage │ Maintenance │ |
| 30 | +│ Layer │ Layer │ Layer │ Layer │ |
| 31 | +├─────────┼───────────┼───────────┼────────────────────┤ |
| 32 | +│ Online │ Graph │ Graph │ Sleep Cycle │ |
| 33 | +│ Policy │ Retriever │ Memory │ Runner │ |
| 34 | +│ + Agent │ (GraphRAG)│ Store │ │ |
| 35 | +│ │ │ (ChromaDB)│ ├─ Consolidation │ |
| 36 | +│ ReRanker│ Knowledge │ │ ├─ Forgetting │ |
| 37 | +│ (11d) │ Graph │ │ ├─ Resolution Regen │ |
| 38 | +│ │ (NetworkX)│ │ └─ Checkpoint │ |
| 39 | +│ Feedback│ │ │ │ |
| 40 | +│ Detector│ Context │ │ │ |
| 41 | +│ │ Composer │ │ │ |
| 42 | +└─────────┴───────────┴───────────┴────────────────────┘ |
| 43 | +``` |
| 44 | + |
| 45 | +## 6개 레이어 상세 |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +### Layer 1: Decision — RL 메모리 정책 |
| 50 | + |
| 51 | +**파일**: `src/aimemory/online/policy.py`, `enhanced_policy.py` |
| 52 | + |
| 53 | +매 대화 턴마다 **SAVE / SKIP / RETRIEVE** 중 하나를 결정합니다. |
| 54 | + |
| 55 | +#### 3단계 결정 파이프라인 |
| 56 | + |
| 57 | +``` |
| 58 | +사용자 메시지 입력 |
| 59 | + │ |
| 60 | + ▼ |
| 61 | +Phase 0: RETRIEVE 판단 (rule-based) |
| 62 | + 질문 패턴? discourse marker? → 저장된 메모리 있으면 RETRIEVE |
| 63 | + │ |
| 64 | + ▼ |
| 65 | +Phase 1: 고/저확신 직접 결정 (rule-based) |
| 66 | + importance ≥ 0.7 → SAVE (개인정보, 강한 선호 등) |
| 67 | + importance ≤ 0.1 → SKIP (인사, 짧은 응답 등) |
| 68 | + │ |
| 69 | + ▼ |
| 70 | +Phase 2: 중간 영역 → MLP Bandit 결정 |
| 71 | + 10d feature vector → Linear(10,64) → ReLU → Linear(64,3) |
| 72 | + epsilon-greedy (ε=0.1) action selection |
| 73 | +``` |
| 74 | + |
| 75 | +#### Importance 가중합 |
| 76 | + |
| 77 | +| 패턴 | 가중치 | 예시 | |
| 78 | +|------|--------|------| |
| 79 | +| 개인정보 | +0.4 | "내 이름은...", "나는 서울에 살아" | |
| 80 | +| 선호 | +0.35 | "나는 Python을 좋아해" | |
| 81 | +| 기술 | +0.3 | "React 18에서 Suspense는..." | |
| 82 | +| 감정 | +0.2 | "요즘 번아웃이 심해" | |
| 83 | +| 키워드 밀도 | +0.15 | 명사 비율이 높은 문장 | |
| 84 | + |
| 85 | +#### StateEncoder (10d feature vector) |
| 86 | + |
| 87 | +``` |
| 88 | +[turn_position, memory_count, keyword_count, is_question, |
| 89 | + has_personal_info, has_preference, has_tech, has_emotion, |
| 90 | + recent_save_count, recent_retrieve_count] |
| 91 | +``` |
| 92 | + |
| 93 | +#### Enhanced Policy (opt-in) |
| 94 | + |
| 95 | +- 778d state: SentenceTransformer 768d + hand-crafted 10d |
| 96 | +- 더 큰 MLP: 778d → 256 → 128 → 3 (dropout 0.1) |
| 97 | +- Experience Replay Buffer (capacity=5000, batch=32) |
| 98 | +- Progressive Autonomy: 긍정 피드백 누적 → RL 영역 점진적 확장 |
| 99 | + |
| 100 | +--- |
| 101 | + |
| 102 | +### Layer 2: Retrieval — GraphRAG 하이브리드 검색 |
| 103 | + |
| 104 | +**파일**: `src/aimemory/memory/graph_retriever.py`, `online/reranker.py` |
| 105 | + |
| 106 | +#### 검색 파이프라인 |
| 107 | + |
| 108 | +``` |
| 109 | +사용자 메시지 |
| 110 | + │ |
| 111 | + ├─→ ChromaDB 벡터 검색 (cosine similarity) |
| 112 | + │ 상위 20개 후보 (reranker_pool_size) |
| 113 | + │ |
| 114 | + ├─→ KnowledgeGraph 탐색 (opt-in) |
| 115 | + │ 엔티티 추출 → multi-hop traversal |
| 116 | + │ |
| 117 | + ▼ |
| 118 | +Score Fusion: final = vector × 0.6 + graph × 0.4 |
| 119 | + │ |
| 120 | + ▼ |
| 121 | +RL Re-ranker (11d feature → 32h → 1 score) |
| 122 | + │ |
| 123 | + ▼ |
| 124 | +Context Composer (token budget 내 top-K 선별) |
| 125 | +``` |
| 126 | + |
| 127 | +#### Re-ranker Features (11d) |
| 128 | + |
| 129 | +| # | Feature | 설명 | |
| 130 | +|---|---------|------| |
| 131 | +| 0 | chroma_similarity | 원본 벡터 유사도 | |
| 132 | +| 1 | keyword_overlap | 쿼리-메모리 키워드 Jaccard | |
| 133 | +| 2 | category_match | 추론된 카테고리 일치 | |
| 134 | +| 3 | recency | 카테고리별 시간 감쇠 | |
| 135 | +| 4 | access_frequency | log1p(access_count) | |
| 136 | +| 5 | content_length_ratio | 정규화된 길이 비율 | |
| 137 | +| 6 | has_related | 그래프 연결 여부 | |
| 138 | +| 7 | resolution_available | 가용 해상도 수 | |
| 139 | +| 8 | graph_connection_count | KG 엔티티 연결 수 | |
| 140 | +| 9 | graph_hop_distance | KG 홉 거리 | |
| 141 | +| 10 | has_negative_relation | 부정 관계 여부 | |
| 142 | + |
| 143 | +#### Context Composer — 다해상도 선택 |
| 144 | + |
| 145 | +토큰 budget(기본 1024) 내에서 MMR(Maximal Marginal Relevance) 알고리즘으로 다양성과 관련성을 균형 있게 선택합니다. |
| 146 | + |
| 147 | +``` |
| 148 | +메모리 A: Level 0 (전문 60토큰) → budget 초과 시 Level 1 (요약 25토큰) → Level 2 (트리플 10토큰) |
| 149 | +메모리 B: Level 0 (전문 40토큰) → budget 내이면 그대로 사용 |
| 150 | +``` |
| 151 | + |
| 152 | +3가지 해상도: |
| 153 | +- **Level 0**: 원문 그대로 |
| 154 | +- **Level 1**: 키워드 포함 1-2문장 요약 (max 100자) |
| 155 | +- **Level 2**: entity triple (subject, predicate, object) |
| 156 | + |
| 157 | +--- |
| 158 | + |
| 159 | +### Layer 3: Storage — GraphMemoryStore |
| 160 | + |
| 161 | +**파일**: `src/aimemory/memory/graph_store.py`, `knowledge_graph.py` |
| 162 | + |
| 163 | +#### MemoryNode 구조 |
| 164 | + |
| 165 | +```python |
| 166 | +MemoryNode( |
| 167 | + memory_id="a1b2c3d4e5f6", # 12-char hex |
| 168 | + content="사용자는 Python을 좋아함", |
| 169 | + keywords=["Python", "선호"], |
| 170 | + category="preference", # fact/preference/experience/emotion/technical/core_principle |
| 171 | + related_ids=["x1y2z3..."], # 양방향 그래프 엣지 |
| 172 | + created_at="2026-02-28T...", |
| 173 | + access_count=5, # 검색 시 자동 증가 |
| 174 | + level1_text="Python 선호", # Level 1 요약 |
| 175 | + level2_text="사용자,좋아함,Python", # Level 2 트리플 |
| 176 | + immutable=False, # True이면 수정/삭제 불가 |
| 177 | + pinned=False, # True이면 망각 보호 |
| 178 | + active=True, # False이면 검색 제외 |
| 179 | +) |
| 180 | +``` |
| 181 | + |
| 182 | +#### ChromaDB 설정 |
| 183 | + |
| 184 | +- Embedding model: `intfloat/multilingual-e5-small` (384d, 한/영 지원) |
| 185 | +- Distance metric: cosine (HNSW) |
| 186 | +- 영속 저장: SQLite 기반 (서버 재시작 후에도 유지) |
| 187 | + |
| 188 | +#### KnowledgeGraph (NetworkX DiGraph) |
| 189 | + |
| 190 | +Level 2 텍스트(`subject,predicate,object`)를 자동 파싱하여 엔티티-관계 그래프를 구축합니다. |
| 191 | + |
| 192 | +``` |
| 193 | +사용자 ──좋아함──→ Python |
| 194 | +사용자 ──싫어함──→ Java |
| 195 | +Python ──관련──→ FastAPI |
| 196 | +``` |
| 197 | + |
| 198 | +- multi-hop 탐색 (깊이 1~3) |
| 199 | +- 부정 관계 감지 ("싫어함", "dislike" 등) |
| 200 | +- 메모리 저장/삭제 시 자동 동기화 |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +### Layer 4: Maintenance — 수면 사이클 |
| 205 | + |
| 206 | +**파일**: `src/aimemory/memory/sleep_cycle.py`, `forgetting.py`, `consolidation.py` |
| 207 | + |
| 208 | +주기적으로 실행되는 4단계 유지보수: |
| 209 | + |
| 210 | +``` |
| 211 | +Sleep Cycle |
| 212 | + │ |
| 213 | + ├─ 1. Consolidation (통합) |
| 214 | + │ 유사도 ≥ 0.92인 메모리 쌍 탐지 → 병합 |
| 215 | + │ access_count 높은 쪽이 생존 |
| 216 | + │ |
| 217 | + ├─ 2. Resolution Regeneration (해상도 재생성) |
| 218 | + │ level1_text / level2_text 누락된 메모리 재생성 |
| 219 | + │ |
| 220 | + ├─ 3. Forgetting (망각) |
| 221 | + │ importance = (1 + access_count) × e^(-λ×days) + related_boost × edges |
| 222 | + │ |
| 223 | + │ importance < 0.3 → Level 2로 압축 |
| 224 | + │ importance < 0.1 → 비활성화 (검색 제외) |
| 225 | + │ 비활성 30일 경과 → 영구 삭제 + 감사 기록 |
| 226 | + │ |
| 227 | + │ ※ pinned / immutable 메모리는 보호됨 |
| 228 | + │ |
| 229 | + └─ 4. Checkpoint (체크포인트) |
| 230 | + RL 모델 파라미터 저장 |
| 231 | +``` |
| 232 | + |
| 233 | +--- |
| 234 | + |
| 235 | +### Layer 5: Reward — 보상 신호 |
| 236 | + |
| 237 | +**파일**: `src/aimemory/reward/`, `online/reranker.py` |
| 238 | + |
| 239 | +RL 정책을 실시간으로 개선하기 위한 보상 수집: |
| 240 | + |
| 241 | +#### 명시적 피드백 (FeedbackDetector) |
| 242 | + |
| 243 | +한국어/영어 패턴으로 사용자 피드백 감지: |
| 244 | +- 긍정: "맞아", "좋아", "exactly", "perfect" → +1.0 |
| 245 | +- 부정: "아니야", "틀렸어", "wrong", "no" → -1.0 |
| 246 | + |
| 247 | +#### 암묵적 보상 (ImplicitRewardDetector) |
| 248 | + |
| 249 | +대화 흐름 패턴으로 보상 추론: |
| 250 | +- 대화 지속 (2+ 턴 이어감) → +0.3 |
| 251 | +- 화제 확장 (기억 키워드 재등장) → +0.2 |
| 252 | +- 짧은 무관심 응답 → -0.1 |
| 253 | + |
| 254 | +--- |
| 255 | + |
| 256 | +### Layer 6: P2P Federated Learning (opt-in) |
| 257 | + |
| 258 | +**파일**: `src/aimemory/online/gossip.py`, `transport.py`, `rule_verifier.py` |
| 259 | + |
| 260 | +여러 사용자의 RL 정책을 P2P로 공유하여 학습 속도 향상: |
| 261 | + |
| 262 | +``` |
| 263 | +Node A ←──gossip──→ Node B ←──gossip──→ Node C |
| 264 | + │ │ │ |
| 265 | + └── 각자의 OnlinePolicy 파라미터 교환 ──┘ |
| 266 | +``` |
| 267 | + |
| 268 | +#### 보안 |
| 269 | + |
| 270 | +- **L2 Norm Clipping**: 파라미터 업데이트 크기 제한 |
| 271 | +- **Differential Privacy**: Gaussian noise 추가 (선택적) |
| 272 | +- **Krum Aggregation**: Byzantine-tolerant 집계 (악의적 노드 필터링) |
| 273 | +- **Rule Hash Verification**: SHA-256으로 보안 규칙 변조 탐지 |
| 274 | + |
| 275 | +--- |
| 276 | + |
| 277 | +## MCP 도구 (12개) |
| 278 | + |
| 279 | +| 도구 | 레이어 | 설명 | |
| 280 | +|------|--------|------| |
| 281 | +| `auto_search` | Retrieval | 매 턴 관련 기억 자동 검색 + 다해상도 컨텍스트 조합 | |
| 282 | +| `memory_save` | Storage | 새 기억 저장 (키워드, 카테고리, 관계 지정) | |
| 283 | +| `memory_search` | Retrieval | 시맨틱 유사도 검색 | |
| 284 | +| `memory_update` | Storage | 기존 기억 내용/키워드 수정 | |
| 285 | +| `memory_delete` | Storage | 기억 삭제 (immutable 존중) | |
| 286 | +| `memory_get_related` | Retrieval | BFS 그래프 탐색 (depth 1~3) | |
| 287 | +| `memory_pin` | Storage | 망각 보호 설정 | |
| 288 | +| `memory_unpin` | Storage | 망각 보호 해제 | |
| 289 | +| `memory_stats` | Storage | 총 개수 + 카테고리별 분포 | |
| 290 | +| `sleep_cycle_run` | Maintenance | 수면 사이클 실행 (통합+망각+체크포인트) | |
| 291 | +| `policy_status` | Decision | RL 정책 상태 (epsilon, action 분포, 업데이트 수) | |
| 292 | +| `policy_decide` | Decision | RL 정책 결정 트레이스 (SAVE/SKIP/RETRIEVE + 이유) | |
| 293 | + |
| 294 | +--- |
| 295 | + |
| 296 | +## 설정 |
| 297 | + |
| 298 | +### 환경변수 |
| 299 | + |
| 300 | +| 변수 | 기본값 | 설명 | |
| 301 | +|------|--------|------| |
| 302 | +| `AIMEMORY_DB_PATH` | `./memory_db` | ChromaDB 저장 경로 | |
| 303 | +| `AIMEMORY_LANGUAGE` | `ko` | 패턴 매칭 언어 (`ko`/`en`) | |
| 304 | +| `AIMEMORY_EMBEDDING_MODEL` | `intfloat/multilingual-e5-small` | 임베딩 모델 | |
| 305 | +| `AIMEMORY_LOG_LEVEL` | `INFO` | 로깅 레벨 | |
| 306 | +| `AIMEMORY_ENHANCED_POLICY` | `0` | Enhanced RL 정책 활성화 | |
| 307 | +| `AIMEMORY_GRAPH_RAG` | `0` | GraphRAG 하이브리드 검색 활성화 | |
| 308 | + |
| 309 | +### Config 클래스 체계 |
| 310 | + |
| 311 | +``` |
| 312 | +AppConfig |
| 313 | +├── OnlinePolicyConfig — RL 정책 (thresholds, epsilon, lr) |
| 314 | +├── ReRankerConfig — Re-ranker (feature_dim, latency budget) |
| 315 | +├── MCPServerConfig — MCP 서버 (token_budget, top_k) |
| 316 | +├── ForgettingConfig — 망각 파이프라인 (thresholds, decay_lambda) |
| 317 | +├── ComposerConfig — Context Composer (budget, level별 평균 토큰) |
| 318 | +├── SleepCycleConfig — 수면 사이클 (간격, 리포트 저장) |
| 319 | +├── GossipConfig — P2P 학습 (interval, DP 설정) |
| 320 | +├── SecurityConfig — 불변 규칙 (비밀번호/API키 차단) |
| 321 | +├── RewardConfig — 보상 가중치 |
| 322 | +├── SelfPlayConfig — Self-play 시뮬레이션 |
| 323 | +├── OllamaConfig — 로컬 LLM (모델명, max_tokens) |
| 324 | +├── DatasetConfig — 데이터셋 분할 비율 |
| 325 | +└── DataPaths — 파일 경로 |
| 326 | +``` |
| 327 | + |
| 328 | +--- |
| 329 | + |
| 330 | +## 기술 스택 |
| 331 | + |
| 332 | +| 영역 | 기술 | 용도 | |
| 333 | +|------|------|------| |
| 334 | +| MCP 프로토콜 | FastMCP | MCP 서버 구현 | |
| 335 | +| 벡터 DB | ChromaDB | 시맨틱 검색 + 영속 저장 | |
| 336 | +| 임베딩 | sentence-transformers | 다국어 텍스트 임베딩 | |
| 337 | +| 지식 그래프 | NetworkX | 엔티티-관계 그래프 | |
| 338 | +| 데이터 모델 | Pydantic v2 | 스키마 검증 + 직렬화 | |
| 339 | +| RL | PyTorch (via MLP) | 순수 Python MLP (경량) | |
| 340 | +| 테스트 | pytest | 590개 테스트 | |
| 341 | +| 린트 | ruff | 포맷팅 + 린팅 | |
| 342 | +| CI | GitHub Actions | Python 3.11/3.12/3.13 매트릭스 | |
| 343 | +| 패키지 | hatchling + uv | 빌드 + 의존성 관리 | |
| 344 | + |
| 345 | +--- |
| 346 | + |
| 347 | +## 설계 원칙 |
| 348 | + |
| 349 | +1. **"저장 품질 > 검색 알고리즘"** — 무엇을 저장할지가 가장 중요 |
| 350 | +2. **Additive 확장** — 기존 클래스 수정 최소화, opt-in config flags |
| 351 | +3. **Graceful Degradation** — Enhanced/GraphRAG 비활성 시 기본 모드로 동작 |
| 352 | +4. **로컬 우선** — 외부 API 불필요, 모든 데이터 로컬 저장 |
| 353 | +5. **다국어 설계** — i18n 모듈로 언어별 패턴 분리 |
0 commit comments