AI-агенты ломаются на UI и девайсах: как дать кодовому агенту доступ к Android, iOS, браузеру и десктопу без самописного хаоса
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production-grade AI-системы для DACH B2B на стеке Claude, Supabase, n8n, Doppler и self-hosted Postgres. В проде я регулярно вижу один и тот же момент: кодовый агент уверенно пишет backend, SQL и пайплайны, а потом упирается в UI-границу — Android, iOS, браузер или десктоп — и команда начинает клеить случайные bridge-скрипты, потому что у агента нет нормальных рук.
Проблема не в модели как таковой. Проблема в том, что большинство команд дают агенту доступ к коду, но не дают управляемый способ наблюдать за интерфейсом, выполнять действие, получать артефакты и возвращать состояние обратно в цикл планирования. В этот момент появляются PNG-скриншоты в одном месте, adb-скрипты в другом, Playwright в третьем, ручные прокси в четвертом. Через 2 недели это уже не агентная система, а набор хрупких обходных путей, которые никто не хочет сопровождать.
Где именно ломается агент
Если агент умеет только генерировать код, он полезен до первой задачи уровня “пройди onboarding, поймай ошибку на реальном Android, воспроизведи это в браузере и приложи лог”. На этой границе нужен не просто tool calling, а единая модель действий: открыть приложение, тапнуть по координате или accessibility-элементу, сделать скриншот, прочитать DOM, сохранить видео, вытащить системный лог, передать это обратно в reasoning loop.
Я обычно вижу 4 типовых режима поломки:
| Поверхность | Что хочет сделать агент | Почему все ломается |
|---|---|---|
| Browser | Открыть страницу, заполнить форму, проверить результат | У команды есть Playwright, но нет стабильного контракта между агентом и браузерной сессией |
| Android | Запустить app, нажать CTA, снять лог | Есть adb, но он торчит напрямую в shell без слоя состояния и ограничений |
| iOS | Пройти сценарий на simulator | Команды смешивают Xcode tooling и ad hoc bash-обертки без общего API |
| Desktop | Проверить Electron или native UI | Нет единого способа синхронизировать окно, ввод и артефакты |
Для production-системы агенту нужен не “доступ ко всему”, а ограниченный интерфейс действий с предсказуемым ответом. Это архитектурная задача, не prompt engineering.
Что работает лучше самописного хаоса
1. Единый action layer вместо прямого shell-доступа
Я рекомендую не пускать кодового агента напрямую в набор утилит. Лучше дать ему узкий набор инструментов с одинаковой схемой ответа: observe, act, artifact, state. Тогда браузер, Android-эмулятор и десктоп становятся разными адаптерами под один и тот же контракт.
Для web это обычно проще всего собрать вокруг Playwright. Для Android — вокруг adb. Для orchestration — через n8n или тонкий Python service. Для артефактов — Postgres или Supabase storage, чтобы каждый шаг был воспроизводим.
import subprocess
from typing import TypedDict
class ToolResult(TypedDict):
ok: bool
stdout: str
stderr: str
def adb_tap(x: int, y: int, serial: str) -> ToolResult:
cmd = ["adb", "-s", serial, "shell", "input", "tap", str(x), str(y)]
proc = subprocess.run(cmd, capture_output=True, text=True)
return {
"ok": proc.returncode == 0,
"stdout": proc.stdout.strip(),
"stderr": proc.stderr.strip(),
}
def adb_screenshot(serial: str, path: str) -> ToolResult:
cmd = ["adb", "-s", serial, "exec-out", "screencap", "-p"]
with open(path, "wb") as f:
proc = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE)
return {"ok": proc.returncode == 0, "stdout": path, "stderr": proc.stderr.decode().strip()}Ключевая идея тут не в adb как таковом. Ключевая идея в том, что агент не пишет shell-команды на лету для каждого шага. Он вызывает ограниченные функции с журналированием, таймаутами и понятной схемой ошибок.
2. Один журнал наблюдений для всех поверхностей
Самая частая ошибка — хранить скриншоты, DOM, видео, логи и traceback-и в разных местах. Тогда агент не может нормально сравнивать состояние и человек не может нормально расследовать инцидент. Я предпочитаю писать каждый шаг в одну таблицу событий.
create table agent_ui_events (
id bigserial primary key,
run_id uuid not null,
step_index int not null,
surface text not null,
action text not null,
status text not null,
artifact_path text,
log_excerpt text,
created_at timestamptz default now()
);Такой журнал решает 3 задачи сразу: воспроизводимость, аудит и handoff от агента к человеку. Для regulated environments это особенно важно: когда клиент спрашивает, почему агент нажал не ту кнопку, вы не отвечаете “примерно так решил модельный слой”, а показываете цепочку артефактов и команд.
Безопасность и контроль доступа важнее удобства
Если дать агенту shell и сетевой доступ без ограничений, вы очень быстро получите лишние действия. OWASP в LLM Top 10 2025 отдельно указывает prompt injection и excessive agency как реальные риски для агентных систем: https://genai.owasp.org/llm-top-10/. В UI-автоматизации это проявляется особенно неприятно, потому что агент может не только сгенерировать плохой код, но и выполнить плохое действие.
Поэтому я обычно ставлю 4 ограничения:
- разрешенный список устройств, доменов и приложений;
- таймаут и лимит шагов на сессию;
- обязательное сохранение артефактов до и после действия;
- статический анализ generated code перед исполнением.
Для Python-кода это легко добавить через bandit. Для secrets — через gitleaks. Для policy checks — через semgrep. Эти инструменты не решают все, но убирают очевидные ошибки до запуска.
#!/usr/bin/env bash
set -euo pipefail
bandit -r ./generated_code -f json -o bandit-report.json
gitleaks detect --source ./generated_code --report-format json --report-path gitleaks-report.json
semgrep --config auto ./generated_code --json --output semgrep-report.json
echo "static checks finished"Anthropic в документации по tool use и computer use тоже последовательно подчеркивает, что инструментальный доступ модели должен быть ограничен и наблюдаем, а не “магически включен” поверх прод-среды. Если вы строите вокруг Claude Code или Anthropic SDK, этот принцип стоит принимать буквально.
Практический паттерн для Android, iOS, web и desktop
Контракт важнее конкретного транспорта
Вместо 4 разных подсистем я рекомендую строить 1 control plane и 4 адаптера. Control plane принимает задачу, разбивает ее на шаги, выдает агенту доступные действия и пишет события в Postgres. Адаптеры знают, как исполнить эти действия на конкретной поверхности.
tools:
- name: browser_open
surface: web
requires_artifact: true
- name: android_tap
surface: android
requires_artifact: true
- name: ios_screenshot
surface: ios
requires_artifact: true
- name: desktop_type
surface: desktop
requires_artifact: trueВ браузере это может быть Playwright session. На Android — emulator или реальное устройство через adb. На iOS — simulator с ограниченным набором действий через xcodebuild и системные утилиты. На десктопе — controlled VM или контейнеризированная среда с UI automation. Важно другое: агент всегда видит один и тот же словарь возможностей и один и тот же формат обратной связи.
Такой подход еще и дешевле в сопровождении. Вы не переписываете orchestration каждый раз, когда появляется новая поверхность. Вы меняете только адаптер и политику доступа. Для команд, которые уже используют n8n как orchestration layer, это хорошо ложится на event-driven схему: tool call → adapter execution → artifact save → planner retry.
FAQ
Нужно ли давать агенту vision, если есть только code tools?
Если агент должен работать с UI, без визуального или структурного наблюдения он быстро слепнет. Для браузера иногда хватает DOM, но для mobile и desktop без screenshot или accessibility tree вы теряете контекст.
Можно ли обойтись одним Playwright для всего?
Нет, если у вас есть native mobile или desktop. Playwright хорошо закрывает web, но Android, iOS и desktop требуют своих адаптеров и другого управления состоянием.
Почему не дать агенту полный shell-доступ и просто логировать?
Потому что shell-доступ без политики — это лишний риск и плохая воспроизводимость. Ограниченные инструменты проще аудировать, проще тестировать и проще объяснять клиенту.
Что важнее: скриншоты или системные логи?
Оба типа артефактов нужны. Скриншот показывает, что видел агент, а лог показывает, что реально произошло внутри приложения или окружения.
С чего начать маленькой команде?
Начните с одного surface, обычно с web или Android, и сделайте единый контракт tool results. Когда появится стабильный журнал событий и артефактов, расширять систему на iOS и desktop станет проще.
Если у вас уже есть кодовый агент, где именно он чаще всего ломается на практике — на browser state, на Android device control, на iOS simulator orchestration или на передаче артефактов обратно в planning loop? Мне правда интересно, где у вас сейчас самая дорогая точка отказа в проде.
I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.