메인 콘텐츠로 건너뛰기
EvaluationLogger는 Python 또는 TypeScript 코드에서 평가 데이터를 직접 로깅할 수 있는 유연하고 점진적인 방법을 제공합니다. Weave의 내부 데이터 타입을 깊이 알 필요는 없습니다. 로거 인스턴스를 생성한 뒤, 제공되는 메서드들(log_prediction, log_score, log_summary)을 사용해 평가 단계를 기록하면 됩니다. 이 접근 방식은 전체 데이터셋이나 모든 스코어러가 처음부터 정의되어 있지 않을 수 있는 복잡한 워크플로우에서 특히 유용합니다. 미리 정의된 DatasetScorer 객체 목록이 필요한 표준 Evaluation 객체와 달리, EvaluationLogger를 사용하면 개별 예측과 해당 점수를 사용 가능해지는 대로 점진적으로 로깅할 수 있습니다.
더 구조화된 평가를 선호하나요?미리 정의된 데이터셋과 스코어러가 있는, 보다 의견이 반영된 평가 프레임워크를 선호한다면 Weave의 표준 Evaluation 프레임워크를 참고하세요.EvaluationLogger는 유연성을 제공하는 반면, 표준 프레임워크는 구조와 가이드를 제공합니다.

기본 워크플로

  1. 로거 초기화: EvaluationLogger 인스턴스를 생성하고, 필요하다면 modeldataset에 대한 메타데이터를 선택적으로 제공할 수 있습니다. 생략하면 기본값이 사용됩니다.
    LLM 호출(예: OpenAI)의 토큰 사용량 및 비용을 수집하려면, 어떤 LLM을 호출하기 이전에 EvaluationLogger를 초기화하세요. 먼저 LLM을 호출한 뒤에 예측 결과를 로깅하면 토큰 및 비용 데이터는 수집되지 않습니다.
  2. 예측 로깅: 시스템의 각 입력/출력 쌍에 대해 log_prediction을 호출합니다.
  3. 점수 로깅: 반환된 ScoreLogger를 사용해 해당 예측에 대해 log_score를 호출합니다. 하나의 예측에 대해 여러 개의 점수를 기록할 수 있습니다.
  4. 예측 완료: 예측에 대한 점수 로깅을 마친 후에는 항상 finish()를 호출하여 예측을 최종 확정합니다.
  5. 요약 로깅: 모든 예측이 처리된 후 log_summary를 호출하여 점수를 집계하고 선택적으로 커스텀 메트릭을 추가합니다.
하나의 예측에 대해 finish()를 호출한 이후에는 해당 예측에 더 이상 점수를 로깅할 수 없습니다.
위에서 설명한 워크플로를 보여주는 Python 코드 예시는 기본 예제를 참조하세요.

기본 예제

다음 예제는 기존 코드 흐름 안에서 EvaluationLogger를 사용해 예측값과 점수를 함께 로깅하는 방법을 보여줍니다.
user_model 모델 함수가 정의되어 입력 목록에 적용됩니다. 각 예제에 대해 다음을 수행합니다:
  • 입력과 출력이 log_prediction을 사용해 로그에 기록됩니다.
  • 단순 정확도 점수(correctness_score)가 log_score를 통해 로그에 기록됩니다.
  • finish()가 해당 예측에 대한 로깅을 마무리합니다. 마지막으로 log_summary가 집계 메트릭을 기록하고, Weave에서 점수를 자동으로 요약하도록 트리거합니다.
import weave
from openai import OpenAI
from weave import EvaluationLogger

weave.init('your-team/your-project')

# 토큰 추적을 보장하려면 모델 호출 전에 EvaluationLogger를 초기화하세요
eval_logger = EvaluationLogger(
    model="my_model",
    dataset="my_dataset"
)

# 예시 입력 데이터 (원하는 어떤 데이터 구조든 사용 가능)
eval_samples = [
    {'inputs': {'a': 1, 'b': 2}, 'expected': 3},
    {'inputs': {'a': 2, 'b': 3}, 'expected': 5},
    {'inputs': {'a': 3, 'b': 4}, 'expected': 7},
]

# OpenAI를 사용한 예시 모델 로직
@weave.op
def user_model(a: int, b: int) -> int:
    oai = OpenAI()
    response = oai.chat.completions.create(
        messages=[{"role": "user", "content": f"What is {a}+{b}?"}],
        model="gpt-4o-mini"
    )
    # 응답을 어떤 방식으로든 활용 (여기서는 단순화를 위해 a + b를 반환)
    return a + b

