[!NOTE] Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.

AI Arquitectura de memoria de agentes en 2026: Checkpoints, almacenes vectoriales y memoria basada en archivos

Parte 2 de la serie de ingeniería de la pila Agentic

Un reasoning loop solo puede persistir durante una única solicitud, a menos que su estado se almacene fuera del worker. Sin memoria de agente, el agente no puede reanudar un plan pausado, recuperarse tras una caída o recuperar una preferencia de una sesión anterior. Parte 1 Se abordó el flujo de control. Este artículo indica qué estado necesita cada turno posterior y dónde debe residir dicho estado.

Explicaré en detalle la arquitectura de memoria del Agente Analista de Mercado, Se mostrará cómo los almacenes de vectores checkpoints calientes y fríos, junto con la memoria de documentos basada en archivos, colaboran entre sí para permitir la ejecución de agentes de larga duración. A continuación, se analizará en qué casos resultan adecuados PostgreSQL, Redis, Qdrant, los almacenes clave-valor y los archivos de Markdown simples.

TL;DR: Separa la memoria según el patrón de acceso. La memoria caliente representa el estado a nivel de hilo checkpoint necesario para realizar pausas y reanudaciones. La memoria fría almacena datos entre sesiones en un sistema de almacenamiento de tipo clave-valor o vectorial. La memoria documental conserva el conocimiento del proyecto en archivos que se pueden inspeccionar. Comienza por identificar el fallo que debes solucionar y, a continuación, elige el tipo de almacenamiento adecuado. No introduzcas datos precisos en un sistema de recuperación basado en patrones difusos, ni trates a un checkpoint como un registro de auditoría.


¿Qué es la memoria del agente AI?

AI memoria del agente es la capa de estado que permite a un agente conservar el progreso de las tareas, recuperar conocimientos previos y actualizar sus datos a lo largo de diferentes ejecuciones. En entornos de producción, no se trata de una única base de datos vectorial, sino de una combinación de almacenamientos checkpoints activos, almacenamientos semánticos o estructurados pasivos, además de una memoria de documentos legible por humanos.

NecesitoMejor valor predeterminado¿Por qué?
Pausar y reanudar una ejecuciónPostgreSQL checkpoint de almacenamientoDatos de la aplicación duraderos, consultables y fáciles de operar
Estado transitorio de baja latenciaAlmacén Redis checkpointRecuperación rápida y estado de corta duración, con compromisos en cuanto a la persistencia
Recuperación semántica entre sesionesQdrant o pgvectorRecupera los recuerdos por su significado, y no solo mediante claves exactas.
Hechos estructurados del usuarioPostgreSQL o almacén clave-valorLas actualizaciones determinísticas superan a la recuperación difusa en el caso de preferencias e identificadores.
Convenciones del proyecto y procedimientos establecidosArchivos en formato Markdown o JSONLegible para humanos, apto para realizar diferencias y fácil de actualizar por parte de los agentes
Memoria de relaciones entre múltiples entidadesGráfico de conocimiento

No comience hablando de la memoria, ya que suena a algo relacionado con la inteligencia artificial. En su lugar, aborde el fallo visible para el usuario: la pérdida del progreso, el olvido de una preferencia, la repetición de tareas de investigación o la imposibilidad de reutilizar una convención establecida en un proyecto.

Los fallos que requieren memoria

Un agente sin estado puede responder a una pregunta aislada, pero olvida la solicitud en cuanto finaliza la llamada. Dicho diseño falla cuando el producto requiere alguno de los siguientes comportamientos:

En el Agente Analista de Mercado desde Parte 1, La solicitud “Analizar NVDA” genera un plan, cinco tool calls, los datos recopilados y un borrador de informe. Cuando el usuario responde “parece bien, pero añada un análisis de la competencia”, un almacén de checkpoint permite al agente cargar el estado del nodo anterior y agregar la fase correspondiente al análisis de la competencia. Sin un estado guardado en puntos de control, no puede determinar a qué se refiere la expresión “parece bien” y debe comenzar todo de nuevo.

La memoria a largo plazo maneja un caso diferente. Si el usuario vuelve una semana después y pregunta: “Actualiza mi análisis de NVDA”, el agente podría necesitar recordar su preferencia por evaluaciones de riesgo conservadoras y su interés en acciones de semiconductores. Un almacén de memoria basado en vectores puede recuperar esos datos entre sesiones sin tener que solicitarlos nuevamente.

LangGraph divide los datos según su ámbito de aplicación. Cada ejecución del grafo tiene lugar dentro de un hilo, es decir, para una conversación o tarea concreta. El estado persistente dentro de dicho hilo se denomina memoria a corto plazo. El estado compartido entre hilos, por su parte, constituye la memoria a largo plazo. El contexto actual del modelo y las variables en proceso forman la capa de memoria de trabajo que se sitúa por encima de ambas almacenaciones.

Taxonomía de memoria


Una taxonomía de la memoria de agente AI

Antes de pasar a la implementación, resulta útil clasificar qué es lo que los agentes deben recordar. CoALA framework (Sumers, Yao et al., 2023) constituye la taxonomía estándar y se basa en la ciencia cognitiva. Yo introduje el concepto de alcance de la memoria en mi trabajo. context engineering publicación; Aquí lo desgloso en seis categorías:

Tipo de memoriaAlcanceVida útilEjemploPatrón de almacenamiento
En funcionamientoPaso actualMilisegundosTool call argumentos, respuesta actual LLM
A corto plazoHilo actualMinutos–horasHistorial de conversación, avance del plan, datos recopiladosCheckpoint almacenar
EpisódicoEntre hilosDías–mesesLa semana pasada, el usuario preguntó por los resultados financieros de NVDA.Almacén de vectores / Almacén KV
SemánticoEntre hilosMeses: permanente”El usuario prefiere inversiones conservadoras”Almacén de vectores / Almacén KV
DocumentoEntre hilosDías – permanenteNotas del proyecto, resúmenes de investigación, patrones aprendidosAlmacén de archivos (Markdown/JSON)
ProcedimentalA nivel de sistemaPermanenteAl analizar acciones, siempre hay que revisar los documentos presentados ante la SEC.Configuración / system prompt

