評価

評価は、LLM の回答を検証し、品質基準を満たしていることを確認するのに役立つテストの一種です。

Firebase Genkit は、プラグインを介してサードパーティの評価ツールをサポートしています。また、LLM を活用したアプリケーションのランタイム状態に関する分析情報を提供する強力なオブザーバビリティ機能も備えています。Genkit ツールを使用すると、中間ステップから入力、出力、情報などのデータを自動的に抽出して、LLM レスポンスをエンドツーエンドで評価し、システムの構成要素のパフォーマンスを把握できます。

評価の種類

Genkit は次の 2 種類の評価をサポートしています。

  • 推論ベースの評価: このタイプの評価は、事前に決定された入力のコレクションに対して実行され、対応する出力の品質を評価します。

    これは最も一般的な評価タイプで、ほとんどのユースケースに適しています。このアプローチでは、評価実行ごとにシステムの実際の出力をテストします。

    結果を目視で確認することで、品質評価を手動で行うことができます。または、評価指標を使用して評価を自動化することもできます。

  • 元の評価: このタイプの評価では、推論なしで入力の品質を直接評価します。このアプローチは通常、指標を使用した自動評価で使用されます。評価に必要なすべてのフィールド(例: inputcontextoutputreference)が入力データセットに存在している必要があります。これは、外部ソース(本番環境のトレースから収集されたデータなど)からのデータがあり、収集されたデータの品質を客観的に測定する場合に便利です。

    詳細については、このページの高度な使用をご覧ください。

このセクションでは、Genkit を使用して推論ベースの評価を行う方法について説明します。

クイックスタート

設定

  1. 既存の Genkit アプリを使用するか、[スタートガイド](get-started.md) に沿って新しいアプリを作成します。
  2. 次のコードを追加して、評価するシンプルな RAG アプリケーションを定義します。このガイドでは、常に同じドキュメントを返すダミー レトリーバーを使用します。
    import { genkit, z, Document } from "genkit";
    import {
      googleAI,
      gemini15Flash,
    } from "@genkit-ai/googleai";
    
    // Initialize Genkit
    export const ai = genkit ({
      plugins: [
        googleAI(),
      ]
    });
    
    // Dummy retriever that always returns the same docs
    export const dummyRetriever = ai.defineRetriever(
      {
        name: "dummyRetriever",
      },
      async (i) => {
        const facts = [
          "Dog is man's best friend", 
          "Dogs have evolved and were domesticated from wolves",
        ];
        // Just return facts as documents.
        return { documents: facts.map((t) => Document.fromText(t)) };
      }
    );
    
    // A simple question-answering flow
    export const qaFlow = ai.defineFlow({
        name: 'qaFlow',
        inputSchema: z.string(),
        outputSchema: z.string(),
      },
      async (query) => {
        const factDocs = await ai.retrieve({
          retriever: dummyRetriever,
          query,
        });
    
        const llmResponse = await ai.generate({
          model: gemini15Flash,
          prompt: `Answer this question with the given context ${query}`,
          docs: factDocs,
        });
        return llmResponse.text;
      }
    );
  3. (省略可)評価中に使用する評価指標をアプリケーションに追加します。このガイドでは、genkitEval プラグインの MALICIOUSNESS 指標を使用します。
    import { genkitEval, GenkitMetric } from "@genkit-ai/evaluator";
    import { gemini15Pro } from "@genkit-ai/googleai";
    
    export const ai = genkit ({
      plugins: [
        ...
        // Add this plugin to your Genkit initialization block
        genkitEval({
          judge: gemini15Pro,
          metrics: [GenkitMetric.MALICIOUSNESS],
        }),
      ]
    });
    注: 上記の構成では、 @genkit-ai/evaluator パッケージのインストールが必要です。
    npm install @genkit-ai/evaluator
  4. Genkit アプリケーションを起動します。
    genkit start -- 

データセットを作成する

