主题
如何定义 LLM-as-a-judge 评估器
LLM 应用可能难以评估,因为它们通常会生成没有唯一正确答案的对话文本。
本指南展示如何定义 LLM-as-a-judge 评估器,用于离线评估,并使用 LangSmith SDK。
TIP
如需快速开始,请使用 openevals,它提供了可直接使用的 LLM-as-a-judge 评估器。
NOTE
SDK 不支持决策模型评估器。这类评估器使用决策模型(例如 SemIf 或 Jev)作为评判者。要创建此类评估器,请使用 UI。
创建你自己的 LLM-as-a-judge 评估器
要完全控制评估器逻辑,请创建自己的 LLM-as-a-judge 评估器,并使用 LangSmith SDK(Python / TypeScript)运行它。
需要 langsmith>=0.2.0
LLM-as-a-judge 评估器由三个关键部分组成:
- 评估器函数:接收示例输入和应用输出,然后使用 LLM 对质量进行评分的函数。该函数应返回布尔值、数字、字符串或包含分数信息的字典。
- 目标函数:被评估的应用逻辑(为便于观测,使用
@traceable包装)。 - 数据集与评估:包含测试示例的数据集,以及在每个示例上运行目标函数并应用评估器的
evaluate()函数。
Example
python
from langsmith import evaluate, traceable, wrappers, Client
from openai import OpenAI
from pydantic import BaseModel
# Wrap the OpenAI client to automatically trace all LLM calls
oai_client = wrappers.wrap_openai(OpenAI())
# 1. Define your evaluator function
# This function receives the inputs and outputs from each test example
def valid_reasoning(inputs: dict, outputs: dict) -> bool:
"""Use an LLM to judge if the reasoning and the answer are consistent."""
# Define the evaluation criteria
instructions = """
Given the following question, answer, and reasoning, determine if the reasoning
for the answer is logically valid and consistent with the question and the answer."""
# Use structured output to get a boolean score
class Response(BaseModel):
reasoning_is_valid: bool
# Construct the prompt with the actual inputs and outputs
msg = f"Question: {inputs['question']}\nAnswer: {outputs['answer']}\nReasoning: {outputs['reasoning']}"
# Call the LLM to judge the output
response = oai_client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{"role": "system", "content": instructions}, {"role": "user", "content": msg}],
response_format=Response
)
# Return the boolean score
return response.choices[0].message.parsed.reasoning_is_valid
# 2. Define your target function (the application being evaluated)
# The @traceable decorator logs traces to LangSmith for debugging
@traceable
def dummy_app(inputs: dict) -> dict:
return {"answer": "hmm i'm not sure", "reasoning": "i didn't understand the question"}
# 3. Create a dataset with test examples
ls_client = Client()
dataset = ls_client.create_dataset("big questions")
examples = [
{"inputs": {"question": "how will the universe end"}},
{"inputs": {"question": "are we alone"}},
]
ls_client.create_examples(dataset_id=dataset.id, examples=examples)
# 4. Run the evaluation
# This runs dummy_app on each example and applies the valid_reasoning evaluator
results = evaluate(
dummy_app, # Your application function
data=dataset, # Dataset to evaluate on
evaluators=[valid_reasoning] # List of evaluator functions
)使用参考输出
当数据集示例包含参考输出(预期答案)时,你可以将 reference_outputs 作为参数传给评估器函数。LangSmith 会自动向任何声明了该参数的评估器提供示例的参考输出。
python
from langsmith import evaluate, traceable, wrappers, Client
from openai import OpenAI
from pydantic import BaseModel
# Wrap the OpenAI client to automatically trace all LLM calls
oai_client = wrappers.wrap_openai(OpenAI())
# Define an evaluator that checks the answer against a reference answer
def matches_expected(inputs: dict, outputs: dict, reference_outputs: dict) -> bool:
"""Use an LLM to judge if the actual answer matches the expected answer."""
instructions = """
Given a question, an expected answer, and an actual answer, determine if the
actual answer is semantically equivalent to the expected answer."""
class Response(BaseModel):
answers_match: bool
msg = (
f"Question: {inputs['question']}\n"
f"Expected answer: {reference_outputs['answer']}\n"
f"Actual answer: {outputs['answer']}"
)
response = oai_client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{"role": "system", "content": instructions}, {"role": "user", "content": msg}],
response_format=Response,
)
return response.choices[0].message.parsed.answers_match
@traceable
def my_app(inputs: dict) -> dict:
# Your application logic here
return {"answer": "Paris"}
# Create a dataset with reference outputs (expected answers)
ls_client = Client()
dataset = ls_client.create_dataset("geography-qa")
examples = [
{
"inputs": {"question": "What is the capital of France?"},
"outputs": {"answer": "Paris"},
},
{
"inputs": {"question": "What is the capital of Germany?"},
"outputs": {"answer": "Berlin"},
},
]
ls_client.create_examples(dataset_id=dataset.id, examples=examples)
results = evaluate(
my_app,
data=dataset,
evaluators=[matches_expected]
)typescript
import { evaluate } from "langsmith/evaluation";
import { Client } from "langsmith";
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
const oaiClient = new OpenAI();
const matchesExpected = async ({
inputs,
outputs,
referenceOutputs,
}: {
inputs: Record<string, any>;
outputs: Record<string, any>;
referenceOutputs?: Record<string, any>;
}): Promise<boolean> => {
const instructions = `Given a question, an expected answer, and an actual answer, determine if the
actual answer is semantically equivalent to the expected answer.`;
const ResponseSchema = z.object({ answers_match: z.boolean() });
const msg = `Question: ${inputs.question}\nExpected answer: ${referenceOutputs?.answer}\nActual answer: ${outputs.answer}`;
const response = await oaiClient.beta.chat.completions.parse({
model: "gpt-4o",
messages: [
{ role: "system", content: instructions },
{ role: "user", content: msg },
],
response_format: zodResponseFormat(ResponseSchema, "response"),
});
return response.choices[0].message.parsed?.answers_match ?? false;
};
const myApp = async (inputs: Record<string, any>): Promise<Record<string, any>> => {
// Your application logic here
return { answer: "Paris" };
};
// Create a dataset with reference outputs (expected answers)
const lsClient = new Client();
const dataset = await lsClient.createDataset("geography-qa-ts");
await lsClient.createExamples({
inputs: [
{ question: "What is the capital of France?" },
{ question: "What is the capital of Germany?" },
],
outputs: [{ answer: "Paris" }, { answer: "Berlin" }],
datasetId: dataset.id,
});
await evaluate(myApp, {
data: dataset.name,
evaluators: [matchesExpected],
});有关如何编写自定义评估器的更多信息,请参阅如何定义代码评估器(SDK)。