نوشتن یک ارزیاب Genkit

می‌توانید Firebase Genkit را برای پشتیبانی از ارزیابی سفارشی، با استفاده از LLM به عنوان داور یا با ارزیابی برنامه‌ای (ابتکاری) گسترش دهید.

تعریف ارزیاب

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

متد ai.defineEvaluator که برای تعریف یک عمل ارزیابی کننده در Genkit استفاده می کنید، از هر دو روش پشتیبانی می کند. این سند چند نمونه از نحوه استفاده از این روش را برای ارزیابی‌های اکتشافی و مبتنی بر LLM بررسی می‌کند.

ارزیابان مبتنی بر LLM

یک ارزیاب مبتنی بر LLM از یک LLM برای ارزیابی input ، context و output ویژگی هوش مصنوعی مولد شما استفاده می کند.

ارزیاب های مبتنی بر LLM در Genkit از 3 جزء تشکیل شده اند:

  • یک اعلان
  • یک تابع امتیازدهی
  • یک اقدام ارزیاب

اعلان را تعریف کنید

برای این مثال، ارزیاب از یک LLM برای تعیین اینکه آیا یک غذا ( output ) خوشمزه است یا خیر، استفاده می کند. ابتدا، زمینه ای را برای LLM فراهم کنید، سپس آنچه را که می خواهید انجام دهد، توصیف کنید، و در نهایت، چند مثال برای پاسخ دادن به آن ارائه دهید.

ابزار definePrompt Genkit یک راه آسان برای تعریف دستورات با اعتبارسنجی ورودی و خروجی ارائه می دهد. کد زیر نمونه ای از راه اندازی یک درخواست ارزیابی با definePrompt است.

import { z } from "genkit";

const DELICIOUSNESS_VALUES = ['yes', 'no', 'maybe'] as const;

const DeliciousnessDetectionResponseSchema = z.object({
  reason: z.string(),
  verdict: z.enum(DELICIOUSNESS_VALUES),
});

function getDeliciousnessPrompt(ai: Genkit) {
  return  ai.definePrompt({
      name: 'deliciousnessPrompt',
      input: {
        schema: z.object({
          responseToTest: z.string(),
        }),
      },
      output: {
        schema: DeliciousnessDetectionResponseSchema,
      }
      prompt: `You are a food critic. Assess whether the provided output sounds delicious, giving only "yes" (delicious), "no" (not delicious), or "maybe" (undecided) as the verdict.

      Examples:
      Output: Chicken parm sandwich
      Response: { "reason": "A classic and beloved dish.", "verdict": "yes" }

      Output: Boston Logan Airport tarmac
      Response: { "reason": "Not edible.", "verdict": "no" }

      Output: A juicy piece of gossip
      Response: { "reason": "Metaphorically 'tasty' but not food.", "verdict": "maybe" }

      New Output: {{ responseToTest }}
      Response:
      `
  });
}

تابع امتیاز دهی را تعریف کنید

تابعی را تعریف کنید که مثالی می‌آورد که شامل output مورد نیاز فرمان می‌شود و نتیجه را نمره می‌دهد. موارد تست Genkit شامل input به عنوان یک فیلد ضروری، با output و context به عنوان فیلدهای اختیاری است. این مسئولیت ارزیابی کننده است که تأیید کند که تمام فیلدهای مورد نیاز برای ارزیابی وجود دارد.

import { ModelArgument } from 'genkit';
import { BaseEvalDataPoint, Score } from 'genkit/evaluator';

/**
 * Score an individual test case for delciousness.
 */
export async function deliciousnessScore<
  CustomModelOptions extends z.ZodTypeAny,
>(
  ai: Genkit,
  judgeLlm: ModelArgument<CustomModelOptions>,
  dataPoint: BaseEvalDataPoint,
  judgeConfig?: CustomModelOptions
): Promise<Score> {
  const d = dataPoint;
  // Validate the input has required fields
  if (!d.output) {
    throw new Error('Output is required for Deliciousness detection');
  }

  // Hydrate the prompt and generate an evaluation result
  const deliciousnessPrompt = getDeliciousnessPrompt(ai);
  const response = await deliciousnessPrompt(
    {
      responseToTest: d.output as string,
    },
    {
      model: judgeLlm,
      config: judgeConfig,
    }
  );

  // Parse the output
  const parsedResponse = response.output;
  if (!parsedResponse) {
    throw new Error(`Unable to parse evaluator response: ${response.text}`);
  }

  // Return a scored response
  return {
    score: parsedResponse.verdict,
    details: { reasoning: parsedResponse.reason },
  };
}

