Для оснащения Python AI-агента возможностью работать с веб-браузером (навигация, авторизация, заполнение форм, анализ контента) существуют четыре принципиально различных класса решений, различающихся по степени интеллектуальности, стоимости и сложности интеграции. Выбор конкретного подхода определяется тремя факторами: характером решаемых задач, допустимым бюджетом и глубиной контроля над процессом.
Наиболее перспективным направлением в 2025–2026 годах стал Model Context Protocol (MCP) — открытый стандарт от Anthropic, представленный в ноябре 2024 года, который стремительно превращается в де-факто шину подключения внешних инструментов к AI-агентам.
Статистика экосистемы MCP:
- 97+ млн ежемесячных загрузок MCP SDK
- 10 000+ опубликованных MCP-серверов (оценка на начало 2026)
- Официальные серверы от Notion, Linear, Figma, Stripe, Microsoft
Практическая рекомендация для большинства сценариев:
@playwright/mcp сервером.Все существующие решения группируются в три архитектурных слоя. Понимание этой иерархии критично для осознанного выбора.
┌─────────────────────────────────┐
│ Уровень 3: Интенциональный │
│ "Что сделать?" │
│ • browser-use │
│ • Skyvern │
├─────────────────────────────────┤
│ Уровень 2: Семантический │
│ "Что на странице?" │
│ • Дерево доступности (a11y tree)│
│ • @playwright/mcp │
├─────────────────────────────────┤
│ Уровень 1: Исполнительный │
│ "Как кликнуть?" │
│ • Playwright / Puppeteer / Selenium │
└─────────────────────────────────┘
Библиотеки, напрямую управляющие браузером через Chrome DevTools Protocol (CDP) или WebDriver. Агент самостоятельно определяет последовательность действий.
| Инструмент | Ключевое преимущество | Ограничение для AI |
|---|---|---|
| Playwright | Авто-ожидания, кроссбраузерность, трассировка | Нет встроенной логики принятия решений |
| Selenium | Зрелость, сообщество, корпоративные интеграции | Многословность, хрупкость к динамическому DOM |
| Puppeteer | Глубокая интеграция с Chrome | Ориентирован на Node.js, Python-порты фрагментированы |
Промежуточная абстракция, заменяющая сырой DOM или скриншоты деревом доступности (accessibility tree). Это структурированное представление содержит:
button, textbox, heading)focused, disabled, expanded)Почему это важно для LLM: модель получает 1–50 КБ структурированного текста вместо мегабайт пикселей или неструктурированного HTML. Это радикально снижает стоимость инференса и повышает стабильность парсинга.
Эталонная реализация: сервер
@playwright/mcpот Microsoft, который транслирует возможности Playwright в MCP-инструменты, используя accessibility tree как основной формат представления страницы.
Высокоуровневые системы, принимающие описание задачи на естественном языке и самостоятельно декомпозирующие её в последовательность действий.
| Решение | Тип | Ключевая фича |
|---|---|---|
| browser-use | Open-source + Cloud | Цикл «наблюдение → размышление → действие» из коробки |
| Skyvern | Hybrid (OSS core + managed) | Визуальное позиционирование на уровне пикселей |
| AIME Browser-Use | Fork | Оптимизированная версия для специфичных сценариев |
MCP как транспорт: Протокол Model Context Protocol служит стандартизированным механизмом вызова инструментов между любым из этих уровней и агентом, независимо от языка реализации сервера (Python, Go, Node.js).
┌─────────────────────────────────────────────────────────────┐
│ Ваш Python AI-агент │
│ (LangChain / LangGraph / Custom Loop) │
└───────────────────────┬─────────────────────────────────────┘
│ MCP Client SDK (mcp-python)
▼
┌─────────────────────────────────────────────────────────────┐
│ MCP-сервер (browser-related) │
│ │
│ ▶ Вариант A: @playwright/mcp ──► Playwright ──► CDP │
│ ▶ Вариант B: community/mcp-browser-use │
│ ▶ Вариант C: Кастомный сервер (Skyvern / browser-use API) │
└───────────────────────┬─────────────────────────────────────┘
│ CDP / HTTP / Unix socket
▼
┌─────────────────────────────────────────────────────────────┐
│ Браузер (Chromium / Firefox / WebKit) │
│ Запуск: локально, в Docker или облачный хостинг │
└─────────────────────────────────────────────────────────────┘
Accessibility tree (дерево доступности, сокращённо a11y tree) — это внутреннее представление веб-страницы, которое браузер создаёт на основе DOM для передачи семантической информации вспомогательным технологиям (скринридерам, переключателям, голосовому управлению).
a11y = abbreviation для "accessibility" (буква "a" + 11 букв + буква "y")
Архитектурное место в браузере
┌─────────────────┐
│ HTML-код │
└────────┬────────┘
▼
┌─────────────────┐
│ DOM Tree │ ← Все элементы, атрибуты, текст
│ (полный) │
└────────┬────────┘
▼
┌─────────────────┐
│ Accessibility │ ← Только семантически значимые
│ Tree (a11y) │ элементы с ролями, состояниями, именами
└────────┬────────┘
▼
┌─────────────────┐
│ Platform APIs │ ← Windows UIA, macOS AXAPI, Linux AT-SPI
│ (OS-specific) │
└────────┬────────┘
▼
┌─────────────────┐
│ Assistive Tech │ ← NVDA, VoiceOver, TalkBack, JAWS
└─────────────────┘
Браузеры преобразуют разметку во внутреннее представление — DOM-дерево, а затем создают на его основе accessibility tree, который используется платформенными Accessibility API для предоставления представления, понятного вспомогательным технологиям.
Каждый объект в дереве доступности содержит четыре ключевых свойства:
| Свойство | Описание | Пример |
|---|---|---|
name |
Как можно обратиться к этому элементу? | "Отправить", "Поиск по сайту" |
role |
Какова роль элемента? | button, textbox, navigation, heading |
state |
Какое текущее состояние? | checked, disabled, expanded, focused |
description |
Дополнительное описание (опционально) | "Таблица с результатами поиска за 2025 год" |
{
"role": "button",
"name": "Войти",
"state": {
"enabled": true,
"focused": false
},
"description": "Авторизация в аккаунте"
}
Дополнительно дерево может содержать информацию о возможных действиях: ссылку можно перейти, текстовое поле — заполнить, чекбокс — переключить [[5]].
Шаг 1: Парсинг HTML → DOM
Браузер парсит HTML и строит полное дерево всех узлов, включая декоративные <div>, <span>, стили и скрипты.
Шаг 2: Фильтрация и обогащение → a11y tree
Браузер применяет алгоритмы для создания accessibility tree:
// Псевдокод процесса
function buildAccessibilityTree(domNode) {
// 1. Пропускаем невидимые элементы
if (!isVisible(domNode) || domNode.ariaHidden) return null;
// 2. Определяем роль (явную или неявную)
const role = domNode.getAttribute('role')
|| inferImplicitRole(domNode.tagName);
// 3. Вычисляем доступное имя (Accessible Name Computation)
const name = computeAccessibleName(domNode); // из aria-label, textContent, alt и т.д.
// 4. Собираем состояния
const states = {
checked: domNode.checked,
disabled: domNode.disabled,
expanded: domNode.getAttribute('aria-expanded') === 'true',
// ...
};
// 5. Рекурсивно обрабатываем детей
const children = domNode.children
.map(child => buildAccessibilityTree(child))
.filter(node => node !== null);
return { role, name, states, children };
}
Шаг 3: Экспорт через платформенные API
Дерево передаётся в ОС через специализированные API:
| Критерий | Сырой DOM / HTML | Accessibility Tree |
|---|---|---|
| Объём данных | 500 КБ – 5 МБ | 1–50 КБ |
| Семантика | Требует парсинга и интерпретации | Явные role, name, state |
| Устойчивость к изменениям | Хрупкие CSS/XPath селекторы | Стабильные семантические идентификаторы |
| Токены для LLM | Дорого, много шума | Дёшево, только сигнал |
| Понимание intent | Модель должна «догадываться» | Явные действия: click, type, select |
Ключевой инсайт: Accessibility tree — это тот же структурированный интерфейс, который используют скринридеры. Вместо хрупких CSS-селекторов вы таргетируете элементы по их семантическим ролям и именам.
Через DOM (упрощённо):
<div class="auth-form"><div class="field-wrapper"><input id="i1" class="form-control" ...></div>...</div>
→ LLM должна парсить классы, угадывать назначение поля.
Через a11y tree:
[1] textbox "Email" | required=True | focused=False
[2] textbox "Password" | required=True | type="password"
[3] button "Войти" | enabled=True
→ LLM сразу понимает: «это форма входа, нужно заполнить поля 1 и 2, затем кликнуть 3».
from playwright.async_api import async_playwright
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://example.com/login")
# Получение snapshot accessibility tree
snapshot = await page.accessibility.snapshot()
# Рекурсивный обход для поиска элемента
def find_element(node, role=None, name=None):
if (role is None or node.get("role") == role) and \
(name is None or node.get("name") == name):
return node
for child in node.get("children", []):
result = find_element(child, role, name)
if result:
return result
return None
email_field = find_element(role="textbox", name="Email")
print(f"Нашел поле: {email_field}")
# Используя библиотеку `cdp` или `pycdp`
from cdp import Page, Accessibility
# Включение accessibility domain
await cdp.send(Accessibility.enable())
# Получение полного дерева
ax_tree = await cdp.send(Accessibility.get_full_ax_tree())
# Пример узла:
# {
# "nodeId": "AX123",
# "role": {"value": "button"},
# "name": {"value": "Submit"},
# "state": {"enabled": True},
# "bounds": {"x": 100, "y": 200, "width": 80, "height": 30}
# }
// Конфигурация MCP-клиента
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp"]
}
}
}
# Агент вызывает инструмент через MCP
result = await mcp_client.call_tool(
"playwright_get_accessibility_tree",
{"simplify": True} # Упрощённый формат для LLM
)
# Возвращает компактное представление:
# [1] link "Главная" | href="/"
# [2] button "Меню" | expanded=False
# [3] textbox "Поиск" | placeholder="Введите запрос..."
Playwright MCP позволяет LLM взаимодействовать с веб-страницами, используя данные accessibility tree, устраняя необходимость в дорогих vision-моделях.
- Старый HTML: <button class="btn-primary">Login</button>
+ Новый HTML: <div role="button" aria-label="Войти в систему"></div>
# CSS-селектор ".btn-primary" сломается
# Но a11y-запрос role="button" + name~="войти" продолжит работать
Accessibility semantics становятся основой надёжной AI-автоматизации: MCP-подход неявно поощряет приложения с правильной семантикой.
aria-hidden="true" или display: none исключаются<div>, <span> без семантики не включаютсяРешение: Добавляйте семантику через ARIA:
<!-- Плохо: декоративный div, невидимый для a11y -->
<div onclick="submitForm()">Отправить</div>
<!-- Хорошо: явная роль и имя -->
<div role="button"
tabindex="0"
aria-label="Отправить форму"
onclick="submitForm()">
Отправить
</div>
Accessibility — это вопрос, сильно зависящий от платформы. Разные браузеры и ОС могут представлять дерево немного по-разному.
Рекомендация: Тестируйте на целевой платформе (Chromium + Linux для серверных агентов).
a11y tree обновляется асинхронно. После AJAX-запросов или анимаций может потребоваться явная синхронизация:
# Playwright: дождаться обновления a11y tree
await page.wait_for_load_state("networkidle")
snapshot = await page.accessibility.snapshot()
| Задача | a11y tree подходит? | Рекомендация |
|---|---|---|
| Навигация по странице | ✅ Отлично | Используйте get_by_role() / get_by_label() |
| Заполнение форм, клики | ✅ Отлично | Используйте семантические локаторы Playwright |
| Извлечение статьи/блога | ⚠️ Частично | Лучше Readability / Firecrawl |
| Парсинг каталога товаров | ⚠️ Частично | Комбинация: семантические локаторы + DOM |
| Чтение документации | ❌ Неоптимально | Markdown-конвертеры |
Вывод: Accessibility tree не теряет весь контент, но он оптимизирован для навигации и взаимодействия, а не для извлечения текста. Для контентных задач нужны другие инструменты.
| Тип контента | Пример | Как выглядит в a11y tree |
|---|---|---|
| Заголовки | <h1>, <h2>, <h3> |
role="heading", name="Заголовок статьи", level=1 |
| Ссылки | <a href="...">Текст</a> |
role="link", name="Текст ссылки" |
| Кнопки | <button>Отправить</button> |
role="button", name="Отправить" |
| Формы | <input>, <label> |
role="textbox", name="Email" |
| Семантические регионы | <nav>, <main>, <article> |
role="navigation", role="main" |
| Текст с ARIA-метками | <div aria-label="Описание"> |
name="Описание" |
| Альтернативный текст изображений | <img alt="..."> |
role="img", name="alt-текст" |
| Тип контента | Почему теряется | Пример |
|---|---|---|
| Параграфы без семантики | <p> вне регионов/без ARIA может быть отфильтрован |
Основной текст статьи |
| Декоративный текст | Считается незначимым для скринридеров | <span class="icon-text"> |
| Текст в кастомных виджетах | Компоненты без ARIA-атрибутов | <div class="custom-card"> |
| Таблицы данных | Упрощаются, если нет role="table" или заголовков |
<table> без семантики |
| Списки без контекста | Могут быть свёрнуты, если не в регионе | <ul><li>...</li></ul> |
| Текст внутри canvas/SVG | Не попадает в a11y tree без явных ARIA-описаний | Инфографика, диаграммы |
⚠️ Важно: Поведение accessibility tree зависит от браузера (Chromium/Firefox/WebKit) и платформы. То, что видно в Chromium, может отличаться в Firefox.
Практический пример: сравнение объёма данных - Страница: новостная статья (примерные цифры)
| Источник | Объём | Что включено |
|---|---|---|
| Сырой HTML | ~150 КБ | Всё, включая стили, скрипты, мета-теги |
| DOM textContent | ~25 КБ | Весь видимый текст |
| Accessibility tree | ~8 КБ | Заголовки, ссылки, кнопки, семантические регионы |
| Readability (article) | ~12 КБ | Основной текст статьи + метаданные |
| Firecrawl Markdown | ~10 КБ | Чистый контент, оптимизированный для LLM |
Вывод: a11y tree может потерять значительную часть текстового контента по сравнению с методами извлечения статей. Точная цифра зависит от структуры страницы.
# ✅ Playwright с семантическими локаторами — идеальный выбор
# Примечание: accessibility.snapshot() deprecated, используйте get_by_role()
from playwright.async_api import async_playwright
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://example.com/login")
# Находим элементы по ARIA-роли и имени — устойчиво к изменениям вёрстки
email_field = page.get_by_role("textbox", name="Email")
await email_field.fill("user@example.com")
submit_btn = page.get_by_role("button", name="Войти")
await submit_btn.click()
Почему семантические локаторы: устойчивы к изменениям вёрстки, компактные селекторы, точная семантика.
⚠️ Важно:
page.accessibility.snapshot()deprecated в Playwright. Для тестирования доступности используйте Axe или аналогичные инструменты. Для навигации агента используйтеget_by_role(),get_by_label(),get_by_text().
from readability import Document
import requests
def extract_article_python(url: str) -> dict:
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
doc = Document(response.text)
return {
"title": doc.title(),
"content": doc.summary(), # HTML-контент статьи
"text_content": doc.text_content(), # Только текст
"short_title": doc.short_title()
}
# Использование
# result = extract_article_python("https://example.com/article")
# print(result["text_content"])
Почему не a11y tree: потеряете параграфы, цитаты, детали контента, не связанные с интерактивными элементами.
# =============================================================================
# HybridAgent: Playwright для навигации + python-readability для контента
# =============================================================================
# Установка зависимостей:
# pip install playwright python-readability lxml html_text requests
# playwright install chromium
from playwright.async_api import Page, async_playwright
from readability import Document
from typing import Optional
class HybridAgent:
"""
Агент для навигации по сайту и извлечения основного контента.
- Навигация: семантические локаторы Playwright (устойчивы к изменениям вёрстки)
- Извлечение контента: python-readability (чистый Python, без JS-инъекций)
"""
def __init__(self, page: Page):
self.page = page
async def navigate_by_goal(self, goal: str) -> bool:
"""
Простая навигация по семантическим локаторам.
В продакшене здесь может быть LLM-планировщик.
"""
# Пример: если в goal есть "статья", ищем ссылку "Статьи" или "Блог"
keywords = {
"статья": ["Статьи", "Блог", "Articles", "Blog"],
"документация": ["Документация", "Docs", "Documentation"],
"товар": ["Каталог", "Товары", "Products", "Shop"],
}
for category, labels in keywords.items():
if category in goal.lower():
for label in labels:
link = self.page.get_by_role("link", name=label)
if await link.count() > 0:
await link.first.click()
await self.page.wait_for_load_state("networkidle")
return True
return False
async def extract_content_python(self) -> dict:
"""
Извлекает основной контент страницы через python-readability.
Работает с текущим состоянием DOM (после навигации/динамической подгрузки).
"""
# Получаем HTML текущего состояния страницы (после JS-рендеринга)
html = await self.page.content()
# Парсим через python-readability (чистый Python, без JS)
doc = Document(html)
return {
"title": doc.title(),
"summary_html": doc.summary(), # Очищенный HTML статьи
"text_content": doc.text_content(), # Только текст, без разметки
"short_title": doc.short_title(),
"author": getattr(doc, "author", None), # если доступно
}
async def navigate_and_extract(self, goal: str) -> dict:
"""
Полный пайплайн: навигация → извлечение контента.
"""
# Шаг 1: Навигация по семантическим локаторам
await self.navigate_by_goal(goal)
# Шаг 2: Небольшая задержка для полной подгрузки динамического контента
await self.page.wait_for_timeout(500) # 500ms, при необходимости увеличить
# Шаг 3: Извлечение контента через python-readability
content = await self.extract_content_python()
# Fallback: если Readability не смог выделить контент, берём весь текст
if not content["text_content"] or len(content["text_content"].strip()) < 100:
content["text_content"] = await self.page.evaluate(
"() => document.body.innerText"
)
content["fallback_used"] = True
else:
content["fallback_used"] = False
return content
# =============================================================================
# Пример использования
# =============================================================================
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://example.com")
agent = HybridAgent(page)
result = await agent.navigate_and_extract("найти статью про ИИ")
print(f"Заголовок: {result['title']}")
print(f"Текст (первые 500 символов): {result['text_content'][:500]}...")
print(f"Использован fallback: {result['fallback_used']}")
await browser.close()
# Запуск:
# import asyncio
# asyncio.run(main())
Почему гибрид: лучшее из обоих миров — устойчивая навигация + полный контент.
📋 Сравнительная таблица методов извлечения
| Метод | Для навигации | Для контента | Объём данных | Устойчивость | Стоимость |
|---|---|---|---|---|---|
| Семантические локаторы (Playwright) | ✅ Отлично | ⚠️ Частично | Низкий | ✅ Высокая | Низкая |
| DOM textContent | ⚠️ Средне | ✅ Хорошо | Средний (10–100 КБ) | ⚠️ Средняя | Низкая |
| Readability.js | ❌ Нет | ✅ Отлично | Средний (5–50 КБ) | ✅ Высокая | Низкая |
| Firecrawl API | ❌ Нет | ✅ Отлично | Низкий (5–30 КБ) | ✅ Высокая | $$ |
| Скриншот + Vision | ✅ Хорошо | ✅ Хорошо | Высокий (изображение) | ✅ Высокая | \($\)$ |
| Сырой HTML | ⚠️ Средне | ✅ Хорошо | Высокий (100 КБ–5 МБ) | ❌ Низкая | $$ |
Используйте семантические локаторы Playwright, когда:
Используйте Readability / Firecrawl, когда:
Используйте гибридный подход, когда:
Практический чеклист
┌─────────────────────────────────────────────────────────┐
│ Что вы хотите сделать с страницей? │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Только чтение Только клики/формы И то, и другое
│ │ │
▼ ▼ ▼
Firecrawl / get_by_role() + Гибридный подход:
Readability Playwright MCP • локаторы для навигации
• Readability для контента
Accessibility tree не теряет «весь» контент, но он теряет значительную часть текстового содержимого, которое не связано с интерактивными элементами или семантической структурой.
Для AI-агентов оптимальная стратегия:
get_by_role(), get_by_label())chrome://accessibilitynpx playwright codegen --save-trace example.zip example.com
# Trace viewer покажет a11y snapshot для каждого шага
Дополнительные ресурсы про Accessibility tree
| Ресурс | Описание |
|---|---|
| MDN: Accessibility tree | Официальная документация, свойства узлов |
| web.dev: The Accessibility Tree | Глубокое объяснение процесса построения |
| Playwright Accessibility API | Программный доступ к a11y tree |
| ARIA Authoring Practices | Как правильно добавлять семантику |
| Fazm: Accessibility Tree vs DOM | Сравнение для AI-агентов |
Сайт: playwright.dev
Лицензия: Apache 2.0
Python-пакет: pip install playwright
Статус: Стабильный продакшен, активная разработка под эгидой Microsoft
✅ Кроссбраузерность из единого API
Единый интерфейс для Chromium, Firefox и WebKit. Для AI-агентов это критично: ряд сайтов рендерит контент по-разному в зависимости от движка, и возможность проверить отображение во всех трёх повышает надёжность парсинга.
✅ Автоматическое ожидание готовности элементов
Playwright автоматически дожидается:
# Пример: не нужно писать явные ожидания
await page.click("#submit-btn") # Playwright сам дождётся, когда кнопка станет кликабельной
Это радикально снижает количество StaleElementReferenceException и нестабильных сценариев по сравнению с Selenium.
✅ Трассировка и наблюдаемость
Встроенный механизм записи:
Незаменимо для отладки падающих агентских сценариев и аудита действий в процессах, связанных с безопасностью.
| ✅ Гибкие режимы выполнения | Режим | Использование |
|---|---|---|
headless |
Продакшен, фоновое выполнение | |
headed |
Отладка, визуальная верификация | |
connect_over_cdp |
Подключение к уже запущенному Chrome (через --remote-debugging-port) |
✅ Codegen
Утилита playwright codegen записывает действия в браузере и генерирует код на Python/JS. Полезна для быстрого создания тестовых скриптов и прототипов.
⚠️ Нет встроенной логики принятия решений
Playwright — это «двигатель без руля». Агент несёт полную ответственность за определение следующего действия на каждом шаге. Это осознанный компромисс: максимальный контроль ценой необходимости самостоятельного построения цикла работы агента.
⚠️ Python-привязка
Исторически немного отстаёт от JS/TS версии по скорости добавления новых функций, хотя разрыв значительно сокращён усилиями Microsoft.
Документация: playwright.dev/docs/getting-started-mcp
Публикация: Официальный пакет Microsoft, активная поддержка
| Подход | Что получает модель | Проблемы |
|---|---|---|
| Сырой HTML/DOM | Мегабайты неструктурированного текста | Огромный контекст, хрупкие селекторы |
| Скриншот + Vision | Пиксели, требует multimodal-модели | Дорого, медленно, сложно парсить текст |
| Accessibility tree ✅ | 1–50 КБ структурированных семантических данных | Меньше шума, больше сигнала |
Пример представления элемента в accessibility tree:
[button] "Отправить" | role=button | focused=False | disabled=False | aria-label=None
После подключения сервера агент получает стандартный набор инструментов:
{
"tools": [
{"name": "playwright_navigate", "description": "Перейти по URL"},
{"name": "playwright_click", "description": "Клик по элементу (селектор или a11y-описание)"},
{"name": "playwright_fill", "description": "Ввод текста в поле"},
{"name": "playwright_select_option", "description": "Выбор значения в <select>"},
{"name": "playwright_evaluate", "description": "Выполнение произвольного JS в контексте страницы"},
{"name": "playwright_screenshot", "description": "Получение скриншота (base64)"},
{"name": "playwright_get_accessibility_tree", "description": "Получение снапшота a11y tree"}
]
}
| Способ | Команда / Конфиг | Когда использовать |
|---|---|---|
| Локальный | npx @playwright/mcp |
Прототипирование, локальная разработка |
| Docker | Официальный образ mcr.microsoft.com/playwright/mcp |
CI/CD, изолированная среда |
| Удалённый (TCP) | Подключение по ws://host:port |
Микросервисная архитектура, масштабирование |
Пример конфигурации для MCP-клиента:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp"],
"env": {
"PLAYWRIGHT_BROWSERS_PATH": "/opt/browsers"
}
}
}
}
GitHub: github.com/browser-use/browser-use
Лицензия: MIT
Финансирование: $17 млн, раунд Seed, март 2025 [^techcrunch]
Натуральный язык - запрос пользователя
│
▼
┌─────────────────┐
│ LLM (GPT-4o / │
│ Claude / Ollama)│
└────────┬────────┘
│ План действий (JSON Schema)
▼
┌─────────────────┐
│ Контроллер │
│ • Машина состояний │
│ • История шагов │
│ • Обработка ошибок│
└────────┬────────┘
│ Команды Playwright
▼
┌─────────────────┐
│ Playwright + │
│ Chromium │
└─────────────────┘
✅ Цикл «наблюдение → размышление → действие» из коробки
Библиотека реализует полноценный агентский паттерн с управлением историей состояний для восстановления после ошибок.
✅ Структурированный вывод
Использует Pydantic-схемы для гарантии parseable ответов модели, что критично для надёжного выполнения действий.
✅ Встроенные решения для продакшена (премиум-версия)
| Режим | Требования | Когда использовать |
|---|---|---|
| Полностью локальный | Playwright + Ollama, GPU 16+ ГБ VRAM | Приватные данные, нулевые облачные расходы |
| Гибридный | Локальная библиотека + коммерческий LLM API (OpenAI/Anthropic) | Баланс контроля и качества |
| Облачный | Только API-ключ, нулевая локальная настройка | Быстрый старт, команды без MLOps |
⚠️ Методологическое примечание: Результаты приведены согласно Steel.dev Leaderboard на февраль 2026. Организации используют разные подмножества датасета WebVoyager, разные evaluator'ы (GPT-4V judge vs собственные) и некоторые результаты являются самоотчётными. Прямое сравнение чисел требует учёта этих различий.
| Агент | WebVoyager Score | Тип | Примечания |
|---|---|---|---|
| Browser Use (официальный) | 89.1% | Open-source | Основная эталонная реализация, полный датасет |
| AIME Browser-Use | 92.34% | Fork | Отдельная оптимизированная версия |
⚠️ Меньше контроля над промежуточными шагами
Если требуется тонкая настройка логики на каждом этапе взаимодействия, browser-use добавляет контрпродуктивный слой абстракции. Библиотека ориентирована на сквозную автоматизацию, а не на программное взаимодействие с детализацией.
⚠️ Вендор-лок и расходы
Облачный вариант несёт риски vendor lock-in и регулярные расходы, пропорциональные объёму задач.
from browser_use import Browser, BrowserConfig, BrowserAgent
from langchain_openai import ChatOpenAI
# Инициализация
llm = ChatOpenAI(model="gpt-4o", temperature=0)
browser = Browser(config=BrowserConfig(headless=True))
# Создание и запуск агента
agent = BrowserAgent(
task="Найди самый дешёвый RTX 5090 на маркетплейсе и сохрани ссылку в файл",
llm=llm,
browser=browser
)
result = await agent.run()
print(f"Результат: {result}")
GitHub: github.com/skyvern-ai/skyvern
Сайт: skyvern.com
Лицензия: Проприетарное ядро + компоненты с открытым кодом (Apache 2.0)
🔹 Визуальное позиционирование
Мультимодальная модель анализирует страницу на уровне пикселей, находит элементы по пространственным координатам. Это позволяет адаптироваться к изменениям вёрстки без зависимости от CSS-селекторов.
🔹 Движок бизнес-процессов
Декларативное определение длинных рабочих процессов, включая:
🔹 API-first подход
Все операции доступны через REST endpoints, Python SDK предоставляет удобную обёртку.
🔹 Инфраструктурная интеграция
Примечание: Цифры приведены для контекста. Для Skyvern в официальном README указывается результат 64.4% на датасете WebBench [^skyvern-readme]. Результат 85.85% на WebVoyager заявлен для версии 2.0, но методология может отличаться от эталонной.
| Датасет | Результат | Комментарий |
|---|---|---|
| WebVoyager (заявлено) | 85.85% | Полный набор, методология может варьироваться |
| WebBench (официально) | 64.4% | Другой датасет, другая методология оценки |
| Вариант | Требования | Когда выбирать |
|---|---|---|
| Self-hosted | GPU-сервер (NVIDIA RTX 3090+ / A100), Docker, Kubernetes | Полный контроль, приватные данные, масштабирование |
| Managed Cloud | Только API-ключ, оплата по использованию | Команды без MLOps, быстрый старт, предсказуемые расходы |
⚠️ Практическое ограничение: Самостоятельное развёртывание связано со значительной операционной сложностью. Команды без выделенных MLOps-ресурсов столкнутся с нетривиальной нагрузкой на настройку и поддержку.
Сайт: selenium.dev
История: Основан в 2004 году [^selenium-history]; в 2025 году проект отметил 20 лет развития
Текущая версия: Selenium 4.x (соответствует W3C WebDriver)
✅ Массивное сообщество и архив знаний
Практически любую проблему можно решить с помощью тредов на StackOverflow десятилетней давности. Инженеры, впервые работающие с Selenium-проектами, найдут ответы быстрее, чем для любых альтернатив.
✅ Корпоративные интеграции
SAP, Oracle EBS, Salesforce и старые ERP-системы часто имеют протестированные Selenium UI automation workflows, документированные SOP и сложившиеся центры компетенций.
✅ Grid-архитектура
Selenium Grid обеспечивает распределённое выполнение тестов на нескольких машинах/датацентрах — зрелый, проверенный в бою паттерн горизонтального масштабирования, недоступный нативно в Playwright.
❌ Нулевой встроенный интеллект
Selenium не понимает семантически, что такое «форма входа» — нужно программировать явные ожидания, обработчики исключений и логику восстановления. Для AI-агента это означает изобретение колеса на каждом workflow.
❌ Эпидемия StaleElementReferenceException
Динамический DOM (SPA, React/Vue, асинхронные обновления) приводит к тому, что элементы становятся недействительными в середине скрипта. Автоматическое ожидание в Playwright радикально снижает эту частоту.
❌ Многословность
# Selenium
element = driver.find_element(By.CSS_SELECTOR, ".btn-primary")
WebDriverWait(driver, 10).until(element_to_be_clickable(element))
element.click()
# Playwright (эквивалент)
await page.click(".btn-primary") # Авто-ожидание включено по умолчанию
| Сценарий | Выбор |
|---|---|
| Расширение существующей Selenium-кодовой базы AI-возможностями | ✅ Selenium + AI-обёртка |
| Строго детерминированные, хорошо изученные workflows | ✅ Selenium |
| Команда уже владеет Selenium, временные ограничения | ✅ Остаться на Selenium |
| Новый проект, AI-агент с неопределёнными сценариями | ❌ Выбирайте Playwright |
Сайт: pptr.dev
Библиотека Node.js от Google для управления headless Chrome. Ситуация с Python фрагментирована: несколько сторонних портов (pyppeteer, pyppeteer2) существуют, но ни один не имеет уровня проработки и активной поддержки, равного официальному Puppeteer.
Рекомендация: Если нет убедительной конкретной причины, решаемой только через Puppeteer (что встречается редко), предпочитайте Playwright.
Причины:
Проекты, ориентированные исключительно на Chrome/ium и уже инвестировавшие в экосистему Puppeteer, могут использовать режим "channel": "chrome" в Playwright, который внутренне запускает Chrome через CDP-подключение, эквивалентное Puppeteer, сохраняя знакомые парадигмы.
Сайт: steel.dev
GitHub: steel-dev/steel-browser
Открытый браузерный API, созданный специально для AI-агентов. Предоставляет REST API + Python SDK + Node SDK поверх управляемого парка headless-браузеров.
Примечательные особенности:
Релевантен как: Infrastructure-as-a-service слой под browser-use или пользовательскими агентами.
Сайт: firecrawl.dev
Веб-краулер, оптимизированный для преобразования сайтов в форматы, готовые для LLM: чистый Markdown, структурированный JSON, скриншоты.
| Характеристика | Значение |
|---|---|
| Основное назначение | Экстракция контента без интерактивности |
| Форматы вывода | Markdown, JSON, HTML, скриншоты |
| Тарифы | Free: 500 кредитов/мес; Paid: от ~$16/мес [^firecrawl-pricing] |
| Когда использовать | Парсинг статей, документаций, каталогов; RSS-ingestion; маркетинговые исследования |
⚠️ Не является полнофункциональным инструментом браузерной автоматизации. Не подходит для задач, требующих авторизации, заполнения форм или взаимодействия с динамическим контентом.
Сайт: jina.ai/reader
Одноэндпоинт-сервис: POST {url} → получить Markdown/JSON представление страницы.
Преимущества:
Ограничения: Только чтение, без интерактивности.
⚠️ Критически важное методологическое примечание
Организации используют разные подмножества датасета WebVoyager (полный / частичный), разные evaluator'ы (GPT-4V judge vs собственные скрипты), и некоторые результаты являются самоотчётными без независимой верификации. Прямое сравнение чисел требует учёта этих различий. Таблица ниже представляет усреднённые значения из официально заявленных submission на момент февраля 2026 согласно Steel.dev Browser Agent Leaderboard.
| Место | Агент | WebVoyager Score | Тип | Примечания |
|---|---|---|---|---|
| 1 | Surfer 2 (H Company) | 97.1% | Коммерческий | Передовой результат, февраль 2026 |
| 2 | Magnitude | 93.9% | Исследовательский | Методология варьируется, публичная доступность ограничена |
| 3 | AIME Browser-Use | 92.34% | Гибридный | Отдельный форк browser-use |
| 4 | Browserable | 90.4% | Платформа | Методология варьируется |
| 5 | Browser Use (официальный) | 89.1% | Open-source | Основная эталонная реализация |
| 6 | OpenAI Operator | 87% | Потребительский продукт | Интегрирован в ChatGPT Pro |
| 7 | Skyvern 2.0 | 85.85% | Open-source гибрид | Самоотчёт, методология может отличаться |
| 8 | Google Project Mariner | 83.5% | Потребительский продукт | На базе Gemini, интегрирован в Chrome |
🔹 Более высокий балл ≠ линейно лучшая продакшен-надёжность
WebVoyager тестирует фиксированный набор из ~15 сайтов. В продакшене будут:
🔹 Trade-off: breadth vs benchmark optimization
OpenAI Operator и Google Mariner намеренно жертвовали оптимизацией под конкретный бенчмарк ради более широкой применимости. Более низкие баллы не означают слабый продукт — они отражают иные приоритеты в дизайне.
🔹 Open-source конкурирует с коммерческими решениями
browser-use (89.1%), являясь open-source решением, демонстрирует результаты, сопоставимые с коммерчески разработанными операторами. Это важный сигнал для команд, выбирающих между контролем и удобством.
| Параметр | Значение |
|---|---|
| Сложность | ★☆☆☆☆ |
| Гибкость | ★★☆☆☆ |
| Стоимость | Бесплатно (OSS) |
| Время до первого результата | Часы |
Сценарий: Быстрое прототипирование, ограниченные детерминированные задачи, учебный период.
Реализация:
mcp)@playwright/mcp:{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp"],
"env": {
"PLAYWRIGHT_BROWSERS_PATH": "0"
}
}
}
}
Что получает агент:
# Пример вызова через MCP-клиент
result = await mcp_client.call_tool(
"playwright_navigate",
{"url": "https://example.com"}
)
Ограничение: По-прежнему по сути scripted-поведение. Интеллект живёт выше по течению в planning-модуле агента, а не в браузерном слое.
| Параметр | Значение |
|---|---|
| Сложность | ★★★☆☆ |
| Гибкость | ★★★☆☆ |
| Стоимость | Бесплатно – \($\), зависит от хостинга |
| Время до первого результата | Дни |
Сценарий: Команды, желающие получить доказанное AI-поведение из коробки, не инвестируя в построение собственных циклов работы агента.
Реализация:
from browser_use import Browser, BrowserAgent
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
agent = BrowserAgent(
task="Авторизуйся на LinkedIn и сохрани список контактов в CSV",
llm=llm
)
result = await agent.run()
Преимущества:
Компромиссы:
| Параметр | Значение |
|---|---|
| Сложность | ★★★★☆ |
| Гибкость | ★★★★★ |
| Стоимость | Предсказуемая (платите только за LLM-токены) |
| Время до первого результата | Недели |
Сценарий: Продакшен-системы, где предсказуемость стоимости, полная наблюдаемость и возможность внедрения доменных эвристик важнее скорости разработки «чёрного ящика».
Архитектура цикла:
┌─────────────────────────────────┐
│ 1. Playwright: получить a11y tree│
└────────────┬────────────────────┘
▼
┌─────────────────────────────────┐
│ 2. LLM: проанализировать снапшот│
│ + цель → сгенерировать action│
└────────────┬────────────────────┘
▼
┌─────────────────────────────────┐
│ 3. Playwright: выполнить action │
│ → получить новое состояние │
└────────────┬────────────────────┘
▼
┌─────────────────────────────────┐
│ 4. Проверка: завершено? │
│ • Да → вернуть результат │
│ • Нет → повтор с шага 1 │
└─────────────────────────────────┘
Ключевые компоненты для проектирования:
🔧 Асинхронный Playwright-контроллер
class RobustPlaywrightController:
async def execute_with_retry(self, action: dict, max_retries: int = 3):
for attempt in range(max_retries):
try:
return await self._execute_action(action)
except ElementStaleError:
await asyncio.sleep(2 ** attempt) # экспоненциальная задержка
continue
raise ActionExecutionError(f"Failed after {max_retries} attempts")
🔧 Буфер истории (краткосрочная память)
from collections import deque
class AgentMemory:
def __init__(self, max_steps: int = 20):
self.history = deque(maxlen=max_steps)
def add_step(self, action: dict, observation: str, llm_reasoning: str):
self.history.append({
"step": len(self.history) + 1,
"action": action,
"observation": observation,
"reasoning": llm_reasoning
})
🔧 Классификаторы исключений
def classify_error(error: Exception) -> RecoveryStrategy:
if isinstance(error, ElementStaleError):
return RecoveryStrategy.RETRY_WITH_REFRESH
elif "CAPTCHA" in str(error):
return RecoveryStrategy.DELEGATE_TO_HUMAN
elif "login required" in str(error).lower():
return RecoveryStrategy.INJECT_CREDENTIALS
return RecoveryStrategy.FAIL
🔧 Управление токен-бюджетом
class TokenBudget:
def __init__(self, max_tokens: int = 100_000):
self.used = 0
self.max = max_tokens
def can_proceed(self, estimated_cost: int) -> bool:
return self.used + estimated_cost <= self.max
def record_usage(self, tokens: int):
self.used += tokens
if self.used > self.max * 0.9:
logger.warning(f"Token budget at {self.used/self.max:.1%}")
🔧 Логирование наблюдаемости
import structlog
logger = structlog.get_logger()
async def run_agent_step(goal: str, memory: AgentMemory):
snapshot = await playwright.get_accessibility_tree()
action, reasoning = await llm.decide(snapshot, goal, memory.history)
logger.info("agent_step",
step=len(memory.history)+1,
action=action,
reasoning=reasoning,
token_estimate=estimate_tokens(snapshot, reasoning)
)
result = await playwright.execute(action)
memory.add_step(action, result, reasoning)
return result
Инструменты для построения каркаса:
| Параметр | Значение |
|---|---|
| Сложность | ★★☆☆☆ |
| Гибкость | ★★★☆☆ |
| Стоимость | Регулярная подписка (\($\)) |
| Время до первого результата | Часы |
| Провайдеры: | Сервис | Ключевая фича | Когда выбирать |
|---|---|---|---|
| Steel.cloud | Инфраструктура с открытым API, интеграция с leaderboard'ом | Команды, ценящие прозрачность и открытость | |
| Bright Data Web Unlocker | Прокси-ротирующие управляемые браузеры | Сайты с агрессивной антибот-защитой | |
| Hyperbrowser | Оптимизирован для AI-агентов, встроенные инструменты экстракции | Быстрый старт, минимальная настройка |
Преимущества:
Компромиссы:
Релевантен когда:
Начать с: browser-use (локальная установка + Ollama)
pip install browser-use
ollama pull llama3.1 # или другая локальная модель
Почему:
Дальнейшая траектория:
Прототип (локальный browser-use)
│
▼
Валидация гипотезы → есть ли ценность?
│
┌────┴────┐
▼ ▼
Нет Да
│ │
▼ ▼
Стоп Переход к Паттерну C
(кастомный цикл + контроль стоимости)
Принять: Паттерн C (пользовательский agent loop) + Playwright + LangGraph-орхестрация
Архитектурный стек:
┌─────────────────────────────────┐
│ LangGraph: оркестрация агента │
│ • Управление состоянием │
│ • Граф диалога с ветвлением │
└────────────┬────────────────────┘
▼
┌─────────────────────────────────┐
│ Кастомный цикл: │
│ • Playwright (исполнение) │
│ • LLM (планирование) │
│ • Память + классификаторы ошибок│
└────────────┬────────────────────┘
▼
┌─────────────────────────────────┐
│ Наблюдаемость: │
│ • structlog + Prometheus │
│ • Playwright Tracing API │
│ • Бюджетирование токенов │
└─────────────────────────────────┘
Преимущества:
Инвестиция: Разработка каркаса занимает 2–4 недели, но амортизируется по неограниченному числу последующих задач.
Оценить: browser-use Cloud или Skyvern Managed + инфраструктурный слой Steel.dev
| Критерии выбора: | Фактор | Вес | Как оценить |
|---|---|---|---|
| Стоимость простоя | Высокий | Если > $1000/час — оправданы расходы на managed | |
| Требования к приватности | Критичный | Self-hosted или приватный cloud провайдер | |
| Наличие MLOps-команды | Средний | Нет команды → managed; есть → self-hosted | |
| Масштаб задач | Высокий | > 1000 задач/день → инфраструктурная оптимизация |
Преимущества managed-подхода:
Целесообразно, когда: стоимость простоя превышает сэкономленные деньги на инфраструктуре.
Оптимально: Firecrawl API + Unstructured.IO + собственный парсер
Типичный пайплайн:
import requests
from unstructured.partition.html import partition_html
# 1. Экстракция контента через Firecrawl
response = requests.post(
"https://api.firecrawl.dev/v1/scrape",
json={"url": "https://example.com/article", "formats": ["markdown"]},
headers={"Authorization": f"Bearer {API_KEY}"}
)
content = response.json()["data"]["markdown"]
# 2. Структурирование через Unstructured
elements = partition_html(text=content)
structured = [el.to_dict() for el in elements if el.category in ["Title", "NarrativeText"]]
# 3. Пост-обработка: ваш кастомный парсер
result = custom_parser(structured)
| Почему не запускать полный браузер: | Критерий | Полный браузер | Firecrawl / Jina Reader |
|---|---|---|---|
| Стоимость | Высокая (ресурсы + токены) | Низкая (только API-вызов) | |
| Скорость | Секунды–минуты на страницу | Сотни миллисекунд | |
| Сложность | Управление сессиями, прокси, CAPTCHA | Один HTTP-запрос | |
| Применимость | Интерактивные сценарии | Статический / многостраничный контент |
✅ Правило: Не запускайте полные экземпляры браузера, если единственная нужная информация — преобразованный контент из статических или многостраничных списков. Мощь полного браузера — для действительно интерактивных сценариев.
Современные системы защиты (Cloudflare Bot Management, Imperva, Distil Networks) обнаруживают автоматизацию по десяткам сигналов:
| Сигнал | Как детектируется | Как минимизировать |
|---|---|---|
navigator.webdriver |
JS-проверка в браузере | Использование stealth-плагинов, модификация контекста |
| Паттерны движения мыши | Прямые линии, мгновенные переходы | Имитация плавных криволинейных траекторий с шумом |
| TLS fingerprint | Порядок шифров, расширения | Ротация пользовательских агентов и профилей |
| Частота запросов | Статистический анализ | Рандомизация задержек (нормальное распределение) |
| Canvas / AudioContext | Уникальные отпечатки рендеринга | Изоляция сессий, сброс контекста между задачами |
Stealth-плагины
Эквиваленты puppeteer-extra-plugin-stealth; премиум-версия browser-use включает базовую защиту.
Ротация прокси
Резидентные прокси (Bright Data, Oxylabs, Smartproxy) предотвращают блокировку по частоте запросов с одного IP.
Рандомизация поведения
import random
import numpy as np
def human_like_delay(mean_sec: float, std_sec: float = 0.5) -> float:
"""Генерирует задержку с нормальным распределением, характерным для человека"""
delay = np.random.normal(mean_sec, std_sec)
return max(0.5, delay) # не менее 0.5 сек
Сегментация сессий
⚠️ Игнорирование этой проблемы приводит к: блокировке по IP, обязательным CAPTCHA-барьерам, подсунутой ложной информации, ловушкам-honeypots, сбору некорректных данных.
| Требование | Практическая реализация |
|---|---|
| Соблюдение robots.txt | Парсить robots.txt перед стартом; уважать Crawl-delay; логировать нарушения для аудита |
| Запрет на credential stuffing | Никогда не автоматизировать вход в аккаунты, которыми вы не владеете; использовать только тестовые / сервисные учётки |
| GDPR / CCPA compliance | При обработке данных граждан ЕС/Калифорнии: минимизация сбора, шифрование, право на удаление; консультация с юристом |
| Условия использования платформ | Читать ToS целевых сайтов; для коммерческого парсинга — получать письменное разрешение или использовать официальные API |
📌 Важно: Судебная практика парсинга веб-страниц существенно различается в зависимости от юрисдикции. Рекомендуется консультация с юристом для коммерческой деятельности такого масштаба.
✅ Изолированная среда выполнения
Запуск экземпляров браузера в контейнерах или виртуальных машинах предотвращает распространение заражения с вредоносных страниц на хост-систему.
# Пример Dockerfile для изолированного браузера
FROM mcr.microsoft.com/playwright/python:v1.40.0-jammy
# Запуск от не-root пользователя
RUN useradd -m browser && chown -R browser:browser /home/browser
USER browser
# Ограничение возможностей контейнера
SECURITY_OPT = ["no-new-privileges:true"]
READ_ONLY = true
TMPFS = ["/tmp", "/home/browser/.cache"]
✅ Управление секретами
Пароли, API-ключи и сессии хранятся в специализированном хранилище (AWS Secrets Manager, HashiCorp Vault), никогда в коде или журналах логов.
from aws_secretsmanager_caching import SecretCache
cache = SecretCache()
credentials = cache.get_secret_string("prod/browser-agent/credentials")
# Использование: credentials["username"], credentials["password"]
✅ Разделение профилей
Не переиспользуйте браузерные контексты между несвязанными задачами без полной очистки:
# Playwright: изолированный контекст на задачу
context = await browser.new_context(
user_agent="CustomAgent/1.0",
viewport={"width": 1280, "height": 720},
accept_downloads=True
)
# После завершения задачи:
await context.close() # Полная очистка cookies, localStorage, cache
✅ Политика логирования
Заблаговременно удалять конфиденциальные поля (пароли, данные банковских карт) из экспортов систем наблюдаемости:
import re
def sanitize_log_entry(entry: dict) -> dict:
"""Удаляет потенциально чувствительные данные из лога"""
patterns = [
r'password["\']?\s*[:=]\s*["\']?[^"\'\s,}]+',
r'Bearer\s+[A-Za-z0-9\-_\.]+',
r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', # номера карт
]
sanitized = str(entry)
for pattern in patterns:
sanitized = re.sub(pattern, "[REDACTED]", sanitized, flags=re.I)
return sanitized
Без структурированного логирования продакшен-браузерная автоматизация — это археология.
| Категория | Метрики | Инструменты |
|---|---|---|
| Навигация | Переходы между URL, время загрузки, статусы ответов | Playwright page.on("response"), Prometheus |
| Действия | Тип действия, селектор, результат (успех/ошибка), время выполнения | Кастомные события + structlog |
| LLM-решения | Обоснование выбора действия, потреблённые токены, стоимость | LangChain callbacks, OpenAI usage API |
| Ошибки | Тип исключения, контекст (URL, элемент), стратегия восстановления, число попыток | Sentry / Loguru с контекстом |
| Ресурсы | Потребление CPU/RAM, число одновременных браузеров, очередь задач | Prometheus node_exporter + кастомные метрики |
async def execute_agent_action(agent, action_spec: dict):
start = time.time()
logger.info("action_start",
action_type=action_spec["type"],
target=action_spec.get("selector"),
reasoning=action_spec.get("llm_reasoning") # Ключевое: почему модель выбрала это действие
)
try:
result = await agent.execute(action_spec)
duration = time.time() - start
logger.info("action_success",
duration_ms=duration*1000,
result_summary=truncate(str(result), 200)
)
return result
except Exception as e:
logger.error("action_failed",
error_type=type(e).__name__,
error_msg=str(e),
recovery_strategy=classify_error(e).name
)
raise
💡 Playwright Tracing API предоставляет продуманные примитивы инструментирования; дополните пользовательскими диапазонами для границ бизнес-логики.
Несколько сходящихся тенденций формируют ближайшее будущее браузерной автоматизации для AI-агентов:
Компании, включая Ai2 (Molmo), Salesforce Research (xGen-MM), Waymo-derived инициативы, разрабатывают модели, предварительно обученные специально на данных взаимодействия с графическим интерфейсом. Ранние результаты свидетельствуют о заметно более высокой точности таких моделей по сравнению с универсальными LLM, переориентированными на задачи распознавания пикселей.
.well-known/mcp-server.json для описателей MCP-серверов) снижают трение конфигурацииСнижение стоимости за токен непрерывно улучшает экономику подходов на основе зрения, ранее считавшихся неоправданно дорогими для высокочастотной автоматизации.
| Период | Стоимость 1K токенов (GPT-4-class) | Экономический эффект |
|---|---|---|
| 2024 | ~$0.03–0.10 | Только критичные сценарии |
| 2025 | ~$0.01–0.03 | Массовая автоматизация возможна |
| 2026 (прогноз) | ~$0.003–0.01 | Визион-подходы становятся конкурентоспособными по стоимости |
Конвергенция краулинга, синтаксического анализа, принятия решений AI-моделью и исполнения в единые пакеты (langchain-contrib/neural-crawler, семейство TabbyML) снижает накладные расходы на сборку многокомпонентных решений для новых пользователей.
Быстрое расширение MCP спровоцировало документированные векторы атак:
Прогноз: Корпоративное внедрение зависит от разрешения этих проблем; следует ожидать усиления требований безопасности к середине 2026 года (аудит конфигураций, sandboxing MCP-серверов, обязательное логирование вызовов).
Конфликты интересов / Ограничения:
Последнее обновление данных: апрель 2026.
[^techcrunch]: TechCrunch. "Browser-use raises $17M to help steer AI agents on the internet". March 2025. https://techcrunch.com/2025/03/23/browser-use-the-tool-making-it-easier-for-ai-agents-to-navigate-websites-raises-17m/
[^selenium-history]: Selenium Project. "Official History". https://www.selenium.dev/history/
[^skyvern-readme]: Skyvern GitHub Repository. README.md. https://github.com/skyvern-ai/skyvern
[^firecrawl-pricing]: Firecrawl. Pricing Page. https://www.firecrawl.dev/pricing