Modern Agent Engineering

Cómo crear un agente tutor de matemáticas que mantenga la precisión

Una arquitectura práctica para agentes tutores de matemáticas: genera problemas aleatorios con plantillas y semillas, calcula la solución canónica fuera del LLM, usa el modelo para las explicaciones y verifica cada respuesta antes de mostrársela a los estudiantes.

16 min de lectura

Al 1 de julio de 2026, la realidad del producto es esta: los modelos de lenguaje grandes pueden sonar como excelentes tutores de matemáticas, pero no son calculadoras confiables. La documentación de Structured Outputs de OpenAI usa una aplicación de tutoría de matemáticas como ejemplo canónico de respuestas para una interfaz con un esquema definido y, aun así, advierte que la salida estructurada «todavía puede contener errores» (Structured Outputs de OpenAI). Una investigación reciente sobre modelos de frontera concluye que incluso los sistemas que han ganado medallas siguen siendo «obstinadamente malos en aritmética básica» a medida que aumenta la longitud de los operandos, y que la mayoría de los errores se relacionan con desajustes en la tokenización y errores de acarreo, más que con razonamiento profundo (AI-rithmetic, febrero de 2026).

Esa combinación define el trabajo de ingeniería. Un agente tutor de matemáticas no consiste en «pedirle al modelo con un prompt que invente una hoja de ejercicios». Se trata de una arquitectura dividida:

  1. Código determinista genera parámetros aleatorios, calcula la respuesta canónica y verifica las respuestas de los estudiantes.
  2. El LLM convierte los datos verificados en enunciados, pistas y explicaciones de los pasos que resulten comprensibles para el estudiante.
  3. Los evaluadores comprueban que las explicaciones coincidan con la solución canónica antes de que algo llegue al estudiante.

Study Mode de OpenAI, lanzado el 29 de julio de 2025, sigue una lógica de producto similar: preguntas socráticas y pistas graduales en lugar de respuestas inmediatas. Sin embargo, OpenAI también señala que funciona con instrucciones de sistema personalizadas y puede mostrar «comportamientos inconsistentes y errores entre conversaciones» (anuncio de Study Mode de OpenAI). Si estás creando tu propio tutor, necesitas garantías más sólidas que el tono de un prompt.

Resumen

  • No le pidas al LLM que invente números aleatorios y la respuesta correcta de una sola vez. Eso acopla dos problemas difíciles: el muestreo y la aritmética.
  • Genera problemas con plantillas paramétricas y semillas. Misma semilla → misma hoja de ejercicios. Semilla diferente → números nuevos, mismo perfil de dificultad.
  • Calcula las respuestas fuera del modelo con SymPy, un evaluador de Python aislado en un sandbox o solucionadores específicos del dominio. Trata al LLM como un narrador, no como una calculadora.
  • Usa Structured Outputs para definir la estructura, no para garantizar la verdad. El esquema JSON garantiza la presencia de campos; no garantiza que 2 + 2 = 5 sea imposible (Structured Outputs de OpenAI).
  • Verifica cada explicación contra la solución canónica antes de mostrarla. Rechaza o vuelve a generar las explicaciones cuando los pasos no coincidan con ella.
  • Evalúa con pruebas de escenarios y comprobaciones contra las respuestas esperadas, no por intuición. Consulta Calificación de trazas vs. pruebas de escenarios para conocer el patrón de evaluación más amplio.

Qué aprenderás aquí

  • Por qué la tutoría de matemáticas rompe el patrón de «un prompt, un modelo»
  • Qué limitaciones de inferencia de los LLM importan para generar problemas, respuestas y explicaciones
  • Una arquitectura de referencia que separa verdad, lenguaje y pedagogía
  • Cómo generar problemas aleatorios pero reproducibles con plantillas y semillas
  • Una implementación mínima en TypeScript/Python que puedes adaptar
  • Puntos de integración para verificación, calificación y evaluaciones de producción que puedes conectar a CI

Alcance previsto del artículo

Este artículo parte de que quieres un agente que pueda:

  1. generar un problema de matemáticas bajo demanda (opcionalmente con una dificultad elegida),
  2. producir la respuesta correcta y los pasos de la solución,
  3. explicar cómo resolverlo en lenguaje sencillo,
  4. mantener la consistencia cuando se reutiliza la misma semilla,
  5. evitar que las alucinaciones aritméticas lleguen a los estudiantes.

Si tu alcance se limita a la tutoría paso a paso sobre problemas fijos de un libro de texto —sin generación aleatoria—, puedes omitir las secciones del generador y conservar las partes de calcular antes de explicar y verificación.

Por qué fallan los tutores de matemáticas creados como chatbots

La mayoría de los tutores de demostración se ven así:

User: "Give me a hard algebra problem"
   |
   v