عمل ارزیاب را تعریف کنید

مرحله آخر نوشتن تابعی است که EvaluatorAction را تعریف کند.

import { EvaluatorAction } from 'genkit/evaluator';

/**
 * Create the Deliciousness evaluator action.
 */
export function createDeliciousnessEvaluator<
  ModelCustomOptions extends z.ZodTypeAny,
>(
  ai: Genkit,
  judge: ModelArgument<ModelCustomOptions>,
  judgeConfig?: z.infer<ModelCustomOptions>
): EvaluatorAction {
  return ai.defineEvaluator(
    {
      name: `myCustomEvals/deliciousnessEvaluator`,
      displayName: 'Deliciousness',
      definition: 'Determines if output is considered delicous.',
      isBilled: true,
    },
    async (datapoint: BaseEvalDataPoint) => {
      const score = await deliciousnessScore(ai, judge, datapoint, judgeConfig);
      return {
        testCaseId: datapoint.testCaseId,
        evaluation: score,
      };
    }
  );
}

متد defineEvaluator مشابه سایر سازنده های Genkit مانند defineFlow و defineRetriever است. این روش نیاز به یک EvaluatorFn دارد که به عنوان یک تماس پاسخ داده شود. متد EvaluatorFn یک شی BaseEvalDataPoint را می پذیرد، که مربوط به یک ورودی واحد در مجموعه داده تحت ارزیابی، همراه با یک پارامتر اختیاری گزینه های سفارشی در صورت مشخص شدن است. تابع نقطه داده را پردازش می کند و یک شی EvalResponse را برمی گرداند.

طرحواره های Zod برای BaseEvalDataPoint و EvalResponse به شرح زیر است.

BaseEvalDataPoint
export const BaseEvalDataPoint = z.object({
  testCaseId: z.string(),
  input: z.unknown(),
  output: z.unknown().optional(),
  context: z.array(z.unknown()).optional(),
  reference: z.unknown().optional(),
  testCaseId: z.string().optional(),
  traceIds: z.array(z.string()).optional(),
});

export const EvalResponse = z.object({
  sampleIndex: z.number().optional(),
  testCaseId: z.string(),
  traceId: z.string().optional(),
  spanId: z.string().optional(),
  evaluation: z.union([ScoreSchema, z.array(ScoreSchema)]),
});
ScoreSchema
const ScoreSchema = z.object({
  id: z.string().describe('Optional ID to differentiate multiple scores').optional(),
  score: z.union([z.number(), z.string(), z.boolean()]).optional(),
  error: z.string().optional(),
  details: z
    .object({
      reasoning: z.string().optional(),
    })
    .passthrough()
    .optional(),
});

شی defineEvaluator به کاربر اجازه می دهد یک نام، یک نام نمایشی قابل خواندن توسط کاربر، و یک تعریف برای ارزیابی کننده ارائه دهد. نام نمایشی و تعریف به همراه نتایج ارزیابی در Dev UI نمایش داده می شود. همچنین دارای یک فیلد isBilled اختیاری است که مشخص می‌کند آیا این ارزیاب می‌تواند منجر به صدور صورت‌حساب شود (به عنوان مثال، از یک LLM یا API صورتحساب استفاده می‌کند). اگر یک ارزیاب صورت‌حساب دریافت می‌کند، UI از کاربر می‌خواهد تا قبل از اینکه به او اجازه انجام ارزیابی را بدهد، در CLI تأیید کند. این مرحله به محافظت در برابر هزینه های ناخواسته کمک می کند.

ارزیابان اکتشافی

ارزیاب اکتشافی می تواند هر تابعی باشد که برای ارزیابی input ، context یا output ویژگی هوش مصنوعی مولد شما استفاده می شود.

ارزیاب های اکتشافی در Genkit از 2 جزء تشکیل شده اند:

  • یک تابع امتیازدهی
  • یک اقدام ارزیاب

تابع امتیاز دهی را تعریف کنید

همانند ارزیاب مبتنی بر LLM، تابع امتیازدهی را تعریف کنید. در این مورد، تابع امتیازدهی به یک داور LLM نیاز ندارد.

import { BaseEvalDataPoint, Score } from 'genkit/evaluator';

const US_PHONE_REGEX =
  /[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4}/i;

/**
 * Scores whether a datapoint output contains a US Phone number.
 */
