Мы можем знать – мы будем знать!
Мне всегда было интересно, что там во всех этих 2000+ вакансиях, которые мне выдает hh.ru, когда я туда захожу? Самому хватало терпения просмотреть 20-30, ну от силы 40 вакансий. Понятно, что можно перелететь в конец (или любую страницу) пэйджинга и там глянуть часть вакансий, но это не дает всей картины в целом, а это важно.
А что если перепоручить задачу (ну хоть какую-то её часть) ai-агенту?
Сказано — сделано (в современную-то эпоху вайбкодинга).
Начала
Первое, что я определил, — это главные функции, которые были нужны:
-
Собрать все рекомендуемые вакансии в локальную БД.
-
Проранжировать каждую вакансию относительно того, насколько в неё попадает моё резюме.
-
Советы по резюме: что добавить, какие скиллы прокачать, чему поучиться.
-
Рекомендации по вакансиям для отклика: на какие вакансии имеет смысл откликнуться прямо сейчас. Вот ради этого всё и затевалось — просмотреть 2000+ вакансий вручную невозможно, а получить топ-10 «на сегодня» — реально.
-
Синхронизация откликов: нет смысла получать рекомендации по вакансиям, на которые уже откликнулся или где уже отказали.
По ходу дела появилась ещё одна функция:
-
1.2. Проверка архивных вакансий — зачем анализировать и рекомендовать то, что уже ушло в архив.
Да, чуть не забыл: чтобы не смотреть всё время в вывод командной строки, сделал ещё и небольшой веб-UI для просмотра результатов работы функций.
Почему через браузер, а не через API
Казалось бы, очевидное решение для такой задачи — официальное API hh.ru. Но в конце 2025 года hh.ru закрыл API для соискателей.
Для проекта это значит простую вещь: браузерная автоматизация — это не костыль и не «обход API», это единственный рабочий способ автоматизировать сбор своих рекомендаций в 2026 году. Поэтому в основе лежит Playwright, запускающий мой настоящий, уже залогиненный Яндекс.Браузер (в отдельном профиле), а капчу, если она выскакивает, я решаю руками — скрипт просто ждёт. Никаких токенов, паролей и скрытых сессий: агент видит ровно то же, что вижу я в своём браузере.
Этот же подход, к слову, заодно решает вопрос «а не забанят ли»: запросы идут из реального браузера с реальной сессией, с человекоподобными задержками между страницами и карточками (лог-нормальное распределение, а не «раз в секунду как робот»).
Базовые функции и зачем тут OpenCode
Фиксированные функции — это «база»
Пять основных функций (плюс функция 1.2) — это так называемые фиксированные функции. Каждая из них — обычный Python-скрипт, который делает строго определённую вещь: собрать, оценить, посоветовать, подобрать, синхронизировать. Они детерминированы, версионируют данные в SQLite и могут работать полностью автономно от OpenCode — хоть из голого терминала.
Логика разделения простая:
-
Повторяющиеся алгоритмы (обход страниц, нормализация, диф по хешу, сохранение версий, выборки) — это Python. Тут не нужен «интеллект», тут нужна надёжность и воспроизводимость.
-
Творческие, исследовательские шаги (понять, насколько резюме подходит под вакансию; сформулировать советы) — отданы LLM.
А зачем тогда вообще OpenCode?
Затем, что фиксированными функциями жизнь не ограничивается. AI-агент (в моём случае OpenCode + подписка z.ai coder plan и LLM glm-5.1) может отвечать на разные вопросы, которые возникают по ходу.
Например: а какие навыки/скиллы входят в топ-20 вакансий аналитиков, которые hh.ru подобрал лично мне?
Скрытый текст
Спойлер: SQL с большим отрывом. Причём интересно, что сам OpenCode для ответа в основном писал именно SQL-код — делал выборки из моей локальной базы и анализировал.
В этом и фокус: имея локальную базу вакансий с их полными описаниями, можно проводить небольшие исследования и понимать, что вообще творится на рынке труда — не по ощущениям, а по данным. OpenCode тут выступает как оркестратор: он знает про функции (через slash-команды и скиллы), умеет сам сходить в базу через sqlite3, дёрнуть локальный REST API веб-UI или открыть браузер, чтобы посмотреть пару свежих страниц.
При этом главные функции (1–5 + 1.2) запускаю я явной командой — никаких авто-запусков и cron. А в opencode.json стоит edit=ask: любые правки файлов агент делает только с моего подтверждения.
Где и на чём всё это собиралось
-
Железо: Mac mini M4. Всё крутится локально — база, браузер, веб-UI.
-
Среда: macOS + conda (Python 3.11), управление через OpenCode (TUI), плюс локальный веб-UI на FastAPI (
localhost:8765) для просмотра результатов. -
LLM: для ранжирования и советов — любой OpenAI-совместимый провайдер (я гонял через aitunnel (модель DeepSeek V4 flash), но можно через Vsegpt, OpenRouter, да хоть локальную Ollama). Для самого агента-оркестратора —
glm-5.1через z.ai coder plan.
Изначально планировал использовать Eigent Ai, но выяснилась пренеприятнейшая вещь о нем и пришлось от него отказаться.
Как именно это разрабатывалось (Осторожно! Вайбкодинг)
Тут есть забавная рекурсия: проект про AI-агента я и сам собирал с помощью AI-агентов.
-
Изначально — в Perplexity Computer (оркестратор Claude Opus 4.7): первичная генерация проекта по подробному промпту плюс первые исправления и доработки.
-
Финальные исправления и последняя функция 1.2 — уже в OpenCode с подпиской z.ai coder plan и LLM
glm-5.1.
Проверял не только на своём резюме, но и на резюме супруги — проект позволяет запускать его из разных папок и создаёт разные БД и разные кэши профиля браузера, так что ничего не смешивается. Два независимых «исследователя» по рынку труда на одной машине.
По ходу работы выяснился нюанс hh.ru – отклики хранятся как бы в двух местах: меню “Отклики” и меню “Чаты/облачко”. Причем, именно в Чатах все отклики и отказы, но сейчас Функция 5 собирает отклики из меню “Отклики”, а там не все. Это надо будет доделать.
Проект на GitHub
Репозиторий (публичный, MIT): github.com/Ivanbsp-coder/hh-agent
Ниже — выдержки из README, под спойлером, чтобы не растягивать статью.
Выдержки из README.md
hh-agent
AI-агент-исследователь вакансий hh.ru. Основные функции:
-
Сканирование вакансий в браузере Яндекс с версионностью описаний (Playwright + SQLite).
-
1.2. Проверка архивных вакансий — помечает ушедшие в архив, чтобы не рекомендовать закрытые позиции.
-
-
Ранжирование относительно вашего резюме по 10-балльной шкале (LLM, OpenAI-совместимый API).
-
Советы по улучшению резюме и навыков на основе результатов скрининга (LLM).
-
Подборка вакансий для отклика — топ-N по баллу + бонусу за свежесть, с опциональной «тёмной лошадкой» от LLM. Сохраняет историю подборок и отметки об откликах (отклики делаются вручную в том же браузере).
-
Синхронизация откликов и отказов с hh.ru: текущие статусы + журнал отказов по работодателям для cooldown.
Управление — через opencode с slash-командами и скиллами, CLI-скрипты, локальный веб-UI.
Архитектура и принципы
-
Повторяющиеся алгоритмы (сканирование, нормализация, диф, сохранение, выборки) написаны на Python.
-
Творческие / исследовательские шаги (понимание соответствия, генерация советов) делегированы LLM через slash-команды.
-
Браузер: установленный у вас Яндекс.Браузер запускается через Playwright в отдельном профиле
~/.hh-agent/browser_profile/— не конфликтует с вашим обычным сёрфингом, отдельный Chromium качать не нужно. -
Безопасность: пароль hh.ru вы вводите лично в окне браузера (агент его не видит и не хранит). API-ключ LLM-провайдера берётся из переменной окружения.
Что внутри
hh-agent/
├── README.md # этот файл
├── setup.sh # установка
├── requirements.txt
├── config.example.yaml # шаблон конфига
├── hh_agent/ # Python-пакет
│ ├── config.py # YAML + интерактивные секреты
│ ├── db.py # SQLite-схема и операции с версионностью
│ ├── scraper.py # Playwright + Яндекс.Браузер
│ ├── llm_client.py # OpenAI-совместимый клиент
│ ├── scoring.py # алгоритм 10-балльного ранжирования
│ ├── advisor.py # генерация советов по резюме
│ ├── recommender.py # Функция 4: отбор + freshness + llm_pick
│ ├── delays.py # human-like log-normal задержки
│ └── notifier.py # macOS уведомления (osascript)
├── scripts/ # CLI точки входа
│ ├── init_db.py
│ ├── scan_vacancies.py # Функция 1
│ ├── check_archived.py # Функция 1.2: проверка архивных вакансий
│ ├── rank_vacancies.py # Функция 2
│ ├── advise_resume.py # Функция 3
│ ├── recommend.py # Функция 4: подборка на отклик
│ ├── sync_responses.py # Функция 5: синхронизация откликов
│ ├── apply_mark.py # отметка «откликнулся вручную»
│ ├── delete_vacancy.py # удаление вакансии из БД
│ ├── add_resume.py
│ └── serve_ui.py
├── ui/ # FastAPI + HTML/JS
├── .opencode/ # конфигурация opencode
│ ├── command/ # slash-команды (/scan, /rank, /advise и др.)
│ └── skills/ # скиллы — инструкции для агента (на русском)
Требования
-
macOS (тестируется на Mac mini M4)
-
conda (Miniconda/Anaconda)
-
Python 3.11 (поставит conda)
-
Яндекс.Браузер, установленный в
/Applications/Yandex.app -
Учётная запись на hh.ru (войти нужно лично, агент пароль не хранит)
-
API-ключ OpenAI-совместимого LLM-провайдера для функций 2 и 3 (DeepSeek, VseGPT, ProxyAPI, OpenRouter, локальная Ollama — любой)
Установка
Проект устанавливается на чистый macOS из репозитория:
git clone https://github.com/Ivanbsp-coder/hh-agent.git
cd hh-agent
chmod +x setup.sh
./setup.sh
setup.sh идемпотентен: создаст conda env hh-agent (Python 3.11), установит зависимости, скопирует config.example.yaml → config.yaml, проверит наличие Яндекс.Браузера и инициализирует пустую БД в ~/.hh-agent/hh.db. Отдельный Chromium не качается — используется ваш установленный Яндекс.Браузер.
Подробная пошаговая инструкция — в INSTALL.md. Минимум, что нужно поправить в config.yaml после установки:
browser:
executable_path: "/Applications/Yandex.app/Contents/MacOS/Yandex"
headless: false # лучше false — увидите, как агент работает
hh:
search_query: "" # пусто = что предлагает hh; или впишите "python backend"
search_params: {} # доп. GET-параметры поиска; {} = ничего не добавлять
max_pages: 100
llm:
base_url: "https://api.aitunnel.ru/v1"
model: "deepseek-v4-flash" # или другая модель вашего провайдера
Ключ LLM — в env-переменной (имя — из config.yaml → llm.api_key_env).
Использование (кратко)
# Функция 1 — сбор вакансий (откроется Яндекс, первый раз войти в hh.ru вручную):
python scripts/scan_vacancies.py
# Функция 1.2 — пометить ушедшие в архив:
python scripts/check_archived.py --older-than-days 14 --limit 50
# Функция 2 — LLM-ранжирование относительно активного резюме:
python scripts/rank_vacancies.py
# Функция 3 — советы по резюме (топ/антитоп оценок):
python scripts/advise_resume.py --top 30 --bottom 30
# Функция 4 — подборка топ-10 на отклик + «тёмная лошадка» от LLM:
python scripts/recommend.py -n 10 --llm-pick
# Функция 5 — синхронизация откликов и отказов с hh.ru:
python scripts/sync_responses.py
# Веб-UI для просмотра результатов:
python scripts/serve_ui.py # → http://localhost:8765
Алгоритм подборки (Функция 4): к LLM-баллу добавляется бонус за свежесть
final_score = score + freshness_bonus_max * exp(-age_days / freshness_halflife_days)
(по умолчанию freshness_bonus_max = 1.5, период полураспада 7 дней). Компании, которые отказали в последние 270 дней, исключаются из выдачи Python-алгоритма; LLM может предложить такую в виде исключения, явно пометив это.
Ключевые принципы хранения
-
Версионируем содержимое, не запись. Одна строка на
uidвvacancies; новые версии описания — вvacancy_versions. Диф по sha256. -
Оценки не перезаписываются. Каждый запуск Функции 2 пишет новые строки в
rankings— можно сравнить эффект правок весов/промпта/резюме. -
Резюме версионируется. «Активное» — то, по которому идёт скрининг сейчас.
-
Отклики и отказы версионируются. Журнал отказов по работодателям используется для cooldown в Функции 4.
Что в итоге увидел в данных
Наблюдение 1. Топ востребованных навыков (вакансий в БД = 2909)
Наблюдение 2. Как ложатся баллы ранжирования
Распределение оценок 1–10 по всей базе: сколько вакансий реально «мои», сколько пограничных, сколько мимо. Картина, которую невозможно получить, листая выдачу глазами.
На текущий момент 88 вакансий с оценкой 9+ среди актуальных.
Наблюдение 3. Подборка «на сегодня»
Та самая фича, ради которой всё затевалось: топ-10 по баллу + свежести и одна «тёмная лошадка» от LLM с обоснованием.
Наблюдение 4. Советы по резюме
Что LLM рекомендует добавить/прокачать — с привязкой к конкретным вакансиям как доказательству.
Совет #2 для резюме id=2
06.06.2026, 19:02 · модель deepseek-v4-flash · вакансий в выборке: 40 · версия скилла v1.0
### Краткое резюме рекомендаций
У вас уникальный 16-летний опыт системного анализа в масштабных государственных проектах, который высоко ценится работодателями (средний балл по топ-20 вакансиям — 9/10). Однако для выхода на новый уровень и расширения возможностей трудоустройства потребуются точечные доработки.
**Резюме:** Ключевые проблемы — в резюме не выделены явно навыки работы в Agile, Git, Docker и инструменты прототипирования, что снижает баллы по hard-скиллам. Также отсутствует демонстрация мотивации работать в коммерческих доменах, что особенно важно для финтеха, ритейла и страхования. Рекомендуется добавить отдельный блок технологий, указать опыт работы по Scrum и добавить в раздел «О себе» фразу о готовности применять опыт в новых отраслях.
**Hard Skills:** Приоритет №1 — освоить базу 1С: ERP (или SAP). Это откроет доступ к 30% релевантных вакансий, которые сейчас получают оценку 2/10. Вторым шагом стоит изучить Python на уровне чтения кода и простые скрипты для автоматизации — требование во многих современных командах. Figma, Miro и Power BI будут полезны, но менее критичны.
**Soft Skills:** Тренируйте навык защиты решений и работы с неопределённостью. Подтяните английский до Intermediate — это даст преимущество при отборе.
**Домены:** Фокус на финтех и банки (ваш опыт с юридически значимыми данными и расчетами идеален). На втором месте — E-commerce и ERP-системы. Начните с изучения одного из них, начав с сертификации по выбранной системе.
Вы — сильный кандидат с отличной базой. Осталось немного скорректировать резюме и небольшое расширение технического кругозора, чтобы стать идеальным кандидатом для 70% вакансий на рынке.
Тут надо добавить оговорку.
LLM (в данном случае deepseek-v4-flash) довольно примитивно, как мне кажется, оценивает то, что написано в резюме и в требованиях вакансий.
Я после первого анализа своего резюме понял, что надо указать использование Postman, работу с REST API и gRPC, разработку BPMN, а также то, что разрабатываемая система имеет микросервисную архитектуру и сразу резюме стало вдруг сильнее ранжироваться.
Понятно, что и hr-ы (и их боты) не особо вникают на первом этапе отбора в суть, а ориентируются на ключевые слова и словосочетания, но все же надо анализировать более предметно (еще один пункт для развития hh-agent-а)
Наблюдение 5.
За 3-4 недели количество предлагаемых вакансий под мое резюме сократилось с примерно 2800 до почти 2000.
За чей счет банкет?
Ранжирование резюме относительно одной вакансии стоит в среднем:
-
deepseek-v4-flash = 15 копеек
-
deepseek-v4-pro = 1 руб
Остальные затраты на LLM – небольшие, так как операции выполняются разово. Все в пределах нескольких рублей даже для deepseek-v4-pro
Вместо вывода
Главный результат — вместо «полистал первые три страницы и составил впечатление» получаешь полную, размеченную базу по всем рекомендованным тебе вакансиям и можешь задавать ей вопросы на естественном языке. А короткий список «откликнись сегодня вот сюда» экономит то самое терпение, которого на 2000 карточек заведомо не хватит.
Продолжение следует…
Автор: ivanbsp