LLM invents problem + answer + steps in one completion
   |
   v
Polished explanation (sometimes wrong)

Ese diseño falla por razones predecibles:

Tipo de fallaQué sale malPor qué el LLM no debería encargarse
Operandos aleatoriosLos valores «aleatorios» cambian entre turnosLos LLM no exponen un generador de números aleatorios real; predicen tokens plausibles
AritméticaLa respuesta final es incorrectaLos modelos de frontera todavía pierden precisión al sumar números de varios dígitos (AI-rithmetic)
Consistencia de las reglasA + B ≠ B + A en casos límiteLos modelos suelen violar invariantes algebraicos ante perturbaciones (diagnóstico de sumas, abril de 2025)
Validez de los pasosLos pasos parecen coherentes, pero omiten razonamientosEl éxito en un benchmark ≠ la corrección de cada paso en entornos educativos (artículo de AIME-Con 2025)
ReproducibilidadMisma solicitud → diferente hoja de ejerciciosEl muestreo no es determinista, a menos que controles las semillas en otro lugar

Una respuesta incorrecta destruye la confianza más rápido que una explicación sencilla. La solución es sacar la verdad del modelo y tratar al LLM como una capa de presentación sobre datos verificados.

Arquitectura de referencia: verdad, lenguaje y pedagogía

                    +---------------------------+
                    | Problem spec (JSON)       |
                    | topic, difficulty, seed   |
                    +-------------+-------------+
                                  |
                                  v
+------------------+   +------------------+   +------------------+
| Parametric       |   | Ground-truth     |   | LLM explainer    |
| generator        |-->| engine (SymPy /  |-->| (hints, steps,   |
| (seeded RNG)     |   | sandboxed code)  |   |  Socratic tone)  |
+------------------+   +--------+---------+   +--------+---------+
                                |                        |
                                v                        v
                       +--------+---------+    +--------+---------+
                       | Canonical result |    | Draft explanation|
                       | problem + answer |    | structured JSON  |
                       +--------+---------+    +--------+---------+
                                \                        /
                                 v                      v
                          +-----+----------------------+-----+
                          | Verifier / grader             |
                          | - numeric equality            |
                          | - step replay                 |
                          | - policy (hint-not-answer)    |
                          +---------------+---------------+
                                          |
                                          v
                               +----------+-----------+
                               | Student-facing UI    |
                               +----------------------+

Tres funciones, tres responsables:

  • Generador — software que controlas por completo.
  • Motor de solución canónica — código simbólico o numérico con pruebas.
  • LLM — lenguaje, apoyo gradual y diagnóstico de conceptos erróneos.

Esta es la misma separación neurosimbólica que describen los stacks matemáticos aumentados con herramientas: analizar con el modelo, calcular con SymPy y volver a explicar con el modelo (ecosistema SymPy MCP, math-logic-mcp).

Limitaciones de inferencia de los LLM que realmente importan aquí

1. La aleatoriedad no es una función del modelo

Si necesitas «10 problemas nuevos cada mañana» o «la misma hoja de ejercicios después de actualizar la página», usa seed + código determinista, no «por favor, genera valores aleatorios».