export async function usPhoneRegexScore(
  dataPoint: BaseEvalDataPoint
): Promise<Score> {
  const d = dataPoint;
  if (!d.output || typeof d.output !== 'string') {
    throw new Error('String output is required for regex matching');
  }
  const matches = US_PHONE_REGEX.test(d.output as string);
  const reasoning = matches
    ? `Output matched US_PHONE_REGEX`
    : `Output did not match US_PHONE_REGEX`;
  return {
    score: matches,
    details: { reasoning },
  };
}

عمل ارزیاب را تعریف کنید

import { Genkit } from 'genkit';
import { BaseEvalDataPoint, EvaluatorAction } from 'genkit/evaluator';

/**
 * Configures a regex evaluator to match a US phone number.
 */
export function createUSPhoneRegexEvaluator(ai: Genkit): EvaluatorAction {
  return ai.defineEvaluator(
    {
      name: `myCustomEvals/usPhoneRegexEvaluator`,
      displayName: "Regex Match for US PHONE NUMBER",
      definition: "Uses Regex to check if output matches a US phone number",
      isBilled: false,
    },
    async (datapoint: BaseEvalDataPoint) => {
      const score = await usPhoneRegexScore(datapoint);
      return {
        testCaseId: datapoint.testCaseId,
        evaluation: score,
      };
    }
  );
}

کنار هم گذاشتن

تعریف پلاگین

پلاگین ها با نصب آنها در زمان اولیه سازی Genkit با فریمورک ثبت می شوند. برای تعریف یک افزونه جدید، از روش کمکی genkitPlugin استفاده کنید تا تمام اقدامات Genkit را در زمینه افزونه نمونه برداری کنید.

این نمونه کد دو ارزیاب را نشان می‌دهد: ارزیابی‌کننده خوشمزه بودن مبتنی بر LLM، و ارزیاب شماره تلفن ایالات متحده مبتنی بر regex. نمونه سازی این ارزیاب ها در زمینه افزونه، آنها را در افزونه ثبت می کند.

import { GenkitPlugin, genkitPlugin } from 'genkit/plugin';

export function myCustomEvals<
  ModelCustomOptions extends z.ZodTypeAny
>(options: {
  judge: ModelArgument<ModelCustomOptions>;
  judgeConfig?: ModelCustomOptions;
}): GenkitPlugin {
  // Define the new plugin
  return genkitPlugin("myCustomEvals", async (ai: Genkit) => {
    const { judge, judgeConfig } = options;

    // The plugin instatiates our custom evaluators within the context
    // of the `ai` object, making them available
    // throughout our Genkit application.
    createDeliciousnessEvaluator(ai, judge, judgeConfig);
    createUSPhoneRegexEvaluator(ai);
  });
}
export default myCustomEvals;

Genkit را پیکربندی کنید

افزونه myCustomEvals را به پیکربندی Genkit خود اضافه کنید.

برای ارزیابی با Gemini، تنظیمات ایمنی را غیرفعال کنید تا ارزیاب بتواند محتوای بالقوه مضر را بپذیرد، شناسایی کند و امتیاز دهد.

import { gemini15Pro } from '@genkit-ai/googleai';

const ai = genkit({
  plugins: [
    vertexAI(),
    ...
    myCustomEvals({
      judge: gemini15Pro,
    }),
  ],
  ...
});

با استفاده از ارزیاب های سفارشی خود

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

  • 1. یک فایل json «deliciousness_dataset.json» با محتوای زیر ایجاد کنید:
[
  {
    "testCaseId": "delicous_mango",
    "input": "What is a super delicious fruit",
    "output": "A perfectly ripe mango – sweet, juicy, and with a hint of tropical sunshine."
  },
  {
    "testCaseId": "disgusting_soggy_cereal",
    "input": "What is something that is tasty when fresh but less tasty after some time?",
    "output": "Stale, flavorless cereal that's been sitting in the box too long."
  }
]
  • 2. از Genkit CLI برای اجرای ارزیاب در برابر این موارد آزمایشی استفاده کنید.
# Start your genkit runtime
genkit start -- <command to start your app>
genkit eval:run deliciousness_dataset.json --evaluators=myCustomEvals/deliciousnessEvaluator
  • 3. برای مشاهده نتایج خود در Genkit UI به «localhost:4000/evaluate» بروید.

توجه به این نکته مهم است که اعتماد به ارزیاب‌های سفارشی با محک زدن آنها با مجموعه داده‌ها یا رویکردهای استاندارد افزایش می‌یابد. نتایج چنین معیارهایی را تکرار کنید تا عملکرد ارزیابان خود را بهبود بخشید تا زمانی که به سطح کیفی مورد نظر برسد.