Memoria de trabajo es aquello con lo que el LLM está razonando activamente en este momento: las variables de Python de la función actual, el contenido de la ventana de contexto y los argumentos de tool call durante su ejecución. Se trata de la capa más rápida, pero también la más efímera, ya que nada permanece más allá del paso actual. La memoria de trabajo está limitada por la ventana de contexto del modelo, lo que la convierte en el cuello de botella real. Todo lo que el agente “sabe” en el momento de tomar una decisión debe caber aquí, independientemente de si proviene del almacenamiento de checkpoint, de una consulta vectorial o de la lectura de un archivo. Las demás capas existen para suministrar la información adecuada a la memoria de trabajo en el momento oportuno.

Memoria a corto plazo es la información que LangGraph escribe después de cada nodo mediante el checkpoint. Las memorias episódicas y semánticas persisten a lo largo de los hilos de ejecución. La memoria de documentos almacena notas del proyecto, resúmenes de investigación y convenciones aprendidas en archivos que tanto las personas como los agentes pueden consultar. Por su parte, la memoria procedural se encuentra en las instrucciones del sistema y las definiciones de herramientas, por lo que no varía para cada usuario.

Para su implementación, estas categorías se reducen a tres niveles. La memoria caliente almacena la sesión actual. La memoria fría permite recuperar información entre sesiones distintas. La memoria de documentos mantiene el conocimiento acumulado del proyecto en un estado legible y directamente editable.

La clase CoALA clasifica la memoria de trabajo, la memoria episódica, la memoria semántica y la memoria procedimental. La memoria en la era de los agentes AI: una revisión Destaca los almacenes vectoriales y los grafos de conocimiento, mientras que LangGraph documenta checkpoints y su interfaz Store. El conocimiento de los proyectos almacenado en archivos queda fuera de esas taxonomías, aunque herramientas como Claude Code, Cursor, Windsurf y Devin cargan archivos de proyecto persistentes.

El mismo patrón de almacenamiento se observa en otros dominios. Voyager almacena habilidades reutilizables para juegos como bibliotecas de código, los equipos de ECR3 trabajaron en documentos procedurales prompt, y la Memoria de Flujo de Trabajo de Agente permite generar flujos de trabajo web reutilizables a partir de episodios exitosos. Los archivos hacen que dicho conocimiento sea inspeccionable y versionable, sin necesidad de un servicio embedding separado.

La memoria gestionada por un agente también difiere de una RAG pipeline fija en cuanto a quién realiza la escritura. El agente o su harness decide qué datos almacenar, actualizar o eliminar, y posteriormente elige el momento adecuado para recuperarlos.

El Artículo sobre Agentes Generativos (Park et al., 2023) demostraron hasta qué punto se puede llegar en este ámbito: los agentes simulados eran capaces de almacenar, reflexionar sobre y recuperar sus propias memorias. Su flujo de memoria ordenaba a los candidatos según su reciente creación, importancia y relevancia, un diseño que sigue sirviendo como punto de referencia útil para la recuperación de memorias por parte de los agentes.


Memoria a corto plazo del agente: el almacén checkpoint

Cada vez que se ejecuta un nodo de LangGraph, el framework serializa todo el estado del grafo y lo escribe en un checkpoint store. Esa es la base para las funcionalidades de pausa/reanudación, el depuración mediante viajes en el tiempo y los flujos de trabajo HITL.

Flujo de memoria caliente Checkpoint

Un checkpoint contiene el estado del grafo necesario para reanudar: la AgentState de Parte 1 (mensajes, identidad, perfil de usuario, pasos del plan, datos de investigación, modo de ejecución), además de los metadatos de LangGraph como el nodo que lo generó y su ID checkpoint. Tras una interrupción HITL o un reinicio del proceso, el grafo carga el límite más reciente registrado e ingresa nuevamente al nodo siguiente. No continúa desde una línea arbitraria de Python. Un checkpoint también difiere de un registro de eventos o traza de solo escritura; Parte 5 Separa de forma explícita esas superficies de observabilidad runtime.

Cómo funciona el guardado de checkpoints en LangGraph

LangGraph’s BaseCheckpointSaver Se trata de una interfaz sencilla: put() escribe un checkpoint. get_tuple() lee el último mensaje de un hilo. list() Devuelve el historial. Cada checkpoint está indexado por (thread_id, checkpoint_ns, checkpoint_id), donde thread_id identifica la conversación. checkpoint_ns gestiona el espacio de nombres de los subgrafos, y checkpoint_id Se trata de una versión única.

La decisión relevante es determinar qué backend se utilizará como backend. PostgreSQL y Redis son dos opciones muy habituales en entornos de producción.

PostgreSQL frente a Redis

Redis frente a PostgreSQL

DimensiónPostgreSQL (langgraph-checkpoint-postgres)Redis (langgraph-checkpoint-redis)
Modelo de durabilidadTransacciones ACID, WAL y replicaciónPersistencia configurable en modo AOF o RDB
Checkpoint historialHistorial duradero para el seguimiento de ejecuciones y la depuraciónLa retención depende de la configuración del salvador y de las reglas de expulsión.
Restricción principalLatencia de escritura en la base de datos y crecimiento de tablasUso de RAM, expulsión de elementos y configuración de persistencia
Adecuación operativaLos equipos que ya utilizan bases de datos relacionalesLos equipos que ya utilizan Redis con un alto rendimiento de procesamiento.
Mejor opción predeterminada paraContinuidad del estado y depuración reproducibleEstado de sesión recuperable y sensible a la latencia

Una base de datos genérica benchmarks no permite predecir el rendimiento checkpoint. Es necesario medir el tamaño del estado serializado, la frecuencia de escritura, los parámetros de persistencia y la concurrencia en su propio grafo.

PostgreSQL: el valor predeterminado duradero

PostgreSQL representa la opción predeterminada más segura para la mayoría de los equipos. Gracias a que Checkpoints resisten las caídas del sistema, se dispone de una semántica de transacciones completa, y el historial de checkpoint facilita enormemente la depuración mediante análisis retrospectivo.

