데이터셋 직렬화
데이터셋 직렬화 (Dataset Serialization)
데이터셋을 다양한 형식으로 저장하고 불러오는 방법을 배워요. 커스텀 평가자와 IDE 통합을 지원해요.
Pydantic Evals는 데이터셋을 파일로 직렬화하는 두 가지 형식을 지원해요:
- YAML (
.yaml,.yml) - 사람이 읽기 쉬워 버전 관리에 좋아요 - JSON (
.json) - 구조화되어 있고 기계가 읽기 좋아요
두 형식 모두 다음을 지원해요:
- IDE 자동 완성과 검증을 위한 자동 JSON 스키마 생성
- 커스텀 평가자 직렬화/역직렬화
- 제네릭 매개변수로 타입 안전하게 불러오기
출처: 문서
본문
YAML 형식
YAML은 가독성과 간결한 문법 덕분에 대부분의 사용 사례에 권장되는 형식이에요.
기본 예시
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import EqualsExpected, IsInstance
# 타입 매개변수로 데이터셋 만들기
dataset = Dataset[str, str, Any](
name='my_tests',
cases=[
Case(
name='test_1',
inputs='hello',
expected_output='HELLO',
),
],
evaluators=[
IsInstance(type_name='str'),
EqualsExpected(),
],
)
# YAML로 저장
dataset.to_file('my_tests.yaml')
이렇게 하면 두 개의 파일이 만들어져요:
my_tests.yaml- 데이터셋my_tests_schema.json- IDE 지원용 JSON 스키마
YAML 출력
# yaml-language-server: $schema=my_tests_schema.json
name: my_tests
cases:
- name: test_1
inputs: hello
expected_output: HELLO
evaluators:
- IsInstance: str
- EqualsExpected
IDE용 JSON 스키마
첫 번째 줄이 스키마 파일을 참조해요:
# yaml-language-server: $schema=my_tests_schema.json
이렇게 하면 다음이 가능해져요:
- ✅ VS Code, PyCharm 및 기타 편집기에서 자동 완성
- ✅ 편집 중 인라인 검증
- ✅ 필드에 대한 문서 툴팁
- ✅ 잘못된 데이터에 대한 오류 강조
편집기 지원
yaml-language-server 주석은 다음에서 지원돼요:
- VS Code (YAML 확장 포함)
- JetBrains IDE (PyCharm, IntelliJ 등)
- YAML 언어 서버를 지원하는 대부분의 편집기
자세한 내용은 YAML Language Server 문서를 참고해요.
YAML에서 불러오기
from pathlib import Path
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import EqualsExpected, IsInstance
# 먼저 데이터셋을 만들고 저장
Path('my_tests.yaml').parent.mkdir(exist_ok=True)
dataset = Dataset[str, str, Any](
name='my_tests',
cases=[Case(name='test_1', inputs='hello', expected_output='HELLO')],
evaluators=[IsInstance(type_name='str'), EqualsExpected()],
)
dataset.to_file('my_tests.yaml')
# 타입 매개변수로 데이터셋 불러오기
dataset = Dataset[str, str, Any].from_file('my_tests.yaml')
def my_task(text: str) -> str:
return text.upper()
# 평가 실행
report = dataset.evaluate_sync(my_task)
JSON 형식
JSON 형식은 프로그래밍 방식의 생성이나 엄격한 구조가 필요할 때 유용해요.
기본 예시
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import EqualsExpected
dataset = Dataset[str, str, Any](
name='my_tests',
cases=[
Case(name='test_1', inputs='hello', expected_output='HELLO'),
],
evaluators=[EqualsExpected()],
)
# JSON으로 저장
dataset.to_file('my_tests.json')
JSON 출력
{
"$schema": "my_tests_schema.json",
"name": "my_tests",
"cases": [
{
"name": "test_1",
"inputs": "hello",
"expected_output": "HELLO"
}
],
"evaluators": [
"EqualsExpected"
]
}
맨 위의 $schema 키가 YAML과 유사하게 IDE 지원을 가능하게 해요.
JSON에서 불러오기
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import EqualsExpected
# 먼저 데이터셋을 만들고 저장
dataset = Dataset[str, str, Any](
name='my_tests',
cases=[Case(name='test_1', inputs='hello', expected_output='HELLO')],
evaluators=[EqualsExpected()],
)
dataset.to_file('my_tests.json')
# JSON에서 불러오기
dataset = Dataset[str, str, Any].from_file('my_tests.json')
스키마 생성
자동 스키마 생성
기본적으로 to_file()은 데이터셋과 함께 JSON 스키마 파일을 만들어요:
from typing import Any
from pydantic_evals import Case, Dataset
dataset = Dataset[str, str, Any](name='my_tests', cases=[Case(inputs='test')])
# my_tests.yaml과 my_tests_schema.json 둘 다 생성
dataset.to_file('my_tests.yaml')
커스텀 스키마 위치
from pathlib import Path
from typing import Any
from pydantic_evals import Case, Dataset
dataset = Dataset[str, str, Any](name='my_tests', cases=[Case(inputs='test')])
# 디렉토리 만들기
Path('data').mkdir(exist_ok=True)
# 커스텀 스키마 파일명 (데이터셋 파일 위치 기준)
dataset.to_file(
'data/my_tests.yaml',
schema_path='my_schema.json',
)
# 스키마 파일 없음
dataset.to_file('my_tests.yaml', schema_path=None)
스키마 경로 템플릿
{stem}을 사용해 데이터셋 파일명을 참조해요:
from typing import Any
from pydantic_evals import Case, Dataset
dataset = Dataset[str, str, Any](name='my_tests', cases=[Case(inputs='test')])
# my_tests.yaml과 my_tests.schema.json 생성
dataset.to_file(
'my_tests.yaml',
schema_path='{stem}.schema.json',
)
수동 스키마 생성
데이터셋을 저장하지 않고 스키마를 생성해요:
import json
from typing import Any
from pydantic_evals import Dataset
# 특정 데이터셋 타입에 대한 스키마를 딕셔너리로 가져오기
schema = Dataset[str, str, Any].model_json_schema_with_evaluators()
# 수동으로 저장
with open('custom_schema.json', 'w', encoding='utf-8') as f:
json.dump(schema, f, indent=2)
커스텀 평가자
커스텀 평가자는 직렬화와 역직렬화 중 특별한 처리가 필요해요.
요구사항
커스텀 평가자는 반드시:
@dataclass로 장식돼야 해요Evaluator를 상속해야 해요to_file()과from_file()둘 다에 전달돼야 해요
완전한 예시
from dataclasses import dataclass
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import Evaluator, EvaluatorContext
@dataclass
class CustomThreshold(Evaluator):
"""Check if output length exceeds a threshold."""
min_length: int
max_length: int = 100
def evaluate(self, ctx: EvaluatorContext) -> bool:
length = len(str(ctx.output))
return self.min_length <= length <= self.max_length
# 커스텀 평가자로 데이터셋 만들기
dataset = Dataset[str, str, Any](
name='custom_threshold_tests',
cases=[
Case(
name='test_length',
inputs='example',
expected_output='long result',
evaluators=[
CustomThreshold(min_length=5, max_length=20),
],
),
],
)
# 커스텀 평가자 타입으로 저장
dataset.to_file(
'dataset.yaml',
custom_evaluator_types=[CustomThreshold],
)
저장된 YAML
# yaml-language-server: $schema=dataset_schema.json
cases:
- name: test_length
inputs: example
expected_output: long result
evaluators:
- CustomThreshold:
min_length: 5
max_length: 20
커스텀 평가자로 불러오기
from dataclasses import dataclass
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import Evaluator, EvaluatorContext
@dataclass
class CustomThreshold(Evaluator):
"""Check if output length exceeds a threshold."""
min_length: int
max_length: int = 100
def evaluate(self, ctx: EvaluatorContext) -> bool:
length = len(str(ctx.output))
return self.min_length <= length <= self.max_length
# 먼저 데이터셋을 만들고 저장
dataset = Dataset[str, str, Any](
name='custom_threshold_tests',
cases=[
Case(
name='test_length',
inputs='example',
expected_output='long result',
evaluators=[CustomThreshold(min_length=5, max_length=20)],
),
],
)
dataset.to_file('dataset.yaml', custom_evaluator_types=[CustomThreshold])
# 커스텀 평가자 레지스트리로 불러오기
dataset = Dataset[str, str, Any].from_file(
'dataset.yaml',
custom_evaluator_types=[CustomThreshold],
)
중요
custom_evaluator_types를 to_file()과 from_file() 둘 다에 전달해야 해요.
to_file(): 평가자를 JSON 스키마에 포함from_file(): 역직렬화를 위해 평가자 등록
평가자 직렬화 형식
평가자는 세 가지 형태로 직렬화될 수 있어요:
1. 이름만 (매개변수 없음)
evaluators:
- EqualsExpected
- IsInstance: str # 기본 매개변수 사용
2. 단일 매개변수 (짧은 형식)
evaluators:
- IsInstance: str
- Contains: "required text"
- MaxDuration: 2.0
3. 여러 매개변수 (Dict 형식)
evaluators:
- CustomThreshold:
min_length: 5
max_length: 20
- LLMJudge:
rubric: "Response is accurate"
model: "openai:gpt-5"
include_input: true
형식 비교
| 기능 | YAML | JSON |
|---|---|---|
| 사람이 읽기 쉬움 | ✅ 훌륭함 | ⚠️ 좋음 |
| 주석 | ✅ 가능 | ❌ 불가 |
| 간결함 | ✅ 예 | ⚠️ 장황함 |
| 기계 파싱 | ✅ 좋음 | ✅ 훌륭함 |
| IDE 지원 | ✅ 예 | ✅ 예 |
| 버전 관리 | ✅ 깔끔한 diff | ⚠️ 시끄러운 diff |
권장: 대부분의 경우 YAML을, 프로그래밍 방식 생성에는 JSON을 사용해요.
고급: 평가자 직렬화 이름
직렬화된 파일에서 평가자가 표시되는 방식을 커스터마이즈해요:
from dataclasses import dataclass
from pydantic_evals.evaluators import Evaluator, EvaluatorContext
@dataclass
class VeryLongDescriptiveEvaluatorName(Evaluator):
@classmethod
def get_serialization_name(cls) -> str:
return 'ShortName'
def evaluate(self, ctx: EvaluatorContext) -> bool:
return True
YAML에서:
evaluators:
- ShortName # VeryLongDescriptiveEvaluatorName 대신
문제 해결
IDE에서 스키마를 찾지 못함
문제: YAML 파일에 자동 완성이 표시되지 않음
해결 방법:
-
YAML 첫 줄의 스키마 경로를 확인해요:
# yaml-language-server: $schema=correct_schema_name.json -
같은 디렉토리에 스키마 파일이 존재하는지 확인해요
-
IDE에서 언어 서버를 재시작해요
-
YAML 확장 설치 (VS Code: Red Hat의 "YAML")
커스텀 평가자를 찾지 못함
문제: ValueError: Unknown evaluator name: 'CustomEvaluator'
해결 방법: 불러올 때 custom_evaluator_types를 전달해요:
from dataclasses import dataclass
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import Evaluator, EvaluatorContext
@dataclass
class CustomEvaluator(Evaluator):
def evaluate(self, ctx: EvaluatorContext) -> bool:
return True
# 먼저 커스텀 평가자로 만들고 저장
dataset = Dataset[str, str, Any](
name='custom_eval_tests',
cases=[Case(inputs='test', evaluators=[CustomEvaluator()])],
)
dataset.to_file('tests.yaml', custom_evaluator_types=[CustomEvaluator])
# 커스텀 평가자 타입으로 불러오기
dataset = Dataset[str, str, Any].from_file(
'tests.yaml',
custom_evaluator_types=[CustomEvaluator], # 필수!
)
형식 추론 실패
문제: ValueError: Cannot infer format from extension
해결 방법: 형식을 명시적으로 지정해요:
from typing import Any
from pydantic_evals import Case, Dataset
dataset = Dataset[str, str, Any](name='my_tests', cases=[Case(inputs='test')])
# 특이한 확장자용 명시적 형식
dataset.to_file('data.txt', fmt='yaml')
dataset_loaded = Dataset[str, str, Any].from_file('data.txt', fmt='yaml')
스키마 생성 오류
문제: 커스텀 평가자가 스키마 생성에 실패함
해결 방법: 평가자가 올바른 dataclass인지 확인해요:
from dataclasses import dataclass
from pydantic_evals.evaluators import Evaluator, EvaluatorContext
# ✅ 올바름
@dataclass
class MyEvaluator(Evaluator):
value: int
def evaluate(self, ctx: EvaluatorContext) -> bool:
return True
# ❌ 오류: @dataclass 누락
class BadEvaluator(Evaluator):
def __init__(self, value: int):
self.value = value
def evaluate(self, ctx: EvaluatorContext) -> bool:
return True
다음 단계
더 알아보기 (Learn more)
- Pydantic Evals 문서: 데이터셋 직렬화