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

Firebase Genkit را می‌توان برای پشتیبانی از ارزیابی سفارشی خروجی مورد آزمایش، یا با استفاده از یک LLM به عنوان داور یا صرفاً برنامه‌ریزی، گسترش داد.

تعریف ارزیاب

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

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

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

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

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

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

برای این مثال، درخواست از LLM می‌خواهد تا میزان خوشمزه بودن خروجی را قضاوت کند. ابتدا، زمینه ای را برای LLM فراهم کنید، سپس آنچه را که می خواهید انجام دهد، توصیف کنید، و در نهایت، چند مثال برای پاسخ دادن به آن ارائه دهید.

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

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

const DeliciousnessDetectionResponseSchema = z.object({
  reason: z.string(),
  verdict: z.enum(DELICIOUSNESS_VALUES),
});
type DeliciousnessDetectionResponse = z.infer<typeof DeliciousnessDetectionResponseSchema>;

const DELICIOUSNESS_PROMPT = ai.definePrompt(
  {
    name: 'deliciousnessPrompt',
    inputSchema: z.object({
      output: z.string(),
    }),
    outputSchema: DeliciousnessDetectionResponseSchema,
  },
  `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:
  {{output}}
  Response:
  `
);

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

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

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

/**
 * Score an individual test case for delciousness.
 */
export async function deliciousnessScore<
  CustomModelOptions extends z.ZodTypeAny,
>(
  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
  const finalPrompt = DELICIOUSNESS_PROMPT.renderText({
    output: d.output as string,
  });

  // Call the LLM to generate an evaluation result
  const response = await generate({
    model: judgeLlm,
    prompt: finalPrompt,
    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 },
  };
}

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

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

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

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

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

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

ارزیاب های اکتشافی در 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 an individual datapoint matches a US Phone Regex.
 */
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 regex ${regex.source}`
    : `Output did not match regex ${regex.source}`;
  return {
    score: matches,
    details: { reasoning },
  };
}

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

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

/**
 * Configures a regex evaluator to match a US phone number.
 */
export function createUSPhoneRegexEvaluator(
  metrics: RegexMetric[]
): EvaluatorAction[] {
  return metrics.map((metric) => {
    const regexMetric = metric as RegexMetric;
    return defineEvaluator(
      {
        name: `myAwesomeEval/${metric.name.toLocaleLowerCase()}`,
        displayName: 'Regex Match',
        definition:
          'Runs the output against a regex and responds with 1 if a match is found and 0 otherwise.',
        isBilled: false,
      },
      async (datapoint: BaseEvalDataPoint) => {
        const score = await regexMatchScore(datapoint, regexMetric.regex);
        return fillScores(datapoint, score);
      }
    );
  });
}

پیکربندی

گزینه های پلاگین

PluginOptions را که افزونه ارزیابی سفارشی از آن استفاده خواهد کرد، تعریف کنید. این شی الزامات سختگیرانه ای ندارد و وابسته به انواع ارزیاب هایی است که تعریف شده اند.

حداقل باید تعریفی از معیارهای ثبت نام داشته باشد.

export enum MyAwesomeMetric {
  WORD_COUNT = 'WORD_COUNT',
  US_PHONE_REGEX_MATCH = 'US_PHONE_REGEX_MATCH',
}

export interface PluginOptions {
  metrics?: Array<MyAwesomeMetric>;
}

اگر این افزونه جدید از یک LLM به عنوان داور استفاده می کند و افزونه از تعویض LLM برای استفاده پشتیبانی می کند، پارامترهای اضافی را در شی PluginOptions تعریف کنید.

export enum MyAwesomeMetric {
  DELICIOUSNESS = 'DELICIOUSNESS',
  US_PHONE_REGEX_MATCH = 'US_PHONE_REGEX_MATCH',
}

export interface PluginOptions<ModelCustomOptions extends z.ZodTypeAny> {
  judge: ModelReference<ModelCustomOptions>;
  judgeConfig?: z.infer<ModelCustomOptions>;
  metrics?: Array<MyAwesomeMetric>;
}

تعریف پلاگین

پلاگین ها با فریم ورک از طریق فایل genkit.config.ts در یک پروژه ثبت می شوند. برای اینکه بتوانید یک پلاگین جدید را پیکربندی کنید، تابعی را تعریف کنید که GenkitPlugin را تعریف کند و آن را با PluginOptions تعریف شده در بالا پیکربندی کند.

در این مورد ما دو ارزیاب DELICIOUSNESS و US_PHONE_REGEX_MATCH داریم. اینجا جایی است که آن ارزیاب ها با افزونه و با Firebase Genkit ثبت می شوند.

export function myAwesomeEval<ModelCustomOptions extends z.ZodTypeAny>(
  options: PluginOptions<ModelCustomOptions>
): PluginProvider {
  // Define the new plugin
  const plugin = (options?: MyPluginOptions<ModelCustomOptions>) => {
    return genkitPlugin(
    'myAwesomeEval',
    async (ai: Genkit) => {
      const { judge, judgeConfig, metrics } = options;
      const evaluators: EvaluatorAction[] = metrics.map((metric) => {
        switch (metric) {
          case DELICIOUSNESS:
            // This evaluator requires an LLM as judge
            return createDeliciousnessEvaluator(ai, judge, judgeConfig);
          case US_PHONE_REGEX_MATCH:
            // This evaluator does not require an LLM
            return createUSPhoneRegexEvaluator();
        }
      });
      return { evaluators };
    })
  }
  // Create the plugin with the passed options
  return plugin(options);
}
export default myAwesomeEval;

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

افزونه جدید تعریف شده را به پیکربندی Genkit خود اضافه کنید.

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

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

const ai = genkit({
  plugins: [
    ...
    myAwesomeEval({
      judge: gemini15Flash,
      judgeConfig: {
        safetySettings: [
          {
            category: 'HARM_CATEGORY_HATE_SPEECH',
            threshold: 'BLOCK_NONE',
          },
          {
            category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
            threshold: 'BLOCK_NONE',
          },
          {
            category: 'HARM_CATEGORY_HARASSMENT',
            threshold: 'BLOCK_NONE',
          },
          {
            category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
            threshold: 'BLOCK_NONE',
          },
        ],
      },
      metrics: [
        MyAwesomeMetric.DELICIOUSNESS,
        MyAwesomeMetric.US_PHONE_REGEX_MATCH
      ],
    }),
  ],
  ...
});

تست کردن

همان مسائلی که برای ارزیابی کیفیت خروجی یک ویژگی هوش مصنوعی مولد اعمال می شود، در ارزیابی ظرفیت قضاوت یک ارزیاب مبتنی بر LLM نیز صدق می کند.

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

به عنوان مثالی برای خوشمزه بودن، ممکن است شبیه فایل 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."
  }
]

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

سپس از Genkit CLI برای اجرای ارزیاب در برابر این موارد آزمایشی استفاده کنید.

genkit eval:run deliciousness_dataset.json

نتایج خود را در Genkit UI مشاهده کنید.

genkit start

به localhost:4000/evaluate بروید.