Desde checkpointer_setup.py:

from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver

async def create_postgres_checkpointer(connection_string: str) -> AsyncPostgresSaver:
    """Create a PostgreSQL-backed checkpoint store.

    PostgreSQL gives us ACID guarantees — if a checkpoint write succeeds,
    the state is durable even if the process crashes immediately after.
    """
    checkpointer = AsyncPostgresSaver.from_conn_string(connection_string)

    # Create the checkpoint tables if they don't exist.
    # This is idempotent — safe to call on every startup.
    await checkpointer.setup()

    return checkpointer

# Usage: wire into the graph compilation
checkpointer = await create_postgres_checkpointer(
    "postgresql://user:pass@localhost:5432/agent_memory"
)
graph = create_graph(checkpointer=checkpointer)

# Every invoke/stream call now persists state automatically
config = {"configurable": {"thread_id": "user-123-session-1"}}
result = await graph.ainvoke({"messages": [HumanMessage(content="Analyze NVDA")]}, config)

# Resume later — loads the latest checkpoint for this thread
result = await graph.ainvoke({"messages": [HumanMessage(content="approved")]}, config)

El AsyncPostgresSaver utiliza el langgraph-checkpoint-postgres package, el cual crea tres tablas: checkpoints (el estado serializado). checkpoint_blobs (grandes volúmenes de datos binarios), y checkpoint_writes (Pendientes escrituras para la recuperación tras fallos). El esquema admite acceso concurrente y emplea bloqueos consultivos para evitar conflictos de escritura.

Redis: cuando la latencia es el cuello de botella

Cuando la latencia de submilisegundos en checkpoint es crítica (agentes de conversación en tiempo real, ciclos de herramientas de alta frecuencia), Redis representa la mejor opción.

Desde checkpointer_setup.py:

from langgraph.checkpoint.redis.aio import AsyncRedisSaver

async def create_redis_checkpointer(redis_url: str) -> AsyncRedisSaver:
    """Create a Redis-backed checkpoint store.

    Redis stores checkpoints in memory for sub-millisecond access.
    Trade-off: less durable than PostgreSQL unless AOF is enabled.
    """
    checkpointer = AsyncRedisSaver.from_conn_string(redis_url)

    # Initialize Redis data structures
    await checkpointer.setup()

    return checkpointer

# Usage: same graph API, different backend
checkpointer = await create_redis_checkpointer("redis://localhost:6379")
graph = create_graph(checkpointer=checkpointer)

El AsyncRedisSaver de langgraph-checkpoint-redis Almacena checkpoints como documentos JSON indexados por el ID del hilo de conversación. El v0.1.0 de rediseño Se sustituyeron múltiples operaciones de búsqueda por una única. JSON.GET Permite realizar llamadas de forma eficiente, reduciendo significativamente la latencia. Redis 8.0+ incluye por defecto RedisJSON y RediSearch; no es necesario instalar módulos adicionales.

En implementaciones con restricciones de memoria, ShallowRedisSaver Almacena únicamente la versión más reciente de checkpoint por hilo: no se conserva ningún historial, lo que permite un consumo mínimo de memoria RAM. Úsalo cuando necesites pausar y reanudar el proceso, pero no requieras la capacidad de depurar mediante retroceso en el tiempo.

Cuándo utilizar cada uno

Usar PostgreSQL cuando:

Usar Redis cuando:

Otras opciones: langgraph-checkpoint-sqlite Funciona para el desarrollo local y despliegues de un solo proceso. En el caso de stacks nativos de AWS, langgraph-checkpoint-aws proporciona un DynamoDBSaver Gracias a un manejo inteligente de la carga útil, los archivos pequeños checkpoints (<350 KB) permanecen en DynamoDB, mientras que los de mayor tamaño se descargan automáticamente a S3. El modelo de precios sin servidores y la ausencia de infraestructura que gestionar lo convierten en una opción atractiva para implementaciones con cargas variables.


Memoria a largo plazo: recordar entre sesiones

La memoria caliente gestiona la conversación actual. Pero, ¿qué ocurre con el usuario que regrese la semana que viene? La memoria a largo plazo almacena hechos, preferencias e historial de interacciones que permanecen intactos a lo largo de distintas sesiones.

LangGraph ofrece un Store interfaz para el acceso a memoria entre hilos a través de la misma BaseStore clase. Cada elemento de memoria es un (namespace, key) Se empareja con un valor de JSON y, opcionalmente, con un vector embedding. El espacio de nombres suele codificar al usuario u organización correspondiente. ("user", "user-123", "preferences").

Flujo de memoria a largo plazo

Almacenamiento vectorial: recuperación semántica con Qdrant

Cuando el agente necesita recuperar datos no estructurados (“¿Qué dijo el usuario sobre su cronograma de inversión?”), la búsqueda vectorial permite una recuperación semántica. En lugar de realizar búsquedas por claves exactas, el agente realiza consultas basadas en el significado.

Qdrant es una base de datos vectoriales diseñada específicamente, escrita en Rust, que gestiona el almacenamiento de embedding, la indexación (HNSW) y las búsquedas filtradas. Ya traté en detalle HNSW y sus compromisos en mi posicionamiento en búsquedas. Qdrant también ofrece una servidor MCP que funciona como una capa de memoria semántica; resulta útil si su agente framework es compatible con el Protocolo de Contexto de Modelo.

Desde memory_store.py:

from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Distance, VectorParams
from langchain_anthropic import ChatAnthropic
import hashlib
import json

