Un benchmark tool per confrontare 3 paradigmi di memoria a lungo termine per LLM. Chatti con ogni sistema di memoria in tab indipendenti, poi analizzi le performance su una dashboard comparativa con metriche, grafici e replay side-by-side.
memory-agent/
├── src/ # Backend Python
│ ├── cli/ # CLI (Typer) — chat, compare, memory, serve
│ ├── agents/ # Chat agent con tool calling
│ ├── tools/ # Tools disponibili per l'agente (store_memory)
│ ├── config/
│ │ ├── settings.py # Configurazione da .env
│ │ ├── taxonomy.yaml # Tassonomia entita/relazioni/categorie
│ │ └── prompts/ # Prompt templates per entity extraction
│ ├── services/
│ │ ├── memory/
│ │ │ ├── amem/ # A-MEM — Knowledge Graph
│ │ │ │ ├── service.py # Orchestratore store/retrieve
│ │ │ │ ├── inductor.py # Estrazione entita, relazioni, keywords (LLM)
│ │ │ │ ├── linker.py # Collegamento semantico tra note (LLM)
│ │ │ │ ├── evolver.py # Evoluzione contesto/tags dei vicini (LLM)
│ │ │ │ └── note.py # Modello nota strutturata
│ │ │ ├── linear/ # Linear RAG — ChromaDB + time decay
│ │ │ ├── context/ # Context Window — in-memory deque
│ │ │ ├── base.py # Interfaccia comune MemoryServiceBase
│ │ │ └── models.py # Modelli condivisi (Conversation, MemoryResult)
│ │ ├── database.py # Connessione MongoDB (motor async)
│ │ ├── session.py # CRUD sessioni
│ │ ├── conversation.py # CRUD conversation turns + debug info
│ │ ├── embedding.py # Servizio embedding OpenAI
│ │ ├── llm.py # Servizio LLM OpenAI
│ │ ├── health.py # Health check (Qdrant, ChromaDB, OpenAI)
│ │ └── obsidian.py # Export/import Obsidian vault
│ └── webserver/
│ ├── app.py # FastAPI app factory
│ ├── routers/ # Endpoint API (chat, session, conversation, memory, analytics, compare)
│ ├── dto/ # Request/Response models (Pydantic)
│ └── services/ # Factory per memory services
├── frontend/ # Frontend React + TypeScript
│ ├── src/
│ │ ├── pages/ # ChatPage, DashboardPage
│ │ ├── components/
│ │ │ ├── chat/ # Sidebar, MessageInput, MessageList, MemoryTypeSelector
│ │ │ ├── dashboard/ # MetricsCards, PerformanceChart, RelevanceDistribution, ChatReplay
│ │ │ ├── debug/ # DebugPanel (memorie recuperate, pipeline, entities)
│ │ │ └── layout/ # NavBar
│ │ └── hooks/ # useSession, useChat, useAnalytics, useReplay, useTheme...
│ └── vite.config.ts # Vite config con proxy API -> :8000
├── docker/
│ └── docker-compose.yaml # Qdrant (:6333), ChromaDB (:8100), MongoDB (:27017)
├── scripts/
│ ├── replay_interactions.py # Replay programmatico dell'esperimento via API
│ └── test_chat.ps1 # Utility PowerShell per test rapido API
├── tests/
│ ├── conftest.py # Fixture condivise (mock OpenAI, settings, user)
│ ├── e2e/ # Test E2E con FastAPI TestClient
│ └── test_*.py # Test integrazione (Qdrant, ChromaDB, OpenAI)
├── docs/ # Documentazione
│ ├── experiment-guide.md # Come replicare l'esperimento di confronto
│ ├── architecture.md # Architettura del sistema
│ ├── api-reference.md # Riferimento API
│ ├── memory-systems.md # Dettagli sui 3 sistemi di memoria
│ ├── amem-theory.md # Paper A-MEM e teoria
│ ├── testing.md # Guida ai test automatici
│ └── ...
├── .env.example # Template variabili d'ambiente
├── pyproject.toml # Dipendenze Python (uv)
└── CLAUDE.md # Istruzioni per Claude Code
- Python 3.11+ e uv
- Docker (Qdrant, ChromaDB, MongoDB)
- Node.js 18+ e npm (frontend React)
- OpenAI API Key
git clone <repo-url> && cd memory-agent
cp .env.example .env # aggiungi OPENAI_API_KEY
cd docker && docker compose up -d && cd ..
uv sync --extra dev # backend
cd frontend && npm install && cd ..Vedi docs/configuration.md per il riferimento completo alla configurazione (config.yaml, .env, override via variabili d'ambiente).
# Produzione (consigliata)
cd frontend && npm run build && cd ..
uv run memory-agent serve
# Sviluppo (2 terminali)
uv run memory-agent serve # Terminal 1 — backend :8000
cd frontend && npm run dev # Terminal 2 — Vite :3000 (proxy -> :8000)Apri http://localhost:8000 (produzione) o http://localhost:3000 (sviluppo).
uv run memory-agent chat -m amem # A-MEM (knowledge graph)
uv run memory-agent chat -m amem -d # con debug panel
uv run memory-agent chat -m linear # Linear RAG (vector + time decay)
uv run memory-agent chat -m context # Context Window (ultimi N messaggi)
uv run memory-agent compare "domanda" # confronto parallelo dei 3 sistemi
uv run memory-agent memory list --type amem
uv run memory-agent memory clear --type all # full reset| Store | Porta | Contenuto |
|---|---|---|
| Qdrant | 6333 | A-MEM notes + entities (vector) |
| ChromaDB | 8100 | Linear RAG vectors (Docker debug only; app usa PersistentClient locale ./data/chromadb) |
| MongoDB | 27017 | Sessioni, conversation turns (con memory_type, metriche, debug info) |
sessions — _id, user_id, memory_type, created_at, last_active
conversation_turns — ogni turno include:
session_id,user_id,memory_type(denormalizzato per aggregazioni veloci)user_message,assistant_response,timestampresponse_time_ms,token_count,memories_retrieved_countdebug_infoembedded (pre-retrieve, store pipeline, usage)
Indici: (user_id, memory_type) su sessions, (user_id, memory_type, timestamp) su turns.
| Metodo | Endpoint | Descrizione |
|---|---|---|
POST |
/api/chat/{memory_type} |
Chat con un sistema di memoria. Cattura response_time_ms, token_count, memories_retrieved_count |
POST |
/api/compare |
Confronto parallelo dei 3 sistemi |
| Metodo | Endpoint | Descrizione |
|---|---|---|
POST |
/api/session/create?user_id=X&memory_type=Y |
Crea sessione per tipo specifico |
GET |
/api/session/user/{user_id}?memory_type=amem |
Lista sessioni (filtro opzionale per tipo) |
GET |
/api/session/{session_id} |
Dettaglio sessione |
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/api/conversation/{session_id} |
Storico conversazione |
GET |
/api/conversation/{session_id}/turns/{turn_id}/debug |
Debug info di un turno passato |
GET |
/api/conversation/replay/{user_id}?limit=50 |
Turni raggruppati per memory_type (replay comparativo) |
DELETE |
/api/conversation/{session_id} |
Cancella storico |
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/api/analytics/{user_id} |
Metriche aggregate, time series, distribuzione relevance |
Response:
{
"user_id": "frabatx",
"metrics": [{
"memory_type": "amem",
"turn_count": 42,
"avg_response_time_ms": 1234.5,
"total_tokens": 50000,
"avg_tokens_per_turn": 1190.5,
"avg_memories_retrieved": 3.2,
"memory_store_count": 38
}],
"time_series": [{
"memory_type": "amem",
"points": [{ "date": "2026-02-08", "avg_response_time_ms": 1100, "avg_tokens": 1200, "turn_count": 5 }]
}],
"relevance_distributions": [{
"memory_type": "amem",
"buckets": [{ "range_label": "0.8-1.0", "count": 15 }]
}]
}| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/api/memory/{memory_type} |
Lista memorie |
DELETE |
/api/memory/{memory_type} |
Cancella memorie |
GET |
/health |
Health check |
Ogni tab (A-MEM, Linear, Context) mantiene sessioni e storico separati. La prima volta che scrivi in un tab, viene creata automaticamente una sessione con il memory_type corretto. La sidebar mostra solo le sessioni del tab attivo.
Layout:
- User Selector + Refresh
- Metrics Cards — 3 card color-coded (amem=viola, linear=cyan, context=ambra) con turn count, avg response time, total tokens, avg memories retrieved, store count
- Performance Chart (Recharts LineChart) — trend temporale di response time per tipo
- Relevance Distribution (Recharts BarChart) — distribuzione score di relevance in 5 bucket per tipo
- Chat Replay — 3 colonne scrollabili con le conversazioni di ogni sistema, per confronto qualitativo
Costruisce un grafo personale dalle conversazioni. Ogni messaggio produce entita, relazioni, categorie e una nota strutturata, collegati tra loro e persistiti come vettori in Qdrant.
Store Pipeline (9 step, 3 chiamate LLM):
User Message
→ [0] Retrieve context precedente (top-5 note simili + entita)
→ [1] Inductor (LLM #1): estrae entita, relazioni, categoria, summary, keywords
→ [2-4] Entity dedup, save relations, save category
→ [5-6] Linker (LLM #2): collega note semanticamente + link sequenziale
→ [7-8] Save nota in Qdrant + link bidirezionali
→ [9] Evolver (LLM #3, ogni N note): evolve context/tags dei vicini
Retrieve Pipeline — Graph RAG (3 canali):
| Canale | Strategia | Score |
|---|---|---|
| 1. Vector Search | Cosine similarity su amem_notes |
Score reale (0.0–1.0) |
| 2. Entity Graph | Entity search → attributi + relation traversal (1-hop) | Score entita × hop_decay (0.7) |
| 3. Link Hop | Segui link bidirezionali dalle note del Canale 1 | 0.5 |
Il contesto viene formattato in due sezioni nel system prompt:
- Fatti noti — attributi e relazioni delle entita matchate (es.
Marco.cognome = Fumagalli) - Conversazioni rilevanti — ranked per score con contesto
Knowledge Graph — 4 tipi di nodo:
| Nodo | Storage | Esempio |
|---|---|---|
| Conversation | Qdrant amem_notes |
nota strutturata con summary, keywords, tags, links |
| Entity | Qdrant amem_entities |
person:Federico Brnotto con attributi e mentioned_in |
| Relation | In-memory | user --collega_di--> Giorgio |
| Category | In-memory | lavoro, famiglia, sogno |
Tassonomia (tipi entita, relazioni, categorie): src/config/taxonomy.yaml
- Storage: ChromaDB
- Retrieve: top-k per cosine similarity, poi
score = similarity × exp(-age_days / 7.0) - Store: salva embedding della conversazione con timestamp
- Storage: in-memory
deque(volatile, non persiste tra restart) - Retrieve: ignora la query, restituisce gli ultimi N messaggi (default 10)
Ogni sistema di memoria ha due binari paralleli:
- Memoria Automatica — salva ogni coppia user/assistant automaticamente (
_chat_loopinmain.py) - Memoria Esplicita — l'agente chiama il tool
store_memoryper fatti importanti (chat_agent.py)
Le note A-MEM vengono esportate come Markdown in un vault Obsidian navigabile con Graph View.
# .env
OBSIDIAN_VAULT_PATH=. # root del progetto come vault
EVOLUTION_THRESHOLD=2 # evolver ogni N noteStruttura: memories/{conversations,entities,categories}/ — file con YAML frontmatter e wikilinks.
Il progetto e stato sviluppato in 7 fasi, per un totale di 84 user stories. Vedi l'elenco completo in docs/user-stories.md.
| Fase | US | Contenuto |
|---|---|---|
| 1. Core Backend | US-001 → US-020 | Servizi memoria (A-MEM, Linear, Context), Obsidian, embedding, LLM |
| 2. API e CLI | US-021 → US-033 | FastAPI endpoints, Typer CLI, chat agent |
| 3. Multi-User | US-034 → US-043 | Sessioni, scoping per utente, MongoDB |
| 4. Frontend React | US-044 → US-057 | Chat page, dashboard, sidebar, routing |
| 5. Documentazione | US-059 → US-066 | Guide in docs/ |
| 6. Testing e CI | US-067 → US-082 | pytest, E2E, CI GitHub Actions |
| 7. Analytics e Debug | US-102 → US-104 | Debug panel, scaffolding Vite |
Vuoi testare i 3 sistemi di memoria con la stessa conversazione e confrontare i risultati sulla dashboard? Leggi la Guida all'Esperimento — spiega passo passo come:
- Chattare con tutti e 3 i sistemi usando gli stessi messaggi
- Analizzare metriche, grafici e replay sulla dashboard comparativa
- Testare recall, persistenza e comportamento su conversazioni lunghe
uv run pytest # test (54 test)
uv run mypy src --ignore-missing-imports # type checking
uv run memory-agent memory clear --type all # full reset (Qdrant + ChromaDB + MongoDB + Obsidian + Context)- Multi-hop traversal (2+ hop, attualmente 1-hop)
- KNN su grafo con
networkx(BFS/DFS) - PageRank scoring per nodi centrali
- Hybrid scoring:
vector_similarity × 0.6 + graph_centrality × 0.4
- Adaptive threshold (trigger piu frequente con grafi piccoli)
- Global evolution pass (consolidamento periodico)
- Decay/Pruning di link deboli
- Clustering automatico di temi
- Persistent graph cache su disco
- Batch embedding
- Incremental Qdrant sync
- Temporal reasoning ("cosa mi hai detto la settimana scorsa?")
- Contradiction detection
- Importance scoring
- Forgetting curve (decay basato su frequenza di richiamo)
- Memory consolidation (merge di note simili)
- A/B comparison dashboard — metriche, grafici, replay side-by-side
- Latency tracking —
response_time_msper ogni turno - Token tracking —
token_countper ogni turno - Relevance distribution — distribuzione score di retrieval per tipo
- Memory accuracy tests — dataset di domande per misurare recall
- Cost tracking granulare (token per induzione/linking/evolution separati)