// Same seed => same operands. Different seed => new worksheet.
function mulberry32(seed: number) {
  return function () {
    seed |= 0; seed = (seed + 0x6d2b79f5) | 0;
    let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

function randInt(rng: () => number, min: number, max: number) {
  return Math.floor(rng() * (max - min + 1)) + min;
}

Guarda { seed, templateId, params } en la sesión o en la base de datos. Reconstruye el problema exacto más adelante sin depender de la memoria del chat.

2. Structured Outputs define la estructura del JSON, no la corrección matemática

La documentación de OpenAI es explícita: Structured Outputs «garantiza la conformidad con el esquema», pero «todavía puede contener errores» (guía de Structured Outputs). Usa esquemas para campos de la interfaz como:

{
  "steps": [{ "explanation": "string", "expression": "string" }],
  "hintLevel": "nudge | scaffold | reveal",
  "finalAnswer": "string"
}

Nunca consideres que cumplir el esquema demuestra que las matemáticas son correctas.

3. La tokenización afecta la aritmética

La investigación sobre modelos de frontera muestra que la tokenización de números cambia los patrones de error; agrupar los dígitos separados por comas o en orden inverso puede alterar la precisión (Tokenization counts, 2024). Conclusión práctica: aunque el modelo a veces obtenga la respuesta correcta, no bases la calificación en su cálculo mental.

4. Las explicaciones pueden contradecirse

Las evaluaciones centradas en educación reportan tanto errores de cálculo como errores de razonamiento lógico en las soluciones generadas por modelos (artículo de AIME-Con 2025). Tu verificador debe comprobar el valor final y los pasos intermedios, no la seguridad con la que se expresa el modelo.

Implementación: plantillas paramétricas de problemas

Empieza con plantillas, no con generación libre. Cada plantilla define:

  • rangos permitidos para los operandos,
  • restricciones (solo enteros, sin divisores negativos, etc.),
  • una función que calcula la solución canónica,
  • metadatos de dificultad para filtros de API y selección de plantillas.
type ProblemTemplate = {
  id: string;
  topic: "linear-equation" | "quadratic-factor" | "percent-change";
  params: (rng: () => number) => Record<string, number>;
  render: (p: Record<string, number>) => string;
  solve: (p: Record<string, number>) => { answer: string; steps: string[] };
};

const linearEquation: ProblemTemplate = {
  id: "linear-equation-v1",
  topic: "linear-equation",
  params: (rng) => {
    const m = randInt(rng, 2, 9);
    const x = randInt(rng, -12, 12);
    const b = randInt(rng, -20, 20);
    const c = m * x + b;
    return { m, b, c, x };
  },
  render: ({ m, b, c }) => `Solve for x: ${m}x + ${b} = ${c}`,
  solve: ({ m, b, c, x }) => ({
    answer: String(x),
    steps: [
      `Subtract ${b} from both sides: ${m}x = ${c - b}`,
      `Divide both sides by ${m}: x = ${x}`,
    ],
  }),
};

export function generateProblem(template: ProblemTemplate, seed: number) {
  const rng = mulberry32(seed);
  const params = template.params(rng);
  const prompt = template.render(params);
  const truth = template.solve(params);
  return { seed, templateId: template.id, prompt, truth, params };
}

Por qué este patrón funciona bien en producción:

  • La dificultad es explícita en el código (m entre 2–9, soluciones enteras), no se infiere del tono del prompt.
  • Cada plantilla incluye una función de solución que se puede probar con pruebas unitarias.
  • Los reportes de errores se pueden reproducir solo con { seed, templateId }.

Implementación: solución canónica con SymPy

Para álgebra que vaya más allá de las plantillas escritas a mano, delega el cálculo a SymPy:

import sympy as sp

def solve_linear(equation: str, variable: str = "x") -> dict:
    x = sp.Symbol(variable)
    lhs, rhs = equation.split("=")
    expr = sp.Eq(sp.sympify(lhs.strip()), sp.sympify(rhs.strip()))
    solution = sp.solve(expr, x)
    return {
        "answer": str(solution[0]),
        "verified": sp.simplify(sp.sympify(lhs) - sp.sympify(rhs).subs(x, solution[0])) == 0,
    }

Patrones que vale la pena adoptar de las herramientas matemáticas de MCP:

  • verify_arithmetic para expresiones simples sin dependencias simbólicas (math-logic-mcp).
  • solve_equation / simplify_expression para álgebra y cálculo.
  • Devuelve los pasos de la demostración desde la herramienta, no desde el modelo.

Nota de seguridad: nunca uses eval() con la salida sin procesar del modelo. Acepta solo parámetros estructurados creados por tu generador o analízalos mediante una política estricta de AST antes de ejecutarlos: la misma medida de protección que se usa en servidores SymPy MCP de producción.

Implementación: prompt para que el LLM explique

Una vez que existe una solución canónica, la tarea del modelo es más acotada y segura:

type ExplainRequest = {
  problem: string;
  canonicalAnswer: string;
  canonicalSteps: string[];
  hintLevel: "nudge" | "scaffold";
  learnerAttempt?: string;
};

const system = `
You are a math tutor. You MUST NOT change the correct answer or canonical steps.
You may rephrase steps, add intuition, and ask Socratic questions.
If the learner attempt is wrong, diagnose the likely misconception without revealing
the full solution when hintLevel=nudge.
Return JSON matching the MathExplanation schema.
`;

El cookbook de Structured Outputs de OpenAI usa la misma separación: un esquema para steps[] y final_answer, con el modelo razonando sobre una pregunta proporcionada por el usuario (introducción a Structured Outputs). En tu aplicación, la pregunta y la respuesta final son entradas, no invenciones del modelo.

Alineación pedagógica: Study Mode de OpenAI enfatiza las preguntas socráticas, las pistas y las comprobaciones de conocimiento en lugar de las respuestas inmediatas (anuncio de Study Mode). Codifica eso como una política de hintLevel en el código, en lugar de confiar en que el prompt lo logre.

Ciclo de verificación (no negociable)

Antes de devolver cualquier cosa a la interfaz:

Draft explanation
      |
      v
1) Parse finalAnswer
      |
      v
2) Compare to canonicalAnswer (symbolic or numeric tolerance)
      |
      v
3) Replay canonicalSteps OR re-solve with SymPy
      |
      v
4) Optional LLM judge: "Do steps support the answer?"
      |
      v
Pass -> render   |   Fail -> regenerate once -> escalate to template-only steps