class UserMemoryStore:
    """Long-term memory backed by Qdrant vector search.

    Stores user facts as embedded vectors for semantic retrieval.
    Each fact is a short natural-language statement about the user.
    """

    def __init__(self, qdrant_url: str, collection_name: str = "user_memory"):
        self.client = QdrantClient(url=qdrant_url)
        self.collection_name = collection_name
        self._ensure_collection()

    def _ensure_collection(self):
        """Create the collection if it doesn't exist."""
        collections = [c.name for c in self.client.get_collections().collections]
        if self.collection_name not in collections:
            self.client.create_collection(
                collection_name=self.collection_name,
                vectors_config=VectorParams(
                    size=1536,  # text-embedding-3-small dimensions
                    distance=Distance.COSINE,
                ),
            )

    def store_fact(self, user_id: str, fact: str, embedding: list[float]):
        """Store a user fact with its embedding."""
        point_id = hashlib.md5(f"{user_id}:{fact}".encode()).hexdigest()
        self.client.upsert(
            collection_name=self.collection_name,
            points=[PointStruct(
                id=point_id,
                vector=embedding,
                payload={"user_id": user_id, "fact": fact},
            )],
        )

    def recall(self, user_id: str, query_embedding: list[float], top_k: int = 5):
        """Retrieve the most relevant facts for a user given a query."""
        results = self.client.query_points(
            collection_name=self.collection_name,
            query=query_embedding,
            query_filter={"must": [{"key": "user_id", "match": {"value": user_id}}]},
            limit=top_k,
        )
        return [hit.payload["fact"] for hit in results.points]

El flujo es el siguiente: (1) tras cada conversación, un LLM extrae los hechos clave de la interacción (“el usuario tiene una alta tolerancia al riesgo”, “el usuario está interesado en acciones de semiconductores”), (2) dichos hechos se incrustan y se almacenan en Qdrant, (3) al inicio de la próxima conversación, el agente realiza una consulta a Qdrant con el nuevo mensaje del usuario para recuperar el contexto relevante.

Puntuación de recuperación: más allá de la similitud coseno

La similitud coseno en bruto constituye un punto de partida, pero los sistemas de memoria para entornos de producción requieren mecanismos de recuperación más sofisticados. Artículo sobre Agentes Generativos (Park et al., 2023) introdujeron una función de puntuación que combina tres señales:

La puntuación final de recuperación es una suma ponderada: score = alpha * recency + beta * importance + gamma * relevance. Eso evita que los hechos recientes e importantes queden ocultos bajo otros obsoletos pero semánticamente similares. Para el Agente Analista de Mercado, Otorgo la mayor ponderación a la relevancia (0.5), seguida de la recencia (0.3) e importancia (0.2), ya que la intención de la consulta actual del usuario es lo más relevante. Estas son ponderaciones iniciales adaptadas del artículo sobre Agentes Generativos (que aplicaba un peso igual a cada factor); he observado que dar mayor énfasis a la relevancia funciona mejor en las consultas de análisis financiero, pero estos valores se basan en intuición y no están optimizados empíricamente.

Alternativas a la búsqueda vectorial

La búsqueda vectorial es muy potente, pero no siempre es la herramienta adecuada. Estos son los casos en los que conviene recurrir a alternativas:

EnfoqueMejor paraCoste operativo principal
Búsqueda vectorial (Qdrant)Recuperación semántica de hechos no estructuradosEmbedding y el ciclo de vida del índice
Almacén clave-valor (Redis)Perfiles de usuario estructurados y preferenciasPolítica de uso de memoria y persistencia
Almacén de documentos (archivos)Conocimiento del proyecto y notas gestionadas por el agenteConcurrencia, permisos y búsqueda
Búsqueda de texto completo (PostgreSQL) índice GIN)**Recuperación de palabras clave a partir del historial de conversaciónCrecimiento del índice y ajuste de consultas
Gráfico de conocimiento (Neo4j)Relaciones entre entidades y consultas de múltiples saltosModelado de grafos y otro sistema de datos
Híbrido (vector + palabra clave)Recuerde el caso en que la intención de la consulta varíaDos rutas de puntuación para ajustar y evaluar

Los almacenes clave-valor son ideales para datos estructurados. Si su memoria a largo plazo corresponde a un perfil de usuario —tolerancia al riesgo, horizonte de inversión, sectores preferidos—, utilizar un hash de Redis o una columna JSONB en PostgreSQL resulta más sencillo y rápido que embedding y realizar búsquedas por vectores. Empiece a emplear la búsqueda vectorial cuando los datos estén desestructurados y las consultas de recuperación varíen en su redacción.

El almacén integrado de LangGraph ofrece una interfaz clave-valor basada en espacios de nombres, con búsqueda vectorial opcional. El BaseStore API es sencillo: put(), get(), search(), y delete() con alcance de nombres de espacio jerárquicos. Están disponibles tres implementaciones:

El index La configuración permite realizar búsquedas vectoriales en los elementos almacenados mediante un modelo embedding configurable. En la mayoría de los casos de uso, este almacén integrado es suficiente para no necesitar recurrir a una base de datos vectorial dedicada.

from langgraph.store.memory import InMemoryStore

# Create a store with vector search enabled
store = InMemoryStore(
    index={
        "dims": 1536,
        "embed": my_embedding_function,  # e.g., OpenAI text-embedding-3-small
    }
)

# Store a user preference (namespace scopes to user)
await store.aput(
    namespace=("user", "user-123", "preferences"),
    key="risk-profile",
    value={"risk_tolerance": "high", "horizon": "long-term"},
)

# Semantic search across user's memories
results = await store.asearch(
    namespace=("user", "user-123"),
    query="What is their investment style?",
    limit=5,
)

Elección de una estrategia de memoria a largo plazo

Comience con el formato clave-valor si su memoria está estructurada y bien definida (perfiles de usuario, configuraciones, entidades nombradas). Agregue la búsqueda vectorial cuando necesite recuperación semántica de datos no estructurados o cuando la formulación de las consultas varíe de forma impredecible.

Gráficos de conocimiento resultan esenciales cuando las relaciones entre entidades son cruciales, por ejemplo: “¿Qué empresas sobre las que preguntó el usuario son competidoras de NVDA?”. El proyecto más interesante desarrollado recientemente en este ámbito es Graphiti (by Zep), el cual construye un gráfico de conocimiento consciente del tiempo que registra cuándo eran verdaderos los hechos, y no solo qué era cierto. Cada arista incluye intervalos de validez, de modo que cualquier cambio en la tolerancia al riesgo del usuario invalida el valor anterior en lugar de sobrescribirlo silenciosamente. Graphiti genera informes 94,8 % de precisión en el DMR benchmark, Y su modelo bitemporal soluciona el problema de la memoria obsoleta en la capa de datos.

