웹사이트 검색

DSPy를 통한 프롬프트: 새로운 접근 방식


소개

언어 모델(LM)을 사용하고 결합하는 더 나은 방법을 항상 연구하는 시대가 왔습니다. 일반적으로 LLM은 시행착오를 통해 만들어진 고정된 "프롬프트 템플릿"을 사용합니다. DSPy는 LM 파이프라인을 관리하기 쉬운 텍스트 변환 그래프로 전환하여 이를 단순화하는 새로운 방법입니다. 이러한 그래프는 프롬프트, 미세 조정 및 추론 방법을 학습하고 개선할 수 있는 모듈을 사용합니다.

DSPy에는 더 나은 성능을 위해 이러한 파이프라인을 최적화하는 도구가 포함되어 있습니다. 연구에 따르면 DSPy는 효과적인 LM 파이프라인을 신속하게 생성하여 기존 방법에 비해 성능을 크게 향상시킬 수 있는 것으로 나타났습니다. 또한 GPT-3.5와 같은 고급 모델을 위해 전문가가 디자인한 프롬프트를 통해 더 작고 개방적인 모델의 경쟁력을 높여줍니다.

전제 조건

DSPy를 시작하기 전에 다음 사항을 확인하세요.

  • 기본 프로그래밍 지식: Python 및 해당 라이브러리에 대한 지식
  • LLM에 대한 이해: 대규모 언어 모델과 그 프롬프트 메커니즘에 대한 기본적인 이해입니다.
  • 환경 설정: 필요한 라이브러리가 설치된 Jupyter Notebook 또는 VS Code와 같은 Python 개발 환경에 액세스합니다.

DSPy란 무엇입니까?

DSPy는 특히 LM을 여러 번 사용할 때 언어 모델(LM) 프롬프트와 가중치를 더 쉽게 최적화할 수 있게 해주는 프레임워크입니다. DSPy가 없으면 LM을 사용하여 복잡한 시스템을 구축하려면 문제 분석, 프롬프트 미세 조정, 단계 조정, 합성 예제 생성, 소규모 LM 미세 조정 등 많은 수동 단계가 필요하며 이는 번거롭고 지저분할 수 있습니다.

DSPy는 매개변수(프롬프트 및 가중치)에서 프로그램 흐름을 분리하고 원하는 결과에 따라 이러한 매개변수를 조정하는 새로운 최적화 프로그램을 도입하여 이를 간소화합니다. 이는 GPT-4 또는 T5 기반과 같은 강력한 모델을 더욱 안정적이고 효과적으로 만듭니다. 수동 프롬프트 조정 대신 DSPy는 알고리즘을 사용하여 매개변수를 업데이트하므로 코드, 데이터 또는 메트릭의 변경 사항에 맞게 프로그램을 다시 컴파일할 수 있습니다.

신경망용 PyTorch와 같은 프레임워크를 사용하는 것과 같다고 생각하세요. 우리는 모든 세부 사항을 수동으로 조정하지 않고 대신 레이어와 최적화 프로그램을 사용하여 최상의 매개 변수를 학습합니다. 마찬가지로 DSPy는 LM 작업을 자동화하고 향상시키는 모듈과 최적화 프로그램을 제공하여 수동 조정이 아닌 체계적인 개선과 성능 향상에 더 중점을 둡니다.

DSPy는 무엇을 의미하나요?

"now"라는 약어는 Stanford NLP University에서 만든 "Declarative Self-improving Language Programs"을 의미합니다.

DSPy는 특히 다단계 파이프라인의 경우 언어 모델(LM) 프롬프트와 가중치를 최적화하는 복잡한 프로세스를 간소화합니다. 전통적으로는 문제를 분석하고, 프롬프트를 개선하고, 단계를 조정하고, 합성 예제를 생성하고, 더 작은 모델을 미세 조정해야 했습니다. 모든 변경에는 프롬프트 재작업과 미세 조정이 필요하므로 이는 지저분하고 시간이 많이 걸립니다.

DSPy는 LM 매개변수에서 프로그램 흐름을 분리하고 최적화 프로그램을 도입하여 GPT-3.5, GPT-4, T5-base 또는 Llama2-13b와 같은 모델의 신뢰성을 향상시킵니다. 이를 통해 결과에 대한 신뢰감과 확신을 심어줌으로써 더욱 효과적이고 오류 발생 가능성이 줄어듭니다.

