LoginSignup
2
1

面倒なことは、Azure OpenAI Service×Power Automateにやらせよう!

Last updated at Posted at 2024-06-08

初めに

昨今、何かとMicrosoftと生成AIが話題ですね(^^♪
この波に乗っていく&生成AIを使って自分の仕事を楽にするために取り組んだ内容を記載します。

目次

生成AI×RPA(Robotic Process Automation)の組み合わせは最高!

生成AIだけでも知能労働の支援はしてくれますが、更に単純労働まで自働化できたら最高じゃないですか?そう、人間は考えることも、手を動かすことも面倒なんです!

image.png

自己紹介

image.png
image.png

記事作成の背景

前職では生成AI技術は全く使っていなかったため、素早く技術にキャッチアップするために何か作ってみることにしました。生成AI案件にアサインされるために、何か作ってアピールしたかったという理由もあります。

image.png

解決したい課題

外資系企業に転職して、大量の英語メールが来るようになりました。
英語が不得意&業務が立て込んできて全て読んでいられません。

そこで、生成AIに日本語に翻訳させた上で、要約させることにしました。その上で、自分宛にメールを再送します。

image.png

image.png

OpenAIとAzure OpenAI Serviceの違い

今回の生成AIによる処理にには、Azure OpenAI Serviceというクラウドサービスを使っています。このサービスを言語モデルにOpenAI社のGPTモデルを使っています。

それでは、 本家OpenAIとAzure OpenAI Serviceで何が違うの? との疑問が生まれます。実際、お客さんに必ずと言ってよいほど聞かれます。違いの概要は以下です。

image.png

Azure OpenAI Serviceを使う最大のメリットは、他のAzureインフラアーキに組み込み易い事です。

これにより、 Azureの強固なセキリュティを享受しつつ、他のAIサービス(Azure AI Document Intelligenceや、Azure AI Search 等)の使用が可能になります。

昨今、需要が増加しているRAG(Retrieval-Augmented Generation:拡張検索生成)システムを組む際、言語モデル単体では機能しません。Azure AI Search等の検索機能を組み合わせて使う必要があります。

Azure OpenAI Serviceを生成部に使っていると、統合が用意ですし、アーキ全体でのコスト管理もし易いです。

image.png

Power Automate とは

Azure OpenAI Service(頭脳部)だけあっても、私の課題は解決しません。

手足となって動くロボットが必要です。そこで、Azure OpenAI Serviceと相性が良いRPA(Robotic Process Automation)ツールがPower Automateです。同じくMicrosoft製品です。

image.png

Power Automateには、上記2種類があります。今回は、「Outlookに受信したメールをトリガーに処理を開始する」 ことがやり易そうなPower Automate Cloudを使うことにしました。

また、デバッグ機能があることもPower Automate Cloudの大きな利点です。

Power Automate CloudとPower Automate Desktopの違いは以下の記事を参考にさせていただきました。

Power Automate Cloudは有料ですが、以下のページから30日間の無料トライアルに申し込めます。

image.png

処理フロー

めちゃくちゃ、シンプルです(笑)
image.png

日本語メールを誤って処理すると、Azure OpenAI Serviceのコストが無駄になるので、件名で処理の可否を判断しています。

データフロー

データフローは以下の様になります。

  • インプット:Outlookで受信したメール
  • アプトプット:日本語訳&翻訳したメール

image.png

Power Automate全体のフロー

7つのコンポーネントからなります。
各コンポーネント詳細設定について、以降で解説します。

image.png

コンポーネントの作成方法は以下の記事を参考にさせていただきました🙇‍♂️

「新しいメールが届いたとき」の設定

image.png

こちらは、OutlookのInboxフォルダに新しいメールが届いた際にトリガーを立てる機能を担います。

「変数を初期化する」の設定

image.png

ここでは、メールの件名を"Subject"という変数に格納しています。

「変数を初期化する(ユーザープロンプト)」の設定

image.png

ここでは、ユーザープロンプトを"User Prompt"という変数に格納しています。変数の値に、メール本文を含めているのがポイントです。

「変数を初期化する(回答用変数)」の設定

image.png

ここでは、Azure OpenAI Serviceからの回答を格納する変数を定義しています。 この時点では空です。

「変数を初期化する(回答用変数)」の設定

image.png

ここでは、返信メールの件名に付与する注意書き(※後ほど説明)を"note"という変数に格納しています。

「言語の検出」の設定

image.png

ここでは、Azure AI Languageのを使って、件名の言語名取得しています。

言語検出については以下を参照ください。

言語検出でサポートされている言語は以下に記載あり。

Apply to eachの設定

image.png

ここでは、 初めにAzure AI Languageの出力(documents)をインプットし、その中の"name"属性がEnglishに等しいか判定します。はいの場合(メールの件名が英語である場合)左のフローが走ります。 いいえの場合は、何もせず終了します。

はいの場合の処理と設定

「HTTP(Azure OpenAI Serviceを呼び出し)」の設定

image.png

ここでは、 本文の内容をAzure OpenAI ServiceにPOSTします。contentに前段で設定した"User Prompt"変数を格納しているのがポイントです。

言語モデルのURIは以下の形式にしてください。

POST https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}/completions?api-version={api-version}

