AI без LLM: создаем свою модель ИИ Урок 30 из 30
Урок 30. Выпускаем консольную модель и проверяем выводы
Готовая аптечка полезна, когда на каждом средстве есть название, срок и инструкция. Наш выпуск — тоже собранный комплект: программа, правила, учебные карточки, команда запуска и проверяемые границы. Она отвечает только на два вида коротких вопросов о вымышленном клубе.
Зачем это нужно
Готовая аптечка полезна, когда на каждом средстве есть название, срок и инструкция. Наш выпуск — тоже собранный комплект: программа, правила, учебные карточки, команда запуска и проверяемые границы. Она отвечает только на два вида коротких вопросов о вымышленном клубе.
Перед кодом
Скопируйте из папки шага 30 все пять файлов: main.py, engine.py, checks.py, facts.json, examples.json. Команда получает дату и вопрос: кавычки сохраняют вопрос с пробелами как один аргумент. Необязательное --trace ставится перед датой и печатает путь решения. sys.argv хранит аргументы; len выбирает одну из двух допустимых форм команды. sys.exit(2) завершает неправильный вызов с кодом ошибки. try пробует превратить текст даты в календарную дату, except ValueError перехватывает неверный формат и выдаёт понятное сообщение. Дата — день, на который спрашивают, а не утверждение, что учебная запись верна сейчас.
Файлы этого шага: examples.json, checks.py, engine.py, facts.json, main.py.
Из корня проекта перейдите в папку шага и запустите программу:
cd course/kazakh-ai/step-30
python3 main.py 2026-09-24 "Шахмат қашан?"
В Windows замените python3 на py.
import sys
from datetime import date
from engine import answer
if len(sys.argv) == 3:
show_trace = False
raw_date = sys.argv[1]
question = sys.argv[2]
elif len(sys.argv) == 4 and sys.argv[1] == "--trace":
show_trace = True
raw_date = sys.argv[2]
question = sys.argv[3]
else:
print('Қолдану: python3 main.py [--trace] YYYY-MM-DD "Сұрақ"')
sys.exit(2)
try:
on_date = date.fromisoformat(raw_date)
except ValueError:
print("Қате күн: YYYY-MM-DD түрінде жазыңыз")
sys.exit(2)
result = answer(question, on_date)
print(result["text"])
if show_trace:
for line in result["trace"]:
print("Із:", line)
Что делает программа
Из папки шага выполните python3 main.py 2026-09-24 "Шахмат қашан?": получите шахмат үйірмесінің уақыты: бейсенбі, 15:00 | 2026-09-24 күнгі дерек | дереккөз: club-sheet-01. На Сурет қайда? — білмеймін: дерек жоқ; на Шахмат қашан қайда? — просьба выбрать один вид; на дату 2027-01-01 — отказ из-за срока. Добавьте --trace для пяти шагов проверки источника. Контрольный набор из урока 25 оценивал только тип вопроса и был мал; он не доказывает качество реальной службы. Мы показали локальную узкую модель, не универсальный ИИ. Нулевые платные API-запросы в учебном коде не означают нулевую полную стоимость; отсутствие свободной генерации не делает ошибку источника невозможной.
Паспорт готовой модели
Паспорт модели похож на табличку на электроприборе: вместо слов «быстро» и «мало» на ней стоят единицы измерения и условия опыта. В папке шага есть ещё два файла: quality_cases.json содержит 16 заранее записанных проверок, а benchmark.py запускает их и измеряет готовую систему. Выполните:
python3 benchmark.py --json
Холодный запуск начинается с нового процесса Python. Тёплый запрос выполняется внутри уже работающего процесса. p95 — граница, быстрее которой завершились 95 процентов запросов. RSS — наибольшая физическая память всего процесса; tracemalloc считает только наблюдаемые выделения Python. Обучаемый параметр — число, которое нейросеть меняет при обучении. У нашей системы таких чисел нет: счётчик намерений строится из 13 карточек при запуске.
Пропускная способность показывает, сколько запросов выполняется за секунду. Один рабочий процесс — одна запущенная копия Python, которая в нашем опыте выполняет по одному запросу за раз и использует не больше одного ядра одновременно. Затем программа прогревает 1, 2, 4 и 8 процессов, трижды даёт каждому по 10 000 запросов и берёт средний по порядку результат. КиБ равен 1024 байтам, а МиБ — 1024 КиБ. ARM — семейство процессоров компьютера, на котором сделан контрольный замер.
Контрольный запуск 25 сентября 2026 года на ARM-компьютере с macOS 26.5.2 и Python 3.14.5 дал:
На телефоне сдвигайте следующие широкие таблицы пальцем влево и вправо.
| Что измерено | Результат |
|---|---|
| Обучаемые нейронные параметры | 0 |
| Учебные карточки / утверждённые факты | 13 / 2 |
| Доступные логические ядра / рабочие процессы / запросы одновременно | 8 / 1 / 1 |
| Код и рабочие данные модели | 6 907 байт (6,7 КиБ) |
| Медиана холодного запуска | 34,682 мс |
Медиана тёплого запроса / p95 |
0,034 / 0,037 мс |
| Пропускная способность одного последовательного процесса | 42 520 запросов/с |
Пиковые выделения tracemalloc |
135 626 байт |
| Пиковая RSS всего Python-процесса | 25 608 192 байта (24,4 МиБ) |
| Все сценарии / правильные ответы на известные факты | 16 из 16 / 6 из 6 |
| Правильные отказы | 10 из 10 |
| Уверенный ответ там, где нужен отказ | 0 из 10 |
| Внешние API-запросы | 0 |
| Прямая плата API | 0; устройство, электричество и труд не равны нулю |
| Энергия на запрос | не измерена: нужен аппаратный счётчик мощности |
Что дали дополнительные процессы
Ускорение сравнивает общую скорость с одним рабочим процессом. Параллельная эффективность делит ускорение на число процессов: 100% означали бы, что каждый новый процесс добавил полную долю скорости. Суммарная RSS ниже складывает пики рабочих процессов; память управляющего процесса в неё не входит.
| Рабочие процессы | Запросы одновременно | Общая скорость, запросов/с | Ускорение | Эффективность | Сумма пиков RSS |
|---|---|---|---|---|---|
| 1 | 1 | 42 953 | 1,00 раза | 100% | 25,4 МиБ |
| 2 | 2 | 80 372 | 1,87 раза | 93,6% | 50,8 МиБ |
| 4 | 4 | 146 241 | 3,41 раза | 85,1% | 101,7 МиБ |
| 8 | 8 | 141 357 | 3,29 раза | 41,1% | 204,0 МиБ |
Два и четыре процесса повысили суммарную скорость, но восемь оказались немного медленнее четырёх и потребовали примерно вдвое больше памяти рабочих процессов. Опыт показывает границу этого компьютера и этой программы, но сам по себе не объясняет причину: ею могут быть разные виды ядер, доступ к общим файлам, память или работа операционной системы. Для другого сервера таблицу нужно получить заново.
Последняя строка качества — наша измеримая замена расплывчатому слову «галлюцинация». Здесь ошибка означает: эталон требовал отказа, а программа уверенно выдала иной ответ. 0 из 10 относится только к опубликованным проверкам. Оно не доказывает нулевую ошибку на любом тексте и не защищает от неверного факта в facts.json.
Сопоставление с большими LLM
У закрытых GPT, Claude и Gemini разработчики не публикуют число весов и память серверов. Поэтому утверждение, что «все параметры всех основных LLM известны», неверно. Для открытых моделей масштаб опубликован; память зависит от точности весов и способа запуска.
Сохранённое значение параметра называют весом. FP8 и BF16 — два способа хранить вес: примерно в 1 или 2 байтах. Поэтому там, где число параметров известно, нижнюю оценку легко повторить умножением. Это только веса; рабочая память, кэш контекста и служебные данные добавляются сверху. Токен — слово или часть слова, на которые LLM делит текст; контекст — набор токенов, доступных ей в одном запросе. Знак ≈ далее означает расчётную, а не измеренную на нашем компьютере величину.
| Система | Опубликованный масштаб | Память или размер | Те же 16 проверок |
|---|---|---|---|
| Наша учебная модель | 0 нейронных параметров; 13 карточек; 2 факта | измерено: 6 907 байт файлов; 24,4 МиБ RSS одного процесса с Python | измерено: 16/16; ошибочный уверенный ответ 0/10 |
| Llama 3.1 405B | 405 млрд параметров; контекст 128 тыс. токенов | ≈405 ГБ FP8 или ≈810 ГБ BF16: в 58,6–117 млн раз больше наших файлов | не запускалась на нашем наборе |
| DeepSeek-V3 | 671 млрд всего, 37 млрд работают на одном токене; контекст 128 тыс. | ≈671 ГБ FP8 или ≈1,342 ТБ BF16: в 97–194 млн раз больше; рабочая память сверху | не запускалась на нашем наборе |
| Qwen3-235B-A22B | 235 млрд всего, 22 млрд активных | ≈235 ГБ FP8 или ≈470 ГБ BF16: в 34–68 млн раз больше; рабочая память сверху | не запускалась на нашем наборе |
| GPT-5.6 Sol / Gemini 3.7 Flash | параметры и серверная RAM не раскрыты; контекст около 1 млн токенов | по открытым данным не вычисляется: контекст и цена не определяют число весов | не запускались на нашем наборе |
По объёму файлов порог «в тысячу раз» для размера выбранных представлений здесь пройден с большим запасом. Этот коэффициент нельзя переносить на интеллект, число задач, скорость или качество: LLM работает со свободным текстом и множеством задач, а наша модель знает два вида вопросов и два факта. Скорость LLM мы тоже не подменяем чужой цифрой: для честного отношения надо прогнать конкретную версию на том же оборудовании или через зафиксированный API и на тех же 16 запросах.
Источники масштаба: Meta о Llama 3.1 405B и контексте 128K, карточка DeepSeek-V3, требования NVIDIA для DeepSeek-V3, описание Qwen3, официальные характеристики GPT-5.6, официальные характеристики Gemini 3.7 Flash.
Где наша модель сильнее, а где уступает
Сравнение нужно для выбора инструмента. Карманный калькулятор быстрее человека умножает числа, но не пересказывает книгу; библиотекарь понимает свободный вопрос, но поиск занимает больше ресурсов. Так же различаются наша модель и LLM.
| Свойство | Наша детерминированная модель | Большая LLM | Вывод для проекта |
|---|---|---|---|
| Узкие утверждённые факты | возвращает только запись из справочника и показывает источник | может составить свободный правдоподобный текст | наша модель лучше там, где ответ обязан совпасть с утверждённой карточкой |
| Ошибка вне границы | отказывает по явной причине | может ответить, но фактическую опору надо проверять отдельно | отказ полезнее догадки при высокой цене ошибки |
| Скорость и ресурсы этой задачи | измерены локально: килобайты файлов, миллисекунды и десятки МиБ вместе с Python | большие веса или удалённый API | узкая модель выгоднее для маленького фиксированного справочника |
| Свободная речь и широкий круг тем | не умеет | умеет объяснять, обобщать, переводить и работать с разными формами запроса | LLM намного сильнее в открытых задачах |
| Новое слово и перефразирование | требует нового правила или примера | часто понимает без изменения программы | наша модель хуже переносит незнакомые формулировки |
| Обновление знаний | человек правит небольшой проверяемый файл | знания весов нельзя исправить одной карточкой; можно подключить поиск или базу | у нашей модели проще точечная проверка, но справочник надо вести вручную |
| Повторяемость | одинаковые код, данные и вход дают тот же путь и ответ | результат зависит от версии, настроек и обслуживающей системы | нашу узкую модель проще воспроизвести побайтно |
| Передача запроса | учебный код не обращается к сети | облачный API получает запрос; локально развёрнутая LLM может оставить его на устройстве | преимущество зависит от способа развёртывания, а не только от вида модели |
| Проверяемость решения | путь можно повторить строка за строкой | внутренний путь огромной сети нельзя полностью проследить | наша модель прозрачнее в своей узкой области |
| Масштаб задачи | два намерения, два факта и несколько известных словоформ | много языков, тем и форматов | результат 16/16 нельзя переносить за пределы учебного набора |
Есть и третий вариант: смешанная система. LLM может понять свободную формулировку, а детерминированная часть — проверить разрешённые поля, дату и источник перед ответом. Такой проект сложнее обеих частей по отдельности, зато сочетает широкий вход с контролируемым фактом.
Правило выбора можно восстановить по трём вопросам:
- Набор фактов мал, утверждён и цена выдумки высока? Начните с детерминированной модели.
- Пользователь просит работать со свободным текстом и заранее нельзя перечислить все формулировки? Рассмотрите LLM и отдельную проверку фактов.
- Нужны оба свойства? Измерьте смешанную систему на одном закрытом наборе, а не складывайте обещания двух технологий.
Опорная карта
Команда + дата + вопрос → охрана слов → тип → одна карточка → допустимая дата → ответ и источник; иначе объяснимый отказ.
Вспомните и проверьте
Закройте код и восстановите цепочку из опорной карты. Проверьте четыре команды: известный вопрос, неизвестный кружок, старую дату и --trace. Подсказка: дата 2026-09-24 попадает между checked_on и valid_until, а 2027-01-01 — уже нет. Эталон для старой даты: білмеймін: бұл күнге жарамды дерек жоқ; для неизвестного кружка: білмеймін: таныс емес сөз. Частая ошибка: назвать дату упражнения текущим расписанием реального клуба.
Рубеж 6: итоговая защита
Покажите, что ответ связан с карточкой и сроком; получите тот же ответ для Шахмат қашан? и известной формы Шахматтың уақыты қашан?; назовите два честных отказа; запустите паспорт и объясните разницу между RSS и выделениями Python. Затем объясните, почему 16/16 не означает безошибочность и почему коэффициент размера нельзя переносить на интеллект. Рубеж пройден, если вы можете провести нового человека по цепочке без текста урока. При затруднении вернитесь к соответствующей из шести опор, затем защитите проект повторно.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.