# 예시를 순회하며 예측하고 로깅
for sample in eval_samples:
    inputs = sample["inputs"]
    model_output = user_model(**inputs) # 입력을 kwargs로 전달

    # 예측 입력 및 출력 로깅
    pred_logger = eval_logger.log_prediction(
        inputs=inputs,
        output=model_output
    )

    # 이 예측에 대한 점수 계산 및 로깅
    expected = sample["expected"]
    correctness_score = model_output == expected
    pred_logger.log_score(
        scorer="correctness", # 스코어러의 간단한 문자열 이름
        score=correctness_score
    )

    # 이 예측에 대한 로깅 완료
    pred_logger.finish()

# 전체 평가에 대한 최종 요약 로깅.
# Weave가 위에서 로깅된 'correctness' 점수를 자동으로 집계합니다.
summary_stats = {"subjective_overall_score": 0.8}
eval_logger.log_summary(summary_stats)

print("평가 로깅이 완료되었습니다. Weave UI에서 결과를 확인하세요.")

고급 사용법

EvaluationLogger는 기본 워크플로를 넘어서는 유연한 패턴을 제공하여 더 복잡한 평가 시나리오를 처리할 수 있도록 합니다. 이 섹션에서는 자동 리소스 관리를 위한 컨텍스트 매니저 사용, 모델 실행과 로깅의 분리, 풍부한 미디어 데이터 처리, 여러 모델 평가를 나란히 비교하기 등의 고급 기법을 다룹니다.

컨텍스트 매니저 사용하기

EvaluationLogger는 예측과 점수 모두에 대해 컨텍스트 매니저(with 구문)를 지원합니다. 이를 사용하면 코드가 더 깔끔해지고, 리소스가 자동으로 정리되며, LLM 판정 호출과 같은 중첩 연산을 더 잘 추적할 수 있습니다. 이 문맥에서 with 구문을 사용하면 다음과 같은 장점이 있습니다:
  • 컨텍스트를 벗어날 때 finish()가 자동으로 호출됨
  • 중첩된 LLM 호출에 대한 토큰/비용 추적 개선
  • 예측 컨텍스트 내에서 모델 실행 이후 출력 설정
import openai
import weave

weave.init("nested-evaluation-example")
oai = openai.OpenAI()

# Initialize the logger
ev = weave.EvaluationLogger(
    model="gpt-4o-mini",
    dataset="joke_dataset"
)

user_prompt = "Tell me a joke"

# Use context manager for prediction - no need to call finish()
with ev.log_prediction(inputs={"user_prompt": user_prompt}) as pred:
    # Make your model call within the context
    result = oai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": user_prompt}],
    )

    # Set the output after the model call
    pred.output = result.choices[0].message.content

    # Log simple scores
    pred.log_score("correctness", 1.0)
    pred.log_score("ambiguity", 0.3)
    
    # Use nested context manager for scores that require LLM calls
    with pred.log_score("llm_judge") as score:
        judge_result = oai.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "Rate how funny the joke is from 1-5"},
                {"role": "user", "content": pred.output},
            ],
        )
        # Set the score value after computation
        score.value = judge_result.choices[0].message.content

# finish() is automatically called when exiting the 'with' block

ev.log_summary({"avg_score": 1.0})
이 패턴은 모든 중첩 연산이 상위 예측에 연결되어 추적되도록 보장하므로, Weave UI에서 정확한 토큰 사용량과 비용 데이터를 확인할 수 있습니다.

로깅 전에 출력 계산하기

먼저 모델 출력을 계산한 다음, 예측값과 점수를 별도로 로깅할 수 있습니다. 이렇게 하면 평가 로직과 로깅 로직을 더 잘 분리할 수 있습니다.
# 토큰 추적을 위해 모델을 호출하기 전에 EvaluationLogger를 초기화
ev = EvaluationLogger(
    model="example_model",
    dataset="example_dataset"
)

# 토큰 추적을 위해 모델 출력(예: OpenAI 호출)은 로거 초기화 이후에 수행해야 함
outputs = [your_output_generator(**inputs) for inputs in your_dataset]
preds = [ev.log_prediction(inputs, output) for inputs, output in zip(your_dataset, outputs)]
for pred, output in zip(preds, outputs):
    pred.log_score(scorer="greater_than_5_scorer", score=output > 5)
    pred.log_score(scorer="greater_than_7_scorer", score=output > 7)
    pred.finish()

