
Azure
Microsoft Azureとは、Microsoftが提供するクラウドサービスの総称です。
企業や開発者向けに、コンピューティング、分析、データストレージ、ネットワーキング、AIサービスなど多岐にわたるサービスを提供しています。
スケーラブルで柔軟性が高く、オンプレミス環境と統合しながら使えるハイブリッドクラウドソリューションとしても評価されています。
イベント
マガジン
技術ブログ
Azureを使ったハンズオンやワークショップを開催する際、参加者のユーザーや参加者毎の専用リソースグループを用意し、それぞれに適切な権限を設定したいことがあると思います。 本記事では、Terraformのfor eachを使用してこれらの準備を効率的に行う方法について解説します。 for eachとは Terraformのfor eachは、リソースを複数回繰り返し作成するための機能です。 通常、複数のリソースを作成する際はそれぞれ個別にresourceブロックを記述必要がありますが、この機能を使用すると複数のリソースを1つのresourceブロックで定義することができます。 メリット 1. 効率性の向上 for eachを使用しない場合、コンソールで作成またはresourceブロックを記述する作業をリソースの数だけ繰り返すことになります。 for eachを使用すれば、リストとresourceブロックをそれぞれ1つ記述するだけで作成できます。 2. パラメーターの設定ミスの低減 「同じパラメーターでリソース名だけが違う」というように、一部のパラメーターだけが異なるリソースを複数作成するケースがあると思います。 for eachを使用せずに個別に作成すると、作業ミスで一部のリソースだけ異なる設定にしてしまうことがあるかもしれません。 しかし、for eachを使用すれば、変えたいパラメーター(リソース名等)だけをリストに記述し、他のパラメーターは全く同じリソースを安全に作成することができます。 使い方 まずは、リストを記述します。 locals { names = ["group_a", "group_b", "group_c"] } for eachにこのリストを指定し、{パラメーター名} = each.key と記述すると、そのパラメーターの値がリストの各要素の値となったリソースが作成されます。 下記のコードの場合、リソース名がgroup_a、group_b、group_cのリソースグループ3つが作成されます。 resource "azurerm_resource_group" "example_groups" { for_each = toset(local.names) name = each.key ・・・ } また、for eachを使用して作成されたリソースはマップ型になっているため、それらのパラメーターはeach.value.{パラメーター名}で参照できます。 下記のコードの場合、リソース名がexample_vmの仮想マシンがgroup_a、group_b、group_cに作成されます。 resource "azurerm_windows_virtual_machine" "example_VMs" { for_each = azurerm_resource_group.example_groups name = "example_vm" resource_group_name = each.value.name ・・・ } 想定ユースケース ここからはfor eachを活用した実践的な例として、Azureのワークショップやハンズオンの環境準備を想定したTerraformコードについて解説します。 想定するユースケースは以下の通りです。 参加者にはそれぞれユーザーを発行する 参加者毎に専用のリソースグループを作成し、自分のリソースグループでのみリソースの作成/閲覧/更新/削除ができるようにする 参加者全員が参照する共通のリソースは閲覧のみ可能にする 構成イメージ Terraformコード 最終的なコードは以下の通りです。以降の章で各部の解説を行います。 # ユーザー名のリスト variable "user_names" { default = ["user1", "user2", "user3"] } # ユーザーIDと専用リソースグループの名前のリスト locals { user_ids = [for user_name in var.user_names: "${user_name}_workshop@xxxxx.onmicrosoft.com"] resource_groups = [for user_name in var.user_names: "${user_name}_workshop_group"] } # ユーザーを作成 resource "azuread_user" "workshop_users" { for_each = toset(local.user_ids) user_principal_name = each.key display_name = each.key password = "xxxxx" } # グループを作成 resource "azuread_group" "workshop_group" { display_name = "workshop" security_enabled = true } # ユーザーをグループに追加 resource "azuread_group_member" "workshop_members" { for_each = azuread_user.workshop_users group_object_id = azuread_group.workshop_group.object_id member_object_id = each.value.object_id } # 共通リソースグループを作成 resource "azurerm_resource_group" "shared_rg" { name = "shared_workshop_group" location = "japaneast" } # 専用リソースグループを作成 resource "azurerm_resource_group" "user_rg" { for_each = toset(local.resource_groups) name = each.key location = "japaneast" } # 共通リソースグループに対する権限を定義 resource "azurerm_role_definition" "shared_rg_read" { name = "SharedRGRead" scope = azurerm_resource_group.shared_rg.id description = "全員共通RGの閲覧権限" permissions { actions = [ "Microsoft.Resources/subscriptions/resourceGroups/read", "Microsoft.Resources/subscriptions/resourceGroups/resources/read" ] not_actions = [] } assignable_scopes = [azurerm_resource_group.shared_rg.id] } # 共通リソースグループに権限を付与 resource "azurerm_role_assignment" "group_shared_rg_read_assign" { scope = azurerm_resource_group.shared_rg.id role_definition_id = azurerm_role_definition.shared_rg_read.role_definition_resource_id principal_id = azuread_group.workshop_group.object_id } # 専用リソースグループへの権限を定義 resource "azurerm_role_definition" "user_rg_crud" { for_each = azurerm_resource_group.user_rg name = "UserRGCRUD_${each.key}" scope = each.value.id description = "${each.key}専用RG用のCRUD権限" permissions { actions = [ "Microsoft.Resources/subscriptions/resourceGroups/read", "Microsoft.Resources/subscriptions/resourceGroups/write", "Microsoft.Resources/subscriptions/resourceGroups/delete", "Microsoft.Resources/*/read", "Microsoft.Resources/*/write", "Microsoft.Resources/*/delete", "Microsoft.Resources/deployments/*" ] not_actions = [] } assignable_scopes = [each.value.id] } # 専用リソースグループに権限を付与 resource "azurerm_role_assignment" "user_rg_crud_assign" { for_each = { for idx, rg_name in local.resource_groups : rg_name => local.user_ids[idx] } scope = azurerm_resource_group.user_rg[each.key].id role_definition_id = azurerm_role_definition.user_rg_crud[each.key].role_definition_resource_id principal_id = azuread_user.workshop_users[each.value].object_id } 1. ユーザー名のリストを作成 ユーザー名のリストを作成しています。 # ユーザー名のリスト variable "user_names" { default = ["user1", "user2", "user3"] } 2. ユーザーIDと専用リソースグループの名前のリストを作成 1のリストを使用して、ユーザーIDと専用リソースグループの名前のリストを作成します。 # ユーザーIDと専用リソースグループの名前のリスト locals { user_ids = [for user_name in var.user_names: "${user_name}_workshop@xxxxx.onmicrosoft.com"] resource_groups = [for user_name in var.user_names: "${user_name}_workshop_group"] } 3. ユーザーを作成 2のユーザーIDのリストを使用して、ユーザーを作成します。 ※ 手順の簡略化のため、ユーザーの表示名はユーザーIDと同じ値にしています。 # ユーザーを作成 resource "azuread_user" "workshop_users" { for_each = toset(local.user_ids) user_principal_name = each.key display_name = each.key password = "xxxxx" } 4. グループを作成 & ユーザーを追加 グループを作成し、3のユーザーをグループに追加します。 # グループを作成 resource "azuread_group" "workshop_group" { display_name = "workshop" security_enabled = true } # ユーザーをグループに追加 resource "azuread_group_member" "workshop_members" { for_each = azuread_user.workshop_users group_object_id = azuread_group.workshop_group.object_id member_object_id = each.value.object_id } 5. 共通リソースグループを作成 共通リソースグループを作成します。 # 共通リソースグループを作成 resource "azurerm_resource_group" "shared_rg" { name = "shared_workshop_group" location = "japaneast" } 6. 各ユーザーの専用リソースグループを作成 2の専用リソースグループの名前のリストを使用して、専用リソースグループを作成します。 # 専用リソースグループを作成 resource "azurerm_resource_group" "user_rg" { for_each = toset(local.resource_groups) name = each.key location = "japaneast" } 7. 共通リソースグループへのRead権限を定義 & グループに権限を付与 5の共通リソースグループへのRead権限を定義し、4のグループに付与します。 # 共通リソースグループに対する権限を定義 resource "azurerm_role_definition" "shared_rg_read" { name = "SharedRGRead" scope = azurerm_resource_group.shared_rg.id description = "全員共通RGの閲覧権限" permissions { actions = [ "Microsoft.Resources/subscriptions/resourceGroups/read", "Microsoft.Resources/subscriptions/resourceGroups/resources/read" ] not_actions = [] } assignable_scopes = [azurerm_resource_group.shared_rg.id] } # 共通リソースグループに権限を付与 resource "azurerm_role_assignment" "group_shared_rg_read_assign" { scope = azurerm_resource_group.shared_rg.id role_definition_id = azurerm_role_definition.shared_rg_read.role_definition_resource_id principal_id = azuread_group.workshop_group.object_id } 8. 専用リソースグループへのCRUD権限を定義 & 各ユーザーに権限を付与 6の専用リソースグループへのCRUD権限を定義し、各ユーザーに付与します。 Microsoft.Resources/*/read, write, delete の、「*」の部分にサービス名を記述することで、特定のサービスに限定した権限を付与することもできます。 # 専用リソースグループへの権限を定義 resource "azurerm_role_definition" "user_rg_crud" { for_each = azurerm_resource_group.user_rg name = "UserRGCRUD_${each.key}" scope = each.value.id description = "${each.key}専用RG用のCRUD権限" permissions { actions = [ "Microsoft.Resources/subscriptions/resourceGroups/read", "Microsoft.Resources/subscriptions/resourceGroups/write", "Microsoft.Resources/subscriptions/resourceGroups/delete", "Microsoft.Resources/*/read", "Microsoft.Resources/*/write", "Microsoft.Resources/*/delete", "Microsoft.Resources/deployments/*" ] not_actions = [] } assignable_scopes = [each.value.id] } # 専用リソースグループに権限を付与 resource "azurerm_role_assignment" "user_rg_crud_assign" { for_each = { for idx, rg_name in local.resource_groups : rg_name => local.user_ids[idx] } scope = azurerm_resource_group.user_rg[each.key].id role_definition_id = azurerm_role_definition.user_rg_crud[each.key].role_definition_resource_id principal_id = azuread_user.workshop_users[each.value].object_id } 確認 terraform applyを実行してAzure環境にコードで記述した内容を反映した後、管理者権限を持つユーザーでログインすると、以下のようにグループにユーザーが3つ追加されていることがわかります。 また、リソースグループも共通1つと専用3つの計4つが作成されていることが確認できます。 続いて、参加者用ユーザーでログインします。(下の画像はuser1_workshop@xxxxx.onmicrosoft.comでログイン) リソースグループを見に行くと、共通リソースグループと自分の専用リソースグループしか表示されないことが確認できます。 まとめ 以上の手順で効率的にユーザー/グループ/リソースグループの作成と権限の付与ができます。 TerraformをはじめとするIaCツールを使用せずに手作業で上記の環境準備を実施する場合、特に各自の専用リソースグループに対する権限付与の部分で多くの手間がかかってしまいます。 本記事で紹介したケースに限らず、for_eachを使用することで効率的にインフラ構築ができますの皆様もぜひお試しください!
TechHarmonyエンジニアブログでは、 AWS・Oracle Cloud・Azure・Google Cloud 各分野の受賞者 にフォーカスし、インタビューを通してこれまでの経歴や他の受賞者に聞いてみたいことをつないでいく「 リレーインタビュー 」をお届けしています。 第二弾は、「2025 Japan AWS Jr. Champions」 を受賞された 佐藤 優音(さとう ゆうと)さん。 Japan AWS Jr. Champions は、AWSを積極的に学び、自らアクションを起こし、その取り組みが周囲にも良い影響を与えている若手エンジニアが選出されるプログラムです。 日々どのようにAWSと向き合い、どんな経験を積み重ねてきたのか。 そして、受賞に至るまでの背景には、どのようなキャリアストーリーがあったのでしょうか。 本インタビューでは、佐藤さんのこれまでの経歴やAWSへの向き合い方、さらに「次の受賞者へ聞いてみたいこと」まで、じっくりとお話を伺いました。 プロフィール 2025 Japan AWS Jr. Champions 所属: 製造事業グループソリューション第一事業本部コンサルティング第三部 氏名: 佐藤 優音 【自己紹介】 製造事業グループソリューション第一事業本部コンサルティング第三部に所属をしている佐藤優音と申します。普段は OracleのSaaS型 ERPパッケージの導入、リフトを担当 しております。AWSは業務では未経験で、自己研鑽(趣味)の範囲内で構築や勉強会の登壇などを行い、2025 Japan AWS Jr. Champions に選出いただきました。 本編 AWSエンジニアになった背景を教えてください。 学生時代、SaaSのスタートアップでインターンをしていた頃は、正直AWSって自分には関係ないものだと思っていました。ITのスペシャリストだけが触れる特別な技術というか、そんなイメージでした。当時は技術そのものより、IT技術を使ってお客さんの課題をどう解決するかという方に興味があったと思います。 AWSに興味を持ったきっかけは資格取得だったんですが、そこから実際にハンズオンをやってみたら 「こんなに簡単にシステムが作れるの?」 って驚いて。自分の思い描いたものを形にする楽しさにすっかりハマってしまいました。案件ではAWSを触る機会がなかったのですが、勉強会で登壇して自分の発表にフィードバックをもらえるのがすごく楽しくて。他の人の発表を聞くたびにモチベーションも上がりましたし、 勉強会に参加することが とても大きな経験 だったと思います。今は登壇やブログ、勉強会の開催に力を入れて 、 もっと多くの人が 気軽にAWSを始められる 環境を作っていきたいな と思っています。 エンジニアとして大切にしている価値観や信条はありますか? 一番大事 にしているのは、 技術の裏側をちゃんと理解 すること です 。なんとなくの理解でも作業は進められるますが、どういうロジックでどんな処理がされているのかを正しく理解しておくと、後々の作業効率が全然違うんです。メンバーに引き継ぐときも、 説明がスムーズになりますね。 そして技術を理解するだけじゃなくて、それを分かりやすく伝える力も大事だと思っています。案件だとメンバーに自分の考えを伝えたり、お客さんの意見を聞いたりする場面が多いのですが、自分一人が理解していてもプロジェクトはうまく回らないと感じています。だからこそ 技術力を高める のはもちろん、 それを 正しく伝える 力 も磨いていきたい なと。 あとは務理解と技術理解の両輪をしっかり回すことですね。このバランスが崩れると、実現できない提案をしちゃったり、開発者目線だけのシステムになったりするので、 業務を正しく 回すために技術をどう活かすか 、それを常に考えながら仕事をしています。 この度は受賞おめでとうございます! 受賞に至るまで特に重点を置いて取り組んできたこと・乗り越えたチャレンジを教えてください。 月1〜2回くらいのペースで勉強会に登壇したり、ブログを書いたりしていました。特に勉強会では、ちょっとユニークなテーマでハンズオンをやったり、技術的な部分もなるべく分かりやすく説明したり、初めてAWSに触れる人でもとっつきやすい発表を心がけていました。 また AWS BuilderCardsを使ったイベント運営 にも力を入れて、 初心者の方とベテランの方をつなぐ場づくり をしてきました。 案件とは全く別の領域を学び続けるのはかなり大変でした 。でも 「 AWSとOracleの両方 を極めたら どんな世界 が見えるんだろう 」 という 好奇心 のおかげで 広く学ぶ楽しみ みたいなもの を 実感 できた気がしています。 受賞がご自身のキャリアやチームに与えた影響はありますか? Jr. Championsに選んでいただいてから、 AWSの活動がすごくやりやすくなったと実感しています。社内外問わず「Jr. Championsだから」っていうことで声をかけてもらえることが増えて、関われるイベントの幅も広がりました。それに、自分よりもっとアウトプットしているすごいメンバーと交流できるようになって、 毎日とても いい 刺激 を受けています。 業務では直接的に活きることは少ないですが、コミュニティでの関わり方とか自己研鑽のモチベーションが上がったりとか、間接的にいい影響はあるなと感じています。 今後はもっと周囲に影響を与えてみたいです。具体的には自分みたいに業務でAWSを使わない初心者の方でも始めやすい環境づくりに力を入れていきたいです。 自分でサーバーを買わなくても 従量課金で 手軽にハンズオンができるというクラウドの魅力 を活かして、 「 AWSに 興味 はあるけど 一歩踏み出せない 」 といった方の 背中を押せたら いい な と思っています 。 今後、個人として、挑戦してみたい新しい技術・分野や、目指している目標について教えてください。 今後はAWSの案件にも携わってみたい です。ERPの知識とAWSの知識を掛け合わせられたら、それが自分の強みになると思っているので、広い視野を持ってAWSに関わっていきたいです。 コミュニティ活動では、もっと運営力を磨いて、 自分がいなくても自立して回っていくようなコミュニティを作りたい なと思っています。最初の旗振りはもちろん大事なんですけど、やっぱり旗振りする人がいなくても自律的に成長していけるコミュニティが一番強いと思うんです。だから今関わっているコミュニティがもっと活性化するように、しっかり携わっていきたいです。 個人としては、 もっと AWSの 技術力を上げて いきたい です。趣味で触っているとどうしても業務的なシステムに関わる機会が少なくて、課金の都合もあって大規模なシステム構築も難しいのが正直なところでして… 。 苦手な分野をなくして 、 いろんなサービスに 知見を 持てるように 成長していきたい と思っています。 前回のリレーインタビュー での間世田 秀さんから 佐藤さんへのご質問です。ご回答をお願いいたします。 佐藤さんは、業務ではOracleを扱っているとお聞きしました。 AWS と Oracle 並行して、 学び続ける秘訣 を教えてください! 「やはり自分の好奇心を信じて進めていくことかなと思います。AWSを学んでOracleの知識が生きること、Oracleを学んでAWSの 知識が生きることが 学習していると 必ず見つかる ので、それらに対して楽しさを見出すことでこれまで二刀流を続けることができていると思っています。自分の 得意を複数領域をかけ算して作り出す ことで、唯一無二の存在になれると信じて日々学習しています!」 次のインタビューは AWS Top Engineers の「寺内 康之 」さんです!寺内さんにお聞きしたいことはありますか? 寺内さんは、クラウド 黎明期 から 新しいサービスに関する知識 を積極的に 収集 されてきたと思いますが、常に最新技術をキャッチアップするための ポイントを教えて ください! 佐藤 優音さん、ありがとうございました! 最後に、読者の方へメッセージをお願いいたします! 私はAWSを業務で扱っていないのに表彰を受けるというややレアケースではありますが、こういう人間がJr. Championsとして選出されることで、 興味とやる気さえあれば不可能なことはない ということを少しは体現できたかなと思っています。これからも自分の好奇心に身を任せて 守備範囲の広いエンジニアとして精進してまいります! 次回インタビューは、2025 Japan AWS Top Engineers を受賞された 寺内 康之(てらうち やすゆき)さんです。 次回の記事もお楽しみにお待ちください!
サイオステクノロジーのひろです。今回はAzureOpenAIを使用したFunctionCallingについて解説していきます。 このブログのゴール FunctionCallingとは何かわかる AzureOpenAIモデルを使用したFunctionCallingの実装方法がわかる FunctionCallingとは FunctionCallingはLLMに関数を使わせることができる機能です。 関数は予め作成しておく必要がありますが、このFunctionCallingを使用することで、LLMができることを拡張することが可能です。 例えば、LLMは文章の生成が可能で、様々な質問に回答してくれます。しかしなんでも正しい答えを教えてくれるわけではなく、最新の情報(例えば今日の天気等)やクローズドな情報には回答できません。 しかしながら、最新の情報を検索して取得する関数や、データベースを検索してクローズドな情報を取得する関数を用意し、FunctionCallingによってLLMに関数を使用させれば、回答させることも可能になります。 さらにそれどころではなく、外部APIを操作する関数を実行させればGoogleカレンダーへのイベント登録やメール送信も可能ですし、ロボットを動作させる関数を実行させれば現実へ干渉させることも可能になります。 組み合わせ次第で新たな価値を生み出すことができるかもしれません。 FunctionCallingでできることについて理解していただけたでしょうか。 ここから具体的な内容に入っていきたいと思います。 FunctionCallingのシーケンス どのようにLLMが関数を実行するかというと、以下のシーケンス図を見ていただければと思います。 まず、アプリケーションからLLMに対して使用可能な関数とプロンプトを渡します。 次に、LLMはプロンプトに沿って独自にどの関数を使用すべきか判断し、アプリケーションへ関数の呼び出しをリクエストします。 実行する関数を教えてもらったアプリケーションは関数を実行し、実行結果をLLMに渡します。 最終的に、LLMが実行結果をもとに回答を生成します。 このような流れでFunctionCallingが行われます。 最終的な回答を生成するまでに必要な情報が足りない場合は複数の関数を実行させることもあります。 例えば、「八王子の天気と現在時刻を教えて」とプロンプトを投げたとします。 その場合、FunctionCallingは並列で2つの関数(天気取得関数と時刻取得関数)を実行して回答します。 また、アプリケーション側で、最終的な回答がされるまでツールの実行を続ける実装を行った場合、LLMが続けて関数を実行できます。 例えば、「天気情報を取得してそれを表にまとめて」とプロンプトを投げたとします。 その場合、1回目のFunctionCallingで天気情報を取得し、2回目に表を操作する関数を使って天気情報を書きこむ等といった処理が可能になります。 生成AIが行っているのは関数と引数を渡すことのみで、関数の実行はアプリケーション側で行います。そのため、アプリケーション側でLLMから渡される関数と引数を読み取って、関数を実行する機能を実装する必要があります。 FunctionCallingの説明については以上です。 続いてAzure OpenAIにおけるFunctionCallingについて解説していきます。 Azure OpenAIのFunctionCalling Azure OpenAIのFunctionCallingは、APIを叩く際のパラメータとして、toolsとtool_choiceを追加することで可能になります。 Azure OpenAIモデルのデプロイ方法は こちら のブログで解説しております。 以下にサンプルコードを記載しています。また、サンプルコードは こちら のリポジトリで公開しています。実行方法をreadmeに記載しているのでクローンして是非試してみていただければと思います。 まずは今回FunctionCallingで使用する関数を作成しましょう。 今回非常に簡易的な、辞書型で値を返す関数を2つ作成します。 サンプルコード Python import datetime def current_time(location: str): # 簡易的に現在時刻を送信 current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") return { "current_time": current_time, "timezone": location, } def current_weather(location: str): # ダミーの天気データを返す return { "location": location, "temperature": 15, "description": "晴れ", } 今回作成した関数では、地域名を引数として、疑似的にその地域の現在時刻を返す関数と天気情報を返す関数を作成しました。これらの関数をFunctionCallingで実行していきます。 次にFunctionCallingで渡すツールについてです。 渡すツール定義のJSONは以下のようになっています。 JSON { "type": "function", "function": { "name": "関数名", "description": "関数の説明(生成AIがこの説明を読んで関数を実行するか判断します)", "parameters": { "type": "object", "properties": { "【引数名】": { "type": "データ型(string, integer, booleanなど)", "description": "引数の説明" }, }, "required": [ "必須の引数名", ] } } } 関数名と関数の説明、引数の説明や引数のデータ型を定義して渡します。 ツール定義はJSONをそのまま記述すると量が多く、メンテナンスし辛いことがあるため、今回はPythonのライブラリであるPydanticを使用します。これにより、メンテナンスし易くなるだけでなく、後ほど引数のバリデーションに使用することができます。 以下はサンプルコードです。 Python from pydantic import BaseModel, Field from typing import Dict, Any class WeatherArgs(BaseModel): """get_current_weather関数の引数モデル""" location: str = Field( ..., description="天気情報を取得したい都市名(日本語)。例: '東京'", ) class TimeArgs(BaseModel): """get_current_time関数の引数モデル""" location: str = Field( ..., description="時刻を取得したい都市名(日本語)。例: '東京', 'ニューヨーク'", ) class FunctionSchemaManager: """複数の関数スキーマを管理するクラス""" @staticmethod def get_weather_tool() -> Dict[str, Any]: """天気取得ツールのスキーマ""" return { "type": "function", "function": { "name": "current_weather", "description": "指定された都市の現在の天気情報を取得します", "parameters": WeatherArgs.model_json_schema(), }, } @staticmethod def get_time_tool() -> Dict[str, Any]: """時刻取得ツールのスキーマ""" return { "type": "function", "function": { "name": "current_time", "description": "指定された都市の現在時刻を取得します", "parameters": TimeArgs.model_json_schema(), }, } @staticmethod def get_all_tools() -> list[Dict[str, Any]]: """利用可能な全てのツールを返す""" return [ FunctionSchemaManager.get_weather_tool(), FunctionSchemaManager.get_time_tool(), ] descriptionには引数の例を入れておくことで正しい引数が期待できます。 最後にFunctionCallingを行う部分のサンプルコードです。 Python import os import json from openai import AzureOpenAI from dotenv import load_dotenv from schemas import FunctionSchemaManager, TimeArgs, WeatherArgs from functions import current_time, current_weather # .envファイルから環境変数を読み込み load_dotenv() api_key = os.getenv("AZURE_OPENAI_API_KEY") endpoint = os.getenv("AZURE_OPENAI_ENDPOINT") api_version = os.getenv("AZURE_OPENAI_API_VERSION") deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME") # Azure OpenAIクライアントの作成 client = AzureOpenAI( api_version=api_version, azure_endpoint=endpoint, api_key=api_key, ) # ツール取得 tools = FunctionSchemaManager.get_all_tools() messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の今の天気と時刻を教えてください。"}, ] # 1回目のFunctionCallingリクエスト response = client.chat.completions.create( messages=messages, max_tokens=1000, temperature=0.7, model=deployment, tools=tools, tool_choice="auto", ) response_message = response.choices[0].message messages.append(response_message) print("レスポンス:") print(response_message) # 関数実行 if response_message.tool_calls: for tool_call in response_message.tool_calls: function_name = tool_call.function.name function_args = json.loads(tool_call.function.arguments) print(f"関数呼び出し: {function_name}") print(f"引数: {function_args}") if function_name == "current_weather": args = WeatherArgs.model_validate(function_args) # 引数チェック tool_response = current_weather(location=args.location) elif function_name == "current_time": args = TimeArgs.model_validate(function_args) # 引数チェック tool_response = current_time(location=args.location) else: tool_response = {"error": "不明な関数"} messages.append( { "tool_call_id": tool_call.id, "role": "tool", "name": function_name, "content": json.dumps(tool_response, ensure_ascii=False), } ) else: print("関数呼び出しはありませんでした。") # 最終回答生成 final_response = client.chat.completions.create( messages=messages, max_tokens=1000, temperature=0.7, model=deployment, ) print("最終レスポンス:") print(final_response.choices[0].message.content) 生成AIモデルからのレスポンスには使用する関数と引数が書かれているため、それを使用して関数の実行を行います。 Azure OpenAIのFunctionCallingは並列関数呼び出しが可能で、一回のレスポンスで複数の使用する関数名を返してくれます。 実行結果 実行結果は以下のようになりました。 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_iFwCt1t3Lzl2WMqQJDvP26Z7', function=Function(arguments='{"location": "八王子"}', name='current_weather'), type='function'), ChatCompletionMessageFunctionToolCall(id='call_6LbONbarZs3sCqoPiZstpieN', function=Function(arguments='{"location": "八王子"}', name='current_time'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 関数呼び出し: current_time 引数: {'location': '八王子'} 最終レスポンス: 八王子の現在の天気は晴れで、気温は15度です。また、現在の時刻は2026年2月24日の13時36分です。 current_weatherとcurrent_timeの2つの関数を一度のレスポンスで呼び出していることがわかります。 また、関数の実行結果をもとにして回答してくれています。 messagesを変更することで、1つの関数だけ実行させることも可能です。 以下にmessagesを変更した場合の実行結果を示します。 時刻を聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の時刻を教えてください。"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_5m0PwZa4t2AIty1trBlKTGAs', function=Function(arguments='{"location":"八王子"}', name='current_time'), type='function')]) 関数呼び出し: current_time 引数: {'location': '八王子'} 最終レスポンス: 現在の八王子の時刻は、2026年2月24日 14:22です。 天気を聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の天気を教えてください。"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_MZmeJ11LfOQufB1dFzyztQEu', function=Function(arguments='{"location":"八王子"}', name='current_weather'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 最終レスポンス: 現在の八王子の天気は晴れで、気温は15度です。 傘が必要か聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "今から八王子に行きます。傘はいるかな"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_Hoa7qoq13vJa4nVqzCdegVJp', function=Function(arguments='{"location":"八王子"}', name='current_weather'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 最終レスポンス: 八王子の天気は晴れで、気温は15度です。今のところ傘は必要なさそうですが、念のため天気予報を確認しておくと良いかもしれません。安全に行ってきてください! 直接天気や時刻を聞かなくとも関数を実行して答えてくれます。 まとめ 今回はAzure OpenAIでFunctionCallingを行う方法についてまとめました。 Azure OpenAIのFunctionCallingは並列関数呼び出しが可能で、前章の例のように複数の関数を一度のレスポンスで呼び出すことができます。 どのような関数を実行させるかはアイデア次第です。是非FunctionCallingを使用して生成AIとツールを組み合わせてみてください。 今後もAzure OpenAIについて学んだことを共有していきたいと思います。 読んでいただきありがとうございました。 関連記事 これまでのAzure OpenAI入門 Azure OpenAI入門:モデルのデプロイとpythonからAPIを実行 AzureOpenAI入門:JSON形式のデータを出力させる 参考文献 https://learn.microsoft.com/ja-jp/azure/ai-foundry/openai/how-to/function-calling?view=foundry-classic&tabs=python-secure ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AzureOpenAI入門:FunctionCallingで生成AI×ツールを実現する first appeared on SIOS Tech Lab .


























