LoginSignup
3

ChatGPTと会話可能なTeams ChatBotを作る Functions編

Posted at

概要

この記事には以下の要素が含まれます。

  • Azure OpenAI、openaiライブラリの解説
  • Azure Functionsの構築
  • Azure FunctionsとAzure KeyVaultの統合

この記事では、Azure OpenAI内のGPTモデルを使用したTeams ChatBotの作成方法について解説します。
Teamsアプリケーションとして追加することで、Teams上で対話形式でAIを使用できます。

完成図
2023-09-20_10h34_09.png

アプリケーション構成

本アプリケーションは、Microsoft Teams上で動作するチャットボットです。
Azure Functions, Azure OpenAI, CosmosDB, KeyVaultなどのサービスを組み合わせて実現します。以下が主な構成です。

  • Microsoft Teams: チャットインターフェイス
  • Azure Functions: バックエンド処理
  • Azure OpenAI: モデルデプロイ
  • CosmosDB: 会話履歴管理
  • KeyVault: シークレット管理
    image.png

チャット関数の構築

今回はこの範囲に絞って解説します。
image.png

Azure OpenAI

Azure OpenAIは、Microsoft Azure上で動作するOpenAIのプラットフォームです。
Portalでリソース作成後、OpenAI Studioからモデルをデプロイしておきます。

image.png

openaiライブラリについて

openaiライブラリはPython向けに提供されているOpenAI APIクライアントです。
本家OpenAIへの呼び出しも可能ですが、今回はAzure OpenAIの呼び出しに使用します。
以下にAPIの一つであるChat Completionについて軽く使用例と解説を示します。

使用例
import openai

# 変数設定
openai.api_type = "azure"
openai.api_base = "your_api_endpoint"
openai.api_key = "your_api_key"
openai.api_version = "api_version"

# API通信部分
response = openai.ChatCompletion.create(
    engine="gpt35-sample",
    messages = [
        {"role":"system","content":"You are an AI assistant that helps people find information."}, 
        {"role":"user","content":"コミュニケーションとは何か、50文字以内で"}, 
        {"role":"assistant","content":"コミュニケーションとは、情報や意見を相手に伝えることであり、双方向のやり取りが含まれる。"},
        {"role":"user","content":"英語に訳して"}
    ],
    max_tokens=500,
    temperature=0.7
)

print(response.choices[0].message)
# {"role": "assistant", "content": "Communication is the act of conveying information or opinions to someone, and it involves a two-way exchange."}

messagesについて

Chat Completionでは以下の要素を持つメッセージオブジェクトのリストを使用します。
会話履歴をリストとして送信することで、履歴をもとにした対話が可能となります。

キー 説明
role system user assistant メッセージの発信者。systemはシステムメッセージ、userはユーザー、assistantはモデル。
content 会話内容 ユーザーの入力、モデルからの応答の内容。

その他のパラメータ

また、Chat Completionの実行時は以下の様なパラメータを使用することで出力結果を調整することが可能です。

パラメータ 入力値 説明
max_tokens 1~ モデルの応答の長さ。文字長ではなくトークン数
temperature 0.0 ~ 0.1 ランダム性の増加。数値が高い程回答に一貫性が無くなる。
top_p 0.0 ~ 0.1 ランダム性の増加その2。数値が高い程回答に一貫性が無くなる。temperatureとは二者択一。
frequency_penalty -2.0 ~ 2.0 同一行繰り返しの抑制。数値が高い程一度出た行が出にくくなる。
presence_penalty -2.0 ~ 2.0 同一トピック繰り返しの抑制。数値が高い程新しいトピックについて話しやすくなる。
stop 停止シーケンスのリスト 応答を停止させるトークンの設定。最大4つまで指定でき、指定のトークンが出力されるとモデルが応答を停止する。

Azure Functions

Azure OpenAIと直接対話を行う部分です。
今回はFunctionsにHttpトリガーの関数を実装しAPI的に使用できるようにしました。
また、クラスは以下の様にチャット関数チャットクライアントの2つで構成しています。

image.png

チャットクライアントの作成

始めにチャット関数から呼び出すChatClientクラスを作成します。
openaiライブラリについてで解説した通り、変数設定後にopenai.ChatCompletion.createでモデルと対話を行っています。

ChatClient.py
import os

import openai


class ChatClient:
    openai.api_type: str = 'azure'
    openai.api_base: str = os.environ['OPENAI_ENDPOINT']
    openai.api_key: str = os.environ['OPENAI_API_KEY']
    openai.api_version: str = os.environ['OPENAI_VERSION']

    model: str = os.environ['OPENAI_MODEL']
    temperature: str = os.environ['OPENAI_TEMPERATURE']
    max_tokens: = os.environ['OPENAI_MAX_TOKENS']

    def chat(self, message: dict) -> dict:
        messages: list = []
        messages.append(message)

        response = openai.ChatCompletion.create(
            engine=self.model,
            messages = messages,
            temperature=self.temperature,
            max_tokens=self.max_tokens
            )

        if response.choices[0].finish_reason == 'stop':
            return response.choices[0].message
        else :
            raise Exception(response.choice[0])

チャット関数の作成

チャット関数側はシンプルにHTTPトリガーで作成し、チャットクライアントを呼び出すだけとしました。

Chat/__init__.py
import azure.functions as func

from ChatClient import ChatClient


def main(req: func.HttpRequest) -> func.HttpResponse:
    response: func.HttpResponse = None

    if req.get_body():
        message = json.loads(req.get_json())

        client = ChatClient()
        chat_response = json.dumps(client.chat(message))

        response = func.HttpResponse(
            chat_response,
            status_code=200
        )
    else:
        response = func.HttpResponse(
            "request is not exist",
            status_code=400
        )

    return response

アプリケーション設定

こちらのコードで使用している環境変数(os.environ[~])については、Azure Functionsの「アプリケーション設定」に設定することで使用可能です。

image.png

Azure KeyVault

Azure Key Vaultはセキュリティ情報(APIキー等)管理用サービスです。
先程はアプリケーション設定にAPIキーを直接保存していましたが、KeyVaultにシークレットとしてAPIキーを保存することでより安全にAPIを使用できるようになります。

シークレットの作成

リソース作成後、シークレット>生成/インポートからシークレットを新規作成できます。

image.png

作成後、シークレット識別子が発行されるのでコピーしておきます。

FunctionsとKeyVaultの統合

作成したシークレットをFunctions側から読み込めるようにします。

アクセスポリシー設定

FunctionsのIDからオブジェクトIDを発行します。

image.png

その後、KeyVaultのアクセスポリシーにFunctionsを登録します。
今回は権限をシークレットの取得のみに絞っています。

image.png

アプリケーション設定変更

最後に、先程まで平文で入力していたアプリケーション設定を変更します。
基本は以下のSecretUriに参照先のシークレット識別子をコピーするだけです。

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)

無事参照ができるようになれば、アプリケーション設定の「ソース」にチェックマークが付きます。

image.png

テスト

Functionsの概要>関数から今回作成したチャット関数を開き、メニューのコードとテストを開きます。
その後、テストと実行からjsonを送信し、モデルからの応答が確認できれば成功です。

image.png

終わりに

今回はFunctions ~ OpenAIの部分について解説しました。
次回はFunctionsからCosmosDBにアクセスし、会話履歴を保持・使用できるように改造していきます。

あとがき

Azure初心者の方でも作成できるように、ガイド的な意味合いも込めて記事を作成しました。

また、今回は記事作成の依頼があり作成してみましたが、慣れていないこともありかなり苦戦しました。
もう何本か書いて慣れる必要がありますね…。

参考

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
3