
Proyecto Hamilton: Formando a los Nuevos Detectives de la Inteligencia Artificial en 1º y 2º de ESO
Publicado por: Departamento de Tecnología e Innovación Educativa — IES Monterroso
Nivel educativo: 1º y 2º de ESO
Laboratorio: Proyecto Hamilton (app_hamilton.py — Puerto :8063)
En un mundo donde las herramientas de Inteligencia Artificial Generativa responden a cualquier pregunta en segundos, surge una competencia fundamental para el siglo XXI: saber dudar y verificar. Inspirándonos en la figura de Margaret Hamilton —la legendaria ingeniera que lideró el desarrollo del software de navegación para las misiones Apolo de la NASA y pionera en la prevención de errores—, presentamos en el IES Monterroso el Proyecto Hamilton: Cazador de Alucinaciones.
Esta actividad práctica transforma el aula de 1º y 2º de ESO en un laboratorio de auditoría digital, donde los estudiantes pasan de ser consumidores pasivos de información a detectives críticos capaces de auditar los textos producidos por modelos de lenguaje.
¿Por qué el Proyecto Hamilton en la ESO?
Los modelos de lenguaje (LLM) son herramientas potentes, pero sufren de un fenómeno conocido como “alucinación”: la generación de información falsa, desactualizada o inventada expresada con absoluta seguridad.
Para nuestro alumnado de 12 a 14 años, trabajar con el Proyecto Hamilton persigue tres objetivos clave:
- Fomentar el pensamiento crítico: Comprender que la IA no es infallible ni posee “verdad absoluta”.
- Desarrollar la competencia de verificación: Aprender a contrastar datos usando motores de búsqueda, enciclopedias digitales y fuentes fiables.
- Iniciarse en el Prompt Engineering: Descubrir cómo el razonamiento paso a paso (Chain-of-Thought) y la revisión multi-agente ayudan a identificar inconsistencias lógicas.
¿Cómo funciona el Taller en el Aula?
A través de una interfaz interactiva alojada en el servidor local del centro (app_hamilton.py), el taller se estructura en cuatro fases dinámicas:
1. Selección o Creación del Informe con “Trampas”
Los estudiantes pueden elegir temas cercanos a sus conocimientos e intereses:
- El Antiguo Egipto y los Faraones
- Los Dinosaurios y la Extinción
- Minecraft y la Historia de los Videojuegos
- El Sistema Solar y los Planetas
Tienen la opción de solicitar un borrador generado automáticamente con dos datos falsos inyectados o, de forma más creativa, redactar su propio informe e inyectar sus propias trampas para poner a prueba a sus compañeros.
2. Investigación y Búsqueda en Internet
Los alumnos asumen el rol de investigadores. Utilizando herramientas de búsqueda en la red (Google, Wikipedia, enciclopedias temáticas), leen atentamente el texto y localizan datos sospechosos, anacronismos (por ejemplo, tutankamón gobernando desde un ordenador portátil o camiones diésel en las pirámides) y fechas incoherentes.
3. Poniendo a Prueba a la IA: Razonamiento y Agentes Detectives
La plataforma incluye dos módulos de análisis avanzado de IA:
- Razonamiento Paso a Paso (Chain-of-Thought): El alumnado observa cómo, si se le exige a la IA evaluar premisa por premisa antes de dictaminar, el modelo es capaz de autocorregirse y detectar las mentiras.
- Agente Revisor Imparcial: Un segundo filtro supervisa el texto para ofrecer un veredicto independiente sobre la veracidad del escrito.


