Tipos de memoria de agentes y su coste real
Tabla de memoria semántica, episódica y procedimental, con el coste de almacenarla y volver a generar embeddings en un VPS. Incluye tamaños y límites prácticos.
Qué son los tres tipos de memoria de los agentes
Los tipos de memoria de los agentes se dividen en tres categorías, y cada una tiene un impacto distinto en el hardware que se paga: la memoria semántica contiene hechos, la memoria episódica contiene lo que ocurrió y la memoria procedimental contiene cómo realizar una tarea. La tabla siguiente define cada tipo con un ejemplo de servidor. Todo lo que aparece después es la parte que normalmente no se documenta: cuánto cuesta almacenar cada tipo y cuánto cuesta reconstruirlo.
The data behind this chart
[
{
"label": "Semantic",
"what_it_holds": "Facts the agent should treat as currently true",
"server_example": "The database listens on 10.8.0.4:5432 and the nightly dump runs at 03:15 UTC"
},
{
"label": "Episodic",
"what_it_holds": "A record of one past event or session",
"server_example": "On 2026-08-11 the deploy failed because the disk was full, and rotating logs fixed it"
},
{
"label": "Procedural",
"what_it_holds": "How to carry out a task, as steps the agent can run",
"server_example": "The restore runbook: stop the service, load the dump, run migrations, start the service"
}
]Los nombres proceden de la psicología humana, pero la correspondencia es aproximada. La división es útil por una razón práctica: los tres tipos tienen tamaños y procesos de recuperación diferentes. Si se almacenan todos en un único almacén vectorial, el resultado es peor para cada tipo.
La memoria semántica es pequeña y conviene editarla manualmente
Varios cientos de datos sobre sus propios servidores ocupan unas decenas de kilobytes de texto. El almacenamiento no es el problema. La corrección sí. Un dato incorrecto en la memoria semántica será incorrecto en todas las respuestas posteriores del agente, por lo que el almacén debe permitir localizar un dato por nombre, cambiarlo y confirmar que el valor antiguo ha desaparecido.
Esto apunta a un almacén con claves: una tabla de Postgres con una clave primaria o un directorio de archivos Markdown pequeños en git. Ambos permiten ejecutar una consulta, ver el valor y editarlo directamente. La búsqueda por similitud no ofrece ese control, porque recupera contenido por semejanza en lugar de hacerlo por clave. «Cambiar el puerto de la base de datos» se convierte en «buscar cada fragmento que mencione el puerto de la base de datos», y no se puede demostrar que se hayan encontrado todos. Mantenga los datos asociados a claves. También puede generar embeddings para obtener búsquedas más flexibles, pero trate la copia asociada a claves como la fuente de verdad.
Los datos obsoletos no se anuncian. El puerto cambia y la fila permanece, por lo que el agente sigue respondiendo con un número que era correcto en junio. Una política de obsolescencia y depuración para la memoria del agente es la otra mitad de esta página y resulta mucho más barato diseñarla mientras la tabla todavía es pequeña.
Por qué la memoria episódica crece sin límite
La memoria episódica es un registro, y los registros crecen. Cada sesión, cada llamada a una herramienta y cada comando fallido puede convertirse en un episodio. Un agente que escribe una fila por turno escribirá en un mes muchas más filas de las que nadie llegará a leer, y el disco no es el único coste: cada episodio indexado también se incorpora al índice que debe recorrer la búsqueda.
Decida la regla de retención el día que cree la tabla, mientras eliminar todavía sea sencillo. Dos preguntas resuelven la mayor parte del problema. Primero, qué merece escribirse: normalmente, el resumen de una sesión sí; la salida completa de un ls -la normalmente no. Segundo, cuánto tiempo debe conservarse cada clase de episodio: por ejemplo, episodios sin procesar durante 30 días y resúmenes de sesión durante un año.
Asigne a cada fila de episodio una marca de tiempo created_at y una columna source. Sin created_at no puede eliminar por antigüedad. Sin source no puede eliminar todo lo que llegó de un mismo origen defectuoso, que es exactamente lo que necesita el día en que descubre que una página web o un ticket estaba escribiendo instrucciones en la memoria.
DELETE FROM episodes WHERE created_at < now() - interval '30 days';Ejecute esto desde un temporizador de systemd y compruebe después que el número de filas y el tamaño de la tabla cambian realmente. Una política de retención que nadie ejecuta es un comentario.
psql -d agentmem -c "SELECT count(*) FROM episodes;"
psql -d agentmem -c "SELECT pg_size_pretty(pg_total_relation_size('episodes'));"La memoria procedimental debe almacenarse en un repositorio
La memoria procedimental define cómo realiza el agente una tarea: un shell script, un archivo de skill o un runbook con pasos numerados. Eso es código, y el código debe estar donde se almacena el código: en un repositorio git con revisiones, versiones y un diff legible.
Si almacena un runbook como fragmentos vectorizados, recuperará una copia aproximada. La recuperación devuelve los fragmentos con la puntuación más alta. Por eso, el agente puede actuar sobre el paso 2 y el paso 5 mientras el paso 3 no aparece. Además, no queda registrado qué versión del procedimiento se ejecutó. En git, git log responde a ambas preguntas. El coste de almacenamiento es casi nulo, que es otra razón para no pagar precios de almacenamiento vectorial por ello.
El coste real de un embedding en disco
The data behind this chart
[
{
"label": "bge-small-en-v1.5 (384 dims)",
"bytes_per_vector": 1544,
"mib_per_100k_rows": 147.2
},
{
"label": "bge-base-en-v1.5 (768 dims)",
"bytes_per_vector": 3080,
"mib_per_100k_rows": 293.7
},
{
"label": "bge-large-en-v1.5 (1024 dims)",
"bytes_per_vector": 4104,
"mib_per_100k_rows": 391.4
},
{
"label": "text-embedding-3-small (1536 dims)",
"bytes_per_vector": 6152,
"mib_per_100k_rows": 586.7
},
{
"label": "text-embedding-3-large (3072 dims)",
"bytes_per_vector": 12296,
"mib_per_100k_rows": 1172.6
}
]pgvector almacena un vector con 4 bytes por dimensión y una cabecera de 8 bytes. Por tanto, este cálculo es fijo y puede planificarlo antes de cargar datos. Un vector de 384 dimensiones ocupa 1544 bytes, por lo que 100,000 chunks ocupan 147.2 MiB de vectores. El mismo corpus, generado con 3,072 dimensiones, ocupa 1172.6 MiB, a razón de 12296 bytes por fila. El texto es el mismo, pero el almacenamiento es casi ocho veces mayor.
Esto corresponde sólo a la columna de vectores. El texto del chunk, la clave primaria, la sobrecarga de las filas y el índice se añaden aparte. El índice es el componente que suele olvidarse. HNSW (hierarchical navigable small world, el índice de grafos que crea pgvector) mantiene su propia copia de los vectores que enlaza. Por eso, un almacén indexado ocupa bastante más del doble de las cifras anteriores. Mida su caso en lugar de hacer estimaciones.
SELECT pg_size_pretty(pg_total_relation_size('memories')) AS total,
pg_size_pretty(pg_relation_size('memories_embedding_idx')) AS idx;La RAM determina si las búsquedas responden rápido, porque el grafo sólo se recorre con rapidez mientras permanece en memoria. Cuando el índice supera la memoria que Postgres puede asignarle, las búsquedas empiezan a leer del disco y la latencia aumenta. La compilación tiene su propio límite, maintenance_work_mem. Cuando el grafo lo supera, la compilación lo indica y se ralentiza:
NOTICE: hnsw graph no longer fits into maintenance_work_mem after 61440 tuples
HINT: Increase maintenance_work_mem to speed up builds.Hay dos opciones para reducir el tamaño del mismo corpus. Elija un modelo más pequeño: 384 dimensiones ocupan una cuarta parte de lo que ocupan 1,536 dimensiones y, para volver a encontrar sus propias notas, la diferencia de precisión suele ser suficientemente pequeña como para aceptarla. También puede almacenar los vectores en precisión media: el tipo halfvec usa 2 bytes por dimensión y la misma cabecera de 8 bytes. Esto reduce casi a la mitad tanto la columna como su índice.
Conviene conocer un límite antes de elegir un modelo. En agosto de 2026, una columna vector puede indexarse hasta 2,000 dimensiones. Por tanto, una embedding de 3,072 dimensiones es aceptada por la columna, pero rechazada por el índice:
ERROR: column cannot have more than 2000 dimensions for hnsw indexhalfvec permite indexar hasta 4,000 dimensiones. Por eso, la solución habitual es indexar la conversión de tipo:
CREATE INDEX ON memories USING hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops);Cuándo pgvector supera a un servicio de memoria independiente
Si el servidor ya ejecuta Postgres, los vectores se reducen a un paquete y una instrucción.
psql -V
sudo apt install postgresql-16-pgvectorCREATE EXTENSION vector;El número del nombre del paquete corresponde a la versión principal de Postgres. En Ubuntu 24.04 es 16, así que lea psql -V antes de escribirlo.
Mantener la memoria en esa base de datos permite usar una única copia de seguridad para la memoria y los datos de la aplicación al mismo tiempo, un único pool de conexiones y transacciones: el hecho y la fila que lo describe se confirman juntos o fallan juntos. Un servicio independiente no puede garantizarlo.
Cambie a un servicio de memoria dedicado cuando se cumpla una de estas condiciones. La carga de búsqueda compite con la aplicación y necesita su propio servidor. Varios agentes en varios hosts comparten una memoria. O quiere la lógica de extracción y deduplicación incluida en un producto terminado. Ese es el motivo para usar un servidor de memoria Mem0 autoalojado. Para un agente y un corpus de unos pocos millones de fragmentos, pgvector en el servidor que ya ejecuta requiere menos operaciones y ofrece menos puntos de fallo. La elección del motor y los requisitos de RAM de cada motor se explican en ejecutar una base de datos vectorial en un VPS.
Qué cuesta volver a generar los embeddings al cambiar de modelo
Los vectores generados por dos modelos distintos no son comparables. Por tanto, no puede generar embeddings para las memorias nuevas con otro modelo y dejar intactas las filas antiguas. Una tabla mixta devuelve resultados sin sentido, porque una distancia calculada entre dos sistemas de coordenadas distintos no representa ningún valor útil. Cambiar de modelo implica volver a generar los embeddings de todo el corpus.
Ese coste tiene cuatro componentes: los tokens (un cargo de API, o tiempo de CPU y GPU en su propio equipo), el tiempo transcurrido mientras se ejecuta el proceso, el espacio de disco necesario para mantener ambas columnas durante la actualización y la reconstrucción del índice al final. El orden seguro es añadir una columna nueva, rellenarla por lotes, cambiar la consulta y, después, eliminar la columna antigua y su índice.
Mida la velocidad en su propio hardware en lugar de confiar en una cifra publicada, porque generar embeddings usando sólo la CPU en un VPS pequeño es mucho más lento que ejecutar el mismo modelo en una GPU. Cronometre un fragmento representativo y multiplique el resultado por el tamaño del corpus.
ollama pull nomic-embed-text
time curl -s http://localhost:11434/api/embed \
-d '{"model": "nomic-embed-text", "input": "one representative chunk of your corpus"}' > /dev/nullUn modelo local para generar embeddings también almacena sus pesos en el mismo disco que el almacén de memorias, y dónde almacena Ollama los modelos descargados explica dónde se utiliza ese espacio.
Hay un requisito que hace posible todo este proceso: conserve el texto de origen junto a cada vector. Un almacén que contiene sólo vectores no se puede procesar de nuevo, porque ya no queda nada que entregar al modelo nuevo. Si no puede responder a «qué texto produjo esta fila», la ruta de migración consiste en reconstruirlo todo desde el origen inicial del texto.
Qué se debe supervisar cuando la memoria está en funcionamiento
El coste no es lo único que cambia a medida que el almacén se llena. Los datos antiguos quedan desactualizados y los episodios antiguos desplazan los resultados útiles. El problema vuelve a ser la poda. Un almacén de memoria también es una entrada modificable para el comportamiento futuro del agente. Por tanto, cualquier elemento que pueda escribir en él puede influir en el agente más adelante. Si el texto de páginas web o tickets llega a la memoria, lea cómo funciona el envenenamiento de la memoria de los agentes antes de ampliar los elementos que pueden escribir en ella. El tamaño de recuperación también determina el consumo de tokens en cada solicitud. Ahí comienza cómo mantener predecible el coste operativo de un agente.
FAQ
¿Necesito una base de datos vectorial para la memoria de un agente?
No para los hechos. La memoria semántica es pequeña y debe corregirse por nombre, por lo que una tabla con claves o un directorio de archivos Markdown en git resulta más adecuado: permite ver un valor y editarlo. Los embeddings justifican su coste cuando es necesario recuperar información por significado en un corpus demasiado grande para enumerarlo. Esto suele corresponder a la memoria episódica y a los documentos. Si ya ejecuta Postgres, CREATE EXTENSION vector cubre ese caso sin añadir otro servicio que administrar.
¿Cuánto espacio de disco utilizará un almacén de memoria de agente?
El tamaño de los vectores es predecible: 4 bytes por dimensión más una cabecera de 8 bytes en pgvector. Con 768 dimensiones, son 293.7 MiB por cada 100,000 filas, y con 384 dimensiones son 147.2 MiB. Después hay que añadir el texto de los fragmentos, la sobrecarga de las filas y un índice HNSW que mantiene su propia copia de los vectores. Por tanto, reserve como mínimo el doble de la cifra de los vectores y mida el valor real con pg_total_relation_size.
¿Dónde debe residir la memoria procedimental?
En un repositorio git, como scripts o archivos de habilidades que el agente ejecute directamente. Un procedimiento necesita una recuperación exacta y un historial de versiones, y la búsqueda por similitud no proporciona ninguna de las dos cosas. Un runbook dividido en fragmentos devuelve las partes con la puntuación más alta. Esto puede hacer que lleguen los pasos 2 y 5 mientras falta el paso 3, y no queda registrado qué versión se ejecutó.
¿Cuál es el coste de cambiar el modelo de embeddings?
Hay que volver a generar los embeddings de todo el corpus, porque no se pueden comparar entre sí los vectores de modelos diferentes. Reserve presupuesto para el coste de los tokens o el tiempo de GPU, el espacio de disco para mantener simultáneamente las columnas antigua y nueva, y la reconstrucción del índice. Añada la columna nueva, rellénela por lotes, cambie la consulta y elimine después la columna antigua. Todo esto requiere haber conservado el texto original junto a cada vector.