왜 DSPy가 필요한가요?

"프롬프트 템플릿"은 주어진 작업에 대한 응답을 안내하기 위해 LM에 제공되는 사전 정의된 지침 또는 데모입니다. 프롬프트 템플릿은 시행착오를 거쳐 생성되는 경우가 많습니다. 이는 특정 작업이나 시나리오에서는 잘 작동하지만 다른 상황에서는 실패하거나 관련 없는 결과를 생성할 수 있음을 의미합니다. 이러한 템플릿은 하드코딩되어 있으므로 적응성이 부족하고 입력 데이터, 작업 요구 사항 또는 기타 언어 모델의 변화를 효과적으로 처리하지 못할 수 있습니다. 특정 프롬프트 템플릿은 특정 LM 파이프라인 또는 프레임워크에 효과적으로 작동할 수 있습니다. 하지만 다른 파이프라인, 다른 LM, 다양한 데이터 도메인 또는 심지어 다른 유형의 입력에도 잘 일반화되지 않을 수 있습니다. 이러한 일반화 부족으로 인해 다양한 사용 사례에서 LM의 유연성과 적용성이 제한됩니다. 다양한 작업이나 LM을 위한 프롬프트 템플릿을 수동으로 제작하고 미세 조정하는 것은 시간이 많이 걸리고 노동 집약적일 수 있습니다. 작업의 복잡성과 다양성이 증가함에 따라 이러한 템플릿을 유지하고 업데이트하는 것은 점점 더 어렵고 비효율적이 됩니다.

또한 응답 생성과 관련된 다른 문제가 있을 수도 있습니다. LM(언어 모델) 파이프라인 및 프레임워크에서 하드코딩된 프롬프트 템플릿을 사용하면 컨텍스트 및 관련성 부족, 출력 불일치, 낮은 응답 품질, 부정확성과 같은 문제가 발생하는 경우가 많습니다. 이러한 과제는 수동으로 제작되고 다양한 LM 모델, 데이터 도메인 또는 입력 변형에 걸쳐 효과적으로 일반화되지 않을 수 있는 프롬프트 템플릿의 제한된 유연성과 확장성에서 비롯됩니다.

그렇다면 왜 DSPy인가?

  • DSPy는 구조화되지 않은 텍스트 입력을 조작하는 것에서 벗어나 프로그래밍을 향한 새로운 언어 모델 파이프라인을 구축하는 데 중점을 둡니다.
  • DSPy 모듈은 신경망 레이어와 유사한 작업 적응형 구성 요소로, 질문 답변이나 요약과 같은 텍스트 변환을 추상화합니다.
  • DSPy 컴파일러는 교육 입력 및 검증 지표를 활용하여 프로그램 품질 또는 비용을 최적화합니다.
  • DSPy Compiler는 프로그램 버전을 시뮬레이션하고 자기 개선 및 효과적인 프롬프트 생성을 위한 부트스트래핑 예제 추적을 수행합니다.
  • DSPy의 최적화는 데이터로부터 모듈 학습을 결정하는 텔레프롬프터에 의해 수행되는 모듈식입니다.
  • DSPy는 선언적 모듈을 프롬프트, 미세 조정, 추론 및 증강의 고품질 구성에 매핑할 수 있습니다.
  • DSPy 프로그래밍 모델은 전문가가 만든 프롬프트의 역할을 줄이는 데 중점을 둡니다.
  • DSPy 모듈의 구성은 컴파일 후 몇 분에서 수십 분 내에 간단한 프로그램의 품질을 크게 향상시킬 수 있습니다.

DSPy의 주요 구성 요소

더 자세히 알아보기 전에 DSPy의 몇 가지 중요한 구성 요소를 이해해 보겠습니다.

  • 서명
  • 모듈
  • 텔레프롬프터 또는 옵티마이저

DSPy 서명은 함수 선언으로, 특정 언어 모델이 해당 동작을 달성하도록 유도하는 방법을 자세히 설명하는 대신 텍스트 변환을 처리해야 하는 내용에 대한 간결한 사양을 제공합니다. DSPy 서명은 선택적 명령이 있는 입력출력 필드로 구성된 튜플입니다. 각 필드에는 필드 이름과 선택적 메타데이터가 포함됩니다.

