Vai al contenuto

Guide

Valutare da Node

L'SDK per Node esegue il tuo sistema e i suoi valutatori in Node, dentro il tuo test runner, e passa i punteggi al motore Python, che decide. Un team TypeScript mantiene il suo codice, le sue fixture e il suo test runner; ogni intervallo, confronto e decisione resta del motore, e l'SDK non ne calcola nessuno, nemmeno una media.

Installazione

npm install --save-dev @oloproof/sdk
pip install oloproof

La prima riga è l'SDK, la seconda il motore a cui passa i punteggi (Python 3.11 o successivo). L'SDK trova oloproof nel tuo PATH; se non c'è, si ferma e spiega come installarlo.

Assegnare un punteggio a un sistema in un test

Una suite è lo stesso file JSON Lines che legge il motore (Scrivere una suite), un caso per riga, ciascuno con un id. Passa a evaluate la suite, il sistema e un valutatore per criterio:

import { test } from "vitest";
import { type Case, decide, evaluate } from "@oloproof/sdk";
import { answer, rateHelpfulness } from "./support-bot.js";

type SupportCase = Case<{ question: string }, { label: string }>;
type Answer = { label: string; text: string };

test("the support bot is good enough to release", async () => {
  const scored = await evaluate<SupportCase, Answer>({
    suitePath: "data/support.jsonl",
    system: (testCase) => answer(testCase.input.question),
    evaluators: {
      exact_label: (output, testCase) => ({ passed: output.label === testCase.expected?.label }),
      helpfulness: {
        scale: [0, 1],
        judge: "gpt-4o-mini",
        evaluate: async (output, testCase) => ({ score: await rateHelpfulness(output, testCase) }),
      },
    },
    concurrency: 8,
    out: "scores/candidate.jsonl",
  });
  console.log(scored.counts);
}, 600_000);

Un valutatore restituisce { passed } o { score }, con un reason facoltativo. Una funzione giudica pass o fail; un valutatore che assegna punteggi dichiara la sua scale, perché un intervallo su una media vale solo all'interno di un intervallo di valori noto prima che i punteggi vengano letti. Indica il judge quando a giudicare è stato un modello: il motore lo tratta allora come un giudice da verificare rispetto alle persone prima che possa fare da gate a un rilascio (Giudici).

concurrency limita quanti casi vengono eseguiti contemporaneamente (quattro per impostazione predefinita). Il file dei punteggi elenca i casi nell'ordine in cui li fornisce la suite, qualunque sia l'ordine in cui terminano.

Lasciare decidere il motore

const decided = await decide({
  scores: "scores/candidate.jsonl",
  baseline: "scores/baseline.jsonl",
  policy: "release.yaml",
});
console.log(decided.exit, decided.comparison?.gate?.decisions);

decide esegue i comandi che digiteresti tu, nella directory indicata come cwd (quella corrente per impostazione predefinita):

oloproof scores import scores/baseline.jsonl scores/candidate.jsonl --tool node
oloproof compare RUN_ID BASELINE_RUN_ID --policy release.yaml --json

Con una baseline, il motore confronta le due esecuzioni caso per caso e decided.comparison è il record che oloproof compare --json ha stampato. Senza baseline, decide esegue oloproof gate sull'esecuzione importata e restituisce ciò che ha stampato in decided.decision.stdout. In entrambi i casi decided.exitCode è il codice di uscita del motore, invariato, e decided.exit il suo nome: EXIT_CODES associa ogni nome al valore del motore, come li elenca Esecuzione in CI.

Che cosa contiene il file

Il file è quello che legge oloproof scores import (Un secondo parere): una riga per caso e criterio, solo id dei casi e punteggi. Una risposta, un input o un reason non vi entrano mai; restano in scored.results, in Node.

  • Un caso il cui sistema solleva un'eccezione viene scritto con un valore vuoto su ogni criterio, e un caso il cui valutatore solleva un'eccezione con un valore vuoto su quel criterio. Il motore conta ciascuno come mancante e lo limita al suo caso peggiore, così un errore abbassa ciò che l'evidenza può mostrare anziché sparirne. scored.errors elenca ciascuno con il suo messaggio.
  • Un verdetto che il file non può contenere ferma l'esecuzione con un errore e non scrive nulla: un punteggio senza scala o al di fuori di essa, sia un punteggio sia un pass, oppure un criterio che il motore non potrebbe nominare come metrica.
  • Ogni file è una versione del sistema identificata dal suo contenuto, quindi importare di nuovo lo stesso file riusa ciò che il motore ha memorizzato.

Senza installare il motore

secondOpinion invia due file di punteggi alla pagina ospitata che risponde a «è reale?» senza installare nulla, e restituisce la risposta del motore così come l'ha scritta:

import { secondOpinion } from "@oloproof/sdk";

const result = await secondOpinion({
  baseUrl: "https://oloproof.com",
  baseline: "scores/baseline.jsonl",
  candidate: "scores/candidate.jsonl",
});
if (result.ok) console.log(result.opinion.answers);
else console.log(result.error, result.description);

La pagina non conserva nulla e non richiede alcun account. Legge fino a 2 MB per file ed è limitata per client; un rifiuto restituisce la frase del motore che indica la riga da cambiare.

Che cosa non è costruito

  • La pubblicazione di @oloproof/sdk su npm. Finché non avviene, costruiscilo da packages/sdk nel repository.
  • Una statistica di qualsiasi tipo in Node, per scelta progettuale: l'SDK scrive punteggi e legge la risposta del motore.
  • Un group_id o un time_order nella tua suite non viene riportato nell'importazione, che legge solo id dei casi e punteggi, quindi il motore legge i casi come indipendenti.

Dove andare dopo