Ir para o conteúdo
mcpd
sem daemon
Código

Início rápido

Daemon no ar, agente instrumentado, trace na tela. Nada para assinar e nada para instalar ao lado.

1. Execute o daemon

Ainda não há uma versão publicada.

A imagem, o chart e os pacotes que os comandos deste site citam são a distribuição pretendida. Nenhum deles foi publicado. O que funciona hoje é compilar a partir do código-fonte, o que exige Rust e Node:

Compilar e executar

git clone https://github.com/mcpd/mcpd && cd mcpd && make build && ./target/release/mcpd demo

O mcpd é um único processo, com o armazenamento compilado dentro dele. Não há banco de dados para subir nem arquivo de configuração para escrever.

docker run -p 4317:4317 -v mcpd-data:/data ghcr.io/mcpd/mcpd

O volume é opcional, mas vale a pena: sem ele, os traces vão embora junto com o contêiner. Prefere um binário? Instale direto.

o que você deve ver
$ docker run -p 4317:4317 ghcr.io/mcpd/mcpdWARN listening on 0.0.0.0:4317 with open ingest. Anyone who can reach this port can write to it. Set --ingest-key (or MCPD_INGEST_KEYS) before exposing it.WARN listening on 0.0.0.0:4317 with an open read API. Stored prompts and completions are readable by anyone who can reach this port. Set --read-key to require a key.WARN listening on 0.0.0.0:4317 with an open run surface. Anyone who can reach this port can start runs and claim steps. Set --execute-key and --worker-key before exposing it.INFO mcpd 0.1.0 listening on http://0.0.0.0:4317INFO   interface   http://0.0.0.0:4317/INFO   OTLP        http://0.0.0.0:4317/v1/tracesINFO   native      http://0.0.0.0:4317/v1/ingestINFO   runs        http://0.0.0.0:4317/v1/api/runsINFO   storage     sqlite at /data/mcpd.db

Os avisos vêm primeiro, e isso é de propósito. No seu notebook eles não importam. Antes que essa porta fique acessível a qualquer outra coisa, leia Implantação.

2. Mande alguma coisa para ele

Há dois caminhos de entrada, e você não é obrigado a escolher o nosso. Se o seu agente já emite OpenTelemetry, aponte-o para o mcpd e não escreva nenhuma linha de código nova:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

Caso contrário, instale o SDK da sua linguagem. Ele não tem dependências obrigatórias, e registrar um span nunca bloqueia e nunca lança uma exceção.

conecte

import { Mcpd } from '@mcpd/sdk'

// Every field here also reads an environment variable, so the same code runs
// unchanged in development and in production. With no arguments at all this
// talks to a daemon on http://localhost:4317.
const mcpd = new Mcpd({
  project: 'support',
  environment: 'development',
  serviceName: 'support-agent',
  serviceVersion: '1.4.0',
})

3. Instrumente uma execução

Envolva o trabalho que o seu agente faz. Um span registra o que entrou, o que saiu, quanto tempo levou e quanto custou; os filhos se aninham dentro dele sozinhos, então uma chamada de ferramenta feita dentro do bloco cai no lugar certo da árvore sem que ninguém precise dizer onde ela fica.

registre uma execução

/**
 * One ticket, one trace.
 *
 * `withSpan` opens the span, keeps it active for everything the callback
 * starts, and ends it when the callback settles. Nothing inside has to be
 * passed a handle to be nested under it.
 */
async function handleTicket(ticket: Ticket): Promise<{ answer: string; traceId: string }> {
  let traceId = ''
  const answer = await mcpd.withSpan('support_agent', async (run) => {
    // Keep the id: a score or a piece of feedback that arrives later attaches
    // to this run by it.
    traceId = run.traceId
    // Tags label the whole run, so the trace list can filter on them.
    run.setTags(['support', 'tier-1'])
    run.setCorrelation({ sessionId: ticket.id, userId: ticket.customerId })
    run.setInput({ question: ticket.question })

    const order = await lookUpOrder(ticket)
    const answer = await draftAnswer(ticket, order)

    run.setOutput({ answer })
    return answer
  })
  return { answer, traceId }
}

4. Leia o resultado

Abra localhost:4317. A sua execução está na lista. Abra-a e você recebe a árvore inteira: cada chamada de modelo com o seu prompt e a sua resposta, cada chamada de ferramenta com os seus argumentos e o seu resultado, tempos, tokens e custo.

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.

5. Ache a execução que interessa

Não é na lista que você vai passar o seu tempo, e sim na busca. O mcpd indexa cada prompt e cada resposta, então dá para ir direto à execução em que o modelo disse aquilo de que um cliente reclamou:

busque e analise

// The same client reads. This is the query that finds bad answers: every run
// that a scorer put below the bar.
const suspect = await mcpd.listTraces({
  hasScore: 'answer_relevance',
  scoreBelow: 0.5,
  limit: 10,
})
console.log(`runs scoring under 0.5: ${suspect.traces.length}`)

const recent = await mcpd.listTraces({ limit: 5, sort: 'start_time', order: 'desc' })
for (const trace of recent.traces) {
  const seconds = ((trace.durationNs ?? 0) / 1e9).toFixed(2)
  console.log(
    `${trace.traceId.slice(0, 8)}  ${trace.name.padEnd(16)} ${trace.status.padEnd(6)} ` +
      `${seconds}s  ${trace.spanCount} spans  $${(trace.cost?.totalCost ?? 0).toFixed(6)}`,
  )
}

// One run, with every span in it, ordered so a waterfall renders directly.
const detail = await mcpd.getTrace(traceId, { include: ['scores', 'feedback'] })
for (const span of detail.spans) {
  console.log(`  ${span.kind.padEnd(18)} ${span.name}`)
}

Para onde ir agora

Agora você tem o ciclo inteiro. As páginas que valem a leitura em seguida dependem do que você está fazendo: