people_analytics
January 31

Классифицируем отзывы сотрудников о работодателе с помощью R, rollama и Ollama

Анализ отзывов сотрудников помогает HR-менеджерам выявлять ключевые проблемы в компании, оценивать уровень удовлетворенности персонала и находить точки роста. Использование локальных моделей LLM (Large Language Models) позволяет анализировать данные без отправки конфиденциальной информации во внешние сервисы, что особенно важно при работе с чувствительными данными сотрудников.

📌Почему стоит использовать локальные LLM для анализа отзывов?

  • Безопасность данных — отзывы остаются на вашем компьютере, исключая риск утечки информации.
  • Быстродействие — модели работают локально, без задержек, связанных с интернет-соединением.
  • Гибкость — можно использовать различные модели и настраивать их под свои задачи.
  • Экономия — не требуется платить за API-запросы, как при использовании облачных сервисов.

🔧 1. Установка Ollama и rollama

Прежде чем начать, нужно установить два компонента:

1. Ollama — это сервер, на котором запускаются модели LLM.
2. rollama — R-пакет для взаимодействия с Ollama.

Шаг 1: Установите Ollama с официального сайта:


Скачать Ollama
После установки запустите Ollama, и он будет работать в фоновом режиме.
❗️Простая и понятная инструкция для установки.

Шаг 2: Установите пакет rollama в R:

install.packages("remotes")
remotes::install_github("JBGruber/rollama")

Шаг 3: Проверьте, работает ли Ollama:

rollama::ping_ollama()

Если всё установлено правильно, вы увидите сообщение:

# ▶ Ollama (v0.5.7) is running at <http://localhost:11434>!

📥 2. Загрузка модели LLM

Перед анализом отзывов нужно загрузить языковую модель. Для этого выполните:

rollama::pull_model("gemma2:2b")

Модель скачивается один раз, после чего готова к работе. Для этого укажем, что именно ее следует использовать:

#так указываем, какую модель использовать
options(rollama_model = "gemma2:2b")

Список доступных локально LLM (уже загруженных на ПК):

rollama::list_models() 
# A tibble: 3 × 11
# name         model modified_at   size digest parent_model format family families
# <chr>        <chr> <chr>        <dbl> <chr>  <chr>        <chr>  <chr>  <list>  
#   1 mistral:lat… mist… 2025-01-29… 4.11e9 f974a… ""           gguf   llama  <chr>   
#   2 deepseek-r1… deep… 2025-01-29… 4.92e9 28f8f… ""           gguf   llama  <chr>   
#   3 gemma2:2b    gemm… 2025-01-29… 1.63e9 8ccf1… ""           gguf   gemma2 <chr>   
#   # ℹ 2 more variables: parameter_size <chr>, quantization_level <chr>

📊 3. Классификация отзывов

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

Простой пример (zero-shot)

Допустим, у нас есть отзыв:

"Компания предоставляет хорошие условия, но с карьерным ростом тут сложно."

Мы можем запросить у модели классификацию:

library(tibble)
library(purrr)
q <- tribble(
  ~role,    ~content,
  "system", "Ты определяешь категорию текста. Отвечай только одним словом.",
  "user", "text: Компания предоставляет хорошие условия, но с карьерным ростом тут сложно.\ncategories: положительный, нейтральный, негативный"
)
result <- rollama::query(q, output = "text")

Ожидаемый результат: "нейтральный"
Ответ модели:

> result <- rollama::query(q, output = "text")
                        
── Answer from gemma2:2b ─────────────────────────────────────────────────────────────────────
негативный

Zero-shot не всегда дает необходимый результат.

Пробуем one-shot:

q <- tribble(
  ~role,    ~content,
  "system", "Ты определяешь категорию текста. Отвечай только одним словом.",
  "user", "text: Зарплата высокая, коллектив дружный.\ncategories: положительный, нейтральный, негативный",
  "assistant", "сategory: положительный",
  "user", "text: Компания предоставляет хорошие условия, но с карьерным ростом тут сложно.\ncategories: положительный, нейтральный, негативный"
)


Ожидаемый результат: "нейтральный"
Ответ модели:

> result <- rollama::query(q, output = "text")
                        
── Answer from gemma2:2b ─────────────────────────────────────────────────────────────────────
нейтральный


🔍 4. Улучшение точности (few-shot и Chain-of-thought)

Чтобы повысить точность классификации, можно показать модели несколько примеров:

q <- tribble(
  ~role,    ~content,
  "system", "Ты определяешь категорию текста. Отвечай только одним словом.",
  "user", "text: Зарплата высокая, коллектив дружный.\ncategories: положительный, нейтральный, негативный",
  "assistant", "положительный",
  "user", "text: Работаю тут давно, но перспективы роста нет.\ncategories: положительный, нейтральный, негативный",
  "assistant", "нейтральный",
  "user", "text: Постоянные переработки и низкая оплата.\ncategories: положительный, нейтральный, негативный",
  "assistant", "негативный",
  "user", "text: Компания предоставляет хорошие условия, но с карьерным ростом тут сложно.\ncategories: положительный, нейтральный, негативный"
)
result <- rollama::query(q, output = "text")

Ожидаемый результат: "нейтральный"
Ответ модели:

> result <- rollama::query(q, output = "text")
                        
── Answer from gemma2:2b ─────────────────────────────────────────────────────────────────────
нейтральный


