쌍별 평가(pairwise evaluation) 실행하는 방법
쌍별 평가(pairwise evaluation) 실행하는 방법
LangSmith는 기존 실험을 비교 방식으로 평가하는 것을 지원해요. 출력을 하나씩 평가하는 대신 여러 실험의 출력을 서로 대조해 점수를 매길 수 있습니다. 이 가이드에서는 두 개의 기존 실험과 함께 evaluate()를 사용해 평가기를 정의하고 쌍별 평가를 실행합니다. 마지막으로 LangSmith UI를 사용해 쌍별 실험을 확인합니다.
개념: 쌍별 평가
출처: 문서
본문
사전 요구사항 (Prerequisites)
- 비교할 실험을 아직 만들지 않았다면, 퀵 스타트 또는 하우투 가이드에서 평가를 시작해 보세요.
- 이 가이드는 Python의 경우
langsmith>=0.2.0, JS의 경우langsmith>=0.2.9가 필요합니다.
두 개 이상의 기존 실험과 함께
evaluate_comparative()를 사용할 수도 있어요.
evaluate() 비교 인자 (evaluate() comparative args)
가장 단순한 형태로, evaluate / aevaluate 함수는 다음 인자를 사용합니다:
| 인자 (Argument) | 설명 |
|---|---|
target |
서로 평가하려는 기존 실험 두 개의 목록. uuid 또는 실험 이름일 수 있다. |
evaluators |
이 평가에 연결하려는 쌍별 평가기의 목록. 정의 방법은 아래 섹션을 참고. |
이와 함께 다음 선택적 인자도 전달할 수 있습니다:
| 인자 (Argument) | 설명 |
|---|---|
randomize_order / randomizeOrder |
각 평가에서 출력 순서를 무작위화할지 여부를 나타내는 선택적 boolean. 프롬프트의 위치 편향을 최소화하기 위한 전략. 종종 LLM은 순서에 따라 응답 중 하나에 편향된다. 이는 주로 프롬프트 엔지니어링으로 해결해야 하지만, 이는 또 다른 선택적 완화 수단이다. 기본값은 False. |
experiment_prefix / experimentPrefix |
쌍별 실험 이름의 앞에 붙이는 접두사. 기본값은 None. |
description |
쌍별 실험에 대한 설명. 기본값은 None. |
max_concurrency / maxConcurrency |
실행할 최대 동시 평가 수. 기본값은 5. |
client |
사용할 LangSmith 클라이언트. 기본값은 None. |
metadata |
쌍별 실험에 연결할 메타데이터. 기본값은 None. |
load_nested / loadNested |
실험의 모든 하위 실행을 로드할지 여부. False인 경우 루트 트레이스만 평가기에 전달된다. 기본값은 False. |
쌍별 평가기 정의하기 (Define a pairwise evaluator)
쌍별 평가기는 예상 시그니처를 가진 단순한 함수입니다.
평가기 인자 (Evaluator args)
커스텀 평가기 함수는 특정 인자 이름을 가져야 합니다. 다음 인자의 부분 집합을 사용할 수 있습니다:
inputs: dict: 데이터셋의 단일 예시에 해당하는 입력의 딕셔너리.outputs: list[dict]: 주어진 입력에 대해 각 실험이 생성한 딕셔너리 출력의 두 항목 목록.reference_outputs/referenceOutputs: dict: 사용 가능한 경우 예시와 연관된 참조 출력의 딕셔너리.runs: list[Run]: 주어진 예시에 대해 두 실험이 생성한 전체 Run 객체의 두 항목 목록. 각 실행의 중간 단계나 메타데이터에 접근해야 하는 경우 사용.example: Example: 예시 입력, 출력(사용 가능한 경우), 메타데이터(사용 가능한 경우)를 포함한 전체 데이터셋 Example.
대부분의 사용 사례에서는 inputs, outputs, reference_outputs / referenceOutputs만 필요합니다. runs와 example은 애플리케이션의 실제 입력과 출력 외에 추가 트레이스 또는 예시 메타데이터가 필요한 경우에만 유용합니다.
평가기 출력 (Evaluator output)
커스텀 평가기는 다음 유형 중 하나를 반환할 것으로 기대됩니다:
Python 및 JS/TS
-
dict: 키가 있는 딕셔너리:key: 로깅될 피드백 키를 나타냄scores: 실행 ID에서 해당 실행의 점수로의 매핑.comment: 문자열. 모델 추론에 가장 흔히 사용.
현재 Python 전용
list[int | float | bool]: 점수의 두 항목 목록. 목록은runs/outputs평가기 인자와 같은 순서라고 가정한다. 평가기 함수 이름이 피드백 키로 사용된다.
실행의 표준 피드백과 구별되는 피드백 키를 선택해야 합니다. 쌍별 피드백 키에는 pairwise_ 또는 ranked_ 접두사를 붙일 것을 권장합니다.
쌍별 평가 실행하기 (Run a pairwise evaluation)
다음 예시는 두 AI 어시스턴트 응답 중 어느 것이 더 나은지 LLM이 결정하도록 하는 프롬프트를 사용합니다. 구조화된 출력을 사용해 AI의 응답을 파싱합니다: 0, 1 또는 2.
아래 Python 예시에서는 LangChain Hub에서 이 구조화된 프롬프트를 가져와 LangChain 채팅 모델 래퍼와 함께 사용합니다.
LangChain 사용은 완전히 선택 사항입니다. 이를 강조하기 위해 TypeScript 예시는 OpenAI SDK를 직접 사용합니다.
- Python:
langsmith>=0.2.0필요 - TypeScript:
langsmith>=0.2.9필요
from langchain_classic import hub
from langchain.chat_models import init_chat_model
from langsmith import evaluate
# See the prompt: https://smith.langchain.com/hub/langchain-ai/pairwise-evaluation-2
prompt = hub.pull("langchain-ai/pairwise-evaluation-2")
model = init_chat_model("gpt-5.5")
chain = prompt | model
def ranked_preference(inputs: dict, outputs: list[dict]) -> list:
# Assumes example inputs have a 'question' key and experiment
# outputs have an 'answer' key.
response = chain.invoke({
"question": inputs["question"],
"answer_a": outputs[0].get("answer", "N/A"),
"answer_b": outputs[1].get("answer", "N/A"),
})
if response["Preference"] == 1:
scores = [1, 0]
elif response["Preference"] == 2:
scores = [0, 1]
else:
scores = [0, 0]
return scores
evaluate(
("experiment-1", "experiment-2"), # 실험 이름/ID로 바꾸세요
evaluators=[ranked_preference],
randomize_order=True,
max_concurrency=4,
)
import { evaluate} from "langsmith/evaluation";
import { Run } from "langsmith/schemas";
import { wrapOpenAI } from "langsmith/wrappers";
import OpenAI from "openai";
import { z } from "zod";
const openai = wrapOpenAI(new OpenAI());
async function rankedPreference({
inputs,
runs,
}: {
inputs: Record<string, any>;
runs: Run[];
}) {
const scores: Record<string, number> = {};
const [runA, runB] = runs;
if (!runA || !runB) throw new Error("Expected at least two runs");
const payload = {
question: inputs.question,
answer_a: runA?.outputs?.output ?? "N/A",
answer_b: runB?.outputs?.output ?? "N/A",
};
const output = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{
role: "system",
content: [
"Please act as an impartial judge and evaluate the quality of the responses provided by two AI assistants to the user question displayed below.",
"You should choose the assistant that follows the user's instructions and answers the user's question better.",
"Your evaluation should consider factors such as the helpfulness, relevance, accuracy, depth, creativity, and level of detail of their responses.",
"Begin your evaluation by comparing the two responses and provide a short explanation.",
"Avoid any position biases and ensure that the order in which the responses were presented does not influence your decision.",
"Do not allow the length of the responses to influence your evaluation. Do not favor certain names of the assistants. Be as objective as possible.",
].join(" "),
},
{
role: "user",
content: [
`[User Question] ${payload.question}`,
`[The Start of Assistant A's Answer] ${payload.answer_a} [The End of Assistant A's Answer]`,
`The Start of Assistant B's Answer] ${payload.answer_b} [The End of Assistant B's Answer]`,
].join("\n\n"),
},
],
tool_choice: {
type: "function",
function: { name: "Score" },
},
tools: [
{
type: "function",
function: {
name: "Score",
description: [
`After providing your explanation, output your final verdict by strictly following this format:`,
`Output "1" if Assistant A answer is better based upon the factors above.`,
`Output "2" if Assistant B answer is better based upon the factors above.`,
`Output "0" if it is a tie.`,
].join(" "),
parameters: {
type: "object",
properties: {
Preference: {
type: "integer",
description: "Which assistant answer is preferred?",
},
},
},
},
},
],
});
const { Preference } = z
.object({ Preference: z.number() })
.parse(
JSON.parse(output.choices[0].message.tool_calls[0].function.arguments)
);
if (Preference === 1) {
scores[runA.id] = 1;
scores[runB.id] = 0;
} else if (Preference === 2) {
scores[runA.id] = 0;
scores[runB.id] = 1;
} else {
scores[runA.id] = 0;
scores[runB.id] = 0;
}
return { key: "ranked_preference", scores };
}
await evaluate(["earnest-name-40", "reflecting-pump-91"], {
evaluators: [rankedPreference],
});
쌍별 실험 보기 (View pairwise experiments)
데이터셋 페이지에서 "쌍별 실험(Pairwise Experiments)" 탭으로 이동합니다.
검사하려는 쌍별 실험을 클릭하면 비교 보기(Comparison View)로 이동합니다.
첫 번째 실험이 더 나았던 실행 또는 그 반대를 필터링하려면 테이블 헤더의 엄지 올림/엄지 내림 버튼을 클릭하면 됩니다.
더 알아보기 (Learn more)
- 이 문서들을 사용하기 — MCP를 통해 Claude, VSCode 등에 연결하여 실시간 답변을 받아 보세요.
- GitHub에서 이 페이지 편집 또는 이슈 등록