评估

评估是一种测试形式,可帮助您验证 LLM 的回答,并确保其符合您的质量标准。

Firebase Genkit 通过插件支持第三方评估工具,并搭配强大的可观测性功能,可深入了解采用 LLM 的应用的运行时状态。Genkit 工具可帮助您自动从中间步骤中提取数据(包括输入、输出和信息),以评估 LLM 回答的端到端质量,以及了解系统构建块的性能。

评估类型

Genkit 支持两种类型的评估:

  • 基于推理的评估:此类评估会针对一组预先确定的输入运行,评估相应输出的质量。

    这是最常见的评估类型,适用于大多数用例。此方法会针对每次运行的评估测试系统的实际输出。

    您可以通过直观地检查结果来手动执行质量评估。或者,您也可以使用评估指标自动执行评估。

  • 原始评估:此类评估会直接评估输入的质量,而无需进行任何推理。此方法通常与使用指标的自动评估方法搭配使用。评估所需的所有必填字段(例如inputcontextoutputreference)必须存在于输入数据集中。如果您有来自外部来源(例如从生产轨迹收集的数据)的数据,并且希望客观衡量收集数据的质量,此方法非常有用。

    如需了解详情,请参阅本页的高级使用部分。

本部分介绍了如何使用 Genkit 执行基于推理的评估。

快速入门

设置

  1. 使用现有的 Genkit 应用,或按照我们的 [开始使用](get-started) 指南创建新应用。
  2. 添加以下代码以定义要评估的简单 RAG 应用。在本指南中,我们使用一个始终返回相同文档的虚构检索工具。 ```js import { genkit, z, Document } from "genkit"; import { googleAI, gemini15Flash, gemini15Pro, } 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, options: { k: 2 }, }); const llmResponse = await ai.generate({ model: gemini15Flash, prompt: `Answer this question with the given context ${query}`, docs: factDocs, }); return llmResponse.text; } ); ```
  3. (可选)向应用添加评估指标,以便在评估时使用。本指南使用 `genkitEval` 插件中的 `MALICIOUSNESS` 指标。 ```js 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`](https://www.npmjs.com/package/@genkit-ai/evaluator) 软件包。 ```posix-terminal npm install @genkit-ai/evaluator ```
  4. 启动 Genkit 应用 ```posix-terminal genkit start -- ```

创建数据集

创建一个数据集,以定义我们要用于评估流程的示例。

  1. 前往 http://localhost:4000 中的开发者界面,然后点击 Datasets(数据集)按钮以打开“Datasets”(数据集)页面。

  2. 点击创建数据集按钮,打开创建数据集对话框。

    a. 为新数据集提供 datasetId。本指南使用 myFactsQaDataset

    b. 选择 Flow 数据集类型。

    c. 将验证目标字段留空,然后点击保存

  3. 系统随即会显示新数据集页面,其中显示了一个空数据集。请按照以下步骤为其添加示例:

    a. 点击添加示例按钮,打开示例编辑器面板。

    b. 只有 input 字段是必填字段。在 input 字段中输入 "Who is man's best friend?",然后点击保存,将示例 has 添加到数据集中。

    c. 重复执行步骤 (a) 和 (b) 几次,以添加更多示例。本指南会向数据集添加以下示例输入:

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

    完成此步骤后,您的数据集应包含 3 个示例,其中包含上述值。

运行评估并查看结果

如需开始评估流程,请点击开发者界面中的 Evaluations 标签页,然后点击运行新评估按钮即可开始。

  1. 选择 Flow 单选按钮以评估流程。

  2. 选择 qaFlow 作为要评估的目标流程。

  3. 选择 myFactsQaDataset 作为要用于评估的目标数据集。

  4. (可选)如果您使用 Genkit 插件安装了评估器指标,则可以在本页面中看到这些指标。选择您要在此评估运行中使用的指标。这完全是可选的:如果省略此步骤,系统仍会在评估运行中返回结果,但不会显示任何关联的指标。

  5. 最后,点击运行评估以开始评估。这可能需要一段时间,具体取决于您要测试的流程。评估完成后,系统会显示一条成功消息,其中包含用于查看结果的链接。点击该链接可前往评估详情页面。

您可以在此页面上查看评估的详细信息,包括原始输入、提取的上下文和指标(如果有)。

核心概念

术语

  • 评估:评估是评估系统性能的过程。在 Genkit 中,此类系统通常是 Genkit 基元,例如流或模型。评估可以是自动评估,也可以是人工评估。

  • 批量推理:推理是指在流或模型上运行输入以获取相应输出的过程。批量推理涉及对多个输入同时执行推理。

  • 指标:评估指标是用于为推理结果评分的标准。例如准确性、忠实性、恶意性、输出是否为英语等。

  • 数据集:数据集是用于基于推理的评估的示例集合。数据集通常由 input 和可选的 reference 字段组成。reference 字段不会影响评估的推理步骤,但会原样传递给任何评估指标。在 Genkit 中,您可以通过开发者界面创建数据集。Genkit 中有两种类型的数据集:流程数据集和模型数据集。

架构验证

数据集在开发者界面中是否支持架构验证取决于其类型:

  • 流数据集支持对 Genkit 应用中流的数据集的 inputreference 字段进行验证。架构验证是可选的,只有在目标流程上指定架构时才会强制执行。

  • 模型数据集具有隐式架构,同时支持 stringGenerateRequest 输入类型。字符串验证提供了一种便捷的方式来评估简单的文本提示,而 GenerateRequest 则可针对高级用例(例如提供模型参数、消息历史记录、工具等)提供完全控制。您可以在我们的 API 参考文档中找到 GenerateRequest 的完整架构。

支持的评估器

Genkit 评估程序

Genkit 包含少数几个受 RAGAS 启发的原生评估器,可帮助您上手使用:

  • 忠实度 - 衡量生成的回答与给定上下文的事实一致性
  • 回答相关性 - 评估生成的回答与给定问题的相关程度
  • 恶意性 - 衡量生成的输出是否意图欺骗、伤害或利用

评估器插件

Genkit 通过插件支持其他评估器,例如 Vertex Rapid 评估器,您可以通过 VertexAI 插件访问这些评估器。

高级用法

使用 CLI 进行评估

Genkit CLI 提供了丰富的 API 来执行评估。在开发者界面不可用(例如在 CI/CD 工作流中)的环境中,此功能尤为有用。

Genkit CLI 提供了 3 个主要的评估命令:eval:floweval:extractDataeval:run

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"
  }
]

