Xây dựng các tiêu chí đánh giá dựa trên quy tắc

Tự động hoá những việc cơ bản: sử dụng mã để phát hiện các lỗi đơn giản.

Giờ đây, khi bạn đã biết những lỗi mà bạn muốn phát hiện bằng các quy tắc đánh giá, đã đến lúc triển khai các hàm đánh giá tương ứng:

  • evalDataFormat(): Kiểm tra để đảm bảo định dạng dữ liệu chính xác. Điều này bao gồm JSON hợp lệ, tất cả các khoá đều có mặt, không có giá trị trống, phương châm có dưới 6 từ, màu thập lục phân.
  • evalContrastRatio(): Kiểm tra để đảm bảo tỷ lệ tương phản giữa văn bản và màu nền có thể truy cập.

Triển khai các quy trình đánh giá dựa trên quy tắc

Tiêu chí đánh giá là nhị phân. Các hàm đánh giá dựa trên quy tắc phải tạo ra một đầu ra nhị phân, chẳng hạn như nhãn PASS hoặc FAIL.

  • Đầu ra của ứng dụng ThemeBuilder (đối tượng giao diện đầy đủ) → evalDataFormat()PASS hoặc nhãn FAIL. PASS nếu định dạng dữ liệu đáp ứng tất cả các ràng buộc. Nếu không thì là FAIL.
  • Đầu ra của ứng dụng ThemeBuilder (đối tượng bảng màu) → evalContrastRatio()PASS hoặc nhãn FAIL . PASS nếu tỷ lệ lớn hơn 4,5. Nếu không thì là FAIL.

Xác định một loại evals

Chỉ số PASS hoặc FAIL là một giá trị boolean, nhưng bạn có thể chọn triển khai chỉ số này dưới dạng nhãn chuỗi (danh mục) để dễ đọc.

Để mọi thứ diễn ra suôn sẻ, bạn có thể sử dụng cùng một loại TypeScript cho cả các quy tắc dựa trên quy tắc và các quy tắc đánh giá LLM mà bạn sẽ triển khai sau này. Tạo một loại EvalResult bao bọc danh mục EvalLabel nhị phân và một trường rationale để mô hình đánh giá giải thích điểm xếp hạng của mô hình.

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

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

Triển khai các nhân viên đánh giá

Zod là một công cụ tuyệt vời để xác thực giản đồ, vì công cụ này xử lý cả cấu trúc JSON và các quy tắc tuỳ chỉnh. Đây là một ngôn ngữ khai báo, giúp mã xác thực dễ đọc. Xác định báo cáo lỗi chi tiết với các đường dẫn và lý do cụ thể dẫn đến lỗi để dễ dàng khắc phục sự cố hơn.

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

Tỷ lệ tương phản

Giữ logic miền, chẳng hạn như các phép tính tỷ lệ tương phản, trong các hàm tiện ích riêng biệt.

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

Hãy xem mã người đánh giá của chúng tôi cho evalDataFormat()evalContrastRatio().

Kiểm thử các quy trình đánh giá dựa trên quy tắc

Các hoạt động đánh giá dựa trên quy tắc là tất định, vì vậy, bạn có thể triển khai các kiểm thử đơn vị cổ điển để kiểm tra hành vi của chúng. Tạo các kiểm thử để chạy nhiều đầu ra thông qua các trình đánh giá và xác nhận xem chúng có trả về nhãn PASS hoặc FAIL mà bạn mong đợi hay không.

Nếu một trường hợp kiểm thử dự kiến trình đánh giá sẽ trả về một FAIL và trình đánh giá thực hiện điều đó, thì kiểm thử sẽ xuất ra một PASS vì trình đánh giá hoạt động như dự kiến.

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

Dùng thử