데이터셋으로 평가하기
데이터셋으로 평가하기 (Evaluate with Datasets)
이 가이드는 데이터셋(dataset)을 설정하고, 그 위에서 experiment를 실행하며, 결과를 평가하는 방법을 차근차근 안내해요. 프로덕션에 배포하기 전에 변경사항을 평가하는 데 유용해요. 무엇을 평가할지 아직 모른다면 "무엇을 평가할지 고르기(Choosing what to evaluate)" 가이드가 도움이 돼요.
출처: 문서
본문
이 워크스루는 SDK를 통한 experiment(experiments via SDK) 실행을 위한 것이에요. Langfuse에서 데이터셋을 가져와서 에이전트를 외부에서 실행하고 결과를 Langfuse 플랫폼에 푸시하는 방식이죠. UI에서 프롬프트 experiment를 실행하거나, UI에서 trace에 점수를 매기거나, annotation queue에서 항목을 검토할 수도 있어요.
에이전트 설치 (Agentic installation)
Langfuse Agent Skill을 설치하면 코딩 에이전트가 모든 Langfuse 기능에 접근할 수 있어요.
코딩 에이전트에게 요청하기 | Cursor 플러그인 | 수동 설치
코딩 에이전트에게 github.com/langfuse/skills 저장소를 가리켜 스킬을 설치하라고 요청하고 오프라인 평가로 시작하라고 지시하세요.
Install the Langfuse Agent Skill from github.com/langfuse/skills
and use it to create a first dataset for this application
with Langfuse.
Langfuse에는 스킬을 자동으로 포함하는 Cursor 플러그인이 있어요.
그런 다음 에이전트에게 프롬프트하세요:
Set up offline evaluation for this application with Langfuse.
npm으로 설치 (skills CLI):
npx skills add langfuse/skills --skill "langfuse"
특정 에이전트를 직접 지정하려면:
npx skills add langfuse/skills --skill "langfuse" --agent "<agent-id>"
또는 스킬을 수동으로 클론할 수도 있어요:
- 안정적인 위치에 저장소를 클론하세요.
git clone https://github.com/langfuse/skills.git /path/to/langfuse-skills
- 에이전트의 skills 디렉토리가 존재하는지 확인하세요.
mkdir -p /path/to/<agent-skill-root>/skills
- 스킬 폴더를 심링크하세요.
ln -s /path/to/langfuse-skills/skills/langfuse /path/to/<agent-skill-root>/skills/langfuse
그런 다음 에이전트에게 프롬프트하세요:
Set up offline evaluation for this application with Langfuse.
수동 설정 (Manual setup)
시스템의 성능을 테스트하는 experiment를 실행하는 데는 세 가지 측면이 있어요:
- 데이터셋(Dataset): 입력과 기대 출력을 갖는 테스트 케이스
- Experiment 조건: 테스트하려는 애플리케이션 변형 또는 모델 호출
- 평가기(Evaluators): 출력을 점수화하는 함수
이 가이드는 현재 Langfuse SDK를 사용해요: Python SDK v4와 JS/TS SDK v5. 둘 다 Langfuse의 OpenTelemetry 기반 트레이싱과 현재 experiment runner를 사용해요. 이전 SDK를 쓴다면 Python v3 → v4 또는 JS/TS v4 → v5 마이그레이션 가이드를 참고하세요.
프로젝트 생성 및 API 키 얻기 (Create a project and get API keys)
- Langfuse 계정을 만들거나 Langfuse를 셀프호스팅하세요.
- 프로젝트를 만들고 Settings → API Keys를 여세요.
- 모델 프로바이더용 API 키를 만드세요. 이 예시는 OpenAI를 사용해요.
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://cloud.langfuse.com"
export OPENAI_API_KEY="sk-..."
키를 환경 변수로 설정하세요. Langfuse Cloud 데이터 리전 또는 셀프호스팅 배포의 base URL을 사용하세요.
SDK 설치 (Install the SDKs)
pip install langfuse openai
# pnpm
pnpm add @langfuse/client @langfuse/openai @langfuse/otel @opentelemetry/sdk-node openai tsx
# npm
npm install @langfuse/client @langfuse/openai @langfuse/otel @opentelemetry/sdk-node openai tsx
Python SDK | JS/TS SDK
데이터셋 만들기 (Create the dataset)
데이터셋은 테스트 케이스의 모음이에요. 각 항목은 입력을 가지며, 선택적으로 평가기가 비교할 수 있는 기대 출력을 가져요. 첫 데이터셋은 대표적인 케이스를 몇 개 가질 수 있고, 나중에 무엇이 실패하는지 배우면서 성장시킬 수 있어요.
아래 예시는 샌프란시스코 관광 명소에 관한 질문 다섯 개를 추가해요.
Python SDK
from langfuse import get_client
langfuse = get_client()
dataset_name = "san-francisco-sites"
langfuse.create_dataset(
name=dataset_name,
description="Questions and expected answers about sites in San Francisco",
)
items = [
{
"id": "evaluation-quickstart-sf-golden-gate-bridge",
"input": {
"question": "Which red-orange suspension bridge connects San Francisco with Marin County?"
},
"expected_output": "Golden Gate Bridge",
},
{
"id": "evaluation-quickstart-sf-alcatraz-island",
"input": {
"question": "Which island in San Francisco Bay is home to a former federal prison?"
},
"expected_output": "Alcatraz Island",
},
{
"id": "evaluation-quickstart-sf-palace-of-fine-arts",
"input": {
"question": "Which Beaux-Arts landmark in the Marina District features a rotunda beside a lagoon?"
},
"expected_output": "Palace of Fine Arts",
},
{
"id": "evaluation-quickstart-sf-coit-tower",
"input": {
"question": "Which Art Deco tower stands on Telegraph Hill?"
},
"expected_output": "Coit Tower",
},
{
"id": "evaluation-quickstart-sf-lombard-street",
"input": {
"question": "Which San Francisco street is famous for a steep block with eight hairpin turns?"
},
"expected_output": "Lombard Street",
},
]
for item in items:
langfuse.create_dataset_item(dataset_name=dataset_name, **item)
print(f"Created {dataset_name} with {len(items)} items")
이 설정 스크립트를 한 번 실행하세요. 다음 단계의 experiment 스크립트는 저장된 데이터셋을 재사용해요.
python seed_dataset.py
실행:
JS/TS SDK
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const datasetName = "san-francisco-sites";
const items = [
{
id: "evaluation-quickstart-sf-golden-gate-bridge",
input: {
question:
"Which red-orange suspension bridge connects San Francisco with Marin County?",
},
expectedOutput: "Golden Gate Bridge",
},
{
id: "evaluation-quickstart-sf-alcatraz-island",
input: {
question:
"Which island in San Francisco Bay is home to a former federal prison?",
},
expectedOutput: "Alcatraz Island",
},
{
id: "evaluation-quickstart-sf-palace-of-fine-arts",
input: {
question:
"Which Beaux-Arts landmark in the Marina District features a rotunda beside a lagoon?",
},
expectedOutput: "Palace of Fine Arts",
},
{
id: "evaluation-quickstart-sf-coit-tower",
input: {
question: "Which Art Deco tower stands on Telegraph Hill?",
},
expectedOutput: "Coit Tower",
},
{
id: "evaluation-quickstart-sf-lombard-street",
input: {
question:
"Which San Francisco street is famous for a steep block with eight hairpin turns?",
},
expectedOutput: "Lombard Street",
},
];
async function main() {
await langfuse.api.datasets.create({
name: datasetName,
description: "Questions and expected answers about sites in San Francisco",
});
for (const item of items) {
await langfuse.dataset.createItem({
datasetName,
...item,
});
}
console.log(`Created ${datasetName} with ${items.length} items`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
이 설정 스크립트를 한 번 실행하세요. 다음 단계의 experiment 스크립트는 저장된 데이터셋을 재사용해요.
npx tsx seed-dataset.ts
실행:
Langfuse UI
Langfuse UI에서 Datasets로 이동해 + New dataset을 클릭하세요. 다음 단계의 예시 experiment를 스크립트 변경 없이 실행하려면 이름을 san-francisco-sites로 지으면 돼요.

항목을 하나씩 추가하거나, CSV를 가져오거나, 기존 trace에서 케이스를 추가하세요. 샌프란시스코 예시에서 각 항목의 입력은 질문이고 기대 출력은 사이트 이름이에요. 자신의 사용 사례에 맞는 항목 수와 입력 형태를 쓰면 돼요. (Add item / Import CSV / Add from trace)
CSV 가져오기, trace에서 항목 추가, 데이터셋 버전에 대해서는 Datasets를 참고하세요.
SDK로 항목을 만들 때 데이터셋 항목 ID는 안정적이어서, 같은 ID로 항목을 추가하면 중복을 만들지 않고 업데이트해요.
Experiment 실행하기 (Run an experiment)
SDK는 각 데이터셋 항목에 대해 기존 애플리케이션을 실행해요. 애플리케이션은 자체 환경에 남아 도구, 검색 로직, 의존성에 접근할 수 있어요. task 함수는 각 항목을 애플리케이션의 입력에 매핑하고 평가를 위해 출력을 반환해요. 프롬프트+모델 조합만 테스트하면 된다면 UI에서 프롬프트 experiment를 실행할 수도 있어요.
UI에서 웹훅을 설정해 외부 실행을 트리거하면 SDK experiment를 시작할 수도 있어요.
Python SDK
from langfuse import Evaluation, get_client
from langfuse.openai import OpenAI
langfuse = get_client()
client = OpenAI()
def answer_question(question: str):
# Sample application. Replace with an import of your existing application.
response = client.responses.create(
model="gpt-5-mini",
input=[
{
"role": "system",
"content": "Answer the question about a site in San Francisco.",
},
{"role": "user", "content": question},
],
)
return response.output_text
def application_task(*, item, **kwargs):
# Adapt the dataset input to your application's function signature.
return answer_question(item.input["question"])
def exact_match(*, output, expected_output, **kwargs):
return Evaluation(
name="exact_match",
value=1.0 if output == expected_output else 0.0,
)
try:
dataset = langfuse.get_dataset("san-francisco-sites")
result = dataset.run_experiment(
name="San Francisco sites",
run_name="San Francisco sites v1",
description="First prompt for answering questions about San Francisco sites",
task=application_task,
evaluators=[exact_match],
)
print(result.format())
finally:
# Required for short-lived processes so all traces reach Langfuse.
langfuse.flush()
아래 예시는 스크립트를 실행 가능하게 유지하기 위해 작은 answer_question / answerQuestion 애플리케이션 함수를 사용해요. 자신의 프로젝트에서는 기존 애플리케이션 함수를 그 자리에 임포트하고 task는 얇은 어댑터로 유지하세요. 애플리케이션에 필요한 모든 입력을 전달하고, 프로덕션에서 쓰는 것과 같은 코드 경로의 출력을 평가하세요. 평가기는 출력이 기대 사이트 이름과 정확히 일치하면 1, 아니면 0을 반환해요.
python sf_sites.py
JS/TS SDK
import { LangfuseClient, type Evaluator } from "@langfuse/client";
import { observeOpenAI } from "@langfuse/openai";
import { LangfuseSpanProcessor } from "@langfuse/otel";
import { NodeSDK } from "@opentelemetry/sdk-node";
import OpenAI from "openai";
const otelSdk = new NodeSDK({
spanProcessors: [new LangfuseSpanProcessor()],
});
otelSdk.start();
const langfuse = new LangfuseClient();
const client = observeOpenAI(new OpenAI());
// Sample application. Replace with an import of your existing application.
async function answerQuestion(question: string): Promise<string> {
const response = await client.responses.create({
model: "gpt-5-mini",
input: [
{
role: "system",
content: "Answer the question about a site in San Francisco.",
},
{ role: "user", content: question },
],
});
return response.output_text;
}
const exactMatch: Evaluator = async ({ output, expectedOutput }) => ({
name: "exact_match",
value: output === expectedOutput ? 1 : 0,
});
async function main() {
const dataset = await langfuse.dataset.get("san-francisco-sites");
const result = await dataset.runExperiment({
name: "San Francisco sites",
runName: "San Francisco sites v1",
description:
"First prompt for answering questions about San Francisco sites",
task: async (item) => {
const { question } = item.input as { question: string };
// Adapt the dataset input to your application's function signature.
return answerQuestion(question);
},
evaluators: [exactMatch],
});
console.log(await result.format({ includeItemResults: true }));
}
main()
.catch((error) => {
console.error(error);
process.exitCode = 1;
})
// Required for short-lived processes so all traces reach Langfuse.
.finally(() => otelSdk.shutdown());
experiment를 실행하세요:
npx tsx sf-sites.ts
experiment runner는 동시 실행을 처리하고, 각 task를 트레이싱하며, 평가기 점수를 첨부하고, Langfuse에서 검사하고 비교할 수 있는 dataset run을 만들어요.
결정적 검사를 재사용하고, 애플리케이션 버전을 비교하며, CI 게이트를 추가하는 실제 예시는 "Evaluate an existing application"을 참고하세요.
결과 보기 (View the results)
포맷된 터미널 출력에는 experiment 요약과 dataset run 링크가 포함돼요. Langfuse에서 Experiments를 열 수도 있어요.
각 항목에 대해 다음을 검사할 수 있어요:
- 데이터셋 입력과 기대 출력
- 모델의 응답
- 정확 일치(exact-match) 점수
- 지연시간, 토큰 사용량, 비용을 포함한 트레이싱된 OpenAI 호출
프롬프트 개선 및 비교 (Improve the prompt and compare)
Exact match는 의도적으로 엄격해요. "The answer is Coit Tower." 같은 답변은
Coit Tower와 정확히 같지 않으므로 0을 받아요.
시스템 메시지를 다음으로 바꾸고:
Answer the question about a site in San Francisco. Return only the site's official name, with no additional text or punctuation.
run 이름을 San Francisco sites v2로 변경하세요.
스크립트를 다시 실행하세요. 두 run 모두 같은 저장된 데이터셋을 사용하므로 Experiments 뷰에서 집계 점수와 개별 출력을 나란히 비교할 수 있어요.
FAQ
데이터셋이 이미 존재하면? 설정 스크립트는 데이터셋을 만들고 한 번만 실행하도록 의도됐어요. san-francisco-sites가 이미 있으면 데이터셋 생성 호출을 건너뛰고 항목 생성 루프만 유지하세요. 안정적인 항목 ID 덕분에 그 호출들은 반복해도 안전해요.
왜 experiment에 trace가 없나요? Langfuse 환경 변수를 확인하세요. Python은 스크립트 끝에 langfuse.flush()를 유지하고, JS/TS는 단기 프로세스가 종료되기 전에 모든 버퍼링된 span을 내보내도록 otelSdk.shutdown()을 유지하세요.
왜 일부 exact-match 점수가 0인가요? 영향을 받은 항목을 열어 모델 출력과 기대 출력을 비교하세요. 대문자, 추가 단어, 구두점 모두 exact match를 실패하게 만들어요. 결정적 출력 계약에 유용하며, 정확성이 의미론적 판단을 요구할 때는 LLM-as-a-Judge를 사용하세요.
다음 단계 (Next steps)
- 데이터셋과 데이터셋 버전이 재현 가능한 테스트를 지원하는 방법을 배워요.
- task 함수를 작성하지 않고 experiments via UI로 프롬프트와 모델을 비교해요.
- async 평가기, 동시성, run 레벨 메트릭을 포함한 전체 experiment runner SDK를 살펴봐요.
- 배포 전 회귀를 잡기 위해 experiments를 CI/CD에 추가해요.
- 신뢰할 수 있는 평가기를 작성해요.
- 애플리케이션에 맞는 code evaluators, LLM-as-a-Judge, 사람 검토 중에서 선택해요.