Skip to main content
Glama

evalmine

Los números de los leaderboards nunca han predicho cómo un cambio de modelo aterriza en las cuarenta y tantas tareas que realmente ejecutas. Uno encabeza un benchmark, lo intercambias, y es silenciosamente peor en el trabajo del que dependes.

evalmine responde a una pregunta sobre un cambio de modelo, en tus tareas: ¿ayudó, perjudicó, o costó más por el mismo resultado? Escribes un suite YAML de tus tareas. Lo ejecuta en dos o más modelos, verifica el esquema de cada respuesta, la cronometra, y un juez LLM compara las respuestas por pares en ambos órdenes, de modo que la preferencia del juez por lo que ve primero se cancela. Puntúa a ese juez contra tus etiquetas de preferencia con el kappa de Cohen, y se niega a destacar una tasa de victorias cuando no puede mostrar que el juez está de acuerdo contigo. El costo proviene de una tabla de precios fijada a una fecha; un modelo desconocido hace fallar la ejecución en lugar de costar $0. Los informes se versionan por hash del suite; un servidor MCP de tres herramientas permite que un agente ejecute las evaluaciones a mitad de tarea.

Resultado, en el suite de ejemplo aquí contra el adaptador falso: kappa 0.25 sobre 12 etiquetas está por debajo del umbral de 0.40, así que la tasa de victorias de 0.463 se imprime marcada, no destacada. Esa negativa es la herramienta funcionando:

$ evalmine run examples/everyday-eight.yaml \
    --models anthropic/claude-haiku-4-5,google/gemini-2.5-flash --fake

run 20260823T210009Z_c4545e4e_dbc76614  (everyday-eight)
  report: reports/everyday-eight/20260823T210009Z_c4545e4e_dbc76614/report.md
  calibration: below_floor - kappa 0.25 (fair) over 12 labels - headline eligible: false
  google/gemini-2.5-flash vs anthropic/claude-haiku-4-5: win-rate 0.463 (UNCALIBRATED) [0.325-0.613] over schema-passing pairs only, n=20 - flips 3 - excluded 0
  cost: $0.0658 this run (answers $0.0081, judge $0.0578); if uncached $0.0658

El adaptador falso es determinista, así que esas cifras se reproducen exactamente en una copia limpia. Nada de lo anterior contactó a un proveedor ni gastó un centavo.

evalmine: valida el suite, ejecútalo contra el adaptador falso, lee las secciones de calibración y tasa de victorias del informe que escribió

Cada fotograma de eso es una ejecución real. Grábalo de nuevo con vhs docs/demo.tape (vhs, brew install vhs).

Estado. v0.1.0, pre-lanzamiento. El núcleo, los tres adaptadores de proveedor, las comprobaciones de ejecución y la superficie MCP están construidos y probados; la tabla de precios está verificada contra la página de precios pública de cada proveedor en su fecha fijada. Aún no existe ninguna entrada de registro de decisiones — ver Aún no.

Especificación: docs/spec.md. Es el contrato contra el que está escrito el código y prevalece sobre este README dondequiera que ambos difieran. Cómo funciona, en profundidad: docs/learning/how-it-works.md (renderizado HTML con estilo).

Inicio rápido

git clone https://github.com/hishamalward/evalmine.git && cd evalmine
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"          # add ,mcp -> ".[dev,mcp]" for the MCP server

Python 3.10 o más reciente. Tres dependencias de ejecución: PyYAML, jsonschema, httpx.

Comprueba un suite sin gastar nada. validate analiza el archivo, aplica el JSON Schema, renderiza cada prompt (un {{placeholder}} sin coincidencia es un error grave) y resuelve cada cadena de modelo contra la tabla de precios. Cero llamadas de red.

evalmine validate examples/everyday-eight.yaml
# ok: examples/everyday-eight.yaml - 8 tasks, 20 cases, 12 labels; every prompt
# rendered; 3 model strings resolved against prices-2026-08-23.yaml

Ejecútalo contra el adaptador falso. --fake enruta cada cadena de modelo a un adaptador determinista integrado: sin clave, sin red, sin gasto. Las dos cadenas de modelo a continuación son las que se refieren a las doce etiquetas humanas del suite de ejemplo, así que esta ejecución ejercita la ruta de calibración de principio a fin.

evalmine run examples/everyday-eight.yaml \
  --models anthropic/claude-haiku-4-5,google/gemini-2.5-flash --fake

Ejecútalo de verdad. Las claves provienen del entorno y de ningún otro lugar. Copia .env.example, complétalo fuera del repositorio y exporta lo que necesites.

export ANTHROPIC_API_KEY=...
export GOOGLE_API_KEY=...

evalmine run examples/everyday-eight.yaml \
  --models anthropic/claude-haiku-4-5,google/gemini-2.5-flash \
  --max-cost 0.50

Una estimación previa al vuelo se ejecuta antes de la primera llamada en vivo. Si supera --max-cost, la ejecución se rechaza (código de salida 4) y no se gasta nada. Sin un límite en ningún lugar, el valor predeterminado de la CLI es $2.00. Cada llamada se almacena en caché en disco por hash de contenido, así que una re-ejecución es gratuita y un informe es reproducible; --no-cache fuerza llamadas nuevas y aún así las escribe.

Otros comandos: evalmine prices [--for suite.yaml], evalmine last suite.yaml, evalmine report <run-id>, evalmine compare <report_a> <report_b>.

Related MCP server: Coval MCP Server

El archivo de suite

Un archivo YAML contiene tus tareas, la configuración del juez y tus etiquetas. El ejemplo incluido es examples/everyday-eight.yaml: ocho tareas inventadas (reescribir, extraer, clasificar, explicar, pequeño cambio de código) sobre veinte casos, tres de ellos con un esquema de salida, con doce etiquetas de preferencia. El esquema completo está en la especificación §5; la forma es:

suite: everyday-eight
version: 1

defaults: { temperature: 0, max_tokens: 700, timeout_s: 60 }
limits:   { max_cost_usd: 1.50 }

judge:
  model: anthropic/claude-sonnet-4-6
  rubric: |
    Prefer the answer that a competent colleague would ship without editing.
    ...
  calibration: { min_kappa: 0.40, min_labels: 10, on_below_floor: flag }

tasks:
  - id: ticket-triage
    kind: classify                # a free label, used only to group report rows
    prompt: |
      Classify this support ticket. Return JSON only.

      Ticket:
      {{ticket}}
    schema: { type: object, required: [category, severity], ... }
    rubric: |                     # appended to the suite rubric for this task
      In addition to the suite rubric: ...
    cases:
      - id: charged-twice
        vars: { ticket: "I was charged twice this month..." }

labels:
  - { task: ticket-triage, case: charged-twice,
      baseline: anthropic/claude-haiku-4-5,
      candidate: google/gemini-2.5-flash,
      prefer: candidate, note: "team-wide lockout is high, not medium" }

Tres cosas sobre este archivo que son deliberadas:

  • El templating no es Jinja. Exactamente {{name}}, sustituido una vez, sin expresiones ni filtros. Un placeholder sin variable coincidente es un error grave en el momento de la carga, porque una variable silenciosamente vacía es la forma más fácil de hacer que una evaluación sea silenciosamente sin sentido.

  • Las claves desconocidas son errores, en todos los niveles. Una rubrik: mal escrita que se ignora produce un informe que parece correcto y no significa nada.

  • labels es de donde proviene la credibilidad de la herramienta. Son tus juicios, registrados antes de que veas la tasa de victorias, y el juez se puntúa contra ellos. Un suite sin etiquetas aún se ejecuta; simplemente no puede producir un número destacado.

Reemplaza el ejemplo con tus propias tareas. Ese es el punto completo de la herramienta.

Comprobaciones de ejecución para tareas de código

