이것은 인터랙티브 노트북입니다. 로컬에서 실행하거나 아래 링크를 사용할 수 있습니다:

DSPy와 Weave를 사용한 LLM 워크플로우 최적화

The BIG-bench (Beyond the Imitation Game Benchmark)는 대규모 언어 모델을 테스트하고 미래 기능을 추론하기 위한 200개 이상의 작업으로 구성된 협업 벤치마크입니다. BIG-Bench Hard (BBH)는 현재 세대의 언어 모델로 해결하기 매우 어려울 수 있는 23개의 가장 도전적인 BIG-Bench 작업 모음입니다. 이 튜토리얼은 BIG-bench Hard 벤치마크의 causal judgement task에서 구현된 LLM 워크플로우의 성능을 향상시키고 프롬프팅 전략을 평가하는 방법을 보여줍니다. 우리는 DSPy LLM 워크플로우를 구현하고 프롬프트 전략을 최적화하기 위해 사용할 것입니다. 또한 Weave를 사용하여 LLM 워크플로우를 추적하고 프롬프트 전략을 평가할 것입니다.

의존성 설치하기

이 튜토리얼에는 다음 라이브러리가 필요합니다:
  • DSPy - LLM 워크플로우를 구축하고 최적화하기 위해 사용합니다.
  • Weave - LLM 워크플로우를 추적하고 프롬프트 전략을 평가하기 위해 사용합니다.
  • datasets - HuggingFace Hub에서 Big-Bench Hard 데이터셋에 접근하기 위해 사용합니다.
!pip install -qU dspy-ai weave datasets
우리는 OpenAI API를 LLM 공급자로 사용할 것이기 때문에 OpenAI API 키도 필요합니다. OpenAI 플랫폼에서 가입하여 자신만의 API 키를 얻을 수 있습니다.
import os
from getpass import getpass

api_key = getpass("Enter you OpenAI API key: ")
os.environ["OPENAI_API_KEY"] = api_key

Weave를 사용한 추적 활성화

Weave는 현재 DSPy와 통합되어 있으며, 코드 시작 부분에 weave.init를 포함하면 DSPy 함수를 자동으로 추적할 수 있으며 이는 Weave UI에서 탐색할 수 있습니다. 자세한 내용은 Weave integration docs for DSPy를 확인하세요.
import weave

weave.init(project_name="dspy-bigbench-hard")
이 튜토리얼에서는 weave.Object에서 상속받은 메타데이터 클래스를 사용하여 메타데이터를 관리합니다.
class Metadata(weave.Object):
    dataset_address: str = "maveriq/bigbenchhard"
    big_bench_hard_task: str = "causal_judgement"
    num_train_examples: int = 50
    openai_model: str = "gpt-3.5-turbo"
    openai_max_tokens: int = 2048
    max_bootstrapped_demos: int = 8
    max_labeled_demos: int = 8

metadata = Metadata()
객체 버전 관리: Metadata 객체는 이를 사용하는 함수가 추적될 때 자동으로 버전 관리되고 추적됩니다

BIG-Bench Hard 데이터셋 로드하기

HuggingFace Hub에서 이 데이터셋을 로드하고, 훈련 및 검증 세트로 분할한 다음, publish를 통해 Weave에 게시할 것입니다. 이를 통해 데이터셋의 버전을 관리하고 weave.Evaluation를 사용하여 프롬프트 전략을 평가할 수 있습니다.
import dspy
from datasets import load_dataset

@weave.op()
def get_dataset(metadata: Metadata):
    # load the BIG-Bench Hard dataset corresponding to the task from Huggingface Hug
    dataset = load_dataset(metadata.dataset_address, metadata.big_bench_hard_task)[
        "train"
    ]

    # create the training and validation datasets
    rows = [{"question": data["input"], "answer": data["target"]} for data in dataset]
    train_rows = rows[0 : metadata.num_train_examples]
    val_rows = rows[metadata.num_train_examples :]

    # create the training and validation examples consisting of `dspy.Example` objects
    dspy_train_examples = [
        dspy.Example(row).with_inputs("question") for row in train_rows
    ]
    dspy_val_examples = [dspy.Example(row).with_inputs("question") for row in val_rows]

    # publish the datasets to the Weave, this would let us version the data and use for evaluation
    weave.publish(
        weave.Dataset(
            name=f"bigbenchhard_{metadata.big_bench_hard_task}_train", rows=train_rows
        )
    )
    weave.publish(
        weave.Dataset(
            name=f"bigbenchhard_{metadata.big_bench_hard_task}_val", rows=val_rows
        )
    )

    return dspy_train_examples, dspy_val_examples

dspy_train_examples, dspy_val_examples = get_dataset(metadata)

DSPy 프로그램

DSPy는 자유 형식의 문자열을 조작하는 것에서 벗어나 프로그래밍(모듈식 연산자를 구성하여 텍스트 변환 그래프 구축)에 가까운 새로운 LM 파이프라인 구축을 추진하는 프레임워크로, 컴파일러가 프로그램에서 최적화된 LM 호출 전략과 프롬프트를 자동으로 생성합니다. 우리는 dspy.OpenAI 추상화를 사용하여 GPT3.5 Turbo에 LLM 호출을 할 것입니다.
system_prompt = """
You are an expert in the field of causal reasoning. You are to analyze the a given question carefully and answer in `Yes` or `No`.
You should also provide a detailed explanation justifying your answer.
"""

