Prompt Flow in Azure AI Foundry（旧称Azure AI Studio）でAmazon Bedrockと連携してみた

Azure AI Foundry（旧称Azure AI Studio）のプロンプトフローでAzure以外のサービスで動作している生成AIのモデルも扱えたらよいかもしれないと思い、試しにAmazon Bedrockと連携したのでその内容をご紹介します。  
なお、試した時点では、Azure AI Studioだったのですが、執筆時点では、Azure AI Foundryに名称変更されているので、本稿では、Azure AI Foundryとして記載します。  
また、Microsoft Ignite 2024でも発表があったように、Azure AI Foundryは今後も機能アップデートが多そうなので、もっとよい連携方法が出てくるかもしれません。  

## 概要
概要というか結論ですが、以下の構成で、Azure AI FoundryのプロンプトフローからAmazon Bedrockを呼び出すことができました。  
プロンプトフロー内のアイコンを見るとわかりますが、結局はPythonのコードでAmazon Bedrockを呼び出しているということになります。
![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835827/b5b793b4-85fc-6dff-d10c-eddaca4ad48a.png)

### 検証環境
いずれも、2024年11月の検証時点の仕様での動作ですが、以下を利用しています。
- Azure AI Foundry（旧称Azure AI Studio）
- Azure OpenAI Service（モデル：GPT-4o）
- Amazon Bedrock（モデル：Amazon Titan Text Express）  

## 詳細
### AWS側の設定
Amazon BedrockをAzure AI Foundryのプロンプトフローから呼び出すには、Amazon Bedrockのモデルを呼び出すAPIを外部に公開しなければなりません。  
Amazon Bedrockのみではこの機能はなさそうでしたので、前述の図のようにAWS LambdaとAmazon API Gatewayを利用して構成しました。  
この辺りは、AWSではAmazon Bedrockに限らず一般的な考え方なのだと思います（私はどちらかというとAzureの方を主に利用しているので、認識間違っていたらすみません）。
なお、Amazon BedrockをAWS Lambdaと連携する方法、AWS LambdaをAmazon API Gatewayと連携する方法は、他に情報が多くあるので、ここでは詳細は割愛します。  

今回のポイントとしては、Amazon API GatewayでAPIを公開するときに、以下の構成としたところになると思います。

- APIタイプ：REST API
- メソッド
  - メソッドタイプ：POST
  - 統合タイプ：Lambda関数
- APIキー：必須