La prosa es un mal proxy para el código que se ejecuta. Un caso puede declarar un check: un fragmento de bash que recibe el código de la respuesta ($ANSWER es un archivo, $ANSWER_TEXT el texto) y sale con 0 si funciona. Se ejecuta en un directorio temporal nuevo, con un tiempo límite, con los secretos eliminados del entorno, y nunca se almacena en caché. Cada bloque delimitado en la respuesta se ejecuta, en orden, cada uno en su propio fixture; el bloque final es el veredicto y los anteriores se registran junto a él, así que una respuesta que retracta un bloque incorrecto y escribe un segundo se puntúa en el segundo y muestra la retractación.

- id: jq-remote
  vars: { task: "Write a jq filter ... the JSON is in postings.json" }
  check:
    setup: 'printf "[{\"t\":\"a\",\"remote\":true}]" > postings.json'
    run: 'jq -r "$(cat "$ANSWER")" postings.json | grep -q a'

El resultado — aprobado/fallido, código de salida, salida — se coloca junto a la respuesta en answers.jsonl, la tarjeta de puntuación y la vista de pares HTML, y al juez se le muestra con una regla fija: una respuesta cuya comprobación falló no puede vencer a una que pasó. Especificación §6.6.

Cómo leer un informe

reports/<suite>/<run-id>/report.md junto a report.json, report.html, answers.jsonl y pairs.jsonl. Léelo en este orden.

1. Calibración, primero. Se imprime por encima de las tasas de victorias a propósito. Quieres el kappa de Cohen entre los veredictos del juez y tus etiquetas, con su nombre de banda Landis-Koch adjunto, y la matriz de confusión 3x3 debajo. Kappa en lugar de acuerdo simple porque el acuerdo se infla en el momento en que una categoría domina, y lo hará: los jueces aprenden que los empates son seguros. La matriz te dice cómo está equivocado el juez, lo cual importa — un juez que nunca dice "empate" cuando tú lo haces es un problema diferente de uno que prefiere sistemáticamente lo que sea nuevo. Debajo, un desglose por tarea te dice dónde: un kappa puede ocultar a un juez que es excelente en tu tarea de reescritura e inútil en tu tarea de triaje, y el promedio es el hallazgo que perderías.

2. Una tasa de victorias en la que no deberías confiar. Tres condiciones, cualquiera de las cuales es suficiente:

  • headline_eligible: false — el kappa está por debajo del umbral, hay demasiadas pocas etiquetas, o el kappa no está definido porque ambos evaluadores usaron una sola categoría en todo momento. El informe prohíbe que el número sea un titular, marca cada cifra con una daga, y el JSON y cada respuesta MCP llevan la misma marca, así que un agente que lea el resumen no puede citar el número sin la advertencia.

  • Tasa de inversión superior a 0.30. Una inversión es un par donde el juez cambió su respuesta cuando las dos respuestas cambiaron de lugar. Por encima de aproximadamente un tercio, la tasa de victorias está midiendo el orden de presentación, no la calidad. El informe lo dice en la misma tabla.

  • Un n pequeño, o uno que se reduce. La tasa de victorias se calcula sobre pares que pasan el esquema solamente: un par donde cualquiera de los lados falló al analizar o falló su esquema se excluye en lugar de puntuarse como pérdida, así que un modelo malo emitiendo JSON no pierde una comparación de calidad por un fallo de formato. El costo es que n se reduce, por eso la sección se titula "solo sobre pares que pasan el esquema, n=…" y por qué n nunca se imprime sin la tasa de aprobación del esquema en la misma pantalla.

Antes de publicar un número, sube min_kappa a 0.60. El valor predeterminado incluido es 0.40 — el fondo convencional del acuerdo justo a moderado, lo suficientemente bajo como para que un primer suite con una docena de etiquetas pueda plausablemente superarlo. Ese es el umbral para usar un número tú mismo, con tu propia memoria de cómo fue el etiquetado. 0.60 — "sustancial" — es el umbral para decirle a otra persona un número, donde esa memoria no viaja. La herramienta se distribuye permisiva para que un primer suite valga la pena ejecutarlo dos veces; esta recomendación existe para que un primer suite no termine en una publicación de blog.

