Automatizzare le nozioni di base: utilizzare il codice per rilevare errori semplici.
Ora che sai quali errori vuoi rilevare con le valutazioni basate su regole, è il momento di implementare le funzioni di valutazione corrispondenti:
evalDataFormat(): verifica che il formato dei dati sia corretto. Sono inclusi JSON validi, tutte le chiavi presenti, nessun valore vuoto, il motto è composto da meno di sei parole, colori esadecimali.evalContrastRatio(): verifica che il rapporto di contrasto tra il testo e il colore di sfondo sia accessibile.
Implementare le valutazioni basate su regole
Scegliere un metodo di punteggio
I criteri di valutazione sono binari. Le funzioni di valutazione basate su regole devono produrre un output binario, ad esempio un'etichetta PASS o FAIL.
- Output dell'app ThemeBuilder (oggetto tema completo) →
evalDataFormat()→ etichettaPASSoFAIL.PASSse il formato dei dati soddisfa tutti i vincoli.FAILin caso contrario. - Output dell'app ThemeBuilder (oggetto tavolozza dei colori) →
evalContrastRatio()→ etichettaPASSoFAIL.PASSse il rapporto è > 4,5.FAILin caso contrario.
Definire un tipo di valutazioni
La metrica PASS o FAIL è un valore booleano, ma puoi scegliere di implementarla come etichetta stringa (categoria) per la leggibilità.
Per semplificare, puoi utilizzare lo stesso tipo TypeScript sia per le valutazioni basate su regole sia per le valutazioni del modello di giudizio LLM che implementerai in un secondo momento. Crea un tipo EvalResult che racchiude una categoria EvalLabel binaria e un campo rationale per il modello di giudizio per spiegare la sua valutazione.
enum EvalLabel {
PASS = "PASS",
FAIL = "FAIL"
}
interface EvalResult {
label: EvalLabel;
rationale?: string;
}
Implementare i valutatori
Zod è un ottimo strumento per la convalida dello schema, in quanto gestisce sia la struttura JSON sia le regole personalizzate. È dichiarativo, il che rende leggibile il codice di convalida. Definisci report di errori dettagliati con percorsi e motivi specifici per gli errori, per semplificare la risoluzione dei problemi.
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)
});
Rapporto del contrasto
Mantieni la logica di dominio, ad esempio i calcoli del rapporto di contrasto, in funzioni di utilità separate.
/*
* 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?)." };
}
}
Dai un'occhiata al nostro codice di valutazione
per evalDataFormat() e evalContrastRatio().
Testare le valutazioni basate su regole
Le valutazioni basate su regole sono deterministiche, quindi puoi implementare i test unitari classici per verificarne il comportamento. Crea i test per eseguire vari output tramite i valutatori e verificare se restituiscono l'etichetta PASS o FAIL prevista.
Se un caso di test prevede che il valutatore restituisca un FAIL e lo fa, il test restituisce un PASS perché il valutatore si è comportato come previsto.
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;
// ...
});
Prova
- Clona il progetto evals-course.
- Configuralo.
- Esegui tu stesso i test del valutatore basato su regole.