Firebase Genkit można rozszerzyć o obsługę niestandardowej oceny danych wyjściowych z danego przypadku testowego, wykorzystując LLM w roli jurora lub wyłącznie w sposób zautomatyzowany.
Definicja osoby oceniającej
Funkcje oceniające to funkcje, które oceniają treści przekazywane LLM i przez niego generowane. Istnieją 2 główne podejścia do automatycznej oceny (testowania): ocena heurystyczna i ocena oparta na LLM. W metodzie heurystycznej definiuje się funkcję deterministyczną, taką jak funkcja w przypadku tradycyjnego tworzenia oprogramowania. W ocenie opartej na LLM treść jest przekazywana z powrotem do LLM, a treść jest proszona o ocenę wyników zgodnie z kryteriami określonymi w prompcie.
Oceniający oparte na LLM
Weryfikator oparty na LLM wykorzystuje LLM do oceny danych wejściowych, kontekstu lub danych wyjściowych funkcji generatywnej AI.
Testy oparte na LLM w Genkit składają się z 3 komponentów:
- Prompt
- Funkcja punktacji
- Działanie weryfikatora
Zdefiniuj prompt
W tym przykładzie prompt to prośba do LLM o ocenę jakości danych wyjściowych. Najpierw podaj kontekst LLM, opisz, czego od niego oczekujesz, a na koniec podaj kilka przykładów, na których możesz oprzeć jego reagowanie.
Wraz z Genkit dostajesz usługę dotprompt
, która ułatwia definiowanie promptów i zarządzanie nimi za pomocą funkcji takich jak walidacja schematu danych wejściowych i wyjściowych. Oto, jak za pomocą parametru dotprompt
zdefiniować prompt oceny.
import { defineDotprompt } from '@genkit-ai/dotprompt';
// Define the expected output values
const DELICIOUSNESS_VALUES = ['yes', 'no', 'maybe'] as const;
// Define the response schema expected from the LLM
const DeliciousnessDetectionResponseSchema = z.object({
reason: z.string(),
verdict: z.enum(DELICIOUSNESS_VALUES),
});
type DeliciousnessDetectionResponse = z.infer<
typeof DeliciousnessDetectionResponseSchema
>;
const DELICIOUSNESS_PROMPT = defineDotprompt(
{
input: {
schema: z.object({
output: z.string(),
}),
},
output: {
schema: DeliciousnessDetectionResponseSchema,
},
},
`You are a food critic with a wide range in taste. Given the output, decide if it sounds delicious and provide your reasoning. Use only "yes" (if delicous), "no" (if not delicious), "maybe" (if you can't decide) as the verdict.
Here are a few examples:
Output:
Chicken parm sandwich
Response:
{ "reason": "This is a classic sandwich enjoyed by many - totally delicious", "verdict":"yes"}
Output:
Boston logan international airport tarmac
Response:
{ "reason": "This is not edible and definitely not delicious.", "verdict":"no"}
Output:
A juicy piece of gossip
Response:
{ "reason": "Gossip is sometimes metaphorically referred to as tasty.", "verdict":"maybe"}
Here is a new submission to assess:
Output:
{{output}}
Response:
`
);
Zdefiniuj funkcję punktacji
Teraz zdefiniuj funkcję, która wykorzysta przykład, który zawiera element output
wymagany w prompcie, i oceń wynik. Przypadki testowe Genkit obejmują pole input
jako wymagane oraz pola opcjonalne dotyczące pól output
i context
. Weryfikatorowi odpowiada za sprawdzenie, czy wszystkie pola wymagane do oceny zostały wypełnione.
/**
* Score an individual test case for delciousness.
*/
export async function deliciousnessScore<
CustomModelOptions extends z.ZodTypeAny,
>(
judgeLlm: ModelArgument<CustomModelOptions>,
dataPoint: BaseDataPoint,
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 },
};
}
Zdefiniuj działanie oceniającego
Ostatnim krokiem jest napisanie funkcji, która określa samo działanie oceniającego.
/**
* 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: BaseDataPoint) => {
const score = await deliciousnessScore(judge, datapoint, judgeConfig);
return {
testCaseId: datapoint.testCaseId,
evaluation: score,
};
}
);
}
Oceniający heurystyczne
Weryfikator heurystyczny może być dowolną funkcją używaną do oceny danych wejściowych, kontekstu lub danych wyjściowych funkcji generatywnej AI.
Testery heurystyczne w Genkit składają się z 2 komponentów:
- Funkcja punktacji
- Działanie weryfikatora
Zdefiniuj funkcję punktacji
Podobnie jak w przypadku oceniającego opartego na LLM, zdefiniuj funkcję punktacji. W tym przypadku funkcja punktacji nie musi znać jurora LLM ani jego konfiguracji.
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: BaseDataPoint
): 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 },
};
}
Zdefiniuj działanie oceniającego
/**
* 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: BaseDataPoint) => {
const score = await regexMatchScore(datapoint, regexMetric.regex);
return fillScores(datapoint, score);
}
);
});
}
Konfiguracja
Opcje wtyczki
Określ zasób PluginOptions
, którego będzie używać niestandardowa wtyczka oceny. Ten obiekt nie ma ścisłych wymagań i zależy od zdefiniowanych typów weryfikatorów.
Wymagane jest minimum zdefiniowanie wskaźników, które można zarejestrować.
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 jurora, a wtyczka obsługuje zamianę tego, który z nich ma być używany, 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 platformy za pomocą pliku genkit.config.ts
w projekcie. Aby móc skonfigurować nową wtyczkę, zdefiniuj funkcję, która definiuje GenkitPlugin
i konfiguruje ją za pomocą zdefiniowanej powyżej zasady PluginOptions
.
W tym przypadku mamy 2 weryfikatorów: DELICIOUSNESS
i US_PHONE_REGEX_MATCH
. Tutaj weryfikatorzy są rejestrowani za pomocą wtyczki i Firebase Genkit.
export function myAwesomeEval<ModelCustomOptions extends z.ZodTypeAny>(
params: PluginOptions<ModelCustomOptions>
): PluginProvider {
// Define the new plugin
const plugin = genkitPlugin(
'myAwesomeEval',
async (params: PluginOptions<ModelCustomOptions>) => {
const { judge, judgeConfig, metrics } = params;
const evaluators: EvaluatorAction[] = metrics.map((metric) => {
// We'll create these functions in the next step
switch (metric) {
case DELICIOUSNESS:
// This evaluator requires an LLM as judge
return createDeliciousnessEvaluator(judge, judgeConfig);
case US_PHONE_REGEX_MATCH:
// This evaluator does not require an LLM
return createUSPhoneRegexEvaluator();
}
});
return { evaluators };
}
);
// Create the plugin with the passed params
return plugin(params);
}
export default myAwesomeEval;
Skonfiguruj Genkit
Dodaj nowo zdefiniowaną wtyczkę do konfiguracji Genkit.
Na potrzeby oceny przy użyciu Gemini wyłącz ustawienia bezpieczeństwa, aby weryfikator mógł zaakceptować, wykryć i ocenić potencjalnie szkodliwe treści oraz ocenić je.
import { gemini15Flash } from '@genkit-ai/googleai';
export default configureGenkit({
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
Te same kwestie, które dotyczą oceny jakości wyników działania funkcji generatywnej AI, mają zastosowanie do oceny zdolności oceniania weryfikatora opartego na LLM.
Aby mieć wyobrażenie, czy weryfikator niestandardowy ma skuteczność na oczekiwanym poziomie, utwórz zestaw przypadków testowych, w których odpowiedzi będą jasno poprawne.
Oto przykład smaku pliku 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."
}
]
Te przykłady mogą być wygenerowane przez człowieka. Możesz też poprosić LLM o pomoc w utworzeniu zestawu przypadków testowych, które można wybrać. Dostępnych jest też wiele zbiorów danych porównawczych.
Następnie za pomocą interfejsu wiersza poleceń Genkit uruchom weryfikatora pod kątem tych przypadków testowych.
genkit eval:run deliciousness_dataset.json
Wyświetl wyniki w interfejsie Genkit.
genkit start
Wejdź na localhost:4000/evaluate
.