← Todos los proyectos

Caso de estudio

Simulador de exámenes de certificación con un banco de preguntas original

Prepararse una certificación te deja elegir entre diez preguntas oficiales de muestra y volcados de examen filtrados. Esto genera un banco original y ponderado por dominios a partir de las guías oficiales, y lo entrena con repetición espaciada.

Problema

Estoy preparando cinco certificaciones de cloud e IA a la vez: GCP Generative AI Leader, Claude Certified Architect, AWS Cloud Practitioner (CLF-C02), AWS AI Practitioner (AIF-C01) y GCP Associate Cloud Engineer. Todas chocan contra el mismo muro. Los proveedores publican una guía de examen con dominios y sus pesos, y como mucho diez preguntas de muestra. Todo lo demás que hay por ahí es un sitio de volcados reciclando preguntas que están bajo NDA, equivocadas tantas veces como acertadas, e inútiles para entender por qué una respuesta es correcta.

Más preguntas no arreglarían eso. Lo que yo quería era un banco que siguiera el esquema oficial dominio a dominio, y una forma de averiguar qué dominio es el más flojo antes de que lo averigüe el examen por mí.

Así que la herramienta genera un banco original anclado en el temario oficial, lo pondera como está ponderado el examen real y lo entrena en condiciones de examen, con repetición espaciada sobre todo lo que fallo.

Arquitectura

El sistema separa con dureza la generación offline del servicio en tiempo de ejecución. Nada llama a un LLM mientras corre un simulacro: el banco es un artefacto de build producido por un pipeline que puede reejecutarse para ampliarlo, y la aplicación que lo sirve es una web local sin ninguna dependencia de red.

Pipeline de generación offline y runtime local del simulador de exámenes En offline, las guías oficiales de examen, las preguntas públicas de muestra y los pesos por dominio alimentan un paso de generación que corre sobre Gemini, Claude o un modelo local Qwen3; su salida la revisa un juez LLM local y se traduce al inglés. En tiempo de ejecución, el banco SQLite resultante lo sirve FastAPI a una single-page app de React que ofrece práctica, exámenes cronometrados y repetición espaciada, sin ninguna llamada de red. A · OFFLINE · SE GENERA UNA VEZ GUÍAS DE EXAMEN 5 temarios oficiales MUESTRAS DE ESTILO preguntas públicas de ejemplo PESOS POR DOMINIO 23 dominios GENERACIÓN · GEMINI · CLAUDE · QWEN3 VÍA OLLAMA reparto proporcional por dominio · validación pydantic · dedup por hash · reanudable JUEZ LLM · GPT-OSS:20B 983 ok · 19 leves · 50 marcadas TRADUCCIÓN · QWEN3:30B 1.012 preguntas → EN banco congelado en el build B · RUNTIME · LOCALHOST, UN SOLO USUARIO SQLITE 1.062 preguntas FASTAPI sqlite3 de stdlib · sin ORM SPA EN REACT 19 práctica · examen · SM-2 routers: certifications · questions · practice · exams · progress · review
fig. 1 · La generación corre como pipeline offline. El runtime nunca llama a un LLM.

La generación lee el temario oficial de una certificación, reparte un número objetivo de preguntas entre sus dominios en proporción a los pesos oficiales, e inyecta el temario más una o dos preguntas públicas de muestra como anclaje de estilo, nunca como contenido a reproducir. La salida se parsea a modelos de Pydantic y se deduplica por hash de contenido, así que reejecutar el script amplía el banco en lugar de duplicarlo. El proveedor es intercambiable entre Gemini, Anthropic y un Qwen3 local a través de Ollama.

El control de calidad es una segunda pasada independiente. Un modelo juez local responde cada pregunta sin ver la respuesta marcada, compara su propia elección con la clave almacenada y señala errores factuales, ambigüedades y preguntas de respuesta múltiple no declaradas. Nunca edita ni borra nada. Escribe un veredicto, y las preguntas señaladas se desactivan en vez de eliminarse, de modo que el rastro de auditoría sobrevive.

El servicio es deliberadamente aburrido: FastAPI sobre el sqlite3 de la biblioteca estándar, sin ORM, seis routers y una SPA de React 19 que cubre el panel, el modo práctica (feedback inmediato, explicaciones por opción), el modo examen cronometrado (muestreo proporcional por dominio, sin feedback hasta el final, resultado contra el umbral real de aprobado) y una cola de repaso SM-2. En modo «producción local» el mismo servidor sirve además el frontend compilado.

