Genkit Evaluator प्लगिन लिखना

Firebase Genkit को, टेस्ट केस आउटपुट का अपने हिसाब से आकलन करने के लिए, जज के तौर पर एलएलएम का इस्तेमाल करके या पूरी तरह से प्रोग्रैम्ड तरीके से किया जा सकता है.

इवैलुएटर की परिभाषा

मूल्यांकन करने वाले ऐसे फ़ंक्शन होते हैं जो किसी एलएलएम को दिए गए और उसके ज़रिए जनरेट किए गए कॉन्टेंट का आकलन करते हैं. अपने-आप होने वाले आकलन (टेस्टिंग) के लिए, दो मुख्य तरीके हैं: अनुभव के आधार पर आकलन और एलएलएम पर आधारित आकलन. अनुभव के नज़रिए से, आप पारंपरिक सॉफ़्टवेयर डेवलपमेंट की तरह ही डेटरमिनिस्टिक फ़ंक्शन तय करते हैं. एलएलएम पर आधारित आकलन के दौरान, कॉन्टेंट को एलएलएम पर फिर से अपलोड किया जाता है. इसके बाद, एलएलएम को सवाल में तय की गई शर्तों के हिसाब से, आउटपुट को स्कोर देने के लिए कहा जाता है.

एलएलएम आधारित इवैलुएटर

एलएलएम पर आधारित आकलन करने वाला, आपकी जनरेटिव एआई की सुविधा के इनपुट, कॉन्टेक्स्ट या आउटपुट का आकलन करने के लिए, एलएलएम का इस्तेमाल करता है.

Genkit में एलएलएम पर आधारित आकलन करने वाले लोगों के तीन कॉम्पोनेंट होते हैं:

  • प्रॉम्प्ट
  • स्कोरिंग फ़ंक्शन
  • समीक्षक की कार्रवाई

प्रॉम्प्ट तय करें

इस उदाहरण के लिए, प्रॉम्प्ट में एलएलएम से पूछा जाएगा कि आउटपुट कितना स्वादिष्ट है. सबसे पहले, एलएलएम के बारे में जानकारी दें. इसके बाद, बताएं कि आपको उससे क्या करना है. आखिर में, उसके जवाब को आधार बनाने के लिए कुछ उदाहरण दें.

Genkit, dotprompt के साथ काम करता है. यह इनपुट/आउटपुट स्कीमा की पुष्टि करने जैसी सुविधाओं के साथ, प्रॉम्प्ट को तय करने और उन्हें मैनेज करने का आसान तरीका है. यहां बताया गया है कि इवै��ुएशन का प्रॉम्प्ट तय करने के लिए, dotprompt का इस्तेमाल कैसे किया जा सकता है.

import { defineDotprompt } from '@genkit-ai/dotprompt';

// Define the expected output values
const DELICIOUSNESS_VALUES = ['yes', 'no', 'maybe'] as const;

// Define the response schema expected from the LLM
const DeliciousnessDetectionResponseSchema = z.object({
  reason: z.string(),
  verdict: z.enum(DELICIOUSNESS_VALUES),
});
type DeliciousnessDetectionResponse = z.infer<
  typeof DeliciousnessDetectionResponseSchema
>;

const DELICIOUSNESS_PROMPT = defineDotprompt(
  {
    input: {
      schema: z.object({
        output: z.string(),
      }),
    },
    output: {
      schema: DeliciousnessDetectionResponseSchema,
    },
  },
  `You are a food critic with a wide range in taste. Given the output, decide if it sounds delicious and provide your reasoning. Use only "yes" (if delicous), "no" (if not delicious), "maybe" (if you can't decide) as the verdict.

Here are a few examples:

Output:
Chicken parm sandwich
Response:
{ "reason": "This is a classic sandwich enjoyed by many - totally delicious", "verdict":"yes"}

Output:
Boston logan international airport tarmac
Response:
{ "reason": "This is not edible and definitely not delicious.", "verdict":"no"}

Output:
A juicy piece of gossip
Response:
{ "reason": "Gossip is sometimes metaphorically referred to as tasty.", "verdict":"maybe"}

Here is a new submission to assess:

Output:
{{output}}
Response:
`
);

स्कोरिंग फ़ंक्शन को परिभाषित करना

अब, वह फ़ंक्शन तय करें जो एक उदाहरण लेगा, जिसमें प्रॉम्प्ट के मुताबिक output शामिल है और नतीजे को स्कोर करें. Genkit टेस्ट केस में input को एक ज़रूरी फ़ील्ड के तौर पर शामिल करना ज़रूरी है. साथ ही, output और context के लिए वैकल्पिक फ़ील्ड भी शामिल किए गए हैं. यह जांच करने वाले की ज़िम्मेदारी है कि आकलन के लिए ज़रूरी सभी फ़ील्ड मौजूद हों.

