메인 콘텐츠로 건너뛰기
이 노트북은 대화형 노트북입니다. 로컬에서 실행하거나 아래 링크를 통해 열 수 있습니다:

Not Diamond를 활용한 LLM 프롬프트 커스텀 라우팅

이 노트북에서는 Weave를 Not Diamond의 커스텀 라우팅과 함께 사용하여 평가 결과를 기반으로 LLM 프롬프트를 가장 적합한 모델로 라우팅하는 방법을 보여줍니다.

프롬프트 라우팅

복잡한 LLM 워크플로를 구축할 때는 정확도, 비용, 호출 지연에 따라 서로 다른 모델에 프롬프트를 보내야 할 수도 있습니다. 사용자는 Not Diamond을 사용해 이러한 워크플로에서 프롬프트를 자신의 요구에 가장 적합한 모델로 라우팅하여, 정확도를 최대화하면서도 모델 비용을 절감할 수 있습니다. 주어진 데이터 분포에서 단일 모델이 모든 쿼리에 대해 다른 모든 모델보다 항상 뛰어난 성능을 내는 경우는 거의 없습니다. 여러 모델을 결합해 각 LLM을 언제 호출할지 학습하는 “메타모델(meta-model)“을 구축하면, 개별 모델 각각의 성능을 능가할 수 있을 뿐만 아니라 그 과정에서 비용과 지연도 줄일 수 있습니다.

커스텀 라우팅

프롬프트용 커스텀 라우터를 학습하려면 세 가지가 필요합니다:
  1. LLM 프롬프트 집합: 프롬프트는 문자열이어야 하며, 애플리케이션에서 사용하는 프롬프트를 대표해야 합니다.
  2. LLM 응답: 각 입력에 대한 후보 LLM들의 응답. 후보 LLM에는 지원되는 LLM과 직접 만든 커스텀 모델 모두를 포함할 수 있습니다.
  3. 후보 LLM의 각 입력에 대한 응답에 대한 평가 점수: 점수는 숫자이며, 필요에 맞는 어떤 메트릭이든 사용할 수 있습니다.
이들을 Not Diamond API에 제출하면 각 워크플로우에 맞게 튜닝된 커스텀 라우터를 학습할 수 있습니다.

트레이닝 데이터 설정

실제로는 여러분만의 Evaluations를 사용해 커스텀 라우터를 트레이닝하게 됩니다. 그러나 이 예제 노트북에서는 코딩 작업을 위한 커스텀 라우터를 트레이닝하기 위해 HumanEval 데이터셋에 대한 LLM 응답을 사용합니다. 먼저 이 예제를 위해 미리 준비해 둔 데이터셋을 다운로드한 다음, 각 모델에 대해 LLM 응답을 EvaluationResults로 파싱합니다.
!curl -L "https://drive.google.com/uc?export=download&id=1q1zNZHioy9B7M-WRjsJPkfvFosfaHX38" -o humaneval.csv
python
import random

import weave
from weave.flow.dataset import Dataset
from weave.flow.eval import EvaluationResults
from weave.integrations.notdiamond.util import get_model_evals

pct_train = 0.8
pct_test = 1 - pct_train

# 실제로는 데이터셋에 대한 Evaluation을 빌드하고
# `evaluation.get_eval_results(model)`을 호출합니다.
model_evals = get_model_evals("./humaneval.csv")
model_train = {}
model_test = {}
for model, evaluation_results in model_evals.items():
    n_results = len(evaluation_results.rows)
    all_idxs = list(range(n_results))
    train_idxs = random.sample(all_idxs, k=int(n_results * pct_train))
    test_idxs = [idx for idx in all_idxs if idx not in train_idxs]

    model_train[model] = EvaluationResults(
        rows=weave.Table([evaluation_results.rows[idx] for idx in train_idxs])
    )
    model_test[model] = Dataset(
        rows=weave.Table([evaluation_results.rows[idx] for idx in test_idxs])
    )
    print(
        f"Found {len(train_idxs)} train rows and {len(test_idxs)} test rows for {model}."
    )

커스텀 라우터 트레이닝

이제 EvaluationResults를 얻었으므로 커스텀 라우터를 트레이닝할 수 있습니다. 먼저 계정을 생성하고 API 키를 발급받은 다음, 아래에 API 키를 입력하세요.
API 키 발급하기
import os

