В уроке 6.3 агент прислал отчёт с красивыми процентами, а выводы модели в базе стояли на нулевой сводке. Отсюда правило этого урока: выводы проверяешь по сводке, которую получила модель, а не по отчёту агента. Здесь разбираем, что можно отдать модели, как читать её числа и как выложить дашборд на сервер в Москве.
Чему научишься в этом уроке:
• собирать для модели сводку только из чисел, без персональных данных и мелких срезов;
• давать агенту задание на «Выводы недели» и проверять, по каким данным они построены;
• читать пометку «не подтверждён» как повод посмотреть глазами, а не как приговор;
• находить в журнале модель, расход и срабатывание кэша.
Код считает, модель объясняет
Правило ты знаешь по уроку 4.4: модель хорошо пересказывает, но плохо считает и легко додумывает. Поэтому все цифры дашборда считает код в dashboard.py, а модель получает уже готовую сводку и пишет 3–5 выводов человеческим языком. Представь бухгалтера и консультанта: бухгалтер сводит баланс, консультант читает баланс и говорит, где проблема.
Модель вызывается не на каждое открытие страницы, а по кнопке «Обновить выводы» (htmx подгружает блок отдельно, страница не ждёт модель). Результат лежит в таблице insights: неделя, модель, расход токенов, текст.
Что можно отдать модели, а что нельзя
Кабинет стоит в Москве, потому что в нём персональные данные (дальше ПД): имена и телефоны людей. Модель же работает за рубежом. Значит, наружу уходят только сводные числа, по которым человека не узнать: «за неделю 23 заявки, 7 записаны, из бота 14». Как в отчёте школы для родительского собрания: «в классе пятеро отличников» можно сказать, а показать журнал с фамилиями нельзя.
- Никаких строк заявок. Ни имён, ни телефонов, ни комментариев менеджеров: в комментарии легко оказывается «перезвонить Ольге».
- Имена менеджеров тоже ПД. В сводку пишем «менеджер 1», «менеджер 2», а не логины.
- Мелкие срезы не отправляем. Срез это кусок данных по одному признаку, например «курс X из Подольска». Если в нём одна заявка с отказом, по нему можно вычислить человека. Срезы меньше 5 заявок уходят в «прочее». Порог 5 про ПД: что можно отдать модели. Порог 10 из урока 6.2 про выводы: что можно сказать владельцу. Это разные правила.
- Проверка тестом, а не на глаз. Тест берёт все телефоны и имена из базы и ищет их в тексте, который уходит модели. Нашёл хоть один, значит тест красный.
Это не юридическая консультация. Трансграничная передача по 152-ФЗ (ст. 3 и ст. 12) касается персональных данных. Сводная статистика по общему смыслу закона к конкретному человеку не относится, но прямого разъяснения Роскомнадзора именно про такие сводки мы не нашли. Поэтому вывод с оговоркой, а у заказчика с чувствительными данными решение за его юристом.
Модель видит только то, что есть в сводке
В демо-данные заложили три закономерности: сайт конвертирует хуже бота, один курс проседает, на 6-й неделе выросло время до первого контакта. Пока в сводке была только общая медиана за 8 недель, третью закономерность модель найти не могла: сбой одной недели в ней растворился. Как средняя температура по больнице. Поэтому в третьем задании урока 6.3 в сводку добавили медиану по каждой неделе.
После этого gemini-3.6-flash по локальной базе назвала все три: бот 43,2% против сайта 26,5%, слабый Data Science (30%) и сбой на неделе 21.09, 5,1 часа при обычных 0,9–1,8. Дальше в уроках числа с сервера (бот 47,7%, сайт 27,8%, Data Science 25%, пик 3,1 часа): там seed-demo запускали заново, и демо-данные сгенерировались другие. Вывод для тебя: если закономерность важна владельцу, она должна быть в сводке в явном виде. Модель не увидит того, чего ей не дали.
Проверка чисел и её шум
Каждое число из текста выводов код ищет в сводке. Не нашёл, значит число попадает в жёлтую полосу «Не подтверждены». Задумка хорошая: так ловятся домыслы, вроде «демпинга» конкурента из П3. На сервере выводы выглядели так:

Разберём полосу. Там три вида чисел. Первый: числа, которые модель досчитала сама, 71% («бот на 71% лучше сайта»), 67,7%, 43,7%, «в 1,7 раза». Они верные, но в сводке их нет. Второй: мусор, номера пунктов «1.», «2.», дата «21.09», «38/39». Третий вид был бы самым важным, выдуманные числа, но в этот раз их не оказалось. Поэтому проверка даёт сигнал «посмотри глазами», а не вердикт. Досчитанные числа либо считать кодом и класть в сводку, либо пересчитать руками: 47,7 делим на 27,8, получаем около 1,7.
Ещё три огреха видны владельцу на экране: служебные имена полей (in_work, refused, fast_pct), сырая разметка с решётками и звёздочками и фраза «из последних обработанных 5 из 15 ушли в refused», смысл которой по данным не восстановить. Вывод про пик 21.09 и рост медианы до 3,1 часа при этом верен. Огрехи чинятся заданием агенту (в прогоне его не давали, это шаблон):
Работай ТОЛЬКО в текущей папке проекта (<папка проекта>).
В «Выводах недели» три огреха: в тексте внутренние имена полей (in_work, refused, fast_pct), разметка ### и ** показана сырой, есть фраза, смысл которой не восстановить по сводке.
1. В сводке для модели дай полям русские названия, как на дашборде («в работе», «отказ», «быстрее 1 часа»).
2. В инструкции к модели: только простой текст без разметки, каждое число — из сводки, без собственных расчётов; если нужен расчёт — скажи, какой, я добавлю его в код.
3. Проверку чисел не считай номера пунктов и даты за числа.
pytest -q — полный итог, старые тесты не удалять и не пропускать.
Кэш и расход
Кэш промпта похож на заготовку у повара: если начало заказа то же, что пять минут назад, повар не режет лук заново. У модели «началом» служит одинаковая инструкция. Поэтому инструкцию ставим в начало промпта, а меняющуюся сводку в конец. По документации CloseRouter запись кэша живёт 20 минут по умолчанию (можно 120), а сработал ли кэш, видно по числу токенов из кэша.
Что показал прогон. Локально (задание с медианой по неделям) все 1 142 токена промпта пришли из кэша, значит, для gemini через CloseRouter кэш работает. На сервере первый вызов дал 1 118 токенов промпта, из них из кэша 0, ответ 559: запись кэша там ещё не была создана. Где смотреть: cached_tokens в usage ответа или cache_read_tokens в журнале запроса. Выводы обновляются раз в неделю, кэш за это время истечёт, и экономии на П5 почти нет: один вызов стоит около 0,0003 $. А вот работа агента над дашбордом дорогая: шесть заданий заняли около 61 минуты и 262 хода, на них ушла бо́льшая часть из 0,45 $ расхода CloseRouter за вечер.
Выкладка на сервер в Москве
Сначала сам добавь в .env на сервере те же три строки, что и локально: ключ CloseRouter и имена двух моделей. Так же, как ключ приёма в П4: ключ в чат агенту не вставляешь, права у файла остаются прежними. Потом задание из прогона:
Работай ТОЛЬКО в текущей папке проекта (<путь к папке проекта>) и на сервере <адрес сервера>.
Выложи дашборд на сервер (ssh root@<адрес сервера>, /opt/crm-kodium, пользователь crm). В .env на сервере я уже добавил CLOSEROUTER_API_KEY, MODEL_MAIN, MODEL_FALLBACK — .env НЕ перезаписывай и не удаляй, базу crm.db НЕ заменяй локальной. Скопируй код, шаблоны и static (без .venv, pip, Microsoft, crm.db, тестов test_*.py, DASHBOARD_REPORT.md, test_insights_demo.py). Если нужны изменения схемы базы — сделай миграцию на месте после резервной копии (backup.sh). Перезапусти службу, проверь, что поднялась и .env на месте (cut -d= -f1 .env).
Затем на сервере: python manage.py seed-demo (демо-заявки для показа владельцу), один раз «Обновить выводы» (через код приложения), покажи: сводку по неделям и выводы модели; journalctl -u crm-kodium -n 10 без секретов; код ответа страницы https://<твой поддомен>/login (curl -I).
Первый запуск сорвался: агент получил вместо задания одну точку. На Windows Claude Code запускается через командную оболочку cmd, а она съела знаки процента из задания. Без процентов выкладка прошла: код, static, миграция с резервной копией, 80 демо-заявок, .env цел, служба работает. Но «Обновить выводы» на сервере не сработала: таблица insights создалась только локально. Второе задание:
Работай ТОЛЬКО в текущей папке проекта (<путь к папке проекта>) и на сервере <адрес сервера>.
Проверил сервер: в /opt/crm-kodium/crm.db нет таблицы insights (sqlite3: no such table: insights) — кнопка «Обновить выводы» там упадёт. Локально таблица была, поэтому ты этого не заметил; миграция на сервере добавила только is_demo.
1. Сделай так, чтобы приложение само создавало недостающие таблицы и колонки при старте (идемпотентно, без потери данных), и добавь тест «на старой базе без insights приложение стартует и создаёт таблицу».
2. Выложи на сервер (как в прошлый раз: без .env, crm.db, тестов; перед изменением схемы — backup.sh), перезапусти, проверь .env (cut -d= -f1) и что служба поднялась.
3. На сервере вызови обновление выводов кодом приложения (тем же, что вызывает кнопка) и покажи: строку в insights (модель, первые 400 символов выводов, usage) — секреты не печатать.
pytest -q — полный итог.
После этого выводы на сервере появились. Проверь сам: cut -d= -f1 /opt/crm-kodium/.env показывает имена переменных без значений, systemctl is-active crm-kodium отвечает active, «Дашборд» открывается под владельцем, а под менеджером даёт 403.
Если не получилось
- Выводы пишут «показатели равны 0», а агент в отчёте приводит проценты → отчёт построен на другом скрипте. Задание-исправление есть в уроке 6.3. Смотри сводку из приложения, а не отчёт.
- Кнопка «Обновить выводы» падает только на сервере или агент получил вместо задания точку → смотри раздел «Выкладка»: нет таблицы insights или знаки % съела cmd.
- Модель не видит закономерность, которую ты видишь на графике → её нет в сводке. Добавь нужную разбивку (по неделям, по курсам) в код сводки.
- В полосе «Не подтверждены» много чисел → раздели их на досчитанные моделью, мусор и выдуманные. Выдуманные означают, что надо чинить инструкцию, остальное пересчитай руками.
- Тест «нет ПД в промпте» зелёный, но ты не уверен, что он работает → сломай и почини из миссии ниже.
Контрольный вопрос. Локально «Обновить выводы» работает, а на сервере после выкладки кнопка падает. В чём вероятнее всего причина?
Подсказка: Сравни, что есть в базе на твоём компьютере и в базе на сервере.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Контрольный вопрос. Что из этого можно включить в сводку, которая уходит модели за рубеж?
Подсказка: Проверь каждый пункт: можно ли по нему выйти на конкретного человека и не меньше ли в срезе 5 заявок.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Контрольный вопрос. В полосе «Не подтверждены» стоит 71. В тексте вывода: «бот 47,7%, на 71% выше сайта (27,8%)». Что верно?
Подсказка: Раздели 47,7 на 27,8 и посмотри, что получится.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Задание. МИССИЯ «Выводы, которым можно верить». 1. Выложи дашборд на сервер заданиями из раздела «Выкладка» (свой путь, адрес и поддомен) и проверь: .env на месте, служба active, менеджеру 403. 2. Нажми на сервере «Обновить выводы» на своём дашборде. Попроси агента показать сводку из приложения (тот же JSON, что ушёл модели) и последнюю строку таблицы insights: модель, первые 400 символов выводов, usage. Сверь: числа в сводке не нулевые, в ней нет имён, телефонов, комментариев и логинов, нет срезов меньше 5. 3. Сломай и почини: попроси агента временно добавить в сводку телефон одной демо-заявки и запусти pytest -q. Тест «нет ПД в промпте» должен стать красным. Убери телефон, тест снова зелёный. 4. Разбери полосу «Не подтверждены»: для каждого числа напиши, что это: досчитано моделью, мусор или выдумка. Досчитанные пересчитай руками. 5. Если в выводах есть служебные имена полей или сырая разметка, дай задание-шаблон из урока и обнови выводы ещё раз. Принято, если: приложены снимок дашборда на сервере под владельцем, вывод cut -d= -f1 .env, сводка (JSON) без ПД, вывод pytest с красным тестом при подложенном телефоне и зелёным после, снимок блока «Выводы недели», таблица разбора чисел «число → вид → пересчёт», строка insights с моделью и usage. Ключей и секретов на снимках нет.
Подсказка: Если тест не покраснел от подложенного телефона, он ищет не там: спроси агента, какой именно текст он проверяет.
✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Что дальше
Дашборд считает, модель объясняет, ты проверяешь. В следующем уроке учимся подавать эти цифры владельцу так, чтобы из них получались решения, а не просто красивая страница.
Итог:
• модели уходят только сводные числа: без ПД, без логинов, срезы меньше 5 — в «прочее»;
• выводы проверяешь по сводке из приложения, а не по отчёту агента;
• на сервере приложение само создаёт недостающие таблицы, .env не трогаем;
• модель видит только то, что есть в сводке: нужная разбивка должна быть там явно;
• «не подтверждён» означает: посмотри глазами; кэш работает, но на еженедельном вызове почти ничего не экономит.
