Мини-проект: свой чат-бот по правилам
Хватит читать про ИИ — пора собрать своего бота своими руками и на нём понять, чем твой код отличается от ChatGPT.
Чат-бот по правилам — это программа, которая отвечает не «думая», а сверяясь со списком заранее прописанных правил «если увидел такое слово — ответь так».
Представь: ты пишешь маленькую программу, открываешь её, печатаешь «привет» — и она отвечает «Привет! Как дела?». Печатаешь «расскажи анекдот» — и она выдаёт шутку. Выглядит почти как настоящий ассистент в телефоне. Только внутри нет ни нейросети, ни обучения, ни эмбеддингов — всего пара десятков строк кода, которые ты написал и полностью понимаешь.
К концу урока у тебя будет работающий бот. А ещё — главное — ты на собственной шкуре прочувствуешь, где такой подход упирается в стену и почему настоящий ИИ устроен совсем иначе. Это и есть лучший способ понять ChatGPT: сначала сделать его наивную версию сам.
Звучит как магия — «программа разговаривает», — но никакой магии тут нет. Когда ты увидишь весь код целиком и поймёшь каждую строчку, у тебя пропадёт священный трепет перед «искусственным интеллектом» и появится кое-что куда полезнее: умение спросить про любую умную систему «а что именно у неё внутри?». Это тот же навык, с которым ты разбираешь, как работает рекомендательная лента в соцсети или автодополнение в телефоне, — не веришь на слово, а заглядываешь под капот.
Зачем вообще собирать бота вручную
Ты уже прошёл длинный путь: от признаков и обучения до языковых моделей и трансформеров. Но всё это время ты был зрителем — читал, как оно работает где-то там, внутри огромных систем. Сейчас ты станешь автором.
Есть огромная разница между «я прочитал, как работает велосипед» и «я проехал на велосипеде». Можно идеально знать теорию равновесия и не уметь крутить педали. С ИИ так же: пока ты сам не написал хотя бы примитивного бота, устройство ChatGPT остаётся красивой абстракцией. А стоит собрать своего — и многие фразы из прошлых уроков вдруг щёлкнут на место.
Бот по правилам — это самый первый, самый честный способ заставить компьютер «разговаривать». Именно с таких ботов начиналась история диалоговых программ: ещё в 1960-х существовала ELIZA — программа, которая изображала психотерапевта, просто переставляя слова из твоей же фразы. Люди всерьёз верили, что их понимают. А под капотом — те самые правила «если в тексте есть слово X, ответь Y».
Собрав такого бота, ты получишь точку отсчёта. Когда ты потом скажешь «ChatGPT понимает контекст» или «модель обобщает», у тебя в голове будет конкретная картинка: вот что бот не умел, а вот что добавила нейросеть. Без этой точки отсчёта слова «обучение» и «понимание» остаются пустыми.
Главная идея: правила против обучения
Вспомни наш сквозной пример — отличить кошку от собаки. В самом начале курса мы делали это по правилам: если уши торчком и морда круглая — кошка, если уши висят и морда вытянутая — собака. Мы, люди, заранее придумали эти правила и вписали их в программу.
Потом мы перешли к обучению: вместо того чтобы выдумывать правила, мы показали модели тысячи фоток с метками «кошка»/«собака», и она сама нашла закономерности. Никто не писал ей «смотри на уши» — она докопалась до этого по примерам.
Чат-бот по правилам — это ровно тот же первый подход, но для текста. Ты заранее прописываешь: «если в сообщении есть слово привет — отвечай так-то». Сравни два мира в таблице:
| Бот по правилам (твой проект) | Языковая модель (ChatGPT) | |
| Откуда берутся ответы | Их вписал человек вручную | Модель научилась на миллиардах текстов |
| Что делает с новой фразой | Ищет знакомое слово; не нашёл — сдаётся | Предсказывает правдоподобное продолжение |
| Понимает ли смысл | Нет, сравнивает строки буквально | Работает с эмбеддингами — близкими по смыслу |
| Легко ли понять, почему ответил так | Да, видно конкретное правило | Трудно — ответ «размазан» по миллионам весов |
Запомни эту разницу: в правилах знание пишет человек, в обучении модель добывает его сама из данных. Это водораздел между «старым» программированием и машинным обучением.
Разбор: собираем бота шаг за шагом
Шаг 1. Самый наивный бот
Начнём с минимума. Бот берёт сообщение, приводит его к нижнему регистру (чтобы «Привет» и «привет» считались одинаковыми) и проверяет, есть ли в нём ключевое слово.
function ответить(сообщение) {
const текст = сообщение.toLowerCase();
if (текст.includes("привет")) {
return "Привет! Как дела?";
}
if (текст.includes("пока")) {
return "До встречи!";
}
return "Извини, я тебя не понял.";
}
console.log(ответить("Привет, бот!"));
console.log(ответить("ну всё, ПОКА"));
console.log(ответить("какая погода?"));Вывод:
Привет! Как дела? До встречи! Извини, я тебя не понял.
Разберём по шагам. toLowerCase() делает буквы строчными — без этого «ПОКА» не совпало бы с «пока». includes("привет") проверяет, встречается ли подстрока в тексте. Правила проверяются по порядку сверху вниз; первое сработавшее даёт ответ. Если не сработало ни одно — бот честно говорит, что не понял. Это и есть тот самый «нет кнопки понимания» в чистом виде.
Обрати внимание на одну важную вещь: бот никогда не ошибётся непредсказуемо. Его поведение полностью определяется этими тремя проверками. Дай ему одну и ту же фразу хоть тысячу раз — ответ будет один и тот же. В этом и сила, и слабость правил: ты на сто процентов знаешь, что бот сделает, но он на сто процентов глуп ко всему, чего ты не предусмотрел. ChatGPT — наоборот: непредсказуем, зато гибок. Эта развилка между «предсказуемо и тупо» и «гибко и непредсказуемо» проходит через весь мир ИИ.
Шаг 2. Список правил вместо лесенки if
Когда правил два — if подходит. Когда их двадцать — это превратится в нечитаемую лесенку. Сделаем аккуратнее: вынесем правила в список, где каждое правило — это пара «ключевые слова → ответ». Так добавить новое правило можно одной строкой, не трогая логику.
const правила = [
{ ключи: ["привет", "здаров", "хай"], ответ: "Привет! Чем помочь?" },
{ ключи: ["пока", "до встречи"], ответ: "Пока! Заходи ещё." },
{ ключи: ["анекдот", "шутк"], ответ: "Почему программист пьёт чай? Потому что Java закончилась." },
{ ключи: ["как дела", "как ты"], ответ: "Я всего лишь набор правил, но у меня всё стабильно!" }
];
function ответить(сообщение) {
const текст = сообщение.toLowerCase();
for (const правило of правила) {
// сработало, если хоть один ключ встретился в тексте
if (правило.ключи.some(ключ => текст.includes(ключ))) {
return правило.ответ;
}
}
return "Хм, я пока не знаю, что на это ответить.";
}
console.log(ответить("хай!"));
console.log(ответить("расскажи шутку"));
console.log(ответить("как ты сегодня?"));
console.log(ответить("посоветуй фильм"));Вывод:
Привет! Чем помочь? Почему программист пьёт чай? Потому что Java закончилась. Я всего лишь набор правил, но у меня всё стабильно! Хм, я пока не знаю, что на это ответить.
Что нового. Каждое правило держит несколько синонимов в массиве ключи: «привет», «здаров», «хай» ведут к одному ответу. Метод some(...) возвращает true, если хотя бы один ключ нашёлся в тексте. Заметь приём с обрезанными словами: ключ "шутк" ловит и «шутка», и «шутку», и «пошути» — потому что includes ищет подстроку. Это грубый, но рабочий способ обойти разные окончания, которых в русском море.
Шаг 3. Чуть-чуть «памяти» и случайности
Настоящие боты звучат живее, когда не повторяют одну и ту же фразу. Добавим выбор случайного ответа из нескольких вариантов и крошечную «память» — счётчик сообщений.
const приветствия = ["Привет!", "Здорово!", "О, снова ты!"];
let счётчикСообщений = 0;
function выбратьСлучайно(массив, номер) {
// детерминированно для примера: крутим по кругу по номеру сообщения
return массив[номер % массив.length];
}
function ответить(сообщение) {
счётчикСообщений++;
const текст = сообщение.toLowerCase();
if (текст.includes("привет")) {
return выбратьСлучайно(приветствия, счётчикСообщений);
}
if (текст.includes("сколько") && текст.includes("сообщен")) {
return "Ты написал мне " + счётчикСообщений + " сообщений.";
}
return "Я не понял, но я запоминаю — это уже сообщение №" + счётчикСообщений + ".";
}
console.log(ответить("привет"));
console.log(ответить("привет ещё раз"));
console.log(ответить("сколько сообщений я написал?"));Вывод:
Здорово! О, снова ты! Ты написал мне 3 сообщений.
Тут две новые идеи. Во-первых, переменная счётчикСообщений живёт между вызовами — это примитивная «память» о диалоге. Во-вторых, ответ на «привет» теперь меняется. В настоящем коде ты взял бы Math.random(), но для воспроизводимого примера мы крутим варианты по номеру сообщения. Кажется, что бот «помнит» и «оживает», — но это всё ещё жёсткие правила, просто чуть хитрее.
И вот тут стоит притормозить и быть честным с самим собой. Эта «память» — всего лишь одно число. Бот не помнит, о чём вы говорили: он не знает, что ты спрашивал про погоду, а потом про музыку. Он помнит ровно столько, сколько ты явно велел запомнить, — и ни байтом больше. Сравни с ChatGPT, который держит в «голове» весь ваш разговор и может сослаться на твою фразу из начала диалога. Эту способность дают не правила, а механизм внимания внутри трансформера, который мы разбирали раньше: модель смотрит сразу на все слова контекста и решает, какие из них важны для следующего ответа. Твой счётчик — это карикатура на такую память, и полезно понимать, насколько она бедна.
Частые ошибки и подводные камни
Когда школьники собирают такого бота впервые, они спотыкаются на одних и тех же местах. Лови список, чтобы не наступить на грабли.
| Ошибка | Что происходит и почему |
Забыть toLowerCase() | «Привет» с большой буквы не совпадёт с ключом «привет», и бот «не услышит» приветствие. |
Сравнивать через === вместо includes | текст === "привет" сработает только на голое слово «привет», но не на «привет, бот!». Нужно искать подстроку, а не точное равенство. |
| Порядок правил перепутан | Слишком общее правило стоит первым и перехватывает фразы, которые должны были попасть в более точное правило ниже. |
| Один ключ ловит лишнее | Ключ "да" сработает внутри слов «погоДА», «приДАёт». Короткие ключи дают ложные срабатывания. |
| Ждать, что бот «поймёт» синоним | Если ты прописал «привет», но не «прив», бот на «прив» ответит «не понял». Он не догадывается — он сверяет буквы. |
Последняя строка — самая важная для всего курса. Бот не обобщает. ChatGPT на «прив», «здравствуй» и «йоу» ответит как на приветствие, даже если таких слов не было в явных инструкциях, потому что в его эмбеддингах эти слова лежат рядом по смыслу. Об этом мы говорили в уроке «Языковые модели: предсказание слова». Твой бот так не умеет: для него «привет» и «здравствуй» — две абсолютно разные строки букв.
Где правила упираются в стену
Поиграй с ботом подольше — и стена станет очевидной. Чтобы он понимал больше, тебе придётся вручную дописывать правило за правилом. Хочешь, чтобы реагировал на 100 тем — пиши 100 правил. На опечатки — добавляй варианты. На перефразировки — ещё варианты. Это бесконечная ручная работа, и всё равно найдётся фраза, которая собьёт бота с толку.
Вот тут и понятно, зачем придумали обучение. Вместо того чтобы человек выписывал миллионы правил, модель сама вытягивает закономерности из текстов. Вспомни сквозной пример «Кошка пьёт ...»: твой бот по правилам ответил бы только если ты заранее вписал правило «после ‘Кошка пьёт’ говори ‘молоко’». А языковая модель предсказывает «молоко» сама, потому что встречала похожие фразы миллионы раз и обобщила. Никто не вписывал это правило руками — оно «выросло» из данных. В этом вся разница между твоим проектом и ChatGPT.
Подумай о масштабе живого языка. Только приветствий в русском — десятки: «привет», «здравствуй», «здаров», «хай», «йоу», «доброго времени суток», «приветик», плюс опечатки и сленг, который появляется каждый месяц. Чтобы покрыть их все правилами, тебе пришлось бы вести бесконечный список и каждую неделю его дополнять. А ведь приветствие — это самая простая категория! Представь то же самое для вопросов о математике, истории, играх, чувствах. Становится ясно: ручные правила — это лестница, по которой невозможно дойти до настоящего разговора. Где-то на сотом правиле ты сдашься, а человек всё равно напишет сто первую фразу, которую ты не предусмотрел.
Именно эта боль и подтолкнула людей к идее обучения. Раз мы, программисты, физически не способны перечислить все случаи — пусть машина выведет правила сама, посмотрев на горы примеров. Так наивный бот, которого ты только что собрал, превращается в логичную ступеньку к огромным языковым моделям. Ты прошёл этот путь не в теории, а руками.
Мини-практика: доделай бота сам
Возьми код из Шага 2 за основу и прокачай его. Делай по порядку — каждый пункт чуть сложнее предыдущего.
- Добавь 3 своих правила на близкие тебе темы: про любимую игру, музыку, мемы. У каждого — минимум два синонима в массиве
ключи. - Сделай «умолчание» полезным. Вместо «не понял» пусть бот предлагает список тем, на которые умеет отвечать. Так пользователь поймёт, чего от него ждать.
- Поймай ложное срабатывание. Добавь короткий ключ вроде
"да"и найди фразу, на которой он срабатывает не к месту. Потом исправь: например, проверяй слово целиком, а не как подстроку. - Сравни с ChatGPT. Возьми любую фразу, которую твой бот не понимает (перефразированное приветствие, опечатку), и задай её настоящему ИИ-чату. Запиши: где он справился, а твой бот — нет. Это и есть наглядная граница между правилами и обучением.
Когда будешь формулировать запрос настоящему ИИ в пункте 4, вспомни урок «Что такое промпт и как его писать» — чёткая формулировка повышает шанс на полезный ответ.
Итоги
- Чат-бот по правилам отвечает, сверяя текст с заранее прописанными человеком правилами «если слово X — ответь Y».
- Ты собрал такого бота сам: от наивной лесенки
ifдо списка правил с синонимами и простой «памятью». - Главная граница: в правилах знание пишет человек, в обучении модель добывает его из данных сама — и поэтому умеет обобщать, а бот по правилам нет.
- Правила быстро упираются в стену: на каждую новую фразу нужно новое правило вручную. Именно этот тупик и сделал обучение нужным.
- Сквозные примеры «кошка/собака» и «Кошка пьёт ...» наглядно показывают: что раньше человек прописывал правилами, нейросеть теперь добывает из примеров.
Дальше в разделе «Сделай сам и будущее» мы посмотрим, куда движется ИИ и какие профессии и навыки он меняет. Но теперь у тебя есть то, чего нет у большинства, — собственный, пусть крошечный, но честно понятый бот. С него и начинается настоящее понимание больших систем.