서명은 우리가 구축하고 있는 시스템 유형에 중점을 둡니다. 예를 들어 - 질문 - > 답변, 영어 문서 -> 프랑스어 번역 또는 내용 -> 요약입니다.

qa = dspy.Predict (" question -> answer ")
qa(question =" Where is Guaran ´ı spoken?")Out: Prediction ( answer = ’ Guaran ´ı is spoken mainly in South America . ’)

DSPy 모듈은 언어 모델을 활용하는 프로그램을 만들기 위한 핵심 구성요소입니다. 각 모듈에는 생각의 사슬 또는 ReAct와 같은 특정 프롬프트 기술이 포함되어 있으며 DSPy Signature와 함께 작동할 수 있을 만큼 다용도로 설계되었습니다.

이러한 모듈에는 프롬프트 및 언어 모델 가중치 요소를 포함하여 조정 가능한 매개변수가 있으며 입력을 처리하고 출력을 생성하기 위해 호출할 수 있습니다. 또한 여러 DSPy 모듈을 결합하여 더 크고 복잡한 프로그램을 형성할 수 있습니다. PyTorch의 신경망 모듈에서 영감을 받은 DSPy 모듈은 언어 모델 프로그래밍과 유사한 기능을 제공합니다.

예를 들어:-

dspy.Predict는 기본 모듈이며 다른 모든 DSPy 모듈은 이 모듈을 사용하여 구축됩니다.

모듈을 사용하려면 특정 서명으로 모듈을 선언하는 것부터 시작합니다. 다음으로 입력 인수를 사용하여 모듈을 호출하고 출력 필드를 추출합니다.

sentence = "it's a charming and often affecting journey."  # example from the SST-2 dataset.
1) Declare with a signature.
classify = dspy.Predict('sentence -> sentiment')
2) Call with input argument(s).
response = classify(sentence=sentence)
3) Access the output.
print(response.sentiment)

산출:-

Positive

우리가 사용할 수 있는 몇 가지 다른 DSPy 모듈이 있습니다:-

  • dspy.ChainOfThought
  • dspy.ReAct
  • dspy.MultiChain비교
  • dspy.ProgramOfThought

그리고 더.

DSPy 텔레프롬프터는 DSPy의 최적화를 위해 사용됩니다. 매우 유연하고 모듈식입니다. 최적화는 모듈이 데이터로부터 학습하는 방법을 안내하는 다목적 전략인 텔레프롬프터에 의해 수행됩니다.

DSPy 최적화 프로그램은 프롬프트 및 언어 모델 가중치와 같은 DSPy 프로그램의 매개변수를 미세 조정하여 정확도와 같은 지정된 측정항목을 최대화하도록 설계된 알고리즘입니다. DSPy는 각각 서로 다른 전략을 사용하는 다양한 내장 최적화 프로그램을 제공합니다. 일반적으로 DSPy 최적화 프로그램에는 세 가지가 필요합니다: DSPy 프로그램(단일 모듈 또는 복잡한 다중 모듈 설정일 수 있음), 프로그램의 출력을 평가하고 점수를 매기는 측정 기능(점수가 높을수록 더 나은 성능을 나타냄), 그리고 몇 가지 학습 입력(라벨이 없더라도 5~10개 정도의 예시도 있음) 데이터가 많으면 유익할 수 있지만 DSPy는 최소한의 입력으로도 강력한 결과를 제공하도록 설계되었습니다.

옵티마이저는 어떻게 성능을 향상시키는가?

기존 심층 신경망(DNN)은 손실 함수와 훈련 데이터가 포함된 경사하강법을 사용하여 최적화됩니다. 이와 대조적으로 DSPy 프로그램은 DSPy 모듈로 통합된 여러 LM(언어 호출 모델)으로 구성됩니다. 각 모듈에는 LM 가중치, 명령, 입력/출력 동작 데모라는 세 가지 내부 매개변수가 있습니다.

DSPy는 LM 가중치에 대한 경사하강법과 개선 지침 및 데모를 위한 LM 기반 최적화를 결합하는 다단계 최적화 알고리즘을 사용하여 세 가지 모두를 최적화할 수 있습니다. 일반적인 몇 장의 예제와 달리 DSPy 데모는 더욱 강력하며 프로그램을 기반으로 처음부터 생성하고 최적화할 수 있습니다. 이러한 편집은 사람이 작성한 것보다 더 나은 프롬프트를 생성하는 경우가 많습니다. 이는 DSPy 최적화 프로그램이 본질적으로 더 창의적이기 때문이 아니라 체계적으로 더 많은 옵션을 탐색하고 측정 항목을 직접 미세 조정할 수 있기 때문입니다.