Здесь модель учится на примерах, что делает классификацию уже точнее.

Chain-of-thought (CoT), или подсказка по цепочке рассуждений

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

q_thought <- tribble(
  ~role,    ~content,
  "system", "Ты определяешь категорию текста. Размышляй перед тем, как дать ответ.",
  "user",   "text: Зарплата высокая, коллектив дружный.\nКакую категорию (положительный, нейтральный или негативный) ты бы назначил? Объясни свой выбор.",
  "assistant", "Этот отзыв содержит положительные элементы: высокая зарплата и дружный коллектив — оба фактора указывают на удовлетворенность сотрудника. Категория: положительный.",
  "user",   "text: Работаю тут давно, но перспективы роста нет.\nКакую категорию (положительный, нейтральный или негативный) ты бы назначил? Объясни свой выбор.",
  "assistant", "Этот отзыв содержит как нейтральные, так и негативные аспекты. Хотя работа стабильная ('давно'), отсутствие карьерного роста — минус. Однако в целом эмоциональная окраска отзыва не резкая. Категория: нейтральный.",
  "user",   "text: Постоянные переработки и низкая оплата.\nКакую категорию (положительный, нейтральный или негативный) ты бы назначил? Объясни свой выбор.",
  "assistant", "Этот отзыв выражает явное недовольство: переработки и низкая оплата — два сильных негативных фактора. Категория: негативный.",
  "user",   "text: Рабочая атмосфера замечательная, руководство всегда поддерживает.\nКакую категорию (положительный, нейтральный или негативный) ты бы назначил? Объясни свой выбор."
)
output_thought <- rollama::query(q_thought, output = "text")


Ожидаемый результат: "положительный"
Ответ модели:

> output_thought <- rollama::query(q_thought, output = "text")
                        
── Answer from gemma2:2b ─────────────────────────────────────────────────────────────────────
Положительный.
 
**Объяснение:**
* **Рабочая атмосфера замечательная**: Это позитивная характеристика, которая указывает на
благоприятные условия для работы.
* **Руководство всегда поддерживает**: Поддержка руководства – важный фактор для
удовлетворенности работника.
В целом, отзыв свидетельствует о положительном опыте работы в компании.

🔄 5. Массовая обработка отзывов

Если у вас есть список отзывов, можно обработать их векторизированым способом:

reviews_df <- tibble::tibble(
  review_id = 1:3,
  review = c(
    "Отличная команда и интересные задачи.",
    "Руководство не ценит сотрудников.",
    "Работа стабильная, но скучная."
  )
)
annotated_reviews <- reviews_df %>%
  mutate(
    sentiment = rollama::make_query(
      text = review,
      prompt = "Категории: положительный, нейтральный, негативный",
      template = "{prefix}{text}\n{prompt}",
      system = "Определи категорию текста. Отвечай только одним словом из указанных категорий.",
      prefix = "Текст отзыва: "
    ) %>%
      rollama::query(screen = FALSE, output = "text")
  )

Пример результата:

> annotated_reviews
# A tibble: 3 × 3
  review_id review                                sentiment         
      <int> <chr>                                 <chr>             
1         1 Отличная команда и интересные задачи. "положительный"
2         2 Руководство не ценит сотрудников.     "негативный"   
3         3 Работа стабильная, но скучная.        "нейтральный"

⚙ 6. Настройка модели

Если модель отвечает слишком длинно или слишком кратко, или вам не нравятся ответы конкретной LLM, можно настроить её поведение или выбрать другую:

options(rollama_config = "Делай ответы краткими, но точными.")
#так указываем, какую модель использовать
options(rollama_model = "gemma2:2b")
#список локальных LLM
rollama::list_models() 
# A tibble: 3 × 11
# name         model modified_at   size digest parent_model format family families
# <chr>        <chr> <chr>        <dbl> <chr>  <chr>        <chr>  <chr>  <list>  
#   1 mistral:lat… mist… 2025-01-29… 4.11e9 f974a… ""           gguf   llama  <chr>   
#   2 deepseek-r1… deep… 2025-01-29… 4.92e9 28f8f… ""           gguf   llama  <chr>   
#   3 gemma2:2b    gemm… 2025-01-29… 1.63e9 8ccf1… ""           gguf   gemma2 <chr>   
#   # ℹ 2 more variables: parameter_size <chr>, quantization_level <chr>

✅ Итоги

Использование локальной LLM через Ollama и пакет rollama в R даёт HR-менеджерам мощный инструмент для анализа отзывов сотрудников, обеспечивая безопасность данных и высокую скорость обработки.

Преимущества метода:
✔ Полная конфиденциальность (данные не покидают ваш компьютер).
✔ Высокая скорость обработки без задержек.
✔ Возможность адаптировать модель под задачи HR.

Теперь вы можете быстро анализировать с помощью локальной LLM отзывы сотрудников, находить проблемные зоны и принимать решения на основе данных, сохраня конфиденциальность и соблюдая политику информационной безопасноти компании 🚀

Дополнительная информация

1. Документация к пакету rollama
2. 2024 LLMs/genAI + R roundup
3. https://ercbk.github.io/Data-Science-Notebook/qmd/llms-general.html
4. Ollama + tidychatmodels: Categorizing Text Data in R

Подписывайтесь на канал People Analytics.