Firebase Genkit można rozszerzyć, aby obsługiwał niestandardową ocenę danych wyjściowych testu, korzystając z modelu LLM jako sędziego lub wyłącznie programowo.
Definicja oceniającego
Oceniacze to funkcje, które oceniają treści przekazywane do modelu LLM i generowane przez niego. Istnieją 2 główne podejścia do automatycznej oceny (testowania): ocena heurystyczna i ocena na podstawie LLM. W przypadku podejścia heurystycznego definiujesz funkcję deterministyczną, taką jak w tradycyjnym rozwoju oprogramowania. W przypadku oceny opartej na LLM treści są przekazywane do tego modelu, który ocenia dane wyjściowe zgodnie z kryteriami określonymi w promptach.
Oceniacze oparte na LLM
Evaluator oparty na LLM korzysta z modelu LLM do oceny danych wejściowych, kontekstu lub danych wyjściowych funkcji generatywnej AI.
Oceny oparte na LLM w Genkit składają się z 3 komponentów:
- prompt
- Funkcja punktacji
- Działanie instancji oceny
Definiowanie promptu
W tym przykładzie prompt poprosi LLM o ocena, jak smaczne są wyniki. Najpierw podaj kontekst LLM, a potem opisz, czego oczekujesz od modelu, i na koniec podaj kilka przykładów, na których może się on oprzeć.
Narzędzie definePrompt
w Genkit umożliwia łatwe definiowanie promptów z weryfikacją danych wejściowych i wyjściowych. Oto jak skonfigurować prompt oceny za pomocą 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:
`
);
Definiowanie funkcji punktacji
Teraz zdefiniuj funkcję, która przyjmie przykład zawierający output
, zgodnie z wymaganiami promptu, i wyznacz wynik. Przypadki testowe Genkit zawierają pole input
jako wymagane, a pola opcjonalne output
i context
. Oceniający musi sprawdzić, czy wszystkie pola wymagane do oceny są obecne.
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 },
};
}
Definiowanie działania oceniającego
Ostatnim krokiem jest napisanie funkcji, która definiuje samo działanie oceniającego.
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,
};
}
);
}
Heurystyka
Heurystycznym oceniającym może być dowolna funkcja służąca do oceny danych wejściowych, kontekstu lub danych wyjściowych funkcji generatywnej AI.
Heurystyczne algorytmy oceniające w Genkit składają się z 2 komponentów:
- Funkcja punktacji
- Działanie instancji oceny
Definiowanie funkcji punktacji
Podobnie jak w przypadku oceniacza opartego na LLM, zdefiniuj funkcję punktacji. W tym przypadku funkcja oceniania nie musi znać LLM sędziego ani jego konfiguracji.
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 },
};
}
Definiowanie działania oceniającego
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);
}
);
});
}
Konfiguracja
Opcje wtyczki
Określ PluginOptions
, których będzie używać niestandardowy wtyczka oceniająca. Ten obiekt nie ma ścisłych wymagań i jest zależny od zdefiniowanych typów oceniaczy.
Musi ona zawierać co najmniej definicję danych, które mają być rejestrowane.
export enum MyAwesomeMetric {
WORD_COUNT = 'WORD_COUNT',
US_PHONE_REGEX_MATCH = 'US_PHONE_REGEX_MATCH',
}
export interface PluginOptions {
metrics?: Array<MyAwesomeMetric>;
}
Jeśli nowa wtyczka używa LLM jako sędziego i obsługuje wymianę LLM, zdefiniuj dodatkowe parametry w obiekcie 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>;
}
Definicja wtyczki
Wtyczki są rejestrowane w ramach za pomocą pliku genkit.config.ts
w projekcie. Aby móc skonfigurować nowy wtyczkę, zdefiniuj funkcję, która definiuje GenkitPlugin
i konfiguruje ją za pomocą zdefiniowanego powyżej PluginOptions
.
W tym przypadku mamy 2 oceniających: DELICIOUSNESS
i US_PHONE_REGEX_MATCH
. Tutaj są one rejestrowane w pluginie i w 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;
Konfigurowanie Genkit
Dodaj nowo zdefiniowaną wtyczkę do konfiguracji Genkit.
W przypadku oceny za pomocą Gemini wyłącz ustawienia bezpieczeństwa, aby oceniający mógł zaakceptować, wykryć i ocenić potencjalnie szkodliwe treści.
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
],
}),
],
...
});
Testowanie
Ocena zdolności oceniania przez weryfikatora opartego na LLM jest związana z tymi samymi problemami, które występują w przypadku oceny jakości danych wyjściowych funkcji generatywnej AI.
Aby sprawdzić, czy funkcja niestandardowa działa zgodnie z oczekiwaniami, utwórz zestaw przypadków testowych z jasno określonymi prawidłowymi i nieprawidłowymi odpowiedziami.
Przykładowy plik json z wartością deliciousness może wyglądać tak: 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."
}
]
Przykłady mogą być tworzone przez człowieka lub możesz poprosić LLM o utworzenie zestawu testów, które można dostosować. Dostępnych jest też wiele zbiorów danych porównawczych, których można użyć.
Następnie użyj interfejsu wiersza poleceń Genkit do uruchomienia oceniacza na tych przypadkach testowych.
genkit eval:run deliciousness_dataset.json
Wyświetl wyniki w interfejsie Genkit.
genkit start
Wejdź na localhost:4000/evaluate
.