【UiPath×OpenAI】開発者向けのプロンプトエンジニアリング① 前編 プロンプト文の原則と反復型開発

LLM（Large Language Models）は人々の生活を着実に変えており、開発者にとっては非常に強力なツールです。LLMが提供するAPIを利用することで、開発者は素早く便利なアプリケーションを開発することができます。
OpenAIは、LLMを開発者に提供するためのAPIを提供しており、これを使用することで、開発者は自分のアプリケーションやプロジェクトにLLMの能力を組み込むことができます。

UiPathでOpenAIを使用すると、本来ルールベースのRPAでできなかったこと、例えば、自然言語処理やチャットボットなども可能になり、UiPath開発者として、OpenAIを使用する際のプロンプト文の構成原則やテクニックを把握することで、自動化の範囲が更に広がると思います。

# 記事概要
本記事は以下の講座を纏めた内容です。

https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/

これが開発者向けのプロンプトエンジニアリングガイドです。Andrew Ng先生の「ChatGPT Prompt Engineering for Developers」コースを基に、**初心者向けのLLM開発者向けに、プロンプトの構築方法とOpenAIのAPIを使用して要約、推論、変換などの一般的な機能を実現する方法をわかりやすく紹介しています。**
記事の最後に、UiPath Studioを使用して、講座でのそれぞれのテーマを実現しました。UiPath×OpenAIの開発において、この情報を活用することで、より高度な自動化ワークフローの開発を期待できます。

本記事では、OpenAIを使用してプロンプト文構築の原則と手法を解説し、最後に、UiPath×OpenAIでの応用も説明します。
本記事で作成したJupiter NotebookとUiPath Workflowは以下の通りです。ご参照ください。

