Ir al contenido
mcpd
sin daemon
Código

Conceptos

Un puñado de palabras sostiene todo el modelo de datos. El resto de la documentación da por hecho que las conoces, así que esta página define cada una y dice para qué sirve.

Span

Un span es una unidad de trabajo. Tiene un nombre, un tipo, una hora de inicio, casi siempre una hora de fin, y un estado. Puede llevar qué entró, qué salió, cuántos tokens usó, cuánto costó y un error si falló.

Mantén el nombre con poca cardinalidad. search_docs es un nombre; search_docs(query=hello) es un nombre y un valor pegados, y deja inservible agrupar por nombre en cuanto tienes dos ejecuciones.

Traza

Una traza son todos los spans de una ejecución, unidos por un id de traza de 128 bits. Dentro de la traza, parent_span_id le da forma al árbol: una llamada a una herramienta hecha dentro de un paso del modelo es hija de ese paso, así que el anidamiento en pantalla es el anidamiento que ocurrió de verdad.

Los ids tienen la forma de OpenTelemetry: 32 caracteres hexadecimales en minúscula para una traza y 16 para un span. Eso no es decoración. Es lo que permite que una traza que empezó en tu capa web y terminó en tu agente siga siendo una sola traza en las dos, y lo que permite que mcpd conviva con cualquier otra cosa que ya lea tu telemetría.

Un span cuyo padre viene de otro sistema de trazado lo lleva en external_parent_span_id. mcpd conserva ese valor para la correlación, pero nunca construye su árbol a partir de él, porque un id de padre que nombra un span que mcpd nunca recibió dejaría todo el subárbol colgando de nada.

Trace b3d9e71a Fault
0ms 2.1s 4.2s 6.3s 8.4s
  1. agent support_agent fail
  2. model chat
  3. tool returns_policy
  4. model chat
  5. tool returns_policy
  6. model chat
  7. tool returns_policy

The model called one tool three times and never answered. That is visible in four seconds here, and invisible in a log file.

mcpd guarda además una proyección de cada traza: el número de spans, el número de errores, el total de tokens, el costo total, cuántas llamadas al modelo y cuántas llamadas a herramientas. Esa fila se recalcula a partir de los spans en cada escritura, en vez de irse incrementando, porque los spans llegan desordenados, se reintentan y se actualizan en el sitio. Un contador se desvía con las tres cosas, y un número de spans visiblemente equivocado en la lista hace que quien lo lee desconfíe de las demás cifras de la página.

Spans raíz y spans de evento

Un span raíz es el que no tiene padre dentro de la traza. Normalmente es un agent_run o un workflow_run, y es de donde la traza saca su nombre, sus etiquetas y su correlación. Las etiquetas solo tienen sentido en una raíz, donde etiquetan la ejecución entera.

Un span de evento es un punto en el tiempo y no una duración, así que no tiene fin ni duración. El caso habitual es un chunk de un flujo. La distinción se guarda en vez de deducirse de una hora de fin ausente, porque «esto nunca tuvo fin» y «esto todavía no ha terminado» son hechos distintos y solo uno de los dos es un problema.

Una traza está completa cuando su raíz ha terminado y no queda ningún span abierto. Hasta entonces sigue apareciendo en la lista, con el mejor nombre disponible, en vez de esconderse hasta acabar. La ejecución que nunca terminó suele ser la que viniste a mirar.

Tipo de span

El tipo dice qué es una operación. Decide cómo se dibuja el span, qué atributos significan algo en él y si la contabilidad de costos lo mira. mcpd define 33 tipos, agrupados en familias:

FamiliaTipos
Agente agent_run
Modelo model_generation, model_step, model_inference, model_chunk
Herramientas tool_call, client_tool_call, provider_tool_call, mcp_tool_call
Workflow workflow_run, workflow_step, workflow_conditional, workflow_parallel, workflow_loop, y el resto
Recuperación rag_ingestion, rag_embedding, rag_vector_operation, rag_action, retrieval, memory_operation, graph_action
Evaluación scorer_run, scorer_step, guardrail, processor_run
Otros mapping, skill_resolution, workspace_action, http_request, generic

Cuatro tipos facturan tokens: model_generation, model_step, model_inference y rag_embedding. Esos son los spans que lee la contabilidad de costos. generic siempre es válido y nunca se deduce, así que un span que mcpd no puede clasificar queda etiquetado con honestidad en vez de a base de suposiciones. El modelo de datos enumera cada tipo con lo que significa.

La jerarquía del modelo

Cuatro de esos tipos se anidan unos dentro de otros, y ese anidamiento es lo más útil del modelo:

  • model_generation es una generación lógica: todo, desde la primera solicitud hasta la respuesta final.
  • model_step es un paso dentro de ella. Una generación que llama a herramientas dos veces tiene tres pasos.
  • model_inference es solo la ida y vuelta al proveedor, sin procesadores y sin ejecución de herramientas dentro.
  • model_chunk es un chunk del flujo, registrado como evento.