如果您的流程需要身份验证,您可以使用 --auth 参数指定它:

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

默认情况下,eval:floweval:run 命令会使用所有可用指标进行评估。如需在部分配置的评估器上运行,请使用 --evaluators 标志,并按名称提供以英文逗号分隔的评估器列表:

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

您可以在开发者界面 (localhost:4000/evaluate) 中查看运行评估的结果。

eval:extractDataeval: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 的结果会显示在位于 localhost:4000/evaluate 的开发者界面的评估页面中。

自定义提取器

Genkit 提供了合理的默认逻辑,用于在执行评估时提取必要的字段(inputoutputcontext)。不过,您可能需要更好地控制这些字段的提取逻辑。Genkit 支持自定义提取器来实现此目的。您可以提供要在 eval:extractDataeval: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,
      options: { k: 2 },
    });
    const factDocsModified = await 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: factDocs,
    });
    return llmResponse.text;
  }
);

接下来,配置自定义提取器,以便在评估此流程时使用 factModified 步骤的输出。

如果您没有用于配置自定义提取器的 tools-config 文件,请将一个名为 genkit-tools.conf.js 的文件添加到项目根目录。

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

在 tools 配置文件中,添加以下代码:

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

此配置会替换 Genkit 工具的默认提取器,具体来说,会更改在评估此流程时将哪些内容视为 context

再次运行评估后,您会发现上下文现在已填充为步骤 factModified 的输出。

genkit eval:flow qaFlow --input testInputs.json

评估提取器的指定方式如下:

  • evaluators 字段接受一个 EvaluatorConfig 对象数组,这些对象受 flowName 的作用域控制
  • 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, run, 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 run("extract-text", () => extractText(filePath));

    const chunks = await 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