Przewodniki
Ewaluacja z poziomu Node
SDK dla Node uruchamia Twój system i jego ewaluatory w Node, wewnątrz Twojego własnego test runnera, i przekazuje wyniki silnikowi Pythona, który podejmuje decyzję. Zespół TypeScript zachowuje swój kod, swoje fixtures i swój test runner; każdy przedział, każde porównanie i każda decyzja należą do silnika, a SDK nie oblicza żadnego z nich, nawet średniej.
Instalacja
npm install --save-dev @oloproof/sdk
pip install oloproofPierwszy wiersz to SDK, drugi to silnik, któremu SDK przekazuje wyniki (Python 3.11 lub nowszy). SDK znajduje oloproof w Twoim PATH; jeśli go tam nie ma, zatrzymuje się i mówi, jak go zainstalować.
Ocena systemu w teście
Zestaw to ten sam plik JSON Lines, który czyta silnik (Pisanie zestawu), jeden przypadek na wiersz, każdy z id. Przekaż evaluate zestaw, system i jeden ewaluator na kryterium:
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);Ewaluator zwraca { passed } lub { score }, z opcjonalnym reason. Funkcja ocenia pass lub fail; ewaluator, który wystawia wyniki, deklaruje swoją scale, ponieważ przedział dla średniej obowiązuje tylko w zakresie znanym przed odczytaniem wyników. Podaj judge, gdy oceniał model: silnik traktuje go wtedy jako sędziego, którego trzeba sprawdzić względem ludzi, zanim będzie mógł bramkować wydanie (Sędziowie).
concurrency ogranicza, ile przypadków działa jednocześnie (domyślnie cztery). Plik wyników wymienia przypadki w kolejności, w jakiej podaje je zestaw, niezależnie od kolejności, w jakiej się kończą.
Niech decyduje silnik
const decided = await decide({
scores: "scores/candidate.jsonl",
baseline: "scores/baseline.jsonl",
policy: "release.yaml",
});
console.log(decided.exit, decided.comparison?.gate?.decisions);decide uruchamia polecenia, które wpisuje się ręcznie, w katalogu podanym jako cwd (domyślnie bieżącym):
oloproof scores import scores/baseline.jsonl scores/candidate.jsonl --tool node
oloproof compare RUN_ID BASELINE_RUN_ID --policy release.yaml --jsonZ punktem odniesienia silnik porównuje oba przebiegi przypadek po przypadku, a decided.comparison to rekord, który wypisało oloproof compare --json. Bez niego decide uruchamia oloproof gate na zaimportowanym przebiegu i zwraca to, co wypisało, w decided.decision.stdout. W obu przypadkach decided.exitCode to kod wyjścia silnika, niezmieniony, a decided.exit jego nazwa: EXIT_CODES przypisuje każdej nazwie wartość silnika, tak jak wymienia je Uruchamianie w CI.
Co zawiera plik
Plik to ten, który czyta oloproof scores import (Druga opinia): jeden wiersz na przypadek i kryterium, wyłącznie identyfikatory przypadków i wyniki. Odpowiedź, wejście ani reason nigdy do niego nie trafiają; pozostają w scored.results, w Node.
- Przypadek, którego system rzuca wyjątek, jest zapisywany z pustą wartością dla każdego kryterium, a przypadek, którego ewaluator rzuca wyjątek, z pustą wartością dla tego kryterium. Silnik liczy każdy z nich jako brakujący i ogranicza go w najgorszym wariancie, więc błąd obniża to, co mogą pokazać dowody, zamiast z nich znikać. scored.errors wymienia każdy z nich wraz z jego komunikatem.
- Werdykt, którego plik nie może przenieść, zatrzymuje przebieg z błędem i niczego nie zapisuje: wynik bez skali lub spoza niej, jednocześnie wynik i pass albo kryterium, którego silnik nie mógłby nazwać jako metryki.
- Każdy plik to wersja systemu identyfikowana przez swoją zawartość, więc ponowny import tego samego pliku wykorzystuje to, co silnik zapisał.
Bez instalowania silnika
secondOpinion wysyła dwa pliki wyników do hostowanej strony, która odpowiada na pytanie „czy to prawdziwa poprawa?” bez instalowania czegokolwiek, i zwraca odpowiedź silnika w takiej postaci, w jakiej ją zapisał:
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);Strona niczego nie przechowuje i nie wymaga konta. Czyta do 2 MB na plik i ma limit na klienta; odmowa zwraca zdanie silnika wskazujące wiersz do zmiany.
Czego nie zbudowano
- Publikacji @oloproof/sdk w npm. Dopóki jej nie ma, zbuduj go z packages/sdk w repozytorium.
- Jakiejkolwiek statystyki w Node, celowo: SDK zapisuje wyniki i czyta odpowiedź silnika.
- group_id ani time_order z Twojego zestawu nie są przenoszone do importu, który czyta tylko identyfikatory przypadków i wyniki, więc silnik traktuje przypadki jako niezależne.
Co dalej
- Druga opinia: format pliku i na co odpowiada porównanie.
- Bramkowanie CI: polityka wydań, którą decide przekazuje silnikowi.
- API Pythona: ta sama ewaluacja, uruchamiana przez sam silnik.