/**
 * Score an individual test case for delciousness.
 */
export async function deliciousnessScore<
  CustomModelOptions extends z.ZodTypeAny,
>(
  judgeLlm: ModelArgument<CustomModelOptions>,
  dataPoint: BaseDataPoint,
  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 },
  };
}

आकलन करने वाले व्यक्ति की कार्रवाई तय करें

आखिरी चरण में, एक ऐसा फ़ंक्शन लिखना चाहिए जो आकलन करने वाले की कार्रवाई के बारे में बताता हो.

/**
 * 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: BaseDataPoint) => {
      const score = await deliciousnessScore(judge, datapoint, judgeConfig);
      return {
        testCaseId: datapoint.testCaseId,
        evaluation: score,
      };
    }
  );
}

अनुमान का आकलन करने वाले

अनुमान का आकलन करने वाला टूल, जनरेटिव एआई की सुविधा के इनपुट, कॉन्टेक्स्ट या आउटपुट का आकलन करने वाला कोई भी फ़ंक्शन हो सकता है.

Genkit में अनुमानित आकलन करने वाले लोगों के दो कॉम्पोनेंट होते हैं:

  • स्कोरिंग फ़ंक्शन
  • समीक्षक की कार्रवाई

स्कोरिंग फ़ंक्शन को परिभाषित करना

एलएलएम पर आधारित आकलन करने वाले की तरह ही, स्कोरिंग फ़ंक्शन तय करें. ऐसे मामले में, स्कोरिंग फ़ंक्शन को जज एलएलएम या उसके कॉन्फ़िगरेशन के बारे में जानने की ज़रूरत नहीं होती.

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: BaseDataPoint
): 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 },
  };
}

आकलन करने वाले व्यक्ति की कार्रवाई तय करें

/**
 * 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: BaseDataPoint) => {
        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>;
}

अगर इस नए प्लगिन में जज के तौर पर एलएलएम का इस्तेमाल किया जाता है और प्लगिन के साथ यह तय किया जा सकता है कि किस एलएलएम का इस्तेमाल करना है, तो 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>(
  params: PluginOptions<ModelCustomOptions>
): PluginProvider {
  // Define the new plugin
  const plugin = genkitPlugin(
    'myAwesomeEval',
    async (params: PluginOptions<ModelCustomOptions>) => {
      const { judge, judgeConfig, metrics } = params;
      const evaluators: EvaluatorAction[] = metrics.map((metric) => {
        // We'll create these functions in the next step
        switch (metric) {
          case DELICIOUSNESS:
            // This evaluator requires an LLM as judge
            return createDeliciousnessEvaluator(judge, judgeConfig);
          case US_PHONE_REGEX_MATCH:
            // This evaluator does not require an LLM
            return createUSPhoneRegexEvaluator();
        }
      });
      return { evaluators };
    }
  );

  // Create the plugin with the passed params
  return plugin(params);
}
export default myAwesomeEval;

Genkit कॉन्फ़िगर करें

अपने Genkit कॉन्फ़िगरेशन में नया तय किया गया प्लगिन जोड़ें.

Gemini की मदद से इवैलुएशन करने के लिए सुरक्षा सेटिंग बंद करें, ताकि समीक्षक नुकसान पहुंचाने वाले कॉन्टेंट को स्वीकार कर सके, उसका पता लगा सके, और उसे स्कोर कर सके.

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

export default configureGenkit({
  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
      ],
    }),
  ],
  ...
});

टेस्ट करना

जनरेटिव एआई की सुविधा के आउटपुट की क्वालिटी का आकलन करने में वही समस्याएं आती हैं जो एलएलएम पर आधारित आकलन करने वाले टूल की क्षमता का आकलन करने पर लागू होती हैं.

यह जानने के लिए कि कस्टम समीक्षक उम्मीद के मुताबिक परफ़ॉर्म करता है या नहीं, टेस्ट केस का एक ऐसा सेट बनाएं जिसमें सही और गलत जवाब साफ़ तौर पर मौजूद हो.

स्वादिष्ट खाने के उदाहरण के तौर पर, यह एक 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."
  }
]

ये उदाहरण मैन्युअल तरीके से जनरेट किए जा सकते हैं. इसके अलावा, किसी एलएलएम से टेस्ट केस का सेट तैयार करने के लिए कहा जा सकता है, ताकि उसे चुना जा सके. कई बेंचमार्क डेटासेट उपलब्ध हैं और उ��का भी इस्तेमाल किया जा सकता है.

इसके बाद, इन टेस्ट केस का आकलन करने के लिए Genkit सीएलआई का इस्तेमाल करें.

genkit eval:run deliciousness_dataset.json

Genkit यूज़र इंटरफ़ेस (यूआई) में अपने नतीजे देखें.

genkit start

localhost:4000/evaluate पर जाएं.