<overview> Les Deep Agents utilisent des backends modulaires pour les opérations sur fichiers et la mémoire :
Court terme (StateBackend) : Persiste au sein d'un thread unique, perdu à la fin du thread Long terme (StoreBackend) : Persiste entre les threads et les sessions Hybride (CompositeBackend) : Route différents chemins vers différents backends
FilesystemMiddleware fournit les outils : ls, read_file, write_file, edit_file, glob, grep
</overview>
| Cas d'usage | Backend | Raison |
|---|---|---|
| Fichiers de travail temporaires | StateBackend | Par défaut, aucune configuration |
| CLI de développement local | FilesystemBackend | Accès direct au disque |
| Mémoire entre sessions | StoreBackend | Persiste entre les threads |
| Stockage hybride | CompositeBackend | Mélange éphémère + persistant |
StateBackend par défaut stocke les fichiers de manière éphémère au sein d'un thread.
from deepagents import create_deep_agent
agent = create_deep_agent() # Par défaut : StateBackend
result = agent.invoke({
"messages": [{"role": "user", "content": "Write notes to /draft.txt"}]
}, config={"configurable": {"thread_id": "thread-1"}})
# /draft.txt est perdu quand le thread se termine
StateBackend par défaut stocke les fichiers de manière éphémère au sein d'un thread.
import { createDeepAgent } from "deepagents";
const agent = await createDeepAgent(); // Par défaut : StateBackend
const result = await agent.invoke({
messages: [{ role: "user", content: "Write notes to /draft.txt" }]
}, { configurable: { thread_id: "thread-1" } });
// /draft.txt est perdu quand le thread se termine
Configurez CompositeBackend pour router les chemins vers différents backends de stockage.
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
composite_backend = lambda rt: CompositeBackend(
default=StateBackend(rt),
routes={"/memories/": StoreBackend(rt)}
)
agent = create_deep_agent(backend=composite_backend, store=store)
# /draft.txt -> éphémère (StateBackend)
# /memories/user-prefs.txt -> persistant (StoreBackend)
Configurez CompositeBackend pour router les chemins vers différents backends de stockage.
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";
const store = new InMemoryStore();
const agent = await createDeepAgent({
backend: (config) => new CompositeBackend(
new StateBackend(config),
{ "/memories/": new StoreBackend(config) }
),
store
});
// /draft.txt -> éphémère (StateBackend)
// /memories/user-prefs.txt -> persistant (StoreBackend)
Les fichiers dans /memories/ persistent entre les threads via le routage StoreBackend.
# Utilisation de CompositeBackend de l'exemple précédent
config1 = {"configurable": {"thread_id": "thread-1"}}
agent.invoke({"messages": [{"role": "user", "content": "Save to /memories/style.txt"}]}, config=config1)
config2 = {"configurable": {"thread_id": "thread-2"}}
agent.invoke({"messages": [{"role": "user", "content": "Read /memories/style.txt"}]}, config=config2)
# Le thread 2 peut lire le fichier sauvegardé par le thread 1
Les fichiers dans /memories/ persistent entre les threads via le routage StoreBackend.
// Utilisation de CompositeBackend de l'exemple précédent
const config1 = { configurable: { thread_id: "thread-1" } };
await agent.invoke({ messages: [{ role: "user", content: "Save to /memories/style.txt" }] }, config1);
const config2 = { configurable: { thread_id: "thread-2" } };
await agent.invoke({ messages: [{ role: "user", content: "Read /memories/style.txt" }] }, config2);
// Le thread 2 peut lire le fichier sauvegardé par le thread 1
Utilisez FilesystemBackend pour le développement local avec accès direct au disque et boucle humain-agent.
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
backend=FilesystemBackend(root_dir=".", virtual_mode=True), # Restreindre l'accès
interrupt_on={"write_file": True, "edit_file": True},
checkpointer=MemorySaver()
)
# L'agent peut lire/écrire des fichiers réels sur le disque
Utilisez FilesystemBackend pour le développement local avec accès direct au disque et boucle humain-agent.
import { createDeepAgent, FilesystemBackend } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";
const agent = await createDeepAgent({
backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
interruptOn: { write_file: true, edit_file: true },
checkpointer: new MemorySaver()
});
Sécurité : N'utilisez jamais FilesystemBackend sur des serveurs web - utilisez StateBackend ou un sandbox à la place.
Accédez directement au store dans les outils personnalisés pour les opérations de mémoire long terme.
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.store.memory import InMemoryStore
@tool
def get_user_preference(key: str, runtime: ToolRuntime) -> str:
"""Récupère une préférence utilisateur du stockage long terme."""
store = runtime.store
result = store.get(("user_prefs",), key)
return str(result.value) if result else "Not found"
@tool
def save_user_preference(key: str, value: str, runtime: ToolRuntime) -> str:
"""Sauvegarde une préférence utilisateur dans le stockage long terme."""
store = runtime.store
store.put(("user_prefs",), key, {"value": value})
return f"Saved {key}={value}"
store = InMemoryStore()
agent = create_agent(
model="gpt-4.1",
tools=[get_user_preference, save_user_preference],
store=store
)
Ce que les agents PEUVENT configurer
- Type et configuration du backend
- Règles de routage pour CompositeBackend
- Répertoire racine pour FilesystemBackend
- Boucle humain-agent pour les opérations sur fichiers
Ce que les agents NE PEUVENT PAS configurer
- Noms des outils (ls, read_file, write_file, edit_file, glob, grep)
- Accéder à des fichiers en dehors des restrictions virtual_mode
- Accès aux fichiers entre threads sans configuration backend appropriée
StoreBackend nécessite une instance store.
# INCORRECT
agent = create_deep_agent(backend=lambda rt: StoreBackend(rt))
# CORRECT
agent = create_deep_agent(backend=lambda rt: StoreBackend(rt), store=InMemoryStore())
StoreBackend nécessite une instance store.
// INCORRECT
const agent = await createDeepAgent({ backend: (c) => new StoreBackend(c) });
// CORRECT
const agent = await createDeepAgent({ backend: (c) => new StoreBackend(c), store: new InMemoryStore() });
Les fichiers StateBackend sont limités au thread - utilisez le même thread_id ou StoreBackend pour l'accès entre threads.
# INCORRECT : thread-2 ne peut pas lire le fichier de thread-1
agent.invoke({"messages": [...]}, config={"configurable": {"thread_id": "thread-1"}}) # Écriture
agent.invoke({"messages": [...]}, config={"configurable": {"thread_id": "thread-2"}}) # Fichier non trouvé !
Les fichiers StateBackend sont limités au thread - utilisez le même thread_id ou StoreBackend pour l'accès entre threads.
// INCORRECT : thread-2 ne peut pas lire le fichier de thread-1
await agent.invoke({ messages: [...] }, { configurable: { thread_id: "thread-1" } }); // Écriture
await agent.invoke({ messages: [...] }, { configurable: { thread_id: "thread-2" } }); // Fichier non trouvé !
Le chemin doit correspondre au préfixe de route de CompositeBackend pour la persistance.
# Avec routes={"/memories/": StoreBackend(rt)} :
agent.invoke(...) # /prefs.txt -> éphémère (pas de correspondance)
agent.invoke(...) # /memories/prefs.txt -> persistant (correspondance de route)
Le chemin doit correspondre au préfixe de route de CompositeBackend pour la persistance.
// Avec routes: { "/memories/": StoreBackend } :
await agent.invoke(...); // /prefs.txt -> éphémère (pas de correspondance)
await agent.invoke(...); // /memories/prefs.txt -> persistant (correspondance de route)
Utilisez PostgresStore pour la production (InMemoryStore perdu au redémarrage).
# INCORRECT # CORRECT
store = InMemoryStore() store = PostgresStore(connection_string="postgresql://...")
Utilisez PostgresStore pour la production (InMemoryStore perdu au redémarrage).
// INCORRECT // CORRECT
const store = new InMemoryStore(); const store = new PostgresStore({ connectionString: "..." });
Activez virtual_mode=True pour restreindre l'accès au chemin (empêche les échappements ../ et ~/).
backend = FilesystemBackend(root_dir="/project", virtual_mode=True) # Sécurisé
CompositeBackend fait correspondre le préfixe le plus long en premier.
routes = {"/mem/": StoreBackend(rt), "/mem/temp/": StateBackend(rt)}
# /mem/file.txt -> StoreBackend, /mem/temp/file.txt -> StateBackend (correspondance plus longue)