3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# SDKを使ってPlaywrightツールを設定したAzure AI Foundry Agentを作成する

Last updated at Posted at 2025-11-12

はじめに

記事の目的

Azure AI Foundry Agentでは、マネージドなAI AgentをAzure環境に作成することができます。特定の業務を実施するAgentを作成し、マルチエージェント構成で様々な業務を対応させることも可能です。
そんなAgentに、ブラウザ自動操作(ブラウザオートメーション)機能が加わったらとても便利そうです。
本記事ではMicrosoft Formsのアンケートを、Azure Foundry Agent から呼び出したPlaywright Workspacesを使って、自動で回答させます。

2025/11現在、AI Foundry AgentからのPlaywright Workspaces呼び出しは結構不安定なように思えます。
うまく実行できることもあれば、"Tool processing for browser_automation failed"といったエラーなどで失敗することがあり、特に画面入力系の操作で失敗することが多いように思えます。
SDKもbeta版だったり、AI Foundry側でも正式に対応していない状態ですので、こちらの記事も技術的な検証としてご覧いただけると幸いです。

記事作成までの経緯

Playwright Workspacesは、MicrosoftがAzureで提供するクラウドベースのテスト実行サービスで、Playwrightフレームワークを基盤に構築されています。

このPlaywright workspacesをAzure AI Foundy Agentから操作するためのサンプルコードがPythonで公開されています。

「またC#はないのか…」とPythonでサンプルを試す日々でしたが、ふと見るとC#用のAzure.AI.Agents.Persistentにもv1.2.0-beta.6からBrowserAutomationToolDefinition classが追加されているじゃないですか。(気が付きませんでした)

さっそく、今回は2025/11/10現在で最新である1.2.0-beta.7のパッケージで試してみます。

事前準備:Playwright Workspacesの作成

1. リソースの作成

  • Azureの検索ボックスから「playwright」と入力すると、「Playwright Workspaces」が表示されますので選択します(まれに表記ゆれで検索できない悲劇があるので書いておきました)
    image.png

  • リソースを作成します。特に特殊な設定はないので、リソースグループ、ワークスペース名、リージョンを適宜設定してください
    image.png

2. トークンの生成

  • Azure AI Foundry側から接続するため、アクセストークンを生成します
    • アクセス管理-->トークン生成
      image.png
    • アクセストークン名と有効期限を設定しますが、有効期限は短すぎると後で試すときにExpiredとなってしまうのでご注意ください(忘れてハマりました)
      image.png
    • あとで利用するので作成したアクセストークンをメモ帳などにコピーします
      image.png

3. ブラウザーエンドポイントの確認

  • 概要に表示されている「ブラウザーエンドポイント」も、AI Foundry Projectから接続時に利用するので、メモ帳などにコピーします
    image.png

4. 共同作成者ロールの追加

  • Playwright Workspacesのアクセス制御で、共同作成者としてAI Foundry ProjectのマネージドIDを追加します
    image.png

事前準備:AI Foundry Agentの設定

[前提]AI Foundryリソースについて

  • Auzre AI FoundryリソースとLLMモデルについては、作成済みを前提とします
    • Azure AI Foundry リソース作成済み
    • モデル + エンドポイントに利用するLLMモデル作成済み(サンプルではgpt-4.1を利用)
    • ツール利用時にLLMモデルがTokenのやり取りを行いますので、TPMはなるべく上げておいたほうが良いと思います
  • 未作成の場合は、以下をご参考いただき作成ください

1. 管理センターからConnected Resourceを作成する

  • プロジェクトの左メニューより「管理センター」を開きます
    image.png
  • 「Connected resources」を開きます
    image.png
  • 「サーバーレス モデル」を選択します
    image.png
  • Playwright Workspaces設定時にコピーしておいた値を設定して作成します
    • ターゲットURI:ブラウザーエンドポイントの値
    • キー:Playwright Workspacesで作成したアクセストークンの値
      image.png
  • Connected Resourceが作成されました
    image.png

作成方法

1. C#でコンソールアプリケーションを作成

本サンプルコードはVisual Studio 2022でコンソールアプリとして作成しています。
C#とインストールするパッケージが正常に動けば、IDEはどれでも問題ないと思います。

1. パッケージインストール

開発者用PowerShellからパッケージをインストールします。(nuget経由でも、パッケージマネージャーコンソールでも問題ありませんが、本記事ではPowerShellコマンドを記載しています)

csprojのあるフォルダに移動します(通常、slnファイルのある一つ下のフォルダ階層にあります)

Azure.AI.Agents.Persistentのパッケージをインストールします。