- [【OpenAI】開発者向けのプロンプトエンジニアリング① 前編.ipynb](https://drive.google.com/file/d/1YjiSqQF-2lwgLAWgM3scdv6sCMeI-SfD/view?usp=drive_link)
- [【UiPath Workflow】開発者向けのプロンプトエンジニアリング 前編](https://drive.google.com/drive/folders/16zu8_rKUDGDLfCKFn6xveH2JA4e4_k3k?usp=drive_link)

上記Jupiter Notebookの開き方は以下のビデオをご参照ください。

https://www.youtube.com/watch?v=inN8seMm7UI

# 環境設定
この記事では、OpenAIが提供するChatGPT APIを使用しています。したがって、最初にChatGPTのAPIキーを取得する必要があります（または公式ウェブサイトでオンラインテストを実施することもできます）。次に、openaiのライブラリをインストールする必要があります。
openai：
```bash
pip install openai
```
ライブラリのインポートと自分のAPIキーを設定します。
```bash
import openai
import os
openai.api_key='自身のOpenAI キー'
```
これから、OpenAIが提供するChatCompletion APIの使用方法を詳しく確認します。ここでは、それを関数にラップしてみます。内部の仕組みを理解する必要はありません。単に、この関数を呼び出すと、プロンプトに対応するCompletionが提供されることを知っていれば十分です。
```python
# 「Prompt」を受け取り、それに対応する結果を返す関数
# gpt-3.5-turbo
def get_completion(prompt, model="gpt-3.5-turbo"):
    '''
    prompt: 入力となるPrompt
    model: 使用するGPTモデルを指定、デフォルトgpt-3.5-turbo(ChatGPT)
    '''
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 生成されたテキストの多様性や予測のランダム性を調整するためのパラメータ
    )
    # OpenAIからの応答からテキストを抽出
    return response.choices[0].message["content"]
```
# プロンプト文の原則
## 原則1：指示を分かりやすく具体的な内容にする
ChatGPTに行う操作を明確にするために、できるだけ明確かつ具体的な指示を与える必要があります。これにより正しい出力をモデルに促し、関係ないまたは不正確な反応を受ける可能性を減らすことができます。
指示を分かりやすくするのは簡略にする意味ではありません。多くの場合、長い指示はより明確であり、より多くの文脈を提供し、実際にはより詳細で関連性の高い出力を可能にすることがあります。
### 戦略１：入力の異なる部分を明確に示すために区切り文字を使用
区切り文字には```、""、<>、<tag>、<\tag>などが使用できます。
特定のテキスト部分をヒントの残りの部分と区別するために、明確な句読点を使用することができます。これは、モデルにそれが個別の部分であることを明示的に伝えることができる任意のマーカーです。
以下の例で、`「」`命令の対象を囲んで、該当対象に対して指示をします。
```python 
text = f"""
プロンプトを書く前には、できるだけ明確で具体的な指示を提供しなければならず、\
望んだ出力を導き、関係なく間違いの可能性を減らしなければなりません。\
簡潔なプロンプトと明確なプロンプトを混同してはいけません。\
多くの場合、より長いプロンプトは、モデルにより詳細な出力を生成し、関連性のある出力を可能にするために、より多くの明確さと文脈を提供します。
"""
# 指示内容
prompt = f"""
「」で囲んだ文を一言でまとめる。
「{text}」
"""
response = get_completion(prompt)
print(response)
```
出力：`明確な指示と文脈は重要。`
### 戦略２：JsonやHTMLなどの形式で構造化された出力を要求 
これにより、モデルの出力を解析しやすくすることができます。たとえば、Pythonで辞書やリストに読み込むことができます。
以下の例では、GPTに対して3冊の本のタイトル、著者、カテゴリを生成し、それをJson形式で返すように要求しています。解析を容易にするために、Jsonのキーを指定しています。
指示：
```python 
prompt = f"""
以下をJSON形式で提供し、book_id、title、author、genreというキーを含む、\
架空の3冊の日本語の書籍リストを生成してください。
"""
response = get_completion(prompt)
print(response)
```
出力：
```json
[
  {
    "book_id": 1,
    "title": "夏目漱石全集",
    "author": "夏目漱石",
    "genre": "小説"
  },
  {
    "book_id": 2,
    "title": "坊ちゃん",
    "author": "夏目漱石",
    "genre": "小説"
  },
  {
    "book_id": 3,
    "title": "銀河鉄道の夜",
    "author": "宮沢賢治",
    "genre": "児童文学"
  }
]
```
### 戦略３：モデルが条件を満たしているかを確認
もし指示文(タスク)が与えられた仮定が満たされない場合、モデルに先にこれらの仮定を確認してもらうことができます。満たされなければ指示して実行を停止する。潜在的なエッジケースや、偶発的な誤りや結果を避けるために、モデルがどのように対処するかも考慮する必要があります。
以下の例では、モデルにお茶の作り方の一連の手順と明示されていないテキストを二つの段落として与えます。モデルは、手順のセットが含まれるかを判断し、含まれなければ「手順が提供されていません」と回答し、含まれていれば示された形式で手順を再書き出すよう要求します。
- 手順が出せる場合：
```python 
text_1 = f"""
水を沸かすのが最初だ。その間、杯に茶葉を入れておく。\
水が温かくなると茶葉に注ぐ。数分間浸かしてから茶葉を取り出す。\
お好みで砂糖か牛乳を加えることも可能だ。\
そうすれば、美味しいお茶が出来上がる。
"""
prompt = f"""
あなたは３つの引用符で囲まれたテキストを受け取ります。\
そしてもしそこに一連の指示があるなら、以下の形式に従ってそれらを再書き起こす必要があります：
1つめの手順 -...
2つめの手順 -...
…
N番目の手順  -...
もし文章中に一連の指示がないなら、そのまま“手順を提供しない”と書いてください。"
\"\"\"{text_1}\"\"\"
"""
response = get_completion(prompt)
print("Text 1 のまとめ:")
print(response)
```
出力：
```json
Text 1 のまとめ:
1つめの手順 - 水を沸かすのが最初だ。
2つめの手順 - その間、杯に茶葉を入れておく。
3つめの手順 - 水が温かくなると茶葉に注ぐ。
4つめの手順 - 数分間浸かしてから茶葉を取り出す。
5つめの手順 - お好みで砂糖か牛乳を加えることも可能だ。
6つめの手順 - そうすれば、美味しいお茶が出来上がる。
```
- 手順が出せない場合：
```python 
# 无步骤的文本
text_2 = f"""
今日は陽気で鳥たちは歌い始めた。\
これは、公園に散歩に行く素敵な日です。\
花々は咲き乱れ、木の枝は微風でそろそろ揺れています。\
人々は素敵な天気を楽しんで外に出ています。\
野球をしている人もいれば、ゲームをしている人もいて、芝生でリラックスしている人もいます。\
完璧な日であり、外に出て自然の美しい景色を楽しむことができます。
"""
prompt = f"""
あなたは３つの引用符で囲まれたテキストを受け取ります。\
そしてもしそこに一連の指示があるなら、以下の形式に従ってそれらを再書き起こす必要があります：
1つめの手順 -...
2つめの手順 -...
…
N番目の手順 -...
もし文章中に一連の指示がないなら、そのまま“手順を提供しない”と書いてください。"
\"\"\"{text_2}\"\"\"
"""
response = get_completion(prompt)
print("Text 2 のまとめ:")
print(response)
```
出力：
```json
Text 2 のまとめ:
手順を提供しない
```
### 戦略４：成功したタスクの示例を少量提供
まず、モデルが実際のタスクを実行する前に、それに成功したタスクの示例を少量提供します。
例えば、以下の例では、モデルにタスクが一貫したスタイルで質問に答えることであることを伝え、子と祖父間の対話の例を与えました。子が「私に耐性を教えてください」と言うと、祖父はこれらの隠喩を使って答えた。そのため、モデルに一貫した口調で答えることを伝えた後、「私に堅毅さを教えてください」と言うと、モデルはこの少量サンプルを持っているので、似たような口調で次のタスクに答えるでしょう。
```python 
prompt = f"""
このあなたの使命は、一貫したスタイルで質問に答えることです。
<子供>：私に耐心を教えて。
<祖父>:最深い峡谷の河川は、見逃すような小さな湧き水から始まり、最も壮大な交響楽は、1つのノートから始まり、最も複雑な織物は1本の独立した線から開始されます。
<子供>：私に粘り強さを教えて。
"""
response = get_completion(prompt)
print(response)
```
出力：
```json
<祖父>：粘り強さは、困難な状況に直面したときに諦めずに努力し続けることです。それは、一歩ずつ進み、目標に向かって取り組むことです。最も美しい花は、最も厳しい条件で育ちますし、最も強い木は、最も強い風に耐えます。粘り強さは、成功への道を切り開く力です。
```
## 原則2：モデルへの時間を掛けて考えさせる
モデルが間違った結論を急いで導き出した場合、検索を再構築して最終答えを提供する前に関連する推論のシリーズをモデルが行うように要求するべきです。つまり、モデルにシャープで時間的制限を受けないかつ少ない文字による不可能なタスクを投げかけた際、間違いを犯す可能性があります。
これは人間にとっても同じです。複雑な数学的な問題を時間を掛けず完成させようとすると間違いを犯す可能性があります。
このような状況下では、モデルがタスクに更なる時間を費やして考えなくてはならないように指示することができます、そしてこれはモデルに計算リソースを使ってそのタスクに費やす時間が増えることを意味します。
### 戦略１：タスクを完了するために必要な手順を指定する
次のステップとして、複雑な課題を与え、その課題を完了するための一連のステップを示して、この戦略の効果を示すことにします。
まず、ジャックとジルの物語を描写し、命令を与えました。その命令は以下の操作を実行することでした。
- 1つ目に、3つの引用符で囲まれたテキストを1つの文でまとめます。
- 2つ目に、概要を英語に翻訳します。
- 3つ目に、英語の要約からそれぞれの名前をリストします。
- 4つ目に、以下のキーを含むJSONオブジェクトを出力します：英語の概要と名前数。
最後に、答えを改行で区切ります。
```python 
text = f"""
おとぎ話のような町で、ジェックとジルが山の頂上の泉に水を汲むために出発しました。\
喜びのうたをうたながら登っていくと、悲劇が降りかかった――ジェックが崖から一の石を落とし、ジルがそのまま追いかけてしまった。\
少し痛い思いをしながらも、おうちへと帰ってきました。
しかし、このような事故があっても、冒険精神は萎えなく、また楽しそうに探検を続けていました。
"""
# example 1
prompt_1 = f"""
以下の指示を実行してください。：
1- 三つのバッククォートで囲まれたテキストを一句でまとめる。
2- 概要を英語に翻訳する。
3- 英語の概要に含まれる各名前をリストアップする。
4- 次のキーが含まれる JSON オブジェクトを出力する：English_summary、num_names。
Text:
```{text}```
"""
response = get_completion(prompt_1)
print("prompt 1:")
print(response)
```
出力：
```json
prompt 1:
1- おとぎ話のような町で、ジェックとジルが山の頂上の泉に水を汲むために出発し、悲劇が起こるが、冒険精神は萎えずに探検を続ける。
2- In a fairytale-like town, Jack and Jill set off to the top of the mountain to fetch water from the spring. As they joyfully climbed, tragedy struck - Jack dropped a stone from the cliff and Jill chased after it. Despite experiencing some pain, they returned home. However, even with such accidents, their adventurous spirit did not waver, and they continued exploring happily.
3- Jack, Jill
4- {
  "English_summary": "In a fairytale-like town, Jack and Jill set off to the top of the mountain to fetch water from the spring. As they joyfully climbed, tragedy struck - Jack dropped a stone from the cliff and Jill chased after it. Despite experiencing some pain, they returned home. However, even with such accidents, their adventurous spirit did not waver, and they continued exploring happily.",
  "num_names": 2
}
```
更に改善してみます：
```python 
text = f"""
おとぎ話のような町で、ジェックとジルが山の頂上の泉に水を汲むために出発しました。\
喜びのうたをうたながら登っていくと、悲劇が降りかかった――ジェックが崖から一の石を落とし、ジルがそのまま追いかけてしまった。\
少し痛い思いをしながらも、おうちへと帰ってきました。
しかし、このような事故があっても、冒険精神は萎えなく、また楽しそうに探検を続けていました。
"""
prompt_2 = f"""
1-一言で<>で囲まれた文を要約する。
2-要約を英語に翻訳する。
3-英語の要約に名前をすべてリストアップする。
4-次のキーを含むJSONオブジェクトを出力する：English_summary、num_names。
以下のフォーマットを使用してください：
テキスト： <要約するテキスト>
要約：<要約>
翻訳：<要約の翻訳>
名前： <英語要約の名前のリスト>
出力JSON: < English_summaryとnum_namesを含むJON>
Text: <{text}>
"""
response = get_completion(prompt_2)
print("\nprompt 2:")
print(response)
```
出力：
```json
prompt 2:
Summary: ジェックとジルは山の頂上の泉に水を汲みに行きましたが、ジェックが石を落とし、ジルが追いかけてしまいました。しかし、彼らは冒険精神を失わずに楽しく探検を続けました。
Translation: Jack and Jill went to the top of the mountain to fetch water from the spring. However, Jack accidentally dropped a stone and Jill chased after it. Despite this accident, they continued their exploration with enthusiasm.
Names: Jack, Jill
Output JSON: 
{
  "English_summary": "Jack and Jill went to the top of the mountain to fetch water from the spring. However, Jack accidentally dropped a stone and Jill chased after it. Despite this accident, they continued their exploration with enthusiasm.",
  "num_names": 2
}
```
### 戦略２：結論に飛びつく前に、モデルに自分で解決策を考えるように指示
判断を下す前に解決策を考えるようにモデルに明示的に指示すると、より良い結果が得られることがあります。
次に、問題と生徒の答えを与え、その答えが正しいかどうかをモデルに判断させます。
```python 
prompt = f"""
生徒の解答が正しいかどうかを判断する。
質問
私は太陽光発電所を建設しており、コストの算出を手伝ってほしい。
    土地代は100ドル/平方フィートです。
    ソーラーパネルを$250/平方フィートで購入できます。
    年間10万ドルの固定支払いと、1平方フィートあたり10ドルの追加支払いが必要な保守契約について交渉しました。
    面積の関数として、運営初年度の総費用はいくらか。
生徒の解答
発電所の大きさを平方フィートで「x」とする。
コスト：
    土地代：100x
    ソーラーパネルの費用：250x
    メンテナンス費用：100,000ドル＋100x
    総費用：100x + 250x + $100,000 + 100x = 450x + $100,000
"""
response = get_completion(prompt)
print(response)
```
出力：`生徒の解答は正しいです。総費用は450x + $100,000となります。`
然しながら、学生の解決策は実際には誤っています。
この問題を解決するために、モデルに自分で解決策を見つけさせることができます。
次のプロンプトでは、モデルにまず自分で問題を解決させ、その後、モデルの解決策と学生の解決策を比較して、学生の解決策が正しいかどうかを判断します。同時に、出力の形式も指定されています。
明確な手順を通じて、モデルにより多くの考える時間を与え、時にはより正確な結果を得ることができます。
この例では、学生の回答が誤っていますが、モデルに自分で計算させない場合、学生が正しいと誤解される可能性があります。
```python 
prompt = f"""
生徒の解答が正しいかどうかを判断するには、以下の手順に従って問題を解きます：
ステップ
    まず、自分で問題を解きます。
    次に自分の解答と学生の解答を比較し、学生の解答が正しいかどうかを評価します。 自分で問題を解き終えるまで、生徒の解答が正しいかどうかを決定しないでください。
次の書式を使用します：
問題: 問題文
    実際の解答とステップ: 実際の解答とステップ テキスト
    学生の解答と実際の解答が同じかどうか: はいまたはいいえ
    学生の評点: 正解または不正解
質問
    私は太陽光発電所を建設しており、コストの算出を手伝ってほしい。
    - 土地のコストは1平方フィートあたり100ドルです。
    - ソーラーパネルは1平方フィートあたり250ドルで購入できます。
    - 年間10万ドルの固定支払いと、1平方フィートあたり10ドルの追加支払いが必要な保守契約について交渉しました。
    面積の関数として、運営初年度の総費用はいくらか。
生徒の解答
発電所の大きさを平方フィートで「x」とする。
    コスト
    1. 土地代：100x
    2. 太陽電池パネルの費用：250x
    3. メンテナンス費用：100,000 + 100x
    総費用：100x + 250x + 100,000 + 100x = 450x + 100,000
現実的な解決策とステップ
"""
response = get_completion(prompt)
print(response)
```
出力：
```json
問題: 太陽光発電所の運営初年度の総費用を求めるために、以下のステップを実行します。
実際の解答とステップ: 
1. 土地のコストは1平方フィートあたり100ドルなので、土地代の合計は100xドルです。
2. ソーラーパネルは1平方フィートあたり250ドルで購入できるので、ソーラーパネルの費用は250xドルです。
3. 年間10万ドルの固定支払いと、1平方フィートあたり10ドルの追加支払いが必要な保守契約について交渉したので、メンテナンス費用は100,000 + 10xドルです。
4. 総費用は土地代 + ソーラーパネルの費用 + メンテナンス費用です。したがって、総費用は100x + 250x + (100,000 + 10x)ドルです。
   総費用を計算すると、350x + 100,000ドルとなります。
学生の解答と実際の解答が同じかどうか: いいえ
学生の評点: 不正解
```

# 反復なプロンプト開発

LLM を使ってアプリケーションを構築するとき、最終のアプリケーションで必要なプロンプトを最初の試行で成功させることは滅多にありません。しかし、より良いイテレーションプロセスを継続してプロンプトを改善していくことで、役割に適したプロンプトを得ることができます。プロンプトについては、最初の成功する可能性はより高くなる可能性がありますが、先ほど述べたように、最初のプロンプトが有効かどうかは重要ではありません。有効な Prompt を見つけるプロセスが最も重要です。

そのため、この部分では、製品の概要からマーケティング用のクリエイティブな内容を生成する例として、プロンプトをどのように繰り返し分析して改善するかを思考するための枠組みを見せています。

## タスク:製品説明書からマーケティング製品説明文を生成

こちらには椅子の製品説明書があります。この説明書は、それが中世のインスピレーションを受けた家具の一部であることを述べ、構成、サイズ、椅子の選択肢、材料などについて説明しており、製造地はイタリアです。この説明書を使用して、マーケティングチームがオンライン小売ウェブサイトのためにマーケティング的な説明文を書くのに役立てることを想定しています。

まずは製品説明文を記載します：
```python 
# 製品説明書
fact_sheet_chair = """
概要

    美しい中世のスタイルのオフィス家具シリーズの一部で、ファイリングキャビネット、デスク、書棚、会議テーブルなどが含まれています。
    さまざまな外装の色とベースコーティングが選択できます。
    プラスチックの背もたれ飾り（SWC-100）または10種類の生地と6種類の革の包括的な装飾（SWC-110）が選択できます。
    ベースコーティングのオプションには、ステンレス、マットブラック、光沢のあるホワイト、またはクロムがあります。
    椅子はアームレストありまたはなしで利用できます。
    家庭用または商業用に適しています。
構成

    プラスチックコーティングのアルミニウム製ベース、5輪。
    空気圧式チェアアジャスターで簡単にリフトアップ。

サイズ

    幅 53cm
    奥行き51cm
    高さ80cm
    シート高 44cm 17.32インチ
    座面奥行 41cm｜16.14インチ

オプション

    ソフトまたはハードのフロアロールオプション。
    ミディアム（1.8 lb/立方フィート）またはハイ（2.8 lb/立方フィート）。
    アームレストなし、または8ポジションのPUアームレスト。

材料
ハウジング・ベース・スライド

    変性ナイロンPA6/PA66コーティング鋳造アルミニウム。
    シェル厚さ：10 mm。
    シート
    HD36フォーム

原産地

    イタリア
"""
```

次は実際のプロンプト文：
```python 
prompt = f"""
あなたの仕事は、マーケティングチームが技術仕様に基づいて製品のマーケティング説明を作成するのを支援することです。

```で囲まれた技術仕様書に記載されている情報に基づいて、製品の説明文を作成してください。

技術説明: ```{fact_sheet_chair}```
"""
response = get_completion(prompt)
print(response)
```

作成した製品説明文が：

```python 
製品の説明文:

美しい中世のスタイルのオフィス家具シリーズの一部として、当製品はファイリングキャビネット、デスク、書棚、会議テーブルなどを含んでいます。外装の色やベースコーティングは、お客様の選択によって様々な組み合わせが可能です。背もたれ飾りにはプラスチックのもの（SWC-100）や、10種類の生地と6種類の革の包括的な装飾（SWC-110）を選ぶことができます。ベースコーティングのオプションには、ステンレス、マットブラック、光沢のあるホワイト、またはクロムがあります。椅子にはアームレストの有無を選ぶことができ、家庭用や商業用にも適しています。

製品の構成は、プラスチックコーティングのアルミニウム製ベースと5輪からなります。また、空気圧式チェアアジャスターにより簡単にリフトアップすることができます。

製品のサイズは、幅53cm、奥行き51cm、高さ80cm、シート高44cm（17.32インチ）、座面奥行41cm（16.14インチ）です。

さらに、製品には以下のオプションがあります。ソフトまたはハードのフロアロールオプション、ミディアム（1.8 lb/立方フィート）またはハイ（2.8 lb/立方フィート）の選択が可能です。また、アームレストはなし、または8ポジションのPUアームレストを選ぶことができます。

製品の材料は、ハウジング、ベース、スライドには変性ナイロンPA6/PA66コーティング鋳造アルミニウムが使用されています。シェルの厚さは10mmです。また、シートにはHD36フォームが使用されています。

この製品はイタリアで製造されています。
```

## 改善1: 作成した説明文を短く

上記作成した説明文で必要な情報が含まれて、合格な文章ですが、それは長すぎましたので、最大で100文字しか使用しないように指示しました。

```python 
# 最適化されたプロンプト（100文字数以下の説明文を生成する必要がある
prompt = f"""
あなたの仕事は、マーケティングチームが技術仕様に基づいて製品のマーケティング説明を作成するのを支援することです。

```で標識された技術規格に記載されている情報に基づいて、製品の説明文を作成してください。
説明文の文字数が100個にしてください。

技術規格：```{fact_sheet_chair}```
"""
response = get_completion(prompt)
print(response)
```

作成した製品説明文：

```python
美しい中世のスタイルのオフィス家具シリーズの一部で、ファイリングキャビネット、デスク、書棚、会議テーブルなどが含まれています。さまざまな外装の色とベースコーティングが選択できます。プラスチックの背もたれ飾り（SWC-100）または10種類の生地と6種類の革の包括的な装飾（SWC-110）が選択できます。ベースコーティングのオプションには、ステンレス、マットブラック、光沢のあるホワイト、またはクロムがあります。椅子はアームレストありまたはなしで利用できます。家庭用または商業用に適しています。幅53cm、奥行き51cm、高さ80cm、シート高44cm、座面奥行41cmのサイズです。プラスチックコーティングのアルミニウム製ベース、5輪。空気圧式チェアアジャスターで簡単にリフトアップできます。ソフトまたはハードのフロアロールオプションがあります。ミディアムまたはハイの密度を選択できます。アームレストなし、または8ポジションのPUアームレストが選択できます。ハウジング、ベース、スライドは変性ナイロンPA6/PA66コーティング鋳造アルミニウムで作られています。シェルの厚さは10mmです。シートにはHD36フォームが使用されています。この製品はイタリア製です。
```

実際に文字数を確認します：

```python 
len(response)
```

出力：`532`

上記のように、100文字数を制限したのに、500以上の文字が出力されました。LLMがテキストをトークン化する際に、トークナイザーと呼ばれるものを使用しているためですが、トークナイザーは文字数の計算において一般的な性能しか発揮しないことがよくあります。出力の長さを制御しようとするさまざまな方法があります。

## 改善2: 実際の対象者に向けて説明文を調整

2つ目の問題は、このウェブサイトが直接消費者に販売されていないことであり、実際には家具小売業者に家具を販売することを意図していることがわかります。彼らは椅子の技術的な詳細や材料に関心を持つでしょう。この場合、このヒントを修正して、椅子の技術的な詳細をより正確に記述するようにできます。

解決策：それを対象者に関連する側面に焦点を当てるように要求してください。

```python 
prompt = f"""
あなたの仕事は、マーケティングチームが技術仕様書に基づいて製品の小売りウェブサイトの説明を作成するのを支援することです。

```で標識された技術規格に提供された情報に基づいて、製品の説明を書いてください。

この説明は家具小売業者を対象としているため、技術的な性質を持ち、製品の材料構造に焦点を当てる必要があります。

説明の最後に、技術仕様書に記載されている各7文字の製品IDを含めてください。

説明文の文字数が100個にしてください。

技術規格：```{fact_sheet_chair}```
"""
response = get_completion(prompt)
print(response)
```

作成した製品説明文：

```python 
美しい中世のスタイルのオフィス家具シリーズの一部で、ファイリングキャビネット、デスク、書棚、会議テーブルなどが含まれています。さまざまな外装の色とベースコーティングが選択できます。プラスチックの背もたれ飾り（SWC-100）または10種類の生地と6種類の革の包括的な装飾（SWC-110）が選択できます。ベースコーティングのオプションには、ステンレス、マットブラック、光沢のあるホワイト、またはクロムがあります。椅子はアームレストありまたはなしで利用できます。家庭用または商業用に適しています。

製品ID：SWC-100, SWC-110
```
## 改善3: テーブル形式で説明文を出力

ここには、情報を抽出し表に整理し、表の列、表の名前、およびフォーマットを指定し、すべてのコンテンツをウェブページで使用できるHTML形式にフォーマットするように求める追加の説明が含まれています。

```python 
prompt = f"""
あなたの仕事は、マーケティングチームが技術仕様書に基づいて製品の小売りウェブサイトの説明を作成するのを支援することです。

```で標識された技術規格に提供された情報に基づいて、製品の説明を書いてください。

この説明は家具小売業者を対象としているため、技術的な性質を持ち、製品の材料構造に焦点を当てる必要があります。
説明の中に、技術仕様書に記載されている各7文字の製品IDを含めてください。

説明文の最後に、テーブルを利用して商品のサイズを示してください。テーブルには、二つの列があります。一つの列がサイズの名称、もう一つがサイズの値です。
このテーブルの名前を「商品サイズ」にしてください。

すべてのコンテンツをウェブサイトで使用できるHTML形式に整形し、説明を<div>要素に配置し、以下のインラインCSSスタイルを適用します。
- 段落を区別し、各段落のテーマに<h1>、<h2>、および<h3>を使用してください。

説明文の文字数が100個にしてください。

技術規格：```{fact_sheet_chair}```
"""
response = get_completion(prompt)
print(response)
```

作成したHTML文の製品説明文：
```html 
<h1>美しい中世のスタイルのオフィス家具シリーズ</h1>

<h2>概要</h2>

<p>この製品は、美しい中世のスタイルのオフィス家具シリーズの一部で、ファイリングキャビネット、デスク、書棚、会議テーブルなどが含まれています。さまざまな外装の色とベースコーティングが選択できます。プラスチックの背もたれ飾り（SWC-100）または10種類の生地と6種類の革の包括的な装飾（SWC-110）が選択できます。ベースコーティングのオプションには、ステンレス、マットブラック、光沢のあるホワイト、またはクロムがあります。椅子はアームレストありまたはなしで利用できます。家庭用または商業用に適しています。</p>

<h2>構成</h2>

<p>この製品は、プラスチックコーティングのアルミニウム製ベース、5輪を備えています。また、空気圧式チェアアジャスターで簡単にリフトアップすることができます。</p>

<h2>商品サイズ</h2>

<table>
  <tr>
    <th>サイズの名称</th>
    <th>サイズの値</th>
  </tr>
  <tr>
    <td>幅</td>
    <td>53cm</td>
  </tr>
  <tr>
    <td>奥行き</td>
    <td>51cm</td>
  </tr>
  <tr>
    <td>高さ</td>
    <td>80cm</td>
  </tr>
  <tr>
    <td>シート高</td>
    <td>44cm (17.32インチ)</td>
  </tr>
  <tr>
    <td>座面奥行</td>
    <td>41cm (16.14インチ)</td>
  </tr>
</table>

<h2>オプション</h2>

<p>この製品には、ソフトまたはハードのフロアロールオプションがあります。また、ミディアム（1.8 lb/立方フィート）またはハイ（2.8 lb/立方フィート）の選択肢もあります。さらに、アームレストなし、または8ポジションのPUアームレストを選ぶことができます。</p>

<h2>材料</h2>

<p>この製品のハウジング、ベース、スライドは変性ナイロンPA6/PA66コーティング鋳造アルミニウムで作られています。シェルの厚さは10mmです。また、シートにはHD36フォームが使用されています。</p>

<h2>原産地</h2>

<p>この製品はイタリアで作られています。</p>
```

最後に、実際にHTML形式で表示してみよう

```python 
from IPython.display import display, HTML

display(HTML(response))
```

## まとめ

この部分の内容は、LLMがアプリケーションの開発における反復的なプロンプト開発プロセスを示しています。開発者は、まずプロンプトを作成し、それを段階的に改善して必要な結果を得る必要があります。鍵は、完璧なプロンプトを知ることではなく、効果的なプロンプト開発プロセスを持つことです。Jupyterノートブックの例を使用する際に、さまざまな変更を試して結果を確認してみてください。

# 応用:UiPath Studio×OpenAIでプロンプト文の利用

UiPath StudioでChatGPTと連携して、これらのプロンプト文を使って、ChatGPTからの回答を自分の業務に利用します。

検証サンプル一式はこちらの[【UiPath Workflow】開発者向けのプロンプトエンジニアリング 前編](https://drive.google.com/drive/folders/16zu8_rKUDGDLfCKFn6xveH2JA4e4_k3k?usp=drive_link)を参照ください。

## プロンプト文の原則
以下の例では、上記の[プロンプト文の原則](#プロンプト文の原則)に従って、Excelファイルの[Data]シートにプロンプト文を記載し、UiPath Studioはテーブル内の「プロンプト文」列を読み込んで、ChatGPTに指示を送信します。ChatGPTからの回答は「回答」列に記入されます。

実際の自動化ワークフローでは、ChatGPTから返された構造化データ（JSON）を解析し、次の処理に渡すことができます。

| No | 戦略 | プロンプト文 | 回答 |
|:-:|:-:|:-:|:-:|
|  1 |   |   |   |
|  ... |   |   |   |

検証した結果([Config_Data.xlsx](https://docs.google.com/spreadsheets/d/1qGiht2RBJ170fsRoDedggz9PaEJCXjdj/edit?usp=drive_link&ouid=100666765262890662323&rtpof=true&sd=true))は、UiPath Studio×ChatGPTの回答が上記のNotebookのと同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177240/2c47c0ee-0581-08be-ccae-947a2245f482.png)

## 反復なプロンプト開発

この例では、UiPathとOpenAIのそれぞれの得意分野を活かします。
[反復なプロンプト開発](#反復なプロンプト開発)で、最終的に書かれたHTML文を作成するプロンプト文を利用して、ChatGPTから作成した回答を別ファイルに記入することで、UiPath StudioがHTML文のファイルを作成します。

UiPath Studioで、Excelファイルの[Constant]シートに記載しているプロンプト文をChatGPTへ投げて、ChatGPTからの回答文を利用してウェーブページのHTMLファイル([商品説明ページ.html](https://drive.google.com/file/d/1V5vcBCPBNZEeUtm_4ttMvYbtmCzqL9Kw/view?usp=drive_link))を作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177240/8d24a3b6-cc3a-cdd1-9d97-63d97cd19cba.png)

作成したHTMLは完全にすっぴんなので、CSSなどを追加するように、プロンプト文を改善してください。


# 最後に
UiPath Studioを利用して、Pythonなどのプログラミング言語を知らなくても、簡単にChatGPTを実際の業務に活用できます。
UiPathは最後の一マイルの自動化を実現するための強力なツールです。このツールを使用することで、複数のシステムをシームレスにつなげ、業務プロセスの効率化が可能となります。さらに、OpenAIの自然言語処理技術を組み込むことで、RPAがさらに進化します。