몇 가지 DSPy 최적화 프로그램이 아래에 나열되어 있습니다.

  • 라벨이 붙은FewShot
  • 부트스트랩FewShot
  • 부트스트랩FewShotWithRandomSearch
  • 부트스트랩FewShotWithOptuna
  • KNN퓨샷

목록은 계속됩니다.

다양한 종류의 최적화 프로그램에 관한 추가 정보를 보려면 DSPy 문서를 적극 권장합니다.

Langchain 및 Llamaindex와의 비교

LangChain 및 LlamaIndex 개요:

  • langchain과 llamaindex는 모두 LM 유도 분야에서 널리 사용되는 라이브러리입니다.
  • 두 라이브러리 모두 애플리케이션 개발자를 위해 사전 패키지된 구성 요소와 체인을 제공하는 데 중점을 둡니다. 또한 재사용 가능한 파이프라인(예: 에이전트, 검색 파이프라인) 및 도구(예: 데이터베이스 연결, 메모리 구현)의 구현을 제공합니다.

DSPy 개요:

  • DSPy는 프롬프트 엔지니어링의 근본적인 과제를 해결하고 수동 프롬프트 엔지니어링 없이 새로운 LM 계산 그래프를 구축하는 것을 목표로 합니다.
  • 또한 핵심 구성 가능 연산자, 서명(추상 프롬프트용), 모듈(추상 프롬프트 기술용) 및 최적화 프로그램인 텔레프롬프터를 소개합니다.
  • DSPy는 자동 컴파일 및 자체 개선을 통해 새로운 LM 파이프라인의 빠른 구축과 고품질 결과를 촉진합니다.

LangChain과 LlamaIndex의 중요한 차이점:

  • LangChain과 LlamaIndex는 DSPy가 해결하는 것을 목표로 하는 수동 프롬프트 엔지니어링에 의존합니다.
  • DSPy는 프롬프트를 자동으로 부트스트랩하는 구조화된 프레임워크를 제공하므로 손으로 직접 작성한 프롬프트 데모가 필요하지 않습니다.
  • 2023년 9월, LangChain의 코드베이스에는 1000자를 초과하는 50개의 문자열과 프롬프트 엔지니어링 전용 파일(12개의 Prompts.py 및 42개의 Prompt.py 파일)이 포함되어 있었습니다. 대조적으로 DSPy에는 손으로 쓴 프롬프트가 포함되어 있지 않지만 다양한 LM을 통해 높은 품질을 달성합니다.
  • DSPy는 하드 코딩된 프롬프트보다 더 모듈화되고 강력한 것으로 입증되었습니다.

DSPy 시작하기

패키지 설치부터 시작해 보겠습니다.

!pip install dspy-ai
#or
!pip install git+https://github.com/stanfordnlp/dspy.git

기본적으로 DSPy는 pip에서 최신 openai를 설치합니다.

필요한 패키지를 가져오고,

import sys
import os
import dspy
from dspy.datasets import HotPotQA
from dspy.teleprompt import BootstrapFewShot
from dspy.evaluate.evaluate import Evaluate
from dsp.utils import deduplicate

시작하기 및 데이터 로드

turbo = dspy.OpenAI(model='gpt-3.5-turbo') #model name 'gpt-3.5-turbo'
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts') #the retriever ColBERTv2

dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)

#load the data
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)

HotpotQA는 영어 Wikipedia에서 가져온 질문 답변 데이터 세트로, 약 113,000개의 크라우드 소스 질문으로 구성됩니다.

이 정보를 활용하여 질의응답 시스템을 구축하겠습니다. 이를 위해 훈련용으로 20개의 데이터 포인트를 사용하고 개발 또는 검증 세트용으로 50개의 데이터 포인트를 사용합니다.

# get the train and validation set.
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]

len(trainset), len(devset)

산출:-

(20, 50)

다음으로 몇 가지 예를 살펴보겠습니다.

train_example = trainset[0]
print(f"Question: {train_example.question}")
print(f"Answer: {train_example.answer}")

산출:-