Decisiones y compromisos

  • Las preguntas se generan offline y nunca en tiempo de ejecución. La carga de preguntas es instantánea, un simulacro no cuesta nada en tokens ni en latencia, y la aplicación funciona con la red desenchufada. El coste es que el banco es un artefacto de build: ampliarlo o arreglar un dominio malo significa reejecutar un pipeline, no pulsar un botón.
  • Solo preguntas originales, con el material oficial como anclaje y no como contenido. Las guías de examen aportan el temario y las muestras públicas aportan el registro, y ninguna de las dos se reproduce ni se muestra nunca. Eso costó bastante más prompt engineering y validación que raspar un volcado, a cambio de un banco limpio legal y éticamente.
  • Un segundo LLM audita al primero. Generación y validación usan modelos distintos, y el juez responde de forma independiente antes de ver la clave, que es lo que hace informativo el desacuerdo. Añade una etapa de pipeline sobre todo el banco, y desactivó 50 preguntas (4,7%) que si no me habrían enseñado algo incorrecto.
  • sqlite3 en crudo, sin ORM, sin autenticación. Un usuario, una máquina, un fichero. A cambio escribo SQL a mano y no tengo herramientas de migración, lo cual es aceptable a este tamaño y sería lo primero en caer si esto llegara a ser multiusuario.
  • El plan gratuito de Gemini se trata como restricción de diseño, no como obstáculo. La limitación de peticiones, el backoff exponencial respetando el retryDelay de la API, las ejecuciones reanudables y la deduplicación por hash existen porque la cuota diaria se agota a mitad de generación. Aquí no hay compromiso digno de mención: la restricción produjo un pipeline idempotente e interrumpible, que es lo que debería haber sido de todos modos.

Métricas

Estas son propiedades del sistema tal y como está, medidas contra la base de datos real. Aquí no hay un antes y un después. El número honesto sobre resultados de estudio es que todavía no hay ninguno: exam_attempts está vacía, así que nada en esta tabla afirma que la herramienta mejore los resultados del examen.

MétricaValor
Preguntas en el banco1.062 en 5 certificaciones y 23 dominios
Por certificaciónde 204 a 229 preguntas
Activas tras la revisión1.012 · 50 desactivadas por el juez
Veredictos del juez983 ok · 19 leves · 50 marcadas (gpt-oss:20b)
Modelos de generación usadosclaude-sonnet-5 (378) · qwen3:30b (274) · claude-opus-4-8 (204) · gemini-2.5-flash (196)
Tipos de pregunta863 de respuesta única · 199 de respuesta múltiple
Reparto por dificultad691 media · 230 difícil · 141 fácil
Traducciones al inglés1.012 (qwen3:30b-a3b), originales en español intactos
Llamadas a LLM en runtime0
Intentos de examen registrados0 (todavía sin datos de resultado)

Lecciones aprendidas

El anclaje le ganó al tamaño del modelo. Las preguntas que más se parecen al examen real salieron de darle al modelo la sección concreta del temario y una muestra para el registro, no de tirar de un modelo más grande. Un Qwen3 local con buen anclaje produjo 274 preguntas utilizables, y los modelos caros no fueron proporcionalmente mejores.

El juez se ganó el sueldo, y es también la parte de la que menos me fío. Cincuenta preguntas señaladas son una tasa de error del 4,7% que se habría ido directa a mi tiempo de estudio: vale cada token. Pero un único juez local es una sola opinión. El TFM que construí alrededor de la validación de LLM-as-a-judge necesitó tres capas de validación independientes antes de que sus puntuaciones significaran algo, y este pipeline no tiene ninguna. Los veredictos son útiles como filtro, no como verdad de referencia.

Los límites de peticiones produjeron un pipeline mejor del que habría salido de una cuota generosa. Verme obligado a hacer la generación reanudable, idempotente y deduplicada la convirtió en algo que puedo reejecutar contra cualquier certificación en cualquier momento, que es como debería haberse escrito desde el principio.

Nada de esto demuestra que funcione. El banco está construido, revisado, traducido y servido, y la cola de repaso está vacía porque todavía no me he sentado a hacer un simulacro completo. Escribir «0 intentos registrados» en un caso de estudio es menos satisfactorio que una mejora de puntuación inventada, pero es la única versión de esta sección que es verdad.

Enlaces

  • Sin repositorio público: esta es una herramienta de un solo usuario que corre en localhost, y parte del material de partida (guías de examen, muestras oficiales) no es mío para redistribuirlo.
  • Relacionado: Medir lo que las técnicas de prompting queman de verdad, la metodología de LLM-as-a-judge de la que este pipeline toma prestado.