llm = dspy.OpenAI(model="gpt-3.5-turbo", system_prompt=system_prompt)
dspy.settings.configure(lm=llm)

인과 추론 시그니처 작성하기

signatureDSPy module의 입력/출력 동작에 대한 선언적 명세로, 이는 특정 텍스트 변환을 추상화하는 작업 적응형 컴포넌트(신경망 레이어와 유사)입니다.
from pydantic import BaseModel, Field

class Input(BaseModel):
    query: str = Field(description="The question to be answered")

class Output(BaseModel):
    answer: str = Field(description="The answer for the question")
    confidence: float = Field(
        ge=0, le=1, description="The confidence score for the answer"
    )
    explanation: str = Field(description="The explanation for the answer")

class QuestionAnswerSignature(dspy.Signature):
    input: Input = dspy.InputField()
    output: Output = dspy.OutputField()

class CausalReasoningModule(dspy.Module):
    def __init__(self):
        self.prog = dspy.TypedPredictor(QuestionAnswerSignature)

    @weave.op()
    def forward(self, question) -> dict:
        return self.prog(input=Input(query=question)).output.dict()
Big-Bench Hard의 인과 추론 하위 집합에서 예제를 통해 우리의 LLM 워크플로우, 즉 CausalReasoningModule를 테스트해 봅시다.
import rich

baseline_module = CausalReasoningModule()

prediction = baseline_module(dspy_train_examples[0]["question"])
rich.print(prediction)

DSPy 프로그램 평가하기

이제 기본 프롬프트 전략이 있으니, weave.Evaluation를 사용하여 예측된 답변과 실제 정답을 비교하는 간단한 메트릭으로 검증 세트에서 평가해 봅시다. Weave는 각 예제를 가져와 애플리케이션을 통과시키고 여러 사용자 정의 점수 함수로 출력을 평가합니다. 이를 통해 애플리케이션의 성능을 볼 수 있고, 개별 출력과 점수를 자세히 살펴볼 수 있는 풍부한 UI를 갖게 됩니다. 먼저, 기준 모듈의 출력에서 나온 답변이 실제 정답과 동일한지 여부를 알려주는 간단한 weave 평가 점수 함수를 만들어야 합니다. 점수 함수는 model_output 키워드 인수가 필요하지만, 다른 인수는 사용자 정의이며 데이터셋 예제에서 가져옵니다. 인수 이름을 기반으로 한 사전 키를 사용하여 필요한 키만 가져올 것입니다.
@weave.op()
def weave_evaluation_scorer(answer: str, output: Output) -> dict:
    return {"match": int(answer.lower() == output["answer"].lower())}
다음으로, 평가를 정의하고 실행할 수 있습니다.
validation_dataset = weave.ref(
    f"bigbenchhard_{metadata.big_bench_hard_task}_val:v0"
).get()

evaluation = weave.Evaluation(
    name="baseline_causal_reasoning_module",
    dataset=validation_dataset,
    scorers=[weave_evaluation_scorer],
)

await evaluation.evaluate(baseline_module.forward)
Python 스크립트에서 실행하는 경우, 다음 코드를 사용하여 평가를 실행할 수 있습니다:
import asyncio
asyncio.run(evaluation.evaluate(baseline_module.forward))
인과 추론 데이터셋에 대한 평가를 실행하면 OpenAI 크레딧으로 약 $0.24가 소요됩니다.

DSPy 프로그램 최적화하기

이제 기본 DSPy 프로그램이 있으니, DSPy teleprompter를 사용하여 인과 추론에 대한 성능을 향상시켜 보겠습니다. 이는 지정된 메트릭을 최대화하기 위해 DSPy 프로그램의 매개변수를 조정할 수 있습니다. 이 튜토리얼에서는 BootstrapFewShot 텔레프롬프터를 사용합니다.
from dspy.teleprompt import BootstrapFewShot

@weave.op()
def get_optimized_program(model: dspy.Module, metadata: Metadata) -> dspy.Module:
    @weave.op()
    def dspy_evaluation_metric(true, prediction, trace=None):
        return prediction["answer"].lower() == true.answer.lower()

    teleprompter = BootstrapFewShot(
        metric=dspy_evaluation_metric,
        max_bootstrapped_demos=metadata.max_bootstrapped_demos,
        max_labeled_demos=metadata.max_labeled_demos,
    )
    return teleprompter.compile(model, trainset=dspy_train_examples)

optimized_module = get_optimized_program(baseline_module, metadata)
인과 추론 데이터셋에 대한 평가를 실행하면 OpenAI 크레딧으로 약 $0.04가 소요됩니다.
이제 최적화된 프로그램(최적화된 프롬프트 전략)이 있으니, 검증 세트에서 다시 한 번 평가하고 기본 DSPy 프로그램과 비교해 봅시다.
evaluation = weave.Evaluation(
    name="optimized_causal_reasoning_module",
    dataset=validation_dataset,
    scorers=[weave_evaluation_scorer],
)

await evaluation.evaluate(optimized_module.forward)
기본 프로그램과 최적화된 프로그램의 평가를 비교해보면, 최적화된 프로그램이 인과 추론 질문에 훨씬 더 정확하게 답변하는 것을 볼 수 있습니다.

결론

이 튜토리얼에서는 DSPy를 사용하여 프롬프트를 최적화하고 Weave를 사용하여 추적 및 평가를 통해 원래 프로그램과 최적화된 프로그램을 비교하는 방법을 배웠습니다.