from weave.integrations.notdiamond.custom_router import train_router

api_key = os.getenv("NOTDIAMOND_API_KEY", "<YOUR_API_KEY>")

preference_id = train_router(
    model_evals=model_train,
    prompt_column="prompt",
    response_column="actual",
    language="en",
    maximize=True,
    api_key=api_key,
    # 첫 번째 커스텀 라우터를 학습할 때는 이 줄을 주석 처리된 상태로 두세요
    # 커스텀 라우터를 재학습하려면 주석을 해제하세요
    # preference_id=preference_id,
)
Not Diamond 앱에서 커스텀 라우터의 트레이닝 진행 과정을 확인할 수 있습니다.
라우터 트레이닝 진행 상황 확인
커스텀 라우터의 트레이닝이 완료되면, 해당 라우터를 사용해 프롬프트를 라우팅할 수 있습니다.
from notdiamond import NotDiamond

import weave

weave.init("notdiamond-quickstart")

llm_configs = [
    "anthropic/claude-3-5-sonnet-20240620",
    "openai/gpt-4o-2024-05-13",
    "google/gemini-1.5-pro-latest",
    "openai/gpt-4-turbo-2024-04-09",
    "anthropic/claude-3-opus-20240229",
]
client = NotDiamond(api_key=api_key, llm_configs=llm_configs)

new_prompt = (
    """
You are a helpful coding assistant. Using the provided function signature, write the implementation for the function
in Python. Write only the function. Do not include any other text.

from typing import List

def has_close_elements(numbers: List[float], threshold: float) -> bool:
    """
    """ Check if in given list of numbers, are any two numbers closer to each other than
    given threshold.
    >>> has_close_elements([1.0, 2.0, 3.0], 0.5)
    False
    >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)
    True
    """
    """
"""
)
session_id, routing_target_model = client.model_select(
    messages=[{"role": "user", "content": new_prompt}],
    preference_id=preference_id,
)

print(f"Session ID: {session_id}")
print(f"Target Model: {routing_target_model}")
이 예제에서는 Not Diamond가 Weave 자동 트레이싱과 호환된다는 점도 활용했습니다. 결과는 Weave UI에서 확인할 수 있습니다. 커스텀 라우팅용 Weave UI

커스텀 라우터 평가하기

커스텀 라우터 트레이닝을 마친 뒤에는 다음 중 한 가지 방식으로 성능을 평가할 수 있습니다.
  • 트레이닝 프롬프트를 제출하여 in-sample 성능을 평가하거나
  • 새로운 프롬프트나 홀드아웃된 프롬프트를 제출하여 out-of-sample 성능을 평가합니다.
아래에서는 테스트 세트를 커스텀 라우터에 제출하여 성능을 평가합니다.
from weave.integrations.notdiamond.custom_router import evaluate_router

eval_prompt_column = "prompt"
eval_response_column = "actual"

best_provider_model, nd_model = evaluate_router(
    model_datasets=model_test,
    prompt_column=eval_prompt_column,
    response_column=eval_response_column,
    api_key=api_key,
    preference_id=preference_id,
)
python
@weave.op()
def is_correct(score: int, output: dict) -> dict:
    # 이미 모델 응답이 있으므로 score를 편법으로 처리합니다
    return {"correct": score}

best_provider_eval = weave.Evaluation(
    dataset=best_provider_model.model_results.to_dict(orient="records"),
    scorers=[is_correct],
)
await best_provider_eval.evaluate(best_provider_model)

nd_eval = weave.Evaluation(
    dataset=nd_model.model_results.to_dict(orient="records"), scorers=[is_correct]
)
await nd_eval.evaluate(nd_model)
이 예시에서 Not Diamond “meta-model”은 여러 다른 모델로 프롬프트를 라우팅합니다. Weave를 통해 커스텀 라우터를 트레이닝하면 자동으로 평가가 실행되고 결과가 Weave UI에 업로드됩니다. 커스텀 라우터 프로세스가 완료되면 Weave UI에서 결과를 검토할 수 있습니다. UI에서 Not Diamond “meta-model”이 프롬프트에 더 정확하게 답변할 가능성이 높은 다른 모델로 프롬프트를 라우팅함으로써, 가장 성능이 좋은 단일 모델보다 더 뛰어난 성능을 보인다는 것을 확인할 수 있습니다.
Evaluating Not Diamond