El problema radica en el ámbito operativo. Ejecutar una base de datos gráfica no es sencillo, y para la mayoría de las aplicaciones de agentes, la búsqueda vectorial con filtrado de metadatos permite lograr los mismos resultados con menos infraestructura.

Memoria gestionada frameworks como Mem0 y Letta (formerly MemGPT) se encargan de realizar la extracción, consolidación y recuperación pipeline por usted. El enfoque de Mem0 es destacable: un LLM extrae las memorias candidatas, un motor de decisión compara cada nuevo hecho con las entradas existentes en el almacén vectorial, y un resolvedor decide si añadirlo, actualizarlo o eliminarlo, lo que mantiene el almacén de memorias coherente y sin redundancias. Letta adopta un enfoque propio de los sistemas operativos: los agentes gestionan su propia ventana de contexto mediante herramientas de gestión de memoria, moviendo de forma autónoma los datos entre la “memoria principal” (dentro del contexto) y la “memoria de archivo” (fuera del contexto). Ambos enfoques merecen ser evaluados si se busca acelerar el tiempo de puesta en producción y no se necesita un control total sobre la pipeline de memoria.


Memoria de documentos: el archivador del agente

La memoria basada en archivos cuenta con una mayor adopción por parte de los productos que con una mayor representación en las taxonomías de memoria mencionadas anteriormente. En una evaluación LoCoMo realizada por un proveedor, Letta informó El 74,0 % se debe al enfoque basado en su sistema de archivos. Es posible mantener dicho resultado dentro de las condiciones de su modelo, benchmark, y harness, pero la ventaja operativa es fácil de observar: los desarrolladores pueden leer, editar e identificar las diferencias en el conocimiento almacenado directamente.

Las ventanas de contexto más extensas también permiten que la lectura de archivos completos sea viable para ciertos documentos de proyecto. La recuperación por fragmentos sigue siendo adecuada para corpus grandes, pero un archivo breve con convenciones o información de transferencia suele poder cargarse directamente. La elección depende del tamaño del documento, de la precisión en la recuperación, del presupuesto de contexto y de la frecuencia con la que es necesario revisar o editar esa memoria.

Los almacenes vectoriales y los backends de tipo clave-valor gestionan de forma eficaz la recuperación semántica y las búsquedas estructuradas. Sin embargo, existe una tercera categoría de conocimiento del agente que ninguno de estos sistemas aborda adecuadamente: el contexto acumulado del proyecto, es decir, las convenciones, notas de investigación y decisiones que el agente necesita a lo largo de las sesiones, y que se benefician de poder ser leídos por humanos y estar bajo control de versiones.

Esto es la memoria de documentos: el agente lee y escribe archivos estructurados (Markdown, JSON, YAML) en un directorio conocido. Sin embeddings, sin base de datos, sin infraestructura. Solo archivos en disco a los que tanto el agente como el desarrollador pueden acceder. cat, grep, git diff, y se edita a mano.

¿Por qué archivos?

En los flujos de trabajo de agentes de larga duración, el patrón más eficaz que he observado no es una base de datos vectorial, sino un directorio de notas bien organizadas. Piense en lo que ocurre cuando un agente de programación trabaja en un proyecto durante semanas:

Estos datos están demasiado estructurados como para ser procesados mediante búsqueda vectorial (se requiere una recuperación exacta, no una similitud difusa), y son demasiado numerosos para almacenarse en un sistema de tipo clave-valor (forman documentos interconectados, no datos aislados). Además, se trata de información que el desarrollador desea ver y modificar directamente. Si el agente aprende algo incorrecto, basta con abrir el archivo y corregirlo.

Así es como de Claude Code CLAUDE.md y .claude/ Trabajo en directorios. El agente lee a nivel de proyecto CLAUDE.md archivos con las convenciones e instrucciones, y realiza escrituras en ~/.claude/MEMORY.md Para el aprendizaje entre sesiones. Los archivos son Markdown puro: los lees, los editas, los commits a Git y los compartes con tu equipo. Cursor’s .cursorrules y El windsurfing .windsurfrules archivos de texto plano que el agente carga al iniciarse para obtener el contexto del proyecto.

Implementación de un almacén en memoria para archivos

La implementación es deliberadamente sencilla. El agente dispone de cuatro operaciones: escribir un documento, leer un documento, listar los documentos disponibles y realizar búsquedas entre ellos por palabra clave.

Desde file_memory.py:

from pathlib import Path
import json
import fnmatch

class FileMemory:
    """Document memory backed by the local filesystem.

    Stores agent knowledge as human-readable files organized by topic.
    No embeddings, no database — just files that both the agent and
    the developer can read, edit, and version-control.
    """

    def __init__(self, base_dir: str | Path):
        self.base_dir = Path(base_dir)
        self.base_dir.mkdir(parents=True, exist_ok=True)

    def write_doc(self, path: str, content: str, metadata: dict | None = None):
        """Write or overwrite a document at the given path.

        Paths are relative to base_dir. Directories are created automatically.
        Metadata (if provided) is stored as a JSON sidecar file.
        """
        full_path = self.base_dir / path
        full_path.parent.mkdir(parents=True, exist_ok=True)
        full_path.write_text(content, encoding="utf-8")

        if metadata:
            meta_path = full_path.with_suffix(full_path.suffix + ".meta")
            meta_path.write_text(json.dumps(metadata, indent=2), encoding="utf-8")

    def read_doc(self, path: str) -> str | None:
        """Read a document by path. Returns None if not found."""
        full_path = self.base_dir / path
        if full_path.exists():
            return full_path.read_text(encoding="utf-8")
        return None

    def list_docs(self, pattern: str = "**/*") -> list[str]:
        """List documents matching a glob pattern."""
        return [
            str(p.relative_to(self.base_dir))
            for p in self.base_dir.glob(pattern)
            if p.is_file() and not p.name.endswith(".meta")
        ]

    def search_docs(self, query: str, pattern: str = "**/*.md") -> list[dict]:
        """Search documents by keyword. Returns matching files with context.

        This is intentionally simple — grep-style keyword search.
        For semantic search, use a vector store instead.

        NOTE: This is a sketch for demonstration. A simple substring check
        won't scale beyond a few hundred documents. For production with 500+
        documents, use TF-IDF/BM25 scoring (e.g., rank_bm25) or a full-text
        search backend (PostgreSQL GIN index, Elasticsearch).
        """
        results = []
        for path in self.base_dir.glob(pattern):
            if not path.is_file() or path.name.endswith(".meta"):
                continue
            content = path.read_text(encoding="utf-8")
            if query.lower() in content.lower():
                # Return the paragraph containing the match for context
                for paragraph in content.split("\n\n"):
                    if query.lower() in paragraph.lower():
                        results.append({
                            "path": str(path.relative_to(self.base_dir)),
                            "match": paragraph.strip()[:500],
                        })
        return results

