Genkit एवैल्यूएटर लिखना

Firebase Genkit को कस्टम मूल्यांकन के लिए इस्तेमाल किया जा सकता है. इसके लिए, जज के तौर पर एलएलएम का इस्तेमाल करें या प्रोग्राम के हिसाब से (हेरिस्टिक) मूल्यांकन करें.

एवैल्यूएटर की परिभाषा

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

ai.defineEvaluator तरीका, दोनों तरीकों के साथ काम करता है. इसका इस्तेमाल, Genkit में एवैल्यूएटर ऐक्शन तय करने के लिए किया जाता है. इस दस्तावेज़ में, हेयुरिस्टिक और एलएलएम पर आधारित आकलन के लिए, इस तरीके का इस्तेमाल करने के कुछ उदाहरण दिए गए हैं.

एलएलएम पर आधारित एवैल्यूएटर

एलएलएम पर आधारित एवैल्यूएटर, एलएलएम का इस्तेमाल करके जनरेटिव एआई की सुविधा के input, context, और output का आकलन करता है.

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

  • प्रॉम्प्ट
  • स्कोरिंग फ़ंक्शन
  • एवैल्यूएटर की कार्रवाई

प्रॉम्प्ट तय करना

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

Genkit की definePrompt सुविधा, इनपुट और आउटपुट की पुष्टि करने वाले प्रॉम्प्ट को आसानी से तय करने का तरीका उपलब्ध कराती है. नीचे दिया गया कोड, 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,
      }
    },
    `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, z } from 'genkit';
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 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 { Genkit, z } from 'genkit';
import { BaseEvalDataPoint, 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(judge, datapoint, judgeConfig);
      return {
        testCaseId: datapoint.testCaseId,
        evaluation: score,
      };
    }
  );
}

defineEvaluator तरीका, defineFlow और defineRetriever जैसे अन्य Genkit कन्स्ट्रक्टर से मिलता-जुलता है. इस तरीके के लिए, EvaluatorFn को कॉलबैक के तौर पर उपलब्ध कराना ज़रूरी है. EvaluatorFn का तरीका, BaseEvalDataPoint ऑब्जेक्ट को स्वीकार करता है. यह ऑब्जेक्ट, आकलन के दायरे में आने वाले डेटासेट में मौजूद किसी एक एंट्री से जुड़ा होता है. साथ ही, इसमें कस्टम-विकल्प पैरामीटर भी शामिल होता है. हालांकि, यह पैरामीटर देना ज़रूरी नहीं है. यह फ़ंक्शन डेटापॉइंट को प्रोसेस करता है और EvalResponse ऑब्जेक्ट दिखाता है.

BaseEvalDataPoint और EvalResponse के लिए Zod स्कीमा इस तरह के हैं.

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 ऑब्जेक्ट की मदद से, उपयोगकर्ता एलिमेंट का नाम, उपयोगकर्ता के लिए दिखने वाला नाम, और एलिमेंट की परिभाषा दे सकता है. डिसप्ले नेम और परिभाषा, डेवलपर यूज़र इंटरफ़ेस (यूआई) में, आकलन के नतीजों के साथ दिखती हैं. इसमें एक isBilled फ़ील्ड भी होता है, जो यह बताता है कि इस एवैल्यूएटर की वजह से बिलिंग हो सकती है या नहीं. उदाहरण के लिए, यह बिलिंग वाले एलएलएम या एपीआई का इस्तेमाल करता है. अगर किसी मूल्यांकन करने वाले व्यक्ति को बिल भेजा जाता है, तो यूज़र इंटरफ़ेस (यूआई), उपयोगकर्ता को CLI में पुष्टि करने के लिए कहता है. इसके बाद ही, उसे मूल्यांकन करने की अनुमति दी जाती है. ऐसा करने से, अनचाहे खर्चों से बचा जा सकता है.

ह्यूरिस्टिक्स (तय नियम) के आधार पर काम करने वाले एलिमेंट

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

Genkit में, हेरिस्टिक एवैल्यूएटर दो कॉम्पोनेंट से बने होते हैं:

  • स्कोरिंग फ़ंक्शन
  • एवैल्यूएटर की कार्रवाई

स्कोरिंग फ़ंक्शन तय करना

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

import { EvalResponses } from 'genkit';
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 को शुरू करने के समय प्लग इन को इंस्टॉल करके, उन्हें फ़्रेमवर्क के साथ रजिस्टर किया जाता है. नया प्लग इन तय करने के लिए, प्लग इन कॉन्टेक्स्ट में सभी Genkit कार्रवाइयों को इंस्टैंशिएट करने के लिए, genkitPlugin हेल्पर विधि का इस्तेमाल करें.

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

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 को कॉन्फ़िगर करना

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

Gemini की मदद से आकलन करने के लिए, सुरक्षा सेटिंग बंद करें, ताकि जांच करने वाला व्यक्ति संभावित रूप से नुकसान पहुंचाने वाले कॉन्टेंट को स्वीकार कर सके, उसका पता लगा सके, और उसे स्कोर दे सके.

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

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

कस्टम एवैल्यूएटर का इस्तेमाल करना

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

  • 1. नीचे दिए गए कॉन्टेंट के साथ, `deliciousness_dataset.json` नाम की एक 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 के यूज़र इंटरफ़ेस (यूआई) में अपने नतीजे देखने के लिए, `localhost:4000/evaluate` पर जाएं.

ध्यान रखें कि स्टैंडर्ड डेटासेट या तरीकों के साथ कस्टम एवैल्यूएटर को बेंचमार्क करने पर, उन पर भरोसा बढ़ता है. अपने मूल्यांकनकर्ताओं की परफ़ॉर्मेंस को बेहतर बनाने के लिए, ऐसे मानदंडों के नतीजों को बार-बार दोहराएं. ऐसा तब तक करें, जब तक कि वह क्वालिटी के टारगेट किए गए लेवल तक न पहुंच जाए.