ev.log_summary()

리치 미디어 로깅

입력, 출력, 점수에는 이미지, 비디오, 오디오, 구조화된 테이블과 같은 리치 미디어를 포함할 수 있습니다. log_prediction 또는 log_score 메서드에 dict 또는 미디어 객체를 그대로 전달하면 됩니다.
import io
import wave
import struct
from PIL import Image
import random
from typing import Any
import weave

def generate_random_audio_wave_read(duration=2, sample_rate=44100):
    n_samples = duration * sample_rate
    amplitude = 32767  # 16-bit 최대 진폭

    buffer = io.BytesIO()

    # wave 데이터를 버퍼에 씀
    with wave.open(buffer, 'wb') as wf:
        wf.setnchannels(1)
        wf.setsampwidth(2)  # 16-bit
        wf.setframerate(sample_rate)

        for _ in range(n_samples):
            sample = random.randint(-amplitude, amplitude)
            wf.writeframes(struct.pack('<h', sample))

    # 버퍼 위치를 처음으로 되돌려 읽을 수 있게 함
    buffer.seek(0)

    # Wave_read 객체 반환
    return wave.open(buffer, 'rb')

rich_media_dataset = [
    {
        'image': Image.new(
            "RGB",
            (100, 100),
            color=(
                random.randint(0, 255),
                random.randint(0, 255),
                random.randint(0, 255),
            ),
        ),
        "audio": generate_random_audio_wave_read(),
    }
    for _ in range(5)
]

@weave.op
def your_output_generator(image: Image.Image, audio) -> dict[str, Any]:
    return {
        "result": random.randint(0, 10),
        "image": image,
        "audio": audio,
    }

ev = EvaluationLogger(model="example_model", dataset="example_dataset")

for inputs in rich_media_dataset:
    output = your_output_generator(**inputs)
    pred = ev.log_prediction(inputs, output)
    pred.log_score(scorer="greater_than_5_scorer", score=output["result"] > 5)
    pred.log_score(scorer="greater_than_7_scorer", score=output["result"] > 7)

ev.log_summary()

여러 평가를 기록하고 비교하기

EvaluationLogger를 사용하면 여러 평가를 기록하고 비교할 수 있습니다.
  1. 아래에 표시된 코드 예제를 실행합니다.
  2. Weave UI에서 Evals 탭으로 이동합니다.
  3. 비교하려는 eval을 선택합니다.
  4. Compare 버튼을 클릭합니다. Compare 뷰에서 다음을 수행할 수 있습니다.
    • 추가하거나 제거할 Evals를 선택합니다.
    • 표시하거나 숨길 메트릭을 선택합니다.
    • 특정 예시를 넘겨 보면서 동일한 데이터셋의 동일한 입력에 대해 서로 다른 모델이 어떻게 동작했는지 확인할 수 있습니다.
    비교에 대한 자세한 내용은 비교(Comparisons)을 참조하세요.
import weave

models = [
    "model1",
    "model2",
     {"name": "model3", "metadata": {"coolness": 9001}}
]

for model in models:
    # EvalLogger must be initialized before model calls to capture tokens
    ev = EvaluationLogger(
        name="comparison-eval",
        model=model, 
        dataset="example_dataset",
        scorers=["greater_than_3_scorer", "greater_than_5_scorer", "greater_than_7_scorer"],
        eval_attributes={"experiment_id": "exp_123"}
    )
    for inputs in your_dataset:
        output = your_output_generator(**inputs)
        pred = ev.log_prediction(inputs=inputs, output=output)
        pred.log_score(scorer="greater_than_3_scorer", score=output > 3)
        pred.log_score(scorer="greater_than_5_scorer", score=output > 5)
        pred.log_score(scorer="greater_than_7_scorer", score=output > 7)
        pred.finish()

    ev.log_summary()
Evals 탭
비교 뷰

사용 팁

  • 각 예측 후에는 바로 finish()를 호출하세요.
  • 단일 예측에 묶여 있지 않은 메트릭(예: 전체 레이턴시)을 수집하려면 log_summary를 사용하세요.
  • 리치 미디어 로깅 기능은 정성적 분석에 매우 유용합니다.