編寫 Genkit Evaluator 外掛程式

可以擴充 Firebase Genkit 來支援對測試案例輸出內容的自訂評估作業,方法包括將大型語言模型當做法官使用,或僅以程式輔助方式進行。

評估工具定義

評估工具會評估 LLM 提供及生成的內容,自動化評估 (測試) 主要有兩種方法:啟發性評估和以 LLM 為基礎的評估。在經驗法則中,您定義了確定性的功能,就像傳統軟體開發一樣。以 LLM 為基礎的評估作業會將內容傳回至大型語言模型,要求 LLM 根據提示中設定的條件為輸出內容評分。

大型語言模型評估工具

大型語言模型評估工具採用大型語言模型,評估生成式 AI 功能的輸入內容、背景資訊或輸出內容。

Genkit 中的 LLM 評估工具由 3 個元件組成:

  • 1 則提示
  • 評分函式
  • 評估者動作

定義提示

在這個示例中,LLM 會要求 LLM 判斷輸出內容是否令人放心。首先,為 LLM 提供背景資訊,然後說明你想完成的工作,最後再提供幾個範例做為回應依據。

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 為必填欄位,以及 outputcontext 的選填欄位。評估人員須負責確認評估作業所需的所有欄位是否都已顯示。

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

啟發式評估工具

經驗評估工具可以是任何函式,用於評估生成式 AI 功能的輸入內容、背景資訊或輸出內容。

Genkit 的啟發式評估工具由 2 個部分組成:

  • 評分函式
  • 評估者動作

定義評分函式

如同 LLM 型評估器,請定義評分函式。在此情況下,評分函式不需要瞭解法官 LLM 或其設定。

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

如果這個新外掛程式將 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 進行設定。

在本例中,我們有兩名評估人員 DELICIOUSNESSUS_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
      ],
    }),
  ],
  ...
});

測試

針對評估生成式 AI 功能輸出結果品質的問題,同樣適用於評估 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