Inicio / Artículos

El sistema de archivos de tu agente es una decisión: explicación de los servidores backend de Deep Agents.

Los backends de LangChain Deep Agents deciden qué archivos sobreviven: cinco integrados, el enrutamiento de CompositeBackend, la trampa de espacio de nombres en almacenes y entornos de pruebas multiusuario.

Editor: REACTAPP.TOP9 min de lectura2174 palabras

Fuentes: LangChain Deep Agents: Your Agent’s Filesystem Is a Decision. Most People Make It by Accident. IV

El bug más aterrador no provoca caídas del sistema. Simplemente olvida silenciosamente lo sucedido ayer, expone la memoria de otra persona o escribe conocimientos valiosos en un espacio temporal al que nunca pretendiste perder acceso. En los Deep Agents de LangChain, el lugar donde se deciden esos resultados es el backend, y el objetivo aquí es dejar de tratar el sistema de archivos como algo mágico y decidir intencionadamente qué sobrevive, qué desaparece y quién puede verlo.

Cada agente de Deep Agents cuenta con un sistema de archivos, pero dónde se encuentra realmente ese sistema de archivos depende de ti: en memoria, en disco, en un almacenamiento duradero que abarque varios hilos, o en una combinación de estos. Elegir mal hace que un agente olvide silenciosamente todo lo ocurrido entre conversaciones.

El bug detrás de las notas que desaparecen

Imagínese que crea un agente con las herramientas del sistema de archivos activadas y ve que guarda notas en /memories/findings.md en medio de una conversación. Más tarde, en la misma conversación, las lee de nuevo. Todo está bien, así que lo lanza al mercado. Al día siguiente, un usuario vuelve, menciona algo que supuestamente el agente sabía ayer, pero el agente no tiene ni idea. Las notas han desaparecido. No hay error, ni línea en los registros. El agente simplemente comenzó de cero sin avisar.

Nadie escribe ese error intencionadamente. Proviene de una configuración por defecto: los archivos del agente se guardan en un espacio temporal vinculado al hilo de conversación, que se elimina al final de la misma. Al omitir la decisión sobre dónde deben almacenarse los archivos, el framework lo decide por usted. Para un espacio temporal, está bien, pero para almacenar información a largo plazo es la elección incorrecta.

Los permisos, la memoria, los entornos aislados y el despliegue se basan todos en esta única elección. Si el backend es adecuado, todo lo demás encaja perfectamente; en cambio, si está mal, pasarás tardes enteras persiguiendo notas que desaparecen.

El sistema de archivos es virtual y el backend es donde se materializa

El agente siempre ve un sistema de archivos ordinario con rutas comunes. El backend decide de qué está compuesto ese sistema de archivos, y puedes cambiar de backend sin que cambie el comportamiento del agente.

Se proporcionan seis herramientas para el sistema de archivos: ls, read_file, write_file, edit_file, glob y grep. Para el modelo, estas herramientas actúan como si estuvieran en un sistema de archivos normal. El modelo escribe /workspace/plan.md, lo lee posteriormente y realiza búsquedas en /repo como si tuviera un disco físico; nada de esto cambia independientemente del backend subyacente.

El backend es la implementación que está detrás de esa abstracción. Responde a algo sobre lo cual el agente nunca se pregunta. Si el modelo escribe /workspace/plan.md, ¿a dónde van los bytes? ¿A la memoria de Python que desaparece cuando finaliza el proceso? ¿Al disco real? ¿A una base de datos que perdura en todas las conversaciones que el usuario tenga en el futuro? Cada respuesta corresponde a un backend diferente.

La elección se realiza al pasarle un backend a create_deep_agent(model=..., backend=...). Si no se pasa nada, se aplica el valor predeterminado, lo que explica la desaparición de las notas mencionadas anteriormente.

Un consejo para que su código sea compatible con las versiones actuales: proporcione al agente una instancia lista para usar, como StateBackend(). Las muestras antiguas utilizaban un envoltorio lambda rt:, que ahora está obsoleto y es innecesario.

Cinco backends, ordenados por lo que sobrevive

La forma sencilla de separar los cinco componentes integrados es por su período de vida y no por sus características internas: ¿cuánto tiempo permanece un archivo escrito a través de cada uno?

StateBackend es el valor predeterminado y funciona como espacio de trabajo por hilo. Los archivos se almacenan en el estado del agente y persisten a lo largo de las interacciones de una conversación (un hilo), pero no se comparten entre hilos. Es como la libreta del agente, ideal para tareas intermedias que se vuelven a leer dos pasos después y desaparecen al finalizar la conversación. Es el valor predeterminado adecuado, y también es exactamente el backend que provoca la sorpresa de los “apuntes desaparecidos” cuando se confunde con la memoria.

StoreBackend es un almacenamiento duradero entre hilos. Los archivos se guardan en un almacén de LangGraph y permanecen a lo largo de las conversaciones, lo cual es necesario para la memoria a largo plazo. El problema, bastante significativo, es que debes indicarle a qué datos debe guardarlos. Eso se tratará más adelante.

