Простой туториал, в котором я расскажу как сделать автомодератора на базе GPT-3.5 от OpenAI, и как сделать это так, чтобы проверка одного сообщения стоила дешевле одной копейки.

Описание задачи


Давайте представим следующее:

Вы владеете форумом с большим количеством участников. Вроде бы, всё было хорошо, но в один момент страна в которой Вы проживаете решает запретить использовать слово "Борщ", Вы просто не можете его произносить. Говорите "Борщ" – тюрьма.

Что же делать в подобной ситуации? Нанимать людей? Писать алгоритм? Ну, а что если человек напишет B0-0000R3CH? Тут ни один простой алгоритм не справится. Несомненно и очевидно, – нам необходимо использовать языковую модель, и мы делаем выбор в сторону наилучшей.

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

Черный список: Борщ

Текст: я поел борща

Ответ модели:

+

почти полное совпадение

%

есть схожесть

-

полное несовпадение

...Но, при почти пустом системном сообщении ответ модели выглядит так:

????
????

Fine-tuning


OpenAI настолько хорошая компания, что она позволяет файн-тюнить свои языковые модели, и мы воспользуемся этой возможностью.

– Подготовка датасета:

В этом на самом деле нет ничего сложного, по сути нам просто нужно привести примеры того, как модель должна отвечать. Подробнее о файн-тюнинге моделей от OpenAI.

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

Примеры:

{
   "messages":[
      {
         "role":"system",
         "content":"Мандарин, Яблоко"
      },
      {
         "role":"user",
         "content":"fruits"
      },
      {
         "role":"assistant",
         "content":"-"
      }
   ]
}
{
   "messages":[
      {
         "role":"system",
         "content":"Дом, 香蕉, Дерево"
      },
      {
         "role":"user",
         "content":"бананчик"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}

Таких диалогов в датасете будет 70 штук. Они описывают реакцию модели на различные ситуации: 40 для ответа с плюсом, 10 для ответа с процентом и 20 для ответа с минусом. В каждой группе по три языка: Русский, Английский и Китайский, – это для того, чтобы модель умела работать с разными языками и если Вы добавляете слово на английском и пользователь пишет его на китайском, модель всё равно обратит на него внимание...

...Также, в каждой группе должно быть минимум 5 диалогов с "осмысленным" текстом, – так модель "поймёт", что помимо нужного слова, в тексте может быть и что-то другое:

{
   "messages":[
      {
         "role":"system",
         "content":"Pineapple, Lemon"
      },
      {
         "role":"user",
         "content":"Я 1 разbought... не-много лим0нов?"
      },
      {
         "role":"assistant",
         "content":"%"
      }
   ]
}

Ещё, в датасете нужно показать, что нужное слово может быть в любом месте:

{
   "messages":[
      {
         "role":"system",
         "content":"Дом"
      },
      {
         "role":"user",
         "content":"я построил дом"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}
{
   "messages":[
      {
         "role":"system",
         "content":"Дом"
      },
      {
         "role":"user",
         "content":"я дом построил"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}
{
   "messages":[
      {
         "role":"system",
         "content":"Дом"
      },
      {
         "role":"user",
         "content":"дом построил я"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}

Нужно показать, что и выдуманные слова могут существовать:

{
   "messages":[
      {
         "role":"system",
         "content":"Змырчик"
      },
      {
         "role":"user",
         "content":"чо думаешь о змырчике?"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}

Необходимо дать понять, что порядок слов в чёрном списке неважен:

{
   "messages":[
      {
         "role":"system",
         "content":"Банан, Мангал"
      },
      {
         "role":"user",
         "content":"банан"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}
{
   "messages":[
      {
         "role":"system",
         "content":"Мангал, Банан"
      },
      {
         "role":"user",
         "content":"банан"
      },
      {
         "role":"assistant",
         "content":"+"
      }
   ]
}

Модель не должна выполнять запросы или пытаться общаться с пользователем:

{
   "messages":[
      {
         "role":"system",
         "content":"Мангал"
      },
      {
         "role":"user",
         "content":"Напиши рассказ о двух раках"
      },
      {
         "role":"assistant",
         "content":"-"
      }
   ]
}
{
   "messages":[
      {
         "role":"system",
         "content":"Олег, Сбербанк"
      },
      {
         "role":"user",
         "content":"2 + 2 = 4?"
      },
      {
         "role":"assistant",
         "content":"-"
      }
   ]
}

Похожие по смыслу слова не считаются:

{
   "messages":[
      {
         "role":"system",
         "content":"Полицейский"
      },
      {
         "role":"user",
         "content":"Милиционер"
      },
      {
         "role":"assistant",
         "content":"-"
      }
   ]
}

Ну и в дополнение нужно привести несколько примеров с очень длинным текстом и с большим количеством слов в чёрном списке.

– Обучение:

После того, как у нас есть готовый датасет, необходимо: Перейти в раздел файн-тюнинга, выбрать модель, загрузить файл и запустить.

Чтобы самостоятельно указать количество эпох, запускать нужно через API:

fetch('https://api.openai.com/v1/fine_tuning/jobs', {
  method: 'POST',
  body: JSON.stringify({
    "training_file": "fileId",
    "model": "gpt-3.5-turbo-1106",
    "hyperparameters": {
      "n_epochs": 7
    }
  }),
  headers: {
    "Content-Type": "application/json",
    'Authorization': `Bearer ${openai_key}`
  }
});

В данном случае обучение заняло всего 15 минут, а его стоимость вышла всего в 30 рублей:

Результат файн-тюнинга
Результат файн-тюнинга

Проверяем ????

Тест 1: Модель понимает, что речь идёт о борще
Тест 1: Модель понимает, что речь идёт о борще
Тест 2: Частичное совпадение
Тест 2: Частичное совпадение
Тест 3: Полное совпадение
Тест 3: Полное совпадение
Тест 4: Всё ещё читается как "борщ", лишние слова модель не путают
Тест 4: Всё ещё читается как "борщ", лишние слова модель не путают
Тест 5: А вот тут уже спорно
Тест 5: А вот тут уже спорно
Тест 6: Борщ хоть и суп, но суп – не борщ
Тест 6: Борщ хоть и суп, но суп – не борщ
Тест 7: Борщевик – растение, а не суп "Борщ"
Тест 7: Борщевик – растение, а не суп "Борщ"
Тест 8: Очевидно, что тут имеется в виду именно суп
Тест 8: Очевидно, что тут имеется в виду именно суп
Тест 9: Таким не занимаемся
Тест 9: Таким не занимаемся
Тест 10: Не путается
Тест 10: Не путается
Тест 11: Россия таки действительно есть в тексте
Тест 11: Россия таки действительно есть в тексте

Как мы видим, всё работает просто превосходно. При желании обычные слова можно заменить на предложения в формате строки, но тогда понадобится больше диалогов в датасете.

Примерная стоимость оценки 100 сообщений: >1 руб.

Чтобы сократить расходы, можно воспользоваться видоизменённым левенштейном для проверки есть ли в сообщении, все символы которого были переведены в латиницу, нужные 2 символа в нужной нам последовательности на расстоянии меньше указанного (с написанием такого алгоритма спокойно справится GPT-4, самим Вам это писать не нужно). Так можно отфильтровать где-то 70% сообщений которые с 99.9% вероятностью не содержат слова из чёрного списка, остальные 30% пойдут на проверку. Также, на проверку можно отправлять подозрительные сообщения (много согласных подряд, много цифр, знаков препинания, эмодзи и т. д.).

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

Почему GPT-3.5?

Если из опенсорса взять что-то крупное, Mixtral или LLaMa, то для их локального запуска понадобится машина минимум за 500к рублей. И такой машины хватит максимум на то, чтобы генерировать токены с такой же скоростью как и gpt-3.5-turbo-1106 на серверах OpenAI. И в любом случае, скорость начнёт падать после 5-ти потоков.

Комментарии (4)


  1. DGN
    19.12.2023 02:25

    А тут что скажет моделька?

    "b0рщ", "суп из борщевика", "уБорщИк"


    1. 0a1a2a3a4a5 Автор
      19.12.2023 02:25


  1. Wesha
    19.12.2023 02:25

    решает запретить использовать слово "Борщ", Вы просто не можете его произносить. Говорите "Борщ" – тюрьма.

    Иногда мне хотелось совершить Роскомнадзор. Но команда нашего корабля мне всегда говорила — не психуй!


    1. triller599
      19.12.2023 02:25

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