Сейчас каждый второй джун пытается генерировать сопроводительные письма через ChatGPT.
И каждый первый рекрутер научился их детектить за секунду.
Стандартный ответ LLM выглядит так:
«Уважаемый менеджер по найму! Я с большим энтузиазмом пишу вам, чтобы выразить свой интерес к позиции... Я обладаю уникальным сплавом навыков...»
Это мусор. Это «AI-slop», как пишут в комментариях. Такие письма летят в корзину, потому что они пустые.
Когда я писал своего агента для поиска работы , передо мной стояла инженерная задача: сделать так, чтобы робот звучал как уставший, но профессиональный мидл-разработчик, а не как восторженный робот.
В этой статье расскажу, как я настраивал пайплайн генерации текста, боролся с галлюцинациями и повышал конверсию в ответы.
Архитектура генератора
Просто скармливать текст вакансии в модель — ошибка. Модель «поплывет» и начнет лить воду.
Я разбил процесс на 3 этапа:
Extraction (Выжимка фактов): Из вакансии достаем стек и боли.
Matching (Сопоставление): Ищем пересечения с моим JSON-резюме.
Generation (Написание): Генерируем текст по жестким правилам.
Этап 1. Чистка вакансии
Вакансии на hh зашумлены. Там куча воды про «печеньки» и «дружный коллектив». Если это подать в LLM, она начнет писать про печеньки.
Сначала я чищу HTML, оставляя только блоки Requirements и Tasks.
Python
# Псевдокод логики очистки
def clean_vacancy(html_text):
soup = BeautifulSoup(html_text, 'html.parser')
# Убираем все лишнее, оставляем только требования
text = soup.get_text()
# LLM-экстрактор достает только хард-скиллы
key_skills = llm.extract_skills(text)
return key_skills
Этап 2. Промпт-инжиниринг: Убиваем «Робота»
Самое сложное — заставить модель писать сухо и по делу.
Я использовал технику Negative Prompting (запрет определенных паттернов) и Few-Shot Learning (показал ей примеры хороших писем).
Вот упрощенная версия моего системного промпта:
Role: Ты — Python-разработчик с 4 годами опыта. Ты пишешь короткое сообщение рекрутеру.
Constraints (Запреты):
ЗАПРЕЩЕНО использовать слова: "энтузиазм", "уникальный шанс", "рассмотрите мою кандидатуру", "синергия".
Не используй вводные конструкции ("Я пишу вам, чтобы..."). Сразу к делу.
Не используй ��ложные деепричастные обороты.
Тон: спокойный, уверенный, немного неформальный.
Task:
Найди в вакансии требование X.
Найди в моем резюме опыт Y, который закрывает это требование.
Напиши 2-3 предложения по формуле: "Увидел, что вам нужен [X]. Я делал это на проекте [Project Name], используя [Tech Stack]".
Борьба с галлюцинациями
Главный страх автоматизации — нейросеть припишет вам опыт, которого нет.
Вакансия: «Нужен опыт с Kubernetes».
Резюме: Docker.
Плохой бот: «Я эксперт в Kubernetes».
Мой бот: «У меня плотный опыт с Docker, с Kubernetes знаком на базовом уровне».
Как это сделано?
Я добавил шаг Fact-Checking. Перед отправкой письма второй (более дешевый) инстанс модели проверяет сгенерированный текст на соответствие исходному JSON-резюме. Если найдено несоответствие — генерация перезапускается.
Результаты: Было / Стало
Default ChatGPT:
«Здравствуйте! Меня очень заинтересовала ваша вакансия Backend Developer. Я считаю, что мой опыт работы с Django позволит мне внести неоценимый вклад в развитие вашей компании...»
(Вердикт: Вода. Скип.)
Мой агент :
«Добрый день.
Заметил в описании, что вы планируете переезд с монолита на микросервисы.
На прошлом месте в Fintech-проекте я как раз занимался распилом легаси на FastAPI + RabbitMQ, процесс занял полгода.
Готов обсудить детали, если этот опыт релевантен для вас сейчас.»
(Вердикт: Конкретика. Приглашение.)
Чтобы автоматизация работала, нужно потратить 80% времени не на код отправки запросов, а на тюнинг лингвистической модели.
Рекрутеры банят не ботов. Рекрутеры банят скучных спамеров.
Если бот пишет по делу лучше, чем 90% живых кандидатов — его зовут на собеседование.
Код, конечно, я полностью не выложу (коммерческая тайна), но логи работы системы и примеры генерации под разные стеки (Java, JS, PM) показываю в своем канале.
Сейчас там идет открытый бета-тест.
