DSPyによるプロンプト・エンジニアリング

Joshua Noble

Data Scientist

DSPyは、大規模言語モデル(LLM)アプリケーションを構築し、プロンプト最適化のための1回限りの手法ではなくコードを通じて性能をファイン・チューニングするための、オープンソースのPythonフレームワークです。DSPyプログラムは、正確なアウトプットを得るためにプロンプトを最適化することにより、LLMアプリケーションを構成およびファイン・チューニングするためのモジュール式の方法を提供します。DSPyの主な利点は、モデルの性能を自分で追跡しなくても、Pythonコードを通じてプロンプト・エンジニアリングと追跡を行えることです。

DSPyの威力は、生成AIを使用して自然言語を生成し、その成果をテストして最も効果的なプロンプトを作成することにあります。これにより、自己改善型AIシステムを構築できます。検索モデルや言語モデルへのさまざまなインターフェースをサポートしています。ollamaやhuggingfaceなどのシステムを介してローカルでモデルを実行することも、OpenAIのChatGPTまたはGPT-4を使用している場合はAPIを使用して実行することもできます。DSPyは、思考の連鎖(CoT)、検索拡張生成(RAG)、要約など、さまざまなユースケースをサポートしています。

このチュートリアルでは、IBM® watsonx上でDSPyを使用してRAG質問応答アプリケーションを作成するワークフローについて説明します。言語モデルとしてLlama 3を使用し、検索モデルとしてColBERTを使用します。DSPyはプロンプトをファイン・チューニングし、質問応答へのさまざまなアプローチを構築して、非常に複雑な質問であっても、より適切な応答を生成する方法を見いだします。

環境を設定する

いくつかあるツールの中から選択することもできますが、このチュートリアルでは、Jupyter Notebookを使用するためにIBMアカウントを設定する方法について説明します。

IBM Cloudアカウントを使用してwatsonx.aiにログインします。

watsonx.aiプロジェクトを作成します。

プロジェクトIDはプロジェクト内から取得できます。

次に「管理」タブをクリックし、「一般」ページの「詳細」セクションからプロジェクトIDをコピーします。このチュートリアルではこのIDが必要になります。

次に、選択した環境でJupyter Notebookを作成します。このチュートリアルのコードを新しいノートブックにコピーします。あるいは、このノートブックをGitHubからローカル・システムにダウンロードし、watsonx.aiプロジェクトにアセットとしてアップロードすることもできます。

Watson Machine Learning(WML)サービス・インスタンスとAPIキーを設定する

watsonx.aiランタイム・サービス・インスタンスを作成します(適切なリージョンを選択し、無料インスタンスであるLiteプランを選択)。

watsonx.aiランタイムでAPIキーを生成します。

watsonx.aiで作成したプロジェクトに、watsonx.aiランタイム・サービスを関連付けます。

DSPyライブラリーをインストールし、認証情報を設定する

DSPyを使用するには、pipをインストールします。環境変数を管理するために、dotenvもインストールします。

!pip install dspy-ai python-dotenv;

次に、このチュートリアルの残りの部分に必要なライブラリーをインポートします。

import dspy
from dspy import LM
from dspy.datasets import HotPotQA
from dspy.teleprompt import BootstrapFewShot
import json
import os

from dotenv import load_dotenv
load_dotenv(os.getcwd()+’/.env’, override=True)

認証情報を設定するには、ステップ1で生成したWATSONX_APIKEYとPROJECT_IDが必要です。それらはディレクトリの.envファイルに保存するか、プレースホルダーテキストを置き換えることができます。また、APIのエンドポイントとして機能するURLも設定します。

os.environ[‘WX_URL’] = “https://us-south.ml.cloud.ibm.com”
os.environ[‘WX_APIKEY’] = os.getenv(“WATSONX_APIKEY”, “”)

WATSONX_APIKEY= os.getenv(“WATSONX_APIKEY”, “”)
PROJECT_ID = os.getenv(“PROJECT_ID”,””)

DSPyでwatsonxを使用する

ここでは、DSPy LMクラスを使用したwatsonxモデルと連携するように、DSPyを設定します。このクラスを使用すると、watsonx APIを呼び出して、新しいプロンプトを生成したり、そのプロンプトをテストするための応答を生成したりできます。DSPyの下層では、watsonxサービスにアクセスするために、LiteLLMと呼ばれる別のライブラリーを使用しています。LiteLLMは、Hugging face、Azure、watsonxなどのOpenAI形式を使用して、非常に幅広いLLM APIを呼び出すためのシンプルなラッパーを提供します。

watsonxアカウントにアクセスする前に、最初のステップで生成したAPIキーを使用して、watsonxサービスのトークンを保存する必要があります。osライブラリーを呼び出して「https://iam.cloud.ibm.com/identity/token」にアクセスし、トークンを取得したら、後ほど使用するために保存します。

