📦 Clona y dale ⭐ a stop-ai-agents-losing-memory-sample-for-aws
La memoria del agente tiene la respuesta. El usuario hace la pregunta. Y la búsqueda no devuelve nada.
stored: dietary_notes: "Vegetarian; severe shellfish allergy — strictly no
crustaceans or mollusks."
asked: "What should I avoid eating when I go out for dinner on this trip?"
keyword scan: 4 hits, answer found: False
Eso es una corrida real, no un experimento mental. La pregunta no nombra ninguna clave y no comparte palabras con la nota almacenada, así que la memoria key-value del post anterior nunca la encuentra. La respuesta estuvo en el store todo el tiempo.
Esta es la línea divisoria de la búsqueda semántica: ¿conocés la clave, o solo la intención? Cuando las preguntas dejan de coincidir con claves, recuperás por significado: embebés cada memoria una vez al escribir, embebés la pregunta al consultar, y devolvés los vecinos más cercanos por similitud coseno. Este post mide dos cosas (si la búsqueda semántica encuentra lo que la búsqueda por palabras clave pierde, y qué vector store se adapta a tu deployment) usando los mismos embeddings y las mismas memorias del repo de referencia.
(Post 2 de una serie; el intro mapea todos los tipos de memoria. El código usa Strands Agents, un SDK open source; el patrón aplica a cualquier framework de agentes.)
¿Por qué la memoria key-value no encuentra la pregunta?
Porque una lectura key-value es una búsqueda que alguien diseñó de antemano, y esta pregunta no mapea a ninguna clave. El demo almacena 10 memorias sobre un viajero (datos de perfil, notas, episodios) y hace la pregunta de la cena contra tres stores. El key-value store tiene exactamente dos movimientos, y los dos fallan honestamente:
-
Keyword scan: busca palabras de la pregunta en claves y valores. Devuelve 4 resultados, ninguno la nota de alergia, porque "avoid eating at dinner" no comparte palabras con
dietary_notesni con "shellfish". Answer found: False. - Dump-all fallback: darle al modelo toda la memoria y dejar que la lea. Funciona, a un costo que crece con cada memoria que agregás. Para estas 10 memorias son 647 caracteres por pregunta; para cientos de notas son miles de tokens, en cada pregunta, para siempre.
Esto no es un bug de la memoria key-value. Las búsquedas por perfil ("¿cuál es mi cabina preferida?") siguen siendo exactas, instantáneas y sin costo de embeddings, que es por eso que el post anterior las construyó así. El límite aparece solo cuando la pregunta es semántica. Esa es la señal para agregar una segunda forma de acceso, no para reemplazar la primera.
¿Cómo lo encuentra la búsqueda semántica?
Comparando significados en lugar de palabras. Cada memoria se embebe una vez al momento de escribir en un vector (aquí: Amazon Titan Text Embeddings V2, 1.024 dimensiones). Al consultar, la pregunta se embebe y el store devuelve los vecinos más cercanos por similitud coseno:
top hit: "Vegetarian; severe shellfish allergy — strictly no crustaceans
or mollusks." (score 0.231)
answer found: True
Sin palabras compartidas entre la pregunta y la nota. Están cerca en significado, y el significado es lo que se indexó. Los dos backends de abajo devuelven el mismo resultado porque usan los mismos embeddings; lo que difiere es todo lo que hay alrededor de la consulta.
FAISS o Amazon S3 Vectors? Misma accuracy, diferente deployment
Los dos son embedding vector stores. Usan el mismo modelo (Titan V2), el mismo algoritmo (similitud coseno), y devuelven el mismo resultado con el mismo score. La accuracy es idéntica: no es un trade-off de calidad.
| Store | Encuentra la respuesta | Similarity score |
|---|---|---|
| Key-value (keyword scan) | No | — keyword miss |
| FAISS — Facebook AI Similarity Search, índice in-process de Meta | Sí | 0.231 |
| Amazon S3 Vectors (managed cloud) | Sí | 0.231 |
La diferencia está en el deployment. FAISS es una librería in-process: cero infraestructura, un pip install, corre local al proceso. Provee persistencia en disco via faiss.write_index / faiss.read_index. En este demo el índice no se persiste y se reconstruye desde cero cada corrida. S3 Vectors es un servicio managed de AWS: el índice vive en un bucket en la nube, accesible desde cualquier proceso con credenciales AWS, sin cluster que administrar ni escalar.
El demo usa las mismas credenciales AWS para los dos: embeddings de Titan via Bedrock y S3 Vectors via boto3; el mismo setup de aws configure los alimenta a los dos, por eso no requiere configuración adicional dentro de un workflow de Strands Agents. El demo auto-provisiona el bucket y el índice en la primera corrida: create_vector_bucket → create_index (1.024 dims, coseno) → put_vectors / query_vectors.
El costo que comparten los dos backends: embeber la pregunta cuesta ~510 ms con Titan V2. El tiempo de query del índice (0.09 ms para FAISS, 195 ms para S3 Vectors) es secundario a eso. Planificá el embedding call en cualquier path sensible a latencia, independientemente del vector store que uses.
¿Necesitás una vector database?
Depende del patrón de queries. AWS posiciona S3 Vectors como "ideal para workloads con queries menos frecuentes", que describe exactamente la memoria de un agente: un agente consulta las memorias de un usuario unas pocas veces por conversación, no miles de veces por segundo.
| FAISS | Amazon S3 Vectors | Vector database dedicada | |
|---|---|---|---|
| Tipo | Librería in-process | AWS vector storage | Motor de base de datos completo |
| Ejemplos | — | — | OpenSearch, Qdrant, Weaviate, Milvus, pgvector, Chroma |
| Accuracy semántica | ✅ igual | ✅ igual | ✅ igual |
| Infraestructura | Ninguna — pip install | Ninguna — fully managed | Self-hosted o managed |
| Máx. vectores | Memoria del proceso | Hasta 2 mil millones por índice | Depende del deployment |
| Query latency | ~0.09 ms | ~100–200 ms | Sub-10 ms a alto QPS |
| Hybrid search | ❌ | ❌ | ✅ la mayoría lo soporta |
| Mejor para | Prototipo / agente local | Agente cloud, queries infrecuentes | Alto QPS, filtros avanzados, producción |
La decisión:
| Necesitás | Usá | Por qué |
|---|---|---|
| Datos bajo claves conocidas (perfil, preferencias) | Key-value (post 1) | Exacto e instantáneo; no pagués ~510 ms de embedding para un lookup |
| Búsqueda semántica, local / prototipo | FAISS | Cero infraestructura, pip install, in-process |
| Búsqueda semántica, cloud / queries infrecuentes | S3 Vectors | AWS vector storage managed, latencia subsegundo, hasta 2 mil millones de vectores |
| Alto QPS, hybrid search o filtros avanzados | Vector DB dedicada | OpenSearch, Qdrant, Weaviate, Milvus, pgvector, Chroma |
| Preguntas multi-hop sobre relaciones | Graph (próximo post) | La búsqueda semántica encuentra piezas; no puede seguir aristas entre ellas |
Lo que este demo no cubre: FAISS y S3 Vectors son storage backends. Almacenan vectores y recuperan por similitud. Construir qué recordar (extraer hechos específicos de conversaciones, deduplicación, memoria estructurada entre sesiones) lo manejan servicios de memoria managed como Amazon Bedrock AgentCore Memory. Esa técnica es el tema de un próximo post de esta serie.
¿Cómo elige el agente entre key lookup y búsqueda semántica?
Por los docstrings de las herramientas, solo. El último test del demo conecta las dos herramientas de recall a un agente de Strands:
@tool
def recall_by_key(key: str) -> str:
"""Recall a memory when the question maps to a known identifier.
Use when the user asks about a stored field: "my preferred cabin",
"my home airport"..."""
@tool
def recall_semantic(question: str, top_k: int = 3) -> str:
"""Recall memories by meaning when no key is obvious.
Use for open questions: "what should I avoid eating on this trip?"..."""
Con la pregunta de la cena, el agente llama recall_semantic; con "¿cuál es mi cabina preferida?", llama recall_by_key. Sin lógica de routing, sin prompt engineering. La frase when to use this al inicio de cada docstring es lo que el modelo lee para decidir. Escribila descuidadamente y el agente paga la latencia del embedding en lookups de perfil.
¿Cómo le pedís a un asistente de código que construya esto?
La calidad de la implementación de búsqueda semántica que construya tu asistente depende de las decisiones que nombres en el prompt. Sin nombrarlas, por defecto embebera todo y consultará un índice único. Estas cinco instrucciones codifican lo que este post midió:
- "Agregá búsqueda semántica solo para preguntas que no mapean a claves; mantené los datos de perfil en key-value state." De lo contrario, el asistente embebe cada query, incluyendo lookups exactos que ya tienen una clave conocida.
- "Embebé cada memoria una vez, al momento de escribir; solo la pregunta se embebe al momento de consultar." Los asistentes tienden a re-embeber todo el store por query.
- "Usá una sola función de embedding para almacenamiento y consultas, y especificá el modelo y las dimensiones." Embedders distintos producen scores de similitud silenciosamente incorrectos.
- "Dame dos herramientas de recall con docstrings de 'cuándo usar': por clave y por significado." El agente rutea por pregunta desde esas frases; sin código de routing.
- "Hacé el deployment explícito: índice in-process para un prototipo local, vector storage managed para un deployment en cloud, y probalo con un test de cliente nuevo que siga viendo todos los vectores."
El repo de referencia implementa y mide los cinco. Correlo para ver cada decisión en acción.
¿Cómo corrés el demo?
git clone https://github.com/elizabethfuentes12/stop-ai-agents-losing-memory-sample-for-aws
cd stop-ai-agents-losing-memory-sample-for-aws/02-vector-memory-demo
uv venv && uv pip install -r requirements.txt
uv run python test_vector_memory.py
Necesitás credenciales AWS (aws configure) para los embeddings de Titan y S3 Vectors. El demo crea el vector bucket y el índice automáticamente si no existen. OPENAI_API_KEY solo se necesita para la conversación del agente en el notebook (o cambiá una línea por Amazon Bedrock); las mediciones de retrieval corren sin ningún LLM.
FAQ
¿Una vector database es lo mismo que la memoria de un agente de IA?
No. Una vector database es un posible backend para un tipo de memoria (recuperación por significado). La memoria del agente es el sistema completo: key-value state, vector o graph storage, reglas de selección e higiene. Muchos agentes en producción necesitan retrieval vectorial sin una vector database.
¿Puedo usar una vector database como memoria de agente?
Sí, para las memorias que consultarás por significado. Pero primero ruteá los datos con clave conocida (preferencias, configuraciones) a key-value storage: un lookup directo no cuesta nada, mientras que cada vector query paga el embedding call de la pregunta (~510 ms con Titan V2) antes de tocar el índice.
¿Cuándo necesito algo más que S3 Vectors?
Cuando cambia el patrón de queries. Las vector databases dedicadas como OpenSearch, Qdrant, Weaviate, Milvus, pgvector y Chroma están diseñadas para alto QPS, hybrid search, agregaciones y filtros avanzados. S3 Vectors es purpose-built para queries infrecuentes: maneja hasta 2 mil millones de vectores por índice con latencia subsegundo, que cubre workloads de memoria de agente mucho más allá del prototipo.
¿Cuál es la latencia real end-to-end?
FAISS: 0.09 ms de query al índice + ~510 ms de embedding = ~0.5 s total. S3 Vectors: 195 ms de query al índice + ~510 ms de embedding = ~0.7 s total. El índice rara vez es tu cuello de botella; el embedding call sí lo es.
¿Por qué mi búsqueda semántica devuelve memorias incorrectas?
Las causas más comunes: el store y las consultas usan modelos o dimensiones de embedding distintos, las memorias se embebieron con texto desactualizado, o datos de perfil con clave contaminaron el índice. Usá un solo embedder para todo, embebé al escribir, y mantené los datos de perfil fuera del vector store.
Recursos
- Repo de referencia — demo 02 con los tests medidos y el notebook
- Amazon S3 Vectors — User Guide y limitaciones
- Amazon Titan Text Embeddings V2
- FAISS, la librería de búsqueda por similitud de Meta
- Zep: A Temporal Knowledge Graph Architecture for Agent Memory, Rasmussen et al., 2025
- From RAG to Memory: Non-Parametric Continual Learning for LLMs (HippoRAG 2), 2025
Gracias!
🇻🇪 Dev.to Linkedin GitHub Twitter Instagram Youtube



Top comments (0)