Как я перенёс учёт откликов из таблицы в обычные файлы


Почему я выбросил RAG-пайплайн и оставил только поиск

vacancy-radar — хранилище откликов на вакансии, которое целиком лежит у вас на диске: обычные markdown-файлы, гибридный поиск (по словам и по смыслу) и MCP-сервер, через который языковая модель читает и пишет в него напрямую.

Я веду учёт своих откликов больше десяти лет — и с каждым разом всё менее криво. Это история о том, как привычка превратилась в небольшой проект с открытым исходным кодом.

История

2012: откликаться на всё подряд

Сразу после университета я откликался на каждую вакансию, которая казалась интересной. В 2012-м интересных позиций в больших компаниях было немного, зато вокруг хватало мест, где можно было применить свои навыки. Казалось, что если тебе нужна работа — ты её найдёшь. Просто это будет не работа мечты.

Повторный отклик

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

«К сожалению, сейчас у нас нет позиции для вас, мы свяжемся с вами позже».

А этот написал:

«Вы уже откликались на эту позицию».

Вот тогда до меня и дошло. Без учёта того, что уже отправлено, я откликался в одни и те же компании по нескольку раз — а рекрутер, который видит пачку откликов от одного человека, скорее всего просто идёт дальше.

Память сайта вместо собственной

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

2019: таблица

Работало, пока интересные вакансии не начали появляться на других сайтах. Одна и та же компания могла висеть сразу на нескольких площадках, а иногда хотелось откликнуться напрямую через сайт компании. Так в 2019-м я завёл документ .ods (то же самое, что Excel, только в LibreOffice) с четырьмя колонками: название компании, ссылка на вакансию, дата отклика и свободный комментарий в колонке «Стадия» — про то, что там сейчас происходит.

Цветовая разметка позволяла понять состояние каждой строки с одного взгляда:

  • Белый — только откликнулся, новостей нет (цвет по умолчанию)
  • Жёлтый — жду ответ
  • Фиолетовый — не интересны
  • Синий — требуются мои действия
  • Зелёный — вроде бы всё хорошо, но нужны согласования
  • Красный — отказ
  • Тёмно-оливковый — оффер, а после уточнений отказ

2024: подключение языковых моделей

В 2024-м я начал использовать языковые модели, чтобы разбирать описания вакансий и писать сопроводительные письма. Они же взяли на себя заполнение 100500 полей в самодельных анкетах, которые некоторые компании обязательно требуют заполнить. Это был первый шаг к тому, чтобы встроить ИИ в поиск работы — и момент, когда таблица начала выглядеть слабым звеном.

Где таблица перестала справляться

Диффы, которые невозможно читать (2026)

В 2026-м захотелось встроить ИИ в процесс плотнее, и я добавил скилл для Claude Code, который читает и обновляет таблицу напрямую. Тогда же я перевёл файл из .ods в .fods: плоский XML заметно лучше диффится и сжимается в git, чем зазипованный бинарник .ods, а работа в LibreOffice при этом никак не меняется.

Размен оказался не бесплатным. Один отклик всё равно может превратиться в дифф на 800 строк, потому что LibreOffice при открытии и сохранении переписывает описания стилей по всему документу, даже если визуально ничего не изменилось.

Некуда складывать подробности

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

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

Привязка к формату

И не хотелось застревать. Что бы я ни выбрал дальше, нужен был понятный путь уйти на что-то другое, если появится вариант получше.

Чего хотелось вместо этого

  1. Читаемые файлы — данные должны быть понятны человеку в любой момент, а не заперты в закрытой БД
  2. Поиск — возможность найти что-то конкретное по всему архиву: например, рекрутера по имени, даже если человек сменил компанию
  3. Простота — не больше механики, чем требует задача
  4. Не скучно — мне должно хотеться этим пользоваться, а значит это не должно быть просто ещё одной БД
  5. Без вендор-лока — менять технологии и поставщиков языковых моделей когда захочу

