Skip to main content
Glama

ML On-Call Agent

"¿Por qué el run de anoche sufrió una regresión?" — un sistema multi-agente que lo responde correlacionando un informe de deriva, una ejecución de evaluación y un registro de despliegue, y cita cada afirmación que hace.

Expuesto a través de MCP, por lo que las herramientas funcionan desde cualquier cliente MCP.

Estado: 65 pruebas. El diagnóstico se calcula de forma determinista a partir de evidencia ponderada, por lo que cada número a continuación es una aserción, no una demo.


El problema real

Un sistema de ML se degrada silenciosamente. Cuando alguien finalmente se da cuenta, la evidencia está dispersa en tres lugares que no se comunican entre sí:

  • un informe de deriva — ¿se movió la distribución de entrada?

  • una ejecución de evaluación — ¿regresaron las puntuaciones offline, y en qué segmentos?

  • un registro de despliegue — ¿desplegó alguien algo?

Correlacionarlos es un trabajo, y es un trabajo que la gente hace mal a las 3 de la madrugada porque significa tener tres archivos JSON en la cabeza a la vez.

Esos tres artefactos no son inventados para este repositorio. Son lo que model-drift-monitor, llm-eval-pipeline y ai-code-review-bot ya producen. El lector se escribió contra un artefacto real, no contra documentación.


El resultado

python -m oncall.cli evaluate
 scenario         truth           verdict          conf  margin  steps  action
 healthy          healthy         healthy          0.57     2.0      9  no action
 data_shift       data_shift      data_shift       0.71     8.0      9  retrain on recent data
 bad_deploy       bad_deploy      bad_deploy       0.66     8.5      9  roll back
 concept_drift    concept_drift   concept_drift    0.81     9.0      9  retrain with fresh labels
 pipeline_break   pipeline_break  pipeline_break   0.62     5.0      9  fix the upstream pipeline
 flaky_eval       noise           noise            0.62     3.0      9  rerun the evaluation

task success    : 100%
action accuracy : 100%
mean steps      : 9.0

La verdad de referencia se conoce por construcción, por lo que el agente se evalúa en lugar de admirarse. "El agente produjo un informe de incidente plausible" no es un resultado — lo plausible es lo que hacen los modelos de lenguaje, incluso cuando la evidencia no respalda nada.

El escenario que es el punto

concept_drift: las entradas son estadísticamente idénticas, no se desplegó nada, y el ranking del modelo se ha invertido (AUC 0.729 → 0.326, peor que aleatorio).

No hay nada a lo que apuntar. La respuesta proviene de combinar dos negativos y un positivo — sin deriva, sin despliegue, ranking colapsado — que es exactamente lo que un resumen de cualquier artefacto individual pasaría por alto. Es también el punto ciego que model-drift-monitor documenta sobre sí mismo, diagnosticado una capa más arriba.


La decisión de diseño sobre la que todo se sostiene

El diagnóstico es determinista. El modelo de lenguaje solo narra.

La construcción obvia es pegar tres archivos JSON en un prompt y preguntar qué salió mal. Produce algo fluido cada vez — incluso cuando la evidencia no respalda nada — y no es comprobable, porque no puedes hacer aserciones sobre prosa ni distinguir una respuesta correcta de una afortunada.

Así que el razonamiento es Python ordinario:

  • cada especialista lee un artefacto y emite Findings

  • cada hallazgo lleva una cita — archivo, campo, valor. Finding requiere una, por lo que no se puede construir una afirmación sin fuente

  • cada hallazgo nombra qué causas raíz respalda y cuáles descarta

  • diagnose() suma los pesos — una función pura, probada unitariamente contra la verdad

