programa
La mayoría de los agentes con LLM empiezan de cero en cada ejecución. Olvidan el nombre del usuario, la última conversación y el archivo en el que estaba trabajando. Cualquier dato específico del usuario hay que volver a establecerlo turno a turno.
Este tutorial añade memoria persistente a un agente para que la siguiente ejecución continúe donde terminó la anterior. La capa de memoria es Supermemory, una API alojada que guarda hechos por usuario y los devuelve en una sola llamada. Construirás un entrenador personal de ejercicio en Python. El agente registra entrenamientos, sugiere la próxima sesión y recuerda preferencias y marcas recientes entre ejecuciones separadas del script.
La pila es mínima. Supermemory guarda la memoria. El OpenAI Agents SDK ejecuta el bucle del agente. El entrenador consta de dos archivos de Python y un archivo pyproject.toml.
Necesitarás Python 3.10 o superior, una cuenta de OpenAI, una cuenta de Supermemory y soltura básica con la línea de comandos.
Construir agentes de IA con Google ADK
¿Qué es Supermemory?
Supermemory se describe mejor como una API de memoria para agentes de IA. Cuando le envías a Supermemory cadenas sobre tu usuario, más tarde devuelve una vista compacta de quién es ese usuario y qué ha estado haciendo recientemente. La incrustación, la indexación y la recuperación se ejecutan dentro de Supermemory, así que tu código de agente se mantiene pequeño.
El benchmark LongMemEval mide lo bien que un sistema de memoria responde a preguntas sobre un historial largo de conversación. Supermemory recuerda el 81,6% de los hechos correctos. Zep, el siguiente mejor sistema, obtiene un 71,2%, una diferencia de 10 puntos que se traduce en aproximadamente 1 respuesta correcta extra por cada 10 preguntas del usuario. El repositorio open-source tiene más de 22k estrellas en GitHub, otra señal de uso real.
Memoria vs RAG
Quien llega buscando una herramienta de memoria para agentes suele haber usado RAG antes. Es útil situar Supermemory al lado. RAG y la memoria resuelven problemas distintos y a menudo conviven en el mismo agente.
Un sistema RAG apunta a un corpus de documentos que el desarrollador prepara una vez: manuales de producto, artículos de soporte, documentación interna. El corpus se carga al desplegar, se consulta en tiempo de ejecución y rara vez cambia. El agente lo usa para responder preguntas cuya respuesta ya está en el producto.
Un sistema de memoria apunta al usuario. Supermemory escribe hechos específicos del usuario conforme el agente habla con él, y el almacén crece con cada conversación. El agente lo usa para responder preguntas que solo el propio usuario puede responder: preferencias, historial y actividad reciente.

En un producto real, ambos funcionan en paralelo. RAG sobre la base de conocimiento de la empresa responde «¿cuál es nuestra política de devoluciones?». Supermemory responde a la del usuario: «¿Cuánto hice de press banca la semana pasada?». Mismo agente, dos almacenes de datos, dos trabajos.
Perfiles de usuario: hechos estáticos y dinámicos
La idea principal de Supermemory es el perfil de usuario. Cada registro se clasifica en dos cubos: hechos estáticos que rara vez cambian y hechos dinámicos sobre la actividad actual. Los patrones recurrentes ascienden a estáticos. La actividad reciente permanece en dinámicos.
Cuando el agente lee el perfil, una sola llamada devuelve ambos cubos más los fragmentos de memoria relevantes.
La separación importa porque los hechos estáticos y dinámicos responden a preguntas distintas sobre el mismo usuario:
|
Hechos estáticos |
Hechos dinámicos |
|
Entrena en casa con mancuernas y una barra de dominadas |
Foco actual: fuerza de tren superior |
|
Lesión en la rodilla izquierda, sin sentadillas profundas |
Último press banca: 4 series de 5 repeticiones con 185 lb |
|
Quiere añadir 20 lb al banca antes de fin de año |
Esta semana trabaja dominadas tipo grease-the-groove |
|
Entrena solo por las tardes, nunca por las mañanas |
Ayer corrió 5 km en 28 minutos |
Lee la primera fila. La parte estática dice cómo entrena el usuario: en casa, con su propio material. Eso no cambia semana a semana. La parte dinámica dice en qué está trabajando ahora mismo: tren superior, en este ciclo.
Un recomendador de entrenamientos necesita ambas. La parte estática descarta ejercicios solo de gimnasio, la dinámica elige la sesión de hoy.
Detrás de ese perfil, Supermemory hace cuatro trabajos que, de otro modo, tendrías que construir: guarda memorias crudas, crea embeddings de cada fragmento, ejecuta búsqueda por similitud al leer y extrae hechos del perfil a partir de lo registrado. Nada de eso aparece en tu código.

Cada memoria se etiqueta con una cadena que el desarrollador elige. Cada lectura pasa la misma cadena para limitar lo que sale. El entrenador fija una etiqueta porque un único usuario basta para mostrar cómo funciona el perfil. Las apps reales calculan la etiqueta a partir del usuario autenticado, como su JWT.
Configurar tu entorno de Supermemory
El entrenador necesita dos claves de API (Supermemory y OpenAI) y un proyecto Python con tres dependencias. Un script de ida y vuelta rápido confirma que ambas claves funcionan antes de que el código del agente las toque.
Obtener tus claves de API
La clave de API de Supermemory está en console.supermemory.ai, NO en app.supermemory.ai. El subdominio app es el producto de memoria para consumidores (para guardar notas y explorar tu espacio). No tiene página de claves de API. Sáltatelo y ve directo a la consola.
En console.supermemory.ai:
-
Inicia sesión.
-
Haz clic en API Keys en la barra lateral.
-
Haz clic en Create API Key.
-
Ponle un nombre (la demo del tutorial usa
datacamp-tutorial). -
Copia la clave resultante. Empieza por
sm_.

También necesitas una clave de OpenAI para las llamadas LLM del agente. Consigue una en platform.openai.com/api-keys si aún no la tienes.
Crea un archivo .env en la raíz de tu proyecto con ambas claves. No lo subas al repositorio.
SUPERMEMORY_API_KEY=sm_your_key_here
OPENAI_API_KEY=sk-your_key_here
La capa gratuita de Supermemory cubre este tutorial sin introducir datos de pago. Los límites exactos están en la página de precios.
Instalar dependencias
El tutorial usa uv para la configuración y ejecución del proyecto. Si no tienes uv, instálalo una vez con el one-liner de astral.sh/uv.
Inicializa el proyecto:
uv init supermemory-trainer
cd supermemory-trainer
Elimina el README.md autogenerado que añade uv init. El hello.py autogenerado se sobrescribirá en el siguiente paso, así que déjalo por ahora.
Añade tres dependencias:
-
supermemory==3.37.0es el cliente de memoria, fijado a la versión verificada para este tutorial. -
openai-agents es el OpenAI Agents SDK. El nombre del paquete lleva guion, la ruta de importación es
agents. -
python-dotenvlee el archivo.envque acabas de crear.
uv add supermemory==3.37.0 openai-agents python-dotenv
El pyproject.toml resultante:
[project]
name = "supermemory-trainer"
version = "0.1.0"
description = "Personal exercise trainer agent built with Supermemory and the OpenAI Agents SDK."
requires-python = ">=3.10"
dependencies = [
"openai-agents>=0.10.2",
"python-dotenv>=1.2.1",
"supermemory==3.37.0",
]
Verificar tu configuración
Antes de escribir código de agente, mira a Supermemory trabajar una vez sobre una sola frase. El script siguiente envía un hecho a Supermemory, espera a la canalización y luego lee el perfil. Si esto se ejecuta bien, las claves funcionan y el SDK es accesible. La salida también te da una primera idea de lo que hace Supermemory con texto en bruto.
Abre hello.py en la raíz del proyecto y sustituye el cuerpo autogenerado por los imports y una llamada de escritura:
import time
from dotenv import load_dotenv
from supermemory import Supermemory
load_dotenv()
client = Supermemory()
USER_ID = "demo_warmup"
response = client.add(
content="The user is learning Supermemory by building a personal trainer agent.",
container_tag=USER_ID,
)
print(f"client.add() -> id={response.id} status={response.status}")
load_dotenv() lee la clave de API desde .env al entorno antes de construir Supermemory(). El cliente recoge SUPERMEMORY_API_KEY automáticamente. El valor container_tag="demo_warmup" acota este hecho a un usuario desechable.
Ahora añade la espera y la lectura al final del mismo archivo:
print("Waiting 20 seconds for processing...")
time.sleep(20)
prof = client.profile(container_tag=USER_ID, q="learning")
print(f"profile.static ({len(prof.profile.static)}): {prof.profile.static}")
print(f"profile.dynamic ({len(prof.profile.dynamic)}): {prof.profile.dynamic}")
print(f"search_results.results ({len(prof.search_results.results)}):")
for r in prof.search_results.results[:3]:
print(f" - {r['memory']} (similarity={r['similarity']:.3f})")
La espera de 20 segundos da tiempo a la canalización de embedding y extracción de Supermemory para procesar la nueva memoria. Sin ella, la lectura no devuelve nada y el script parece roto cuando no lo está.
Ejecuta el archivo:
uv run python hello.py
Salida esperada:
client.add() -> id=zNLsJBrY1PZupAeZ3Qn6EL status=queued
Waiting 20 seconds for processing...
profile.static (0): []
profile.dynamic (1): ['Building a personal trainer agent to learn Supermemory.']
search_results.results (1):
- Building a personal trainer agent to learn Supermemory. (similarity=0.650)
Hay tres detalles importantes en esta salida. client.add() devuelve inmediatamente con status="queued", ya que Supermemory procesa los documentos asíncronamente. La espera de 20 segundos cubre la canalización de embedding y extracción. Para cuando se ejecuta la lectura, la frase original ya es un fragmento de memoria consultable.
La línea interesante es profile.dynamic. La entrada era la frase «The user is learning Supermemory by building a personal trainer agent.» La salida es el hecho dinámico 'Building a personal trainer agent to learn Supermemory.'. Supermemory reescribió una frase en tercera persona en un hecho en primera persona sobre el usuario. Es el extractor de perfiles haciendo su trabajo.
profile.static es una lista vacía. Los hechos estáticos se consolidan con el tiempo, tras acumular varios registros relacionados, así que una única escritura de calentamiento no produce ninguno. La herramienta de sugerencias del entrenador cuenta con ello y trata static como un extra, no como garantía.
Construir un agente con Supermemory: entrenador personal en Python
El entrenador envuelve client.add() y client.profile() en dos herramientas del agente, para que las lecturas y escrituras ocurran automáticamente mientras chateas. El historial de entrenamientos encaja bien en memoria: equipamiento, lesiones y marcas recientes no están en los datos de entrenamiento del LLM y se acumulan sesión a sesión.