token = os.popen(‘curl -k -X POST \
    --header “Content-Type: application/x-www-form-urlencoded” \
    --header “Accept: application/json” \
    --data-urlencode “grant_type=urn:ibm:params:oauth:grant-type:apikey” \
    --data-urlencode “apikey=’ + WATSONX_APIKEY + ‘” \
    “https://iam.cloud.ibm.com/identity/token”’).read()

これで、watsonxを使用するLanguageModelインスタンスを作成できます。以前に取得したトークンをAPIキーとして使用し、Metaの「llama-3-8b-instruct」モデルを言語モデルとして使用します。言語モデルとして使用するためのそのモデルへのパスと、言語モデルで使用したい温度を、DSPyに渡します。watsonxを使用するようにLiteLLMを設定する方法の詳細については、GitHubドキュメントを参照してください。以下の例では、「0.7」にすることで、過度のハルシネーションを回避しつつ創造性を高めることができます。

lm = dspy.LM(‘watsonx/meta-llama/llama-3-8b-instruct’, api_key=WATSONX_APIKEY, api_base=”https://us-south.ml.cloud.ibm.com”)

dspy.configure(lm=lm, trace=[], temperature=0.7, experimental=True)

検索モデルを追加する

次に、RAGのRの検索モデルを読み込みます。ColBERTv2を使用して、Wikipedia 2017のデータセットから抽出をロードします。ColBERTは、高速で正確な検索モデルであり、大規模なテキスト・コレクションに対するスケーラブルなBERTベースの検索を数十ミリ秒で実現します。ColBERTは、ベクトル・データベースから情報を取得するために使用できる多くのオプションの1つにすぎません。これは、QdrantMilvusPineconeChromaWeaviateなどの他のベクトル・データベースに匹敵します。

ベクトル・データベースには、言語モデルが迅速にアクセスできる特定の情報セットが含まれます。この場合、Wikipedia 2017の一連の要約を使用して、言語モデルが生成で使用する幅広い事実を提供します。ColBERTとWiki 17データセットのこの組み合わせは、このバージョンがDSPyチームによって無料でホストされ、誰でも使用できるため、特に便利です。データを取り込んだり、独自のベクトル・データベース・システムをセットアップしたりする必要なく、幅広い情報にアクセスできるようになります。このデータセットの欠点の1つは、2017年以降のイベントに関するものが何も含まれていないことですが、デモンストレーションが目的の場合には非常に役立ちます。

独自のデータまたは更新されたデータセットを使用して独自バージョンのColBERTを実行することをご希望の場合は、こちらのチュートリアルをご覧ください。

次に、HotPotQAデータセットをロードし、検索チェーンのテストに使用できるトレーニング・セットとテスト・セットに分割します。HotpotQAは、自然なマルチホップ質問を含む質問応答データセットであり、裏付けとなる事実を強力に監視することで、より説明可能な質問応答システムを実現します。

colbertv2_wiki17_abstracts = dspy.ColBERTv2(url=’http://20.102.90.50:2017/wiki17_abstracts’)
dspy.configure(rm=colbertv2_wiki17_abstracts)

基本的なQAをテストする

ここでは最初の例に使用するシグネチャーを作成します。シグネチャーは、モジュールのインプットとアウトプットのタイプを定義するクラスであり、DSPyプログラム内の異なるモジュール間の互換性を保証します。シグネチャーは、質問の取り込みや応答のアウトプット、モデルの推論など、複数のタスクを組み合わせます。ここで使用するシグネチャーは、質問の取り込みと、応答の提供のみを行います。

class BasicQA(dspy.Signature):
    “””Answer questions with short factoid answers.”””

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

これで、DSPyのPredictメソッドを呼び出すだけでテストできる予測変数ができました。このメソッドは、以前に定義したnewBasicQAクラスを取得し、DSPyに質問を渡すときにそのクラスを使用します。

# Define the predictor.
generate_answer = dspy.Predict(BasicQA)

次に、正しく答えるためには複数の情報を必要とする質問を作成し、言語モデルのみを使用したアーキテクチャーでテストします。質問に答えるために、先ほど作成したgenerate_answer関数を使用します。

# Call the predictor on a particular input.
test_question = “What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?”

pred = generate_answer(question=test_question)

if pred == None:
    print(“ no answer “)
else:
    # Print the input and the prediction.
    print(f”Answer: Turkey, Orhan Pamuk”)
    print(f”Predicted Answer: {pred.answer}”)

コードは以下を返します(答えは異なる場合があります)。

Answer: Turkey, Orhan Pamuk
Predicted Answer: The winner was France and the author was Orhan Pamuk.

Orhan Pamuk氏は2006年にノーベル文学賞を受賞しましたが、彼はフランス出身ではなく、応答の構成も適切ではありません。次に、検索拡張生成を使用して検索機能でモデルを拡張し、DSPyでより優れたプロンプトを設計して性能を向上させます。

検索拡張生成(RAG)

検索拡張生成(RAG)は、信頼できるナレッジ・ベースからの参照を使用して大規模言語モデルのアウトプットを最適化するアーキテクチャーです。これにより、言語モデルが応答を生成する前に、トレーニング・データが検証済みのソースで強化されます。LLMは、大規模なコーパスでトレーニングされ、数十億のパラメーターを使用してアウトプットを生成しますが、トレーニング・コーパスからの最新または正確な情報にアクセスできない場合があります。RAGは、モデルを再トレーニングすることなく、すでに強力なLLMの機能を特定のドメインに拡張します。LLMのアウトプットを改善する強力で潜在的にコスト効率の高い方法であり、あらゆる状況での関連性、正確性、有用性を維持します。

DSPyでは、シグネチャーにコンテキスト・ステップを追加することで、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”)

この新しいGenerateAnswerシグネチャーは、RAGモデルで使用できます。GenerateAnswerを「ChainOfThought」モジュールに渡し、検索されるコンテキストと質問応答が「思考の連鎖」アプローチを使用するようにします。

また、RAGからコンテキストの文章を生成し、それらのコンテキストの文章を使用して応答を生成するために、forwardメソッドを更新します。DSPyは、質問に応じて新しい応答を生成するたびに、この「forward」メソッドを呼び出し、ColBERT Wiki 17の要約データセットから両方のコンテキストを収集し、そのコンテキストを言語モデル(この場合はLlama 3.1)に渡します。それぞれの応答が生成されると、DSPyはそのアウトプットと目的のアウトプットを比較し、モデルが正しい応答を生成するのにプロンプトが役立っているか確認します。

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)

DSPyが最適なプロンプトを設計するのを支援するには、プロンプトをテストして評価するために使用できるテスト用データセットが必要です。

DSPyにテスト用の質問を出すには、HotPotQAデータセットをロードします。HotpotQAは、正しい答えに到達するために複数の検索と推論を必要とする自然なマルチホップ質問を主要な機能とする、質問応答データセットです。これは、モデルが裏付けとなる事実をどの程度適切に生成できるかをテストし、より説明可能な質問応答システムをトレーニングおよびテストするための優れたツールです。

例えば、データセットからの質問の1つは、「フランクリン・ルーズベルト大統領は、選挙人団の票を議会に送る責任を負う役職に誰を任命したか?」です。この質問に正しく答えるには、いくつかの情報が必要であることがわかります。

The answer is: “Robert Digges Wimberly Connor”.

サポート・コンテキストは、ロバート・ディッグス・ウィンバリー・コナーおよび米国立公文書記録管理局に関するWikipediaのページから得られます。

HotPotQAは、カーネギーメロン大学、スタンフォード大学、モントリオール大学のNLP研究者チームによって収集および公開されています。HotPotQAの詳細については、HotPotQAのGitHubサイトをご覧ください。

データセットをロードした後、トレーニング・セットとテスト・セットに分割します。これにより、検索チェーンをテストし、DSPyが言語モデルに最適なプロンプトを見つけるのを支援できます。

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

# Tell DSPy that the ‘question’ field is the input. Any other fields are labels and/or metadata.
trainset = [x.with_inputs(‘question’) for x in dataset.train]
devset = [x.with_inputs(‘question’) for x in dataset.dev]

次に、DSPyにプロンプトを生成して評価する機会を増やすために、より多くの例をブートストラップします。Callingcompileは、構成したすべてのアーキテクチャーとHotPotQAデータセットを使用してプロンプトを生成およびテストし、言語モデルから最高の性能を引き出すものです。

  from dspy.teleprompt import 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 DSPy optimizer, which will compile your RAG program.
bfs_optimizer = BootstrapFewShot(metric=validate_context_and_answer)

# Compile!
compiled_rag = bfs_optimizer.compile(RAG(), trainset=trainset)

DSPyがプロンプト・エンジニアリングを行ってくれたので、次は以前に使用した2006年ノーベル賞に関するカスタム質問でテストします検索モデルは2017年のWikipediaからの抽出を使用しているため、そのコーパスに存在する可能性のある知識を使用して最大限のパフォーマンスを発揮します。

# Get the prediction. This contains `pred.context` and `pred.answer`.
pred = compiled_rag(test_question)

# Print the contexts and the answer.
print(f”Question: {test_question}”)
print(f”Predicted Answer: {pred.answer}”)

これで正しい答えが得られます。

    Question: What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?
    Predicted Answer: Turkey, Orhan Pamuk

Orhan Pamuk氏はトルコ出身なので、この答えは正しいです。コンパイルされたバージョンのDSPyは、答えが正しいだけでなく、答えを正しく組み立て、完結かつ明確に応答しました。この予測応答のコンテキストを見て、モデルがどのようにして正しい答えに到達したかを確認してみましょう。

pred.context

これにより、次のものが返されます。

    ["Orhan Pamuk | Ferit Orhan Pamuk (generally known simply as Orhan Pamuk; born 7 June 1952) is a Turkish novelist, screenwriter, academic and recipient of the 2006 Nobel Prize in Literature. One of Turkey's most prominent novelists, his work has sold over thirteen million books in sixty-three languages, making him the country's best-selling writer.",
     '2006 Palanca Awards | The Carlos Palanca Memorial Awards for Literature winners in the year 2006 (rank, title of winning entry, name of author).',
     "Miguel Donoso Pareja | Miguel Donoso Pareja (July 13, 1931 – March 16, 2015) was an Ecuadorian writer and 2006 Premio Eugenio Espejo Award-winner (Ecuador's National Prize in literature, given by the President of Ecuador)."]

答えは、返されたコンテキストの最初のチャンクにあります。言語モデルのinspect_history()メソッドを使用すると、言語モデルの履歴を見ることで、DSPyがどのように最適なプロンプトを設計したかを確認できます。

lm.inspect_history()

DSPyが生成したプロンプトをテストしたコンパイル・プロセスの例がすべて含まれているため、この履歴は非常に長くなっています。履歴の最後の部分には、モデルがどのようにして正しい答えと正しい形式に到達したかが表示されます。

    [[ ## context ## ]]
    [1] «Orhan Pamuk | Ferit Orhan Pamuk (generally known simply as Orhan Pamuk; born 7 June 1952) is a Turkish novelist, screenwriter, academic and recipient of the 2006 Nobel Prize in Literature. One of Turkey's most prominent novelists, his work has sold over thirteen million books in sixty-three languages, making him the country's best-selling writer.»
    [2] «2006 Palanca Awards | The Carlos Palanca Memorial Awards for Literature winners in the year 2006 (rank, title of winning entry, name of author).»
    [3] «Miguel Donoso Pareja | Miguel Donoso Pareja (July 13, 1931 – March 16, 2015) was an Ecuadorian writer and 2006 Premio Eugenio Espejo Award-winner (Ecuador's National Prize in literature, given by the President of Ecuador).»
    
    [[ ## question ## ]]
    What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?
    
    Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## answer ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
    
    
    [31mResponse:[0m
    
    [32m[[ ## reasoning ## ]]
    The text mentions the 2006 Nobel Prize in Literature and states that Orhan Pamuk, a Turkish novelist, was the winner.
    
    [[ ## answer ## ]]
    Turkey, Orhan Pamuk
    
    [[ ## completed ## ]][0m
    

DSPyがモデルを使用してプロンプトを生成したことがわかります。

対応するアウトプット・フィールドで応答します。先頭のフィールドは [[ ## reasoning ## ]] で、次に [[ ## answer ## ]] 、最後は次のマーカーで終わります [[ ## completed ## ]] .

これにより、正しい答えとフレーミングが導き出されます。

まとめ

このチュートリアルでは、DSPyを使用して、watsonxプラットフォームを使用したRAGエージェントのファイン・チューニングを支援しました。RAGエージェントは、言語モデル、Llama 3、および検索モデルのColBERTで構成されています。次に、DSPyを使用して、モデルをコンパイルし、最適化されたプロンプトを生成することで、質問応答タスクのプロンプト・エンジニアリングを行いました。

DSPyの詳細は、チュートリアル、デモ、ドキュメントがホストされているGitHubリポジトリをご覧ください。

関連ソリューション
IBM watsonx.ai

AI開発者向けの次世代エンタープライズ・スタジオであるIBM watsonx.aiを使用して、生成AI、基盤モデル、機械学習機能をトレーニング、検証、チューニング、導入しましょう。わずかなデータとわずかな時間でAIアプリケーションを構築できます。

watsonx.aiの詳細はこちら
人工知能ソリューション

IBMの業界をリードするAIの専門知識とソリューションのポートフォリオを活用して、AIをビジネスの業務に利用しましょう。

AIソリューションの詳細はこちら
人工知能(AI)コンサルティングおよびサービス

IBMコンサルティングAIサービスは、企業がAIをトランスフォーメーションに活用する方法を再考するのに役立ちます。

AIサービスの詳細はこちら
次のステップ

AIを使用することで、IBM Concertはお客様のオペレーションに関する重要な洞察を明らかにし、改善のためのアプリケーション固有の推奨事項を提供します。Concertがどのようにビジネスを前進させることができるかをご覧ください。

Concertの詳細はこちら ビジネス・プロセス自動化ソリューションの詳細はこちら