本文へスキップ

ガイド

Node から評価する

Node SDK は、お使いのシステムとその評価器を Node 上のお使いのテストランナーの中で実行し、判断を下す Python エンジンにスコアを渡します。TypeScript のチームは自分たちのコード、フィクスチャー、テストランナーをそのまま保てます。区間、比較、判断はすべてエンジンのものであり、SDK はそのどれも計算しません。平均さえ計算しません。

インストール

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

1 行目は SDK、2 行目は SDK がスコアを渡す先のエンジンです(Python 3.11 以降)。SDK は PATH 上の oloproof を見つけます。そこにない場合は停止し、インストール方法を示します。

テストの中でシステムを採点する

スイートは、エンジンが読むものと同じ JSON Lines ファイルです(スイートを書く)。1 行に 1 ケースで、それぞれに id があります。evaluate に、スイート、システム、そして基準ごとに 1 つの評価器を渡します。

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);

評価器は { passed } または { score } を返し、任意で reason を付けられます。関数は合格か不合格かを判定します。スコアを付ける評価器は scale を宣言します。平均に対する区間は、スコアを読む前にわかっている範囲の内側でしか成り立たないからです。モデルが判定した場合は judge を指定してください。するとエンジンはそれをジャッジとして扱い、リリースをゲートできるようになる前に人と照らし合わせて確認します(ジャッジ)。

concurrency は、同時に実行するケースの数の上限です(既定では四つ)。スコアファイルは、ケースが終わった順序にかかわらず、スイートが与える順序でケースを並べます。

エンジンに判断させる

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

decide は、あなたが入力するはずのコマンドを、cwd として指定したディレクトリ(既定では現在のディレクトリ)で実行します。

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

ベースラインがある場合、エンジンは 2 つの実行をケースごとに比較し、decided.comparison は oloproof compare --json が出力したレコードになります。ベースラインがない場合、decide はインポートした実行に対して oloproof gate を実行し、その出力を decided.decision.stdout に入れて返します。どちらの場合も、decided.exitCode はエンジンの終了コードを変えずにそのまま示し、decided.exit はその名前です。EXIT_CODES は各名前をエンジンの値に対応付けており、その一覧は CI での実行 にあります。

ファイルが保持するもの

このファイルは、oloproof scores import が読むファイルです(セカンドオピニオン)。ケースと基準の組み合わせごとに 1 行で、ケース ID とスコアだけを持ちます。回答、入力、reason がそこに入ることは決してなく、それらは Node の中の scored.results に残ります。

  • システムが例外を投げたケースは、すべての基準で空の値として書き込まれ、評価器が例外を投げたケースは、その基準で空の値として書き込まれます。エンジンはそれぞれを欠損として数え、最悪の値で範囲を定めます。そのため、失敗はエビデンスから消えるのではなく、エビデンスが示せることを引き下げます。scored.errors は、それぞれをそのメッセージとともに一覧にします。
  • ファイルが保持できない判定は、エラーで実行を止め、何も書き込みません。尺度のないスコアや尺度の範囲外のスコア、スコアと合格の両方、あるいはエンジンがメトリクスとして名前を付けられない基準がそれにあたります。
  • 各ファイルは、その内容によって識別されるシステムのバージョンです。そのため、同じファイルをもう一度インポートすると、エンジンが保存したものが再利用されます。

エンジンをインストールせずに

secondOpinion は、何もインストールせずに「本物か」に答えるホスト型のページに 2 つのスコアファイルを送り、エンジンが書いたとおりの答えを返します。

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);

このページは何も保持せず、アカウントも必要ありません。1 ファイルあたり最大 2 MB まで読み込み、クライアントごとに制限されています。拒否された場合は、変更すべき行を示すエンジンの文が返されます。

まだ作られていないもの

  • @oloproof/sdk を npm に公開すること。公開されるまでは、リポジトリの packages/sdk からビルドしてください。
  • Node での統計は、種類を問わず設計上行いません。SDK はスコアを書き出し、エンジンの答えを読むだけです。
  • スイートにある group_id や time_order はインポートに引き継がれません。インポートが読むのはケース ID とスコアだけなので、エンジンはケースを独立したものとして読みます。

次に読むページ

  • セカンドオピニオン では、ファイル形式と、比較が何に答えるかを扱います。
  • CI のゲート では、decide がエンジンに渡すリリースポリシーを扱います。
  • Python API では、同じ評価をエンジン自身が実行する方法を扱います。