MÓDULO 20 · EJERCICIO · FASE 2 DE 2

Proyecto final · Fase 2: de prototipo a servicio

El mismo agente de la fase 1, con las dos memorias movidas a PostgreSQL, una caché de respuestas, trazabilidad con LangFuse y una API HTTP con FastAPI delante. El front de Chainlit sigue funcionando; deja de ser la única puerta de entrada.
// enunciado, no lección: sin tarjetas y sin preguntas de examen

La fuente son las páginas 21–28 del PDF, que en realidad son un segundo documento pegado detrás del primero: tiene su propio índice y está titulado también «1.».

01 — El delta
Qué cambia respecto a la fase 1
PiezaFase 1Fase 2
Memoria cortaCheckpointer sobre SQLiteCheckpointer sobre PostgreSQL
Memoria largaAlmacén vectorial embebidoPGVector, en la misma base
CachéNo hayTabla de respuestas cacheadas
TrazasSolo logs por consolaLangFuse, un decorador por nodo
EntradaChainlitChainlit + cuatro endpoints HTTP
Dependenciasrequirements.txtpyproject.toml, lockfile, .python-version

El grafo no cambia. Cambia lo que hay debajo y lo que hay delante. Si te encuentras tocando nodos o aristas, es que algo se ha desviado del enunciado.

02 — Requisitos previos
Infraestructura antes que código
03 — Criterios de aceptación
Otra vez propuestos, no heredados
Igual que en la fase 1: el material no trae criterios, ni pesos, ni fecha. Estos son un mínimo comprobable propuesto aquí.
#CriterioCómo se comprueba
1Ninguna escritura va ya a SQLiteBorrar el fichero .db y que todo siga funcionando
2Un hilo sobrevive al reinicio del procesoConversar, matar el proceso, reanudar el mismo hilo
3Las memorias largas están en PGVectorConsultarlas con psql, no solo por la app
4La caché acierta y se puede vaciarRepetir una consulta y ver el ahorro; luego invalidarla
5Cada nodo aparece en LangFuseUna conversación completa trazada de principio a fin
6Los cuatro endpoints respondenUn curl por endpoint, con su fichero
7El entorno se reconstruye desde el lockfileEntorno limpio, instalar desde el lock, arrancar
8El README describe la estructura realComparar su árbol con git ls-files
Auditoría

El script de setup puede «terminar bien» sin crear nada. El código de inicialización de las tablas prueba un método, luego otro, y si ninguno existe imprime que «puede que las tablas se creen solas en el primer uso» y que «puede que haya que crearlas a mano». El except exterior imprime algo parecido. En ningún camino devuelve un código de salida distinto de cero. ¿Cómo sabes si ese script ha hecho algo? ¿Y por qué se entrega como código cerrado, cuando todo lo demás del proyecto se entrega como prompt?

El cambio de checkpointer aparece en un sitio y hace falta en dos. La guía da una línea de reemplazo para pasar de SQLite a Postgres, pero en la fase 1 el checkpointer se abre en dos manejadores distintos: el de mensajes y el de fin de audio. Si migras solo el que enseña la guía, la conversación por voz sigue escribiendo en SQLite y ninguna prueba obvia lo delata. ¿Cuántos sitios hay realmente en tu app.py?

Tres gestores de entorno en un proyecto. Empieza con conda, instala con pip durante unos treinta prompts —cada uno con licencia para añadir lo que le falte— y en el último paso pide generar el lockfile y el pyproject.toml «a partir del proyecto entero». El lockfile no previene el desorden: lo fotografía. ¿Qué versión de cada librería estás fijando, y por qué esa?

La caché indexa por la cadena literal de la consulta. En un agente cuya respuesta depende del historial, de la memoria larga y de la modalidad que eligió el router. Dos usuarios distintos con la misma pregunta reciben la misma respuesta cacheada. Después de un máster entero sobre embeddings y similitud, ¿por qué una caché de coincidencia exacta? ¿Y cuándo se invalida?

La instalación solo vale en un ordenador. brew, una versión mayor de PostgreSQL que ya no es reciente y una ruta de pg_config específica de Apple Silicon. Ni Linux, ni Windows, ni contenedor. En un módulo que se titula «producción», ¿qué dice que la única forma documentada de levantar la base de datos dependa del portátil que tengas?

Credenciales de ejemplo que invitan al desastre. La URI de muestra se conecta como root con contraseña password y se copia en .env, con la palabra gitignore todavía sin aparecer en el documento. ¿Cuánto de ese ejemplo acabaría tal cual en un repositorio si nadie lo cuestiona?

Para hacer
Cuenta tú los sitios antes de migrar uno

Antes de tocar nada, en tu propio proyecto:

grep -rni "sqlite" --include="*.py" --include="*.txt" .

Ese número —no el de la guía— es el número de sitios que tienes que cambiar. Apúntalo, migra, y vuelve a correr el mismo grep: si no sale vacío, la migración no ha terminado.