Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.sh text eol=lf

# Preserve published evidence bytes so SHA-256 manifests work on every platform.
results/** -text
68 changes: 60 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ data
!paper/data/RQ5/
!paper/data/RQ5/README.md
!paper/data/RQ5/*.csv
!methods/cognee/source/cognee/infrastructure/data/
!methods/cognee/source/cognee/infrastructure/data/**
!methods/cognee/source/cognee/modules/data/
!methods/cognee/source/cognee/modules/data/**
!methods/other/cognee/source/cognee/infrastructure/data/
!methods/other/cognee/source/cognee/infrastructure/data/**
!methods/other/cognee/source/cognee/modules/data/
!methods/other/cognee/source/cognee/modules/data/**
agents
__pycache__
.DS_Store
Expand All @@ -63,12 +63,64 @@ croissant_files
results/*
!results/README.md
benchmark/memoryagentbench/resources/raw
methods/cognee/source/cognee/.cognee_system/
methods/cognee/source/cognee/.data_storage/
methods/other/cognee/source/cognee/.cognee_system/
methods/other/cognee/source/cognee/.data_storage/
.codex
!methods/cognee/source/cognee/api/v1/datasets/
!methods/cognee/source/cognee/api/v1/datasets/**
!methods/other/cognee/source/cognee/api/v1/datasets/
!methods/other/cognee/source/cognee/api/v1/datasets/**
!methods/lightmem/source/lightmem/memory_toolkits/memories/datasets/
!methods/lightmem/source/lightmem/memory_toolkits/memories/datasets/**
.spec-workspace
.memos

# Isolated environment for the six common memory baselines
.venv-six/

# Local downloaded runtimes and document render intermediates
/tools/llama-b10796/
/.tmp_docs/
/.pytest_cache/
/.ruff_cache/

# Local environments, temporary renders and installed analysis dependencies
/.venv*/
/tmp/
**/parser_deps/
*.py[cod]
*.aux
*.blg
*.log
*.out
*.toc
*.fls
*.fdb_latexmk
*.synctex.gz
.env.*
!.env.example
!.env.sample

