LLM을 판사로 사용하거나 프로그래매틱 (휴리스틱) 평가를 사용하여 맞춤 평가를 지원하도록 Firebase Genkit을 확장할 수 있습니다.
평가자 정의
평가자는 LLM의 응답을 평가하는 함수입니다. 자동 평가에는 휴리스틱 평가와 LLM 기반 평가라는 두 가지 주요 접근 방식이 있습니다. 휴리스틱 접근 방식에서는 확정적인 함수를 정의합니다. 반면 LLM 기반 평가에서는 콘텐츠가 LLM에 다시 제공되고 LLM에 프롬프트에 설정된 기준에 따라 출력에 점수를 매기도록 요청됩니다.
Genkit에서 평가자 작업을 정의하는 데 사용하는 ai.defineEvaluator
메서드는 두 가지 접근 방식을 모두 지원합니다. 이 문서에서는 휴리스틱 및 LLM 기반 평가에 이 메서드를 사용하는 방법의 몇 가지 예를 살펴봅니다.
LLM 기반 평가자
LLM 기반 평가자는 LLM을 활용하여 생성형 AI 기능의 input
, context
, output
를 평가합니다.
Genkit의 LLM 기반 평가자는 다음 세 가지 구성요소로 구성됩니다.
- 프롬프트
- 점수 함수
- 평가자 작업
프롬프트 정의
이 예시에서 평가자는 LLM을 활용하여 음식 (output
)이 맛있는지 아닌지 판단합니다. 먼저 LLM에 컨텍스트를 제공한 다음 수행할 작업을 설명하고 마지막으로 응답의 기반이 될 몇 가지 예시를 제공합니다.
Genkit의 definePrompt
유틸리티는 입력 및 출력 유효성 검사를 사용하여 프롬프트를 간편하게 정의할 수 있는 방법을 제공합니다. 다음 코드는 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:
`
});
}
점수 함수 정의
프롬프트에 따라 output
가 포함된 예시를 사용하고 결과에 점수를 부여하는 함수를 정의합니다. Genkit 테스트 사례에는 input
가 필수 필드로, output
및 context
가 선택적 필드로 포함됩니다.
평가에 필요한 모든 필드가 있는지 확인하는 것은 평가자의 책임입니다.
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 },
};
}
평가자 작업 정의
마지막 단계는 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,
};
}
);
}
defineEvaluator
메서드는 defineFlow
및 defineRetriever
과 같은 다른 Genkit 생성자와 유사합니다. 이 메서드에는 EvaluatorFn
가 콜백으로 제공되어야 합니다. EvaluatorFn
메서드는 평가 중인 데이터 세트의 단일 항목에 해당하는 BaseEvalDataPoint
객체와 지정된 경우 선택적 맞춤 옵션 매개변수를 허용합니다. 이 함수는 데이터 포인트를 처리하고 EvalResponse
객체를 반환합니다.
BaseEvalDataPoint
및 EvalResponse
의 Zod 스키마는 다음과 같습니다.
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
객체를 사용하면 사용자가 이름, 사용자가 읽을 수 있는 표시 이름, 평가자의 정의를 제공할 수 있습니다. 표시 이름과 정의는 Dev UI의 평가 결과와 함께 표시됩니다.
또한 이 평가자가 결제의 결과를 가져올 수 있는지 여부를 표시하는 선택적 isBilled
필드가 있습니다 (예: 결제된 LLM 또는 API를 사용함). 평가자에게 비용이 청구되는 경우 UI는 사용자에게 CLI에서 확인을 요청한 후 평가를 실행하도록 허용합니다. 이 단계를 통해 의도치 않은 지출을 방지할 수 있습니다.
휴리스틱 평가자
휴리스틱 평가자는 생성형 AI 기능의 input
, context
또는 output
를 평가하는 데 사용되는 모든 함수일 수 있습니다.
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 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을 초기화할 때 설치하여 프레임워크에 등록됩니다. 새 플러그인을 정의하려면 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 구성
Genkit 구성에 myCustomEvals
플러그인을 추가합니다.
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 UI에서 결과를 확인합니다.
맞춤 평가자를 표준 데이터 세트 또는 접근 방식으로 벤치마킹하면 맞춤 평가자에 대한 신뢰도가 높아진다는 점에 유의해야 합니다. 이러한 벤치마크의 결과를 반복하여 평가자의 실적이 타겟 품질 수준에 도달할 때까지 개선합니다.