Skip to main content
Glama
menoxz

llm-memory-tool

by menoxz
README.md
# LLM Memory Tool

**Mémoire persistante, hybride et locale pour agents LLM** — serveur MCP + API REST + SDK Python.

LLM Memory Tool stocke les connaissances, décisions et conventions d'un projet, puis
fournit le contexte pertinent à injecter dans les prompts, sans jamais dépasser un
budget de tokens. Recherche hybride **vectorielle + BM25** avec fusion RRF, graphe de
connaissances, moteur de politiques (décroissance, rétention, renforcement) et serveur
**MCP** pour une intégration directe dans les assistants (VS Code, opencode, Claude…).

---

## Fonctionnalités

- **Recherche hybride** : similarité cosinus (vecteurs) + full-text BM25 + fusion RRF
- **4 types de mémoire** : `semantic`, `episodic`, `procedural`, `profile`
- **Injection pilotée par budget** : jamais au-delà du plafond de tokens configuré
- **Moteur de politiques** : décroissance de confiance, renforcement, rétention/élagage
- **Graphe de connaissances** : entités, relations typées, parcours, plus court chemin,
  clustering (KMeans/DBSCAN) et extraction d'entités par NLP (spaCy)
- **Génération de skills** : transforme un cluster du graphe en fiche `SKILL.md`
- **API REST** : FastAPI + spec OpenAPI auto-générée sur `/docs`
- **SDK Python** : un appel `get_context(query, project_id)` pour le contexte de prompt
- **Serveur MCP** : 20+ outils exposés (`memory_store`, `memory_retrieve`, `graph_*`…)
- **Observabilité** : métriques Prometheus, logs structurés
- **Docker** : conteneur de production avec service d'embeddings (Ollama) intégré

---

## Architecture

```
┌──────────────┐   stdio / MCP    ┌──────────────────┐   HTTP :8765   ┌──────────────────┐
│  Assistant   │ ◄──────────────► │  Serveur MCP     │ ─────────────► │   API REST        │
│  (opencode,  │                  │  mcp_server/     │  (MEMORY_API_URL)│  memory_tool/    │
│  VS Code…)   │                  │  server.py       │ ◄───────────── │  (FastAPI)       │
└──────────────┘                  └──────────────────┘   HTTP :8765   └────────┬─────────┘
                                                                               │
                                                                       ┌───────┴────────┐
                                                                       │  SQLite        │
                                                                       │  /data/memory.db│
                                                                       └────────────────┘
                                ┌──────────────────┐  HTTP :11434
                                │  Ollama          │ ◄────── embeddings (nomic-embed-text)
                                │  (conteneur)     │
                                └──────────────────┘
```

- **API** (`memory_tool/`) : FastAPI, port `8765`, endpoints sous `/api/v1`
- **Serveur MCP** (`mcp_server/`) : transport stdio, s'appuie sur l'API via `MEMORY_API_URL`
- **UI** : accessible sur `http://localhost:8766` (optionnelle, voir docker-compose)

---

## Prérequis

| Outil | Version minimum |
|---|---|
| Python | 3.11+ (3.13 testé) |
| Docker | 24+ (recommandé, avec plugin compose) |
| pip | 23+ |

---

## Installation

### Option A — Docker (recommandé)

```bash
cd memory_tool/
cp .env.example .env          # définir MEMORY_API_KEY
docker compose up -d --build  # démarre API :8765 + embeddings Ollama
curl http://localhost:8765/api/v1/health
```

Le service `embeddings` télécharge `nomic-embed-text` au premier démarrage.

### Option B — Local (pip)

```bash
cd memory_tool/
python -m venv .venv
source .venv/bin/activate          # Windows : .venv\Scripts\activate
pip install -e ".[dev]"
# Pour le NLP (spaCy) : python -m spacy download en_core_web_sm
MEMORY_API_KEY=changeme MEMORY_EMBED_MODEL=mock uvicorn memory_tool.app:app --port 8765
```

---

## Configuration du serveur MCP

Ajoutez ce bloc à votre `opencode.json` (ou équivalent pour VS Code / Claude) :

```json
{
  "mcp": {
    "llm-memory-tool": {
      "type": "local",
      "command": ["python", "-m", "mcp_server.server"],
      "environment": {
        "MEMORY_API_URL": "http://localhost:8765/api/v1",
        "MEMORY_API_KEY": "changeme",
        "MEMORY_DEFAULT_PROJECT": "default"
      },
      "enabled": true
    }
  }
}
```

Le serveur MCP parle à l'API sur `MEMORY_API_URL` (défaut : `http://localhost:8765/api/v1`).

### Outils MCP exposés

| Outil | Rôle |
|---|---|
| `memory_health` | Vérifie que l'API est joignable |
| `memory_store` | Stocke une mémoire (type, tags, importance) |
| `memory_retrieve` | Récupère le contexte prêt à injecter (budget tokens) |
| `memory_retrieve_graph_augmented` | Recherche augmentée par le graphe de connaissances |
| `memory_list` / `memory_get` | Parcours et lecture des mémoires |
| `memory_update` / `memory_delete` | Mise à jour / suppression (soft ou hard) |
| `memory_consolidate` | Applique décroissance/rétention (dry-run par défaut) |
| `graph_entity_create` / `graph_entity_search` / `graph_entity_get` | Entités du graphe |
| `graph_edge_create` / `graph_edge_list` | Relations typées entre nœuds |
| `graph_traverse` / `graph_shortest_path` | Exploration du graphe (BFS, plus court chemin) |
| `graph_cluster` | Clustering KMeans/DBSCAN des entités |
| `graph_discover_entities` | Extraction d'entités par NLP (spaCy) |
| `graph_skill_sync` / `graph_skill_sync_all` | Génération de fiches `SKILL.md` |

---

## Utilisation rapide

### API REST

```bash
# Stocker une mémoire
curl -X POST http://localhost:8765/api/v1/memories \
  -H "X-API-Key: changeme" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "my-project",
       "content": "On utilise FastAPI pour tous les endpoints REST, pydantic v2 pour la validation.",
       "memory_type": "procedural",
       "tags": ["architecture", "fastapi"]}'

# Récupérer le contexte
curl -X POST http://localhost:8765/api/v1/retrieve \
  -H "X-API-Key: changeme" \
  -H "Content-Type: application/json" \
  -d '{"query": "quel framework pour les APIs ?", "project_id": "my-project", "token_budget": 600}'
```

### SDK Python

```python
from memory_tool.sdk import MemoryClient, get_context

client = MemoryClient(api_key="changeme")
client.create_memory(
    project_id="my-project",
    content="Convention : snake_case pour toutes les fonctions Python.",
    tags=["conventions"],
)

context = get_context("conventions de nommage", project_id="my-project")
prompt = f"Contexte :\n{context}\n\nUtilisateur : {user_message}"
```

### Outils MCP (exemple de workflow)

1. `memory_retrieve` **d'abord** — injectez le contexte pertinent dans votre prompt ;
2. après une interaction utile, `memory_store` pour persister la nouvelle connaissance ;
3. `memory_consolidate` périodiquement pour appliquer les politiques.

---

## Configuration (variables d'environnement)

Toutes les réglages passent par des variables préfixées `MEMORY_` (fichier `.env` supporté) :

| Variable | Défaut | Description |
|---|---|---|
| `MEMORY_DB_PATH` | `/data/memory.db` | Chemin SQLite |
| `MEMORY_API_KEY` | `changeme` | **À changer en production** |
| `MEMORY_EMBED_MODEL` | `local` | `local` / `mock` |
| `MEMORY_EMBED_URL` | `http://localhost:11434` | URL Ollama / LM Studio |
| `MEMORY_EMBED_MODEL_NAME` | `nomic-embed-text` | Modèle d'embedding |
| `MEMORY_TOP_K` | `5` | k par défaut de la recherche |
| `MEMORY_MAX_TOKEN_BUDGET` | `1500` | Plafond de tokens injectés |
| `MEMORY_DECAY_DAYS` | `30` | Jours avant décroissance de confiance |
| `MEMORY_RETENTION_DAYS` | `90` | Rétention par défaut |
| `MEMORY_API_URL` | `http://localhost:8765/api/v1` | URL de l'API (côté MCP/SDK) |
| `MEMORY_DEFAULT_PROJECT` | `default` | Projet par défaut (MCP) |

---

## Tests

```bash
cd memory_tool/
pytest tests/ -q            # 38 tests (SQLite en mémoire, aucun service externe requis)

# Avec couverture
pytest --cov=memory_tool --cov-report=term-missing

# Lint
ruff check memory_tool/
```

> Les tests utilisent une base SQLite en mémoire : aucune API Docker n'est nécessaire.

---

## Structure du projet

```
memory_tool/
├── mcp_server/          # Serveur MCP (stdio) : server.py, client.py
├── memory_tool/         # API FastAPI
│   ├── app.py           # Point d'entrée FastAPI
│   ├── auth.py          # Authentification par clé API
│   ├── config.py        # Paramètres (pydantic-settings, env MEMORY_*)
│   ├── dependencies.py  # Injection de dépendances
│   ├── sdk.py           # Client SDK Python
│   ├── adapters/        # Embeddings (Ollama/mock), graphe
│   ├── db/              # Schéma SQLite + migrations + repository
│   ├── domain/          # Modèles métier purs + exceptions
│   ├── routers/         # Endpoints REST (memories, retrieve, admin, graph, infra)
│   └── services/        # mémoire, recherche hybride, politiques, NLP, clustering, skills
├── scripts/             # Synchronisation de l'index des skills, évaluation Recall@K
├── tests/               # Suite pytest
├── docs/                # Documentation (skill-index)
├── Dockerfile
├── docker-compose.yml   # API :8765 + embeddings Ollama + UI :8766
├── pyproject.toml
└── requirements.txt
```

---

## Licence

[MIT](LICENSE) © 2026 Jean-Luc KOUMAGLO (menoxz)

Maintenance

ActivitySlowing
ResponsivenessNo issues