Estructura de carpetas

La mayor parte del valor de la memoria de documento proviene de la forma en que está organizado el directorio. Esta es la estructura que utilizo para el Agente Analista de Mercado:

.agent-memory/
    README.md                  # What this directory is, for human readers
    user-profiles/
        user-123.md            # Preferences, history, risk profile
        user-456.md
    research/
        NVDA-2026-02.md        # Research notes from recent analysis
        TSLA-2026-01.md
    conventions/
        analysis-format.md     # How to structure analysis reports
        data-sources.md        # Preferred data sources and API patterns
    learnings/
        common-errors.md       # Mistakes the agent has learned to avoid
        tool-patterns.md       # Effective tool call sequences

Cada archivo es de formato Markdown. El propósito de cada archivo se deduce claramente a partir de su ruta. Puedes git diff el directorio completo de memoria para conocer qué aprendió el agente durante una sesión. git revert Un mal proceso de aprendizaje, o bien copiar el directorio a otro proyecto. Intente realizar cualquiera de estas acciones con una colección de Qdrant.

Cuándo utilizar memoria de documento frente a vectores o clave-valor

Los tres backend de memoria satisfacen patrones de acceso diferentes:

DimensiónAlmacén de vectoresAlmacén clave-valorAlmacén de documentos
Patrón de consulta”Buscar hechos similares a X”Obtener el valor asociado a la clave.
Mejor paraRecuperación de información no estructurada y diversaBúsquedas estructuradasContexto del proyecto, notas
Legible para humanosNo (embeddings)Parcialmente (JSON)
DepurableFácil (claves exactas)Trivial (abrir el archivo)
Versión controlableNoPosibles
Embedding infraestructuraRequeridoNo es necesarioNo es necesario
Escalabilidad hastaMillones de hechosMillones de clavesMiles de documentos
Capacidad de búsquedaSimilitud semánticaCoincidencia exactaBasado en palabras clave/rutas

Utilice la memoria de documento cuando:

Utilice almacenes vectoriales cuando:

Utilice almacenes clave-valor cuando:

En la práctica, los agentes en entorno de producción suelen combinar los tres tipos. El Agente Analista de Mercado Utiliza PostgreSQL checkpoints como almacenamiento en memoria rápida, Qdrant para la recuperación semántica de datos relacionados con los usuarios, y un almacén de documentos basado en archivos para guardar las convenciones del proyecto y las notas de investigación.

Ejemplos del mundo real

El patrón ya está muy extendido en los asistentes de codificación AI:

El elemento común: todos ellos almacenan el conocimiento del agente como archivos de texto legibles por humanos, con operaciones explícitas de lectura y escritura. No existe embeddings. Tampoco hay infraestructura vectorial. El agente decide qué escribir, el desarrollador puede ver y editar todo, y todo el sistema cabe en un git diff.

Más allá de los asistentes de programación

La memoria de documentación no está limitada a los agentes de programación. Este patrón se observa en dominios de agentes muy diversos:

El Taller MemAgents en el ICLR 2026

Las habilidades utilizan documentos para encapsular instrucciones procedimentales. El Estándar de Habilidades de Agente almacena esas instrucciones en SKILL.md Archivos que contienen frontmatter en formato YAML y un cuerpo en Markdown. Esto se asemeja a la memoria de documento a nivel de capa de almacenamiento, pero su función es distinta: una habilidad indica al agente cómo realizar un tipo específico de tarea, mientras que la memoria registra los hechos aprendidos de un proyecto o de ejecuciones anteriores. Parte 3 Aborda dicha distinción desde la perspectiva de la herramienta.

MCP (Protocolo de contexto del modelo) sigue la misma lógica: las definiciones de herramientas son archivos JSON Schema que cualquier agente puede descubrir y utilizar. El protocolo tiene 97 millones de descargas mensuales de SDK Además, cuenta con el soporte de OpenAI, Google, Microsoft y AWS. MCP no está relacionado específicamente con la programación. Estos mismos servidores conectan a los agentes con bases de datos, APIs internos y sistemas empresariales.

Ambos apuntan al mismo patrón: conocimiento procedimental almacenado como documentos sometidos a esquemas, con operaciones de lectura/escritura explícitas. MCP, que ahora está regulado por el Agentic AI Fundamento, Se trata de lo más cercano a un estándar de interoperabilidad que existe en el ecosistema de agentes.

Escalado de la memoria de documentos para entornos de producción

El límite de archivos en un único nodo se vuelve evidente: no es posible escalar la entrada/salida de archivos de forma horizontal, las escrituras concurrentes requieren bloqueo, y gestionar los permisos entre diferentes usuarios es complicado. En entornos de producción se necesita un almacén de respaldo capaz de manejar adecuadamente la concurrencia, la búsqueda y el modelo multiusuario.

Tres enfoques comunes:

Enfoque A: híbrido con una capa de base de datos ligera

