Validé sur PC Windows (DESKTOP-58D5CAC, 2560x1600) : - 8 clics résolus visuellement (1 anchor_template, 1 som_text_match, 6 som_vlm) - Score moyen 0.75, temps moyen 1.6s - Texte tapé correctement (bonjour, test word, date, email) - 0 retries, 2 actions non vérifiées (OK) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14 KiB
Design Document - FAISS Rebuild Propre
Auteur : Dom, Alice Kiro - 22 décembre 2025
Overview
Le système FAISS Rebuild Propre résout le problème de pollution d'index causé par l'accumulation de vecteurs obsolètes lors des mises à jour de prototypes. La stratégie adoptée est simple et sûre : clear + reindex complet depuis les derniers prototypes validés.
Architecture
Composants Principaux
┌─────────────────────────────────────────────────────────────┐
│ FAISS Rebuild Propre │
├─────────────────────────────────────────────────────────────┤
│ │
│ FAISSManager Enhanced ←→ WorkflowPipeline Enhanced │
│ ✅ clear() amélioré ✅ _extract_node_vector() │
│ ✅ reindex() nouveau ✅ _index_workflow_embeddings │
│ │
│ Test Suite ←→ Trigger Logic │
│ ✅ test_faiss_reindex.py ✅ Post-validation trigger │
│ ✅ Batch session trigger │
│ │
└─────────────────────────────────────────────────────────────┘
Components and Interfaces
1. FAISSManager Enhanced
Interface Améliorée
class FAISSManager:
def clear(self) -> None:
"""Vider complètement l'index + reset état d'entraînement."""
def reindex(self, items: Iterable[Tuple[str, np.ndarray, dict]],
force_train_ivf: bool = True) -> int:
"""Reconstruit l'index à partir d'une source canonique."""
def _create_index(self) -> faiss.Index:
"""Créer un nouvel index selon la configuration."""
Méthode clear() Améliorée
def clear(self) -> None:
"""Vider complètement l'index + reset état d'entraînement."""
self.index = self._create_index()
self.metadata_store.clear()
self.next_id = 0
# IMPORTANT: reset IVF training state
self.training_vectors.clear()
self.is_trained = (self.index_type == "Flat")
Améliorations :
- Reset complet de l'état IVF training
- Réinitialisation des training_vectors
- Gestion correcte du flag is_trained selon le type d'index
Méthode reindex() Nouvelle
def reindex(self, items: Iterable[Tuple[str, np.ndarray, dict]],
force_train_ivf: bool = True) -> int:
"""
Reconstruit l'index à partir d'une source canonique (vecteurs).
items: Iterable[(embedding_id: str, vector: np.ndarray, metadata: dict)]
"""
self.clear()
count = 0
for embedding_id, vector, metadata in items:
if vector is None:
continue
self.add_embedding(embedding_id, vector, metadata or {})
count += 1
# Si IVF + petit volume, add_embedding ne déclenche pas forcément l'entraînement
if (self.index_type == "IVF" and force_train_ivf and
(not self.is_trained) and self.training_vectors):
self._train_ivf_index()
return count
Fonctionnalités :
- Clear complet avant reconstruction
- Ajout sécurisé avec validation des vecteurs
- Force training IVF même pour petits volumes
- Retour du nombre d'éléments indexés
2. WorkflowPipeline Enhanced
Extraction de Vecteurs Multi-Version
def _extract_node_vector(self, node) -> Optional[np.ndarray]:
"""
Récupérer le prototype vecteur d'un node, compatible avec plusieurs versions de modèle.
Retourne np.ndarray ou None.
"""
import numpy as np
# v1: prototype stocké en liste directement
tpl = getattr(node, "template", None)
if tpl is not None:
proto_list = getattr(tpl, "embedding_prototype", None)
if isinstance(proto_list, list):
v = np.array(proto_list, dtype=np.float32)
return v
# v2: prototype stocké sur disque via EmbeddingPrototype.vector_id
emb = getattr(tpl, "embedding", None)
if emb is not None:
vector_id = getattr(emb, "vector_id", None)
if vector_id:
try:
return np.load(vector_id).astype(np.float32)
except Exception:
return None
# fallback (ancienne nomenclature)
st = getattr(node, "screen_template", None)
if st is not None:
p = getattr(st, "embedding_prototype_path", None)
if p:
try:
return np.load(p).astype(np.float32)
except Exception:
return None
return None
Support Multi-Version :
- v1: embedding_prototype en liste directe
- v2: embedding.vector_id avec fichier sur disque
- Fallback: screen_template legacy
- Gestion robuste des erreurs
Indexation Workflow Améliorée
def _index_workflow_embeddings(self, workflow: Workflow) -> None:
"""
Indexer les embeddings des nodes dans FAISS (rebuild propre).
"""
if not self.faiss_manager:
return
items = []
for node in workflow.nodes:
vec = self._extract_node_vector(node)
if vec is None:
continue
items.append((
node.node_id,
vec,
{
"workflow_id": workflow.workflow_id,
"node_id": node.node_id,
"node_name": getattr(node, "name", "")
}
))
n = self.faiss_manager.reindex(items, force_train_ivf=True)
logger.info(f"FAISS reindexed: {n} node prototypes (workflow={workflow.workflow_id})")
Avantages :
- Construction de liste canonique avant reindex
- Métadonnées enrichies (workflow_id, node_id, node_name)
- Force training IVF pour cohérence
- Logging informatif
Data Models
Item de Reindex
@dataclass
class ReindexItem:
embedding_id: str
vector: np.ndarray
metadata: Dict[str, Any]
def __post_init__(self):
if self.vector is not None:
self.vector = self.vector.astype(np.float32)
Résultat de Reindex
@dataclass
class ReindexResult:
success: bool
items_processed: int
items_skipped: int
training_performed: bool
duration_ms: float
error_message: Optional[str] = None
Correctness Properties
Une propriété est une caractéristique ou un comportement qui doit être vrai pour toutes les exécutions valides d'un système - essentiellement, une déclaration formelle sur ce que le système devrait faire.
Property 1: Clear Operation Completeness
Pour tout FAISSManager, après un appel à clear(), l'index doit être vide (ntotal=0), les métadonnées vides, next_id remis à 0, training_vectors vidé, et is_trained défini selon le type d'index Validates: Requirements 1.2, 1.3, 1.4, 1.5
Property 2: Embedding Removal Completeness
Pour tout embedding ajouté puis supprimé via remove_embedding(), ni les métadonnées ni le vecteur ne doivent être présents dans l'index Validates: Requirements 1.1
Property 3: Reindex Consistency
Pour tout ensemble d'items valides, reindex() doit produire un index contenant exactement ces items, sans doublons ni éléments manquants, et retourner le bon nombre d'items traités Validates: Requirements 2.1, 2.2, 2.4
Property 4: Invalid Vector Handling
Pour tout ensemble d'items contenant des vecteurs invalides (None), reindex() doit les ignorer et continuer le traitement des vecteurs valides Validates: Requirements 2.5
Property 5: IVF Training Consistency
Pour tout reindex avec force_train_ivf=True sur un index IVF contenant des vecteurs, l'index résultant doit être dans l'état is_trained=True Validates: Requirements 2.3
Property 6: Vector Extraction Multi-Format
Pour tout node contenant un vecteur prototype dans n'importe quel format supporté (template.embedding_prototype, embedding.vector_id, ou screen_template legacy), _extract_node_vector() doit retourner un np.ndarray de type float32 Validates: Requirements 3.1, 3.2, 3.3, 3.4
Property 7: Vector Extraction Graceful Failure
Pour tout node sans vecteur prototype valide, _extract_node_vector() doit retourner None sans lever d'exception Validates: Requirements 3.5
Property 8: Workflow Indexing Completeness
Pour tout workflow contenant des nodes avec vecteurs valides, _index_workflow_embeddings() doit extraire tous les vecteurs valides et les indexer avec les métadonnées appropriées (workflow_id, node_id) Validates: Requirements 4.1, 4.2
Property 9: IVF Training Force in Pipeline
Pour tout workflow indexé avec un FAISSManager IVF, le système doit forcer l'entraînement IVF pour assurer la cohérence Validates: Requirements 4.3
Property 10: Trigger Logic Validation
Pour tout prototype mis à jour avec post-conditions OK, le système doit déclencher un rebuild FAISS Validates: Requirements 5.1
Property 11: Batch Session Trigger
Pour toute session d'apprentissage par batch qui se termine, le système doit déclencher un rebuild FAISS Validates: Requirements 5.2
Property 12: Frame Update Restraint
Pour toute série de mises à jour de frames, le système ne doit pas déclencher de rebuild à chaque frame Validates: Requirements 5.3
Property 13: Rebuild Failure Resilience
Pour tout échec de rebuild, le système doit maintenir l'index existant dans un état valide sans corruption Validates: Requirements 5.5
Property 14: Flat Index Reindex Cleanup
Pour tout index Flat, après reindex avec de nouveaux items, les anciens items doivent être complètement supprimés Validates: Requirements 6.1
Property 15: IVF Small Dataset Training
Pour tout index IVF, même avec un petit dataset, reindex() avec force_train_ivf=True doit déclencher l'entraînement Validates: Requirements 6.2
Property 16: Metadata Consistency After Reindex
Pour tout reindex, les métadonnées de chaque item doivent être préservées et cohérentes après l'opération Validates: Requirements 6.3
Property 17: Search Accuracy After Reindex
Pour tout reindex suivi d'une recherche, les résultats doivent être corrects et correspondre aux vecteurs indexés Validates: Requirements 6.4
Property 18: Index State Validation
Pour tout reindex, l'état de l'index (ntotal, is_trained) doit être cohérent avec le contenu effectivement indexé Validates: Requirements 6.5
Error Handling
Stratégies de Gestion d'Erreurs
-
Vector Loading Errors
- Try/catch sur np.load() avec fallback gracieux
- Log warning pour vecteurs non chargeables
- Continue processing avec autres vecteurs
-
FAISS Training Errors
- Validation du nombre minimum de vecteurs pour IVF
- Retry avec paramètres ajustés si échec
- Fallback vers index Flat si IVF impossible
-
Memory Errors
- Monitoring de l'utilisation mémoire pendant reindex
- Batch processing pour gros volumes
- Cleanup automatique en cas d'échec
Logging Strategy
# Niveaux de logging
logger.info(f"FAISS reindex started: {len(items)} items")
logger.debug(f"Processing item {embedding_id}: vector shape {vector.shape}")
logger.warning(f"Skipped invalid vector for {embedding_id}")
logger.error(f"FAISS reindex failed: {error}")
logger.info(f"FAISS reindex completed: {count} items in {duration}ms")
Testing Strategy
Tests Unitaires
-
test_faiss_clear_resets_state
- Valide reset complet après clear()
- Vérifie état IVF training
-
test_faiss_reindex_flat_removes_old_entries
- Valide suppression des anciens vecteurs
- Vérifie cohérence métadonnées
-
test_faiss_reindex_ivf_trains_even_small
- Valide training forcé sur petits datasets
- Vérifie état is_trained
-
test_extract_node_vector_multi_version
- Teste support des différents formats
- Valide fallback gracieux
Tests d'Intégration
-
test_workflow_pipeline_reindex_integration
- Test complet pipeline → FAISS
- Validation end-to-end
-
test_reindex_performance_large_dataset
- Test performance sur gros volumes
- Validation mémoire
Tests de Propriétés
Chaque propriété de correctness sera implémentée comme un test property-based avec minimum 100 itérations.
Trigger Logic
Moments de Déclenchement
-
Post-Validation Trigger
# Après mise à jour de prototype validée if post_conditions_ok and prototype_updated: self.trigger_faiss_rebuild() -
Batch Session Trigger
# À la fin d'une session d'apprentissage def end_learning_session(self): self.trigger_faiss_rebuild() self.save_session_metrics() -
Manual Trigger
# Commande administrative def admin_rebuild_faiss(self): return self.faiss_manager.reindex(self.get_all_prototypes())
Éviter les Triggers Excessifs
- PAS de rebuild à chaque frame
- PAS de rebuild sur échecs temporaires
- OUI rebuild après validation réussie
- OUI rebuild en fin de batch
Performance Considerations
Optimisations
-
Batch Processing
- Grouper les updates avant rebuild
- Éviter les rebuilds fréquents
-
Memory Management
- Clear explicite des anciens vecteurs
- Monitoring utilisation mémoire
-
IVF Training
- Force training même petits volumes
- Paramètres optimisés par défaut
Métriques
- Temps de rebuild par nombre de vecteurs
- Utilisation mémoire pendant rebuild
- Taux de réussite des training IVF
- Fréquence des rebuilds déclenchés
Conclusion
Le système FAISS Rebuild Propre garantit la cohérence et la propreté de l'index FAISS en éliminant la pollution par vecteurs obsolètes. L'approche "clear + reindex complet" est simple, sûre et efficace pour maintenir la qualité de l'apprentissage du système RPA Vision V3.