Question: At My Window was released by which American singer-songwriter?
Answer: John Townes Van Zandt
dev_example = devset[18]
print(f"Question: {dev_example.question}")
print(f"Answer: {dev_example.answer}")
print(f"Relevant Wikipedia Titles: {dev_example.gold_titles}")

산출:-

Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Answer: English
Relevant Wikipedia Titles: {'Robert Irvine', 'Restaurant: Impossible'}

챗봇 만들기

짧고 사실적인 답변이 필요한 질문에 대해 서명이 있는 기본 QA라는 기능을 만들고 있습니다. 각 질문에는 하나의 답변이 있으며 1~5단어로 제한됩니다.

이 서명은 질문에 답하는 챗봇을 개발하는 우리의 목표를 정의합니다.

class BasicQA(dspy.Signature): #Signature
    """Answer questions with short factoid answers."""

    question = dspy.InputField()
    answer = dspy.OutputField(desc="often between 1 and 5 words")

다음으로 dspy.predict를 사용하여 응답을 생성하고 기본 QA 클래스를 전달한 다음 예시 질문과 함께 generate_answer 함수를 호출합니다. 마지막으로 질문 답변 챗봇이 올바르게 응답하는지 테스트하기 위해 출력을 인쇄합니다.

# Define the predictor.
generate_answer = dspy.Predict(BasicQA)
Call the predictor on a particular input.
pred = generate_answer(question=dev_example.question)
Print the input and the prediction.
print(f"Question: {dev_example.question}")
print(f"Predicted Answer: {pred.answer}")

산출:-

Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Predicted Answer: American

여기서는 답변이 잘못되었으므로 수정해야 합니다. 이 출력이 어떻게 생성되었는지 살펴보겠습니다.

turbo.inspect_history(n=1)
turbo.inspect_history(n=1)

Answer questions with short factoid answers.

---

Follow the following format.

Question: ${question}
Answer: often between 1 and 5 words

---

Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Answer: American

이 셰프는 영국인이자 미국인이지만, 표준적인 답변이기 때문에 모델이 단지 "미국인"이라고 추측했는지는 알 수 없습니다.

'생각의 사슬'을 소개하겠습니다.

Chain of Thought를 사용하여 챗봇 만들기

사고 사슬에는 일련의 중간 추론 단계가 포함되어 있어 대규모 언어 모델의 복잡한 추론 수행 능력이 크게 향상됩니다.

generate_answer_with_chain_of_thought = dspy.ChainOfThought(BasicQA)
Call the predictor on the same input.
pred = generate_answer_with_chain_of_thought(question=dev_example.question)
Print the input, the chain of thought, and the prediction.
print(f"Question: {dev_example.question}")
print(f"Thought: {pred.rationale.split('.', 1)[1].strip()}")
print(f"Predicted Answer: {pred.answer}")
Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Thought: We know that the chef and restaurateur featured in Restaurant: Impossible is Robert Irvine.
Predicted Answer: British

여기서 답변은 이전에 받은 응답보다 낫습니다.

아래 코드를 자유롭게 실행하고 추론과 이 응답이 어떻게 생성되는지 확인하세요.

turbo.inspect_history(n=1)

RAG 애플리케이션 생성

답변 생성을 위해 검색이 강화된 파이프라인을 구축하겠습니다. 먼저 서명을 만든 다음 모듈을 만들고 이를 구체화하기 위한 최적화 프로그램을 설정한 다음 마지막으로 GenerateAnswer라는 클래스를 정의하여 RAG 프로세스를 실행합니다.

RAG 시그니처

서명을 정의합니다(컨텍스트, 질문 --> 답변).

class GenerateAnswer(dspy.Signature):
    """Answer questions with short factoid answers."""

    context = dspy.InputField(desc="may contain relevant facts")
    question = dspy.InputField()
    answer = dspy.OutputField(desc="often between 1 and 5 words")

RAG 모듈

모듈 역할을 하는 RAG 클래스의 init 함수에서 모델을 정의합니다. 우리는 'Retrieve'와 'GenerateAnswer'에 중점을 둡니다. 'Retrieve'는 관련 구절을 맥락으로 수집하고, 'GenerateAnswer'는 'ChainOfThought'를 사용하여 사용자의 질문을 기반으로 예측을 제공합니다.