データセットを作成して、フローの評価に使用するサンプルを定義します。

  1. http://localhost:4000 の Dev UI に移動し、[データセット] ボタンをクリックして [データセット] ページを開きます。

  2. [データセットを作成] ボタンをクリックして、データセットの作成ダイアログを開きます。

    a. 新しいデータセットに datasetId を指定します。このガイドでは myFactsQaDataset を使用します。

    b. Flow データセット タイプを選択します。

    c. 検証対象フィールドは空白のままにして、[Save] をクリックします。

  3. 新しいデータセット ページが表示され、空のデータセットが表示されます。例を追加する手順は次のとおりです。

    a. [例を追加] ボタンをクリックして、サンプル エディタパネルを開きます。

    b. input フィールドのみが必須です。input フィールドに "Who is man's best friend?" と入力し、[保存] をクリックして、サンプルをデータセットに追加します。

    c. 手順(a)と(b)をさらに数回繰り返して、例を追加します。このガイドでは、次のサンプル入力をデータセットに追加します。

    "Can I give milk to my cats?"
    "From which animals did dogs evolve?"
    

    このステップが完了すると、データセットに上記の値を含む 3 つの例が含まれます。

評価を実行して結果を確認する

フローの評価を開始するには、データセット ページの [新しい評価を実行] ボタンをクリックします。[評価] タブから新しい評価を開始することもできます。

  1. フローを確認するには、[Flow] ラジオボタンを選択します。

  2. 評価するターゲット フローとして qaFlow を選択します。

  3. 評価に使用するターゲット データセットとして myFactsQaDataset を選択します。

  4. (省略可)Genkit プラグインを使用して評価指標をインストールした場合は、このページでこれらの指標を確認できます。この評価実行で使用する指標を選択します。これは完全に任意です。このステップを省略しても、評価実行の結果は返されますが、関連する指標は返されません。

  5. 最後に、[評価を実行] をクリックして評価を開始します。テストするフローによっては、時間がかかることがあります。評価が完了すると、結果を表示するためのリンクとともに成功メッセージが表示されます。リンクをクリックして [評価の詳細] ページに移動します。

このページには、元の入力、抽出されたコンテキスト、指標(該当する場合)など、評価の詳細が表示されます。

基本コンセプト

用語

  • 評価: 評価は、システムのパフォーマンスを評価するプロセスです。Genkit では、このようなシステムは通常、フローやモデルなどの Genkit プリミティブです。評価は自動または手動(人間による評価)で行うことができます。

  • 一括推論 推論とは、フローまたはモデルで入力を実行して、対応する出力を取得する行為です。一括推論では、複数の入力に対して推論を同時に実行します。

  • 指標 評価指標は、推論のスコア付けを行う基準です。例: 精度、忠実性、悪意、出力が英語かどうかなど。

  • データセット データセットは、推論ベースの評価に使用するサンプルの集合です。通常、データセットは input フィールドとオプションの reference フィールドで構成されます。reference フィールドは評価の推論ステップには影響しませんが、評価指標にそのまま渡されます。Genkit では、デベロッパー UI からデータセットを作成できます。Genkit には、フロー データセットとモデル データセットの 2 種類のデータセットがあります。

スキーマ検証

データセットの種類に応じて、Dev UI でスキーマ検証がサポートされています。

  • フロー データセットは、Genkit アプリケーションのフローに対するデータセットの input フィールドと reference フィールドの検証をサポートしています。スキーマ検証は省略可能です。ターゲット フロー上にスキーマが指定されている場合にのみ適用されます。

  • モデル データセットには暗黙のスキーマがあり、string 入力タイプと GenerateRequest 入力タイプの両方をサポートしています。文字列検証は、シンプルなテキスト プロンプトを評価する便利な方法です。一方、GenerateRequest は、モデル パラメータ、メッセージ履歴、ツールなどの高度なユースケースを完全に制御できます。GenerateRequest の完全なスキーマについては、API リファレンス ドキュメントをご覧ください。

サポートされている評価ツール

Genkit エバリュエータ

Genkit には、RAGAS を参考にした少数のネイティブ評価ツールが用意されており、すぐに使用できます。

  • 忠実性 - 生成された回答が指定されたコンテキストに対して事実とどの程度一致しているかを測定します。
  • 回答の関連性 - 生成された回答が指定されたプロンプトにどれほど関連しているかを評価します。
  • 悪意 - 生成された出力が欺瞞、害、悪用を意図しているかどうかを測定します。

評価プラグイン

Genkit は、Vertex ラピッド評価ツールなどのプラグインを介して追加の評価ツールをサポートしています。これらの評価ツールには、VertexAI プラグインからアクセスできます。

高度な使用方法

CLI を使用した評価

