GUI автоматизация на локальных VLM: пайплайн с PyAutoGUI, Ollama или llama.cpp | AiManual
AiManual Logo Ai / Manual.
01 Мар 2026 Гайд

Мышь, которая видит: автоматизация GUI на локальных мультимодальных моделях

Пошаговый гайд по созданию пайплайна для автоматизации графического интерфейса с помощью PyAutoGUI и локальных мультимодальных моделей. Сравнение Ollama и llama

Мышь, которая думает: зачем вам мультимодальная модель вместо макроса

Попробуйте написать скрипт, который зайдет в Photoshop, найдет в меню фильтр "Размытие по Гауссу", применит его с радиусом 5 пикселей и сохранит файл. С PyAutoGUI это набор жестких координат, хрупкий как стекло. Сменили разрешение экрана, обновили программу - скрипт мертв.

Проблема в том, что традиционная автоматизация слепа. Она не понимает, что видит на экране. Мультимодальная модель (VLM) решает это через visual grounding - способность связывать текст с областями на изображении. Она смотрит на скриншот и говорит: "Кнопка 'Сохранить' находится в правом верхнем углу, ее координаты (x: 1450, y: 80)".

Visual Grounding - это не просто описание картинки. Это точное соотнесение словесных инструкций с пикселями на экране. Модель превращает "нажми на синюю кнопку" в конкретные координаты для мыши.

Столкновение титанов: Ollama против llama.cpp для мультимодальных задач

Здесь два главных претендента. Ollama - это удобная обертка, которая все делает за вас. Llama.cpp - голый движок, где вы контролируете каждый байт.

Критерий Ollama (v0.6.0 на 01.03.2026) llama.cpp (v3000+ на 01.03.2026)
Установка Одна команда, работает из коробки Требует сборки, настройки CMake
Поддержка VLM Встроенная, но только для официальных моделей Через биндинги, но можно засунуть любую GGUF
Производительность Хорошая, но с оверхедами обертки Максимальная, можно выжимать последние кадры из VRAM
Управление моделями `ollama pull/push`, как Docker Скачал GGUF файл и работай

Ollama выигрывает в скорости старта. Запустил `ollama run qwen3-vl:14b` и через минуту уже общаешься с моделью. Но если нужно загрузить кастомную модель, конвертированную через GGUF Converter Studio, придется танцевать с бубном.

Llama.cpp требует времени на настройку, но зато дает полный контроль. Хотите запустить 70-миллиардную модель на 16 ГБ VRAM с квантованием Q4_K_M? Пожалуйста. Только не забудьте про гибридный ад из iGPU и eGPU.

💡
На 01.03.2026 самыми стабильными для visual grounding остаются Qwen3-VL-14B, Gemma3-VL-12B и LLaVA-Next-34B. В Ollama они есть под тегами `qwen3-vl:14b`, `gemma3:12b-vl` и `llava-next:34b`. Для llama.cpp ищите GGUF версии с суффиксом `-vl`.

Пайплайн, который работает: от скриншота до клика

1 Ловим экран и вытаскиваем структуру

PyAutoGUI делает скриншот, но это просто картинка. Нам нужно разбить ее на элементы: кнопки, поля ввода, меню. Здесь помогает OmniParser (актуальная версия 3.2 на 01.03.2026) - он преобразует скриншот в структурированное дерево элементов.

import pyautogui
import json
from omniparser import OmniParser  # pip install omniparser==3.2

# Делаем скриншот всего экрана
screenshot = pyautogui.screenshot()
screenshot.save('current_screen.png')

# Парсим в структуру
parser = OmniParser(device='cuda')  # Использует GPU для ускорения
gui_tree = parser.parse('current_screen.png')

# Сохраняем для отладки
with open('gui_tree.json', 'w') as f:
    json.dump(gui_tree, f, indent=2)

OmniParser выдает JSON с типами элементов, их bounding boxes и текстом. Но этого недостаточно - он не понимает семантику. "Кнопка сохранить" и "Кнопка удалить" для него одинаковы.

2 Спрашиваем у модели, где что находится

Теперь отправляем скриншот и дерево элементов в VLM модель. Prompt должен быть точным: мы просим модель найти элемент по описанию и вернуть координаты.

Не делайте так: "Где кнопка сохранить?". Модель начнет философствовать. Делайте так: "Верни JSON с полем 'coordinates', содержащим массив [x, y] центра элемента, который лучше всего соответствует описанию 'синяя кнопка с текстом Save'."

Вот код для Ollama:

import requests
import base64

def ask_ollama_vlm(image_path, prompt):
    with open(image_path, "rb") as f:
        image_base64 = base64.b64encode(f.read()).decode('utf-8')
    
    payload = {
        "model": "qwen3-vl:14b",
        "prompt": prompt,
        "images": [image_base64],
        "stream": False,
        "options": {
            "temperature": 0.1,  # Низкая температура для точности
            "num_ctx": 4096
        }
    }
    
    response = requests.post("http://localhost:11434/api/generate", json=payload)
    return response.json()["response"]

prompt = """
Analyze this GUI screenshot and return ONLY valid JSON.
Find the element that matches: 'blue button with text Save'.
Return format: {"coordinates": [x, y]}
"""