3. Luego la tarjeta de puntuación, y lee el costo con la calidad, nunca después. Tasa de aprobación del esquema (etiquetada native o prompted, porque un proveedor que aplica un esquema por ti y uno al que solo se le pidió amablemente no son la misma medición), la tasa de aprobación de ejecución con su n donde una tarea declara comprobaciones de ejecución, latencia p50 y p95 con su n, costo de esta ejecución y costo si no se almacena en caché. Un candidato que gana 0.55 por el triple de dinero es una decisión diferente de uno que gana 0.55 por la mitad.

4. La tabla por tarea, ordenada de peor a mejor. Una tasa de victorias destacada que no se movió mientras tres tareas se movieron 0.4 en direcciones opuestas es el hallazgo que de otro modo te perderías. evalmine compare A B imprime exactamente esos movimientos entre dos ejecuciones.

5. report.html, y el flujo de etiquetado. Cada ejecución también escribe una página autocontenida — sin servidor, sin dependencias, se abre desde una ruta file://. Mismas secciones, más cada par juzgado lado a lado con los nombres de los modelos ocultos y el veredicto del juez plegado, para que leas las respuestas exactamente como las leyó el juez. Preferir A · Empate · Preferir B debajo de cada uno, luego copiar etiquetas YAML te da las entradas labels: para pegar de nuevo en tu suite: diez minutos de clics en lugar de media hora de edición manual, que es la diferencia entre un conjunto de calibración que crece y uno que no.

El informe no contiene adjetivos y no hace ninguna recomendación. El juicio va en DECISIONS.md, redactado desde tu veredicto — el informe pre-completa la plantilla por ti al final de cada ejecución.

MCP

evalmine-mcp es un servidor MCP stdio que expone exactamente tres herramientas, que llaman a las mismas funciones core.py que llama la CLI:

herramienta

hace

gasta

run_suite(suite_path, models, max_cost, baseline, no_cache)

ejecuta el suite, devuelve el resumen y las rutas del informe

hasta el límite

compare(report_a, report_b)

el delta entre dos informes

nada

last_report(suite_path)

el informe más reciente para un suite

nada

Regístralo copiando .mcp.json.example a .mcp.json. Instala el extra primero: pip install -e ".[mcp]".

El punto es que un agente puede ejecutar tus evaluaciones a mitad de tarea — "antes de intercambiar el modelo en este archivo, ejecuta el suite y dime la tasa de victorias" — en lugar de que una persona lea un informe después.

Tres herramientas en lugar de toda la CLI porque una superficie orientada a agentes debería ser el conjunto más pequeño de verbos que respalde la decisión, y cada herramienta extra es otra forma de gastar dinero que nadie autorizó.

Los límites, y por qué el valor predeterminado del agente es más bajo que el tuyo. El límite es un parámetro de core.run_suite(), no una bandera de CLI que MCP reimplementa: hay exactamente un lugar donde se puede gastar dinero, y está limitado allí. Si el agente proporciona max_cost, se usa, pero una solicitud por encima de EVALMINE_MCP_MAX_COST_CEILING ($5.00 por defecto) se rechaza directamente en lugar de recortarse y ejecutarse. Si el agente lo omite, el límite es min(suite.limits.max_cost_usd, EVALMINE_MCP_MAX_COST), por defecto $1.00 — la mitad de los $2.00 de la CLI, porque el humano en la CLI escribió el número y el agente no. Una ejecución por encima del límite devuelve un rechazo estructurado, no gasta nada y nunca se trunca silenciosamente para que quepa; una ejecución truncada produce un número más pequeño que parece uno completo.

run_suite devuelve el resumen y las rutas, nunca las respuestas crudas del proveedor. Esas permanecen en answers.jsonl en disco. Una herramienta que transmite cada respuesta de vuelta al contexto de un agente le cuesta al llamador más que la evaluación, y convierte un arnés de evaluación en una vía de exfiltración para lo que sea que esté en tus prompts. suite_path también debe resolverse dentro de EVALMINE_MCP_SUITE_ROOT (por defecto: el directorio de trabajo del servidor).