image.png
出典:Azure OpenAI Service の REST API リファレンス

APIのバージョンは以下のページを参照ください。

「JSONの解析」の設定

image.png

ここでは、 Azure OpenAI Serviceからの回答内から、必要箇所(日本語要約文)だけを取り出すために回答のJSON形式を定義しておきます。

サンプルから生成 ⇒ サンプル JSON ペイロードの挿入に、以下のJSONを張り付けて、完了ボタンを押してください。

{
    "type": "object",
    "properties": {
        "choices": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "content_filter_results": {
                        "type": "object",
                        "properties": {
                            "hate": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "self_harm": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "sexual": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "violence": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    },
                    "finish_reason": {
                        "type": "string"
                    },
                    "index": {
                        "type": "integer"
                    },
                    "logprobs": {},
                    "message": {
                        "type": "object",
                        "properties": {
                            "content": {
                                "type": "string"
                            },
                            "role": {
                                "type": "string"
                            }
                        }
                    }
                },
                "required": [
                    "content_filter_results",
                    "finish_reason",
                    "index",
                    "logprobs",
                    "message"
                ]
            }
        },
        "created": {
            "type": "integer"
        },
        "id": {
            "type": "string"
        },
        "model": {
            "type": "string"
        },
        "object": {
            "type": "string"
        },
        "prompt_filter_results": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "prompt_index": {
                        "type": "integer"
                    },
                    "content_filter_results": {
                        "type": "object",
                        "properties": {
                            "hate": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "self_harm": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "sexual": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            },
                            "violence": {
                                "type": "object",
                                "properties": {
                                    "filtered": {
                                        "type": "boolean"
                                    },
                                    "severity": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                },
                "required": [
                    "prompt_index",
                    "content_filter_results"
                ]
            }
        },
        "system_fingerprint": {},
        "usage": {
            "type": "object",
            "properties": {
                "completion_tokens": {
                    "type": "integer"
                },
                "prompt_tokens": {
                    "type": "integer"
                },
                "total_tokens": {
                    "type": "integer"
                }
            }
        }
    }
}

このJSONは、一度右上のテストボタンから、テストを実行し、Azure OpenAI Serviceからのレスポンスをコピーしたものになります。
image.png

変数の設定

image.png

ここでは、"response"という変数を定義して、そこにAzure OpenAI Serviceからの回答(JSONの解析済み)のbody部を格納しています。

値欄のbodyをクリックして、以下の式を設定して更新してください。

image.png

設定式 : body('JSON_の解析')?['choices'][0]?['message']['content']

「メールの送信(V2)」の設定

image.png

最後に、件名に"note"変数、"Subject"変数設定、本文に"response"を設定します。宛先には、自分宛のメールアドレスを入れてください。

アウトプット事例

上記フローを作成し、フローの表示画面から、当該フローをオンにします。
すると、Outlookにメールが届くたびに処理が走ります。
image.png

以下は、元のメールと処理後に送信されたメールの例です。
image.png

image.png

工夫点

とは言え、元のメールを全く読まないのは不安です。
また、要約メールを元もメールと混同して重要な情報を見落とすリスクがあります。

そこで、件名の前に、「これはAOAIによる要約です!」 という自分への警鐘(?)を付けて、内容を信じ過ぎないよう意識しました。

image.png

image.png

特に苦労した点

Webの知識が乏しく、「JSONの解析」に特に苦労しました。
以下の図のように、不要なレスポンスも返信メールに含めてしまっていました。これをクリアするのに、結構時間が掛かりました(;^_^A

image.png

Process Mining

Power Automateには、プロセスを解析できる便利な機能があります。
以下は、処理平均時間を表示した図です。 やはり、Azure OpenAI Serviceからのレスポンスに圧倒的に時間を要しています。

image.png

image.png

まとめと予定

image.png

ここまで、読んでくださりありがとうございました。
皆様の仕事が、 Azure OpenAI Service× Power Automateで少しでも楽になることを祈っております😊

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1