| finding                                                    | source                     |
|------------------------------------------------------------|----------------------------|
| input drift is 'none': the scored population is             | `drift:severity=none`      |
| statistically the same as training                          |                            |
| roc_auc is 0.326 - WORSE THAN RANDOM. The model's ranking   | `evals:metrics.roc_auc     |
| has inverted, which is a changed relationship               |  =0.326`                   |
| 1 change(s) landed but none touch model behaviour           | `changes:changes[].files`  |

test_the_narration_does_not_change_the_diagnosis afirma que el veredicto es idéntico con y sin un modelo. Si alguna vez falla, el modelo ha empezado a hacer el razonamiento — y el razonamiento deja de ser comprobable en el momento en que lo hace.

La evidencia negativa es donde está la mayor parte del poder diagnóstico. "Sin deriva" y "no se desplegó nada" son hallazgos, con pesos. Un LLM que resumiera el JSON de deriva los omitiría, porque no pasó nada.


El grafo

   SUPERVISOR ──► drift ──┐
        ▲   ├──► evals ───┤   one specialist per artifact, each consulted once
        │   └──► changes ─┤
        │                 ▼
        │             DIAGNOSE          sum the weighted findings
        │                 ▼
        └──────────────  CRITIC         "is this conclusion supported?"
           (bounded)      ▼
                        REPORT

Dos propiedades que un pipeline en línea recta no tiene:

El crítico puede devolver el trabajo. Si el veredicto se apoya en dos artefactos mientras un tercero nunca fue leído, el control vuelve al supervisor en lugar de publicar una conclusión extraída de la mitad de la evidencia.

El ciclo está acotado. MAX_REVISIONS = 2 lo limita y recursion_limit atrapa lo que escape. Un agente que puede iterar es un agente que puede iterar para siempre, y un agente on-call desbocado genera páginas en lugar de responderlas.

Se ejecuta sin LLM y sin API key — el supervisor enruta mediante una regla Python simple — así que el enrutamiento, la delegación y el bucle de retorno del crítico se prueban unitariamente offline. test_the_graph_and_the_plain_loop_agree afirma que una ejecución de LangGraph y un bucle for simple llegan a veredictos idénticos en cada escenario, lo que demuestra que el grafo añade orquestación, no razonamiento.


Cuánto vale realmente cada artefacto

python -m oncall.cli ablate

evidencia

éxito de tarea

precisión de acción

las tres

100%

100%

sin deriva

67%

67%

sin evaluaciones

67%

67%

sin cambios

100%

100%

Un resultado negativo honesto, y se afirma para que no pueda olvidarse en silencio. Quitar el registro de cambios no cuesta nada en este conjunto de escenarios — bad_deploy ya es separable solo con la evidencia de deriva y evaluación. El registro de cambios se gana su lugar al nombrar el commit, que es lo que un humano necesita para actuar, no al cambiar el diagnóstico.

test_the_change_log_currently_changes_no_verdicts lo fija. Si un escenario futuro lo vuelve estructural, la prueba falla y esta tabla tiene que cambiar. Para eso sirve la aserción.

La ablación es la única forma de descubrir que una fuente que dedicaste una semana a integrar no cambia ningún veredicto.

Y cuando un artefacto falta

Los trabajos fallan, los buckets están vacíos, las rutas cambian. La pregunta interesante no es si el agente sigue respondiendo — lo hará — sino si se da cuenta:

  missing drift     -> verdict bad_deploy   flagged=True
  missing evals     -> verdict bad_deploy   flagged=True
  missing changes   -> verdict bad_deploy   flagged=True

Un agente que diagnostica en silencio desde dos de tres archivos es peor que uno que se niega, porque nadie sabe que debe desconfiar de él.


El servidor MCP

python -m oncall.mcp_server                 # stdio, for Claude Desktop et al
python -m oncall.mcp_server --http --port 8931

Siete herramientas — list_incidents, get_drift_report, get_eval_run, get_changes, investigate_incident, compare_incidents, list_specialists — más un recurso y un recurso con plantilla.

Las herramientas devuelven evidencia, no prosa. Cada una entrega el artefacto o el diagnóstico estructurado, así que el modelo del cliente razona sobre datos con citas en lugar de sobre un párrafo que alguien ya resumió. Un resumen es donde muere el detalle.

Escrito contra mcp 2.0.0, que es una reescritura que rompe compatibilidad

Vale la pena decirlo, porque casi todo lo publicado es 1.x y no funciona. Cada uno de estos fue verificado ejecutándolo:

1.x

2.0.0

from mcp.server.fastmcp import FastMCP

desaparecidoModuleNotFoundError. Usa MCPServer de mcp.server.mcpserver

@server.list_tools() / @server.call_tool()

desaparecido — el Server de bajo nivel acepta callbacks en el constructor

stdio_client + ClientSession a mano

Client(server_or_url_or_transport)

tool.inputSchema

tool.input_schema — snake_case en el modelo, camelCase en el cable

Dos más que costaron tiempo real:

  • @server.tool() debe ser llamado. @server.tool a secas lanza un TypeError que lo dice.

  • Un -> dict a secas no produce ningún structuredContent. El contenido de texto sigue ahí, por lo que se ve bien en un cliente de chat y rompe silenciosamente cualquier cliente que lea el campo estructurado. Cada herramienta aquí devuelve un genérico parametrizado (Dict[str, Any]) por esa razón, y hay una prueba.

Probando un servidor de protocolo sin un subproceso

Client(server) acepta un objeto de servidor directamente, por lo que todo el ciclo de ida y vuelta del protocolo se ejecuta en proceso — sin subproceso, sin puerto, sin inestabilidad de ninguno. Esa facilidad es la única razón por la que las pruebas de protocolo son baratas aquí.


Inicio rápido

git clone https://github.com/kanishqtanwar35-hub/ml-oncall-agent
cd ml-oncall-agent
pip install -r requirements.txt
export PYTHONPATH=src

python -m oncall.cli incidents                  # what can be investigated
python -m oncall.cli investigate concept_drift  # the full report
python -m oncall.cli evaluate                   # score it against truth
python -m oncall.cli ablate                     # what each artifact is worth
pytest -q                                       # 65 tests

Apúntalo a artefactos reales:

python -m oncall.cli write ./artifacts --scenario bad_deploy
# then: Evidence.load("./artifacts") reads a real pipeline's output unchanged

Todo se ejecuta sin API key. investigate --narrate añade un párrafo inicial escrito por el modelo si GEMINI_API_KEY está configurada, y no cambia nada más.


Bugs que vale la pena leer

Una tolerancia codificada se tragó el caso de evaluación inestable. regressions() usaba un umbral de 0.02, por lo que un movimiento de 0.006 nunca se registraba y la verificación de ruido nunca se ejecutaba — el agente decía healthy cuando la verdad era noise. Ese es exactamente el error de umbral folclórico contra el que argumenta model-drift-monitor, reproducido un repositorio más allá. Detección y significancia son dos preguntas: el piso ahora es 0.005 ("cualquier cosa que un dashboard mostraría") y el noise_std medido por el propio harness hace la discriminación.

La prueba de recuperación no podía fallar. Fingía un especialista omitido pre-sembrando consulted — pero el crítico compara available contra consulted, así que marcar algo como consultado ocultaba la brecha del mismo chequeo que se estaba probando. Reportaba recovered: False y parecía un crítico roto. La falta debe inyectarse en el enrutamiento, no en el registro; build_graph(skip_first_pass=...) lo hace, y el crítico ahora demuestra que captura la brecha y devuelve al supervisor.


Limitaciones, dichas claramente

  • Los escenarios son sintéticos. Deliberadamente — los incidentes reales no vienen con una causa raíz etiquetada, que es precisamente por lo que diagnosticarlos es difícil. Los números caracterizan el método, no ningún sistema de producción.

  • Seis escenarios es un conjunto pequeño. El 100% en seis no es 100% en general, y el siguiente escenario añadido tiene más probabilidades de romperlo que de confirmarlo.

  • La calibración no es medible aquí. Sin respuestas incorrectas no hay nada contra lo que comparar la confianza. La CLI imprime n/a y dice por qué en lugar de inventar una cifra — test_calibration_is_honestly_unmeasurable_here lo fija.

  • Los pesos están fijados a mano. Codifican mi juicio sobre cuánto vale la evidencia, y un conjunto de incidentes etiquetado más grande permitiría ajustarlos en su lugar — con una división de reserva, porque ajustarlos en seis escenarios sería memorización.

  • La precisión de selección de herramientas es trivialmente 1.0 con tres artefactos siempre presentes. La métrica está aquí porque empieza a importar en la cuarta herramienta, y añadirla retroactivamente es como descubres que el agente ha estado llamando a todo durante meses.

  • Sin integraciones en vivo. Lee artefactos desde el disco. Conectarlo a un warehouse real, un sistema de CI y un host de git es trabajo de despliegue, no de razonamiento.

  • El crítico comprueba completitud y respaldo, no corrección. No puede decirte que los pesos están mal, solo que la evidencia era escasa.

Hoja de ruta

  1. Un conjunto de incidentes etiquetado más grande, y ajustar los pesos en una división de reserva.

  2. Más especialistas — latencia de servicio, ledger de costes, frescura del feature store — que es donde la precisión de selección de herramientas empieza a significar algo.

  3. Conectar el servidor MCP a fuentes de artefactos reales en lugar de un constructor de escenarios.

  4. Correlación multi-incidente: tres servicios regresando a la vez es un incidente, no tres.

Licencia

MIT.

-
license - not tested
Not graded
quality - not tested
C
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 Connectors

  • MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.

  • Monitor MCP servers, API contracts and AI outputs for schema drift. Alerts on breaking changes.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

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/kanishqtanwar35-hub/ml-oncall-agent'

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