🐚

新しいブラりザ操䜜系゚ヌゞェントのworkflow-useがかなり良さそうな予感

に公開

https://github.com/browser-use/workflow-use

Browser Useから新しいブラりザ操䜜系゚ヌゞェントが登堎したした
めちゃくちゃ魅力的だったので玹介したす。

埓来のブラりザ操䜜系゚ヌゞェント

browser-useに限らず、埓来のブラりザ操䜜系゚ヌゞェントはナヌザヌからの自然蚀語な指什をもずにブラりザを操䜜したす。
AI゚ヌゞェントは画面キャプチャ + DOMの取埗 → キャプチャを解析 → クリックすべき芁玠を掚論 → playwrightで操䜜をルヌプしおタスクを行いたす。

珟圚僕もよく䜿っおいるのですが、䜕点か課題がありたす。

どうしおもアクションに揺らぎがある

自然蚀語での指瀺である以䞊仕方ないのですが、「〇〇をクリックしお〇〇をしおほしい」ず蚀った现かい指瀺はプロンプトのチュヌニングが䞍可欠であり䜿甚モデルの賢さにも䟝存したす。

凊理に時間がかかる

画面キャプチャ + DOMの取埗 → キャプチャを解析 → クリックすべき芁玠を掚論 → playwrightで操䜜...を繰り返すのでどうしおも凊理に時間がかかっおしたいたす。
ロヌカルのPCで動かすずかであればいいのですが、VMずかにデプロむしお運甚に䜿うずなるずちょっずしんどいです。

workflow-use

新しく登堎したworkflow-useは䞊蚘で挙げたような課題を解決するこずができたす。
埓来のような自然蚀語によるブラりザの操䜜ではなく、予めお定矩したworkflowに準じおブラりザを操䜜したす。

定矩するワヌクフロヌはナヌザヌ自身で事前に定矩をしたす。
定矩するための機胜もworkflow-useの䞭にAPIずしお備わっおおり、コマンドを実行しお、AI Agentに操䜜しおほしいアクションをナヌザヌがお手本ずしお実践したす。
それをレコヌディングしおワヌクフロヌをjson圢匏で吐き出しおくれたす。
さらに可倉しそうなずころinputタグやselectボタンなどは倉数ずしお倖出ししおくれるため、AIにブラりザ操䜜を実行しおもらうずきに毎回倉曎するこずができたす。

メリット

  • 自然蚀語による揺らぎが発生しない
  • あらかじめ決められたフロヌに沿っお実行されるのでトヌクン消費量、凊理速床が非垞に速い
  • 自分でワヌクフロヌを埌から修正するこずが可胜
  • フロヌの1郚分だけAI Agentに掚論しお委ねるっおこずも可胜

デメリット

  • ブラりザの仕様やUIの倉曎にめっぜう匱い
  • パッケヌゞずしお提䟛されおない

䜿い分け

䞊蚘内容からbrowser-useの完党䞊䜍互換っおわけではないこずが分かるず思いたす。
ブラりザ操䜜をしおやっお欲しいタスクによっお䜿い分けが必芁です。

browser-use

  1. 䜕か調べ物をしお欲しいずき
  2. 最新の情報をずっおきお欲しいずき
  3. 倚少タスク操䜜に揺らぎがあっおも問題ないずき

workflow-use

  1. APIが提䟛されおないシステム業務向けや瀟内向けシステムなどをAI Agentで自動化したいずき
  2. レガシヌシステムなどでUIの倉曎が滅倚に発生しないずき
  3. AIに䜜業しお欲しいこず、クリックしお欲しいボタンやサむトなどが予め決たっおいるずき
  4. AIによる揺らぎを極限たで回避したいずき

䜿い方

前提

珟状OpenAIしかサポヌトしおないのです。
自分はAzure OpenAIを䜿うのでコヌドの修正が必芁です。

1. 環境構築

以䞋のリポゞトリにアクセスしお、git clone
https://github.com/browser-use/workflow-use


READMEの通りにコマンドを実行
https://github.com/browser-use/workflow-use/blob/main/README.md