Genkit CLI には、評価を実行するための豊富な API が用意されています。これは、Dev UI を使用できない環境(CI/CD ワークフローなど)で特に便利です。

Genkit CLI には、eval:floweval:extractDataeval:run の 3 つの主要な評価コマンドがあります。

eval:flow コマンド

eval:flow コマンドは、入力データセットに対して推論ベースの評価を実行します。このデータセットは、JSON ファイルとして指定することも、Genkit ランタイムの既存のデータセットを参照することもできます。

# Referencing an existing dataset
genkit eval:flow qaFlow --input myFactsQaDataset
# or, using a dataset from a file
genkit eval:flow qaFlow --input testInputs.json

ここで、testInputs.json は、input フィールドとオプションの reference フィールドを含むオブジェクトの配列にする必要があります。

[
  {
    "input": "What is the French word for Cheese?",
  },
  {
    "input": "What green vegetable looks like cauliflower?",
    "reference": "Broccoli"
  }
]

フローで認証が必要な場合は、--context 引数を使用して指定できます。

genkit eval:flow qaFlow --input testInputs.json --context '{"auth": {"email_verified": true}}'

デフォルトでは、eval:flow コマンドと eval:run コマンドは、評価に使用可能なすべての指標を使用します。構成済みのエバリュエータのサブセットで実行するには、--evaluators フラグを使用して、エバリュエータの名前をカンマ区切りで指定します。

genkit eval:flow qaFlow --input testInputs.json --evaluators=genkitEval/maliciousness,genkitEval/answer_relevancy

評価実行の結果は、localhost:4000/evaluate の Dev UI で確認できます。

eval:extractData コマンドおよび eval:run コマンド

元の評価をサポートするために、Genkit には、トレースからデータを抽出し、抽出されたデータに対して評価指標を実行するツールが用意されています。これは、評価に別のフレームワークを使用している場合や、別の環境から推論を収集してローカルで出力の品質をテストする場合などに便利です。

Genkit フローをバッチ実行し、実行に一意のラベルを追加して、評価データセットを抽出できます。元の評価データセットは、事前推論を実行せずに、評価指標の入力を収集したものです。

テスト入力に対してフローを実行します。

genkit flow:batchRun qaFlow testInputs.json --label firstRunSimple

評価データを抽出します。

genkit eval:extractData qaFlow --label firstRunSimple --output factsEvalDataset.json

エクスポートされたデータの形式は、前述のデータセット形式とは異なります。これは、このデータは推論ステップなしで評価指標で直接使用することを目的としているためです。抽出されたデータの構文は次のとおりです。

Array<{
  "testCaseId": string,
  "input": any,
  "output": any,
  "context": any[],
  "traceIds": string[],
}>;

データ抽出ツールは、取得ツールを自動的に検出し、生成されたドキュメントをコンテキスト アレイに追加します。抽出されたデータセットに対して評価指標を実行するには、eval:run コマンドを使用します。

genkit eval:run factsEvalDataset.json

デフォルトでは、eval:run は構成されたすべてのエバリュエータに対して実行されます。eval:flow と同様に、eval:run の結果はデベロッパー UI の評価ページ(localhost:4000/evaluate)に表示されます。

カスタム エクストラクタ

Genkit には、評価中に必要なフィールド(inputoutputcontext)を抽出するための妥当なデフォルト ロジックが用意されています。ただし、これらのフィールドの抽出ロジックをより細かく制御する必要がある場合があります。Genkit は、この目的でカスタム抽出ツールをサポートしています。eval:extractData コマンドと eval:flow コマンドで使用するカスタム抽出ツールを指定できます。

まず、準備として、qaFlow の例に補助ステップを導入します。

export const qaFlow = ai.defineFlow({
    name: 'qaFlow',
    inputSchema: z.string(),
    outputSchema: z.string(),
  },
  async (query) => {
    const factDocs = await ai.retrieve({
      retriever: dummyRetriever,
      query,
    });
    const factDocsModified = await ai.run('factModified', async () => {
        // Let us use only facts that are considered silly. This is a 
        // hypothetical step for demo purposes, you may perform any 
        // arbitrary task inside a step and reference it in custom 
        // extractors.
        //
        // Assume you have a method that checks if a fact is silly
        return factDocs.filter(d => isSillyFact(d.text));
    });

    const llmResponse = await ai.generate({
      model: gemini15Flash,
      prompt: `Answer this question with the given context ${query}`,
      docs: factDocsModified,
    });
    return llmResponse.text;
  }
);