Estructura del proyecto y el agente
El entrenador es lo bastante pequeño como para que todo el proyecto quepa en dos archivos Python más el pyproject.toml que ya tienes:
supermemory-trainer/
├── .env # tus claves reales (gitignored)
├── .env.example # marcadores de posición, se comitea
├── .gitignore
├── .python-version
├── main.py # definición del agente, prompt del sistema, bucle REPL
├── pyproject.toml
└── tools.py # log_workout y suggest_next_session
tools.py contiene las dos herramientas con memoria que escribirás ahora. log_workout escribe un entrenamiento en Supermemory vía client.add(). suggest_next_session lee el perfil del usuario vía client.profile(). main.py importa ambas y cablea el agente.
La mayor parte de main.py es boilerplate del OpenAI Agents SDK. Una frase en el prompt del sistema hace el trabajo de Supermemory: todo hecho sobre el usuario debe llegar vía llamadas a herramientas. Al agente se le dice que no tiene memoria propia. Esa única regla es lo que convierte al entrenador en memory-backed.
Abre main.py y empieza con los imports y el prompt del sistema:
import asyncio
from agents import Agent, Runner, SQLiteSession
from tools import log_workout, suggest_next_session
SYSTEM_PROMPT = """You are a personal exercise trainer who logs the user's
workouts and recommends what to do next.
You have no memory of the user's history on your own. Every fact about the
user lives in Supermemory and reaches you only through tool calls.
Two rules, no exceptions:
1. Whenever the user reports completing a workout, call log_workout immediately, before responding. Extract the exercise, sets, reps, weight, and any notes from what they said. If a value is missing, ask one short follow-up question instead of guessing. After logging, confirm in one short sentence and stop. Do NOT recommend the next session unless the user asks for one.
2. When the user explicitly asks what to do next (or asks for a recommendation, suggestion, or plan), call suggest_next_session first. Never recommend from your own training data. The tool returns the user's
recent activity, stable preferences, and matching past sessions. Reference those facts directly in your reply.
Keep replies concise (2-4 sentences). Be specific: name the exercise, sets, reps, and weight. Honor any injuries or equipment constraints the tool surfaces.
"""
Ambas reglas del prompt del sistema obligan al modelo a pasar por Supermemory.
La regla 1 fuerza una llamada a log_workout siempre que el usuario informe de un entrenamiento, para que cada sesión llegue al almacén de memoria. La regla 2 obliga a leer con suggest_next_session antes de recomendar, así toda recomendación se basa en lo que sabe Supermemory.
Sáltate esas reglas y el agente responderá desde sus datos de entrenamiento, lo que invalida la capa de memoria.
Ahora define el agente y el bucle de chat en el mismo archivo:
def build_agent() -> Agent:
return Agent(
name="Trainer",
instructions=SYSTEM_PROMPT,
tools=[log_workout, suggest_next_session],
model="gpt-5",
)
async def chat() -> None:
agent = build_agent()
session = SQLiteSession(session_id="trainer-cli")
print("Trainer ready. Type a message, or 'exit' to quit.\n")
while True:
try:
message = input("You: ").strip()
except (EOFError, KeyboardInterrupt):
print()
break
if not message:
continue
if message.lower() in {"exit", "quit"}:
break
result = await Runner.run(agent, message, session=session)
print(f"\nTrainer: {result.final_output}\n")
if __name__ == "__main__":
asyncio.run(chat())
Hay dos líneas en ese bloque que conviene destacar. tools=[log_workout, suggest_next_session] registra las dos herramientas con memoria. El decorador @function_tool en cada una (en tools.py) le dice al SDK que son invocables. Sin el decorador, el agente no tiene herramientas en tiempo de ejecución, aunque la construcción se complete.
SQLiteSession(session_id="trainer-cli") mantiene el historial de turnos a corto plazo dentro del proceso de Python en ejecución. Supermemory guarda los hechos del usuario a largo plazo entre procesos. Matar el proceso de Python elimina la sesión de SQLite, pero los datos de Supermemory permanecen.
Importante: Ejecuta main.py como script, no en una celda de Jupyter, ya que el bucle de eventos de Jupyter entra en conflicto con asyncio.run(). El cliente síncrono Supermemory() funciona dentro de funciones de herramienta asíncronas porque el Agents SDK ejecuta herramientas en un pool de hilos. Para más detalles del propio SDK, consulta el tutorial de OpenAI Agents SDK.
Escribir la herramienta de registro de entrenamientos
log_workout es el lado de escritura de la memoria del agente. La función recibe argumentos estructurados del agente: ejercicio, series, repeticiones, peso y notas opcionales. Los convierte en una frase corta en inglés y la entrega a Supermemory mediante client.add(). La canalización de embedding y extracción se ejecuta dentro de Supermemory y no necesita nada del entrenador.
Abre tools.py y empieza con los imports y un único cliente compartido:
from agents import function_tool
from dotenv import load_dotenv
from supermemory import Supermemory
load_dotenv()
USER_ID = "demo_user"
client = Supermemory()
load_dotenv() se ejecuta al importar para que SUPERMEMORY_API_KEY esté en el entorno antes de construir Supermemory(). Si construyes el cliente antes de cargar el entorno, obtendrás un cliente no autenticado y la primera llamada devolverá un 401 confuso. Ambas funciones de herramienta en este archivo comparten ese cliente y la constante USER_ID.
Añade la herramienta de registro debajo del cliente:
@function_tool
def log_workout(
exercise: str,
sets: int,
reps: int,
weight: float,
notes: str = "",
) -> str:
"""Log a completed workout to the user's memory.
Args:
exercise: Name of the exercise.
sets: Number of sets performed.
reps: Number of reps per set.
weight: Weight in pounds. Pass 0 for bodyweight or cardio.
notes: Optional notes about the session.
"""
print(f"[log_workout] {exercise=} {sets=} {reps=} {weight=} {notes=}")
content = f"Performed {exercise}: {sets} sets of {reps} reps at {weight} lbs."
if notes:
content += f" Notes: {notes}"
response = client.add(content=content, container_tag=USER_ID)
print(f"[log_workout] -> id={response.id} status={response.status}")
return f"Logged {exercise} ({sets}x{reps} @ {weight} lb)."
El docstring del @function_tool es lo que ve el LLM al decidir si llamar a la herramienta. El bloque Args: mapea descripciones por parámetro. Ambos forman parte del contrato del agente con la función.
La herramienta envía una frase en lenguaje natural a client.add(), no JSON. El extractor de perfiles de Supermemory lee lenguaje natural e infiere hechos. JSON funciona técnicamente, pero la calidad de extracción baja porque el modelo no tiene una narrativa que resumir. «Performed bench press: 4 sets of 5 reps at 185.0 lbs» le da al extractor una frase limpia con la que trabajar.
Las dos llamadas print() escriben cada invocación de herramienta en la terminal: primero los args parseados y luego la respuesta.
[log_workout] exercise='bench press' sets=4 reps=5 weight=185.0 notes=''
[log_workout] -> id=xY7AK3qLzBPx5Vd2HnRf1M status=queued
El valor status="queued" coincide con lo que devolvió el script de calentamiento. El registro crudo está guardado, pero client.profile() no lo devolverá como resultado de búsqueda hasta que la canalización termine. Más tarde añadirás una verificación que espere a que se estabilice.
Escribir la herramienta de sugerencias de entrenamiento
suggest_next_session es el lado de lectura, y aquí es donde compensa la división entre estático y dinámico. Una sola llamada client.profile(container_tag=USER_ID, q=focus) devuelve tres vistas del usuario en un único viaje.
Las preferencias estables llegan en profile.static, la actividad actual en profile.dynamic y los recuerdos pasados más cercanos como search_results.results. El trabajo de la herramienta es aplanar esas tres vistas en un único bloque de contexto que el agente pueda citar.
Tras unos cuantos entrenamientos, la herramienta produce algo como esto:
Recent activity:
- Trains at home instead of a gym
- Performed deadlift: 3 sets of 5 reps at 225.0 lbs
- Performed 5k run in 26 minutes
- Reports no knee pain during bench press
- Performed bench press: 4 sets of 5 reps at 185.0 lbs
Closest matching past entries:
- Trains at home instead of a gym
- Performed deadlift: 3 sets of 5 reps at 225.0 lbs
- Performed bench press: 4 sets of 5 reps at 185.0 lbs
- Performed 5k run in 26 minutes
- Reports no knee pain during bench press
El agente lee ese bloque y redacta una recomendación basada en el historial real del usuario. Sin el perfil de Supermemory, construirías ese mismo contexto tú mismo: una búsqueda semántica aparte, tu propio almacén de perfiles y fusionar los resultados. La única llamada client.profile() sustituye a las tres.
Añade esto a tools.py debajo de log_workout:
@function_tool
def suggest_next_session(focus: str) -> str:
"""Fetch the user's training history and preferences for a given focus.
Returns a context string the agent can use to recommend the next session.
The agent is responsible for the actual recommendation. This tool only
surfaces what Supermemory knows about the user.
Args:
focus: What the user wants to train next (e.g. "upper body", "legs",
"cardio", "today"). Drives semantic search against past logs.
"""
print(f"[suggest_next_session] focus={focus!r}")
profile = client.profile(container_tag=USER_ID, q=focus)
static_facts = profile.profile.static
dynamic_facts = profile.profile.dynamic
matches = profile.search_results.results
print(
f"[suggest_next_session] static={len(static_facts)} "
f"dynamic={len(dynamic_facts)} matches={len(matches)}"
)
sections = []
if static_facts:
sections.append("Stable preferences and constraints:")
sections.extend(f"- {fact}" for fact in static_facts)
if dynamic_facts:
sections.append("Recent activity:")
sections.extend(f"- {fact}" for fact in dynamic_facts)
if matches:
sections.append("Closest matching past entries:")
for r in matches[:5]:
sections.append(f"- {r['memory']}")
if not sections:
return (
"No prior training history found for this user. "
"Ask the user about their goals, equipment, and recent training."
)
return "\n".join(sections)
client.profile(container_tag=USER_ID, q=focus) devuelve un objeto ProfileResponse. Tras 5 registros cortos, los tres campos que lee la herramienta se ven así:
profile.profile.static # [] (list[str])
profile.profile.dynamic # ["Performed bench press: 4 sets of 5 reps at 185.0 lbs", ...]
profile.search_results.results # [{"memory": "...", "similarity": 0.631, ...}, ...] (list[dict])
Cada resultado de búsqueda es un dict de Python, no un objeto Pydantic. Usa r["memory"] para el texto y r["similarity"] para la puntuación. El dict completo tiene estas claves:
-
id -
memory -
rootMemoryId -
metadata -
updatedAt -
version -
similarity -
filepath -
documents
El snippet r.memory or r.chunk de la página de integración del OpenAI Agents SDK de Supermemory lanza AttributeError con supermemory==3.37.0. Usa acceso por corchetes.
static está vacío aquí, por eso la herramienta ramifica con if static_facts:. Las ramas de dynamic y search_results hacen el trabajo real en la primera docena de registros.
Supermemory también aplica un umbral de similitud por defecto. Un hecho que mencionaste una vez puede no volver en cada consulta. Los 5 registros anteriores volvieron para q="today", pero una cadena de consulta más específica podría devolver menos. La guarda if matches: lo maneja sin fallar.
Ejecutar la sesión 1: registrar entrenamientos
Inicia la sesión 1 y registra algunos entrenamientos para llenar Supermemory con algo que leer después. Ejecuta el script:
uv run python main.py
Registra press banca, luego una carrera de 5 km y después peso muerto, además de una preferencia: «Solo entreno en casa, no voy al gimnasio». El agente dispara log_workout una vez por entrenamiento, y las líneas print() de la herramienta hacen visible cada llamada en la terminal.