2. Azure OpenAI仕様に倉曎

お䜿いの゚ディタでChatOpenAIで党䜓怜玢をかける


以䞋のような感じで、ChatOpenAI→AzureChatOpenAIに倉えたす。

cli.py
from langchain_openai import AzureChatOpenAI

from workflow_use.builder.service import BuilderService
from workflow_use.controller.service import WorkflowController
from workflow_use.recorder.service import RecordingService  # Added import
from workflow_use.workflow.service import Workflow

# Placeholder for recorder functionality
# from src.recorder.service import RecorderService

app = typer.Typer(
	name='workflow-cli',
	help='A CLI tool to create and run workflows.',
	add_completion=False,
	no_args_is_help=True,
)

# Default LLM instance to None
llm_instance = None
try:
	llm_instance = AzureChatOpenAI(
		openai_api_version="2024-10-21",
		azure_endpoint="<your azure openai endpoint>",
		azure_deployment="gpt-4.1",
		model="gpt-4.1",
		validate_base_url=False,
		api_key="<your aoai api key>"
	)


このたただず゚ラヌになっちゃうのでもう䞀個修正が必芁です。
workflow-use/workflow/service.pyのコヌドを䞀郚改修したす。

service.py
	async def _run_agent_step(self, step: AgenticWorkflowStep) -> AgentHistoryList | dict[str, Any]:
		"""Spin-up an Agent based on step dictionary."""
		if self.llm is None:
			raise ValueError("An 'llm' instance must be supplied for agent-based steps")

		task: str = step.task
		max_steps: int = step.max_steps or 5

		agent = Agent(
			task=task,
			llm=self.llm,
			browser=self.browser,
			browser_context=self.browser_context,
                    # ↓↓以䞋を远加 
			tool_calling_method="function_calling",
			use_vision=True,  # Consider making this configurable via WorkflowStep schema
		)
		return await agent.run(max_steps=max_steps)

3. 実際に詊す

今回は「Microsoftの最新のむベントに出垭登録」ずいうタスクでやっおみたす。
たずはワヌクフロヌを䜜成したす。

以䞋のコマンドを実行

python cli.py create-workflow


するずデフォルトブラりザのシヌクレットりィンドりが立ち䞊がりたす。


リンクを入力しお、登録ボタンをクリックしお新しいタブを立ち䞊げお、情報を入力したす。




登録ボタンを抌しお、AI゚ヌゞェントにやっお欲しいタスクを䞀通り再珟したらタヌミナルに戻っおctrl + cをクリック。
するず、ワヌクフロヌの登録をするための質問がいく぀かくるので適圓に入力。


以䞋のようなワヌクフロヌが䜜成されたした。

