← На главную

Опубликовано

Как собрать свой домашний Perplexity на нулевом бюджете

Автор: Гусев Николай [портфолио]

Темы: ai-agents, benchmarks, devops, llm-api

Как собрать свой домашний Perplexity на нулевом бюджете

Perplexity устроен почти неприлично удобно. Задаешь вопрос и получаешь готовый ответ со ссылками на источники. Только запрос в этот момент уходит на чужой сервер, поиск подчиняется чужим правилам, а закрытые данные вообще остаются за дверью. Если вы ищете внутренний документ или цену, которой не хочется делиться, удобство быстро приобретает неприятный привкус.

У меня эту работу делает Hermes Agent, персональный ассистент. Я говорю ему: "найди цену на такой-то товар", он идет в веб, выбирает инструменты и возвращается с фактами и источниками. Однажды этот простой сценарий уперся в антибот. Тогда я собрал внутри Hermes Agent скил local-web-search-pipeline. В нем поиск устроен как лесенка: если легкий способ не сработал, ассистент поднимается на следующую ступень.

Теперь Hermes Agent ищет через свой метапоиск, достает контент из-под антибота, при необходимости управляет настоящим браузером, отделяет полезное от поискового шума и сводит факты в ответ. Каждый этап пайплайна представляет собой вызов конкретного агентского инструмента. Все работает на моих машинах. Из расходов остаются электричество и интернет.

Почему стандартный способ не работает

Чтобы узнать цену в интернет-магазине, ассистенту нужно пройти простой маршрут: найти страницу, прочитать ее и пересказать найденное. На бумаге это три скучных шага. В работе веселье начинается уже на втором.

Я попросил Hermes Agent найти цену. Он полез в веб, а прямой запрос к магазину вернул 401. В другой попытке пришла страница без товара, зато с просьбой подтвердить человеческое происхождение. Антибот хотел видеть настоящий браузер, а не аккуратный запрос из скрипта. Поисковик эту стену проходит сам, но отдает наружу лишь обезличенный сниппет. Заголовок есть, ссылка есть, нужной цифры нет.

Поэтому я не стал изображать поиск одним волшебным ящиком. В скиле local-web-search-pipeline каждый следующий инструмент включается только тогда, когда предыдущий уперся в стену. Владелец по-прежнему дает одну обычную команду. Разбираться с лестницей и выбирать следующий ход должен Hermes Agent.

Ступень 1: поиск. SearXNG как своя точка входа

Первую ступень занимает метапоиск SearXNG. Hermes Agent вызывает его, когда получает задачу найти товар, документ или факт. SearXNG опрашивает несколько поисковых бэкендов и возвращает JSON. На выходе получается не страница с рекламой и украшениями, а инженерная заготовка: заголовок, ссылка и сниппет для каждого результата.

Запрос к нему выглядит так:

import urllib.request, urllib.parse, json
q = urllib.parse.quote("овощной сок ашан цена")
url = "http://127.0.0.1:8888/search?" + urllib.parse.urlencode(
    {"q": q, "format": "json", "language": "ru"})
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
res = json.loads(urllib.request.urlopen(req, timeout=30).read())
for r in res["results"][:5]:
    print(r["title"], r["url"])

Порт 8888 здесь появился не для красоты. Мой SearXNG работает в Docker на удаленном сервере с хорошим каналом в РФ. До локальной машины он протянут туннелем ssh -L 8888:localhost:8080, поэтому инструмент обращается к 127.0.0.1:8888, а в веб выходит сервер из РФ. Эту схему можно повторить в Docker на своем или любом удобном хосте в РФ с нормальным сетевым каналом.

Теперь у ассистента есть выдача из нескольких источников. Это уже материал для работы, но сниппет редко содержит все цены и характеристики. Hermes Agent видит, что ответа пока нет, и поднимается на следующую ступень.

Ступень 2: достать контент. trafilatura и ее предел