class RAG(dspy.Module):
    def __init__(self, num_passages=3):
        super().__init__()

        self.retrieve = dspy.Retrieve(k=num_passages)
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)

    def forward(self, question):
        context = self.retrieve(question).passages
        prediction = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=prediction.answer)

RAG 옵티마이저

다음으로 훈련 세트 사용, 검증 지표 정의, 프로그램 최적화를 위한 텔레프롬프터 선택이 포함된 RAG 프로그램을 컴파일합니다. 텔레프롬프터는 모듈에 대한 효과적인 프롬프트를 선택하는 강력한 최적화 도구입니다. SGD, Adam 또는 RMSProp과 같은 기존 지도 학습 설정에서 최적화 프로그램을 선택하는 것과 유사하게 BootstrapFewShot을 간단한 기본 텔레프롬프터로 사용하겠습니다.

# Validation logic: check that the predicted answer is correct.Also check that the retrieved context does actually contain that answer.
def validate_context_and_answer(example, pred, trace=None):
    answer_EM = dspy.evaluate.answer_exact_match(example, pred)
    answer_PM = dspy.evaluate.answer_passage_match(example, pred)
    return answer_EM and answer_PM
Set up a basic teleprompter, which will compile our RAG program.
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)
Compile!
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

이제 이 파이프라인을 실행해 보겠습니다.

# Ask any question you like to this simple RAG program.
my_question = "What castle did David Gregory inherit?"
Get the prediction. This contains `pred.context` and `pred.answer`.
pred = compiled_rag(my_question)
Print the contexts and the answer.
print(f"Question: {my_question}")
print(f"Predicted Answer: {pred.answer}")
print(f"Retrieved Contexts (truncated): {[c[:200] + '...' for c in pred.context]}")
Question: What castle did David Gregory inherit?
Predicted Answer: Kinnairdy Castle
Retrieved Contexts (truncated): ['David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinn...', 'Gregory Tarchaneiotes | Gregory Tarchaneiotes (Greek: Γρηγόριος Ταρχανειώτης , Italian: "Gregorio Tracanioto" or "Tracamoto" ) was a "protospatharius" and the long-reigning catepan of Italy from 998 t...', 'David Gregory (mathematician) | David Gregory (originally spelt Gregorie) FRS (? 1659 – 10 October 1708) was a Scottish mathematician and astronomer. He was professor of mathematics at the University ...']

역사를 살펴보겠습니다.

turbo.inspect_history(n=1)
Context:
[1] «David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinnairdy Castle in 1664. Three of his twenty-nine children became mathematics professors. He is credited with inventing a military cannon that Isaac Newton described as "being destructive to the human species". Copies and details of the model no longer exist. Gregory's use of a barometer to predict farming-related weather conditions led him to be accused of witchcraft by Presbyterian ministers from Aberdeen, although he was never convicted.»
[2] «Gregory Tarchaneiotes | Gregory Tarchaneiotes (Greek: Γρηγόριος Ταρχανειώτης , Italian: "Gregorio Tracanioto" or "Tracamoto" ) was a "protospatharius" and the long-reigning catepan of Italy from 998 to 1006. In December 999, and again on February 2, 1002, he reinstituted and confirmed the possessions of the abbey and monks of Monte Cassino in Ascoli. In 1004, he fortified and expanded the castle of Dragonara on the Fortore. He gave it three circular towers and one square one. He also strengthened Lucera.»
[3] «David Gregory (mathematician) | David Gregory (originally spelt Gregorie) FRS (? 1659 – 10 October 1708) was a Scottish mathematician and astronomer. He was professor of mathematics at the University of Edinburgh, Savilian Professor of Astronomy at the University of Oxford, and a commentator on Isaac Newton's "Principia".»

Question: What castle did David Gregory inherit?

Reasoning: Let's think step by step in order to produce the answer. We know that David Gregory inherited a castle. The name of the castle is Kinnairdy Castle.

Answer: Kinnairdy Castle

평가하다

마지막 단계는 RAG 모델의 성능을 평가하는 평가입니다. 기본 RAG, 컴파일되지 않은 RAG(옵티마이저 없음) 및 컴파일된 RAG(옵티마이저 포함)를 평가합니다. 이러한 평가를 통해 얻은 점수를 비교해보겠습니다.

기본 RAG

