はじめに
LLM (大規模言語モデル) をブラウザ操作エージェントから呼び出すとき、「どのミドルウェアを選ぶか」 で消費 token 数が劇的に変わります。
本稿では LangChain + Playwright MCP と Browser-use の 2 つのブラウザ自動化スタックを対象に、同一タスクで実際に発生した token 数を比較しました。
トークン使用量の比較:Playwright MCP vs Browser-use
テスト環境と測定方法
項目 | Playwright MCP | Browser-use |
---|---|---|
LLM | gemini-2.5-flash | gemini-2.5-flash |
token 計測方法 | LangSmith ダッシュボード | history.usage |
テストシナリオ
- youtubeでサンドイッチマンの漫才の動画を検索して動画を再生して
- yahoo.co.jpでニュース一覧を取得してTOP3のニュースの内容を調べて
- Amazonで2024年の話題の小説を検索して、レビュー評価が高い順に上位3冊を教えて
- 食べログで東京都内のラーメン店を検索して、評価の高い順にTOP3の店舗情報とレビューを教えて
- 楽天市場で「ワイヤレスイヤホン」を検索して、売れ筋ランキング上位3商品の価格とレビューを調べて
実測 token 数
テスト内容 | Playwright MCP | Browser-use |
---|---|---|
YouTube 動画再生 | 193,432 | 30,100 |
Yahoo ニュース TOP 3 | 287,521 | 21,102 |
Amazon TOP 3 | (quota error) 2,600,115 | 70,046 |
食べログ TOP 3 | 521,718 | 98,915 |
楽天イヤホン TOP 3 | 310,305 | 83,320 |
- Amazon TOP 3 : Playwright MCP はトークン上限に達してエラーとなった
ブラウザ操作の違い
Playwright MCP | Browser-use |
---|---|
![]() |
![]() |
Playwright MCP が大量のトークンを消費する理由
Playwright MCP のログは 「ページ全体の DOM スナップショット+付帯メタ情報」をほぼそのままテキスト化 しているため、Browser-use のログよりも必然的にトークン数(=LLM が扱うサブワード単位の総量)が桁違いに多くなるようだ。
下記のように Playwright と Browser-use のDOMの出力方法を比較する。
Playwright の出力
- Page URL: https://www.youtube.com/watch?v=r9B5VehoJ9E
- Page Title: 【広告無し】 サンドウィッチマン コント・漫才 「今年一番ウケたネタ大賞」「お笑い王者」 #4 - YouTube
- Page Snapshot
- generic [ref=e2]:
- generic:
- dialog
- generic [ref=e23]:
- banner [ref=e26]:
- generic [ref=e29]:
- generic [ref=e30]:
- button \"ガイド\" [ref=e32] [cursor=pointer]:
- generic [ref=e35] [cursor=pointer]:
- img
- generic [ref=e41]:
- link \"YouTube ホーム\" [ref=e42] [cursor=pointer]:
- /url: /
- generic [ref=e47] [cursor=pointer]:
- img
- generic [ref=e60]: JP
- button \"ナビゲーションをスキップ\" [ref=e64] [cursor=pointer]:
- generic [ref=e66] [cursor=pointer]: ナビゲーションをスキップ
- generic [ref=e72]:
- search [ref=e73]:
- generic [ref=e74]:
- combobox \"検索\" [expanded] [ref=e76]: サンドイッチマンの漫才
- button \"検索クエリをクリア\" [ref=e1735] [cursor=pointer]:
- generic [ref=e1738] [cursor=pointer]:
- img
- button \"Search\" [ref=e77] [cursor=pointer]:
- generic [ref=e80] [cursor=pointer]:
- img
- generic [ref=e84]:
- button \"音声で検索\" [ref=e86] [cursor=pointer]:
- generic [ref=e1759] [cursor=pointer]:
- img
- tooltip \"tooltip\"
- generic [ref=e95]:
- button \"設定\" [ref=e100] [cursor=pointer]:
- generic [ref=e1762] [cursor=pointer]:
- img
- link \"ログイン\" [ref=e108] [cursor=pointer]:
- /url: https://accounts.google.com/ServiceLogin?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Dja%26next%3D%252Fwatch%253Fv%253Dr9B5VehoJ9E%2526pp%253DygUh44K144Oz44OJ44Kk44OD44OB44Oe44Oz44Gu5ryr5omN&hl=ja&ec=65620
- generic [ref=e1766] [cursor=pointer]:
- img
- generic [ref=e112] [cursor=pointer]: ログイン
<<<以下省略>>>
Browser-use の出力
[Start of page]
[0]<ytd-masthead role=banner>戻る
JP
ナビゲーションをスキップ
検索 />
[1]<yt-icon-button />
[2]<button aria-label=ガイド />
[3]<yt-icon />
[4]<span />
[5]<a title=YouTube ホーム />
[6]<div />
[7]<ytd-logo />
[8]<yt-icon />
[9]<span />
[10]<div />
[11]<input name=search_query aria-expanded=true type=text role=combobox placeholder=検索 />
[12]<button aria-label=検索クエリをクリア />
[13]<div />
[14]<button aria-label=Search title=検索 />
[15]<yt-icon />
[16]<span />
[17]<ytd-button-renderer >音声で検索 />
[18]<button aria-label=音声で検索 />
[19]<div />
[20]<ytd-topbar-menu-button-renderer />
[21]<a />
[22]<yt-icon-button />
[23]<button aria-label=設定 />
[24]<yt-icon />
[25]<span />
[26]<ytd-button-renderer />
[27]<a >ログイン />
<<<以下省略>>>
DOM 情報の構造化とトークン数への影響
Browser-use がDOM情報を極力圧縮していることが確認できる。Browser-use はDOM情報の前に毎回長大なプロンプトを付加してLLMに情報を送っているが、DOM情報の大きさがその差を逆転してしまうため、Playwright が消費する token が大きくなると推察される。
項目 | Playwright MCP | Browser-use |
---|---|---|
取得範囲 | ページ全 DOM(shadow-DOM 含む)を逐次 YAML 風ツリーで保存 | 可視ビュー + クリック可能要素のみを番号付きリストで保存 |
含まれる属性 |
role , aria-label , title , ref , cursor , expanded など多数 |
type , text など最小限 |
階層表現 | インデントで深さをそのまま保持(ネストが深いほど行数増) | 1 要素 1 行で完結 |
重複データ | 同一画像やリンクでもノードごとに繰り返し記録 | インデックス管理なので重複ほぼなし |
結果: 同じページでも Playwright MCP は数千〜数万行、Browser-use は数百行で済む
ソースコード (抜粋) と token 集計方法
Langchain + Playwright MCP
LangSmith で token 数を取得
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.tools import load_mcp_tools
from langgraph.prebuilt import create_react_agent
# Playwright MCPサーバーの設定
# npxコマンドを使用して@playwright/mcpパッケージを実行
client = MultiServerMCPClient(
{
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
],
"transport": "stdio",
}
}
)
async def run_agent():
"""
セッション管理を使用してエージェントを実行する関数
"""
# セッションを使用してMCPクライアントとの接続を管理
async with client.session("playwright") as session:
# セッションからツールを読み込み
tools = await load_mcp_tools(session)
# ReAct エージェントを作成(Google Geminiモデルを使用)
agent = create_react_agent("google_genai:gemini-2.5-flash", tools)
# YouTubeでサンドイッチマンの漫才動画を検索・再生するタスクを実行
response = await agent.ainvoke(
{"messages": [{"role": "user", "content": "youtubeでサンドイッチマンの漫才の動画を検索して動画を再生して"}]}
)
# レスポンスメッセージの内容を出力
print("Agent response:", response["messages"][-1].content)
if __name__ == "__main__":
# メイン実行部:非同期関数を実行
asyncio.run(run_agent())
Browser-use
Browser-use の history.usage
から token 数を取得
import asyncio
from browser_use import Agent
from browser_use.browser import BrowserProfile
from browser_use.llm import ChatGoogle
async def main():
# より簡単なタスクでテスト
task = "youtubeでサンドイッチマンの漫才の動画を検索して動画を再生して"
llm = ChatGoogle(
model="gemini-2.5-flash", # より安価なモデル
temperature=0.1,
)
# ブラウザプロファイルでwindowサイズを指定
browser_profile = BrowserProfile(
window_size={'width': 1280, 'height': 720}, # HD解像度
headless=False, # ブラウザを表示する
viewport={'width': 1280, 'height': 720}, # コンテンツエリアのサイズ
# no_viewport=True, # viewportを無効にする場合
)
# エージェント作成(タイムアウト設定とブラウザプロファイル指定)
agent = Agent(
task=task,
llm=llm,
browser_profile=browser_profile, # ブラウザプロファイルを指定
max_time=60, # 60秒でタイムアウト
max_steps=5, # 最大5ステップ
)
print(f"🚀 Starting task: {task}")
print(f"🤖 Using model: {llm.model}")
print(f"📐 Window size: {browser_profile.window_size}")
print("⏱️ Max time: 60 seconds, Max steps: 5")
try:
# エージェント実行
history = await agent.run()
print(f"✅ Task completed! Steps taken: {len(history.history)}")
# トークン使用量を表示
if history.usage:
print(f"💰 Token usage: {history.usage}")
# 最終結果を表示
if history.final_result():
print(f"📋 Final result: {history.final_result()}")
except Exception as e:
print(f"❌ Error occurred: {e}")
print("This might be normal if the task completed successfully")
if __name__ == '__main__':
print('🌐 Browser-use Basic Example')
print('=' * 30)
asyncio.run(main())
まとめ
今回の比較により、同じタスクを実行してもミドルウェアの選択によってトークン使用量が大きく異なることがわかりました。特に Playwright MCP は DOM 全体を詳細に渡って出力するため、モデルの処理コストが高騰する傾向があります。
一方、Browser-use は DOM 情報を圧縮し、トークン消費を抑える設計になっており、実運用でのコスト最適化が期待できます。エージェント設計時には、必要な精度とトークンコストのバランスを慎重に見極めることが重要です。