dotnet add package Azure.AI.Agents.Persistent --version 1.2.0-beta.7 

以下のパッケージもサンプルコードで利用するので、同様にインストールします。
Azure.AI.Projectsは、AI Froundry Projectから事前準備で作成したPlaywright Workspacesのコネクション情報を取得するために使います。

dotnet add package Azure.AI.Projects
dotnet add package Azure.Identity

3. サンプルコードの実装

サンプルコード

  • こちらのサンプルコードでは、Formsを開いてアンケートに回答を行います
    • 1000ミリ秒ごとにステータスを確認していますが、その際にconsoleログを出力しますので、見づらい場合は適宜削除してください
  • 今回、AI Foundryのポータル上から実行を試したいので、作成したAgentは削除していません

2025/11/20 Playwright Workspacesから返却される操作イメージのgifをダウンロードするようにコードを修正しました。ポータル上からAgentを操作した時、チャット欄に表示される操作イメージと同じものとなります。
実行ディレクトリ配下に保存されます。
コードはざっと検証していますが、ファイル操作をしますのでご注意ください。

Program.cs
using Azure;
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;

// Azure AI Foundry Projectのendpoint
var endpoint = "<Azure AI Foundryのプロジェクトエンドポイント>";

// Azure AI Foundry ProjectのConnectedResource名
var connectedResourceName = "PlaywrightDemo";

var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());

var connections = projectClient.Connections.GetConnections();

// ** エージェントの設定値
// 作成するAgent名
var agentName = $"BrowserAutomation agent from .NET SDK {DateTime.Now.ToString("yyyy-MM-dd-HH_mm_ss")}";

// Azure AI Foundry側に作成したモデル名
var modelDeploymentName = "gpt-4.1";

// エージェントに設定する手順(サンプル)
var instructions = "ツールとして設定されたBrowserAutomationToolを利用して、回答を生成してください";

// BrowserAutomationToolのConnectionIDを取得し、パラメーターとして設定
var playwrightWorkspaceConnectionID = connections.ToList().Find(x => x.Name == connectedResourceName)?.Id;
var browserAutomationParamaters = new BrowserAutomationToolParameters(
        connection: new BrowserAutomationToolConnectionParameters(playwrightWorkspaceConnectionID!)
        );
var browserAutomationTool = new BrowserAutomationToolDefinition(
        browserAutomation: browserAutomationParamaters
    );

// エージェントクライアントの生成
PersistentAgentsClient agentClientPersistent = new(endpoint, new DefaultAzureCredential());

// BrowserAutomationを利用するAgentの生成
PersistentAgent agent = await agentClientPersistent.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: agentName,
    instructions: instructions,
    tools: new List<ToolDefinition>
    {
        browserAutomationTool
    }
);

Console.WriteLine($"Created Agent ID: {agent.Id}");

// スレッド生成
PersistentAgentThread thread = await agentClientPersistent.Threads.CreateThreadAsync();
Console.WriteLine($"Thread '{thread.Id}' created successfully.");


// メッセージ作成
PersistentThreadMessage message = await agentClientPersistent.Messages.CreateMessageAsync(
    thread.Id,
    MessageRole.User,
"https://forms.office.com/r/qkPdp1Q74Gを開いて、アンケートにポジティブな値を入力し「送信」してください");

Console.WriteLine($"Start Agent[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]");

// Agentの実行
ThreadRun run = await agentClientPersistent.Runs.CreateRunAsync(
    thread,
    agent);

// Agent実行結果を待機して確認する
do
{
    await Task.Delay(TimeSpan.FromMilliseconds(1000));
    run = await agentClientPersistent.Runs.GetRunAsync(thread.Id, run.Id);
    Console.WriteLine($"Status[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] : {run.Status.ToString()}");
}

while (run.Status == RunStatus.Queued
    || run.Status == RunStatus.InProgress);

if (run.Status == RunStatus.Failed)
{
    Console.WriteLine($"Status[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] : {run.Status.ToString()} : {run.LastError.Message}");
    return;
}

AsyncPageable<PersistentThreadMessage> messages
    = agentClientPersistent.Messages.GetMessagesAsync(
        threadId: thread.Id, order: ListSortOrder.Ascending);