Verificador mínimo:

function verifyExplanation(
  canonical: { answer: string; steps: string[] },
  draft: { finalAnswer: string; steps: { expression: string }[] }
) {
  if (canonical.answer.trim() !== draft.finalAnswer.trim()) {
    return { ok: false, reason: "final_answer_mismatch" };
  }
  // Stronger: evaluate each draft.expression with your symbolic engine
  return { ok: true };
}

Si la verificación falla, recurre a los pasos deterministas de la plantilla. Una explicación correcta pero sencilla es mejor que una explicación carismática e incorrecta.

Flujo de orquestación del agente

Para un agente completo (generar → explicar → orientar → calificar):

Student                Orchestrator                 Tools / Services
  |                          |                              |
  |-- "Give me medium algebra"|                              |
  |                          |-- pick template + seed ------>| generator
  |                          |<-- problem, truth ------------|
  |                          |-- explain(truth) ------------>| LLM
  |                          |<-- draft JSON -----------------|
  |                          |-- verify(truth, draft) ------>| verifier
  |<-- problem + hints ------|                              |
  |                          |                              |
  |-- student attempt ------>|-- grade attempt ------------->| grader
  |<-- feedback -------------|<-- compare to truth ----------|

Consejos para el diseño de herramientas:

  • generate_problem(templateId, seed, difficulty) — determinista.
  • compute_solution(problemSpec) — SymPy / sandbox.
  • explain_solution(truth, pedagogyPolicy) — solo LLM.
  • grade_attempt(truth, attempt) — primero lógica determinista; después, el LLM para etiquetar conceptos erróneos.

Esto refleja el stack de agentes más amplio de Cómo aprender ingeniería de agentes de IA para producción: herramientas explícitas, puntos de control de políticas, trazas y puntos de integración para evaluaciones, no un solo ciclo de chat sin límites.

Evaluación: qué medir antes del lanzamiento

CapaQué probarEjemplo de criterio de aprobación
Generadormisma semilla → mismo problema100% de coincidencia con 1k semillas
Solucionadorrespuestas de las plantillas frente a SymPy100% de igualdad en el conjunto generado
Explicadorborradores verificados≥ 99% aprueba la verificación
Pedagogíapolítica de pistas0 respuestas completas cuando hintLevel=nudge
Regresióncambio de modelopruebas contra las respuestas esperadas sin cambios

Usa pruebas de escenarios para el comportamiento del tutor («el estudiante pide la respuesta repetidamente y el tutor sigue ofreciendo apoyo gradual») y calificación de trazas o comprobaciones contra las respuestas esperadas para detectar desviaciones en la corrección después de cambiar el prompt o el modelo (Calificación de trazas vs. pruebas de escenarios).

Como medida de protección para los resultados de aprendizaje, combina las evaluaciones de ingeniería con la advertencia de las ciencias del aprendizaje en Cómo usar la IA para aprender más rápido sin volverte dependiente de ella: mide si tu tutor desarrolla habilidades, no solo si ayuda a completar ejercicios.

Lista de verificación antes del lanzamiento

Antes de lanzar:

  1. ¿Qué temas son seguros para usar con plantillas desde el primer día? Empieza con ecuaciones lineales de enteros, problemas de porcentajes y factorización de cuadráticas con raíces enteras, no con generación abierta de demostraciones.
  2. ¿Necesitas ejercicios reproducibles? Si es así, conserva seed en el estado de la sesión y en los enlaces para compartir.
  3. ¿Qué sucede cuando falla la verificación? Por defecto: muestra los pasos canónicos de la plantilla y omite los adornos del LLM.
  4. ¿La arquitectura respalda lo que afirmas? Un «motor de práctica verificado» necesita código que calcule la solución canónica; un tutor basado solo en prompts acabará entregando respuestas incorrectas.
  5. ¿Cómo se detectarán las regresiones? Antes del lanzamiento: una suite de pruebas contra las respuestas esperadas en CI. Después del lanzamiento: reportes de respuestas incorrectas y reproducción periódica con SymPy.

Qué no debes prometer de más

Criterio editorial, expresado con claridad:

  • Esta arquitectura reduce el riesgo aritmético; por sí sola no resuelve la tutoría de demostraciones abiertas ni la comprensión de problemas enunciados en lenguaje natural.
  • Las pistas generadas por LLM todavía pueden ser débiles desde el punto de vista pedagógico aunque sean matemáticamente correctas.
  • El comportamiento socrático al estilo de Study Mode favorece los resultados de aprendizaje, pero el texto de la interfaz no debería insinuar que existe verificación formal a menos que hayas construido esa capa de verificación.

Haz de la honestidad una funcionalidad.

Fuentes

Fuentes primarias y fuentes técnicas sólidas:

Lecturas relacionadas en este sitio: