De la carpeta de apuntes al 100: un agente de IA que arma tu exposición con AWS Bedrock
Un agente de código abierto que convierte tus apuntes en una exposición con guion, tiempos medidos, datos respaldados por fuentes y slides en Canva. Usa Amazon Bedrock, Bedrock Guardrails y Strands Agents. Cuento cómo funciona por dentro, cuánto cuesta y los errores que más me enseñaron.
Un agente de IA que arma tu exposición con Amazon Bedrock (y lo que aprendí al construirlo)
Resumen: un agente de código abierto que convierte tus apuntes en una exposición con guion, tiempos medidos, datos respaldados por fuentes y slides en Canva. Usa Amazon Bedrock, Bedrock Guardrails y Strands Agents. Cuento cómo funciona por dentro, cuánto cuesta y los errores que más me enseñaron.
Preparar una exposición tiene muchas partes: ordenar ideas, comprobar datos, escribir un guion que dure lo que tiene que durar y diseñar las slides. Quise ver cuánto de eso puede hacer un agente de IA y, sobre todo, cómo se construye uno que no te mienta.
El resultado es un proyecto de código abierto que convierte una carpeta de apuntes en una exposición completa. Lo construí para mi charla en el AWS Student Community Day de Cochabamba. Este post cuenta cómo funciona, cuánto cuesta y qué errores me enseñaron más.
Índice
- Qué hace
- La idea que quería enseñar
- Cómo está armado
- Una ejecución, acto por acto
- Dónde entra Amazon Bedrock
- Dónde entra Strands
- Lo que aprendí
- Costo y rendimiento medidos
- Límites
- Pruébalo
Qué hace
Le das cuatro cosas: un brief (título y duración), tus apuntes en Markdown, una guía de cómo hablas y una guía visual con tu paleta. El agente devuelve:
- Un plan y un guion por slide, con el tiempo calculado.
- Cada dato con su fuente, o marcado como tuyo si no la tiene.
- Las slides en Canva, con tu paleta.
- Un resumen de tus apuntes contrastados con fuentes confiables, para que corrijas lo que esté mal.
Una exposición es un nombre que une tres carpetas:
1
2
3
input/expo-de-s3.json el brief (solo título y duración son obligatorios)
knowledge/expo-de-s3/*.md tus apuntes
output/expo-de-s3/ lo que genera el agenteEl título del diseño en Canva es ese mismo nombre.
La idea que quería enseñar
Un agente es un modelo con herramientas, estado de la tarea y la obligación de revisar su propio trabajo. El modelo decide qué hacer. El código decide qué se acepta.
Dicho con una palabra que se usa mucho: agente = modelo + harness. El harness es todo lo que rodea al modelo: el bucle, las herramientas, el estado, los límites y las validaciones. En este proyecto el modelo se cambia con una línea. Lo que no se puede cambiar sin perder confiabilidad es todo lo demás.
Un punto de partida útil es preguntarse quién decide el camino:
| Qué es | Quién decide el camino |
|---|---|
| Un LLM | Nadie: devuelve un texto |
| Un chatbot | Tú, turno a turno |
| Un workflow | El programador, con pasos fijos |
| Un agente | El modelo, dentro de límites que pone el código |
Cómo está armado
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
brief + apuntes + voz + guía visual
│
▼
┌──────────── MODELO ────────────┐ Amazon Bedrock
│ (decide el paso) │ (Claude Sonnet 4.5 por defecto)
└──────┬───────────────────▲───────┘
│ llama │ resultado
▼ │
┌──────────── HERRAMIENTAS ──────┐ Strands: tool()
│ leer apuntes · buscar · registrar│
│ un dato · editar · medir tiempo │
└──────┬───────────────────────────┘
│ escribe
▼
┌──────────── ESTADO ────────────┐
│ deck.json · claims.json │ validado con Zod
└──────┬───────────────────────────┘
│
▼
┌──────────── REVISIÓN ──────────┐ Strands: hooks
│ validadores · topes · compuerta │ Bedrock Guardrails
└──────────────────────────────────┘| Pieza | En el proyecto |
|---|---|
| Modelo | Claude Sonnet 4.5 en Amazon Bedrock. Mistral Large 3 y Nova 2 Lite como alternativas |
| Herramientas | read_knowledge, research, record_claim, review_note, mark_own_notes, update_section, check_timing, validate_deck, critique_voice |
| Estado | deck.json (la fuente de verdad) y claims.json (la procedencia de cada dato) |
| Bucle | Strands Agents SDK, en TypeScript |
| Revisión | Validadores deterministas, topes de turnos y llamadas, y Bedrock Guardrails |
Lo que se ve del estado:
script.md (el guion) y timing.md (la tabla de tiempos) no los escribe el modelo. Los genera el código desde deck.json, así que no pueden contradecirse con él.Una ejecución, acto por acto
Cada paso es un comando y cada uno muestra una pieza de la arquitectura.
| Acto | Comando | Qué pasa |
|---|---|---|
| 1 | npm run demo -- brief | Muestra el brief, los apuntes y los datos que parecen externos y no tienen fuente |
| 2 | npm run demo -- research | Contrasta cada apunte con fuentes confiables y respalda los datos que faltan |
| 3 | npm run demo -- plan | Escribe el deck sección por sección, mide el tiempo y valida |
| 4 | npm run demo -- edit "Haz el inicio más provocador" | Edición puntual con diff: el código impide tocar otras secciones |
| 5 | npm run demo -- bedrock | Costo real por modelo y cómo cambiarlo con una línea |
| 6 | npm run demo -- guardrails all | Los guardrails en vivo con cuatro escenarios |
| 7 | npm run demo -- canva | Slides en Canva vía MCP, con tu paleta |
El Acto 2: tus apuntes frente a las fuentes
El agente revisa todos los fragmentos de tus apuntes. Cada uno termina de una de dos formas: contrastado con una fuente o marcado como tuyo (ideas, experiencias, opiniones). El código no deja terminar hasta que no quede ninguno pendiente. El veredicto lo arma el código:
| Caso | Veredicto | Quién decide |
|---|---|---|
| La fuente lo respalda y pasa la verificación (cita, cifras y respaldo semántico) | confirmado | código |
| La fuente lo respalda, pero la verificación falla | sin verificar (no se reporta) | código |
| La fuente dice otra cosa | inconsistente | modelo |
| Ninguna fuente trata el punto | sin verificar (no se reporta) | modelo |
Si hay un apunte inconsistente, el proceso se detiene y te deja un resumen en
revision-apuntes.md con el pasaje de la fuente. Además genera una versión de tus apuntes sin lo marcado, lista para copiar, corregir y volver a correr.Dónde entra Amazon Bedrock
Un solo punto de acceso a varios modelos. Cambiar de modelo es una línea de configuración:
1
2
model:
active: claude45 # o mistral, o novaCon eso comparé costo y comportamiento entre tres modelos sin tocar el código del agente.
Guardrails, con una sorpresa. Quise filtrar tanto lo que entra como lo que sale. Al revisar la documentación descubrí que la API Converse no evalúa los resultados de las herramientas: solo lo que escribe el usuario y lo que responde el modelo. Mis apuntes entran justamente por una herramienta, así que se colaban sin revisión.
La solución fue un diseño híbrido, con un solo guardrail y dos puertas:
| Puerta | Qué revisa | Funciona con |
|---|---|---|
guardrailConfig dentro de Converse | Lo que escribe el usuario y lo que responde el modelo | Solo modelos de Bedrock |
ApplyGuardrail por separado | Los apuntes y el texto que entra al guion | Cualquier texto, sin modelo |
También usé contextual grounding para comprobar que una fuente realmente respalda una afirmación. Los cuatro escenarios de demostración (inyección de prompts, datos personales, citas inventadas y grounding) dan 10 de 10 en las pruebas.
Dónde entra Strands
Strands me da el bucle del agente ya resuelto: el modelo piensa, llama una herramienta, recibe el resultado y repite. Yo defino cada herramienta con su nombre, su descripción y el esquema de su entrada, y el modelo decide cuándo usarla:
1
2
3
4
5
6
7
8
9
10
11
tool({
name: 'review_note',
description: 'Registra la revisión de UN fragmento de los apuntes contra las fuentes…',
inputSchema: z.object({
fragmentId: z.string(),
passageId: z.string().optional(),
relation: z.enum(['supports', 'contradicts']).optional(),
explanation: z.string(),
}),
callback: async (input) => { /* el código arma el veredicto */ },
})Lo que más me gustó fueron los hooks, que me dejan interceptar el bucle. Con ellos pongo topes (máximo de turnos y de llamadas a herramientas) y una compuerta: si el agente intenta terminar sin haber validado su trabajo, el hook lo reanuda con el reporte del validador. Con un máximo de rondas, para que nunca quede en un bucle:
1
2
3
4
5
6
7
agent.addHook(AfterInvocationEvent, async (e) => {
lastResult = await opts.validate(agent);
if (lastResult.ok || rounds >= opts.maxRounds) return; // termina, o se rinde
rounds++;
e.resume = `La validación falló. Corrige SOLO esto y vuelve a validar:\n` +
lastResult.problems.map((p) => `- ${p}`).join('\n');
});La salida final también está estructurada y validada con Zod. Si el modelo no cumple el formato, se permite un solo reintento y después falla con un error claro.
Lo que aprendí
1. El modelo propone, el código verifica. Cuando le pedí al modelo que respaldara un dato con una cita, a veces la parafraseaba de memoria o la inventaba. Ahora el modelo solo puede elegir un pasaje real que devolvió la búsqueda, y el código comprueba tres cosas: que la cita siga en la fuente, que las cifras coincidan y que la fuente respalde la afirmación. Puse a propósito un dato falso ("el 90% de las startups usan esto"). El modelo lo daba por bueno. El código lo rechaza siempre, porque ninguna fuente tiene esa cifra.
2. Todo lo que sea cálculo va en código, no en el prompt. Con aritmética por prompt, los modelos no convergían. El tiempo de cada sección (palabras ÷ 135 por minuto), los objetivos por sección y el alcance de una edición los calcula el código. Si dices "cambia solo el inicio", el código rechaza cualquier edición a otra sección.
3. El código solo debe decidir lo que es verificable. Mi primera versión era demasiado estricta: marcaba apuntes correctos como errores porque la fuente estaba en inglés y el puntaje de grounding salía bajo (0,68 a 0,71). Ahora un respaldo que falla no se reporta como error. Solo el modelo puede señalar una contradicción, y es el autor quien decide.
4. Los modelos fallan de maneras distintas. Descarté Nova Pro porque reescribía hasta nueve secciones por turno y no convergía. Mistral a veces emite JSON inválido en una herramienta y la ejecución se corta. Por eso el proyecto trae grabaciones que se reproducen sin cuenta de AWS y con la latencia real: una demo no puede depender de que la red y el modelo cooperen ese día.
5. Un token vencido no siempre avisa.
aws sts get-caller-identity puede funcionar con el token de SSO vencido, porque el CLI usa credenciales de rol en caché. El SDK de JavaScript, en cambio, necesita el token vigente y falla. Si algo anda mal antes de una demo, conviene comprobar con una llamada real y no con el CLI.Costo y rendimiento medidos
Todas las cifras salen de mis pruebas, con el registro de tokens de cada ejecución.
| Tarea | Modelo | Herramientas | Tiempo | Costo |
|---|---|---|---|---|
| Investigar y revisar apuntes | Claude Sonnet 4.5 | — | 73–88 s | USD 0,11–0,13 |
| Escribir el guion | Claude Sonnet 4.5 | — | ~153 s | ~USD 0,19 |
| Generar el deck | Mistral Large 3 | 15 | ~80 s | ~USD 0,06 |
| Generar el deck | Nova 2 Lite | 15–20 | 55–90 s | USD 0,03–0,06 |
| Edición puntual | Nova 2 Lite | ~11 | ~42 s | ~USD 0,03 |
Una ejecución completa de investigación más plan ronda USD 0,35 con Claude Sonnet 4.5. El caché de prompts ayuda mucho: en el acto de investigación leyó entre 44 000 y 75 000 tokens desde caché. Los precios de Claude están en el archivo de configuración como precios de lista, y no los verifiqué contra la página de Bedrock: confírmalos antes de tomarlos como verdad.
Límites
- La investigación solo busca en una lista de fuentes que tú eliges. No es un buscador abierto.
- El veredicto "este apunte contradice la fuente" lo da el modelo y puede variar entre corridas. El código solo comprueba lo verificable.
- Canva recibe tu paleta como texto, no como un parámetro. Puede ajustar colores poco legibles.
- Con muchas slides, el tiempo de generación en Canva puede crecer. Con tres slides tarda unos 50 segundos.
- Si lo que necesitas es un proceso con pasos fijos, un workflow es más barato y más predecible que un agente.
Pruébalo
No necesitas cuenta de AWS para ver cómo funciona. Con Node 24:
1
2
3
4
npm install
npm test # pruebas sin red
npm run demo -- brief # el Acto 1 con la exposición de ejemplo
npm run demo -- guardrails all --replay # el Acto 6, reproducido desde grabacionesPara correrlo de verdad hace falta una cuenta con Amazon Bedrock y un perfil local de AWS. Las credenciales viven en tu máquina y nunca en el repositorio. El código es público con licencia MIT: puedes cambiarle el dominio y quedarte con la estructura. Sirve igual para revisar tus gastos contra un presupuesto, o tus apuntes de clase contra un temario.
Repositorio:
https://github.com/IsaacJaldinDev/expo-generator-cliPara cerrar
Un agente confiable no se logra con un modelo más grande. Se logra con herramientas pequeñas, estado fuera del modelo y reglas en código que el modelo no puede saltarse. Si construyes uno, invierte en lo que lo rodea tanto como en el modelo.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article