Azure AI Agent学習記録

Microsoft Azureについて調べたことを発信しています。

シンプルなエージェントの作成 〜 その11 : Webアプリ開発(StreamlitにAI Agentの処理を追加) - Azure AI Agent

前回は、PythonのWebクライアントである「Streamlit」のUIを改善しました。

azure-ai-agent.hatenablog.com

今回は、このコードにAzure AI Agentの呼び出しコードを、含めていきます。

Azure AI Foundryの準備

Azure AIとつなぐために、AI FoundryにProjectとHubを作成します。East USを利用します。

ProjectとHubの作成

AI Modelとしてgpt-4oを選びます。

gpt-4oモデルの作成

エージェントプレイグラウンドで、動くことを確認しておきます。

エージェントプレイグラウンド

Streamlitのコードの拡張

前回のコードに、Azure AI Agentのコードを含めていきます。

github.com

今回は、azure-ai-projects_1.0.0b7バージョンを使います。

# 依存モジュールのインストール
$ pip install azure-ai-projects==1.0.0b7
$ pip install azure-identity  

# 環境変数の設定
$ export PROJECT_CONNECTION_STRING="eastus.api.azureml.ms;5c76d21f-35d5-4b60-a0f4-xxxxxxxxxxx;rg-east-us;pr-east-us"
$ export MODEL_DEPLOYMENT_NAME="gpt-4o"

環境設定を行って、Pythonコードを変更します。

import os
import streamlit as st
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
import logging

st.title('AIエージェント')
st.write('こんにちは。これはAIエージェントです。')

# 初期処理
if 'messages' not in st.session_state:
    st.session_state.messages = []

    # Azure AI プロジェクトの接続文字列とデプロイメント名を環境変数から取得
    # $ export PROJECT_CONNECTION_STRING="eastus.api.azureml.ms;5c76d21f-35d5-4b60-a0f4-xxxxxxxxxxx;rg-east-us;pr-east-us"
    # $ export MODEL_DEPLOYMENT_NAME="gpt-4o"

if 'agent' not in st.session_state:
    logging.basicConfig(level=logging.INFO)
    logging.info("PROJECT_CONNECTION_STRING: %s", os.environ["PROJECT_CONNECTION_STRING"])
    logging.info("MODEL_DEPLOYMENT_NAME: %s", os.environ["MODEL_DEPLOYMENT_NAME"])

    # Azure AI プロジェクトのクライアントを初期化
    st.session_state.project_client = AIProjectClient.from_connection_string(
        credential=DefaultAzureCredential(),
        conn_str=os.environ["PROJECT_CONNECTION_STRING"]
    )

    st.session_state.agent = st.session_state.project_client.agents.create_agent(
        model=os.environ["MODEL_DEPLOYMENT_NAME"],
        name="WebAppAgent",
        instructions="You are a helpful assistant",
    )

# チャットメッセージ表示エリア
st.markdown("### チャット履歴")
chat_container = st.container()
with chat_container:
    for msg in st.session_state.messages:
        if msg['sender'] == 'user':
            st.markdown(
                f"<div style='background-color: #104E8B; padding: 10px; border-radius: 10px; margin: 5px; text-align: right;'>{msg['text']}</div>",
                unsafe_allow_html=True,
            )
        else:
            st.markdown(
                f"<div style='background-color: #2E8B57; padding: 10px; border-radius: 10px; margin: 5px; text-align: left;'>{msg['text']}</div>",
                unsafe_allow_html=True,
            )

# 固定下部の入力フォーム
st.markdown("---")
with st.form(key='chat_form', clear_on_submit=True):
    user_input = st.text_input("あなたのメッセージを入力してください")
    submitted = st.form_submit_button("送信")
    if submitted and user_input:
        st.session_state.messages.append({"sender": "user", "text": user_input})
        
        # プロジェクトクライアント
        # Directly use st.session_state.project_client in subsequent calls
        
        # 新しいスレッドを作成してセッションステートに保存
        thread = st.session_state.project_client.agents.create_thread()
        st.session_state.thread_id = thread.id
        logging.info(f"スレッドが作成されました。スレッドID: {thread.id}")

        # ユーザーのメッセージを作成
        message = st.session_state.project_client.agents.create_message(
            thread_id=st.session_state.thread_id,
            role="user",
            content=user_input,
        )
        logging.info(f"メッセージが作成されました。ID: {message.id}")
        
        # エージェントへメッセージを送信
        run = st.session_state.project_client.agents.create_and_process_run(
            thread_id=st.session_state.thread_id,
            agent_id=st.session_state.agent.id,
        )
        logging.info(f"処理が完了しました。ステータス: {run.status}")
        
        if run.status == "failed":
            logging.error(f"処理が失敗しました: {run.last_error}")
        
        # すべてのメッセージを取得
        messages = st.session_state.project_client.agents.list_messages(thread_id=st.session_state.thread_id)
        logging.info(f"メッセージ: {messages}")

        # エージェントのテキストを取り出す
        mdata = messages.get('data', [])
        agent_msg = next((msg for msg in mdata if msg.get('role') == 'assistant'), None)
        agent_last_msg = agent_msg["content"][0]["text"]["value"]
        logging.info(f"agent_last_msg: {agent_last_msg}")

        # エージェントのレスポンスとして実行結果のステータスを表示
        st.session_state.messages.append({"sender": "agent", "text": f"{agent_last_msg}"})
        st.rerun()

これまで検証してきた「AI Agentの初期化」「スレッド作成」「メッセージ送信」「返信されたメッセージ群の取り出し」を行っています。

Streamlitでは、st.session_stateに状態を保存しているようだったので、AI Agentの変数も入れてみました。

以前使えたget_last_text_message_by_senderというメソッドが使えなかったので、Jsonから、最後のメッセージを取り出すようにしました。

動作確認

ローカルPCから、Azure AI Agent Serviceを呼び出せたことを確認できました。簡単にWebブラウザで使える、AI エージェントが呼び出せて良かったです。

ローカルPCから、Azure AI Agent Searviceを呼び出せたことを確認

Pythonコードを動くようにするには、少し時間がかかりましたが、動作して良かったです。

次回は、コードを調整してから、Azureにデプロイしたいと思います。