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()→ etykietaPASSlubFAIL.PASS, jeśli format danych spełnia wszystkie ograniczenia. W przeciwnym razieFAIL. - Dane wyjściowe aplikacji ThemeBuilder (obiekt palety kolorów) →
evalContrastRatio()→ etykietaPASSlubFAIL.PASS, jeśli współczynnik jest większy niż 4,5. W przeciwnym razieFAIL.
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;
// ...
});