ارزیابی‌های مبتنی بر قانون بسازید

خودکارسازی اصول اولیه: از کد برای گرفتن خطاهای ساده استفاده کنید.

حالا که می‌دانید کدام شکست‌ها را می‌خواهید با ارزیابی‌های مبتنی بر قانون تشخیص دهید، وقت آن رسیده که توابع ارزیاب مربوطه را پیاده‌سازی کنید:

  • evalDataFormat() : بررسی می‌کند که قالب داده‌ها صحیح باشد. این شامل JSON معتبر، وجود همه کلیدها، عدم وجود مقادیر خالی، شعار کمتر از شش کلمه و رنگ‌های هگزادسیمال می‌شود.
  • evalContrastRatio() : بررسی می‌کند که آیا نسبت کنتراست رنگ متن به پس‌زمینه قابل دسترسی است یا خیر.

پیاده‌سازی ارزیابی‌های مبتنی بر قانون

انتخاب روش امتیازدهی

معیارهای ارزیابی دودویی هستند. توابع ارزیابی مبتنی بر قانون شما باید یک خروجی دودویی، مانند برچسب PASS یا FAIL ، تولید کنند.

  • خروجی برنامه ThemeBuilder (شیء کامل تم) → evalDataFormat() → برچسب PASS یا FAIL . اگر قالب داده همه محدودیت‌ها را برآورده کند، PASS در غیر این صورت FAIL .
  • خروجی برنامه ThemeBuilder (شیء پالت رنگ) → evalContrastRatio() → برچسب PASS یا FAIL . اگر نسبت بزرگتر از ۴.۵ باشد، PASS . در غیر این صورت، FAIL .

تعریف نوع ارزیابی (evals)

معیار PASS یا FAIL یک مقدار بولی است، اما می‌توانید برای خوانایی بیشتر، آن را به صورت یک برچسب رشته‌ای (دسته‌بندی) پیاده‌سازی کنید.

برای ساده نگه داشتن همه چیز، می‌توانید از همان نوع TypeScript برای ارزیابی‌های مبتنی بر قانون و ارزیابی‌های قاضی LLM که بعداً پیاده‌سازی خواهید کرد، استفاده کنید. یک نوع EvalResult ایجاد کنید که یک دسته EvalLabel دودویی و یک فیلد rationale برای مدل قاضی برای توضیح رتبه‌بندی آن را در بر می‌گیرد.

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

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

پیاده‌سازی ارزیاب‌ها

Zod ابزاری عالی برای اعتبارسنجی طرحواره است، زیرا هم ساختار JSON و هم قوانین سفارشی را مدیریت می‌کند. این ابزار اعلانی است که باعث می‌شود کد اعتبارسنجی خوانا باشد. گزارش‌های خطای دقیقی را با مسیرهای مشخص و دلایل شکست‌ها تعریف کنید تا عیب‌یابی آسان‌تر شود.

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

نسبت کنتراست

منطق دامنه، مانند محاسبات نسبت کنتراست، را در توابع مطلوبیت جداگانه نگه دارید.

/*
 * 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?)." };
  }
}

به کد ارزیاب ما برای evalDataFormat() و evalContrastRatio() نگاهی بیندازید.

ارزیابی‌های مبتنی بر قانون را آزمایش کنید

ارزیابی‌های مبتنی بر قانون قطعی هستند، بنابراین می‌توانید تست‌های واحد کلاسیک را برای بررسی رفتار آنها پیاده‌سازی کنید. تست‌های خود را طوری بسازید که خروجی‌های مختلف را از طریق ارزیاب‌ها اجرا کنند و مشخص کنید که آیا برچسب PASS یا FAIL مورد انتظار شما را برمی‌گردانند یا خیر.

اگر یک مورد آزمایشی انتظار داشته باشد که ارزیاب FAIL را برگرداند و این اتفاق بیفتد، خروجی آزمون PASS خواهد بود زیرا ارزیاب طبق انتظار رفتار کرده است.

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;
 // ...
});

امتحانش کن