Мышь, которая думает: зачем вам мультимодальная модель вместо макроса
Попробуйте написать скрипт, который зайдет в 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.
Пайплайн, который работает: от скриншота до клика
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 ГБ на миллиард, но с потерей точности.
Что дальше? Когда этот подход станет mainstream
Сейчас это хакерский инструмент. Через год, когда появятся модели, специально обученные для GUI automation (что-то вроде Show UI Aloha, но локальные), все изменится.
Проблема сегодня - отсутствие датасетов с разметкой GUI элементов. Когда кто-то соберет миллион скриншотов с аннотациями "здесь кнопка, здесь поле ввода", модели научатся определять элементы с точностью 99%.
А пока - это мощный, но хрупкий инструмент. Используйте его для автоматизации рутинных задач, где интерфейс стабилен. Не доверяйте ему управление банковским приложением без человеческого надзора.
И помните: лучшая автоматизация та, которая не нужна. Прежде чем писать пайплайн на 1000 строк, спросите - может, есть API?