Для открытых страниц Hermes Agent вызывает trafilatura. Она берет сырой HTML и извлекает из него статью без навигационного мусора: заголовки, списки, текст и таблицы. На новостях и блогах этого часто достаточно. Ассистент получает чистый текст и может сразу перейти к отбору фактов.

С российским ритейлом разговор короче. Защищенный магазин отвечает кодом 401, возвращает пустую страницу или оставляет HTML без товарного текста. trafilatura честно разбирает то, что получила, а получила она почти ничего. Проверка нескольких крупных магазинов дала один и тот же результат. Для Hermes Agent пустой результат служит сигналом не сочинять ответ, а сменить инструмент.

Ступень 3: обойти антибот. Camoufox

Если сервер требует браузер, Hermes Agent запускает Camoufox. Это уже не повторный запрос тем же загрузчиком, а переход к настоящему браузерному инструменту. Camoufox построен на патченном Firefox и скрывает обычные следы веб-драйвера. Его отпечатки экрана и канваса выглядят достаточно последовательно, чтобы антибот не хватался за сирену при первом же открытии страницы.

Пакет ставится одной командой, движок скачивается второй и только один раз:

pip install camoufox
python -m camoufox fetch

Дальше агентский инструмент управляет им как обычным драйвером браузера:

from camoufox.sync_api import Camoufox
with Camoufox(headless=True) as browser:
    pg = browser.new_page()
    pg.goto('https://example.ru/catalog/soki', timeout=45000)
    pg.wait_for_timeout(4000)
    print(pg.inner_text('body'))  # цены и названия

Но закрытые площадки умеют считать до двух. Авито и похожие сервисы проверяют, есть ли у браузера настоящее окно. Режим без окна сразу приводит на форму проверки. Тогда Hermes Agent меняет режим запуска, включает имитацию человеческого поведения и дает странице спокойно загрузиться:

with Camoufox(headless=False, humanize=True) as browser:
    pg = browser.new_page()
    pg.goto('https://board.example/explorer', timeout=50000, wait_until='networkidle')
    pg.wait_for_timeout(6000)

Это не магия и не универсальный плащ-невидимка. Запрос просто проходит тем же путем, которым ходит обычный пользователь. Важнее другое: я не переключаю режимы вручную при каждом поиске. Это делает персональный ассистент по правилам скила.

Ступень 4: капча. Честный клик

Иногда и браузеру с окном достается проверка. Антибот.Клауд рисует кнопку "I'm not a robot" как обычный живой элемент с атрибутом [onclick]. В простом случае Hermes Agent находит ее в дереве страницы и нажимает:

for el in pg.query_selector_all('[onclick]'):
    try:
        if 'robot' in el.inner_text().lower():
            el.click(timeout=2000, force=True)
            pg.wait_for_timeout(6000)
            break
    except Exception:
        pass

После клика каталог открывается и отдает цены. Но не всякая капча оставляет удобный элемент в дереве страницы. Проверка может попросить выбрать фрагмент изображения, повернуть картинку или нажать в определенное место. Здесь в пайплайн включается computer_use, настоящее и проверенное звено Hermes Agent.

Через computer_use ассистент управляет реальным браузером не как слепой скрипт. Он получает скриншот, разбирает изображение зрением, видит капчу и нажимает по нужным координатам. Затем смотрит на новый экран и решает, прошла ли проверка. Это тот же цикл, которым пользуется человек: увидеть, понять, кликнуть и проверить результат.

Поэтому ступень не сводится к одному селектору. Сначала Hermes Agent пробует дешевый и точный клик по элементу страницы. Если элемента нет или задача зрительная, он переходит к computer_use. Владелец в этот момент не ищет координаты и не перехватывает мышь. Он все еще ждет ответ на исходную просьбу "найди цену".

Ступень 5: отобрать релевантное

