MÓDULO 20 · EJERCICIO · FASE 1 DE 2

Proyecto final · Fase 1: el agente multimodal

Entregas un repositorio con un agente conversacional multimodal sobre LangGraph y un front de pruebas en Chainlit: acepta texto y audio, analiza imágenes y ficheros, genera imágenes y responde con voz. Con memoria de corto plazo y de largo plazo. Un commit por fichero, y un agents.md que registre cómo se generó cada uno.
// esto es un enunciado, no una lección: no lleva tarjetas y no computa progreso
01 — El alcance
Nueve capacidades, una sola aplicación
CapacidadPieza que la implementa
Conversación con personalidadChain de personaje, con el resumen del hilo inyectado
Decidir texto / imagen / audioNodo router con salida estructurada
Voz → textoMódulo de transcripción
Texto → vozMódulo de síntesis
Texto → imagenGeneración, con enriquecimiento previo del prompt
Imagen y ficheros → textoModelo de visión
Memoria cortaCheckpointer sobre el hilo
Memoria largaExtracción de hechos + almacén vectorial
Resumen al crecer el hiloNodo de resumen disparado por longitud
02 — La forma del grafo
Dos aristas condicionales, y solo dos
START
↓
memory_extraction
↓
router
↓
memory_injection
↓   select_workflow   ↓
conversation
image
audio
↓   should_summarize_conversation   ↓
summarize_conversation
END

select_workflow decide la modalidad de la respuesta; should_summarize_conversation decide si el hilo ya es lo bastante largo para comprimirlo. Todo lo demás es secuencial. El orden de las aristas es la parte que hay que entender, no copiar.

03 — Requisitos previos
Antes de pegar el primer prompt
04 — Criterios de aceptación
Un «hecho» comprobable, porque la guía no trae ninguno
Estos criterios no salen del material. La guía no tiene rúbrica, ni pesos, ni porcentajes, ni lista de entregables, ni fecha: las palabras criteria, rubric, evaluate, score, grade y deadline no aparecen ni una vez en sus 28 páginas. Lo de abajo es un mínimo razonable propuesto aquí para que el ejercicio se pueda dar por terminado.
#CriterioCómo se comprueba
1Arranca de cero siguiendo solo el READMEClonar en carpeta limpia y seguirlo al pie de la letra
2Las cuatro modalidades respondenUna conversación con texto, audio, imagen subida e imagen pedida
3El router acierta al no generarMencionar algo visual sin pedir una imagen: no debe generarla
4La memoria larga sobrevive al reinicioContar un dato, reiniciar el proceso, preguntarlo
5El resumen se disparaSuperar el umbral de mensajes y ver el resumen en el estado
6Los errores están tipadosForzar un fallo de cada módulo y ver su excepción propia
7Un commit por ficherogit log --oneline legible de arriba abajo
8agents.md reconstruye la generaciónQue un tercero pueda regenerar un fichero leyéndolo
9.env no está en la historia de Gitgit log --all --full-history -- .env sale vacío
Auditoría

El documento está cortado. 191 de sus 845 líneas —un 22,6 %— terminan a mitad de palabra en el margen derecho, medido sobre las cajas de línea del PDF. En las páginas de prompts por fichero son 10–15 por página. Vas a tener que reconstruir el final de muchas frases: ¿a ojo, o escribiendo tú la spec entera de cada fichero con lo que sí se lee?

.env y 26 commits. El proyecto guarda cinco claves de API en .env, la guía te dice 26 veces que commitees, y la palabra gitignore no aparece ni una vez en las 28 páginas. ¿Qué acaba en el repositorio si la sigues literalmente?

El fichero de settings declara la misma variable dos veces. ELEVENLABS_VOICE_ID aparece como str obligatorio bajo «api keys» y otra vez con un valor por defecto codificado bajo «model names». En una clase de Pydantic la segunda anotación gana: el campo deja de ser obligatorio y se queda con un ID fijo. ¿Descuido, o intencionado? ¿Y qué hace un ID de voz real publicado en el material del curso?

El personaje niega ser una IA. El prompt de personalidad plantea un juego de test de Turing y prohíbe mencionar que es una IA o un asistente virtual. En paralelo, el prompt de memoria extrae y almacena datos personales —nombre, edad, ubicación, trabajo, familia, relaciones— sin consentimiento, sin retención declarada y sin forma de borrarlos. El módulo 6 tiene una lección publicada sobre PII y soberanía del dato. ¿Se sostienen las dos cosas a la vez?

Un tope de 2500 palabras por respuesta. En un chat, junto a la instrucción de «combinar respuestas cortas y largas para que sea natural». ¿De dónde sale ese número?

El fichero de prompts no se nombra nunca. El apartado «System prompts file» vuelca código Python etiquetado como MARKDOWN y jamás dice en qué fichero va. El scaffold sí lista core/prompts.py, pero ningún prompt lo conecta con ese contenido. Ese mismo scaffold escribe init.py en vez de __init__.py en todos los paquetes, y a modules/memory/long_term/ no le pone ninguno — aunque después se importe de ahí. ¿Cuántas de esas rutas vas a tener que corregir antes de que el primer import funcione?

Para hacer
El único paso que no se puede añadir después

Antes de pegar el primer prompt: git init, y de primer commit solo el .gitignore con .env dentro. Todo lo demás del proyecto se puede arreglar más tarde. Una clave publicada, no.

git init
printf '.env\ndata/\ngenerated_images/\n__pycache__/\n' > .gitignore
git add .gitignore
git commit -m "chore: ignorar .env antes de que exista"