Tworzenie ocen opartych na regułach

Automatyzacja podstawowych czynności: używanie kodu do wykrywania prostych błędów

Wiesz już, jakie błędy chcesz wykrywać za pomocą ocen opartych na regułach. Czas wdrożyć odpowiednie funkcje oceniające:

  • evalDataFormat(): sprawdza, czy format danych jest prawidłowy. Obejmuje to prawidłowy format JSON, obecność wszystkich kluczy, brak pustych wartości, motto składające się z maksymalnie 6 słów i kolory szesnastkowe.
  • evalContrastRatio(): sprawdza, czy współczynnik kontrastu między tekstem a tłem jest dostępny.

Wdrażanie ocen opartych na regułach

Wybieranie metody oceniania

Kryteria oceny są binarne. Funkcje oceny opartej na regułach powinny generować dane wyjściowe w postaci binarnej, np. etykiety PASS lub FAIL.

  • Dane wyjściowe aplikacji ThemeBuilder (pełny obiekt motywu) → evalDataFormat() → etykieta PASS lub FAIL. PASS, jeśli format danych spełnia wszystkie ograniczenia. W przeciwnym razie FAIL.
  • Dane wyjściowe aplikacji ThemeBuilder (obiekt palety kolorów) → evalContrastRatio() → etykieta PASS lub FAIL .PASS, jeśli współczynnik jest większy niż 4,5. W przeciwnym razie FAIL.

Definiowanie typu oceny

Dane PASS lub FAIL są wartością logiczną, ale dla czytelności możesz je zaimplementować jako etykietę tekstową (kategorię).

Aby uprościć kod, możesz użyć tego samego typu TypeScript zarówno w przypadku ocen opartych na regułach, jak i ocen modelu LLM, które wdrożysz później. Utwórz typ EvalResult, który zawiera binarną kategorię EvalLabel oraz pole rationale (uzasadnienie), aby model oceniający mógł wyjaśnić swoją ocenę.

enum EvalLabel {
    PASS = "PASS",
    FAIL = "FAIL"
}

interface EvalResult {
    label: EvalLabel;
    rationale?: string;
}

Wdrażanie oceniających

Zod to świetne narzędzie do sprawdzania schematów, ponieważ obsługuje zarówno strukturę JSON, jak i reguły niestandardowe. Jest deklaratywny, co sprawia, że kod weryfikacyjny jest czytelny. Zdefiniuj szczegółowe raporty o błędach z konkretnymi ścieżkami i przyczynami niepowodzeń, aby ułatwić rozwiązywanie problemów.

import { z } from 'zod';
import { MAX_WORD_COUNT } from './app.config';

const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;

// Reusable schema for hex colors
const HexColor = z.string().regex(hexColorRegex, { message: "Invalid hex color code" });

// zod schema definition for AppOutput
export const AppOutputSchema = z.object({
  motto: z.string().min(1, { message: "Motto is missing or empty" }).refine((val) => {
    const words = val.replace(/[^\w\s]|_/g, "").trim();
    const count = words ? words.split(/\s+/).length : 0;
    return count > 0 && count <= MAX_WORD_COUNT;
  }, { message: `Motto must be between 1 and ${MAX_WORD_COUNT} words` }),
  colorPalette: z.object({
    textColor: HexColor,
    backgroundColor: HexColor,
    primary: HexColor,
    secondary: HexColor
  }).catchall(HexColor)
});

Współczynnik kontrastu

Logikę domeny, np. obliczenia współczynnika kontrastu, przechowuj w osobnych funkcjach narzędziowych.

/*
 * Input: ColorPalette {"textColor":"#333333","backgroundColor":"#000000", ...}
 * Output: EvalResult {"status":"FAIL","rationale":"Contrast ratio is 1.66:1 (must be >= 4.5:1)."}
 * minContrastRatio is an app config variable, MIN_CONTRAST_RATIO = 4.5
*/
export function evalContrastRatio(colorPalette: ColorPalette, minContrastRatio: number): EvalResult {
  if (!colorPalette || !colorPalette.textColor || !colorPalette.backgroundColor) {
    return { status: EvalLabel.FAIL, rationale: "Missing textColor or backgroundColor." };
  }
  try {
    const ratio = getContrastRatio(colorPalette.textColor, colorPalette.backgroundColor);
    const rationale = `Contrast ratio is ${ratio.toFixed(2)}:1 (must be >= ${minContrastRatio}:1).`;
    if (ratio < minContrastRatio) {
      return { status: EvalLabel.FAIL, rationale };
    }
    return { status: EvalLabel.PASS, rationale };
  } catch (e) {
    return { status: EvalLabel.FAIL, rationale: "Could not calculate contrast ratio (invalid hex?)." };
  }
}

Zapoznaj się z naszym kodem oceniającym dla evalDataFormat() i evalContrastRatio().

Testowanie ocen opartych na regułach

Oceny oparte na regułach są deterministyczne, więc możesz wdrożyć klasyczne testy jednostkowe, aby sprawdzić ich działanie. Utwórz testy, które będą uruchamiać różne dane wyjściowe za pomocą oceniających i sprawdzać, czy zwracają one oczekiwaną etykietę PASS lub FAIL.

Jeśli przypadek testowy oczekuje, że oceniający zwróci etykietę FAIL, a tak się stanie, test zwróci etykietę PASS, ponieważ oceniający zachował się zgodnie z oczekiwaniami.

import { MIN_CONTRAST_RATIO } from '../src/app.config'; // 4.5

const testCases = [
  {
  // ...
      appOutput: {
        motto: "Test motto",
        colorPalette: {
          textColor: "#333333",
          backgroundColor: "#000000",
          primary: "#FF0000",
          secondary: "#333333"
        }
      },
    expected: {
      // Dark grey on black (low contrast): FAIL
      contrast: EvalLabel.FAIL
    }
  }
  // ... more test cases
];

testCases.forEach((testCase) => {
  const result = evalContrastRatio(
    testCase.appOutput.colorPalette as any, MIN_CONTRAST_RATIO
  );
  const actualEvalLabel = result.label;
  const expectedEvalLabel = testCase.expected.contrast;
  const isSuccess = actualEvalLabel === expectedEvalLabel;
 // ...
});

Wypróbuj