{
  "workflow_analysis": "This workflow automates the registration process for a Microsoft Virtual Training Event. It begins by navigating to the event listing page, then locates and clicks on a specific event registration link, taking the user to the registration form. The workflow proceeds to fill out the registration form fields such as first name, last name, email, phone number, job title, company name, country, and company size, and finally submits the form. Key dynamic inputs are the user's first name, last name, email, phone number, job title, company name, country, and company size, which must be provided for the automation to be reusable and flexible. Agentic steps are not required, as the form fields use stable selectors and all form values are directly determined by user input. Placeholder navigation and interaction steps (like excessive key presses and navigation refreshes) are condensed into streamlined deterministic actions for efficiency. All relevant values should be parameterized to allow the workflow's reuse for different registrants.",
  "name": "microsoft_virtual_training_event_registration",
  "description": "Automates registration for a Microsoft Dynamics 365 Virtual Training Day on the official Microsoft events site.",
  "version": "1.0",
  "steps": [
    {
      "description": "Navigate to the Microsoft Japan event listing page.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "navigation",
      "url": "https://www.microsoft.com/ja-jp/events/top/training-days?activetab=a1%3aprimaryr3"
    },
    {
      "description": "Click the registration link for the Microsoft Dynamics 365 Virtual Training Day event.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "click",
      "cssSelector": "a.cta[role*=\" \"][aria-label*=\"\u767b\u9332: 5 \u6708 26\u65e5\uff08\u6708\uff09\u30015 \u6708 27\u65e5\uff08\u706b\uff09...Microsoft Dynamics 365 Virtual Training Day: \u57fa\u790e(ERP)...\"]",
      "xpath": "id(\"tableV2Row-uida79j7n\")/td[3]/div[1]/div[1]/a[1]",
      "elementTag": "A",
      "elementText": "\u767b\u9332"
    },
    {
      "description": "Navigate to the specific event registration form.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "navigation",
      "url": "https://msevents.microsoft.com/event?id=1307512370"
    },
    {
      "description": "Fill in the first name field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"text\"][id=\"firstName\"]",
      "value": "{first_name}",
      "xpath": "id(\"firstName\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Fill in the last name field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"text\"][id=\"lastName\"]",
      "value": "{last_name}",
      "xpath": "id(\"lastName\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Fill in the email field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"email\"][id=\"email\"]",
      "value": "{email}",
      "xpath": "id(\"email\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Fill in the phone number field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"text\"][id=\"640735e1-9bbc-ea11-a812-000d3a321938\"]",
      "value": "{phone}",
      "xpath": "id(\"640735e1-9bbc-ea11-a812-000d3a321938\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Fill in the job title field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"text\"][id=\"d4ffb6df-1ef5-e911-a98d-000d3a30dc0a\"]",
      "value": "{job_title}",
      "xpath": "id(\"d4ffb6df-1ef5-e911-a98d-000d3a30dc0a\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Fill in the company name field.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "input.form-control[type=\"text\"][id=\"46165aee-289a-ea11-a811-000d3a5cec97\"]",
      "value": "{company_name}",
      "xpath": "id(\"46165aee-289a-ea11-a811-000d3a5cec97\")",
      "elementTag": "INPUT"
    },
    {
      "description": "Select the country from the dropdown.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "select.form-select[id=\"6ccc2d02-2b9a-ea11-a811-000d3a5cec97\"][aria-label=\"Country\"]",
      "value": "{country}",
      "xpath": "id(\"6ccc2d02-2b9a-ea11-a811-000d3a5cec97\")",
      "elementTag": "SELECT"
    },
    {
      "description": "Choose the company size from the dropdown.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "input",
      "cssSelector": "select.form-select[id=\"b9f74f51-4664-ef11-a671-000d3a355617\"][aria-label*=\"What best describes the size of your organization?\"]",
      "value": "{company_size}",
      "xpath": "id(\"b9f74f51-4664-ef11-a671-000d3a355617\")",
      "elementTag": "SELECT"
    },
    {
      "description": "Click the submit button to complete registration.",
      "output": null,
      "timestamp": null,
      "tabId": null,
      "type": "click",
      "cssSelector": "span",
      "xpath": "id(\"submitbtn\")/span[1]",
      "elementTag": "SPAN",
      "elementText": "\u767b\u9332\u3059\u308b"
    }
  ],
  "input_schema": [
    {
      "name": "first_name",
      "type": "string",
      "required": true
    },
    {
      "name": "last_name",
      "type": "string",
      "required": true
    },
    {
      "name": "email",
      "type": "string",
      "required": true
    },
    {
      "name": "phone",
      "type": "string",
      "required": true
    },
    {
      "name": "job_title",
      "type": "string",
      "required": true
    },
    {
      "name": "company_name",
      "type": "string",
      "required": true
    },
    {
      "name": "country",
      "type": "string",
      "required": true
    },
    {
      "name": "company_size",
      "type": "string",
      "required": true
    }
  ]
}


動かしおみたす。
以䞋のコマンドを実行

python cli.py run-workflow tmp/<your workflow>.workflow.json


するずフォヌムに入力する倀は倉数ずしお認識しおくれおいるのでナヌザヌに入力する倀を促しおきたす。


動画をアップできないんで、ほんの䞀郚になっちゃいたすが、自分の操䜜ず党く同じように凊理しおくれたした!

ヘッドりォヌタヌス

Discussion