プロンプトエンジニアリング:AIを騙して問題を解決する方法
プロンプトエンジニアリング:AI問題解決の手法
7つのプロンプトのテクニック、LangChain、およびPythonのサンプルコード
これは大規模な言語モデル(LLM)を実践的に使用するシリーズの4番目の記事です。ここでは、プロンプトエンジニアリング(PE)とそれを使用してLLM対応アプリケーションを構築する方法について説明します。まず、主要なPEの技術を説明し、次にLangChainを使用してLLMベースのアプリケーションを構築するPythonのサンプルコードを紹介します。
プロンプトエンジニアリングについて初めて聞いたとき、多くの技術者(私自身も含めて)はその考えに冷笑する傾向があります。私たちは、「プロンプトエンジニアリング? ふざけてるんじゃないの?ゼロからLLMを構築する方法を教えてくれ」と思うかもしれません。
しかし、より深く掘り下げると、プロンプトエンジニアリングを自動的に無視することは開発者にとってよくないことだと警告します。さらに進んで言えば、プロンプトエンジニアリングはほとんどのLLMのユースケースの価値の80%を実現できる(比較的)努力の低い方法だとさえ言えます。
この記事での私の目標は、プロンプトエンジニアリングと具体的な例を通じてこのポイントを伝えることです。プロンプトエンジニアリングができることには間違いなく限界があるかもしれませんが、それは私たちの問題に対する単純で巧妙な解決策を見つけるための扉を開くものです。
- 「GPT-4 8つのモデルを1つに統合、秘密が明かされる」
- 「GPTQまたはbitsandbytes:LLMsのためにどの量子化方法を使用するか — Llama 2の例」
- 「信じられないほどの新しい中間補間機能(領域の変化)」
プロンプトエンジニアリングとは何ですか?
このシリーズの最初の記事では、プロンプトエンジニアリングをLLMをそのまま使用すること(つまり、内部のモデルパラメータをトレーニングしないこと)と定義しました。しかし、これについてはもっと言えることがあります。
- プロンプトエンジニアリングは「LLMにプロンプトをプログラムする手段」です。[1]
- プロンプトエンジニアリングは「モデルのパフォーマンスを最大化するためにプロンプトを組み立て、フォーマットする経験主義的な芸術です。」[2]
- 「言語モデルは…文書を完成させたいと思っているので、偽の文書を配置することでタスクを実行させることができます。」[3]
最初の定義は、コンピューターをプレーンな英語でプログラムできるというLLMからの主要なイノベーションを伝えています。2つ目のポイントでは、プロンプトエンジニアリングを主に経験主義的な取り組みとして捉え、実践者、手を加える人、ビルダーがこの新しいプログラミング方法の主要な探求者であると位置付けています。
3番目のポイント(Andrej Karpathy氏から)は、LLMは私たちが頼んだほとんど何でもするように明示的にトレーニングされていないことを思い出させてくれます。したがって、ある意味では、これらの言語モデルを問題解決に使用するために「だます」必要があります。私はこれがプロンプトエンジニアリングの本質を捉えており、それはあなたの技術的なスキルよりもあなたの創造力に頼るものです。
2つのレベルのプロンプトエンジニアリング
プロンプトエンジニアリングを行う方法には、シリーズの最初の記事で「簡単な方法」と「少し難しい方法」と呼んだ2つの異なる方法があります。
簡単な方法
これは世界のほとんどの人がプロンプトエンジニアリングを行う方法であり、ChatGPT(または類似のもの)を介して行われます。これは直感的でコードを書かずにLLMと対話する方法であり、費用もかかりません。
これは簡単で素早く行いたいことには適したアプローチです。例えば、テキストの要約、メールの書き直し、誕生日パーティーの計画のアイデア出しの手助けなどですが、欠点もあります。大きな欠点の1つは、このアプローチを大規模な自動化プロセスやソフトウェアシステムに統合することが容易ではないということです。これを実現するためには、さらに一歩進む必要があります。
少し難しい方法
これは、「簡単な方法」の欠点の多くを解消するために、プログラムでLLMと対話する方法、つまりPythonを使用する方法です。このシリーズの前の2つの記事で、OpenAIのPython APIとHugging Face Transformersライブラリを探索する方法について見てきました。
これにはより多くの技術的知識が必要ですが、これがプロンプトエンジニアリングの真の力がある場所です。なぜなら、これにより開発者はLLMベースのモジュールを大規模なソフトウェアシステムに統合することができるからです。
これには、ChatGPTが良い(そしておそらく皮肉な)例です。この製品の中心は、事前にトレーニングされたモデル(つまりGPT-3.5-turbo)にチャットボットのように振る舞わせ、それを使いやすいWebインターフェースで包むことです。
もちろん、GPT-3.5-turboの開発が難しい部分ですが、それはここで心配する必要がないものです。私たちの手にあるすべての事前トレーニング済みLLMを使えば、AI研究者や機械学習の博士でなくても、基本的なプログラミングスキルを持つほとんどの人がChatGPTのような強力なAIアプリケーションを作成できます。
プロンプトエンジニアリングによるAIアプリの構築
より簡単ではない方法は、プログラミングとソフトウェア開発の新しいパラダイムを開放します。開発者はもはやソフトウェアシステムのすべての論理を定義する必要はありません。非自明な部分をLLMにオフロードするオプションがあります。具体的な例を見てみましょう。
例えば、高校の歴史の授業のための自動採点システムを作成したいとします。しかし、問題は全てが文章で回答されるため、正しい答えのバリエーションが存在することがよくあります。例えば、「アメリカ合衆国の35代大統領は誰ですか?」という問いに対して、以下の回答は正しいかもしれません。
- ジョン・F・ケネディ
- JFK
- ジャック・ケネディ(一般的なニックネーム)
- ジョン・フィッツジェラルド・ケネディ(おそらく高得点を狙っている)
- ジョン・F・ケネディ(名前のスペルミス)
従来のプログラミングパラダイムでは、開発者はこれらのバリエーションを考慮する方法を見つける必要がありました。これには、すべての可能な正しい答えをリストアップし、正確な文字列マッチングアルゴリズムを使用したり、スペルミスに対応するためにファジーマッチングを使用したりすることがあります。
しかし、この新しいLLMを利用したパラダイムでは、シンプルなプロンプトエンジニアリングを通じて問題を解決できます。例えば、以下のプロンプトを使用して生徒の回答を評価することができます。
あなたは高校の歴史の先生で、宿題の採点を行います。「Q:」で示される宿題の問題と「A:」で示される正しい答えに基づいて、生徒の回答が正しいかどうかを判断することがあなたの仕事です。採点はバイナリです。したがって、生徒の回答は正しいか間違っています。簡単なスペルミスは許容します。
Q: {question}A: {correct_answer} Student Answer: {student_answer}
このプロンプトは、質問、正しい答え、生徒の回答を与えられると、生徒の成績を生成する関数と考えることができます。これは、自動採点を実装する大きなソフトウェアに統合することができます。
時間の節約の観点から考えると、このプロンプトを書くのに約2分かかりましたが、同じことを行うアルゴリズムを開発しようとすると、数時間(もしくは数日)かかり、パフォーマンスも悪くなるかもしれません。したがって、このようなタスクに対しては時間の節約が100〜1000倍になります。
もちろん、LLMが実質的な利益を提供しない多くのタスクや、他の既存の方法の方が適しているタスクもあります(例:明日の天気の予測)。LLMはすべての問題の解決策ではありませんが、自然言語の処理を効果的に行う必要があるタスクに対して新しい解決策を提供します。これは、コンピュータが過去に難しかったことです。
プロンプトエンジニアリングのための7つのトリック
以前のプロンプトの例は、自動採点タスクをフレーム化する自然で明らかな方法のように見えるかもしれませんが、特定のプロンプトエンジニアリングのヒューリスティクス(または「トリック」と呼ぶこともあります)が意図的に使用されています。これらのトリックは、LLMの応答品質を向上させるための信頼性のある方法として浮かび上がっています。
良いプロンプトを書くための多くのヒントやトリックがありますが、ここでは、いくつかの参考文献[1,3-5]に基づいて、最も基本的なものに絞って議論します。より詳細な情報を求める場合は、ここで引用されているソースを探索することをお勧めします。
トリック1:具体的であること(多いほど良い)
LLMの特徴の1つは、大量のテキストコーパスで訓練されていることです。これにより、彼らは世界の広範な知識と、非常に多様なタスクを実行する能力を備えています。しかし、適切な文脈が提供されない場合、この印象的な一般性は特定のタスクのパフォーマンスを妨げる可能性があります。
例えば、私の父への誕生日メッセージを生成するための2つのプロンプトを比較しましょう。
トリックなし
父の誕生日メッセージを書いてください。
トリックあり
父の誕生日メッセージを、200文字以下で書いてください。彼が50歳になるので、これは大きな誕生日です。お祝いに、カンクンへの男子旅行を予約しました。チープなユーモアを含めてください、彼はそれが大好きです。
トリック2:例を示す
次のトリックは、特定のタスクでLLMのパフォーマンスを向上させるために、LLMの応答例を提供することです。これの技術的な用語はfew-shot learningと呼ばれ、LLMのパフォーマンスを大幅に向上させることが示されています[6]。
具体的な例を見てみましょう。Towards Data Scienceの記事のサブタイトルを書きたいとします。既存の例を使用して、LLMの補完をガイドすることができます。
トリックなし
Given the title of a Towards Data Science blog article, write a subtitle for it.Title: Prompt Engineering—How to trick AI into solving your problemsSubtitle:
トリックあり
Given the title of a Towards Data Science blog article, write a subtitle for it.Title: A Practical Introduction to LLMsSubtitle: 3 levels of using LLMs in practiceTitle: Cracking Open the OpenAI (Python) APISubtitle: A complete beginner-friendly introduction with example codeTitle: Prompt Engineering-How to trick AI into solving your problemsSubtitle:
トリック3:構造化テキストの使用
プロンプトが整理された構造に従っていることは、読み書きが容易になるだけでなく、モデルが良い補完を生成するのにも役立ちます。これはトリック2の例で使用されたテクニックであり、各例のタイトルとサブタイトルを明示的にラベル付けしました。
ただし、プロンプトに構造を与える方法は無数にあります。以下にいくつかの例を示します:強調するためにすべて大文字を使用する、“`のような区切り記号を使用して本文を強調する、MarkdownやHTMLのようなマークアップ言語を使用してテキストを整形する、情報を整理するためにJSONを使用するなど。それでは、これを実際に見てみましょう。
トリックなし
チョコレートチップクッキーのレシピを書いてください。
トリックあり
チョコレートチップクッキーのための整理されたレシピを作成してください。次のフォーマット要素を使用してください:**タイトル**:クラシックチョコレートチップクッキー**材料**:正確な量とフォーマットで材料をリストアップしてください。**手順**:焼き方の詳細なステップバイステップの指示を番号付き形式で提供してください。**ヒント**:有益な焼き方のヒントと可能なバリエーションを別のセクションに含めてください。
トリック4:思考の連鎖
このトリックは、Wei et al.によって提案されました[7]。基本的なアイデアは、LLMに「ステップバイステップ」で考えるように導くことです。これにより、複雑な問題を管理可能なサブ問題に分解することができ、LLMに「考える時間」を与えることができます[3,5]。Zhang et al.は、プロンプトに「ステップバイステップで考えましょう」というテキストを含めるだけで良いことを示しました[8]。
この考えは、任意のレシピのようなプロセスに拡張することができます。たとえば、私が最新のVoAGIブログに基づいてLinkedInの投稿を作成したい場合、LLMに私が実際に行っているステップバイステップのプロセスを反映させることができます。
トリックなし
以下のVoAGIブログに基づいてLinkedInの投稿を書いてください。VoAGIブログ:{VoAGIブログのテキスト}
トリックあり
以下のステップバイステップのプロセスとVoAGIブログに基づいてLinkedInの投稿を書いてください。ステップ1:ブログに関連する1行フックを考える。ステップ2:記事から3つのキーポイントを抽出する。ステップ3:各ポイントを50文字未満に圧縮する。ステップ4:フック、ステップ3の圧縮されたキーポイント、および最終出力を生成するためのアクションを組み合わせる。VoAGIブログ:{VoAGIブログのテキスト}
トリック5:チャットボットのパーソナリティ
LLMのパフォーマンスを向上させる傾向がある、やや驚くべきテクニックは、特定のパーソナリティを持つように促すことです。たとえば、「あなたは専門家です」といった具体的なパーソナリティを与えます。これは、LLMに問題を最適に説明する方法を知らないかもしれませんが、その問題を解決するのに役立つ人物を知っているかもしれないからです[1]。実践では、次のようになります。
トリックなし
ニューヨーク市での週末の旅行の予定を作ってください。
トリックあり
ニューヨーク市のナティブであり、市のすべてを知っているタクシー運転手として振る舞ってください。あなたの経験に基づいて、ニューヨーク市での週末の旅行の予定を作ってください。応答にはあなたの魅力的なニューヨーク訛りも忘れずに含めてください。
トリック6:フリップアプローチ
LLMが何を知っているのか、どのように考えるのかがわからない場合、LLMに最適なプロンプトを与えるのは難しいことがあります。そのような場合に役立つのが「フリップアプローチ」です。これは、LLMに問題の理解(つまり文脈)を十分に得るまで、LLMに質問をするように促す方法です。
トリックなし
LLMベースのアプリケーションのアイデアは何ですか?
トリックあり
LLMベースのアプリケーションのアイデアを考えるのを手伝うために、私に質問をしてください。会話形式を保つために、1回に1つの質問をしてください。
トリック7:反省、レビュー、改善
この最後のトリックでは、モデルに過去の応答を反省させ、それらを改善するよう促します。一般的な使用例としては、モデルに「課題を完了したか」と尋ねたり、応答の背後にある「推論と仮定」を説明させたりすることがあります[1, 3]。
さらに、LLMには、応答だけでなくプロンプト自体も改善するように求めることができます。これは、モデルが「理解」しやすいようにプロンプトを自動的に書き換える簡単な方法です。
トリックあり
前回の応答を見直し、改善点を特定し、改善版を提供してください。その後、応答の改善方法についての理由を説明してください。
サンプルコード:LangChainを使用した自動採点システム
これまでにいくつかのプロンプトのヒューリスティックを見直しましたが、それらを特定のユースケースにどのように適用できるか見てみましょう。これを行うために、以前の自動採点の例に戻りましょう。
あなたは高校の歴史の教師で、宿題の採点を行います。 "Q:"で示される宿題の質問と、"A:"で示される正解に基づいて、学生の回答が正しいかどうかを判断するタスクです。採点は2値です。つまり、学生の回答は正しいか間違っています。簡単なスペルのミスは許容します。 Q: {question}A: {correct_answer} 学生の回答: {student_answer}
よく見ると、以前に言及したいくつかのトリックが明らかになるはずです。すなわち、トリック6:チャットボットのパーソナリティ、トリック3:構造化テキストの使用、およびトリック1:具体的な説明です。これが実践では典型的な良いプロンプトの例です。つまり、複数の技法を一つのプロンプトで組み合わせることです。
このプロンプトテンプレートをそのままChatGPTにコピー&ペーストし、質問、correct_answer、およびstudent_answerのフィールドを置き換えることもできますが、自動採点システムを実装するスケーラブルな方法ではありません。むしろ、このプロンプトをより大規模なソフトウェアシステムに統合し、人間が使用できるユーザーフレンドリーなアプリケーションを構築したいのです。
LangChain
このために使用できる方法の一つがLangChainです。LangChainは、大規模な言語モデルの上にアプリケーションを構築するのを簡素化するためのPythonライブラリです。これは、LLMをプログラムで使用するためのさまざまな便利な抽象化を提供することでこれを実現します。
このための中心的なクラスはchainと呼ばれます(それがライブラリ名の由来です)。このクラスは、プロンプトの生成、LLMへの送信、および出力の解析のプロセスを抽象化し、簡単に呼び出してより大きなスクリプトに統合することができます。
自動採点のユースケースでLangChainを使用する方法を見てみましょう。この記事のGitHub Repoにはサンプルコードがあります。
インポート
まず、必要なライブラリモジュールをインポートします。
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser
ここでは、OpenAIのAPIには秘密鍵が必要なgpt-3.5-turboを使用します。持っていない場合は、このシリーズの過去の記事で1つ手順ガイドを提供しました。私は秘密鍵を別のPythonファイル(sk.py)に保存し、次のコード行でインポートすることが好きです。
from sk import my_sk #別のPythonファイルから秘密鍵をインポート
最初のチェーン
チェーンを定義するには、LLMとプロンプトの2つの主要な要素が必要です。まず、LLMのオブジェクトを作成します。
# LLMオブジェクトの定義chat_model = ChatOpenAI(openai_api_key=my_sk, temperature=0)
LangChainには、OpenAI(およびその他多くの)チャットモデル専用のクラスがあります。ここでは、秘密のAPIキーを渡し、温度を0に設定しています。ここでのデフォルトモデルはgpt-3.5-turboですが、”model_name”の入力引数を使用して代わりにgpt-4を使用することもできます。他の入力引数を設定することで、さらにチャットモデルをカスタマイズできます。
次に、プロンプトテンプレートを定義します。このオブジェクトを使用すると、基本テンプレートを自動的に更新する入力文字列を介して動的にプロンプトを生成できます。以下にその例を示します。
# プロンプトテンプレートの定義prompt_template_text = """You are a high school history teacher grading homework assignments. \
Based on the homework question indicated by “**Q:**” and the correct answer indicated by “**A:**”, your task is to determine whether the student's answer is correct. \
Grading is binary; therefore, student answers can be correct or wrong. \
Simple misspellings are okay.**Q:** {question}**A:** {correct_answer}**Student's Answer:** {student_answer}"""prompt = PromptTemplate(input_variables=["question", "correct_answer", "student_answer"], \
template = prompt_template_text)
LLMとプロンプトがそろったら、チェーンを定義できます。
# チェーンの定義chain = LLMChain(llm=chat_model, prompt=prompt)
次に、チェーンに入力を渡して1行のコードで成績を取得できます。
# 入力の定義question = "Who was the 35th president of the United States of America?"correct_answer = "John F. Kennedy"student_answer = "FDR"# チェーンの実行chain.run({'question':question, 'correct_answer':correct_answer, \
'student_answer':student_answer})# 出力: Student's Answer is wrong.
このチェーンは採点のタスクを効果的に実行できますが、その出力は自動化プロセスには適していない場合があります。たとえば、上記のコードブロックでは、LLMは正しく学生の回答「FDR」が間違っていると述べていますが、LLMがダウンストリーム処理で使用できる標準形式の出力を提供してくれる方が良いでしょう。
出力パーサー
ここで、出力パーサーが便利になります。これらは、LLMの出力を標準形式に変換するためにチェーンに統合できる関数です。LLMの応答を真偽値(つまりTrueまたはFalse)出力に変換する出力パーサーを作成してみましょう。
# 出力パーサーの定義class GradeOutputParser(BaseOutputParser): """採点が正しいか間違っているかを判断する""" def parse(self, text: str): """LLMの呼び出しの出力を解析する。""" return "wrong" not in text.lower()
ここでは、「wrong」という単語がLLMの出力に含まれているかどうかをチェックする単純な出力パーサーを作成しています。含まれていない場合はTrueを返し、学生の正しい回答を示します。それ以外の場合はFalseを返し、学生の回答が不正解であることを示します。
次に、この出力パーサーをチェーンに組み込んで、チェーンを実行する際にテキストをシームレスに解析できるようにします。
# チェーンの更新chain = LLMChain( llm=chat_model, prompt=prompt, output_parser=GradeOutputParser())
最後に、学生の回答リスト全体を実行し、出力を表示できます。
# forループでチェーンを実行
student_answer_list = ["John F. Kennedy", "JFK", "FDR", "John F. Kenedy", \ "John Kennedy", "Jack Kennedy", "Jacquelin Kennedy", "Robert F. Kenedy"]
for student_answer in student_answer_list:
print(student_answer + " - " + str(chain.run({'question':question, 'correct_answer':correct_answer, 'student_answer':student_answer})))
print('\n')
# 出力
# John F. Kennedy - True
# JFK - True
# FDR - False
# John F. Kenedy - True
# John Kennedy - True
# Jack Kennedy - True
# Jacqueline Kennedy - False
# Robert F. Kenedy - False
YouTube-Blog/LLMs/langchain-example at main · ShawhinT/YouTube-Blog
YouTubeビデオとVoAGIのブログ記事を補完するコード – YouTube-Blog/LLMs/langchain-example at main ·…
github.com
制約事項
プロンプトエンジニアリングは、電子メールの作成のためのChatGPTへのヘルプや量子コンピューティングについての学習以上のものです。これは開発者がアプリケーションを構築する方法を変える新しいプログラミングパラダイムです。
これは強力な革新ですが、制約事項もあります。まず、最適なプロンプト戦略はLLMに依存します。例えば、GPT-3に「ステップバイステップで考える」とプロンプトを与えることで、単純な数学的推論タスクでの性能向上が見られました [8]。ただし、最新バージョンのChatGPTでは、同じ戦略は効果的ではないようです(既にステップバイステップで考えているため)。
プロンプトエンジニアリングのもう一つの制約事項は、ChatGPTなどの大規模汎用言語モデルを使用する必要があることですが、これにはかなりの計算リソースと費用がかかります。これは、文字列の一致、感情分析、テキスト要約など、より狭義に定義された多くのユースケースにとってはオーバーキルかもしれません。
これらの制約を克服する方法として、事前学習済み言語モデルの微調整があります。これは、既存の言語モデルを特定のユースケースに合わせて調整することです。このシリーズの次の記事では、人気のある微調整技術とPythonの例コードを紹介します。
👉 LLMsについて詳しく: イントロダクション | OpenAI API | Hugging Face Transformers
リソース
コネクト: 私のウェブサイト | 電話を予約する | 何でも聞いてください
ソーシャル: YouTube 🎥 | LinkedIn | Twitter
サポート: 私にコーヒーをご馳走してください ☕️
データ起業家
データ空間の起業家のためのコミュニティ。👉 Discordに参加しましょう!
VoAGI.com
[1] arXiv:2302.11382 [cs.SE]
[2] arXiv:2106.09685 [cs.CL]
[3] Microsoft Build 2023でのAndrei KarpathyによるGPTの状態
[4] arXiv:2206.07682 [cs.CL]
[5] deeplearning.aiによる開発者向けChatGPTプロンプトエンジニアリング
[6] arXiv:2005.14165 [cs.CL]
[7] arXiv:2201.11903 [cs.CL]
[8] arXiv:2210.03493 [cs.CL]
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles