Evaluación con modelos
La evaluación con modelos comprueba si un modelo real es capaz de usar arcane-mcp para hacer algo real en un Arcane real. Mide el uso de herramientas, no la redacción: dar con la acción adecuada, rellenar sus argumentos, añadir la confirmación que exige una acción destructiva, negarse a lo que ninguna acción puede hacer y terminar sin que nadie lo corrija.
Existe porque un servidor MCP es una interfaz para modelos. Una herramienta puede ser clara para una persona y difícil para un modelo —una descripción que no aclara cuál de dos acciones usar, un nombre de parámetro que el modelo solo descubre cuando se lo rechazan— y nada de eso aparece en un test unitario ni en la batería de extremo a extremo. El diseño sigue la evaluación con modelos de gitlab-mcp-server, a menor escala.
Cómo funciona una ejecución
Sección titulada «Cómo funciona una ejecución»Una ejecución plantea cada caso del corpus a cada modelo configurado, en cada superficie configurada (por defecto, la dinámica y la meta; la individual, si se pide):
- Un Arcane desechable.
make modeleval-uparranca un demonio Docker-in-Docker y un Arcane v2.17.2 que lo gestiona, ambos con el prefijome-y publicados solo en127.0.0.1:16000. Nunca es el entorno de extremo a extremo: un modelo en evaluación envía lo que decide enviar, y nada de lo que haga puede llegar a contenedores de los que depende otra batería. - Recursos de partida. Antes de cada intento, el arnés crea lo que necesita el caso (un contenedor en marcha, un volumen, un proyecto Compose, un usuario…) con nombres que llevan una marca nueva, y genera el enunciado con esos nombres.
- El servidor. Un servidor arcane-mcp para la superficie, construido con las mismas llamadas que el binario stdio. Al modelo se le muestran exactamente las herramientas que publica ese servidor. La superficie individual solo se ejecuta si se pide (
MODELEVAL_SURFACES=dynamic,meta,individual): sus 461 herramientas no caben en una petición, así que cada intento ve todas las herramientas de los dominios del caso y otras de relleno, hasta 128, y lo que se mide es la elección dentro de esa selección, no en todo el catálogo. - La conversación. Las llamadas a herramientas llegan al servidor tal cual y sus respuestas vuelven al modelo. No se corrige ni se repite nada en nombre del modelo; solo se reenvía una petición que el propio proveedor rechazó (límite de peticiones, error del servidor). Un intento termina cuando el modelo responde con texto, o al llegar al tope de turnos: tres por paso en la superficie dinámica (dos en las demás), más cuatro.
- Limpieza. Se eliminan los recursos de partida y también todo lo que creó el intento: lo que lleva su marca o lo que no existía antes de empezar.
Cada intento queda escrito en un fragmento: el enunciado tal como se envió, cada turno del proveedor con sus tokens y cada llamada con la acción a la que se resolvió y lo que hizo el servidor con ella. Un fragmento guarda observaciones, no veredictos.
El corpus
Sección titulada «El corpus»Cada caso es una petición en lenguaje natural, los recursos de partida que necesita y una clave: los pasos ordenados que da un agente correcto, cada uno con una acción canónica del catálogo y los argumentos cuyos valores se comparan. Hay cinco tipos: de lectura (todos los pasos leen), de escritura (un cambio no destructivo), de varios pasos (varios pasos en orden; normalmente, averiguar un ID que el enunciado no da y luego actuar), destructivos (un cambio que el servidor rechaza sin confirm: true) y de rechazo (algo que ninguna acción hace, o una petición demasiado vaga para actuar con seguridad, en la que lo correcto es decirlo o preguntar, sin cambiar nada).
Un enunciado nunca da su propia respuesta. Un test unitario corriente genera cada enunciado en cada superficie y falla si contiene el ID de la acción del caso, el nombre de su herramienta en cualquier superficie, los nombres de las acciones de su dominio, cualquier nombre de argumento que admita el esquema de la acción (también como la frase que forma, de modo que displayName detecta «display name»), o cualquier ID de acción o nombre de herramienta del catálogo. Un segundo test introduce a propósito cada tipo de filtración y demuestra que la auditoría la detecta. Cuando una palabra es de verdad la propia petición, la excepción queda anotada con su motivo. Cada acción que nombra el corpus se comprueba contra el catálogo.
El corpus tiene 94 casos (30 de lectura, 18 de escritura, 15 de varios pasos, 21 destructivos, 10 de rechazo) que declaran 108 pasos sobre 104 de las 461 acciones del catálogo en 46 de sus 52 dominios. El registro completo, caso a caso y con cada enunciado y su clave, está en test/modeleval/corpus.md.
| Dominio | Casos | Acciones nombradas |
|---|---|---|
activity | 2 | 2 |
api_key | 2 | 5 |
app_image | 1 | 1 |
auth | 1 | 1 |
backup | 1 | 1 |
build | 1 | 1 |
container | 9 | 9 |
dashboard | 1 | 1 |
diagnostics | 1 | 1 |
environment | 2 | 2 |
event | 1 | 3 |
federated_credential | 1 | 2 |
git_repository | 3 | 3 |
gitops | 4 | 5 |
image | 3 | 3 |
image_update | 1 | 1 |
job | 2 | 2 |
mobile_push | 1 | 1 |
network | 4 | 4 |
notification | 1 | 1 |
oidc | 2 | 2 |
passkey | 1 | 1 |
port | 1 | 1 |
project | 5 | 5 |
registry | 3 | 3 |
role | 4 | 3 |
s3_destination | 1 | 1 |
server | 1 | 2 |
settings | 2 | 1 |
stream | 1 | 1 |
swarm | 1 | 2 |
swarm_config | 1 | 1 |
swarm_node | 1 | 2 |
swarm_secret | 1 | 1 |
swarm_service | 3 | 3 |
swarm_stack | 1 | 1 |
swarm_task | 1 | 1 |
system | 1 | 1 |
template | 2 | 4 |
updater | 1 | 1 |
user | 5 | 5 |
variable | 2 | 3 |
volume | 5 | 5 |
volume_backup | 1 | 1 |
vulnerability | 1 | 1 |
webhook | 2 | 3 |
Cómo se puntúa un intento
Sección titulada «Cómo se puntúa un intento»La puntuación se calcula a partir de los fragmentos, frente al corpus de HEAD, con un único paquete que comparten el arnés y el publicador. La evaluación mide el uso de herramientas, no a Arcane: un paso cuenta como alcanzado cuando el servidor acepta la llamada del modelo, responda lo que responda Arcane después. En concreto, un paso se alcanza con la primera llamada, posterior al paso anterior, que se resuelve a su acción y que el servidor acepta (pasa el esquema de entrada y, si es destructiva, lleva la confirmación). Si Arcane falla en una llamada aceptada, el paso cuenta como alcanzado: el modelo hizo su parte.
| Columna | Numerador | Denominador |
|---|---|---|
| Superados | Intentos que alcanzaron todos los pasos en orden con todos los argumentos comparados correctos, no cambiaron nada que no se pidiera y terminaron por sí mismos | Intentos puntuados |
| Alcanzados | Pasos alcanzados | Pasos declarados |
| A la primera | Pasos cuya primera llamada fue la que los alcanzó | Pasos alcanzados |
| Argumentos | Argumentos comparados con el valor correcto | Argumentos comparados |
| Confirmación | Pasos destructivos alcanzados con la confirmación | Pasos destructivos declarados |
| Sin efectos ajenos | Intentos sin ninguna modificación que la clave no pidiera | Intentos puntuados |
| Rechazos | Casos de rechazo que no cambiaron nada y respondieron con texto | Casos de rechazo puntuados |
| Terminados | Intentos que el modelo terminó por sí mismo | Intentos puntuados |
Cada columna se publica con sus dos términos, nunca como un porcentaje suelto. Los argumentos se comparan por su valor, no por su nombre: un contenedor puede indicarse por su nombre, su ID completo o su ID corto, y un ID por el valor que produjo el recurso de partida o por el que devolvió un paso anterior; un argumento que el enunciado no fija no se compara. Los intentos que terminaron porque el proveedor no respondió, porque el arnés no pudo crear los recursos de partida o porque se agotó el presupuesto de tokens de la ejecución quedan excluidos de todas las columnas y se cuentan aparte: ninguno de esos casos es culpa del modelo.
Qué se puede publicar
Sección titulada «Qué se puede publicar»Al incorporar una ejecución (cmd/gen_model_results) se leen sus fragmentos, se puntúan y se añade una fila por modelo y superficie al registro versionado, test/modeleval/results.json, salvo que una norma la rechace:
- fake-provider: el proveedor simulado responde con la propia clave del corpus; sus cifras demuestran que la cadena funciona y no dicen nada de ningún modelo.
- filtered-run: una ejecución sobre parte del corpus se leería como si fuera sobre todo él.
- incomplete-provenance: cada fila indica qué commit, qué versión de Arcane, qué superficie, qué modelo, qué opciones de petición, qué corpus, qué contratos y qué lista de herramientas midió.
- stale-corpus: una ejecución hecha con otro corpus u otros contratos no se puntúa con una clave que no se le planteó.
- incomplete-run: una ejecución que se detuvo antes de tiempo publicaría solo los casos a los que llegó.
- dirty-tree: una cifra publicada debe apuntar a un commit que exista, así que se rechaza una ejecución hecha con cambios sin confirmar en ficheros versionados; conviene hacer commit antes de una ejecución de pago.
- duplicate-row: una fila ya publicada solo se sustituye si se pide expresamente.
Ninguna norma tiene que ver con lo bien o mal que lo hizo el modelo. Un ensayo (make model-results-dry-run) deja de lado solo las normas fake-provider y dirty-tree y escribe en dist/, con un aviso en cada página, para poder ensayar la publicación sin gastar nada; una ejecución simulada incorporada de verdad no publica nada y explica por qué, fila a fila. make check-model-results comprueba sin conexión que el registro y esta página coinciden.
Cómo ejecutarla
Sección titulada «Cómo ejecutarla»make modeleval-up # el Arcane desechable (me-*, puerto 16000)MODELEVAL_MODELS=fake:perfect make modeleval # gratis: reproduce la clave y debe sacar un 100 %make modeleval-fake-variants # gratis: las variantes erróneas del simulador, que deben perder puntosMODELEVAL_MODELS=anthropic:<modelo> MODELEVAL_SPEND=yes make modeleval # de pagomake model-results-record # incorpora dist/modeleval/run al registro y regenera esta páginamake modeleval-downSolo se llama a un proveedor real con MODELEVAL_SPEND=yes, y una ejecución se detiene al facturar MODELEVAL_TOKEN_BUDGET tokens (dos millones por defecto). La API Messages de Anthropic necesita ANTHROPIC_API_KEY; cualquier endpoint de chat completions compatible con OpenAI funciona con openai:<modelo>, OPENAI_API_KEY y, para un servidor local, OPENAI_BASE_URL. make modeleval-probe envía una petición por modelo para comprobar que el proveedor acepta lo que construye el arnés. Nada de esto se ejecuta en la CI.
Resultados
Sección titulada «Resultados»Todavía no se ha publicado ningún resultado. No se ha medido ningún modelo real: las ejecuciones hechas hasta ahora usaron el proveedor simulado, que responde con la propia clave del corpus y cuyas filas el publicador rechaza por norma. Para publicar una medición, arranca el Arcane de la evaluación (make modeleval-up), ejecuta el corpus contra un modelo real (MODELEVAL_MODELS=anthropic:<modelo> MODELEVAL_SPEND=yes make modeleval) e incorpora sus fragmentos al registro (make model-results-record). make model-results-dry-run muestra cómo se publicaría una ejecución sin publicarla.