Anda dapat memperluas Firebase Genkit untuk mendukung evaluasi kustom, menggunakan LLM sebagai hakim, atau dengan evaluasi terprogram (heuristik).
Definisi evaluator
Evaluator adalah fungsi yang menilai respons LLM. Ada dua pendekatan utama untuk evaluasi otomatis: evaluasi heuristik dan evaluasi berbasis LLM. Dalam pendekatan heuristik, Anda menentukan fungsi deterministik. Sebaliknya, dalam penilaian berbasis LLM, konten akan dimasukkan kembali ke LLM, dan LLM diminta untuk menilai output sesuai dengan kriteria yang ditetapkan dalam perintah.
Metode ai.defineEvaluator
, yang Anda gunakan untuk menentukan
tindakan evaluator di Genkit, mendukung salah satu pendekatan tersebut. Dokumen
ini membahas beberapa contoh cara menggunakan metode
ini untuk evaluasi berbasis heuristik dan LLM.
Evaluator Berbasis LLM
Evaluator berbasis LLM memanfaatkan LLM untuk mengevaluasi
input
, context
, dan output
dari fitur AI
generatif Anda.
Evaluator berbasis LLM di Genkit terdiri dari 3 komponen:
- Perintah
- Fungsi penskoran
- Tindakan evaluator
Menentukan perintah
Untuk contoh ini, evaluator memanfaatkan LLM untuk menentukan apakah
makanan (output
) lezat atau tidak. Pertama, berikan konteks ke LLM,
lalu jelaskan apa yang Anda inginkan, dan terakhir, berikan beberapa contoh
untuk mendasarkan responsnya.
Utilitas definePrompt
Genkit menyediakan cara mudah untuk menentukan perintah dengan
validasi input dan output. Kode berikut adalah contoh
menyiapkan perintah evaluasi dengan 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,
}
prompt: `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:
`
});
}
Menentukan fungsi penskoran
Tentukan fungsi yang menggunakan contoh yang menyertakan output
seperti
yang diperlukan oleh perintah, dan beri skor pada hasilnya. Pengujian kasus Genkit menyertakan
input
sebagai kolom wajib, dengan output
dan context
sebagai kolom opsional.
Evaluator bertanggung jawab untuk memvalidasi bahwa semua kolom
yang diperlukan untuk evaluasi ada.
import { ModelArgument } from 'genkit';
import { BaseEvalDataPoint, Score } from 'genkit/evaluator';
/**
* Score an individual test case for delciousness.
*/
export async function deliciousnessScore<
CustomModelOptions extends z.ZodTypeAny,
>(
ai: Genkit,
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 },
};
}
Menentukan tindakan evaluator
Langkah terakhir adalah menulis fungsi yang menentukan EvaluatorAction
.
import { 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(ai, judge, datapoint, judgeConfig);
return {
testCaseId: datapoint.testCaseId,
evaluation: score,
};
}
);
}
Metode defineEvaluator
mirip dengan konstruktor Genkit lainnya seperti
defineFlow
dan defineRetriever
. Metode ini memerlukan EvaluatorFn
untuk diberikan sebagai callback. Metode EvaluatorFn
menerima objek BaseEvalDataPoint
, yang sesuai dengan satu entri dalam set data yang sedang dievaluasi, beserta parameter opsi kustom opsional jika ditentukan. Fungsi ini memproses titik data dan menampilkan objek EvalResponse
.
Skema Zod untuk BaseEvalDataPoint
dan EvalResponse
adalah sebagai berikut.
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(),
});
Objek defineEvaluator
memungkinkan pengguna memberikan nama, nama tampilan
yang dapat dibaca pengguna, dan definisi untuk evaluator. Nama tampilan dan
definisi ditampilkan bersama dengan hasil evaluasi di UI Dev.
Evaluator ini juga memiliki kolom isBilled
opsional yang menandai apakah evaluator ini
dapat menghasilkan penagihan (misalnya, menggunakan LLM atau API yang ditagih). Jika evaluator
ditagihkan, UI akan meminta konfirmasi kepada pengguna di CLI sebelum
mengizinkannya menjalankan evaluasi. Langkah ini membantu mencegah
biaya yang tidak diinginkan.
Evaluator Heuristik
Evaluator heuristik dapat berupa fungsi apa pun yang digunakan untuk mengevaluasi input
, context
, atau output
fitur AI generatif Anda.
Evaluator heuristik di Genkit terdiri dari 2 komponen:
- Fungsi penskoran
- Tindakan evaluator
Menentukan fungsi penskoran
Seperti halnya evaluator berbasis LLM, tentukan fungsi penskoran. Dalam hal ini, fungsi penskoran tidak memerlukan LLM hakim.
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 },
};
}
Menentukan tindakan evaluator
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,
};
}
);
}
Menyatukan
Definisi plugin
Plugin didaftarkan ke framework dengan menginstalnya pada saat
melakukan inisialisasi Genkit. Untuk menentukan plugin baru, gunakan metode bantuan genkitPlugin
untuk membuat instance semua tindakan Genkit dalam konteks plugin.
Contoh kode ini menunjukkan dua evaluator: evaluator kelezatan berbasis LLM, dan evaluator nomor telepon AS berbasis ekspresi reguler. Membuat instance evaluator ini dalam konteks plugin akan mendaftarkannya ke plugin.
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;
Mengonfigurasi Genkit
Tambahkan plugin myCustomEvals
ke konfigurasi Genkit Anda.
Untuk evaluasi dengan Gemini, nonaktifkan setelan keamanan agar evaluator dapat menerima, mendeteksi, dan memberi skor konten yang berpotensi berbahaya.
import { gemini15Pro } from '@genkit-ai/googleai';
const ai = genkit({
plugins: [
vertexAI(),
...
myCustomEvals({
judge: gemini15Pro,
}),
],
...
});
Menggunakan evaluator kustom
Setelah Anda membuat instance evaluator kustom dalam konteks aplikasi Genkit (baik melalui plugin maupun secara langsung), evaluator tersebut siap digunakan. Contoh berikut mengilustrasikan cara mencoba evaluator kelezatan dengan beberapa contoh input dan output.
- 1. Buat file json `deliciousness_dataset.json` dengan konten berikut:
[
{
"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. Gunakan Genkit CLI untuk menjalankan evaluator terhadap kasus pengujian ini.
# Start your genkit runtime genkit start -- <command to start your app>
genkit eval:run deliciousness_dataset.json --evaluators=myCustomEvals/deliciousnessEvaluator
- 3. Buka `localhost:4000/evaluate` untuk melihat hasil Anda di UI Genkit.
Penting untuk diperhatikan bahwa kepercayaan pada evaluator kustom meningkat saat Anda melakukan benchmark dengan set data atau pendekatan standar. Lakukan iterasi pada hasil benchmark tersebut untuk meningkatkan performa evaluator Anda hingga mencapai tingkat kualitas yang ditargetkan.