### Azure側の設定
最初、Azure AI Foundryに外部サービス（今回は、Amazon Bedrock）と簡単に連携できるような機能がないかと探してみましたが、特になさそうでした。
「[Connected resources](https://learn.microsoft.com/ja-jp/azure/ai-studio/concepts/connections)」の機能に期待したのですが、Microsoft以外のサービスへの接続に利用できるのは、「APIキー接続」か「カスタム接続」あたりしかなさそうです。

https://learn.microsoft.com/ja-jp/azure/ai-studio/how-to/connections-add#connection-types

「APIキー接続」は、名称だけではよくわからなかったのですが、どうやら検索エンジンと連携するためのAPI用の機能のようだったので、「カスタム接続」を利用することにしました。

「カスタム接続」の設定は下図のようにしました。  

![img02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835827/f7285f92-3d16-09af-70f1-c8792148c024.png)

カスタムキーに、Amazon API Gatewayで公開したREST APIのURLと設定したAPIキーを設定します。  
キーの名前は、プロンプトフローから呼び出すときに指定するだけなのでわかりやすい名前としておけばよいと思います。  
同じく「接続名」についてもプロンプトフローから呼び出すときに指定することになります。  
APIキーの方は「シークレットである」にチェックを入れています。こうすることで、自動でAzure Key Vaultで管理してくれるようです。

外部の任意のAPIを呼び出せる[プロンプトフローツール](https://learn.microsoft.com/ja-jp/azure/ai-studio/how-to/prompt-flow#prompt-flow-tools)はなさそうだったので、「[Pythonツール](https://learn.microsoft.com/ja-jp/azure/ai-studio/how-to/prompt-flow-tools/python-tool)」を利用してPythonで記述することとしました。  

「カスタム接続」の利用方法は、下記の公式サイトに記載がありますが、2024/11時点の記載内容のみではすぐには理解できませんでした。。。  

https://learn.microsoft.com/ja-jp/azure/ai-studio/how-to/prompt-flow-tools/python-tool#consume-a-custom-connection-in-python

今回「Pythonツール」に記述したコードは下記の通りです。  
```python
import requests
from promptflow import tool
from promptflow.connections import CustomConnection

@tool
def my_python_tool(message: str, myconn: CustomConnection) -> str:
    # Get authentication key-values from the custom connection
    api_key = myconn.apikey
    api_url = myconn.url
    # ヘッダーの設定
    headers = {
        'x-api-key': f'{api_key}',
        'Content-Type': 'application/json'
    }
    
    # リクエストのペイロード
    payload = {
        'message': message
    }
    
    # APIリクエストの送信
    response = requests.post(api_url, headers=headers, json=payload)
    
    # レスポンスの処理
    if response.status_code == 200:
        return response.json()['body']['results'][0]['outputText']
    else:
        return f"Error: {response.status_code}, {response.text}"
```  

上記のコードをPythonツールの「コード」に記述すると、下図のように「入力」部分に変数「myconn」への入力内容をドロップダウンで指定できるようになるので、ここで、「カスタムキー接続」で設定した接続名を指定します。
なお、「message」には、Amazon Bedrockへの指示内容を入力するようにします。

![img03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835827/a717c7e8-8a39-f0d7-4e52-e654d6fc1328.png)

## 動作確認
### 動作確認用のプロンプトフロー
あとは、通常のプロンプトフローの手順で、動作確認用に以下のようなお遊びのフローを作成してみました。  

![img04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835827/992b7062-0cf9-8427-a0d0-407e4941f252.png)

- ①　ユーザの入力（お題）に対して、Azure OpenAI Service（GPT-4o）で、Amazon Bedrockに問い合わせる質問文を作成する。  
  実際の「プロンプト」に設定した内容は、以下です。
  ```
  # system:
  あなたは質問を作成するアシスタントです。ユーザから与えられたお題に対して、Amazon BedrockのTitanモデルに聞くべき質問文を1つだけ作成します。
  # user:
  {{question}}
  ```
- ②　①で作成した質問をAmazon Bedrock（Amazon Titan Text Express）に問い合わせ、回答を得る。  
  設定した内容は、前述のPythonのコードです。
- ③　②の回答を、Azure OpenAI Service（GPT-4o）でレビューする。  
  実際の「プロンプト」に設定した内容は、以下です。
  ```
  # system:
  与えられた文章をレビューしてください。
  # user:
  {{question}}
  ```
- ④　①～③の内容をPythonで以下のように人間が見やすいように整形する（この部分は、生成AIは関係ありません）。
  > 【GPT-4o(Azure OpenAI)】 ①の内容（GPT-4oが回答した内容）を出力  
    【Titan Text G1 -Express(Amazon Bedrock)】 ②の内容（Amazon Titan Text Expressが回答した内容）を出力  
    【レビュー結果(GPT-4o(Azure OpenAI))】 ③の内容（GPT-4oが回答した内容）を出力

### 動作確認結果
実際にプロンプトフローのチャット機能で動作させてみた結果が以下です。

:::note warn
この出力結果は生成AIが作成した文章ですので、本記事の執筆者や執筆者が所属する組織の見解とは関係ありません。また、生成AIが回答した内容には手を入れていません。
:::

![img05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835827/5641f47b-4816-f459-e596-2a44fe9fbb93.png)

## まとめ
今回、Azure AI FoundryのプロンプトフローでAmazon Bedrockと連携してみました。  
連携部分は、REST APIを呼び出しているだけではありますが、プロンプトフローで扱うことができました。  
これにより、Azure以外の生成AIのモデルを利用したいときにも、プロンプトフローでの開発ができるようになり、開発しやすくなるのではないかと思います。