BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

プロンプトエンジニアリングの基礎: 2/3 (C# +Azure.OpenAI SDK)

前回から引き続きで、DeepLearning.AIというサイトの無償コンテンツのひとつで OpenAI + Python の「ChatGPT Prompt Engineering for Developers」を受講して学んだことのまとめメモの2回目です。

  • プロンプトエンジニアリングの基礎: 1/3 (C# +Azure.OpenAI SDK)
    • プロンプトエンジニアリングにおける2大原則
  • プロンプトエンジニアリングの基礎: 2/3 (C# +Azure.OpenAI SDK) 👈 今ここ
    • プロンプトの育て方、文章要約、感情分析+α の Tips
  • プロンプトエンジニアリングの基礎: 3/3 (C# +Azure.OpenAI SDK)
    • 概要は後日更新予定

今回はこんな内容をまとめています。

準備

前回同様で、以下のようなベースのコードがあって try-and-error って region の中をいじっていきます。

using Azure.AI.OpenAI;
using Azure;

namespace Learning.PromptEngineering;

internal class Program
{
    private static async Task Main()
    {
        var options = OpenAIOptions.ReadFromUserSecrets();
        var client = new OpenAIClient(new Uri(options.Endpoint), new AzureKeyCredential(options.ApiKey));

        #region try-and-error


        var prompt = """

            """;

        #endregion

        var result = await GetChatCompletionAsync(client, options, prompt);
        Console.WriteLine(result);
    }

    private static async Task<string> GetChatCompletionAsync(OpenAIClient client, OpenAIOptions options, string prompt)
    {
        var chatCompletionsOptions = new ChatCompletionsOptions
        {
            MaxTokens = 1000,
            Messages =
            {
                new ChatMessage(ChatRole.User, prompt)
            }
        };

        var response = await client.GetChatCompletionsAsync(options.DeploymentName, chatCompletionsOptions);
        return response.Value.Choices[0].Message.Content;
    }
}

この構成の詳しくは以前の記事に書いています。

blog.beachside.dev

Iterative Prompt Development

いいプロンプトを作成するには、試して繰り返して開発するんだよって話しです。
製品の詳細が書かれた文章から製品概要を作成する例をもとに手法を学んでいきます。

ここでは、DeepLearning.AI で学んだ、プロンプトをトライアンドエラーでイテレーティブに作り上げていく基本的なプロセスの一例を示すのが目的なので、出力結果がほんまに適切に変わったかはあまりフォーカスしてない点はご了承くださいね。それやるともっと細かい話になってしまうので。

最初のプロンプト

まずは私が以下買おうと思ってる AsRock のグラボを題材にこんな factSheet (長文)と prompt を用意しました。

        // こちらから引用させて頂きました♪
        // https://pg.asrock.com/Graphics-Card/AMD/Radeon%20RX%207900%20XTX%20Phantom%20Gaming%2024GB%20OC/index.jp.asp
        var factSheet = """
            ## PRODUCT NAME:

            AMD Radeon RX 7900 XTX Phantom Gaming 24GB OC

            ## PRODUCT BRIEF

            - クロック:GPU /メモリ
              - ブーストクロック: 最大 2615MHz / 20Gbps
              - ゲームクロック: 2455MHz / 20Gbps
            - 主な仕様
              - AMD Radeon™ RX 7900 XTX GPU
              - 24GB GDDR6 on 384-Bit Memory Bus
              - 96 AMD RDNA 3 Compute Units (With Rt+Ai Accelerators)
              - 96MB AMD Infinity Cache™ Technology
              - PCI® Express 4.0 Support
              - 3 x 8 ピン 電源コネクタ
              - 3 x DisplayPort™ 2.1 / 1 x HDMI™ 2.1
            - 主な特徴
              - Polychrome SYNC
              - Phantom Gaming 3X Cooling System
              - Striped Ring Fan
              - Reinforced Metal Frame
              - スタイリッシュなメタルバックプレート
              - 0dB サイレントクーリング
              - Super Alloy Graphics Card

            ## PRODUCT FEATURES

            - Reverse Spin
              - The center fan spins reversely to lower turbulence and enhance air dispersion through the heatsink.
            - Phantom Gaming 3X Cooling System For Cool And Silent.
              - Crafted for the best balance between the thermal efficiency and silence by all the details.
            - Striped Ring Fan Designed For Enhanced Airflow
              - ASRock’s all new Striped Ring Fan get more lateral intake and to provide better airflow through the cooling array.
            - Air Deflecting Fin Guide Airflow To Go Through Regularly & Quickly.
              - Guide the airflow to go more regularly and quickly to enhance the cooling efficiency by the V-shaped cutting fins and the V-shaped air vents.
            - Ultra-Fit Heatpipe Consolidated To Maximize The Contact.
              - The heatpipes are consolidated to maximize the contact among each others and also the GPU baseplate for the optimized heat dissipation.
            - Nickel-Plated Copper Base Maximize GPU Contact Area.
              - With premium copper base heatsink design, the direct contact area to the GPU would be maximized to improve thermal transfer effectively.
            - High-Density Metal Welding Improve Heat Dissipation.
              - Effectively isolate all coverage of the gap between pipe and stacked fins, hence improve heat dissipation effectively.
            - Nano Thermal Paste Perfect Thermal Teamwork.
              - Eliminate the gaps in the contact area to maximize heat transfer and thermal efficiency.
            - Premium Thermal Pad Better Heat Transfer.
              - The premium thermal pad helps to transfer the heat of the components to the heatsink, improving heat dissipation.
            - Precise Screw Torque Optimized Mounting Pressure.
              - ASRock adopts precise screw torque when assembling its graphics cards to optimize the cooler mounting pressure to improve thermal efficiency while avoiding damage to GPU die.
            - 0dB サイレントクーリング
              - 作業負荷が軽いときには、0dB サイレントクーリング技術がノイズなしにファンを完全に停止します。
            - Polychrome SYNC
              - 統合された ARGB LED を使用して、独自のカラフルな照明効果を作成してください。また、Polychrome SYNC に対応する ASRock マザーボードと同期させることもできます。
            - LED On/Off Switch On Or Off? Switch As You Want.
              - You can switch not only the built-in ARGB LEDs but also the ARGB LEDs equipping with the connected strips/devices at once.
            - ARGB Pin-Header More ARGB, More Fancy.
              - With the ARGB pin-header, it can connect ARGB strips/devices to make the lighting effects more rich and vivid.
            - 強化された金属製フレーム
              - 強化された構造で PCB が曲がることを防止します。
            - スタイリッシュなメタルバックプレート
              - Phantom Gaming ルックです。Phantom Gaming グラフィックスカードのスタイリッシュなメタルプレートは、おしゃれな外観で頑丈な構造です。さらに、裏側のサーマルパッドも熱効率を向上させます。
            - Japanese SP-Cap
              - With a high conductive polymer as the electrolyte, it has a lower equivalent series resistance (ESR) to provide outstanding electrical characteristics. In addition to that, it also has excellence in product operational life, reliability and heat resistance.
            - SPS (Smart Power Stage)
              - Dr.MOS design features the latest SPS (Smart Power Stage) technology. It’s optimized for monitoring current and temperature of each phase, thus delivering smoother and neater power to the GPU with enhanced performance and OC capability.
            - プレミアム 100A パワーチョーク
              - 従来のチョークと比較して、ASRock の新世代プレミアムパワーチョークは飽和電流を最大 3 倍まで効果的に増加させるため、マザーボードの Vcore 電圧が強化・向上します。
            - 2 オンスの銅 PCB
              - PCB レイヤー向けに厳選された銅材料を使用しています。2 オンスの銅 PCB は、オーバークロックの際に温度を低く抑えて、優れたエネルギー効率を提供します。
            - マットブラック PCB
              - 新しい神秘的なマットブラックと銅のカラースキームは ASRock のハイエンドマザーボードの最高のコンポーネントにぴったりです。
            - 高密度ガラス繊維 PCB
              - 高密度ガラス繊維 PCB 設計は、PCB レイヤー間の隙間を減らして、湿度による電気短絡からマザーボードを保護します。
            """;

        var prompt = $"""
            あなたのタスクは、製品の Fact sheet に基づいて、製品の販売 Web サイトでの説明文を作成することです。
            説明文は、日本語で作成する必要があります。
            以下の3つのバッククォートで区切られた Fact sheet の情報に基づいて、製品の概要を記述してください。

            Fact sheet: ```{factSheet}```
            """;

これを実行するとこんな感じで、440文字弱の説明文ができました。

文字数を制限する

文章を短くするなら、文字数や単語数や文章数の制約を付ける方法があります。今回はシンプルに「文字数は約100文字にしてください。」と指定してみました。

        var prompt = $"""
            あなたのタスクは、製品の Fact sheet に基づいて、製品の販売 Web サイトでの説明文を作成することです。
            説明文は、日本語で作成する必要があります。
            文字数は約100文字にしてください。

            以下の3つのバッククォートで区切られた Fact sheet の情報に基づいて、製品の概要を記述してください。

            Fact sheet: ```{factSheet}```
            """;

結果は... さっきより短くなってるけど約280文字。英語だとうまく制御できるやつもあれば、英語でもうまく指定通りにできることもあるので、うまくいかないときはもっとプロンプトを工夫したり MaxTokens を制御するとか必要そうですね。

誰を対象としてどんな内容を生成してほしいか

読み手に応じて文章はことなるものです。ということで、今回は、実際に購入するエンドユーザー向けではなく、PC パーツの小売業者向けと仮定して、それにあった文章を生成するようにしてみます。文字列制限はとりあえずはずしました。

        var prompt = $"""
            あなたのタスクは、製品の Fact sheet に基づいて、製品の販売 Web サイトでの説明文を作成することです。
            説明文は、日本語で作成する必要があります。
            この説明文は、PCパーツの小売業者を対象としています。そのため、製品の技術的な強みにフォーカスしてください。
            ただし、文章は500文字以内にまとめてください。
            
            Fact sheet: ```{factSheet}```
            """;

結果はこんな感じになりました。元々技術要素強めの文章ではありますが、気持ちは伝わった感じしますね。

出力形式の指定

最後にこんなプロンプトにして、出力形式を指定してみます。

        var prompt = $"""
            あなたのタスクは、製品の Fact sheet に基づいて、製品の販売 Web サイトでの説明文を作成することです。
            説明文は、日本語で作成する必要があります。
            この説明文は、PCパーツの小売業者を対象としています。そのため、製品の技術的な強みにフォーカスしてください。
            文章の構成として、"製品概要"1文章で完結に概要を説明し、
            そのあとに "PRODUCT BRIEF" を Markdown の Table で出力してください。
            
            Fact sheet: ```{factSheet}```
            """;

結果はこんな感じで出してくれました。まぁ...まぁってところでしょうか。

もとの学習コンテンツで伝えたいことは、思った回答じゃないときはその部分をより具体的に指示することを繰り返して改善していこうって話だと思いますが、前回学んだ原則をベースに改善していくことがプロンプトエンジニアリングの第一歩って感じの話でしたね。

文章要約のコツ

DeepLearning.AI のコンテンツの中では、いくつかのプロンプトの例から出力内容の改善をする流れをやっていました。
内容的にサンプルのコードを書くほどでもない気がしてるのでポイントだけ書くと、文章要約する際は要約したいポイントは明確に指示しようって話しでした。

例えば、商品レビューで商品の発送と配達にフォーカスしたい場合だと、以下のように指示しようって感じ。

  • あなたのタスクは Eコマース サイトから製品レビューの短い概要を生成し、配送部門にフィードバックを提供することです。以下にレビューおを最大200文字で要約し、製品の発送と配達について言及した側面に焦点を当ててください。

Inferring

ChatGPT でやれることとして、文章から感情を推測したりその文章に含まれているトピックやキーワードを抽出することも可能です。

例えば商品のレビューの文章に対して何かする場合、怒りの感情があるフィードバックなのか、なんの商品についてのフィードバックなのかを抽出することも可能で、そのプロンプトの例を書いていきます。

Sentiment の分析のプロンプト例:

三重のバッククォートで区切られた次の製品レビューの感情は何ですか?
「positive」または「negative」のいずれか1つの単語で答えてください。

怒りの感情があるかの例:

次のレビューの文章で、レビューアーは怒りの感情を持っていますか?   
レビューは3つのバッククォートで区切られています。  
「Yes」または「No」で答えてください。

商品名と製造会社(ブランド) を抽出例

レビューの文章から次の項目を特定します。

- レビューアーが購入した商品
- 商品を製造した会社

「Item」と「Brand」をキーとして応答を JSON オブジェクトとしてフォーマットします。  
情報が存在しない場合は、値として「unknown」を使用します。応答はできるだけ短くしてください。

実際のプロンプトで、先述のタスクを一度に実行してみます。コードは冒頭の「準備」のセクションで書いたやつに以下のを実行させてみます。

        var reviewText = """
            寝室におしゃれなランプが欲しかったのですが、これは追加の収納スペースもついているのに価格もそれほど高くありませんでした。
            発送中にランプのケーブルが切れてしまったようですが、会社はすぐに新しいものを送ってくれました。
            こちらも数日以内に届きました。組み立ても簡単でした。
            足りない部品があったのでサポートに連絡したところ、こちらもすぐに発送してくれました。
            ルミナは顧客と製品を大切にする素晴らしい会社と感じました。
            """;

        var prompt = $"""
            Review Text は 3 つのバッククォートで区切られています。
            あなたタスクは、Review Text から次のことを特定します。

            - 感情 ("Positive" または "Negative" のどちらかで回答)
            - レビューアーは、怒りの感情を持っているか ( "true" または "False" で回答)
            - レビューアーが購入した商品。情報が存在しない場合は "Item unknown" と回答。
            - 商品のブランド。情報が存在しない場合は "Brand unknown" と回答。

            回答はできるだけ短くしてください。

            Review Text: ``` {reviewText} ```
            """;

わかりやすいレビューだったので、いい感じに回答を得れました。

他にも色々試していい感じでした。例えば「開封済みの物が届いた。誰が使ったかもわからないので気分が悪いです。XXX から二度と商品を買いません。」(← XXX には実際はブランド名書いてます) って文章だと結果はこうなりました。

ということ感情の推論はかなりいい感じにできます。そうすると、JSON 形式でプロパティ名も指定して結果を出力させ、にして結果を自分たちの API に送り、怒りのレビューだったら API からアラートを出すみたいな機能は簡単に実現できそうですね。
こういうタスクのチェーンは Semantic Kernel とか LangChain とか使うと容易にできますが、そんな話はまた別の今後の記事で書ければと思っています。

終わりに

前回の内容と似たような感じですがここら辺は Zero-shot, Few-shot, CoT とかのその他諸々の基本的な手法に通じて、そういうのも意識しつつ次回もまとめていこうと思うところです。