La razón de que haya cuatro niveles y no uno es que «la llamada al modelo fue lenta» casi nunca es cierto tal cual. Una llamada desde tu código no es una sola ida y vuelta HTTP en cuanto hay herramientas de por medio: es una solicitud, una herramienta, otra solicitud, un guardrail, otra solicitud. Junta todo eso en un solo span y una ejecución que pasó seis segundos en tu propio bucle de reintentos parece idéntica a otra que pasó seis segundos esperando a un proveedor. Separar la inferencia del paso, y el paso de la generación, es lo que hace legible la diferencia, y el evento del primer chunk es lo que te da el tiempo hasta el primer token.

Registra el uso de tokens una sola vez, en el span que hizo la llamada al proveedor. La proyección de la traza suma los tokens de entrada y de salida de todos los spans de la traza, así que las mismas cifras puestas en una generación y otra vez en cada uno de sus pasos duplicarán el total de tokens y duplicarán el costo en pantalla. La jerarquía es para los tiempos; los tokens pertenecen al nivel que habló de verdad con el proveedor.

Las seis señales

Los spans son una de las seis cosas que guarda mcpd. Los logs son las líneas que emitió una ejecución. Las métricas son observaciones numéricas, en forma de contadores, medidores o histogramas. Las puntuaciones son la evaluación que una máquina hace de un span o de una traza. El feedback es el de una persona. Una nota de aspecto es una frase sobre una ejecución ya terminada. Un modelo escribe la mayoría. El daemon escribe las notas de outcome, a partir del estado de la ejecución y de otros hechos que ya tiene.

  • Spans

    What ran, nested, with timings

  • Logs

    Lines the run emitted

  • Metrics

    Numbers, with exemplars back to a run

  • Scores

    Machine evaluation

  • Feedback

    What a person thought

  • Aspect notes

    A sentence a model wrote about the run

trace_id Store Search Export

Las seis llevan el id de traza al que pertenecen, y casi todas también el id de span, y las seis pasan por el mismo pipeline de ocultación antes de que se escriba nada. Un secreto se escapa por una línea de log igual de bien que por un prompt.

Una puntuación siempre declara su escala: el valor, y el mínimo y el máximo entre los que está. Todos los SDK exigen los dos en el punto de llamada, porque un 0.7 suelto y sin escala no se puede comparar con nada, ni siquiera con lo que dio el mismo evaluador la semana pasada.

El feedback se guarda aparte de las puntuaciones, y nunca se promedia con ellas. Viene en cinco formas: thumbs, rating, correction, tag y comment. La corrección es la más valiosa de las cinco, porque es la única señal que trae la respuesta correcta.

Correlación

La correlación es el contexto al que pertenece una señal. Es la diferencia entre un montón de ejecuciones y un conjunto que puedes segmentar.

CampoQué contiene
projectLa clave de tenencia. Cada señal pertenece exactamente a uno.
environmentDónde se ejecutó, por ejemplo production o staging.
service_nameEl servicio que la emite.
service_versionSu versión, para poder atribuir una regresión a una entrega.
session_idUna sesión de cara al usuario. Agrupa muchas trazas en una conversación.
thread_idUn hilo dentro de esa sesión.
user_idEl usuario final para el que era la ejecución.
resource_idUn inquilino o espacio de trabajo dentro de tu propia aplicación.
run_idTu propio identificador de esta ejecución.
request_idLa solicitud entrante que provocó el trabajo.
experiment_idSe rellena cuando la ejecución la produjo un experimento.
releaseUn nombre de entrega o un sha de git.

project es el único campo obligatorio. Cuando quien envía no nombra ninguno, el daemon archiva la señal bajo el valor por defecto de --project, así nada queda guardado sin un sitio al que pertenecer.

Rellena session_id aunque parezca redundante. Una ejecución de un agente es una traza, pero una queja casi siempre trata de una conversación, y sin un id de sesión no hay nada que devuelva once trazas sueltas al intercambio que la persona tuvo de verdad.

La lista de trazas filtra directamente por environment, session_id, thread_id y user_id, junto con el estado, el tipo, el nombre, las etiquetas, el modelo, el rango de tiempo, la duración mínima, el costo mínimo y la puntuación. Encontrar una ejecución los junta todos.

Enlaces

Un span tiene un padre y cualquier número de enlaces. Un enlace apunta a otro span o a otra traza y dice por qué: follows_from, retry_of, replay_of, o el nombre que tú le pongas.

Los enlaces existen porque la paternidad no sabe expresar una convergencia. Un trabajo por lotes provocado por veinte solicitudes tiene veinte enlaces y un padre. Meter eso a la fuerza en el árbol inventaría diecinueve subárboles duplicados o tiraría diecinueve de las causas.

A continuación