Mantenga los archivos para la fase de creación (los desarrolladores editan el Markdown localmente), pero sirva el contenido desde una base de datos en runtime. Durante el despliegue, sincronice los archivos con las filas de PostgreSQL. El agente lee la información directamente de la base de datos, y no del disco. Esto le brinda:

Enfoque B: almacenamiento de objetos + sidecar de índice vectorial

Los documentos se almacenan en S3/GCS como objetos, y existe una colección de Qdrant que indexa sus embeddings. El agente consulta Qdrant en busca de los IDs de los documentos relevantes y, a continuación, obtiene su contenido desde el almacenamiento de objetos. Este enfoque permite escalar horizontalmente y soporta búsquedas semánticas, pero añade complejidad: se deben gestionar dos sistemas, mantener una embedding pipeline, y garantizar la consistencia eventual entre el almacenamiento y el índice.

Enfoque C: almacén de documentos estructurado con PostgreSQL (recomendado)

Almacene los documentos como filas JSONB en PostgreSQL, aprovechando la búsqueda de texto completo mediante índices GIN y, opcionalmente, vectores embeddings (pgvector). De este modo, podrá contar con una búsqueda híbrida (basada en palabras clave y semántica), transacciones ACID, así como un único sistema operativo para gestionar todo.

Un esquema del Enfoque C:

from typing import Optional
import asyncpg

