אפשר להרחיב את Firebase Genkit כדי לתמוך בהערכה מותאמת אישית של הפלט של תרחישי הבדיקה, באמצעות LLM ככלי להערכה או באופן פרוגרמטי בלבד.
הגדרת הבודק
פונקציות הערכה הן פונקציות שמעריכות את התוכן שניתנה ל-LLM ושהיא יוצרת. יש שתי גישות עיקריות להערכה (בדיקה) אוטומטית: הערכה היוריסטית והערכה מבוססת-LLM. בגישה ההוריסטית, מגדירים פונקציה דטרמיניסטית כמו אלה של פיתוח תוכנה מסורתי. כשמשתמשים בהערכה שמבוססת על LLM, התוכן מוחזר ל-LLM וה-LLM מתבקש לדרג את הפלט בהתאם לקריטריונים שהוגדרו בהנחיה.
מודלים להערכה מבוססי LLM
בודק שמבוסס על LLM משתמש ב-LLM כדי להעריך את הקלט, ההקשר או הפלט של תכונת ה-AI הגנרטיבית.
המודלים להערכה שמבוססים על LLM ב-Genkit מורכבים מ-3 רכיבים:
- הנחיה
- פונקציית ניקוד
- פעולת מעריך
הגדרת ההנחיה
בדוגמה הזו, ההנחיה תבקש מה-LLM לשפוט כמה הפלט טעים. קודם כול, נותנים ל-LLM הקשר, ואז מתארים מה רוצים שהוא יעשה, ולבסוף נותנים לו כמה דוגמאות שעליהן הוא יסתמך בתשובה שלו.
הכלי definePrompt
של Genkit מספק דרך קלה להגדיר הנחיות עם אימות קלט ופלט. כך מגדירים הודעת הערכה באמצעות definePrompt
.
const DELICIOUSNESS_VALUES = ['yes', 'no', 'maybe'] as const;
const DeliciousnessDetectionResponseSchema = z.object({
reason: z.string(),
verdict: z.enum(DELICIOUSNESS_VALUES),
});
type DeliciousnessDetectionResponse = z.infer<typeof DeliciousnessDetectionResponseSchema>;
const DELICIOUSNESS_PROMPT = ai.definePrompt(
{
name: 'deliciousnessPrompt',
inputSchema: z.object({
output: z.string(),
}),
outputSchema: 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:
{{output}}
Response:
`
);
הגדרת פונקציית הדירוג
עכשיו מגדירים את הפונקציה שתקבל דוגמה שכוללת את output
כפי שנדרש בהנחיה, ותספק ציון לתוצאה. תרחישי הבדיקה של Genkit כוללים את השדה input
כחובה, עם שדות אופציונליים ל-output
ול-context
. האחריות של המאבחן היא לוודא שכל השדות הנדרשים לצורך הערכה נמצאים.
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
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 },
};
}
הגדרת הפעולה של הכלי להערכת הביצועים
השלב האחרון הוא לכתוב פונקציה שמגדירה את פעולת המאבחן עצמה.
import { BaseEvalDataPoint, EvaluatorAction } from 'genkit/evaluator';
/**
* 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: BaseEvalDataPoint) => {
const score = await deliciousnessScore(judge, datapoint, judgeConfig);
return {
testCaseId: datapoint.testCaseId,
evaluation: score,
};
}
);
}
כלי הערכה היוריסטיים
מעריך הוליסטי יכול להיות כל פונקציה שמשמשת להערכת הקלט, ההקשר או הפלט של תכונת ה-AI הגנרטיבי.
הכלי להערכה לפי שיטות ניתוח נתונים (heuristic) ב-Genkit מורכב משני רכיבים:
- פונקציית ניקוד
- פעולת מעריך
הגדרת פונקציית הדירוג
בדומה למעריך שמבוסס על LLM, מגדירים את פונקציית הניקוד. במקרה כזה, פונקציית הדירוג לא צריכה לדעת על ה-LLM של השופט או על ההגדרות שלו.
import { BaseEvalDataPoint, Score } from 'genkit/evaluator';
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: 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 regex ${regex.source}`
: `Output did not match regex ${regex.source}`;
return {
score: matches,
details: { reasoning },
};
}
הגדרת הפעולה של הכלי להערכת הביצועים
import { BaseEvalDataPoint, EvaluatorAction } from 'genkit/evaluator';
/**
* 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: BaseEvalDataPoint) => {
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>;
}
הגדרת הפלאגין
הפלאגינים נרשמים ב-framework באמצעות הקובץ genkit.config.ts
בפרויקט. כדי להגדיר פלאגין חדש, מגדירים פונקציה שמגדירה GenkitPlugin
ומגדירה אותו באמצעות PluginOptions
שהוגדר למעלה.
במקרה הזה יש לנו שני מעריכים, DELICIOUSNESS
ו-US_PHONE_REGEX_MATCH
. כאן מתבצע הרישום של הבודקים האלה ב-Plugin וב-Firebase Genkit.
export function myAwesomeEval<ModelCustomOptions extends z.ZodTypeAny>(
options: PluginOptions<ModelCustomOptions>
): PluginProvider {
// Define the new plugin
const plugin = (options?: MyPluginOptions<ModelCustomOptions>) => {
return genkitPlugin(
'myAwesomeEval',
async (ai: Genkit) => {
const { judge, judgeConfig, metrics } = options;
const evaluators: EvaluatorAction[] = metrics.map((metric) => {
switch (metric) {
case DELICIOUSNESS:
// This evaluator requires an LLM as judge
return createDeliciousnessEvaluator(ai, judge, judgeConfig);
case US_PHONE_REGEX_MATCH:
// This evaluator does not require an LLM
return createUSPhoneRegexEvaluator();
}
});
return { evaluators };
})
}
// Create the plugin with the passed options
return plugin(options);
}
export default myAwesomeEval;
הגדרת Genkit
מוסיפים את הפלאגין שהוגדר לאחרונה להגדרות של Genkit.
כדי לבצע הערכה באמצעות Gemini, צריך להשבית את הגדרות הבטיחות כדי שהבודק יוכל לאשר, לזהות ולתת ניקוד לתוכן שעלול להזיק.
import { gemini15Flash } from '@genkit-ai/googleai';
const ai = genkit({
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 לעזור ליצור קבוצה של תרחישי בדיקה שאפשר לבחור מתוכם. יש גם הרבה מערכי נתונים זמינים של נקודות השוואה שאפשר להשתמש בהם.
לאחר מכן, משתמשים ב-CLI של Genkit כדי להריץ את הכלי להערכה מול תרחישי הבדיקה האלה.
genkit eval:run deliciousness_dataset.json
הצגת התוצאות בממשק המשתמש של Genkit.
genkit start
נווט אל localhost:4000/evaluate
.