Salida de ejemplo. La redacción exacta de tu agente puede variar porque el modelo no es determinista.
Las tres líneas status=queued son el momento en que Supermemory toma el relevo. Cada una corresponde a un documento pasando por la canalización de embedding y extracción en el lado de Supermemory. Para registros cortos como estos, el documento pasa a ser consultable vía client.profile() en ~12 segundos.
Nada en el código del entrenador espera a eso. El agente sigue y Supermemory termina el trabajo en segundo plano.
Cada registro dispara exactamente una llamada a log_workout y el agente se detiene. Sin recomendaciones proactivas, sin llamadas extra, sin sugerencias de seguimiento. La primera regla del prompt del sistema hace ese trabajo. Sin la regla, el agente sugeriría la siguiente sesión tras cada registro, duplicando las llamadas a herramientas.
Escribe exit para cerrar la sesión 1. El proceso de Python termina y la SQLiteSession desaparece con él. Los registros de entrenamiento y la declaración de preferencia ahora viven en Supermemory bajo container_tag="demo_user", independiente del script que los escribió.
Verificar el recuerdo y ejecutar la sesión 2
Antes de la sesión 2, confirma que los hechos de la sesión 1 son consultables. Abre un REPL de Python nuevo o guarda esto como un script corto:
from dotenv import load_dotenv
from supermemory import Supermemory
load_dotenv()
client = Supermemory()
prof = client.profile(container_tag="demo_user", q="training")
print(f"static ({len(prof.profile.static)}): {prof.profile.static}")
print(f"dynamic ({len(prof.profile.dynamic)}):")
for fact in prof.profile.dynamic:
print(f" - {fact}")
print(f"matches ({len(prof.search_results.results)}):")
for r in prof.search_results.results[:5]:
print(f" - {r['memory']} (similarity={r['similarity']:.3f})")
Salida real capturada entre las dos sesiones:
static (0): []
dynamic (5):
- Trains at home instead of a gym
- Performed deadlift: 3 sets of 5 reps at 225.0 lbs
- Performed 5k run in 26 minutes
- Reports no knee pain during bench press
- Performed bench press: 4 sets of 5 reps at 185.0 lbs
matches (5):
- Trains at home instead of a gym (similarity=0.682)
- Performed deadlift: 3 sets of 5 reps at 225.0 lbs (similarity=0.643)
- Performed bench press: 4 sets of 5 reps at 185.0 lbs (similarity=0.631)
- Performed 5k run in 26 minutes (similarity=0.585)
- Reports no knee pain during bench press (similarity=0.585)
Fíjate en lo que produjo el extractor de Supermemory. El usuario dijo una vez: «Solo entreno en casa, no gimnasio». El extractor convirtió eso en el hecho dinámico "Trains at home instead of a gym".
El registro de banca incluía una nota sobre ausencia de dolor de rodilla. El extractor dividió ese único registro en dos hechos dinámicos: uno para el entrenamiento y otro para la ausencia de dolor.
Cuatro registros se convirtieron en cinco hechos dinámicos normalizados más cinco fragmentos de memoria coincidentes con similitudes entre 0.585 y 0.682. Nada de esa división, normalización o matching ocurrió en el código del entrenador. Si dynamic te sale vacío, espera 10 segundos más y vuelve a ejecutar el snippet. La cola de procesamiento a veces se dispara.
Ahora inicia la sesión 2 en un proceso totalmente nuevo:
uv run python main.py
Es un intérprete de Python fresco. Sin memoria compartida con la sesión 1. Sin caché caliente. Cualquier cosa que recuerde el agente viene de Supermemory.
Envía un mensaje: «What should I do for my workout today?»