# Published experiment evidence (runtime output remains ignored by default).
!results/PUBLICATION_MANIFEST.json
!results/PUBLICATION_VALIDATION.json
!results/locomo_full_20260908/
!results/locomo_full_20260908/**
!results/recursive_locomo_20260907/
!results/recursive_locomo_20260907/**
!results/methodological_refinement_20260908/
!results/methodological_refinement_20260908/**
results/**/*.tgz
results/**/*.log
results/**/__pycache__/
results/**/*.pyc
results/**/.pytest_cache/
results/**/*.tar.gz
!results/locomo_full_20260908/provenance/**/source-r*.tar.gz
results/locomo_full_20260908/provenance/locomo10.json
results/locomo_full_20260908/mem0/raw_*/
results/locomo_full_20260908/mem0/final_r*/locomo-finish-mem0-r*/
results/locomo_full_20260908/**/*_usage.jsonl
results/**/*.db
results/**/.env
results/**/.env.*
results/**/agents/
results/**/artifacts/
86 changes: 86 additions & 0 deletions .tours/new-joiner-e-mem.tour
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"$schema": "https://aka.ms/codetour-schema",
"title": "E-mem 온보딩: 저장에서 에피소드 복원까지",
"description": "E-mem의 Master-Assistant 구조를 따라 메모리 저장, 블록 전환, 하이브리드 라우팅, 지역 증거 추출, 최종 집계와 MemoryData 어댑터 연결을 학습하는 투어입니다.",
"ref": "codex/vastai-mem0-qwen35",
"steps": [
{
"file": "methods/e-mem/README.md",
"line": 15,
"title": "문제 정의: 검색이 아니라 에피소드 복원",
"description": "E-mem은 긴 대화를 작은 사실로 비맥락화하는 대신, 원문 에피소드 블록을 보존합니다. Master Agent가 전체 작업을 조율하고 Assistant Agent가 선택된 블록 안에서 질의별 증거를 다시 추출한다는 구분이 이후 모든 코드의 기준입니다."
},
{
"file": "methods/e-mem/src/conversation_manager/factory.py",
"line": 11,
"title": "조립 지점: 두 저장 모드의 공통 입구",
"description": "create_chat_manager가 동일한 외부 API 뒤에서 kv_cache와 text 구현을 선택합니다. 전자는 로컬 모델의 attention KV를 저장하고 후자는 원문 JSON과 API 모델을 사용하며, 라우터·블록 크기·overlap 설정은 두 경로가 공유합니다."
},
{
"file": "methods/e-mem/src/conversation_manager/base_chat_manager.py",
"line": 104,
"title": "Master Agent의 공개 chat 흐름",
"description": "auto_save=True이면 입력을 곧바로 저장하고, 일반 모드이면 Manager LLM에 add_memory와 query_memory 도구를 제공해 행동을 고르게 합니다. 검색 결과는 같은 클래스의 aggregator가 합치므로, Manager의 대화 응답과 메모리 블록의 지역 추론은 서로 다른 책임입니다."
},
{
"file": "methods/e-mem/src/memory/memory_agent/text_agent.py",
"line": 52,
"title": "쓰기 단위: TextMemoryAgent",
"description": "각 입력은 토큰 수와 함께 현재 TextBlock에 추가됩니다. 누적 토큰이 block_size에 닿으면 agent가 inactive가 되고 원문 전체로 summary를 생성합니다. summary는 라우팅용 표지판일 뿐, 실제 답변 근거는 계속 원문 블록에서 뽑는다는 점이 핵심입니다."
},
{
"file": "methods/e-mem/src/memory/core/text_loop_handler.py",
"line": 248,
"title": "블록 수명주기와 overlap",
"description": "TextMemoryHandler는 가득 찬 active agent를 inactive 풀과 Router에 등록한 뒤 새 agent를 만듭니다. 직전 블록 끝부분을 overlap_ratio만큼 재생해 경계에서 문맥이 끊기는 문제를 줄이며, 라우터에는 완료된 블록만 들어갑니다."
},
{
"file": "methods/e-mem/src/memory/kv_block_manager/text_block.py",
"line": 30,
"title": "Text 모드의 실제 영속화",
"description": "TextBlock은 chunk마다 원문·토큰 수·시각을 JSON에 즉시 저장합니다. 별도의 agents_metadata.json이 active/inactive 상태와 summary를 기록해 재시작 시 블록을 복원합니다. 저장 위치는 TEXT_DATA_DIR라는 프로세스 전역 환경 변수에 좌우됩니다."
},
{
"file": "methods/e-mem/src/memory/router/hybrid_router.py",
"line": 260,
"title": "세 가지 검색 인덱스 만들기",
"description": "inactive 블록이 추가되면 Router는 summary embedding, 겹치는 원문 chunk embedding, 블록 전체 BM25 인덱스를 함께 재구축합니다. 전역 주제·세부 의미·정확한 이름/키워드를 서로 다른 신호로 잡기 위한 준비 단계입니다."
},
{
"file": "methods/e-mem/src/memory/router/hybrid_router.py",
"line": 427,
"title": "Multi-Pathway Routing 점수 결합",
"description": "질의마다 세 점수를 0~1로 정규화하고 기본 가중치 0.3/0.4/0.3으로 합쳐 max_blocks개를 선택합니다. 모든 점수가 0이면 첫 블록을 최소 fallback으로 고르고, 계산 실패 시 설정에 따라 LLM Router 또는 앞쪽 블록들로 후퇴합니다."
},
{
"file": "methods/e-mem/src/memory/memory_agent/text_agent.py",
"line": 96,
"title": "Assistant의 지역 에피소드 복원",
"description": "선택된 TextMemoryAgent는 벡터 검색 결과 자체를 반환하지 않습니다. 자기 블록의 원문 전체를 API LLM에 넣고 질문과 관련된 원정보를 날짜와 함께 추출하게 하므로, 순서와 주변 맥락을 유지한 evidence가 만들어집니다."
},
{
"file": "methods/e-mem/src/memory/router/hybrid_router.py",
"line": 582,
"title": "선택된 Assistant들을 실행",
"description": "map_reduce_blocks는 선택된 블록들을 병렬 또는 KV shared-model batch 방식으로 질의하고 결과 목록을 모읍니다. 이름은 map-reduce지만 이 함수의 책임은 map과 수집까지이며, 최종 의미적 reduce는 BaseChatManager의 aggregator가 담당합니다."
},
{
"file": "methods/e-mem/src/memory/core/text_loop_handler.py",
"line": 297,
"title": "오래된 기억과 방금 전 기억 합치기",
"description": "완료된 inactive 블록은 Router 경로로, 아직 차지 않은 active 블록은 직접 질의하며 두 작업을 병렬 실행합니다. active 블록은 아직 summary/index가 없어도 검색에서 빠지지 않도록 별도 경로를 갖는 것이 중요한 예외 처리입니다."
},
{
"file": "methods/e-mem/src/memory/memory_agent/agent.py",
"line": 454,
"title": "KV 모드가 Text 모드와 다른 지점",
"description": "KV MemoryAgent는 원문 토큰을 한 번 forward해 past_key_values를 누적하고, 블록이 닫힐 때 CPU tensor로 디스크에 저장합니다. 질의 시 이 latent context 뒤에 질문 토큰만 이어 붙여 재인코딩 비용을 줄이지만, 캐시는 model_id와 구조가 같은 모델에서만 재사용할 수 있습니다."
},
{
"file": "methods/e_mem/e_mem_adapter.py",
"line": 13,
"title": "MemoryData 벤치마크에 연결되는 경계",
"description": "이 저장소의 EMemAdapter는 upstream을 text 모드로 고정하고 add_chunk/retrieve/save/load 네 동작으로 감쌉니다. 각 history의 TEXT_DATA_DIR를 state_dir 아래로 격리하고 잠금으로 전역 환경 변수 충돌을 막으며, retrieve에서는 지역 evidence를 한 번 더 aggregator로 합쳐 공통 벤치마크 응답 경로에 넘깁니다."
}
]
}
84 changes: 84 additions & 0 deletions .tours/new-joiner-lightmem.tour
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"$schema": "https://aka.ms/codetour-schema",
"title": "LightMem 코드 학습 투어",
"description": "MemoryData에 통합된 LightMem을 설정부터 저장, 검색, 답변 생성까지 따라가는 신규 학습자용 투어입니다. 현재 기본 direct 경로와 원본 pipeline 경로의 차이를 중심으로 읽습니다.",
"steps": [
{
"directory": "methods/lightmem",
"title": "먼저 세 갈래를 구분하기",
"description": "여기에는 세 역할이 공존합니다. `upstream/`은 원본 프로젝트를 참고하기 위한 미러이고, `source/lightmem/`은 실제 import되는 런타임이며, `lightmem_adapter.py`는 MemoryData 벤치마크 규격과 LightMem 사이의 번역기입니다. 처음부터 upstream 전체를 읽기보다 adapter가 호출하는 source 파일만 좁혀 읽는 것이 좋습니다."
},
{
"file": "config/hybrid_lightmem.yaml",
"line": 9,
"title": "현재 실험의 실제 기본값",
"description": "이 프리셋은 top-k 10, `direct` 적재, 로컬 Qwen 채팅 서버, 384차원 MiniLM 임베딩, 온디스크 Qdrant를 선택합니다. `lightmem_messages_use`가 없으므로 AgentWrapper 기본값인 `user_only`가 적용됩니다. 즉 이 저장소의 기본 실행은 논문의 모든 전처리 단계를 켠 구성이 아니라, 비용을 줄인 벤치마크용 경량 경로입니다."
},
{
"file": "utils/initialization.py",
"line": 248,
"title": "컨텍스트 하나가 메모리 하나의 생명주기",
"description": "러너는 각 평가 컨텍스트마다 AgentWrapper를 만들고, 저장 상태가 없으면 모든 청크를 `memorizing=True`로 보낸 뒤 저장합니다. `lightmem_ready.txt`가 있으면 기존 Qdrant 상태를 재사용합니다. 이 경계를 이해하면 같은 데이터가 중복 적재되는지, `--force`가 왜 필요한지 추적할 수 있습니다."
},
{
"file": "utils/agent.py",
"line": 1714,
"title": "벤치마크 설정을 LightMem 객체로 조립",
"description": "`_initialize_lightmem_agent`가 YAML과 환경변수를 합쳐 per-context DB 경로, 컬렉션 이름, 모델, 임베더, 적재 모드를 결정하고 LightMemAdapter를 생성합니다. 환경변수 `LIGHTMEM_*`가 YAML보다 우선하며, 임베딩 차원은 실제 모델 출력과 반드시 같아야 Qdrant 삽입이 성공합니다."
},
{
"file": "methods/lightmem/lightmem_adapter.py",
"line": 22,
"title": "실행 코드는 source를 import한다",
"description": "어댑터는 `methods/lightmem/source`를 `sys.path` 맨 앞에 넣고 그 안의 `LightMemory`와 `MemoryEntry`를 import합니다. 따라서 동작을 디버깅할 때 `upstream/src`가 아니라 `source/lightmem`을 읽어야 합니다. 두 트리가 비슷해 보여도 실행 기준은 이 다섯 줄입니다."
},
{
"file": "methods/lightmem/source/lightmem/memory/lightmem.py",
"line": 107,
"title": "LightMemory는 컴포넌트 조립기다",
"description": "핵심 클래스는 직접 모든 알고리즘을 구현하기보다 설정에 따라 압축기, 주제 분할기, LLM 메모리 매니저, 임베더, 검색기를 Factory로 생성합니다. 현재 프리셋에서는 압축·주제 분할은 꺼지고 OpenAI 호환 매니저, HuggingFace 임베더, Qdrant 검색기가 살아납니다. `index_strategy`와 `retrieve_strategy`가 필요한 객체의 존재를 결정합니다."
},
{
"file": "methods/lightmem/lightmem_adapter.py",
"line": 144,
"title": "쓰기 경로의 가장 중요한 분기",
"description": "`add_chunk`는 `pipeline`이면 메시지를 원본 `LightMemory.add_memory`로 보내고, 기본 `direct`이면 청크를 직접 `MemoryEntry`로 만들어 `offline_update`에 넣습니다. direct는 압축·주제 분할·LLM 메타데이터 추출을 건너뛰어 빠르고 원문 보존에 유리하지만, LightMem의 구조화 능력은 사용하지 않습니다."
},
{
"file": "methods/lightmem/lightmem_adapter.py",
"line": 285,
"title": "문자열 청크를 대화 메시지로 복원",
"description": "벤치마크 입력은 `Session ...`, `speaker: content` 형태의 평문이므로 파서가 세션 시간, 화자, user/assistant 역할, LoCoMo 출처 ID를 복원합니다. 이어지는 줄은 직전 메시지에 붙고, 파싱 실패 시 전체를 user 메시지 하나로 보존합니다. 세션 ID는 숫자뿐 아니라 임의 문자열을 허용하며 분 단위 타임스탬프도 지원합니다."
},
{
"file": "methods/lightmem/source/lightmem/memory/utils.py",
"line": 14,
"title": "저장의 공통 화폐: MemoryEntry",
"description": "LightMem 내부 저장 단위는 텍스트 하나가 아니라 UUID, ISO/float 시간, 주제, 화자, 원문·압축문, 업데이트 큐를 함께 가진 `MemoryEntry`입니다. direct 모드는 이 필드 중 상당수를 `benchmark_context`, `verbatim_chunk` 같은 고정값으로 채웁니다. 검색 결과의 payload가 어디서 왔는지 알고 싶다면 이 데이터 모델에서 시작하면 됩니다."
},
{
"file": "methods/lightmem/source/lightmem/memory/lightmem.py",
"line": 204,
"title": "원본 pipeline: 감각 버퍼에서 장기 기억까지",
"description": "`add_memory`는 메시지 정규화 → 선택적 사전 압축 → 감각 버퍼의 주제 분할 → 단기 버퍼 임계치 확인 → LLM 메타데이터/요약 추출 → MemoryEntry 변환 순서로 동작합니다. `force_segment`와 `force_extract`는 버퍼가 덜 찼어도 배출하게 합니다. 현재 코드에서는 추출 결과를 쓰기 전에 `metadata_generate`와 `text_summary`가 모두 켜져 있어야 하는 경로를 특히 주의해서 읽으세요."
},
{
"file": "methods/lightmem/source/lightmem/memory/lightmem.py",
"line": 389,
"title": "offline_update는 실제 저장 단계",
"description": "이름과 달리 기본 direct 실행에서는 청크마다 즉시 호출됩니다. 각 MemoryEntry의 `memory`를 임베딩하고, ID 충돌을 피한 뒤 시간·주제·화자·원문 필드를 payload로 묶어 검색기에 삽입합니다. 별도의 `offline_update_all_entries`는 유사 과거 기억을 후보로 삼아 LLM으로 갱신·삭제 여부를 판단하는 더 무거운 통합 작업입니다."
},
{
"file": "methods/lightmem/source/lightmem/factory/retriever/embeddingretriever/qdrant.py",
"line": 126,
"title": "검색은 코사인 유사도 top-k",
"description": "Qdrant 어댑터는 질문 임베딩으로 `query_points`를 호출하고 score와 payload를 돌려줍니다. 필터가 있으면 시간이나 메타데이터 조건을 추가할 수 있지만, 현재 LightMemAdapter의 일반 질의는 `filters=None`입니다. `return_full=True`여야 상위 레이어가 실제 memory 텍스트와 LoCoMo 출처 메타데이터를 읽을 수 있습니다."
},
{
"file": "utils/agent.py",
"line": 3262,
"title": "읽기와 최종 답변 생성은 분리되어 있다",
"description": "질의 시 AgentWrapper는 `LightMemAdapter.retrieve`로 기억만 가져온 뒤 출처 ID를 추출하고, 컨텍스트 길이에 맞춰 자르고, 공통 답변 생성 함수로 LLM을 호출합니다. 따라서 어댑터의 `ask()`는 이 벤치마크 경로에서 사용되지 않습니다. 디버깅할 때 검색 실패와 답변 생성 실패를 이 경계에서 분리하면 빠릅니다. 이제 `add_chunk → offline_update → Qdrant → retrieve → _generate_answer_from_memories`를 한 번 직접 따라가 보세요."
}
]
}
Loading