SearXNG может вернуть десяток ссылок, и каждая формально похожа на ответ. Читать все подряд дорого даже на нулевом бюджете, потому что время тоже умеет заканчиваться.

Hermes Agent передает вопрос и сниппеты локальной эмбеддинговой модели bge-m3. Она превращает их в векторы размером 1024 и сравнивает близость. Результаты выстраиваются по смысловой полезности, а не по месту, которое им досталось в поисковике. В браузер и дальнейшую обработку идут лучшие кандидаты, остальной шум остается за бортом.

Этот отбор влияет и на выбор дорогих ступеней. Ассистент не открывает настоящий браузер для каждой ссылки подряд. Сначала bge-m3 сокращает список, затем Hermes Agent применяет Camoufox или computer_use там, где это действительно нужно.

Ступень 6: свести в ответ локально

Финальную сводку Hermes Agent поручает локальной smollm3. Модель небольшая, и это даже полезно: от нее требуется не мировоззрение, а аккуратная сборка уже найденных фактов.

Есть жесткое правило. Нельзя отдавать ей голый текст страниц и надеяться на дисциплину. В таком режиме модель охотно изобретает магазины и цены. На вход сводке идет только выделенный список фактов: названия, цены и числа. Тогда smollm3 пересказывает найденное, а не дописывает каталог по вдохновению.

После сводки Hermes Agent возвращает владельцу ответ со ссылками. В проверочном запросе он сообщил конкретный диапазон: соки стоят от 89 до 280 рублей, рядом перечислил источники. Никаких цен из воздуха.

Ступень 7: глаза для скриншотов закрытого

Иногда нужные данные живут не в HTML, а прямо в изображении на экране. Текстовый извлекатель там бессилен. Тогда Hermes Agent делает скриншот браузера и передает его локальной зрительной модели lfm2.5-vl. Она читает с изображения название товара, цену, город и остаток.

Так ассистенту удалось разобрать закрытую витрину с шинами. Модель достала цену, город и остаток. Это последняя ступень эскалации. Она тяжелее обычного разбора страницы, зато спасает там, где сайт показывает данные глазам, но не отдает их текстовым инструментам.

Зрение здесь решает две разные задачи. На четвертой ступени computer_use помогает понять капчу и управлять браузером кликами по координатам. На седьмой lfm2.5-vl извлекает факты из снимка закрытой витрины. Hermes Agent выбирает нужный путь по тому, что видит на экране и чего не нашел в HTML.

Экономика: что закрывает цена электричества и интернета

После сборки возникает здравый вопрос: зачем тратить на это время, если рынок уже продает готовые сервисы? Потому что рынок продает каждую ступень отдельно, с отдельным счетчиком и отдельной подпиской.

  • поиск + рендер + антибот - это Firecrawl, Zyte и ScraperAPI. Цена начинается примерно с 16 долларов и уходит за 100 долларов в месяц в зависимости от лимитов.

  • релевантный отбор (наш bge-m3) - отдельный платный реранк или умная выдача Perplexity и Exa.

  • капчи - 2Captcha, CaptchaSolver и CapSolver. Каждое решение стоит центы, а на больших объемах центы быстро вспоминают таблицу умножения.

  • локальные модели генератора и глаза (smollm3, lfm2.5-vl) - облачная подписка, где каждый запрос считают в токенах.

  • работа с закрытыми площадками (форумы, кабинеты, банки) - публичного товара почти нет. Платные прокси и рендеры ограничены географией и правилами сервисов, а под логином часто не работают вовсе.

Расклад по сервисам и что закрывает каждая ступень лесенки (тарифы округлены, домашний сценарий - сотни запросов в день):