Trabajo previo

promptfoo y Braintrust son las herramientas obvias aquí, y ambas son más capaces que esta.

promptfoo tiene muchos más tipos de aserciones, un visor web, red-teaming y una cobertura de proveedores que no es de tres. Braintrust es una plataforma alojada: trazabilidad, conjuntos de datos construidos a partir de registros de producción, una interfaz real, colaboración y la madurez operativa que viene con ser el producto de alguien. Si quieres amplitud, o un equipo que mire los mismos números, usa una de esas.

evalmine existe por tres razones más específicas.

  • El juez está calibrado contra ti, o su número no se imprime. Ambas herramientas pueden puntuar con un juez LLM. Ninguna hace que la calibración con tus etiquetas sea la condición para que una tasa de victorias sea citable. Esa inversión — que la negativa sea la opción por defecto — es toda la tesis, y no es una característica que puedas añadir a una herramienta que publica el número de todos modos.

  • El registro de decisiones es un artefacto de primera clase. La salida de una evaluación no es un número, es una decisión que tendrás que defender en seis meses. DECISIONS.md se rellena previamente con el informe y lo escribe un humano, y vive en tu repositorio junto al código sobre el que se tomó la decisión.

  • La superficie es lo suficientemente pequeña como para leerla de una sentada. Aproximadamente 6,000 líneas incluyendo cuatro adaptadores, los informes y las comprobaciones de ejecución. Sin framework de LLM, sin SDKs de proveedores — tres POSTs escritos a mano a endpoints JSON documentados. Ese costo es real y vale la pena decirlo: cuando un proveedor cambia su API, nos enteramos por la rotura, no por la actualización.

Si esas tres cosas no te importan, la recomendación honesta es promptfoo.

Aún no

Fuera del alcance de v0.1.0, y el README lo dice en lugar de dejarte descubrirlo: evaluación RAG o de recuperación; trayectorias de agente o de múltiples turnos; ajuste fino de cualquier cosa; una interfaz web; cualquier cosa alojada; más de tres proveedores; generación automática de rúbricas; herramientas MCP más allá de las tres anteriores.

Cada número en este README proviene del adaptador falso en el conjunto de ejemplo inventado. Ninguna ejecución etiquetada en un conjunto real ha producido aún un número calibrado o una entrada en DECISIONS.md; eso viene antes de cualquier etiqueta v0.1.0.

Desarrollo

pip install -e ".[dev,mcp]"
python -m pytest -q          # 310 tests, none of which make a network call
python -m ruff check src tests

CI ejecuta {ubuntu, macos, windows} x {3.10, 3.13}, cada rama ejecutando todas las pruebas, además de un escaneo de secretos sobre el árbol de trabajo y todo el historial de git. Ninguna clave API pertenece a este repositorio, y evalmine run se niega a iniciar si un archivo de suite contiene una cadena que coincida con un prefijo de clave conocido.

Ver CONTRIBUTING.md. Los cambios comienzan en docs/spec.md.

Licencia

MIT. Ver LICENSE.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides advanced evaluation tools for assessing AI safety, alignment, and performance of LLM outputs. Enables programmatic evaluation of quality, safety metrics like toxicity and PII detection, and operational metrics including carbon footprint and cost estimation.
    4
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI assistants to interact with Coval's evaluation platform for launching and monitoring evaluation runs, managing agents and test sets, and retrieving evaluation metrics.
    18
    33
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables LLM evaluation and observability by uploading documents, building test sets, running RAG pipelines, and automatically scoring answers for groundedness, hallucination risk, retrieval quality, latency, and cost, with tools exposed to MCP-compatible clients.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Build, validate, and deploy multi-agent AI solutions from any AI environment.

  • See, price, and control every tool call your AI agents make: policy checks, cost, and audit tools.

  • Runtime permission, approval, and audit layer for AI agent tool execution.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hishamalward/evalmine'

If you have feedback or need assistance with the MCP directory API, please join our Discord server