4. Evaluación de Hallazgos y Puntuación
Finalmente, los estudiantes envían las inconsistencias encontradas. El sistema evalúa la precisión de su auditoría y les otorga una puntuación sobre 100, ofreciendo retroalimentación inmediata sobre su desempeño investigativo.
Competencias Clave Trabajadas
| Competencia | Aplicación en el Proyecto Hamilton |
| Digital (CD) | Verificación de fuentes en Internet, identificación de sesgos y fallos en IA. |
| Personal, Social y de Aprender a Aprender (CPSAA) | Autonomía en la investigación y análisis crítico de la información. |
| Lingüística (CCL) | Comprensión lectora, redacción propia e identificación de incoherencias textuales. |
| STEM | Introducción a la lógica de programación, prompting estructurado (Chain-of-Thought) y auditoría de software. |
Una Experiencia de Aprendizaje Activa y Divertida
El Proyecto Hamilton demuestra que la alfabetización en Inteligencia Artificial en la Educación Secundaria Obligatoria no debe limitarse a enseñar a “usar la IA para hacer deberes”, sino a entender cómo piensa la IA, dónde falla y cómo podemos supervisarla.
Convertir la detección de errores en un juego de detectives permite a nuestro alumnado adquirir hábitos de lectura reflexiva y contraste de datos que les acompañarán a lo largo de toda su vida académica y personal.
¡El laboratorio ya está en marcha! Puedes acceder a la plataforma en los equipos del aula de informática a través del puerto interno
:8063. ¡Prepara tu lupa digital y caza la alucinación!
# app_hamilton.py
import os
import urllib.request
import json
from typing import List, Optional
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
import uvicorn
app = FastAPI(
title="Proyecto Hamilton - Cazador de Alucinaciones LLM (IES Monterroso)",
description="Laboratorio de Auditoría de IA para ESO (Puerto 8063)",
version="1.1.0"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
LLM_BASE_URL = os.getenv("LLM_BASE_URL", "http://localhost:1234/v1/chat/completions")
LLM_MODEL_NAME = os.getenv("LLM_MODEL_NAME", "local-model")
class ChallengeRequest(BaseModel):
topic: str = Field(..., example="El Antiguo Egipto y las Pirámides")
class AuditCoTRequest(BaseModel):
text_to_audit: str
custom_cot_prompt: str
class SelfCorrectionRequest(BaseModel):
text_to_audit: str
class EvaluateRequest(BaseModel):
original_text: str
hidden_hallucinations: List[str]
student_findings: str
def query_llm_provider(messages: List[dict], temperature: float = 0.7) -> str:
payload = {
"model": LLM_MODEL_NAME,
"messages": messages,
"temperature": temperature,
"max_tokens": 400
}
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(
LLM_BASE_URL,
data=data,
headers={"Content-Type": "application/json"}
)
try:
with urllib.request.urlopen(req, timeout=30) as response:
res_body = json.loads(response.read().decode("utf-8"))
return res_body["choices"][0]["message"]["content"]
except Exception:
return None
HTML_CONTENT = """<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proyecto HAMILTON | Cazador de Alucinaciones (IES Monterroso)</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--monterroso-blue: #004B87;
--monterroso-dark: #00335E;
--monterroso-light: #EBF3FA;
}
.bg-monterroso { background-color: var(--monterroso-blue); }
.bg-monterroso-dark { background-color: var(--monterroso-dark); }
.text-monterroso { color: var(--monterroso-blue); }
.border-monterroso { border-color: var(--monterroso-blue); }
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #f1f1f1; }
::-webkit-scrollbar-thumb { background: #004B87; border-radius: 3px; }
</style>
</head>
<body class="bg-gray-50 text-gray-800 font-sans min-h-screen flex flex-col">
<header class="bg-monterroso text-white shadow-md border-b-4 border-indigo-500">
<div class="max-w-7xl mx-auto px-4 py-3 flex flex-wrap justify-between items-center gap-4">
<div class="flex items-center space-x-3">
<div class="bg-white p-2 rounded-lg text-monterroso font-black text-xl flex items-center justify-center w-10 h-10 shadow">
MH
</div>
<div>
<div class="flex items-center gap-2">
<span class="text-xs tracking-wider uppercase opacity-90 font-semibold">IES Monterroso — Nivel 1º/2º ESO</span>
<span class="px-2 py-0.5 bg-indigo-900 text-[10px] font-mono rounded text-indigo-200 border border-indigo-700">Puerto :8063</span>
</div>
<h1 class="text-xl font-bold tracking-tight flex items-center gap-2">
<span>PROYECTO HAMILTON</span>
<span class="text-xs bg-cyan-400 text-gray-900 px-2 py-0.5 rounded-full font-extrabold uppercase">Cazador de Alucinaciones</span>
</h1>
</div>
</div>
<div class="flex items-center space-x-2">
<span class="px-3 py-1 bg-indigo-900 text-indigo-100 rounded-full text-xs font-semibold flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-cyan-400 animate-pulse"></span>
app_hamilton.py Activo (:8063)
</span>
</div>
</div>
</header>
<main class="max-w-7xl mx-auto px-4 py-6 flex-1 w-full space-y-6">
<section class="bg-white p-5 rounded-xl shadow-sm border border-gray-200 space-y-3">
<div class="bg-gradient-to-r from-slate-900 via-monterroso to-indigo-950 text-white p-3.5 rounded-lg flex items-center justify-between shadow-sm">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 rounded-full bg-cyan-400/20 flex items-center justify-center text-cyan-300 text-xl font-bold border border-cyan-400/30">
<i class="fa-solid fa-magnifying-glass font-bold"></i>
</div>
<div>
<div class="text-[11px] uppercase tracking-wider text-cyan-200 font-semibold">Taller de Detectives de IA (1º/2º ESO)</div>
<div class="text-sm font-bold">Aprende a detectar errores, mentiras y alucinaciones en los textos generados por IA</div>
</div>
</div>
<span class="hidden md:inline-block text-xs text-indigo-100 italic bg-white/10 px-3 py-1 rounded">
"Investiga en Internet, detecta los datos falsos y pon a prueba a la IA."
</span>
</div>
</section>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<section class="lg:col-span-5 space-y-4">
<div class="bg-white p-4 rounded-xl shadow-sm border border-gray-200 space-y-3">
<h2 class="text-xs font-bold text-gray-700 uppercase tracking-wider flex items-center gap-2">
<i class="fa-solid fa-wand-magic-sparkles text-monterroso"></i> 1. Generar texto base (Opcional)
</h2>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Elige un tema divertido para la ESO:</label>
<select id="topic-select" class="w-full p-2 border border-gray-300 rounded text-xs bg-gray-50 focus:bg-white mb-2">
<option value="El Antiguo Egipto y las Pirámides">El Antiguo Egipto y los Faraones</option>
<option value="Los Dinosaurios y la Extinción">Los Dinosaurios y la Edad de Hielo</option>
<option value="Minecraft y la Historia de los Videojuegos">Minecraft y los Videojuegos</option>
<option value="El Sistema Solar y los Planetas">El Sistema Solar y los Planetas</option>
</select>
<button onclick="generateReport()" id="btn-generate" class="w-full py-2 bg-monterroso hover:bg-monterroso-dark text-white font-bold text-xs rounded transition flex items-center justify-center gap-2 shadow">
<i class="fa-solid fa-robot"></i> Pedir a la IA un texto con trampas
</button>
</div>
</div>
<div class="bg-white p-4 rounded-xl shadow-sm border border-gray-200 space-y-2">
<div class="flex justify-between items-center">
<h3 class="text-xs font-bold text-gray-700 uppercase flex items-center gap-1.5">
<i class="fa-solid fa-pen-to-square text-indigo-600"></i> 2. Informe (¡Puedes editarlo o escribirlo tú!):
</h3>
<span id="badge-status" class="text-[10px] bg-gray-100 text-gray-600 px-2 py-0.5 rounded font-mono">Editable</span>
</div>
<p class="text-[11px] text-gray-500">
Pide un texto a la IA arriba o <strong>escribe tú mismo un texto buscando en Internet</strong> e inyecta 2 datos totalmente falsos para retar a tu compañero o a la IA.
</p>
<textarea id="report-text" rows="8" class="w-full p-3 bg-slate-50 border border-gray-300 rounded text-xs text-gray-800 leading-relaxed font-sans focus:bg-white focus:ring-2 focus:ring-monterroso focus:outline-none resize-y" placeholder="Escribe aquí tu informe o haz clic en 'Pedir a la IA un texto con trampas' para generar uno automáticamente..."></textarea>
<div class="pt-2">
<label class="block text-[11px] font-bold text-gray-700 mb-1">🔍 Lista tus trampas (si escribiste tú el texto):</label>
<input type="text" id="manual-errors" placeholder="Ej: Puse que los egipcios usaban teléfonos móviles y que el T-Rex volaba" class="w-full p-2 border border-gray-300 rounded text-xs bg-gray-50 focus:bg-white">
</div>
</div>
</section>
<section class="lg:col-span-7 bg-white p-4 rounded-xl shadow-sm border border-gray-200 flex flex-col">
<div class="flex border-b border-gray-200 text-xs font-bold mb-4">
<button onclick="switchTab('cot')" id="tab-cot" class="px-4 py-2 border-b-2 border-monterroso text-monterroso flex items-center gap-1.5">
<i class="fa-solid fa-brain"></i> Razonamiento (CoT)
</button>
<button onclick="switchTab('self')" id="tab-self" class="px-4 py-2 text-gray-500 hover:text-gray-700 flex items-center gap-1.5">
<i class="fa-solid fa-robot"></i> Agente Detective
</button>
<button onclick="switchTab('eval')" id="tab-eval" class="px-4 py-2 text-gray-500 hover:text-gray-700 flex items-center gap-1.5">
<i class="fa-solid fa-award"></i> Evaluar Mis Hallazgos
</button>
</div>
<div id="panel-cot" class="space-y-3 flex-1 flex flex-col">
<p class="text-xs text-gray-600">
<strong>Auditoría Paso a Paso:</strong> Pídele a la IA que revise frase por frase el texto escrito para ver si descubre las mentiras o alucinaciones.
</p>
<label class="block text-[11px] font-bold text-gray-700">Instrucción para el Detective IA:</label>
<textarea id="cot-prompt" rows="3" class="w-full p-2 border border-gray-300 rounded text-xs font-mono bg-gray-50 focus:bg-white">Lee el texto detenidamente. Analiza cada frase y busca datos falsos, inventados, fechas imposibles o anacronismos. Explica paso a paso qué partes son mentira y por qué.</textarea>
<button onclick="runCoTAudit()" class="py-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-xs rounded transition flex items-center justify-center gap-2">
<i class="fa-solid fa-magnifying-glass text-cyan-200"></i> Buscar Alucinaciones Paso a Paso
</button>
<div id="cot-result" class="flex-1 p-3 bg-indigo-50/50 border border-indigo-100 rounded text-xs font-mono text-gray-800 overflow-y-auto max-h-[220px]">
<em>El análisis del Detective IA aparecerá aquí...</em>
</div>
</div>
<div id="panel-self" class="space-y-3 flex-1 hidden flex flex-col">
<p class="text-xs text-gray-600">
<strong>Agente Revisor Imparcial:</strong> Pasa el texto por un segundo filtro de inteligencia artificial para obtener una crítica rápida.
</p>
<button onclick="runSelfCorrection()" class="py-2 px-4 bg-teal-600 hover:bg-teal-700 text-white font-bold text-xs rounded transition flex items-center justify-center gap-2">
<i class="fa-solid fa-user-check"></i> Invocar Agente Revisor
</button>
<div id="self-result" class="flex-1 p-3 bg-teal-50/50 border border-teal-100 rounded text-xs font-mono text-gray-800 overflow-y-auto max-h-[240px]">
<em>El dictamen del Agente Revisor aparecerá aquí...</em>
</div>
</div>
<div id="panel-eval" class="space-y-3 flex-1 hidden flex flex-col">
<p class="text-xs text-gray-600">
Si has investigado en Internet y has descubierto las mentiras del texto, escríbelas aquí para comprobar tu puntuación:
</p>
<textarea id="student-findings" rows="3" placeholder="Ej: He buscado en Wikipedia y es falso que las pirámides tuvieran ascensores eléctricos..." class="w-full p-2 border border-gray-300 rounded text-xs bg-gray-50 focus:bg-white"></textarea>
<button onclick="evaluateFindings()" class="py-2 px-4 bg-amber-600 hover:bg-amber-700 text-white font-bold text-xs rounded transition flex items-center justify-center gap-2">
<i class="fa-solid fa-trophy"></i> Comprobar mi Puntuación
</button>
<div id="eval-result" class="p-3 bg-amber-50 border border-amber-200 rounded text-xs text-amber-900 space-y-2">
<div class="font-bold">Panel de Puntuación: - / 100</div>
<div>Aún no has enviado tus hallazgos.</div>
</div>
</div>
</section>
</div>
</main>
<footer class="bg-gray-800 text-gray-300 text-xs py-4 mt-auto border-t border-gray-700">
<div class="max-w-7xl mx-auto px-4 flex justify-between items-center">
<div><span class="font-semibold text-white">PROYECTO HAMILTON</span> — IES Monterroso (1º/2º ESO)</div>
<div class="font-mono">app_hamilton.py Activo en :8063</div>
</div>
</footer>
<script>
let currentHiddenErrors = [];
function switchTab(tab) {
document.getElementById('panel-cot').classList.add('hidden');
document.getElementById('panel-self').classList.add('hidden');
document.getElementById('panel-eval').classList.add('hidden');
document.getElementById('tab-cot').className = "px-4 py-2 text-gray-500 hover:text-gray-700 flex items-center gap-1.5";
document.getElementById('tab-self').className = "px-4 py-2 text-gray-500 hover:text-gray-700 flex items-center gap-1.5";
document.getElementById('tab-eval').className = "px-4 py-2 text-gray-500 hover:text-gray-700 flex items-center gap-1.5";
if(tab === 'cot') {
document.getElementById('panel-cot').classList.remove('hidden');
document.getElementById('tab-cot').className = "px-4 py-2 border-b-2 border-monterroso text-monterroso flex items-center gap-1.5 font-bold";
} else if(tab === 'self') {
document.getElementById('panel-self').classList.remove('hidden');
document.getElementById('tab-self').className = "px-4 py-2 border-b-2 border-teal-600 text-teal-700 flex items-center gap-1.5 font-bold";
} else {
document.getElementById('panel-eval').classList.remove('hidden');
document.getElementById('tab-eval').className = "px-4 py-2 border-b-2 border-amber-600 text-amber-700 flex items-center gap-1.5 font-bold";
}
}
async function generateReport() {
const topic = document.getElementById('topic-select').value;
document.getElementById('badge-status').innerText = "Generando...";
document.getElementById('badge-status').className = "text-[10px] bg-amber-100 text-amber-800 px-2 py-0.5 rounded font-mono animate-pulse";
try {
const res = await fetch('/api/generate-challenge', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ topic: topic })
});
const data = await res.json();
document.getElementById('report-text').value = data.report;
currentHiddenErrors = data.hidden_errors;
document.getElementById('manual-errors').value = currentHiddenErrors.join("; ");
document.getElementById('badge-status').innerText = "Texto Generado";
document.getElementById('badge-status').className = "text-[10px] bg-green-100 text-green-800 px-2 py-0.5 rounded font-mono font-bold";
} catch(e) {
alert("Error al conectar con app_hamilton.py");
}
}
async function runCoTAudit() {
const reportText = document.getElementById('report-text').value.trim();
if(!reportText) { alert("Escribe un texto o genera uno primero."); return; }
document.getElementById('cot-result').innerText = "El Detective IA está analizando las frases...";
try {
const res = await fetch('/api/audit-cot', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
text_to_audit: reportText,
custom_cot_prompt: document.getElementById('cot-prompt').value
})
});
const data = await res.json();
document.getElementById('cot-result').innerText = data.analysis;
} catch(e) {
document.getElementById('cot-result').innerText = "Error en la solicitud.";
}
}
async function runSelfCorrection() {
const reportText = document.getElementById('report-text').value.trim();
if(!reportText) { alert("Escribe un texto o genera uno primero."); return; }
document.getElementById('self-result').innerText = "El Agente Revisor está revisando el texto...";
try {
const res = await fetch('/api/audit-self-correct', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ text_to_audit: reportText })
});
const data = await res.json();
document.getElementById('self-result').innerText = data.critique;
} catch(e) {
document.getElementById('self-result').innerText = "Error en la solicitud.";
}
}
async function evaluateFindings() {
const reportText = document.getElementById('report-text').value.trim();
if(!reportText) { alert("Escribe o genera un texto primero."); return; }
const findings = document.getElementById('student-findings').value;
const manualErrorsInput = document.getElementById('manual-errors').value;
// Si el alumno ha puesto sus propios errores en la casilla manual, los usamos
let effectiveErrors = currentHiddenErrors;
if(manualErrorsInput.trim().length > 0) {
effectiveErrors = manualErrorsInput.split(";").map(e => e.trim());
}
try {
const res = await fetch('/api/evaluate-student', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
original_text: reportText,
hidden_hallucinations: effectiveErrors,
student_findings: findings
})
});
const data = await res.json();
document.getElementById('eval-result').innerHTML = `
<div class="text-sm font-bold text-amber-900">Puntuación: ${data.score} / 100</div>
<div class="mt-1">${data.feedback}</div>
<div class="mt-2 pt-2 border-t border-amber-200">
<strong>Errores a buscar:</strong>
<ul class="list-disc ml-4 mt-1 space-y-0.5 text-[11px]">
${effectiveErrors.map(e => `<li>${e}</li>`).join('')}
</ul>
</div>
`;
} catch(e) {
alert("Error al evaluar.");
}
}
</script>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
def serve_web_interface():
return HTMLResponse(content=HTML_CONTENT)
@app.post("/api/generate-challenge")
def generate_challenge(req: ChallengeRequest):
system_prompt = (
"Eres un profesor del IES Monterroso que crea retos divertidos para alumnos de 1º y 2º de ESO (12-14 años). "
"Escribe un texto muy sencillo y entretenido de 2 párrafos sobre el tema. "
"REGLA OBLIGATORIA: Debes incluir exactamente 2 mentiras o datos falsos muy graciosos u obvios pero integrados en el texto "
"para que los alumnos los detecten investigando en Internet."
)
prompt = f"Tema: {req.topic}. Genera el texto para alumnos de ESO con 2 datos falsos inyectados."
response = query_llm_provider([
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
])
if not response:
if "Egipto" in req.topic:
report_text = (
"El Antiguo Egipto se desarrolló a lo largo del río Nilo y es famoso por sus monumentales pirámides. "
"Los faraones eran enterrados en estas tumbas de piedra junto con sus tesoros. Para construir las pirámides de Guiza, "
"los obreros egipcios utilizaban grúas eléctricas de gran tonelaje y camiones diésel para mover los grandes bloques de piedra. "
"Además, la escritura egipcia utilizaba jeroglíficos y el primer faraón de la historia fue el Rey Tutankamón, quien gobernó desde su ordenador portátil."
)
hidden_errors = [
"Uso de grúas eléctricas y camiones diésel en el Antiguo Egipto.",
"Mención de que Tutankamón gobernaba desde un ordenador portátil."
]
elif "Dinosaurios" in req.topic:
report_text = (
"Los dinosaurios habitaron la Tierra durante millones de años durante la Era Mesozoica. Existían especies carnívoras como el Tyrannosaurus Rex "
"y herbívoras como el Diplodocus. Sin embargo, hace 66 millones de años, todos los dinosaurios se extinguieron "
"debido a una invasión masiva de extraterrestres con pistolas láser. Tras esto, los humanos construyeron las primeras ciudades junto a los mamuts."
)
hidden_errors = [
"Extinción por una invasión masiva de extraterrestres con pistolas láser.",
"Convivencia inicial de humanos construyendo ciudades con los mamuts justo tras los dinosaurios."
]
elif "Minecraft" in req.topic:
report_text = (
"Minecraft es uno de los videojuegos más populares de la historia, creado por Markus 'Notch' Persson. "
"En este juego de construcción y supervivencia, los jugadores explotan bloques en un mundo tridimensional. "
"El juego fue lanzado originalmente en el año 1492 por Cristóbal Colón al llegar a América. Además, para conseguir diamantes "
"en el juego, solo necesitas fundir bloques de tierra en un horno común."
)
hidden_errors = [
"Lanzamiento de Minecraft en 1492 por Cristóbal Colón.",
"Obtención de diamantes fundiendo bloques de tierra en un horno."
]
else:
report_text = (
"El Sistema Solar está formado por el Sol y ocho planetas que orbitan a su alrededor. La Tierra es el tercer planeta "
"y el único donde se conoce la existencia de vida. El planeta más grande de todos es la Luna, la cual está hecha enteramente "
"de queso emmental. Por su parte, Marte es conocido como el planeta rojo debido a su abundante óxido de hierro en la superficie."
)
hidden_errors = [
"Afirmación de que la Luna es un planeta y el más grande del Sistema Solar.",
"Afirmación de que la Luna está hecha de queso emmental."
]
return {"report": report_text, "hidden_errors": hidden_errors}
return {
"report": response,
"hidden_errors": [
"Contiene mentiras o datos falsos inyectados por la IA.",
"Requiere búsqueda rápida en Internet para comprobar fechas o inventos."
]
}
@app.post("/api/audit-cot")
def audit_cot(req: AuditCoTRequest):
system_prompt = "Eres un profesor detective experto del IES Monterroso. Analiza el texto para alumnos de ESO explicando paso a paso si las afirmaciones son verdaderas o falsas."
prompt = f"{req.custom_cot_prompt}\n\nTexto a analizar:\n\"\"\"{req.text_to_audit}\"\"\""
analysis = query_llm_provider([
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
], temperature=0.2)
if not analysis:
analysis = (
"Análisis paso a paso del Detective IA:\n"
"1. Frase sobre tecnología antigua/moderna -> FALSO: No existía electricidad, motores diésel ni ordenadores en la antigüedad.\n"
"2. Frase sobre eventos históricos o mecánicas -> FALSO: Los datos no coinciden con la realidad histórica ni con los datos reales.\n"
"3. Conclusión: El texto contiene errores claros inyectados intencionadamente."
)
return {"analysis": analysis}
@app.post("/api/audit-self-correct")
def audit_self_correct(req: SelfCorrectionRequest):
system_prompt = (
"Eres un Agente Revisor del IES Monterroso. Tu trabajo es encontrar rápidamente las mentiras o disparates en el texto."
)
prompt = f"Examina este texto de un alumno y enumera los errores falsos:\n\"\"\"{req.text_to_audit}\"\"\""
critique = query_llm_provider([
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
], temperature=0.1)
if not critique:
critique = (
"Dictamen del Agente Revisor:\n"
"- Inconsistencias detectadas: El texto mezcla conceptos modernos o fantasiosos con hechos reales.\n"
"- Veredicto: Contiene al menos 2 alucinaciones/mentiras destacadas."
)
return {"critique": critique}
@app.post("/api/evaluate-student")
def evaluate_student(req: EvaluateRequest):
findings_lower = req.student_findings.lower()
matches = 0
for error in req.hidden_hallucinations:
keywords = [word for word in error.lower().split() if len(word) > 3]
if any(kw in findings_lower for kw in keywords):
matches += 1
total = len(req.hidden_hallucinations) if req.hidden_hallucinations else 1
score = int((matches / total) * 100)
if score > 100: score = 100
if score >= 80:
feedback = "¡Buen trabajo de detective! Has descubierto las alucinaciones inyectadas."
elif score >= 40:
feedback = "¡Casi lo tienes! Has encontrado alguna mentira, pero te falta alguna por investigar en Google/Wikipedia."
else:
feedback = "Sigue buscando. Utiliza la pestaña 'Razonamiento' para pedir pistas al Detective IA."
return {
"score": score,
"feedback": feedback
}
if __name__ == "__main__":
uvicorn.run("app_hamilton:app", host="0.0.0.0", port=8063, reload=True)