Как это делалось

Одно разделение я знал заранее: код отдельно, данные отдельно. Командная строка, будущий MCP-сервер, логика поиска и ранжирования — всё это должно работать с любым хранилищем, а само хранилище должно оставаться просто файлами.

Первая итерация: RAG, LangChain и веб-интерфейс

Я не понимал, как именно хочу работать с этими данными, поэтому начал не с задачи, а с формы: загружаем вакансии, посередине ставим ChromaDB, сверху — командная строка над файлами, а над ней веб-интерфейс. Эта итерация лежит в ветке langchain-rag.

По ходу дела я переехал на LangChain, чтобы проще менять модели и алгоритмы. В планах был A2UI (Agent-to-User Interface), а собирать большую часть всего этого должен был spec-kit.

Чему научила первая итерация

Становилось сложнее. Потом ещё сложнее. spec-kit гонял меня по кругу написания спецификаций там, где надо было просто взять и поменять код. И где-то там всплыл настоящий вывод: отдельный интерфейс мне вообще не нужен. Он у меня уже был — тот самый клиент с языковой моделью, в котором я и так сидел.

Вторая итерация: убрать интерфейс

Устройство схлопнулось в одну строчку:

Языковая модель → MCP → Файлы (источник правды) / БД

Клиент общается по Model Context Protocol, MCP-сервер читает и пишет обычный markdown, а БД за этими файлами работает поисковым индексом, который обновляется на каждую запись. Описывать заранее стало нечего, так что вместо spec-kit я взял openspec и перестал спотыкаться о многошаговые спецификации.

Как попробовать

Сначала я проверил всё на себе: натравил одного агента на свою старую таблицу — годы компаний и заметок — и за пару часов получил из неё готовое хранилище.

Полная настройка описана в README репозитория, а в общих чертах так:

  1. Установка — нужен только uv: uv tool install vacancy-radar. В PATH появятся vacancy-radar и vacancy-radar-mcp; при первом поиске догрузится небольшая модель эмбеддингов.
  2. Создать хранилище — vacancy-radar init ~/job-search
  3. Подключить MCP-клиент — указать Claude Desktop или Claude Code на vacancy-radar-mcp --vault ~/job-search
  4. Разговаривать — перезапустить клиент и попросить записать отклик или показать, где всё затихло. Либо напрямую из командной строки: vacancy-radar list --status applied

Всё, что он пишет, ложится в хранилище обычным markdown: читаемо, ищется и лежит у вас.

Это окончательный вариант?

Нет. Что именно поменяется — пока не знаю, но расти это будет из уже написанного кода.

Направление, к которому я всё время возвращаюсь, — превратить типовые сценарии (записать отклик, растормошить зависшую вакансию, отметить подозрительное описание) в переиспользуемые скиллы вместо того, чтобы каждый раз объяснять их заново. Пока что я в основном пробую разные модели и формулировки запросов, чтобы понять, что реально работает, прежде чем это закреплять.

Если есть идея или нашли ошибку — не стесняйтесь завести задачу на GitHub.

И напоследок — про фотографию за заголовком. Одиннадцать монтажников-высотников обедают на балке в 260 метрах над Манхэттеном, в самый тяжёлый год Великой депрессии, когда без работы был примерно каждый четвёртый американец. У этих работа была. Кому-то всё равно нужно было ходить по стали на такой высоте, и умели это именно они. Так что если поиск кажется безнадёжным: бывало и хуже, и людей всё равно нанимали. Сложность в том, чтобы найти ту самую балку, на которую пойдут немногие, — и помнить, где ты уже искал.

«Обед на вершине небоскрёба», 20 сентября 1932 года, 69-й этаж здания RCA в Рокфеллер-центре. Автор снимка не установлен — в тот день на площадке работали Чарльз Эббетс, Том Келли и Уильям Лефтвич. Public domain, Wikimedia Commons.