次に、このフローを評価するときに factModified ステップの出力を使用するようにカスタム抽出ツールを構成します。

カスタム抽出ツールを構成する tools-config ファイルがない場合は、genkit-tools.conf.js という名前のファイルをプロジェクトのルートに追加します。

cd /path/to/your/genkit/app
touch genkit-tools.conf.js

ツールの構成ファイルに、次のコードを追加します。

module.exports = {
  evaluators: [
    {
      actionRef: '/flow/qaFlow',
      extractors: {
        context: { outputOf: 'factModified' },
      },
    },
  ],
};

この構成は、Genkit のツールのデフォルトの抽出ツールをオーバーライドします。具体的には、このフローの評価時に context と見なされるものを変更します。

評価を再度実行すると、ステップ factModified の出力としてコンテキストが入力されていることがわかります。

genkit eval:flow qaFlow --input testInputs.json

評価エクストラクタは次のように指定します。

  • evaluators フィールドには、flowName によってスコープされる EvaluatorConfig オブジェクトの配列を指定します。
  • extractors は、抽出ツールのオーバーライドを指定するオブジェクトです。extractors で現在サポートされているキーは [input, output, context] です。使用できる値の型は次のとおりです。
    • string - ステップ名を文字列で指定します。このステップの出力は、この鍵用に抽出されます。
    • { inputOf: string } または { outputOf: string } - これらのオブジェクトは、ステップの特定のチャネル(入力または出力)を表します。たとえば、{ inputOf: 'foo-step' } は、このキーのステップ foo-step の入力を抽出します。
    • (trace) => string; - より柔軟にするには、Genkit トレースを受け取って any 型の値を返す関数を指定し、この関数内に抽出ロジックを指定します。正確な TraceData スキーマについては、genkit/genkit-tools/common/src/types/trace.ts をご覧ください。

注: これらの抽出ツールで抽出されるデータは、抽出ツールに対応する型になります。たとえば、context: { outputOf: 'foo-step' } を使用していて、foo-step がオブジェクトの配列を返す場合、抽出されたコンテキストもオブジェクトの配列になります。

LLM を使用してテストデータを合成する

以下は、PDF ファイルを使用して潜在的なユーザーの質問を生成するフローのサンプルです。

import { genkit, z } from "genkit";
import { googleAI, gemini15Flash } from "@genkit-ai/googleai";
import { chunk } from "llm-chunk"; // npm i llm-chunk
import path from "path";
import { readFile } from "fs/promises";
import pdf from "pdf-parse"; // npm i pdf-parse

const ai = genkit({ plugins: [googleAI()] });

const chunkingConfig = {
  minLength: 1000, // number of minimum characters into chunk
  maxLength: 2000, // number of maximum characters into chunk
  splitter: "sentence", // paragraph | sentence
  overlap: 100, // number of overlap chracters
  delimiters: "", // regex for base split method
} as any;

async function extractText(filePath: string) {
  const pdfFile = path.resolve(filePath);
  const dataBuffer = await readFile(pdfFile);
  const data = await pdf(dataBuffer);
  return data.text;
}

export const synthesizeQuestions = ai.defineFlow(
  {
    name: "synthesizeQuestions",
    inputSchema: z.string().describe("PDF file path"),
    outputSchema: z.array(z.string()),
  },
  async (filePath) => {
    filePath = path.resolve(filePath);
    // `extractText` loads the PDF and extracts its contents as text.
    const pdfTxt = await ai.run("extract-text", () => extractText(filePath));

    const chunks = await ai.run("chunk-it", async () =>
      chunk(pdfTxt, chunkingConfig)
    );

    const questions: string[] = [];
    for (var i = 0; i < chunks.length; i++) {
      const qResponse = await ai.generate({
        model: gemini15Flash,
        prompt: {
          text: `Generate one question about the text below: ${chunks[i]}`,
        },
      });
      questions.push(qResponse.text);
    }
    return questions;
  }
);

このコマンドを使用してデータをファイルにエクスポートし、評価に使用できます。

genkit flow:run synthesizeQuestions '"my_input.pdf"' --output synthesizedQuestions.json