こんにちは、MLBお兄さんこと松村です。
Google が4月に発表した AI エージェント用のオープンプロトコルである「Agent2Agent (A2A)」を試してみようと、Semantic Kernel のサンプルを試してみました。
その際に OpenAI の API ではなく、Azure OpenAI Service を使うために行った手順をまとめておきます。
サンプルリポジトリ
A2A のサンプルリポジトリは Google によって公開されています。
Semantic Kernel のサンプルはこのリポジトリに含まれています。
リポジトリをクローンし、Python のサンプルディレクトリを VS Code で開きます。
git clone https://github.com/google/A2A code A2A/samples/python
Python 環境を用意する
サンプルを動かすために Python の実行環境が必要となります。
今回は VS Code Dev container を利用するため、samples/python/.devcontainer/devcontainer.json
を用意します。
{ "name": "A2A Python Samples", "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", "features": { "ghcr.io/va-h/devcontainers-features/uv:1": {} } }
設定ファイルを準備する
Semantic Kernel で実装するエージェントの設定ファイルを用意します。
下記の内容で samples/python/agents/semantickernel/.env
を用意します。
OPENAI_API_KEY="your_api_key" OPENAI_CHAT_MODEL_ID="your_model_id" OPENAI_API_ENDPOINT="your_api_endpoint"
本来のサンプルでは OPENAI_API_KEY
と OPENAI_CHAT_MODEL_ID
だけでよいですが、Azure OpenAI Service の場合は API エンドポイントも必要であるため、 OPENAI_API_ENDPOINT
を追加します。
値は Azure AI Foundry から取得してください。
エージェントのコードを変更する
OpenAI のモデルを使用する従来のコードを、Azure OpenAI Service 向けに変更します。
samples/python/agents/semantickernel/agent.py
にいくつか変更を行います。
クラスを置き換える
Semantic Kernel での ChatCompletion に使用するクラスを OpenAI から Azure OpenAI Service に変更します。
OpenAIChatCompletion
->AzureChatCompletion
OpenAIChatPromptExecutionSettings
->AzureChatPromptExecutionSettings
from semantic_kernel.connectors.ai.open_ai import ( OpenAIChatCompletion, OpenAIChatPromptExecutionSettings, )
↓
from semantic_kernel.connectors.ai.open_ai import ( AzureChatCompletion, AzureChatPromptExecutionSettings, )
設定からエンドポイントを取得する
.env
に追加したエンドポイントの設定値 OPENAI_API_ENDPOINT
を取得します。
def __init__(self): api_key = os.getenv('OPENAI_API_KEY', None) if not api_key: raise ValueError('OPENAI_API_KEY environment variable not set.') model_id = os.getenv('OPENAI_CHAT_MODEL_ID', 'gpt-4.1') api_endpoint = os.getenv('OPENAI_API_ENDPOINT', None) # ここ
モデル名やエンドポイントを指定する
AzureChatCompletion
クラスを使用する際に、設定に追加したエンドポイントを指定します。
また、モデル名のパラメーター名も変わります。サンプルは3箇所変更します。
currency_exchange_agent = ChatCompletionAgent( service=OpenAIChatCompletion( api_key=api_key, ai_model_id=model_id, ),
↓
currency_exchange_agent = ChatCompletionAgent( service=AzureChatCompletion( deployment_name=model_id, api_key=api_key, endpoint=api_endpoint, ),
スレッドのチェック処理を変更する
会話の履歴となるスレッドの有無をチェックする処理を変更します。
async def _ensure_thread_exists(self, session_id: str) -> None: ... if self.thread is None or self.thread._thread_id != session_id:
↓
async def _ensure_thread_exists(self, session_id: str) -> None: ... if self.thread is None or self.thread.id != session_id:
以上で Azure OpenAI Service を使うよう変更できましたので、チャットも行えるようになりました。
$ uv run hosts/cli --agent http://localhost:10020 ======= Agent Card ======== {"name":"SK Travel Agent","description":"Semantic Kernel-based travel agent providing comprehensive trip planning services including currency exchange and personalized activity planning.","url":"http://localhost:10020/","version":"1.0.0","capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":false},"defaultInputModes":["text"],"defaultOutputModes":["text"],"skills":[{"id":"trip_planning_sk","name":"Semantic Kernel Trip Planning","description":"Handles comprehensive trip planning, including currency exchanges, itinerary creation, sightseeing, dining recommendations, and event bookings using Frankfurter API for currency conversions.","tags":["trip","planning","travel","currency","semantic-kernel"],"examples":["Plan a budget-friendly day trip to Seoul including currency exchange.","What's the exchange rate and recommended itinerary for visiting Tokyo?"]}]} ========= starting a new task ======== What do you want to send to the agent? (:q or quit to exit): I am traveling to Fukuoka, Japan for 2 days. I have a budget of $100 USD a day. How much is that in Japanese Yen? What sort of things can I do and eat? Select a file path to attach? (press enter to skip): stream event => {"jsonrpc":"2.0","id":"6170f43c985e436099426ca03b0cd6de","result":{"id":"d78493cfc7d042fcae2fc3f72445e212","status":{"state":"working","message":{"role":"agent","parts":[{"type":"text","text":"Building the trip plan..."}]},"timestamp":"2025-05-11T12:14:16.876885"},"final":false}} stream event => {"jsonrpc":"2.0","id":"6170f43c985e436099426ca03b0cd6de","result":{"id":"d78493cfc7d042fcae2fc3f72445e212","artifact":{"parts":[{"type":"text","text":"Here's what you need for your trip to Fukuoka:\n\n1. **Currency:** Based on the current exchange rate (1 USD = 145.18 JPY), your daily budget of $100 USD amounts to approximately 14,518 JPY per day.\n\n2. **Activities and Dining:** Fukuoka offers a mix of cultural, culinary, and modern experiences. From exploring Ohori Park and Fukuoka Castle Ruins to tasting Hakata Ramen and enjoying yatai food stalls in Nakasu, your two-day adventure will be unforgettable. Visit landmarks like Dazaifu Tenmangu Shrine and Kyushu National Museum for cultural insights and explore Canal City Hakata for entertainment. Enjoy local specialties such as mentaiko and yakitori, and consider taking in coastal views from Momochi Seaside Park and Fukuoka Tower.\n\nEnjoy your visit!"}],"index":0,"append":false}}} stream event => {"jsonrpc":"2.0","id":"6170f43c985e436099426ca03b0cd6de","result":{"id":"d78493cfc7d042fcae2fc3f72445e212","status":{"state":"completed","timestamp":"2025-05-11T12:14:18.554729"},"final":true}} ========= starting a new task ======== What do you want to send to the agent? (:q or quit to exit): Can you give me a plan for an additional $50? Select a file path to attach? (press enter to skip): stream event => {"jsonrpc":"2.0","id":"0efcdbd2f38e46eba03e6b2f68848936","result":{"id":"35ca436914fc412ea3685e909f52aec4","status":{"state":"working","message":{"role":"agent","parts":[{"type":"text","text":"Building the trip plan..."}]},"timestamp":"2025-05-11T12:14:35.765736"},"final":false}} stream event => {"jsonrpc":"2.0","id":"0efcdbd2f38e46eba03e6b2f68848936","result":{"id":"35ca436914fc412ea3685e909f52aec4","artifact":{"parts":[{"type":"text","text":"With an additional $50 USD (approximately 6,500 JPY), here are ideas to enhance your trip to Fukuoka:\n\n1. **Day 1 Enhancements:**\n - Engage in a private tea tasting session at Maizuru Tea Shop (~2,000-3,000 JPY per person) to experience Japanese tea culture.\n - Treat yourself to upgraded dining options at yatai food stalls (~3,500 JPY), enjoying delicacies like grilled yakitori and regional specialties.\n\n2. **Day 2 Enhancements:**\n - Rent a bicycle to explore Ohori Park and nearby attractions like Fukuoka Art Museum (~800-1,500 JPY).\n - Indulge in a luxurious dessert adventure at specialty pâtisseries or cafés (~2,000 JPY) featuring strawberry shortcakes or matcha parfaits.\n\n3. **Miscellaneous Additions:**\n - Purchase unique souvenirs, such as Hakata dolls, or artisanal sweets like mentaiko (~2,500 JPY).\n - Explore underground subway art stations (~1,500 JPY) that double as artistic attractions.\n\nYou can mix these ideas into your itinerary based on your preferences for culinary experiences, cultural activities, or leisure. Let me know if you would like a more tailored plan!"}],"index":0,"append":false}}} stream event => {"jsonrpc":"2.0","id":"0efcdbd2f38e46eba03e6b2f68848936","result":{"id":"35ca436914fc412ea3685e909f52aec4","status":{"state":"completed","timestamp":"2025-05-11T12:14:38.756673"},"final":true}} ========= starting a new task ========