Зарубежный сервис        Наша связка                Экономия, $/мес
-----------------------------------------------------------------------------------
Firecrawl               SearXNG + trafilatura       от 29
Zyte / ScraperAPI       Camoufox-рендер             от 50 до 100+
Tavily / Exa            bge-m3 отбор релевантности  от 20
2Captcha / CapSolver    клик по капче               от 5 на объеме
Perplexity Pro          своя сводка smollm3         от 20
Облачная генерация      локальный генератор         от 10-30
Зрительная API (eyes)   локальный lfm2.5-vl         от 10
РФ residential прокси   свой сервер в РФ            от 30-50
Auth/скрейп под логином  многосессионный Camoufox    не продается
-----------------------------------------------------------------------------------
Итого                                                 ~174-265 долларов в месяц

Одна лесенка заменяет примерно десяток платных сервисов. Эксплуатация оплачивается электричеством и интернетом, а не пачкой подписок. Локальные модели работают на своей видеокарте, SearXNG живет на своем сервере в РФ, браузер рендерит на своей машине. Миллион запросов не превращается в миллион строк счета. Растет только расход электричества и сетевой трафик.

Для меня не менее важен контроль над приватностью и данными. В Hermes Agent модели, история работы и сам скил остаются локальными, а наружу уходят только необходимые веб-запросы. Это не отвлеченная схема из сборного руководства. Канал описывает опыт работы с собственным персональным ассистентом, поэтому здесь важно знать, где находятся его память, браузер и найденные данные.

Есть еще преимущество, которое зарубежная подписка не исправит. Пайплайн работает из РФ. Зарубежный рендер приходит с иностранного IP, а российские магазины режут такой трафик по географии или показывают более строгую капчу. Здесь SearXNG стоит в РФ, и рендер идет с российского адреса. Для сайта запрос выглядит как обращение местного пользователя, без геоблока. На закрытых российских площадках это часто не удобная оптимизация, а единственный рабочий маршрут.

Карта стека

Всем дирижирует Hermes Agent. Пользователь ставит задачу, а ассистент на каждом шаге решает, какой инструмент вызвать и куда перейти, если текущая ступень не сработала. SearXNG ищет, trafilatura читает открытое, Camoufox открывает защищенную страницу, computer_use смотрит на экран и кликает, bge-m3 отбирает кандидатов, smollm собирает ответ. Правила этого выбора хранятся в скиле local-web-search-pipeline.

Вопрос владельца -> Hermes Agent -> SearXNG (поиск)
   -> trafilatura (если страница открытая)
   -> Camoufox (если нужен настоящий браузер)
   -> computer_use (если нужно увидеть капчу и кликнуть по координатам)
   -> снимок экрана + lfm-глаз (если факты остались только на изображении)
   -> bge-m3 (отбор релевантного)
   -> smollm (сводка только по фактам)
   -> ответ владельцу со ссылками

Это не жесткая цепочка, которая обязана прогнать каждый запрос через все узлы. Hermes Agent выступает оркестратором. Если trafilatura уже достала нужный факт, браузер не запускается. Если Camoufox отдал текст, зрительная модель не нужна. Если капча видна только на экране, ассистент вызывает computer_use и продолжает работу после клика.

Принцип

Персональному ассистенту не нужна одна модель-гигант для любой задачи. Ему нужна лесенка простых локальных инструментов и правило выбора следующего шага. Каждый инструмент отвечает на один вопрос: "что делать, если предыдущая ступень не сработала?" Hermes Agent задает этот вопрос после каждого результата и сам ведет пайплайн дальше.

Готовый облачный монстр быстрее покупается, но режет работу лимитами, просит подписку и оставляет данные у себя. Скил собирается дольше. Зато каждый его узел можно проверить, заменить и починить отдельно. Владелец при этом общается не с набором скриптов. Он просит персонального ассистента найти цену или документ и получает законченный результат.

В этом и состоит инженерный принцип: не растить монстра, если задачу можно разложить на проверяемые ступени. Оркестратор связывает их в одну способность Hermes Agent, а не перекладывает ручное переключение на человека.

Это часть серии о локальных свободных решениях внутри персонального ассистента Hermes Agent.

🌐 hermes-agent.ru