class ProductionDocumentMemory:
    """PostgreSQL-backed document memory with hybrid search.

    Schema:
        CREATE TABLE documents (
            id SERIAL PRIMARY KEY,
            tenant_id TEXT NOT NULL,
            path TEXT NOT NULL,
            content TEXT NOT NULL,
            metadata JSONB,
            embedding vector(1536),  -- pgvector extension
            ts_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED,
            created_at TIMESTAMPTZ DEFAULT NOW(),
            UNIQUE(tenant_id, path)
        );
        CREATE INDEX ON documents USING GIN(ts_vector);
        CREATE INDEX ON documents USING ivfflat(embedding vector_cosine_ops);
    """

    def __init__(self, pool: asyncpg.Pool):
        self.pool = pool

    async def write(
        self,
        tenant_id: str,
        path: str,
        content: str,
        metadata: Optional[dict] = None,
        embedding: Optional[list[float]] = None,
    ):
        """Write or update a document."""
        async with self.pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO documents (tenant_id, path, content, metadata, embedding)
                VALUES ($1, $2, $3, $4, $5)
                ON CONFLICT (tenant_id, path) DO UPDATE
                SET content = EXCLUDED.content,
                    metadata = EXCLUDED.metadata,
                    embedding = EXCLUDED.embedding
                """,
                tenant_id, path, content, metadata, embedding,
            )

    async def search(
        self,
        tenant_id: str,
        query: str,
        embedding: Optional[list[float]] = None,
        limit: int = 5,
    ) -> list[dict]:
        """Hybrid search: full-text + optional vector similarity."""
        async with self.pool.acquire() as conn:
            if embedding:
                # Hybrid scoring: 0.6 * text relevance + 0.4 * vector similarity
                rows = await conn.fetch(
                    """
                    SELECT path, content, metadata,
                           (0.6 * ts_rank(ts_vector, plainto_tsquery('english', $2)) +
                            0.4 * (1 - (embedding <=> $3))) AS score
                    FROM documents
                    WHERE tenant_id = $1
                      AND ts_vector @@ plainto_tsquery('english', $2)
                    ORDER BY score DESC
                    LIMIT $4
                    """,
                    tenant_id, query, embedding, limit,
                )
            else:
                # Full-text search only
                rows = await conn.fetch(
                    """
                    SELECT path, content, metadata,
                           ts_rank(ts_vector, plainto_tsquery('english', $2)) AS score
                    FROM documents
                    WHERE tenant_id = $1
                      AND ts_vector @@ plainto_tsquery('english', $2)
                    ORDER BY score DESC
                    LIMIT $3
                    """,
                    tenant_id, query, limit,
                )
            return [dict(row) for row in rows]

Qué obtendrá:

Los archivos son ideales para flujos de trabajo con un único desarrollador. En entornos de producción multiinquilino, un almacén de documentos estructurado basado en PostgreSQL suele ofrecer el equilibrio óptimo entre sencillez, rendimiento y madurez operativa.


Integrándolo todo: la arquitectura completa

Así es como funcionan conjuntamente los tres niveles de memoria en el Agente Analista de Mercado. El diagrama muestra el flujo completo desde la solicitud del usuario hasta la respuesta, con todas las capas de memoria activas.

Arquitectura de memoria completa

La arquitectura cuenta con tres vías de memoria:

  1. Ruta crítica (checkpoint store): Cada nodo de LangGraph escribe su estado de grafo reanudable en el checkpoint store. Cuando el grafo llega a un interrupt_before node (al igual que el reportero en Parte 1), Se producen pausas en la ejecución. El usuario puede cerrar la aplicación y, al volver, el gráfico reanuda su proceso a partir del checkpoint. Los registros de eventos y las trazas de Runtime constituyen cuestiones distintas relacionadas con la operación en producción.

  2. Ruta en frío (almacén a largo plazo): Al inicio de cada conversación, el agente consulta el almacén a largo plazo en busca de contexto de usuario relevante. Al final, extrae y almacena nuevos hechos. Este proceso se ejecuta de forma asíncrona; por lo tanto, nunca debe bloquear al reasoning loop principal.

  3. Ruta del documento (almacén de archivos): Al iniciarse, el agente carga las convenciones del proyecto y las notas de investigación relevantes desde el almacén de documentos. Durante la ejecución, escribe nuevos resúmenes de investigación y los patrones aprendidos de vuelta en el disco. A diferencia de la ruta en frío, las lecturas de documentos son síncronas (ya que sirven para informar sobre la tarea actual), mientras que las escrituras pueden ser diferidas.

El cableado en LangGraph es sencillo: el checkpoint store y el long-term store se pasan durante la compilación del grafo, mientras que el document store se introduce como una dependencia. El boceto local que aparece a continuación utiliza InMemoryStore Por lo tanto, el fragmento se mantiene breve; la topología de Docker de referencia utiliza Qdrant para desempeñar la misma función relacionada con la recuperación semántica.

from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from langgraph.store.memory import InMemoryStore

# Hot memory: PostgreSQL for durable checkpoints
checkpointer = await create_postgres_checkpointer(pg_connection_string)

# Cold memory: local sketch with vector search
# (The reference Docker topology uses Qdrant for persistent recall.)
memory_store = InMemoryStore(
    index={"dims": 1536, "embed": embedding_function}
)

# Document memory: file-based store for project knowledge
doc_memory = FileMemory(base_dir=".agent-memory")

# Checkpoint store and long-term store wired into the graph
graph = create_graph(
    checkpointer=checkpointer,
    store=memory_store,
)

# The store is accessible inside any node via the store parameter
def planner_node(state: AgentState, *, store: BaseStore) -> dict:
    """Plan with user context from long-term memory."""

    # Recall relevant user facts from vector store
    user_memories = store.search(
        namespace=("user", state.user_id),
        query=state.messages[-1].content,
        limit=5,
    )

    # Load project conventions from document memory
    conventions = doc_memory.read_doc("conventions/analysis-format.md")

    # Inject both into planning context
    memory_context = "\n".join(m.value["fact"] for m in user_memories)
    # ... rest of planning logic with personalized context and conventions

El flujo completo

¿Qué ocurre cuando un usuario que ya ha iniciado sesión envía “Analizar TSLA” al Agente Analista de Mercado:

  1. Carga de memoria de los documentos: Al iniciarse, el agente lee las convenciones del proyecto desde el almacén de documentos: preferencias de formato de análisis, fuentes de datos preferidas y patrones de uso de herramientas. Todo esto establece el comportamiento de referencia.

  2. Recuperación de memoria a frío: Antes de que el nodo del router ejecute la acción, el grafo consulta el almacenamiento a largo plazo en busca del mensaje del usuario. De allí obtiene la información siguiente: “El usuario tiene una alta tolerancia al riesgo”, “El usuario prefiere análisis detallados de los competidores” y “El usuario ya investigó previamente a NVDA y AMD”.

  3. Router + Planner: La clase de router lo clasifica como DEEP_RESEARCHEl planificador genera un plan de investigación de 5 pasos, personalizado en función de las preferencias recuperadas. Incluye una fase de análisis de competidores, ya que el historial del usuario indica que este la desea. El plan sigue el formato establecido en el documento de convenciones.

  4. Bucle del ejecutor (memoria activa): Cada paso se ejecuta mediante el patrón ReAct desde Parte 1. Tras cada nodo (router, planificador y cada paso del ejecutor), LangGraph escribe un checkpoint en PostgreSQL. Si el proceso se bloquea después del paso 3 de un total de 5, se reinicia la ejecución para continuar desde el paso 4.

  5. Interrupción HITL: El gráfico alcanza el reporter nodo con interrupt_before. El borrador del informe se encuentra en el checkpoint. El usuario lo revisa unas horas después, y el gráfico carga el checkpoint y continúa su proceso.

  6. Actualizaciones de memoria: Una vez finalizada la conversación: (a) un proceso asíncrono extrae nuevos hechos del usuario (“el usuario ahora está haciendo seguimiento a TSLA”, “el usuario aprobó el formato del informe”) y los almacena en el repositorio de vectores a largo plazo, y (b) el agente escribe un resumen de la investigación en el repositorio de documentos.research/TSLA-2026-02.md) para futuras referencias.

El patrón de tres capas permite separar las responsabilidades de forma clara y estructurada. El almacén checkpoint se encarga de garantizar la durabilidad y la reanudación de operaciones; corresponde a la infraestructura. El almacén a largo plazo se utiliza para la personalización; forma parte de la lógica del producto. Por su parte, el almacén de documentos alberga todo el conocimiento acumulado sobre los proyectos; funciona como el cuaderno de notas del agente.


Compromisos y consideraciones

La memoria aporta valor, pero también incrementa los costes y la complejidad. Hay que ser sinceros respecto a estos compromisos:


Conclusiones principales

  1. La memoria del agente está compuesta por varios almacenes con patrones de acceso diferentes. Es necesario mantener separados los datos checkpoints reanudables, los hechos estructurados, la recuperación semántica y los documentos del proyecto.
  2. Implementar funcionalidades de pausa y reanudación antes de proceder con la personalización. La pérdida del progreso de una tarea es el primer fallo de memoria que presenta un agente de ejecución prolongada.
  3. Guardar los hechos deterministas en almacenamiento estructurado. Utilizar búsquedas vectoriales cuando la consulta sea vaga y la redacción varíe.
  4. Emplear archivos para el conocimiento del proyecto que las personas necesiten inspeccionar, editar, versionar o revisar mediante comparaciones de diferencias.
  5. Establecer reglas de vencimiento, conflicto y eliminación para cada tipo de memoria. Una memoria que el sistema no pueda corregir se convierte en deuda técnica.
  6. Limitar lo que se envía al modelo. La memoria almacenada solo tiene valor cuando su recuperación introduce las pruebas adecuadas en el contexto actual.

La siguiente capa corresponde a la acción

Parte 3, AI Agente Tool Use en 2026, Pasa del estado almacenado a la acción. Se analiza cómo un agente descubre y llama a las herramientas, así como cómo los límites de estas devuelven errores que el reasoning loop puede utilizar. Las partes 5 y 6 vuelven a la memoria desde el punto de vista operativo: el runtime restaura un checkpoint, mientras que el harness decide qué contenido debe incluirse en la transferencia hacia la siguiente sesión del modelo.

Referencias

Artículos científicos

Documentación de LangGraph

Checkpoint servidores backend

Bases de datos vectoriales y herramientas de memoria

Memoria basada en documentos y archivos

Memoria frameworks

Benchmarks

Talleres

Proyecto de demostración


El código completo del agente Market Analyst, incluida la arquitectura de memoria descrita en esta publicación, se encuentra en GitHub Si deseas seguir la lectura._

Serie: Ingeniería de la pila Agentic