result = ask_ollama_vlm('current_screen.png', prompt)
# Парсим JSON из ответа
import json
coords = json.loads(result.strip())['coordinates']

Для llama.cpp через биндинг Python (llama-cpp-python==0.3.0+ на 01.03.2026):

from llama_cpp import Llama

llm = Llama(
    model_path="./models/qwen3-vl-14b-Q4_K_M.gguf",
    n_ctx=4096,
    n_gpu_layers=35  # Все слои на GPU
)

# llama-cpp-python поддерживает мультимодальность через специальный формат
response = llm.create_chat_completion(
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": prompt},
                {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_base64}"}}
            ]
        }
    ],
    temperature=0.1
)

Разница в подходе: Ollama проще, но llama.cpp быстрее на 15-20% на том же железе, особенно с использованием новых квантований Q6_K (появились в конце 2025).

3 Выполняем действие и проверяем результат

Получили координаты - теперь кликаем. Но нужно учесть timing: после клика интерфейс может измениться. Добавляем паузу и проверяем результат.

import time

def click_and_verify(coords, expected_change_prompt, timeout=5):
    """Кликаем и ждем, пока интерфейс изменится"""
    pyautogui.click(coords[0], coords[1])
    
    start_time = time.time()
    while time.time() - start_time < timeout:
        time.sleep(0.5)
        new_screenshot = pyautogui.screenshot()
        new_screenshot.save('after_click.png')
        
        # Спрашиваем у модели, произошло ли ожидаемое изменение
        verification = ask_ollama_vlm('after_click.png', expected_change_prompt)
        if "yes" in verification.lower():
            return True
    return False

# Использование
coords = [1450, 80]
success = click_and_verify(coords, "Has the save dialog appeared? Answer yes or no.")
if not success:
    print("Что-то пошло не так, нужно повторить или выбрать другой путь")

Галлюцинации моделей и как с ними бороться

Самая большая проблема VLM моделей - они врут. Модель может уверенно указать на пустое место и сказать, что там кнопка. Особенно этим страдают более мелкие модели (7B параметров).

Проверка от Qwen3 VL галлюцинирует tool-calls в Ollama: всегда просите модель указывать уверенность от 0 до 1. Если уверенность ниже 0.7 - используйте fallback стратегию.

Fallback стратегии:

  • Попросить модель описать область вокруг предполагаемых координат. Если описание не совпадает с ожидаемым - ошибка.
  • Использовать каскад моделей: маленькая быстрая модель делает первичный поиск, большая точная - проверяет.
  • Добавить человеческую проверку через Telegram-бота для критических действий.
def get_coordinates_with_confidence(image_path, description):
    prompt = f"""
    Find '{description}' and return JSON with coordinates and confidence (0-1).
    Format: {{"coordinates": [x, y], "confidence": 0.95}}
    """
    result = ask_ollama_vlm(image_path, prompt)
    data = json.loads(result.strip())
    
    if data['confidence'] < 0.7:
        # Fallback: пробуем найти через шаблон matching
        return find_by_template_matching(description)
    return data['coordinates']

Железо имеет значение: что купить в 2026 для такого пайплайна

Типичная ошибка - пытаться запустить 34-миллиардную модель на ноутбуке с 8 ГБ ОЗУ. Не выйдет. Или выйдет со скоростью 1 токен в секунду.

Минимальная конфигурация на 01.03.2026:

  • Бюджетная: RTX 4070 Ti Super (16 ГБ VRAM) + 32 ГБ ОЗУ. Потянет Qwen3-VL-14B в Q4_K_M.
  • Оптимальная: RTX 5090 (28 ГБ VRAM по слухам) + 64 ГБ ОЗУ. Для LLaVA-Next-34B в Q6_K.
  • Серверная: Две RTX 4090 через NVLink + 128 ГБ ОЗУ. Можно запускать исходные, неквантованные модели.

Память важнее ядер. VLM модели жрут видеопамять как печеньки. Каждый миллиард параметров в FP16 - это 2 ГБ. Q4_K_M квантование уменьшает до ~0.5 ГБ на миллиард, но с потерей точности.

💡
Если GPU не хватает, используйте llama.cpp с флагом `--split-mode layer` для распределения слоев между GPU и CPU. Производительность упадет в 2-3 раза, но хотя бы запустится.

Что дальше? Когда этот подход станет mainstream

Сейчас это хакерский инструмент. Через год, когда появятся модели, специально обученные для GUI automation (что-то вроде Show UI Aloha, но локальные), все изменится.

Проблема сегодня - отсутствие датасетов с разметкой GUI элементов. Когда кто-то соберет миллион скриншотов с аннотациями "здесь кнопка, здесь поле ввода", модели научатся определять элементы с точностью 99%.

А пока - это мощный, но хрупкий инструмент. Используйте его для автоматизации рутинных задач, где интерфейс стабилен. Не доверяйте ему управление банковским приложением без человеческого надзора.

И помните: лучшая автоматизация та, которая не нужна. Прежде чем писать пайплайн на 1000 строк, спросите - может, есть API?

Подписаться на канал