메인 콘텐츠로 건너뛰기
이 노트북은 대화형입니다. 로컬에서 실행하거나 아래 링크를 사용하세요:

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 key를 생성한 후, 아래에 API key를 입력하세요.
API key 생성하기
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}")
이 예제에서는 Weave 자동 트레이싱과의 호환성을 제공하는 Not Diamond도 활용했습니다. 결과는 Weave UI에서 확인할 수 있습니다. Weave UI for custom routing

커스텀 라우터 평가하기

커스텀 라우터를 학습한 후에는 다음과 같은 방식으로 성능을 평가할 수 있습니다.
  • 학습에 사용한 프롬프트를 제출하여 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 “메타 모델”이 여러 다른 모델로 프롬프트를 라우팅합니다. Weave를 통해 커스텀 라우터를 학습하는 과정에서 평가가 함께 실행되고, 결과가 Weave UI에 업로드됩니다. 커스텀 라우터 학습 프로세스가 완료되면 Weave UI에서 결과를 확인할 수 있습니다. UI에서 Not Diamond “메타 모델”이 프롬프트에 더 정확히 답변할 가능성이 높은 다른 모델로 프롬프트를 라우팅함으로써, 가장 성능이 좋은 개별 모델보다 더 뛰어난 성능을 보인다는 것을 확인할 수 있습니다.
Evaluating Not Diamond