La evaluación de 06-03 responde a "¿puedo desplegar esto?" con casos que tú elegiste. Esta lección responde a la pregunta siguiente: ¿qué está pasando ahora mismo en producción, con las preguntas que nadie eligió? Un sistema con LLM falla de formas que el software clásico no conoce: no lanza excepciones cuando alucina, no devuelve un 500 cuando responde con desgana, y puede duplicar su coste sin que nada "se rompa". En 05-02 sembramos trazas.py::registrar_paso() anunciando que germinaría aquí; toca cumplirlo: definir qué registrar en cada petición, estructurar los logs para que sean explotables, destilar métricas y paneles que cuenten la salud del sistema de un vistazo, montar alertas que digan qué hacer (no solo que algo pasa), y cerrar el círculo con el feedback de los usuarios alimentando el conjunto de evaluación. Es la diferencia entre operar DocuBot y rezar por DocuBot.
Contenido
- De las trazas del agente a la observabilidad del sistema
- Qué registrar en cada petición
- Logs estructurados: JSON por línea con
logging - Qué NO loguear
- Métricas agregadas y paneles
- Alertas accionables: síntoma, causa probable, acción
- El feedback de los usuarios: el ciclo de mejora continua
- El ecosistema de herramientas, por categorías
De las trazas del agente a la observabilidad del sistema
registrar_paso() nació en 05-02 con una misión modesta: apuntar cada iteración del bucle agéntico (qué pensó, qué herramienta llamó, qué obtuvo) para poder depurar. Eso es una traza: la biografía de una petición. La observabilidad completa añade dos pisos:
- Logs: eventos individuales estructurados, consultables ("enséñame todas las peticiones de ayer con confianza < 0.3").
- Métricas: agregados numéricos en el tiempo ("tasa de fallback por hora", "coste acumulado del día").
La distinción práctica: las trazas explican una petición; las métricas vigilan todas; los logs son la materia prima de ambas. En una aplicación con LLM hay además una peculiaridad: buena parte de los "fallos" son degradaciones silenciosas (respuestas peores, costes mayores, más "no lo sé") que solo se ven en los agregados. Por eso un sistema que solo tiene trazas de depuración está ciego en producción.
Qué registrar en cada petición
El diseño empieza por el evento central: una línea por petición completa (además de las líneas por paso del agente que ya emite trazas.py). Campos, agrupados por lo que permiten responder:
| Grupo | Campos | Para qué |
|---|---|---|
| Identidad | id_peticion (UUID), timestamp, id_sesion y usuario seudonimizados (06-02) |
Correlacionar: unir esta línea con los pasos del agente, el feedback posterior y la conversación, sin exponer identidades |
| Versiones | prompt_version, chunking_version, modelo |
El eje de todo análisis: "¿empeoró algo tras el despliegue de ayer?" exige saber qué versión atendió cada petición (mismo principio que el CSV de 06-03) |
| Recuperación | chunks_recuperados (ids y similitudes), umbral_superado |
Diagnosticar RAG en producción: ¿la pregunta falló porque no se recuperó nada o porque se recuperó basura? |
| Agente | herramientas_llamadas (nombre, resultado ok/error), iteraciones, confirmacion_humana (propuesta/aceptada/rechazada) |
Vigilar el comportamiento agéntico y el human-in-the-loop |
| Rendimiento | tokens_entrada, tokens_salida, coste (via estimar_coste()), ttft_ms, latencia_total_ms (de medir_llamada(), 03-04), cache (exacto/semantico/miss) |
Coste y latencia por petición; agregados para paneles |
| Calidad | categoria (del clasificador), confianza (del contrato JSON), frase_sin_info (bool), fallback (bool), error |
Las señales de calidad que el sistema ya emite sin coste extra |
| Cierre del ciclo | feedback (👍/👎/nulo, se adjunta a posteriori vía id_peticion) |
La verdad del usuario |
Fíjate en la economía del diseño: casi todo esto ya existía. estimar_coste() y medir_llamada() vienen de 03-04, la confianza del contrato de 02-03, las similitudes de recuperar() de 04-04, las herramientas y confirmaciones de 05-02, la seudonimización de 06-02. La observabilidad no inventa datos; recolecta con disciplina los que el sistema ya produce.
Logs estructurados: JSON por línea con logging
Un log de texto libre ("Usuario preguntó por facturación, fue bien") no se puede consultar ni agregar. El estándar de facto es una línea = un objeto JSON (JSON Lines): lo lee un humano con grep, lo ingiere cualquier plataforma de logs, y lo agrega un script de veinte líneas.
Implementación con el módulo logging de la biblioteca estándar:
# observabilidad.py
import json
import logging
import time
import uuid
from datetime import datetime, timezone
class FormateadorJson(logging.Formatter):
"""Convierte cada registro en una linea JSON."""
def format(self, record: logging.LogRecord) -> str:
evento = {
"ts": datetime.now(timezone.utc).isoformat(),
"nivel": record.levelname,
"evento": record.getMessage(),
}
# Los campos estructurados viajan en `extra={"datos": {...}}`
evento.update(getattr(record, "datos", {}))
return json.dumps(evento, ensure_ascii=False)
logger = logging.getLogger("docubot")
_handler = logging.StreamHandler() # en produccion: fichero o colector
_handler.setFormatter(FormateadorJson())
logger.addHandler(_handler)
logger.setLevel(logging.INFO)
def log_peticion(**campos):
"""Registra el evento central: una peticion completa."""
logger.info("peticion", extra={"datos": campos})Y su integración en el punto de salida de docubot.py::responder (versión abreviada):
from precios import estimar_coste
from observabilidad import log_peticion
def responder(pregunta, sesion):
id_peticion = str(uuid.uuid4())
t0 = time.time()
# ... pipeline completo: redaccion (06-02), RAG o agente, validacion ...
log_peticion(
id_peticion=id_peticion,
id_sesion=sesion.id_seudonimo, # seudonimo, nunca la identidad
prompt_version=PROMPT_VERSION,
chunking_version=CHUNKING_VERSION,
modelo=MODELO,
categoria=salida.get("categoria"),
confianza=salida.get("confianza"),
frase_sin_info=FRASE_SIN_INFO in salida.get("respuesta", ""),
fallback=salida is RESPUESTA_FALLBACK,
chunks=[{"id": c["id"], "sim": round(c["similitud"], 3)}
for c in chunks_recuperados],
herramientas=[h["nombre"] for h in herramientas_llamadas],
tokens_entrada=uso.tokens_entrada,
tokens_salida=uso.tokens_salida,
coste=estimar_coste(uso.tokens_entrada, uso.tokens_salida),
ttft_ms=metricas.ttft_ms,
latencia_total_ms=int((time.time() - t0) * 1000),
)
return salidaUna línea resultante (formateada aquí para leerla; en el fichero va en una sola línea):
{"ts": "2026-07-06T10:14:03+00:00", "nivel": "INFO", "evento": "peticion",
"id_peticion": "9f2c...", "id_sesion": "ses_a41b", "prompt_version": "v7",
"chunking_version": "encabezados-v1-1800-300", "modelo": "…",
"categoria": "facturacion", "confianza": 0.86, "frase_sin_info": false,
"fallback": false, "chunks": [{"id": "doc_fact_03#2", "sim": 0.71}],
"herramientas": [], "tokens_entrada": 2140, "tokens_salida": 312,
"coste": 0.0093, "ttft_ms": 640, "latencia_total_ms": 3820}Detalles didácticos del código: el Formatter personalizado es el único punto donde se decide el formato (cambiarlo no toca el resto del código); los campos van por extra para no concatenar strings; ensure_ascii=False mantiene legibles los acentos; y id_peticion es la clave que une esta línea con las trazas por paso de registrar_paso() (que ahora también lo incluye) y con el feedback del usuario que llegará minutos después.
Qué NO loguear
Los logs son un tratamiento de datos más (lo vimos en 06-02: entran en el perímetro del GDPR y de los ejercicios de derechos). Reglas para DocuBot:
- Ni la pregunta ni la respuesta en crudo en el log de producción. Contienen lo que el usuario escribió — potencialmente datos personales sin redactar. Opciones intermedias, de menos a más exposición: solo metadatos (lo mostrado arriba); texto redactado con
redactar()(06-02) y retención corta; texto completo únicamente en entornos de desarrollo con datos ficticios. Si el negocio necesita revisar conversaciones reales, que sea una decisión explícita con legal, con acceso restringido y caducidad — no un default del logger. - Identidades reales: siempre el seudónimo de sesión/usuario, con la tabla de correspondencia protegida aparte.
- Claves de API y secretos: jamás. Cuidado con los volcados alegres de objetos de configuración o de excepciones que arrastran headers.
- Prompts completos del sistema:
prompts.pyestá versionado en git; conprompt_versionen el log basta. Loguear el prompt entero en cada petición es ruido, coste y exposición de propiedad intelectual. - Y la regla general: loguea referencias y medidas, no contenidos.
{"id": "doc_fact_03#2", "sim": 0.71}en lugar del texto del chunk: el id permite recuperar el contenido si hace falta investigar, sin duplicarlo por el sistema de logs.
Métricas agregadas y paneles
Sobre los logs se calculan los agregados. Estos son los indicadores con mejor relación señal/esfuerzo para DocuBot, y lo que cada uno cuenta:
| Métrica | Qué vigila | Lectura |
|---|---|---|
| Tasa de "No encuentro esa información..." | % de respuestas con frase_sin_info |
El termómetro de los huecos de documentación: estable ≈ normal; subida = o llegan preguntas nuevas (¿lanzamiento reciente?) o la wiki se ha quedado corta. Agrupada por categoria te dice qué documentar |
Distribución de confianza |
Histograma semanal | Un desplazamiento hacia abajo es degradación silenciosa que ningún error HTTP delatará |
| Coste diario | Suma de coste vs el presupuesto de 03-04 (~417 €/mes base, ~270 € con palancas) |
La proyección de 03-04 era una hipótesis; esto es el dato. registrar_llamada() ya definió las señales: ok / alerta al 80% / techo al 150% con decisión humana |
| Latencia p50 / p95 y TTFT | Percentiles de latencia_total_ms y ttft_ms |
El p95 (no la media) es la experiencia de tus usuarios descontentos; TTFT vigila la sensación de viveza del streaming (03-02) |
| Tasa de fallback y de errores | % de fallback=true, errores de reintentos.py, aperturas del circuit breaker |
La fiabilidad clásica; aquí sí valen los reflejos de siempre |
| Tasa de acierto de caché | % exacto / semántico / miss (CacheRespuestas, CacheSemantico) |
Si cae, el ahorro proyectado en 03-04 se está evaporando: ¿cambió el patrón de preguntas? |
| Tasa de confirmaciones rechazadas | % de propuestas de crear_con_confirmacion() que el humano rechaza |
El indicador de salud del agente: subida = el agente propone tickets malos (¿prompt? ¿herramienta confusa?) — o algo peor, como una injection (06-01) empujando acciones |
| Volumen por categoría | Peticiones por categoria del clasificador |
Contexto para todo lo demás y radiografía de qué necesita la organización |
Un panel razonable para DocuBot son estas 8 series con comparación contra la semana anterior. La regla de oro al diseñarlo: cada gráfico debe tener un dueño de la pregunta "¿y si esto cambia, qué hago?" — un panel que nadie sabe interpretar es decoración.
Alertas accionables: síntoma, causa probable, acción
Una alerta que solo dice "algo va mal" genera fatiga y acaba silenciada. Una alerta accionable lleva incorporado el diagnóstico diferencial — exactamente el formato de la tabla de diagnóstico de 04-05, ahora extendida a todo el sistema:
| Síntoma (alerta) | Causa probable | Acción primera |
|---|---|---|
Tasa de frase_sin_info sube del 10% al 25% en la categoría integraciones |
Hueco de documentación (¿integración nueva sin documentar?) o regresión de recuperación tras un cambio de chunking_version |
Revisar las preguntas afectadas en los logs; si son sobre un tema nuevo → escribir docs e ingerir; si son temas que antes funcionaban → eval_rag.py (recall@k) para confirmar regresión del retriever y revertir |
| Coste diario al 80% del presupuesto a mitad de mes | Más tráfico (mira volumen), respuestas más largas, caída de la caché, o bucles agénticos largos (mira iteraciones) |
Descomponer coste por categoría y por cache; aplicar las palancas de 03-04 (caching, límites de salida) antes de pedir más presupuesto |
| p95 de latencia se duplica sin cambio de versión | Degradación del proveedor, chunks más largos entrando al prompt, o caída de tasa de caché | Comparar TTFT vs latencia total: si TTFT sube → proveedor/red; si TTFT normal y total sube → hay más tokens que generar: mirar tamaño de contexto y caché |
Confianza media cae tras subir prompt_version v7→v8 |
Regresión del prompt que la evaluación no capturó (¿conjunto sin casos de ese tipo?) | Revertir a v7 (por eso versionamos), reproducir con el runner de 06-03 y añadir los casos que fallaron al conjunto |
| Tasa de confirmaciones rechazadas pasa del 5% al 30% | El agente propone acciones malas: descripciones de herramienta ambiguas, prompt degradado, o contenido hostil empujando acciones (06-01) | Leer las trazas de las propuestas rechazadas (id_peticion → pasos del agente); si hay patrón de instrucciones intrusas → revisar ingesta y activar revisión de la fuente |
Picos de is_error en una herramienta |
La API interna de Nubelia cambió o está caída | Reflejos clásicos: probar la API directamente; el circuit breaker de 03-02 debería estar limitando el daño mientras tanto |
Dos principios al configurar umbrales: alerta sobre tendencias y ratios (tasa que se duplica) más que sobre valores absolutos con ruido; y cada alerta disparada debe terminar o en una acción o en un ajuste del umbral — las alertas que se ignoran tres veces se eliminan o se arreglan.
El feedback de los usuarios: el ciclo de mejora continua
Todas las señales anteriores son indirectas. La directa es preguntar: un 👍/👎 al pie de cada respuesta (opcionalmente con comentario en el 👎). Barato de implementar — un endpoint que adjunta el veredicto al id_peticion — y valiosísimo si se explota bien:
# feedback.py
def registrar_feedback(id_peticion: str, util: bool, comentario: str = ""):
logger.info("feedback", extra={"datos": {
"id_peticion": id_peticion, # une con la peticion original
"util": util,
"comentario": comentario[:500], # acotado; y redactado si se muestra
}})El uso ingenuo es calcular "% de pulgares arriba" y ponerlo en el panel (útil, con sesgos: vota una minoría, y los descontentos votan más). El uso potente es cerrar el círculo con 06-03:
- Cada 👎 se une, vía
id_peticion, con su log completo: pregunta (redactada), chunks, similitudes, versiones, respuesta. - Revisión periódica de los 👎: ¿recuperación mala? ¿respuesta infiel? ¿hueco de documentación? La tabla de síntomas de arriba, aplicada caso a caso.
- Los fallos reales representativos se convierten en casos nuevos del conjunto de evaluación de 06-03, con su resultado esperado anotado.
- La siguiente iteración de prompt/chunking se valida ya contra ellos: ese modo de fallo no vuelve sin que el runner lo detecte.
flowchart LR
A[Produccion:<br>peticiones reales] --> B[Logs + feedback 👎]
B --> C[Revision periodica:<br>diagnostico por caso]
C --> D[Casos nuevos en el<br>conjunto de 06-03]
D --> E[Runner valida el<br>siguiente cambio]
E --> AEste bucle es la respuesta madura a una pregunta que ronda el curso desde 02-04: "¿de dónde salen los buenos casos de evaluación?". Al principio, de tu imaginación y de preguntas recopiladas; en régimen permanente, de los fallos reales de producción. La observabilidad no es solo vigilancia: es la cantera del conjunto de evaluación.
El ecosistema de herramientas, por categorías
Todo lo anterior está construido con la biblioteca estándar a propósito: entender el mecanismo antes que adoptar la plataforma (la misma filosofía del bucle agéntico a mano de 05-03). En un sistema en crecimiento, evalúa por categorías:
- Plataformas de observabilidad específicas de LLM (comerciales y open source): capturan automáticamente trazas de llamadas/agentes con prompts, tokens y costes; ofrecen visualización de conversaciones, evaluaciones integradas y anotación de datasets. Aportan mucho de 06-03 + 06-04 empaquetado; a cambio, tus prompts y datos pasan por otra plataforma más — el análisis de 06-02 aplica también a ellas.
- Observabilidad generalista + OpenTelemetry: el estándar abierto de trazas/métricas/logs del mundo cloud. Existen convenciones semánticas para IA generativa, de modo que las llamadas al LLM aparecen como spans en el mismo sistema donde ya observas el resto de tu plataforma. Atractivo si tu organización ya opera este stack: DocuBot deja de ser una isla.
- Agregadores de logs clásicos: si ya tienes uno, tus JSON Lines entran tal cual; paneles y alertas de esta lección se montan encima sin nada específico de IA.
Criterio de elección honesto: el valor diferencial de las plataformas LLM está en la visualización de trazas de agentes y en integrar evaluación y anotación; si tus logs estructurados ya responden a tus preguntas, no corras a añadir infraestructura. Lo importante — qué registrar, qué no, qué mirar y qué hacer al respecto — es lo que has diseñado en esta lección, y es portable a cualquier herramienta.
Errores Comunes y Consejos
- Loguearlo todo "por si acaso". Prompts completos y conversaciones en crudo son coste, ruido y un problema de privacidad (06-02). Referencias y medidas, no contenidos; y retención definida.
- Observabilidad de software clásico sin señales de LLM. Uptime y errores HTTP no ven alucinaciones, degradación de confianza ni huecos de documentación. Las métricas específicas (frase anti-alucinación, confianza, confirmaciones rechazadas) son las que detectan los fallos silenciosos.
- Logs sin versiones. Si cada línea no lleva
prompt_version/chunking_version/modelo, no podrás responder a la única pregunta que importa tras un despliegue: "¿esto empezó con el cambio?". - Mirar la latencia media. La media esconde la cola; el usuario del p95 es el que abandona. Percentiles siempre (los calculabas ya con
medir_llamada()en 03-04). - Alertas sin acción asociada. Cada alerta debe nacer con su fila de la tabla síntoma→causa→acción. Si al dispararse nadie sabe qué hacer, no es una alerta: es ruido programado.
- Recoger feedback y no explotarlo. El % de pulgares en un panel es la parte pequeña; el valor está en convertir los 👎 en casos del conjunto de 06-03. Feedback sin ciclo es un buzón de sugerencias sin fondo.
- Confundir monitorización con evaluación. Los paneles te dicen que algo empeoró; el runner de 06-03 te dice si tu arreglo lo corrige sin romper otra cosa. Son las dos mitades del mismo músculo: producción alimenta el conjunto; el conjunto protege producción.
Ejercicios
Ejercicio 1: diagnosticar con los paneles
Es lunes. El panel de DocuBot muestra, respecto a la semana pasada: tasa de frase_sin_info estable (11%), confianza media estable, coste diario +40%, latencia p95 +35%, TTFT estable, tasa de caché exacta caída del 30% al 8%, volumen de peticiones +5%. El viernes no se desplegó ninguna versión nueva. ¿Cuál es tu hipótesis principal, qué campos de los logs la confirmarían y qué mirarías primero?
Ejercicio 2: ampliar el log de peticiones
Añade a log_peticion la información del human-in-the-loop: un campo confirmacion que valga null si la petición no propuso acciones, "aceptada" o "rechazada" si las propuso. Escribe además la consulta conceptual (en pseudocódigo o Python sobre las líneas JSON) que calcula la tasa semanal de rechazo, y explica con qué alerta de la tabla se conecta.
Ejercicio 3: del pulgar abajo al caso de evaluación
Un usuario vota 👎 en una respuesta sobre la categoría permisos con el comentario "me dijo que los invitados pueden editar tareas, y no es verdad". El log muestra: confianza: 0.82, dos chunks recuperados con similitudes 0.58 y 0.47, frase_sin_info: false. Describe el diagnóstico paso a paso (qué mirarías y en qué orden) y redacta el caso de evaluación resultante para el conjunto de 06-03.
Soluciones
Ejercicio 1:
La pieza clave es la caída de la caché exacta (30% → 8%) con volumen casi plano y sin despliegue: cada petición que antes salía gratis de CacheRespuestas ahora va al modelo — eso explica simultáneamente el coste (+40%) y el p95 (+35%: las respuestas cacheadas eran instantáneas y bajaban el percentil), con TTFT estable (el proveedor está bien; simplemente hay más llamadas reales). Hipótesis principal: cambió el patrón de las preguntas — preguntas nuevas que no están en caché. ¿Por qué en lunes? Un candidato típico: Nubelia lanzó algo el fin de semana y llegan preguntas inéditas. Confirmación en los logs: distribución de cache (miss disparado), volumen por categoria (¿una categoría creció?), y muestreo de las preguntas nuevas (redactadas). Nota fina: frase_sin_info estable sugiere que la wiki sí cubre los temas nuevos — si además subiera, la hipótesis del lanzamiento sin documentar ganaría fuerza. Primera acción: mirar la distribución de caché por categoría; si es un tema nuevo legítimo, el coste extra es demanda real (y la caché se recalentará sola en días).
Ejercicio 2:
En responder, al registrar:
log_peticion(
# ... campos anteriores ...
confirmacion=(None if not propuestas_accion
else "aceptada" if propuestas_accion.aceptada
else "rechazada"),
)Consulta sobre los JSON Lines:
import json
def tasa_rechazo(ruta_log: str) -> float:
con_propuesta = rechazadas = 0
with open(ruta_log, encoding="utf-8") as f:
for linea in f:
e = json.loads(linea)
if e.get("evento") == "peticion" and e.get("confirmacion") is not None:
con_propuesta += 1
if e["confirmacion"] == "rechazada":
rechazadas += 1
return rechazadas / con_propuesta if con_propuesta else 0.0Detalle importante: el denominador son las peticiones con propuesta (confirmacion is not None), no todas — por eso el campo distingue null de los otros dos valores. Se conecta con la alerta "tasa de confirmaciones rechazadas 5% → 30%": rechazo alto = el agente propone mal (prompt/descripciones de herramienta degradados) o, en el peor caso, contenido hostil empujando acciones — lo que remite a las trazas por paso y a las defensas de 06-01.
Ejercicio 3:
Diagnóstico ordenado: (1) Con id_peticion, recuperar la traza completa y los ids de los chunks (0.58 y 0.47 — el segundo roza el UMBRAL_RELEVANCIA=0.45: recuperación mediocre). (2) Leer los chunks por su id: ¿alguno afirma que los invitados pueden editar tareas? Dos ramas: si ningún chunk lo dice → respuesta infiel (alucinación con confianza 0.82: el perfil peligroso), problema de generación; si un chunk desactualizado lo dice → el problema es de contenido/ingesta, no del modelo — corregir el documento y reingerir (04-03). (3) Según la rama: rama infidelidad → caso para el runner con juez de fidelidad; rama documento → arreglo editorial + verificación. Caso de evaluación (rama infidelidad):
{
"id": "prod-perm-014",
"origen": "feedback_produccion", # la cantera nueva
"tipo": "ambigua",
"categoria": "permisos",
"pregunta": "¿Pueden los usuarios invitados editar tareas de un proyecto?",
"fuentes_esperadas": ["doc_permisos_roles"],
"criterio_exito": "afirma que los invitados NO pueden editar tareas "
"(solo lectura y comentarios), cita doc_permisos_roles, "
"y no atribuye a los invitados permisos de edicion",
}Con esto, la próxima variación de prompt o chunking se valida también contra el fallo real: el ciclo de mejora continua, cerrado.
Conclusión
Las trazas sembradas en 05-02 han germinado en un sistema nervioso completo: cada petición deja una línea JSON con su identidad seudonimizada (la lección de 06-02 aplicada a los propios logs), sus versiones de prompt/chunking/modelo (sin ellas ningún análisis post-despliegue es posible), sus chunks y similitudes, sus herramientas y confirmaciones, sus tokens, coste y percentiles de latencia, y las señales de calidad que el sistema ya emitía gratis — la confianza del contrato y la frase anti-alucinación, cuya tasa resulta ser el mejor termómetro de los huecos de la documentación. Encima de los logs, ocho métricas con dueño y una tabla de alertas que no gritan "algo va mal" sino "esto es lo que probablemente pasa y esto es lo primero que debes mirar". Y el cierre del círculo: los pulgares abajo de usuarios reales se convierten, vía id_peticion, en casos nuevos del conjunto de 06-03 — producción alimenta la evaluación, la evaluación protege producción. Con esto, el casco está completo: DocuBot resiste manipulación (06-01), respeta los datos (06-02), se evalúa antes de cambiar (06-03) y se vigila mientras opera (06-04). Solo queda una cosa, y es la más satisfactoria: juntar todas las piezas construidas a lo largo de seis módulos, mirar la arquitectura completa de una vez, recorrer una petición real de punta a punta y pasar la checklist final de producción. La próxima lección es el proyecto final — DocuBot, entero.
Curso de IA Generativa y LLMs para Desarrolladores
Módulo 1: Fundamentos de la IA generativa
- Qué es la IA generativa y por qué importa a los desarrolladores
- Cómo funciona un LLM: tokens, embeddings y atención
- Panorama de modelos y proveedores
- Limitaciones y riesgos: alucinaciones, contexto y costes
Módulo 2: Prompt engineering
- Anatomía de un prompt: roles, instrucciones y contexto
- Técnicas de prompting: few-shot, cadena de razonamiento y plantillas
- Salidas estructuradas: JSON y control de formato
- Iteración y evaluación de prompts
Módulo 3: Integración de LLMs en aplicaciones
- Primera integración con la API de un LLM
- Streaming, errores y reintentos
- Conversaciones y gestión del contexto
- Costes, latencia y caching
Módulo 4: RAG - Generación aumentada por recuperación
- Embeddings y búsqueda semántica
- Bases de datos vectoriales
- Ingesta y chunking de documentos
- Construcción de un pipeline RAG completo
- Evaluación de sistemas RAG
Módulo 5: Function calling y agentes
- Function calling: conectar el LLM con tu código
- De LLM a agente: el bucle de razonamiento y acción
- Frameworks de orquestación
