Duelo en directo
Mira cómo se resuelve una tarea: cada modelo escribe su código, los tests caen uno a uno y sale el marcador. Dura unos 25 segundos y puedes pausarlo o detenerlo cuando quieras. Es un resultado pregrabado: no se llama a ningún modelo ni se ejecuta código.
Esta reproducción necesita JavaScript. Ver el informe estático del mismo duelo.
Resultado pregrabado con respuestas de ejemplo (replay). Ver el informe completo.
Qué hace
Pregunta
Envía el mismo enunciado a cada modelo y les pide un único bloque de código Python.
Ejecuta
Guarda cada respuesta como solution.py en un directorio temporal y pasa los tests de la tarea con pytest y un límite de tiempo.
Compara
Genera results.json y un informe HTML con marcador, tiempos, tokens, coste estimado y el código de cada modelo.
Instalación y uso
Necesitas Python 3.12 o superior. modelduel no tiene dependencias; pytest hace falta para ejecutar los tests de las tareas.
pip install "modelduel[pytest]" # o: pip install modelduel pytest
# Demo sin claves ni coste: una liga de tres contendientes con respuestas grabadas
modelduel demo
modelduel demo --copy MIS-EJEMPLOS # copia las tareas de ejemplo como plantilla
# Dos modelos reales (o repite --model para una liga de 2 a 6)
modelduel run MIS-EJEMPLOS/tasks --a gemini:<modelo> --b openai:<modelo> --runs 3 --out runs/duelo
# Continuar un duelo cortado
modelduel run MIS-EJEMPLOS/tasks --a gemini:<modelo> --b openai:<modelo> --runs 3 --out runs/duelo --resume
# Otras órdenes
modelduel list-tasks MIS-EJEMPLOS/tasks
modelduel report runs/duelo/results.json --out runs/duelo
El paquete está en PyPI. Para la última versión sin publicar: pip install git+https://github.com/BertMarti/modelduel pytest.
Novedades de v0.7.0
- Señal de vida: si una llamada a un modelo tarda más de unos 10 s, modelduel avisa cada 10 s por
stderrde que sigue esperando. El límite de red por defecto baja a 90 s (MODELDUEL_HTTP_TIMEOUTlo cambia). - Desde v0.6.0: informe en Markdown:
modelduel report results.json --format md --out DIRgenerainforme.md, listo para pegar en un PR o un issue, con el texto deresults.jsonescapado. - Desde v0.5.0: el duelo en directo de esta página y los informes más legibles. Desde v0.4.0: proveedor
omniroute:y clasificación pública. Desde v0.2.0: liga de 2 a 6, reintentos y--resume.
Todos los cambios, en el registro de cambios; el uso paso a paso, en la guía de uso.
Crear una tarea
Una tarea es una carpeta con tres archivos. El enunciado debe pedir una función concreta con nombre y firma; los tests la importan de solution.
mis-tareas/
└── invertir_palabras/
├── task.md # enunciado para el modelo
├── test_task.py # tests pytest: from solution import invertir_palabras
└── meta.toml # opcional: title, difficulty, order
# test_task.py
from solution import invertir_palabras
def test_basico():
assert invertir_palabras("hola mundo") == "mundo hola"
Consejo: incluye casos límite. Son los que separan a un modelo que entiende el enunciado de uno que solo se parece a la respuesta correcta.
Proveedores
| Especificación | Qué usa | Variables de entorno |
|---|---|---|
| replay:<nombre> | Respuestas grabadas en examples/replays/<nombre>/<tarea>.md. Sin red ni coste. | — |
| gemini:<modelo> | API REST generateContent de Google. | GEMINI_API_KEY |
| omniroute:<modelo> | El router local OmniRoute (API compatible con OpenAI). | OMNIROUTE_BASE_URL, OMNIROUTE_API_KEY (opcional) |
| openai:<modelo> | Cualquier API compatible con Chat Completions: OpenAI, OpenRouter, Ollama… | OPENAI_API_KEY, OPENAI_BASE_URL |
Las claves se leen solo de variables de entorno y nunca aparecen en el informe. Con Ollama en local basta con OPENAI_BASE_URL=http://localhost:11434/v1.
Coste estimado
Las tarifas van por millón de tokens y las pones tú con --prices precios.json, porque cambian a menudo. Si un modelo no tiene precio, el informe dice «sin datos»: nunca se inventa. Los precios de replay son ficticios y así se indica.
Seguridad
El código generado por los modelos se ejecuta en tu máquina. modelduel lo hace siempre en un directorio temporal, en un subproceso con límite de tiempo y sin tus variables de entorno secretas, pero eso no es un aislamiento real. Úsalo con tareas de confianza e, idealmente, dentro de un contenedor o una máquina virtual.
Una sola ejecución es una señal débil
Los modelos no son deterministas. Repite el duelo con --runs N, usa tareas de tu propio trabajo y lee el código, no solo el marcador.
Cómo se ha hecho
Lo ha desarrollado un equipo de agentes de IA (Claude Code), cada uno en su rama y con pull requests. Alberto Martínez supervisa y fusiona todo.
- v0.1.0: lead, builder y qa con Claude Opus; docs con Claude Sonnet.
- v0.2.0: todo con Claude Sonnet, guiado por issues del hito.
- OpenCode estaba previsto para la documentación, pero no pudo ejecutarse en modo autónomo.