Exercices Projets guidés Memoire de l'agent
🎉

Bravo!

Intermédiaire 🧠 Fondamentaux 20 XP 0 personnes ont réussi

Memoire de l'agent

Imagine que tu demandes a ton agent "Quelles sont les nouveautes de Python 3.13 ?" puis "Et celles de Python 3.12 ?" puis "Compare les deux versions." Pour la troisieme question, l'agent devrait se souvenir des resultats des deux premieres recherches. Sans memoire, il referait les memes recherches, gaspillant du temps et de l'argent.

La memoire d'un agent, c'est comme un carnet de notes. A chaque recherche, il note la requete et les resultats. Avant de lancer une nouvelle recherche, il verifie son carnet : "Est-ce que j'ai deja cherche ca ?" Si oui, il reutilise directement les resultats.

Ce mecanisme s'appelle un cache. C'est un pattern fondamental en informatique : stocker les resultats de calculs couteux pour les reutiliser. Ici, les "calculs couteux" sont les appels API (recherche web, lecture de page).

Ecris une classe MemoireAgent qui gere le cache des resultats d'outils.

Methodes :

a_deja_cherche(requete) : renvoie True si la requete a deja ete faite (comparaison insensible a la casse)

sauvegarder(requete, resultats) : stocke les resultats associes a la requete

recuperer(requete) : renvoie les resultats sauvegardes (ou None si pas en cache)

chercher_avec_cache(requete, search_fn) : verifie le cache d'abord. Si la requete est en cache, renvoie les resultats caches. Sinon, appelle search_fn(requete), sauvegarde et renvoie le resultat.

stats() : renvoie un dictionnaire avec "total_requetes" (nombre de requetes uniques), "requetes" (la liste des requetes), et "taux_cache" (pourcentage de requetes servies depuis le cache, entre 0 et 100)

Pour le taux de cache, il faut compter le nombre total d'appels a chercher_avec_cache et combien ont ete servis depuis le cache.

Exemple :

mem = MemoireAgent()
mem.chercher_avec_cache("Python 3.13", fake_search) appelle fake_search
mem.chercher_avec_cache("Python 3.13", fake_search) utilise le cache, pas d'appel
mem.stats() renvoie {"total_requetes": 1, "requetes": ["python 3.13"], "taux_cache": 50.0}

Tests (4/5)

Cache basique : sauvegarder et recuperer
mem = MemoireAgent()
assert not mem.a_deja_cherche("Python"), "Pas encore en cache"
mem.sauvegarder("Python", ["resultat1", "resultat2"])
assert mem.a_deja_cherche("Python"), "Doit etre en cache apres sauvegarde"
assert mem.recuperer("Python") == ["resultat1", "resultat2"]
Cache insensible a la casse
mem = MemoireAgent()
mem.sauvegarder("Python 3.13", "resultats")
assert mem.a_deja_cherche("python 3.13"), "La comparaison doit etre insensible a la casse"
assert mem.a_deja_cherche("PYTHON 3.13"), "Les majuscules doivent etre ignorees"
assert mem.recuperer("python 3.13") == "resultats"
chercher_avec_cache evite les appels inutiles
mem = MemoireAgent()
compteur = [0]
def fake_search(q):
    compteur[0] += 1
    return f"resultats pour {q}"

r1 = mem.chercher_avec_cache("Python", fake_search)
r2 = mem.chercher_avec_cache("Python", fake_search)
r3 = mem.chercher_avec_cache("python", fake_search)  # meme requete, casse differente
assert compteur[0] == 1, f"La fonction de recherche ne doit etre appelee qu'une fois, pas {compteur[0]}"
assert r1 == r2 == r3
Statistiques correctes
mem = MemoireAgent()
def fake_search(q): return f"r:{q}"

mem.chercher_avec_cache("A", fake_search)
mem.chercher_avec_cache("B", fake_search)
mem.chercher_avec_cache("A", fake_search)  # cache
mem.chercher_avec_cache("B", fake_search)  # cache
s = mem.stats()
assert s["total_requetes"] == 2, f"2 requetes uniques, pas {s['total_requetes']}"
assert s["taux_cache"] == 50.0, f"50% de cache, pas {s['taux_cache']}"

+ 0 tests cachés

Indices (3 disponibles)

solution.py