Guides
Évaluer depuis Node
Le SDK Node exécute votre système et ses évaluateurs dans Node, à l’intérieur de votre propre lanceur de tests, et transmet les scores au moteur Python, qui décide. Une équipe TypeScript garde son code, ses fixtures et son lanceur de tests ; chaque intervalle, chaque comparaison et chaque décision restent ceux du moteur, et le SDK n’en calcule aucun, pas même une moyenne.
Installation
npm install --save-dev @oloproof/sdk
pip install oloproofLa première ligne est le SDK, la seconde le moteur auquel il transmet les scores (Python 3.11 ou ultérieur). Le SDK trouve oloproof dans votre PATH ; s’il n’y est pas, il s’arrête et indique comment l’installer.
Noter un système dans un test
Une suite est le même fichier JSON Lines que lit le moteur (Écrire une suite), un cas par ligne, chacun avec un id. Donnez à evaluate la suite, le système et un évaluateur par critère :
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 évaluateur renvoie { passed } ou { score }, avec une reason facultative. Une fonction juge la réussite ou l’échec ; un évaluateur qui note déclare son scale, car un intervalle sur une moyenne ne tient qu’à l’intérieur d’une plage connue avant que les scores soient lus. Nommez le judge quand un modèle a jugé : le moteur le traite alors comme un juge à vérifier par rapport à des personnes avant qu’il puisse servir de porte à une publication (Juges).
concurrency limite le nombre de cas exécutés en même temps (quatre par défaut). Le fichier de scores liste les cas dans l’ordre où la suite les donne, quel que soit l’ordre dans lequel ils se terminent.
Laisser le moteur décider
const decided = await decide({
scores: "scores/candidate.jsonl",
baseline: "scores/baseline.jsonl",
policy: "release.yaml",
});
console.log(decided.exit, decided.comparison?.gate?.decisions);decide exécute les commandes que vous taperiez, dans le répertoire donné par cwd (le répertoire courant par défaut) :
oloproof scores import scores/baseline.jsonl scores/candidate.jsonl --tool node
oloproof compare RUN_ID BASELINE_RUN_ID --policy release.yaml --jsonAvec une référence, le moteur compare les deux exécutions cas par cas et decided.comparison est l’enregistrement qu’a imprimé oloproof compare --json. Sans référence, decide exécute oloproof gate sur l’exécution importée et renvoie ce que cette commande a imprimé dans decided.decision.stdout. Dans les deux cas, decided.exitCode est le code de sortie du moteur, inchangé, et decided.exit son nom : EXIT_CODES associe chaque nom à la valeur du moteur, comme les liste Exécution en CI.
Ce que contient le fichier
Le fichier est celui que lit oloproof scores import (Un second avis) : une ligne par cas et par critère, uniquement des identifiants de cas et des scores. Une réponse, une entrée ou une reason n’y entre jamais ; elles restent dans scored.results, dans Node.
- Un cas dont le système lève une exception est écrit avec une valeur vide sur chaque critère, et un cas dont l’évaluateur lève une exception avec une valeur vide sur ce critère. Le moteur compte chacun comme manquant et le borne à son pire, si bien qu’un échec abaisse ce que les preuves peuvent montrer au lieu d’en disparaître. scored.errors liste chacun avec son message.
- Un verdict que le fichier ne peut pas porter arrête l’exécution avec une erreur et n’écrit rien : un score sans échelle ou en dehors d’elle, à la fois un score et une réussite, ou un critère que le moteur n’a pas pu nommer comme métrique.
- Chaque fichier est une version du système identifiée par son contenu, donc importer de nouveau le même fichier réutilise ce que le moteur a stocké.
Sans installer le moteur
secondOpinion envoie deux fichiers de scores à la page hébergée qui répond à « est-ce réel ? » sans rien installer, et renvoie la réponse du moteur telle qu’il l’a écrite :
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 page ne conserve rien et ne demande aucun compte. Elle lit jusqu’à 2 MB par fichier et est limitée par client ; un refus renvoie la phrase du moteur qui nomme la ligne à modifier.
Ce qui n’est pas construit
- Publier @oloproof/sdk sur npm. En attendant, construisez-le depuis packages/sdk dans le dépôt.
- Une statistique de quelque sorte que ce soit dans Node, par conception : le SDK écrit des scores et lit la réponse du moteur.
- Un group_id ou un time_order dans votre suite n’est pas reporté dans l’import, qui ne lit que les identifiants de cas et les scores, si bien que le moteur lit les cas comme indépendants.
Pour aller plus loin
- Un second avis : le format du fichier et ce à quoi répond une comparaison.
- Porte de CI : la politique de publication que decide transmet au moteur.
- L’API Python : la même évaluation, exécutée par le moteur lui-même.