FilesystemBackend y LocalShellBackend utilizan el disco real de la máquina anfitriona. Leen y escriben archivos reales en un directorio que elijas, y LocalShellBackend también proporciona al agente una herramienta execute que ejecuta comandos de shell directamente en tu máquina, sin entorno aislado. Son adecuados para un asistente de programación local que desarrollas en tu escritorio, pero son peligrosos en cualquier otro lugar; por eso la documentación advierte claramente contra su uso en agentes desplegados. El acceso directo al sistema anfitrión combinado con entradas dinámicas del usuario es un incidente de seguridad que está a punto de ocurrir.

ContextHubBackend es la opción nativa y duradera de LangSmith. Los archivos se almacenan en un repositorio de LangSmith Hub y se guardan como commits, lo que permite la persistencia entre ejecuciones además de registrar cada cambio en el sistema de archivos, sin necesidad de alojar un almacenamiento propio. Tiene sentido cuando ya se está dentro del ecosistema de LangSmith y se desea persistencia sin tener que configurar una base de datos.

En conjunto, las opciones se distribuyen a lo largo de un único eje: nada sobrevive, la conversación sobrevive, todo sobrevive, o todo sobrevive con su historial. Elija el nivel de persistencia que necesite su funcionalidad.

CompositeBackend: rutas diferentes, ciclos de vida diferentes

La idea que hace que los backends funcionen bien es que rara vez se desea una sola política de persistencia para todo el sistema de archivos. Los archivos en uso deben ser económicos, rápidos y desechables, mientras que la memoria debe ser duradera. Esos son dos tipos de backends, y CompositeBackend te ofrece ambos dentro de un mismo sistema de archivos mediante la redirección según el prefijo de la ruta.

Asigna un backend predeterminado para la mayoría de las rutas y una tabla de enrutamiento que dirija los prefijos seleccionados. La configuración habitual es usar un espacio temporal para todo, con almacenamiento duradero detrás de /memories/:

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore

agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    backend=CompositeBackend(  # ①
        default=StateBackend(),  # ②
        routes={  # ③
            "/memories/": StoreBackend(namespace=lambda _rt: ("memories",)),  # ④
        },
    ),
    store=InMemoryStore(),  # passed to create_deep_agent, not to the backend  ⑤
)

Recorriendo los marcadores numerados de esa lista:

  1. CompositeBackend presenta un sistema de archivos al agente y reenvía cada operación al sub-backend cuya ruta coincide con la ruta solicitada.
  2. default se encarga de todo aquello para lo que no existe ninguna ruta asignada. En este ejemplo se trata del StateBackend con alcance de hilo.
  3. routes relaciona prefijos de ruta con backends. Si dos prefijos coinciden, gana el más largo; por lo tanto, /memories/projects/ tiene prioridad sobre /memories/.
  4. Las escrituras en /memories/ van a un StoreBackend duradero, cuya función namespace devuelve la tupla que identifica al propietario y define el alcance de los datos.
  5. El store de LangGraph se pasa a create_deep_agent, no al backend; es un detalle de conexión que la gente suele pasar por alto la primera vez.

El efecto es que todo lo que se escribe bajo /memories/ queda almacenado de forma permanente y sobrevive a través de las conversaciones, mientras que todo lo demás, ya sea un plan en /workspace, un archivo temporal o un contenido leído en caché, va al StateBackend predeterminado y desaparece cuando finaliza el hilo de ejecución. El agente ni lo sabe ni le importa; solo escribe rutas.

Una estrategia de sistema de archivos para un agente real

Tomemos un agente de mantenimiento de código, por ejemplo uno llamado buggy-shop. Cuando trabaja en un repositorio, los archivos de dicho repositorio representan su estado actual de trabajo. Se cargan, se editan y se prueban, y no hay razón para que se filtren a la siguiente conversación. Lo que el agente aprende en el proceso es otra cuestión, y eso es lo que debería recordar en la siguiente solicitud: pruebas inestables en un módulo, un fixture compartido por varias suites, o un error de paginación de tipo “off-by-one” detectado anteriormente.

Por lo tanto, buggy-shop utiliza la estructura compuesta mencionada anteriormente. El repositorio se encuentra bajo el StateBackend predeterminado como área temporal de alcance de hilo, mientras que las notas acumuladas se almacenan en /memories/ dentro de un StoreBackend persistente. Se trata de un agente que cuenta con una solución deliberada para determinar qué debe sobrevivir a la conversación. Separar el estado de trabajo temporal del conocimiento duradero es la estrategia adoptada, y la enrutación mediante prefijos de ruta es la forma de implementarla.

Dónde se ejecuta el código versus dónde se almacenan los archivos

Hasta ahora todo ha girado en torno a los archivos, y muchos agentes nunca necesitan más que eso. Pero un agente cuya tarea es demostrar una corrección ejecutando pytest necesita una shell, ya que ejecutar comandos no es una operación del sistema de archivos. Un backend de tipo sandbox añade esto: además del sistema de archivos, expone la herramienta execute para ejecutar comandos, todo dentro de un contenedor aislado para que el agente no pueda dañar al host.

Los agentes pueden conectarse a un entorno de pruebas de dos maneras. Una consiste en colocar el agente dentro del entorno, donde trabaja con su sistema de archivos. Esto mantiene el desarrollo local cercano a la producción, pero obliga a que las claves API se encuentren dentro del entorno de pruebas. La otra opción trata al entorno de pruebas como una herramienta: el agente permanece en su servidor y solo hace llamadas al entorno para ejecutar código. Las credenciales quedan fuera, se puede desechar el entorno de pruebas, y si este falla, el estado del agente permanece seguro. Deep Agents maneja ambas situaciones, lo cual contrasta claramente con las herramientas que solo permiten la primera opción.

Tenga en cuenta que ejecutar código y almacenar archivos son dos cosas distintas. Un backend basado en sistema de archivos resuelve una de ellas, mientras que uno basado en entorno de pruebas resuelve la otra, y muchos agentes avanzados necesitan ambos.

La configuración que no se puede omitir

En el momento en que StoreBackend atiende a más de un usuario, se necesita una fábrica de nombres de espacio. Si falta, no habrá caída del sistema, pero sí habrá fugas de memoria. El backend necesita saber de quiénes son los archivos que almacena, y lo averigua a través de un nombre de espacio: una función muy pequeña que recibe el entorno de ejecución y devuelve una tupla con el nombre del propietario. Al delimitar el acceso por usuario, cada persona cuenta con un almacenamiento independiente:

from deepagents.backends import StoreBackend
backend = StoreBackend(
    namespace=lambda rt: (rt.server_info.user.identity,),
)

Deje de lado el espacio de nombres y los alcances predeterminados heredados, de modo que todos los usuarios del mismo agente compartan un único conjunto de almacenamiento y puedan leer la memoria supuestamente privada de los demás.

Ese error pasa todas las pruebas en su propia máquina, ya que usted es el único usuario. Aparece como un incidente de privacidad el día en que otra persona inicia sesión. Considere la fábrica de espacios de nombres como algo obligatorio para cualquier uso que vaya más allá de un proyecto local con un solo usuario. La documentación indica que se está convirtiendo en un requisito, así que escríbala ahora y omita la migración más adelante.

También viene incluido el backend predeterminado con una solución más ligera. StateBackend guarda como puntos de control todo el estado del agente en cada paso, lo que permite reanudar la conversación de manera ordenada. El costo es que los archivos grandes almacenados en el estado se serializan una y otra vez, paso tras paso, por lo que un archivo grande allí consume silenciosamente el rendimiento y el almacenamiento. La solución es el mismo patrón compuesto: envía los elementos grandes o duraderos a un almacén y utiliza StateBackend solo para datos pequeños y temporales.

Lista de verificación para hoy

  • Descubre qué backend utiliza tu agente. Si no se proporciona el argumento backend= a create_deep_agent, se está utilizando StateBackend y el agente olvida todo entre conversaciones. Verifica que esto sea lo que deseabas.
  • Determine qué debe sobrevivir a una conversación. Enumere los archivos en uso y el conocimiento duradero por separado. Todo lo que esté en la columna de conocimiento duradero debe ir a un StoreBackend.
  • Utilice el patrón compuesto. Cree un CompositeBackend que utilice por defecto StateBackend y dirija /memories/ a un StoreBackend. El propio store debe enviarse a create_deep_agent, nunca al backend.
  • Asigne a cada StoreBackend multiusuario una fábrica de nombres de espacio. Asóciesela con la identidad del usuario y hágalo antes de que se conecte la segunda persona.
  • Realice auditorías de archivos grandes en el estado. Si el agente escribe archivos grandes, diríjalos fuera de StateBackend para que no se vuelvan a serializar en cada paso.

El backend se convierte en una decisión

Trata el backend como una opción y ya habrás evitado desde el principio el problema de comer por la tarde. Puedes describir los cinco componentes integrados según su duración de vida, enviar rutas diferentes a cada duración de vida mediante CompositeBackend, y sabes que el almacenamiento multiusuario no puede funcionar sin una fábrica de nombres de espacio. Un agente diseñado de esta manera tiene un plan para sus archivos: un área temporal para el repositorio en uso y memoria permanente para lo que guarda.

El almacenamiento duradero al que el agente escribe debería hacer que te detengas a pensar, y eso es positivo. Un agente capaz de escribir archivos puede escribir el incorrecto, eliminar el correcto o ejecutar una orden que nunca quisiste. Un sistema de archivos es como darle manos. Lo que sigue es la correa, es decir, permisos declarativos que restringen qué archivos puede modificar y la aprobación humana que le hace detenerse y preguntar primero. La correa solo sirve de ayuda si ya has decidido, intencionadamente, dónde se encontrarán los archivos.