Salida de ejemplo. Mismo almacén de memoria, proceso de Python nuevo.
El agente llama a suggest_next_session("today"). La herramienta imprime static=0 dynamic=5 matches=5. La ejecución capturada respondió con una sesión de tren inferior en casa (sentadillas, zancadas, step-ups).
La recomendación encajó con los registros previos porque el perfil de Supermemory se los dijo al agente. Banca, peso muerto y un 5k eran tren superior o cardio, y el usuario solo entrenaba en casa. Ambos hechos vinieron de la misma llamada a client.profile(). Tu ejecución lo formulará distinto porque el modelo no es determinista, pero la ruta de recuerdo es la misma.
Próximos pasos para tu agente con Supermemory
La demo es un usuario, dos herramientas y una CLI. Una versión real del entrenador se amplía en tres direcciones «con forma de Supermemory» antes de tocar el bucle del agente.
Acota la memoria por usuario real. La constante USER_ID = "demo_user" sirve para una persona. En producción, las apps calculan la etiqueta a partir del ID del usuario autenticado, como container_tag="user_sarah" o container_tag=customer_id. La memoria entre usuarios permanece separada porque cada lectura vuelve a pasar la etiqueta. Un cambio en tools.py, y no hace falta tocar nada más.
Añade más herramientas con memoria. Semanas de descarga, seguimiento de PRs y recordatorios semanales de movilidad. Cada una es otra función con @function_tool que llama a client.add() para escribir y a client.profile() para leer con la misma container_tag. La forma de la herramienta es la misma; solo cambia qué registra y qué pide el agente.
Gestiona fallos de Supermemory. Envuelve client.add() y client.profile() en try/except supermemory.APIError para que fallos transitorios de Supermemory no tumben el agente. Define timeouts por petición si tu agente corre en un entorno con restricciones.
El lado del bucle del agente es independiente de Supermemory y puede cambiar después. Pon una interfaz de Telegram, Discord o Slack delante de la CLI para que el usuario envíe un entrenamiento por texto y el bot llame a Runner.run(). O cambia de framework. Supermemory tiene una integración con LangChain si tu stack ya usa agentes de LangChain, y el código de memoria no cambia.
La división entre estático y dinámico también encaja en otros dominios.
- Agente de soporte al cliente: estático = problemas conocidos y preferencias de cuenta; dinámico = tickets abiertos y contactos recientes.
- Agente de programación: estático = lenguajes y frameworks preferidos; dinámico = tarea actual y archivos tocados recientemente.
La separación se sostiene siempre que la fuente de verdad sea el usuario.
Conclusión
Acabas de crear un entrenador en Python con dos herramientas y memoria persistente entre procesos. client.add() escribe entrenamientos. client.profile() lee al usuario como hechos estáticos, hechos dinámicos y coincidencias semánticas en una llamada, todo acotado por container_tag. Supermemory hace el troceado, embedding, búsqueda y extracción de perfil que la demo no tuvo que programar.
Combínalo con RAG, y el mismo agente responde preguntas sobre el usuario y sobre el producto. LLM Agents Explained cubre patrones de agentes más amplios, y el itinerario Associate AI Engineer for Developers ahonda más en agentes con memoria.
Preguntas frecuentes sobre Supermemory
¿Qué es Supermemory?
Supermemory es una API de memoria alojada que almacena, indexa y recupera contexto a largo plazo para que los agentes de IA recuerden a los usuarios entre sesiones.
¿En qué se diferencia Supermemory de una base de vectores convencional?
Supermemory añade embeddings, indexación, búsqueda semántica y extracción de hechos en formato perfil sobre el almacenamiento, así que obtienes memorias utilizables con una sola llamada a la API.
¿Puede Supermemory gestionar tanto RAG como memoria de usuario?
Sí, admite RAG de tipo documento sobre archivos y URLs, además de memorias centradas en el usuario, lo que permite que la misma API cubra conocimiento de producto e historial personal.
¿Necesito gestionar mis propios modelos de embedding con Supermemory?
No, Supermemory ejecuta por ti la canalización de embedding y recuperación; envías texto o contenido en bruto y lo consultas más tarde sin gestionar modelos o índices por tu cuenta.
¿Hay una capa gratuita para probar Supermemory?
Sí, hay un plan gratuito pensado para pruebas y proyectos pequeños, con límites mensuales de tokens y consultas para que puedas integrar y experimentar antes de actualizar.

Soy un creador de contenidos de ciencia de datos con más de 2 años de experiencia y uno de los mayores seguidores en Medium. Me gusta escribir artículos detallados sobre IA y ML con un estilo un poco sarcastıc, porque hay que hacer algo para que sean un poco menos aburridos. He publicado más de 130 artículos y un curso DataCamp, y estoy preparando otro. Mi contenido ha sido visto por más de 5 millones de ojos, 20.000 de los cuales se convirtieron en seguidores tanto en Medium como en LinkedIn.



