Esta es la implementacion educativa completa del ejemplo del articulo Memoria del agente: que recuerda y para que.
Si aun no leiste el articulo, empieza por ahi. Aqui el foco es solo el codigo y la diferencia practica entre short-term y long-term memory.
Que Demuestra Este Ejemplo
- Como la memoria de corto plazo puede perder instrucciones tempranas por contexto limitado
- Como la memoria de largo plazo guarda configuraciones entre tareas
- Por que la misma solicitud puede dar resultados distintos segun el tipo de memoria
- Como construir un agente memory-aware simple sin complejidad innecesaria
Estructura del Proyecto
foundations/
└── agent-memory/
└── python/
├── main.py # ejecuta dos escenarios y compara el resultado
├── agent.py # logica del agente con short/long memory
├── memory.py # almacenes short-term y long-term
├── tools.py # fuentes de datos simples y render del reporte
└── requirements.txt
Como Ejecutar
1. Clona el repositorio y ve a la carpeta:
git clone https://github.com/AgentPatterns-tech/agentpatterns.git
cd foundations/agent-memory/python
2. Instala dependencias (este ejemplo no tiene paquetes externos):
pip install -r requirements.txt
3. Ejecuta la demo:
python main.py
Que Construimos en el Codigo
Construimos un agente minimo que genera un reporte semanal en dos modos.
SCENARIO 1: solo short-term memory (el contexto es limitado y puede "olvidar" prefs tempranas)SCENARIO 2: short-term + long-term memory (las prefs se guardan entre tareas)
Idea clave: el contexto de tarea y la memoria entre tareas tienen roles distintos.
Codigo
memory.py - memoria short-term y long-term
from dataclasses import dataclass, field
from typing import Any
@dataclass
class ShortMemory:
max_items: int = 6
items: list[dict[str, Any]] = field(default_factory=list)
def add(self, role: str, content: str) -> None:
self.items.append({"role": role, "content": content})
if len(self.items) > self.max_items:
self.items = self.items[-self.max_items :]
def snapshot(self) -> list[dict[str, Any]]:
return list(self.items)
def clear(self) -> None:
self.items.clear()
@dataclass
class LongMemoryStore:
_prefs: dict[str, dict[str, str]] = field(default_factory=dict)
def save_prefs(self, user_key: str, prefs: dict[str, str]) -> None:
self._prefs[user_key] = dict(prefs)
def load_prefs(self, user_key: str) -> dict[str, str]:
return dict(self._prefs.get(user_key, {}))
tools.py - datos y formato del reporte
def get_sales_total(user_id: int) -> float:
_ = user_id
return 12400.0
def get_orders_count(user_id: int) -> int:
_ = user_id
return 31
def render_report(*, total: float, orders: int, currency: str, report_format: str) -> str:
if report_format == "short-bullets":
return (
f"- Total sales: {total:.2f} {currency}\n"
f"- Orders: {orders}\n"
"- Status: stable"
)
return (
f"Sales report: total={total:.2f} {currency}, "
f"orders={orders}, status=stable"
)
agent.py - logica de resolucion de prefs
from memory import LongMemoryStore, ShortMemory
from tools import get_orders_count, get_sales_total, render_report
DEFAULT_PREFS = {
"report_format": "default",
"currency": "USD",
}
def save_user_preferences(
*,
user_key: str,
prefs: dict[str, str],
short_memory: ShortMemory,
long_memory: LongMemoryStore,
) -> None:
short_memory.add("user", f"Save prefs: {prefs}")
long_memory.save_prefs(user_key, prefs)
short_memory.add("assistant", "Preferences saved to long-term memory")
def parse_prefs_from_short_memory(short_memory: ShortMemory) -> dict[str, str]:
# Simplified parser for learning: looks for lines like "pref:key=value".
parsed: dict[str, str] = {}
for item in short_memory.snapshot():
content = item["content"]
if "pref:" not in content:
continue
payload = content.split("pref:", 1)[1]
if "=" not in payload:
continue
key, value = payload.split("=", 1)
parsed[key.strip()] = value.strip()
return parsed
def build_weekly_report(
*,
user_id: int,
user_key: str,
request: str,
short_memory: ShortMemory,
long_memory: LongMemoryStore,
use_long_memory: bool,
) -> dict:
trace: list[str] = []
short_memory.add("user", request)
trace.append(f"request={request}")
short_prefs = parse_prefs_from_short_memory(short_memory)
trace.append(f"short_prefs={short_prefs}")
long_prefs = long_memory.load_prefs(user_key) if use_long_memory else {}
trace.append(f"long_prefs={long_prefs}")
prefs = {**DEFAULT_PREFS, **short_prefs, **long_prefs}
trace.append(f"resolved_prefs={prefs}")
total = get_sales_total(user_id)
orders = get_orders_count(user_id)
report = render_report(
total=total,
orders=orders,
currency=prefs["currency"],
report_format=prefs["report_format"],
)
short_memory.add("assistant", f"Report generated with prefs={prefs}")
return {
"prefs": prefs,
"report": report,
"trace": trace,
"short_memory_snapshot": short_memory.snapshot(),
}
main.py - comparacion de dos escenarios
from agent import build_weekly_report, save_user_preferences
from memory import LongMemoryStore, ShortMemory
USER_ID = 42
USER_KEY = "user:anna"
def print_result(title: str, result: dict) -> None:
print(f"\n=== {title} ===")
print("Resolved prefs:", result["prefs"])
print("\nReport:")
print(result["report"])
print("\nTrace:")
for line in result["trace"]:
print(" ", line)
def main() -> None:
long_memory = LongMemoryStore()
# Scenario 1: only short-term memory, early instruction falls out of context.
short_memory_1 = ShortMemory(max_items=4)
short_memory_1.add("user", "pref:report_format=short-bullets")
short_memory_1.add("user", "pref:currency=EUR")
short_memory_1.add("assistant", "working...")
short_memory_1.add("assistant", "still working...")
short_memory_1.add("assistant", "collecting data...") # pushes out old prefs
result_short_only = build_weekly_report(
user_id=USER_ID,
user_key=USER_KEY,
request="Build weekly sales report",
short_memory=short_memory_1,
long_memory=long_memory,
use_long_memory=False,
)
print_result("SCENARIO 1: SHORT MEMORY ONLY", result_short_only)
# Scenario 2: persist prefs in long-term memory, then start a new task.
short_memory_2 = ShortMemory(max_items=4)
save_user_preferences(
user_key=USER_KEY,
prefs={"report_format": "short-bullets", "currency": "EUR"},
short_memory=short_memory_2,
long_memory=long_memory,
)
short_memory_2.clear() # new task, short memory resets
result_with_long = build_weekly_report(
user_id=USER_ID,
user_key=USER_KEY,
request="Build weekly sales report like last time",
short_memory=short_memory_2,
long_memory=long_memory,
use_long_memory=True,
)
print_result("SCENARIO 2: WITH LONG MEMORY", result_with_long)
if __name__ == "__main__":
main()
requirements.txt
# No external dependencies for this learning example.
Ejemplo de Salida
python main.py
=== SCENARIO 1: SHORT MEMORY ONLY ===
Resolved prefs: {'report_format': 'default', 'currency': 'USD'}
Report:
Sales report: total=12400.00 USD, orders=31, status=stable
Trace:
request=Build weekly sales report
short_prefs={}
long_prefs={}
resolved_prefs={'report_format': 'default', 'currency': 'USD'}
=== SCENARIO 2: WITH LONG MEMORY ===
Resolved prefs: {'report_format': 'short-bullets', 'currency': 'EUR'}
Report:
- Total sales: 12400.00 EUR
- Orders: 31
- Status: stable
Trace:
request=Build weekly sales report like last time
short_prefs={}
long_prefs={'report_format': 'short-bullets', 'currency': 'EUR'}
resolved_prefs={'report_format': 'short-bullets', 'currency': 'EUR'}
Lo Que Se Ve en la Practica
| Solo short memory | Short + long memory | |
|---|---|---|
| Guarda prefs entre tareas | ❌ | ✅ |
| Resiste la perdida de contexto temprano | ❌ | ✅ |
| Formato/moneda se reproducen "como la vez pasada" | ❌ | ✅ |
Que Cambiar en Este Ejemplo
- Reduce
max_itemsa2y mira que tan rapido se pierden prefs en short memory - Agrega una tercera preferencia de usuario (por ejemplo,
timezone) y pasala al reporte - Guarda tambien
last_report_totalen long memory y compara la dinamica en la siguiente tarea - Agrega una regla: no permitir prefs vacias en
save_user_preferences
Codigo Completo en GitHub
En el repositorio esta la version completa de esta demo: memoria short-term/long-term, comparacion de escenarios y trace de pasos.
Ver codigo completo en GitHub ↗