אפשר להרחיב את Firebase Genkit כך שתתמוך בהערכה בהתאמה אישית, באמצעות LLM בתור שופט או באמצעות הערכה פרוגרמטית (הוריסטית).
הגדרת הבודק
פונקציות הערכה הן פונקציות שמעריכות את התשובה של LLM. יש שתי גישות עיקריות להערכה אוטומטית: הערכה היוריסטית והערכה מבוססת-LLM. בגישה ההיוריסטית, מגדירים פונקציה דטרמיניסטית. לעומת זאת, כשמשתמשים בהערכה שמבוססת על LLM, התוכן מוחזר ל-LLM, וה-LLM מתבקש לדרג את הפלט בהתאם לקריטריונים שהוגדרו בהנחיה.
השיטה ai.defineEvaluator
, שבה משתמשים כדי להגדיר פעולת מעריך ב-Genkit, תומכת בשתי הגישות. במסמך הזה מפורטות כמה דוגמאות לשימוש בשיטה הזו להערכות מבוססות-היגוריסטיקה ולהערכות שמבוססות על מודלים גדולים של שפה (LLM).
מודלים להערכה מבוססי LLM
במסגרת הכלי להערכה שמבוסס על LLM, נעשה שימוש ב-LLM כדי להעריך את הערכים של input
, context
ו-output
של תכונת ה-AI הגנרטיבית.
המודלים להערכה מבוססי-LLM ב-Genkit מורכבים משלושה רכיבים:
- הנחיה
- פונקציית ניקוד
- פעולת מעריך
הגדרת ההנחיה
בדוגמה הזו, המערכות להערכת הביצועים משתמשות ב-LLM כדי לקבוע אם המזון (ה-output
) טעים או לא. קודם צריך לספק הקשר ל-LLM, ואז לתאר מה רוצים שהוא יעשה, ולבסוף לספק לו כמה דוגמאות שעליהן התשובה שלו תתבסס.
הכלי definePrompt
של Genkit מספק דרך קלה להגדיר הנחיות עם אימות קלט ופלט. הקוד הבא הוא דוגמה להגדרת הנחיה להערכה באמצעות 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
דומה למבנים אחרים של Genkit, כמו defineFlow
ו-defineRetriever
. בשיטה הזו צריך לספק EvaluatorFn
בתור קריאה חוזרת. השיטה EvaluatorFn
מקבלת אובייקט BaseEvalDataPoint
, שתואם לרשומה אחת במערך הנתונים שנמצא בבדיקה, יחד עם פרמטר אופציונלי של אפשרויות בהתאמה אישית, אם צוין. הפונקציה מעבדת את נקודת הנתונים ומחזירה אובייקט EvalResponse
.
הסכמות של Zod עבור BaseEvalDataPoint
ו-EvalResponse
הן:
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
אופציונלי שמציין אם הכלי הזה יכול להוביל לחיוב (למשל, אם הוא משתמש ב-LLM או ב-API לחיוב). אם המשתמש מחויב על הבדיקה, בממשק המשתמש תוצג בקשה לאישור ב-CLI לפני שהוא יוכל להריץ את הבדיקה. כך תוכלו למנוע הוצאות לא רצויות.
כלי הערכה לפי שיטות ניתוח היוריסטיות
מעריך הוליסטי יכול להיות כל פונקציה שמשמשת להערכת הערכים input
, context
או output
של התכונה מבוססת-ה-AI הגנרטיבי.
הכלי להערכה לפי שיטות ניתוח נתונים (heuristic) ב-Genkit מורכב משני רכיבים:
- פונקציית ניקוד
- פעולת מעריך
הגדרת פונקציית הדירוג
כמו במערכות הערכה שמבוססות על LLM, מגדירים את פונקציית הניקוד. במקרה כזה, פונקציית הניקוד לא זקוקה ל-LLM של שופט.
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. כדי להגדיר פלאגין חדש, משתמשים ב-method העזר genkitPlugin
כדי ליצור את כל הפעולות של Genkit בהקשר של הפלאגין.
בדוגמת הקוד הזו מוצגים שני מעריכים: מעריך הטעם המבוסס על LLM, ומעריך מספרי הטלפון בארה"ב שמבוסס על ביטוי רגולרי. יצירת המכונות האלה להערכה בהקשר של הפלאגין רושמת אותן בפלאגין.
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
מוסיפים את הפלאגין myCustomEvals
להגדרות של Genkit.
כדי לבצע הערכה באמצעות Gemini, צריך להשבית את הגדרות הבטיחות כדי שהבודק יוכל לקבל, לזהות ולתת ניקוד לתוכן שעלול להזיק.
import { gemini15Pro } from '@genkit-ai/googleai';
const ai = genkit({
plugins: [
vertexAI(),
...
myCustomEvals({
judge: gemini15Pro,
}),
],
...
});
שימוש במערכות הערכה בהתאמה אישית
אחרי שיוצרים את המערכות למדידת הביצועים בהתאמה אישית בהקשר של אפליקציית Genkit (דרך פלאגין או ישירות), אפשר להשתמש בהן. הדוגמה הבאה ממחישה איך לנסות את הכלי להערכת הטעם עם כמה דוגמאות של קלט ופלט.
- 1. יוצרים קובץ 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."
}
]
- 2. משתמשים ב-Genkit CLI כדי להריץ את הכלי להערכה מול תרחישים הבדיקה האלה.
# Start your genkit runtime genkit start -- <command to start your app>
genkit eval:run deliciousness_dataset.json --evaluators=myCustomEvals/deliciousnessEvaluator
- 3. עוברים אל localhost:4000/evaluate כדי להציג את התוצאות בממשק המשתמש של Genkit.
חשוב לציין שהאמון במודלים להערכה מותאמת אישית גדל ככל שמבצעים השוואה ביניהם לבין גישות או מערכי נתונים רגילים. כדאי לבדוק שוב את התוצאות של אמות המידה האלה כדי לשפר את הביצועים של הבודקים עד שהם יגיעו לרמת האיכות הרצויה.