# 메모리 모범 사례 메모리를 어떻게 구조화하느냐가 유용성을 결정합니다. 이 가이드는 LLM이 적절한 시기에 적절한 정보를 회상할 수 있도록 메모리를 카테고리화, 태깅, 우선순위 지정하는 패턴을 다룹니다. ## 카테고리: 가장 구체적인 것 선택 | 카테고리 | 사용 용도 | 예시 | |----------|---------|---------| | `identity` | 사용자 이름, 역할, 연락처 정보 | `"user_name": "Michael Schäfer"` | | `preference` | 좋아함, 싫어함, 작업 스타일 | `"communication": "Prefers concise responses"` | | `fact` | 검증 가능한 사실 | `"office_location": "Berlin, Germany"` | | `project` | 프로젝트 상태, 결정 | `"project_synapse": "v1.5.0 deployed"` | | `skill` | 사용자 기술 | `"skill_python": "Advanced, 10+ years"` | | `mistake` | 피해야 할 과거 오류 | `"mistake_npm_version": "Always bump version"` | | `context` | 세션 관련 컨텍스트 | `"current_focus": "Working on docs system"` | | `note` | 기타 노트 | `"note_idea": "Try Redis for caching"` | > [!TIP] > 망설여지면 검증 가능한 정보에는 `fact`를, 그 외 모든 것에는 `note`를 > 사용하십시오. 과도하게 카테고리화하지 마십시오 — 혼란스러운 `context`보다 > 명확한 `fact`가 낫습니다. ## 키: 의미 있는 식별자 `key` 필드는 메모리의 식별자입니다. 의미 있고 안정적인 키를 사용하십시오: **좋은 키:** - `user_name` - `project_synapse_status` - `preference_communication_style` - `mistake_npm_version_bump` **나쁜 키:** - `mem_001` (의미 없음) - `temp` (설명적이지 않음) - `2026-06-27-note` (날짜는 회상에 도움되지 않음) ### 키 명명 규칙 - `snake_case` (밑줄이 있는 소문자) - 카테고리로 접두사: `preference_*`, `project_*`, `mistake_*` - 동사가 아닌 설명적인 명사 사용 - 50자 이하로 유지 ## 태그: 검색 및 필터링용 태그를 사용하면 빠른 필터링과 검색이 가능합니다. 메모리당 2-5개 태그 추가: ```json { "category": "project", "key": "project_synapse_status", "content": "Synapse v1.5.0 deployed. Next: v1.6.0 with docs system.", "tags": ["synapse", "deployment", "status", "v1.5.0"] } ``` ### 태그 패턴 - **프로젝트 이름**: `synapse`, `synapse-mcp`, `synapse-chat` - **주제**: `deployment`, `ci`, `database`, `auth` - **상태**: `active`, `completed`, `blocked` - **우선순위 지표**: `urgent`, `long-term` > [!NOTE] > 태그는 대소문자를 구분하지 않습니다. 일관성을 위해 소문자를 사용하십시오. ## 우선순위: 현실적으로 | 우선순위 | 사용 용도 | 메모리 비율 | |----------|---------|---------------| | `critical` | 사용자 정체성, 법적 정보, 되돌릴 수 없는 결정 | ~5% | | `high` | 활성 프로젝트, 중요한 선호도 | ~20% | | `normal` | 대부분의 사실, 노트, 컨텍스트 | ~65% | | `low` | 일시적, 알면 좋음 | ~10% | > [!WARNING] > 모든 것을 `critical`로 표시하지 마십시오. 모든 것이 중요하면, 아무것도 > 중요하지 않습니다. 잊었을 때 실제 피해를 초래할 것들에만 `critical`을 > 사용하십시오. ## 저장 여부 ### 항상 저장 - 사용자 정체성 (이름, 이메일, 역할) - 장기 선호도 - 프로젝트 결정 및 근거 - 과거 실수 및 교훈 - 사용자에게 한 약속 ### 저장하지 않음 - 일시적 상태 (변수 사용) - 동일한 대화 기록 (채팅 시스템이 처리) - 민감한 데이터 (비밀번호, API 키) - 쉽게 도출 가능한 사실 (현재 날짜, 파일 내용) - 일시적 컨텍스트 (`context` 카테고리에 낮은 우선순위로 사용) ## 메모리 업데이트 동일한 `category` + `key`로 `/memory`를 POST하면 기존 메모리가 업데이트됩니다: ```python # Initial store store("project", "project_synapse_status", "v1.4.0 deployed", priority="high") # Later: update with same key store("project", "project_synapse_status", "v1.5.0 deployed. CI green.", priority="high") ``` > [!TIP] > 중복을 만들지 않고 업데이트할 수 있도록 안정적인 키를 사용하십시오. LLM은 > 정보가 변경될 때 새 메모리를 만드는 대신 동일한 키를 다시 POST해야 합니다. ## 메모리 라이프사이클 ``` Create → Active → Stale → Archive → Delete ``` - **Create**: 전체 컨텍스트로 POST /memory - **Active**: 자주 회상, 필요시 업데이트 - **Stale**: 여전히 관련은 있지만 활발히 사용되지 않음 (우선순위 낮추기?) - **Archive**: 우선순위를 `low`로 설정, 역사적 참조용으로 유지 - **Delete**: 더 이상 관련 없을 때 DELETE /memory/:id ### 주기적 정리 ```python # Find memories not updated in 90 days old_memories = requests.get( f"{URL}/memory/search?q=*", headers={"Authorization": f"Bearer {KEY}"} ) for mem in old_memories["results"]: if is_stale(mem, days=90): # Either delete or lower priority if is_obsolete(mem): delete_memory(mem["id"]) else: update_memory(mem["id"], priority="low") ``` ## 패턴: 메모리 상속 계층적 컨텍스트 (프로젝트 → 하위 프로젝트 → 작업)의 경우: ```python # Parent project store("project", "project_synapse", "Main Synapse project", tags=["synapse", "parent"], priority="high") # Sub-project (tags link to parent) store("project", "project_synapse_docs", "Docs system for Synapse", tags=["synapse", "docs", "synapse-parent"], priority="high") # Specific task (tags link to sub-project) store("project", "task_docs_loader", "Implement docs-loader.ts", tags=["synapse", "docs", "task"], priority="normal") ``` 그러면 LLM은 `q=synapse+docs`를 검색하여 모든 관련 메모리를 찾을 수 있습니다. ## 패턴: 결정 로그 LLM이 다시 논의하지 않도록 근거와 함께 결정을 저장: ```python store("fact", "decision_postgres_over_sqlite", "Chose PostgreSQL over SQLite for production. Reason: concurrent writes, " "FTS5 native support, better backup story. Date: 2026-06-15. Decided by: Michael.", tags=["decision", "database", "postgres", "sqlite"], priority="high") ``` ## 패턴: 실수 방지 구체적인 방지 지침과 함께 실수를 저장: ```python store("mistake", "mistake_forget_version_bump", "Forgot to bump package.json version after changes. npm publish failed. " "FIX: Always run `npm version patch` before pushing. " "CI fails with 'version already exists' if you forget.", tags=["npm", "ci", "publish", "version"], priority="high") ``` ## 피해야 할 안티 패턴 > [!WARNING] > - **대화 로그 저장** — 채팅 시스템이 처리 > - **전체 파일 저장** — 스크립트 저장소 또는 외부 저장소 사용 > - **일시적 상태 저장** — 변수 사용 > - **비밀 저장** — 환경 변수 사용 > - **메모리 중복** — 안정적인 키 사용 > - **과도한 태깅** — 메모리당 2-5개 태그가 이상적 > - **모든 것이 critical** — 우선순위를 현실적으로 ## 다음 단계 - [Memory API](/docs/api/memory) - [영구 LLM 에이전트](/docs/guides/persistent-llm-agent) - [메모리 태깅 전략](/docs/llm-cookbook/memory-tagging-strategy)