// メッセージの表示 
await foreach (PersistentThreadMessage threadMessage in messages)
{
    Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
    foreach (MessageContent contentItem in threadMessage.ContentItems)
    {
        if (contentItem is MessageTextContent textItem)
        {
            Console.Write(textItem.Text);
        }
        else if (contentItem is MessageImageFileContent imageFileItem)
        {
            Console.WriteLine($"<image from ID: {imageFileItem.FileId}");
            Console.WriteLine($"<Try saving image - start");
            // ファイルメタ情報の取得
            var fileItemInfo = await agentClientPersistent.Files.GetFileAsync(imageFileItem.FileId); // PersistentFile などの型想定
            var fileName = string.IsNullOrWhiteSpace(fileItemInfo.Value.Filename)
                ? fileItemInfo.Value.Id + ".bin"
                : fileItemInfo.Value.Filename;

            // パスの生成
            var outputDir = "./output_images";
            var localPath = Path.Combine(outputDir, fileName);

            // 実データのダウンロード
            var remoteBinary = await agentClientPersistent.Files.GetFileContentAsync(imageFileItem.FileId);
            // ファイルの生成
            Directory.CreateDirectory(Path.GetDirectoryName(localPath)!);
            await File.WriteAllBytesAsync(localPath, remoteBinary.Value.ToArray());
            Console.WriteLine($"<Try saving image - End : {localPath}");
        }
        Console.WriteLine();
    }
}

実行結果

  • 実行が完了すると、実行結果が回答として返却されました
Created Agent ID: asst_iHvx9nkrP0zBIyE0nuBcFE6H
Thread 'thread_4oCfEkePNOydjIQCDakFQcDE' created successfully.
Start Agent[2025-11-11 21:09:13]
Status[2025-11-11 21:09:15] : in_progress
~省略~
Status[2025-11-11 21:10:59] : completed
2025-11-11 12:09:12 -       user: https://forms.office.com/r/qkPdp1Q74Gを開いて、アンケートにポジティブな値を入力し「送信」してください
2025-11-11 12:10:54 -  assistant: <image from ID: assistant-3oRskdvzgJWnJSKr7Ejrys
アンケートフォーム(https://forms.office.com/r/qkPdp1Q74G)を開いて、すべての必須項目にポジティブな値(会社名、氏名、メールアドレス、参加目的、満足度、感想など)を入力し、「送信」しました。
送信完了の確認ページも表示されています。アンケートは正常に提出されました。

2025/11/20にPlaywright Workspacesから返却される操作イメージを保存するように変更しました。
その場合、以下のような実行結果となります。
こちらにgifファイルは記載しませんが、ローカルにしっかりと作成されていました!

~省略~
2025-11-20 12:03:14 -  assistant:
<image from ID: assistant-E5Q2G7VExmD4QjZntAjmvc
<Try saving image - start
<Try saving image - End : ./output_images\run_eZ8wG5GviTG3QcbhD2reEJH7_output.gif
~省略~
  • アンケート結果を見てみると、セミナーにポジティブなフィードバックをいただけたようです(企業名、メールアドレスはLLMモデルが作成した架空の企業ですがメールアドレスだけなんとなくマスクしました)
    image.png

エラーとなる場合も

どうしても失敗する場合は「〇〇〇のサイトから東京の店舗を検索してください」など、入力ではなく情報を取得するだけのプロンプトなどでお試しください。こちらですと、かなり成功の確率は高いと思います。

  • 以下のようにエラーが発生するケースもありますが、Formsの入力は完了しており、アンケートの回答は+1されていました
  • AgentのTool呼び出しが完了したときに何かエラーが発生しているのかと思いますが特定できていません
Created Agent ID: asst_OgPb80YQ3nLMlcGqSF1kNlOn
Thread 'thread_eddH9lSV1oVgnJusCWQQAF4u' created successfully.
Start Agent[2025-11-12 13:23:44]
Status[2025-11-12 13:26:11] : failed
Status[2025-11-12 13:26:11] : failed : Error: tool_processing_error; Tool processing for browser_automation failed.

4. ポータルからの実行

  • AI Foundryポータルからエージェントを確認すると、C#から作成したエージェントが確認できます
  • image.png
  • ポータルから実行ができるのでしょうか?formsのURLとともに指示すると、無事に実行できました!
    • 画面には操作された画面キャプチャが表示されます(このスクショでは見えないのですが画面遷移が数枚のイメージで表示されます)
      image.png

まとめ

AI Foundry Agent + Playwright Workspacesはまだ動作に不安定なところがあるため、エラーが発生する場面も結構ありました。
Agent経由で自然言語によるウェブ画面の操作ができるというのは、テスト用途だけではなく、社内システムのデータ登録といった業務自動化や、ウェブサイトからの情報収集にも応用が期待できます。
もちろん、ブラウザーオートメーションは便利な反面、セキュリティリスクや、ウェブサイトからの情報収集へのポリシーなど気を付けるべき点は多いかなと思います。

ブラウザーオートメーションは実際に動かしてみると結構面白いので、お時間があればぜひお試しください!

3
1
0

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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?