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.

Read more

Computer-Use-Agenten scheitern an Pixeln: wie Sie auf stabile UI-Referenzen über Accessibility Trees umstellen und fehleranfällige Desktop-Automatisierung nicht mehr ständig reparieren

von Denis Shokhirev, Enterprise AI Architect aus Freiburg im Breisgau Ich bin Denis Shokhirev, Agentic AI Systems Architect in Freiburg im Breisgau, Germany, und bei DennisCraft AI Studio setze ich produktive KI-Systeme für DACH-B2B-Kunden auf Basis von Claude, Supabase, n8n, Doppler und selbst betriebenem Postgres um. Die teuersten Fehler in

By Denis Shokhirev

Компьютерные агенты ломаются на пикселях: как перейти на stable UI refs через accessibility tree и перестать чинить flaky desktop automation

Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production AI-системы для DACH B2B на Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самая дорогая поломка в desktop automation, которую я вижу у клиентов, почти никогда не связана с моделью: агент

By Denis Shokhirev