def gold_passages_retrieved(example, pred, trace=None):
    gold_titles = set(map(dspy.evaluate.normalize_text, example['gold_titles']))
    found_titles = set(map(dspy.evaluate.normalize_text, [c.split(' | ')[0] for c in pred.context]))

    return gold_titles.issubset(found_titles)

evaluate_on_hotpotqa = Evaluate(devset=devset, num_threads=1, display_progress=True, display_table=5)

compiled_rag_retrieval_score = evaluate_on_hotpotqa(compiled_rag, metric=gold_passages_retrieved)

컴파일되지 않은 Baleen RAG(옵티마이저 없음)

교육/개발 세트에서 어려운 질문을 탐색하면 더 많은 세부 정보가 필요한 경우와 같이 단일 검색 쿼리를 수정해야 하는 경우가 많다는 것을 알 수 있습니다. 이 문제를 해결하기 위해 검색 강화 NLP 문헌에서는 추가 정보를 수집하기 위해 추가 쿼리를 생성하는 GoldEn 및 Baleen과 같은 다중 홉 검색 시스템을 제안합니다.

DSPy를 사용하면 RAG 구현의 생성Answer 서명과 "홉" 동작에 대한 서명을 사용하여 이러한 시스템을 쉽게 시뮬레이션할 수 있습니다. 즉, 부분적인 컨텍스트와 질문을 기반으로 누락된 정보를 찾기 위해 검색 쿼리를 생성하는 것입니다.

class GenerateSearchQuery(dspy.Signature):
    """Write a simple search query that will help answer a complex question."""

    context = dspy.InputField(desc="may contain relevant facts")
    question = dspy.InputField()
    query = dspy.OutputField()

다음으로 모듈을 생성합니다.

class SimplifiedBaleen(dspy.Module):
    def __init__(self, passages_per_hop=3, max_hops=2):
        super().__init__()

        self.generate_query = [dspy.ChainOfThought(GenerateSearchQuery) for _ in range(max_hops)]
        self.retrieve = dspy.Retrieve(k=passages_per_hop)
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
        self.max_hops = max_hops

    def forward(self, question):
        context = []

        for hop in range(self.max_hops):
            query = self.generate_query[hop](context=context, question=question).query
            passages = self.retrieve(query).passages
            context = deduplicate(context + passages)

        pred = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=pred.answer)

Baleen의 주요 목적은 질문이나 쿼리를 덩어리로 나누어 자동으로 수정하는 것입니다. 청크에서 컨텍스트를 검색한 다음 이를 변수에 저장하므로 보다 정확한 답변을 생성하는 데 도움이 됩니다.

Baleen 프로그램의 제로샷 버전 검사

제로샷(컴파일되지 않은) 설정에서 프로그램을 사용하려면 최소한의 지침으로 하위 작업을 이해하는 기본 언어 모델의 능력이 필요합니다. 이는 단순하고 일반적인 작업에 대한 강력한 모델(예: GPT-4)과 잘 작동합니다. 그러나 제로샷 접근 방식은 특수 작업, 새로운 영역, 보다 효율적이거나 개방형 모델에는 덜 실용적입니다. DSPy는 이러한 상황에서 성능을 향상시킬 수 있습니다.

# Ask any question you like to this simple RAG program.
my_question = "How many storeys are in the castle that David Gregory inherited?"
Get the prediction. This contains `pred.context` and `pred.answer`.
uncompiled_baleen = SimplifiedBaleen()  # uncompiled (i.e., zero-shot) program
pred = uncompiled_baleen(my_question)
Print the contexts and the answer.
print(f"Question: {my_question}")
print(f"Predicted Answer: {pred.answer}")
print(f"Retrieved Contexts (truncated): {[c[:200] + '...' for c in pred.context]}")
Question: How many storeys are in the castle that David Gregory inherited?
Predicted Answer: five
Retrieved Contexts (truncated): ['David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinn...', 'The Boleyn Inheritance | The Boleyn Inheritance is a novel by British author Philippa Gregory which was first published in 2006. It is a direct sequel to her previous novel "The Other Boleyn Girl," an...', 'Gregory of Gaeta | Gregory was the Duke of Gaeta from 963 until his death. He was the second son of Docibilis II of Gaeta and his wife Orania. He succeeded his brother John II, who had left only daugh...', 'Kinnairdy Castle | Kinnairdy Castle is a tower house, having five storeys and a garret, two miles south of Aberchirder, Aberdeenshire, Scotland. The alternative name is Old Kinnairdy....', 'Kinnaird Head | Kinnaird Head (Scottish Gaelic: "An Ceann Àrd" , "high headland") is a headland projecting into the North Sea, within the town of Fraserburgh, Aberdeenshire on the east coast of Scotla...', 'Kinnaird Castle, Brechin | Kinnaird Castle is a 15th-century castle in Angus, Scotland. The castle has been home to the Carnegie family, the Earl of Southesk, for more than 600 years....']

컴파일된 Baleen RAG(최적화 프로그램 포함)

먼저 다음을 보장하는 유효성 검사 논리를 정의합니다.

1.예측 답변과 정답이 일치합니다. 2. 검색된 컨텍스트에는 정답이 포함되어 있습니다. 3. 생성된 쿼리 중 너무 긴 쿼리는 없습니다(즉, 100자를 초과하는 쿼리가 없습니다). 4. 생성된 쿼리 중 어느 것도 반복적이지 않습니다(즉, 이전 쿼리보다 F1 점수가 0.8 이상인 쿼리는 없습니다).

def validate_context_and_answer_and_hops(example, pred, trace=None):
    if not dspy.evaluate.answer_exact_match(example, pred): return False
    if not dspy.evaluate.answer_passage_match(example, pred): return False

    hops = [example.question] + [outputs.query for *_, outputs in trace if 'query' in outputs]

    if max([len(h) for h in hops]) > 100: return False
    if any(dspy.evaluate.answer_exact_match_str(hops[idx], hops[:idx], frac=0.8) for idx in range(2, len(hops))): return False

    return True

다음으로 DSPy의 가장 기본적인 텔레프롬프터 중 하나인 BootstrapFewShot을 사용하겠습니다.

teleprompter = BootstrapFewShot(metric=validate_context_and_answer_and_hops)

마지막으로 최적화 프로그램을 컴파일하고 컴파일된 파이프라인과 컴파일되지 않은 baleen 파이프라인의 검색 품질을 평가합니다.

compiled_baleen = teleprompter.compile(SimplifiedBaleen(), teacher=SimplifiedBaleen(passages_per_hop=2), trainset=trainset)

uncompiled_baleen_retrieval_score = evaluate_on_hotpotqa(uncompiled_baleen, metric=gold_passages_retrieved)

compiled_baleen_retrieval_score = evaluate_on_hotpotqa(compiled_baleen, metric=gold_passages_retrieved)

이제 비교를 위해 점수를 인쇄해 보겠습니다.

print(f"## Retrieval Score for RAG: {compiled_rag_retrieval_score}")  # note that for RAG, compilation has no effect on the retrieval step
print(f"## Retrieval Score for uncompiled Baleen: {uncompiled_baleen_retrieval_score}")
print(f"## Retrieval Score for compiled Baleen: {compiled_baleen_retrieval_score}")

산출:-

## Retrieval Score for RAG: 26.0
## Retrieval Score for uncompiled Baleen: 48.0
## Retrieval Score for compiled Baleen: 60.0

따라서 컴파일된 Baleen 방법은 기본 RAG 응용 프로그램보다 더 정확한 답변을 제공합니다. 컴파일된 Baleen은 질문을 여러 개의 작은 덩어리로 나누고 컨텍스트를 검색하여 보다 정확한 답변을 제공합니다.

compiled_baleen("How many storeys are in the castle that David Gregory inherited?")
turbo.inspect_history(n=3)

결론

이 기사에서는 사전 훈련된 언어 모델(LM)의 파이프라인과 기타 도구를 사용하여 AI 시스템을 설계하기 위한 새로운 프로그래밍 모델인 DSPy를 소개합니다. 우리는 DSPy 서명, 모듈, 텔레프롬프터라는 세 가지 핵심 개념을 제시했습니다. 또한 간단한 q와 챗봇, RAG 애플리케이션을 만들어 프레임워크를 탐색했습니다. 이러한 실험을 통해 우리는 DSPy가 상대적으로 작은 LM을 사용하여 효과적인 시스템의 신속한 개발을 가능하게 한다는 것을 입증했습니다.

우리는 당신이 기사를 즐겼기를 바랍니다!

참고자료

  • DSPy github 저장소
  • DSPY: 선언적 언어 모델 호출을 자체 개선 파이프라인으로 컴파일

관련기사: