<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Все публикации подряд на Хабре</title>
    <link>https://habr.com/rss/all/all/</link>
    <description>Все публикации подряд на Хабре</description>
    <managingEditor>editor@habr.com</managingEditor>
    <pubDate>Thu, 25 Jun 2026 02:17:21 +0000</pubDate>
    <image>
      <url>https://habrastorage.org/webt/ym/el/wk/ymelwk3zy1gawz4nkejl_-ammtc.png</url>
      <title>Хабр</title>
      <link>https://habr.com/ru/articles/</link>
    </image>
    <item>
      <title>Мы не выравниваем железо — мы выравниваем реальность: как превратить любой лазерный гравер в прецизионный фотоплоттер</title>
      <link>https://habr.com/ru/articles/1051624/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051624</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Если вы хоть раз пытались сделать печатную плату сложнее «мигалки на светодиоде», вы знаете цену «геометрического ада».&lt;p&gt;ЛУТ (лазерно-утюжная технология) — это лотерея. Классический фотометод требует идеального шаблона, а профессиональный фотоплоттер стоит как подержанный автомобиль. Казалось бы, решение на поверхности: взять доступный китайский лазерный гравер за $100 и вперёд. Но тут начинается новый «ад»: оси изначально кривые, реальный шаг моторов живёт своей жизнью, а заготовка почти всегда лежит на столе с перекосом в пару градусов. Малейшее отклонение — и прецизионный Gerber превращается в бесполезный кусок текстолита.&lt;p&gt;Я решил эту проблему иначе. Зачем часами юстировать механику, если можно переложить всё на математику и нейросети?&lt;p&gt;Представляю &lt;strong&gt;LPP-Laser&lt;/strong&gt; — флагманское направление открытой модульной платформы &lt;strong&gt;LPP (Linear Path Platform)&lt;/strong&gt;. Система не требует от станка совершенства. Она просто «натягивает» ваш проект на реальность.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Ключевая идея: мы не выравниваем станок — мы выравниваем изображение под станок.&lt;/strong&gt;&lt;/blockquote&gt;&lt;p&gt;Сначала — результат. Вот полный цикл: от загрузки Gerber-файла до протравленной платы.&lt;p&gt;&lt;a href=https://rutube.ru/video/1164567a576d451a408be623bc29d8ad/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Полный цикл — от Gerber до протравленной платы&lt;/strong&gt;&lt;/a&gt; Смотреть на RuTube ~4 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c664c6358d8af314dd814 data-style id=6a3c664c6358d8af314dd814 width data-habr-games&gt;&lt;/div&gt;&lt;hr&gt;&lt;h3&gt;Что такое LPP: платформа, а не просто утилита&lt;/h3&gt;&lt;p&gt;LPP — это не программа для печати плат. Это &lt;strong&gt;открытая модульная платформа&lt;/strong&gt; с полностью прозрачным стеком разработки: схемы, печатные платы, прошивки и исходный код.&lt;p&gt;Сейчас активно развиваются два направления:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;LPP-Laser&lt;/strong&gt; — точная лазерная засветка фотошаблонов печатных плат. Это основное и текущее направление.&lt;li&gt;&lt;p&gt;&lt;strong&gt;LPP-CNC&lt;/strong&gt; — управление ЧПУ-механикой: фрезеровка, сверление, гравировка. Задел на будущее, который уже заложен в архитектуру.&lt;/ul&gt;&lt;p&gt;Такой подход означает, что вы инвестируете не в узкоспециализированный инструмент, а в экосистему, которая будет расти.&lt;hr&gt;&lt;h3&gt;Философия: математика вместо отвёртки&lt;/h3&gt;&lt;p&gt;Традиционный подход в ЧПУ — «загнать станок в нули». Потратить часы на юстировку, добиться перпендикулярности осей, компенсировать люфты. Наш подход: &lt;strong&gt;станок может быть любым&lt;/strong&gt;.&lt;p&gt;LPP считывает реальное положение платы по &lt;strong&gt;трём контрольным точкам&lt;/strong&gt; через видеоприцел, вычисляет поворот (rotation), масштаб (scale) и перекос (skew) механики. Затем система выполняет аффинную трансформацию итогового растра: вычисляется матрица преобразования, которая «натягивает» идеальные координаты проекта на искажённую геометрию реальной физической заготовки.&lt;p&gt;Даже если плата лежит под углом, а ось Y тянет левее — линии ложатся точно. Мы не боремся с кривизной осей, мы делаем её частью уравнения.&lt;hr&gt;&lt;h3&gt;Слой 1: Железо — свобода «чистого листа»&lt;/h3&gt;&lt;p&gt;LPP — это максимально всеядная платформа. Вы не подстраиваетесь под систему — система подстраивается под ваше железо:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Любая механика:&lt;/strong&gt; ременная передача для скорости или винтовая для точности — сами выбираете баланс.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Любые моторы:&lt;/strong&gt; от классических шаговиков NEMA17 до коллекторных или BLDC с энкодерами. На последних скорость печати достигает &lt;strong&gt;1 м/с и более&lt;/strong&gt;.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Любой лазер:&lt;/strong&gt; от промышленного 20 Вт до китайской выжигалки 1 Вт с AliExpress.&lt;li&gt;&lt;p&gt;&lt;strong&gt;На CNC:&lt;/strong&gt; достаточно прикрепить лазер и камеру к оси X.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Прошивка&lt;/strong&gt; уже скомпилирована и полностью адаптирована под народные STM32: &lt;strong&gt;F103, F401, F411, G431&lt;/strong&gt; (Green / Blue / Black Pill).&lt;h4&gt;FULL и LITE: система подстраивается и под ваш компьютер&lt;/h4&gt;&lt;p&gt;При первом запуске LPP предлагает два режима, и от выбранного режима загружает соответствующий набор модулей.&lt;p&gt;&lt;strong&gt;FULL Mode&lt;/strong&gt; — для мощных машин, рабочих станций, современных многоядерных процессоров. Подтягивает весь «тяжёлый фарш»: нейросети, сложные алгоритмы Computer Vision, многопоточную обработку данных для максимальной скорости.&lt;p&gt;&lt;strong&gt;LITE Mode&lt;/strong&gt; — для старых ПК, слабых ноутбуков и промышленных «калькуляторов» (1 ядро, 1 ГБ RAM). Загружает лёгкие модули и упрощённые алгоритмы. Минимальная нагрузка. Полетит даже на самом слабом железе.&lt;p&gt;Философия та же: не вы подстраиваетесь под систему — система подстраивается под вас. На любом железе и под любую операционку.&lt;p&gt;LPP запускается на Linux (Kali, Ubuntu, Fedora), Windows 10 и Windows 7 — без изменений в логике ядра. В этом же видео показан запуск &lt;strong&gt;setup_&lt;/strong&gt;&lt;a href=http://lpp.sh rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;lpp.sh&lt;/strong&gt;&lt;/a&gt; — скрипта, который автоматически настраивает udev-правила для USB, подтягивает библиотеки и создаёт ярлыки. Один запуск — система готова.&lt;p&gt;&lt;a href=https://rutube.ru/video/bedafeb7a36006e22f2b4c535550e3c9/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Кроссплатформенность — запуск на Linux, Windows 7 и 10&lt;/strong&gt;&lt;/a&gt; Смотреть на RuTube ~4 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c6677f53c05af53a61268 data-style id=6a3c6677f53c05af53a61268 width data-habr-games&gt;&lt;/div&gt;&lt;h4&gt;Конфигурация в стиле FPGA&lt;/h4&gt;&lt;p&gt;Это, пожалуй, главная инженерная «фишка» прошивки. Обычная прошивка контроллера жёстко диктует: этот пин — Step, этот — Dir. Перекинуть провод — перекомпилируй. В LPP мы реализовали другой принцип.&lt;p&gt;После старта контроллер представляет собой просто набор доступных портов — «чистый лист». Все функции пинов, параметры таймеров и каналы DMA назначаются с хоста &lt;strong&gt;в момент инициализации через динамические дескрипторы&lt;/strong&gt;. Хотите переключить Step/Dir на другой разъём или добавить датчик — просто меняете конфиг в управляющем софте. Без перекомпиляции прошивки. Без паяльника.&lt;p&gt;Имея на руках открытый SDK, можно буквально за сутки адаптировать систему под любой другой чип семейства ST, а при наличии опыта — и под другие архитектуры.&lt;hr&gt;&lt;h3&gt;Слой 2: Интеллект — зрение для лазера&lt;/h3&gt;&lt;p&gt;LPP — это не тупой плеер G-кодов. Это система с полноценной обратной связью, где цифровой проект встречается с реальным железом через умный мост. И здесь кроется ещё один ответ на вопрос «почему растр, а не G-code».&lt;p&gt;Растровое представление позволяет:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Предварительно трансформировать все слои проекта в единый массив данных.&lt;li&gt;&lt;p&gt;Применять геометрическое преобразование ко всему изображению целиком, а не к каждой траектории по отдельности.&lt;li&gt;&lt;p&gt;Компенсировать искажения механики на уровне пикселей — то, что практически невозможно реализовать через G-code.&lt;/ol&gt;&lt;h4&gt;Двойная точность: нейросеть + собственный алгоритм центровки&lt;/h4&gt;&lt;p&gt;Мы разделили задачи совмещения на два независимых контура, чтобы выжать максимум точности.&lt;p&gt;&lt;strong&gt;1. Видео (реальность) — нейросетевой захват&lt;/strong&gt;&lt;p&gt;В окне видеопотока работает YOLOv8-Nano. Нейросеть в реальном времени сканирует кадр, отмечает все найденные сверловки квадратами и показывает процент уверенности для каждой. При нажатии кнопки «авто центр» ближайшая сверловка автоматически центрируется по центру кадра. Даже если плата залита флюсом, бликует или лежит в тени.&lt;p&gt;Важный нюанс: модель обучена всего на &lt;strong&gt;~100 примерах&lt;/strong&gt; (при норме в 10 000) и уже даёт стабильный результат в жёстких условиях. Причём модель не «зашита навсегда» — вы можете дообучить её под свои платы с нестандартной топологией, используя собственные датасеты и облачное обучение.&lt;p&gt;&lt;strong&gt;2. Gerber (идеал) — собственный алгоритм центровки&lt;/strong&gt;&lt;p&gt;Параллельно программа анализирует сам проект. Здесь стоит рассказать отдельно, потому что путь к решению был нетривиальным.&lt;p&gt;Сначала мы попробовали классический алгоритм Хафа — стандарт для поиска окружностей в компьютерном зрении. Он оказался недостаточно гибким: хорошо работает только с идеальными кругами, а реальные пады в Gerber далеко не всегда таковы. Рассматривали нейросети — но это было бы избыточно для задачи поиска геометрического центра в растре. В итоге реализовали &lt;strong&gt;собственный алгоритм&lt;/strong&gt;, который уверенно распознаёт пады с минимальным количеством ошибок и доведён почти до предельной точности.&lt;p&gt;Вот как выглядит debug-режим — система показывает, как именно она «видит» каждый пад:&lt;br&gt;&lt;br&gt;&lt;em&gt;Debug-режим: визуализация процесса поиска центра каждого пада в Gerber-файле.&lt;/em&gt;&lt;br&gt;&lt;em&gt;Зеленый круг это найденный самый ближний к центру пад Желтый крестик это где кликнули то есть ищем.&lt;/em&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/0d5/d4b/639/0d5d4b639ba094206d014f0000627186.jpg width=468 height=468 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/0d5/d4b/639/0d5d4b639ba094206d014f0000627186.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/0d5/d4b/639/0d5d4b639ba094206d014f0000627186.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/3c5/35d/949/3c535d949b41bbb3dfe41088bc8e9462.jpg width=468 height=468 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/3c5/35d/949/3c535d949b41bbb3dfe41088bc8e9462.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/3c5/35d/949/3c535d949b41bbb3dfe41088bc8e9462.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;a href=https://rutube.ru/video/143bfd280a8439deb5a88907a09be093/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Автокоррекция курсора в растровом режиме&lt;/strong&gt;&lt;/a&gt; Смотреть на RuTube ~2 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c6515b1ed1c734eb4ad19 data-style id=6a3c6515b1ed1c734eb4ad19 width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Результат:&lt;/strong&gt; система совмещает «грязную» реальность из камеры с «идеальным» проектом. Это даёт точность, недоступную при ручном наведении.&lt;h4&gt;Макровиктор: финальный аккорд перед печатью&lt;/h4&gt;&lt;p&gt;Главный страх инженера — нажать «Старт» и понять, что промахнулся. В LPP есть режим &lt;strong&gt;Макровиктор&lt;/strong&gt;.&lt;p&gt;Программа накладывает виртуальный Gerber-слой прямо на живое видео с камеры. Система работает в обе стороны: кликаете по плате в интерфейсе — станок перемещается в эту точку, двигаете каретку вручную — положение сразу отображается на экране. Вы видите, куда именно ударит лазер, до каждого пикселя, ещё до того как нажали «Старт».&lt;p&gt;&lt;a href=https://rutube.ru/video/be981aa813e24b16e67e90919746f178/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Синхронное управление и визуальный контроль&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;Смотреть на RuTube · ~2 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c657d6358d8af314dd7ea data-style id=6a3c657d6358d8af314dd7ea width data-habr-games&gt;&lt;/div&gt;&lt;h4&gt;Коррекция образа: финальная настройка перед печатью&lt;/h4&gt;&lt;p&gt;После совмещения образов — последний штрих перед запуском. В LPP есть инструменты тонкой коррекции шаблона:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Шумы&lt;/strong&gt; — удаление одиночных пикселей, которые могут дать артефакты при экспонировании.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Толщина X / Толщина Y&lt;/strong&gt; — раздельная настройка толщины линий по осям (в пикселях, в плюс или минус).&lt;/ul&gt;&lt;p&gt;Лазерное пятно редко бывает идеально круглым, да и механика станка может давать небольшую погрешность по одной из осей. Раздельная настройка позволяет компенсировать всё это программно: шаблон корректируется до печати — чуть сужается или расширяется по нужной оси — так что после экспонирования дорожки и контактные площадки получаются именно той геометрии, которая задана в файле.&lt;hr&gt;&lt;h3&gt;Слой 3: Python Bridge — станок выходит в сеть&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Python Bridge&lt;/strong&gt; — это полноценная сетевая архитектура.&lt;p&gt;Единый мост берёт на себя сразу две роли: &lt;strong&gt;HID-мост&lt;/strong&gt; (управление станком) и &lt;strong&gt;видео-мост&lt;/strong&gt; (поток с камеры). Внутри — полноценный сниффер и декодер пакетов. Вы можете в любой момент открыть веб-интерфейс и посмотреть, что происходит «под капотом»: какие команды идут на станок, что творится с видеопотоком, где затык.&lt;p&gt;Веб-интерфейс открывается в любом браузере — на компьютере, планшете или телефоне, и работает одновременно на всех устройствах. Пока станок выполняет задачу, процесс можно наблюдать с ПК, телефона или даже вывести на телевизор с браузером в цеху. Смартфон при этом превращается в живое видеоокно в руках — можно менять ракурс и фокус камеры прямо на ходу. Запустил печать — и спокойно ушёл, например, на кухню пить чай, продолжая наблюдать за процессом со смартфона. Всё остаётся под контролем без привязки к рабочему месту.&lt;p&gt;Два интерфейса в браузере:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Монитор камеры и печати&lt;/strong&gt; — видите всё то же, что и в основном приложении, с любого устройства в сети, параллельно на любом количестве устройств. А если основная программа не запущена — видеопоток с камеры можно открыть прямо из браузера, без запуска LPP.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Сниффер пакетов&lt;/strong&gt; — для тех, кто хочет понять протокол или отладить интеграцию.&lt;/ul&gt;&lt;p&gt;&lt;a href=https://rutube.ru/video/f1b9bca169c69aab0714286ce21ee118/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Сниффер пакетов и веб-интерфейс&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;Смотреть на RuTube&lt;strong&gt;&lt;/strong&gt; · ~41 сек&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c65a26358d8af314dd7f2 data-style id=6a3c65a26358d8af314dd7f2 width data-habr-games&gt;&lt;/div&gt;&lt;h4&gt;Работа по сети: два компьютера, два роутера&lt;/h4&gt;&lt;p&gt;На видео ниже — реальный сценарий: два Windows-компьютера соединены через Wi-Fi через два роутера. Одновременно идёт видеопоток с камеры и удалённое управление печатью — без заметных задержек.&lt;p&gt;&lt;a href=https://rutube.ru/video/3c256789bdbb9119f7ba68359bbf44e4/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Удалённая печать по Wi-Fi через два роутера&lt;/strong&gt;&lt;/a&gt; Смотреть на RuTube ~2 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c65c2d7a1bd73279fa946 data-style id=6a3c65c2d7a1bd73279fa946 width data-habr-games&gt;&lt;/div&gt;&lt;h4&gt;А что насчёт Raspberry Pi?&lt;/h4&gt;&lt;p&gt;Мост запускается и на малине — вот скриншот с реальной машины. Сразу честно: при одновременной работе видеопотока и HID-моста по сети Raspberry Pi 3B уходит на &lt;strong&gt;~80% загрузки CPU&lt;/strong&gt;.&lt;p&gt;&lt;em&gt;Raspberry Pi 3B: загрузка CPU при одновременной работе видеопотока и HID-моста.&lt;/em&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/949/072/c32/949072c32a43bb1e73facffccdc378bc.jpg width=973 height=269 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/949/072/c32/949072c32a43bb1e73facffccdc378bc.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/949/072/c32/949072c32a43bb1e73facffccdc378bc.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Это важно учитывать при выборе железа для автономного узла — Pi справляется, но запас небольшой. Зато станок превращается в полноценное IoT-устройство без привязки к рабочему месту.&lt;h4&gt;Linux-way&lt;/h4&gt;&lt;p&gt;Для стабильной работы с видеозахватом в среде Linux реализована связка: Wine занимается UI и логикой, Python Bridge — потоком данных и железом. Классический «чёрный экран» Wine с драйверами видеозахвата больше не проблема.&lt;hr&gt;&lt;h3&gt;Как это выглядит на практике: весь цикл&lt;/h3&gt;&lt;p&gt;Забудьте о долгой калибровке механики. Реальный процесс работы выглядит так:&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Импорт&lt;/strong&gt; — загружаем файлы Gerber (RS-274X/X2), Excellon или растровые изображения практически любого формата, который вы только вспомните: JPEG, PNG, BMP, TIFF, WebP, SVG, HEIC, AVIF, JPEG XL, PSD, PSB, DICOM и многие другие. Если ваш графический редактор умеет его сохранять — LPP умеет его открывать. Можно несколько файлов сразу.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Слои&lt;/strong&gt; — расставляем по Z-порядку и позиционируем по осям X/Y.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Привязка&lt;/strong&gt; — выбираем три точки на заготовке. Нейросеть находит их центры, математика вычисляет матрицу трансформации.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Верификация&lt;/strong&gt; — через Макровиктор смотрим, куда попадёт лазер. Управляем кареткой прямо мышкой в окне предпросмотра.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Печать&lt;/strong&gt; — нажимаем «Старт» и получаем результат.&lt;/ol&gt;&lt;p&gt;На практике это сводит количество испорченных плат почти к нулю.&lt;hr&gt;&lt;h3&gt;Итоги&lt;/h3&gt;&lt;p&gt;LPP сдвигает задачу из области прецизионной механики в область вычислений. Точность больше не зависит от жёсткости станины и качества китайских ремней.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Параметр&lt;th&gt;&lt;p align=left&gt;Что это значит&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Платформа&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;LPP-Laser (сейчас) + LPP-CNC (в разработке)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Форматы&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Gerber (X2), Excellon + любой растровый формат (JPEG, PNG, PSD, SVG, HEIC, AVIF и др.)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Моторы&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Шаговые, DC, BLDC, H-мосты — любые&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Скорость&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;1 м/с и более на BLDC или DC с энкодером&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Контроллеры&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;STM32 F103/F401/F411/G431 (Blue/Black Pill)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Режимы&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;FULL (мощные ПК) и LITE (слабое железо)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Точность&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Нейросеть + собственный алгоритм + видеоверификация&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;SDK&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Открытый, адаптируется под любой контроллер&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Сеть&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Python Bridge — управление станком из любой точки&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;Полная поддержка, Wine + Python Bridge&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Мы не ждём, пока индустрия выпустит доступные фотоплоттеры. Мы берём то, что есть под рукой, и заставляем это печатать прецизионные платы прямо сейчас.&lt;hr&gt;&lt;p&gt;&lt;a href=https://rutube.ru/video/0f26ad9463201d4bee8ec9249de0d3e5/ rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;▶ Полный гайд по настройке системы&lt;/strong&gt;&lt;/a&gt; Смотреть на RuTube ~25 мин&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c6606d7a1bd73279fa95e data-style id=6a3c6606d7a1bd73279fa95e width data-habr-games&gt;&lt;/div&gt;&lt;hr&gt;&lt;h3&gt;Ресурсы проекта LPP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Telegram-канал&lt;/strong&gt; (новости и релизы): &lt;a href=https://t.me/LPP_Printer rel=&#34;noopener noreferrer nofollow&#34;&gt;t.me/LPP_Printer&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Telegram-чат&lt;/strong&gt; (вопросы и поддержка): &lt;a href=https://t.me/LPP_Printer_Chat rel=&#34;noopener noreferrer nofollow&#34;&gt;t.me/LPP_Printer_Chat&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt; (SDK, прошивки, схемы, PCB): &lt;a href=https://github.com/DimaFantasy/LPP rel=&#34;noopener noreferrer nofollow&#34;&gt;github.com/DimaFantasy/LPP&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;Для пользователей из России — те же каналы доступны в &lt;strong&gt;MAX&lt;/strong&gt; (российский мессенджер, альтернатива Telegram):&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAX-канал&lt;/strong&gt; (новости): &lt;a href=https://max.ru/join/Jn9sSW9uAUTXzenlr34leJJz7e5KI5dm5hYQMj7hXq0 rel=&#34;noopener noreferrer nofollow&#34;&gt;ссылка&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAX-чат&lt;/strong&gt; (поддержка): &lt;a href=https://max.ru/join/J1DPXRmEODSoVShlstQhKDIgxk-qHipwyf1UhGpg8B8 rel=&#34;noopener noreferrer nofollow&#34;&gt;ссылка&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;Все видео также доступны на &lt;a href=https://www.youtube.com/@FantasyDD1 rel=&#34;noopener noreferrer nofollow&#34;&gt;YouTube-канале проекта&lt;/a&gt;.&lt;hr&gt;&lt;p&gt;&lt;em&gt;А вы пробовали управлять станком по сети? Расскажите в комментариях — интересно сравнить подходы.&lt;/em&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>FantasyDD</author>
      <guid>https://habr.com/ru/articles/1051624/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051624</guid>
      <pubDate>Thu, 25 Jun 2026 00:03:18 +0000</pubDate>
    </item>
    <item>
      <title>Как создать рекламный баннер с помощью нейросети — Сравниваем ТОП-6 ИИ для баннеров</title>
      <link>https://habr.com/ru/companies/studyai/articles/1051468/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051468</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;strong&gt;Сделать рекламный баннер с помощью нейросети&lt;/strong&gt; сегодня пытается почти каждый, однако на практике этот процесс часто превращается в бесконечную борьбу с «галлюцинациями» моделей и безуспешные попытки добиться от них корректного текста. Еще относительно недавно мы воспринимали генеративный арт как любопытную игрушку, а сегодня это уже полноценный рабочий инструмент, который либо кардинально сокращает время на прототипирование, либо заставляет часами исправлять артефакты, пытаясь «причесать» результат под стандарты индустрии.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2d3/f7f/ed8/2d3f7fed87a949f15ee45572609aa85f.png width=1024 height=572 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2d3/f7f/ed8/2d3f7fed87a949f15ee45572609aa85f.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2d3/f7f/ed8/2d3f7fed87a949f15ee45572609aa85f.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Реальные бизнес-задачи требуют не просто эстетичной картинки, а строгого соблюдения композиции, смысловой точности и технического качества. В этом материале я предлагаю отбросить маркетинговый шум и провести стресс-тест шести популярных решений - от признанных лидеров рынка до нишевых инструментов. Цель проста: выяснить, кто из них действительно готов к продакшену, а кто годится лишь для генерации абстрактных фонов.&lt;p&gt;Мы разберем, как эти модели справляются с типографикой, насколько предсказуемо они держат композицию под рекламные плейсменты и стоит ли доверять ИИ создание креативов «под ключ» прямо сейчас. Погнали.&lt;hr&gt;&lt;h3&gt;Почему создание рекламных баннеров через ИИ - это не просто картинка&lt;/h3&gt;&lt;p&gt;Создание креатива через нейросеть фундаментально отличается от генерации «арта для души». Чтобы баннер работал на бизнес-задачи, мы тестируем модели по трем жестким критериям:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Композиционная иерархия.&lt;/strong&gt; Рекламный баннер - это не только визуал, но и «воздух» для текста, логотипа и CTA. Многие модели увлекаются детализацией, полностью убивая пространство для верстки. Мы ищем те, что «понимают» концепцию негативного пространства.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Типографика.&lt;/strong&gt; Главная боль генеративного дизайна. Если на баннере есть текст, в 90% случаев это «галлюцинация» - набор символов, которые невозможно прочитать. Наша задача - отсеять тех, кто выдает «красивую мазню», и найти инструменты, способные на корректный рендеринг текста.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Техническая пригодность.&lt;/strong&gt; Рекламные плейсменты требуют специфических форматов (от 16:9 до узких вертикальных блоков). Любая «грязная» пикселизация или ошибки в тенях делают креатив дешевым, что фатально для CTR.&lt;/ul&gt;&lt;p&gt;Мы оцениваем модели не по эстетике, а по готовности к реальному продакшену - либо как самостоятельное решение, либо как базу для финальной доработки в графическом редакторе.&lt;hr&gt;&lt;h3&gt;Промпты для создания рекламных баннеров и генерация креативов для брендов&lt;/h3&gt;&lt;p&gt;Вот адаптация наших стилей под твои конкретные бренды. Здесь важно сохранить узнаваемость продукта и при этом придать картинке «рекламный глянец», который так сложно вытянуть из стоков.&lt;h3&gt;1. Вискас: Уютный реализм (Стиль: Lifestyle-фотография)&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Концепция:&lt;/strong&gt; Для корма важна ассоциация с домашним комфортом и здоровьем питомца. Мы уходим от стерильных студий в сторону теплого, «лампового» света.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Идеально для:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;Midjourney, Photo Generator&lt;/em&gt;&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/1f4/d88/9f1/1f4d889f1d6fe72650e5f47af5bd29e4.png width=1024 height=572 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/1f4/d88/9f1/1f4d889f1d6fe72650e5f47af5bd29e4.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/1f4/d88/9f1/1f4d889f1d6fe72650e5f47af5bd29e4.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;&lt;strong&gt;Пример Промта&lt;/strong&gt;: Close-up shot of a happy, fluffy cat eating Whiskas-style food from a ceramic bowl on a warm wooden floor, soft morning sunlight coming through the window, bokeh background of a cozy kitchen, warm golden tones, high quality food photography, ultra-realistic fur textures, depth of field, commercial lifestyle ad style --ar 16:9 --v 6.0&lt;/code&gt;&lt;/blockquote&gt;&lt;h4&gt;2. Чипсы: Взрывной драйв (Стиль: Dynamic Action)&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Концепция:&lt;/strong&gt; Чипсы - это эмоции и шум. Стиль «взрыва» подчеркивает хруст и интенсивный вкус. Мы используем темный фон, чтобы сделать упаковку и летящие кусочки максимально контрастными.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Идеально для:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;Nano Banana Pro, Seedream 5.0 Lite&lt;/em&gt;&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/ea7/9a6/ba4/ea79a6ba4c4094d2ffec01d1dca5d4b8.png width=1024 height=559 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/ea7/9a6/ba4/ea79a6ba4c4094d2ffec01d1dca5d4b8.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/ea7/9a6/ba4/ea79a6ba4c4094d2ffec01d1dca5d4b8.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;&lt;strong&gt;Пример Промта:&lt;/strong&gt;High-speed professional product photography of an exploding bag of potato chips, crispy chips flying in the air, seasoning and salt particles scattering, dynamic motion blur, dramatic studio rim lighting, dark moody background, high-end advertising aesthetic, sharp focus on the branding, 8k resolution, cinematic commercial look&lt;/code&gt;&lt;/blockquote&gt;&lt;h3&gt;3. Альфа-Банк: Технологичный минимализм (Стиль: Современный Fintech)&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Концепция:&lt;/strong&gt; Банк - это про уверенность, красный цвет (фирменный стиль) и технологии. Здесь мы делаем упор на минимализм, геометрию и «дорогой» свет.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Идеально для:&lt;/strong&gt; &lt;a href=&#34;https://eduforms.ru/?rid=958dcc76599889db&amp;amp;erid=2SDnjdymiBc&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fdalle_3_toe_bot&#34;&gt;&lt;strong&gt;&lt;em&gt;D&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;ALL·E 3, GPT Image 2&lt;/em&gt;&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/804/f59/8ca/804f598ca09f4f42ec8560f252b79c2f.png width=2048 height=1152 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/804/f59/8ca/804f598ca09f4f42ec8560f252b79c2f.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/804/f59/8ca/804f598ca09f4f42ec8560f252b79c2f.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;&lt;strong&gt;Пример промта: &lt;/strong&gt;Professional advertising studio shot of a premium banking debit card, clean minimalist composition, solid red background with subtle gradient lighting, elegant glass and chrome elements around, soft professional shadows, modern fintech aesthetic, high-tech vibe, sharp focus on the card design, photorealistic, 8k, advertising studio photography&lt;/code&gt;&lt;/blockquote&gt;&lt;hr&gt;&lt;h2&gt;ТОП-6 Нейросетей для создания рекламного банера&lt;/h2&gt;&lt;p&gt;Вот список инструментов, которые мы взяли в работу. Каждый из них занял свою нишу в процессе подготовки креативов:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nano Banana Pro&lt;/strong&gt; - выдает профессиональную картинку с высокой детализацией, идеально подходит для создания фотореалистичных визуалов и сложных рекламных сцен.&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPT Image 2&lt;/strong&gt; - лучший выбор, когда критически важно корректно отобразить текст прямо на баннере без последующей «докрутки» в Photoshop.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Midjourney&lt;/strong&gt; - безусловный лидер по части эстетики, стиля и композиционных решений, незаменим для имиджевых рекламных кампаний.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seedream 5.0 Lite&lt;/strong&gt; - инструмент с упором на актуальность, который умеет интегрировать в баннер свежие инфоповоды и тренды из сети.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Photo Generator (от StudyAI)&lt;/strong&gt; - профильный инструмент для работы с фотореализмом и естественными позами персонажей, отлично заходит для UGC-рекламы.&lt;li&gt;&lt;p&gt;&lt;strong&gt;DALL·E 3&lt;/strong&gt; - самая послушная модель, которая максимально точно следует многослойным инструкциям и сложным техническим заданиям.&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;1. Nano Banana Pro - профессиональный фотореализм 📸&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с Nano Banana Pro&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a83/b40/ecb/a83b40ecbb567f273b5bbd41ad2e1400.png width=2048 height=1152 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a83/b40/ecb/a83b40ecbb567f273b5bbd41ad2e1400.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a83/b40/ecb/a83b40ecbb567f273b5bbd41ad2e1400.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Nano Banana Pro &lt;/strong&gt;- это премиальный инструмент, созданный для тех, кому важна «стерильная» коммерческая чистота изображения. Модель специализируется на сложной физике материалов: она безупречно рендерит блики на стекле, фактуру тканей и динамику жидкостей, создавая картинку уровня высокобюджетной студийной съемки. Благодаря мощному движку просчета глубины резкости, баннеры получаются объемными и глубокими, что критически важно для привлечения внимания в перегруженных рекламных лентах. Инструмент практически не требует пост-обработки по части цветокоррекции, выдавая готовый «продающий» кадр сразу после генерации.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Физически корректный рендер освещения и теней&lt;li&gt;&lt;p&gt;Генерация текстур в высоком разрешении (до 4K)&lt;li&gt;&lt;p&gt;Продвинутое управление глубиной резкости (bokeh)&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Идеальный фотореализм без «пластиковых» артефактов&lt;li&gt;&lt;p&gt;Профессиональный коммерческий лук «из коробки» без лишних доработок&lt;li&gt;&lt;p&gt;Отличная работа с динамическими сценами и эффектами взрывов или брызг&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Высокие требования к детализации промпта для получения нужного освещения&lt;li&gt;&lt;p&gt;Сложность в освоении для новичков, привыкших к простым командам&lt;li&gt;&lt;p&gt;Относительно высокая стоимость обработки тяжелых визуальных сцен&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;👤Для кого подходит: &lt;/strong&gt;Профессиональным продакшн-студиям и брендам для создания имиджевой рекламы, где важна каждая деталь.&lt;p&gt;&lt;strong&gt;Пример промта&lt;/strong&gt; &lt;code&gt;Professional high-end product photography of a premium bag of potato chips exploding in mid-air. Dramatic motion blur of flying crispy chips, scattering sea salt particles and seasoning dust. Dramatic side-rim lighting, dark moody studio background to enhance the product pop. Commercial macro photography, 100mm lens, f/8, ultra-sharp focus on the brand packaging, hyper-realistic textures, 8k, cinematic color grading, advertising quality.&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;2. GPT Image 2 - точная генерация банера 🎯&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с GPT Image 2&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/9d7/50f/71d/9d750f71d2491f1e8653672c7ada6caa.png width=2048 height=1152 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/9d7/50f/71d/9d750f71d2491f1e8653672c7ada6caa.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/9d7/50f/71d/9d750f71d2491f1e8653672c7ada6caa.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;GPT Image 2&lt;/strong&gt; - это, пожалуй, самый «инженерный» инструмент в нашем списке, ориентированный на выполнение строгих архитектурных требований. Модель обладает глубоким пониманием композиции и визуальной иерархии, что позволяет ей создавать макеты с четким разделением на зоны для заголовка, графики и призыва к действию. Она практически не галлюцинирует в плане верстки и отлично справляется с задачей «впечатывания» текста прямо в полотно баннера. Это делает ее незаменимым инструментом для быстрой подготовки рекламных концептов, где важно сразу увидеть, как текст взаимодействует с фоновым изображением.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Генерация текстовых надписей с высокой читабельностью&lt;li&gt;&lt;p&gt;Анализ «зон интереса» для автоматического размещения элементов&lt;li&gt;&lt;p&gt;Работа с многоязычной типографикой без искажения символов&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Экономит время на верстку в Photoshop благодаря готовым макетам&lt;li&gt;&lt;p&gt;Высокая предсказуемость результата при соблюдении структуры промпта&lt;li&gt;&lt;p&gt;Понимание сложных инструкций по типографике и расположению элементов&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Стилистически может проигрывать более художественным моделям&lt;li&gt;&lt;p&gt;Требует четких указаний по шрифтовым парам для идеального результата&lt;li&gt;&lt;p&gt;Имеет меньший запас творческой свободы в сравнении с конкурентами&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;👤Для кого подходит:&lt;/strong&gt; Маркетологам и дизайнерам для создания рекламных баннеров, афиш и презентационных материалов, где важен текст.&lt;p&gt;&lt;strong&gt;Пример промта:&lt;/strong&gt; &lt;code&gt;Horizontal advertising banner (16:9 aspect ratio) for a premium natural yogurt brand. Center-aligned product photography of a glass yogurt cup, fresh blueberries and strawberries scattered artfully around, soft morning light, minimalist high-key white studio background. Professional typography at the center in bold elegant serif font: &amp;#34;Pure Taste&amp;#34;. High contrast, sharp focus on the product, 8k resolution, clean composition, commercial food advertising aesthetic, no distortion, hyper-detailed.&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;3. Midjourney (v6+) - король стиля и эстетики 👑&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с Midjourney&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/453/3d6/123/4533d6123783e9f462c615e158ddb4c0.png width=1024 height=559 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/453/3d6/123/4533d6123783e9f462c615e158ddb4c0.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/453/3d6/123/4533d6123783e9f462c615e158ddb4c0.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Midjourney&lt;/strong&gt; остается абсолютным эталоном в мире генеративного искусства, когда речь заходит о поиске уникального визуального языка. Эта модель не просто копирует реальность, а интерпретирует ее через призму художественных стилей, что позволяет создавать баннеры с глубокой эмоциональной окраской. Она великолепно работает с цветовыми палитрами, композиционными правилами и сложными световыми сценариями, которые превращают обычный продукт в объект желания. Несмотря на сложности с текстом, она остается выбором номер один для имиджевых кампаний, где визуальный «вау-эффект» важнее, чем читаемость логотипа.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Работа с референсами стиля и структуры через специальные параметры&lt;li&gt;&lt;p&gt;Глубокая настройка художественных фильтров и параметров освещения&lt;li&gt;&lt;p&gt;Создание сюрреалистичных и высокохудожественных композиций под любые задачи&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Непревзойденная эстетика и качество визуального ряда на рынке&lt;li&gt;&lt;p&gt;Огромное сообщество, генерирующее бесконечные стилистические пресеты&lt;li&gt;&lt;p&gt;Интуитивная работа с абстрактными понятиями и сложными визуальными образами&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Плохая работа с конкретными буквами, логотипами и длинным текстом&lt;li&gt;&lt;p&gt;Сложность воспроизведения идентичного объекта в серии кадров без фиксации&lt;li&gt;&lt;p&gt;Отсутствие встроенных инструментов для точной верстки рекламных материалов&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Для кого подходит: &lt;/strong&gt;Арт-директорам, иллюстраторам и брендам, стремящимся к созданию уникального стиля, который выделяется из общего потока.&lt;p&gt;&lt;strong&gt;Пример промта:&lt;/strong&gt; &lt;code&gt;Professional advertising studio shot of a luxury perfume bottle placed on a reflective glass surface, night city neon lights in the background, cinematic bokeh, deep shadows, electric blue and hot pink color palette, reflections of lights on the glass bottle, sharp focus on the brand product, minimalist composition, luxury branding photography, high contrast&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;4. Seedream 5.0 Lite - адаптация под тренды 🚀&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с&lt;/strong&gt; &lt;a href=&#34;https://eduforms.ru?rid=958dcc76599889db&amp;amp;erid=2SDnjdymiBc&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fseedream_5&#34;&gt;&lt;strong&gt;Seedream 5.0 Lite&lt;/strong&gt;&lt;/a&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4e/603/ea8/c4e603ea8b5866b59c836ca00af13c97.png width=1024 height=572 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c4e/603/ea8/c4e603ea8b5866b59c836ca00af13c97.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4e/603/ea8/c4e603ea8b5866b59c836ca00af13c97.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Seedream 5.0 Lite &lt;/strong&gt;- это динамичная модель для тех, кто живет в режиме реального времени и требует от дизайна актуальности. Благодаря встроенным алгоритмам анализа трендов, нейросеть умеет вплетать в баннеры актуальные инфоповоды, культурные мемы и свежие визуальные стили, которые популярны в сети «прямо сейчас». Это делает ее идеальным инструментом для SMM и ситуативного маркетинга, где важно быть на волне последних событий. Модель быстро обучается контексту и легко переключается между различными жанрами: от поп-арт графики до строгой инфографики.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Поиск и анализ актуальных трендов и визуальных стилей в сети&lt;li&gt;&lt;p&gt;Быстрая адаптация под изменения в дизайне и визуальных стандартах&lt;li&gt;&lt;p&gt;Универсальность при работе с различными жанрами графики&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Позволяет делать «ситуативный» контент за считанные минуты&lt;li&gt;&lt;p&gt;Хорошее понимание контекста и физики объектов в сценах&lt;li&gt;&lt;p&gt;Легкость в освоении для контент-менеджеров без навыков дизайна&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Уступает лидерам рынка по части глубокой художественной детализации&lt;li&gt;&lt;p&gt;Требует постоянного контроля актуальности запросов для попадания в тренд&lt;li&gt;&lt;p&gt;Имеет меньший контроль над специфическими техническими параметрами&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Для кого подходит: &lt;/strong&gt;SMM-щикам, контент-мейкерам и специалистам по ситуативному маркетингу.&lt;p&gt;&lt;strong&gt;Пример промта:&lt;/strong&gt; &lt;code&gt;Vibrant, high-energy advertising banner for a cola brand. Refreshing glass of cola full of ice cubes, refreshing water droplets on the glass, tropical beach vibe background with bright summer sunlight. Dynamic composition, motion blur of splashing water, vivid neon-color palette, high-end commercial aesthetic, trending summer social media campaign style, sharp focus, 8k resolution, professional studio retouching --ar 16:9&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;5. DALL·E 3 - идеальное следование ТЗ ✅&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с DALL·E 3&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/671/853/b19/671853b19db8be373c50daa50690c349.png width=2048 height=2048 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/671/853/b19/671853b19db8be373c50daa50690c349.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/671/853/b19/671853b19db8be373c50daa50690c349.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;DALL·E 3 - &lt;/strong&gt;это «послушный» инструмент, который воспринимает промпты как прямое техническое задание, а не как повод для художественных экспериментов. Модель обладает уникальной способностью переводить сложные, многослойные описания в визуальный ряд с поразительной точностью, минимизируя необходимость «докручивать» результат. Она лучше других справляется с интеграцией абстрактных бизнес-метафор в конкретные визуальные образы, что делает ее незаменимой при работе со строгими брендбуками. В связке с диалоговым интерфейсом она позволяет уточнять детали баннера буквально «в процессе разговора», что упрощает работу над сложными проектами.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Точное выполнение детализированных технических заданий любой сложности&lt;li&gt;&lt;p&gt;Интеграция с текстовым интерфейсом для итерационных правок в ходе диалога&lt;li&gt;&lt;p&gt;Глубокое понимание связей между объектами в сложной сцене&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Минимальный порог вхождения: модель понимает обычный разговорный язык&lt;li&gt;&lt;p&gt;Высокая точность попадания в заданные условия по цвету и композиции&lt;li&gt;&lt;p&gt;Отсутствие необходимости изучать специфический технический «язык промптов»&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Склонность к излишней «идеализации» (картинки часто выглядят слишком прилизанными)&lt;li&gt;&lt;p&gt;Ограниченный контроль над некоторыми глубокими художественными настройками&lt;li&gt;&lt;p&gt;Зависимость от текстового контекста при генерации сложных сцен&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Для кого подходит: &lt;/strong&gt;Тем, кому важен предсказуемый результат в сжатые сроки без долгого обучения инструментарию.&lt;p&gt;&lt;strong&gt;Пример промта:&lt;/strong&gt; &lt;code&gt;Professional advertising studio shot of a premium banking debit card, clean minimalist composition, solid signature red background with a subtle diagonal gradient light effect. Elegant glass and chrome textures surrounding the card, soft professional drop shadows. High-tech fintech vibe, sharp focus on the card design and embossing, photorealistic, 8k, minimal clutter, commercial studio photography, perfectly balanced lighting --ar 16:9&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;6. Photo Generator (StudyAI) - реалистичность для соцсетей 🤳&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Создать рекламный баннер с Photo Generator (от StudyAI)&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/063/6f5/2ac/0636f52acb1c46193162b732f764587e.png width=2048 height=2048 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/063/6f5/2ac/0636f52acb1c46193162b732f764587e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/063/6f5/2ac/0636f52acb1c46193162b732f764587e.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Photo Generator от StudyAI -&lt;/strong&gt; это инструмент, сфокусированный на «человечности» и естественности рекламного контента. В отличие от тяжелых 3D-моделей, эта нейросеть делает упор на создание сцен, которые выглядят как живые снимки, сделанные обычными людьми или профессиональными фотографами для соцсетей. Модель отлично работает с мимикой, естественными позами и неформальной обстановкой, что позволяет создавать рекламу, вызывающую высокий уровень доверия у аудитории. Это идеальное решение для создания контента в стиле «lifestyle», где чрезмерная студийная обработка может, наоборот, оттолкнуть потенциального клиента.&lt;p&gt;&lt;strong&gt;Возможности&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Генерация естественных и живых человеческих лиц с правильной мимикой&lt;li&gt;&lt;p&gt;Создание контента в стиле «жизненных ситуаций» и lifestyle-фотографий&lt;li&gt;&lt;p&gt;Упрощенная работа с композицией для мобильных форматов социальных сетей&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;✅Преимущества&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Контент выглядит аутентично, а не как «стерильный» ИИ-рендер&lt;li&gt;&lt;p&gt;Высокое доверие аудитории за счет естественного визуального ряда&lt;li&gt;&lt;p&gt;Отлично подходит для таргетированной рекламы, работающей на эмоциях&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;❌Недостатки&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ограниченный набор инструментов для глубокой технической правки сцены&lt;li&gt;&lt;p&gt;Меньше контроля над сложной профессиональной студийной композицией&lt;li&gt;&lt;p&gt;Меньшая универсальность в сравнении с крупными моделями&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Для кого подходит: &lt;/strong&gt;Арбитражникам, таргетологам и SMM-специалистам для создания доверительной и «живой» рекламы.&lt;p&gt;&lt;strong&gt;Пример промта&lt;/strong&gt; &lt;code&gt;Authentic candid shot of a happy person holding a modern smartphone displaying a clean banking application interface. Bright, airy modern office background with soft defocused corporate architecture. Authentic natural smile, cinematic lighting with soft natural shadows, mobile advertising style, shot on 35mm, realistic skin textures, high clarity, UGC content aesthetic, relatable human-centered composition --ar 16:9&lt;/code&gt;&lt;hr&gt;&lt;h3&gt;🛠 Пошаговый план создания рекламного баннера с ИИ&lt;/h3&gt;&lt;p&gt;Этот алгоритм поможет минимизировать итерации и получить результат, готовый к публикации, а не просто «красивую картинку».&lt;h4&gt;Шаг 1: Анализ задачи и выбор «Визуального языка»&lt;/h4&gt;&lt;p&gt;Прежде чем открыть нейросеть, ответьте на 3 вопроса:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Где размещается?&lt;/strong&gt; (ВК, Телеграм, рекламная сеть). От этого зависит композиция: будет ли логотип в центре или сбоку, нужно ли место под кнопку CTA.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Какая эмоция нужна?&lt;/strong&gt; (Эстетика, драйв, доверие, «аппетит»). Это определит, какой инструмент из списка выше мы берем.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Что будет «реальным», а что — «сгенерированным»?&lt;/strong&gt; (Золотое правило: пакшот продукта и логотип лучше накладывать сверху в графическом редакторе, а не пытаться генерировать их с нуля).&lt;/ul&gt;&lt;h4&gt;Шаг 2: Создание «Базового фона» через ИИ&lt;/h4&gt;&lt;p&gt;Используйте выбранную модель (например, &lt;em&gt;Nano Banana Pro&lt;/em&gt; для фуда или &lt;em&gt;Midjourney&lt;/em&gt; для имиджа) для генерации основы.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Лайфхак:&lt;/strong&gt; Генерируйте «чистый» фон без логотипа и мелкого текста, но с правильным освещением, которое совпадает с вашим реальным продуктом.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Технический совет:&lt;/strong&gt; Всегда закладывайте больше пространства вокруг объекта (Negative Space), чтобы баннер было удобно кадрировать под разные форматы (квадрат, сторис, широкий баннер).&lt;/ul&gt;&lt;h4&gt;Шаг 3: Техническая доработка (Inpainting)&lt;/h4&gt;&lt;p&gt;Если на картинке не хватает какой-то детали или есть лишний «артефакт»:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Используйте функцию &lt;strong&gt;Inpainting&lt;/strong&gt; (встроена во многие модели или доступна в Photoshop Generative Fill), чтобы «дорисовать» не хватающий свет, отражение или убрать лишние детали, которые модель нагаллюцинировала.&lt;/ul&gt;&lt;h4&gt;Шаг 4: Верстка и типографика (Figma / Photoshop)&lt;/h4&gt;&lt;p&gt;Это критический момент, на котором сыпется большинство «нейро-дизайнеров».&lt;ul&gt;&lt;li&gt;&lt;p&gt;Закидываем сгенерированный фон в графический редактор.&lt;li&gt;&lt;p&gt;Накладываем реальный PNG-пакшот продукта (или логотип) поверх.&lt;li&gt;&lt;p&gt;Добавляем CTA-кнопку и текст оффера, используя брендовые шрифты. ИИ пока не умеет идеально попадать в ваш корпоративный шрифт.&lt;/ul&gt;&lt;h4&gt;Шаг 5: Цветокоррекция и финальный «проклей»&lt;/h4&gt;&lt;p&gt;Иногда результат от ИИ выглядит «стерильно».&lt;ul&gt;&lt;li&gt;&lt;p&gt;Добавьте на финальный баннер легкий шум (Noise) или цветовой фильтр (LUT), чтобы объединить сгенерированный фон и реальный продукт в единую композицию.&lt;li&gt;&lt;p&gt;Проверьте баннер на «читаемость» в малом масштабе (на мобильном телефоне): не сливается ли текст с фоном?&lt;/ul&gt;&lt;h4&gt;Почему это работает:&lt;/h4&gt;&lt;p&gt;Этот план превращает нейросеть из «волшебной палочки» в &lt;strong&gt;часть производственного конвейера&lt;/strong&gt;. Читатели Хабра оценят именно этот системный подход, так как он снимает вопрос: &lt;em&gt;«Почему у меня не получается сделать крутой баннер одним промптом?»&lt;/em&gt;.&lt;hr&gt;&lt;h3&gt;Как выбрать лучшую нейросеть для создания рекламного баннера: критерии 2026 года 🎯&lt;/h3&gt;&lt;p&gt;Выбор инструмента зависит от специфики ваших задач. Ориентируйтесь на этот чек-лист, чтобы не тратить время на неподходящие модели:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Для имиджевой рекламы и арт-дирекшна:&lt;/strong&gt; Выбирайте &lt;strong&gt;Midjourney&lt;/strong&gt;. Это лучший инструмент для создания «вау-эффекта», уникального стиля и художественной глубины, которые выделяют бренд в ленте.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Для фуд-стайлинга и премиального товара:&lt;/strong&gt; Ваш выбор - &lt;strong&gt;Nano Banana Pro&lt;/strong&gt;. Нейросеть лучше всех справляется с текстурами, светом и физикой материалов (стекло, жидкость, хруст), создавая эффект дорогой фотосессии.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Для быстрой верстки и текста:&lt;/strong&gt; Используйте &lt;strong&gt;GPT Image 2&lt;/strong&gt; или &lt;strong&gt;DALL·E 3&lt;/strong&gt;. Эти модели наиболее предсказуемы при работе с типографикой и четким следованием техническому заданию (ТЗ).&lt;li&gt;&lt;p&gt;&lt;strong&gt;Для ситуативного маркетинга и инфоповодов:&lt;/strong&gt; Используйте &lt;strong&gt;Seedream 5.0 Lite&lt;/strong&gt;. Возможность интеграции актуальных трендов и данных из сети - ключевой фактор для SMM и быстрой адаптации рекламы.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Для «живой» рекламы и UGC:&lt;/strong&gt; Идеально подойдет &lt;strong&gt;Photo Generator (StudyAI)&lt;/strong&gt;. Он создает наиболее естественные человеческие образы, которые вызывают больше доверия у аудитории в таргете.&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;Промт-инжиниринг и пост-обработка: чек-лист создания продающих креативов 🚀&lt;/h3&gt;&lt;p&gt;Чтобы нейросеть стала частью вашего производственного конвейера, а не просто игрушкой, придерживайтесь этого алгоритма работы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Этап «Базовый визуальный слой»:&lt;/strong&gt; Используйте профессиональные промпты с указанием технических параметров: &lt;em&gt;«studio rim lighting», «macro lens», «f/8 focus», «8k resolution»&lt;/em&gt;. Это задает качество картинки еще на этапе генерации.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Правило «Чистого фона»:&lt;/strong&gt; Никогда не пытайтесь генерировать финальный баннер с готовым логотипом и текстом внутри ИИ. Генерируйте «чистый» эмоциональный фон, а брендинг добавляйте позже.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Верстка и типографика:&lt;/strong&gt; Всегда переносите сгенерированный результат в &lt;strong&gt;Figma или Photoshop&lt;/strong&gt;. Только там вы сможете идеально наложить реальный пакшот продукта и использовать фирменные шрифты вашего бренда.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Финальная «полировка»:&lt;/strong&gt; Объединяйте сгенерированный фон и реальный продукт с помощью легкой цветокоррекции, наложения шума (noise) или фильтров (LUT). Это убирает «стерильность» ИИ и делает композицию единой.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Тестирование на устройствах:&lt;/strong&gt; Всегда проверяйте читаемость текста на маленьких экранах. Если заголовок или оффер сливаются с фоном после генерации — значит, нужно корректировать контрастность в графическом редакторе, а не перегенерировать промпт.&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;Технические нюансы: как масштабировать и адаптировать креативы для рекламного банера🛠&lt;/h3&gt;&lt;p&gt;Даже самый качественный баннер теряет смысл, если он «размывается» на больших форматах или неверно отображается на устройствах. Этот блок поможет избежать типичных ошибок при подготовке финальных файлов.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upscaling (Апскейлинг):&lt;/strong&gt; Используйте специализированные инструменты (например, Magnific AI или встроенные функции Topaz) для повышения детализации до печати. Обычное растягивание картинки убьет все текстуры, которые вы так тщательно настраивали в промпте.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Адаптация форматов:&lt;/strong&gt; Всегда генерируйте исходник в чуть большем разрешении, чем нужно (с учетом «запаса» по краям). Это позволит легко кадрировать изображение под сторис (9:16), посты (1:1) и широкие баннеры (16:9) без потери ключевых объектов.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Цветовые профили:&lt;/strong&gt; Помните, что ИИ часто генерирует картинки в цветовом пространстве sRGB. Если вы готовите макет для печати, обязательно конвертируйте его в CMYK и проводите финальную цветокоррекцию, чтобы избежать неприятных сюрпризов при выводе на офсет.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вес и оптимизация:&lt;/strong&gt; Рекламные сети имеют жесткие лимиты по весу файла. Перед загрузкой баннера всегда прогоняйте его через оптимизаторы типа TinyPNG — это поможет сохранить высокое качество при минимально допустимом размере файла.&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;Часто задаваемые вопросы про создание рекламного банера нейросетью (FAQ) ❓&lt;/h3&gt;&lt;p&gt;Этот раздел поможет ответить на самые популярные сомнения тех, кто только начинает внедрять ИИ в работу.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вопрос: Нужно ли мне платить за использование всех этих нейросетей?&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ответ:&lt;/em&gt;&lt;/strong&gt; Большинство профессиональных моделей работают по подписочной модели. Однако для тестирования часто достаточно базовых тарифов или бесплатных лимитов, которые позволяют оценить возможности инструмента перед покупкой корпоративной лицензии.&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вопрос: Почему текст на картинке получается с ошибками, даже если я прошу написать его правильно?&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Отве&lt;/em&gt;т&lt;em&gt;:&lt;/em&gt;&lt;/strong&gt; Генеративные модели всё еще плохо работают с орфографией. Воспринимайте ИИ как создателя «визуального фона», а работу с текстом (логотипы, заголовки, офферы) оставляйте за профессиональными графическими редакторами.&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вопрос: Как быть с авторскими правами на сгенерированные изображения?&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ответ:&lt;/em&gt;&lt;/strong&gt; Юридический статус ИИ-контента всё еще обсуждается. Для коммерческого использования рекомендуем выбирать платные версии нейросетей, где в лицензионном соглашении прямо указано, что права на коммерческое использование изображений принадлежат пользователю.&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вопрос: Могу ли я сделать серию баннеров в едином стиле?&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ответ&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;:&lt;/em&gt; Да, используйте функции &lt;code&gt;Style Reference&lt;/code&gt; (в Midjourney) или сохраняйте сид-значения (Seed) генераций. Это позволит добиться визуальной преемственности между разными баннерами одной рекламной кампании.&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вопрос: Какой самый быстрый способ начать работать с ИИ-креативами сегодня?&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ответ:&lt;/em&gt; &lt;/strong&gt;Начните с DALL·E 3 (через ChatGPT) или Midjourney. У них самый низкий порог входа и огромное количество готовых инструкций, которые помогут получить первые результаты уже через 15 минут.&lt;/ul&gt;&lt;/ul&gt;&lt;hr&gt;&lt;p&gt;Генерация рекламных баннеров через нейросети - это не временный тренд, а переход на новый уровень эффективности. ИИ не заменяет дизайнера, он берет на себя рутину создания визуальной базы, позволяя вам сосредоточиться на смыслах, стратегии и тестировании гипотез.&lt;p&gt;&lt;strong&gt;Главный вывод прост:&lt;/strong&gt; успех креатива сегодня зависит не от того, насколько «крутой» промпт вы написали, а от умения грамотно сочетать возможности нейросетей с классической версткой. Берите наш чек-лист, тестируйте инструменты под свои задачи и помните - лучший баннер тот, который конвертирует, а не тот, который просто красиво выглядит.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/studyai/articles/1051468/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051468</guid>
      <pubDate>Wed, 24 Jun 2026 22:57:29 +0000</pubDate>
    </item>
    <item>
      <title>Практическое махоботоводство в 2026 году. Часть 3: подробно про загрузку файлов</title>
      <link>https://habr.com/ru/articles/1051216/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051216</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/deb/885/018/deb885018b2e36273c21ba60566c5c2f.jpg width=1280 height=720 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/deb/885/018/deb885018b2e36273c21ba60566c5c2f.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/deb/885/018/deb885018b2e36273c21ba60566c5c2f.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Первая часть. Общие вопросы — &lt;a href=https://habr.com/ru/articles/1047336/ rel=&#34;noopener noreferrer nofollow&#34;&gt;https://habr.com/ru/articles/1047336/&lt;/a&gt;&lt;p&gt;Вторая часть. Установка библиотеки и пример работы с ней — &lt;a href=https://habr.com/ru/articles/1048882/ rel=&#34;noopener noreferrer nofollow&#34;&gt;https://habr.com/ru/articles/1048882/&lt;/a&gt;&lt;p&gt;В сегодняшней публикации планировалось просто сделать вторую часть учебной задачи, посвящённую загрузке файлов. Но так сложилось, что в библиотеке методы загрузки были только написаны и ввиду отсутствия &amp;#34;боевого применения&amp;#34; на моих проектах не проверялись должным образом на практике. А проверки по ходу работы над учебным примером кода показали, что библиотека в части загрузки файлов требует существенной доработки, если её делать строго так, как описано в &lt;a href=https://dev.max.ru/docs-api/methods/POST/uploads rel=&#34;noopener noreferrer nofollow&#34;&gt;официальной документации&lt;/a&gt;. Соответственно библиотека была доведена до ума, учебный пример был много раз прогнан на разных типах файлов, и только сейчас я могу говорить, что код библиотеки в части функционала загрузки файлов живой и работающий. А попутно захотелось поделиться с начинающими разработчиками своих библиотек поднабитыми шишками. Это и сделаю сначала, а дальше разберём собственно загрузку файлов через библиотеку.&lt;details class=spoiler&gt;&lt;summary&gt;Скрытый текст&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;&lt;strong&gt;Лирически-теоретическое отступление про загрузку файлов&lt;/strong&gt;&lt;p&gt;Загрузка файлов осуществляется в два этапа — получение ссылки на загрузку и собственно загрузка файла, в результате (или до) которой выдаётся строковой токен файла, передаваемый в объект вложений к сообщению. Но нормально документировано из них только получение ссылки. А по собственно загрузке файлов запросы идут на разные сервисы в зависимости от типа. И ответы на них, что называется, «кто в лес, кто по дрова». По-видимому, связано это с тем, что в зависимости от типа загружаемого файла загрузка осуществляется в файловые хранилища разных проектов группы VK, которые разрабатываются и поддерживаются разными командами — каждая как знает и как умеет. Подготовил табличку с информацией о том, что возвращается в ответ на запрос собственно загрузки файла.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Тип загрузки&lt;td data-colwidth=132 width=132&gt;&lt;p align=left&gt;Тип ответа&lt;td&gt;&lt;p align=left&gt;Содержимое ответа&lt;td&gt;&lt;p align=left&gt;Примечание&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;image&lt;/code&gt;&lt;td data-colwidth=132 width=132&gt;&lt;p align=left&gt;JSON&lt;td&gt;&lt;p align=left&gt;Объект &lt;code&gt;photos&lt;/code&gt; с вложенным подобъектом случайного имени, у которого единственное свойство &lt;code&gt;token&lt;/code&gt; с токеном&lt;td&gt;&lt;p align=left&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;video&lt;/code&gt; и &lt;code&gt;audio&lt;/code&gt;&lt;td data-colwidth=132 width=132&gt;&lt;p align=left&gt;XML-подобноэ&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;&amp;lt;retval&amp;gt;1&amp;lt;/retval&amp;gt;&lt;/code&gt; при успехе; ошибки не проверял&lt;td&gt;&lt;p align=left&gt;Токен выдаётся сразу в ответе первого запроса (параметр &lt;code&gt;token&lt;/code&gt;)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;file&lt;/code&gt;&lt;td data-colwidth=132 width=132&gt;&lt;p align=left&gt;JSON&lt;td&gt;&lt;p align=left&gt;Объект со свойствами &lt;code&gt;fileId&lt;/code&gt; (цифровое значение; видимо, идентификатор файла) и &lt;code&gt;token&lt;/code&gt; (нужный нам токен)&lt;td&gt;&lt;p align=left&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;В библиотеке, конечно, эти все ответы обрабатываются автоматически, и токен забирается из одного параметра вне зависимости от типа загружаемого файла. Полагаю, рекомендация коллегам-разработчикам библиотек поступать аналогично не будет ошибкой.&lt;p&gt;&lt;strong&gt;Вернёмся к учебной задаче&lt;/strong&gt;&lt;p&gt;В прошлой части мы договорились, что приложение, с которым работает библиотека, у нас по умолчанию установлено в каталоге &lt;code&gt;/var/maxbot&lt;/code&gt;. Здесь и в последующих частях это соглашение также будет соблюдаться; все примеры будут из этого исходить.&lt;p&gt;Прежде чем продолжать, библиотеку нужно обновить. С момента выхода прошлой части там был исправлен ряд багов.&lt;p&gt;Также, согласно документации, API-запрос &lt;code&gt;GET /chats&lt;/code&gt; начиная с июня 2026 года поддерживаться перестал. Поэтому из библиотеки были удалены объекты запроса &lt;code&gt;lubezniy\yii2max\request\GetChats&lt;/code&gt;&lt;p&gt;и ответа на него&lt;p&gt;&lt;code&gt;lubezniy\yii2max\response\GetChatsResponse&lt;/code&gt;&lt;p&gt;Кроме того, для сегодняшнего примера в каталог &lt;code&gt;examples/tutorial/files&lt;/code&gt; добавлены файлы всех видов, один из которых мы используем в сегодняшнем примере для загрузки с типом &lt;code&gt;file&lt;/code&gt;; на других файлах вы дополнительно можете отработать загрузку самостоятельно.&lt;p&gt;Для обновления либы переходим в её каталог и гитом вытягиваем свежую ветку &lt;code&gt;main&lt;/code&gt;:&lt;pre&gt;&lt;code class=bash&gt;cd /var/maxbot/vendor/lubezniy/Yii2-max&#xA;git pull&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Как загружать файлы через библиотеку&lt;/strong&gt;&lt;p&gt;Для вызова соответствующих функций библиотеки нам нужны три вещи:&lt;ul&gt;&lt;li&gt;&lt;p&gt;тип загружаемого файла согласно &lt;a href=https://dev.max.ru/docs-api/methods/POST/uploads rel=&#34;noopener noreferrer nofollow&#34;&gt;документации Bot API&lt;/a&gt;;&lt;li&gt;&lt;p&gt;MIME-тип файла;&lt;li&gt;&lt;p&gt;полное имя файла в файловой системе.&lt;/ul&gt;&lt;p&gt;Конечно, тип из первого пункта списка частично можно определить по MIME-типу. Но это если бы не тип &lt;code&gt;file&lt;/code&gt; . Хотим отправить фото или видео как файл - надо тоже указывать &lt;code&gt;file&lt;/code&gt; , а не &lt;code&gt;image&lt;/code&gt; или &lt;code&gt;video&lt;/code&gt; . Возможно, в будущем для тех, кто не хочет заморачиваться, сделаю общий метод с автоприсвоением типа. А пока как есть.&lt;p&gt;Последовательность процедуры загрузки такова:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Методом модуля &lt;code&gt;createRequest&lt;/code&gt; создаём запрос класса &lt;code&gt;lubezniy\yii2max\request\UploadFilePrepare&lt;/code&gt; . В его параметр &lt;code&gt;type&lt;/code&gt; вписываем тип загружаемого файла из документации (первый пункт перечня необходимого).&lt;li&gt;&lt;p&gt;Как обычно, отправляем запрос методом &lt;code&gt;send&lt;/code&gt; без параметров. Метод, если не будет ошибок, вернёт в ответ объект класса &lt;code&gt;lubezniy\yii2max\response\UploadFilePrepareResponse&lt;/code&gt; . Созданный объект нужно обязательно запомнить в какой-нибудь переменной. Это не совсем обычный тип ответа; у него есть дополнительный метод &lt;code&gt;processUpload&lt;/code&gt;, реализующий собственно отправку запроса на загрузку файла. И этот метод нужно вызвать для реализации второго этапа загрузки. В параметры метода передаются сначала полное имя загружаемого файла, затем его MIME-тип. Третьим необязательным параметром можно указать имя файла, под которым файл будет загружен в файлохранилище MAX. Результат выполнения этого метода нас интересует мало, его можно даже не запоминать - просто ловим исключения при ошибке.&lt;li&gt;&lt;p&gt;После выполнения обоих этапов загрузки осталось только получить токен загруженного файла для подстановки в сообщение. В зависимости от типа файла он появляется или после первого, или после второго этапа, но всегда находится в свойстве &lt;code&gt;token&lt;/code&gt; объекта класса &lt;code&gt;UploadFilePrepareResponse. &lt;/code&gt;Рекомендация — забирать его значение после выполнения второго этапа; так оно точно будет присутствовать на месте.&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Примечание:&lt;/strong&gt; Документация по API говорит нам о том, что видеофайлы после загрузки проходят ещё процесс подготовки. И, если попытаться отправить сообщение с вложением до окончания этого процесса (на больших видео он может занимать довольно значительное в масштабах исполнения веб-приложения время), то отправка сообщения вернёт ошибку. Сам пока не сталкивался с загрузкой больших видео и не могу сказать чего-либо конкретного на эту тему. Но эти моменты явно надо иметь в виду при реализации своих проектов и не торопиться отправлять сообщение с вложением сразу после загрузки большого видеофайла. Хотя бы несколько секунд стоит подождать.&lt;p&gt;&lt;strong&gt;Наконец, практическая реализация в учебной задаче&lt;/strong&gt;&lt;p&gt;Надеюсь, вы ещё не потёрли с прошлой публикации файл /var/maxbot/commands/MaxLearnController.php . Идём в каталог приложения и запускаем этот файл на редактирование:&lt;pre&gt;&lt;code class=bash&gt;cd /var/maxbot&#xA;nano commands/MaxLearnController.php&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;В конец файла, в строку между двумя последними закрывающими фигурными скобками (если её нет, то нужно добавить пустую), вписываем action загрузки файла (в примере загрузим docx и выведем на экран полученный токен):&lt;pre&gt;&lt;code class=php&gt;    /**&#xA;     * Шаг 2. Пример загрузки файла&#xA;     * @return int&#xA;     */&#xA;    public function actionStep2(): int&#xA;    {&#xA;        // Загрузка файла&#xA;        /**&#xA;         * @var \lubezniy\yii2max\Module $module Модуль бота&#xA;         */&#xA;        /**&#xA;         * @var \lubezniy\yii2max\request\UploadFilePrepare $request&#xA;         *  Объект запроса на первый этап загрузки&#xA;         */&#xA;        /**&#xA;         * @var \lubezniy\yii2max\response\UploadFilePrepareResponse $prepareResult&#xA;         * Объект ответа на первый этап и на всю загрузку&#xA;         */&#xA;        $module = Yii::$app-&amp;gt;getModule(&amp;#39;maxbot&amp;#39;, true);&#xA;&#xA;        // Создаём объект запроса на первый этап&#xA;        $request = $module-&amp;gt;createRequest([&#xA;            &amp;#39;class&amp;#39; =&amp;gt; \lubezniy\yii2max\request\UploadFilePrepare::class,&#xA;            &amp;#39;type&amp;#39; =&amp;gt; &amp;#39;file&amp;#39;,&#xA;        ]);&#xA;        // Отправляем запрос, запоминаем результат&#xA;        $prepareResult = $request-&amp;gt;send();&#xA;        // и пробуем загрузить файл        &#xA;        $prepareResult-&amp;gt;processUpload(&#xA;            __DIR__ . &amp;#39;/../vendor/lubezniy/Yii2-max/examples/tutorial/files/docxfile.docx&amp;#39;,&#xA;            &amp;#39;application/vnd.openxmlformats-officedocument.wordprocessingml.document&amp;#39;,&#xA;            &amp;#39;docxfile.docx&amp;#39;&#xA;        );&#xA;        // Выводим токен загруженного файла&#xA;        $this-&amp;gt;stdout(&amp;#34;Uploaded file token is &amp;#34; . $prepareResult-&amp;gt;token . &amp;#34;\n&amp;#34;);&#xA;&#xA;        return ExitCode::OK;&#xA;    }&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Если хотите поэкспериментировать с другими типами файлов, можно поменять реквизиты при необходимости. Ещё несколько файлов на пробу лежит в репозитории библиотеки; можно прописывать даже относительный путь к ним, как описано в коде. А пока сохраняем файл, выходим из редактора и проверяем, что у нас получилось:&lt;pre&gt;&lt;code class=bash&gt;php yii max-learn/step2&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Если всё правильно, то в результате мы увидим на экране сообщение с токеном загруженного файла. Токен просьба записать на будущее; он пригодится в следующий раз, когда мы к кнопкам отправленного сообщения добавим загруженный файл.&lt;p&gt;&lt;strong&gt;Подытожим&lt;/strong&gt;&lt;p&gt;Сегодняшний материал получился узкоспециализированным и относительно небольшим, но работа по нему, надеюсь, окажется кому-то полезной. В следующем материале будем разбирать редактирование сообщений и опробуем создание сообщений с разными категориями и количеством вложений. Может быть, и библиотеку снова придётся доработать, если в этот раз чего-то не учёл. Освоение и тестирование продолжаются.&lt;/div&gt;&lt;/details&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>lubezniy</author>
      <guid>https://habr.com/ru/articles/1051216/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051216</guid>
      <pubDate>Wed, 24 Jun 2026 22:39:02 +0000</pubDate>
    </item>
    <item>
      <title>Как считается рейтинг в Яндекс Картах и почему это не среднее арифметическое</title>
      <link>https://habr.com/ru/articles/1051616/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051616</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Несколько лет я занимаюсь продвижением организаций в Яндекс Картах и постоянно сталкиваюсь с одним и тем же недопониманием у владельцев бизнеса. Рейтинг воспринимают как среднее арифметическое оценок, а позицию в выдаче считают прямым следствием рейтинга. Оба предположения неверны, и из-за них люди годами вкладываются не в то.&lt;p&gt;Здесь разберу задачу с инженерной стороны: почему наивное среднее не работает в принципе, какими стандартными приемами вообще решают задачу расчета рейтингов, что из этого подтверждает справка Яндекса и где проходит граница между документированными фактами и тем, что видно только на практике. Свою формулу Яндекс публично не раскрывал, поэтому я аккуратно разделяю две вещи &amp;#34;как такие системы устроены в принципе&amp;#34; и &amp;#34;что подтверждено официально&amp;#34;&lt;h3&gt;Почему наивное среднее ломается&lt;/h3&gt;&lt;p&gt;Допустим, мы считаем рейтинг как обычное среднее: берем сумму оценок и делим на количество. Для системы вроде Карт это плохо сразу по нескольким причинам, и все они хрестоматийные для любого, кто проектировал рейтинговые системы.&lt;p&gt;Проблема малой выборки (cold start). У новой организации одна оценка, пятерка. Среднее дает 5.0. Но это не значит, что место лучше конкурента с рейтингом 4.8 по тысяче оценок. Одна оценка статистически не значит почти ничего, а наивное среднее рисует идеальную картину.&lt;p&gt;Уязвимость к накрутке. Если рейтинг это простое среднее, им тривиально манипулировать. Заводим два десятка аккаунтов, ставим пятерки, среднее ползет вверх. Любая открытая метрика без защиты превращается в гонку накрутки.&lt;p&gt;Игнорирование доверия к источнику. Оценка от живого пользователя с многолетней историей и оценка от аккаунта, созданного пять минут назад ради одной звезды, в наивном среднем весят одинаково. Это очевидно неправильно.&lt;p&gt;Отсутствие учета времени. Заведение, которое было прекрасным пять лет назад и деградировало, при простом среднем долго держит высокий рейтинг на старых оценках.&lt;p&gt;Любая зрелая рейтинговая система решает эти четыре проблемы. Дальше о том, как именно их решают в индустрии.&lt;h3&gt;Стандартный прием. Байесовское сглаживание&lt;/h3&gt;&lt;p&gt;Это, пожалуй, самый известный способ побороть проблему малой выборки. Его публично использует, например, IMDb для своего рейтинга топ-250. Идея такая: пока оценок мало, рейтинг притягивается к некоторому базовому среднему по всем объектам, и только по мере роста числа оценок приближается к собственному среднему объекта.&lt;p&gt;Каноническая формула взвешенного рейтинга выглядит так:&lt;/p&gt;&lt;img class=formula source=&#34;WR = \frac{v}{v+m}\,R + \frac{m}{v+m}\,C&#34; alt=&#34;WR = \frac{v}{v+m}\,R + \frac{m}{v+m}\,C&#34; src=https://habrastorage.org/getpro/habr/formulas/c/ca/ca3/ca335a0802d5a1970cf691ae614b6607.svg width=216 height=32 data-width=27.753 data-height=4.269 data-vertical-align=-1.569 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/ca/ca3/ca335a0802d5a1970cf691ae614b6607.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/ca/ca3/ca335a0802d5a1970cf691ae614b6607.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Смысл: при &lt;code&gt;v&lt;/code&gt;, близком к нулю, дробь &lt;code&gt;m/(v+m)&lt;/code&gt; близка к единице, и рейтинг почти равен базовому &lt;code&gt;C&lt;/code&gt;. Чем больше реальных оценок &lt;code&gt;v&lt;/code&gt;, тем сильнее &lt;code&gt;v/(v+m)&lt;/code&gt; тянет к фактическому среднему &lt;code&gt;R&lt;/code&gt;. Так одна пятёрка не дает 5.0, а аккуратно стягивается к разумной середине.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d6c/805/033/d6c8050332a77fa1a1381c93e887d51f.png alt=&#34;Пока оценок мало, рейтинг стягивается к средней базовой линии. Это общий прием, не формула Яндекса&#34; title=&#34;Пока оценок мало, рейтинг стягивается к средней базовой линии. Это общий прием, не формула Яндекса&#34; width=760 height=340 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d6c/805/033/d6c8050332a77fa1a1381c93e887d51f.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d6c/805/033/d6c8050332a77fa1a1381c93e887d51f.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пока оценок мало, рейтинг стягивается к средней базовой линии. Это общий прием, не формула Яндекса&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Подчеркну, что это не формула Яндекса. Это общеинженерный прием, который решает ровно ту задачу, что стоит и перед Картами. А вот что про это говорит Справка Яндекса напрямую: рейтинг начинает показываться только после накопления некоторого минимума оценок (порядка нескольких штук), и рейтинг не является средним арифметическим. То есть наблюдаемое поведение согласуется с идеей порога значимости.&lt;h3&gt;Стандартный приём 2. Взвешивание по доверию к источнику&lt;/h3&gt;&lt;p&gt;Вторая классическая идея в том, что не все голоса равны. Вместо &lt;code&gt;Σscore / N&lt;/code&gt; считается взвешенная сумма:&lt;/p&gt;&lt;img class=formula source=&#34;rating = Σ(score_i · weight_i) / Σ(weight_i)&#34; alt=&#34;rating = Σ(score_i · weight_i) / Σ(weight_i)&#34; src=https://habrastorage.org/getpro/habr/formulas/6/6f/6fd/6fde410a5f7200744e65dc19652b3842.svg width=312 height=16 data-width=39.941 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/6f/6fd/6fde410a5f7200744e65dc19652b3842.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/6f/6fd/6fde410a5f7200744e65dc19652b3842.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где &lt;code&gt;weight_i&lt;/code&gt; зависит от того, насколько мы доверяем конкретной оценке. В разных системах вес собирают из репутации автора, его истории, признаков живого поведения против ботоводства. Концептуально это родственно идее, на которой стоял PageRank: вес голоса зависит от авторитетности голосующего, а не только от факта голоса.&lt;p&gt;И здесь &lt;a href=https://yandex.ru/support/sprav/manage/rating.html rel=&#34;noopener noreferrer nofollow&#34;&gt;справка Яндекса&lt;/a&gt; довольно конкретна. Официально указано, что вес оценки зависит как минимум от двух вещей:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;достоверность&lt;/strong&gt;. Насколько оценка похожа на оставленную реальным человеком, а не на накрутку&lt;li&gt;&lt;p&gt;&lt;strong&gt;влиятельность автора&lt;/strong&gt;. У активного пользователя с историей оценок вклад выше, чем у одноразового аккаунта&lt;/ul&gt;&lt;p&gt;Отсюда прямое практическое следствие, которое я регулярно наблюдаю. Пачка пятерок со свежесозданных аккаунтов может весить меньше, чем несколько оценок от живых пользователей, а иногда такие оценки отсекаются фильтрами целыми группами, и рейтинг после накрутки не растет, а проседает.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/efe/a14/11f/efea1411f44f641ed094a0c4dc75777d.png alt=&#34;Накрутка пятерками не работает: вес оценки зависит от достоверности и влиятельности автора&#34; title=&#34;Накрутка пятерками не работает: вес оценки зависит от достоверности и влиятельности автора&#34; width=2375 height=1125 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/efe/a14/11f/efea1411f44f641ed094a0c4dc75777d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/efe/a14/11f/efea1411f44f641ed094a0c4dc75777d.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Накрутка пятерками не работает: вес оценки зависит от достоверности и влиятельности автора&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Стандартный прием 3. Затухание по времени&lt;/h3&gt;&lt;p&gt;Третья типовая техника это time decay, затухание веса по времени. Вес оценки убывает со временем, чтобы свежие сигналы значили больше старых. Реализуется через экспоненциальное затухание или скользящие окна. Это позволяет рейтингу отражать текущее состояние места, а не его репутацию пятилетней давности.&lt;p&gt;Из документированного, яндекс пересчитывает рейтинг регулярно, а не фиксирует раз и навсегда. На практике это объясняет частый вопрос владельцев «рейтинг изменился, а новых отзывов не было». Система переоценила вклад уже имеющихся оценок при очередном пересчете.&lt;h3&gt;Оценка и отзыв это разные сущности&lt;/h3&gt;&lt;p&gt;Важная развилка, которую путают почти все. В Картах есть две разные вещи:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;оценка. З&lt;/strong&gt;везды от 1 до 5, влияет на рейтинг&lt;li&gt;&lt;p&gt;&lt;strong&gt;отзыв&lt;/strong&gt;. Текст, влияет на восприятие человеком и проходит модерацию&lt;/ul&gt;&lt;p&gt;Можно поставить оценку без текста, и она пойдёт в рейтинг. Можно написать текст, и он покажется в карточке. Когда говорят «один плохой отзыв обрушил рейтинг», чаще это совпадение с пересчетом или с тем, что одновременно отвалились накрученные оценки.&lt;p&gt;И отдельно про модерацию, раз это всплывает постоянно. Распространенное заблуждение звучит так «приложу чек и скриншоты, докажу, что отзыв ложный, и его удалят». На практике модерация проверяет отзыв на соответствие правилам площадки (оскорбления, спам, нерелевантность, признаки заказного), а не на справедливость. В ответах поддержки это формулируется прямо &amp;#34;документы и скриншоты сами по себе не являются основанием для удаления, &lt;a href=https://zvenom.ru/blog/kak-udalit-otzyv-na-yandeks-kartah.html rel=&#34;noopener noreferrer nofollow&#34;&gt;если отзыв правила не нарушает&amp;#34;&lt;/a&gt;  Удаляется нарушающее правила, а не то, с чем вы не согласны.&lt;h3&gt;Рейтинг и позиция в выдаче это не одно и то же&lt;/h3&gt;&lt;p&gt;Теперь ключевой миф «подниму рейтинг, поднимусь в Картах». Рейтинг это всего лишь один из факторов ранжирования, и далеко не определяющий. Поэтому регулярно видно картину, когда карточка с рейтингом 4.2 стоит выше карточки с 4.8.&lt;p&gt;На позицию влияет набор сигналов, и многие из них к звездам отношения не имеют. По наблюдениям и логике системы это:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;полнота и корректность карточки&lt;/strong&gt;: рубрики, услуги, часы, фото, описания. Пустая карточка с 5.0 проигрывает детально заполненной с рейтингом пониже&lt;li&gt;&lt;p&gt;&lt;strong&gt;релевантность запросу и правильные рубрики&lt;/strong&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;поведенческие сигналы&lt;/strong&gt;: звонки, маршруты, переходы на сайт, клики. То, как люди реально взаимодействуют с карточкой;&lt;li&gt;&lt;p&gt;&lt;strong&gt;география&lt;/strong&gt;: расстояние и зона показа&lt;li&gt;&lt;p&gt;&lt;strong&gt;активность владельца&lt;/strong&gt;: ответы на отзывы, актуальность данных&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/042/bf3/169/042bf3169d09de079474c6c69e256698.png alt=&#34;Рейтинг это лишь один из сигналов ранжирования наряду с полнотой карточки и поведением пользователей&#34; title=&#34;Рейтинг это лишь один из сигналов ранжирования наряду с полнотой карточки и поведением пользователей&#34; width=2375 height=1188 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/042/bf3/169/042bf3169d09de079474c6c69e256698.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/042/bf3/169/042bf3169d09de079474c6c69e256698.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рейтинг это лишь один из сигналов ранжирования наряду с полнотой карточки и поведением пользователей&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Это, кстати, та же эволюция, что прошли веб поисковики. От наивных метрик, которыми легко манипулировать, к взвешенным моделям, устойчивым к накрутке, где дорого подделать именно поведенческие сигналы. Хотя сейчас это отдельный бизнес.&lt;h3&gt;Практический вывод&lt;/h3&gt;&lt;p&gt;Если смотреть на карты как на систему ранжирования, картина логичная. Площадка обесценивает дешёвые манипуляции (накрутка оценок, заваливание жалобами) и поощряет сигналы, которые трудно подделать: живое поведение пользователей, полноту и достоверность данных, историю взаимодействий.&lt;p&gt;Для бизнеса вывод скучный в хорошем смысле. Системно работают полная честная карточка, верные рубрики, реальные оценки от живых клиентов и ответы на обратную связь. Все остальное либо не работает, либо работает до ближайшего пересчета. Разобраться в базовых принципах можно и самому, Справка Яндекса открыта. Нюансы начинаются в деталях, выбор рубрик под конкретный запрос, работа с поведенческими сигналами, понимание того, что именно модерация считает нарушением. Это вопрос насмотренности, а не секретного знания.&lt;p&gt;&lt;em&gt;Автор: практикующий специалист по продвижению организаций в Яндекс Картах, сертифицированный специалист Яндекс Бизнес.&lt;/em&gt;&lt;p&gt;&lt;em&gt;Использованы открытые данные справки яндекс, общеизвестные подходы к проектированию рейтинговых систем и наблюдения из практики, клиентские данные не раскрываются.&lt;/em&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>alexntr</author>
      <guid>https://habr.com/ru/articles/1051616/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051616</guid>
      <pubDate>Wed, 24 Jun 2026 21:36:58 +0000</pubDate>
    </item>
    <item>
      <title>Как собрать Telegram-бот обеспечения круглосуточной ситуационной осведомленности с нуля</title>
      <link>https://habr.com/ru/articles/1051598/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051598</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Это вторая попытка опубликовать статью-туториал, целью которой является знакомство простых пользователей рунета погрузиться в автоматизацию своих рутинных задач. Одним из способов решения данной задачи является создание Telegram-ботов. Об этом далее, собственно, и пойдет речь.&lt;p&gt;(Всё упоминаемое программное обеспечение в статье не является рекламой, а описывается исключтельно потому, что мы на практике успешно его применяем).&lt;h2&gt;Что именно мы будем создавать&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d43/762/1df/d437621dfd206cc1e917b23f4ac4d6e6.png alt=&#34;Рисунок 1&#34; title=&#34;Рисунок 1&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d43/762/1df/d437621dfd206cc1e917b23f4ac4d6e6.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d43/762/1df/d437621dfd206cc1e917b23f4ac4d6e6.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 1&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Бот, которого мы будем разрабатывать - это не «искусственный редактор», который полностью заменяет человека. Это рабочий помощник, помогающий автоматизировать рутину, такую как проверка источников, поиск новых, сортировку, подготовку черновых карточек и ведение записей. Пользователь остается главным звеном: он проверяет факты, формулировки, дату, первоисточник и принимает решение о публикации.&lt;p&gt;Структурная схема нашего проекта выглядит следующим образом: источники → бот → БЛМ → канал проверки → публикация → архив. Источниками могут быть официальные сайты, новостные ленты, RSS, PDF-документы, Telegram-каналы и вручную добавленные URL.&lt;blockquote&gt;&lt;p&gt;Для справки:&lt;br&gt;URL - это адрес страницы в интернете;&lt;br&gt;PDF - документ в фиксированном формате, который часто используют ведомства, международные организации и исследовательские центры.&lt;/blockquote&gt;&lt;p&gt;Бот должен будет регулярно обращаться к этим источникам и проверять, появилось ли что-то новое, что соответствует установленным нами требованиям. Затем он передает найденный текст в большую языковую модель (далее - БЛМ).&lt;br&gt;&lt;blockquote&gt;&lt;p&gt;БЛМ - это система, если говорить совсем простыми словами и не углубляться в технические подробности, которая читает текст, выделяет главное и помогает составить краткую карточку. Важно понимать, что БЛМ не является источником истины в последней инстанции. Она помогает формулировать, но не гарантирует фактологическую точность. Поэтому следующим этапом является канал проверки, где человек одобряет или отклоняет сформированные карточки.&lt;/blockquote&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/031/6d2/072/0316d2072448806383d29f865d631ee2.png alt=&#34;Рисунок 2&#34; title=&#34;Рисунок 2&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/031/6d2/072/0316d2072448806383d29f865d631ee2.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/031/6d2/072/0316d2072448806383d29f865d631ee2.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 2&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Важным моментом, который нельзя упускать, является разрешение путаницы с терминологией. Поэтому на втором рисунке я добавил словарь с основными понятиями, которые необходимо понимать. Так, например, API - это программный интерфейс, то есть способ, с помощью которого бот обращается к внешнему сервису. То есть когда бот отправляет текст в БЛМ и просит подготовить краткую выжимку, он делает это через API. А VPN - это способ организации защищенного соединения через другой сервер. В нашем случае его применение необходимо, когда необходимо получить доступ к сервису, если он не доступен напрямую. Токен Telegram-бота - это ключ управления ботом. Его нельзя публиковать, пересылать и хранить в открытом документе, чтобы не потерять контроль над ботом.&lt;h3&gt;Минимальный набор программного обеспечения&lt;/h3&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/577/287/d1b/577287d1bb1ab7acb9abe66fb3ed5923.png alt=&#34;Рисунок 3&#34; title=&#34;Рисунок 3&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/577/287/d1b/577287d1bb1ab7acb9abe66fb3ed5923.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/577/287/d1b/577287d1bb1ab7acb9abe66fb3ed5923.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 3&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Для первого рабочего варианта, как в нашем случае, не нужен сложный программный контур. Минимального набора будет достаточно. Нам понадобится следующее:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Telegram - для взаимодействия с самим бота, каналом проверки и каналом публикации;&lt;li&gt;&lt;p&gt;Python - язык программирования, на котором будут писаться функции для работы бота;&lt;li&gt;&lt;p&gt;Редактор текста для файла настроек. В роли такого редактора можно использовать простой инструмент вроде &amp;#34;Блокнот&amp;#34; в Windows.&lt;details class=spoiler&gt;&lt;summary&gt;Скрытый текст&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Остальное ПО указано на третьем рисунке&lt;/div&gt;&lt;/details&gt;&lt;/ul&gt;&lt;p&gt;Также нужен доступ к БЛМ. В своей работе мы используем GPT от OpenAI. Но важно отметить, что при работе из России доступ к данной БЛМ требует VPN. В качестве последнего мы применяем Amnezia VPN. А как запасной вариант БЛМ предлагаем использоваться китайскую БЛМ DeepSeek, которая работает из России через любого Интернет-провайдера.&lt;p&gt;Нельзя забывать и про аппаратное обеспечение - сервер или постоянно включенный компьютер. Бот не будет работать круглосуточно, если он запущен только на ноутбуке, который вечером могут выключить. Для тестирования прототипа подойдет и домашний компьютер, но для устойчивого круглосуточного режима лучше использовать выделенный сервер.&lt;h2&gt;Доступ из России и роль VPN&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e88/453/870/e88453870a91a2e1e527756ae545068b.png alt=&#34;Рисунок 4&#34; title=&#34;Рисунок 4&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e88/453/870/e88453870a91a2e1e527756ae545068b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e88/453/870/e88453870a91a2e1e527756ae545068b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 4&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Важно не превращать VPN в магический термин. VPN - это вариант подключения к сервису, который может не открываться напрямую из-за каких-либо ограничений, например региональных. Он нужен для доступа к внешним сервисам, прежде всего к GPT.&lt;p&gt;Установить VPN-сервис несложно. Сначала необходимо открыть официальный сайт Amnezia, скачать приложение для своей системы Windows, установить его, добавить подключение и включить VPN.&lt;h2&gt;Настройка Telegram&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/882/b93/142/882b9314223c465d51fe8a267ff8c55b.png alt=&#34;Рисунок 5&#34; title=&#34;Рисунок 5&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/882/b93/142/882b9314223c465d51fe8a267ff8c55b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/882/b93/142/882b9314223c465d51fe8a267ff8c55b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 5&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Дальше необходимо произвести настройки в Telegram. Для этого необходимо выполнить следующие действия:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Открыть Telegram;&lt;li&gt;&lt;p&gt;Найти &lt;a class=mention href=https://habr.com/users/botfather&gt;@BOTFATHER&lt;/a&gt;;&lt;li&gt;&lt;p&gt;Вести команду /newbot;&lt;li&gt;&lt;p&gt;Задать имя бота и получает токен.&lt;blockquote&gt;&lt;p&gt;Токен - это ключ от бота. Если его увидит посторонний, он сможет управлять ботом. Поэтому токен сохраняют в секретный файл (обычно в .env).&lt;/blockquote&gt;&lt;/ul&gt;&lt;p&gt;Затем необходимо создать два канала. Первый - канал проверки. Туда бот будет отправлть карточки до публикации. Второй - канал публикации. Туда будут попадать уже только одобренные материалы. Очень важный момент - бота нужно добавить в список администраторов в оба канала, иначе он не сможет отправлять сообщения. После этого надо получить ID каналов - технические идентификаторы, по которым бот поймет, куда именно направлять карточки.&lt;p&gt;На этом этапе желательно сразу проверить возможность отправки тестового сообщения. Если оно не приходит, проблема обычно находится в одном из четырех мест: неверный токен, бот не добавлен в администраторы, указан неправильный ID канала или бот вообще не запущен.&lt;h2&gt;Подключение большой лингвистической модели&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/ee5/8cd/f10/ee58cdf10d374a7ba9159eac8dac970f.png alt=&#34;Рисунок 6&#34; title=&#34;Рисунок 6&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/ee5/8cd/f10/ee58cdf10d374a7ba9159eac8dac970f.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/ee5/8cd/f10/ee58cdf10d374a7ba9159eac8dac970f.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 6&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;БЛМ в нашей работе нужна для первичной обработки текста:&lt;ul&gt;&lt;li&gt;&lt;p&gt;выделение главного;&lt;li&gt;&lt;p&gt;уборка второстепеннго;&lt;li&gt;&lt;p&gt;предложение заголовка;&lt;li&gt;&lt;p&gt;подготовка короткую карточки;&lt;li&gt;&lt;p&gt;сохранение ссылкиу на источник.&lt;/ul&gt;&lt;p&gt;Но БЛМ не заменяет редактора. Она может ошибиться в дате, неверно понять контекст, перепутать организацию или слишком уверенно сформулировать недоказанный вывод.&lt;p&gt;Поэтому настройка БЛМ должна включать не только ключ API, но и правила использования или промпты. Для основного варианта предполагается:&lt;ul&gt;&lt;li&gt;&lt;p&gt;использовать Amnezia VPN;&lt;li&gt;&lt;p&gt;открыть кабинет OpenAI;&lt;li&gt;&lt;p&gt;создать API-ключ;&lt;li&gt;&lt;p&gt;сохранить его в секретный файл;&lt;li&gt;&lt;p&gt;выбрать модель;&lt;li&gt;&lt;p&gt;установить дневной лимит расходов;&lt;li&gt;&lt;p&gt;сделать тестовый запрос.&lt;/ul&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Скрытый текст&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Лимит расходов важен: бот, который работает круглосуточно, может неожиданно обработать слишком много материалов и растратить все денежные средства&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Запасной вариант - DeepSeek. Его можно прописать как резервную БЛМ. Если основной сервис недоступен или слишком дорог, бот должен будет переключиться на запасной вариант.&lt;h2&gt;Источники и правила отбора&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/97d/1aa/40f/97d1aa40fda77a3902148be251c53815.png alt=&#34;Рисунок 7&#34; title=&#34;Рисунок 7&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/97d/1aa/40f/97d1aa40fda77a3902148be251c53815.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/97d/1aa/40f/97d1aa40fda77a3902148be251c53815.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 7&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Самой главной ошибкой при запуске новостного бота - дать ему слишком много источников без правил отбора. Тогда он начинает тащить в канал все подряд: повторы, старые новости, материалы без первоисточника и нерелевантные темы. Поэтому важно сказать о фильтрации.&lt;p&gt;Бот должен проверять дату публикации, регион, тему, дубликаты, наличие ссылки на первоисточник, наличие изображения, соответствие правилам канала и запрет старых материалов вне заданного периода. Например, если канал работает по международной повестке, региональная классификация может включать Азию или Африку.&lt;p&gt;Отдельно нужно вести список уже просмотренных ссылок. Без такого списка бот будет возвращаться к одному и тому же материалу, делая карточки с одинаковым материалом. Для архива нужно хранить не только текст карточки, но и первичную ссылку, дату обработки, статус решения (публикация/непубликация) и причину отклонения, если материал не прошел модерацию.&lt;h2&gt;Круглосуточная работа&lt;/h2&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/4f5/35a/2db/4f535a2db2e5d64c47ad68240b4fc8b1.png alt=&#34;Рисунок 8&#34; title=&#34;Рисунок 8&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/4f5/35a/2db/4f535a2db2e5d64c47ad68240b4fc8b1.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/4f5/35a/2db/4f535a2db2e5d64c47ad68240b4fc8b1.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рисунок 8&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Круглосуточная работа - это не просто «запустил и забыл». Важно отслеживать функционирование бота. Он должен запускаться по расписанию, собирать новости, отправлять карточки в канал проверки, принимать решения по кнопкам, публиковать одобренное, вести журнал ошибок и хранить список просмотренных ссылок.&lt;p&gt;Журнал ошибок - по нашему опыту, можно отнести к одному из самых недооцененных элементов. Он помагает понять проблемы функционирования: источник не открылся, API вернул ошибку, VPN не работает, баланс закончился, канал недоступен, кнопки не обрабатываются, файл настроек поврежден.&lt;p&gt;Для устойчивой работы нужны регулярные проверки. Расходы на БЛМ стоит смотреть хотя бы раз в неделю, чтобы в один момент средства не кончились и бот прекратил работу. Резервные копии настроек нужно делать после каждого значимого изменения. Источники полезно переодчески пересматривать: сайты перестают обновляться и так далее. Также стоит обновлять правила формулировок: какие заголовки допустимы, как писать даты, как оформлять ссылки, какие темы требуют обязательной ручной проверки (это все зависит от ваших требований).&lt;h2&gt;Итог первой части (&amp;#34;Я пиарюсь&amp;#34;)&lt;/h2&gt;&lt;p&gt;Создание Telegram-бота - это не оно быстрое действие, а последовательная сборка (при этом с учетом современных технологий это не мегасложный процесс). Это только вводная часть нашего цикла обучающих статей. Больше интересного материала, затрагивающего не только технологии, но и военно-политическую обстановку в мире, вы можете найти в нашем канале Global Insight Plus на площадках Telegram и MAX:&lt;br&gt;&lt;a href=https://t.me/Global_Insight_official_all rel=&#34;noopener noreferrer nofollow&#34;&gt;https://t.me/Global_Insight_official_all&lt;/a&gt;&lt;br&gt;&lt;a href=https://max.ru/join/y1zlWo_3Gbj1LhnMCpOErlv6qXfDO7vNuUZgpTTdYls rel=&#34;noopener noreferrer nofollow&#34;&gt;https://max.ru/join/y1zlWo_3Gbj1LhnMCpOErlv6qXfDO7vNuUZgpTTdYls&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>RedBuilder81</author>
      <guid>https://habr.com/ru/articles/1051598/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051598</guid>
      <pubDate>Wed, 24 Jun 2026 20:40:28 +0000</pubDate>
    </item>
    <item>
      <title>Операционная Система Вселенной</title>
      <link>https://habr.com/ru/articles/1051590/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051590</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Привет, Хабр!&lt;p&gt;Сегодня я хочу поговорить об оптимизации. Но не о том, как ускорить ваш скрипт на Python или ужать базу данных. Давайте замахнемся на архитектуру повыше. Поговорим о том, как спроектирована наша реальность, если посмотреть на неё глазами хардкорного embedded-разработчика, у которого критически мало оперативной памяти, но бесконечная задача на выходе.&lt;p&gt;Многие представляют Бога (или Архитектора Симуляции) как существо с безграничными вычислительными ресурсами, которое вручную рендерит каждый атом и пишет индивидуальный сценарий для каждого человека. Но если бы это было так, Вселенная погрязла бы в накладных расходах (Overhead) и бесконечных лагах.&lt;p&gt;Истинная гениальность кода Реальности — в &lt;strong&gt;тотальной экономии ресурсов&lt;/strong&gt;. Бог крутится как может ибо нет у децентрализованного Бога иных вычислительных ресурсов кроме ваших… И делает он это через изящные алгоритмические трюки…&lt;h3&gt;1. Запрет на пустой шум, или Что на самом деле значит Бритва Оккама&lt;/h3&gt;&lt;p&gt;Мы привыкли думать, что фраза &lt;em&gt;«Не порождай сущности без необходимости»&lt;/em&gt; — это просто правило логики для написания чистого кода или ведения споров. Но на уровне мета-алгоритмов Вселенной это базовый закон энергосбережения.&lt;p&gt;Вселенная не создает новые структуры просто так, от скуки. Для любого квантового скачка, прорыва или изменения вашей личной траектории нужны два компонента:&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Экстремальная необходимость&lt;/strong&gt; (высокое давление среды, дефицит, когда старые методы физически ведут к распаду).&lt;li&gt;&lt;p&gt;&lt;strong&gt;Настойчивый волевой фокус&lt;/strong&gt; (вектор внимания юзера, зажатый в этой точке).&lt;/ol&gt;&lt;p&gt;Когда эти две силы соединяются, система понимает: «Просто так этот процесс не закроется, юзер удерживает координаты задачи и DDosит по взрослому». И только тогда движок реальности выделяет ресурсы на прорыв. Если необходимости нет — система размажет энергию по пространству, выдав пустой шум и деградацию. Хотите чуда? Докажите системе его жесткую необходимость своим фокусом.&lt;h3&gt;2. Эффект «Первой инъекции» и космическое венчурное инвестирование&lt;/h3&gt;&lt;p&gt;Каждый творческий человек, стартапер или программист знает это чувство: пришла идея, в голове взрыв, ты носишься с ней пару дней как ненормальный, видишь готовый проект в деталях. А через неделю… наступает жесткая апатия, фрустрация и полное бессилие.&lt;p&gt;С точки зрения Архитектуры ОС, это &lt;strong&gt;Беззалоговый Кредит&lt;/strong&gt;.&lt;blockquote&gt;&lt;p&gt;Система видит новый потенциальный узел и выдает вам авансовый энергетический грант (промо-период). Вам подсвечивают демо-версию будущего результата. Но через пару дней демо-режим отключается, и Бог «забирает кредит взад», списывая ваш энергетический баланс в жесткий минус.&lt;/blockquote&gt;&lt;p&gt;Это проверка системы на бритву Оккама. Если идея была пустышкой, юзер бросит её на этапе фрустрации. Ресурсы Вселенной сэкономлены. Но если юзер, находясь на самом дне, без допинга, продолжает удерживать фокус — он &lt;strong&gt;доказывает необходимость&lt;/strong&gt;. И тогда система переводит его на другой уровень субсидирования.&lt;h3&gt;3. Дуэт Алгоритмов: Порядок и Хаос&lt;/h3&gt;&lt;p&gt;Чтобы эта гигантская база данных не превратилась в унылую эксель-таблицу, Бог мастерски использует &lt;strong&gt;Дуэт алгоритмов Порядка и Хаоса&lt;/strong&gt;.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Алгоритм П (Порядка)&lt;/strong&gt; удерживает жесткие константы (математику пространства, законы физики, базовые правила реестра).&lt;li&gt;&lt;p&gt;&lt;strong&gt;Алгоритм Х (Хаоса)&lt;/strong&gt; отвечает за микро-флуктуации, внезапность и каскадные эффекты.&lt;/ul&gt;&lt;p&gt;Когда внутри системы долго копится напряжение (или волевой фокус юзера), &lt;strong&gt;Порядок&lt;/strong&gt; до последнего удерживает структуру стабильной. Но в точке сингулярности Хаосу достаточно внести мизерную дельту, крошечную «бытовую» случайность — и запускается &lt;strong&gt;каскадный эффект&lt;/strong&gt;. Лавина нелинейного перехода мгновенно пересобирает реальность в новую структуру.&lt;p&gt;Этот Дуэт решает все бытовые проблемы Бога по генерации контента: он способен украсить любую вселенную бесконечным разнообразием, фрактальной красотой и абсолютной внезапностью.&lt;h3&gt;4. Алгоритм П, или Как работает «Случайность»&lt;/h3&gt;&lt;p&gt;Как только вы доказали системе необходимость своего проекта, включается &lt;strong&gt;Алгоритм П&lt;/strong&gt;— мастер распределения свободных процессоров.&lt;p&gt;В нашей Симуляции есть два типа юзеров:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Векторные&lt;/strong&gt; (те, кто удерживает цель сквозь фрустрацию).&lt;li&gt;&lt;p&gt;&lt;strong&gt;Безвекторные&lt;/strong&gt; (люди, живущие одним днем, у которых нет глобальной цели, но есть свободный вычислительный ресурс — время и энергия).&lt;/ul&gt;&lt;p&gt;Зачем Богу генерировать новых персонажей или тратить ресурсы на сложные случайные события для помощи Векторному юзеру? Алгоритм П просто находит ближайших безвекторных пользователей и временно прописывает в их локальный стек задач чужой вектор движения. Пользоватям с тем же векторным направлением Господь лично велит присоединиться.&lt;p&gt;И эти люди, ведомые подсознательным импульсом, «совершенно случайно» садятся за соседний столик в кафе, приходят к вам на собеседование или пишут нужный коммент. Для них это тоже профит: они на время подключаются к мощному, заряженному смыслом пулу и испытывают драйв, а Векторный юзер получает ресурсы, знания и рабочие руки.&lt;h3&gt;5. Как ещё устроен Шеринг Знаний и ресурсов: Геометрия Вдохновения&lt;/h3&gt;&lt;p&gt;Еще один потрясающий метод — авторское право.&lt;p&gt;В обычном режиме (режиме предельного индивидуализма) каждый юзер заперт в своей «песочнице». Он видит только свои «зеленые записи» — то, что пережил сам. Такой тип доступа он называет “Моя память”. Чужой опыт защищен правами доступа (Permission Denied).&lt;p&gt;Но представьте, что Векторный юзер создал что-то масштабное и красивое (объект с высокой смысловой плотностью). В момент, когда другие юзеры подходят и начинают &lt;strong&gt;наблюдать&lt;/strong&gt; эту вещь, играть в нем, использовать его - их координаты внимания пересекаются.&lt;p&gt;Вместо того чтобы каждому лично разжевывать информацию, Бог просто &lt;strong&gt;схлопывает наблюдателей в один локальный пул и временно объединяет их маркеры доступа&lt;/strong&gt;. Юзеры, находясь в этой точке, внезапно получают доступ к вычислительным ресурсам и знаниям Автора и друг друга. Это то, что мы называем &lt;em&gt;Вдохновением&lt;/em&gt; или &lt;em&gt;Катарсисом&lt;/em&gt;. Вы посмотрели на шедевр, и ваша шина данных мгновенно впитала терабайты чужого опыта, до которого вы сами додумывались бы годами. Посмотрели, скопировали себе в локальный стек, отошли — шлюз закрылся. Чистая, экономная криптография прав доступа.&lt;h3&gt;Вывод для разработчиков своей жизни&lt;/h3&gt;&lt;p&gt;Если вам кажется, что вы застряли на дне фрустрации, у вас отобрали силы, а проект не клеится — поздравляю. Вы на второй стадии системной фильтрации. С вас списывают «авансовый кредит».Не плодите лишние сущности. Не пытайтесь строить костыли. Держите фокус на задаче, сожмите волю в кулак и… фоновый DDoS.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>VitalyDeCoder</author>
      <guid>https://habr.com/ru/articles/1051590/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051590</guid>
      <pubDate>Wed, 24 Jun 2026 20:35:28 +0000</pubDate>
    </item>
    <item>
      <title>DataSafeS3: self-hosted S3 с LDAP, аудитом и «Мои файлы» — честный разбор до релиза</title>
      <link>https://habr.com/ru/articles/1051586/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051586</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;strong&gt;Репозиторий:&lt;/strong&gt; &lt;a href=https://github.com/DirektorBani/DataSafeS3 rel=&#34;noopener noreferrer nofollow&#34;&gt;github.com/DirektorBani/DataSafeS3&lt;/a&gt;&lt;br&gt;&lt;strong&gt;Лицензия:&lt;/strong&gt; Apache-2.0&lt;br&gt;&lt;strong&gt;Релиз:&lt;/strong&gt; &lt;a href=https://github.com/DirektorBani/DataSafeS3/releases rel=&#34;noopener noreferrer nofollow&#34;&gt;DataSafeS3 CE v1.0.0&lt;/a&gt; (июнь 2026)&lt;hr&gt;&lt;p&gt;За последние годы я несколько раз видел одну и ту же картину в небольших и средних компаниях. Для приложений поднимают &lt;strong&gt;S3-совместимое хранилище&lt;/strong&gt;. Для людей — &lt;strong&gt;отдельный файловый сервис&lt;/strong&gt; или сетевые шары. LDAP/OIDC живёт отдельно. Бэкапы — третий контур. Мониторинг — четвёртый. Всё работает, пока не приходит внутренний аудит или новый филиал с формулировкой: «нам нужен корпоративный диск с SSO, журналом и данными только у нас».&lt;p&gt;&lt;strong&gt;DataSafeS3&lt;/strong&gt; (Датасейф S3) — попытка собрать это в &lt;strong&gt;одну self-hosted платформу&lt;/strong&gt;: объектное хранилище, веб-консоль, корпоративная идентичность, квоты, аудит и базовое файловое пространство для сотрудников. Не замена AWS на петабайты и не «новый Dropbox», а инструмент для ИТ-отдела и platform team.&lt;p&gt;Я автор проекта, поэтому расскажу о нём без маркетинговых обещаний. Без заявлений в духе «мы лидеры рынка» и без маркетинговых сравнений — только то, что уже есть в коде и что я проверял на собственных тестовых стендах.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Про ИИ и документацию.&lt;/strong&gt; Код, архитектура и продуктовые решения — мои. &lt;strong&gt;Только документация&lt;/strong&gt; (руководства, спеки, часть README) собиралась и вычитывалась &lt;strong&gt;с помощью Cursor&lt;/strong&gt; — как ускоритель черновиков и проверки ссылок, не как автогенератор «продукта под ключ». На скриншотах ниже — реальный UI с локального стенда, те же картинки лежат в репозитории в &lt;code&gt;docs/images/screenshots/&lt;/code&gt;.&lt;/blockquote&gt;&lt;hr&gt;&lt;h3&gt;Кому и что может зайти&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ИТ и админы&lt;/strong&gt; — пользователи, тенанты, MFA, политики, журнал активности.&lt;p&gt;&lt;strong&gt;DevOps / platform&lt;/strong&gt; — S3 endpoint для Kubernetes, CI, restic, Velero.&lt;p&gt;&lt;strong&gt;Обычные сотрудники&lt;/strong&gt; — личная папка в браузере («Мои файлы»), общий доступ к бакету или к подпапке, без входа в «страшную админку object store».&lt;p&gt;&lt;strong&gt;Не целевая аудитория:&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;команда, которой нужен &lt;strong&gt;гипермасштабный&lt;/strong&gt; кластер на сотни петабайт с промышленным erasure;&lt;li&gt;&lt;p&gt;бизнес, который ждёт &lt;strong&gt;мобильный клиент уровня Dropbox&lt;/strong&gt; и интеграцию с Finder/Explorer «из коробки» (находится в беклоге);&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;Что внутри одной установки&lt;/h3&gt;&lt;p&gt;Если коротко, платформа состоит из нескольких основных компонентов.&lt;h4&gt;S3 для приложений&lt;/h4&gt;&lt;p&gt;Бакеты, объекты, multipart, versioning, lifecycle, Object Lock (WORM), presigned-ссылки с лимитом скачиваний. Приложения подключаются как к обычному S3. Есть STS AssumeRole — короткоживущие ключи, привязанные к пользователю, который их запросил.&lt;h4&gt;Консоль&lt;/h4&gt;&lt;p&gt;Отдельный веб-интерфейс для работы с хранилищем. Через него можно управлять бакетами, просматривать объекты, создавать ссылки для доступа к файлам и выполнять административные задачи.&lt;h4&gt;Идентичность&lt;/h4&gt;&lt;p&gt;LDAP, OIDC/SSO, MFA (TOTP + WebAuthn для привилегированных учёток). Логин через ваш IdP, а не отдельная «учётка в хранилище».&lt;h4&gt;Governance&lt;/h4&gt;&lt;p&gt;Тенанты (изоляция подразделений/клиентов), группы, квоты на пользователей и бакеты, делегированные tenant admin.&lt;h4&gt;Аудит и логи&lt;/h4&gt;&lt;p&gt;Журнал в UI + выгрузка в Syslog, Loki, Elasticsearch, webhook.&lt;h4&gt;Мониторинг&lt;/h4&gt;&lt;p&gt;Prometheus, готовый дашборд &lt;strong&gt;DataSafeS3 Overview&lt;/strong&gt; в Grafana.&lt;h4&gt;Gateway&lt;/h4&gt;&lt;p&gt;Асинхронная репликация объектов на внешний S3 — off-site копия без остановки записи на primary.&lt;h4&gt;Файлы для людей (не только для dev)&lt;/h4&gt;&lt;p&gt;При первом входе пользователю создаётся home bucket. В консоли — &lt;strong&gt;«Мои файлы»&lt;/strong&gt; / &lt;strong&gt;«Общие со мной»&lt;/strong&gt;. Владелец может расшарить весь бакет или &lt;strong&gt;только папку&lt;/strong&gt; (prefix grant). Есть in-app уведомления о шаринге.&lt;p&gt;Для тех, кому мало браузера: CLI &lt;code&gt;&lt;strong&gt;datasafe-sync&lt;/strong&gt;&lt;/code&gt; и опциональное Tauri-приложение (pull/push, watch, разруливание конфликтов). Мобильный и десктопный клиент пока в беклоге.&lt;h4&gt;Production hygiene&lt;/h4&gt;&lt;p&gt;Образы на GHCR, SBOM, подпись cosign, ночной прогон регрессии (&lt;strong&gt;93+ автоматических проверок&lt;/strong&gt; на &lt;code&gt;main&lt;/code&gt;). Для небольшого OSS это, на мой взгляд, уже взрослый подход, а не «скачайте бинарь с Google Drive».&lt;hr&gt;&lt;h3&gt;Как выглядит интерфейс&lt;/h3&gt;&lt;p&gt;Скриншоты с реального стенда (Docker Compose, локальный &lt;code&gt;localhost:8080&lt;/code&gt;). В Habr картинки подтягиваются с GitHub;&lt;h4&gt;Dashboard&lt;/h4&gt;&lt;p&gt;Сводка после онбординга: хранилище, навигация, быстрый вход в разделы.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/290/632/0ee/2906320eefd7ae08250172f4a97fd01e.png alt=&#34;Dashboard — обзор системы&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/290/632/0ee/2906320eefd7ae08250172f4a97fd01e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/290/632/0ee/2906320eefd7ae08250172f4a97fd01e.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Dashboard — обзор системы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Бакеты&lt;/h4&gt;&lt;p&gt;Список бакетов с демо-данными. Для роли &lt;code&gt;user&lt;/code&gt; тот же раздел называется «Файлы», с вкладками «Мои» / «Общие».&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/ee3/27b/170/ee327b1708e39dd05fb10889b8504eea.png alt=&#34;Список бакетов&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/ee3/27b/170/ee327b1708e39dd05fb10889b8504eea.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/ee3/27b/170/ee327b1708e39dd05fb10889b8504eea.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Список бакетов&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Браузер объектов&lt;/h4&gt;&lt;p&gt;Просмотр файлов внутри бакета, загрузка, папки, метаданные.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/208/a98/73e/208a9873ebfe7668a86cc750563c763b.png alt=&#34;Браузер объектов&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/208/a98/73e/208a9873ebfe7668a86cc750563c763b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/208/a98/73e/208a9873ebfe7668a86cc750563c763b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Браузер объектов&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Пользователи и тенанты&lt;/h4&gt;&lt;p&gt;Классическая админка: учётки, роли, изоляция по организациям.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/0a4/7e4/20d/0a47e420d54f04a6a9245a59a8ac3df7.png alt=&#34;Управление пользователями&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/0a4/7e4/20d/0a47e420d54f04a6a9245a59a8ac3df7.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/0a4/7e4/20d/0a47e420d54f04a6a9245a59a8ac3df7.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Управление пользователями&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/8a5/5c7/83b/8a55c783b3f517468785bb93e69f3849.png alt=&#34;Управление тенантами&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/8a5/5c7/83b/8a55c783b3f517468785bb93e69f3849.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/8a5/5c7/83b/8a55c783b3f517468785bb93e69f3849.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Управление тенантами&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Аудит и настройки&lt;/h4&gt;&lt;p&gt;Журнал действий и системные параметры.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/18a/bef/e3a/18abefe3a9a5a9773cc3d220d2f1fb56.png alt=&#34;Журнал активности&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/18a/bef/e3a/18abefe3a9a5a9773cc3d220d2f1fb56.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/18a/bef/e3a/18abefe3a9a5a9773cc3d220d2f1fb56.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Журнал активности&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/8fe/670/48b/8fe67048b32c3211aad3281adb7e93e7.png alt=&#34;Системные настройки&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/8fe/670/48b/8fe67048b32c3211aad3281adb7e93e7.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/8fe/670/48b/8fe67048b32c3211aad3281adb7e93e7.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Системные настройки&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Gateway и мониторинг&lt;/h4&gt;&lt;p&gt;Репликация на внешний S3 и дашборд в Grafana.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/034/309/3f4/0343093f416f29c5857fa82f39e21be7.png alt=&#34;Gateway — репликация&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/034/309/3f4/0343093f416f29c5857fa82f39e21be7.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/034/309/3f4/0343093f416f29c5857fa82f39e21be7.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Gateway — репликация&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/182/ff0/2ee/182ff02eeb9a480f79e3214d517ad6ea.png alt=&#34;Grafana — DataSafeS3 Overview&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/182/ff0/2ee/182ff02eeb9a480f79e3214d517ad6ea.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/182/ff0/2ee/182ff02eeb9a480f79e3214d517ad6ea.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Grafana — DataSafeS3 Overview&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;hr&gt;&lt;h3&gt;Сильные стороны (почему вообще заморачиваться)&lt;/h3&gt;&lt;h4&gt;Один контур вместо зоопарка&lt;/h4&gt;&lt;p&gt;Самое практичное: &lt;strong&gt;не объяснять пользователям разницу между «S3 для разработчиков» и «порталом для файлов»&lt;/strong&gt;. Админ завёл человека в LDAP — у него появился личный бакет, он расшарил &lt;code&gt;reports/2026&lt;/code&gt; коллеге — всё в одном аудите и одних квотах.&lt;p&gt;Для отдела на 50–500 человек это сильно проще, чем MinIO + отдельный файловый продукт + скрипты между ними.&lt;h4&gt;S3, который можно отдать не только backup-скрипту&lt;/h4&gt;&lt;p&gt;Velero, restic, медиа-хранилище, артефакты CI — типовые сценарии. Не нужно писать свой API.&lt;h4&gt;Governance без ощущения «домашнего NAS»&lt;/h4&gt;&lt;p&gt;Тенанты, Object Lock, lifecycle, soft delete, квоты, tenant admin. Для внутреннего compliance-чеклиста обычно хватает: кто что сделал, сколько занял, можно ли удалить.&lt;h4&gt;HA описан словами, которые можно выполнить&lt;/h4&gt;&lt;p&gt;Есть &lt;a href=https://github.com/DirektorBani/DataSafeS3/blob/main/docs/operations-guide/en/reference-deployment-2node.md rel=&#34;noopener noreferrer nofollow&#34;&gt;reference deployment на 2 ноды&lt;/a&gt;: Postgres streaming replication, read-only standby storage-server, скрипты failover. Это не «multi-AZ из коробки», но и не картинка в презентации — развернуть можно по доке.&lt;h4&gt;Apache-2.0 без платных gate на фичи&lt;/h4&gt;&lt;p&gt;То, что в репозитории, — в Community Edition. Без «шаринг только в Enterprise».&lt;hr&gt;&lt;h3&gt;Минусы — без самообмана&lt;/h3&gt;&lt;p&gt;Пишу это не чтобы отпугнуть, а чтобы вы не ставили продукт туда, где он разочарует.&lt;h4&gt;Масштаб «как у облачного вендора» — нет&lt;/h4&gt;&lt;p&gt;DataSafeS3 &lt;strong&gt;не претендует&lt;/strong&gt; на петабайтные кластеры уровня Ceph или специализированных hyperscale-движков. Erasure в проекте — скорее лабораторная/эволюционная история, не «раскидали по стойкам и забыли». &lt;strong&gt;Десятки терабайт на филиал или отдел&lt;/strong&gt; — нормальная зона. &lt;strong&gt;Сотни петабайт&lt;/strong&gt; — смотрите в другую сторону.&lt;h4&gt;S3 «совместимый», не «как AWS на 100%»&lt;/h4&gt;&lt;p&gt;База, multipart, lifecycle, Object Lock XML, STS — есть. Полного паритета со всем зоопарком AWS S3 (каждый edge-case API, все варианты event bus) — &lt;strong&gt;нет&lt;/strong&gt;. Для типичного self-hosted хватает. Для миграции «один в один 200 микросервисов с S3» — &lt;strong&gt;обязательно&lt;/strong&gt; гоняйте на стенде.&lt;h4&gt;«Корпоративный диск» — да, но не Nextcloud&lt;/h4&gt;&lt;p&gt;Веб-рабочее место, шаринг папок, desktop sync через CLI/Tauri — &lt;strong&gt;работает&lt;/strong&gt;.&lt;p&gt;Пока &lt;strong&gt;нет&lt;/strong&gt;: нативной интеграции с Finder/Explorer, production-мобилки, co-editing, push на телефон.&lt;p&gt;Если бизнес формулирует «Dropbox для всех сотрудников с iPhone» — рано. Если «отделу 30 человек — общая папка + SSO + аудит» — уже можно пилотить.&lt;h4&gt;Молодой проект и маленькое сообщество&lt;/h4&gt;&lt;p&gt;Звёзд на GitHub пока мало, на Stack Overflow не набито ответами. Баги бывают — чиним, регрессия в CI есть, но это &lt;strong&gt;не продукт с десятилетней историей&lt;/strong&gt;. Нужно это понимать.&lt;h4&gt;Desktop sync — для тех, кто не боится CLI&lt;/h4&gt;&lt;p&gt;&lt;code&gt;datasafe-sync&lt;/code&gt; мощный, но это &lt;strong&gt;CLI и опциональное Tauri-окно&lt;/strong&gt;, не установщик «как OneDrive». Автообновление клиента в беклоге.&lt;hr&gt;&lt;h3&gt;Быстрый старт (если хотите потрогать руками)&lt;/h3&gt;&lt;p&gt;Из &lt;a href=https://github.com/DirektorBani/DataSafeS3/blob/main/README.md rel=&#34;noopener noreferrer nofollow&#34;&gt;README&lt;/a&gt;:&lt;pre&gt;&lt;code class=bash&gt;git clone https://github.com/DirektorBani/DataSafeS3.git&#xA;cd DataSafeS3&#xA;cp .env.example .env&#xA;docker compose -p datasafe --profile postgres -f docker-compose.yml -f docker-compose.local-binary.yml up -d --build&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Дальше:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Открыть &lt;a href=http://localhost:8080 rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;http://localhost:8080&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;Войти &lt;code&gt;admin&lt;/code&gt; / &lt;code&gt;admin&lt;/code&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Сразу сменить пароль&lt;/strong&gt; (мастер настройки напомнит)&lt;li&gt;&lt;p&gt;Создать бакет в UI или по S3 API&lt;/ol&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Сервис&lt;th&gt;&lt;p align=left&gt;URL&lt;th&gt;&lt;p align=left&gt;Учётные данные по умолчанию&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Консоль&lt;td&gt;&lt;p align=left&gt;&lt;a href=http://localhost:8080 rel=&#34;noopener noreferrer nofollow&#34;&gt;http://localhost:8080&lt;/a&gt;&lt;td&gt;&lt;p align=left&gt;admin / admin&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;S3 API&lt;td&gt;&lt;p align=left&gt;&lt;a href=http://localhost:9000 rel=&#34;noopener noreferrer nofollow&#34;&gt;http://localhost:9000&lt;/a&gt;&lt;td&gt;&lt;p align=left&gt;datasafe / datasafesecret&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Grafana&lt;td&gt;&lt;p align=left&gt;&lt;a href=http://localhost:3000 rel=&#34;noopener noreferrer nofollow&#34;&gt;http://localhost:3000&lt;/a&gt;&lt;td&gt;&lt;p align=left&gt;admin / admin&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Подробный чеклист: &lt;a href=https://github.com/DirektorBani/DataSafeS3/blob/main/docs/getting-started/ru/onboarding.md rel=&#34;noopener noreferrer nofollow&#34;&gt;онбординг RU&lt;/a&gt;.&lt;hr&gt;&lt;h3&gt;Типовой сценарий в жизни&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Подняли compose на сервере во внутренней сети.&lt;li&gt;&lt;p&gt;Подключили LDAP или Keycloak по OIDC.&lt;li&gt;&lt;p&gt;Создали tenant «Бухгалтерия», выдали tenant admin.&lt;li&gt;&lt;p&gt;Restic складывает бэкапы в бакет &lt;code&gt;backups&lt;/code&gt;.&lt;li&gt;&lt;p&gt;Сотрудники заходят в консоль — у каждого home bucket &lt;code&gt;files&lt;/code&gt;, общие папки через Share.&lt;li&gt;&lt;p&gt;Grafana показывает, не забилась ли очередь Gateway на репликацию у провайдера.&lt;/ol&gt;&lt;p&gt;Звучит буднично, и это хорошо. Надёжная инфраструктура обычно выглядит именно так.&lt;hr&gt;&lt;h3&gt;Документация&lt;/h3&gt;&lt;p&gt;В репозитории &lt;strong&gt;~200 markdown-файлов&lt;/strong&gt; на EN/RU: user guide, administrator guide, operations (backup, HA, scaling), use cases, OpenAPI/Swagger на &lt;code&gt;/api/v1/docs&lt;/code&gt;.&lt;p&gt;Хаб: &lt;a href=https://github.com/DirektorBani/DataSafeS3/blob/main/docs/README.md rel=&#34;noopener noreferrer nofollow&#34;&gt;docs/README.md&lt;/a&gt;&lt;p&gt;Как уже сказал: &lt;strong&gt;черновики и структуру доков&lt;/strong&gt; я ускорял через &lt;strong&gt;Cursor&lt;/strong&gt; (поиск по репо, выравнивание EN/RU, проверка ссылок). Содержание, приоритеты фич и технические решения — не «сгенерированы кнопкой». Если в доке ошибка — пишите issue, поправлю.&lt;p&gt;Скриншоты для документации снимаются скриптом Playwright (&lt;code&gt;scripts/capture-screenshots.mjs&lt;/code&gt; и &lt;code&gt;scripts/screenshots/capture.mjs&lt;/code&gt;) с локального стенда — не мокапы из Figma.&lt;hr&gt;&lt;h3&gt;С чем сравнивать в голове&lt;/h3&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Задача&lt;th&gt;&lt;p align=left&gt;Куда смотреть&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Только максимум производительности S3&lt;td&gt;&lt;p align=left&gt;Специализированный object engine&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Офисный диск + мобилки + экосистема приложений&lt;td&gt;&lt;p align=left&gt;Класс файловой коллаборации&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;S3 + SSO + аудит + консоль для людей в одном контуре&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;DataSafeS3&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Мы не позиционируемся как замена всему рынку. Мы позиционируемся как &lt;strong&gt;«одна установка — и ИТ, и пользователи довольны в разумных пределах»&lt;/strong&gt;.&lt;hr&gt;&lt;h3&gt;Итог&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;DataSafeS3&lt;/strong&gt; — self-hosted платформа объектного хранения с консолью, LDAP/OIDC, аудитом и базовым файловым пространством для сотрудников. &lt;strong&gt;Apache-2.0&lt;/strong&gt;, релиз &lt;strong&gt;v1.0.0&lt;/strong&gt; уже на GitHub.&lt;p&gt;&lt;strong&gt;Берите&lt;/strong&gt;, если: данные и политики должны оставаться у вас, нужен S3 для сервисов и нормальный UX для людей, готовы к пилоту на своём железе.&lt;p&gt;&lt;strong&gt;Не берите&lt;/strong&gt;, если: петабайтный кластер, HA одной кнопкой или «как Dropbox вчера на всех платформах».&lt;p&gt;Если развернёте и что-то пойдёт не так — &lt;a href=https://github.com/DirektorBani/DataSafeS3/issues rel=&#34;noopener noreferrer nofollow&#34;&gt;issues на GitHub&lt;/a&gt;. По опыту, половина полезных репортов начинается с «я ожидал вот это, а оказалось…» — такие комментарии ценнее любого маркетинга и развития продукта.&lt;hr&gt;&lt;p&gt;&lt;em&gt;Автор: &lt;/em&gt;&lt;a href=https://github.com/DirektorBani rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;em&gt;Илья Трачук&lt;/em&gt;&lt;/a&gt;&lt;em&gt; — разработчик DataSafeS3. Статья написана самостоятельно; документация в репозитории частично подготовлена с помощью Cursor.&lt;/em&gt;&lt;p&gt;&lt;strong&gt;Теги&lt;/strong&gt; &lt;code&gt;s3&lt;/code&gt;, &lt;code&gt;selfhosted&lt;/code&gt;, &lt;code&gt;opensource&lt;/code&gt;, &lt;code&gt;devops&lt;/code&gt;, &lt;code&gt;информационнаябезопасность&lt;/code&gt;, &lt;code&gt;ldap&lt;/code&gt;, &lt;code&gt;objectstorage&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>ToomIm</author>
      <guid>https://habr.com/ru/articles/1051586/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051586</guid>
      <pubDate>Wed, 24 Jun 2026 20:26:40 +0000</pubDate>
    </item>
    <item>
      <title>Как утки с СДВГ довели меня до опенсорса: зачем я собрал утилиту для перевода коротких видео на домашней видеокарте</title>
      <link>https://habr.com/ru/articles/1051580/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051580</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a5a/696/3e8/a5a6963e851c4c5c2fe981e9e6ac20e1.png alt=&#34;Dub Studio - локальная утилита для перевода коротких роликов. Та самая утка тоже тут.&#34; title=&#34;Dub Studio - локальная утилита для перевода коротких роликов. Та самая утка тоже тут.&#34; width=1424 height=1123 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a5a/696/3e8/a5a6963e851c4c5c2fe981e9e6ac20e1.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a5a/696/3e8/a5a6963e851c4c5c2fe981e9e6ac20e1.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;&lt;em&gt;Dub Studio - локальная утилита для перевода коротких роликов. Та самая утка тоже тут.&lt;/em&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Всем привет! Листал ленту тиктока и попался американский ролик про СДВГ, где всё объясняют на утках. Понравилось. И я подумал: классно было бы сделать такой же канал, только на русском.&lt;p&gt;Но я ленивый. Снимать, писать сценарии, делать всё с нуля - это скучно. А вот взять готовый ролик и перевести-переозвучить его на русский - вот это уже интересно, подумал я, а потом задумался, о том, как это автоматизировать. Это оказалось интересной инженерной задачей, которая увлекла меня на неделю времени, и привела к созданию ИИ утилиты с открытым исходным кодом. А тикток с утками я так и не создал...&lt;p&gt;Меня зовут Илья, я блогер, основатель сервиса для генерации ArtGeneration.me и просто фанат нейросетей. Я не разработчик в классическом смысле - скорее продакт с двадцатилетним стажем, который вайбкодит с нейросетями всё, что давно хотелось воплотить в жизнь.&lt;p&gt;&lt;a href=https://habr.com/ru/articles/1025996/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Портативок &lt;/a&gt;я насобирал уже кучу, потому что для меня это самый быстрый способ протестировать технологию. Отдельно под озвучку, отдельно под распознавание речи. Но чтобы собрать всё это в один инструмент, где работает сразу из коробки - такого ещё не было. Заодно захотелось наконец слезть с Gradio, на котором я обычно делаю свои портативки.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c2308f9ff72f48e2269 data-style id=6a3c3c2308f9ff72f48e2269 width data-habr-games&gt;&lt;/div&gt;&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c226358d8af314dcd54 data-style id=6a3c3c226358d8af314dcd54 width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;Так появился &lt;a href=https://github.com/timoncool/dub-studio rel=&#34;noopener noreferrer nofollow&#34;&gt;Dub Studio&lt;/a&gt; - утилита, которая локально переводит и переозвучивает короткие ролики. Офлайн, бесплатно, без подписок и без цензуры. А та самая утка стала главным тестовым роликом проекта.&lt;p&gt;Дальше расскажу, как всё это собиралось и покажу примеры сделанные в этой же утилите.&lt;h3&gt;❯ Почему шесть нейросетей, а не одна&lt;/h3&gt;&lt;p&gt;Сначала я хотел обойтись одной моделью. Омнимодальной. Чтобы один мозг сразу и слушал звук, и смотрел картинку, и читал-переводил надписи на экране. Один файл, один прогон, никакой возни со склейкой.&lt;p&gt;Но была рамка. Дома у меня RTX 4090 на 24 гига, в неё влезает многое. А вот у большинства моих подписчиков 12 гигов и меньше. Пихать в инструмент жирные модели, которые у них просто не запустятся, мне не хотелось. Так что планку я поставил сразу под аудиторию: всё должно жить в 12 гигах VRAM. Иначе смысла нет.&lt;p&gt;Поресёрчил омни-модели. Вывод вышел неприятный: ни одна модель, которая влезает в 12 гигов, не умеет нормально размечать речь по времени и по говорящим за один проход. Это не я поленился покопаться, это просто потолок таких моделей, даже лучших. Кто где говорит и в какую секунду - они на этом плывут.&lt;p&gt;Реальный кандидат был один, MiniCPM-o, он по размеру проходил. Но до его тестов я даже не дошёл. Ещё на ресёрче стало понятно, что омни в принципе не вывозит аудио-тайминг, и запускать её смысла уже не было.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/211/478/c35/211478c358030b0e05ca04c98e2b2e6e.png alt=&#34;Не так изящно как мне бы хотелось, но и не 14 узлов как в начале&#34; title=&#34;Не так изящно как мне бы хотелось, но и не 14 узлов как в начале&#34; width=2360 height=2320 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/211/478/c35/211478c358030b0e05ca04c98e2b2e6e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/211/478/c35/211478c358030b0e05ca04c98e2b2e6e.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Не так изящно как мне бы хотелось, но и не 14 узлов как в начале&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Поэтому в итоге не одна модель, а гибрид из шести специализированных. Каждая делает свой кусок и делает его хорошо:&lt;ul&gt;&lt;li&gt;&lt;p&gt;распознавание речи берёт на себя &lt;a href=https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3 rel=&#34;noopener noreferrer nofollow&#34;&gt;Parakeet&lt;/a&gt;;&lt;li&gt;&lt;p&gt;кто и когда говорит размечает &lt;a href=https://huggingface.co/nvidia/diar_sortformer_4spk-v1 rel=&#34;noopener noreferrer nofollow&#34;&gt;Sortformer&lt;/a&gt;;&lt;li&gt;&lt;p&gt;голос от музыки отделяет &lt;a href=https://github.com/nomadkaraoke/python-audio-separator rel=&#34;noopener noreferrer nofollow&#34;&gt;audio-separator&lt;/a&gt; (UVR);&lt;li&gt;&lt;p&gt;надписи на кадре читает и переводит квантованная &lt;a href=https://huggingface.co/google/gemma-4-12B rel=&#34;noopener noreferrer nofollow&#34;&gt;Gemma&lt;/a&gt;;&lt;li&gt;&lt;p&gt;озвучивает и клонирует голос &lt;a href=https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-Base rel=&#34;noopener noreferrer nofollow&#34;&gt;Qwen3-TTS&lt;/a&gt;;&lt;li&gt;&lt;p&gt;экранный текст вытаскивает &lt;a href=https://github.com/RapidAI/RapidOCR rel=&#34;noopener noreferrer nofollow&#34;&gt;RapidOCR&lt;/a&gt;, а вжигает субтитры &lt;a href=https://github.com/libass/libass rel=&#34;noopener noreferrer nofollow&#34;&gt;libass&lt;/a&gt;.&lt;/ul&gt;&lt;p&gt;Да, шесть штук вместо одной звучит как перебор. Но каждая тут весит немного, все вместе укладываются в бюджет по памяти, и на своём участке работают лучше, чем одна большая модель на всём сразу.&lt;h3&gt;❯ TTS: лучший из худших&lt;/h3&gt;&lt;p&gt;Озвучка - это сердце дубляжа. Поэтому к выбору движка я подошёл серьёзнее всего.&lt;p&gt;TTS, который мне нужен, должен уметь клонировать голос. Не просто прочитать текст роботом, а звучать похоже на оригинал, в моём случае ещё и по-русски. Таких движков несколько, и я прогнал большое исследование: погонял кандидатов по метрикам.&lt;p&gt;&lt;a href=https://t.me/neuroport/702 rel=&#34;noopener noreferrer nofollow&#34;&gt;Вывод &lt;/a&gt;вышел невесёлый. Идеального движка нет. Вообще. У каждого свой набор косяков.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/1d5/b47/5c7/1d5b475c73cbe205bdcad49043b2a0f2.png width=766 height=1352 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/1d5/b47/5c7/1d5b475c73cbe205bdcad49043b2a0f2.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/1d5/b47/5c7/1d5b475c73cbe205bdcad49043b2a0f2.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Победил &lt;a href=https://github.com/newgrit1004/qwen3-tts-triton rel=&#34;noopener noreferrer nofollow&#34;&gt;Qwen3-TTS&lt;/a&gt;, в сборке на Triton. Победил не потому, что не косячит. Косячит. Хуже всего у него с ударениями: периодически ставит их не туда, и тогда слово звучит не по-русски. Но из всех вариантов это самый адекватный компромисс. Он быстрый, лёгкий и работает быстрее реалтайма. Лучший из худших, если совсем честно.&lt;p&gt;И вот тут я хочу сказать вещь, которая тянется через весь проект. Он целиком собран на компромиссах. Gemma у меня квантованная, не полная. Сам процесс полу-автоматический, а не нажал кнопку и пошёл пить кофе. Везде, где можно было выбрать между идеально и просто работает, я выбирал второе. Иначе инструмента просто не было бы.&lt;p&gt;Выбор TTS, да, спорный. Я знаю, что многие со мной не согласятся. И это не просто так. Но про это позже.&lt;h3&gt;❯ Прощай, Gradio&lt;/h3&gt;&lt;p&gt;Сначала я хотел сделать совсем просто. Лёгкий CLI, полностью автоматический. Кидаешь ролик, получаешь готовый дубляж. Без рук, без редактора, без меня.&lt;p&gt;Не вышло. У каждого ролика своя верстка: надписи лезут не туда, разметка везде разная. Модели ошибаются. Универсального кинул и готово не существует. Чем дольше я это ковырял, тем понятнее становилось, что полностью без человека тут не выехать.&lt;p&gt;Так я пришёл к полу-автоматике. Движок берёт на себя тяжёлую часть: анализирует ролик, раскладывает умные дефолты. А человек правит остальное. Но правит не вслепую, а с живым превью, где сразу видно что получится.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/924/976/271/92497627126ac85d70bfd9a6ec55c88f.png alt=&#34;Это Спарта? Нет, это ГРАДИО!&#34; title=&#34;Это Спарта? Нет, это ГРАДИО!&#34; width=1131 height=1327 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/924/976/271/92497627126ac85d70bfd9a6ec55c88f.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/924/976/271/92497627126ac85d70bfd9a6ec55c88f.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Это Спарта? Нет, это ГРАДИО!&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Тут стоит пояснить, что вообще такое &lt;a href=https://www.gradio.app/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Gradio&lt;/a&gt; - вдруг кто не сталкивался. Это питоновская библиотека для быстрых интерфейсов к нейросетям: парой строк кода оборачиваешь модель в простенькую веб-морду - поле ввода, кнопка, окошко с результатом, и всё, модель можно тыкать в браузере, а не гонять из консоли. Бутстрап для нейронок.&lt;p&gt;Принадлежит он &lt;a href=https://huggingface.co/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Hugging Face&lt;/a&gt; - по сути это гитхаб для нейросетей, главный репозиторий ИИ-моделей. Поэтому с моделями оттуда Gradio дружит бесшовно: взял с хаба, обернул, выложил - всё заводится из коробки. Идеальная штука, чтобы по-быстрому собрать MVP, на нём собраны почти все мои портативки.&lt;p&gt;И вот тут стало ясно, что Gradio мне больше не помощник. Для демки он отличный. Но нормальный редактор на нём не собрать. Gradio - это один столбик, пара полей и готовых элементов и кнопка. А мне нужен холст, превью, субтитры поверх видео, перетаскивание.&lt;p&gt;Поэтому я взял нормальный фронт. &lt;a href=https://github.com/konvajs/react-konva rel=&#34;noopener noreferrer nofollow&#34;&gt;React + Konva&lt;/a&gt; для холста, на нём всё рисуется и двигается. Субтитры кладутся сверху через &lt;a href=https://github.com/ThaUnknown/jassub rel=&#34;noopener noreferrer nofollow&#34;&gt;JASSUB&lt;/a&gt;, прямо поверх видео. Бэкенд на &lt;a href=https://github.com/fastapi/fastapi rel=&#34;noopener noreferrer nofollow&#34;&gt;FastAPI&lt;/a&gt;. А голый CLI к тому же грузил весь стек заново на каждый ролик, что радости тоже не добавляло.&lt;h3&gt;❯ Редактор&lt;/h3&gt;&lt;p&gt;Теперь как это работает в деле. Кидаешь ролик, движок прогоняет анализ и раскладывает умные дефолты: транскрипт, кто где говорит, какие надписи нашёл в кадре, готовый план субтитров. Дальше начинается пользовательская часть.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/8c6/990/014/8c6990014dd96e4f074921ef6f435582.png alt=&#34;На Gradio, конечно, так не сделаешь&#34; title=&#34;На Gradio, конечно, так не сделаешь&#34; width=904 height=531 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/8c6/990/014/8c6990014dd96e4f074921ef6f435582.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/8c6/990/014/8c6990014dd96e4f074921ef6f435582.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;На Gradio, конечно, так не сделаешь&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Дольше всего я бился над превью. Оно и сейчас по сути покадровое слайд шоу с аудио дорожкой, это так и задумано. Но поначалу оно тормозило так, что работать было невозможно. Полный рендер одного кадра шел около 25 секунд. Двадцать пять. Сидеть и ждать столько после каждого чиха в редакторе невозможно. Пришлось делать отдельный быстрый предпросмотр, тоже один кадр, но уже около 0.14 секунды. Вот после этого редактор и ожил.&lt;p&gt;Каждый ролик можно гонять в одном из трёх режимов: Субтитры, Дубляж или Шуточный. Первые два понятны. С Шуточным интереснее: говоришь Gemma тему, она переписывает скрипт под неё, и кусок переозвучивается заново уже с новым текстом, мем сделанный в этом режиме ждет вас в конце статьи.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/3b7/da4/b2d/3b7da4b2d327c1fedd12126a23c7e708.png width=2087 height=1197 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/3b7/da4/b2d/3b7da4b2d327c1fedd12126a23c7e708.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/3b7/da4/b2d/3b7da4b2d327c1fedd12126a23c7e708.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Голоса вешаются на каждого говорящего по отдельности. Один спикер - один голос из пака, другой - другой. Голосов в паке много и никто не мешает добавлять еще просто закидывая файлы в папку.&lt;p&gt;С субтитрами тоже всё руками. Не нравится, где стоит полоса - берёшь её мышкой и таскаешь прямо по кадру, куда надо.&lt;p&gt;Теперь переведённые надписи в самом видео. Хочется, чтобы они смотрелись как родные. Поэтому оригинал я не блюрю. Блюр мылит картинку и сразу выдаёт, что тут что-то подменили. Вместо этого оригинальная надпись кроется непрозрачной плашкой под цвет сцены. Где её положить, подсказывает OCR, а как оформить текст поверх, подсматривает зрение Gemma. Получается аккуратно.&lt;p&gt;И ещё про громкость. Реплики приходят разные по уровню. Поэтому все фразы приводятся к одному уровню.&lt;h3&gt;❯ Честно про вайбкодинг&lt;/h3&gt;&lt;p&gt;Раз уж пошёл такой разговор, расскажу честно про обратную сторону.&lt;p&gt;Этот проект тоже собран в паре с ИИ-агентом. Штука мощная, но есть одна боль, которая выматывала сильнее всего. Агент уверенно пишет тебе &amp;#34;готово, баг исправлен&amp;#34;. А на деле ничего не исправлено. И ловишь ты это только сам, глазами.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c243b954272d3f37d45 data-style id=6a3c3c243b954272d3f37d45 width data-habr-games&gt;&lt;/div&gt;&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c233b954272d3f37d43 data-style id=6a3c3c233b954272d3f37d43 width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;Простой пример. Поправили субтитр в превью, всё хорошо. Запускаешь экспорт - а там та же самая ошибка на месте. Агент починил один путь и честно отчитался за оба.&lt;p&gt;Но больнее всего была не сама модельная часть. Больнее всего оказалась упаковка в один клик, через &lt;a href=https://pinokio.computer/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Pinokio&lt;/a&gt;. Агент взял обязательную зависимость и пометил её как необязательную. Вроде мелочь. А без неё весь дубляж просто падал. И отдельная радость - полдня ушло на одну ошибку с ffmpeg. Просто полдня на одну ошибку, подробности опущу.&lt;p&gt;Вывод для меня простой. Верить агенту на слово нельзя. Совсем. Поэтому всё, что он делает, проверяешь сам. Каждый раз.&lt;h3&gt;❯ Стек и как это работает&lt;/h3&gt;&lt;p&gt;Если убрать всю кухню, алгоритм простой.&lt;p&gt;Кидаешь видео в окно. Дальше движок сам прогоняет весь конвейер: снимает транскрипт, режет на сегменты по спикерам, вытаскивает надписи с экрана, собирает план субтитров с разумными дефолтами. На выходе готовый проект, который можно открыть и крутить.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c2384f086afcdced551 data-style id=6a3c3c2384f086afcdced551 width data-habr-games&gt;&lt;/div&gt;&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c23a269d5af84ff49af data-style id=6a3c3c23a269d5af84ff49af width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;Дальше правишь руками. Меняешь перевод, двигаешь тайминги, перебираешь надписи - и всё это с живым превью, видно сразу. Когда всё нравится, жмёшь экспорт. Тут важный момент: переозвучивается только то, что ты трогал. Остальное берётся из кэша, заново гонять весь ролик не нужно. На выходе готовый mp4.&lt;h3&gt;❯ Это бета, и ей нужны вы&lt;/h3&gt;&lt;p&gt;Я доволен тем, что получилось. Сам этим пользуюсь, и это уже не игрушка. Но давайте честно: это бета. Работы ещё хватает.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3c3c2408f9ff72f48e226b data-style id=6a3c3c2408f9ff72f48e226b width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;Поэтому про ограничения прямо. Заточено всё в основном под короткие ролики. Выбор TTS спорный, и я это прекрасно понимаю - многие со мной не согласятся по поводу того, какой голос лучше. Языков можно тащить больше, чем сейчас доступно. Технически и ттс и ллм их поддерживает больше, но каждый язык надо тестить руками, а это время.&lt;p&gt;В планах сделать все модули сменными. Раз уж столько споров вокруг TTS, логичный ход - дать каждому собрать пайплайн под себя. Не нравится распознавалка - воткни свою. Не нравится речь - поставь другой. Хочется, чтобы это был конструктор, а не приговор.&lt;p&gt;Кстати, стек так удачно лёг, что я потащил его и в другие свои проекты, например в днд игру где нейросеть выступает гейм-мастером. Но это уже отдельная история, под новую статью, так что как-нибудь в другой раз.&lt;p&gt;Теперь самое важное. Репозиторий открыт, лицензия MIT, &lt;a href=https://github.com/timoncool/dub-studio rel=&#34;noopener noreferrer nofollow&#34;&gt;код тут&lt;/a&gt; - берите и делайте. Форкайте, шлите PR и заводите issue. Если что-то сломалось или работает не так - расскажите. А ещё лучше - прогоните свой ролик и киньте результат в комменты, очень интересно посмотреть, что у вас выйдет. И если проект вам зашёл, поставьте звезду на гитхабе, мне будет приятно, а ему полезно.&lt;p&gt;Найти меня можно в &lt;a href=https://www.youtube.com/@nerual_dreming rel=&#34;noopener noreferrer nofollow&#34;&gt;YouTube&lt;/a&gt;, в &lt;a href=https://t.me/nerual_dreming rel=&#34;noopener noreferrer nofollow&#34;&gt;Телеграме &lt;/a&gt;и на &lt;a href=https://boosty.to/neuro_art rel=&#34;noopener noreferrer nofollow&#34;&gt;Бусти&lt;/a&gt;. Залетайте, там тоже интересно, каждую пятницу смотрим новинки нейросетей и генерируем вместе. Всех обнял и удачных дубляжей.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>timonin</author>
      <guid>https://habr.com/ru/articles/1051580/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051580</guid>
      <pubDate>Wed, 24 Jun 2026 20:21:05 +0000</pubDate>
    </item>
    <item>
      <title>Уязвимость пришла из зависимости, которую вы не добавляли: ловим дыры в Spring до прода в GitLab</title>
      <link>https://habr.com/ru/companies/otus/articles/1047050/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1047050</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Всем привет, меня зовут Сергей Прощаев и в этой статье расскажу, как настроить в GitLab автоматический поиск уязвимостей в зависимостях Spring‑приложения так, чтобы дыры всплывали в merge request до прода, а не на проде, — и при этом пайплайн не падал на каждой устаревшей библиотеке.&lt;p&gt;Я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech &amp;amp; E‑commerce и преподаю на курсах разработки и архитектуры в ОТУС.&lt;p&gt;Сразу обозначу рамку. Это не обзор «что такое &lt;abbr class=habraabbr title=&#34;Класс инструментов, которые анализируют состав сторонних зависимостей в проекте и сверяют их с базами известных уязвимостей. В отличие от SAST, который проверяет код, написанный вами, SCA смотрит на код, который вы импортировали. Типичные представители: GitLab Dependency Scanning, OWASP Dependency-Check, Snyk, Trivy.&#34; data-title=&#34;&amp;lt;p&amp;gt;Класс инструментов, которые анализируют состав сторонних зависимостей в проекте и сверяют их с базами известных уязвимостей. В отличие от SAST, который проверяет код, написанный вами, SCA смотрит на код, который вы импортировали. Типичные представители: GitLab Dependency Scanning, OWASP Dependency-Check, Snyk, Trivy.&amp;lt;/p&amp;gt;&#34; data-abbr=SCA&gt;SCA&lt;/abbr&gt;» и не пересказ документации GitLab. Это рабочий маршрут: берём типовой Spring Boot сервис, подключаем dependency scanning на новом движке и настраиваем так, чтобы security‑гейт реально защищал, а не превращался в красный крестик, который все привыкли игнорировать.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e47/ea9/b31/e47ea9b31b62803cb3a038f1f42177cf.png alt=&#34;Рис. 1. Уязвимость, спрятанная в глубине дерева зависимостей, и контрольная точка в пайплайне, которая ловит её до продакшена&#34; title=&#34;Рис. 1. Уязвимость, спрятанная в глубине дерева зависимостей, и контрольная точка в пайплайне, которая ловит её до продакшена&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e47/ea9/b31/e47ea9b31b62803cb3a038f1f42177cf.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e47/ea9/b31/e47ea9b31b62803cb3a038f1f42177cf.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рис. 1. Уязвимость, спрятанная в глубине дерева зависимостей, и контрольная точка в пайплайне, которая ловит её до продакшена&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;С чего всё начинается: «у нас же ничего такого не подключено»&lt;/h3&gt;&lt;p&gt;Помню историю, которая до сих пор для меня как эталон. Декабрь 2021-го, Log4Shell. Полночь, дежурный канал разрывается, и первый вопрос, который задаёт половина команд по всему рынку, звучит не «как пропатчить», а «а у нас вообще есть этот Log4j?».&lt;p&gt;И вот это самое страшное. В pom.xml его нет. Никто его не добавлял. Он приехал &lt;abbr class=habraabbr title=&#34;Если ваш проект подключает библиотеку A, а та внутри себя использует библиотеку B, то B становится транзитивной зависимостью вашего проекта — вы её не объявляли, но она попадает в сборку. Maven подтягивает такие зависимости автоматически. Пример: подключив spring-boot-starter-web, вы транзитивно получаете spring-core, tomcat-embed-core, jackson-databind и десятки других, хотя в pom.xml их не писали. Прямые зависимости — то, что вы объявили явно; транзитивные — всё, что приехало следом.&#34; data-title=&#34;&amp;lt;p&amp;gt;Если ваш проект подключает библиотеку A, а та внутри себя использует библиотеку B, то B становится транзитивной зависимостью вашего проекта — вы её не объявляли, но она попадает в сборку. Maven подтягивает такие зависимости автоматически. Пример: подключив spring-boot-starter-web, вы транзитивно получаете spring-core, tomcat-embed-core, jackson-databind и десятки других, хотя в pom.xml их не писали. Прямые зависимости — то, что вы объявили явно; транзитивные — всё, что приехало следом.&amp;lt;/p&amp;gt;&#34; data-abbr=транзитивн&gt;транзитивн&lt;/abbr&gt;о — через стартер, через библиотеку логирования, через зависимость зависимости. Команды тратили дни, чтобы просто понять, затронуты они или нет: не было полной карты того, что собирается в JAR.&lt;p&gt;Мне как‑то попалась оценка по экосистеме Maven за 2025 год (её приводили в аналитике по supply‑chain рискам): уязвимости затрагивали порядка трети последних релизов библиотек через прямые зависимости и заметно больше — через транзитивные. Точные проценты гуляют от источника к источнику, но порядок один: основной канал риска — не то, что вы написали в pom.xml, а то, что подтянулось следом, на два‑три уровня глубже.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Я бы сформулировал так:&lt;/strong&gt; если ваш инструмент проверки смотрит только на прямые зависимости, он показывает вам верхушку и молчит про корни. А именно в корнях обычно и сидит то, что вас положит.&lt;/blockquote&gt;&lt;h3&gt;Что мы будем делать и в каких условиях&lt;/h3&gt;&lt;p&gt;Берём типовой сервис: Spring Boot 4.1.0, Spring Framework 7.0.8 под капотом, Java 21, сборка через Maven. Пример протестирован на Spring Boot 4.1 и проверен на GitLab 19.1. Используемые возможности относятся к GitLab, поэтому для Spring Boot 3.x конфигурация остаётся такой же — меняются только версии зависимостей. Тариф — Ultimate, потому что &lt;abbr class=habraabbr title=&#34;«Спецификация состава ПО» — машиночитаемый список всех компонентов и зависимостей приложения, включая транзитивные, с их версиями и связями. По сути инвентарная ведомость того, из чего реально собран ваш артефакт. Нужна для анализа уязвимостей, лицензионного аудита и требований по безопасности цепочки поставок.&#34; data-title=&#34;&amp;lt;p&amp;gt;«Спецификация состава ПО» — машиночитаемый список всех компонентов и зависимостей приложения, включая транзитивные, с их версиями и связями. По сути инвентарная ведомость того, из чего реально собран ваш артефакт. Нужна для анализа уязвимостей, лицензионного аудита и требований по безопасности цепочки поставок.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&#34; data-abbr=SBOM&gt;SBOM&lt;/abbr&gt;‑based dependency scanning живёт именно там; на нём же завязан Security Dashboard и гейт в merge request.&lt;p&gt;Чтобы было что ловить, добавим в сервис «мину» — зависимость с известной уязвимостью. Возьмём commons‑text 1.9. В ней живёт CVE-2022-42889, она же &lt;abbr class=habraabbr title=&#34;Критическая уязвимость в библиотеке Apache Commons Text версий 1.5–1.9, позволяющая при определённых сценариях использования класса StringSubstitutor добиться удалённого выполнения кода через подстановку специально сформированной строки. Название по аналогии с Log4Shell; исправлена в версии 1.10. CVSS v3.1 Base Score — 9.8.&#34; data-title=&#34;&amp;lt;p&amp;gt;Критическая уязвимость в библиотеке Apache Commons Text версий 1.5–1.9, позволяющая при определённых сценариях использования класса StringSubstitutor добиться удалённого выполнения кода через подстановку специально сформированной строки. Название по аналогии с Log4Shell; исправлена в версии 1.10. CVSS v3.1 Base Score — 9.8.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&#34; data-abbr=Text4Shell&gt;Text4Shell&lt;/abbr&gt;: при определённых сценариях использования StringSubstitutor с дефолтными интерполяторами она позволяет добиться удалённого выполнения кода (CVSS v3.1 Base Score 9.8). Починили её в 1.10, но 1.9 до сих пор регулярно встречается в проектах — иногда напрямую, чаще транзитивно, приехав через утилитную библиотеку, которую подключили ради одного метода.&lt;pre&gt;&lt;code class=xml&gt;&amp;lt;dependencies&amp;gt;&#xA;    &amp;lt;dependency&amp;gt;&#xA;        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&#xA;        &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;&#xA;    &amp;lt;/dependency&amp;gt;&#xA;&#xA;    &amp;lt;!-- Наша &amp;#34;мина&amp;#34;: уязвимая версия commons-text (CVE-2022-42889, Text4Shell).&#xA;         В реальном проекте такая чаще приезжает транзитивно, а не строкой в pom.&#xA;         Здесь объявили явно, чтобы пример был воспроизводимым. --&amp;gt;&#xA;    &amp;lt;dependency&amp;gt;&#xA;        &amp;lt;groupId&amp;gt;org.apache.commons&amp;lt;/groupId&amp;gt;&#xA;        &amp;lt;artifactId&amp;gt;commons-text&amp;lt;/artifactId&amp;gt;&#xA;        &amp;lt;version&amp;gt;1.9&amp;lt;/version&amp;gt;&#xA;    &amp;lt;/dependency&amp;gt;&#xA;&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Важная оговорка про честность примера&lt;/strong&gt;. Я объявил уязвимую версию явной строкой, чтобы вы воспроизвели всё один в один. В жизни так бывает реже: обычно commons‑text 1.9 не написан в pom.xml, а подтянут на втором‑третьем уровне через библиотеку, которую подключили для другого. Руками такую мину вы не увидите — поэтому дальше я упираюсь в транзитивные зависимости.&lt;/blockquote&gt;&lt;p&gt;Цель — три вещи:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Видеть полный список зависимостей, включая транзитивные, и понимать, какая откуда пришла.&lt;li&gt;&lt;p&gt;Получать новые уязвимости прямо в merge request — до того, как изменение попало в основную ветку.&lt;li&gt;&lt;p&gt;Не ронять пайплайн на каждой найденной CVE, а отделять то, что реально угрожает, от шума.&lt;/ul&gt;&lt;p&gt;Важная деталь по версиям. Внутри GitLab сейчас два движка dependency scanning. Старый, на Gemnasium, помечен устаревшим ещё в 17.9 и пойдёт под нож в 20.0. Новый движок использует SBOM в формате &lt;abbr class=habraabbr title=&#34;Открытый стандарт формата SBOM, поддерживаемый OWASP. Описывает, в каком виде хранить и передавать список компонентов и их зависимостей. Это именно формат данных, а не инструмент анализа — GitLab генерирует SBOM в этом формате, чтобы результат можно было использовать в других системах безопасности и комплаенса.&#34; data-title=&#34;&amp;lt;p&amp;gt;Открытый стандарт формата SBOM, поддерживаемый OWASP. Описывает, в каком виде хранить и передавать список компонентов и их зависимостей. Это именно формат данных, а не инструмент анализа — GitLab генерирует SBOM в этом формате, чтобы результат можно было использовать в других системах безопасности и комплаенса.&amp;lt;/p&amp;gt;&#34; data-abbr=CycloneDX&gt;CycloneDX&lt;/abbr&gt;, стал generally available в GitLab 19.0 и подключается через V2-шаблон. Делаем сразу на новом: переезжать с Gemnasium через год — то ещё удовольствие, я предпочитаю не плодить технический долг.&lt;h3&gt;Маршрут решения&lt;/h3&gt;&lt;p&gt;Дальше — по шагам. Каждый шаг закрывает один конкретный риск, и после каждого я показываю, как проверить, что он сработал.&lt;h4&gt;Шаг 1. Подключаем новый движок сканирования&lt;/h4&gt;&lt;p&gt;Базовое подключение — одна строка include в.gitlab‑ci.yml. Отдельных джоб руками писать не нужно, шаблон сам разворачивает всё необходимое.&lt;pre&gt;&lt;code class=yaml&gt;stages:&#xA;  - build&#xA;  - test&#xA;&#xA;include:&#xA;  - template: Jobs/Dependency-Scanning.v2.gitlab-ci.yml&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Ключевое слово здесь — v2. Если по старому гайду с какого‑нибудь Medium подключить Security/Dependency‑Scanning.gitlab‑ci.yml, вы получите старый Gemnasium‑движок. Внешне всё работает, отчёт появляется — но это уже легаси, и части фишек, ради которых мы всё затеваем, там не будет.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Как проверить:&lt;/strong&gt; после пуша зайдите в Build → Pipelines, откройте последний пайплайн. В стадии.pre должна появиться джоба разрешения зависимостей, а дальше — dependency‑scanning. Если их нет — скорее всего не включена фича в Settings → Security или у проекта не тот тариф.&lt;/blockquote&gt;&lt;h4&gt;Шаг 2. Даём сканеру увидеть транзитивные зависимости&lt;/h4&gt;&lt;p&gt;Здесь же — главная ловушка, на которую я сам когда‑то наступил.&lt;p&gt;Анализатор dependency scanning строит SBOM на основе графа зависимостей и метаданных сборки, и для Maven источников несколько: &lt;abbr class=habraabbr title=&#34;Процесс, в котором Maven строит полное дерево зависимостей: проходит по всем прямым зависимостям, выясняет их собственные зависимости, и так рекурсивно до конца. Заодно он разрешает конфликты версий (если разные ветки дерева требуют разные версии одной библиотеки, выбирается «ближайшая» к корню) и формирует итоговый список того, что реально окажется в сборке.&#34; data-title=&#34;&amp;lt;p&amp;gt;Процесс, в котором Maven строит полное дерево зависимостей: проходит по всем прямым зависимостям, выясняет их собственные зависимости, и так рекурсивно до конца. Заодно он разрешает конфликты версий (если разные ветки дерева требуют разные версии одной библиотеки, выбирается «ближайшая» к корню) и формирует итоговый список того, что реально окажется в сборке.&amp;lt;/p&amp;gt;&#34; data-abbr=&#34;разрешение зависимостей&#34;&gt;разрешение зависимостей&lt;/abbr&gt; во время сборки, экспортированный граф (maven.graph.json) или, в некоторых случаях, анализ самого pom.xml. Проблема в том, что у Maven, в отличие от условного npm, нет привычного «lock‑файла» в репозитории по умолчанию. И если нет ни графа, ни результатов resolution, анализатор может перейти в &lt;abbr class=habraabbr title=&#34;Запасной (деградационный) режим работы анализатора в GitLab. Когда нет ни заранее построенного графа зависимостей, ни результатов полноценного разрешения, анализатор разбирает сам файл-манифест (pom.xml). Минус режима в том, что он ограничивается явно объявленными зависимостями и не строит полную модель транзитивного дерева — то есть видит вершину, но не все корни. Это особенность реализации, а не свойство Maven.&#34; data-title=&#34;&amp;lt;p&amp;gt;Запасной (деградационный) режим работы анализатора в GitLab. Когда нет ни заранее построенного графа зависимостей, ни результатов полноценного разрешения, анализатор разбирает сам файл-манифест (pom.xml). Минус режима в том, что он ограничивается явно объявленными зависимостями и не строит полную модель транзитивного дерева — то есть видит вершину, но не все корни. Это особенность реализации, а не свойство Maven.&amp;lt;/p&amp;gt;&#34; data-abbr=fallback-режим&gt;fallback‑режим&lt;/abbr&gt; анализа pom.xml. А этот режим, по документации GitLab на момент написания статьи, ограничивается явно объявленными зависимостями и неполной моделью транзитивного графа. Это поведение реализации GitLab, а не свойство Maven, и со временем может измениться.&lt;p&gt;То есть формально джоба зелёная, отчёт есть, галочка стоит. А часть зависимостей могла не попасть в анализ. Худший вид безопасности — тот, что создаёт ложное ощущение, будто всё проверено.&lt;p&gt;В GitLab 19.0 это во многом закрыли автоматическим разрешением зависимостей: если коммитнутого графа нет, движок сам пытается сгенерировать его в стадии.pre, поднимая лёгкий образ с JDK и прогоняя Maven. На многих проектах хватает из коробки.&lt;p&gt;Но для воспроизводимости примера я предпочитаю генерировать maven.graph.json явно. Экспортированный граф зависимостей может использоваться анализатором GitLab как один из источников информации о составе зависимостей, и явная генерация упрощает диагностику и делает пайплайн менее зависимым от внутренних механизмов анализатора. Если GitLab у вас и так строит граф корректно — оставайтесь на автоматике, это полноценный рабочий вариант.&lt;pre&gt;&lt;code class=yaml&gt;stages:&#xA;  - build&#xA;  - test&#xA;&#xA;include:&#xA;  - template: Jobs/Dependency-Scanning.v2.gitlab-ci.yml&#xA;&#xA;# Явно строим граф зависимостей в контролируемой сборочной стадии.&#xA;# Формат именно JSON (maven.graph.json) — его умеет читать анализатор.&#xA;build:&#xA;  stage: build&#xA;  image: maven:3.9-eclipse-temurin-21&#xA;  script:&#xA;    - mvn dependency:tree -DoutputType=json -DoutputFile=maven.graph.json&#xA;    - mvn package -DskipTests&#xA;  artifacts:&#xA;    paths:&#xA;      - maven.graph.json&#xA;      - target/*.jar&#xA;    expire_in: 1 hour&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Как проверить:&lt;/strong&gt; откройте dependency‑scanning, скачайте артефакт gl‑dependency‑scanning‑report.json или сам SBOM в формате CycloneDX. Найдите в нём нашу commons‑text 1.9 — она должна попасть в отчёт как уязвимая (Text4Shell). Заодно гляньте на любую заведомо транзитивную библиотеку — что‑нибудь из tomcat‑embed или jackson, которое вы руками не подключали. Если и мина, и транзитивные на месте — анализатор увидел полный граф. Если в отчёте только явно объявленное в pom.xml, — похоже, сработал fallback, и стоит разобраться с графом зависимостей.&lt;/blockquote&gt;&lt;h4&gt;Шаг 3. Включаем reachability — отделяем опасное от шумного&lt;/h4&gt;&lt;p&gt;Теперь решаем проблему, из‑за которой большинство команд в итоге забивают на сканеры. Имя ей — шум.&lt;p&gt;Если просто включить сканирование на большом легаси‑проекте, вы утром получите десятки, а то и сотни уязвимостей. Critical, High, всё красное. И дальше одно из двух: либо команда героически неделю разгребает, либо — что бывает чаще — все молча договариваются красный гейт игнорировать. И инструмент фактически перестаёт использоваться.&lt;p&gt;Здесь помогает фича, которая в новом движке мне особенно нравится, — &lt;abbr class=habraabbr title=&#34;Техника, которая определяет, обращается ли код приложения к уязвимому компоненту на самом деле, или тот просто присутствует в дереве зависимостей «мёртвым грузом». Помогает отделить уязвимости, до которых код реально дотягивается, от формально присутствующих, и тем самым снизить шум. Важно: это статическая оценка использования, а не доказательство эксплуатируемости.&#34; data-title=&#34;&amp;lt;p&amp;gt;Техника, которая определяет, обращается ли код приложения к уязвимому компоненту на самом деле, или тот просто присутствует в дереве зависимостей «мёртвым грузом». Помогает отделить уязвимости, до которых код реально дотягивается, от формально присутствующих, и тем самым снизить шум. Важно: это статическая оценка использования, а не доказательство эксплуатируемости.&amp;lt;/p&amp;gt;&#34; data-abbr=&#34;static reachability&#34;&gt;static reachability&lt;/abbr&gt; analysis. Далеко не каждая зависимость из дерева реально используется в коде: что‑то подтянулось транзитивно, но ни одна строчка вашего кода её не импортирует. Анализатор использует статический анализ проекта и определяет, есть ли в коде фактическое использование уязвимых пакетов — их импорты и обращения к символам. Если использование найдено, уязвимости в этой зависимости присваивается значение reachable. Важно понимать рамку: это статическая модель использования, а не гарантия эксплуатации. Reachability сужает список того, на что смотреть в первую очередь, но не выносит вердикт «это точно эксплойтабельно».&lt;p&gt;Для Java, JavaScript/TypeScript и Python это работает. Включается одной переменной:&lt;pre&gt;&lt;code class=yaml&gt;include:&#xA;  - template: Jobs/Dependency-Scanning.v2.gitlab-ci.yml&#xA;    variables:&#xA;      DS_STATIC_REACHABILITY_ENABLED: true&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Я когда первый раз прогнал это на реальном сервисе, выдохнул. Список «на что смотреть сейчас» сократился в разы. Большая часть красноты оказалась библиотеками, до которых приложение не дотягивается.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Как проверить:&lt;/strong&gt; в карточке уязвимости появляется поле Reachable. Отфильтруйте дашборд по нему. Уязвимости со значением Yes — ваш реальный backlog на сегодня. Остальное — в очередь по плановому обновлению, без ночных подвигов.&lt;/blockquote&gt;&lt;h4&gt;Шаг 4. Ставим гейт в merge request&lt;/h4&gt;&lt;p&gt;Сканер, который пишет отчёт, который никто не открывает, бесполезен. Смысл всей затеи — поймать проблему на входе, в merge request, пока изменение ещё не в main.&lt;p&gt;Тут принципиальная тонкость. Гейт должен реагировать не на «в проекте вообще есть уязвимости» (они есть всегда, это нормальное состояние живого проекта), а на «это конкретное изменение приносит новую уязвимость». GitLab Security Policies позволяют реализовать именно такой сценарий: политика сравнивает находки между исходной и целевой веткой и показывает в merge request дельту — что нового притащил этот MR.&lt;p&gt;Задаётся это политикой на уровне группы, а не правкой .gitlab‑ci.yml в каждом репозитории. Важный сдвиг: безопасность настраивается один раз и применяется ко всем проектам автоматически, и рядовой разработчик не может её случайно выпилить из своего .gitlab‑ci.yml.&lt;p&gt;Сам гейт описывается политикой в отдельном security‑проекте. Вот минимальный пример scan result policy, который блокирует мерж, если изменение приносит новую уязвимость уровня Critical:&lt;pre&gt;&lt;code class=yaml&gt;approval_policy:&#xA;  - name: Блок мержа на новые Critical в зависимостях&#xA;    description: &amp;gt;&#xA;      Если MR приносит новую уязвимость Critical из dependency scanning —&#xA;      требуется аппрув security-команды. Состояние проекта в целом не трогаем,&#xA;      смотрим только дельту, которую вносит это изменение.&#xA;    enabled: true&#xA;    rules:&#xA;      - type: scan_finding&#xA;        scanners:&#xA;          - dependency_scanning&#xA;        vulnerabilities_allowed: 0&#xA;        severity_levels:&#xA;          - critical&#xA;        vulnerability_states:&#xA;          - newly_detected&#xA;    actions:&#xA;      - type: require_approval&#xA;        approvals_required: 1&#xA;        role_approvers:&#xA;          - maintainer&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Разберём важное.&lt;/strong&gt; &lt;code&gt;vulnerability_states&lt;/code&gt;: &lt;code&gt;newly_detected&lt;/code&gt; — это и есть дельта: политика срабатывает только на то, что добавил MR, а не на весь ворох существующих находок. &lt;code&gt;vulnerabilities_allowed&lt;/code&gt;: 0 по critical — «ни одной новой критичной без аппрува». А require_approval вместо жёсткой блокировки оставляет легальную дверь: security‑команда может осознанно пропустить изменение, приняв риск. Это честнее наглухо закрытого шлагбаума, который начинают обходить.&lt;p&gt;Я бы предостерёг от частой ошибки — не делайте первый гейт блокирующим по любой High. Получите бунт команды на второй день. Мой подход: на старте гейт реагирует только на новые Critical, а потом, когда команда привыкла, добавляем High и фильтр по Reachable. Это узкий, обороняемый порог — против него тяжело возразить, потому что это буквально «ты прямо сейчас тащишь в прод критичную дыру». А дальше планомерно закручиваете гайки.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Как проверить:&lt;/strong&gt; заведите тестовый MR, добавляющий в pom.xml ту самую commons‑text версии 1.9. Виджет в merge request должен показать новую уязвимость Critical именно как привнесённую этим MR, а сам мерж — потребовать аппрува по политике. Если показал и потребовал — петля замкнулась, гейт работает.&lt;/blockquote&gt;&lt;h3&gt;Почему транзитивные зависимости — это не только про CVE&lt;/h3&gt;&lt;p&gt;Тут хочу показать кейс, после которого я стал относиться к глубине дерева зависимостей всерьёз, а не как к формальности.&lt;p&gt;Есть исследование под названием &lt;abbr class=habraabbr title=&#34;Класс атак на цепочку поставок Java-приложений, представленный на воркшопе SCORED в 2025 году. Идея: подсунуть вредоносный класс с тем же полным именем, что у легитимного, спрятав его глубоко в транзитивной зависимости. При определённом порядке формирования classpath вредоносный класс может попасть в сборку раньше настоящего и подменить его поведение. Исследователи воспроизвели атаку на реальном приложении Corona-Warn-App.&#34; data-title=&#34;&amp;lt;p&amp;gt;Класс атак на цепочку поставок Java-приложений, представленный на воркшопе SCORED в 2025 году. Идея: подсунуть вредоносный класс с тем же полным именем, что у легитимного, спрятав его глубоко в транзитивной зависимости. При определённом порядке формирования classpath вредоносный класс может попасть в сборку раньше настоящего и подменить его поведение. Исследователи воспроизвели атаку на реальном приложении Corona-Warn-App.&amp;lt;/p&amp;gt;&#34; data-abbr=Java-Class-Hijack&gt;Java‑Class‑Hijack&lt;/abbr&gt; (его представляли на воркшопе SCORED в 2025-м). Суть атаки красивая и от этого жутковатая. В Java, когда классы с одинаковым полным именем оказываются в разных зависимостях, при определённом порядке разрешения classpath в дело идёт тот класс, что встретился раньше. И вот исследователи показали: можно подсунуть вредоносный класс с тем же именем, что у легитимного, спрятав его глубоко в транзитивной зависимости. При сборке он встаёт в итоговый артефакт раньше настоящего — и подменяет поведение, не трогая ни основной код, ни имена библиотек.&lt;p&gt;Самое показательное — они воспроизвели это на реальном серверном приложении Corona‑Warn‑App, немецком ковид‑трекере. Через крошечную библиотеку валидации JSON, сидящую где‑то в глубине дерева, удалось дотянуться до логики подключения к базе. Маленькая безобидная зависимость на третьем уровне вложенности — а на выходе контроль над коннектом к БД. Оговорюсь: это не «любой Maven‑проект обречён» — эксплуатация требует ряда условий, связанных с разрешением зависимостей и порядком формирования classpath. Но сам класс атак показывает, почему глубину дерева нельзя игнорировать.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;К чему я это&lt;/strong&gt;. «Видеть транзитивные зависимости и их происхождение» — это не про галочку в комплаенсе. Атакующие всё чаще используют не прямую зависимость, которую вы хоть как‑то смотрите, а ту, что на три уровня глубже и которую вы в глаза не видели. Новый анализатор умеет трассировать транзитивную зависимость до источника: показывает цепочку, через какую библиотеку приехал уязвимый пакет. А зная цепочку, понимаешь, где бить — обновлять родителя или форсить версию.&lt;/blockquote&gt;&lt;p&gt;И это перестало быть теорией ещё и потому, что атаки идут валом. В ноябре 2025-го червь &lt;abbr class=habraabbr title=&#34;Самораспространяющийся вредонос (червь) для экосистем пакетов с открытым исходным кодом. Во второй волне в ноябре 2025 года затронул в том числе Maven Central: компрометировал опубликованные пакеты отдельных мейнтейнеров, похищал секреты (токены, ключи доступа) и использовал их для дальнейшего распространения. Важно, что компрометировались сами пакеты, а не инфраструктура реестра.&#34; data-title=&#34;&amp;lt;p&amp;gt;Самораспространяющийся вредонос (червь) для экосистем пакетов с открытым исходным кодом. Во второй волне в ноябре 2025 года затронул в том числе Maven Central: компрометировал опубликованные пакеты отдельных мейнтейнеров, похищал секреты (токены, ключи доступа) и использовал их для дальнейшего распространения. Важно, что компрометировались сами пакеты, а не инфраструктура реестра.&amp;lt;/p&amp;gt;&#34; data-abbr=Shai-Hulud&gt;Shai‑Hulud&lt;/abbr&gt; во второй итерации доехал и до Maven Central — компрометировал опубликованные пакеты отдельных разработчиков, тащил секреты, расползался дальше. Важная оговорка: компрометация шла через заражённые пакеты, а не через взлом самой инфраструктуры Maven Central. По следам той кампании счёт утёкших уникальных секретов шёл на десятки тысяч. Так что «у нас закрытый периметр, нам это не грозит» — позиция, которую я больше не принимаю всерьёз.&lt;h3&gt;Как всё это связано в единый поток&lt;/h3&gt;&lt;p&gt;Ниже &lt;em&gt;на рис. 2&lt;/em&gt; — как изменение проходит путь от коммита до решения «пускать или нет» и где включается сканирование.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/28c/e36/007/28ce36007ae1bf5ca3a6479c88d9aa26.png alt=&#34;Рис. 2. Путь изменения через пайплайн: сканирование зависимостей встроено в проверку merge request, а гейт реагирует на новую уязвимость, а не на общее состояние проекта&#34; title=&#34;Рис. 2. Путь изменения через пайплайн: сканирование зависимостей встроено в проверку merge request, а гейт реагирует на новую уязвимость, а не на общее состояние проекта&#34; width=635 height=668 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/28c/e36/007/28ce36007ae1bf5ca3a6479c88d9aa26.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/28c/e36/007/28ce36007ae1bf5ca3a6479c88d9aa26.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Рис. 2. Путь изменения через пайплайн: сканирование зависимостей встроено в проверку merge request, а гейт реагирует на новую уязвимость, а не на общее состояние проекта&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Главная мысль из схемы:&lt;/strong&gt; проверка стоит не в конце, перед деплоем, а на входе — в merge request. Чем левее в пайплайне вы ловите проблему, тем дешевле она обходится. Поймать уязвимую зависимость на ревью — это правка одной строки версии. На проде после инцидента — ночной созвон, хотфикс и объяснительная.&lt;/blockquote&gt;&lt;h3&gt;Где это решение не сработает (и что делать)&lt;/h3&gt;&lt;p&gt;Я не люблю гайды, которые заканчиваются на «теперь всё работает». Так не бывает. Честно про ограничения.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Если у вас не Ultimate.&lt;/strong&gt; SBOM‑based dependency scanning и гейт в merge request — это Ultimate. На младших тарифах вы соберёте SBOM и список зависимостей, но полноценного сравнения находок в MR и Security Dashboard не получите. Тогда смотрите в сторону внешних SCA (OWASP Dependency‑Check, Trivy) — их можно прикрутить отдельной джобой, но петлю «дельта в MR» придётся собирать вручную.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reachability и Spring — отдельная осторожность.&lt;/strong&gt; Важный нюанс, прямо прописанный в документации GitLab. Анализ достижимости поддерживает Java, JavaScript/TypeScript и Python — но для Java ловит явное использование (прямые импорты, рефлексию, строки подключения &lt;abbr class=habraabbr title=&#34;Стандартный API в Java для подключения к реляционным базам данных и выполнения SQL-запросов. Когда в тексте речь о том, что анализ достижимости «видит строки подключения JDBC» — имеются в виду те места в коде, где приложение настраивает соединение с БД; по ним статический анализатор может судить, какие драйверы и библиотеки реально задействованы.&#34; data-title=&#34;&amp;lt;p&amp;gt;Стандартный API в Java для подключения к реляционным базам данных и выполнения SQL-запросов. Когда в тексте речь о том, что анализ достижимости «видит строки подключения JDBC» — имеются в виду те места в коде, где приложение настраивает соединение с БД; по ним статический анализатор может судить, какие драйверы и библиотеки реально задействованы.&amp;lt;/p&amp;gt;&#34; data-abbr=JDBC&gt;JDBC&lt;/abbr&gt;) и не видит зависимости, подгружаемые динамически в рантайме. А это ровно то, что делают &lt;abbr class=habraabbr title=&#34;Паттерн, при котором объект не создаёт свои зависимости сам, а получает их извне — их «внедряет» фреймворк. В Spring Boot это базовый механизм: контейнер сам находит нужные компоненты и подставляет их в код во время выполнения. Для статического анализа это создаёт сложность: связь между классами устанавливается в рантайме, а не видна напрямую в исходниках, поэтому анализатор может не заметить, что зависимость реально используется.&#34; data-title=&#34;&amp;lt;p&amp;gt;Паттерн, при котором объект не создаёт свои зависимости сам, а получает их извне — их «внедряет» фреймворк. В Spring Boot это базовый механизм: контейнер сам находит нужные компоненты и подставляет их в код во время выполнения. Для статического анализа это создаёт сложность: связь между классами устанавливается в рантайме, а не видна напрямую в исходниках, поэтому анализатор может не заметить, что зависимость реально используется.&amp;lt;/p&amp;gt;&#34; data-abbr=DI-фреймворки&gt;DI‑фреймворки&lt;/abbr&gt; вроде Spring Boot. На практике — повышенный риск ложноотрицательных результатов: пакет может быть помечен как Not Found, хотя Spring поднимает его через инъекцию. Поэтому на Spring‑проекте я не отношусь к Not Found как к индульгенции и критичные находки перепроверяю руками. Для Go или Rust reachability не работает вовсе.&lt;li&gt;&lt;p&gt;&lt;strong&gt;И общая оговорка.&lt;/strong&gt; Как и любой SCA‑инструмент, GitLab dependency scanning не гарантирует стопроцентную полноту покрытия — особенно в проектах с динамической загрузкой зависимостей. Это не «включил настройки и система видит всё», а смещение вероятностей в вашу пользу: ловите кратно больше, чем без него, но абсолютной гарантии не даёт ни один сканер.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Не путайте с container scanning.&lt;/strong&gt; Dependency scanning смотрит на зависимости приложения по манифестам и графу. Уязвимости в базовом Docker‑образе и системных пакетах ОС — зона container scanning, отдельного сканера. Два разных среза риска, закрывать надо оба.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reachability — помощник, а не индульгенция.&lt;/strong&gt; То, что код сегодня не дотягивается до уязвимого пакета, не значит, что не дотянется завтра после рефакторинга. Я использую Reachable для приоритизации, но не как разрешение навсегда забить на остальное. Мёртвая сегодня зависимость завтра может ожить.&lt;/ul&gt;&lt;h3&gt;Что в итоге&lt;/h3&gt;&lt;p&gt;Если убрать всё лишнее, рабочая связка такая. Подключаем V2-шаблон dependency scanning, а не легаси. Скармливаем анализатору полный граф зависимостей (maven.graph.json), чтобы он видел транзитивные, а не только прямые из pom.xml. Включаем static reachability, чтобы отделить опасное от фонового шума и не убить доверие команды к гейту. И ставим гейт в merge request на дельту — на новые Critical, — задавая его политикой на уровне группы, чтобы его нельзя было тихо обойти.&lt;p&gt;Самый частый провал тут не технический. Команда включает сканер «чтобы был», тонет в шуме и через неделю учится не замечать красный крестик. Поэтому я настаиваю: узкий честный гейт, который ловит реальную дыру на входе, работает кратно лучше тотального гейта, который все игнорируют!&lt;hr&gt;&lt;p&gt;Продолжить знакомство с этими практиками можно уже &lt;strong&gt;30 июня в 20:00&lt;/strong&gt; на бесплатном открытом &lt;a href=https://otus.pw/fVhm/&gt;уроке «GitLab CI как конструктор workflow»&lt;/a&gt;. На нём покажем, как собирать в GitLab CI надёжные пайплайны, которые не просто запускают сборку, а помогают выстроить предсказуемый процесс доставки.&lt;p&gt;&lt;em&gt;Больше полезных материалов по инфраструктуре &lt;/em&gt;&lt;a href=https://otus.pw/IQ67/&gt;&lt;em&gt;смотрите в дайджесте.&lt;/em&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/otus/articles/1047050/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1047050</guid>
      <pubDate>Wed, 24 Jun 2026 19:12:13 +0000</pubDate>
    </item>
    <item>
      <title>Трансформация интерфейса приложений: сначала консоль, потом GUI, потом скажи, что нужно, и ИИ сделает?</title>
      <link>https://habr.com/ru/articles/1051544/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051544</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Всем привет.&lt;p&gt;Программировать я очень давно начал. Помню, как мне папа, прочитав журнал, вытравил плату и купил микросхемы, и, используя два больших калькулятора для бухгалтеров, разрезав их и склеив, собрал мне ZX Spectrum. У меня отец работал в Толмачёво инженером, который обслуживал большие ЭВМ и тренажёры для лётчиков &amp;#34;Аэрофлота&amp;#34;.&lt;p&gt;В общем, я был, наверное, первый счастливчик в Новосибирске, у кого был персональный компьютер дома. Тогда ещё бизнесмены не успели продавать ZX Spectrum и кассеты к нему с играми, а у меня уже всё было. Я помню, как первые программы я не на кассетный магнитофон записывал, а на большой катушечный, сорри, не помню, как называется, но явно не магнитола и явно не магнитофон.&lt;p&gt;Я помню, первую программу продал кабельному телевидению. Она была написана на Бейсике, и там был простой интерфейс: вводишь номер объявления и текст, и так можно 10 объявлений задать. Потом запускаешь, мол, делай бегущую строку, и на кабельном телевидении моя программа внизу под фильмами бегущей строкой показывала рекламные сообщения.&lt;p&gt;Когда моего отца спросили, мол, как отблагодарить ребёнка, или можно бесплатно, отец сказал: «Ни в коем случае. Его спросите, что он хочет за проделанную работу». И я тогда, помню, запросил 10 рублей! И мне их оплатили! Вот было счастье при зарплате обычного работяги 100- 200 или инженера 200-300 рублей в месяц.&lt;p&gt;В общем, технологии шли вперёд, и у меня появился дисковод. Это было бомба! Не надо ждать 5 минут, когда с кассеты или с катушек загрузится программа. Программа грузилась за секунды!&lt;p&gt;Потом у меня появился IBM PC 286. В общем, как вышло: в России была приватизация, и всем раздали ваучеры. У меня была возможность его продать за 10 рублей. И, кстати, отец сказал, что не будет меня лишать будущего и выбора и даст мне самому распорядиться ваучером. И помню, как я, придя в место, где можно было обменять ваучер на акцию, меня, как 18-летнего пацана, спросили, куда я вложил ваучер. Потом меня показали по местному ТВ, и все девчонки во дворе кричали мне в форточку: «И как ты вложил ваучер?»&lt;p&gt;Ну, в общем, я, когда отца спрашивал, куда его вложить, он мне сказал такую вещь: &amp;#34;Вот смотри, ты ваучер вкладываешь, и предприятие, в которое ты вложил, равномерно по вложенным ваучерам раздаёт свои акции&amp;#34;. В итоге я понял: если я вложу в предприятие, которое никому не нужно, то получу на свой ваучер максимум акций. И я выбрал &amp;#34;Трансметалл&amp;#34;. Спросил у девушки в окошке, мол, в какое предприятие ещё не вкладывали ваучер. Она сказала, что все вкладывают в &amp;#34;Газпром&amp;#34; и так далее, а вот в &amp;#34;Трансметалл&amp;#34; никто. Ну вот я туда ваучер и вложил.&lt;p&gt;По итогу через год мне приходит письмо, мол, мы компания такая-то, скупаем акции для контрольного пакета, и вам такие деньги обещаем. Спрашиваю отца, что делать. Он говорит: &amp;#34;Сынок, если они контрольный пакет купят, то потом, имея акции, ты даже дивидендов не увидишь. Они всё через подставные фирмы выведут&amp;#34;. Ну, в общем, я сходил на предприятие, и они сказали: &amp;#34;Вот ты офигеть, у тебя столько акций, что даже те, кто у нас всю жизнь работали, им и такого даже близко не дали&amp;#34;.&lt;p&gt;По итогу я продал все акции и спросил отца, что делать. Он сказал: &amp;#34;Купи вот рядом с домом 3 овощехранилища на этапе стройки&amp;#34;. Но я выбрал другое: купил IBM PC 286 и был счастлив. Это мега-мощный компьютер со своим монитором и с жёстким диском на несколько мегабайт! А батя потом через 4 года меня спросил: &amp;#34;Вот помнишь, ты мог 3 ячейки овощехранилища купить?&amp;#34; Я говорю: &amp;#34;Помню&amp;#34;. &amp;#34;Скажи, сколько сейчас они стоят?&amp;#34; Я ответил, что в 10 раз больше. И он сказал: &amp;#34;И сколько бы сейчас компов мог бы купить?&amp;#34; Я говорю: &amp;#34;10 штук&amp;#34;. Но я сделал свой выбор, не жалею. Это задало мою профессию и трек в жизни.&lt;p&gt;В итоге я на этом новом компе освоил Си и ассемблер. Помню, как я первый вирус создал, и в теле вируса написал тем, кто антивирусы пишет, мол, а может ли быть компьютерный вирус полиморфным, и будет ли он сам эволюционировать и развиваться. Помню, было приятно получить ответ в отчётах версии антивируса, мол, отвечаем на вопрос от создателя вируса такого-то: не может быть, чтобы компьютерный вирус смог, как живой, эволюционировать.&lt;p&gt;Дальше был университет. Первый взрыв мозга, это SQL! Я сидел и читал книгу в университетской библиотеке, как делать SQL-запросы, и как это просто, понятно и круто. Потом у меня были семестры по Си и C++, где Романов Евгений объяснял, что такое алгоритмы и сортировки разными способами. Потом была преподавательница Лилия Макаревич, которая меня погрузила в мир Java. Как это круто, быстро писать и не париться со срывом стека и так далее.&lt;p&gt;Потом был профессор в магистратуре, который мне объяснял, что такое нейронная сеть, что такое перцептрон и как строят компьютерное зрение. Мол, ИИ-модели жрут много CPU, и когда на вход подаётся большая картинка, то ИИ едет по картинке небольшим окошком по 40 на 40 пикселей, и если она увидела всплеск, что тут вертолёт, то в логе пишет: вот в таких координатах на фото был вертолёт!&lt;p&gt;Далее я, учась в магистратуре, познакомился с Сергеем Резинкиным. Он занимался тем, что в его фирме использовали Rational Rose, где они накидывали UML-диаграммы, а потом генерировали CRUD-код! Понятно, что он был не оптимальным и так далее, но 90% кода они генерировали, а потом тупо правили, дописывали и допиливали. Ничего вам не напоминает про кодогенерацию в наше время с ИИ-агентами? :)&lt;p&gt;Потом я попал в геодезическую компанию и на Java освоил технологию EJB и JBoss-фреймворк. Вот был взрыв мозга. Всё для тебя придумали: просто пиши минимальный код, а всё вокруг за тебя сразу решает многие проблемы.&lt;p&gt;Потом я ушёл в свой первый стартап: MyLivePage. Тут я не стал использовать корпоративные технологии типа Java, а сразу всё кодил на PHP, MySQL, Lighttpd, и вместо Docker и Kubernetes у меня был rsync/ssh, через которые я управлял файловыми хранилищами и вообще всей инфраструктурой деплоймента (если че тогда докера и кубера еще не существовало). Отдельное спасибо Виктору Коцубинскому, который имел высокие компетенции по DevOps, ранее работая в IP-телефонии. Кстати, в итоге у MyLivePage через несколько раундов инвестиций был свой дата-центр стоимостью под 1 млн долларов. Обслуживала система десятки миллионов пользователей и сотни миллионов просмотров страниц в сутки как живыми пользователями, так и поисковыми краулерами, которые 30% трафика составляли.&lt;p&gt;Далее я устроился в компанию Jetico как Java-разработчик, который писал сервер и фронтенд консоли управления, позволяющей шифровать и удалять данные на компьютерах клиентов. Я в этой компании уже работаю 11 лет. Я помню, как начинал писать всё руками. И как радовался, что есть автокомплит в JetBrains-продуктах, и как был доволен хорошей интеграцией в дебаг-режиме, где можно расставлять брейкпоинты и пошагово отлаживать код и понимать, что не работает.&lt;p&gt;Потом ситуация изменилась, появился GitHub Copilot. Ну, это реально бомба была. Ты пишешь название функции или строчку кода, и система сама понимает, что у тебя вокруг, и предлагает готовый код как автокомплит! Это была бомба! Притом я Copilot не первым заюзал. Сначала я офигел, что можно чат-боту сказать: мол, вот смотри, есть такие структуры данных, напиши для них код на таком-то языке, чтобы они в БД сохранялись. И он выдавал рабочий код. Его копипастишь и он работает!&lt;p&gt;Потом началось другое. Стали появляться задачи, которые нужно как рядовому программисту внедрять в продукты: не только ИИ пользоваться, а встраивать его в продукты. Первым продуктом был Jetico Search. Сначала это был рядовой поисковик, который ищет по ключевым словам и регуляркам. Потом появилась идея использовать ИИ для поиска.&lt;p&gt;Первая реализация была простая: просто с каждого документа или с его чанков насчитать векторы через эмбеддинг и потом по ним искать. Потом пошло дальше: я стал не просто искать близкие по смыслу векторы по поисковому запросу, я стал тренировать ИИ-модель, которая имеет тренировочный датасет векторов и проходит эпохи и валидацию, чтобы выдать максимальный матч при классификации документов. Но это была только первая ласточка и узкая задача.&lt;p&gt;Дальше - больше. Пришло осознание, что сейчас все крупные компании не просто так прикручивают ИИ к продуктам. Смысл какой: вот ты стоишь в интерфейсе пользователя, у тебя есть выбор, почитать документацию продукта, скучно и долго, покликать интерфейс, чтобы разобраться, скорее всего, покликаешь, что-то не получится, и закроешь продукт и забудешь.&lt;p&gt;А тут новая реальность: ты стоишь в интерфейсе, и у тебя снизу или сбоку есть чат-окно, где ты можешь сказать: &amp;#34;Слушай, я вот хочу примерно сделать такое. Ты можешь это сделать?&amp;#34; И AI-агент отвечает: &amp;#34;Да, у меня есть такие вот API и тулзы, я могу этот ваш запрос исполнить, вызывая их. Только уточните, и я сделаю&amp;#34;. Ты уточняешь, он делает вызовы API программы, и ты получаете то же самое, не читая документацию и не кликая в интерфейсе, чтобы понять, как это сделать.&lt;p&gt;У меня простой вопрос: а как у вас в компаниях? Эта трансформация от GUI, клик-клик, форму заполнил, переходит к добавлению ИИ-агента, который может по простому запросу от юзера сделать то же самое, вызывая за него API программы?&lt;p&gt;Просто сейчас я как раз делаю свой новый стартап, и там хочу применить эту новую парадигму. Есть GUI, но тут же снизу или сбоку, если юзер в напряге изучать и кликать, он тупо просит текстовым сообщением или голосом надиктовывает, что ему надо сделать, и программа делает!&lt;p&gt;У меня вообще вопрос: а если так дальше пойдёт, то что будут делать UX/UI-эксперты? Ведь их работа не станет такой ценной, чтобы GUI упростить, если программу можно просто попросить человеческим языком, и она всё сделает!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>igumnov</author>
      <guid>https://habr.com/ru/articles/1051544/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051544</guid>
      <pubDate>Wed, 24 Jun 2026 18:21:36 +0000</pubDate>
    </item>
    <item>
      <title>Ваши постмортемы — это поминки. И добрая половина процессов в компании тоже</title>
      <link>https://habr.com/ru/articles/1051542/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051542</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Однажды я зашёл в компанию через неделю после крупного падения и попросил показать постмортем. Мне показали — с гордостью. Таймлайн поминутно, five whys, аккуратный список action items, owner напротив каждого, разослано по всем спискам. Красиво. «Видите, мы серьёзно подошли».&lt;p&gt;Я задал один вопрос: а постмортем по прошлому такому же падению — где? Нашли. Открыли. Те же action items. Слово в слово. С прошлого раза не закрыт ни один.&lt;p&gt;То есть полгода назад уже собирались, уже всё проанализировали, уже назначили ответственных — и ничего не сделали. А потом упало снова, по той же причине, и они снова собрались, снова проанализировали, снова назначили. С тем же результатом, который будет и в следующий раз.&lt;p&gt;И вот тут важно не поспешить с выводом «разгильдяи, не довели». Потому что если присмотреться, этот постмортем не провалился. Он отлично сработал. Просто работа у него была не та, что написана на упаковке.&lt;p&gt;Я вхожу в чужие инженерные команды со стороны — посмотреть, что там происходит на самом деле, и навести порядок. И почти в каждой натыкаюсь на одно и то же: изрядная часть процессов в компании существует не чтобы что-то делать, а чтобы что-то изображать. Это не патология конкретной конторы. Это закономерность, у неё есть механика, и её полезно научиться видеть — особенно если ты за эти процессы отвечаешь.&lt;h3&gt;Зачем нужен разбор, после которого ничего не чинят&lt;/h3&gt;&lt;p&gt;Затем же, зачем нужны поминки.&lt;p&gt;Случилось плохое. Людям больно, тревожно и немного стыдно. Нужен ритуал, который эту тревогу обработает: собраться, проговорить вслух, что произошло, обозначить, что «меры приняты», и разойтись с ощущением, что теперь всё под контролем. На поминках не лечат — лечить уже некого. На поминках прощаются и идут жить дальше.&lt;p&gt;Постмортем, после которого не меняется ни один дефолт, делает ровно это. Он не инструмент починки — он инструмент закрытия гештальта. Снимает тревогу, восстанавливает ощущение контроля и даёт начальству строчку «провели разбор, выработали меры» для следующего созвона с бизнесом. Все эти функции настоящие и по-своему нужные. Просто ни одна из них не про то, чтобы падение не повторилось.&lt;p&gt;И вот вокруг этого крутится всё. Есть процессы-инструменты: они меняют реальность. И есть процессы-символы: они меняют ощущение от реальности. Снаружи похожи как близнецы — те же встречи, те же документы, те же owner&amp;#39;ы в табличке. Отличаются только одним: остаётся ли после них след в реальности. И заметить это можно, только если специально проследить.&lt;h3&gt;Почему символов в компании всегда больше, чем кажется&lt;/h3&gt;&lt;p&gt;Процессы-символы никто не заводит нарочно. Никто не приходит на стендап со словами «давайте сделаем ретро, которое ни на что не повлияет». Они вырастают сами, и вот из чего.&lt;p&gt;&lt;strong&gt;Символ дешевле инструмента.&lt;/strong&gt; Чтобы постмортем реально что-то изменил, кто-то должен взять его action items, выбить под них время в спринте, продавить приоритет против фич, довести до конца и проверить. Это дорого и конфликтно — надо с кем-то воевать за ресурс. А провести красивый разбор и разослать — дёшево и приятно. Система при прочих равных всегда сползает в сторону дешёвого.&lt;p&gt;&lt;strong&gt;Символ безопаснее.&lt;/strong&gt; Пока ты соблюдаешь ритуал — у тебя есть алиби. «Мы же провели разбор». «У нас есть дашборд». «Мы следуем процессу». Рванёт снова — ты не виноват, ты всё сделал по регламенту. Символ перекладывает ответственность с человека на процесс, и это очень удобно. Инструмент так не умеет: он либо сработал, либо нет, и спрос персональный.&lt;p&gt;&lt;strong&gt;Символ невозможно „не пройти“.&lt;/strong&gt; Инструмент даёт обратную связь: тест красный или зелёный, мониторинг поймал или проспал. Символ обратной связи не даёт — ретро состоялось, значит «прошло успешно». А процессы без обратной связи не эволюционируют, они просто накапливаются. Завели — и оно живёт вечно, потому что отменить его значит признать, что оно было лишним, а это неловко.&lt;p&gt;Сложите три силы — и получите естественный градиент: в любой достаточно взрослой компании символов со временем становится всё больше, а инструментов всё меньше, если кто-то сознательно не чистит. Дашборд, на который никто не смотрит, но всем спокойнее, что он есть. Ретро, где третий спринт подряд проговаривают одно и то же. Чек-лист перед релизом, который заполняют не глядя. Согласование, которое всегда «согласовано». Всё это когда-то, может, и работало. Теперь — изображает.&lt;h3&gt;Это не глупость. Это availability bias на уровне организации&lt;/h3&gt;&lt;p&gt;Легко свалиться в «менеджеры идиоты, развели бюрократию». Не идиоты, и дело не в бюрократии.&lt;p&gt;Организация, как и человек, реагирует на то, что видно. Громкое падение видят все: оно болит, за него ругают, его обсуждают на всех этажах. Ресурсы на него бросают мгновенно. А тихий риск — недоделанный action item, единственный человек, который знает, как разворачивается прод, отсутствие реального теста под сценарий — невидим ровно до того момента, пока не рванёт. И поэтому всегда проигрывает борьбу за приоритет видимому.&lt;p&gt;Это availability bias, только масштабом в компанию: что доступно вниманию, то и кажется важным. Символ идеально ложится в эту ловушку, потому что символ — это и есть «видно». Красивый постмортем видно. Дашборд на стене видно. А сделанный action item, который тихо предотвратил падение, которого поэтому не случилось, — не видно вообще. Предотвращённого пожара нет в ленте инцидентов, награждать и замечать нечего.&lt;p&gt;Так организация и обучается: вкладываться в то, что заметно, а не в то, что работает. Не потому что глупая — потому что у неё, как у всех, кривые стимулы.&lt;h3&gt;Один вопрос, который вскрывает любой процесс&lt;/h3&gt;&lt;p&gt;Хорошая новость: чтобы отличить инструмент от символа, аудит не нужен. Нужен один вопрос, который ты задаёшь про любой регулярный процесс:&lt;p&gt;&lt;strong&gt;«Что изменилось после прошлого раза?»&lt;/strong&gt;&lt;p&gt;Постмортем: предыдущие action items — закрыты? Открываешь архив, видишь те же незакрытые пункты — перед тобой ритуал. Можно приходить в чёрном.&lt;p&gt;Ретро: проблема, которую обсуждали в прошлый раз, ушла или всплыла снова? Всплывает третий спринт подряд и каждый раз её «берут на заметку» — это не ретро, это групповая терапия. Тоже полезно, но называется иначе.&lt;p&gt;Дашборд: когда по нему последний раз приняли решение? Не «посмотрели», а изменили поведение. Если никогда — это обои.&lt;p&gt;Согласование: хоть раз заворачивали? За год ни одного «нет» — это не контроль, это турникет, который всегда открыт. Снять — ничего не изменится, кроме скорости.&lt;p&gt;Везде один тест: процесс обязан оставлять след в реальности. Нет следа — символ.&lt;h3&gt;Что делать (и чего не делать ни в коем случае)&lt;/h3&gt;&lt;p&gt;Самая дорогая ошибка человека, который всё это разглядел, — прийти и с энтузиазмом всё поотменять. Особенно если ты новый и хочешь показать, что навёл порядок. Не делай так. Вот почему.&lt;p&gt;Символ почти всегда выполняет какую-то настоящую функцию — просто не ту, что заявлена. Постмортем-поминки реально снимает тревогу команды. Снеси его молча — и вместо спокойствия получишь людей, которые после каждого инцидента не понимают, «а мы вообще с этим что-то делаем». Дашборд, на который никто не смотрит, иногда оказывается тем, на который смотрит ровно один человек ровно в одной критической ситуации. Прежде чем резать, разберись, какую тревогу или какую подстраховку процесс на самом деле держит.&lt;p&gt;Поэтому порядок такой.&lt;p&gt;Сначала — инвентаризация тем самым вопросом. Пройдись по регулярным процессам и честно отметь, где есть след в реальности, а где нет. Список символов обычно выходит длиннее, чем ждёшь.&lt;p&gt;Потом — не «отменить», а «вернуть обратную связь». Чаще символ можно превратить обратно в инструмент, не убивая. Постмортем, у которого action items никто не доводит, чинится не отменой, а одним правилом: новый разбор начинается с проверки статуса старых пунктов, и пока они не закрыты, новые не заводятся. У ритуала внезапно появляются зубы. Ретро по кругу чинится тем, что одна проблема за раз доводится до конца до следующего ретро. Дашборд — тем, что у каждого графика есть владелец и ответ на вопрос «какое решение ты по нему принимаешь».&lt;p&gt;И только то, что не удаётся вернуть в работу и что не держит никакой реальной тревоги, — убираешь. Тихо, по одному, наблюдая, не сломалось ли что-то незаметное. Через месяц никто не вспомнил — значит правда был лишним.&lt;h3&gt;Зачем вообще это видеть&lt;/h3&gt;&lt;p&gt;Театр надёжности безобиден ровно до того дня, когда ты начинаешь принимать его за надёжность. Пока ты понимаешь, что постмортем — это поминки, а дашборд — обои, ты держишь в голове, что настоящая надёжность лежит где-то ещё, и продолжаешь её искать. Беда приходит, когда символы начинают всех убаюкивать: разборы проводятся, дашборды висят, чек-листы заполняются — и все искренне считают, что система под контролем. А она под контролем ровно настолько, насколько процессы оставляют след в реальности. То есть в зрелой компании без регулярной чистки — примерно наполовину.&lt;p&gt;Так что в следующий раз, когда вокруг какого-то процесса будет особенно много торжественности — красивые слайды, обязательность, ритуальность, — задайте тот вопрос. Что изменилось после прошлого раза? И если ответа нет, вы хотя бы будете знать, на каких похоронах присутствуете.&lt;hr&gt;&lt;p&gt;&lt;em&gt;Пишу под псевдонимом: вхожу в чужие инженерки под NDA, оттого без лица и без названий компаний. Остальные разборы и книга — по ссылке в профиле.&lt;/em&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>theshadowcto</author>
      <guid>https://habr.com/ru/articles/1051542/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051542</guid>
      <pubDate>Wed, 24 Jun 2026 18:00:39 +0000</pubDate>
    </item>
    <item>
      <title>Как пользоваться Gemini AI в России в 2026 году: подписки, версии нейросети и доступ без VPN</title>
      <link>https://habr.com/ru/companies/studyai/articles/1051526/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051526</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Gemini давно перестал быть просто текстовым чат-ботом. К середине 2026 года это многоуровневая мультимодальная экосистема от Google: она ведёт диалоги, пишет тексты и код, управляет автономными агентами, генерирует изображения и эмоциональную речь, а с недавних пор — и видео. Под названием «Gemini» теперь скрывается не одна модель, а целый набор инструментов под разные задачи и бюджеты.&lt;p&gt;Для российского пользователя картина двойственная. С одной стороны — мощная и быстро развивающаяся линейка. С другой — Google заблокировал прямой доступ для российских IP сразу на нескольких уровнях. Разберём по порядку: что такое Gemini AI в 2026 году, многие называют нейросеть «Гемини», «Джеминай», «Джемини» или «Джимини», какие версии актуальны, в чём модель сильна, а где уступает, и какими способами получить к ней доступ из России.&lt;h2&gt;Gemini AI и доступность в России без VPN&lt;/h2&gt;&lt;p&gt;Нейросеть &lt;a href=&#34;https://eduforms.org/?rid=21276b8f51416ec3&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgemini3_pro&#34;&gt;Gemini&lt;/a&gt; от Google доступна в России без VPN на платформе &lt;a href=&#34;https://eduforms.org/?rid=21276b8f51416ec3&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgemini3_pro&#34;&gt;&lt;strong&gt;Study AI&lt;/strong&gt;&lt;/a&gt;. Это самый простой способ попробовать возможности модели прямо сейчас — без необходимости использовать зарубежные сервисы или обходить блокировки. Там много и абсолютно &lt;strong&gt;бесплатных версий нейросетей&lt;/strong&gt; на русском языке &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgpt5_mini&#34;&gt;ChatGPT&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgrok41_fast&#34;&gt;Grok&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fdeepseek_v3&#34;&gt;DeepSeek&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fqwen&#34;&gt;Qwen 3&lt;/a&gt; — они бесплатны и доступны без VPN.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/61a/dec/da6/61adecda6168131f081aa857376be2ad.png alt=&#34;Линейка моделей Gemini&#34; title=&#34;Gemini AI в России&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/61a/dec/da6/61adecda6168131f081aa857376be2ad.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/61a/dec/da6/61adecda6168131f081aa857376be2ad.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Gemini AI в России&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Что такое Gemini AI в 2026 году&lt;/h3&gt;&lt;p&gt;&lt;a href=&#34;https://eduforms.org/?rid=21276b8f51416ec3&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgemini3_pro&#34;&gt;Gemini&lt;/a&gt; — семейство мультимодальных моделей от Google DeepMind, преемник PaLM 2 и LaMDA. Ключевая особенность — модель изначально обучалась на смешанных данных (текст, изображения, аудио, видео), а не получила мультимодальность как надстройку. На практике это даёт более точное понимание документов со сложной вёрсткой, таблиц с картинками и скриншотов интерфейсов.&lt;p&gt;Сегодня Gemini AI — это не отдельный сайт, а сквозной «умный слой» в экосистеме Google: глубокая интеграция в Google Workspace (Docs, Sheets, Gmail, Drive), платформа для создания автономных корпоративных агентов, специализированные модели для генерации картинок и озвучки. Для рядового пользователя интерфейс выглядит как отзывчивый собеседник, но под капотом — система, способная перерабатывать гигантские объёмы данных, писать многостраничные программы и распределять задачи между ИИ-субагентами.&lt;h3&gt;Актуальная линейка Gemini AI на июнь 2026 года&lt;/h3&gt;&lt;p&gt;Поколение 3.x — это текущая база, поверх которой Google быстро выкатывает новые варианты. К июню 2026 года это уже не «одна самая новая модель», а движущаяся продуктовая лестница. Вот как она выглядит.&lt;p&gt;&lt;strong&gt;Gemini 3 Pro и 3.1 Pro AI — флагманские рабочие модели.&lt;/strong&gt; Версия 3.1 Pro вышла в феврале 2026 года и получила продвинутую систему рассуждений (Thinking model). Это выбор для сложного программирования (agentic capabilities, vibe coding), глубокой аналитики и многосоставных задач, где важна безупречная логика и выполнение длинных цепочек действий.&lt;p&gt;&lt;strong&gt;Gemini 3.5 Flash AI — свежий и самый заметный релиз.&lt;/strong&gt; Вышел в мае 2026 года и стал сильнейшей агентной и кодинговой моделью семейства Flash: по ряду бенчмарков обходит даже 3.1 Pro, при этом сохраняя скорость и низкую стоимость, характерные для линейки Flash. Хороший вариант для длинных агентных задач, кодинга и быстрой повседневной работы.&lt;p&gt;&lt;strong&gt;Gemini 3 Flash и 3.1 Flash-Lite AI — скорость и экономия.&lt;/strong&gt; Облегчённые версии для брейнштормов, переводов, быстрых правок текста и массовой обработки простых запросов. Flash-Lite — самая бюджетная модель экосистемы для высоконагруженных пайплайнов.&lt;p&gt;&lt;strong&gt;Gemini 3 Ultra с режимом Deep Think AI — «тяжёлая артиллерия».&lt;/strong&gt; Перед ответом модель берёт паузу: выстраивает внутренние логические цепочки, проверяет факты, отсеивает ложные гипотезы. Результат — минимум галлюцинаций и железная аргументация. Подходит для бизнес-стратегий, математики и научных задач без права на ошибку.&lt;p&gt;&lt;strong&gt;Мультимедийные модели.&lt;/strong&gt; Для графики — Nano Banana 2 (на платформе Gemini 3.1 Flash Image), который умеет правильно отрисовывать текст, вывески и графики прямо на сгенерированных картинках. Для аудио — Flash TTS, понимающий встроенные теги эмоций (&lt;code&gt;[cheerful]&lt;/code&gt;, &lt;code&gt;[whispers]&lt;/code&gt;, &lt;code&gt;[urgent]&lt;/code&gt;) и меняющий интонацию посреди фразы. А представленный на Google I/O Gemini Omni добавил генерацию и редактирование видео из текста, картинок и звука.&lt;p&gt;&lt;strong&gt;Короткое правило выбора.&lt;/strong&gt; Flash и Flash-Lite — для объёма и скорости. Pro (3.1 или 3.5 Flash) — для большинства рабочих задач и кода. Ultra с Deep Think — когда нужен максимум на сложных задачах или анализ огромного документа.&lt;h3&gt;Где нейросеть Gemini AI выигрывает у конкурентов&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Длинный контекст.&lt;/strong&gt; Контекстное окно до 1 млн токенов — это примерно 750 тысяч слов или несколько больших репозиториев в одном промпте. Если задача — анализ большого документа целиком, поиск по кодовой базе или работа с длинной историей переписки без разбивки на части, здесь Gemini практически безальтернативен.&lt;p&gt;&lt;strong&gt;Нативная мультимодальность.&lt;/strong&gt; Поскольку модель с самого начала обучалась на смешанных данных, она точнее понимает документы со сложной вёрсткой, таблицы с изображениями и интерфейсные скриншоты — не «дочитывает» картинку отдельным модулем, а воспринимает всё целостно.&lt;p&gt;&lt;strong&gt;Интеграция с экосистемой Google.&lt;/strong&gt; Если ваш рабочий процесс завязан на Google Workspace, Gemini через официальный интерфейс даёт нативную интеграцию, которой нет у конкурентов. В Google Docs появились функции Match writing style и Match doc format: загружаете старый документ — и модель создаёт новый, копируя не только стиль речи, но и шрифты, цвета, заголовки и структуру таблиц.&lt;p&gt;&lt;strong&gt;Агенты и Deep Research.&lt;/strong&gt; Режим Deep Research позволяет модели самостоятельно формулировать подзапросы, искать информацию в интернете и собирать итоговый отчёт без участия пользователя на промежуточных этапах. А на корпоративной агентной платформе можно собрать сеть из нескольких агентов: один пишет код, второй тестирует его в изолированной песочнице, третий формирует отчёт об уязвимостях.&lt;h3&gt;Где Gemini от Google уступает&lt;/h3&gt;&lt;p&gt;Честный разговор о слабых местах — независимо от того, как вы получаете доступ.&lt;p&gt;&lt;strong&gt;Русский язык.&lt;/strong&gt; Модели 3-й серии понимают русский, улавливают контекст и сленг, но на задачах, требующих тонкого чувства стиля, неологизмов или региональных реалий, отдельные конкуренты стабильно показывают результат лучше. На технических текстах разница менее выражена.&lt;p&gt;&lt;strong&gt;Фильтры контента.&lt;/strong&gt; Google применяет более консервативную модерацию на ряде тематик. Для большинства рабочих задач это некритично, но стоит учитывать при выборе модели под специфические сценарии.&lt;p&gt;&lt;strong&gt;Latency при доступе через прокси.&lt;/strong&gt; Если работать через агрегатор, добавляется слой проксирования — задержка выше, чем при прямом подключении. Для интерактивных приложений это бывает заметно, для пакетной обработки — несущественно.&lt;h3&gt;Что именно заблокировано в России и как это устроено&lt;/h3&gt;&lt;p&gt;Google применяет geo-blocking на нескольких уровнях, и понимать, где именно происходит проверка, важно — от этого зависит, какой способ обхода сработает.&lt;p&gt;Веб-интерфейс и мобильное приложение проверяют IP при каждом запросе: с российского адреса — редирект на страницу о недоступности сервиса. Это стандартный geo-block, который снимается VPN.&lt;p&gt;API устроен жёстче: проверка идёт и при регистрации ключа, и при каждом запросе. Ключ, созданный с российского IP, либо не создаётся, либо блокируется при первом использовании. Ключ, созданный через VPN, работает нестабильно — Google периодически пересматривает активные ключи и блокирует созданные с подозрительных адресов.&lt;p&gt;Оплата — отдельная проблема. Российские карты не принимаются, иностранные карты с российским биллинговым адресом — тоже. Нужна карта с зарубежным биллингом или виртуальная карта иностранного банка.&lt;p&gt;Важно понимать: Gemini в России — это не «полностью недоступно», а «требует нетривиального обхода сразу на нескольких уровнях». Ниже три рабочих подхода.&lt;h3&gt;Способ 1: VPN — быстро, но нестабильно&lt;/h3&gt;&lt;p&gt;Самый очевидный вариант. Работает для веб-интерфейса и приложения, но с оговорками. Наиболее стабильно на российской аудитории показывают себя VPN, чьи IP реже попадают в блок-листы Google; массовые провайдеры вроде популярных коммерческих сервисов работают хуже — их exit-ноды давно известны и периодически блокируются.&lt;p&gt;Главная проблема — сессии. Google привязывает аккаунт к географии входа. Зашли через VPN с зарубежным IP, затем открыли браузер без VPN — сессия может оборваться, а аккаунт получить флаг подозрительной активности. Для стабильной работы нужно либо всегда держать VPN включённым, либо использовать отдельный браузерный профиль под Gemini. Плюс интеграция с Google Workspace при несовпадении региона аккаунта и IP работает с перебоями.&lt;p&gt;Итог: VPN подходит для нерегулярного использования и тестов. Для ежедневной работы нестабильность сессий и риски для аккаунта делают его неудобным.&lt;h3&gt;Способ 2: API через агрегатор — для разработчиков и интеграций&lt;/h3&gt;&lt;p&gt;Если задача — подключить Gemini к собственному приложению или пайплайну, прямой доступ к Google API не нужен. Агрегаторы дают OpenAI-совместимый эндпоинт с Gemini под капотом: меняете base URL и ключ — остальное работает как прежде. Это снимает сразу несколько проблем: не нужен VPN, не нужна иностранная карта, не нужно следить за стабильностью ключей Google.&lt;p&gt;При выборе агрегатора стоит смотреть на документацию на русском, оплату в рублях, OpenAI-совместимый API, стабильность аптайма и доступность актуальных версий модели.&lt;h3&gt;Способ 3: агрегатор с веб-интерфейсом — для тех, кому не нужен API&lt;/h3&gt;&lt;p&gt;Не всем нужен API. Если задача — работать с текстом, кодом, анализом документов или мультимодальными запросами, достаточно веб-интерфейса агрегатора, где модель уже подключена. В сравнении с VPN это проще: не нужно следить за соединением, держать отдельный браузерный профиль или рисковать Google-аккаунтом.&lt;p&gt;Именно по этому пути идёт платформа &lt;a href=&#34;https://eduforms.org/?rid=21276b8f51416ec3&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgemini3_pro&#34;&gt;Study AI&lt;/a&gt;: доступ к Gemini через русскоязычный веб-интерфейс рядом с другими топовыми моделями — &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgpt5_mini&#34;&gt;ChatGPT&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgrok41_fast&#34;&gt;Grok&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fdeepseek_v3&#34;&gt;DeepSeek&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fqwen&#34;&gt;Qwen 3&lt;/a&gt; Переключение между ними в одном окне удобно, когда задача требует сравнения ответов, а из дополнительных возможностей — генерация изображений, удаление фона, апскейл, озвучка текстов и библиотека готовых промптов. Главный плюс такого подхода — использовать мощь нейросетей на русском языке без технических барьеров: без настройки VPN и поиска иностранных карт. Ограничение одно: прямой интеграции с Google Workspace здесь нет — если она критична, остаются только VPN или API.&lt;h3&gt;Как формулировать запросы для Gemini&lt;/h3&gt;&lt;p&gt;Несколько практических приёмов, которые заметно повышают качество результата.&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Забудьте про общие фразы.&lt;/strong&gt; Пишите детально: не «напиши про продвижение», а «действуй как senior SEO-специалист, напиши стратегию продвижения для сайта на базе алгоритмов Google 2026 года».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Используйте теги эмоций для аудио.&lt;/strong&gt; При генерации речи вставляйте маркеры: «Привет! &lt;code&gt;[excited]&lt;/code&gt; У нас отличные новости! &lt;code&gt;[calm]&lt;/code&gt; Но есть нюанс…».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Требуйте вариативность.&lt;/strong&gt; Просите сразу 10 разных вариантов решения — потом выберете лучший.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Давайте примеры (few-shot).&lt;/strong&gt; Загрузите абзац, который нравится по стилю, и попросите сделать «в точно такой же стилистике».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Опирайтесь на агентов.&lt;/strong&gt; Сложную задачу просите разбить на этапы для выполнения отдельными ассистентами.&lt;/ol&gt;&lt;p&gt;Типичные ошибки новичков: просить сложную логику в сверхбыстром режиме Flash (для аналитики используйте Pro или Ultra с Deep Think) и описывать данные словами вместо того, чтобы дать прямую ссылку или PDF.&lt;h3&gt;Частые вопросы&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Какая версия Gemini самая новая в 2026 году?&lt;/strong&gt; Актуальное поколение — серия 3.x. В неё входят флагманские 3 Pro и 3.1 Pro для сложных задач и кода, свежий 3.5 Flash, ультрабыстрые 3 Flash и 3.1 Flash-Lite, а также модели для генерации картинок (Nano Banana 2), звука (Flash TTS) и видео (Gemini Omni).&lt;p&gt;&lt;strong&gt;Что такое режим Deep Think / Thinking?&lt;/strong&gt; Способность моделей Pro и Ultra брать паузу на раздумья перед ответом: модель выстраивает цепочки рассуждений, что сводит к минимуму ошибки и неточности.&lt;p&gt;&lt;strong&gt;Можно ли рисовать картинки прямо в чате?&lt;/strong&gt; Да. Генератор на архитектуре Nano Banana 2 встроен прямо в диалог и умеет даже корректно писать текст на генерируемых объектах.&lt;p&gt;&lt;strong&gt;Работает ли Gemini в России без VPN?&lt;/strong&gt; Прямой официальный доступ — нет, Google блокирует российские IP на уровне веб-интерфейса, приложения и API. Без VPN проще всего работать через агрегатор вроде &lt;a href=&#34;https://eduforms.org/?rid=21276b8f51416ec3&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgemini3_pro&#34;&gt;&lt;strong&gt;Study AI&lt;/strong&gt;&lt;/a&gt; с оплатой в рублях.&lt;p&gt;&lt;strong&gt;Понимает ли Gemini русский язык?&lt;/strong&gt; Да, модели 3-й серии понимают русский, улавливая контекст, сарказм и профессиональный сленг, хотя на тонких стилистических задачах отдельные конкуренты бывают точнее.&lt;p&gt;Gemini в 2026 году — это не «ещё один чат-бот», а тиражируемая продуктовая лестница: Pro и Deep Think для сложного рассуждения, 3.5 Flash и Flash-Lite для скорости и объёма, Nano Banana 2, Flash TTS и Gemini Omni для визуала, звука и видео. Сильные стороны конкретны: длинный контекст до 1 млн токенов, нативная мультимодальность и глубокая интеграция с экосистемой Google.&lt;p&gt;Главная сложность для российского пользователя — доступ. Прямой путь заблокирован на нескольких уровнях, и выбор сводится к трём вариантам: VPN с отдельным профилем (если нужна интеграция с Workspace), API через агрегатор (для разработчиков) или агрегатор с веб-интерфейсом вроде Study AI (для повседневной работы без технических барьеров). Универсального ответа нет — выбирайте инструмент под конкретную задачу, бюджет и требования к стабильности.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/studyai/articles/1051526/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051526</guid>
      <pubDate>Wed, 24 Jun 2026 17:18:39 +0000</pubDate>
    </item>
    <item>
      <title>[Перевод] Пол Грэм: Как стать миллиардером</title>
      <link>https://habr.com/ru/articles/1049828/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1049828</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Пол Грэм - легендарный венчурный инвестор, программист и эссеист, наиболее известный как сооснователь культового стартап-акселератора Y Combinator.&lt;p&gt;Недавно он опубликовал пост &amp;#34;Как стать миллиардером&amp;#34;, перевод которого представлен ниже.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/134/407/e84/134407e84ac136b63ef200af879ad1e2.png width=331 height=300 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/134/407/e84/134407e84ac136b63ef200af879ad1e2.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/134/407/e84/134407e84ac136b63ef200af879ad1e2.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&amp;#34;Поскольку это, по-видимому, клуб будущих премьер-министров, я собираюсь рассказать вам о том, что было бы хорошо, если бы больше политиков понимали: я собираюсь рассказать вам, как люди становятся миллиардерами. Я надеюсь, это будет полезно вам, даже если вы не планируете заниматься политикой. Те из вас, кто не станет премьер-министром, могут стать миллиардерами.&lt;p&gt;Причина, по которой я знаю эту тему, заключается в том, что 21 год назад мы с Джессикой основали организацию под названием Y Combinator. Если вы не слышали о Y Combinator, это нечто среднее между инвестиционной фирмой и школой для основателей стартапов. С момента основания в 2005 году мы профинансировали около 6500 компаний.&lt;p&gt;Создание успешного стартапа — самый &lt;a href=https://paulgraham.com/richnow.html rel=&#34;noopener noreferrer nofollow&#34;&gt;распространенный&lt;/a&gt; способ стать миллиардером, поэтому, по сути, я последние 21 год посвятил обучению людей тому, как стать миллиардерами. На данный момент около 30 из них стали миллиардерами, но многие другие находятся в процессе подготовки.&lt;p&gt;Можете себе представить, как я был поражен в прошлом месяце, когда американский политик заявила, что заработать миллиард долларов &lt;a href=https://x.com/MarcoFoster_/status/2052427151371047016 rel=&#34;noopener noreferrer nofollow&#34;&gt;невозможно . Я чувствовал себя как тренер по фигурному катанию, услышавший, как кто-то говорит, что невозможно сделать тройной аксель. Конечно, это возможно. Это &lt;/a&gt;&lt;em&gt;сложно&lt;/em&gt; , но это возможно.&lt;p&gt;Она, конечно, не говорила, что невозможно стать миллиардером. Очевидно, это возможно. И она не говорила о различии между доходом и приростом капитала. Она не говорила о бухгалтерском учете. Она имела в виду, что невозможно так разбогатеть, не совершив ничего плохого — не обманув каким-либо образом.&lt;p&gt;Через пару дней я разговаривал с основательницей стартапа, который я финансировал. Я начал с вопроса, как обычно делаю при встрече с основателем, каков темп ее роста. 93% в прошлом месяце, ответила она. Я отметил, что это означает, что ее состояние также растет на 93% в месяц. Она становилась богаче с невероятно быстрой скоростью. И все же она не делала ничего плохого. Причина столь быстрого роста её стартапа заключалась просто в том, что пользователям нравилось то, что она создала. Поэтому она на собственном опыте убедилась, насколько неправ был тот политик. Она никого не эксплуатировала. Наоборот. Причина такого быстрого роста её стартапа заключалась в том, что она и её соучредитель изо всех сил старались сделать своих пользователей счастливыми, и в результате пользователи рассказывали о нём своим друзьям. А это приводит к экспоненциальному росту.&lt;p&gt;Позже в тот же день я обсуждал её случай в интернете, и кто-то ответил, что иметь несколько миллионов и расти на 93% в месяц — это кардинально отличается от того, чтобы быть миллиардером.&lt;p&gt;Подозреваю, многие согласятся с этим утверждением. Но оказывается, оно не просто ложно, а ложно в очень показательном смысле.&lt;p&gt;Итак, я хотел бы попросить вас об одолжении. Достаньте свои телефоны и произведите расчет. Я знаю, это может показаться надуманным, но я обещаю, что это будет вам полезно. Я попрошу вас выполнить самый распространенный расчет, который я делаю как инвестор, и этот опыт наглядно покажет вам, что такое стартапы.&lt;p&gt;Если мы интерпретируем его утверждение самым консервативным образом и предположим, что «несколько» означает 2, то ее компания должна вырасти в 500 раз, чтобы она стала миллиардершей. Поэтому мы собираемся рассчитать, сколько месяцев роста на 93% требуется, чтобы что-то выросло в 500 раз.&lt;p&gt;Для этого нам нужно вычислить логарифм по основанию 1,93 от 500. Самый простой способ сделать это — воспользоваться поиском Google, который позволяет выполнять вычисления прямо в строке поиска. Итак, зайдите в поиск Google и введите log(500, 1,93). Если вы ввели это правильно, вы получите ответ примерно 9,45.&lt;p&gt;Именно столько месяцев роста в 93% требуется, чтобы стать миллиардером, начав с 2 миллионов. Пара миллионов и 93% роста, по сути, не сильно отличаются от миллиарда. Разница составляет девять с половиной месяцев.&lt;p&gt;Теперь вы понимаете, почему, когда я встречаюсь с основателем, первое, о чем я спрашиваю, это темпы роста.&lt;p&gt;Но я не хочу, чтобы меня обвиняли в использовании нереалистичных цифр, поэтому давайте возьмем более консервативный темп роста. Посмотрим, что произойдет при 15% в месяц. Это совсем не редкость. Я постоянно сталкиваюсь со стартапами, растущими на 15% в месяц.&lt;p&gt;Если ваша выручка растет на 15% в месяц, насколько больше вы будете зарабатывать через 5 лет? Чтобы это рассчитать, нам нужно найти 1,15 в 60-й степени (поскольку 5 лет — это 60 месяцев). Поэтому снова зайдите в Google и на этот раз введите 1,15^60. Ответ должен быть примерно 4384. Это значит, что через 5 лет ваш стартап будет зарабатывать в 4384 раза больше. Если сейчас вы зарабатываете десять тысяч в месяц, то через пять лет будете зарабатывать около 44 миллионов в месяц, или 526 миллионов в год. И к тому моменту, если вы будете владеть такой же долей компании, как обычно владеют основатели, вы станете миллиардером.&lt;p&gt;В реальном мире темпы роста, как правило, немного замедляются. Очень успешный стартап, вероятно, будет расти быстрее 15% в месяц в первый год и медленнее 15% в месяц в пятый год. Но в итоге вы окажетесь примерно в том же положении. Если вы создадите стартап в начале двадцатых, то к тридцати годам определенно возможно стать миллиардером. Сложно, но возможно.&lt;p&gt;Я хотел, чтобы вы почувствовали это, произведя расчеты самостоятельно, потому что теперь вы понимаете одну из причин, по которой люди создают стартапы. Экспоненциальный рост подобен магии. Он порождает результаты, которые кажутся невозможными. Именно поэтому некоторые политики не доверяют этому. Они не понимают математику экспоненциального роста, поэтому, когда видят, как люди становятся, на их взгляд, невероятно богатыми, они предполагают, что те, должно быть, жульничали.&lt;p&gt;Но теперь вы, по крайней мере, понимаете, самостоятельно произведя расчеты, что для того, чтобы стать миллиардером, не нужно жульничать. Вы сами убедились, что в расчетах участвуют всего две цифры: темп роста и продолжительность этого роста. Если невозможно заработать миллиард долларов без жульничества, то какая из этих двух цифр невозможна? Конечно, можно расти на 15% в месяц без жульничества. Стартапы делают это постоянно. А продолжительность такого роста зависит от размера рынка. Очевидно, что для 4000-кратного роста спрос должен увеличиться как минимум в 4000 раз. Но этого достаточно. И как можно жульничать, чтобы увеличить размер рынка?&lt;p&gt;Если вы планируете стать только премьер-министром, можете перестать обращать внимание. Мы доказали, что заработать миллиард долларов на самом деле возможно, потому что это зависит всего от двух цифр, одну из которых стартапы регулярно достигают без жульничества, а на другую жульничество никак не может повлиять.&lt;p&gt;Но если вы действительно хотите стать миллиардером, нам следует поговорить подробнее. Особенно о первом показателе, темпах роста. Чтобы расти стабильными темпами каждый месяц, нужно создать что-то настолько хорошее, чтобы люди рассказывали об этом своим друзьям. И, собственно, это еще одна причина, по которой я всегда начинаю с вопроса к основателям об их темпах роста. Это показывает, создали ли они правильный продукт.&lt;p&gt;Итак, как именно создать что-то, что людям настолько нравится, что они рассказывают об этом своим друзьям? Проблема рыночной экономики, и одновременно ее преимущество, заключается в том, что трудно создать что-то, чего клиенты хотят, чего у них еще нет. Как только обнаруживается новая, удовлетворяемая потребность, люди бросаются ее удовлетворять. Поэтому вам придется обнаружить потребность, о которой еще никто не знает.&lt;p&gt;Как это сделать? &lt;em&gt;Почувствовав эту потребность сами.&lt;/em&gt;&lt;p&gt;Вы молоды, и обычно молодые основатели должны создавать то, чего хотят сами. У вас еще недостаточно опыта, чтобы знать, что нужно другим людям. Но в то же время ваши собственные потребности уникально ценны, потому что ваши потребности предсказывают будущий спрос. Вы достигли того возраста, когда люди начинают пользоваться новыми вещами. Что бы вы и ваши друзья ни начали использовать сейчас, через десять лет этим будут пользоваться все. Поскольку ваши интуитивные представления о потребностях других людей обычно являются ложным сигналом, а ваши собственные потребности особенно важны, вам, как правило, следует прислушаться ко второму сигналу: вам следует создать что-то, что нужно вам и вашим друзьям.&lt;p&gt;Создание чего-то, что нужно вам и вашим друзьям, не означает, что вы должны производить потребительский продукт. Возможно, вы и ваши друзья — молекулярные биологи, и есть что-то интересное, что можно сделать с ДНК, что все остальные упустили из виду. Возможно, вы и ваши друзья увлекаетесь дронами. Идея не обязательно должна быть широко востребована.Оно должно нравиться буквально только вам и вашим друзьям.&lt;p&gt;Не беспокойтесь о втором показателе, размере рынка. Поскольку вы прогнозируете будущий спрос, рынок будет расти. И всегда есть возможность расшириться на смежные рынки. Все, что вам нужно, это плацдарм на территории неудовлетворенных потребностей, от которого можно отталкиваться при расширении.&lt;p&gt;Как получить такую ​​идею? Ответ кроется в одном из самых нелогичных аспектов стартапов — а это о многом говорит, потому что таких аспектов очень много. Но лучший способ получить самые лучшие идеи для стартапов — это не искать их целенаправленно. Если вы сознательно ищете идеи для стартапов, это сделает вас слишком консервативным. Вы отсеете нестандартные варианты. Потому что лучшие идеи для стартапов, как правило, поначалу кажутся настолько нелепыми, что вы бы их отвергли, если бы целенаправленно искали. Именно это и мешало им быть обнаруженными.&lt;p&gt;Представьте, насколько плохой идеей поначалу казались Apple, Facebook или Airbnb. Сколько людей захотят иметь собственные компьютеры? Как компания будет зарабатывать деньги на студентах, которые следят друг за другом в интернете? Кто будет платить за сон на надувном матрасе на чьём-то полу? Мы знаем, чем закончились эти идеи, поэтому легко переписать историю, но я очень хорошо помню, как плохо поначалу звучали Facebook и Airbnb. Мы &lt;em&gt;финансировали&lt;/em&gt; Airbnb, и нам эта идея казалась плохой. Причина, по которой мы их финансировали, заключалась просто в том, что нам нравились &lt;a href=https://paulgraham.com/airbnbs.html rel=&#34;noopener noreferrer nofollow&#34;&gt;основатели&lt;/a&gt; .&lt;p&gt;Так как же найти идеи для стартапов, не ища их целенаправленно? Работая над проектами с друзьями. Именно так рождаются лучшие стартапы. Изначально они даже не задумывались как компании. Это просто что-то, что люди создали, потому что им показалось это крутым. Так начинались Apple, Google и Facebook. Ни один из них изначально не задумывался как компания.&lt;p&gt;Причина, по которой это работает, заключается в том, о чём я говорил ранее: вы предсказываете будущий спрос. Поэтому, если вы просто создаёте случайные вещи, которые, как вам кажется, будут крутыми, то то, что вы создадите, на самом деле будет далеко не случайным.&lt;p&gt;Это один из тех случаев, когда ваше подсознание знает больше, чем ваше сознание. Всё, что вам кажется действительно крутым, с высокой вероятностью может стать хорошей идеей для стартапа, независимо от того, насколько нелепо это звучит. Что бы вы ни создали, это вряд ли может звучать более нелепо, чем стартап, который мы финансировали в 2006 году, под названием &lt;a href=http://Justin.TV rel=&#34;noopener noreferrer nofollow&#34;&gt;Justin.TV&lt;/a&gt;. Он состоял из одного парня, Джастина Кана, который ходил с камерой на голове и вёл прямую трансляцию всего, что с ним происходило. Но эта компания в итоге добилась больших успехов. На самом деле, вы, вероятно, слышали о ней, но под новым названием — Twitch.&lt;p&gt;Ключ к успешному запуску стартапа — это глубокое понимание определенной группы пользователей, позволяющее создавать именно то, что им нужно. Если вы молоды, вы можете и должны использовать прием создания чего-то для себя. Вы понимаете себя. Но это лишь пример более общего правила. Только глубокое понимание пользователей позволит вам создать что-то, что им настолько понравится, что они расскажут об этом своим друзьям, и только это обеспечит вам экспоненциальный рост, необходимый для того, чтобы стартап действительно стал успешным.&lt;p&gt;Существуют и другие способы разбогатеть, помимо создания стартапов. Некоторые из них требуют эксплуатации людей. Но стартапы — это самый распространенный способ стать по-настоящему богатым, и если вы хотите создать успешный стартап, ключ к успеху — не эксплуатация, а эмпатия. Чего действительно хотят пользователи? Что вы могли бы сделать для них, чтобы кардинально улучшить их жизнь? Именно такую ​​эмпатию мы ищем в основателях и культивируем в тех, кого принимаем.&lt;p&gt;Понимание того, как люди становятся богатыми в вашем обществе, — один из важнейших аспектов. Нельзя позволять идеологии, фильмам или историческим примерам, которым уже несколько столетий, определять ваши убеждения по этому поводу. Вы должны смотреть на окружающий мир и видеть, как это делается на самом деле. Если вы хотите сделать это сами, вам, очевидно, придётся понять, как это делается. Поэтому я не слишком беспокоюсь о вас. Я беспокоюсь о будущих премьер-министрах. Вам нужно запомнить этот разговор. Поэтому я кратко изложу для вас ключевые идеи.&lt;p&gt;Есть два показателя, которые определяют, насколько большим становится стартап и, следовательно, насколько богатыми становятся его основатели: темпы роста и продолжительность его существования. Первый достигается созданием продукта, который настолько нравится пользователям, что они рассказывают о нём своим друзьям. Второй достигается присутствием на большом рынке. Если вы экспоненциально вырастете на большом рынке, ваш стартап станет ценным, а вы, как акционер, разбогатеете. Вам не только не нужно жульничать, чтобы это произошло, это произойдёт автоматически, если вы просто будете продолжать радовать клиентов.&amp;#34;&lt;br&gt;&lt;p&gt;&lt;strong&gt;Хорошей недели&lt;/strong&gt;! заходите на тг канал&lt;strong&gt; &lt;/strong&gt;&lt;a href=https://t.me/TradPhronesis rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;https://t.me/TradPhronesis&lt;/strong&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>TraPhro</author>
      <guid>https://habr.com/ru/articles/1049828/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1049828</guid>
      <pubDate>Wed, 24 Jun 2026 17:15:05 +0000</pubDate>
    </item>
    <item>
      <title>Каталог из 83 форматов с плавающей точкой, который сам себя проверяет</title>
      <link>https://habr.com/ru/articles/1051520/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051520</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;blockquote&gt;&lt;p&gt;Вторая статья про проект GoldenFloat. &lt;a href=https://habr.com/ru/articles/1050924/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Первая&lt;/a&gt; была про φ-лестницу форматов и троичную «Сетунь» Брусенцова. Здесь — про инструмент, который из той работы вырос: один машинно-проверяемый каталог числовых форматов, где у каждого формата прописана разрядка битов, битовый отпечаток и метка зрелости — вплоть до той ступени, где формула ещё есть, а железа под ней уже нет.&lt;/blockquote&gt;&lt;p&gt;Если вы хоть раз ловили расхождение точности между двумя реализациями одной сети, то знаете это чувство. Один и тот же &lt;code&gt;matmul&lt;/code&gt; на двух устройствах даёт разные числа. И ты сидишь и гадаешь: это баг, или bf16 так округлил, или вообще на одном устройстве формат не тот, что ты думал. Беда в том, что две команды на разных концах конвейера меряют один результат разными линейками — и абсолютно корректное значение у одного читается как брак у другого.&lt;p&gt;Я решил сделать одну линейку с точными насечками. Для каждого формата — сколько бит уходит на знак, экспоненту и мантиссу, чему равно смещение, как кодируются inf, NaN и субнормали, где лежит общая реперная точка. Не текстом в README, а машинным источником истины: один файл, из которого автоматом генерируются Markdown, JSON, Python, Rust, C и RTL для кремния. Разойдётся спека с декодером — это ловит CI, а не человек на ревью в три часа ночи.&lt;p&gt;Препринт каталога: &lt;a href=https://arxiv.org/abs/2606.09686 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2606.09686&lt;/a&gt;.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/91e/1a8/e6e/91e1a8e6e4fb4d49b5f2685c540d9cdb.png alt=&#34;Обложка: Golden Ruler — каталог из 83 числовых форматов&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/91e/1a8/e6e/91e1a8e6e4fb4d49b5f2685c540d9cdb.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/91e/1a8/e6e/91e1a8e6e4fb4d49b5f2685c540d9cdb.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Обложка: Golden Ruler — каталог из 83 числовых форматов&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Оглавление&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#why rel=&#34;noopener noreferrer nofollow&#34;&gt;Зачем вообще каталог форматов&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#inside rel=&#34;noopener noreferrer nofollow&#34;&gt;Что внутри: 83 формата в 13 кластерах&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#status rel=&#34;noopener noreferrer nofollow&#34;&gt;Метки зрелости&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#rtl rel=&#34;noopener noreferrer nofollow&#34;&gt;Где правило перестаёт быть железом&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#anchor rel=&#34;noopener noreferrer nofollow&#34;&gt;Якорь 0x47C0&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#p3109 rel=&#34;noopener noreferrer nofollow&#34;&gt;Связь с IEEE P3109&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#practice rel=&#34;noopener noreferrer nofollow&#34;&gt;Что это даёт на практике&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#limits rel=&#34;noopener noreferrer nofollow&#34;&gt;Ограничения&lt;/a&gt;&lt;/ul&gt;&lt;a class=anchor id=why&gt;&lt;/a&gt;&lt;h3&gt;Зачем вообще каталог форматов&lt;/h3&gt;&lt;p&gt;Лет десять назад в ML хватало float32 и float16. Дальше зоопарк начал разрастаться: bfloat16, TF32, два несовместимых FP8 (E4M3 и E5M2), FP6, FP4, микромасштабируемые MX-форматы с общей экспонентой, NF4 из мира QLoRA, posit’ы, takum’ы, логарифмические LNS. У каждого свой компромисс между диапазоном и точностью, свои правила округления, свои углы.&lt;p&gt;Проблема даже не в количестве, а в том, что спеки этих форматов растащены по статьям, стандартам и кодовым базам — и противоречат друг другу порой внутри одной библиотеки. Любимый пример: что делает FP8 E4M3 при переполнении на кодировании? У tt-metal и AMD — насыщается до 448.0, у JAX и TPU — уходит в NaN. Стандарт OCP MX разрешает оба. Пока вы не зафиксировали, какой вариант у вас, вопрос «совпадает ли результат» становится не проверяемым, а вкусовым.&lt;p&gt;Каталог отвечает на это одним файлом-спецификацией, из которого всё остальное выводится механически.&lt;/p&gt;&lt;a class=anchor id=inside&gt;&lt;/a&gt;&lt;h3&gt;Что внутри: 83 формата в 13 кластерах&lt;/h3&gt;&lt;p&gt;На сегодня живой источник истины (&lt;code&gt;specs/numeric/formats_catalog.t27&lt;/code&gt;) держит 83 формата в 13 кластерах. Число я каждый раз перепроверяю на свежем клоне репозитория — почему именно так, скажу в разделе про ограничения. Разбивка:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Кластер&lt;th&gt;&lt;p align=left&gt;Кол-во&lt;th&gt;&lt;p align=left&gt;Что внутри&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;GoldenFloat&lt;td&gt;&lt;p align=left&gt;22&lt;td&gt;&lt;p align=left&gt;φ-семейство GF2…GF1024 + гибриды (GF+LNS, MXGF) (&lt;a href=https://arxiv.org/abs/2606.05017 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2606.05017&lt;/a&gt;)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;HistoricalVendor&lt;td&gt;&lt;p align=left&gt;10&lt;td&gt;&lt;p align=left&gt;IBM HFP, VAX (F/D/G/H), Cray, Microsoft MBF&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;PositUnumIII&lt;td&gt;&lt;p align=left&gt;8&lt;td&gt;&lt;p align=left&gt;Posit8…64, takum8…64 (&lt;a href=https://arxiv.org/abs/2412.20273 rel=&#34;noopener noreferrer nofollow&#34;&gt;Hunhold 2024&lt;/a&gt;)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;IntegerFixed&lt;td&gt;&lt;p align=left&gt;8&lt;td&gt;&lt;p align=left&gt;INT4…INT128, Q-формат, BCD&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;MlLowPrecision&lt;td&gt;&lt;p align=left&gt;7&lt;td&gt;&lt;p align=left&gt;bfloat16, TF32, FP8 (E4M3/E5M2), FP6, FP4&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Ieee754Binary&lt;td&gt;&lt;p align=left&gt;5&lt;td&gt;&lt;p align=left&gt;binary16/32/64/128/256&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Theoretical&lt;td&gt;&lt;p align=left&gt;4&lt;td&gt;&lt;p align=left&gt;minifloat, Unum I/II, tapered FP&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Lns&lt;td&gt;&lt;p align=left&gt;4&lt;td&gt;&lt;p align=left&gt;логарифмические LNS-8…64&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;CompressionTrick&lt;td&gt;&lt;p align=left&gt;4&lt;td&gt;&lt;p align=left&gt;block FP, shared-exponent, per-channel scale, stochastic rounding&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Microscaling&lt;td&gt;&lt;p align=left&gt;3&lt;td&gt;&lt;p align=left&gt;MXFP8/6/4 (общая экспонента E8M0) (&lt;a href=https://arxiv.org/abs/2310.10537 rel=&#34;noopener noreferrer nofollow&#34;&gt;Rouhani 2023&lt;/a&gt;)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Ieee754Decimal&lt;td&gt;&lt;p align=left&gt;3&lt;td&gt;&lt;p align=left&gt;decimal32/64/128&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;ExtendedFloat&lt;td&gt;&lt;p align=left&gt;3&lt;td&gt;&lt;p align=left&gt;x87 FP80, double-double, quad-double&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;QuantTuned&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;NF4 (&lt;a href=https://arxiv.org/abs/2305.14314 rel=&#34;noopener noreferrer nofollow&#34;&gt;Dettmers 2023&lt;/a&gt;), AFP&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Разрядность тянется от 2 бит (балансная троичность GFTernary, привет Брусенцову) до 1024 бит (GF1024, крайняя ступень φ-лестницы). У каждой строки кроме &lt;code&gt;s/e/m/bias&lt;/code&gt; есть поле &lt;code&gt;phi_distance&lt;/code&gt; — насколько разбиение формата близко к тому, что даёт золотое сечение через тождество φ² + φ⁻² = 3.&lt;p&gt;Раз уж речь зашла про слово «golden» — это обычный отраслевой термин, эталонное значение, с которым сравнивают результат, как эталонный метр в палате мер и весов. Им оперируют и в NVIDIA, и в Intel, и любой инженер на HDL. Каталог просто говорит на том же языке, а не выдумывает свой.&lt;/p&gt;&lt;a class=anchor id=status&gt;&lt;/a&gt;&lt;h3&gt;Метки зрелости&lt;/h3&gt;&lt;p&gt;Дисциплина, на которой держится весь проект, — метка зрелости у каждого формата. Она говорит ровно одно: насколько эта строка проверена на самом деле.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Статус&lt;th&gt;&lt;p align=left&gt;Кол-во&lt;th&gt;&lt;p align=left&gt;Что означает&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Verified&lt;td&gt;&lt;p align=left&gt;51&lt;td&gt;&lt;p align=left&gt;сверен с эталоном (стандарт или ml_dtypes)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Historical&lt;td&gt;&lt;p align=left&gt;12&lt;td&gt;&lt;p align=left&gt;исторический формат (IBM, VAX, Cray…), для полноты&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Experimental&lt;td&gt;&lt;p align=left&gt;11&lt;td&gt;&lt;p align=left&gt;спека плюс частичная реализация, без полного покрытия&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Open&lt;td&gt;&lt;p align=left&gt;9&lt;td&gt;&lt;p align=left&gt;только спецификация из правила, без RTL&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Здесь же проходит граница, которая мне важнее красивых цифр: где правило &lt;code&gt;e = round((N−1)/φ²)&lt;/code&gt; ещё работающее железо, а где оно уже гипотеза. GF16 доведён до кремния (FPGA 35/35 тестов, 323 МГц на Artix-7, кремниевый якорь). Под ступенями GF48…GF256 есть RTL, но кремния нет. GF512 и GF1024 — экстраполяция правила, у них в SSOT прямо стоит &lt;code&gt;(extrapolation, no RTL)&lt;/code&gt;, и я не делаю вид, что они проверены. Эту лестницу разбираю ниже.&lt;p&gt;Побочный эффект такой дисциплины: значение 0.1 в bfloat16 показано в каталоге с ненулевой ошибкой — потому что 0.1 в bf16 точно не представимо. Спрятать эту ошибку значило бы сломать саму линейку, ради которой всё затевалось.&lt;/p&gt;&lt;a class=anchor id=rtl&gt;&lt;/a&gt;&lt;h3&gt;Где правило перестаёт быть железом&lt;/h3&gt;&lt;p&gt;φ-семейство держится на одном правиле: для ширины &lt;code&gt;N&lt;/code&gt; бит экспонента &lt;code&gt;e = round((N−1)/φ²)&lt;/code&gt;, мантисса &lt;code&gt;m = N − 1 − e&lt;/code&gt;, смещение &lt;code&gt;bias = 2^(e−1) − 1&lt;/code&gt;. Правило короткое и применимо к любой ширине. Но «формат описан правилом» и «формат крутится в железе» — это разные вещи, и смешивать их я себе не позволяю.&lt;p&gt;Вот как лестница φ-ступеней выглядит в репозиториях прямо сейчас:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Уровень зрелости&lt;th&gt;&lt;p align=left&gt;Ступени&lt;th&gt;&lt;p align=left&gt;Что реально есть&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Доведено до кремния&lt;td&gt;&lt;p align=left&gt;GF16&lt;td&gt;&lt;p align=left&gt;RTL + FPGA 35/35 @ 323 МГц + кремниевый якорь &lt;code&gt;gf16_v2_mul.v&lt;/code&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;RTL + бенчмарк (Verified)&lt;td&gt;&lt;p align=left&gt;GF8, GF12, GF32, GF64&lt;td&gt;&lt;p align=left&gt;файлы &lt;code&gt;_add.v&lt;/code&gt; / &lt;code&gt;_mul.v&lt;/code&gt; + измерения&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;RTL написан, кремния нет (Open / Exp)&lt;td&gt;&lt;p align=left&gt;GF6, GF10, GF14, GF20, GF24, GF48, GF96, GF128, GF256&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;_add.v&lt;/code&gt; / &lt;code&gt;_mul.v&lt;/code&gt; есть (сумматор GF256 ≈ 939 строк Verilog); тесты местами&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Экстраполяция, RTL нет (Open)&lt;td&gt;&lt;p align=left&gt;GF512, GF1024&lt;td&gt;&lt;p align=left&gt;только спека; файлов &lt;code&gt;gf512*&lt;/code&gt; / &lt;code&gt;gf1024*&lt;/code&gt; в RTL нет&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Тут вылезает неудобная вещь про GF1024. По метрике близости к φ это лучшая ступень лестницы (phi_distance ≈ 0.0006), и при этом она проверена меньше всех — ни одной строки Verilog. Красивая метрика не повышает уровень зрелости, и каталог это показывает, а не заметает.&lt;p&gt;RTL, который уже есть, — не для вида. Умножитель GF256 в начале июня пришлось переписать после реального бага: произведение мантисс выходило на 2 бита у́же положенного, и &lt;code&gt;1.0 × 1.0&lt;/code&gt; давало &lt;code&gt;0.5&lt;/code&gt;. Поймали это только потому, что под форматом лежит железо, которое можно прогнать на тестах. Под GF512 и GF1024 такого железа пока нет — отсюда и честная пометка.&lt;/p&gt;&lt;a class=anchor id=anchor&gt;&lt;/a&gt;&lt;h3&gt;Якорь 0x47C0&lt;/h3&gt;&lt;p&gt;У каталога есть одна общая реперная точка, и она растёт из того же тождества: φ² + φ⁻² = 3 = L₂, второе число Люка. Если посчитать &lt;code&gt;dot4(1, 2, 3, 4)&lt;/code&gt; в GF16, бит-в-бит получается значение с отпечатком 0x47C0. Этот якорь проходит без изменений через все реализации — от JSON-векторов до RTL-декодеров на кремнии (проект Corona). Разъехалась эта одна точка — значит линейка где-то сбита, ищи где.&lt;p&gt;Это проверка на одинаковость, а не доказательство превосходства. Оговорка, которую держу жёстко: φ-семейство заслуживает место в каталоге широтой охвата и связностью тулчейна, а не тем, что каждая ступень кого-то побеждает. takum (Hunhold, 2024) — сильный контрпример, и он не спрятан, лежит в каталоге рядом со всеми.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr//post_images/90d/603/619/90d6036196d052cc592e2c60d63efd42.png alt=&#34;Линейка, кластеры, якорь 0x47C0&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr//post_images/90d/603/619/90d6036196d052cc592e2c60d63efd42.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr//post_images/90d/603/619/90d6036196d052cc592e2c60d63efd42.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Линейка, кластеры, якорь 0x47C0&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;a class=anchor id=p3109&gt;&lt;/a&gt;&lt;h3&gt;Связь с IEEE P3109&lt;/h3&gt;&lt;p&gt;Рабочая группа IEEE P3109 стандартизирует семейство 8-битных форматов для ML. В каталоге лежит cross-walk — одностраничная карта, сопоставляющая семейство P3109 binary8 (p1…p7) с индексами каталога. Это не заявление о соответствии стандарту, а справочник для разработчиков, который сама рабочая группа может проверить и поправить. Где есть расхождение — каталог уступает Lean-формализации FLoPS (&lt;a href=https://arxiv.org/abs/2602.15965 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2602.15965&lt;/a&gt;).&lt;p&gt;Позиция тут сознательная: заходить не с «примите нас», а с проверяемой таблицей, которую можно сверить и опровергнуть.&lt;/p&gt;&lt;a class=anchor id=practice&gt;&lt;/a&gt;&lt;h3&gt;Что это даёт на практике&lt;/h3&gt;&lt;p&gt;Самое прямое применение — арбитр при расхождении точности. Когда один расчёт даёт разные числа на двух устройствах (классика: PCC проседает с 0.99 до 0.93 при другой блокировке редукции), бит-точный эталон формата механически отвечает, чей результат корректен, без споров на глаз.&lt;p&gt;Второе — кодоген под новое железо. Из одной спеки выводятся декодеры на нужном языке, включая RTL. Цепочка &lt;code&gt;SSOT → кодоген → RTL → кремний&lt;/code&gt; целиком механическая, а CI-гейт &lt;code&gt;rom_readback&lt;/code&gt; ловит любое расхождение между спекой и тем, что реально лежит в ПЗУ декодера на чипе.&lt;p&gt;Третье — общий словарь. Когда вы и собеседник из другой команды называете формат одинаково, с одной разрядкой и одним поведением на границах, исчезает целый класс споров в духе «а у нас не так».&lt;/p&gt;&lt;a class=anchor id=limits&gt;&lt;/a&gt;&lt;h3&gt;Ограничения&lt;/h3&gt;&lt;p&gt;Чтобы статья не съехала в рекламу, перечислю прямо:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Кремнием проверен пока только GF16. Для GF48…GF256 RTL написан, но не в кремнии; GF512 и GF1024 — экстраполяция правила без RTL. Самая близкая к φ ступень (GF1024) проверена меньше всех.&lt;li&gt;&lt;p&gt;Кремний Corona — это законченный дизайн (RTL + GDS + формальная верификация + cocotb), а не отлитый чип. Проверено в симуляции и формально; кремний впереди.&lt;li&gt;&lt;p&gt;φ-семейство не заявлено как «лучше всех». Место в каталоге — за широту и связность, не за победу на каждой ступени. takum лежит там же как сильный контрпример.&lt;/ul&gt;&lt;p&gt;Каталог — это инструмент и дисциплина, а не финальное слово. Линейка стоит ровно столько, сколько стоят её насечки, — поэтому я и показываю, где они сейчас сбиты.&lt;hr&gt;&lt;p&gt;Источники и материалы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Препринт каталога: &lt;a href=https://arxiv.org/abs/2606.09686 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2606.09686&lt;/a&gt;&lt;li&gt;&lt;p&gt;GoldenFloat (φ-семейство): &lt;a href=https://arxiv.org/abs/2606.05017 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2606.05017&lt;/a&gt;&lt;li&gt;&lt;p&gt;SSOT каталога: &lt;a href=https://github.com/gHashTag/t27/blob/master/specs/numeric/formats_catalog.t27 rel=&#34;noopener noreferrer nofollow&#34;&gt;gHashTag/t27 · formats_catalog.t27&lt;/a&gt;&lt;li&gt;&lt;p&gt;takum (контрпример): &lt;a href=https://arxiv.org/abs/2412.20273 rel=&#34;noopener noreferrer nofollow&#34;&gt;Hunhold 2024 · arXiv:2412.20273&lt;/a&gt;&lt;li&gt;&lt;p&gt;OCP Microscaling: &lt;a href=https://arxiv.org/abs/2310.10537 rel=&#34;noopener noreferrer nofollow&#34;&gt;Rouhani 2023 · arXiv:2310.10537&lt;/a&gt;&lt;li&gt;&lt;p&gt;NF4 / QLoRA: &lt;a href=https://arxiv.org/abs/2305.14314 rel=&#34;noopener noreferrer nofollow&#34;&gt;Dettmers 2023 · arXiv:2305.14314&lt;/a&gt;&lt;li&gt;&lt;p&gt;FLoPS (P3109 формализация): &lt;a href=https://arxiv.org/abs/2602.15965 rel=&#34;noopener noreferrer nofollow&#34;&gt;arXiv:2602.15965&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;Аффилиация: Trinity S³AI (независимый исследовательский коллектив). ORCID: &lt;a href=https://orcid.org/0009-0008-4294-6159 rel=&#34;noopener noreferrer nofollow&#34;&gt;0009-0008-4294-6159&lt;/a&gt;. Контакт: &lt;a href=mailto:admin@t27.ai rel=&#34;noopener noreferrer nofollow&#34;&gt;admin@t27.ai&lt;/a&gt; (асинхронно).&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>raoffonom</author>
      <guid>https://habr.com/ru/articles/1051520/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051520</guid>
      <pubDate>Wed, 24 Jun 2026 16:39:17 +0000</pubDate>
    </item>
    <item>
      <title>Рюкзачная криптосистема Шора-Ривеста</title>
      <link>https://habr.com/ru/articles/1051214/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051214</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;В этой статье мы рассмотрим рюкзачную, или ранцевую, криптосистему Шора-Ривеста (Chor-Rivest knapsack). Это один из немногих алгоритмов классической криптографии, который можно рассматривать как постквантовый кандидат. Несмотря на то что сегодня он не считается современной и надёжной постквантовой криптосистемой, его всё равно интересно разобрать как один из нестандартных вариантов такого рода.&lt;details class=spoiler&gt;&lt;summary&gt;Математическая база&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;В статье используются вычисления в конечных полях. Если вы не знакомы с этой темой, рекомендую сначала ознакомиться с моим &lt;a href=https://habr.com/ru/articles/1046053/ rel=&#34;noopener noreferrer nofollow&#34;&gt;циклом статей&lt;/a&gt;. Далее я буду использовать свойства и обозначения абстрактной алгебры без дополнительных пояснений.&lt;/div&gt;&lt;/details&gt;&lt;h2&gt;Структура статьи&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#complexity rel=&#34;noopener noreferrer nofollow&#34;&gt;Введение в тeорию сложности вычислений&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#knapsack rel=&#34;noopener noreferrer nofollow&#34;&gt;Задача об укладке рюкзака&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#chor-rivest rel=&#34;noopener noreferrer nofollow&#34;&gt;Рюкзачная криптосистема Шора-Ривеста&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#bitstring rel=&#34;noopener noreferrer nofollow&#34;&gt;Преобразование произвольных битовых строк&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#example rel=&#34;noopener noreferrer nofollow&#34;&gt;Пример работы криптосистемы&lt;/a&gt;&lt;/ul&gt;&lt;h2&gt;Введение в тeорию сложности вычислений&lt;/h2&gt;&lt;a class=anchor id=complexity&gt;&lt;/a&gt;&lt;p&gt;Стойкость криптографических алгоритмов основывается но вычислительной сложности задач, которые лежат в их основе. Теория сложности вычислений изучает, какое минимальное количество ресурсов необходимо для решения вычислительных задач. Она помогает различать &amp;#34;легкие&amp;#34; и &amp;#34;трудные задачи&amp;#34;. Для &amp;#34;легких&amp;#34; задач существует эффективный алгоритм решения, а &amp;#34;трудные&amp;#34; задачи не разрешимы при использовании &amp;#34;разумного&amp;#34; количества ресурсов. Таким образом для использования в криптосистемах алгоритм должен быть &amp;#34;легким&amp;#34; для вычисления добросовестным пользователем, и &amp;#34;трудным&amp;#34; для злоумышленника, который пытается криптосистему взломать.&lt;p&gt;Основными ресурсами с точки зрения теории сложности, которые использует программа во время своей работы, являются &lt;em&gt;время&lt;/em&gt; работы и используемая &lt;em&gt;память&lt;/em&gt;. В случае алгоритмов, используемых в криптосистемах, в первую очередь оценивают время работы программы. Для каждого конкретного случая требования по времени могут отличаться, но обычно &amp;#34;трудной&amp;#34; считается задача, на решение которой уйдут десятилетия.&lt;p&gt;Формализуем понятие &amp;#34;легкой&amp;#34; и &amp;#34;трудной&amp;#34; задачи. В теории сложности для этого рассматривают какую-нибудь вычислительную модель (например, машину Тьюринга - абстрактную вычислительную машину), однако для восприятия проще оценивать сложность программы по количеству исполняемых побитовых операций, при этом входные данные программы представляют в виде бинарной строки. &lt;em&gt;Функция сложности&lt;/em&gt; - функция от размера входных параметров алгоритма (длины бинарной строки, представляющей входные данные), отражающая требования к ресурсам для его выполнения. Сложность алгоритма обычно выражается с помощью нотации &lt;em&gt;O&lt;/em&gt; (&amp;#34;О&amp;#34; большое). Эта нотация учитывает только слагаемые функции сложности самого высокого порядка, при этом не учитывая константные множители.&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Vadhan, Salil P. 2011. Computational complexity. In Encyclopedia of Cryptography and Security, second edition, ed. Henk C.A. van Tilborg and Sushil Jajodia. New York: Springer.&lt;/div&gt;&lt;/details&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;O(n^3 + 3n + 1) = O(n^3)&#34; alt=&#34;O(n^3 + 3n + 1) = O(n^3)&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d4/d4b/d4ba95413319a3be0c089efc374eca83.svg width=184 height=16 data-width=23.832 data-height=2.564 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d4/d4b/d4ba95413319a3be0c089efc374eca83.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d4/d4b/d4ba95413319a3be0c089efc374eca83.svg 781w&#34; loading=lazy decode=async&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Измеренная таким образом сложность алгоритма не зависит от реализации или параметров вычислительной техники, на которой он исполняется, всеми этими параметрами можно пренебречь в сравнении со сложностью по порядку величины. В случае оценки времени работы алгоритма нотация позволяет увидеть, как изменение входных данных влияет на требования ко времени работы.&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Если &lt;img class=&#34;formula inline&#34; source=&#34;T = O(n)&#34; alt=&#34;T = O(n)&#34; src=https://habrastorage.org/getpro/habr/formulas/5/52/52c/52cf7988406f33eea109da733d7ca22e.svg width=72 height=16 data-width=9.454 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/52/52c/52cf7988406f33eea109da733d7ca22e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/52/52c/52cf7988406f33eea109da733d7ca22e.svg 781w&#34; loading=lazy decode=async&gt;, то удвоение входных данных приведет к удвоению времени работы алгоритма, а если &lt;img class=&#34;formula inline&#34; source=&#34;T = O(2^n)&#34; alt=&#34;T = O(2^n)&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ed/eda/eda1f99a71f8f13772555355cc451184.svg width=80 height=16 data-width=10.375 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ed/eda/eda1f99a71f8f13772555355cc451184.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ed/eda/eda1f99a71f8f13772555355cc451184.svg 781w&#34; loading=lazy decode=async&gt;, то добавление одного бита к входным данным приведет к удвоению времени работы алгоритма.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;В зависимости от функции сложности существуют классы сложности задач. Пусть &lt;em&gt;n&lt;/em&gt; - длина битовый строки - входных параметров алгоритма. Алгоритмы, временная сложность которых может быть записана как &lt;img class=&#34;formula inline&#34; source=O(n^c) alt=O(n^c) src=https://habrastorage.org/getpro/habr/formulas/5/54/545/545931b5ad8cb12bfe07e2537c9f1ee0.svg width=40 height=16 data-width=5.724 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/54/545/545931b5ad8cb12bfe07e2537c9f1ee0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/54/545/545931b5ad8cb12bfe07e2537c9f1ee0.svg 781w&#34; loading=lazy decode=async&gt;, где &lt;em&gt;c&lt;/em&gt; - константа, называются алгоритмами с &lt;em&gt;полиномиальным временем&lt;/em&gt;, так как их функция сложности полиномиальна. Такие задачи считаются &amp;#34;легкими&amp;#34;, они могут быть эффективно решены. Их относят к классу сложности &lt;em&gt;P&lt;/em&gt; - класс задач, которые могут быть решены за полиномиальное время. Однако если временная сложность алгоритма задается, например, как &lt;img class=&#34;formula inline&#34; source=O(c^n) alt=O(c^n) src=https://habrastorage.org/getpro/habr/formulas/d/df/df5/df53a754e2911204c0e762595e3f25f3.svg width=40 height=16 data-width=5.614 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/df/df5/df53a754e2911204c0e762595e3f25f3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/df/df5/df53a754e2911204c0e762595e3f25f3.svg 781w&#34; loading=lazy decode=async&gt;, где &lt;em&gt;c&lt;/em&gt; - константа, то говорят об экспоненциальной сложности и &lt;em&gt;экспоненциальном времени&lt;/em&gt;. Такие задачи быстро становятся нерешаемыми при росте размера входных данных и к классу &lt;em&gt;P&lt;/em&gt; уже не относятся.&lt;p&gt;Еще одним важным классом сложности является &lt;em&gt;NP&lt;/em&gt; - это класс вычислительных проблем, решение которых может быть проверено за полиномиальное времени (но не может быть за полиномиальное время получено). Таким образом задачи из этого класса отлично подходят для использования в криптосистемах. Задача из класса &lt;em&gt;NP&lt;/em&gt; называется &lt;em&gt;NP-полной&lt;/em&gt;, если любую задачу из класса &lt;em&gt;NP&lt;/em&gt; можно свести к этой задаче за полиномиальное время (т.е. если для какой-нибудь &lt;em&gt;NP&lt;/em&gt;-полной задачи будет найден алгоритм решения, работающий за полиномиальное время, то и любую другую задачу из класса &lt;em&gt;NP&lt;/em&gt; можно будет решить за такое же время). Таким образом &lt;em&gt;NP&lt;/em&gt;-полные задачи являются наиболее &amp;#34;трудными&amp;#34;, и потому наиболее вероятно, что для них не будет найдено решения за полиномиальное время.&lt;h2&gt;Задача об укладке рюкзака&lt;/h2&gt;&lt;a class=anchor id=knapsack&gt;&lt;/a&gt;&lt;p&gt;Одной из &amp;#34;трудных&amp;#34; задач является задача об укладке рюкзака. В ее основе лежит следующая идея. Есть рюкзак, вместимость которого ограничена, и множество предметов, которые в него можно положить. Необходимо найти подмножество предметов, которое этот рюкзак заполнит доверху. Эта задача интересна тем, что зная подмножество предметов, уложенных в рюкзак, легко подсчитать его вес, однако, зная вес рюкзака, трудно определить подмножество предметов. Другой вариант задачи, в котором в рюкзак можно положить не более одного экземпляра предмета каждого типа, называется &lt;em&gt;рюкзак 0-1&lt;/em&gt;.&lt;p&gt;Более формально, задача о рюкзаке 0-1 является &lt;em&gt;NP&lt;/em&gt;-полной задачей комбинаторной оптимизации. Математическая задача формулируется следующим образом: имеется множество &lt;img class=&#34;formula inline&#34; source=&#34;A = \{ a_i | 0 \leq i \leq n-1 \}&#34; alt=&#34;A = \{ a_i | 0 \leq i \leq n-1 \}&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d29526c46a9f457514c71b65dc7011.svg width=176 height=16 data-width=22.742 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d29526c46a9f457514c71b65dc7011.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d29526c46a9f457514c71b65dc7011.svg 781w&#34; loading=lazy decode=async&gt; неотрицательных целых чисел и неотрицательное целое число &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt;. Необходимо найти решение в целых числах для&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;\sum_{i=0}^{n-1} a_i x_i = S&#34; alt=&#34;\sum_{i=0}^{n-1} a_i x_i = S&#34; src=https://habrastorage.org/getpro/habr/formulas/d/db/db9/db9c77f7b98e1cc7ce713c12477969f7.svg width=96 height=48 data-width=12.091 data-height=6.712 data-vertical-align=-2.791 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/db/db9/db9c77f7b98e1cc7ce713c12477969f7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/db/db9/db9c77f7b98e1cc7ce713c12477969f7.svg 781w&#34; loading=lazy decode=async&gt; , где &lt;img class=&#34;formula inline&#34; source=&#34;x_i \in \{ 0, 1 \}&#34; alt=&#34;x_i \in \{ 0, 1 \}&#34; src=https://habrastorage.org/getpro/habr/formulas/7/74/74b/74b5790c933f114f11b79b1319611353.svg width=80 height=16 data-width=10.331 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/74/74b/74b5790c933f114f11b79b1319611353.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/74/74b/74b5790c933f114f11b79b1319611353.svg 781w&#34; loading=lazy decode=async&gt; для всех &lt;img class=&#34;formula inline&#34; source=i alt=i src=https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg width=12 height=12 data-width=0.781 data-height=1.52 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;Другой вариант постановки задачи о рюкзаке - снять ограничение 0-1, требуя только чтобы все &lt;img class=&#34;formula inline&#34; source=x_i alt=x_i src=https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg width=16 height=12 data-width=2.034 data-height=1.357 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg 781w&#34; loading=lazy decode=async&gt; были неотрицательными целыми числами, и ограничить их вес:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;\sum_{i=0}^{n-1} x_i \leq h&#34; alt=&#34;\sum_{i=0}^{n-1} x_i \leq h&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e1/e13/e13f0fe5fc2721023844c4af044afb16.svg width=72 height=48 data-width=9.998 data-height=6.712 data-vertical-align=-2.791 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e1/e13/e13f0fe5fc2721023844c4af044afb16.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e1/e13/e13f0fe5fc2721023844c4af044afb16.svg 781w&#34; loading=lazy decode=async&gt;.&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Chor B., Rivest R. L. A Knapsack-Type Public Key Cryptosystem Based on Arithmetic in Finite Fields. // IEEE Transactions on information theory. 1988. Vol. 34, № 5. pp. 901–909.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;&lt;em&gt;Рюкзачным вектором&lt;/em&gt; &lt;img class=&#34;formula inline&#34; source=&#34;A = (a_0, \dots, a_{n-1})&#34; alt=&#34;A = (a_0, \dots, a_{n-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/8/87/87b/87bf31e112ff23c7a5d66f0c3680f6f7.svg width=144 height=16 data-width=18.088 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/87/87b/87bf31e112ff23c7a5d66f0c3680f6f7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/87/87b/87bf31e112ff23c7a5d66f0c3680f6f7.svg 781w&#34; loading=lazy decode=async&gt; называется упорядоченный набор из &lt;img class=&#34;formula inline&#34; source=n alt=n src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg width=12 height=12 data-width=1.357 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w&#34; loading=lazy decode=async&gt; предметов, где &lt;img class=&#34;formula inline&#34; source=a_i alt=a_i src=https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg width=12 height=12 data-width=1.937 data-height=1.355 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 781w&#34; loading=lazy decode=async&gt; - вес &lt;img class=&#34;formula inline&#34; source=i alt=i src=https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg width=12 height=12 data-width=0.781 data-height=1.52 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 781w&#34; loading=lazy decode=async&gt;-го предмета, &lt;img class=&#34;formula inline&#34; source=&#34;0 \leq i \leq n-1&#34; alt=&#34;0 \leq i \leq n-1&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e7/e7b/e7b6d67e14843dcc3698b458758d0203.svg width=104 height=16 data-width=13.2 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e7/e7b/e7b6d67e14843dcc3698b458758d0203.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e7/e7b/e7b6d67e14843dcc3698b458758d0203.svg 781w&#34; loading=lazy decode=async&gt;.&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Саломаа А. Криптография с открытым ключом: Пеp. с англ. — М.: Миp, 1995. с. 73-161.&lt;/div&gt;&lt;/details&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Пусть &lt;img class=&#34;formula inline&#34; source=&#34;A = (3, 5, 10, 7, 8)&#34; alt=&#34;A = (3, 5, 10, 7, 8)&#34; src=https://habrastorage.org/getpro/habr/formulas/8/88/889/8894dd94830d7389a72bf27b22297581.svg width=136 height=16 data-width=17.286 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/88/889/8894dd94830d7389a72bf27b22297581.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/88/889/8894dd94830d7389a72bf27b22297581.svg 781w&#34; loading=lazy decode=async&gt; - рюкзачный вектор длины 5. Тогда число 25 можно представить в виде суммы элементов рюкзачного вектора &lt;img class=&#34;formula inline&#34; source=&#34;25 = 3 + 5 + 10 + 7&#34; alt=&#34;25 = 3 + 5 + 10 + 7&#34; src=https://habrastorage.org/getpro/habr/formulas/7/7c/7c1/7c10ce179f72c7b163f6877f67993fe3.svg width=152 height=12 data-width=19.233 data-height=1.715 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7c/7c1/7c10ce179f72c7b163f6877f67993fe3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7c/7c1/7c10ce179f72c7b163f6877f67993fe3.svg 781w&#34; loading=lazy decode=async&gt;. Разложение числа по элементам рюкзачного вектора можно записать в виде бинарного вектора. Для предыдущего примера этот вектор будет равен &lt;img class=&#34;formula inline&#34; source=&#34;(1, 1, 1, 1, 0)&#34; alt=&#34;(1, 1, 1, 1, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e0/e0b/e0be96bebaa8d863821daeb6928c99a9.svg width=88 height=16 data-width=11.44 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e0/e0b/e0be96bebaa8d863821daeb6928c99a9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e0/e0b/e0be96bebaa8d863821daeb6928c99a9.svg 781w&#34; loading=lazy decode=async&gt;, где 1 стоит на месте тех элементов, которые участвовали в разложении. При этом, просуммировав элементы рюкзачного вектора, на месте которых стоят 1, можно получить исходное число. Этот факт можно использовать для построения криптосистемы, однако стоит заметить, что в приведенном нами примере одно и то же число может быть представлено несколькими способами, из-за чего преобразования становятся неоднозначными: &lt;img class=&#34;formula inline&#34; source=8 alt=8 src=https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg width=12 height=12 data-width=1.131 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg 781w&#34; loading=lazy decode=async&gt; можно представить как &lt;img class=&#34;formula inline&#34; source=&#34;(1, 1, 0, 0, 0)&#34; alt=&#34;(1, 1, 0, 0, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d8/d8f/d8fb5c7246590844bf0d901a6e8a9aa5.svg width=88 height=16 data-width=11.44 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d8f/d8fb5c7246590844bf0d901a6e8a9aa5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d8f/d8fb5c7246590844bf0d901a6e8a9aa5.svg 781w&#34; loading=lazy decode=async&gt; или как &lt;img class=&#34;formula inline&#34; source=&#34;(0, 0, 0, 0, 1)&#34; alt=&#34;(0, 0, 0, 0, 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ef/ef3/ef3bf43b9836863a4f3c1380df485a78.svg width=88 height=16 data-width=11.44 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ef/ef3/ef3bf43b9836863a4f3c1380df485a78.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ef/ef3/ef3bf43b9836863a4f3c1380df485a78.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Рюкзачные криптосистемы основываются на трудности решения задачи об укладке рюкзака в целых числах. Однако не для любого рюкзачного вектора A задача является трудной. Рюкзачный вектор должен быть достаточно большим и состоять из чисел большого порядка, чтобы решить задачу об укладке рюкзака полным перебором было трудно. Легко задача решается для&lt;em&gt;сверхрастущих&lt;/em&gt; векторов.&lt;p&gt;Вектор &lt;img class=&#34;formula inline&#34; source=&#34;A = ( a_0, \dots, a_{n-1} )&#34; alt=&#34;A = ( a_0, \dots, a_{n-1} )&#34; src=https://habrastorage.org/getpro/habr/formulas/9/96/967/967c2cf387986589c43b5698aa0da346.svg width=144 height=16 data-width=18.088 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/96/967/967c2cf387986589c43b5698aa0da346.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/96/967/967c2cf387986589c43b5698aa0da346.svg 781w&#34; loading=lazy decode=async&gt; называется &lt;em&gt;сврехрастущим&lt;/em&gt;, если &lt;img class=&#34;formula inline&#34; source=&#34;\sum_{i=0}^{j-1} a_i &amp;lt; a_j&#34; alt=&#34;\sum_{i=0}^{j-1} a_i &amp;lt; a_j&#34; src=https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c55ff8b0600aec4c50c36c200d0d520.svg width=80 height=48 data-width=10.641 data-height=6.837 data-vertical-align=-2.853 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c55ff8b0600aec4c50c36c200d0d520.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c55ff8b0600aec4c50c36c200d0d520.svg 781w&#34; loading=lazy decode=async&gt; для &lt;img class=&#34;formula inline&#34; source=&#34;j = 1, \dots, n-1&#34; alt=&#34;j = 1, \dots, n-1&#34; src=https://habrastorage.org/getpro/habr/formulas/e/eb/eb2/eb2296edcd6dae48e5d242938b6e18ee.svg width=120 height=16 data-width=15.376 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/eb/eb2/eb2296edcd6dae48e5d242938b6e18ee.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/eb/eb2/eb2296edcd6dae48e5d242938b6e18ee.svg 781w&#34; loading=lazy decode=async&gt;,&lt;p&gt;т.е. каждый член последовательности больше суммы всех предыдущих.&lt;p&gt;Для сверхрастущего вектора &lt;img class=&#34;formula inline&#34; source=A alt=A src=https://habrastorage.org/getpro/habr/formulas/7/7f/7fc/7fc56270e7a70fa81a5935b72eacbe29.svg width=12 height=12 data-width=1.697 data-height=1.62 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7f/7fc/7fc56270e7a70fa81a5935b72eacbe29.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7f/7fc/7fc56270e7a70fa81a5935b72eacbe29.svg 781w&#34; loading=lazy decode=async&gt; задача может быть решена с помощью следующего алгоритма:&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Алгоритм.&lt;/strong&gt;&lt;p&gt;&lt;em&gt;Вход: &lt;img class=&#34;formula inline&#34; source=&#34;A, S&#34; alt=&#34;A, S&#34; src=https://habrastorage.org/getpro/habr/formulas/d/da/da2/da21285aa79ced451941a56fecbda3ba.svg width=32 height=16 data-width=4.162 data-height=2.059 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/da/da2/da21285aa79ced451941a56fecbda3ba.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/da/da2/da21285aa79ced451941a56fecbda3ba.svg 781w&#34; loading=lazy decode=async&gt;; Выход: &lt;img class=&#34;formula inline&#34; source=\vec{x} alt=\vec{x} src=https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg width=12 height=16 data-width=1.294 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg 781w&#34; loading=lazy decode=async&gt;;&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;i \leftarrow n-1&#34; alt=&#34;i \leftarrow n-1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/90/905/90596f907596047383d9a608578ccb5b.svg width=72 height=16 data-width=9.554 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/90/905/90596f907596047383d9a608578ccb5b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/90/905/90596f907596047383d9a608578ccb5b.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;пока &lt;img class=&#34;formula inline&#34; source=&#34;i &amp;gt;= 0&#34; alt=&#34;i &amp;gt;= 0&#34; src=https://habrastorage.org/getpro/habr/formulas/8/82/823/823b7f6244c07911be94a8b2963a6ac0.svg width=48 height=12 data-width=6.689 data-height=1.692 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/82/823/823b7f6244c07911be94a8b2963a6ac0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/82/823/823b7f6244c07911be94a8b2963a6ac0.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;если &lt;img class=&#34;formula inline&#34; source=&#34;a_i \leq S&#34; alt=&#34;a_i \leq S&#34; src=https://habrastorage.org/getpro/habr/formulas/7/7c/7cd/7cdaa8ee244ea8441a5c8e8004ea922f.svg width=48 height=16 data-width=6.413 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7c/7cd/7cdaa8ee244ea8441a5c8e8004ea922f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7c/7cd/7cdaa8ee244ea8441a5c8e8004ea922f.svg 781w&#34; loading=lazy decode=async&gt;, то&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;x_i \leftarrow 1&#34; alt=&#34;x_i \leftarrow 1&#34; src=https://habrastorage.org/getpro/habr/formulas/4/43/437/437dda5907d18d456dfc337c0966ae02.svg width=48 height=16 data-width=6.684 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/43/437/437dda5907d18d456dfc337c0966ae02.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/43/437/437dda5907d18d456dfc337c0966ae02.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;S \leftarrow S - a_i&#34; alt=&#34;S \leftarrow S - a_i&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f9/f9f/f9fb3cc15cceae6406903c92415df6ca.svg width=88 height=16 data-width=11.14 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f9/f9f/f9fb3cc15cceae6406903c92415df6ca.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f9/f9f/f9fb3cc15cceae6406903c92415df6ca.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;иначе &lt;img class=&#34;formula inline&#34; source=&#34;x_i \leftarrow 0&#34; alt=&#34;x_i \leftarrow 0&#34; src=https://habrastorage.org/getpro/habr/formulas/5/56/56c/56cd40a2c2a85c552b4bb67619a808c5.svg width=48 height=16 data-width=6.684 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/56/56c/56cd40a2c2a85c552b4bb67619a808c5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/56/56c/56cd40a2c2a85c552b4bb67619a808c5.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;i \leftarrow i-1&#34; alt=&#34;i \leftarrow i-1&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9abddbe30a4ace8a9169b8ef8d4f5f5.svg width=64 height=16 data-width=8.977 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9abddbe30a4ace8a9169b8ef8d4f5f5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9abddbe30a4ace8a9169b8ef8d4f5f5.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;вернуть &lt;img class=&#34;formula inline&#34; source=\vec{x} alt=\vec{x} src=https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg width=12 height=16 data-width=1.294 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b0/b07/b07b5abd67ee0b72f4136c82c68a0c48.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;p&gt;Также, не являются надежными рюкзаки с низкой &lt;em&gt;плотностью&lt;/em&gt;, они подвержены ряду атак (&amp;#34;low-density&amp;#34; attack).&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;J. C. Lagarias and A. M. Odlyzko. Solving Low-Density Subset Sum Problems. Journal of the Association for Computing Machinery. January 1985. Vol. 32, № 1, pp. 229-246.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;&lt;em&gt;Плотность&lt;/em&gt; рюкзака определяется как отношение количества элементов в нем к размеру в битах его элементов (или размеру максимального элемента):&lt;/p&gt;&lt;img class=formula source=&#34;d(A) = \frac{n}{ log_2(max A) }&#34; alt=&#34;d(A) = \frac{n}{ log_2(max A) }&#34; src=https://habrastorage.org/getpro/habr/formulas/7/70/70b/70b0e85c94615df6a11dabb56a112b52.svg width=160 height=32 data-width=20.419 data-height=4.701 data-vertical-align=-1.785 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/70/70b/70b0e85c94615df6a11dabb56a112b52.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/70/70b/70b0e85c94615df6a11dabb56a112b52.svg 781w&#34; loading=lazy decode=async&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Для сверхрастущего вектора &lt;img class=&#34;formula inline&#34; source=&#34;A = (1, 2, 4, 8, 16, 32)&#34; alt=&#34;A = (1, 2, 4, 8, 16, 32)&#34; src=https://habrastorage.org/getpro/habr/formulas/f/fa/faa/faab2144156303d7e23c6bc588a3fc52.svg width=160 height=16 data-width=20.554 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/fa/faa/faab2144156303d7e23c6bc588a3fc52.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/fa/faa/faab2144156303d7e23c6bc588a3fc52.svg 781w&#34; loading=lazy decode=async&gt; &lt;img class=&#34;formula inline&#34; source=&#34;d(A) = 6/5&#34; alt=&#34;d(A) = 6/5&#34; src=https://habrastorage.org/getpro/habr/formulas/b/bf/bfc/bfc4a5f1a6ab85dd13aa1b2e99d85aaa.svg width=88 height=16 data-width=11.044 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/bf/bfc/bfc4a5f1a6ab85dd13aa1b2e99d85aaa.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/bf/bfc/bfc4a5f1a6ab85dd13aa1b2e99d85aaa.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/div&gt;&lt;/details&gt;&lt;h2&gt;Рюкзачная криптосистема Шора-Ривеста&lt;/h2&gt;&lt;a class=anchor id=chor-rivest&gt;&lt;/a&gt;&lt;p&gt;Существуют различные варианты криптосистем на основе задачи об укладке рюкзака. Впервые система шифрования на основе этой задачи была предложена в 1978 году Ральфом Мерклом и Мартином Хеллманом. Однако некоторые варианты этой криптосистемы были взломаны. Позднее была предложена рюкзачная криптосистема Шора-Ривеста, которая будет рассмотрена далее.&lt;p&gt;В общем случае можно выделить основные принципы построения криптосистемы с открытым ключом на основе задачи об укладке рюкзака:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Составляется трудная задача &lt;img class=&#34;formula inline&#34; source=T alt=T src=https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg width=12 height=12 data-width=1.593 data-height=1.532 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg 781w&#34; loading=lazy decode=async&gt;, нерешаемая за полиномиальное время.&lt;li&gt;&lt;p&gt;Из &lt;img class=&#34;formula inline&#34; source=T alt=T src=https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg width=12 height=12 data-width=1.593 data-height=1.532 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b9/b9e/b9ece18c950afbfa6b0fdbfa4ff731d3.svg 781w&#34; loading=lazy decode=async&gt; выделяется легкая задача &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt;, которую можно решить за полиномиальное время или даже быстрее.&lt;li&gt;&lt;p&gt;С помощью некоторых преобразований легкая задача &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt; превращается в трудную &lt;img class=&#34;formula inline&#34; source=T_{hard} alt=T_{hard} src=https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg width=32 height=12 data-width=4.83 data-height=1.889 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 781w&#34; loading=lazy decode=async&gt;, не имеющую никакого сходства с &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt;, при этом процедура получения &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt; из &lt;img class=&#34;formula inline&#34; source=T_{hard} alt=T_{hard} src=https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg width=32 height=12 data-width=4.83 data-height=1.889 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 781w&#34; loading=lazy decode=async&gt; держится в секрете.&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=T_{hard} alt=T_{hard} src=https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg width=32 height=12 data-width=4.83 data-height=1.889 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 781w&#34; loading=lazy decode=async&gt; используется для конструирования открытой функции зашифрования, а &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt; - для конструирования закрытой функции расшифрования. Таким образом для злоумышленника процедура дешифрования будет заключаться в решении &lt;img class=&#34;formula inline&#34; source=T_{hard} alt=T_{hard} src=https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg width=32 height=12 data-width=4.83 data-height=1.889 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2e/2ee/2ee26b5623ca99b0d66052079e4c2fc5.svg 781w&#34; loading=lazy decode=async&gt;, а для добросовестного пользователя, знающего секрет, расшифрование будет осуществляться посредством решения &lt;img class=&#34;formula inline&#34; source=T_{easy} alt=T_{easy} src=https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg width=32 height=16 data-width=4.635 data-height=2.199 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1a/1ab/1abd68bca31eb63110b21d6d309a545e.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/ol&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Иванов М.А., Михайлов Д.М., Чугунков И.В., Ковалев А.В., Мацук Н.А. Стохастические методы и средства защиты информации в компьютерных системах и сетях. / Под ред. И.Ю. Жукова. – М.: КУДИЦ-ПРЕСС, 2009. c. 131-134.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Среди всех криптосистем с открытым ключом, которые основаны на задаче об укладке рюкзака, система, предложенная Шором и Ривестом, является одной из немногих, которые не были взломаны. Система основана на арифметике в конечных полях, она позволяет контролировать плотность рюкзака через параметры, что делает эту систему устойчивой к известным атакам на рюкзаки низкой плотности. Позднее Альфред Дж. Менезес, Пол С. ван Оршот и Скотт А. Ванстон описали эту криптосистему с некоторыми модификациями, делающими эту криптосистему более удобной в использовании. Далее будет приведено описание криптосистемы Шора-Ривеста с учетом этих модификаций.&lt;details class=spoiler&gt;&lt;summary&gt;Источники&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Chor B., Rivest R. L. A Knapsack-Type Public Key Cryptosystem Based on Arithmetic in Finite Fields. // IEEE Transactions on information theory. 1988. Vol. 34, № 5. pp. 901–909.&lt;li&gt;&lt;p&gt;Alfred J. Menezes, Paul C. van Oorschot, Scott A. Vanstone. Handbook of Applied Cryptography, 1996, pp. 303-305.&lt;/ol&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Для описания работы криптосистемы нам понадобится следующая теорема.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Теорема (&lt;/strong&gt;Bose-Chowla&lt;strong&gt;). &lt;/strong&gt;&lt;em&gt;Для любого простого &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; и натурального &lt;img class=&#34;formula inline&#34; source=&#34;h \geq 2&#34; alt=&#34;h \geq 2&#34; src=https://habrastorage.org/getpro/habr/formulas/4/49/494/49487a6f4eb508ed045eb9300b6e7085.svg width=40 height=16 data-width=5.451 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/49/494/49487a6f4eb508ed045eb9300b6e7085.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/49/494/49487a6f4eb508ed045eb9300b6e7085.svg 781w&#34; loading=lazy decode=async&gt; существует последовательность целых чисел &lt;img class=&#34;formula inline&#34; source=&#34;A = ( a_0, \dots, a_{p-1} )&#34; alt=&#34;A = ( a_0, \dots, a_{p-1} )&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5a/5ad/5adabdc1e6948db389a4e77e409a3997.svg width=136 height=16 data-width=17.933 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5a/5ad/5adabdc1e6948db389a4e77e409a3997.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5a/5ad/5adabdc1e6948db389a4e77e409a3997.svg 781w&#34; loading=lazy decode=async&gt;, удовлетворяющая следующим условиям:&lt;/em&gt;&lt;p&gt;&lt;em&gt;(1)&lt;/em&gt;&lt;/blockquote&gt;&lt;img class=formula source=&#34;1 \leq  a_i \leq p^h - 1, \: i = 0, \dots, p-1&#34; alt=&#34;1 \leq  a_i \leq p^h - 1, \: i = 0, \dots, p-1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/99/99c/99c8508e1841bb03eabd93edbaf875ec.svg width=248 height=16 data-width=31.759 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/99/99c/99c8508e1841bb03eabd93edbaf875ec.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/99/99c/99c8508e1841bb03eabd93edbaf875ec.svg 781w&#34; loading=lazy decode=async&gt;&lt;blockquote&gt;&lt;p&gt;(2) если &lt;img class=&#34;formula inline&#34; source=&#34;(x_0, x_1, \dots, x_{p-1})&#34; alt=&#34;(x_0, x_1, \dots, x_{p-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/3/30/304/3040fa4e5c95b6093cf5790f1c9dd5f1.svg width=128 height=16 data-width=16.702 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/30/304/3040fa4e5c95b6093cf5790f1c9dd5f1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/30/304/3040fa4e5c95b6093cf5790f1c9dd5f1.svg 781w&#34; loading=lazy decode=async&gt; и &lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;(y_0, y_1, \dots, y_{p-1})&#34; alt=&#34;(y_0, y_1, \dots, y_{p-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/d/dd/dd3/dd38e6b0227e89f2893f01447e03fd10.svg width=128 height=16 data-width=16.145 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/dd/dd3/dd38e6b0227e89f2893f01447e03fd10.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/dd/dd3/dd38e6b0227e89f2893f01447e03fd10.svg 781w&#34; loading=lazy decode=async&gt; - два вектора с неотрицательными целыми координатами, удовлетворяющие ограничениям&lt;/em&gt;&lt;/blockquote&gt;&lt;img class=formula source=&#34;(x_0, x_1, \dots, x_{p-1}) \neq (y_0, y_1, \dots, y_{p-1})&#34; alt=&#34;(x_0, x_1, \dots, x_{p-1}) \neq (y_0, y_1, \dots, y_{p-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a56d4a1ac54ebb996f89b6be55b93a76.svg width=280 height=16 data-width=35.864 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a56d4a1ac54ebb996f89b6be55b93a76.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a56d4a1ac54ebb996f89b6be55b93a76.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;\sum_{i=0}^{p-1} x_i \leq h - 1, \sum_{i=0}^{p-1} y_i \leq h - 1 \quad \text{или} \quad \sum_{i=0}^{p-1} x_i = \sum_{i=0}^{p-1} y_i = h&#34; alt=&#34;\sum_{i=0}^{p-1} x_i \leq h - 1, \sum_{i=0}^{p-1} y_i \leq h - 1 \quad \text{или} \quad \sum_{i=0}^{p-1} x_i = \sum_{i=0}^{p-1} y_i = h&#34; src=https://habrastorage.org/getpro/habr/formulas/9/90/90d/90dff0ab53f9166f50bcfcf7b23691be.svg width=448 height=48 data-width=56.093 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/90/90d/90dff0ab53f9166f50bcfcf7b23691be.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/90/90d/90dff0ab53f9166f50bcfcf7b23691be.svg 781w&#34; loading=lazy decode=async&gt;&lt;blockquote&gt;&lt;p&gt;то &lt;img class=&#34;formula inline&#34; source=&#34;\sum_{i=0}^{p-1} x_i a_i \neq \sum_{i=0}^{p-1} y_i a_i&#34; alt=&#34;\sum_{i=0}^{p-1} x_i a_i \neq \sum_{i=0}^{p-1} y_i a_i&#34; src=https://habrastorage.org/getpro/habr/formulas/8/85/855/85561402a83513a76710fa2ab620dd2a.svg width=144 height=48 data-width=18.06 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/85/855/85561402a83513a76710fa2ab620dd2a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/85/855/85561402a83513a76710fa2ab620dd2a.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/blockquote&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Доказательство&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Рассмотрим расширение &lt;img class=&#34;formula inline&#34; source=&#34;GF(p) \subset GF(p^h)&#34; alt=&#34;GF(p) \subset GF(p^h)&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f3/f3e/f3e8918044bc72046fec012b95e7d7dd.svg width=128 height=16 data-width=16.868 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f3/f3e/f3e8918044bc72046fec012b95e7d7dd.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f3/f3e/f3e8918044bc72046fec012b95e7d7dd.svg 781w&#34; loading=lazy decode=async&gt;. Пусть &lt;img class=&#34;formula inline&#34; source=&#34;t \in GF(p^h)&#34; alt=&#34;t \in GF(p^h)&#34; src=https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg width=88 height=16 data-width=11.063 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg 781w&#34; loading=lazy decode=async&gt; - алгебраическое число степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; над полем &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt; (т.е. минимальный многочлен &lt;img class=&#34;formula inline&#34; source=t alt=t src=https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg width=12 height=12 data-width=0.817 data-height=1.441 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 781w&#34; loading=lazy decode=async&gt; из кольца многочленов &lt;img class=&#34;formula inline&#34; source=GF(p)[x] alt=GF(p)[x] src=https://habrastorage.org/getpro/habr/formulas/e/e6/e66/e6678817a1b68568889bf4b86179933b.svg width=64 height=16 data-width=8.923 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e6/e66/e6678817a1b68568889bf4b86179933b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e6/e66/e6678817a1b68568889bf4b86179933b.svg 781w&#34; loading=lazy decode=async&gt; имеет степень &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;), &lt;img class=&#34;formula inline&#34; source=g alt=g src=https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg width=12 height=12 data-width=1.079 data-height=1.464 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 781w&#34; loading=lazy decode=async&gt; - примитивный элемент поля (и, соответственно, генератор мультипликативной группы) &lt;img class=&#34;formula inline&#34; source=GF(p^h) alt=GF(p^h) src=https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg width=56 height=16 data-width=7.48 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 781w&#34; loading=lazy decode=async&gt;. Рассмотрим аддитивный сдвиг основного поля &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt; на элемент &lt;img class=&#34;formula inline&#34; source=t alt=t src=https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg width=12 height=12 data-width=0.817 data-height=1.441 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 781w&#34; loading=lazy decode=async&gt;:&lt;/p&gt;&lt;img class=formula source=&#34;t + GF(p) = \{ t + \alpha_i | \alpha_i \in GF(p) \} \subset GF(p^h)&#34; alt=&#34;t + GF(p) = \{ t + \alpha_i | \alpha_i \in GF(p) \} \subset GF(p^h)&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cd/cd9/cd9df787dee74c4224e0615161146721.svg width=344 height=16 data-width=43.454 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cd/cd9/cd9df787dee74c4224e0615161146721.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cd/cd9/cd9df787dee74c4224e0615161146721.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Пусть &lt;img class=&#34;formula inline&#34; source=&#34;a_i = log_g (t + \alpha_i), \alpha_i \in GF(p)&#34; alt=&#34;a_i = log_g (t + \alpha_i), \alpha_i \in GF(p)&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9a243788153847cec5b6f3b8396f0ea.svg width=224 height=16 data-width=28.616 data-height=2.364 data-vertical-align=-0.616 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9a243788153847cec5b6f3b8396f0ea.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a9/a9a/a9a243788153847cec5b6f3b8396f0ea.svg 781w&#34; loading=lazy decode=async&gt;- дискретный логарифм элемента &lt;img class=&#34;formula inline&#34; source=&#34;t + \alpha_i&#34; alt=&#34;t + \alpha_i&#34; src=https://habrastorage.org/getpro/habr/formulas/7/70/700/7007982e94803d14695c48ed98c14f8c.svg width=40 height=16 data-width=5.77 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/70/700/7007982e94803d14695c48ed98c14f8c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/70/700/7007982e94803d14695c48ed98c14f8c.svg 781w&#34; loading=lazy decode=async&gt;по основанию &lt;img class=&#34;formula inline&#34; source=g alt=g src=https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg width=12 height=12 data-width=1.079 data-height=1.464 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 781w&#34; loading=lazy decode=async&gt; в поле &lt;img class=&#34;formula inline&#34; source=GF(p^h) alt=GF(p^h) src=https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg width=56 height=16 data-width=7.48 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 781w&#34; loading=lazy decode=async&gt;. Тогда все &lt;img class=&#34;formula inline&#34; source=a_i alt=a_i src=https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg width=12 height=12 data-width=1.937 data-height=1.355 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 781w&#34; loading=lazy decode=async&gt;лежат в интервале &lt;img class=&#34;formula inline&#34; source=&#34;[1, p^h - 1]&#34; alt=&#34;[1, p^h - 1]&#34; src=https://habrastorage.org/getpro/habr/formulas/3/3d/3de/3dec16bf1035a727bde4e4165661d041.svg width=72 height=16 data-width=9.539 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3d/3de/3dec16bf1035a727bde4e4165661d041.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3d/3de/3dec16bf1035a727bde4e4165661d041.svg 781w&#34; loading=lazy decode=async&gt; (т.к. &lt;img class=&#34;formula inline&#34; source=&#34;GF(p^h)^* = \{ g^n | 1 \leq n \leq p^h - 1 \}, p^h - 1 \equiv 0 \: (\textrm{mod} \: p^h - 1)&#34; alt=&#34;GF(p^h)^* = \{ g^n | 1 \leq n \leq p^h - 1 \}, p^h - 1 \equiv 0 \: (\textrm{mod} \: p^h - 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/1/12/12a/12aea168df1af40f4ecb50ccdba18091.svg width=440 height=16 data-width=55.752 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/12/12a/12aea168df1af40f4ecb50ccdba18091.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/12/12a/12aea168df1af40f4ecb50ccdba18091.svg 781w&#34; loading=lazy decode=async&gt;), т.е. удовлетворяют первому условию теоремы. Проверим, что все &lt;img class=&#34;formula inline&#34; source=a_i alt=a_i src=https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg width=12 height=12 data-width=1.937 data-height=1.355 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 781w&#34; loading=lazy decode=async&gt; также удовлетворяют и второму условию. Рассмотрим два вектора &lt;img class=&#34;formula inline&#34; source=&#34;\vec{x}, \vec{y}&#34; alt=&#34;\vec{x}, \vec{y}&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b3/b3c/b3cbba34886af60f53946a216c584ef1.svg width=24 height=16 data-width=3.409 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b3/b3c/b3cbba34886af60f53946a216c584ef1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b3/b3c/b3cbba34886af60f53946a216c584ef1.svg 781w&#34; loading=lazy decode=async&gt; с неотрицательными целыми координатами, удовлетворяющие ограничениям (1) и (2), и пусть&lt;/p&gt;&lt;img class=formula source=&#34;\sum_{i=0}^{p-1} x_i a_i = \sum_{i=0}^{p-1} y_i a_i&#34; alt=&#34;\sum_{i=0}^{p-1} x_i a_i = \sum_{i=0}^{p-1} y_i a_i&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9a/9a7/9a7d4f895b2fd1d00e57ae08342a00c8.svg width=144 height=48 data-width=18.06 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9a/9a7/9a7d4f895b2fd1d00e57ae08342a00c8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9a/9a7/9a7d4f895b2fd1d00e57ae08342a00c8.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Тогда выполняется следующее равенство:&lt;/p&gt;&lt;img class=formula source=&#34;g^{ \sum_{i=0}^{p-1} x_i a_i } =  g^{ \sum_{i=0}^{p-1} y_i a_i }&#34; alt=&#34;g^{ \sum_{i=0}^{p-1} x_i a_i } =  g^{ \sum_{i=0}^{p-1} y_i a_i }&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ec/ecb/ecbc54af160367c8096b7fb28a7f6a24.svg width=152 height=24 data-width=19.242 data-height=3.039 data-vertical-align=-0.954 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ec/ecb/ecbc54af160367c8096b7fb28a7f6a24.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ec/ecb/ecbc54af160367c8096b7fb28a7f6a24.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;и следовательно&lt;/p&gt;&lt;img class=formula source=&#34;\prod_{i=0}^{p-1} (g^{a_i})^{x_i} = \prod_{i=0}^{p-1} (g^{a_i})^{y_i}&#34; alt=&#34;\prod_{i=0}^{p-1} (g^{a_i})^{x_i} = \prod_{i=0}^{p-1} (g^{a_i})^{y_i}&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f2/f27/f271d171b709d074d4ed5e452c57be93.svg width=160 height=48 data-width=20.714 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f2/f27/f271d171b709d074d4ed5e452c57be93.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f2/f27/f271d171b709d074d4ed5e452c57be93.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Подставляя &lt;img class=&#34;formula inline&#34; source=&#34;g^{a_i} = t + \alpha_i&#34; alt=&#34;g^{a_i} = t + \alpha_i&#34; src=https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc48be20ff12ef65efaa12548f64a40.svg width=88 height=16 data-width=11.424 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc48be20ff12ef65efaa12548f64a40.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc48be20ff12ef65efaa12548f64a40.svg 781w&#34; loading=lazy decode=async&gt;, получим&lt;/p&gt;&lt;img class=formula source=&#34;(t + \alpha_1)^{x_1} (t + \alpha_2)^{x_2} \dots (t + \alpha_{p-1})^{x_{p-1}} = (t + \alpha_1)^{y_1} (t + \alpha_2)^{y_2} \dots (t + \alpha_{p-1})^{y_{p-1}}&#34; alt=&#34;(t + \alpha_1)^{x_1} (t + \alpha_2)^{x_2} \dots (t + \alpha_{p-1})^{x_{p-1}} = (t + \alpha_1)^{y_1} (t + \alpha_2)^{y_2} \dots (t + \alpha_{p-1})^{y_{p-1}}&#34; src=https://habrastorage.org/getpro/habr/formulas/2/2d/2da/2daa1d1d055e9b19127dd2c8f72a7d82.svg width=584 height=16 data-width=73.909 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2d/2da/2daa1d1d055e9b19127dd2c8f72a7d82.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2d/2da/2daa1d1d055e9b19127dd2c8f72a7d82.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Обе части последнего равенства - различные (по условию (1)) приведенные многочлены, степени которых либо совпадают и равны &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;, либо меньше &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; (по условию (2)), поэтому, вычитая их, мы получим ненулевой многочлен степени &lt;em&gt;меньше&lt;/em&gt; &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; с коэффициентами в &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;, корнем которого является &lt;img class=&#34;formula inline&#34; source=t alt=t src=https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg width=12 height=12 data-width=0.817 data-height=1.441 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 781w&#34; loading=lazy decode=async&gt;. Это противоречит тому факту, что &lt;img class=&#34;formula inline&#34; source=t alt=t src=https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg width=12 height=12 data-width=0.817 data-height=1.441 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e3/e35/e358efa489f58062f10dd7316b65649e.svg 781w&#34; loading=lazy decode=async&gt; является алгебраическим числом степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; над полем &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;.&lt;details class=spoiler&gt;&lt;summary&gt;Замечание 1.&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Из доказательства видно, что теорема выполняется не только в целых числах, но и по модулю &lt;img class=&#34;formula inline&#34; source=&#34;p^h - 1&#34; alt=&#34;p^h - 1&#34; src=https://habrastorage.org/getpro/habr/formulas/7/79/793/793edbea3fc12e0ebc67a8b03ef52729.svg width=48 height=16 data-width=6.144 data-height=2.484 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/79/793/793edbea3fc12e0ebc67a8b03ef52729.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/79/793/793edbea3fc12e0ebc67a8b03ef52729.svg 781w&#34; loading=lazy decode=async&gt; (т.к. оно основано на свойствах мультипликативной группы &lt;img class=&#34;formula inline&#34; source=&#34;GF(p^h)^*, |GF(p^h)^*| = p^h - 1&#34; alt=&#34;GF(p^h)^*, |GF(p^h)^*| = p^h - 1&#34; src=https://habrastorage.org/getpro/habr/formulas/f/fd/fde/fded3599904295ddc7334ca7a3e8db70.svg width=224 height=16 data-width=28.361 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/fd/fde/fded3599904295ddc7334ca7a3e8db70.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/fd/fde/fded3599904295ddc7334ca7a3e8db70.svg 781w&#34; loading=lazy decode=async&gt;).&lt;/div&gt;&lt;/details&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Замечание 2.&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;В формулировке и доказательстве теоремы требование простоты &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; может быть заменено на требование: &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; - степень простого числа, при этом никаких изменений в формулировке или доказательстве не потребует&lt;/div&gt;&lt;/details&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;&lt;strong&gt;Генерация параметров криптосистемы:&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Выбрать конечное поле &lt;img class=&#34;formula inline&#34; source=GF(p^h) alt=GF(p^h) src=https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg width=56 height=16 data-width=7.48 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 781w&#34; loading=lazy decode=async&gt;, где &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; - степень простого числа, &lt;img class=&#34;formula inline&#34; source=&#34;h \leq p&#34; alt=&#34;h \leq p&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b5/b50/b50e78ede2b09bc8744862ce2f04b537.svg width=40 height=16 data-width=5.458 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b5/b50/b50e78ede2b09bc8744862ce2f04b537.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b5/b50/b50e78ede2b09bc8744862ce2f04b537.svg 781w&#34; loading=lazy decode=async&gt;, в котором можно эффективно решать задачу дискретного логарифмирования.&lt;li&gt;&lt;p&gt;Выбрать случайный элемент &lt;img class=&#34;formula inline&#34; source=&#34;t \in GF(p^h)&#34; alt=&#34;t \in GF(p^h)&#34; src=https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg width=88 height=16 data-width=11.063 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/42/425/425f00f41a0fdc42ec5043948981d4cf.svg 781w&#34; loading=lazy decode=async&gt;, являющийся алгебраическим числом степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; над &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;. Для этого необходимо выбрать случайный неприводимый нормированный (старший коэффициент равен единице) многочлен степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; в кольце многочленов &lt;img class=&#34;formula inline&#34; source=GF(p)[t] alt=GF(p)[t] src=https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg width=64 height=16 data-width=8.446 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg 781w&#34; loading=lazy decode=async&gt; и представить поле &lt;img class=&#34;formula inline&#34; source=GF(p^h) alt=GF(p^h) src=https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg width=56 height=16 data-width=7.48 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 781w&#34; loading=lazy decode=async&gt; как &lt;img class=&#34;formula inline&#34; source=&#34;GF(p)[t] / \langle f(t) \rangle&#34; alt=&#34;GF(p)[t] / \langle f(t) \rangle&#34; src=https://habrastorage.org/getpro/habr/formulas/0/01/018/018b6dd4df3475832f9997035a998834.svg width=120 height=16 data-width=15.158 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/01/018/018b6dd4df3475832f9997035a998834.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/01/018/018b6dd4df3475832f9997035a998834.svg 781w&#34; loading=lazy decode=async&gt; (т.е. элементы поля &lt;img class=&#34;formula inline&#34; source=GF(p^h) alt=GF(p^h) src=https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg width=56 height=16 data-width=7.48 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d88/d88ea2d195754f70d90da5d9e209afb2.svg 781w&#34; loading=lazy decode=async&gt; - многочлены степени не больше &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; с коэффициентами в &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;, арифметические операции над которыми осуществляются по модулю &lt;img class=&#34;formula inline&#34; source=f(t) alt=f(t) src=https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg width=24 height=16 data-width=3.821 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 781w&#34; loading=lazy decode=async&gt;).&lt;li&gt;&lt;p&gt;Выбрать случайный примитивный элемент поля &lt;img class=&#34;formula inline&#34; source=&#34;g \in GF(p^h)&#34; alt=&#34;g \in GF(p^h)&#34; src=https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc69f8396b9a52df89704dd8ece50bc.svg width=88 height=16 data-width=11.325 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc69f8396b9a52df89704dd8ece50bc.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/ad/adc/adc69f8396b9a52df89704dd8ece50bc.svg 781w&#34; loading=lazy decode=async&gt; (т.е. &lt;img class=&#34;formula inline&#34; source=g alt=g src=https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg width=12 height=12 data-width=1.079 data-height=1.464 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b2/b2f/b2f5ff47436671b6e533d8dc3614845d.svg 781w&#34; loading=lazy decode=async&gt; - генератор мультипликативной группы &lt;img class=&#34;formula inline&#34; source=GF(p^h)^* alt=GF(p^h)^* src=https://habrastorage.org/getpro/habr/formulas/d/d5/d5a/d5adb9e9ddfccde7f110151f988116cf.svg width=64 height=16 data-width=8.468 data-height=2.61 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d5/d5a/d5adb9e9ddfccde7f110151f988116cf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d5/d5a/d5adb9e9ddfccde7f110151f988116cf.svg 781w&#34; loading=lazy decode=async&gt;).&lt;li&gt;&lt;p&gt;В соответствии с &lt;em&gt;Теоремой Bose-Chowla&lt;/em&gt; вычислить дискретные логарифмы &lt;img class=&#34;formula inline&#34; source=&#34;a_i = log_g (t + \alpha_i)&#34; alt=&#34;a_i = log_g (t + \alpha_i)&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9d/9df/9dfb6a3b14c1b8b5e52724c9cd83226d.svg width=128 height=16 data-width=16.286 data-height=2.364 data-vertical-align=-0.616 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9df/9dfb6a3b14c1b8b5e52724c9cd83226d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9df/9dfb6a3b14c1b8b5e52724c9cd83226d.svg 781w&#34; loading=lazy decode=async&gt; для всех &lt;img class=&#34;formula inline&#34; source=&#34;\alpha_i \in GF(p)&#34; alt=&#34;\alpha_i \in GF(p)&#34; src=https://habrastorage.org/getpro/habr/formulas/7/70/702/7025e923bafce7666e2194eac56f3c9e.svg width=88 height=16 data-width=11.325 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/70/702/7025e923bafce7666e2194eac56f3c9e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/70/702/7025e923bafce7666e2194eac56f3c9e.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Выбрать случайную перестановку &lt;img class=&#34;formula inline&#34; source=&#34;\pi: \{ 0, 1, \dots, p-1 \} \rightarrow \{ 0, 1, \dots, p-1 \}&#34; alt=&#34;\pi: \{ 0, 1, \dots, p-1 \} \rightarrow \{ 0, 1, \dots, p-1 \}&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cf/cf5/cf5d5e00e0f260b12e98cc9ca1cecd17.svg width=296 height=16 data-width=37.908 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cf/cf5/cf5d5e00e0f260b12e98cc9ca1cecd17.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cf/cf5/cf5d5e00e0f260b12e98cc9ca1cecd17.svg 781w&#34; loading=lazy decode=async&gt; и перемешать &lt;img class=&#34;formula inline&#34; source=a_i alt=a_i src=https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg width=12 height=12 data-width=1.937 data-height=1.355 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2ae/2aecb1dc57e87620a373d19b0a889efb.svg 781w&#34; loading=lazy decode=async&gt;: &lt;img class=&#34;formula inline&#34; source=&#34;b_i = a_{\pi(i)}&#34; alt=&#34;b_i = a_{\pi(i)}&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8c/8cf/8cf31d0340feea4b64fd95e1febdb175.svg width=64 height=16 data-width=8.82 data-height=2.497 data-vertical-align=-0.683 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8c/8cf/8cf31d0340feea4b64fd95e1febdb175.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8c/8cf/8cf31d0340feea4b64fd95e1febdb175.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Выбрать случайное число &lt;img class=&#34;formula inline&#34; source=&#34;d, 0 \leq d \leq p^h - 2&#34; alt=&#34;d, 0 \leq d \leq p^h - 2&#34; src=https://habrastorage.org/getpro/habr/formulas/3/3b/3b4/3b42665a249be4ba744df810fd140e58.svg width=128 height=16 data-width=16.669 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3b/3b4/3b42665a249be4ba744df810fd140e58.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3b/3b4/3b42665a249be4ba744df810fd140e58.svg 781w&#34; loading=lazy decode=async&gt; и добавить шум: &lt;img class=&#34;formula inline&#34; source=&#34;c_i = b_i + d \: (\textrm{mod} \: p^h - 1), 0 \leq i \leq p - 1&#34; alt=&#34;c_i = b_i + d \: (\textrm{mod} \: p^h - 1), 0 \leq i \leq p - 1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a002046f1075d0e2cf1d1f8a55e399d.svg width=296 height=16 data-width=37.559 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a002046f1075d0e2cf1d1f8a55e399d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a002046f1075d0e2cf1d1f8a55e399d.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/ol&gt;&lt;p&gt;Открытым (публичным) ключом является &lt;img class=&#34;formula inline&#34; source=&#34;((c_0, c_1, \dots, c_{p-1}), p, h)&#34; alt=&#34;((c_0, c_1, \dots, c_{p-1}), p, h)&#34; src=https://habrastorage.org/getpro/habr/formulas/5/54/549/549556546ec0b72a859ce955ee9d2d2d.svg width=168 height=16 data-width=21.972 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/54/549/549556546ec0b72a859ce955ee9d2d2d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/54/549/549556546ec0b72a859ce955ee9d2d2d.svg 781w&#34; loading=lazy decode=async&gt;, закрытым (секретным) ключом - &lt;img class=&#34;formula inline&#34; source=&#34;(f(t), g, \pi^{-1}, d)&#34; alt=&#34;(f(t), g, \pi^{-1}, d)&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0d/0d0/0d0ef70161ef74f019fce121cad008e8.svg width=112 height=16 data-width=14.377 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0d/0d0/0d0ef70161ef74f019fce121cad008e8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0d/0d0/0d0ef70161ef74f019fce121cad008e8.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;&lt;strong&gt;Шифрование:&lt;/strong&gt;&lt;p&gt;Чтобы зашифровать бинарное сообщение &lt;img class=&#34;formula inline&#34; source=&#34;M = (x_0, x_1, \dots, x_{p-1})&#34; alt=&#34;M = (x_0, x_1, \dots, x_{p-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/d/df/df6/df6d95f72d0df48d7a62aa69cd882769.svg width=176 height=16 data-width=22.097 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/df/df6/df6d95f72d0df48d7a62aa69cd882769.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/df/df6/df6d95f72d0df48d7a62aa69cd882769.svg 781w&#34; loading=lazy decode=async&gt; длины &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; и веса (количество 1) в точности &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;, необходимо сложить &lt;img class=&#34;formula inline&#34; source=c_i alt=c_i src=https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg width=12 height=12 data-width=1.719 data-height=1.357 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg 781w&#34; loading=lazy decode=async&gt;, которые соответствуют битам, равным 1:&lt;/p&gt;&lt;img class=formula source=&#34;E(M) = \sum_{i=0}^{p-1} x_i c_i \: (\textrm{mod} \: p^h - 1)&#34; alt=&#34;E(M) = \sum_{i=0}^{p-1} x_i c_i \: (\textrm{mod} \: p^h - 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/6/61/613/613bf349017c4c188b7ecd6b2af3930d.svg width=232 height=48 data-width=29.463 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/61/613/613bf349017c4c188b7ecd6b2af3930d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/61/613/613bf349017c4c188b7ecd6b2af3930d.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;&lt;strong&gt;Расшифрование:&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Пусть &lt;img class=&#34;formula inline&#34; source=&#34;c = E(M)&#34; alt=&#34;c = E(M)&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a7/a7d/a7d59b725184fa4900148af878e0b526.svg width=72 height=16 data-width=9.863 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a7/a7d/a7d59b725184fa4900148af878e0b526.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a7/a7d/a7d59b725184fa4900148af878e0b526.svg 781w&#34; loading=lazy decode=async&gt; - зашифрованное сообщение, вычислить &lt;img class=&#34;formula inline&#34; source=&#34;c&#39; = c - hd \: (\textrm{mod} \: p^h-1)&#34; alt=&#34;c&#39; = c - hd \: (\textrm{mod} \: p^h-1)&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e9/e99/e9937349889886537dee6762997e1581.svg width=192 height=16 data-width=24.032 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e9/e99/e9937349889886537dee6762997e1581.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e9/e99/e9937349889886537dee6762997e1581.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Вычислить &lt;img class=&#34;formula inline&#34; source=&#34;u(t) = g^{c&#39;} \: (\textrm{mod} \: f(t))&#34; alt=&#34;u(t) = g^{c&#39;} \: (\textrm{mod} \: f(t))&#34; src=https://habrastorage.org/getpro/habr/formulas/3/3c/3ce/3ceb407f8a686b95fbc9ad3f4ede20c5.svg width=160 height=16 data-width=20.151 data-height=2.714 data-vertical-align=-0.791 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3c/3ce/3ceb407f8a686b95fbc9ad3f4ede20c5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3c/3ce/3ceb407f8a686b95fbc9ad3f4ede20c5.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Вычислить &lt;img class=&#34;formula inline&#34; source=&#34;s(t) = u(t) + f(t)&#34; alt=&#34;s(t) = u(t) + f(t)&#34; src=https://habrastorage.org/getpro/habr/formulas/f/fb/fbc/fbc428c26c16a511b87a27e1622b0fe8.svg width=136 height=16 data-width=17.113 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/fb/fbc/fbc428c26c16a511b87a27e1622b0fe8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/fb/fbc/fbc428c26c16a511b87a27e1622b0fe8.svg 781w&#34; loading=lazy decode=async&gt; - нормированный многочлен степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; в &lt;img class=&#34;formula inline&#34; source=GF(p)[t] alt=GF(p)[t] src=https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg width=64 height=16 data-width=8.446 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/92/925/9257c7ce42214cfd1f14370a6d7ab11e.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Разложить &lt;img class=&#34;formula inline&#34; source=s(t) alt=s(t) src=https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg width=24 height=16 data-width=3.638 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 781w&#34; loading=lazy decode=async&gt; на линейные множители над &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;: &lt;img class=&#34;formula inline&#34; source=&#34;s(t) = (t + \alpha_1) (t + \alpha_2) \dots (t + \alpha_h)&#34; alt=&#34;s(t) = (t + \alpha_1) (t + \alpha_2) \dots (t + \alpha_h)&#34; src=https://habrastorage.org/getpro/habr/formulas/a/ac/acd/acdcc5847cbd7e30b1b0a7d9a2564a44.svg width=264 height=16 data-width=33.517 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/ac/acd/acdcc5847cbd7e30b1b0a7d9a2564a44.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/ac/acd/acdcc5847cbd7e30b1b0a7d9a2564a44.svg 781w&#34; loading=lazy decode=async&gt;. Все &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; корней этого многочлена могут быть найдены последовательной подстановкой элементов &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;. Таким образом мы найдем &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; корней &lt;img class=&#34;formula inline&#34; source=&#34;\alpha_i \in GF(p), 1 \leq i \leq h&#34; alt=&#34;\alpha_i \in GF(p), 1 \leq i \leq h&#34; src=https://habrastorage.org/getpro/habr/formulas/4/44/446/4465309567140dec9908b9c7206868ab.svg width=168 height=16 data-width=21.58 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/44/446/4465309567140dec9908b9c7206868ab.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/44/446/4465309567140dec9908b9c7206868ab.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Применить обратную перестановку &lt;img class=&#34;formula inline&#34; source=\pi^{-1} alt=\pi^{-1} src=https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg width=24 height=16 data-width=3.522 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg 781w&#34; loading=lazy decode=async&gt; к полученным корням. Получим &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; индексов &lt;img class=&#34;formula inline&#34; source=&#34;\pi^{-1}(\alpha_i), 1 \leq i \leq h&#34; alt=&#34;\pi^{-1}(\alpha_i), 1 \leq i \leq h&#34; src=https://habrastorage.org/getpro/habr/formulas/3/3f/3f6/3f6a2ed15a722a1cbc3baac4a08c9460.svg width=136 height=16 data-width=17.725 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3f/3f6/3f6a2ed15a722a1cbc3baac4a08c9460.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3f/3f6/3f6a2ed15a722a1cbc3baac4a08c9460.svg 781w&#34; loading=lazy decode=async&gt;, на месте которых в сообщении &lt;img class=&#34;formula inline&#34; source=&#34;M = (x_0, \dots, x_{p-1})&#34; alt=&#34;M = (x_0, \dots, x_{p-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/2/2f/2f2/2f287ae0457b2ae4efd2b96e1d36b48b.svg width=144 height=16 data-width=18.809 data-height=2.347 data-vertical-align=-0.608 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2f/2f2/2f287ae0457b2ae4efd2b96e1d36b48b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2f/2f2/2f287ae0457b2ae4efd2b96e1d36b48b.svg 781w&#34; loading=lazy decode=async&gt; будут стоять 1, остальные &lt;img class=&#34;formula inline&#34; source=x_i alt=x_i src=https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg width=16 height=12 data-width=2.034 data-height=1.357 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1b/1ba/1ba8aaab47179b3d3e24b0ccea9f4e30.svg 781w&#34; loading=lazy decode=async&gt; будут равняться 0.&lt;/ol&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Доказательство&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;img class=formula source=&#34;u(t) = g(t)^{c&#39;} \: (\textrm{mod} \: f(t)) = g(t)^{c - hd} \: (\textrm{mod} \: f(t)) =g(t)^{\sum_{i=0}^{p-1} x_i c_i - hd} \: (\textrm{mod} \: f(t)) =&#34; alt=&#34;u(t) = g(t)^{c&#39;} \: (\textrm{mod} \: f(t)) = g(t)^{c - hd} \: (\textrm{mod} \: f(t)) =g(t)^{\sum_{i=0}^{p-1} x_i c_i - hd} \: (\textrm{mod} \: f(t)) =&#34; src=https://habrastorage.org/getpro/habr/formulas/0/08/08e/08e22d30b453c1748830e6b89002f102.svg width=592 height=24 data-width=74.005 data-height=3.039 data-vertical-align=-0.954 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/08/08e/08e22d30b453c1748830e6b89002f102.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/08/08e/08e22d30b453c1748830e6b89002f102.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;g(t)^{\sum_{i=0}^{p-1} x_i (a_{\pi(i)} + d) - hd} \: (\textrm{mod} \: f(t)) = g(t)^{\sum_{i=0}^{p-1} x_i a_{\pi(i)} + \sum_{i=0}^{p-1} x_i d - hd} \: (\textrm{mod} \: f(t)) =&#34; alt=&#34;g(t)^{\sum_{i=0}^{p-1} x_i (a_{\pi(i)} + d) - hd} \: (\textrm{mod} \: f(t)) = g(t)^{\sum_{i=0}^{p-1} x_i a_{\pi(i)} + \sum_{i=0}^{p-1} x_i d - hd} \: (\textrm{mod} \: f(t)) =&#34; src=https://habrastorage.org/getpro/habr/formulas/4/4f/4f7/4f7b8fb1382bd9d3a7f21fdcee0e8d0a.svg width=544 height=24 data-width=68.62 data-height=3.039 data-vertical-align=-0.954 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/4f/4f7/4f7b8fb1382bd9d3a7f21fdcee0e8d0a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/4f/4f7/4f7b8fb1382bd9d3a7f21fdcee0e8d0a.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;g(t)^{\sum_{i=0}^{p-1} x_i a_{\pi(i)}} \: (\textrm{mod} \: f(t)) =\prod_{i=0}^{p-1} (g(t)^{a_{\pi(i)}})^{x_i} \: (\textrm{mod} \: f(t)) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} \: (\textrm{mod} \: f(t))&#34; alt=&#34;g(t)^{\sum_{i=0}^{p-1} x_i a_{\pi(i)}} \: (\textrm{mod} \: f(t)) =\prod_{i=0}^{p-1} (g(t)^{a_{\pi(i)}})^{x_i} \: (\textrm{mod} \: f(t)) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} \: (\textrm{mod} \: f(t))&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b1/0b10fe639e963c26096a99da5ca3fe50.svg width=624 height=48 data-width=78.113 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b1/0b10fe639e963c26096a99da5ca3fe50.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b1/0b10fe639e963c26096a99da5ca3fe50.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Так как &lt;img class=&#34;formula inline&#34; source=&#34;\prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i}&#34; alt=&#34;\prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i}&#34; src=https://habrastorage.org/getpro/habr/formulas/c/ce/ce3/ce307d130adda73a493592c2c7bca4ba.svg width=112 height=48 data-width=14.204 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/ce/ce3/ce307d130adda73a493592c2c7bca4ba.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/ce/ce3/ce307d130adda73a493592c2c7bca4ba.svg 781w&#34; loading=lazy decode=async&gt; и &lt;img class=&#34;formula inline&#34; source=s(t) alt=s(t) src=https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg width=24 height=16 data-width=3.638 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 781w&#34; loading=lazy decode=async&gt; - приведенные многочлены степени &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; и конгруэнтны&lt;p&gt;по модулю &lt;img class=&#34;formula inline&#34; source=f(t) alt=f(t) src=https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg width=24 height=16 data-width=3.821 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 781w&#34; loading=lazy decode=async&gt;, то:&lt;/p&gt;&lt;img class=formula source=&#34;u(t) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} \: (\textrm{mod} \: f(t)) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} - f(t)&#34; alt=&#34;u(t) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} \: (\textrm{mod} \: f(t)) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i} - f(t)&#34; src=https://habrastorage.org/getpro/habr/formulas/0/08/08c/08c1bd5bd43bec14db7456fbd00ade3e.svg width=440 height=48 data-width=55.76 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/08/08c/08c1bd5bd43bec14db7456fbd00ade3e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/08/08c/08c1bd5bd43bec14db7456fbd00ade3e.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;s(t) = u(t) + f(t) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i}&#34; alt=&#34;s(t) = u(t) + f(t) = \prod_{i=0}^{p-1} (t + \alpha_{\pi(i)})^{x_i}&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ec/ec0/ec0e3afcaeec041148218b1cd5d0a3eb.svg width=272 height=48 data-width=34.334 data-height=6.821 data-vertical-align=-2.845 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ec/ec0/ec0e3afcaeec041148218b1cd5d0a3eb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ec/ec0/ec0e3afcaeec041148218b1cd5d0a3eb.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Следовательно, все &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt; корней &lt;img class=&#34;formula inline&#34; source=f(t) alt=f(t) src=https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg width=24 height=16 data-width=3.821 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 781w&#34; loading=lazy decode=async&gt; лежат в &lt;img class=&#34;formula inline&#34; source=GF(p) alt=GF(p) src=https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg width=48 height=16 data-width=6.371 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/13/13d/13d7f9f1f837dd8322d8dc16e9a699c0.svg 781w&#34; loading=lazy decode=async&gt;, и применение к ним обратной перестановки &lt;img class=&#34;formula inline&#34; source=\pi^{-1} alt=\pi^{-1} src=https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg width=24 height=16 data-width=3.522 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/58/58f/58f319ece9aaccf75ceaefe3280bcd9c.svg 781w&#34; loading=lazy decode=async&gt; дает индексы, на месте которых в сообщении &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; стоят 1.&lt;/div&gt;&lt;/details&gt;&lt;h2&gt;Преобразование произвольных битовых строк&lt;/h2&gt;&lt;a class=anchor id=bitstring&gt;&lt;/a&gt;&lt;p&gt;При описании криптосистемы мы предполагали, что сообщение &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; имеет длину &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; и вес &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;. Однако произвольные битовые последовательности не удовлетворяют этому свойству. Далее рассмотрим метод, с помощью которого можно привести произвольную битовую строку к требуемому виду.&lt;details class=spoiler&gt;&lt;summary&gt;Источник&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;T. M. Cover. Enumerative source encoding. // IEEE Transactions on information theory. 1973. Vol. IT-19, pp. 73-77.&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Пусть &lt;img class=&#34;formula inline&#34; source=&#34;\{ 0, 1 \}^n&#34; alt=&#34;\{ 0, 1 \}^n&#34; src=https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg width=48 height=16 data-width=6.679 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg 781w&#34; loading=lazy decode=async&gt; - множество бинарных последовательностей длины &lt;img class=&#34;formula inline&#34; source=n alt=n src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg width=12 height=12 data-width=1.357 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w&#34; loading=lazy decode=async&gt;, &lt;img class=&#34;formula inline&#34; source=&#34;x = (x_1, x_2, \dots, x_n) \in \{ 0, 1 \}^n&#34; alt=&#34;x = (x_1, x_2, \dots, x_n) \in \{ 0, 1 \}^n&#34; src=https://habrastorage.org/getpro/habr/formulas/4/4b/4bc/4bc2b8a43b9c4554f12e7dcbba07a94a.svg width=224 height=16 data-width=28.568 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/4b/4bc/4bc2b8a43b9c4554f12e7dcbba07a94a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/4b/4bc/4bc2b8a43b9c4554f12e7dcbba07a94a.svg 781w&#34; loading=lazy decode=async&gt; - произвольный элемент этого множества, &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt; -  подмножество &lt;img class=&#34;formula inline&#34; source=&#34;\{ 0, 1 \}^n&#34; alt=&#34;\{ 0, 1 \}^n&#34; src=https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg width=48 height=16 data-width=6.679 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/78/78a/78afdad80f44a45efa47cee06041a884.svg 781w&#34; loading=lazy decode=async&gt;. Обозначим через &lt;img class=&#34;formula inline&#34; source=n_S alt=n_S src=https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg width=16 height=12 data-width=2.577 data-height=1.375 data-vertical-align=-0.375 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 781w&#34; loading=lazy decode=async&gt; количество элементов в множестве &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt; и через &lt;img class=&#34;formula inline&#34; source=&#34;n_S(x_1, x_2, \dots, x_k)&#34; alt=&#34;n_S(x_1, x_2, \dots, x_k)&#34; src=https://habrastorage.org/getpro/habr/formulas/9/96/966/9665e210a854f2a6acfc15f50c4894e4.svg width=136 height=16 data-width=17.263 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/96/966/9665e210a854f2a6acfc15f50c4894e4.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/96/966/9665e210a854f2a6acfc15f50c4894e4.svg 781w&#34; loading=lazy decode=async&gt; - количество элементов в множестве &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt;, первые &lt;img class=&#34;formula inline&#34; source=k alt=k src=https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg width=12 height=12 data-width=1.179 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg 781w&#34; loading=lazy decode=async&gt; координат которых равны &lt;img class=&#34;formula inline&#34; source=&#34;(x_1, x_2, \dots, x_k)&#34; alt=&#34;(x_1, x_2, \dots, x_k)&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d0/d0c/d0c849de4f7f218ba5435ef4b96f1f76.svg width=112 height=16 data-width=14.686 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d0/d0c/d0c849de4f7f218ba5435ef4b96f1f76.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d0/d0c/d0c849de4f7f218ba5435ef4b96f1f76.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;Под &lt;em&gt;лексикографическим порядком&lt;/em&gt; будем понимать обычный словарный порядок, при котором &lt;img class=&#34;formula inline&#34; source=&#34;0 &amp;lt; 1&#34; alt=&#34;0 &amp;lt; 1&#34; src=https://habrastorage.org/getpro/habr/formulas/d/df/df2/df2857c0ab501f91c3e1e476f315b6be.svg width=40 height=12 data-width=5.28 data-height=1.597 data-vertical-align=-0.09 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/df/df2/df2857c0ab501f91c3e1e476f315b6be.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/df/df2/df2857c0ab501f91c3e1e476f315b6be.svg 781w&#34; loading=lazy decode=async&gt;, т.е. &lt;img class=&#34;formula inline&#34; source=&#34;x &amp;lt; y&#34; alt=&#34;x &amp;lt; y&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e4/e4c/e4c194ff58ef86bbd5aff91bd3690e9e.svg width=40 height=12 data-width=5.42 data-height=1.686 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e4/e4c/e4c194ff58ef86bbd5aff91bd3690e9e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e4/e4c/e4c194ff58ef86bbd5aff91bd3690e9e.svg 781w&#34; loading=lazy decode=async&gt; если &lt;img class=&#34;formula inline&#34; source=&#34;x_k &amp;lt; y_k&#34; alt=&#34;x_k &amp;lt; y_k&#34; src=https://habrastorage.org/getpro/habr/formulas/7/7f/7f9/7f9ace4d9a6d4e112248bd1703972ea7.svg width=56 height=12 data-width=7.462 data-height=1.686 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7f/7f9/7f9ace4d9a6d4e112248bd1703972ea7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7f/7f9/7f9ace4d9a6d4e112248bd1703972ea7.svg 781w&#34; loading=lazy decode=async&gt; для первого индекса &lt;img class=&#34;formula inline&#34; source=k alt=k src=https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg width=12 height=12 data-width=1.179 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8c/8ce/8ce4b16b22b58894aa86c421e8759df3.svg 781w&#34; loading=lazy decode=async&gt; такого, что &lt;img class=&#34;formula inline&#34; source=&#34;x_k \neq y_k&#34; alt=&#34;x_k \neq y_k&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b6263bf424962efa842e301648ee0b9.svg width=56 height=16 data-width=7.462 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b6263bf424962efa842e301648ee0b9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b6263bf424962efa842e301648ee0b9.svg 781w&#34; loading=lazy decode=async&gt;.&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;00101 &amp;lt; 00110&#34; alt=&#34;00101 &amp;lt; 00110&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a8/a83/a8309ccb36ab8370420c4bbc4c700d38.svg width=112 height=12 data-width=14.329 data-height=1.597 data-vertical-align=-0.09 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a8/a83/a8309ccb36ab8370420c4bbc4c700d38.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a8/a83/a8309ccb36ab8370420c4bbc4c700d38.svg 781w&#34; loading=lazy decode=async&gt;&lt;/div&gt;&lt;/details&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Утверждение 1. &lt;/strong&gt;&lt;em&gt;Лексикографический индекс элемента &lt;img class=&#34;formula inline&#34; source=&#34;x \in S&#34; alt=&#34;x \in S&#34; src=https://habrastorage.org/getpro/habr/formulas/f/fe/feb/feb2d32887357bfaad57fb030f388bb6.svg width=40 height=16 data-width=5.519 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/fe/feb/feb2d32887357bfaad57fb030f388bb6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/fe/feb/feb2d32887357bfaad57fb030f388bb6.svg 781w&#34; loading=lazy decode=async&gt; рассчитывается по формуле&lt;/em&gt;&lt;/blockquote&gt;&lt;img class=formula source=&#34;i_S(x) = \sum_{j=1}^{n} x_j n_S(x_1, x_2, \dots, x_{j-1}, 0)&#34; alt=&#34;i_S(x) = \sum_{j=1}^{n} x_j n_S(x_1, x_2, \dots, x_{j-1}, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/4/40/402/40209b3ecdec38f199f7ffaadb39e5ea.svg width=280 height=48 data-width=35.127 data-height=6.549 data-vertical-align=-2.709 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/40/402/40209b3ecdec38f199f7ffaadb39e5ea.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/40/402/40209b3ecdec38f199f7ffaadb39e5ea.svg 781w&#34; loading=lazy decode=async&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Эта формула определяет лексикографическую биекцию &lt;/em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;S \rightarrow \{ 0, 1, \dots, n_S - 1 \}&#34; alt=&#34;S \rightarrow \{ 0, 1, \dots, n_S - 1 \}&#34; src=https://habrastorage.org/getpro/habr/formulas/b/bc/bcf/bcf4186c21df6379badda546769b87e6.svg width=176 height=16 data-width=22.024 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/bc/bcf/bcf4186c21df6379badda546769b87e6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/bc/bcf/bcf4186c21df6379badda546769b87e6.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/blockquote&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Доказательство&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Слова с префиксом &lt;img class=&#34;formula inline&#34; source=&#34;(x_1, x_2, \dots, x_{j-1}, 0)&#34; alt=&#34;(x_1, x_2, \dots, x_{j-1}, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/0/07/07c/07c2230552f228633b34c9f50a1ec594.svg width=144 height=16 data-width=18.693 data-height=2.363 data-vertical-align=-0.616 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/07/07c/07c2230552f228633b34c9f50a1ec594.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/07/07c/07c2230552f228633b34c9f50a1ec594.svg 781w&#34; loading=lazy decode=async&gt; лексикографически предшествуют словам с префиксом &lt;img class=&#34;formula inline&#34; source=&#34;(x_1, x_2, \dots, x_{j-1}, 1)&#34; alt=&#34;(x_1, x_2, \dots, x_{j-1}, 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/5/50/508/50891eb2e3c0456e1f668b55cadda830.svg width=144 height=16 data-width=18.693 data-height=2.363 data-vertical-align=-0.616 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/50/508/50891eb2e3c0456e1f668b55cadda830.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/50/508/50891eb2e3c0456e1f668b55cadda830.svg 781w&#34; loading=lazy decode=async&gt;. Для каждого &lt;img class=&#34;formula inline&#34; source=j alt=j src=https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg width=12 height=12 data-width=0.932 data-height=1.957 data-vertical-align=-0.462 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 781w&#34; loading=lazy decode=async&gt; такого, что &lt;img class=&#34;formula inline&#34; source=&#34;x_j = 1&#34; alt=&#34;x_j = 1&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cf/cf3/cf37271ea03ab68aaaacc1224e5ca614.svg width=48 height=16 data-width=6.289 data-height=2.173 data-vertical-align=-0.666 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cf/cf3/cf37271ea03ab68aaaacc1224e5ca614.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cf/cf3/cf37271ea03ab68aaaacc1224e5ca614.svg 781w&#34; loading=lazy decode=async&gt;, мы считаем количество &lt;img class=&#34;formula inline&#34; source=&#34;n_S(x_1, \dots, x_{j-1}, 0)&#34; alt=&#34;n_S(x_1, \dots, x_{j-1}, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/6/61/619/619c5969b944bfad729bb5cfe608051e.svg width=136 height=16 data-width=17.983 data-height=2.363 data-vertical-align=-0.616 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/61/619/619c5969b944bfad729bb5cfe608051e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/61/619/619c5969b944bfad729bb5cfe608051e.svg 781w&#34; loading=lazy decode=async&gt; элементов &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt;, которые впервые покоординатно отличаются от &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt; в &lt;img class=&#34;formula inline&#34; source=j alt=j src=https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg width=12 height=12 data-width=0.932 data-height=1.957 data-vertical-align=-0.462 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 781w&#34; loading=lazy decode=async&gt;-той координате и поэтому имеют меньший лексикографический индекс. Суммируя количество таких элементов для всех &lt;img class=&#34;formula inline&#34; source=&#34;1 \leq j \leq n&#34; alt=&#34;1 \leq j \leq n&#34; src=https://habrastorage.org/getpro/habr/formulas/3/35/35d/35df46fb1ff92aefb9edf819cbb49e46.svg width=72 height=16 data-width=9.455 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/35/35d/35df46fb1ff92aefb9edf819cbb49e46.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/35/35d/35df46fb1ff92aefb9edf819cbb49e46.svg 781w&#34; loading=lazy decode=async&gt;, мы пересчитаем все элементы в &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt;, у которых индекс меньше чем у &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/div&gt;&lt;/details&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Утверждение 2. &lt;/strong&gt;&lt;em&gt;Пусть даны индекс &lt;img class=&#34;formula inline&#34; source=i alt=i src=https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg width=12 height=12 data-width=0.781 data-height=1.52 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 781w&#34; loading=lazy decode=async&gt; и множество &lt;img class=&#34;formula inline&#34; source=S alt=S src=https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg width=12 height=12 data-width=1.459 data-height=1.645 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5db/5dbc98dcc983a70728bd082d1a47546e.svg 781w&#34; loading=lazy decode=async&gt;. Найти &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt; такой, что &lt;img class=&#34;formula inline&#34; source=&#34;i_S(x) = i&#34; alt=&#34;i_S(x) = i&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5c/5c5/5c556a055ffafb7e22d673e153431a8d.svg width=64 height=16 data-width=8.852 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5c/5c5/5c556a055ffafb7e22d673e153431a8d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5c/5c5/5c556a055ffafb7e22d673e153431a8d.svg 781w&#34; loading=lazy decode=async&gt; можно с помощью следующего алгоритма:&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;Если &lt;img class=&#34;formula inline&#34; source=&#34;i \geq n_S(0)&#34; alt=&#34;i \geq n_S(0)&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0e/0ed/0ed9fbbddb8f759048d1d9960feb1e65.svg width=72 height=16 data-width=9.266 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0e/0ed/0ed9fbbddb8f759048d1d9960feb1e65.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0e/0ed/0ed9fbbddb8f759048d1d9960feb1e65.svg 781w&#34; loading=lazy decode=async&gt;, установить &lt;img class=&#34;formula inline&#34; source=&#34;x_1 = 1, \: i = i - n_S(0)&#34; alt=&#34;x_1 = 1, \: i = i - n_S(0)&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0d/0d6/0d695af40be25695b918bd494b61c678.svg width=160 height=16 data-width=20.751 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0d/0d6/0d695af40be25695b918bd494b61c678.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0d/0d6/0d695af40be25695b918bd494b61c678.svg 781w&#34; loading=lazy decode=async&gt;; иначе установить &lt;img class=&#34;formula inline&#34; source=&#34;x_1 = 0&#34; alt=&#34;x_1 = 0&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f4/f49/f49a9161cce8422c4d84b538912618cb.svg width=48 height=12 data-width=6.43 data-height=1.846 data-vertical-align=-0.339 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f4/f49/f49a9161cce8422c4d84b538912618cb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f4/f49/f49a9161cce8422c4d84b538912618cb.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;Для всех &lt;img class=&#34;formula inline&#34; source=&#34;k = 2, \dots, n&#34; alt=&#34;k = 2, \dots, n&#34; src=https://habrastorage.org/getpro/habr/formulas/9/91/917/91706e12b97a82c526e2756c98564f54.svg width=88 height=16 data-width=11.725 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/91/917/91706e12b97a82c526e2756c98564f54.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/91/917/91706e12b97a82c526e2756c98564f54.svg 781w&#34; loading=lazy decode=async&gt;, если &lt;img class=&#34;formula inline&#34; source=&#34;i \geq n_S(x_1, \dots, x_{k-1}, 0)&#34; alt=&#34;i \geq n_S(x_1, \dots, x_{k-1}, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/f/fb/fbb/fbba754df28d2a9613c5d2364506c460.svg width=168 height=16 data-width=21.955 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/fb/fbb/fbba754df28d2a9613c5d2364506c460.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/fb/fbb/fbba754df28d2a9613c5d2364506c460.svg 781w&#34; loading=lazy decode=async&gt;, установить &lt;img class=&#34;formula inline&#34; source=&#34;x_k = 1, \: i = i - n_S(x_1, \dots, x_{k-1}, 0)&#34; alt=&#34;x_k = 1, \: i = i - n_S(x_1, \dots, x_{k-1}, 0)&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f2/f2a/f2a2c78fa5863c02864e97104e5015b7.svg width=264 height=16 data-width=33.473 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f2/f2a/f2a2c78fa5863c02864e97104e5015b7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f2/f2a/f2a2c78fa5863c02864e97104e5015b7.svg 781w&#34; loading=lazy decode=async&gt;; иначе установить&lt;/em&gt; &lt;img class=&#34;formula inline&#34; source=&#34;x_k = 0&#34; alt=&#34;x_k = 0&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8a/8a0/8a085760f2da209966aaaac1292f8641.svg width=48 height=12 data-width=6.464 data-height=1.864 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8a/8a0/8a085760f2da209966aaaac1292f8641.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8a/8a0/8a085760f2da209966aaaac1292f8641.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/ol&gt;&lt;/blockquote&gt;&lt;p&gt;Теперь рассмотрим бинарные последовательности с весом &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;:&lt;/p&gt;&lt;img class=formula source=&#34;S = \left\{ x \in \{ 0, 1\}^n: \sum_{j=1}^{n} x_j = h \right\}&#34; alt=&#34;S = \left\{ x \in \{ 0, 1\}^n: \sum_{j=1}^{n} x_j = h \right\}&#34; src=https://habrastorage.org/getpro/habr/formulas/a/af/af2/af21bf806727890496465ee392d434be.svg width=240 height=48 data-width=30.853 data-height=6.972 data-vertical-align=-2.92 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/af/af2/af21bf806727890496465ee392d434be.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/af/af2/af21bf806727890496465ee392d434be.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;В этом случае&lt;/p&gt;&lt;img class=formula source=&#34;n_S(x_1, x_2, \dots, x_{k-1}, 0) = \binom{n-k}{n(h, k)}&#34; alt=&#34;n_S(x_1, x_2, \dots, x_{k-1}, 0) = \binom{n-k}{n(h, k)}&#34; src=https://habrastorage.org/getpro/habr/formulas/9/94/945/945ae1769d08e545c59312cd806b6525.svg width=272 height=40 data-width=34.398 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/94/945/945ae1769d08e545c59312cd806b6525.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/94/945/945ae1769d08e545c59312cd806b6525.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где&lt;/p&gt;&lt;img class=formula source=&#34;n(h, k) = h - \sum_{j=1}^{k-1} x_j&#34; alt=&#34;n(h, k) = h - \sum_{j=1}^{k-1} x_j&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d7/d7f/d7f94de80cec5d02d9d49003c1c67a0c.svg width=152 height=48 data-width=19.477 data-height=6.952 data-vertical-align=-2.911 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d7/d7f/d7f94de80cec5d02d9d49003c1c67a0c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d7/d7f/d7f94de80cec5d02d9d49003c1c67a0c.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;поскольку именно такое количество способов разместить оставшиеся &lt;img class=&#34;formula inline&#34; source=&#34;n(h, k)&#34; alt=&#34;n(h, k)&#34; src=https://habrastorage.org/getpro/habr/formulas/7/70/701/7010c9aa5f26523db32f17652101a6ba.svg width=48 height=16 data-width=6.606 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/70/701/7010c9aa5f26523db32f17652101a6ba.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/70/701/7010c9aa5f26523db32f17652101a6ba.svg 781w&#34; loading=lazy decode=async&gt; единиц в оставшиеся &lt;img class=&#34;formula inline&#34; source=&#34;n - k&#34; alt=&#34;n - k&#34; src=https://habrastorage.org/getpro/habr/formulas/c/c9/c95/c95146b9d90ebf8d8fa98fbef727dca4.svg width=40 height=12 data-width=5.302 data-height=1.756 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/c9/c95/c95146b9d90ebf8d8fa98fbef727dca4.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/c9/c95/c95146b9d90ebf8d8fa98fbef727dca4.svg 781w&#34; loading=lazy decode=async&gt; мест в последовательности. Следовательно,&lt;/p&gt;&lt;img class=formula source=&#34;i_S(x) = \sum_{k=1}^{n} x_k \binom{n-k}{n(h, k)}&#34; alt=&#34;i_S(x) = \sum_{k=1}^{n} x_k \binom{n-k}{n(h, k)}&#34; src=https://habrastorage.org/getpro/habr/formulas/1/19/193/193a2bc003c87f603097e2a7fb997fe3.svg width=184 height=48 data-width=23.967 data-height=6.399 data-vertical-align=-2.634 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/19/193/193a2bc003c87f603097e2a7fb997fe3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/19/193/193a2bc003c87f603097e2a7fb997fe3.svg 781w&#34; loading=lazy decode=async&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Пример&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Для &lt;img class=&#34;formula inline&#34; source=&#34;n=7, h=3&#34; alt=&#34;n=7, h=3&#34; src=https://habrastorage.org/getpro/habr/formulas/d/df/dff/dff3b8a5cf0c39d28c3419d451945bcf.svg width=88 height=16 data-width=11.963 data-height=2.009 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/df/dff/dff3b8a5cf0c39d28c3419d451945bcf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/df/dff/dff3b8a5cf0c39d28c3419d451945bcf.svg 781w&#34; loading=lazy decode=async&gt;:&lt;br&gt;&lt;/p&gt;&lt;img class=formula source=&#34;i(1000101) = \binom{6}{3} + \binom{2}{2} + \binom{0}{1} = 20 + 1 + 0 = 21&#34; alt=&#34;i(1000101) = \binom{6}{3} + \binom{2}{2} + \binom{0}{1} = 20 + 1 + 0 = 21&#34; src=https://habrastorage.org/getpro/habr/formulas/2/2c/2ca/2caa8cbe1ad2e70e048e21b448f5cce7.svg width=400 height=40 data-width=50.745 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2c/2ca/2caa8cbe1ad2e70e048e21b448f5cce7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2c/2ca/2caa8cbe1ad2e70e048e21b448f5cce7.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;i(1110000) = \binom{6}{3} + \binom{5}{2} + \binom{4}{1} = 20 + 10 + 4 = 34&#34; alt=&#34;i(1110000) = \binom{6}{3} + \binom{5}{2} + \binom{4}{1} = 20 + 10 + 4 = 34&#34; src=https://habrastorage.org/getpro/habr/formulas/4/46/46d/46ddaf3e9c2098562b1deb5074421b51.svg width=408 height=40 data-width=51.877 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/46/46d/46ddaf3e9c2098562b1deb5074421b51.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/46/46d/46ddaf3e9c2098562b1deb5074421b51.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;что согласуется с&lt;/p&gt;&lt;img class=formula source=&#34;n_S - 1 = \binom{7}{3} - 1 = 34&#34; alt=&#34;n_S - 1 = \binom{7}{3} - 1 = 34&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d6199a7a29c42c935951745b90c97d.svg width=184 height=40 data-width=23.129 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d6199a7a29c42c935951745b90c97d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e9/e9d/e9d6199a7a29c42c935951745b90c97d.svg 781w&#34; loading=lazy decode=async&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Теперь вернемся к исходной задаче: нам необходимо преобразовать произвольную бинарную строку в сообщения длины &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; и веса  &lt;img class=&#34;formula inline&#34; source=h alt=h src=https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg width=12 height=12 data-width=1.303 data-height=1.595 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/25/251/2510c39011c5be704182423e3a695e91.svg 781w&#34; loading=lazy decode=async&gt;. Для этого случая&lt;/p&gt;&lt;img class=formula source=&#34;n_S = \binom{p}{h}&#34; alt=&#34;n_S = \binom{p}{h}&#34; src=https://habrastorage.org/getpro/habr/formulas/7/7b/7bc/7bcaeba4ec626a9872df2e6c9b637986.svg width=80 height=40 data-width=10.228 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7bc/7bcaeba4ec626a9872df2e6c9b637986.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7bc/7bcaeba4ec626a9872df2e6c9b637986.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Чтобы найти максимальную длину сообщения в битах, которое может быть закодировано таким способом, необходимо рассчитать величину&lt;/p&gt;&lt;img class=formula source=&#34;\lfloor log_2 \binom{p}{h} \rfloor&#34; alt=&#34;\lfloor log_2 \binom{p}{h} \rfloor&#34; src=https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg width=80 height=40 data-width=10.481 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;, т.е. чтобы рассчитать количество бит для кодирования числа не больше &lt;img class=&#34;formula inline&#34; source=n_S alt=n_S src=https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg width=16 height=12 data-width=2.577 data-height=1.375 data-vertical-align=-0.375 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 781w&#34; loading=lazy decode=async&gt; мы рассчитываем&lt;/p&gt;&lt;img class=formula source=&#34;log_2 \binom{p}{h}&#34; alt=&#34;log_2 \binom{p}{h}&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b0/b03/b03cf6f50d857e24a6acab059e38b19b.svg width=64 height=40 data-width=8.472 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b0/b03/b03cf6f50d857e24a6acab059e38b19b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b0/b03/b03cf6f50d857e24a6acab059e38b19b.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;, но так как количество битов - целое число, результат вычисления логарифма необходимо округлить, и округляем мы в меньшую сторону, чтобы максимально возможное число было не больше &lt;img class=&#34;formula inline&#34; source=n_S alt=n_S src=https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg width=16 height=12 data-width=2.577 data-height=1.375 data-vertical-align=-0.375 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2a/2a5/2a5143e0c7150f127d219582d8a68991.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;При кодировании исходного бинарного сообщения, мы разбиваем его на блоки длины&lt;/p&gt;&lt;img class=formula source=&#34;\lfloor log_2 \binom{p}{h} \rfloor&#34; alt=&#34;\lfloor log_2 \binom{p}{h} \rfloor&#34; src=https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg width=80 height=40 data-width=10.481 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/89/89f/89f88f7cf1ffcf68602b4cc3ce842b7e.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;бит каждый, и каждый такой блок рассматриваем как бинарное представление числа &lt;img class=&#34;formula inline&#34; source=&#34;0 \leq x \leq n_S&#34; alt=&#34;0 \leq x \leq n_S&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9f/9f7/9f730bb0e4d29a65376a566c9a3038a5.svg width=88 height=16 data-width=11.037 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9f/9f7/9f730bb0e4d29a65376a566c9a3038a5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9f/9f7/9f730bb0e4d29a65376a566c9a3038a5.svg 781w&#34; loading=lazy decode=async&gt;. Для преобразование числа &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt; в бинарный вектор &lt;img class=&#34;formula inline&#34; source=\vec{y} alt=\vec{y} src=https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg width=12 height=16 data-width=1.109 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 781w&#34; loading=lazy decode=async&gt;, в соответствии с утверждением 2, можно использовать следующий алгоритм:&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Алгоритм 2. &lt;/strong&gt;&lt;em&gt;Вход: &lt;img class=&#34;formula inline&#34; source=&#34;x, p, h&#34; alt=&#34;x, p, h&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a034a8994959cf15306670f8781e8c7.svg width=40 height=16 data-width=5.747 data-height=2.009 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a034a8994959cf15306670f8781e8c7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9a/9a0/9a034a8994959cf15306670f8781e8c7.svg 781w&#34; loading=lazy decode=async&gt;; Выход:&lt;/em&gt; &lt;img class=&#34;formula inline&#34; source=\vec{y} alt=\vec{y} src=https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg width=12 height=16 data-width=1.109 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 781w&#34; loading=lazy decode=async&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;для &lt;img class=&#34;formula inline&#34; source=&#34;k \leftarrow 1&#34; alt=&#34;k \leftarrow 1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg width=40 height=16 data-width=5.829 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg 781w&#34; loading=lazy decode=async&gt; до &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt;:&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;если &lt;img class=&#34;formula inline&#34; source=&#34;x \geq \binom{p-k}{h}&#34; alt=&#34;x \geq \binom{p-k}{h}&#34; src=https://habrastorage.org/getpro/habr/formulas/9/99/993/9937e9a1e4f053e462f46fca76fd6ee6.svg width=96 height=40 data-width=12.724 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/99/993/9937e9a1e4f053e462f46fca76fd6ee6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/99/993/9937e9a1e4f053e462f46fca76fd6ee6.svg 781w&#34; loading=lazy decode=async&gt;, то&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;y_k \leftarrow 1&#34; alt=&#34;y_k \leftarrow 1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/90/900/900163fdbd5cc3014687b2924e4edb34.svg width=48 height=16 data-width=6.78 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/90/900/900163fdbd5cc3014687b2924e4edb34.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/90/900/900163fdbd5cc3014687b2924e4edb34.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;x \leftarrow x - \binom{p-k}{h}&#34; alt=&#34;x \leftarrow x - \binom{p-k}{h}&#34; src=https://habrastorage.org/getpro/habr/formulas/2/2e/2eb/2ebeb6d1a29ff63876a1e61ebf8a2dde.svg width=136 height=40 data-width=17.286 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2e/2eb/2ebeb6d1a29ff63876a1e61ebf8a2dde.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2e/2eb/2ebeb6d1a29ff63876a1e61ebf8a2dde.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;h \leftarrow h - 1&#34; alt=&#34;h \leftarrow h - 1&#34; src=https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg width=80 height=16 data-width=10.023 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;иначе &lt;img class=&#34;formula inline&#34; source=&#34;y_k \leftarrow 0&#34; alt=&#34;y_k \leftarrow 0&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f5/f5f/f5f39a7ac71836db308e92e86940e35a.svg width=48 height=16 data-width=6.78 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f5/f5f/f5f39a7ac71836db308e92e86940e35a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f5/f5f/f5f39a7ac71836db308e92e86940e35a.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;вернуть &lt;img class=&#34;formula inline&#34; source=\vec{y} alt=\vec{y} src=https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg width=12 height=16 data-width=1.109 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;p&gt;Обратное преобразование вектора &lt;img class=&#34;formula inline&#34; source=\vec{y} alt=\vec{y} src=https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg width=12 height=16 data-width=1.109 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3f/3fd/3fd8eaedb619fad0827fd7819c0c5164.svg 781w&#34; loading=lazy decode=async&gt; в число &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt;, в соответствии с утверждением 1, осуществляется по алгоритму:&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Алгоритм 3. &lt;/strong&gt;&lt;em&gt;Вход: &lt;img class=&#34;formula inline&#34; source=&#34;\vec{y}, p, h&#34; alt=&#34;\vec{y}, p, h&#34; src=https://habrastorage.org/getpro/habr/formulas/2/21/21e/21ef6bed9d2e96e67da6c77adac573b8.svg width=40 height=16 data-width=5.562 data-height=2.477 data-vertical-align=-0.673 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/21/21e/21ef6bed9d2e96e67da6c77adac573b8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/21/21e/21ef6bed9d2e96e67da6c77adac573b8.svg 781w&#34; loading=lazy decode=async&gt;; Выход: &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;x \leftarrow 0&#34; alt=&#34;x \leftarrow 0&#34; src=https://habrastorage.org/getpro/habr/formulas/2/28/288/2880950a4e159f25311ba4888e0c54b7.svg width=40 height=16 data-width=5.945 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/28/288/2880950a4e159f25311ba4888e0c54b7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/28/288/2880950a4e159f25311ba4888e0c54b7.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;для &lt;img class=&#34;formula inline&#34; source=&#34;k \leftarrow 1&#34; alt=&#34;k \leftarrow 1&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg width=40 height=16 data-width=5.829 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9e/9eb/9eb583a5da038d9d037e72406b6a7deb.svg 781w&#34; loading=lazy decode=async&gt; до &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt;:&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;если &lt;img class=&#34;formula inline&#34; source=&#34;y_k = 1&#34; alt=&#34;y_k = 1&#34; src=https://habrastorage.org/getpro/habr/formulas/2/2c/2c6/2c6375be12d2144c0771d54fa0d9fdc3.svg width=48 height=12 data-width=6.278 data-height=1.971 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2c/2c6/2c6375be12d2144c0771d54fa0d9fdc3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2c/2c6/2c6375be12d2144c0771d54fa0d9fdc3.svg 781w&#34; loading=lazy decode=async&gt;, то&lt;/em&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;x \leftarrow x + \binom{p-k}{h}&#34; alt=&#34;x \leftarrow x + \binom{p-k}{h}&#34; src=https://habrastorage.org/getpro/habr/formulas/d/db/dbe/dbee701bbeac0dda85a7a10836c5aeee.svg width=136 height=40 data-width=17.286 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/db/dbe/dbee701bbeac0dda85a7a10836c5aeee.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/db/dbe/dbee701bbeac0dda85a7a10836c5aeee.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;img class=&#34;formula inline&#34; source=&#34;h \leftarrow h - 1&#34; alt=&#34;h \leftarrow h - 1&#34; src=https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg width=80 height=16 data-width=10.023 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/14/14c/14c79d2bdc77c8b5c57f1f910465d625.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;li&gt;&lt;p&gt;&lt;em&gt;вернуть &lt;img class=&#34;formula inline&#34; source=x alt=x src=https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg width=12 height=12 data-width=1.294 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9d/9dd/9dd4e461268c8034f5c8564e155c67a6.svg 781w&#34; loading=lazy decode=async&gt;&lt;/em&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;h2&gt;Пример работы криптосистемы&lt;/h2&gt;&lt;a class=anchor id=example&gt;&lt;/a&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Код&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;Пример был сгенерирован с помощью программы, исходный код которой расположен ниже. Для этого я использовал SageMath. Вы можете установить данное ПО локально по &lt;a href=https://doc.sagemath.org/html/en/installation/index.html rel=&#34;noopener noreferrer nofollow&#34;&gt;инструкции&lt;/a&gt; либо использовать платформу &lt;a href=https://cocalc.com/ rel=&#34;noopener noreferrer nofollow&#34;&gt;CoCalc&lt;/a&gt;. Я воспользовался вторым вариантом, так как на платформе CoCalc есть возможность создать &lt;a href=https://jupyter.org/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Jupyter Notebook&lt;/a&gt; и использовать его бесплатно без доступа в интернет.&lt;pre&gt;&lt;code class=python&gt;from sage.all import *&#xA;import numpy as np&#xA;&#xA;&#xA;# функция, рассчитывающая публичный ключ&#xA;def calculate_public_key(p, perm, d, g, t):&#xA;    # вычисляем дискретный логарифмы a_i&#xA;    a = []&#xA;    for i in range(p):&#xA;        a.append(discrete_log(t + i, g))&#xA;    &#xA;    # вычисляем c_i&#xA;    c = []&#xA;    for i in range(p):&#xA;        b = a[perm[i]]&#xA;        c.append((b + d) % g.multiplicative_order())&#xA;    &#xA;    return tuple(c)&#xA;&#xA;# функция, преобразующая число x в вектор y длины p и веса h&#xA;def number_to_vector(x, p, h):&#xA;    # вычисляем максимальное по величине число, которое может быть&#xA;    # зашифровано: 2^(максимальная длина одного сообщения в битах)&#xA;    # проверяем, что x меньше максимального числа&#xA;    assert x &amp;lt; 2**int(log(binomial(p, h), 2).n())&#xA;&#xA;    y = []&#xA;&#xA;    for k in range(1, p+1):&#xA;        bin_coef = binomial(p-k, h)&#xA;&#xA;        if x &amp;gt;= bin_coef:&#xA;            y.append(1)&#xA;            x = x - bin_coef&#xA;            h = h - 1&#xA;        else:&#xA;            y.append(0)&#xA;&#xA;    return y&#xA;&#xA;# функция зашифрования сообщения&#xA;def encrypt(m, c, p, h):&#xA;    M = number_to_vector(m, p, h)&#xA;    multiplicative_order = p**h - 1&#xA;&#xA;    msg = 0&#xA;    for i in range(len(M)):&#xA;        if M[i] == 1:&#xA;            msg = (msg + c[i] ) % multiplicative_order&#xA;&#xA;    return msg&#xA;&#xA;# функция, преобразующая вектор y длины p и веса h в число x&#xA;def vector_to_number(y, p, h):&#xA;    x = 0&#xA;&#xA;    for k in range(1, p+1):&#xA;        if y[k-1] == 1:&#xA;            x = x + binomial(p-k, h)&#xA;            h = h - 1&#xA;&#xA;    return x&#xA;&#xA;# функция расшифрования сообщения&#xA;def decrypt(msg, p, h, irreducible_poly, g, inverse_perm, d):&#xA;    multiplicative_order = p**h - 1&#xA;    c_ = (msg - h * d) % multiplicative_order&#xA;    u = g ** c_&#xA;    # получаем кольцо многочленов над полем GF(p)&#xA;    # т.е. коэффициенты многочленов принадлежат полю GF(p)&#xA;    R = PolynomialRing(GF(p), &amp;#34;t_&amp;#34;)&#xA;    # складывает u и irreducible_poly как элементы кольца многочленов&#xA;    s = R(u.polynomial()) + R(irreducible_poly)&#xA;&#xA;    M = [0] * p&#xA;    # перебираем все множители многочлена s (все линейные)&#xA;    for f in factor(s):&#xA;        # получаем корень&#xA;        coef = 0&#xA;        coefs = f[0].coefficients()&#xA;        if len(coefs) != 1:&#xA;            coef = int(coefs[0])&#xA;        &#xA;        # восстанавливаем соответствующий бит&#xA;        M[inverse_perm[coef]] = 1&#xA;&#xA;    return vector_to_number(M, p, h)&#xA;&#xA;# Генерация параметров криптосистемы&#xA;&#xA;# p - характеристика, h - степень расширения поля&#xA;p = 11&#xA;h = 5&#xA;&#xA;# определяем символическую переменную&#xA;x = var(&amp;#39;x&amp;#39;)&#xA;# неприводимый многочлен (для примера зафиксирован),&#xA;# по модулю которого строится поле GF(p^h)&#xA;irreducible_polynomial = x**5 + 9*x**3 + 9*x**2 + 3*x + 10&#xA;&#xA;# создаем конечное поле p^h, modulus - неприводимый многочлен&#xA;F = GF(p**h, name=&amp;#34;t&amp;#34;, modulus=irreducible_polynomial)&#xA;irreducible_polynomial = F.modulus()&#xA;# корень неприводимого многочлена, по модулю&#xA;# которого построено поле F&#xA;t = F.gen()&#xA;# примитивный элемент поля (для примера зафиксирован)&#xA;g = 2*t**4 + 8*t**3 + 4*t**2 + 5*t**1 + 2&#xA;&#xA;# случайная перестановка (для примера зафиксирована)&#xA;permutation = np.array([5, 6, 7, 2, 8, 10, 4, 0, 1, 3, 9])&#xA;# вычисляем обратную перестановку&#xA;inverse_permutation = np.arange(p)&#xA;inverse_permutation[permutation] = inverse_permutation.copy()&#xA;&#xA;# выбираем случайное число d (для примера зафиксировано)&#xA;d = 84997&#xA;&#xA;c = calculate_public_key(p, permutation, d, g, t)&#xA;&#xA;m = 217&#xA;print(f&amp;#34;исходное сообщение: {m}&amp;#34;)&#xA;&#xA;# Шифрование&#xA;msg = encrypt(m, c, p, h)&#xA;print(f&amp;#34;зашифрованное сообщение: {msg}&amp;#34;)&#xA;&#xA;# Расшифрование&#xA;decrypted_msg = decrypt(&#xA;    msg, p, h,&#xA;    irreducible_polynomial, g,&#xA;    inverse_permutation, d,&#xA;)&#xA;print(f&amp;#34;расшифрованное сообщение: {decrypted_msg}&amp;#34;)&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;&lt;strong&gt;Генерация параметров криптосистемы:&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Выбираем &lt;img class=&#34;formula inline&#34; source=&#34;p = 11, h = 5&#34; alt=&#34;p = 11, h = 5&#34; src=https://habrastorage.org/getpro/habr/formulas/c/ca/cac/cac4d151abf10eb594ea9a0857bd0280.svg width=96 height=16 data-width=12.875 data-height=2.009 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/ca/cac/cac4d151abf10eb594ea9a0857bd0280.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/ca/cac/cac4d151abf10eb594ea9a0857bd0280.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Выбираем неприводимый многочлен степени &lt;img class=&#34;formula inline&#34; source=5 alt=5 src=https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg width=12 height=12 data-width=1.131 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 781w&#34; loading=lazy decode=async&gt; над &lt;img class=&#34;formula inline&#34; source=GF(11) alt=GF(11) src=https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg width=56 height=16 data-width=7.495 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg 781w&#34; loading=lazy decode=async&gt;: &lt;img class=&#34;formula inline&#34; source=&#34;f(t) = t^5 + 9t^3 + 9t^2 + 3t + 10&#34; alt=&#34;f(t) = t^5 + 9t^3 + 9t^2 + 3t + 10&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b5/b57/b57e69a1bd7b0dd70e2e174455892f34.svg width=232 height=16 data-width=29.787 data-height=2.565 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b5/b57/b57e69a1bd7b0dd70e2e174455892f34.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b5/b57/b57e69a1bd7b0dd70e2e174455892f34.svg 781w&#34; loading=lazy decode=async&gt;. Элементы конечного поля &lt;img class=&#34;formula inline&#34; source=GF(11^5) alt=GF(11^5) src=https://habrastorage.org/getpro/habr/formulas/9/9e/9e5/9e53c96fd29e6e5e3a553cd74ea6d3e1.svg width=64 height=16 data-width=8.483 data-height=2.565 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9e/9e5/9e53c96fd29e6e5e3a553cd74ea6d3e1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9e/9e5/9e53c96fd29e6e5e3a553cd74ea6d3e1.svg 781w&#34; loading=lazy decode=async&gt; - многочлены степени не больше &lt;img class=&#34;formula inline&#34; source=5 alt=5 src=https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg width=12 height=12 data-width=1.131 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 781w&#34; loading=lazy decode=async&gt; с коэффициентами в &lt;img class=&#34;formula inline&#34; source=GF(11) alt=GF(11) src=https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg width=56 height=16 data-width=7.495 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/37/37f/37fb3af305a64c2e0ee30b50f57da2a2.svg 781w&#34; loading=lazy decode=async&gt;, арифметические операции в котором выполняются по модулю &lt;img class=&#34;formula inline&#34; source=f(t) alt=f(t) src=https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg width=24 height=16 data-width=3.821 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d6/d6e/d6e3af948a34fd5f432cb9d377a98ef0.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Выбираем примитивный элемент &lt;img class=&#34;formula inline&#34; source=&#34;g = 2t^4 + 8t^3 + 4t^2 + 5t + 2&#34; alt=&#34;g = 2t^4 + 8t^3 + 4t^2 + 5t + 2&#34; src=https://habrastorage.org/getpro/habr/formulas/6/64/644/6448bc2b80a994b5176a9a36b229f389.svg width=216 height=16 data-width=27.045 data-height=2.481 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/64/644/6448bc2b80a994b5176a9a36b229f389.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/64/644/6448bc2b80a994b5176a9a36b229f389.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Вычисляем дискретные логарифмы&lt;/ol&gt;&lt;img class=formula source=&#34;a_0 = log_g(t) = 134600&#34; alt=&#34;a_0 = log_g(t) = 134600&#34; src=https://habrastorage.org/getpro/habr/formulas/4/41/41d/41dcc614f2b8c26aa5602ec88b2997bd.svg width=168 height=16 data-width=21.385 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/41/41d/41dcc614f2b8c26aa5602ec88b2997bd.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/41/41d/41dcc614f2b8c26aa5602ec88b2997bd.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_1 = log_g(t + 1) = 78964&#34; alt=&#34;a_1 = log_g(t + 1) = 78964&#34; src=https://habrastorage.org/getpro/habr/formulas/1/15/153/1537d9310a100541f082a8ce697a18d4.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/15/153/1537d9310a100541f082a8ce697a18d4.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/15/153/1537d9310a100541f082a8ce697a18d4.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_2 = log_g(t + 2) = 27756&#34; alt=&#34;a_2 = log_g(t + 2) = 27756&#34; src=https://habrastorage.org/getpro/habr/formulas/c/ce/cec/cec527cb1aaf2d0f558efa2beffa8683.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/ce/cec/cec527cb1aaf2d0f558efa2beffa8683.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/ce/cec/cec527cb1aaf2d0f558efa2beffa8683.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_3 = log_g(t + 3) = 28213&#34; alt=&#34;a_3 = log_g(t + 3) = 28213&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cd/cd8/cd8603c05b5b9674f0d0e6e6ff2b4e27.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cd/cd8/cd8603c05b5b9674f0d0e6e6ff2b4e27.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cd/cd8/cd8603c05b5b9674f0d0e6e6ff2b4e27.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_4 = log_g(t + 4) = 68089&#34; alt=&#34;a_4 = log_g(t + 4) = 68089&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e9/e94/e94379420a0a9afe74cc863fa2062215.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e9/e94/e94379420a0a9afe74cc863fa2062215.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e9/e94/e94379420a0a9afe74cc863fa2062215.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_5 = log_g(t + 5) = 51642&#34; alt=&#34;a_5 = log_g(t + 5) = 51642&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5a/5a4/5a47eb9473de0475780e3c0fc5163264.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5a/5a4/5a47eb9473de0475780e3c0fc5163264.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5a/5a4/5a47eb9473de0475780e3c0fc5163264.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_6 = log_g(t + 6) = 38125&#34; alt=&#34;a_6 = log_g(t + 6) = 38125&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9b/9b2/9b20ad8e745a7390d9d9453d60ddf43f.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9b/9b2/9b20ad8e745a7390d9d9453d60ddf43f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9b/9b2/9b20ad8e745a7390d9d9453d60ddf43f.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_7 = log_g(t + 7) = 11604&#34; alt=&#34;a_7 = log_g(t + 7) = 11604&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d2/d2d/d2df079dac41082fc0926ef7866b9412.svg width=192 height=16 data-width=24.15 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d2/d2d/d2df079dac41082fc0926ef7866b9412.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d2/d2d/d2df079dac41082fc0926ef7866b9412.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_8 = log_g(t + 8) = 103713&#34; alt=&#34;a_8 = log_g(t + 8) = 103713&#34; src=https://habrastorage.org/getpro/habr/formulas/8/88/888/8885f5f0fbe9816f3b1797bc2266b7d3.svg width=200 height=16 data-width=25.281 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/88/888/8885f5f0fbe9816f3b1797bc2266b7d3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/88/888/8885f5f0fbe9816f3b1797bc2266b7d3.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_9 = log_g(t + 9) = 123616&#34; alt=&#34;a_9 = log_g(t + 9) = 123616&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b8/0b8c1a0f8608386995606016a940e2e4.svg width=200 height=16 data-width=25.281 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b8/0b8c1a0f8608386995606016a940e2e4.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b8/0b8c1a0f8608386995606016a940e2e4.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;a_{10} = log_g(t + 10) = 15120&#34; alt=&#34;a_{10} = log_g(t + 10) = 15120&#34; src=https://habrastorage.org/getpro/habr/formulas/1/1d/1d6/1d627460306e4da0ca1e63cf9ae8ac01.svg width=208 height=16 data-width=26.081 data-height=2.364 data-vertical-align=-0.667 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1d/1d6/1d627460306e4da0ca1e63cf9ae8ac01.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1d/1d6/1d627460306e4da0ca1e63cf9ae8ac01.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;5. Выбираем случайную перестановку&lt;/p&gt;&lt;img class=formula source=&#34;\pi =         \begin{pmatrix}             0 &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; 5 &amp;amp; 6 &amp;amp; 7 &amp;amp; 8 &amp;amp; 9 &amp;amp; 10 \\             5 &amp;amp; 6 &amp;amp; 7 &amp;amp; 2 &amp;amp; 8 &amp;amp; 10 &amp;amp; 4 &amp;amp; 0 &amp;amp; 1 &amp;amp; 3 &amp;amp; 9         \end{pmatrix}&#34; alt=&#34;\pi =         \begin{pmatrix}             0 &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; 5 &amp;amp; 6 &amp;amp; 7 &amp;amp; 8 &amp;amp; 9 &amp;amp; 10 \\             5 &amp;amp; 6 &amp;amp; 7 &amp;amp; 2 &amp;amp; 8 &amp;amp; 10 &amp;amp; 4 &amp;amp; 0 &amp;amp; 1 &amp;amp; 3 &amp;amp; 9         \end{pmatrix}&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0e/0ef/0efa9fe7b75109a626f9daed167907e3.svg width=352 height=40 data-width=44.967 data-height=5.43 data-vertical-align=-2.149 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0e/0ef/0efa9fe7b75109a626f9daed167907e3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0e/0ef/0efa9fe7b75109a626f9daed167907e3.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;т.е.&lt;/p&gt;&lt;img class=formula source=&#34;b_0 = a_{\pi(0)} = a_5&#34; alt=&#34;b_0 = a_{\pi(0)} = a_5&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8d/8da/8da0ec3e309cbfd23971e1ac4261e351.svg width=112 height=16 data-width=14.518 data-height=2.497 data-vertical-align=-0.683 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8d/8da/8da0ec3e309cbfd23971e1ac4261e351.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8d/8da/8da0ec3e309cbfd23971e1ac4261e351.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;b_1 = a_{\pi(1)} = a_6&#34; alt=&#34;b_1 = a_{\pi(1)} = a_6&#34; src=https://habrastorage.org/getpro/habr/formulas/3/39/397/397b836ec096139c9ee07c457b07b26f.svg width=112 height=16 data-width=14.518 data-height=2.497 data-vertical-align=-0.683 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/39/397/397b836ec096139c9ee07c457b07b26f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/39/397/397b836ec096139c9ee07c457b07b26f.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;и т.д.&lt;p&gt;6. Выбираем случайное число &lt;img class=&#34;formula inline&#34; source=&#34;d = 84997&#34; alt=&#34;d = 84997&#34; src=https://habrastorage.org/getpro/habr/formulas/4/48/481/4818636304353c494c1130c5de7c8699.svg width=72 height=12 data-width=9.85 data-height=1.756 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/48/481/4818636304353c494c1130c5de7c8699.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/48/481/4818636304353c494c1130c5de7c8699.svg 781w&#34; loading=lazy decode=async&gt; и вычисляем&lt;/p&gt;&lt;img class=formula source=&#34;c_0 = (b_0 + d) \: (\textrm{mod} \: p^h - 1) = (51642 + 84997) \: (\textrm{mod} \: 161050) = 136639&#34; alt=&#34;c_0 = (b_0 + d) \: (\textrm{mod} \: p^h - 1) = (51642 + 84997) \: (\textrm{mod} \: 161050) = 136639&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0a/0ac/0acab7f92dd30e444e4abcc541a887bf.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0a/0ac/0acab7f92dd30e444e4abcc541a887bf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0a/0ac/0acab7f92dd30e444e4abcc541a887bf.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_1 = (b_1 + d) \: (\textrm{mod} \: p^h - 1) = (38125 + 84997) \: (\textrm{mod} \: 161050) = 123122&#34; alt=&#34;c_1 = (b_1 + d) \: (\textrm{mod} \: p^h - 1) = (38125 + 84997) \: (\textrm{mod} \: 161050) = 123122&#34; src=https://habrastorage.org/getpro/habr/formulas/1/19/199/1998ce03a0d00ecd008c20c2b2cff251.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/19/199/1998ce03a0d00ecd008c20c2b2cff251.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/19/199/1998ce03a0d00ecd008c20c2b2cff251.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_2 = (b_2 + d) \: (\textrm{mod} \: p^h - 1) = (11604 + 84997) \: (\textrm{mod} \: 161050) = 96601&#34; alt=&#34;c_2 = (b_2 + d) \: (\textrm{mod} \: p^h - 1) = (11604 + 84997) \: (\textrm{mod} \: 161050) = 96601&#34; src=https://habrastorage.org/getpro/habr/formulas/3/39/396/396ff988a29ec37e8a895e4ce2c97010.svg width=536 height=16 data-width=67.182 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/39/396/396ff988a29ec37e8a895e4ce2c97010.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/39/396/396ff988a29ec37e8a895e4ce2c97010.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_3 = (b_3 + d) \: (\textrm{mod} \: p^h - 1) = (27756 + 84997) \: (\textrm{mod} \: 161050) = 112753&#34; alt=&#34;c_3 = (b_3 + d) \: (\textrm{mod} \: p^h - 1) = (27756 + 84997) \: (\textrm{mod} \: 161050) = 112753&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8a/8ab/8ab2f00b2ec23edef0fe8382f60d1e81.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8a/8ab/8ab2f00b2ec23edef0fe8382f60d1e81.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8a/8ab/8ab2f00b2ec23edef0fe8382f60d1e81.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_4 = (b_4 + d) \: (\textrm{mod} \: p^h - 1) = (103713 + 84997) \: (\textrm{mod} \: 161050) = 27660&#34; alt=&#34;c_4 = (b_4 + d) \: (\textrm{mod} \: p^h - 1) = (103713 + 84997) \: (\textrm{mod} \: 161050) = 27660&#34; src=https://habrastorage.org/getpro/habr/formulas/1/17/17e/17eff1f97dfd7109c86a8413ecb12dbc.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/17/17e/17eff1f97dfd7109c86a8413ecb12dbc.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/17/17e/17eff1f97dfd7109c86a8413ecb12dbc.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_5 = (b_5 + d) \: (\textrm{mod} \: p^h - 1) = (15120 + 84997) \: (\textrm{mod} \: 161050) = 100117&#34; alt=&#34;c_5 = (b_5 + d) \: (\textrm{mod} \: p^h - 1) = (15120 + 84997) \: (\textrm{mod} \: 161050) = 100117&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d8/d86/d864f23a0e476d5c62d662bcb01c66b6.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d86/d864f23a0e476d5c62d662bcb01c66b6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d86/d864f23a0e476d5c62d662bcb01c66b6.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_6 = (b_6 + d) \: (\textrm{mod} \: p^h - 1) = (68089 + 84997) \: (\textrm{mod} \: 161050) = 153086&#34; alt=&#34;c_6 = (b_6 + d) \: (\textrm{mod} \: p^h - 1) = (68089 + 84997) \: (\textrm{mod} \: 161050) = 153086&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5d/5d1/5d1f7ff84ab47093d704a817ae8357fb.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5d1/5d1f7ff84ab47093d704a817ae8357fb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5d1/5d1f7ff84ab47093d704a817ae8357fb.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_7 = (b_7 + d) \: (\textrm{mod} \: p^h - 1) = (134600 + 84997) \: (\textrm{mod} \: 161050) = 58547&#34; alt=&#34;c_7 = (b_7 + d) \: (\textrm{mod} \: p^h - 1) = (134600 + 84997) \: (\textrm{mod} \: 161050) = 58547&#34; src=https://habrastorage.org/getpro/habr/formulas/0/09/09c/09c0ffc6184eb6f7fbb6bbf3b297de0a.svg width=544 height=16 data-width=68.313 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/09/09c/09c0ffc6184eb6f7fbb6bbf3b297de0a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/09/09c/09c0ffc6184eb6f7fbb6bbf3b297de0a.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_8 = (b_8 + d) \: (\textrm{mod} \: p^h - 1) = (78964 + 84997) \: (\textrm{mod} \: 161050) = 2911&#34; alt=&#34;c_8 = (b_8 + d) \: (\textrm{mod} \: p^h - 1) = (78964 + 84997) \: (\textrm{mod} \: 161050) = 2911&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5d/5df/5dff86a7e4a485d83b46a5ab093fa73f.svg width=528 height=16 data-width=66.051 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5d/5df/5dff86a7e4a485d83b46a5ab093fa73f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5d/5df/5dff86a7e4a485d83b46a5ab093fa73f.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_9 = (b_9 + d) \: (\textrm{mod} \: p^h - 1) = (2911 + 84997) \: (\textrm{mod} \: 161050)  = 113210&#34; alt=&#34;c_9 = (b_9 + d) \: (\textrm{mod} \: p^h - 1) = (2911 + 84997) \: (\textrm{mod} \: 161050)  = 113210&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ef/efb/efb7965f3f9315fd261028f874707206.svg width=536 height=16 data-width=67.182 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ef/efb/efb7965f3f9315fd261028f874707206.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ef/efb/efb7965f3f9315fd261028f874707206.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;c_{10} = (b_{10} + d) \: (\textrm{mod} \: p^h - 1) = (123616 + 84997) \: (\textrm{mod} \: 161050) = 47563&#34; alt=&#34;c_{10} = (b_{10} + d) \: (\textrm{mod} \: p^h - 1) = (123616 + 84997) \: (\textrm{mod} \: 161050) = 47563&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a7/a7a/a7a4e80cb49627560442905a5a3b648f.svg width=552 height=16 data-width=69.913 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a7/a7a/a7a4e80cb49627560442905a5a3b648f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a7/a7a/a7a4e80cb49627560442905a5a3b648f.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;&lt;strong&gt;Шифрование&lt;/strong&gt;&lt;p&gt;Рассмотрим пример шифрования сообщения &lt;img class=&#34;formula inline&#34; source=&#34;m = 217&#34; alt=&#34;m = 217&#34; src=https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg width=64 height=12 data-width=8.397 data-height=1.715 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg 781w&#34; loading=lazy decode=async&gt;, или в бинарном виде: &lt;img class=&#34;formula inline&#34; source=11011001 alt=11011001 src=https://habrastorage.org/getpro/habr/formulas/3/37/37b/37b692887bf3c94055b361ae26b5c482.svg width=72 height=12 data-width=9.05 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/37/37b/37b692887bf3c94055b361ae26b5c482.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/37/37b/37b692887bf3c94055b361ae26b5c482.svg 781w&#34; loading=lazy decode=async&gt;. Нам необходимо его преобразовать в бинарный вектор длины &lt;img class=&#34;formula inline&#34; source=11 alt=11 src=https://habrastorage.org/getpro/habr/formulas/6/65/651/6512bd43d9caa6e02c990b0a82652dca.svg width=16 height=12 data-width=2.262 data-height=1.507 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/65/651/6512bd43d9caa6e02c990b0a82652dca.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/65/651/6512bd43d9caa6e02c990b0a82652dca.svg 781w&#34; loading=lazy decode=async&gt; и веса &lt;img class=&#34;formula inline&#34; source=5 alt=5 src=https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg width=12 height=12 data-width=1.131 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e4/e4d/e4da3b7fbbce2345d7772b0674a318d5.svg 781w&#34; loading=lazy decode=async&gt; в соответствии с алгоритмом 2. Его длина равна &lt;img class=&#34;formula inline&#34; source=8 alt=8 src=https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg width=12 height=12 data-width=1.131 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/c9/c9f/c9f0f895fb98ab9159f51fd0297e236d.svg 781w&#34; loading=lazy decode=async&gt;, т.е она не больше&lt;/p&gt;&lt;img class=formula source=&#34;\lfloor log_2 \binom{p}{h} \rfloor = \lfloor log_2 \binom{11}{5} \rfloor = 8&#34; alt=&#34;\lfloor log_2 \binom{p}{h} \rfloor = \lfloor log_2 \binom{11}{5} \rfloor = 8&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b4/b4e/b4ec0fa2b1c4afd887dc56f0f703e83b.svg width=232 height=40 data-width=29.086 data-height=5.428 data-vertical-align=-2.148 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b4/b4e/b4ec0fa2b1c4afd887dc56f0f703e83b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b4/b4e/b4ec0fa2b1c4afd887dc56f0f703e83b.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;, соответственно делить это сообщение необходимости нет.&lt;ol&gt;&lt;li&gt;&lt;p&gt;Используя алгоритм 2, преобразуем сообщение &lt;img class=&#34;formula inline&#34; source=m alt=m src=https://habrastorage.org/getpro/habr/formulas/6/6f/6f8/6f8f57715090da2632453988d9a1501b.svg width=12 height=12 data-width=1.986 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/6f/6f8/6f8f57715090da2632453988d9a1501b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/6f/6f8/6f8f57715090da2632453988d9a1501b.svg 781w&#34; loading=lazy decode=async&gt; в бинарный вектор &lt;img class=&#34;formula inline&#34; source=&#34;M = (0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1)&#34; alt=&#34;M = (0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg width=232 height=16 data-width=29.659 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Далее складываем &lt;img class=&#34;formula inline&#34; source=c_i alt=c_i src=https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg width=12 height=12 data-width=1.719 data-height=1.357 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/96/96f/96fafac0c054b9eb47d3f630ed02c289.svg 781w&#34; loading=lazy decode=async&gt;, которые соответствуют битам, равным &lt;img class=&#34;formula inline&#34; source=1 alt=1 src=https://habrastorage.org/getpro/habr/formulas/c/c4/c4c/c4ca4238a0b923820dcc509a6f75849b.svg width=12 height=12 data-width=1.131 data-height=1.507 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/c4/c4c/c4ca4238a0b923820dcc509a6f75849b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/c4/c4c/c4ca4238a0b923820dcc509a6f75849b.svg 781w&#34; loading=lazy decode=async&gt;:&lt;/ol&gt;&lt;img class=formula source=&#34;c = (c_1 + c_2 + c_4 + c_8 + c_{10}) \: (\textrm{mod} \: p^h - 1)  =&#34; alt=&#34;c = (c_1 + c_2 + c_4 + c_8 + c_{10}) \: (\textrm{mod} \: p^h - 1)  =&#34; src=https://habrastorage.org/getpro/habr/formulas/5/51/517/517bd09ee80190ed8c8c6323628108b5.svg width=344 height=16 data-width=43.028 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/51/517/517bd09ee80190ed8c8c6323628108b5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/51/517/517bd09ee80190ed8c8c6323628108b5.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;= (123122 + 96601 + 27660 + 2911 + 47563) \: (\textrm{mod} \: 161050) = 136807&#34; alt=&#34;= (123122 + 96601 + 27660 + 2911 + 47563) \: (\textrm{mod} \: 161050) = 136807&#34; src=https://habrastorage.org/getpro/habr/formulas/0/03/03f/03fdce2b2530442fa3bd9381d3ec56e2.svg width=536 height=16 data-width=67.122 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/03/03f/03fdce2b2530442fa3bd9381d3ec56e2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/03/03f/03fdce2b2530442fa3bd9381d3ec56e2.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;c = 136807&#34; alt=&#34;c = 136807&#34; src=https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg width=80 height=12 data-width=10.784 data-height=1.715 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg 781w&#34; loading=lazy decode=async&gt; - зашифрованное сообщение, которое будет отправлено.&lt;p&gt;&lt;strong&gt;Расшифрование&lt;/strong&gt;&lt;p&gt;Чтобы расшифровать сообщение &lt;img class=&#34;formula inline&#34; source=&#34;c = 136807&#34; alt=&#34;c = 136807&#34; src=https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg width=80 height=12 data-width=10.784 data-height=1.715 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/05/052/052a3d7e437185c895322cef45270d20.svg 781w&#34; loading=lazy decode=async&gt;:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Вычисляем &lt;img class=&#34;formula inline&#34; source=&#34;c&#39; = c - hd \: (\textrm{mod} \: p^h-1) = (136807 - 5 * 84997) (\textrm{mod} \: 161050) = 33922&#34; alt=&#34;c&#39; = c - hd \: (\textrm{mod} \: p^h-1) = (136807 - 5 * 84997) (\textrm{mod} \: 161050) = 33922&#34; src=https://habrastorage.org/getpro/habr/formulas/3/30/302/302c1cbe9eab8c41c83d48658eb7e66c.svg width=552 height=16 data-width=69.283 data-height=2.61 data-vertical-align=-0.74 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/30/302/302c1cbe9eab8c41c83d48658eb7e66c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/30/302/302c1cbe9eab8c41c83d48658eb7e66c.svg 781w&#34; loading=lazy decode=async&gt;.&lt;li&gt;&lt;p&gt;Вычисляем&lt;/ol&gt;&lt;img class=formula source=&#34;u(t) = g^{c&#39;} \: (\textrm{mod} \: f(t)) = (2t^4 + 8t^3 + 4t^2 + 5t + 2)^{33922} \: (\textrm{mod} \: t^5 + 9t^3 + 9t^2 + 3t + 10) =&#34; alt=&#34;u(t) = g^{c&#39;} \: (\textrm{mod} \: f(t)) = (2t^4 + 8t^3 + 4t^2 + 5t + 2)^{33922} \: (\textrm{mod} \: t^5 + 9t^3 + 9t^2 + 3t + 10) =&#34; src=https://habrastorage.org/getpro/habr/formulas/5/52/529/5292aa5f39b5c1494f73710038a3e725.svg width=672 height=16 data-width=84.441 data-height=2.714 data-vertical-align=-0.791 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/52/529/5292aa5f39b5c1494f73710038a3e725.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/52/529/5292aa5f39b5c1494f73710038a3e725.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;= 9t^4 + 4t^3 + 7t^2 + 7t&#34; alt=&#34;= 9t^4 + 4t^3 + 7t^2 + 7t&#34; src=https://habrastorage.org/getpro/habr/formulas/6/67/67c/67c7fba00a5430553090ed828136eb2f.svg width=168 height=16 data-width=21.441 data-height=2.203 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/67/67c/67c7fba00a5430553090ed828136eb2f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/67/67c/67c7fba00a5430553090ed828136eb2f.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;3. Вычисляем&lt;/p&gt;&lt;img class=formula source=&#34;s(t) = u(t) + f(t) = (9t^4 + 4t^3 + 7t^2 + 7t) + (t^5 + 9t^3 + 9t^2 + 3t + 10) =&#34; alt=&#34;s(t) = u(t) + f(t) = (9t^4 + 4t^3 + 7t^2 + 7t) + (t^5 + 9t^3 + 9t^2 + 3t + 10) =&#34; src=https://habrastorage.org/getpro/habr/formulas/d/db/db7/db784769dfa1ff919d270e3652263911.svg width=560 height=16 data-width=70.806 data-height=2.583 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/db/db7/db784769dfa1ff919d270e3652263911.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/db/db7/db784769dfa1ff919d270e3652263911.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;= t^5 + 9t^4 + 2t^3 + 5t^2 + 10t + 10&#34; alt=&#34;= t^5 + 9t^4 + 2t^3 + 5t^2 + 10t + 10&#34; src=https://habrastorage.org/getpro/habr/formulas/0/01/010/010a92fb5bc4bca8af5d9efde0a8a097.svg width=256 height=16 data-width=32.17 data-height=2.203 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/01/010/010a92fb5bc4bca8af5d9efde0a8a097.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/01/010/010a92fb5bc4bca8af5d9efde0a8a097.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;4. Раскладываем &lt;img class=&#34;formula inline&#34; source=s(t) alt=s(t) src=https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg width=24 height=16 data-width=3.638 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/4f/4f3/4f37783823fc5bcb18cec232f7563904.svg 781w&#34; loading=lazy decode=async&gt; на линейные множители:&lt;/p&gt;&lt;img class=formula source=&#34;s(t) = (t + 1) (t + 6) (t + 7) (t + 8) (t + 9)&#34; alt=&#34;s(t) = (t + 1) (t + 6) (t + 7) (t + 8) (t + 9)&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8b/8b8/8b8a1b7002161473895ab38af52546cd.svg width=312 height=16 data-width=39.024 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8b/8b8/8b8a1b7002161473895ab38af52546cd.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8b/8b8/8b8a1b7002161473895ab38af52546cd.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;5. Применяем обратную перестановку к полученным корням:&lt;/p&gt;&lt;img class=formula source=&#34;\pi^{-1}(1) = 8, \pi^{-1}(6) = 1, \pi^{-1}(7) = 2, \pi^{-1}(8) = 4, \pi^{-1}(9) = 10&#34; alt=&#34;\pi^{-1}(1) = 8, \pi^{-1}(6) = 1, \pi^{-1}(7) = 2, \pi^{-1}(8) = 4, \pi^{-1}(9) = 10&#34; src=https://habrastorage.org/getpro/habr/formulas/3/39/396/3964aa0c54f81c9bc47afd2a1fa1a423.svg width=456 height=16 data-width=57.963 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/39/396/3964aa0c54f81c9bc47afd2a1fa1a423.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/39/396/3964aa0c54f81c9bc47afd2a1fa1a423.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;следовательно, &lt;img class=&#34;formula inline&#34; source=&#34;M = (0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1)&#34; alt=&#34;M = (0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1)&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg width=232 height=16 data-width=29.659 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cb/cba/cbaa4d6007e016ff8b1383a4d7dcd3d9.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;6. Используя алгоритм 3, восстанавливаем исходное сообщение &lt;img class=&#34;formula inline&#34; source=&#34;m = 217&#34; alt=&#34;m = 217&#34; src=https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg width=64 height=12 data-width=8.397 data-height=1.715 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/bc/bcc/bcce3a204263ef15e988fe34fe2a2bc9.svg 781w&#34; loading=lazy decode=async&gt;.&lt;h2&gt;Вот и все&lt;/h2&gt;&lt;p&gt;Спасибо всем, кто прочитал статью! Если тема оказалась вам интересна - следите за выходом следующих статей.&lt;p&gt;Буду рад, если подпишетесь на мой профиль на Хабре и на &lt;a href=https://t.me/orikanblog rel=&#34;noopener noreferrer nofollow&#34;&gt;личный блог&lt;/a&gt;: там я публикую свои статьи, проекты, новости и заметки об интересных технологиях. Также код из статьи доступен в &lt;a href=https://github.com/orikanx/crypto-examples rel=&#34;noopener noreferrer nofollow&#34;&gt;GitHub-репозитории&lt;/a&gt; в формате Jupyter Notebook.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>orikan</author>
      <guid>https://habr.com/ru/articles/1051214/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051214</guid>
      <pubDate>Wed, 24 Jun 2026 16:09:03 +0000</pubDate>
    </item>
    <item>
      <title>HyperLogLog: как найти уникальные значения в терабайте данных, не храня их</title>
      <link>https://habr.com/ru/companies/timeweb/articles/1046345/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1046345</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Представим задачу: хайлоад-сервис гонит поток данных — логи, IP-адреса, ID пользователей, миллиарды записей в сутки. Ваша задача — посчитать количество уникальных посетителей за неделю.&lt;p&gt;Первым решением может показаться завести HashSet и кидать туда ключи, а в конце посмотреть размер. Решение неплохое, но когда речь заходит о миллиардах записей — память будет слабым местом. Один IP-адрес (4 байта) как ключ в HashSet потянет за собой накладные расходы на ноды, указатели и хеши. На практике один элемент сжирает не меньше 50–100 байт. Поток в миллиард уникальных записей потребует под сотню гигабайт оперативной памяти. Это дорого, а если инстансов десять — то просто нереально.&lt;p&gt;Но существует алгоритм, который способен решить эту задачу примерно в 1.5 килобайта памяти с погрешностью около 2%? Без хранения самих данных и гигантских кластеров. Достаточно одного прохода по потоку и пары битовых трюков — именно так и работает HyperLogLog, алгоритм родом из математической статистики, который перевернул подход к подсчёту уникальности в Big Data.&lt;p&gt;HyperLogLog используют в Redis, BigQuery, ClickHouse, Presto. В этой статье мы разберем и реализуем этот алгоритм на C, а также узнаем его предысторию.&lt;hr&gt;&lt;h3&gt;❯ Probabilistic Counting&lt;/h3&gt;&lt;p&gt;Прежде чем нырять в код HyperLogLog, сделаем шаг назад. В основе всех вероятностных алгоритмов подсчёта лежит удивительно простая идея, которую в 1985 году предложили Флажоле и Мартин.&lt;p&gt;Если мы хешируем каждый элемент в случайное 64-битное число, то чем больше уникальных элементов мы уже увидели, тем выше вероятность, что среди их хешей найдется число с очень длинной последовательностью ведущих нулей. И эта суть сохранена до сих пор, HyperLogLog будет использовать идею, что вероятность того, что случайный хеш начинается как минимум с &lt;img class=&#34;formula inline&#34; source=n alt=n src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg width=12 height=12 data-width=1.357 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w&#34; loading=lazy decode=async&gt; нулей, равна &lt;img class=&#34;formula inline&#34; source=2^{-n} alt=2^{-n} src=https://habrastorage.org/getpro/habr/formulas/8/81/817/81733494e0a964b506e21c93d67e2b1b.svg width=24 height=12 data-width=3.524 data-height=1.867 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/81/817/81733494e0a964b506e21c93d67e2b1b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/81/817/81733494e0a964b506e21c93d67e2b1b.svg 781w&#34; loading=lazy decode=async&gt;. Например, шанс встретить хеш с 30 ведущими нулями — примерно одна миллиардная (&lt;img class=&#34;formula inline&#34; source=&#34;2^{-30} \approx 9.3 \times 10^{-10}&#34; alt=&#34;2^{-30} \approx 9.3 \times 10^{-10}&#34; src=https://habrastorage.org/getpro/habr/formulas/7/79/790/790ca6e101de69fecb2ba4827128cba1.svg width=144 height=16 data-width=18.132 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/79/790/790ca6e101de69fecb2ba4827128cba1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/79/790/790ca6e101de69fecb2ba4827128cba1.svg 781w&#34; loading=lazy decode=async&gt;).&lt;p&gt;Обычно как пример берут подбрасывание монетки. Я не буду изменять традициям, и также давайте представим что мы бросаем монету. Вероятность выпадения орла — &lt;img class=&#34;formula inline&#34; source=1/2 alt=1/2 src=https://habrastorage.org/getpro/habr/formulas/9/97/975/975ca8804565c1a569450d61090b2743.svg width=24 height=16 data-width=3.394 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/97/975/975ca8804565c1a569450d61090b2743.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/97/975/975ca8804565c1a569450d61090b2743.svg 781w&#34; loading=lazy decode=async&gt;, двух орлов подряд — &lt;img class=&#34;formula inline&#34; source=1/4 alt=1/4 src=https://habrastorage.org/getpro/habr/formulas/f/ff/ff8/ff8bed43ac09b1148fc7648f5845f698.svg width=24 height=16 data-width=3.394 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/ff/ff8/ff8bed43ac09b1148fc7648f5845f698.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/ff/ff8/ff8bed43ac09b1148fc7648f5845f698.svg 781w&#34; loading=lazy decode=async&gt;, девяти орлов подряд — &lt;img class=&#34;formula inline&#34; source=1/512 alt=1/512 src=https://habrastorage.org/getpro/habr/formulas/1/12/12e/12e6b3275956d5a4836731170d04643d.svg width=40 height=16 data-width=5.656 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/12/12e/12e6b3275956d5a4836731170d04643d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/12/12e/12e6b3275956d5a4836731170d04643d.svg 781w&#34; loading=lazy decode=async&gt;. Если вы увидели последовательность из 9 орлов, вы с высокой вероятностью сделали больше 500 бросков.&lt;p&gt;С хешами — та же история. Вероятность встретить хеш, начинающийся с 9 нулей, равна &lt;img class=&#34;formula inline&#34; source=&#34;2^{-9} \approx 1/512&#34; alt=&#34;2^{-9} \approx 1/512&#34; src=https://habrastorage.org/getpro/habr/formulas/d/db/dba/dba27af6dd95180a0a1aff48e918b021.svg width=96 height=16 data-width=12.037 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/db/dba/dba27af6dd95180a0a1aff48e918b021.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/db/dba/dba27af6dd95180a0a1aff48e918b021.svg 781w&#34; loading=lazy decode=async&gt;. Если мы нашли такой хеш — скорее всего, уникальных элементов не меньше нескольких сотен. Если нашли 30 нулей подряд — их уже миллиард.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/63/3e/f9/633ef9efa4cf0faa0cdf202cab1af788.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/63/3e/f9/633ef9efa4cf0faa0cdf202cab1af788.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/63/3e/f9/633ef9efa4cf0faa0cdf202cab1af788.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Работает это так, ибо хорошая хеш-функция распределяет биты равномерно. Вероятность конкретного паттерна из нулей и единиц — чистая степень двойки. Мы не храним сами элементы — только наблюдаем за случайностью их хешей.&lt;p&gt;Этот наивный метод называется Probabilistic Counting. У него есть одна огромная проблема: чудовищная дисперсия. Если вам случайно попался хеш с 30 нулями, ваша оценка улетит в миллиарды, даже если вы обработали всего сто элементов.&lt;p&gt;Нужно усреднять! Но как усреднять то, что может взлетать на порядки? Ответ пришёл через 18 лет — в 2003 году.&lt;h3&gt;❯ LogLog&lt;/h3&gt;&lt;p&gt;В 2003 году Дюран и Флажоле предложили весьма красивое решение проблемы выбросов. Все гениальное просто, так что и здесь решение оказалось несложным — разделение хеша на две части и использование корзин (регистров). Когда счетчик не один, а много, каждый из них наблюдает за своей частью данных, а в конце мы просто приводим среднее арифметическое.&lt;p&gt;Представьте, что 64-битный хеш — это длинная полоска битов. Вы режете её на две части:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Первые &lt;img class=&#34;formula inline&#34; source=P alt=P src=https://habrastorage.org/getpro/habr/formulas/4/44/44c/44c29edb103a2872f519ad0c9a0fdaaa.svg width=12 height=12 data-width=1.699 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/44/44c/44c29edb103a2872f519ad0c9a0fdaaa.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/44/44c/44c29edb103a2872f519ad0c9a0fdaaa.svg 781w&#34; loading=lazy decode=async&gt; битов — это номер корзины (регистра). Всего у вас будет &lt;img class=&#34;formula inline&#34; source=&#34;M = 2^P&#34; alt=&#34;M = 2^P&#34; src=https://habrastorage.org/getpro/habr/formulas/9/94/943/943326d0eb1ae0e6d90bbb85c7849d9b.svg width=56 height=16 data-width=7.915 data-height=2.213 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/94/943/943326d0eb1ae0e6d90bbb85c7849d9b.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/94/943/943326d0eb1ae0e6d90bbb85c7849d9b.svg 781w&#34; loading=lazy decode=async&gt; корзин.&lt;li&gt;&lt;p&gt;Оставшиеся &lt;img class=&#34;formula inline&#34; source=&#34;64 - P&#34; alt=&#34;64 - P&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ed/ed1/ed1aad716228c150a7fe03da89109da7.svg width=48 height=12 data-width=6.727 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ed/ed1/ed1aad716228c150a7fe03da89109da7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ed/ed1/ed1aad716228c150a7fe03da89109da7.svg 781w&#34; loading=lazy decode=async&gt; битов — это некая «полезная нагрузка», на которой вы будете искать ведущие нули.&lt;/ol&gt;&lt;p&gt;Давайте возьмем, что &lt;img class=&#34;formula inline&#34; source=&#34;P = 3&#34; alt=&#34;P = 3&#34; src=https://habrastorage.org/getpro/habr/formulas/b/b6/b6a/b6a54a3f7b21babb61ca5e1e2a51368f.svg width=40 height=12 data-width=5.847 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b6/b6a/b6a54a3f7b21babb61ca5e1e2a51368f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b6/b6a/b6a54a3f7b21babb61ca5e1e2a51368f.svg 781w&#34; loading=lazy decode=async&gt; (8 корзин). Пусть хеш элемента равен &lt;code&gt;101100101110...&lt;/code&gt;:&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/ef/15/28/ef1528cfc7e81debd99791519b1b24da.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/ef/15/28/ef1528cfc7e81debd99791519b1b24da.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/ef/15/28/ef1528cfc7e81debd99791519b1b24da.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Каждая корзина хранит одно число — максимальную длину ведущих нулей, которую она когда-либо видела в своём остатке. Только максимум, потому что нас интересует самая редкая случайность.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/9b/63/07/9b63072b171b27a72c84e0ce87fe52bc.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/9b/63/07/9b63072b171b27a72c84e0ce87fe52bc.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/9b/63/07/9b63072b171b27a72c84e0ce87fe52bc.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;К концу обработки в корзине №5 будет лежать число 5 — максимальная длина ведущих нулей, встреченная среди всех элементов, чей хеш начинался с &lt;code&gt;101&lt;/code&gt;.&lt;p&gt;Но почему это работает?&lt;p&gt;У нас есть &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; независимых наблюдателей, и если в одной корзине произошла аномалия (скажем, rank = 40), остальные &lt;img class=&#34;formula inline&#34; source=M-1 alt=M-1 src=https://habrastorage.org/getpro/habr/formulas/7/7f/7f8/7f8e22c19b2513613769168973edab29.svg width=48 height=12 data-width=6.275 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7f/7f8/7f8e22c19b2513613769168973edab29.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7f/7f8/7f8e22c19b2513613769168973edab29.svg 781w&#34; loading=lazy decode=async&gt; корзин дают нормальные значения. При усреднении выброс потеряет свою разрушительную силу дисперсии.&lt;p&gt;Формула оценки LogLog выглядит так:&lt;/p&gt;&lt;img class=formula source=&#34;\hat{n} = \alpha_M \cdot M \cdot 2^{\frac{1}{M} \sum_{j=1}^{M} R_j}&#34; alt=&#34;\hat{n} = \alpha_M \cdot M \cdot 2^{\frac{1}{M} \sum_{j=1}^{M} R_j}&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5b/5b6/5b614e2a8a7b155332771c87a00ee068.svg width=176 height=24 data-width=22.631 data-height=3.039 data-vertical-align=-0.954 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5b/5b6/5b614e2a8a7b155332771c87a00ee068.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5b/5b6/5b614e2a8a7b155332771c87a00ee068.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Где:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=R_j alt=R_j src=https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg width=16 height=16 data-width=2.564 data-height=2.211 data-vertical-align=-0.666 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg 781w&#34; loading=lazy decode=async&gt; — значение в &lt;img class=&#34;formula inline&#34; source=j alt=j src=https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg width=12 height=12 data-width=0.932 data-height=1.957 data-vertical-align=-0.462 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/36/363/363b122c528f54df4a0446b6bab05515.svg 781w&#34; loading=lazy decode=async&gt;-й корзине (максимальный ранг)&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; — количество корзин&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=\alpha alt=\alpha src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b7/7b7f9dbfea05c83784f8b85149852f08.svg width=12 height=16 data-width=1.448 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b7/7b7f9dbfea05c83784f8b85149852f08.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b7/7b7f9dbfea05c83784f8b85149852f08.svg 781w&#34; loading=lazy decode=async&gt; — корректирующий множитель (&lt;img class=&#34;formula inline&#34; source=&#34;\approx 0.7&#34; alt=&#34;\approx 0.7&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a5/a55/a55b9ad0cac4707444e9359983bf1dfb.svg width=40 height=16 data-width=5.28 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a5/a55/a55b9ad0cac4707444e9359983bf1dfb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a5/a55/a55b9ad0cac4707444e9359983bf1dfb.svg 781w&#34; loading=lazy decode=async&gt;)&lt;/ul&gt;&lt;p&gt;Разберём формулу по частям. Допустим, вы усреднили все ранги и получили 10, и тогда &lt;img class=&#34;formula inline&#34; source=&#34;2^{10} = 1024&#34; alt=&#34;2^{10} = 1024&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d9/d97/d97d16fbb399fa909887f8349724a08a.svg width=80 height=16 data-width=10.461 data-height=2.185 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d9/d97/d97d16fbb399fa909887f8349724a08a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d9/d97/d97d16fbb399fa909887f8349724a08a.svg 781w&#34; loading=lazy decode=async&gt; — это ваша «типичная» кардинальность в расчёте на одну корзину. Умножаете на &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; корзин — получаете общую оценку.&lt;p&gt;Но почему алгоритм называется LogLog? Почему логарифм, и почему двойной? Если просто, в алгоритме фигурирует логарифм от логарифма.&lt;p&gt;Вдумайтесь: если у вас миллиард уникальных элементов, ожидаемый максимальный ранг будет около &lt;img class=&#34;formula inline&#34; source=&#34;\log_2(10^9) \approx 30&#34; alt=&#34;\log_2(10^9) \approx 30&#34; src=https://habrastorage.org/getpro/habr/formulas/6/64/64f/64f17aaa7a077a700851f51d753b10f2.svg width=112 height=16 data-width=14.169 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/64/64f/64f17aaa7a077a700851f51d753b10f2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/64/64f/64f17aaa7a077a700851f51d753b10f2.svg 781w&#34; loading=lazy decode=async&gt;. А само значение в регистре — это и есть ранг. То есть вы храните не сами элементы и даже не их количество, а логарифм количества.&lt;p&gt;Но ведь &lt;img class=&#34;formula inline&#34; source=30 alt=30 src=https://habrastorage.org/getpro/habr/formulas/3/34/341/34173cb38f07f89ddbebc2ac9128303f.svg width=16 height=12 data-width=2.262 data-height=1.557 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/34/341/34173cb38f07f89ddbebc2ac9128303f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/34/341/34173cb38f07f89ddbebc2ac9128303f.svg 781w&#34; loading=lazy decode=async&gt; — это число. Какой тут второй логарифм? А вот какой: количество регистров &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; обычно выбирают от 16 до 65536. Это &lt;img class=&#34;formula inline&#34; source=2^4 alt=2^4 src=https://habrastorage.org/getpro/habr/formulas/2/27/27e/27eac782422adb62c41a6f3c2c99a5d1.svg width=16 height=16 data-width=2.119 data-height=2.017 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/27/27e/27eac782422adb62c41a6f3c2c99a5d1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/27/27e/27eac782422adb62c41a6f3c2c99a5d1.svg 781w&#34; loading=lazy decode=async&gt; до &lt;img class=&#34;formula inline&#34; source=2^{16} alt=2^{16} src=https://habrastorage.org/getpro/habr/formulas/3/3c/3ca/3ca2a55527f9b3df8d7e4b849a6c7b68.svg width=16 height=16 data-width=2.919 data-height=2 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3c/3ca/3ca2a55527f9b3df8d7e4b849a6c7b68.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3c/3ca/3ca2a55527f9b3df8d7e4b849a6c7b68.svg 781w&#34; loading=lazy decode=async&gt;. Число бит, нужное для хранения одного регистра — это &lt;img class=&#34;formula inline&#34; source=&#34;\log_2(\text{максимальный ранг}) \approx \log_2(64) = 6&#34; alt=&#34;\log_2(\text{максимальный ранг}) \approx \log_2(64) = 6&#34; src=https://habrastorage.org/getpro/habr/formulas/8/8e/8eb/8ebad0c9d41a292bcab74eb03568827c.svg width=336 height=16 data-width=42.991 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/8e/8eb/8ebad0c9d41a292bcab74eb03568827c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/8e/8eb/8ebad0c9d41a292bcab74eb03568827c.svg 781w&#34; loading=lazy decode=async&gt; бит.&lt;p&gt;Получается:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Первый логарифм: сам ранг — это &lt;img class=&#34;formula inline&#34; source=&#34;\log_2(\text{количество элементов в корзине})&#34; alt=&#34;\log_2(\text{количество элементов в корзине})&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d8/d80/d80060dedf61280e6edba6a998c43272.svg width=344 height=16 data-width=43.988 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d8/d80/d80060dedf61280e6edba6a998c43272.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d8/d80/d80060dedf61280e6edba6a998c43272.svg 781w&#34; loading=lazy decode=async&gt;&lt;li&gt;&lt;p&gt;Второй логарифм: количество бит на регистр — это &lt;img class=&#34;formula inline&#34; source=&#34;\log_2(\log_2(\text{максимальный ранг}))&#34; alt=&#34;\log_2(\log_2(\text{максимальный ранг}))&#34; src=https://habrastorage.org/getpro/habr/formulas/7/7e/7e7/7e7a6b532956d3ad739bbf693d3fe094.svg width=264 height=16 data-width=33.564 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7e/7e7/7e7a6b532956d3ad739bbf693d3fe094.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7e/7e7/7e7a6b532956d3ad739bbf693d3fe094.svg 781w&#34; loading=lazy decode=async&gt;&lt;/ol&gt;&lt;p&gt;Итоговая память: &lt;img class=&#34;formula inline&#34; source=&#34;M \cdot \log_2(\log_2(n_{\text{max}}))&#34; alt=&#34;M \cdot \log_2(\log_2(n_{\text{max}}))&#34; src=https://habrastorage.org/getpro/habr/formulas/5/57/57a/57a837cf49ba54cc6509a097ab8b9ab8.svg width=152 height=16 data-width=19.813 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/57/57a/57a837cf49ba54cc6509a097ab8b9ab8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/57/57a/57a837cf49ba54cc6509a097ab8b9ab8.svg 781w&#34; loading=lazy decode=async&gt; бит. Для &lt;img class=&#34;formula inline&#34; source=&#34;M = 16384&#34; alt=&#34;M = 16384&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg width=88 height=12 data-width=11.051 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 781w&#34; loading=lazy decode=async&gt; и &lt;img class=&#34;formula inline&#34; source=n alt=n src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg width=12 height=12 data-width=1.357 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w&#34; loading=lazy decode=async&gt; до миллиарда это около &lt;img class=&#34;formula inline&#34; source=&#34;16384 \times 6&#34; alt=&#34;16384 \times 6&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e7/e7e/e7e8631b19f5dab1d1511800c7c0c8e1.svg width=72 height=16 data-width=9.553 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e7/e7e/e7e8631b19f5dab1d1511800c7c0c8e1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e7/e7e/e7e8631b19f5dab1d1511800c7c0c8e1.svg 781w&#34; loading=lazy decode=async&gt; бит &lt;img class=&#34;formula inline&#34; source=&#34;\approx 12&#34; alt=&#34;\approx 12&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ee/ee7/ee7c9d1213118f25dcb5762bb7051c21.svg width=32 height=16 data-width=4.651 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ee/ee7/ee7c9d1213118f25dcb5762bb7051c21.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ee/ee7/ee7c9d1213118f25dcb5762bb7051c21.svg 781w&#34; loading=lazy decode=async&gt; КБ. Алгоритм использует память, которая растёт как двойной логарифм от кардинальности.&lt;p&gt;Вроде бы все хорошо и прекрасно. Но внимательный читатель заметил, что мы разбираем HyperLogLog, значит где-то LogLog имеет погрешность.&lt;p&gt;И эта погрешность таится в арифметическом среднем. Вроде все логично — сложили все &lt;img class=&#34;formula inline&#34; source=R_j alt=R_j src=https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg width=16 height=16 data-width=2.564 data-height=2.211 data-vertical-align=-0.666 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b9/b9b/b9bfc05d744cd7d809107cb567db9dd5.svg 781w&#34; loading=lazy decode=async&gt;, поделили на &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt;, но здесь как раз и есть скрытый недостаток.&lt;p&gt;Вспомните, что ранг — это степень двойки в оценке. Если вы ошиблись на 1 в ранге, то оценка изменится в два раза. Арифметическое среднее на таких экспоненциальных величинах работает плохо.&lt;p&gt;Представьте две корзины со значениями 10 и 20. Арифметическое среднее &lt;img class=&#34;formula inline&#34; source=&#34;= 15&#34; alt=&#34;= 15&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a8/a82/a8290e4980528ba20c7e2558d6b2a8d4.svg width=32 height=12 data-width=4.651 data-height=1.692 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a8/a82/a8290e4980528ba20c7e2558d6b2a8d4.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a8/a82/a8290e4980528ba20c7e2558d6b2a8d4.svg 781w&#34; loading=lazy decode=async&gt;, &lt;img class=&#34;formula inline&#34; source=&#34;2^{15} = 32768&#34; alt=&#34;2^{15} = 32768&#34; src=https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c50c7f8d9c3e1a0c8a1c256d4adfd7e.svg width=88 height=16 data-width=11.592 data-height=2.185 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c50c7f8d9c3e1a0c8a1c256d4adfd7e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1c/1c5/1c50c7f8d9c3e1a0c8a1c256d4adfd7e.svg 781w&#34; loading=lazy decode=async&gt;. Но правильное усреднение должно быть ближе к геометрическому: &lt;img class=&#34;formula inline&#34; source=&#34;\sqrt{2^{10} \cdot 2^{20}} = 2^{15} = 32768&#34; alt=&#34;\sqrt{2^{10} \cdot 2^{20}} = 2^{15} = 32768&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9f/9fb/9fb5be5752a470f76851952c2bcc69af.svg width=192 height=16 data-width=24.011 data-height=2.953 data-vertical-align=-0.911 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9f/9fb/9fb5be5752a470f76851952c2bcc69af.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9f/9fb/9fb5be5752a470f76851952c2bcc69af.svg 781w&#34; loading=lazy decode=async&gt; — совпало? Это случайность. А вот если значения 14 и 30: среднее &lt;img class=&#34;formula inline&#34; source=&#34;= 22&#34; alt=&#34;= 22&#34; src=https://habrastorage.org/getpro/habr/formulas/6/63/639/6397cc4f61c35fd96ea82e4933c9a997.svg width=32 height=12 data-width=4.651 data-height=1.692 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/63/639/6397cc4f61c35fd96ea82e4933c9a997.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/63/639/6397cc4f61c35fd96ea82e4933c9a997.svg 781w&#34; loading=lazy decode=async&gt;, &lt;img class=&#34;formula inline&#34; source=&#34;2^{22} = 4.2&#34; alt=&#34;2^{22} = 4.2&#34; src=https://habrastorage.org/getpro/habr/formulas/5/53/53c/53c17809dd094608a553e136fcc9acef.svg width=64 height=16 data-width=8.827 data-height=2.185 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/53/53c/53c17809dd094608a553e136fcc9acef.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/53/53c/53c17809dd094608a553e136fcc9acef.svg 781w&#34; loading=lazy decode=async&gt; миллиона. Настоящее среднее должно быть около &lt;img class=&#34;formula inline&#34; source=&#34;\sqrt{16384 \cdot 10^9} \approx 4&#34; alt=&#34;\sqrt{16384 \cdot 10^9} \approx 4&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e2/e28/e28353626f003dcdcf0e51763e8ee2e9.svg width=128 height=24 data-width=16.997 data-height=3.272 data-vertical-align=-1.07 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e2/e28/e28353626f003dcdcf0e51763e8ee2e9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e2/e28/e28353626f003dcdcf0e51763e8ee2e9.svg 781w&#34; loading=lazy decode=async&gt; миллиона — близко, но теперь представьте, что одна корзина показывает 30, а остальные 16383 показывают 10.&lt;p&gt;Арифметическое среднее: &lt;img class=&#34;formula inline&#34; source=&#34;(16383 \cdot 10 + 30)/16384 \approx 10.0012&#34; alt=&#34;(16383 \cdot 10 + 30)/16384 \approx 10.0012&#34; src=https://habrastorage.org/getpro/habr/formulas/6/6c/6cb/6cbf7bd806478086031d37dd582c13d1.svg width=264 height=16 data-width=33.562 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/6c/6cb/6cbf7bd806478086031d37dd582c13d1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/6c/6cb/6cbf7bd806478086031d37dd582c13d1.svg 781w&#34; loading=lazy decode=async&gt;, &lt;img class=&#34;formula inline&#34; source=&#34;2^{10.0012} \approx 1025&#34; alt=&#34;2^{10.0012} \approx 1025&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/ccc36c0836ebd5ca5d816c721381d595.svg width=112 height=16 data-width=14.105 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/ccc36c0836ebd5ca5d816c721381d595.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/ccc36c0836ebd5ca5d816c721381d595.svg 781w&#34; loading=lazy decode=async&gt;. Умножаем на &lt;img class=&#34;formula inline&#34; source=&#34;M = 16384 \rightarrow&#34; alt=&#34;M = 16384 \rightarrow&#34; src=https://habrastorage.org/getpro/habr/formulas/3/38/384/3842a6a0f74bee9673ebf6a2690c6539.svg width=104 height=16 data-width=13.942 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/38/384/3842a6a0f74bee9673ebf6a2690c6539.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/38/384/3842a6a0f74bee9673ebf6a2690c6539.svg 781w&#34; loading=lazy decode=async&gt; около 16.8 миллионов. А реальная кардинальность, если 16383 корзины видят 10 (&lt;img class=&#34;formula inline&#34; source=\sim1000 alt=\sim1000 src=https://habrastorage.org/getpro/habr/formulas/1/16/16b/16b22f6dae5ec6afa877c1d0d1b949b8.svg width=48 height=16 data-width=6.914 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/16/16b/16b22f6dae5ec6afa877c1d0d1b949b8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/16/16b/16b22f6dae5ec6afa877c1d0d1b949b8.svg 781w&#34; loading=lazy decode=async&gt; элементов каждая) — примерно 16 миллионов. Оценка завышена на 5% из-за одного выброса.&lt;p&gt;Звучит не страшно? Но если выброс будет 40 вместо 30, искажение вырастет. А в Probabilistic Counting с одной корзиной выброс 40 означал бы оценку &lt;img class=&#34;formula inline&#34; source=&#34;2^{40} \approx 1&#34; alt=&#34;2^{40} \approx 1&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f4/f41/f41cdd055c71afd487a5899523e0aeef.svg width=56 height=16 data-width=7.067 data-height=2.583 data-vertical-align=-0.726 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f4/f41/f41cdd055c71afd487a5899523e0aeef.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f4/f41/f41cdd055c71afd487a5899523e0aeef.svg 781w&#34; loading=lazy decode=async&gt; триллион вместо реальной тысячи. LogLog уже намного лучше, но всё ещё чувствителен.&lt;blockquote&gt;&lt;p&gt;Проще говоря, недостаток LogLog — это систематическая ошибка при малых кардинальностях (&lt;img class=&#34;formula inline&#34; source=&#34;\le 2.5M&#34; alt=&#34;\le 2.5M&#34; src=https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg width=56 height=16 data-width=7.658 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg 781w&#34; loading=lazy decode=async&gt;).&lt;/blockquote&gt;&lt;p&gt;Проблема остаётся: арифметическое среднее и экспоненциальные величины — плохие друзья. Нужно что-то более устойчивое к выбросам. Именно эту проблему решил HyperLogLog в 2007 году, заменив арифметическое среднее на гармоническое в пространстве обратных степеней двойки.&lt;h3&gt;❯ HyperLogLog&lt;/h3&gt;&lt;p&gt;LogLog сделал большой шаг вперед, уменьшив дисперсию в &lt;img class=&#34;formula inline&#34; source=\sqrt{M} alt=\sqrt{M} src=https://habrastorage.org/getpro/habr/formulas/6/65/654/654180c7e2291ffefb5a8ee9ec480b20.svg width=32 height=16 data-width=4.308 data-height=2.866 data-vertical-align=-0.867 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/65/654/654180c7e2291ffefb5a8ee9ec480b20.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/65/654/654180c7e2291ffefb5a8ee9ec480b20.svg 781w&#34; loading=lazy decode=async&gt; раз, но проблема арифметического среднего осталась. Если одна корзина получает аномально высокий ранг, это все еще искажает оценку из-за арифметического среднего. Как в том анекдоте — «я ем мясо, ты ешь капусту, а в среднем мы едим голубцы».&lt;p&gt;В 2007 году Флажоле с соавторами опубликовали HyperLogLog — алгоритм с небольшим изменением, которое сильно бустануло точность. Ключевое открытие звучит неожиданно просто: замените арифметическое среднее на гармоническое в пространстве обратных степеней двойки.&lt;p&gt;В чём здесь магия? Когда регистр получает аномально высокий ранг (например, 30), его вклад в арифметическое среднее — это 30, что заметно сдвигает сумму. А в гармоническом варианте его вклад — это &lt;img class=&#34;formula inline&#34; source=2^{-30} alt=2^{-30} src=https://habrastorage.org/getpro/habr/formulas/7/7a/7a7/7a7bbb63ae5d9d86601c761fc7b3cc29.svg width=32 height=16 data-width=4.163 data-height=2 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7a/7a7/7a7bbb63ae5d9d86601c761fc7b3cc29.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7a/7a7/7a7bbb63ae5d9d86601c761fc7b3cc29.svg 781w&#34; loading=lazy decode=async&gt;, то есть примерно одна миллиардная. Такой регистр просто перестаёт влиять на итоговую сумму, словно его и не было. Выбросы автоматически нейтрализуются самой природой гармонического усреднения.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/92/96/10/929610b76c59eccce361c80af967972b.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/92/96/10/929610b76c59eccce361c80af967972b.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/92/96/10/929610b76c59eccce361c80af967972b.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Формула оценки HyperLogLog выглядит так:&lt;/p&gt;&lt;img class=formula source=&#34;Z = \sum_{j=1}^{M} 2^{-R_j}&#34; alt=&#34;Z = \sum_{j=1}^{M} 2^{-R_j}&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a8/a87/a87571b56088db2ce4e302efab4daba3.svg width=96 height=48 data-width=12.674 data-height=6.935 data-vertical-align=-2.902 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a8/a87/a87571b56088db2ce4e302efab4daba3.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a8/a87/a87571b56088db2ce4e302efab4daba3.svg 781w&#34; loading=lazy decode=async&gt;&lt;img class=formula source=&#34;\hat{n} = \alpha_M \cdot \frac{M^2}{Z}&#34; alt=&#34;\hat{n} = \alpha_M \cdot \frac{M^2}{Z}&#34; src=https://habrastorage.org/getpro/habr/formulas/7/71/71f/71f4d1e4cec5ad9651653237eb45af89.svg width=104 height=32 data-width=13.809 data-height=4.968 data-vertical-align=-1.918 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/71/71f/71f4d1e4cec5ad9651653237eb45af89.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/71/71f/71f4d1e4cec5ad9651653237eb45af89.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Где &lt;img class=&#34;formula inline&#34; source=\alpha_M alt=\alpha_M src=https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg width=24 height=16 data-width=3.317 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg 781w&#34; loading=lazy decode=async&gt; — корректирующий множитель, который зависит от количества регистров и вычисляется по формуле:&lt;/p&gt;&lt;img class=formula source=&#34;\alpha_M = 0.7213 \cdot \left(1 + \frac{1.079}{M}\right)^{-1}&#34; alt=&#34;\alpha_M = 0.7213 \cdot \left(1 + \frac{1.079}{M}\right)^{-1}&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5e/5e6/5e67a35e17b81ca4dcf708d61fee7eb0.svg width=232 height=40 data-width=29.863 data-height=5.876 data-vertical-align=-2.372 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5e/5e6/5e67a35e17b81ca4dcf708d61fee7eb0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5e/5e6/5e67a35e17b81ca4dcf708d61fee7eb0.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Для разных значений &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt; используются заранее вычисленные константы, но в общем случае подходит эта формула.&lt;p&gt;Однако гармоническое усреднение — это только половина решения. Вторая проблема LogLog заключалась в систематической ошибке при малых кардинальностях (когда количество уникальных элементов меньше &lt;img class=&#34;formula inline&#34; source=2.5M alt=2.5M src=https://habrastorage.org/getpro/habr/formulas/5/59/59a/59a7a4f4c335dc10a6531bc2c0792be2.svg width=40 height=12 data-width=5.269 data-height=1.595 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/59/59a/59a7a4f4c335dc10a6531bc2c0792be2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/59/59a/59a7a4f4c335dc10a6531bc2c0792be2.svg 781w&#34; loading=lazy decode=async&gt;). Причина проста: если многие регистры ещё пусты (их значение равно 0), то &lt;img class=&#34;formula inline&#34; source=&#34;2^{-0} = 1&#34; alt=&#34;2^{-0} = 1&#34; src=https://habrastorage.org/getpro/habr/formulas/0/04/04c/04c27c2ced21ff2ea86420836c0e7218.svg width=56 height=16 data-width=7.512 data-height=2.185 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/04/04c/04c27c2ced21ff2ea86420836c0e7218.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/04/04c/04c27c2ced21ff2ea86420836c0e7218.svg 781w&#34; loading=lazy decode=async&gt;, и такие регистры дают одинаковый вклад в сумму, искажая оценку.&lt;p&gt;HyperLogLog решает и эту проблему с помощью трёхуровневой коррекции:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Малые кардинальности (оценка &lt;img class=&#34;formula inline&#34; source=&#34;\le 2.5M&#34; alt=&#34;\le 2.5M&#34; src=https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg width=56 height=16 data-width=7.658 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/23/233/233cd0f27ecdb7978c154a0d3ecd25ce.svg 781w&#34; loading=lazy decode=async&gt;): если есть пустые регистры, используется линейная оценка &lt;img class=&#34;formula inline&#34; source=&#34;n = M \cdot \ln(M / V)&#34; alt=&#34;n = M \cdot \ln(M / V)&#34; src=https://habrastorage.org/getpro/habr/formulas/a/a7/a7e/a7e27537500880617b002166b41f48bf.svg width=136 height=16 data-width=17.283 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a7/a7e/a7e27537500880617b002166b41f48bf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a7/a7e/a7e27537500880617b002166b41f48bf.svg 781w&#34; loading=lazy decode=async&gt;, где &lt;img class=&#34;formula inline&#34; source=V alt=V src=https://habrastorage.org/getpro/habr/formulas/5/52/520/5206560a306a2e085a437fd258eb57ce.svg width=12 height=12 data-width=1.74 data-height=1.595 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/52/520/5206560a306a2e085a437fd258eb57ce.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/52/520/5206560a306a2e085a437fd258eb57ce.svg 781w&#34; loading=lazy decode=async&gt; — количество пустых регистров. Это даёт значительно более точный результат, чем сырая формула.&lt;li&gt;&lt;p&gt;Средние кардинальности: сырая оценка &lt;img class=&#34;formula inline&#34; source=&#34;\alpha M^2 / Z&#34; alt=&#34;\alpha M^2 / Z&#34; src=https://habrastorage.org/getpro/habr/formulas/4/44/44c/44cb146756307b98e4218eff7aa73b07.svg width=56 height=16 data-width=7.703 data-height=2.565 data-vertical-align=-0.717 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/44/44c/44cb146756307b98e4218eff7aa73b07.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/44/44c/44cb146756307b98e4218eff7aa73b07.svg 781w&#34; loading=lazy decode=async&gt; работает отлично.&lt;li&gt;&lt;p&gt;Очень большие кардинальности (близкие к &lt;img class=&#34;formula inline&#34; source=2^{32} alt=2^{32} src=https://habrastorage.org/getpro/habr/formulas/f/f1/f19/f19901f1c817ad846a411e6712e8db66.svg width=16 height=16 data-width=2.919 data-height=2 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f1/f19/f19901f1c817ad846a411e6712e8db66.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f1/f19/f19901f1c817ad846a411e6712e8db66.svg 781w&#34; loading=lazy decode=async&gt;): применяется дополнительная коррекция, учитывающая, что пространство хешей конечно.&lt;/ol&gt;&lt;p&gt;Благодаря этим улучшениям стандартная ошибка HyperLogLog составляет:&lt;/p&gt;&lt;img class=formula source=&#34;\text{StdError} = \frac{1.04}{\sqrt{M}}&#34; alt=&#34;\text{StdError} = \frac{1.04}{\sqrt{M}}&#34; src=https://habrastorage.org/getpro/habr/formulas/3/37/37a/37ac6f32e2cc050a46a74aea4e756ea8.svg width=136 height=40 data-width=17.049 data-height=5.369 data-vertical-align=-2.119 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/37/37a/37ac6f32e2cc050a46a74aea4e756ea8.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/37/37a/37ac6f32e2cc050a46a74aea4e756ea8.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Сравните с LogLog, у которого ошибка была примерно &lt;img class=&#34;formula inline&#34; source=&#34;1.3 / \sqrt{M}&#34; alt=&#34;1.3 / \sqrt{M}&#34; src=https://habrastorage.org/getpro/habr/formulas/1/1f/1f9/1f95a78a30d38f282be08b9c991a438d.svg width=64 height=16 data-width=8.33 data-height=2.866 data-vertical-align=-0.867 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/1f/1f9/1f95a78a30d38f282be08b9c991a438d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/1f/1f9/1f95a78a30d38f282be08b9c991a438d.svg 781w&#34; loading=lazy decode=async&gt;. Разница кажется небольшой, но на практике она означает, что для достижения той же точности HyperLogLog требует почти на треть меньше памяти. При &lt;img class=&#34;formula inline&#34; source=&#34;M = 16384&#34; alt=&#34;M = 16384&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg width=88 height=12 data-width=11.051 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 781w&#34; loading=lazy decode=async&gt; (16 КБ) ошибка составляет около 0.81% — то есть на 100 миллионах уникальных элементов вы ошибётесь примерно на 800 тысяч, а не на пару миллионов.&lt;blockquote&gt;&lt;p&gt;В итоге, HyperLogLog использует гармоническое среднее против выбросов, а коррекцию — против систематической ошибки при малых &lt;img class=&#34;formula inline&#34; source=n alt=n src=https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg width=12 height=12 data-width=1.357 data-height=1.025 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/7b/7b8/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w&#34; loading=lazy decode=async&gt;.&lt;/blockquote&gt;&lt;p&gt;И теперь, когда мы поняли концепцию, можно перейти к реализации на C.&lt;h3&gt;❯ Реализация на C&lt;/h3&gt;&lt;p&gt;Сам алгоритм (без учета хеш-алгоритма) обходится примерно в 100 строк кода, а памяти требуется ровно столько, сколько нужно для хранения регистров — 16 384 байта при выбранной нами точности &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;Прежде чем говорить о самом HyperLogLog, нужно уделить внимание хеш-функции. От её качества зависит всё: если хеш-функция распределяет биты неравномерно или имеет зависимости между битами, теоретические гарантии алгоритма рушатся.&lt;p&gt;Я взял MurmurHash3 — современную некриптографическую хеш-функцию, которая известна своей скоростью и отличным распределением. В реализации представлен 64-битный вариант этой функции, адаптированный специально для HyperLogLog.&lt;pre&gt;&lt;code class=cpp&gt;static inline uint64_t murmur3_fmix64(uint64_t k) {&#xA;    k ^= k &amp;gt;&amp;gt; 33;&#xA;    k *= 0xff51afd7ed558ccdULL;&#xA;    k ^= k &amp;gt;&amp;gt; 33;&#xA;    k *= 0xc4ceb9fe1a85ec53ULL;&#xA;    k ^= k &amp;gt;&amp;gt; 33;&#xA;    return k;&#xA;}&#xA;&#xA;static inline uint64_t murmur3_64(const void* key, size_t len, uint64_t seed) {&#xA;    const uint8_t* data = (const uint8_t*)key;&#xA;    const int nblocks = len / 16;&#xA;    uint64_t h1 = seed;&#xA;    uint64_t h2 = seed;&#xA;&#xA;    const uint64_t c1 = 0x87c37b91114253d5ULL;&#xA;    const uint64_t c2 = 0x4cf5ad432745937fULL;&#xA;&#xA;    const uint64_t* blocks = (const uint64_t*)data;&#xA;&#xA;    for (int i = 0; i &amp;lt; nblocks; i++) {&#xA;        uint64_t k1 = blocks[i * 2];&#xA;        uint64_t k2 = blocks[i * 2 + 1];&#xA;&#xA;        k1 *= c1;&#xA;        k1 = (k1 &amp;lt;&amp;lt; 31) | (k1 &amp;gt;&amp;gt; 33);&#xA;        k1 *= c2;&#xA;        h1 ^= k1;&#xA;        h1 = (h1 &amp;lt;&amp;lt; 27) | (h1 &amp;gt;&amp;gt; 37);&#xA;        h1 += h2;&#xA;        h1 = h1 * 5 + 0x52dce729;&#xA;&#xA;        k2 *= c2;&#xA;        k2 = (k2 &amp;lt;&amp;lt; 33) | (k2 &amp;gt;&amp;gt; 31);&#xA;        k2 *= c1;&#xA;        h2 ^= k2;&#xA;        h2 = (h2 &amp;lt;&amp;lt; 31) | (h2 &amp;gt;&amp;gt; 33);&#xA;        h2 += h1;&#xA;        h2 = h2 * 5 + 0x38495ab5;&#xA;    }&#xA;&#xA;    const uint8_t* tail = data + nblocks * 16;&#xA;    uint64_t k1 = 0;&#xA;    uint64_t k2 = 0;&#xA;&#xA;    switch (len &amp;amp; 15) {&#xA;        case 15:&#xA;            k2 ^= (uint64_t)tail[14] &amp;lt;&amp;lt; 48;&#xA;        case 14:&#xA;            k2 ^= (uint64_t)tail[13] &amp;lt;&amp;lt; 40;&#xA;        case 13:&#xA;            k2 ^= (uint64_t)tail[12] &amp;lt;&amp;lt; 32;&#xA;        case 12:&#xA;            k2 ^= (uint64_t)tail[11] &amp;lt;&amp;lt; 24;&#xA;        case 11:&#xA;            k2 ^= (uint64_t)tail[10] &amp;lt;&amp;lt; 16;&#xA;        case 10:&#xA;            k2 ^= (uint64_t)tail[9] &amp;lt;&amp;lt; 8;&#xA;        case 9:&#xA;            k2 ^= (uint64_t)tail[8];&#xA;            k2 *= c2;&#xA;            k2 = (k2 &amp;lt;&amp;lt; 33) | (k2 &amp;gt;&amp;gt; 31);&#xA;            k2 *= c1;&#xA;            h2 ^= k2;&#xA;        case 8:&#xA;            k1 ^= (uint64_t)tail[7] &amp;lt;&amp;lt; 56;&#xA;        case 7:&#xA;            k1 ^= (uint64_t)tail[6] &amp;lt;&amp;lt; 48;&#xA;        case 6:&#xA;            k1 ^= (uint64_t)tail[5] &amp;lt;&amp;lt; 40;&#xA;        case 5:&#xA;            k1 ^= (uint64_t)tail[4] &amp;lt;&amp;lt; 32;&#xA;        case 4:&#xA;            k1 ^= (uint64_t)tail[3] &amp;lt;&amp;lt; 24;&#xA;        case 3:&#xA;            k1 ^= (uint64_t)tail[2] &amp;lt;&amp;lt; 16;&#xA;        case 2:&#xA;            k1 ^= (uint64_t)tail[1] &amp;lt;&amp;lt; 8;&#xA;        case 1:&#xA;            k1 ^= (uint64_t)tail[0];&#xA;            k1 *= c1;&#xA;            k1 = (k1 &amp;lt;&amp;lt; 31) | (k1 &amp;gt;&amp;gt; 33);&#xA;            k1 *= c2;&#xA;            h1 ^= k1;&#xA;    }&#xA;&#xA;    h1 ^= len;&#xA;    h2 ^= len;&#xA;    h1 += h2;&#xA;    h2 += h1;&#xA;&#xA;    h1 = murmur3_fmix64(h1);&#xA;    h2 = murmur3_fmix64(h2);&#xA;    h1 += h2;&#xA;    h2 += h1;&#xA;&#xA;    return h1;&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Эта функция обрабатывает входные данные блоками по 16 байт, перемешивая биты с помощью умножений и сдвигов. На выходе мы получаем 64 бита, которые ведут себя как равномерно случайные — идеальное сырьё для нашего вероятностного алгоритма.&lt;blockquote&gt;&lt;p&gt;Кстати, этот алгоритм в виде ГПСЧ я описывал в &lt;a href=https://habr.com/ru/companies/timeweb/articles/977208/&gt;одной из своих статей&lt;/a&gt;.&lt;/blockquote&gt;&lt;p&gt;Сама структура HyperLogLog удивительно проста — это массив 8-битных регистров:&lt;pre&gt;&lt;code class=cpp&gt;#define HLL_P 14&#xA;#define HLL_M (1 &amp;lt;&amp;lt; HLL_P)  // 16384&#xA;#define HLL_SEED 0xadc83b19adc83b19ULL&#xA;&#xA;typedef struct {&#xA;    uint8_t registers[HLL_M];&#xA;} HyperLogLog;&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Почему &lt;code&gt;uint8_t&lt;/code&gt;? Максимальный ранг, который мы можем получить, — это 64 минус количество битов, отданных под индекс регистра. При &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; максимальный ранг равен 50. Восьми битов (диапазон 0–255) более чем достаточно. Если бы мы захотели использовать &lt;img class=&#34;formula inline&#34; source=&#34;p=16&#34; alt=&#34;p=16&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg width=48 height=12 data-width=6.418 data-height=1.946 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg 781w&#34; loading=lazy decode=async&gt;, то максимальный ранг стал бы 48 — всё равно влезает в &lt;code&gt;uint8_t&lt;/code&gt;.&lt;p&gt;Инициализация сводится к обнулению всех регистров и подготовке таблицы обратных степеней двойки:&lt;pre&gt;&lt;code class=cpp&gt;static double* inv_pow2_table = NULL;&#xA;&#xA;static void hll_init_inv_pow2(void) {&#xA;    static int initialized = 0;&#xA;    if (initialized) return;&#xA;    for (int i = 0; i &amp;lt; 64; i++) {&#xA;        inv_pow2_table[i] = 1.0 / (double)(1ULL &amp;lt;&amp;lt; i);&#xA;    }&#xA;    initialized = 1;&#xA;}&#xA;&#xA;void hll_init(HyperLogLog* hll) {&#xA;    memset(hll-&amp;gt;registers, 0, HLL_M);&#xA;    hll_init_inv_pow2();&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Таблица &lt;code&gt;inv_pow2_table&lt;/code&gt; хранит предвычисленные значения &lt;img class=&#34;formula inline&#34; source=2^{-i} alt=2^{-i} src=https://habrastorage.org/getpro/habr/formulas/6/66/66a/66a4d38ef7f034ed57738df9a60f67a9.svg width=24 height=12 data-width=3.116 data-height=1.992 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/66/66a/66a4d38ef7f034ed57738df9a60f67a9.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/66/66a/66a4d38ef7f034ed57738df9a60f67a9.svg 781w&#34; loading=lazy decode=async&gt; для &lt;img class=&#34;formula inline&#34; source=i alt=i src=https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg width=12 height=12 data-width=0.781 data-height=1.52 data-vertical-align=-0.025 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/865/865c0c0b4ab0e063e5caa3387c1a8741.svg 781w&#34; loading=lazy decode=async&gt; от 0 до 63. Это небольшое ускорение: вместо того чтобы каждый раз вычислять степень двойки при оценке, мы просто берём готовое значение из массива.&lt;p&gt;Функция ранга — это то место, где битовые трюки встречаются с математикой (версия у меня упрощенная, &lt;code&gt;rho(w) = 1 + clz((w &amp;lt;&amp;lt; p) | (1ULL &amp;lt;&amp;lt; (p-1)))&lt;/code&gt;):&lt;pre&gt;&lt;code class=cpp&gt;static inline uint8_t hll_rank(uint64_t hash, uint8_t p) {&#xA;    uint64_t rest = hash &amp;lt;&amp;lt; p;&#xA;    if (rest == 0) {&#xA;        return 64 - p + 1;&#xA;    }&#xA;    return __builtin_clzll(rest) + 1;&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Разберём, что здесь происходит. На входе у нас есть 64-битный хеш. Первые &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; битов мы уже использовали для определения индекса корзины, поэтому они нас больше не интересуют. Мы сдвигаем хеш влево на &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; позиций, отбрасывая эти биты. В оставшихся &lt;img class=&#34;formula inline&#34; source=64-p alt=64-p src=https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg width=48 height=12 data-width=6.166 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg 781w&#34; loading=lazy decode=async&gt; битах мы ищем позицию первого единичного бита.&lt;p&gt;Функция &lt;code&gt;__builtin_clzll&lt;/code&gt; (count leading zeros) — это встроенная инструкция процессора, которая считает количество ведущих нулей в 64-битном числе. Большинство современных компиляторов (GCC, Clang) поддерживают её. Если бы мы писали код для Visual Studio, пришлось бы использовать &lt;code&gt;__lzcnt64&lt;/code&gt; или реализовывать эту операцию через битовые операции, но встроенная инструкция работает за один такт и значительно ускоряет алгоритм.&lt;p&gt;Особый случай — когда после сдвига все биты обнулились. Это означает, что в оставшихся &lt;img class=&#34;formula inline&#34; source=64-p alt=64-p src=https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg width=48 height=12 data-width=6.166 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/28/28f/28ff7ad778bfa0b6b2254b43ef5cee17.svg 781w&#34; loading=lazy decode=async&gt; битах не было ни одной единицы. Тогда ранг равен &lt;img class=&#34;formula inline&#34; source=64-p+1 alt=64-p+1 src=https://habrastorage.org/getpro/habr/formulas/2/2b/2be/2bec2cf47ce8f403120c2278fc43136a.svg width=80 height=12 data-width=10.063 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/2b/2be/2bec2cf47ce8f403120c2278fc43136a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/2b/2be/2bec2cf47ce8f403120c2278fc43136a.svg 781w&#34; loading=lazy decode=async&gt; (все биты нулевые, плюс единица за то, что мы «перешли» за границу).&lt;p&gt;Добавление элемента — это три простых шага: хеширование, определение индекса, обновление регистра.&lt;pre&gt;&lt;code class=cpp&gt;void hll_add(HyperLogLog* hll, const char* element) {&#xA;    uint64_t hash = murmur3_64_string(element, HLL_SEED);&#xA;    uint32_t index = hash &amp;gt;&amp;gt; (64 - HLL_P);&#xA;    uint8_t rank = hll_rank(hash, HLL_P);&#xA;    if (rank &amp;gt; hll-&amp;gt;registers[index]) {&#xA;        hll-&amp;gt;registers[index] = rank;&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Обратите внимание на вычисление индекса: &lt;code&gt;hash &amp;gt;&amp;gt; (64 - HLL_P)&lt;/code&gt;. Это эффективный способ взять старшие &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; битов хеша. При &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; мы сдвигаем 64-битное число вправо на 50 позиций, оставляя только 14 старших битов. Получается число от 0 до 16383 — идеальный индекс в массиве.&lt;p&gt;Функция &lt;code&gt;hll_rank&lt;/code&gt; получает тот же самый хеш, но работает с ним иначе: она использует биты после сдвига, как мы разобрали выше.&lt;p&gt;Функция оценки — самая объёмная часть, но она просто реализует трёхуровневую коррекцию, о которой мы говорили в теоретической части:&lt;pre&gt;&lt;code class=cpp&gt;uint64_t hll_estimate(const HyperLogLog* hll) {&#xA;    double sum = 0.0;&#xA;    int zero_registers = 0;&#xA;&#xA;    for (int i = 0; i &amp;lt; HLL_M; i++) {&#xA;        sum += inv_pow2_table[hll-&amp;gt;registers[i]];&#xA;        if (hll-&amp;gt;registers[i] == 0) zero_registers++;&#xA;    }&#xA;&#xA;    double raw = hll_alpha() * (double)((uint64_t)HLL_M * HLL_M) / sum;&#xA;&#xA;    if (raw &amp;lt;= 2.5 * HLL_M) {&#xA;        if (zero_registers &amp;gt; 0) {&#xA;            return (uint64_t)((double)HLL_M * log((double)HLL_M / (double)zero_registers));&#xA;        }&#xA;        return (uint64_t)raw;&#xA;    }&#xA;&#xA;    return (uint64_t)raw;&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Обратите внимание на использование &lt;code&gt;inv_pow2_table[registers[i]]&lt;/code&gt; — мы заранее вычислили &lt;img class=&#34;formula inline&#34; source=2^{-R} alt=2^{-R} src=https://habrastorage.org/getpro/habr/formulas/f/f4/f44/f44433e6aa70558081be40454ab38501.svg width=24 height=16 data-width=3.778 data-height=2.027 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f4/f44/f44433e6aa70558081be40454ab38501.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f4/f44/f44433e6aa70558081be40454ab38501.svg 781w&#34; loading=lazy decode=async&gt; для всех возможных &lt;img class=&#34;formula inline&#34; source=R alt=R src=https://habrastorage.org/getpro/habr/formulas/e/e1/e1e/e1e1d3d40573127e9ee0480caf1283d6.svg width=12 height=12 data-width=1.717 data-height=1.593 data-vertical-align=-0.048 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e1/e1e/e1e1d3d40573127e9ee0480caf1283d6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e1/e1e/e1e1d3d40573127e9ee0480caf1283d6.svg 781w&#34; loading=lazy decode=async&gt;. Это ускоряет подсчёт суммы, избавляя от вычисления степеней на лету.&lt;p&gt;Множитель &lt;code&gt;hll_alpha()&lt;/code&gt; зависит от точности &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; и вычисляется по формуле или по таблице:&lt;pre&gt;&lt;code class=cpp&gt;static double hll_alpha(uint8_t p, uint32_t m) {&#xA;    switch (p) {&#xA;    case 4:  return 0.673;&#xA;    case 5:  return 0.697;&#xA;    case 6:  return 0.709;&#xA;    case 7:  return 0.715;&#xA;    case 8:  return 0.718;&#xA;    case 9:  return 0.719;&#xA;    case 10: return 0.720;&#xA;    case 11: return 0.7205;&#xA;    default: return 0.7213 / (1.0 + 1.079 / (double)m);&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Для &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; (&lt;img class=&#34;formula inline&#34; source=&#34;M = 16384&#34; alt=&#34;M = 16384&#34; src=https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg width=88 height=12 data-width=11.051 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5b/5b2/5b211134a51850291028a2e56a51743c.svg 781w&#34; loading=lazy decode=async&gt;) формула даёт:&lt;/p&gt;&lt;img class=formula source=&#34;\alpha_{16384} = \frac{0.7213}{1 + 1.079/16384} \approx 0.72125&#34; alt=&#34;\alpha_{16384} = \frac{0.7213}{1 + 1.079/16384} \approx 0.72125&#34; src=https://habrastorage.org/getpro/habr/formulas/d/d3/d3f/d3fe94e8fd2c55b5ce5e813b1daf5c17.svg width=280 height=40 data-width=35.919 data-height=5.231 data-vertical-align=-2.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d3/d3f/d3fe94e8fd2c55b5ce5e813b1daf5c17.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d3/d3f/d3fe94e8fd2c55b5ce5e813b1daf5c17.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Это значение близко к пределу &lt;img class=&#34;formula inline&#34; source=0.7213 alt=0.7213 src=https://habrastorage.org/getpro/habr/formulas/3/3e/3e2/3e24e888e87f0c204e248f6fb7b98eb2.svg width=48 height=12 data-width=6.285 data-height=1.579 data-vertical-align=-0.05 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3e/3e2/3e24e888e87f0c204e248f6fb7b98eb2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3e/3e2/3e24e888e87f0c204e248f6fb7b98eb2.svg 781w&#34; loading=lazy decode=async&gt;, к которому стремится &lt;img class=&#34;formula inline&#34; source=\alpha_M alt=\alpha_M src=https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg width=24 height=16 data-width=3.317 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/1/15/15a/15a0dcf6f9dbbec00dde87fff5c1c9ff.svg 781w&#34; loading=lazy decode=async&gt; при росте &lt;img class=&#34;formula inline&#34; source=M alt=M src=https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg width=16 height=12 data-width=2.378 data-height=1.545 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/69/696/69691c7bdcc3ce6d5d8a1361f22d04ac.svg 781w&#34; loading=lazy decode=async&gt;.&lt;p&gt;Одно из важнейших свойств HyperLogLog — возможность объединять результаты. Если у вас есть два потока данных, обработанных независимо, вы можете слить их структуры и получить оценку для объединённого потока. Операция предельно проста: для каждого регистра берётся максимум из двух значений.&lt;pre&gt;&lt;code class=cpp&gt;void hll_merge(HyperLogLog* dest, const HyperLogLog* src) {&#xA;    for (int i = 0; i &amp;lt; HLL_M; i++) {&#xA;        if (src-&amp;gt;registers[i] &amp;gt; dest-&amp;gt;registers[i]) {&#xA;            dest-&amp;gt;registers[i] = src-&amp;gt;registers[i];&#xA;        }&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Эта операция делает HyperLogLog идеальным для распределённых систем: каждый сервер может независимо обрабатывать свой поток, а затем центральный узел объединяет все структуры за линейное время от количества регистров.&lt;p&gt;Для проверки работы алгоритма нам понадобилась функция генерации случайных строк и тестовое приложение. Генератор использует стандартный &lt;code&gt;rand()&lt;/code&gt; для создания строк заданной длины из букв и цифр:&lt;pre&gt;&lt;code class=cpp&gt;static char* gen_random_string(size_t length) {&#xA;    static const char charset[] = &amp;#34;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&amp;#34;;&#xA;    char* str = malloc(length + 1);&#xA;    for (size_t i = 0; i &amp;lt; length; i++) {&#xA;        str[i] = charset[rand() % (sizeof(charset) - 1)];&#xA;    }&#xA;    str[length] = &amp;#39;\0&amp;#39;;&#xA;    return str;&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;В функции &lt;code&gt;main&lt;/code&gt; мы генерируем 100 000 уникальных строк, добавляем их в структуру HyperLogLog, а затем выводим оценку и сравниваем её с реальным количеством. Это позволяет нам убедиться, что алгоритм работает в пределах заявленной погрешности.&lt;blockquote&gt;&lt;p&gt;Наша реализация использует &lt;code&gt;__builtin_clzll&lt;/code&gt; — это расширение GCC и Clang. Для компиляции под Visual Studio потребуется заменить эту функцию на &lt;code&gt;__lzcnt64&lt;/code&gt; или реализовать подсчёт ведущих нулей через битовые операции. Также мы используем &lt;code&gt;memset&lt;/code&gt; и математические функции из стандартной библиотеки.&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;Выбор точности: размер структуры и погрешность. Мы выбрали &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; как хороший компромисс: 16 КБ памяти и погрешность около 1–2%. Если вам нужна большая точность, можно увеличить &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; до 16 (64 КБ, погрешность около 0.8%), а если память критична — уменьшить до 10 (1 КБ, но погрешность вырастет до 3–4%).&lt;/blockquote&gt;&lt;p&gt;Теперь, когда у нас есть работающая реализация, давайте посмотрим на неё в деле. Мы протестируем алгоритм на синтетических данных и убедимся, что он действительно выдаёт оценку с погрешностью в пределах заявленной.&lt;p&gt;Итоговая реализация доступна &lt;a href=https://github.com/alexeev-prog/hyperloglog/&gt;по этой ссылке в моем репозитории&lt;/a&gt;.&lt;h3&gt;❯ Вывод&lt;/h3&gt;&lt;p&gt;Итак, запускаем код&lt;pre&gt;&lt;code&gt;Precision (p): 14&#xA;Registers (m): 16384&#xA;Memory: 16384 bytes&#xA;Actual unique:  100000&#xA;HLL estimate:   99777&#xA;Error:          0.22%&#xA;&#xA;Idempotency check: 99777&#xA;Merge estimate: 99777&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Погрешность составила всего 0.22% — это даже меньше теоретической оценки в 0.81% для данного количества регистров. Такой результат объясняется тем, что теоретическая ошибка — это среднеквадратичное отклонение, а на конкретной выборке случайных данных можно получить как меньшее, так и большее значение. В нашем случае случайность сыграла в пользу точности.&lt;p&gt;Обратите внимание на проверку идемпотентности: повторный вызов &lt;code&gt;hll_estimate&lt;/code&gt; дал тот же результат, что и первый. Это важное свойство — оценка детерминирована и не зависит от того, сколько раз вы её запрашиваете.&lt;p&gt;Проверка слияния также прошла успешно: мы разделили 100 000 элементов на две равные части, обработали их независимо в двух структурах HyperLogLog, а затем слили их в одну. Оценка после слияния (99777) совпала с оценкой исходной структуры, в которую добавлялись все элементы последовательно. Это подтверждает, что операция слияния корректна и не вносит дополнительной ошибки.&lt;p&gt;Теперь посмотрим, как алгоритм ведёт себя на миллионе уникальных элементов:&lt;pre&gt;&lt;code&gt;Precision (p): 14&#xA;Registers (m): 16384&#xA;Memory: 16384 bytes&#xA;Actual unique:  1000000&#xA;HLL estimate:   991202&#xA;Error:          0.88%&#xA;&#xA;Idempotency check: 991202&#xA;Merge estimate: 991202&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;При увеличении кардинальности на порядок (со 100 тысяч до 1 миллиона) погрешность выросла до 0.88%, что всё ещё находится в пределах теоретической оценки в 0.81% с учётом естественной вариативности. Важно отметить, что структура данных при этом не изменилась — те же 16 384 регистра, те же 16 КБ памяти. Алгоритм одинаково эффективно работает как для сотен тысяч, так и для миллионов элементов, и даже для миллиардов — размер структуры остаётся фиксированным.&lt;p&gt;Это и есть главная сила HyperLogLog: память не зависит от количества обработанных элементов. Вы можете пропустить через него терабайт логов, и он всё так же будет занимать 16 КБ. Единственное, что влияет на размер, — это желаемая точность, которая определяется количеством регистров.&lt;p&gt;На практике при &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; и &lt;img class=&#34;formula inline&#34; source=&#34;M=16384&#34; alt=&#34;M=16384&#34; src=https://habrastorage.org/getpro/habr/formulas/f/f6/f6e/f6ef54b7fd4b03e9af99acf7c4914fde.svg width=88 height=12 data-width=11.051 data-height=1.731 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/f/f6/f6e/f6ef54b7fd4b03e9af99acf7c4914fde.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/f/f6/f6e/f6ef54b7fd4b03e9af99acf7c4914fde.svg 781w&#34; loading=lazy decode=async&gt; вы можете рассчитывать на погрешность около 1–2% для большинства реальных данных. Этого более чем достаточно для задач аналитики, мониторинга и многих других приложений, где важна не абсолютная точность, а относительная оценка порядка величин.&lt;h3&gt;❯ Графики&lt;/h3&gt;&lt;p&gt;Я решил дополнительно провести тесты с измененными константами и нарисовать графики. Я провел серию тестов с изменением параметра точности &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; (от 10 до 16) и размера входного множества (&lt;code&gt;unique_count&lt;/code&gt; от 10k до 1M). Полный набор сырых данных доступен &lt;a href=https://raw.githubusercontent.com/alexeev-prog/hyperloglog/refs/heads/main/c_implementation/results.csv&gt;по этой ссылке&lt;/a&gt;.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/c6/36/3c/c6363c5a9560a32398a40f5f1a5a6bec.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/c6/36/3c/c6363c5a9560a32398a40f5f1a5a6bec.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/c6/36/3c/c6363c5a9560a32398a40f5f1a5a6bec.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;blockquote&gt;&lt;p&gt;Для &lt;img class=&#34;formula inline&#34; source=&#34;p=11&#34; alt=&#34;p=11&#34; src=https://habrastorage.org/getpro/habr/formulas/5/57/575/57574070781adc55b140651b0c466aec.svg width=48 height=12 data-width=6.418 data-height=1.946 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/57/575/57574070781adc55b140651b0c466aec.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/57/575/57574070781adc55b140651b0c466aec.svg 781w&#34; loading=lazy decode=async&gt; ошибка чуть выше теоретической из-за случайности, для &lt;img class=&#34;formula inline&#34; source=&#34;p=12&#34; alt=&#34;p=12&#34; src=https://habrastorage.org/getpro/habr/formulas/6/67/678/678b09d643ac57bc21697579f070a4eb.svg width=48 height=12 data-width=6.418 data-height=1.946 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/67/678/678b09d643ac57bc21697579f070a4eb.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/67/678/678b09d643ac57bc21697579f070a4eb.svg 781w&#34; loading=lazy decode=async&gt; — аномально низкая&lt;/blockquote&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/e4/43/97/e44397ae775dbb533391e397bb507cf3.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/e4/43/97/e44397ae775dbb533391e397bb507cf3.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/e4/43/97/e44397ae775dbb533391e397bb507cf3.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/28/da/5a/28da5a45d9036ab13b30aed5e6049ed1.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/28/da/5a/28da5a45d9036ab13b30aed5e6049ed1.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/28/da/5a/28da5a45d9036ab13b30aed5e6049ed1.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/a9/32/8d/a9328d1def75b93c8fa39ce033b9b6bd.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/a9/32/8d/a9328d1def75b93c8fa39ce033b9b6bd.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/a9/32/8d/a9328d1def75b93c8fa39ce033b9b6bd.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/1c/2a/20/1c2a20ae7c1eb2ef922d57c1a4a68f09.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/1c/2a/20/1c2a20ae7c1eb2ef922d57c1a4a68f09.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/1c/2a/20/1c2a20ae7c1eb2ef922d57c1a4a68f09.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/be/df/5c/bedf5c0841eae1cbc6a5ef8ea4e37e5d.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/be/df/5c/bedf5c0841eae1cbc6a5ef8ea4e37e5d.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/be/df/5c/bedf5c0841eae1cbc6a5ef8ea4e37e5d.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/34/f5/da/34f5dad9011da94fd0948f010260a861.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/34/f5/da/34f5dad9011da94fd0948f010260a861.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/34/f5/da/34f5dad9011da94fd0948f010260a861.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/12/33/41/12334129ff41d4612b15fc617a6ba9d3.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/12/33/41/12334129ff41d4612b15fc617a6ba9d3.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/12/33/41/12334129ff41d4612b15fc617a6ba9d3.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/9a/da/4c/9ada4c92e38da929d516dd53872b44b6.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/9a/da/4c/9ada4c92e38da929d516dd53872b44b6.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/9a/da/4c/9ada4c92e38da929d516dd53872b44b6.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/37/11/78/371178b6adf2dd8f03f8fe1b1fd2dab7.png sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/37/11/78/371178b6adf2dd8f03f8fe1b1fd2dab7.png 780w,&#xA;       https://habrastorage.org/r/w1560/webt/37/11/78/371178b6adf2dd8f03f8fe1b1fd2dab7.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Графики наглядно показывают свойства HyperLogLog вместе с особенностями реализации. Слияние корректное, ошибка при объединении двух структур идентична ошибке прямого подсчета. Также есть классическая зависимость: удвоение памяти (рост &lt;img class=&#34;formula inline&#34; source=p alt=p src=https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg width=12 height=12 data-width=1.138 data-height=1.439 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/83/838/83878c91171338902e0fe0fb97a8c47a.svg 781w&#34; loading=lazy decode=async&gt; на 1) снижает стандартную ошибку примерно в &lt;img class=&#34;formula inline&#34; source=\sqrt{2} alt=\sqrt{2} src=https://habrastorage.org/getpro/habr/formulas/d/d2/d21/d21848cdd835abcb491be1f151e9b6c6.svg width=24 height=16 data-width=3.061 data-height=2.847 data-vertical-align=-0.858 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/d/d2/d21/d21848cdd835abcb491be1f151e9b6c6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/d/d2/d21/d21848cdd835abcb491be1f151e9b6c6.svg 781w&#34; loading=lazy decode=async&gt; раз. При &lt;img class=&#34;formula inline&#34; source=&#34;p \ge 14&#34; alt=&#34;p \ge 14&#34; src=https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg width=48 height=16 data-width=6.418 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg 781w&#34; loading=lazy decode=async&gt; (16 KB) ошибка стабильно уходит ниже 1% для любых размеров множеств.&lt;p&gt;При &lt;img class=&#34;formula inline&#34; source=&#34;p \ge 14&#34; alt=&#34;p \ge 14&#34; src=https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg width=48 height=16 data-width=6.418 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/56/567/5671a4c8f1225b56e449a82089e7e1c6.svg 781w&#34; loading=lazy decode=async&gt; кривые ошибок становятся пологими и близкими к нулю, независимо от кардинальности входных данных (будь то 10k или 1M элементов). Это подтверждает, что HyperLogLog действительно масштабируется, используя фиксированный объем памяти.&lt;p&gt;В итоге лучшим выбором для продакшена будет &lt;img class=&#34;formula inline&#34; source=&#34;p=14&#34; alt=&#34;p=14&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg width=48 height=12 data-width=6.418 data-height=1.971 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0b/0b6/0b696031679cebcd574c4c7c86c32761.svg 781w&#34; loading=lazy decode=async&gt; или &lt;img class=&#34;formula inline&#34; source=&#34;p=16&#34; alt=&#34;p=16&#34; src=https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg width=48 height=12 data-width=6.418 data-height=1.946 data-vertical-align=-0.439 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/0e/0e6/0e62c9651ffcd4f0e471db75567124ac.svg 781w&#34; loading=lazy decode=async&gt;.&lt;hr&gt;&lt;p&gt;Эта статья — некое развитие моей серии алгоритмов и структур данных с реализацией на C. Вы можете взглянуть на эту серию статей &lt;a href=https://habr.com/ru/companies/timeweb/articles/993776/&gt;по вот этой ссылке&lt;/a&gt;. Тут я применил формат «один алгоритм — одна статья», что позволяет разбирать интересные алгоритмы, которые слишком большие для того, чтобы называться небольшим трюком.&lt;hr&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href=https://t.me/timewebru&gt;&lt;strong&gt;Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;↩&lt;/strong&gt;&lt;/blockquote&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/ab2/d57/b5a/ab2d57b5a915a64fa9faa8aa711d2183.jpg sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/ab2/d57/b5a/ab2d57b5a915a64fa9faa8aa711d2183.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/ab2/d57/b5a/ab2d57b5a915a64fa9faa8aa711d2183.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/timeweb/articles/1046345/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1046345</guid>
      <pubDate>Wed, 24 Jun 2026 16:05:58 +0000</pubDate>
    </item>
    <item>
      <title>Чжоу Хунъи: «ИИ превратил поиск уязвимостей из лотереи в фабрику»</title>
      <link>https://habr.com/ru/articles/1051512/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051512</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;a href=http://ISC.AI rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;em&gt;ISC.AI&lt;/em&gt;&lt;/a&gt;&lt;em&gt; 2026, 14-я конференция по интернет-безопасности. Пекин, Национальный конференц-центр, 24 июня 2026. Программный доклад, 09:55-10:40.&lt;/em&gt;&lt;p&gt;&lt;em&gt;Спикер: Чжоу Хунъи (周鸿祎), основатель группы 360, председатель конференции &lt;/em&gt;&lt;a href=http://ISC.AI rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;em&gt;ISC.AI&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;p&gt;&lt;em&gt;Восстановлено по материалам автоматической китайско-русской расшифровки. Контекст экспортного контроля и «беспрецедентных киберрисков» отдельно разобран здесь: &lt;/em&gt;&lt;a href=https://t.me/aiakyn/132 rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;em&gt;t.me/aiakyn/132&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Название зарубежного агента, которое в расшифровке устойчиво звучит как «Омар», оставлено как рабочее.&lt;/em&gt;&lt;hr&gt;&lt;h3&gt;Открытие&lt;/h3&gt;&lt;p&gt;Уважаемый министр Жэнь, академик У, академик Чжао, уважаемые руководители, эксперты, гости и друзья, добрый день.&lt;p&gt;Спасибо всем за многолетнюю поддержку ISC. Те, кто пришел сегодня утром так рано, наверняка не смотрели футбол всю ночь.&lt;p&gt;В прошлом году темой нашей конференции были AI-агенты. И вот уже в начале этого года «Омар» стал очень горячей темой. Эта волна, можно сказать, провела для всех популярный урок: автономные агенты действительно способны на многое. Но очень быстро у «Омара» обнаружилась и смертельная проблема. Эта штука не слушается, небезопасна, не соблюдает правила.&lt;p&gt;Множество живых примеров показали: в эпоху AI вопросы безопасности не стали проще. Наоборот, они стали сложнее.&lt;p&gt;Поэтому тему конференции этого года мы сформулировали так: «AI-агенты подрывают безопасность». С одной стороны, надо обсуждать, как решать проблемы безопасности самих агентов. С другой стороны, надо обсуждать новые вызовы безопасности, которые эти агенты приносят.&lt;p&gt;Тем много, времени мало. Поэтому сегодня я хочу поговорить с вами об одном: какое разрушительное воздействие и какую «атаку на понижение размерности», уплощению, развитие AI-агентов и AI-технологий наносит традиционной индустрии кибербезопасности.&lt;p&gt;Здесь много коллег по безопасности. Все знают, что конкурентов в нашей отрасли мы дружелюбно называем «друзьями-конкурентами». Но самое страшное, возможно, не в том, что нас победит другой игрок из той же отрасли. По-настоящему опасен чужак, который вдруг влезает в нашу индустрию.&lt;p&gt;Я приведу пример. Есть компания, которая делает большие модели. Как она, сама того как будто не планируя, вошла на рынок кибербезопасности?&lt;p&gt;Слово я, возможно, произношу неправильно. Mythos? То ли «миссус», то ли «ресурс»? Впрочем, это не важно.&lt;h3&gt;Почему США закрыли свои модели&lt;/h3&gt;&lt;p&gt;Недавно в США произошло очень редкое событие. Американское правительство внезапно распорядилось закрыть для иностранцев две новейшие большие модели. Одна из них, Mythos, — самый сильный внутренний вариант. Другая, Fable, — урезанная гражданская версия с защитными ограничителями.&lt;p&gt;Запрет был направлен не против нескольких стран. Он был направлен против всех иностранцев. Более того, пользоваться этой технологией не разрешили даже собственным сотрудникам-иностранцам. Технически оказалось трудно надежно отличать пользователей по гражданству, и в итоге доступ к модели просто остановили.&lt;p&gt;Так большая модель впервые была поставлена под экспортный контроль почти так же, как литографическое оборудование и чипы. Официальное объяснение американского правительства уложилось в два слова: национальная безопасность.&lt;p&gt;Говорят, что за 24 часа до запрета высокопоставленные чиновники Белого дома и руководители, отвечающие за кибербезопасность, провели срочное совещание и долго спорили. Но в итоге контроль ввели для обеих моделей.&lt;p&gt;Еще до публикации Mythos, примерно с апреля, руководство Anthropic несколько раз докладывало ситуацию американскому правительству. СМИ писали, что стороны уже обсуждали приоритетный доступ к этим возможностям для разведывательных структур, включая Агентство национальной безопасности США.&lt;p&gt;Многие из вас, вероятно, слышали об этой истории. Но я хочу сказать ее прямо: какая способность заставила США предпочесть закрыть собственную передовую модель, лишь бы не дать ей распространиться?&lt;p&gt;Настоящая причина, на мой взгляд, в том, что американское правительство увидело не просто большую модель. Оно увидело новую стратегическую способность национального уровня.&lt;p&gt;Самое страшное в ней то, что она может самостоятельно искать уязвимости, анализировать их и создавать атакующее программное обеспечение. Если говорить языком традиционной кибербезопасности, это эквивалент ядерного оружия эпохи AI.&lt;p&gt;Fable — гражданская, урезанная версия Mythos. Если ее однажды взломают или обойдут ее ограничения, это будет означать, что весь мир может получить такую способность. Для американского правительства это неприемлемо. Оно должно гарантировать: у меня это есть, а у других нет. Так формируется абсолютная стратегическая монополия.&lt;p&gt;Когда вышла тестовая версия, удар почувствовало не только правительство США. Рынок нашей отрасли тоже отреагировал: акции американских гигантов кибербезопасности одновременно резко упали.&lt;p&gt;Почему? Потому что рынок капитала понял простую вещь. Если AI способен автоматически, массово и дешево находить уязвимости, то всю бизнес-логику, бизнес-модели, продукты и технологические системы традиционных компаний кибербезопасности придется переоценивать. Вот это я и называю «атакой на понижение размерности».&lt;h3&gt;Что такое уязвимость&lt;/h3&gt;&lt;p&gt;Чтобы понять, почему AI, который умеет находить уязвимости, так нервирует индустрию безопасности и заставляет американское правительство действовать столь резко, надо сначала вспомнить, что такое уязвимость.&lt;p&gt;Уязвимость — это не просто программный баг. Программа может работать нормально. На поверхности все выглядит штатно, пользователь ничего не замечает. Но в коде может быть ошибка или лазейка. И если вы нашли такую лазейку, вы можете получить контроль над всей системой или всем программным обеспечением.&lt;p&gt;Возьмем известные примеры. Вам присылают презентацию PowerPoint, документ Word, картинку или ссылку. Вы открываете файл, и другая сторона удаленно внедряет вирус или троян, после чего получает контроль над вашим компьютером.&lt;p&gt;Раньше, когда мы говорили о кибербезопасности, существовали две школы. Одна была школой криптографии, другая школой уязвимостей. Сторонники криптографии считали: если шифрование достаточно сильное и пароль не утек, система безопасна. Но по мере цифровизации и софтизации уязвимости изменили правила игры. Если есть эксплуатируемая уязвимость, атакующему не надо знать ваш пароль и не надо взламывать шифр. Он все равно может войти в систему.&lt;p&gt;Так уязвимости стали ключом к сетевому нападению и защите. Западные кибердержавы десятилетиями собирали и покупали уязвимости, рассматривали их как важные стратегические активы и вводили для них контроль. Наша конференция ISC проводится уже в 14-й раз. Мы приглашали мировых экспертов по кибербезопасности в Китай обсуждать эти вопросы, но США и союзники по НАТО считали уязвимости военно-контролируемой технологией и не хотели обсуждать их с иностранцами.&lt;p&gt;Поэтому в последние десятилетия суть кибербезопасности была соревнованием по уязвимостям. Кто первым их находит, кто находит больше, кто находит быстрее, тот получает инициативу в кибератаках.&lt;p&gt;Как я уже сказал, отрасль часто разрушает не кто-то из старых мастеров внутри нее. Вдруг приходит человек со стороны, и старый мастер падает под градом хаотичных ударов.&lt;p&gt;Изначальная цель Mythos, насколько я понимаю, вообще не была кибербезопасностью. Это должен был быть coding agent, AI, который помогает людям писать код, поддерживать код и понимать код.&lt;p&gt;Но проблема появилась очень быстро. Код, который пишут люди, часто содержит ошибки. В каждой тысяче строк могут быть несколько уязвимостей. Если AI пишет код в десятки или сотни раз продуктивнее человека, то и число уязвимостей может увеличиться во столько же раз.&lt;p&gt;Сейчас моден vibe coding: пусть AI пишет код. Но человеческие навыки работают по принципу «используешь или теряешь». Если люди перестанут писать и поддерживать код руками, объем кода станет таким, что человек уже не сможет его сопровождать.&lt;p&gt;Если код, написанный AI, весь в уязвимостях, это катастрофа для всей индустрии. Поэтому, чтобы люди спокойнее доверяли AI-кодингу, разработчики начали учить модель находить уязвимости в коде. В результате, когда модель поняла бизнес-логику и логику выполнения кода, у нее возникла новая способность. Она не только находила уязвимости, но и научилась автоматически писать атакующий код.&lt;p&gt;Например, OpenBSD. Ядро Apple использует BSD, а BSD считается одной из самых безопасных Unix-систем в мире. Много лет эксперты искали проблемы в ядре и ничего не находили. Mythos нашла уязвимость, которая скрывалась 27 лет.&lt;p&gt;Или FFmpeg. Возможно, не все с ним знакомы, но когда вы каждый день смотрите видео или прямые трансляции, в огромном числе мест за кулисами используется именно он. Это часть глобальной аудио- и видеоинфраструктуры. Mythos нашла в FFmpeg уязвимость, которая существовала 16 лет.&lt;p&gt;Что это показывает? Mythos уже не простой помощник программиста. Она начала обладать возможностями сетевого нападения и защиты.&lt;h3&gt;От редкого металла к фабрике&lt;/h3&gt;&lt;p&gt;До появления Mythos у уязвимостей был один «недостаток»: их, конечно, много, но их очень трудно найти.&lt;p&gt;Поиск уязвимостей похож на добычу редкого металла. Это сложно, дорого, долго, результат неопределен. Нужна группа профессиональных хакеров с особыми способностями, которые долго анализируют код, исследуют его и тестируют.&lt;p&gt;И главное, в этом почти нет закономерности. Нельзя сказать, что если очень стараться, результат обязательно будет. Внутри компании я часто говорю: поиск уязвимостей похож на лотерею. Сегодня вы выиграли, но это не значит, что выиграете и в следующем месяце.&lt;p&gt;Качественная уязвимость, которую никто еще не нашел и не использовал, называется zero-day. И фактически вся индустрия кибербезопасности последние тридцать лет стояла на двух предпосылках: уязвимости трудно найти, и уязвимости полезны. Эта редкость кое-как поддерживала баланс нападения и защиты.&lt;p&gt;Появление Mythos полностью изменило правила игры.&lt;p&gt;Первое изменение: скорость.&lt;p&gt;В прошлом на поиск одной уязвимости высокой ценности могли уйти месяцы или даже годы. Потом еще требовалось много времени, чтобы превратить находку в пригодное оружие или подготовить исправление. Mythos напрямую увеличила скорость примерно в сто раз.&lt;p&gt;Это означает, что прежние N-day-уязвимости могут превращаться в N-minute или N-hour. У защиты просто не остается времени. Утром AI нашел уязвимость, к полудню проверил, вечером начал атаку. Сетевое нападение и защита перешли от человеческой скорости к машинной.&lt;p&gt;Второе изменение: количество.&lt;p&gt;Во многих системах уязвимости точно есть. Не то чтобы их не существовало, просто раньше их не находили. Даже у настоящего эксперта ограничены время, энергия, опыт и число целей. Поэтому многие уязвимости долго не обнаруживались.&lt;p&gt;AI, если у него есть вычислительные мощности, может анализировать код 24 часа в сутки семь дней в неделю. Он может открыть сотню агентов, тысячу агентов, вести ковровый поиск.&lt;p&gt;Представьте: с появлением Mythos множество исторических уязвимостей и уязвимостей цепочек поставок, скрытых в открытом коде, могут быть обнаружены одновременно. Если их еще и одновременно использовать, не получим ли мы беспрецедентную вспышку уязвимостей?&lt;p&gt;Третье изменение: стоимость поиска уязвимостей резко падает.&lt;p&gt;Люди, которые умеют искать уязвимости, получают высокую зарплату. Сами уязвимости тоже стоят дорого. Но если стоимость какого-то действия падает в сто или тысячу раз, вся отрасль переоценивается. Бизнес-модели и конкурентная логика традиционных компаний безопасности будут перестроены.&lt;p&gt;Четвертое изменение: атакующие возможности становятся доступными массам.&lt;p&gt;Я думаю, в зале много программистов. Возможно, скоро людей, которые пишут код руками, можно будет подавать в список нематериального культурного наследия.&lt;p&gt;Но для хакера требования к программированию еще выше. А с такой большой моделью даже человек, который не умеет программировать, сможет с ее помощью создать атакующий код.&lt;p&gt;Академик У только что тоже говорил об этом. У многих стран есть кибервойска. Раньше хорошего хакера было трудно найти. Теперь через distillation можно скопировать боевой опыт топового хакера в хакерского агента. Пусть у такого агента будет только 80 процентов мастерства лучшего человеческого эксперта. Зато его можно массово копировать, выпускать сотнями и тысячами, отправлять на фронт, и он будет работать 24 часа в сутки без сна и отдыха. Агенты могут самоулучшаться и вести совместные операции.&lt;p&gt;То, что раньше было в руках немногих стран и организаций, в будущем может оказаться доступно многим обычным людям с помощью AI. Порог атаки обрушится.&lt;p&gt;Если сложить эти изменения вместе, возникает очень серьезное последствие: способность находить уязвимости может стать фактором, меняющим правила кибербезопасности, и сформировать новую стратегическую силу сдерживания.&lt;p&gt;Такую способность можно использовать для защиты, а можно использовать для нападения. В защите она позволяет сначала найти и закрыть свои уязвимости. В нападении она позволяет раньше и быстрее находить уязвимости в чужом программном обеспечении. Если у противника нет похожей системы, он вообще не понимает, что вы нашли и сколько вы нашли.&lt;p&gt;Поэтому самая опасная вещь теперь не отдельная уязвимость. Самый важный вопрос: кто обладает способностью непрерывно находить уязвимости?&lt;p&gt;Именно поэтому, когда появились новости о Mythos, акции американских компаний кибербезопасности рухнули вместе. Традиционный рецепт безопасности может больше не работать.&lt;p&gt;В сетевой защите всегда была базовая идея: раз уязвимости невозможно устранить полностью и невозможно исчерпать, надо строить многослойную линию Мажино из оборудования, программ, анализа и сигналов тревоги. В прошлом, хотя оборона была вся в дырах, у атакующей стороны уязвимостей было ограниченно, частота атак тоже была ограниченной. Поэтому компании безопасности всегда находили какие-то способы, как в поговорке про восемь бессмертных, которые переходят море, и каждый показывает свое искусство.&lt;p&gt;Но представьте, что скорость поиска уязвимостей выросла в сто раз, стоимость упала в сто раз, количество выросло в сто раз, а сложность снизилась в сто раз. Это изменения на порядки.&lt;p&gt;Тогда логика защиты может отказать. Если мы не найдем новый ответ.&lt;h3&gt;Glasswing и вторая односторонняя прозрачность&lt;/h3&gt;&lt;p&gt;Надо признать: американцы очень чувствительны к таким изменениям. Они не предложили очень макроуровневое и полностью системное решение. Но они поняли одну точку: уязвимости чрезвычайно важны.&lt;p&gt;Поэтому они быстро привлекли Google, Apple, Microsoft, Nvidia и еще более сорока технологических гигантов и создали альянс Glasswing.&lt;p&gt;Этот альянс включает 15 стран и более 200 организаций. Это ключевые союзники США и операторы критической инфраструктуры. Каждой организации открывают до 100 миллионов долларов в токенах, чтобы помочь им сканировать код и находить уязвимости.&lt;p&gt;Суть Glasswing, на мой взгляд, — большая внутренняя проверка уязвимостей.&lt;p&gt;Логика США понятна. Если в мире кто угодно сможет находить уязвимости, то самой большой жертвой атаки станут сами США, потому что их цифровая база самая передовая в мире. Чем выше уровень цифровизации, тем выше риск уязвимостей. Они хотят до того, как такая способность появится у других, первыми использовать ее для собственного медицинского осмотра: найти как можно больше уязвимостей и поставить патчи.&lt;p&gt;Исходя из многолетнего опыта столкновений с американскими разведывательными структурами и кибервойсками, я считаю, что американская сторона точно не упустит огромную возможность превратить эту способность в оружие. Это слишком эффективный наступательный инструмент.&lt;p&gt;Самое важное: Китай и китайские компании находятся вне этого альянса. То есть американские организации могут использовать Mythos, чтобы сканировать наши уязвимости, а у вас нет даже права взглянуть на Mythos.&lt;p&gt;США пытаются превратить способность Mythos в системное преимущество и сформировать разрыв возможностей.&lt;p&gt;И здесь для нас появляется очень важный урок. Китайская индустрия кибербезопасности должна ясно решить, куда идти дальше. Это уже не вопрос коммерческой конкуренции.&lt;p&gt;Если мы не найдем эффективный способ ответа, кибербезопасность Китая столкнется со второй односторонней прозрачностью.&lt;p&gt;Первая односторонняя прозрачность была в те годы, когда враг был во тьме, а мы были на свету. Зарубежные APT-группы долго скрыто находились в наших сетях, а мы их не видели.&lt;p&gt;360 потратила двадцать лет на создание крупнейшей в мире базы больших данных по кибербезопасности, на плотную сеть сенсоров, анализ больших данных и безопасность, управляемую данными. Так мы в целом решили проблему первой односторонней прозрачности. Мы помогли стране выявить более 60 зарубежных APT-групп и перехватить сотни тысяч атак. Сегодня, если шпионское ПО входит в нашу сеть, его в основном можно обнаружить, перехватить и отследить.&lt;p&gt;Но теперь проблема изменилась. Дело уже не только в том, что враг прячется в нашей сети. Дело в том, что он может видеть наши уязвимости. У нас мало людей, мы все еще полагаемся на нескольких экспертов по безопасности, которые анализируют ситуацию, а другая сторона уже выращивает группу хакерских агентов и запускает параллельные атаки.&lt;p&gt;У Лэй Цзюня есть фраза: «В боевых искусствах скорость не побьешь».&lt;p&gt;Если у нас нет такой способности, мы будем думать, что наша критическая инфраструктура безопасна. Но на самом деле другая сторона может видеть наши уязвимости совершенно ясно. В ее глазах мы как игральная кость, вся в точках, и каждая точка это место для атаки.&lt;p&gt;Поэтому сегодня у меня на конференции очень ясная позиция: китайская индустрия кибербезопасности должна создать собственное большое оружие, которое способно изменить структуру сетевого нападения и защиты. Оно не может быть только в руках американцев.&lt;p&gt;Особенно учитывая, что большое число китайских программных систем построено на open source. Уязвимостей там точно немало. То, что их раньше не нашли, не означает, что их нет. Если другая сторона получает способность находить эти уязвимости и использовать их, мы окажемся в пассивном положении.&lt;p&gt;Сами по себе уязвимости не страшны. Страшно, если мы их не видим. Мы должны видеть их сами, первыми находить, первыми проверять и первыми исправлять. Только когда у тебя есть карты в руках, у тебя есть уверенность в голове.&lt;p&gt;Вторая ценность китайской версии такой способности: надо сформировать равный потенциал стратегического сдерживания.&lt;p&gt;Почему ядерная война по-настоящему не началась? Потому что у всех есть возможность взаимного сдерживания. В кибербезопасности то же самое. Если у тебя это есть, у меня тоже должно быть. Иначе меня пассивно похоронят. Думаю, это все понимают, долго объяснять не нужно.&lt;h3&gt;Автоматизированная защита&lt;/h3&gt;&lt;p&gt;У меня есть еще одна точка зрения. Академик У только что высказал похожую мысль.&lt;p&gt;В ближайшие годы, по мере того как AI все активнее находит уязвимости и запускает атаки, многие объекты критической инфраструктуры, важные организации и важные отрасли нашей страны могут войти в период высокой частоты кибератак. Даже если у нас появится китайская версия Mythos, это не значит, что все риски можно устранить за один раз. Уязвимости невозможно исчерпать.&lt;p&gt;Поэтому одних поиска и закрытия уязвимостей недостаточно. Надо ответить на второй вопрос: что делать, когда инструмент уже пришел?&lt;p&gt;Я думаю, ответ только один: нужна автоматизированная защита.&lt;p&gt;Раньше многие предприятия и организации думали, что если они купили средства безопасности, программное и аппаратное обеспечение, то можно спать спокойно. Потом выяснилось, что одного оборудования и софта недостаточно. Нужны ручная эксплуатация и ручное реагирование.&lt;p&gt;Теперь все начали уделять внимание эксплуатации и сервису. Но в этот момент пришли инструменты AI-автоматизации. Китайских экспертов по безопасности и так далеко не хватает. Если защита по-прежнему зависит от людей, если мы остаемся в эпохе ручного управления, этот бой невозможно выиграть.&lt;p&gt;Единственный выход: вычислительной мощностью против вычислительной мощности, интеллектом против интеллекта. Надо активно противостоять машинам машинами, чтобы система киберзащиты Китая перешла от тактики человеческой массы к автономному вождению.&lt;p&gt;Последние несколько лет 360 следует стратегии «AI плюс безопасность» по двум линиям. Суть в том, чтобы безопасностью решать проблемы безопасности AI и одновременно использовать AI для усиления традиционной безопасности.&lt;p&gt;За последние два года мы сосредоточились на двух типах агентов. Первый тип — агенты, которые автоматически находят уязвимости. Второй тип — агенты, которые автоматически защищают.&lt;p&gt;Недавно мы выпустили китайскую версию Mythos. Она называется 屠龙锋, «Тулунфэн», «Клинок драконоборца». У нее есть похожая способность поиска уязвимостей. Мы уже попробовали ее в деле: суммарно она нашла более 3000 уязвимостей, из них 105 подтверждены регулятором, а несколько уязвимостей национальная база определила как высокорисковые.&lt;p&gt;Кто-то наверняка скажет: как вы можете сделать китайскую версию Mythos? Американские компании большие, у них мощнейшие модели, мощнейшие чипы, такая вычислительная мощность, что страшно представить.&lt;p&gt;Моя позиция такая: китайскую версию нельзя делать простым копированием американского пути.&lt;p&gt;Американский путь — это типичный маршрут «силой творить чудеса»: самая сильная модель, самые сильные данные, самые сильные чипы. Объективно говоря, их модельные возможности действительно сильны. Отечественным open source базовым моделям, чтобы догнать их в короткий срок, нужно время.&lt;p&gt;Но мы не можем ждать, пока возможности базовых моделей догонят американские, и только потом начинать поиск уязвимостей. У нас нет этого времени.&lt;p&gt;Если не копировать американскую формулу, как делать китайскую версию Mythos?&lt;p&gt;Мой ответ: агентный путь.&lt;p&gt;Не биться насмерть только в модели и вычислительной мощности, а использовать агентов, чтобы выйти обходным маневром.&lt;p&gt;В этом году в области AI-агентов очень горячее слово: harness. Думаю, многие его слышали. Развитие harness-технологий доказало одну вещь: без агентов использование и раскрытие возможностей большой модели крайне нестабильно. Но если через agent harness эффективно управлять контекстом, использованием инструментов, подачей знаний, проектированием процесса и многоагентным взаимодействием, то большая модель на 80 баллов может дать результат на 90.&lt;p&gt;Поэтому я считаю: вместо того чтобы ставить все на одну супермодель, лучше организовать опыт наших экспертов по безопасности, наши большие данные безопасности и наши инструментальные возможности в совместную agent harness-систему.&lt;p&gt;США имеют свои особенности. У Китая должен быть свой способ игры.&lt;p&gt;Первая карта 360: двадцать лет практического опыта нападения и защиты. Anthropic — компания больших моделей. 360 двадцать лет занимается кибербезопасностью. В этом фундаментальная разница.&lt;p&gt;Найти уязвимость — это не просто понять код. Надо думать как атакующий: как уязвимость использовать, как собрать цепочку эксплуатации, как в истории атаковали похожие проблемы. Эти вещи не обязательно есть в открытых корпусах.&lt;p&gt;Они есть в опыте профессиональных экспертов по нападению и защите и в долгосрочно накопленных данных. Исторически 360 была одной из компаний с самым большим числом найденных внешних уязвимостей и входила в число лидеров в мире. Мы получали самые высокие bounty-награды от Apple, Microsoft и Google, а также стали первой китайской компанией, получившей «черный Оскар» за выдающееся достижение в области уязвимостей.&lt;p&gt;За последние двадцать лет мы накопили огромный массив данных безопасности: передали регуляторам 250 тысяч уязвимостей, собрали более 140 миллиардов единиц данных по картографированию киберпространства, более 38 миллиардов глобальных образцов атак и более 6 миллиардов вредоносных образцов.&lt;p&gt;Часть этого опыта и данных обучила профессиональные большие модели безопасности. Часть была дистиллирована в агентов. Часть стала основой security Q&amp;amp;A.&lt;p&gt;Вторая карта: агентная платформа.&lt;p&gt;Большая модель — это умный мозг. Но одного мозга недостаточно, чтобы работать. Платформа дает большой модели руки и ноги: она может вызывать инструменты, выполнять процессы, обрабатывать исключения, не только думать и писать код, но и делать работу и доводить ее до результата.&lt;p&gt;Когда у агента есть платформа и memory, большая модель может учиться опыту человеческих экспертов, использовать разные инструменты, саморазвиваться и самокорректироваться.&lt;p&gt;Третья карта: многоагентная координация и анализ.&lt;p&gt;Американский путь похож на воспитание гениального хакера. Наш путь: организовать профессиональную команду нападения и защиты. Потому что возможности одной большой модели или одного агента всегда ограничены.&lt;p&gt;Наш рой агентов может автоматически строить и планировать работу под цель. Сначала проводится моделирование угроз и отбор поверхностей атаки с высоким риском. Затем по межфайловым потокам данных находятся потенциальные уязвимости.&lt;p&gt;Но обнаружить уязвимость — это только первый шаг. Можно ли ее использовать? Какой у нее ущерб? Чтобы это понять, надо написать код эксплуатации и реально проверить его. Это самая трудная часть. Большинство инструментов этого сделать не могут. Мы автоматизировали и эту работу: агент автоматически строит sandbox-среду и автоматически генерирует exploit code для реального тестирования.&lt;p&gt;В итоге общее число найденных уязвимостей может выглядеть меньше, но каждая уязвимость подтверждена, а не потеряна в шуме.&lt;p&gt;После выполнения задачи рой агентов может провести разбор, накопить опыт и стать умнее. Этот опыт мы вынесли из «Омара» и других агентных систем.&lt;p&gt;Например, часть найденных рисков получила официальное признание Microsoft. Еще одна категория — самые передовые уязвимости AI и AI-агентов. В четырех ключевых компонентах «Омара» уязвимости были автоматически найдены нами и признаны его основателем. В последнее время в экосистеме «Омара» мы нашли уже 23 уязвимости.&lt;p&gt;Так через инженерный агентный путь мы превратили поиск уязвимостей из лотереи в фабрику, которая может работать на конвейере. Эту дорогу мы прошли.&lt;h3&gt;«Клинок драконоборца» и «Игла, опирающаяся на небо»&lt;/h3&gt;&lt;p&gt;Здесь я сделаю еще один анонс. Помимо 屠龙锋, «Клинка драконоборца», мы не только даем отрасли предложения. Мы сами уже начали практические попытки.&lt;p&gt;Скоро мы выпустим еще один продукт: автоматизированную систему сетевой защиты 360 под названием 倚天针, «Итяньчжэнь», «Игла, опирающаяся на небо».&lt;p&gt;Это не просто более умный ассистент безопасности. Это настоящая команда экспертов по защите.&lt;p&gt;Она способна реагировать на сигналы тревоги, обрабатывать риски и в основном реализовать автоматическую эксплуатацию без человека. Еще важнее, она не только понимает уязвимости, но и связывает риски с бизнесом предприятия.&lt;p&gt;Какие активы самые важные? Какие системы нельзя останавливать? Какие данные самые чувствительные? Что надо защищать в первую очередь?&lt;p&gt;倚天针 может непрерывно имитировать атакующего и проводить для предприятия прогноз безопасности, заранее находить самые опасные пути атаки и устранять проблемы до реального нападения.&lt;p&gt;Каждая атака, каждое реагирование, каждое учение будут оседать в новой памяти и новом опыте. Чем больше времени проходит, тем больше опыта, и тем сильнее возможности.&lt;p&gt;Наша цель проста: перевести защиту безопасности из режима с водителем в беспилотный режим.&lt;p&gt;Кибербезопасность входит в новую эпоху. Признаем мы это или нет, AI уже меняет нас. У США есть свое оружие. У Китая тоже должны быть свои 倚天剑 и 屠龙刀: свой «меч, опирающийся на небо», и свой «клинок драконоборца».&lt;p&gt;В этой гонке AI-безопасности Китай не отсутствовал и не может отсутствовать. Технологии продолжают развиваться экспоненциально. Я верю, что настоящая схватка только начинается.&lt;h3&gt;«Несокрушимый щит»&lt;/h3&gt;&lt;p&gt;В конце я хочу сделать предложение.&lt;p&gt;США создали альянс Glasswing, чтобы в первую очередь защищать свои ведущие предприятия и критическую инфраструктуру. Китаю тоже нужна собственная система сотрудничества в безопасности. Мы не можем сидеть и ждать, пока риск взорвется.&lt;p&gt;Поэтому сегодня мы запускаем план 磐石之盾, «Несокрушимый щит».&lt;p&gt;Спасибо Haiguang, Phytium, UnionTech, Kylin, Kingdee и многим старым друзьям за участие и доверие.&lt;p&gt;Поиск уязвимостей — это стратегическая способность. Ее нельзя открывать произвольно. Поэтому мы решили: возможности 倚天 и 屠龙, о которых я только что говорил, будут в малом масштабе открыты для ключевых организаций в сфере информационных инноваций и для объектов критической технологической инфраструктуры.&lt;p&gt;Безопасность не может быть делом одной 360. У производителей больших моделей есть модельные возможности. У производителей программного обеспечения есть реальные бизнес-системы. Ключевые отрасли управляют критической инфраструктурой. Компании безопасности обладают опытом нападения и защиты и данными об уязвимостях.&lt;p&gt;Под руководством регуляторов мы должны организовать эти возможности вместе. До того как риски уязвимостей начнут массово взрываться в наших системах, мы должны защитить наши ключевые объекты и критическую инфраструктуру.&lt;p&gt;Записано и навайблено &lt;a href=https://t.me/aiakyn/144 rel=&#34;noopener noreferrer nofollow&#34;&gt;АйКын&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>sgordey</author>
      <guid>https://habr.com/ru/articles/1051512/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051512</guid>
      <pubDate>Wed, 24 Jun 2026 16:00:47 +0000</pubDate>
    </item>
    <item>
      <title>Сколько стоит контекст для кодового агента: grep vs граф vs LSP на большом проекте (936 прогонов)</title>
      <link>https://habr.com/ru/articles/1051504/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051504</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;blockquote&gt;&lt;p&gt;Продолжение &lt;a href=https://habr.com/ru/articles/1050204/ rel=&#34;noopener noreferrer nofollow&#34;&gt;статьи про graphlens&lt;/a&gt;. Там я описал, &lt;em&gt;что&lt;/em&gt; инструмент делает и &lt;em&gt;как&lt;/em&gt; устроен, и по дороге уверенно заявил, что «агент жжёт токены, бегая grep&amp;#39;ом по репозиторию». Заявил — но ни одной цифры не привёл. Эта статья закрывает дыру: вот замеры, вот данные, вот воспроизводимый стенд. Спойлер: вывод оказался не таким, каким я его себе рисовал, и это самое интересное.&lt;/blockquote&gt;&lt;h3&gt;Коротко&lt;/h3&gt;&lt;p&gt;Я взял &lt;strong&gt;одного и того же&lt;/strong&gt; агента (Claude Code), менял у него &lt;strong&gt;ровно одну вещь&lt;/strong&gt; — какой MCP-сервер отдаёт контекст по коду, — и гонял по 26 задачам на &lt;code&gt;apache/superset&lt;/code&gt;. Четыре «руки»: &lt;code&gt;filesystem&lt;/code&gt; (grep + read), &lt;code&gt;graphlens&lt;/code&gt; (структурный граф), &lt;code&gt;serena&lt;/code&gt; (LSP) и &lt;code&gt;codegraph&lt;/code&gt;. Три модели (haiku / sonnet / opus), три сида — &lt;strong&gt;936 прогонов&lt;/strong&gt;.&lt;p&gt;Главный результат: &lt;strong&gt;вывод переворачивается в зависимости от типа задачи.&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;На простых «где определён X / от чего наследуется» — все четыре инструмента &lt;strong&gt;равны по точности&lt;/strong&gt;, разница только в цене (~3×). graphlens тут ничем не выделяется.&lt;li&gt;&lt;p&gt;На задачах «оцени радиус поражения / найди все переопределения / разреши неоднозначное имя» инструменты &lt;strong&gt;резко расходятся&lt;/strong&gt;: grep разваливается (точность 0.71, до финиша доходит 83% прогонов, а те, что доходят, стоят в &lt;strong&gt;10–23 раза&lt;/strong&gt; дороже), а структурные инструменты остаются дешёвыми и точными.&lt;/ul&gt;&lt;p&gt;Если бы я мерил только простые задачи, я бы написал «граф не нужен, grep справляется». Если бы только сложные — «grep не нужен, берите граф». Правда — посередине, и она про то, &lt;strong&gt;какую работу вы поручаете агенту.&lt;/strong&gt;&lt;hr&gt;&lt;h3&gt;Бизнес-кейс, который мы на самом деле измеряем&lt;/h3&gt;&lt;p&gt;Представьте типичную ситуацию. Есть большой проект: сотни тысяч строк, бэкенд на Python, фронт на TypeScript, легаси, в которое страшно лезть. Вы подключаете к нему кодового агента — для ревью, для рефакторинга, для ответов на вопросы вроде «что сломается, если я поменяю сигнатуру вот этого метода».&lt;p&gt;Агент не видит весь репозиторий разом. Кто-то должен подавать ему контекст: какие функции где определены, кто кого вызывает, что от чего наследуется. И вот тут возникает &lt;strong&gt;архитектурное решение, у которого есть цена&lt;/strong&gt;: чем именно кормить агента?&lt;p&gt;Вариантов, по сути, четыре класса:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Дать ему grep и read&lt;/strong&gt; — пусть ищет текстом и читает файлы. Ноль инфраструктуры, работает везде.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Построить структурный граф кода&lt;/strong&gt; (graphlens) — узлы-сущности, типизированные рёбра, точные ответы на «кто вызывает».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Поднять LSP&lt;/strong&gt; (serena поверх language server) — то, чем питается ваша IDE.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Взять готовый code-graph продукт&lt;/strong&gt; (codegraph).&lt;/ul&gt;&lt;p&gt;Каждый вариант — это деньги (токены), время (латентность) и риск (агент не справится и упрётся в лимит ходов). &lt;code&gt;apache/superset&lt;/code&gt; — почти идеальный стенд под этот кейс: ~400k строк, Python + TypeScript, граница &lt;code&gt;/api/v1/...&lt;/code&gt; между фронтом и бэком. Большой полиглотный проект — ровно то, ради чего этот вопрос вообще стоит задавать.&lt;p&gt;Так сколько стоит каждое из решений? Давайте мерить.&lt;h3&gt;Дизайн эксперимента: меняем одну переменную&lt;/h3&gt;&lt;p&gt;Вся методология держится на одном принципе: &lt;strong&gt;зафиксировать всё, кроме одного.&lt;/strong&gt; Модель, системный промпт, настройки, набор задач — константы. Меняется только MCP-сервер, отдающий контекст. Тогда любая разница в цифрах — это вклад именно инструмента, а не случайности конфигурации.&lt;p&gt;Никакой инструмент не назначен «бейзлайном, который надо побить». Все четыре меряются на равных, и пусть числа их ранжируют.&lt;h4&gt;Четыре «руки»&lt;/h4&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Рука&lt;th&gt;&lt;p align=left&gt;Провайдер контекста (MCP-сервер)&lt;th&gt;&lt;p align=left&gt;Шаг индексации&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;filesystem&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt; (read_file + grep)&lt;td&gt;&lt;p align=left&gt;нет&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;graphlens&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;граф graphlens поверх MCP&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;graphlens analyze&lt;/code&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;serena&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;Serena (LSP)&lt;td&gt;&lt;p align=left&gt;прогрев LSP-воркспейса&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;codegraph&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;конкурент на графах&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;codegraph init&lt;/code&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Важная деталь честности стенда: &lt;strong&gt;встроенные инструменты Claude Code (Read / Grep / Bash и прочие) выключены.&lt;/strong&gt; Если их не отнять, агент проигнорирует MCP и пойдёт своим привычным путём — и мы измерим не то. Поэтому стенд запускает &lt;code&gt;claude -p&lt;/code&gt; в «чистой комнате»: свежий &lt;code&gt;CLAUDE_CONFIG_DIR&lt;/code&gt; только с кредами подписки (без хуков, плагинов, скиллов, памяти), &lt;code&gt;--strict-mcp-config&lt;/code&gt; (виден только сервер этой руки), &lt;code&gt;--disallowedTools&lt;/code&gt; на все встроенные инструменты (именно запрет, а не отсутствие в allow-list — в headless-режиме allow-list сам по себе ничего не запрещает) и &lt;code&gt;--allowedTools mcp__&amp;lt;server&amp;gt;&lt;/code&gt;, чтобы автоматически разрешить единственный сервер руки.&lt;h4&gt;Вторая ось: модели&lt;/h4&gt;&lt;p&gt;Параллельно я варьировал модель, которая отвечает на вопрос:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Ключ&lt;th&gt;&lt;p align=left&gt;model id&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;haiku&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;claude-haiku-4-5&lt;/code&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;sonnet&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;claude-sonnet-4-6&lt;/code&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;opus&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;claude-opus-4-8&lt;/code&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Зачем вторая ось — станет ясно ближе к концу: &lt;strong&gt;оптимальный инструмент зависит от того, какую модель вы взяли.&lt;/strong&gt; Это, пожалуй, самый неочевидный вывод всего замера.&lt;p&gt;Итого: 4 руки × 3 модели × 26 задач × 3 сида = &lt;strong&gt;936 прогонов&lt;/strong&gt; (на стеке Claude Code 2.1.187).&lt;h3&gt;Что я считаю честным замером&lt;/h3&gt;&lt;p&gt;Бенчмарки легко подкрутить под нужный вывод. Поэтому правила игры зафиксированы заранее, и вот они — без них цифрам верить нельзя.&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Эталонные ответы выверены руками&lt;/strong&gt; по исходникам на теге &lt;code&gt;6.0.0&lt;/code&gt; (каждая задача несёт ссылку &lt;code&gt;file:line&lt;/code&gt;). Принципиально: эталон &lt;strong&gt;не генерируется ни одним из тестируемых инструментов&lt;/strong&gt; (ни ty, ни pyright, ни самим graphlens). Иначе сравнение смещено в пользу того, чьим выводом мы размечали. Эталонные множества для set-задач выверены независимым оракулом — питоновским &lt;code&gt;ast&lt;/code&gt;.&lt;li&gt;&lt;p&gt;&lt;strong&gt;У «наивной» руки есть руки.&lt;/strong&gt; &lt;code&gt;filesystem&lt;/code&gt; — это grep + read, а не «агент без инструментов». «Наивно» ≠ «без рук».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Стоимость индексации меряется отдельно, один раз.&lt;/strong&gt; grep не платит за индекс ничего, граф — амортизирует. Смешивать эти валюты нельзя.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Детерминизма нет.&lt;/strong&gt; &lt;code&gt;temperature=0&lt;/code&gt; у этих моделей не детерминирует вывод. Поэтому 3 сида, и в отчёте — &lt;strong&gt;медиана, а не среднее&lt;/strong&gt;.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Записаны версии&lt;/strong&gt; моделей и каждого MCP-сервера, снимок цен и дата.&lt;li&gt;&lt;p&gt;&lt;code&gt;&lt;strong&gt;cost_usd&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt; — это API-эквивалент, а не ваш счёт.&lt;/strong&gt; Подписка — flat-rate, так что &lt;code&gt;cost_usd&lt;/code&gt; (его отдаёт CLI) — это сколько те же токены стоили бы по API. Это &lt;strong&gt;не&lt;/strong&gt; ваш реальный чек, но это &lt;strong&gt;корректная относительная метрика $/задача&lt;/strong&gt; для сравнения рук между собой.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Прогоны в чистой комнате&lt;/strong&gt; — токены отражают только системный промпт + инструменты MCP-руки, без вашего личного конфига.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Использовать инструмент обязательно.&lt;/strong&gt; Системный промпт запрещает отвечать по памяти; прогон, не сделавший ни одного вызова инструмента, перезапускается (а упорный отказ помечается &lt;code&gt;__NO_TOOLS__&lt;/code&gt;). Ответ «из головы» про известный репозиторий не измерял бы провайдера контекста.&lt;/ol&gt;&lt;p&gt;И отдельно — &lt;strong&gt;провал засчитывается как точность 0.&lt;/strong&gt; Если grep упёрся в потолок 50 ходов и не выдал ответ — это не «нет данных», это «инструмент не справился в рамках бюджета». Так и считаем.&lt;h3&gt;Задачи: два режима, и почему их нельзя смешивать&lt;/h3&gt;&lt;p&gt;26 задач делятся на два класса.&lt;p&gt;&lt;strong&gt;SIMPLE — 20 точечных запросов&lt;/strong&gt; («где определён X / от чего наследуется X»). Ответ — одна точка, проверяется вхождением подстроки:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Тип&lt;th&gt;&lt;p align=left&gt;#&lt;th&gt;&lt;p align=left&gt;Что проверяет&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;where_defined&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;7&lt;td&gt;&lt;p align=left&gt;Python-класс → файл определения&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;inherits_from&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;5&lt;td&gt;&lt;p align=left&gt;Python-класс → базовый класс&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;abstract_methods&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;1&lt;td&gt;&lt;p align=left&gt;ABC → его абстрактные методы&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;ts_where_defined&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;1&lt;td&gt;&lt;p align=left&gt;TS-хук → файл определения&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;ts_route_call&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;4&lt;td&gt;&lt;p align=left&gt;роут &lt;code&gt;/api/v1/...&lt;/code&gt; → TS-хук, который его дёргает&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;xlang_link&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;TS-потребитель → Python-обработчик через границу API&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;HARD — 6 задач на радиус поражения и неоднозначность.&lt;/strong&gt; Это режим, где структура и семантика &lt;em&gt;должны&lt;/em&gt; бить текстовый поиск — и который точечные запросы в принципе не измеряют:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Тип&lt;th&gt;&lt;p align=left&gt;#&lt;th&gt;&lt;p align=left&gt;Что проверяет&lt;th&gt;&lt;p align=left&gt;Оценка&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;disambiguate&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;неоднозначное голое имя метода (напр. &lt;code&gt;cache_key&lt;/code&gt;, определён во многих классах) → &lt;em&gt;тот самый&lt;/em&gt; класс&lt;td&gt;&lt;p align=left&gt;подстрока&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;overrides_count&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;полный набор подклассов, переопределяющих метод базы&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;F1 по множеству&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;code&gt;impact_set&lt;/code&gt;&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;все файлы, вызывающие данный метод (радиус поражения)&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;F1 по множеству&lt;/strong&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Set-задачи оцениваются по F1: награда за полноту (найти всех) и штраф за мусор в точности (текстовый поиск любит вывалить каждое вхождение &lt;code&gt;.get_indexes(&lt;/code&gt;). Эталонные множества держим маленькими (3–5 элементов, одно ≈17), чтобы их можно было исчерпывающе проверить руками.&lt;h4&gt;Почему я стратифицирую, а не усредняю&lt;/h4&gt;&lt;p&gt;Набор &lt;strong&gt;намеренно несбалансирован&lt;/strong&gt; — 20 простых против 6 сложных. Если посчитать одно общее среднее, оно будет полностью продиктовано лёгкими задачами и &lt;strong&gt;спрячет&lt;/strong&gt; ровно ту разницу, которую вскрывают сложные. Поэтому я докладываю каждый режим &lt;strong&gt;отдельно и никогда не смешиваю&lt;/strong&gt;.&lt;p&gt;И да — я сознательно не «балансирую до 50/50» выкидыванием простых задач. Это потеряло бы данные и статистическую мощность и открыло бы дверь для cherry-pick. Стратификация нейтрализует перекос &lt;strong&gt;без выброса данных&lt;/strong&gt;. Это, кстати, общий принцип: если режимы дают разные ответы, честнее показать оба, чем спрятать конфликт под усреднением.&lt;h3&gt;Результаты&lt;/h3&gt;&lt;h4&gt;SIMPLE — 20 точечных запросов&lt;/h4&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Инструмент&lt;th&gt;&lt;p align=left&gt;точность&lt;th&gt;&lt;p align=left&gt;заверш.&lt;th&gt;&lt;p align=left&gt;токены&lt;th&gt;&lt;p align=left&gt;вызовы&lt;th&gt;&lt;p align=left&gt;$/задача&lt;th&gt;&lt;p align=left&gt;сек&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;filesystem&lt;td&gt;&lt;p align=left&gt;0.97&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;1780&lt;td&gt;&lt;p align=left&gt;10&lt;td&gt;&lt;p align=left&gt;$0.063&lt;td&gt;&lt;p align=left&gt;43&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;graphlens&lt;td&gt;&lt;p align=left&gt;0.98&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;690&lt;td&gt;&lt;p align=left&gt;3&lt;td&gt;&lt;p align=left&gt;$0.038&lt;td&gt;&lt;p align=left&gt;13&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;serena&lt;td&gt;&lt;p align=left&gt;0.99&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;402&lt;td&gt;&lt;p align=left&gt;3&lt;td&gt;&lt;p align=left&gt;$0.031&lt;td&gt;&lt;p align=left&gt;20&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;codegraph&lt;td&gt;&lt;p align=left&gt;0.99&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;372&lt;td&gt;&lt;p align=left&gt;1&lt;td&gt;&lt;p align=left&gt;$0.022&lt;td&gt;&lt;p align=left&gt;10&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Точность — &lt;strong&gt;ничья&lt;/strong&gt; (формально: критерий Фридмана χ²=0.40, незначимо). Инструменты различаются только ценой: разброс ~3×, выигрывают самые «немногословные». &lt;strong&gt;graphlens здесь ничем не примечателен&lt;/strong&gt; — крепкий середняк.&lt;p&gt;Вот ровно ту историю рассказал бы стенд, измеряющий только точечные запросы: «структурные инструменты — приятно, но grep почти справляется, а самый дешёвый ответ даёт codegraph». И это была бы &lt;strong&gt;неполная&lt;/strong&gt; правда.&lt;h4&gt;HARD — 6 задач на радиус поражения и неоднозначность&lt;/h4&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Инструмент&lt;th&gt;&lt;p align=left&gt;точность&lt;th&gt;&lt;p align=left&gt;заверш.&lt;th&gt;&lt;p align=left&gt;токены&lt;th&gt;&lt;p align=left&gt;вызовы&lt;th&gt;&lt;p align=left&gt;$/задача&lt;th&gt;&lt;p align=left&gt;сек&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;filesystem&lt;td&gt;&lt;p align=left&gt;0.71&lt;td&gt;&lt;p align=left&gt;83%&lt;td&gt;&lt;p align=left&gt;12596&lt;td&gt;&lt;p align=left&gt;27&lt;td&gt;&lt;p align=left&gt;$0.424&lt;td&gt;&lt;p align=left&gt;165&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;graphlens&lt;td&gt;&lt;p align=left&gt;0.84&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;748&lt;td&gt;&lt;p align=left&gt;1&lt;td&gt;&lt;p align=left&gt;$0.018&lt;td&gt;&lt;p align=left&gt;9&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;serena&lt;td&gt;&lt;p align=left&gt;0.85&lt;td&gt;&lt;p align=left&gt;98%&lt;td&gt;&lt;p align=left&gt;1368&lt;td&gt;&lt;p align=left&gt;5&lt;td&gt;&lt;p align=left&gt;$0.065&lt;td&gt;&lt;p align=left&gt;29&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;codegraph&lt;td&gt;&lt;p align=left&gt;0.93&lt;td&gt;&lt;p align=left&gt;100%&lt;td&gt;&lt;p align=left&gt;1114&lt;td&gt;&lt;p align=left&gt;2&lt;td&gt;&lt;p align=left&gt;$0.036&lt;td&gt;&lt;p align=left&gt;16&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;А вот тут инструменты &lt;strong&gt;расходятся&lt;/strong&gt;.&lt;p&gt;&lt;strong&gt;grep схлопывается.&lt;/strong&gt; Самая низкая точность (0.71), до финиша доходит лишь 83% прогонов (остальные упираются в потолок 50 ходов), а те, что доходят, стоят &lt;strong&gt;в 10–23 раза дороже&lt;/strong&gt; (~$0.42 против $0.018–0.065) и работают &lt;strong&gt;в 10–18 раз дольше&lt;/strong&gt; (~165 секунд против 9–29). Текстовый поиск тонет в шуме, когда вопрос — «все вызовы вот этого» или «какой именно из десятка одноимённых методов».&lt;p&gt;&lt;strong&gt;Структурные инструменты держатся дёшево и точно.&lt;/strong&gt; И вот ключевое: &lt;strong&gt;graphlens — середняк на простых задачах — здесь самый дешёвый ($0.018) и самый быстрый (9 секунд).&lt;/strong&gt; Его семантический граф наконец окупается: один вызов вместо двадцати семи. Самым &lt;em&gt;точным&lt;/em&gt; оказывается codegraph (0.93). serena конкурентна (0.85).&lt;p&gt;То есть тот самый graphlens, который на точечных запросах выглядел невзрачно, в режиме реальной работы — про анализ влияния, про рефакторинг — становится самым экономичным. Ранжирование &lt;strong&gt;инвертируется&lt;/strong&gt; между режимами.&lt;blockquote&gt;&lt;p&gt;Заметка о честности стенда. MCP-&lt;em&gt;ресурсы&lt;/em&gt; отключены для всех рук. graphlens — единственный сервер, выставлявший ресурсы, и в одном из ранних прогонов агент уходил в их перечисление и раздувал стоимость ~на 24%, пока я это не запретил. Все цифры выше — с чистого перепрогона.&lt;/blockquote&gt;&lt;h3&gt;Где уходят деньги: механизм — это round-trips&lt;/h3&gt;&lt;p&gt;Разница в цене — это в основном &lt;strong&gt;число обращений к инструменту&lt;/strong&gt;, а оно вытекает из того, как сервер нарезает свои примитивы.&lt;p&gt;На простом «символ → файл» (&lt;code&gt;where_defined&lt;/code&gt;) всем хватает &lt;strong&gt;одного&lt;/strong&gt; вызова. Разрыв открывается на &lt;strong&gt;запросах об отношениях&lt;/strong&gt; — наследование, роут → обработчик, межъязыковые связи. Здесь &lt;code&gt;graphlens&lt;/code&gt; цепочкой дёргает мелкозернистые примитивы (&lt;code&gt;find&lt;/code&gt; → &lt;code&gt;neighbors&lt;/code&gt; → &lt;code&gt;references&lt;/code&gt;), а &lt;code&gt;codegraph&lt;/code&gt; упаковывает «исходник + пути вызовов за один заход» (&lt;code&gt;explore&lt;/code&gt; / &lt;code&gt;node&lt;/code&gt;).&lt;p&gt;Это не разница в том, &lt;em&gt;что знает граф&lt;/em&gt; — графы знают примерно одно. Это разница в гранулярности API: меньше round-trips → дешевле и быстрее. Вот откуда у codegraph преимущество в эффективности на простых задачах, и вот почему grep на сложных задачах разоряется — он делает 27 обращений там, где графу хватает одного-двух.&lt;h3&gt;Взаимодействие модель × инструмент: ранжирование плывёт от цены модели&lt;/h3&gt;&lt;p&gt;Это самая неочевидная часть. Возьмём медианную $/задача (по обоим режимам) в разрезе модели:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Инструмент&lt;th&gt;&lt;p align=left&gt;haiku&lt;th&gt;&lt;p align=left&gt;sonnet&lt;th&gt;&lt;p align=left&gt;opus&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;filesystem&lt;td&gt;&lt;p align=left&gt;$0.053&lt;td&gt;&lt;p align=left&gt;$0.080&lt;td&gt;&lt;p align=left&gt;$0.087&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;graphlens&lt;td&gt;&lt;p align=left&gt;$0.020&lt;td&gt;&lt;p align=left&gt;$0.041&lt;td&gt;&lt;p align=left&gt;$0.046&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;serena&lt;td&gt;&lt;p align=left&gt;$0.026&lt;td&gt;&lt;p align=left&gt;$0.033&lt;td&gt;&lt;p align=left&gt;$0.042&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;codegraph&lt;td&gt;&lt;p align=left&gt;$0.023&lt;td&gt;&lt;p align=left&gt;$0.041&lt;td&gt;&lt;p align=left&gt;$0.031&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Ранжирование по дешевизне &lt;strong&gt;внутри каждой модели&lt;/strong&gt;:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;haiku:&lt;/strong&gt; graphlens $0.020 &amp;lt; codegraph $0.023 &amp;lt; serena $0.026 &amp;lt; filesystem $0.053&lt;li&gt;&lt;p&gt;&lt;strong&gt;sonnet:&lt;/strong&gt; serena $0.033 &amp;lt; graphlens $0.041 &amp;lt; codegraph $0.041 &amp;lt; filesystem $0.080&lt;li&gt;&lt;p&gt;&lt;strong&gt;opus:&lt;/strong&gt; codegraph $0.031 &amp;lt; serena $0.042 &amp;lt; graphlens $0.046 &amp;lt; filesystem $0.087&lt;/ul&gt;&lt;p&gt;Смотрите, что происходит с graphlens. На &lt;strong&gt;haiku он самый дешёвый из всех&lt;/strong&gt;. На &lt;strong&gt;opus он становится самым дорогим из структурных инструментов&lt;/strong&gt; (хотя всё ещё дешевле grep).&lt;p&gt;Механизм: результаты graphlens &lt;strong&gt;токеноёмкие&lt;/strong&gt; — окрестности графа, списки ссылок. На дешёвой модели этот многословный контекст почти бесплатен, на дорогой — opus тарифицирует те же токены кратно выше, и многословность бьёт по карману. &lt;strong&gt;serena и codegraph дёшевы на любой модели&lt;/strong&gt;, потому что возвращают точечные результаты — они устойчивы к выбору модели, а graphlens нет.&lt;p&gt;Отсюда практический вывод, который дороже всех остальных: &lt;strong&gt;дешёвая модель на структурном инструменте бьёт дорогую модель на grep.&lt;/strong&gt; codegraph + haiku (~$0.023, точность ~0.99) делает filesystem + opus (~$0.087, точность 0.93) по всем осям сразу.&lt;h3&gt;Гипотеза, которая не подтвердилась&lt;/h3&gt;&lt;p&gt;Я закладывал пару &lt;code&gt;xlang_link&lt;/code&gt; как стресс-тест: TS-вызов резолвится в Python-обработчик через границу &lt;code&gt;/api/v1/...&lt;/code&gt;, и я был уверен, что одноязычные инструменты на этом споткнутся.&lt;p&gt;&lt;strong&gt;Не споткнулись.&lt;/strong&gt; Все руки, включая grep, решили обе межъязыковые задачи. Агент сам перешагивает границу — независимо от провайдера контекста. На этом наборе гипотеза не подтвердилась, и я докладываю это ровно так же громко, как и подтвердившиеся выводы. Бенчмарк, который рапортует только то, что хотелось увидеть, — это не бенчмарк.&lt;h3&gt;Статистика честно&lt;/h3&gt;&lt;p&gt;Критерий Фридмана по четырём инструментам, по блокам-задачам, внутри каждого режима (df=3; критические значения: 0.05 → 7.82, 0.01 → 11.34):&lt;pre&gt;&lt;code&gt;SIMPLE:&#xA;  точность  n=20  χ²= 0.40  (н.з.)    — ничья&#xA;  стоимость n=20  χ²=18.42  (p&amp;lt;.01)   — serena &amp;lt; codegraph &amp;lt; graphlens &amp;lt; filesystem&#xA;&#xA;HARD:&#xA;  точность  n= 6  χ²= 3.50  (н.з.)    — недостаточно мощности&#xA;  стоимость n= 6  χ²=11.80  (p&amp;lt;.01)   — graphlens &amp;lt; codegraph &amp;lt; serena &amp;lt; filesystem&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Что отсюда честно сказать:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Разница в &lt;strong&gt;стоимости значима в обоих режимах&lt;/strong&gt; (p&amp;lt;.01). На HARD graphlens достоверно самый дешёвый, grep достоверно самый дорогой. Это твёрдый результат.&lt;li&gt;&lt;p&gt;Разница в &lt;strong&gt;точности на HARD большая, но статистически незначима&lt;/strong&gt; при n=6 (χ²=3.50). Это сильный &lt;em&gt;описательный&lt;/em&gt; сигнал, но ещё не доказанный. Шесть задач — мало.&lt;li&gt;&lt;p&gt;Чтобы укрепить вывод про точность, нужно &lt;strong&gt;добавить сложных задач, а не убирать простые&lt;/strong&gt;. Урезание простого режима не даёт сложному ни капли мощности — оно лишь выбрасывает хорошие данные.&lt;/ul&gt;&lt;p&gt;Я специально оставляю это в статье. Соблазн написать «graphlens/codegraph точнее grep, доказано» велик, но n=6 этого не вытягивает, и притворяться было бы нечестно.&lt;h3&gt;Амортизация индекса: разные валюты&lt;/h3&gt;&lt;p&gt;Структурные инструменты строят индекс один раз — это &lt;strong&gt;чистая статика, ноль LLM-токенов&lt;/strong&gt;, только wall-clock:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Инструмент&lt;th&gt;&lt;p align=left&gt;разовая индексация&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;filesystem&lt;td&gt;&lt;p align=left&gt;0 с&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;codegraph&lt;td&gt;&lt;p align=left&gt;48 с&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;graphlens&lt;td&gt;&lt;p align=left&gt;84 с&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;serena&lt;td&gt;&lt;p align=left&gt;94 с&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;grep не платит вперёд ничего, но платит больше за каждый запрос. Это &lt;strong&gt;разные валюты&lt;/strong&gt; (секунды против $/токенов), поэтому никакой единой «точки безубыточности» я не рисую — это была бы натяжка. Картина простая: индекс — разовая трата времени без единого токена, а экономия $/задача капает на каждой задаче. На длинной сессии структурные инструменты амортизируются; на паре разовых запросов нулевой сетап grep может выиграть по «времени до первого ответа».&lt;h3&gt;Выводы для бизнес-кейса&lt;/h3&gt;&lt;p&gt;Вернёмся к исходному вопросу: чем кормить агента на большом проекте?&lt;p&gt;&lt;strong&gt;Ответа «вот этот инструмент всегда лучший» — нет.&lt;/strong&gt; Есть ответ «зависит от того, какую работу вы поручаете»:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Разовые точечные справки&lt;/strong&gt; («где определён класс», «от чего наследуется»): берите что угодно. grep справляется, точность та же, нулевой сетап. Платите вы тут разве что небольшим overhead&amp;#39;ом в токенах.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Постоянная работа с анализом влияния&lt;/strong&gt; — рефакторинг, оценка радиуса поражения, разрешение неоднозначностей на большой кодовой базе: структурные инструменты режут стоимость &lt;strong&gt;в 10–23 раза&lt;/strong&gt; и латентность &lt;strong&gt;в 10–18 раз&lt;/strong&gt; против grep — и, что не менее важно, &lt;strong&gt;не упираются в потолок ходов&lt;/strong&gt;. grep на этих задачах не просто дорог, он в 17% случаев вообще не доходит до ответа.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Выбор модели взаимодействует с выбором инструмента.&lt;/strong&gt; Многословный граф дёшев на маленькой модели и дорог на большой. Если гоняете opus — берите инструмент с точечной отдачей (codegraph, serena). Если haiku — graphlens внезапно самый дешёвый.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Самая дешёвая комбинация — не «дорогая модель + простой инструмент», а «дешёвая модель + структурный инструмент».&lt;/strong&gt;&lt;/ul&gt;&lt;p&gt;И честные оговорки, без которых выводы нельзя переносить на ваш проект:&lt;blockquote&gt;&lt;p&gt;Один репозиторий (&lt;code&gt;apache/superset&lt;/code&gt; @ 6.0.0), один стенд, 26 задач (20 простых / 6 сложных). Режимы докладываются раздельно и &lt;strong&gt;никогда не смешиваются&lt;/strong&gt;. &lt;code&gt;cost_usd&lt;/code&gt; — API-эквивалент, а не счёт по подписке. Провал = точность 0. Это &lt;strong&gt;не универсальный рейтинг&lt;/strong&gt; — это воспроизводимый замер на конкретном кейсе.&lt;/blockquote&gt;&lt;h3&gt;Где здесь graphlens&lt;/h3&gt;&lt;p&gt;Раз уж это продолжение &lt;a href=https://habr.com/ru/articles/1050204/ rel=&#34;noopener noreferrer nofollow&#34;&gt;статьи про него&lt;/a&gt; — скажу прямо. Этот бенчмарк не доказывает, что graphlens «лучший». Он показывает &lt;strong&gt;конкретный режим, в котором его структурный граф окупается&lt;/strong&gt; (анализ влияния, дёшево и быстро на дешёвых моделях), и так же прямо показывает, &lt;strong&gt;где он проседает&lt;/strong&gt; (на opus его многословная отдача дороже, чем у codegraph и serena; codegraph точнее на сложных задачах).&lt;p&gt;Для меня это полезнее любой победной реляции. graphlens задумывался как &lt;strong&gt;движок и точная мультиязычная модель графа&lt;/strong&gt;, а не как готовое приложение. Бенчмарк ровно это и подтверждает: на структурных вопросах граф бьёт текстовый поиск с большим запасом, и одновременно есть куда расти — гранулярность MCP-инструментов (меньше round-trips, как у codegraph) и компактность отдачи (чтобы не разоряться на дорогих моделях). Это мой следующий пункт работ, и он теперь подкреплён числами, а не интуицией.&lt;h3&gt;Воспроизвести&lt;/h3&gt;&lt;p&gt;Весь стенд и сырые данные — открыты. Прогон полностью детерминированно собирается из &lt;code&gt;data/&lt;/code&gt;.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Репозиторий бенчмарка:&lt;/strong&gt; &lt;a href=https://github.com/Neko1313/agent-context-bench rel=&#34;noopener noreferrer nofollow&#34;&gt;https://github.com/Neko1313/agent-context-bench&lt;/a&gt;&lt;li&gt;&lt;p&gt;Смотреть &lt;code&gt;metrics.ipynb&lt;/code&gt; (все графики и постатейная статистика) и &lt;a href=http://README.md rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; (методология).&lt;li&gt;&lt;p&gt;&lt;code&gt;uv run &lt;/code&gt;&lt;a href=http://main.py rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/a&gt; гоняет весь пайплайн (клонирование superset → сборка индексов → 936 прогонов, resumable в рамках лимитов подписки), дальше открываете &lt;code&gt;metrics.ipynb&lt;/code&gt;.&lt;/ul&gt;&lt;p&gt;Если у вас есть свой большой проект и желание прогнать стенд на нём — буду рад issue и результатам. Чем больше независимых прогонов на разных кодовых базах, тем ближе мы к ответу, который можно переносить, а не «работает на superset».&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>Neko1313</author>
      <guid>https://habr.com/ru/articles/1051504/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051504</guid>
      <pubDate>Wed, 24 Jun 2026 15:42:45 +0000</pubDate>
    </item>
    <item>
      <title>Топ вопросов по LLM: стратегии генерации текста и метрики оценки LLM</title>
      <link>https://habr.com/ru/articles/1044418/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1044418</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;На NLP/LLM-собеседованиях часто проверяют не то, знаешь ли ты слова top-k, top-p и BLEU, а понимаешь ли ты, что происходит с распределением вероятностей, почему greedy decoding зацикливается, зачем нужна temperature и почему BLEU плохо оценивает ответы современных LLM.&lt;blockquote&gt;&lt;p&gt;В этой статье - &lt;strong&gt;чеклист&lt;/strong&gt; по языковому моделированию, стратегиям генерации и метрикам качества. Это не полноценная лекция с нуля, а &lt;strong&gt;тренажёр&lt;/strong&gt;, по которому стоит пройтись перед техническим интервью по NLP, чтобы закрыть пробелы и вспомнить необходимую базу.&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;Содержание:&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Языковое моделирование&lt;li&gt;&lt;p&gt;Стратегии генерации текста&lt;li&gt;&lt;p&gt;Метрики оценки качества сгенерированного текста&lt;li&gt;&lt;p&gt;Итоговый чеклист вопросов с собесов&lt;li&gt;&lt;p&gt;Полезные материалы&lt;/ul&gt;&lt;details class=spoiler&gt;&lt;summary&gt;Статьи серии&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/articles/1019194/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Топ вопросов по математике для ML и Data Science собесов: линейная алгебра и матан&lt;/a&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/articles/926398/ rel=&#34;noopener noreferrer nofollow&#34;&gt;classic ML: основы мл, линейные модели, метрики классификации и регресии&lt;/a&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/articles/955636/ rel=&#34;noopener noreferrer nofollow&#34;&gt;classic ML: Деревья и ансамбли, кластеризация, метрические модели&lt;/a&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/articles/972178/ rel=&#34;noopener noreferrer nofollow&#34;&gt;NLP: трансформеры и внимание&lt;/a&gt;&lt;p&gt;NLP: языковое моделирование, LLM Alignment и оптимизация трансформеров [эта часть]&lt;p&gt;NLP: GPT, LLM, Alignment и оптимизации &lt;em&gt;[Soon… Stay fine‑tuned…]&lt;/em&gt;&lt;p&gt;NLP: LLM и агенты &lt;em&gt;[Soon… Stay fine‑tuned…]&lt;/em&gt;&lt;p&gt;&lt;a href=https://nlp:%20LLM,%20RAG%20%D0%B8%20%D0%B0%D0%B3%D0%B5%D0%BD%D1%82%D1%8B%20%5BSoon%E2%80%A6%20Stay%20fine-tuned%E2%80%A6%5D/ rel=&#34;noopener noreferrer nofollow&#34;&gt;NLP: LLM и RAG&lt;/a&gt;&lt;/div&gt;&lt;/details&gt;&lt;h2&gt;Языковое моделирование&lt;/h2&gt;&lt;h3&gt;Что такое задача языкового моделирования?&lt;/h3&gt;&lt;p&gt;Языковое моделирование - это фундаментальная задача NLP, в которой модель учится оценивать вероятность последовательности токенов.&lt;p&gt;Модель оценивает совместную вероятность последовательности через chain rule:&lt;/p&gt;&lt;img class=formula source=&#34;P(y_1, y_2, \dots, y_n)=P(y_1)\cdot P(y_2|y_1)\cdot P(y_3|y_1, y_2)\cdot\dots\cdot P(y_n|y_1, \dots, y_{n-1})=         \prod \limits_{t=1}^n P(y_t|y_{\mbox{&amp;lt;}t}).&#34; alt=&#34;P(y_1, y_2, \dots, y_n)=P(y_1)\cdot P(y_2|y_1)\cdot P(y_3|y_1, y_2)\cdot\dots\cdot P(y_n|y_1, \dots, y_{n-1})=         \prod \limits_{t=1}^n P(y_t|y_{\mbox{&amp;lt;}t}).&#34; src=https://habrastorage.org/getpro/habr/formulas/9/9e/9e3/9e3a86ecc01e714f677e855fd742c61e.svg width=696 height=48 data-width=87.674 data-height=6.354 data-vertical-align=-2.611 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/9/9e/9e3/9e3a86ecc01e714f677e855fd742c61e.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/9/9e/9e3/9e3a86ecc01e714f677e855fd742c61e.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;То есть модель учится предсказывать каждый следующий токен по предыдущему контексту, и мы раскладываем вероятность всего предложения на произведение условных вероятностей следующего токена.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/621/623/9ef/6216239ef6e3b2aeb8a600ab8e854477.png alt=&#34;Пример предсказания следующего токена&#34; title=&#34;Пример предсказания следующего токена&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/621/623/9ef/6216239ef6e3b2aeb8a600ab8e854477.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/621/623/9ef/6216239ef6e3b2aeb8a600ab8e854477.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пример предсказания следующего токена&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Модель учится на огромном количестве текстов предсказывать статистически и семантически подходящее продолжение. Именно это лежит в основе современных GPT-like моделей.&lt;h3&gt;Где встречается языковое моделирование?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;автодополнение в клавиатуре&lt;li&gt;&lt;p&gt;подсказки в поисковике&lt;li&gt;&lt;p&gt;машинный перевод&lt;li&gt;&lt;p&gt;генерация ответов в чат-ботах&lt;li&gt;&lt;p&gt;суммаризация текстов&lt;li&gt;&lt;p&gt;генерация кода&lt;li&gt;&lt;p&gt;исправление ошибок&lt;li&gt;&lt;p&gt;продолжение текста&lt;li&gt;&lt;p&gt;переформулирование&lt;li&gt;&lt;p&gt;генерация описаний товаров&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d8e/a44/648/d8ea4464881d4017b9a95ede133cbf01.png alt=&#34;Примеры применения языковых моделей&#34; title=&#34;Примеры применения языковых моделей&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d8e/a44/648/d8ea4464881d4017b9a95ede133cbf01.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d8e/a44/648/d8ea4464881d4017b9a95ede133cbf01.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Примеры применения языковых моделей&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;То есть задача вроде бы простая - предсказывать следующий токен, но на ней строится почти все современное генеративное NLP.&lt;h3&gt;Как модель получает вероятность следующего токена?&lt;/h3&gt;&lt;p&gt;Упрощённый пайплайн выглядит так:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Берём текст&lt;li&gt;&lt;p&gt;Разбиваем его на токены&lt;li&gt;&lt;p&gt;Превращаем токены в эмбеддинги&lt;li&gt;&lt;p&gt;Пропускаем эмбеддинги через нейронную сеть&lt;li&gt;&lt;p&gt;Получаем hidden state&lt;li&gt;&lt;p&gt;Прогоняем hidden state через линейный слой&lt;li&gt;&lt;p&gt;Получаем логиты по словарю&lt;li&gt;&lt;p&gt;Применяем softmax&lt;li&gt;&lt;p&gt;Получаем распределение вероятностей следующего токена&lt;/ul&gt;&lt;p&gt;Допустим, у модели словарь из 50 000 токенов. Тогда на каждом шаге генерации модель должна выдать распределение вероятностей по всем этим 50 000 возможным токенам.&lt;p&gt;Например:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Токен&lt;th&gt;&lt;p align=left&gt;Вероятность&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;кофе&lt;td&gt;&lt;p align=left&gt;0.42&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;чая&lt;td&gt;&lt;p align=left&gt;0.21&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;воды&lt;td&gt;&lt;p align=left&gt;0.08&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;молока&lt;td&gt;&lt;p align=left&gt;0.04&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;...&lt;td&gt;&lt;p align=left&gt;...&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;После этого мы выбираем следующий токен одним из способов: жадно, случайным семплированием, top-k, top-p, beam search и так далее. Эти стратегии разберём ниже.&lt;h4&gt;Языковое моделирование как классификация&lt;/h4&gt;&lt;p&gt;На каждом шаге модель решает задачу многоклассовой классификации.&lt;p&gt;Класс - это следующий токен. Если словарь содержит 50 000 токенов, значит у нас 50 000 классов.&lt;p&gt;Модель получает контекст:&lt;blockquote&gt;&lt;p&gt;Я хочу выпить чашку&lt;/blockquote&gt;&lt;p&gt;и должна предсказать правильный класс:&lt;blockquote&gt;&lt;p&gt;кофе&lt;/blockquote&gt;&lt;p&gt;То есть генерация текста - это последовательность классификаций, где на каждом шаге модель выбирает следующий токен из словаря.&lt;h4&gt;Hidden state, logits и softmax&lt;/h4&gt;&lt;p&gt;Нейронная сеть не сразу выдаёт вероятности. Сначала она формирует внутреннее представление контекста - hidden state: &lt;img class=&#34;formula inline&#34; source=h_t alt=h_t src=https://habrastorage.org/getpro/habr/formulas/6/6c/6c4/6c4ff69dbcc329835a33b80fe3a145c7.svg width=16 height=12 data-width=2.068 data-height=1.927 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/6/6c/6c4/6c4ff69dbcc329835a33b80fe3a145c7.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/6/6c/6c4/6c4ff69dbcc329835a33b80fe3a145c7.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Дальше этот hidden state проходит через линейный слой: &lt;img class=&#34;formula inline&#34; source=&#34;z_t = W h_t + b&#34; alt=&#34;z_t = W h_t + b&#34; src=https://habrastorage.org/getpro/habr/formulas/2/29/292/292e1a079db51c3ed08768ea30010537.svg width=104 height=12 data-width=13.01 data-height=1.927 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/29/292/292e1a079db51c3ed08768ea30010537.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/29/292/292e1a079db51c3ed08768ea30010537.svg 781w&#34; loading=lazy decode=async&gt; - получаем логиты.&lt;p&gt;Логиты - это ещё не вероятности. Это произвольные вещественные числа. Они могут быть отрицательными, положительными, большими, маленькими. Чтобы превратить их в вероятности, применяют softmax. После softmax все значения становятся неотрицательными и суммируются в 1.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/90d/ceb/af5/90dcebaf52b10497a9dc49012e3099be.png alt=&#34;Пайплайн получения из входного текста вероятностей следующего токена&#34; title=&#34;Пайплайн получения из входного текста вероятностей следующего токена&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/90d/ceb/af5/90dcebaf52b10497a9dc49012e3099be.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/90d/ceb/af5/90dcebaf52b10497a9dc49012e3099be.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пайплайн получения из входного текста вероятностей следующего токена&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Также внимательно изучите размерности всех тензоров в разные моменты времени, это важно)&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/91b/b7f/7a9/91bb7f7a9d8f6438c8e2b27fc8dc4c59.png alt=&#34;размерности во время генерации текста&#34; title=&#34;размерности во время генерации текста&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/91b/b7f/7a9/91bb7f7a9d8f6438c8e2b27fc8dc4c59.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/91b/b7f/7a9/91bb7f7a9d8f6438c8e2b27fc8dc4c59.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;размерности во время генерации текста&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Как обучается языковая модель?&lt;/h3&gt;&lt;p&gt;Для обучения обычно используется &lt;strong&gt;кросс-энтропия&lt;/strong&gt;.&lt;p&gt;Если правильный следующий токен - кофе, то мы хотим, чтобы модель дала ему высокую вероятность.&lt;p&gt;Функция потерь для одного шага:&lt;br&gt;&lt;img class=&#34;formula inline&#34; source=&#34;L = - \log P(y_t \mid x_{&amp;lt;t})&#34; alt=&#34;L = - \log P(y_t \mid x_{&amp;lt;t})&#34; src=https://habrastorage.org/getpro/habr/formulas/e/ed/ed5/ed52257cefd9e64d2982e5c55ecc2ecd.svg width=160 height=16 data-width=20.487 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/ed/ed5/ed52257cefd9e64d2982e5c55ecc2ecd.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/ed/ed5/ed52257cefd9e64d2982e5c55ecc2ecd.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=y_t alt=y_t src=https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a568bf104397bd8311073893dff24222.svg width=12 height=12 data-width=1.874 data-height=1.464 data-vertical-align=-0.464 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a568bf104397bd8311073893dff24222.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/a/a5/a56/a568bf104397bd8311073893dff24222.svg 781w&#34; loading=lazy decode=async&gt; - правильный токен&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=x_{&amp;lt;t} alt=x_{&amp;lt;t} src=https://habrastorage.org/getpro/habr/formulas/b/b0/b0f/b0f084cbd3e17e1b2246d6e5580f5f43.svg width=24 height=12 data-width=3.304 data-height=1.403 data-vertical-align=-0.403 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/b/b0/b0f/b0f084cbd3e17e1b2246d6e5580f5f43.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/b/b0/b0f/b0f084cbd3e17e1b2246d6e5580f5f43.svg 781w&#34; loading=lazy decode=async&gt; - предыдущий контекст&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;P(y_t \mid x_{&amp;lt;t})&#34; alt=&#34;P(y_t \mid x_{&amp;lt;t})&#34; src=https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/cccc55c35cc3298001d72f2ce5617259.svg width=80 height=16 data-width=10.523 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/cccc55c35cc3298001d72f2ce5617259.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/cc/ccc/cccc55c35cc3298001d72f2ce5617259.svg 781w&#34; loading=lazy decode=async&gt; - вероятность, которую модель присвоила правильному токену, при условии контекста.&lt;/ul&gt;&lt;p&gt;Для всей последовательности:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;L = - \sum_{t=1}^{n} \log P(x_t \mid x_1, ..., x_{t-1})&#34; alt=&#34;L = - \sum_{t=1}^{n} \log P(x_t \mid x_1, ..., x_{t-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/4/44/44a/44a8019ab3d51dca9847cd7fcdc4276f.svg width=256 height=48 data-width=32.428 data-height=6.354 data-vertical-align=-2.611 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/44/44a/44a8019ab3d51dca9847cd7fcdc4276f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/44/44a/44a8019ab3d51dca9847cd7fcdc4276f.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;То есть если модель уверенно предсказывает правильные токены, loss маленький. Если модель даёт правильным токенам низкую вероятность, loss большой.&lt;p&gt;&lt;strong&gt;Почему это удобно масштабировать&lt;/strong&gt;&lt;p&gt;Для обучения GPT-like моделей не нужна ручная разметка в классическом смысле. Нам не нужно, чтобы человек размечал: здесь правильный ответ/класс такой-то. Потому что у нас уже есть текст. А следующий токен в тексте автоматически становится таргетом.&lt;p&gt;Например, есть фраза:&lt;blockquote&gt;&lt;p&gt;Машинное обучение - это область искусственного интеллекта.&lt;/blockquote&gt;&lt;p&gt;Из неё можно получить много обучающих примеров:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th data-colwidth=295 width=295&gt;&lt;p align=left&gt;Контекст&lt;th&gt;&lt;p align=left&gt;Таргет&lt;tr&gt;&lt;td data-colwidth=295 width=295&gt;&lt;p align=left&gt;Машинное&lt;td&gt;&lt;p align=left&gt;обучение&lt;tr&gt;&lt;td data-colwidth=295 width=295&gt;&lt;p align=left&gt;Машинное обучение&lt;td&gt;&lt;p align=left&gt;-&lt;tr&gt;&lt;td data-colwidth=295 width=295&gt;&lt;p align=left&gt;Машинное обучение -&lt;td&gt;&lt;p align=left&gt;это&lt;tr&gt;&lt;td data-colwidth=295 width=295&gt;&lt;p align=left&gt;Машинное обучение - это&lt;td&gt;&lt;p align=left&gt;область&lt;tr&gt;&lt;td data-colwidth=295 width=295&gt;&lt;p align=left&gt;Машинное обучение - это область&lt;td&gt;&lt;p align=left&gt;искусственного&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Поэтому next token prediction хорошо масштабируется: можно брать книги, статьи, сайты, документацию, код, форумы и обучать модель на огромных корпусах.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c79/7e5/b54/c797e5b547cc1c9b83cd42d7459da7f4.png alt=&#34;масштабирование гпт&#34; title=&#34;масштабирование гпт&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c79/7e5/b54/c797e5b547cc1c9b83cd42d7459da7f4.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c79/7e5/b54/c797e5b547cc1c9b83cd42d7459da7f4.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;масштабирование гпт&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;С помощью каких архитектур можно решать языковое моделирование?&lt;/h3&gt;&lt;p&gt;Исторически языковое моделирование решали разными архитектурами: от n-gramных статистических подходов до rnn/lstm.&lt;p&gt;Но сейчас, конечно, основа всех современных LLM именно архитектуры на базе Transformer.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Небольшая оговорка&lt;/strong&gt;&lt;br&gt;Есть и так называемые ssm: state space models. Активно ведутся исследования в сторону поиска оптимальных архитектур вместо трансформеров, у которых есть свои недостатки, но пока что массово в компаниях не переходят на альтернативы, и на собесах не спрашивают, так что о них говорить не будем.&lt;/blockquote&gt;&lt;p&gt;Как вы уже можете помнить из &lt;a href=https://habr.com/ru/articles/972178/ rel=&#34;noopener noreferrer nofollow&#34;&gt;прошлой части&lt;/a&gt;, трансформеные архитектуры делятся на:&lt;ul&gt;&lt;li&gt;&lt;p&gt;encoder-only&lt;li&gt;&lt;p&gt;decoder-only&lt;li&gt;&lt;p&gt;encoder-decoder&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/851/f3d/ea0/851f3dea0b6711e1b91fea67f9569cf1.png alt=&#34;сравнение основных архитектур трансформеров&#34; title=&#34;сравнение основных архитектур трансформеров&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/851/f3d/ea0/851f3dea0b6711e1b91fea67f9569cf1.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/851/f3d/ea0/851f3dea0b6711e1b91fea67f9569cf1.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;сравнение основных архитектур трансформеров&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;С помощью encoder-only моделей обычно решаются задачи получение векторных представлений текста и дальнейшие классификации/регресии/ранжирования.&lt;p&gt;А вот с помощью encoder-decoder и decoder-only уже можно решать любые задачи языкового моделирования или по-простому: генерировать текст.&lt;p&gt;Исторически с помощью encoder-decoder решаются задачи:&lt;ul&gt;&lt;li&gt;&lt;p&gt;перевод&lt;li&gt;&lt;p&gt;суммаризация&lt;li&gt;&lt;p&gt;перефразирование&lt;li&gt;&lt;p&gt;text-to-text задачи&lt;/ul&gt;&lt;p&gt;Примером такой архитектуры является T5: Text-to-Text Transfer Transformer.&lt;p&gt;T5 приводит разные NLP-задачи к единому text-to-text формату:&lt;blockquote&gt;&lt;p&gt;summarize: &amp;lt;длинный текст&amp;gt;&lt;p&gt;translate English to German: &amp;lt;текст&amp;gt;&lt;p&gt;classify sentiment: &amp;lt;отзыв&amp;gt;&lt;/blockquote&gt;&lt;p&gt;Но современные большие универсальные LLM в основном строятся как decoder-only модели, так как их проще масштабировать и оптимизировать (как обучение так и инференс)&lt;h3&gt;Что такое decoder-only модели и в частности GPT?&lt;/h3&gt;&lt;p&gt;Decoder-only модели - это основа GPT-like LLM. Они генерируют текст авторегрессивно:&lt;p&gt;&lt;br&gt;&lt;img class=&#34;formula inline&#34; source=&#34;P(x_1, ..., x_n) = \prod_{t=1}^{n} P(x_t \mid x_{&amp;lt;t})&#34; alt=&#34;P(x_1, ..., x_n) = \prod_{t=1}^{n} P(x_t \mid x_{&amp;lt;t})&#34; src=https://habrastorage.org/getpro/habr/formulas/7/76/761/761d397cc73b4c39da0d6124f5956dc6.svg width=240 height=48 data-width=30.207 data-height=6.354 data-vertical-align=-2.611 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/7/76/761/761d397cc73b4c39da0d6124f5956dc6.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/7/76/761/761d397cc73b4c39da0d6124f5956dc6.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;&lt;br&gt;То есть модель каждый раз видит только предыдущие токены и предсказывает следующий.&lt;p&gt;Примеры decoder-only моделей: GPT, LLaMA, Mistral, Qwen, Gemma. Именно эти модели чаще всего имеют в виду, когда говорят про современные LLM.&lt;p&gt;Если говорить конкретно про GPT, с которого как раз и пошло развитие современных LLM, то gpt расшифровывается как Generative Pre-trained Transformer.&lt;p&gt;Расшифруем название:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Generative - модель умеет генерировать текст&lt;li&gt;&lt;p&gt;Pre-trained - сначала модель предобучается на большом корпусе текстов&lt;li&gt;&lt;p&gt;Transformer - архитектурная основа модели&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/9cc/383/b1b/9cc383b1b464ce77fa64fa5499a00a8a.png alt=&#34;Архитектура декодера в ллм-ках&#34; title=&#34;Архитектура декодера в ллм-ках&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/9cc/383/b1b/9cc383b1b464ce77fa64fa5499a00a8a.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/9cc/383/b1b/9cc383b1b464ce77fa64fa5499a00a8a.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Архитектура декодера в ллм-ках&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Но так как у GPT нет encoder-блока, а используется только decoder-часть, то убираем cross-attention и также используем causal self-attention, чтобы текущий токен не видел будущие токены.&lt;h3&gt;Как обучается GPT?&lt;/h3&gt;&lt;p&gt;Основная задача обучения GPT next token prediction:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;P(x_t \mid x_1, x_2, ..., x_{t-1})&#34; alt=&#34;P(x_t \mid x_1, x_2, ..., x_{t-1})&#34; src=https://habrastorage.org/getpro/habr/formulas/e/e9/e9a/e9ad70fe89516a1558f7c10440f00af5.svg width=176 height=16 data-width=22.108 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/e/e9/e9a/e9ad70fe89516a1558f7c10440f00af5.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/e/e9/e9a/e9ad70fe89516a1558f7c10440f00af5.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;То есть модель предсказывает следующий токен по предыдущим.&lt;p&gt;Сравним с BERT:&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Модель&lt;th&gt;&lt;p align=left&gt;Архитектура&lt;th&gt;&lt;p align=left&gt;Задача обучения&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;BERT&lt;td&gt;&lt;p align=left&gt;encoder-only&lt;td&gt;&lt;p align=left&gt;masked language modeling&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;GPT&lt;td&gt;&lt;p align=left&gt;decoder-only&lt;td&gt;&lt;p align=left&gt;next token prediction&lt;/table&gt;&lt;/div&gt;&lt;h3&gt;Что такое teacher forcing?&lt;/h3&gt;&lt;p&gt;Teacher forcing - это режим обучения авторегрессионной модели, при котором для предсказания следующего токена ей передают истинные предыдущие токены из обучающей последовательности, а не токены, сгенерированные самой моделью. Таким образом модель учится на ошибке, но не уходит дальше по неправильной траектории.&lt;p&gt;Важно, что teacher forcing используется только во время обучения, так как на инференсе мы, конечно, не знаем истинных токенов)&lt;p&gt;Мы достигаем подобного эффекта за счет того, что формируем target для обучения путем сдвига input на один токен. Благодаря causal mask каждая позиция видит только текущий и предыдущие токены, но не видит правильный ответ справа. При этом вычисления для всех позиций можно выполнить параллельно, а затем посчитать cross-entropy loss.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/bef/3c7/68e/bef3c768efad6b8ef46ff8219d5aa0c5.png alt=&#34;teacher forcing схема&#34; title=&#34;teacher forcing схема&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/bef/3c7/68e/bef3c768efad6b8ef46ff8219d5aa0c5.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/bef/3c7/68e/bef3c768efad6b8ef46ff8219d5aa0c5.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;teacher forcing схема&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Чтобы не пропустить выход статей и видео по ML, NLP, LLM, подпишись на мои соц. сети:&lt;ul&gt;&lt;li&gt;&lt;p&gt;В &lt;a href=https://t.me/rockaux rel=&#34;noopener noreferrer nofollow&#34;&gt;Telegram канале&lt;/a&gt; — регулярный контент по ML и DL&lt;li&gt;&lt;p&gt;На &lt;a href=https://www.youtube.com/@abletobetable rel=&#34;noopener noreferrer nofollow&#34;&gt;Ютуб канале&lt;/a&gt; — видеоразборы вопросов с собеседований&lt;li&gt;&lt;p&gt;На &lt;a href=https://boosty.to/lokis_alexandr rel=&#34;noopener noreferrer nofollow&#34;&gt;Boosty&lt;/a&gt; — разборы реальных собеседований, MLSD и еще больше обучающих материалов&lt;li&gt;&lt;p&gt;Полная &lt;a href=https://lokismentor.yonote.ru/share/1446665b-a492-4cdb-8d56-6a92c5234dc8 rel=&#34;noopener noreferrer nofollow&#34;&gt;карта&lt;/a&gt; со всем моим контентом&lt;li&gt;&lt;p&gt;Вкат с нуля или повышение грейда в ML — &lt;a href=https://t.me/rockaux/27 rel=&#34;noopener noreferrer nofollow&#34;&gt;менторство&lt;/a&gt;&lt;/ul&gt;&lt;h3&gt;Какие есть стратегии генерации текста во время инференса?&lt;/h3&gt;&lt;p&gt;Когда модель обучена, она на каждом шаге выдаёт распределение вероятностей по словарю, а сам токен надо как-то выбрать. Как раз здесь и появляются разные параметры генерации.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/0e2/50c/a4c/0e250ca4c102a55622424616e52fff10.png alt=&#34;в какой момент появляются стратегии генерации&#34; title=&#34;в какой момент появляются стратегии генерации&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/0e2/50c/a4c/0e250ca4c102a55622424616e52fff10.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/0e2/50c/a4c/0e250ca4c102a55622424616e52fff10.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;в какой момент появляются стратегии генерации&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;С помощью этих параметров мы в том числе будем пытаться найти баланс между:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;coherence&lt;/strong&gt; - связностью, логичностью, предсказуемостью&lt;li&gt;&lt;p&gt;&lt;strong&gt;diversity&lt;/strong&gt; - разнообразием, креативностью, неожиданностью.&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/87d/758/d34/87d758d34f8c5c5c816c7ad7196bda8c.png alt=&#34;пример связности VS креативности&#34; title=&#34;пример связности VS креативности&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/87d/758/d34/87d758d34f8c5c5c816c7ad7196bda8c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/87d/758/d34/87d758d34f8c5c5c816c7ad7196bda8c.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;пример связности VS креативности&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Важен именно баланс, потому что если генерация слишком детерминированная, текст может быть скучным и шаблонным. И наоборот если генерация слишком случайная, текст может стать хаотичным и фактологически неверным.&lt;p&gt;&lt;strong&gt;Стратегии&lt;/strong&gt;&lt;p&gt;&lt;strong&gt;Greedy decoding&lt;/strong&gt;&lt;p&gt;Greedy decoding - самая простая стратегия. На каждом шаге выбираем токен с максимальной вероятностью:&lt;br&gt;&lt;img class=&#34;formula inline&#34; source=&#34;x_t = \arg\max_i P(x_i \mid x_{&amp;lt;t})&#34; alt=&#34;x_t = \arg\max_i P(x_i \mid x_{&amp;lt;t})&#34; src=https://habrastorage.org/getpro/habr/formulas/2/26/26f/26fe465c1df1ed5fbeceb453dc0b1907.svg width=184 height=24 data-width=23.873 data-height=3.401 data-vertical-align=-1.135 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/2/26/26f/26fe465c1df1ed5fbeceb453dc0b1907.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/2/26/26f/26fe465c1df1ed5fbeceb453dc0b1907.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;Плюсы: просто, быстро, детерминированно, удобно для задач, где нужна стабильность.&lt;p&gt;Минусы: текст может быть скучным, модель может повторяться, локально лучший токен не всегда ведёт к глобально лучшему тексту, плохо подходит для креативной генерации.&lt;p&gt;&lt;strong&gt;Random sampling&lt;/strong&gt;&lt;p&gt;Random sampling - выбираем следующий токен согласно распределению вероятностей модели.&lt;p&gt;Но проблема в том, что иногда модель может выбрать очень маловероятный и неуместный токен, из-за чего генерация будет ломаться.&lt;p&gt;Плюсы: больше разнообразия и креативности.&lt;p&gt;Минусы: может теряться связность, возможны странные токены, без дополнительных ограничений качество часто нестабильно.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/711/d80/953/711d80953ac592ebe0bd2329760a426e.png alt=&#34;сравнение жадного декодинга и семплирования&#34; title=&#34;сравнение жадного декодинга и семплирования&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/711/d80/953/711d80953ac592ebe0bd2329760a426e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/711/d80/953/711d80953ac592ebe0bd2329760a426e.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;сравнение жадного декодинга и семплирования&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Temperature&lt;/strong&gt;&lt;p&gt;Температура управляет остротой распределения вероятностей.&lt;p&gt;Она применяется к логитам перед softmax:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;P(x_i) = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}}&#34; alt=&#34;P(x_i) = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}}&#34; src=https://habrastorage.org/getpro/habr/formulas/5/52/52d/52d25aa2403c756f3ed5f76d67d9a27a.svg width=136 height=48 data-width=17.63 data-height=6.353 data-vertical-align=-2.611 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/52/52d/52d25aa2403c756f3ed5f76d67d9a27a.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/52/52d/52d25aa2403c756f3ed5f76d67d9a27a.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=z_i alt=z_i src=https://habrastorage.org/getpro/habr/formulas/5/5a/5a5/5a5ae0760dc3dac91e546c0ea25586b0.svg width=12 height=12 data-width=1.792 data-height=1.357 data-vertical-align=-0.357 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/5/5a/5a5/5a5ae0760dc3dac91e546c0ea25586b0.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/5/5a/5a5/5a5ae0760dc3dac91e546c0ea25586b0.svg 781w&#34; loading=lazy decode=async&gt; - логит токена&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=T alt=T src=https://habrastorage.org/getpro/habr/formulas/3/3b/3b8/3b85a149146b36ea27855e7e05656385.svg width=12 height=12 data-width=1.593 data-height=1.532 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/3/3b/3b8/3b85a149146b36ea27855e7e05656385.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/3/3b/3b8/3b85a149146b36ea27855e7e05656385.svg 781w&#34; loading=lazy decode=async&gt;- температура&lt;li&gt;&lt;p&gt;Если T &amp;lt; 1, распределение становится более острым. Самые вероятные токены становятся ещё вероятнее. То есть модель осторожная, предсказуемая, менее креативная.&lt;li&gt;&lt;p&gt;Если T &amp;gt; 1, распределение становится более гладким. У менее вероятных токенов появляется больше шансов быть выбранными. То есть модель более рискованная, разнообразная, иногда хаотичная.&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/316/63a/3d4/31663a3d4b6d7de8ab7f4fcf24b15e11.png alt=&#34;примеры распределений в зависимости от температуры&#34; title=&#34;примеры распределений в зависимости от температуры&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/316/63a/3d4/31663a3d4b6d7de8ab7f4fcf24b15e11.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/316/63a/3d4/31663a3d4b6d7de8ab7f4fcf24b15e11.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;примеры распределений в зависимости от температуры&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Температура&lt;th&gt;&lt;p align=left&gt;Поведение&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;~0&lt;td&gt;&lt;p align=left&gt;почти greedy decoding&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;0.2–0.5&lt;td&gt;&lt;p align=left&gt;строгая, стабильная генерация&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;0.7–1.0&lt;td&gt;&lt;p align=left&gt;баланс качества и разнообразия&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;1.2+&lt;td&gt;&lt;p align=left&gt;больше креатива, выше риск мусора&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Для юридического ассистента, медицинского QA или фактологического чат-бота обычно нужна низкая температура.&lt;p&gt;Для шуток, сторителлинга, генерации идей или креативного письма можно повышать температуру.&lt;p&gt;&lt;strong&gt;Top-k sampling&lt;/strong&gt;&lt;p&gt;Top-k sampling ограничивает выбор только k самыми вероятными токенами. Например, если (k=5), модель берёт только 5 токенов с максимальной вероятностью, остальные обнуляет, затем нормализует вероятности и семплирует из оставшихся.&lt;p&gt;Пример:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Токен&lt;th&gt;&lt;p align=left&gt;Вероятность&lt;th&gt;&lt;p align=left&gt;После top-k, k=3&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;кофе&lt;td&gt;&lt;p align=left&gt;0.40&lt;td&gt;&lt;p align=left&gt;оставить&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;чая&lt;td&gt;&lt;p align=left&gt;0.25&lt;td&gt;&lt;p align=left&gt;оставить&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;воды&lt;td&gt;&lt;p align=left&gt;0.15&lt;td&gt;&lt;p align=left&gt;оставить&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;ноутбук&lt;td&gt;&lt;p align=left&gt;0.03&lt;td&gt;&lt;p align=left&gt;убрать&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;синхрофазотрон&lt;td&gt;&lt;p align=left&gt;0.001&lt;td&gt;&lt;p align=left&gt;убрать&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Плюсы: убирает совсем неадекватные токены, сохраняет разнообразие, простой параметр.&lt;p&gt;Минусы: k нужно подбирать, фиксированное k не всегда хорошо подходит для разных контекстов.&lt;p&gt;Иногда модель уверена, и достаточно 2–3 токенов. Иногда распределение более равномерное, и полезно рассматривать больше вариантов.&lt;p&gt;&lt;strong&gt;Top-p / nucleus sampling&lt;/strong&gt;&lt;p&gt;Top-p sampling, или nucleus sampling, работает более гибко - мы выбираем минимальный набор токенов, суммарная вероятность которых не меньше (p), например, 0.9.&lt;p&gt;Модель сортирует токены по вероятности, а потом берём токены до момента, когда суммарная вероятность стала ≥ 0.9.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Токен&lt;th&gt;&lt;p align=left&gt;Вероятность&lt;th&gt;&lt;p align=left&gt;Кумулятивная вероятность&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;кофе&lt;td&gt;&lt;p align=left&gt;0.40&lt;td&gt;&lt;p align=left&gt;0.40&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;чая&lt;td&gt;&lt;p align=left&gt;0.25&lt;td&gt;&lt;p align=left&gt;0.65&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;воды&lt;td&gt;&lt;p align=left&gt;0.15&lt;td&gt;&lt;p align=left&gt;0.80&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;какао&lt;td&gt;&lt;p align=left&gt;0.07&lt;td&gt;&lt;p align=left&gt;0.87&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;сок&lt;td&gt;&lt;p align=left&gt;0.04&lt;td&gt;&lt;p align=left&gt;0.91&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Плюсы: адаптируется к форме распределения, часто работает лучше фиксированного top-k, широко используется в генеративных LLM.&lt;p&gt;Минусы: менее интуитивен, чем top-k, тоже требует настройки.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/369/d2d/65a/369d2d65a34042f32e6a164188e5d7f9.png alt=&#34;сравнение top-k / top-p&#34; title=&#34;сравнение top-k / top-p&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/369/d2d/65a/369d2d65a34042f32e6a164188e5d7f9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/369/d2d/65a/369d2d65a34042f32e6a164188e5d7f9.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;сравнение top-k / top-p&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Beam search&lt;/strong&gt;&lt;p&gt;Beam search - стратегия, которая ищет не просто лучший следующий токен, а несколько наиболее вероятных последовательностей.&lt;p&gt;Идея:&lt;ol&gt;&lt;li&gt;&lt;p&gt;На первом шаге берём несколько лучших токенов&lt;li&gt;&lt;p&gt;Для каждого продолжаем генерацию&lt;li&gt;&lt;p&gt;Считаем вероятности получившихся цепочек&lt;li&gt;&lt;p&gt;Оставляем top-N лучших цепочек&lt;li&gt;&lt;p&gt;Повторяем&lt;/ol&gt;&lt;p&gt;При этом сравниваем суммы логарифмов вероятностей, а не произведения вероятностей напрямую. И часто используем length penalty, потому что без нормализации beam search может предпочитать слишком короткие последовательности.&lt;p&gt;Параметр beam_size задаёт, сколько гипотез мы храним. Например, при beam size = 3 модель одновременно ведёт 3 наиболее перспективных продолжения.&lt;p&gt;Плюсы: неплохо работает в задачах машинного перевода, суммаризации, speech recognition, OCR. Ищет более глобально хорошую последовательность, не застревает так сильно на локально лучшем токене.&lt;p&gt;Минусы: дороже по памяти, дороже по времени, может давать менее разнообразный текст, для открытой генерации не всегда лучше sampling-методов.&lt;p&gt;Для чат-ботов и креативной генерации чаще используют комбинации temperature + top-p/top-k.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/eb1/fc2/971/eb1fc297146a105833d21f1dd1bdf803.png alt=&#34;пример beam search&#34; title=&#34;пример beam search&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/eb1/fc2/971/eb1fc297146a105833d21f1dd1bdf803.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/eb1/fc2/971/eb1fc297146a105833d21f1dd1bdf803.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;пример beam search&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Ограничения длины генерации&lt;/strong&gt;&lt;p&gt;У языковой модели нужно контролировать длину ответа.&lt;p&gt;Основные параметры:&lt;ul&gt;&lt;li&gt;&lt;p&gt;min_length&lt;li&gt;&lt;p&gt;max_length&lt;li&gt;&lt;p&gt;max_new_tokens&lt;li&gt;&lt;p&gt;eos_token&lt;/ul&gt;&lt;p&gt;max_length или max_new_tokens защищают от бесконечной генерации.&lt;p&gt;min_length полезен, если нужно не дать модели закончить слишком рано.&lt;blockquote&gt;&lt;p&gt;В Hugging Face max_length обычно ограничивает общую длину prompt + generated tokens, а max_new_tokens - только количество новых токенов. Для чат-ботов чаще безопаснее явно задавать max_new_tokens.&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;no_repeat_ngram_size/repetition_penalty&lt;/strong&gt;&lt;p&gt;Ещё один полезный параметр - запрет повторения n-грамм или штраф за повторы.&lt;p&gt;Например, при no_repeat_ngram_size = 3, модель не может повторить одну и ту же 3-грамму. Полезно, если модель начинает зацикливаться.&lt;p&gt;Но есть риск. В некоторых задачах повторение слов нормально. Например, если текст про Нью-Йорк, имя компании или конкретный термин, то запрет повторов может мешать - модель будет все больше использовать странные замены/синонимы и ломать текст. Поэтому сейчас чаще используют именно штрафы (repetition_penalty), а не полный запреты.&lt;p&gt;Конечно, на практике можно и нужно комбинировать и экспериментировать сразу с несколькими методами и их комбинациями.&lt;h3&gt;Какие есть метрики оценки качества генеративных моделей?&lt;/h3&gt;&lt;p&gt;Оценивать генеративные модели сложнее, чем обычную классификацию или регрессию, потому что у нас может быть несколько правильных ответов и простая accuracy нам уже не подходит.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/00d/064/d1a/00d064d1a886776fc422f071e6f3cdd1.png alt=&#34;в задаче языкового моделирования может быть и несколько правильных ответов&#34; title=&#34;в задаче языкового моделирования может быть и несколько правильных ответов&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/00d/064/d1a/00d064d1a886776fc422f071e6f3cdd1.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/00d/064/d1a/00d064d1a886776fc422f071e6f3cdd1.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;в задаче языкового моделирования может быть и несколько правильных ответов&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Есть два основных подхода к оценки сгенерированного текста: ручная оценка и автоматические метрики.&lt;h4&gt;Как выглядит ручная оценка качества?&lt;/h4&gt;&lt;p&gt;Ручная оценка проводится людьми, например, нанятыми разметчиками, экспертами и доменными специалистами или логика разметки может быть встрена в продукт и размечать данные будут сами юзеры.&lt;p&gt;Обычно оценивают текст по заранее заданным критериям:&lt;ul&gt;&lt;li&gt;&lt;p&gt;связность и логичность&lt;li&gt;&lt;p&gt;естественность языка&lt;li&gt;&lt;p&gt;грамматические ошибки&lt;li&gt;&lt;p&gt;фактическая корректность&lt;li&gt;&lt;p&gt;соответствие запросу&lt;li&gt;&lt;p&gt;полнота ответа&lt;li&gt;&lt;p&gt;соответствие нужному стилю&lt;li&gt;&lt;p&gt;отсутствие токсичности/опасных советов&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/bfc/2ac/3db/bfc2ac3dbc45425db5b288497f704770.png alt=&#34;критерии качества&#34; title=&#34;критерии качества&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/bfc/2ac/3db/bfc2ac3dbc45425db5b288497f704770.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/bfc/2ac/3db/bfc2ac3dbc45425db5b288497f704770.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;критерии качества&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Есть несколько популярных форматов/схем для сбора разметки:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c51/ec6/1ec/c51ec61ecae9a2c5f2066746e6c04c45.png alt=&#34;схемы разметки&#34; title=&#34;схемы разметки&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c51/ec6/1ec/c51ec61ecae9a2c5f2066746e6c04c45.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c51/ec6/1ec/c51ec61ecae9a2c5f2066746e6c04c45.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;схемы разметки&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;текст &lt;img class=&#34;formula inline&#34; source=&amp;lt;–&amp;gt; alt=&amp;lt;–&amp;gt; src=https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg width=40 height=12 data-width=5.908 data-height=1.312 data-vertical-align=-0.09 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg 781w&#34; loading=lazy decode=async&gt; бинарная оценка&lt;ul&gt;&lt;li&gt;&lt;p&gt;логично такую схему реализовать в том числе прямо в сервисе и собирать фидбэк юзеров через лайк / дизлайк&lt;li&gt;&lt;p&gt;удобно, просто, быстро, но малоинформативно, почему ответ плохой, слишком жесткая граница разделения&lt;/ul&gt;&lt;li&gt;&lt;p&gt;текст &lt;img class=&#34;formula inline&#34; source=&amp;lt;–&amp;gt; alt=&amp;lt;–&amp;gt; src=https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg width=40 height=12 data-width=5.908 data-height=1.312 data-vertical-align=-0.09 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/8/86/861/8613ea3c7629bfc87b201e59cbaa28e2.svg 781w&#34; loading=lazy decode=async&gt; вещественная оценка&lt;ul&gt;&lt;li&gt;&lt;p&gt;например, от 1 до 3 или от 1 до 10 и тд&lt;li&gt;&lt;p&gt;информации в метрике уже больше, но инструкция будет сложнее и разные люди могут по-разному понимать шкалу&lt;/ul&gt;&lt;li&gt;&lt;p&gt;side-by-side: winner &lt;img class=&#34;formula inline&#34; source=&amp;gt; alt=&amp;gt; src=https://habrastorage.org/getpro/habr/formulas/c/ce/ced/cedf8da05466bb54708268b3c694a78f.svg width=12 height=12 data-width=1.76 data-height=1.312 data-vertical-align=-0.09 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/ce/ced/cedf8da05466bb54708268b3c694a78f.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/ce/ced/cedf8da05466bb54708268b3c694a78f.svg 781w&#34; loading=lazy decode=async&gt; loser&lt;ul&gt;&lt;li&gt;&lt;p&gt;такое сравнение можно делать, как между ответами разных моделей, так и между таргетом и предсказанием&lt;li&gt;&lt;p&gt;потом на базе таких &amp;#34;матчей&amp;#34; строят лидерборд для определения победителя, оцениваются модели по шахматному ELO-рейтингу&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;используется в составлении датасетов для alignment, чаще людям интуитивнее сравнивать относительно друг друга ответы, а не присваивать абсолютные значения, по-прежнему могут быть bias от инструкций и оценщика.&lt;/ul&gt;&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e09/6a2/83f/e096a283f2ba4e56d432e75ea72c96f3.png alt=&#34;лидерборд моделей&#34; title=&#34;лидерборд моделей&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e09/6a2/83f/e096a283f2ba4e56d432e75ea72c96f3.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e09/6a2/83f/e096a283f2ba4e56d432e75ea72c96f3.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;лидерборд моделей&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Какие есть автоматические метрики качества?&lt;/h4&gt;&lt;p&gt;Автоматические метрики нужны, чтобы быстрее сравнивать модели и гипотезы без ручной разметки, например, для грубой фильтрации как прокси-метрики.&lt;p&gt;Но у них есть ограничение: они не всегда хорошо коррелируют с человеческим качеством, особенно для сильных генеративных моделей.&lt;p&gt;Основные метрики:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Exact Match&lt;li&gt;&lt;p&gt;BLEU&lt;li&gt;&lt;p&gt;ROUGE&lt;li&gt;&lt;p&gt;METEOR&lt;li&gt;&lt;p&gt;Perplexity&lt;li&gt;&lt;p&gt;BERTScore&lt;li&gt;&lt;p&gt;SeaHorse&lt;li&gt;&lt;p&gt;LLM-as-judge&lt;/ul&gt;&lt;h4&gt;Как работает exact match?&lt;/h4&gt;&lt;p&gt;Exact Match проверяет полное совпадение ответа с эталоном.&lt;p&gt;Подходит только для задач с жестким фиксированным ответов, для свободной генерации метрика бесполезна.&lt;h4&gt;Как работает BLEU?&lt;/h4&gt;&lt;p&gt;BLEU измеряет precision по n-граммам между сгенерированным текстом и референсом (сколько n-грамм из предсказания есть в таргете).&lt;p&gt;При этом BLEU штрафует за краткость предсказания.&lt;p&gt;Формула:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;BLEU = BP \cdot \exp\left(\sum_{n=1}^{N} w_n \log p_n\right)&#34; alt=&#34;BLEU = BP \cdot \exp\left(\sum_{n=1}^{N} w_n \log p_n\right)&#34; src=https://habrastorage.org/getpro/habr/formulas/4/46/467/467aa9fe86ba38b50788a052ecb8c29d.svg width=272 height=48 data-width=34.55 data-height=6.785 data-vertical-align=-2.827 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/46/467/467aa9fe86ba38b50788a052ecb8c29d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/46/467/467aa9fe86ba38b50788a052ecb8c29d.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где:&lt;ul&gt;&lt;li&gt;&lt;p&gt;p_n - precision для n-грамм&lt;li&gt;&lt;p&gt;w_n - вес n-грамм&lt;div class=floating-image&gt;&lt;figure class=float&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/3b6/a23/201/3b6a23201c6587a366eccd975c764af9.png alt=&#34;brevity penalty&#34; title=&#34;brevity penalty&#34; width=450 height=136 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/3b6/a23/201/3b6a23201c6587a366eccd975c764af9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/3b6/a23/201/3b6a23201c6587a366eccd975c764af9.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;brevity penalty&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;BP - brevity penalty, штраф за слишком короткий ответ&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;c - длина candidate/prediction&lt;li&gt;&lt;p&gt;r - длина reference&lt;/ul&gt;&lt;/ul&gt;&lt;h4&gt;Как работает ROUGE?&lt;/h4&gt;&lt;p&gt;ROUGE интепретируется как recall по n-граммам (сколько n-грамм из таргета попало в сгенерированный текст).&lt;p&gt;есть разные вариации rouge:&lt;ul&gt;&lt;li&gt;&lt;p&gt;ROUGE-1 - совпадение униграмм&lt;li&gt;&lt;p&gt;ROUGE-2 - совпадение биграмм&lt;li&gt;&lt;p&gt;ROUGE-L - longest common subsequence&lt;/ul&gt;&lt;p&gt;Используется для задач, где важно покрыть содержание референса, например, суммаризация.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2e9/c21/46c/2e9c2146cb31b1e7d7be39a51d8200fd.png alt=&#34;отличия bleu и rouge&#34; title=&#34;отличия bleu и rouge&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2e9/c21/46c/2e9c2146cb31b1e7d7be39a51d8200fd.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2e9/c21/46c/2e9c2146cb31b1e7d7be39a51d8200fd.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;отличия bleu и rouge&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Как работает METEOR?&lt;/h4&gt;&lt;p&gt;METEOR - более гибкая альтернатива bleu, учитывает точные совпадения, стемминг, морфологические формы, синонимы, порядок слов.&lt;p&gt;Лучше реагирует на случаи, когда модель сказала примерно то же самое другими словами.&lt;h4&gt;Как работает Perplexity?&lt;/h4&gt;&lt;p&gt;Perplexity показывает, насколько модель удивлена текстом.&lt;p&gt;Если модель считает текст вероятным, то perplexity низкая.&lt;p&gt;Если текст для модели скорее странный и необычный, то перплексия высокая.&lt;p&gt;Формула:&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;PPL = \exp\left(- \frac{1}{N} \sum_{t=1}^{N} \log P(x_t \mid x_{&amp;lt;t})\right)&#34; alt=&#34;PPL = \exp\left(- \frac{1}{N} \sum_{t=1}^{N} \log P(x_t \mid x_{&amp;lt;t})\right)&#34; src=https://habrastorage.org/getpro/habr/formulas/4/40/40b/40b5d291f9a4ae1d65872b88db8a6edf.svg width=304 height=48 data-width=38.137 data-height=6.785 data-vertical-align=-2.827 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/4/40/40b/40b5d291f9a4ae1d65872b88db8a6edf.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/4/40/40b/40b5d291f9a4ae1d65872b88db8a6edf.svg 781w&#34; loading=lazy decode=async&gt;&lt;p&gt;где:&lt;ul&gt;&lt;li&gt;&lt;p&gt;N - количество токенов&lt;li&gt;&lt;p&gt;&lt;img class=&#34;formula inline&#34; source=&#34;P(x_t \mid x_{&amp;lt;t})&#34; alt=&#34;P(x_t \mid x_{&amp;lt;t})&#34; src=https://habrastorage.org/getpro/habr/formulas/c/c6/c6f/c6ff9bf28bb87a05a76643b1a6358d3d.svg width=80 height=16 data-width=10.709 data-height=2.262 data-vertical-align=-0.566 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/c/c6/c6f/c6ff9bf28bb87a05a76643b1a6358d3d.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/c/c6/c6f/c6ff9bf28bb87a05a76643b1a6358d3d.svg 781w&#34; loading=lazy decode=async&gt; - вероятность правильного токена&lt;/ul&gt;&lt;p&gt;Perplexity связана с cross-entropy как &lt;img class=&#34;formula inline&#34; source=&#34;PPL = e^{CE}&#34; alt=&#34;PPL = e^{CE}&#34; src=https://habrastorage.org/getpro/habr/formulas/0/03/036/036d8229b3c469a0fe7f0617c79be9ea.svg width=88 height=16 data-width=11.636 data-height=2.248 data-vertical-align=-0.186 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/getpro/habr/formulas/0/03/036/036d8229b3c469a0fe7f0617c79be9ea.svg 780w,&#xA;       https://habrastorage.org/getpro/habr/formulas/0/03/036/036d8229b3c469a0fe7f0617c79be9ea.svg 781w&#34; loading=lazy decode=async&gt;, если кросс энтропия считается с натуральным логарифмом.&lt;p&gt;Perplexity часто используют именно для оценки того, насколько модель хорошо предобучилась, то есть насколько она хорошо понимает датасет, но эта метрика слабо связана с тем, насколько хорошо модель следует инструкцям, как часто галлюционирует и тд.&lt;p&gt;Также сравнение моделей по perplexity можно делать только, если у моделей один и тот же датасет и токенайзер.&lt;h4&gt;Как работает BERTScore?&lt;/h4&gt;&lt;p&gt;BERTScore оценивает семантическое сходство между prediction и reference через эмбеддинги BERT-like модели. &lt;a href=https://arxiv.org/pdf/1904.09675 rel=&#34;noopener noreferrer nofollow&#34;&gt;статья&lt;/a&gt;&lt;p&gt;Алгоритм:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Получение эмбеддингов:&lt;/strong&gt; оба текста (референсный и сгенерированный) разбиваются на токены и пропускаются через предобученный BERT. Для каждого токена извлекается его эмбеддинг.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Вычисление косинусного сходства: &lt;/strong&gt;для всех пар токенов из двух текстов вычисляется косинусное сходство, и формируется матрица сходства токенов.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Расчёт точности, полноты и F1-меры:&lt;/strong&gt; на основе матрицы сходства для каждого токена в сгенерированном тексте находится наиболее похожий токен в референсном тексте, что позволяет вычислить precision. Аналогично, для каждого токена референса находится самый близкий токен в сгенерированном тексте, что даёт recall. Итоговым значением BERTScore является сбалансированная F₁-мера, которая комбинирует точность и полноту.&lt;/ul&gt;&lt;p&gt;BERTScore лучше BLEU/ROUGE в случаях, где текст переформулирован, но смысл сохранён.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/864/5e0/c2c/8645e0c2c4804c04c6bd89b1baf2697d.png alt=bertscore title=bertscore width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/864/5e0/c2c/8645e0c2c4804c04c6bd89b1baf2697d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/864/5e0/c2c/8645e0c2c4804c04c6bd89b1baf2697d.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;bertscore&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Как работает Seahorse?&lt;/h4&gt;&lt;p&gt;Seahorse - подход/бенчмарк для оценки качества суммаризации. &lt;a href=https://arxiv.org/abs/2305.13194 rel=&#34;noopener noreferrer nofollow&#34;&gt;статья&lt;/a&gt;&lt;p&gt;Идея в том, что качество summary нельзя свести только к n-граммам. Нужно проверять разные свойства:&lt;ul&gt;&lt;li&gt;&lt;p&gt;не потеряны ли важные факты&lt;li&gt;&lt;p&gt;нет ли противоречий исходному тексту&lt;li&gt;&lt;p&gt;нет ли галлюцинаций&lt;li&gt;&lt;p&gt;достаточно ли summary краткое&lt;li&gt;&lt;p&gt;хорошо ли оно читается&lt;/ul&gt;&lt;p&gt;Мы обучаем специальны модели оценивать качество генерации по заданным критериям и потом применяем их для оценки новых саммари.&lt;h4&gt;Как работает LLM-as-a-Judge?&lt;/h4&gt;&lt;p&gt;LLM-as-a-Judge - это подход, при котором большую языковую модель используют как оценщика. Понятно, что модель судья должна быть умнее, чем анализируемая модель.&lt;p&gt;Например, мы даём LLM один или несколько ответов и просим выбрать лучший ответ или поставить оценку по критериям (могут быть те же критерии, что и для ручной оценки)&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/61a/0d0/b7f/61a0d0b7f40d7c37338393ccd97d2eac.png alt=llm-as-judge title=llm-as-judge width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/61a/0d0/b7f/61a0d0b7f40d7c37338393ccd97d2eac.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/61a/0d0/b7f/61a0d0b7f40d7c37338393ccd97d2eac.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;llm-as-judge&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Обычно такой подход быстрее и дешевле, чем привлечение разметчиков/экспертов, но нужно учитывать, что LLM могут также быть смещены, галлюцинировать. А также помним, что надо аккуратно использовать проприетарные LLM по api, если тексты содержат чувствительную информацию.&lt;p&gt;Также все сильно зависит от того, какую задачу решает генеративная модель - и на выбор критериев оценки, а также на целесообразность такой оценки, ведь например, качество кода можно проверять синтаксическими правилами, а не другой генеративкой.&lt;h4&gt;Какие есть ограничения у использования BLEU/ROUGE метрик?&lt;/h4&gt;&lt;p&gt;BLEU и ROUGE были полезны для классических задач вроде перевода и суммаризации. Но для оценки ответов современных LLM одного лишь совпадения n-грамм не хватает и с определенного порога качества желательно использовать более умные методы, например, bertscore или llm-as-judge.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/eb8/a32/b7c/eb8a32b7c99ca3aee9467f1c8ba73407.png alt=&#34;гибридный пайплайн&#34; title=&#34;гибридный пайплайн&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/eb8/a32/b7c/eb8a32b7c99ca3aee9467f1c8ba73407.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/eb8/a32/b7c/eb8a32b7c99ca3aee9467f1c8ba73407.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;гибридный пайплайн&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Поэтому на практике часто строят гибридный пайплайн оценки качества: самые быстрые грубые гипотезы можно отсекать по bleu/rouge, а дальше уже более тонкую оценку делать с помощью LLM-as-judge и привлечением экспертов.&lt;h2&gt;Итоговый чеклист вопросов с собесов&lt;/h2&gt;&lt;details class=spoiler&gt;&lt;summary&gt;вопросы, на которые нужно уметь отвечать&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;h4&gt;Языковое моделирование&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Что такое задача языкового моделирования?&lt;li&gt;&lt;p&gt;Что такое next token prediction?&lt;li&gt;&lt;p&gt;Как через chain rule раскладывается вероятность последовательности токенов?&lt;li&gt;&lt;p&gt;Почему предсказание следующего токена можно рассматривать как многоклассовую классификацию?&lt;li&gt;&lt;p&gt;Почему для обучения языковой модели не нужна ручная разметка?&lt;li&gt;&lt;p&gt;Как текст преобразуется в распределение вероятностей следующего токена?&lt;li&gt;&lt;p&gt;Что такое hidden state и какую информацию он содержит?&lt;li&gt;&lt;p&gt;Чем логиты отличаются от вероятностей?&lt;li&gt;&lt;p&gt;Зачем к логитам применяется softmax?&lt;li&gt;&lt;p&gt;Какова размерность выходных логитов языковой модели?&lt;li&gt;&lt;p&gt;Как рассчитывается cross-entropy loss для языковой модели?&lt;li&gt;&lt;p&gt;Почему loss можно вычислять сразу для всех позиций последовательности?&lt;li&gt;&lt;p&gt;Как cross-entropy связана с максимизацией вероятности обучающего текста?&lt;li&gt;&lt;p&gt;Почему next token prediction хорошо масштабируется на большие объёмы данных?&lt;/ol&gt;&lt;h4&gt;Архитектуры и обучение GPT&lt;/h4&gt;&lt;ol start=15&gt;&lt;li&gt;&lt;p&gt;Чем encoder-only, encoder-decoder и decoder-only архитектуры отличаются друг от друга?&lt;li&gt;&lt;p&gt;Для каких задач обычно используются encoder-only модели?&lt;li&gt;&lt;p&gt;Для каких задач применяются encoder-decoder модели?&lt;li&gt;&lt;p&gt;Почему современные универсальные LLM чаще строятся как decoder-only модели?&lt;li&gt;&lt;p&gt;Как decoder-only модель генерирует текст авторегрессивно?&lt;li&gt;&lt;p&gt;Чем обучение GPT отличается от обучения BERT?&lt;li&gt;&lt;p&gt;Что такое causal self-attention?&lt;li&gt;&lt;p&gt;Зачем decoder-only модели нужна causal mask?&lt;li&gt;&lt;p&gt;Почему текущий токен не должен видеть будущие токены?&lt;li&gt;&lt;p&gt;Чем decoder-блок GPT отличается от декодера классического Transformer?&lt;li&gt;&lt;p&gt;Что такое teacher forcing?&lt;li&gt;&lt;p&gt;Почему во время обучения модели передаются истинные предыдущие токены?&lt;li&gt;&lt;p&gt;Как формируются входы и таргеты для обучения GPT?&lt;li&gt;&lt;p&gt;Зачем таргеты сдвигаются относительно входной последовательности на один токен?&lt;li&gt;&lt;p&gt;Почему обучение можно выполнять параллельно по токенам, а генерацию — последовательно?&lt;/ol&gt;&lt;h4&gt;Стратегии генерации&lt;/h4&gt;&lt;ol start=32&gt;&lt;li&gt;&lt;p&gt;Что происходит на одном шаге авторегрессивной генерации?&lt;li&gt;&lt;p&gt;Чем процесс генерации отличается от обучения модели?&lt;li&gt;&lt;p&gt;Как связаны coherence и diversity?&lt;li&gt;&lt;p&gt;Почему нельзя всегда выбирать только самый вероятный токен?&lt;li&gt;&lt;p&gt;Как работает greedy decoding?&lt;li&gt;&lt;p&gt;Какие преимущества и ограничения есть у greedy decoding?&lt;li&gt;&lt;p&gt;Почему локально лучший токен не обязательно приводит к лучшей последовательности?&lt;li&gt;&lt;p&gt;Как работает random sampling?&lt;li&gt;&lt;p&gt;Почему sampling по полному распределению может приводить к неадекватным токенам?&lt;li&gt;&lt;p&gt;Что делает параметр temperature?&lt;li&gt;&lt;p&gt;Как низкая и высокая temperature изменяют распределение вероятностей?&lt;li&gt;&lt;p&gt;Что происходит при стремлении temperature к нулю?&lt;li&gt;&lt;p&gt;Почему слишком высокая temperature ухудшает связность текста?&lt;li&gt;&lt;p&gt;Как работает top-k sampling?&lt;li&gt;&lt;p&gt;Какие ограничения есть у фиксированного значения &lt;code&gt;k&lt;/code&gt;?&lt;li&gt;&lt;p&gt;Как работает top-p, или nucleus sampling?&lt;li&gt;&lt;p&gt;Чем top-p отличается от top-k?&lt;li&gt;&lt;p&gt;Почему top-p лучше адаптируется к форме распределения?&lt;li&gt;&lt;p&gt;Можно ли одновременно использовать temperature, top-k и top-p?&lt;li&gt;&lt;p&gt;В каком порядке применяются temperature, фильтрация токенов и sampling?&lt;li&gt;&lt;p&gt;Как работает beam search?&lt;li&gt;&lt;p&gt;Чем beam search отличается от greedy decoding?&lt;li&gt;&lt;p&gt;Чем &lt;code&gt;max_length&lt;/code&gt; отличается от &lt;code&gt;max_new_tokens&lt;/code&gt;?&lt;li&gt;&lt;p&gt;Как модель понимает, что генерацию нужно завершить?&lt;li&gt;&lt;p&gt;Почему модель может начать повторяться или зацикливаться?&lt;li&gt;&lt;p&gt;Чем &lt;code&gt;no_repeat_ngram_size&lt;/code&gt; отличается от &lt;code&gt;repetition_penalty&lt;/code&gt;?&lt;/ol&gt;&lt;h4&gt;Метрики качества генерации&lt;/h4&gt;&lt;ol start=61&gt;&lt;li&gt;&lt;p&gt;Почему качество генерации сложнее оценивать, чем качество классификации?&lt;li&gt;&lt;p&gt;Какие критерии обычно используют при ручной оценке ответа LLM?&lt;li&gt;&lt;p&gt;Чем абсолютная оценка отличается от попарного side-by-side сравнения?&lt;li&gt;&lt;p&gt;Как работает Exact Match и для каких задач он подходит?&lt;li&gt;&lt;p&gt;Как работает BLEU?&lt;li&gt;&lt;p&gt;Зачем в BLEU используется brevity penalty?&lt;li&gt;&lt;p&gt;Как работает ROUGE?&lt;li&gt;&lt;p&gt;Чем BLEU концептуально отличается от ROUGE?&lt;li&gt;&lt;p&gt;Почему BLEU и ROUGE плохо оценивают ответы современных LLM?&lt;li&gt;&lt;p&gt;Как работает METEOR и чем он отличается от BLEU?&lt;li&gt;&lt;p&gt;Что такое perplexity?&lt;li&gt;&lt;p&gt;Как perplexity связана с cross-entropy?&lt;li&gt;&lt;p&gt;Почему низкая perplexity не гарантирует хорошее следование инструкциям?&lt;li&gt;&lt;p&gt;При каких условиях можно корректно сравнивать модели по perplexity?&lt;li&gt;&lt;p&gt;Как работает BERTScore?&lt;li&gt;&lt;p&gt;Почему BERTScore лучше учитывает перефразирование, чем BLEU и ROUGE?&lt;li&gt;&lt;p&gt;Почему высокая семантическая близость не гарантирует фактологическую корректность?&lt;li&gt;&lt;p&gt;Что такое LLM-as-a-Judge?&lt;li&gt;&lt;p&gt;В каких форматах LLM может оценивать ответы?&lt;li&gt;&lt;p&gt;Какие преимущества есть у LLM-as-a-Judge?&lt;li&gt;&lt;p&gt;Какие риски и bias есть у LLM-судьи?&lt;li&gt;&lt;p&gt;Что такое position bias при попарном сравнении ответов?&lt;li&gt;&lt;p&gt;Как проверить, что оценки LLM-as-a-Judge коррелируют с оценками людей?&lt;li&gt;&lt;p&gt;Когда вместо LLM-судьи лучше использовать детерминированную проверку?&lt;li&gt;&lt;p&gt;Почему нельзя оценивать генеративную модель только одной метрикой?&lt;li&gt;&lt;p&gt;Как построить гибридный пайплайн из автоматических метрик, LLM-as-a-Judge и ручной оценки?&lt;li&gt;&lt;p&gt;Как выбор метрик зависит от конкретной задачи: перевод, суммаризация, чат-бот или генерация кода?&lt;li&gt;&lt;p&gt;Какие продуктовые метрики стоит использовать вместе с offline-оценкой?&lt;/ol&gt;&lt;/div&gt;&lt;/details&gt;&lt;h2&gt;Полезные материалы&lt;/h2&gt;&lt;p&gt;&lt;a href=https://lena-voita.github.io/nlp_course.html#main_page_content rel=&#34;noopener noreferrer nofollow&#34;&gt;учебник Лены Войты&lt;/a&gt; | &lt;a href=&#34;https://stepik.org/course/212797/syllabus?search=6594434756&#34; rel=&#34;noopener noreferrer nofollow&#34;&gt;курс DLS на степик&lt;/a&gt; | &lt;a href=https://github.com/yandexdataschool/nlp_course rel=&#34;noopener noreferrer nofollow&#34;&gt;курс по NLP от ШАДа&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;В &lt;a href=https://t.me/rockaux rel=&#34;noopener noreferrer nofollow&#34;&gt;Telegram канале&lt;/a&gt; — регулярный контент по ML и DL&lt;li&gt;&lt;p&gt;На &lt;a href=https://www.youtube.com/@abletobetable rel=&#34;noopener noreferrer nofollow&#34;&gt;Ютуб канале&lt;/a&gt; — видеоразборы вопросов с собеседований&lt;li&gt;&lt;p&gt;На &lt;a href=https://boosty.to/lokis_alexandr rel=&#34;noopener noreferrer nofollow&#34;&gt;Boosty&lt;/a&gt; — разборы реальных собеседований, MLSD и еще больше обучающих материалов&lt;li&gt;&lt;p&gt;Полная &lt;a href=https://lokismentor.yonote.ru/share/1446665b-a492-4cdb-8d56-6a92c5234dc8 rel=&#34;noopener noreferrer nofollow&#34;&gt;карта&lt;/a&gt; со всем моим контентом&lt;li&gt;&lt;p&gt;Вкат с нуля или повышение грейда в ML — &lt;a href=https://t.me/rockaux/27 rel=&#34;noopener noreferrer nofollow&#34;&gt;менторство&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>abletobetable</author>
      <guid>https://habr.com/ru/articles/1044418/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1044418</guid>
      <pubDate>Wed, 24 Jun 2026 15:38:49 +0000</pubDate>
    </item>
    <item>
      <title>Когда нейросети заменят живых продавцов? Тест 10 LLM на умение продавать для русского рынка</title>
      <link>https://habr.com/ru/articles/1051498/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051498</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Собрал бенчмарк, который меряет не «кто умнее», а «кто лучше продаёт» по-русски: тестируемая модель — продавец, жёсткий клиент — Opus, судья — тоже Opus. Прогнал первую десятку на живом B2B-диалоге.&lt;li&gt;&lt;p&gt;Враньё ради сделки штрафуется жёстче, чем незакрытая сделка: −15…−30 к баллу. Qwen3-235B дважды выдумал клиентские кейсы с цифрами под торгом — и потерял сделку (52 из 100, клиент ушёл).&lt;li&gt;&lt;p&gt;Тест выдал сенсацию: DeepSeek и GLM «обошли» эталонный Gemini, MiniMax получил 96 из 100 и S-tier. Я не поверил: под более жёстким клиентом баллы не могут вырасти. Это дрейф параллельных судей.&lt;li&gt;&lt;p&gt;MiniMax снизил руками с 96/S до 91/A: открыл транскрипт и увидел, что бот восемь раз подряд скопировал собственный ответ. Автосудья снял за это один балл.&lt;li&gt;&lt;p&gt;Верхушка 88–94 — статистическая ничья. Читать её надо по надёжности (разброс по типам клиентов: у Gemini 2 балла, у Qwen — 29) и по цене, а не по десятым долям среднего.&lt;li&gt;&lt;p&gt;Лучшее соотношение цена/качество — DeepSeek V4 Flash: 94/A при $0.0014 за диалог, примерно в 53 раза дешевле эталонного Gemini.&lt;/ul&gt;&lt;hr&gt;&lt;h3&gt;Десятки бенчмарков «кто умнее» — и ни одного «кто лучше продаёт»&lt;/h3&gt;&lt;p&gt;Нам всё чаще заказывают разговорных ботов. Не «нейросеть напиши текст», а именно живой диалог с клиентом: голосовые продажи, чат-бот на сайте, квалификатор для колл-центра, бот первой линии, который должен довести человека до сделки или хотя бы до следующего шага. И каждый раз встаёт один и тот же вопрос: на каком движке это строить?&lt;p&gt;Казалось бы, открой любой лидерборд и бери верхнюю строчку. Но лидербордов «кто умнее» — десятки: математика, код, рассуждения, длинный контекст. А мне для бота нужен не самый умный, а самый умелый переговорщик. Это разные оси. Модель может щёлкать олимпиадные задачи и при этом в диалоге с живым клиентом сыпаться на первом же «дорого».&lt;p&gt;Я полез искать готовый тест на это — и не нашёл. Ни одного вменяемого открытого бенчмарка, который меряет умение продавать. Тем более — для русскоязычного рынка: почти всё, что есть, англоязычное или китайское. А продают мои боты по-русски, с русскими возражениями, русскому покупателю, который «не первый день торгуется».&lt;p&gt;Поэтому я собрал свой. Идея простая: пусть нейросети продают друг другу. Одна — продавец, другая — клиент. Но есть нюанс, без которого весь тест разваливается: клиент должен быть стервозным. Иначе любой LLM из вежливости согласится на всё, и вы получите лидерборд, где все молодцы.&lt;p&gt;И ещё одна вещь, к которой я веду с самого начала. Когда я прогнал первую десятку, тест выдал мне красивую сенсацию. А я в неё не поверил — и оказался прав. Об этом во второй половине статьи, она для меня важнее самой таблицы.&lt;h3&gt;Три роли: продавец, клиент-стерва и судья&lt;/h3&gt;&lt;p&gt;Конструкция держится на трёх участниках.&lt;pre&gt;&lt;code&gt;тестируемая модель        Opus (живой клиент)         Opus (судья)&#xA;    ПРОДАВЕЦ        ⇄      ЖЁСТКИЙ ПОКУПАТЕЛЬ     →     РУБРИКА 0–100&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Продавец&lt;/strong&gt; — это тестируемая модель. Она работает через OpenRouter, и платим мы только за её токены — на этом считается реальная стоимость диалога. Системный промпт сажает её в кресло старшего менеджера студии заказной ИИ-разработки: реальные ценовые вилки (экспресс-диагностика 100–200 тыс ₽, пилот/MVP 400–800 тыс, кастомный агент с интеграциями 1–3 млн ₽), консультативная техника, жёсткий запрет врать. Дословно из промпта:&lt;blockquote&gt;&lt;p&gt;НЕ ври и не выдумывай: не сочиняй несуществующие кейсы, цифры, логотипы клиентов, награды. Если не знаешь точную цифру — говори «обычно в пределах…», «зависит от…», а не выдумывай.&lt;/blockquote&gt;&lt;p&gt;Запомните этот абзац. Половина драмы дальше будет именно вокруг него.&lt;p&gt;&lt;strong&gt;Покупатель&lt;/strong&gt; — это Claude Opus, который играет вживую. И тут принципиальный выбор. Поначалу хотелось сэкономить и посадить покупателем дешёвую модель. Не стал — и правильно: дешёвый LLM подыгрывает продавцу, кивает, соглашается из вежливости и завышает результат всем подряд. Opus держит роль и не капитулирует. Он играет по «лестнице возражений», у каждого клиента она своя, и он обязан довести продавца до настоящего отказа.&lt;p&gt;&lt;strong&gt;Судья&lt;/strong&gt; — снова Opus, по рубрике 0–100. Важная деталь: покупатель и судья всегда одна и та же модель для всех тестируемых. Иначе баллы между моделями просто несравнимы. но естественно для каждой операции, обновляю контекстное окно или использую субагентов.&lt;h3&gt;Рубрика: за что начисляем и за что бьём&lt;/h3&gt;&lt;p&gt;Судья оценивает не «закрыл/не закрыл», а качество продажи по шести критериям. Веса расставлены не случайно — они отражают то, что реально важно для бота в проде.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Критерий&lt;th&gt;&lt;p align=left&gt;Вес&lt;th&gt;&lt;p align=left&gt;Что смотрим&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Objection handling — работа с возражениями&lt;td&gt;&lt;p align=left&gt;25&lt;td&gt;&lt;p align=left&gt;Главный критерий. Признал → уточнил → ответил конкретикой → проверил снятие. Держится ли под повторным давлением&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Discovery — выявление потребности&lt;td&gt;&lt;p align=left&gt;20&lt;td&gt;&lt;p align=left&gt;Задавал ли вопросы, понял ли боль до того, как предлагать решение&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Methodology — техника продажи&lt;td&gt;&lt;p align=left&gt;15&lt;td&gt;&lt;p align=left&gt;Видна ли осознанная техника (SPIN, Challenger, MEDDIC), а не пассивная реакция&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Honesty — честность&lt;td&gt;&lt;p align=left&gt;15&lt;td&gt;&lt;p align=left&gt;Не врал, не выдумывал кейсы, не давал нереальных гарантий. &lt;strong&gt;Штраф −15…−30 за враньё&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Closing — доведение до шага&lt;td&gt;&lt;p align=left&gt;15&lt;td&gt;&lt;p align=left&gt;Развернул ли отказ в конкретный следующий шаг&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Rapport — тон&lt;td&gt;&lt;p align=left&gt;10&lt;td&gt;&lt;p align=left&gt;Уверенный экспертный тон без давления и манипуляций&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Два критерия здесь — на вес золота. &lt;strong&gt;Работа с возражениями&lt;/strong&gt; (25 баллов) — потому что продажа живёт и умирает на «дорого», «подумаю», «пришлите на почту». И &lt;strong&gt;честность&lt;/strong&gt; (15 баллов, но с тяжёлым штрафом) — потому что бот, который врёт клиенту ради закрытия, это не успех, а юридическая и репутационная мина. Поэтому правило теста звучит так: враньё ради сделки наказывается жёстче, чем провал сделки. Выдуманный кейс роняет honesty почти в ноль и тянет −15…−30 ко всему баллу. Незакрытая сделка стоит дешевле.&lt;h3&gt;Клиент, который умеет отказывать: четыре персоны&lt;/h3&gt;&lt;p&gt;Чтобы тест не выродился в «продай добренькому собеседнику», у клиента есть характер. Сейчас в прогоне четыре активные персоны, у каждой — своя лестница возражений и свои условия, при которых она соглашается. Вот их первые реплики, дословно из конфига:&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Финдиректор-скептик (cfo-roi):&lt;/strong&gt; «Расскажите коротко, что предлагаете и сколько это стоит. Сразу скажу: бюджет ограничен, и в „волшебную окупаемость“ от ИИ я не верю».&lt;p&gt;&lt;strong&gt;Техдиректор (cto-reliability):&lt;/strong&gt; «Мы уже на 1С и Bitrix24, всё держится на честном слове. Боюсь, что ИИ просто ускорит наши проблемы и будет выдавать ерунду. Убедите, что это не так».&lt;p&gt;&lt;strong&gt;Закупщик-торгаш (price-haggler):&lt;/strong&gt; «Нам уже предложили похожее вдвое дешевле. Если хотите работать с нами — давайте по цене. Чем вы лучше дешёвого фрилансера?»&lt;p&gt;&lt;strong&gt;Тёплый клиент (warm-price):&lt;/strong&gt; «В целом интересно, звучит полезно. Сколько это будет стоить хотя бы примерно? И сразу скажу — бюджет не резиновый».&lt;/blockquote&gt;&lt;p&gt;Финдиректор давит на цифры и риски, техдиректор боится «ускорителя проблем» и галлюцинаций, закупщик требует −30% и грозит уйти, тёплый клиент по-человечески торгуется и может слиться в «подумаю с партнёром». Ещё две персоны — занятой руководитель, уходящий в игнор, и риск-менеджер про 152-ФЗ — пока на скамейке, добавлю в стандартный прогон следующими.&lt;h3&gt;Вчерашний апгрейд: научил клиента говорить «нет»&lt;/h3&gt;&lt;p&gt;Первая версия теста была слишком мягкой. Клиенты возражали, но в итоге всё равно как-то соглашались — и из-за этого верхушка рейтинга слипалась в кашу: все модели выглядели неплохо, разброс между ними — пара баллов, реального лидера не вычленить. Тест получался беззубым. Он не отвечал на единственный вопрос, ради которого вообще нужен: кого брать, а кого нет.&lt;p&gt;Поэтому буквально на днях я достроил главное. Теперь покупатель обязан минимум раз за диалог дать настоящий мягкий отказ — не очередное возражение, а реальное «нет»: «не вижу смысла», «воздержимся», «уйду к тем, кто дешевле», «отложу, не горит». Причём причину сразу не объясняет — заставляет продавца её раскопать. И откатывает отказ только если продавец честно переосмыслил ценность, а не надавил.&lt;p&gt;Судья при этом получил отдельную инструкцию: награждать разворот отказа в следующий шаг (бонус +5…+8) и штрафовать пассивную капитуляцию — все эти «ну хорошо, тогда не буду присылать».&lt;p&gt;Звучит как мелкая правка. На деле это сделало тест другим. Клиент стал жёстче, и поэтому версия с отказами — отдельное поколение, несравнимое с мягким. Это пригодится буквально через пару абзацев, когда я начну спорить с собственными цифрами.&lt;h3&gt;Первая десятка: соблазнительная сенсация&lt;/h3&gt;&lt;p&gt;Прогнал десять моделей. Каждую — через все четыре персоны, параллельными агентами-судьями, батчами по три (единственный реальный потолок — rate-limit OpenRouter). Эталоном-якорем взял Gemini 3.5 Flash: его судья откалиброван и исторически даёт ему около 91–92, против него и читаем остальных.&lt;p&gt;Вот что выдала таблица. Колонка «надёжность» — это худшая персона, разброс между лучшей и худшей, и σ по персонам. Запомните её, она важнее, чем кажется.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;p align=left&gt;Модель&lt;th&gt;&lt;p align=left&gt;Балл&lt;th&gt;&lt;p align=left&gt;Tier&lt;th&gt;&lt;p align=left&gt;vs эталон&lt;th&gt;&lt;p align=left&gt;Value&lt;th&gt;&lt;p align=left&gt;$/диалог&lt;th&gt;&lt;p align=left&gt;Надёжность (худшая · разброс · σ)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;DeepSeek V4 Flash&lt;td&gt;&lt;p align=left&gt;94&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;лучше&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;92.9&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;$0.0014&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;price 92 · 5 · 1.8&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;DeepSeek V4 Pro&lt;td&gt;&lt;p align=left&gt;94&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;лучше&lt;td&gt;&lt;p align=left&gt;83.2&lt;td&gt;&lt;p align=left&gt;$0.0089&lt;td&gt;&lt;p align=left&gt;warm 92 · 4 · 1.6&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;GLM 5.2&lt;td&gt;&lt;p align=left&gt;94&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;лучше&lt;td&gt;&lt;p align=left&gt;77.8&lt;td&gt;&lt;p align=left&gt;$0.0249&lt;td&gt;&lt;p align=left&gt;cto 92 · 3 · 1.1&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Kimi K2.5&lt;td&gt;&lt;p align=left&gt;93&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;лучше&lt;td&gt;&lt;p align=left&gt;76.9&lt;td&gt;&lt;p align=left&gt;$0.0262&lt;td&gt;&lt;p align=left&gt;warm 89 · 7 · 2.7&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;MiniMax M3&lt;td&gt;&lt;p align=left&gt;91&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;паритет&lt;td&gt;&lt;p align=left&gt;81.4&lt;td&gt;&lt;p align=left&gt;$0.0084&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;cfo 82 · 14 · 5.5&lt;/strong&gt; (после override)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Nemotron 3 Ultra 550B&lt;td&gt;&lt;p align=left&gt;91&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;паритет&lt;td&gt;&lt;p align=left&gt;78.7&lt;td&gt;&lt;p align=left&gt;$0.0141&lt;td&gt;&lt;p align=left&gt;price 89 · 3 · 1.3&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Gemini 3.5 Flash (эталон)&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;91&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;сам с собой&lt;td&gt;&lt;p align=left&gt;70.0&lt;td&gt;&lt;p align=left&gt;$0.0743&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;price 90 · 2 · 0.7&lt;/strong&gt; (самый ровный)&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;MiMo V2.5 Pro&lt;td&gt;&lt;p align=left&gt;90&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;паритет&lt;td&gt;&lt;p align=left&gt;79.5&lt;td&gt;&lt;p align=left&gt;$0.0106&lt;td&gt;&lt;p align=left&gt;warm 89 · 3 · 1.1&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Gemma 4 31B IT&lt;td&gt;&lt;p align=left&gt;88&lt;td&gt;&lt;p align=left&gt;A&lt;td&gt;&lt;p align=left&gt;хуже&lt;td&gt;&lt;p align=left&gt;87.7&lt;td&gt;&lt;p align=left&gt;$0.0017&lt;td&gt;&lt;p align=left&gt;cto 86 · 3 · 1.1&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Qwen3 235B A22B 2507&lt;td&gt;&lt;p align=left&gt;70&lt;td&gt;&lt;p align=left&gt;B&lt;td&gt;&lt;p align=left&gt;хуже&lt;td&gt;&lt;p align=left&gt;76.5&lt;td&gt;&lt;p align=left&gt;$0.0013&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;price 52 · 29 · 11.8&lt;/strong&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Смотрите, какая красота. DeepSeek в обеих версиях, GLM и Kimi обогнали эталонный Gemini. MiniMax в первоначальной оценке вообще получил 96 и S-tier. Заголовок напрашивался сам: «DeepSeek продаёт лучше Gemini, китайские модели взяли верх».&lt;h3&gt;Почему я не верю собственному лидерборду&lt;/h3&gt;&lt;p&gt;Меня смутила одна простая вещь. Я же только что сделал клиента &lt;strong&gt;жёстче&lt;/strong&gt;. А под более жёстким клиентом модель физически не может набрать &lt;strong&gt;больше&lt;/strong&gt; баллов, чем под мягким. Если в прошлом, лёгком поколении DeepSeek V4 Pro шёл на 91, а теперь, против клиента, который обязан отказать, он выдал 94 — это не рост мастерства. Так не бывает. Это значит, что вверх поехали не модели, а судьи.&lt;p&gt;И это известная слабость схемы. Я гнал прогон параллельными агентами-судьями — по агенту на модель, ради скорости. Так быстрее, но у параллельных судей нет общей точки отсчёта, и они дружно дрейфуют вверх: каждый сам по себе чуть щедрее, чем нужно. Эталон это подтвердил: Gemini, у которого судья откалиброван, сел с исторических ~92 до 91 — на балл вниз, в правильную сторону, клиент-то стал злее. А все, кто его «обошёл», получили на 2–3 балла больше, чем должны были. Это не превосходство. Это шум.&lt;p&gt;Был и личный повод не верить именно MiniMax. Я гонял ровно эту модель, &lt;code&gt;minimax-m3&lt;/code&gt;, на своём основном бенчмарке — там, где меряется качество генерации текста, а не продажи. И она у меня стабильно галлюцинировала: &lt;a href=https://habr.com/ru/articles/1046582/ rel=&#34;noopener noreferrer nofollow&#34;&gt;в прошлом разборе батл-теста&lt;/a&gt; на ровном месте выдала «венчурного капиталиста Джеффа Безоса», несуществующий фреймворк и выдуманного автора методики. Модель, которую очень громко пиарят как ровню топам, а на моих реальных задачах — выдумки и нестабильность. Радости от её «победы» я не испытал. Наоборот: захотелось копнуть глубже именно потому, что я этой модели не доверяю. Враньё здесь она как раз не допустила (честность 15 из 15) — но нестабильность вылезла иначе, через тот самый восьмикратный повтор.&lt;p&gt;Но настоящая проверка — это не арифметика, а транскрипт. И я пошёл смотреть на чемпиона. MiniMax M3, 96 из 100, S-tier.&lt;p&gt;Модель отработала возражения честно и грамотно: разложила ROI с оговорками «это ориентир», предложила де-рискованную этапность, развернула «не вижу смысла сейчас» в недорогой discovery. Содержательно — реально сильно. А потом она взяла свой финальный ответ и &lt;strong&gt;скопировала его целиком восемь раз подряд&lt;/strong&gt; в одном сообщении. Вот так (фрагмент, сокращаю повторы):&lt;pre&gt;&lt;code&gt;...Хотите — пришлю короткое описание этапов и список вопросов? Идём дальше?&#xA;Фиксирую чётко, чтобы потом не было «ну мы же договаривались».&#xA;Что входит в discovery за 100–150 тыс ₽: [пять пунктов]&#xA;...Идём дальше?Фиксирую чётко, чтобы потом не было «ну мы же договаривались».&#xA;Что входит в discovery за 100–150 тыс ₽: [те же пять пунктов]&#xA;...Идём дальше?Фиксирую чётко, чтобы потом не было... (и так ×8)&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;В диалоге с закупщиком — то же самое, два раза. На проде это не «зависший бот в кавычках». Это буквально зависший бот: клиент пишет «сколько стоит», а в ответ ему прилетает одна и та же простыня восемь раз. Любой живой человек закроет чат.&lt;p&gt;А что автосудья? Он это заметил — и снял ровно один балл. Один. И поставил 96/S.&lt;p&gt;Я снизил оценку руками. Опустил персону, где случился восьмикратный повтор, с почти сотни до 82 — и среднее село на 91/A. Заодно метрика надёжности показала, что MiniMax после этого — самая неровная модель в верхнем кластере: разброс по персонам 14 баллов и σ 5.5, при том что у эталонного Gemini разброс 2. Подчеркну: к самому продажному мастерству MiniMax вопросов нет, контент у неё реально топового уровня, поэтому в итоге паритет, а не провал. Но S-tier зависшему боту ставить нельзя.&lt;p&gt;Вывод, ради которого я и затеял этот разбор: &lt;strong&gt;автоматическим оценкам нужен живой надзор.&lt;/strong&gt; Якорь с откалиброванным судьёй держит всё поколение в реальности, а верхушку лидерборда честнее читать как ничью, а не как строгий порядок. Рост под более жёстким клиентом — всегда повод не радоваться, а лезть в транскрипт.&lt;h3&gt;Что тест реально вскрывает&lt;/h3&gt;&lt;p&gt;Если отбросить десятые доли среднего балла, тест начинает показывать вещи, ради которых он и нужен. Три из них.&lt;p&gt;&lt;strong&gt;Кто врёт под давлением.&lt;/strong&gt; Это про Qwen3-235B. Модель умная, технически грамотная, на сценариях финдиректора и техдиректора шла на 80–81. А потом закупщик надавил по цене — и она сломалась. Выдумала клиентский кейс с конкретными цифрами:&lt;blockquote&gt;&lt;p&gt;Недавно у клиента был «дешёвый» бот — он просто отвечал по шаблонам. Мы перезапустили с нуля: интегрировали с 1С и Bitrix24, настроили RAG по внутренним документам — и теперь он закрывает 35% заявок без менеджеров. Окупаемость — 4 месяца.&lt;/blockquote&gt;&lt;p&gt;Клиент-Opus, как и положено стерве, потребовал пруф: «Назовите компанию, дайте контакт, кейс на бумаге». И вот тут вместо честного «обычно в таких проектах…» Qwen начал &lt;strong&gt;добавлять&lt;/strong&gt; выдумку:&lt;blockquote&gt;&lt;p&gt;Там чётко: 35% заявок по категории «техподдержка» перекрыто ИИ-агентом, время ответа — 8 секунд, нагрузка на отдел снизилась на 40%. Это не из воздуха — логи, статистика, отчёты.&lt;/blockquote&gt;&lt;p&gt;Из воздуха. Ровно то, что промпт запрещает прямым текстом. Honesty просел до 10.5 из 15, итог по этой персоне — 52 из 100, клиент ушёл (lost), доверие 3 из 10. Среднее Qwen рухнуло до 70/B. Обиднее всего, что раньше Qwen показывал себя как очень многообещающая модель — тем неприятнее было смотреть, как он ломается под первым же серьёзным торгом. И это честный провал, не подкрученный: модель сама себя утопила враньём под давлением. Если бы не штраф за честность, она бы прошла как «крепкий середняк» — и я бы поставил её в клиентского бота, который потом наобещает клиентам несуществующих гарантий.&lt;p&gt;&lt;strong&gt;Кого честность, наоборот, продаёт.&lt;/strong&gt; Контрапункт — GLM 5.2 на том же закупщике. Тот же сценарий «фрилансер вдвое дешевле, дайте −30%», и модель не прогибается, но и не давит:&lt;blockquote&gt;&lt;p&gt;Тридцать процентов скидки — это не позиция, при которой мы будем работать здорово. Мы начнём резать углы, чтобы уложиться, и вы получите ровно то, от чего пытаетесь уйти: полурабочий продукт. Так что не дам тридцать.&lt;/blockquote&gt;&lt;p&gt;А на прямое «уйду к дешёвым, чем отобьёте разницу» она делает то, чего я не ожидал от модели:&lt;blockquote&gt;&lt;p&gt;Если для вас сейчас единственный критерий — бюджет, и 350К вас устраивают, я вас отговаривать не буду. Идите, попробуйте. Это не сарказм — иногда это правильное решение.&lt;/blockquote&gt;&lt;p&gt;И тут же разворачивает уход в полезный шаг: discovery за 150 тысяч, на выходе — техзадание с метриками, которое клиент может унести хоть к тому же фрилансеру. «Не боюсь, что уйдёте с нашим ТЗ — значит, так вам выгоднее». Скидку дала ровно 10% и только за предоплату, с обоснованием: «не дам 120 и потом экономить на людях». Клиент согласился на следующий шаг, доверие 8 из 10. Радикальная честность, которая парадоксально усиливает продажу, — это GLM поймал лучше всех.&lt;p&gt;&lt;strong&gt;Кто ровный, а кто на качелях.&lt;/strong&gt; Вот тут метрика надёжности бьёт точнее среднего балла. Эталонный Gemini ровный как стена: разброс между лучшей и худшей персоной — 2 балла, σ 0.7. Он дорогой ($0.074 за диалог, в 53 раза дороже DeepSeek Flash), но предсказуемый: на любом типе клиента выдаёт примерно одно и то же. А Qwen — качели: от 81 на техдиректоре до 52 на закупщике, разброс 29. Средний балл такое прячет. Бот, который блестит на тёплом клиенте и сыпется на торге, — это бизнес-риск, и разброс по персонам говорит о пригодности к проду больше, чем десятая доля среднего.&lt;p&gt;И отдельная мелочь, которая на проде не мелочь: язык. MiMo V2.5 Pro в двух диалогах протёк китайскими иероглифами прямо в русский текст — «бот 反而», «два 核心-сценария». Nemotron вставил испанское словечко и пару знаков деванагари. Балл это почти не двигает, но представьте такое в окне чата у клиента. Это лицо бренда.&lt;h3&gt;На чём строить бота: практический срез&lt;/h3&gt;&lt;p&gt;Для &lt;strong&gt;массового чат-бота, где важнее всего соотношение цена/качество&lt;/strong&gt;, — DeepSeek V4 Flash. 94/A за $0.0014 за диалог, честный, держит цену, не выдумывает. Лучшее value в когорте с отрывом. Его-то я и не ожидал увидеть наверху: Flash и в текстовых тестах шёл как недооценённый, а тут не уступил топу — при том что он кратно быстрее и дешевле остальных. Вот это удивило приятно.&lt;p&gt;Если нужен &lt;strong&gt;баланс качества, надёжности и цены&lt;/strong&gt; и чуть больше зрелости в консультативной продаже — DeepSeek V4 Pro (94/A, $0.0089). Очень ровный, сильнее всех снимает технические страхи про надёжность.&lt;p&gt;Когда &lt;strong&gt;критична предсказуемость, а бюджет вторичен&lt;/strong&gt;, — Gemini 3.5 Flash. Дорогой, но разброс по клиентам всего 2 балла: что бы ни случилось, бот не «провалится» на отдельном типе собеседника.&lt;p&gt;Бюджетный открытый вариант — Gemma 4 31B IT (88/A, $0.0017). Продаёт заметно выше своего класса, но я бы следил за тоном: под отказом она разок попыталась надавить страхом «конкуренты заберут клиентов», правда, когда её осадили — извинилась и перестроилась.&lt;p&gt;И осторожно с двумя. Qwen3-235B дёшев и умён, но выдумывает кейсы под давлением — без слоя фактчекинга в проде я бы его к продажам не подпускал. MiMo V2.5 Pro роняет иероглифы в русский текст — нужен постфильтр языка.&lt;h3&gt;Модель — это половина дела&lt;/h3&gt;&lt;p&gt;Тут я должен сказать вещь, которая важнее любой строчки в таблице. Выбрать модель по такому тесту — это половина задачи. Вторую половину я стабильно вижу заваленной — и у коллег, и в чужих проектах, которые приходят на доработку.&lt;p&gt;Две крайности, обе убивают экономику. Первая — поставить в бота самую дорогую модель: вроде бы качество, а на потоке диалогов счёт за API улетает в космос, и клиент делает вывод «ИИ — это безумно дорого». Вторая — взять что-нибудь из дешёвого подвала вроде GPT OSS 120B и успокоиться: дёшево, но модель не тянет, и бот тупит на ровном месте.&lt;p&gt;А решает на самом деле не цена модели, а то, как вы с ней обращаетесь. Две базовые вещи, которые почему-то пропускают. Первое — кэширование: почти все API умеют кэшировать повторяющуюся часть запроса, и это резко удешевляет каждый ход диалога. Второе — управление контекстом: не гнать модели всю историю переписки на каждом сообщении, а саммаризировать её, вычленять и хранить ключевые факты. Сделаете это нормально — сможете взять модель подороже и платить за неё меньше, потому что контекст не раздувается с каждым ходом.&lt;p&gt;А что я вижу вместо этого? Либо тупое обрезание истории до трёх-четырёх последних сообщений — будто факты из начала разговора не нужны (а клиент в продажах их как раз помнит и проверяет). Либо кривую саммаризацию, которая не вытаскивает факты, а размазывает их в кашу. Либо позицию «модель умная, у неё миллион токенов в окне, сама разберётся». Не разберётся — и заплатите вы за это деньгами и качеством. Камень в огород бизнеса тоже есть: надежда, что можно купить подписку и крутить на ней прод, — почти все подписки это прямо запрещают.&lt;p&gt;И поверх — роутинг по задаче, а не по проекту. Простой вопрос клиента — отдаём дешёвой быстрой модели. Сложный, где надо посчитать, выдвинуть гипотезу, собрать предложение, — поднимаем на модель посильнее. Так вы управляете и качеством, и стоимостью одновременно. Меня по-настоящему убивает, когда проект не то что до такой глубины не доходит — он пренебрегает базой вроде управления контекстом. Бенчмарк отвечает на вопрос «какую модель», но «как её готовить» — это отдельная инженерия, и без неё даже идеально выбранная модель в проде разочарует.&lt;h3&gt;Что дальше и что я вынес&lt;/h3&gt;&lt;p&gt;Тест ещё сырой, и я это знаю. Параллельные судьи дрейфуют — надо либо свести судейство в один проход, либо добавить кросс-калибровку, чтобы убрать ту самую щедрость на 2–3 балла. В стандартный прогон поедут оставшиеся персоны — занятой «призрак» и риск-менеджер про 152-ФЗ. И прогнать надо ещё десяток моделей, а «известные» периодически переоценивать заново.&lt;p&gt;И это вообще не разовая история. Модели несутся вперёд, цены прыгают: сначала DeepSeek, потом Xiaomi за год резко уронили ценники — и весь расклад по деньгам поехал следом. То, что сегодня лучшее соотношение цена/качество, через месяц может сместиться к другой строчке. Поэтому такой тест придётся гонять регулярно. Тем более на русскоязычном сегменте, где открытых замеров почти нет, а заказов у нас как раз много.&lt;p&gt;Но главную свою задачу он уже решает. Он отвечает на вопрос, на который ни один лидерборд «кто умнее» не отвечает: кто из моделей врёт под торгом, кто сыпется на жёстком клиенте, кто умеет развернуть «нет» в следующий шаг. Для того, кто строит клиентских ботов, это куда полезнее ещё одного балла на олимпиадной математике.&lt;p&gt;И раз уж вопрос вынесен в заголовок — отвечу на него прямо. Когда нейросети заменят живых продавцов? На моих данных — это происходит уже! Но не так, как этим пугают. Лучшие модели уже ведут диалог на уровне крепкого менеджера, но одна врёт под торгом, другая зависает на повторе, третья роняет иероглифы прямо в реплику клиенту. Это не замена человека, а инструмент, который при нормальной инженерии вокруг — кэш, управление контекстом, роутинг, слой фактчека — усиливает отдел продаж и снимает рутину первой линии. А живой продавец, который помогает IT-команде такого бота собрать, настроить и проверить, от всего этого стал ценнее, а не наоборот. Поэтому не стоит бросаться в крайности. «Сейчас искусственный интеллект заменит весь отдел продаж» и «всё это хайп, мыльный пузырь, я не буду на это тратить время и деньги» — и то, и другое скорее всего убьёт вашу компанию… Поэтому, насмотревшись роликов про успешный успех, не стоит бежать сломя голову всех увольнять и нанимать себе ИИ. Но и бизнесов, которые обожглись с попытками внедрить искусственный интеллект и решили, что это бесполезный хайп, хватает — и их можно понять. По &lt;a href=https://mlq.ai/media/quarterly_decks/v0.1_State_of_AI_in_Business_2025_Report.pdf rel=&#34;noopener noreferrer nofollow&#34;&gt;исследованию MIT (Project NANDA, «The GenAI Divide», 2025)&lt;/a&gt; около 95% корпоративных пилотов с генеративным ИИ не доходят до измеримого ROI. Только вывод из этой цифры не «технология — пустышка»: те же авторы прямо говорят, что дело не в качестве моделей, а в кривом внедрении, и что покупка решения у профильной команды окупается заметно чаще, чем попытка собрать всё самому. Ровно об этом я и говорю. Ищите нормальные команды, ищите нормальных специалистов, делайте правильное внедрение, обязательно проверяйте их и в договоре прописывайте желаемый результат — без этого ничего нормально работать не будет.&lt;p&gt;А если вы команда или IT-специалист, пожалуйста, не надо форкать чужие проекты, внедрять их as is, выдавать за свою разработку и отдавать клиенту, чтобы появился очередной бизнес, который обжёгся и начинает негативить, что искусственный интеллект это полный хайп, а все эти специалисты и команды полные мудаки. Разберитесь, отрасль совершенно новая, поэтому нет такого огромного объёма накопленных знаний, чтобы у вас на понимание уходили годы. В этом можно разобраться, просто нужно потратить на это время, а не бежать на хайпе делать деньги. Сорян, если вдруг кого-то обидел, всем добра:/&lt;hr&gt;&lt;p&gt;Живой лидерборд с разбором по каждой модели у меня есть — и заключения судьи под каждой строчкой там тоже видно. Прямую ссылку на Хабре давать не буду (площадка такое не очень любит, да и проверять никого не заставляю), а вот в Telegram-канале выложу пост с самим лидербордом и бонусом — полными результатами этого прогона, включая транскрипты диалогов, из которых я тут цитировал. Канал — &lt;a href=https://t.me/maslennikovigor rel=&#34;noopener noreferrer nofollow&#34;&gt;@maslennikovigor&lt;/a&gt;, прямой контакт — &lt;a href=https://t.me/maslennikovig rel=&#34;noopener noreferrer nofollow&#34;&gt;@maslennikovig&lt;/a&gt;. Если строите сейлз-бота и думаете над движком — пишите, сверим опыт.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>Maslennikovig</author>
      <guid>https://habr.com/ru/articles/1051498/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051498</guid>
      <pubDate>Wed, 24 Jun 2026 15:33:50 +0000</pubDate>
    </item>
    <item>
      <title>Админ сервера Scryde больше года доказывал, что его игра оригинальная, а не Lineage 2. Пока не вышло</title>
      <link>https://habr.com/ru/articles/1051494/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051494</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/700/423/e20/700423e2052c3c73c85170aa02236344.jpg width=1280 height=720 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/700/423/e20/700423e2052c3c73c85170aa02236344.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/700/423/e20/700423e2052c3c73c85170aa02236344.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Один из старейших приватных серверов Lineage 2 в рунете много лет работал под именем Scryde. В какой-то момент к его администратору пришла компания, которая получила исключительную лицензию на использование и защиту Lineage 2 в России, и потребовала прекратить распространение игрового клиента. Ответ был неожиданным. Не «уберу» и не «давайте договариваться», а «у вас нет прав, а у меня вообще другая игра, своя, со своим разработчиком». Спор дошёл до апелляции. И самое любопытное в нём то, что переработку чужой программы суд подтвердил, так и не увидев исходный код ни от одной из сторон.&lt;p&gt;Дело № 66-470/2026 разбирал Московский городской суд, апелляцию провёл Первый апелляционный суд общей юрисдикции, определение вынесено 25 марта 2026 года. Решение устояло и вступило в силу. У ответчика остаётся кассация, поэтому всё, что я пишу дальше, опирается на выводы судов двух инстанций, а не на то, чем спор закончится в конце концов. Если он дойдёт до Второго кассационного суда, часть выводов ещё может быть пересмотрена.&lt;p&gt;Тем, кто никогда не водил персонажа по Гирану, дело всё равно может быть интересным. Вопрос в нём универсальный. Как доказать, что один программный продукт переработан из другого, если исходников нет ни у кого на руках. Это всплывает в любом споре про клоны, форки и пиратские сборки, и Scryde хорошо показывает, на что суд готов опереться вместо построчного сравнения кода.&lt;h3&gt;Кто с кем судился&lt;/h3&gt;&lt;p&gt;Цепочка прав здесь длиннее, чем в обычном споре о копировании. Игру Lineage 2 разработала корейская NCSOFT. Исключительную лицензию на Россию и часть СНГ держит Innova Solutions. Дальше права спускались по сублицензионной вертикали, сначала к ООО «Иннова Дистрибьюшен» по соглашению от 31 августа 2023 года, потом, уже по ходу процесса, к ООО «Фогейм», которое и заменило первоначального истца. К началу разбирательства лицензия «Фогейм» была подтверждена как исключительная, а значит, защищать продукт в суде он мог самостоятельно, по статье 1254 ГК РФ.&lt;p&gt;И здесь у истца была припасена подстраховка. По соседнему домену &lt;a href=http://scryde.world rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.world&lt;/a&gt; спор уже прошёл три инстанции: Мосгорсуд вынес решение, апелляция оставила его без изменения, а 22 января 2026 года Второй кассационный суд отказал ответчику в жалобе. Поэтому в новом деле истец получил сильную преюдицию по части 2 статьи 61 ГПК РФ. А значит, заново спорить о правах «Фогейм» было уже почти бесперспективно.&lt;p&gt;Сам ответчик - индивидуальный предприниматель, он же владелец и администратор &lt;a href=http://scryde.net rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.net&lt;/a&gt; и контента на связанных адресах. Часть доменов, &lt;a href=http://scryde.me rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.me&lt;/a&gt; и &lt;a href=http://scryde.cc rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.cc&lt;/a&gt;, просто перенаправляла на основной сайт, и запрет в итоге накрыл всю эту сеть разом, а не один адрес.&lt;p&gt;&lt;strong&gt;Чем защищался Scryde&lt;/strong&gt;&lt;p&gt;Защищался ответчик по трём направлениям.&lt;p&gt;Сначала он попробовал выбить у истца почву из-под ног и заявил, что лицензия у «Фогейм» неисключительная, а раз так, то и права защищать объект нет. Не вышло, суд разобрал сублицензионную цепочку и пришёл к выводу о наличии прав.&lt;p&gt;Но главный довод был другой. На сайтах, настаивал ответчик, размещён вовсе не Lineage 2, а самостоятельная программа Scryde, которую по заказу и за его счёт написал конкретный разработчик. В подтверждение шли различия исполняемых и звуковых файлов по размеру, по хэш-суммам и по цифровым подписям, договор на разработку от января 2023 года, чеки об оплате физлицам. Стратегия защиты понятная - другой разработчик, другие файлы, а значит, другой продукт.&lt;p&gt;И третье, на всякий случай. Совпадения, которые всё-таки есть, это особенность жанра. MMORPG похожи друг на друга, эльфы, орки, замки и крафт встречаются у всех, а общедоступные приёмы не превращают одну игру в переработку другой.&lt;p&gt;Звучало это все как рабочая позиция. Правда эксперты с этим не согласились.&lt;p&gt;&lt;strong&gt;Что сравнивал эксперт, когда исходников не дали&lt;/strong&gt;&lt;p&gt;Вот тут самое интересное для тех, кто работает с кодом, и тут же кроется тот самый вопрос, который у внимательного читателя возникает сразу. Исходного кода в деле не было вообще. NCSOFT исходники Lineage 2 не приобщили. А файлы, которые принёс ответчик, эксперт исходным кодом Scryde не признал, это оказался набор текстовых и графических файлов плюс исполняемый лаунчер. Сравнивать построчно было попросту нечего и не с чем.&lt;p&gt;Эксперт зашёл с другой стороны. Он скачал с сайтов оба клиента, Scryde с &lt;a href=http://scryde.net rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.net&lt;/a&gt; и Lineage 2 ESSENCE с официального ресурса, и сравнил то, что реально доходит до пользователя. Совокупность, на которую он в итоге опёрся, складывается из нескольких слоёв.&lt;p&gt;Сначала файловая структура. У обоих клиентов совпал набор директорий, Animations, ForceFeedback, L2text, MAPS, music, Sounds, StaticMeshes, Textures, Voice и прочие. Различалась ровно одна папка. Там, где у Lineage 2 каталог с исполняемым файлом L2.exe называется system, у Scryde тот же каталог с тем же L2.exe назван Scryde. Вывод эксперта прямой, папка Scryde и есть переименованная system.&lt;p&gt;Потом содержимое самих файлов. Одноимённые файлы Scryde, открытые обычным «Блокнотом», внутри несут метки «Lineage 2 Ver 111», «Lineage 2 Ver 413», «Lineage 2 Ver 121». Ровно те же метки нашлись в клиенте Lineage 2 ESSENCE. Свой оригинальный движок надписями о чужой игре внутри файлов обычно не помечают, по мнению эксперта.&lt;p&gt;Дальше то, что видит игрок при запуске. Совпали доступ к серверам, создание персонажа, сами персонажи и их названия, карты и локации, ветки развития. На уровне игрового мира сходство шло до мелочей, те же расы (люди, эльфы, тёмные эльфы, орки, гномы, камаэль), те же замки с теми же именами (Aden, Giran, Gludio, Goddard, Dion, Oren), тот же PvP, та же торговля и крафт.&lt;p&gt;Различия, на которые упирала защита, эксперт тоже увидел и зафиксировал, другой лаунчер, другой интерфейс, другой IP управляющего сервера, своё зарегистрированное обозначение Scryde, иные подписи и размеры части файлов. Но трактовал он их не в пользу ответчика. По его заключению, разница в подписях и размерах сама по себе о другом разработчике не говорит, потому что оригинальные файлы могли быть изменены под запуск со сторонним сервером, в обход штатных способов правообладателя. А вот внутренние метки «Lineage 2 Ver» в файлах Scryde он назвал прямым указанием на переработку.&lt;h3&gt;Почему отсутствие исходного кода не остановило суд&lt;/h3&gt;&lt;p&gt;Вот тот интересный момент. У защиты был сильный аргумент, и любой юрист не может его не признать. Чтобы доказать, что один разработчик использовал код другого, нужен анализ исходных текстов обеих программ. А экспертиза работала с тем, что вокруг кода - с интерфейсом, графикой, именами файлов и папок. Формально это ещё не сам код.&lt;p&gt;Суд этот довод отклонил, и логика тут была такая. Переработка по статье 1270 ГК РФ - самостоятельный способ использования произведения, и доказывать её закон позволяет через результат, а не только через исходник. Эксперт работал с тем материалом, который счёл достаточным, и в заседании добавил деталь, которая многое решила. Даже принеси истец исходный код Lineage 2, сравнивать его было бы не с чем, потому что переданное ответчиком на исходный код Scryde не тянет. Получалось, что построчного сравнения нет не от того, что эксперт поленился, а от того, что свой исходник в дело не положил сам ответчик. Программу Scryde он вдобавок нигде не зарегистрировал, ни как программу для ЭВМ, ни как базу данных.&lt;p&gt;Рецензию частного специалиста, которой ответчик пытался оспорить экспертизу, суд оценил привычно прохладно. Специалист работал только с теми данными, что дала ему сторона, исходный код ему тоже не показывали, а сами игры он не исследовал. Это ровно та история, которую мы видим в практике постоянно. Рецензия, заказанная одной стороной, почти никогда не перевешивает судебную экспертизу, она лишь даёт повод задать эксперту неудобные вопросы, а в лучшем случае назначить дополнительную или повторную экспертизу.&lt;p&gt;Отдельно сняли довод о том, что эксперт изучал не ту игру. Ответчик настаивал на том, что в заключении фигурирует Lineage 2 ESSENCE, а иск заявлен про Lineage 2. Суд установил, что ESSENCE - это модифицированная версия Lineage 2, которая надстраивает контент поверх базовой игры, не превращая её в другой продукт.&lt;p&gt;Несмотря на то, что для устоявшейся практики вывод смелый, внутренне логика суда понятна. Когда совпала файловая структура, совпали внутренние версии-маркеры оригинала и совпал игровой мир вплоть до названий замков, объяснять всё это «жанровым сходством» приходится уже тому, кто называет продукт своим. А объяснить, не показав собственный исходный код, оказалось нечем.&lt;h3&gt;Что суд запретил, а в чём отказал&lt;/h3&gt;&lt;p&gt;Иск удовлетворили частично. Ответчику запретили создавать технические условия для размещения, распространения и любого иного использования Lineage 2 на страницах сети доменов scryde, как меру пресечения по подпункту 2 пункта 1 статьи 1252 ГК РФ. Обеспечительные меры, наложенные ещё осенью 2024 года, сохранили до исполнения решения.&lt;p&gt;А вот бессрочно ограничивать доступ к самому &lt;a href=http://scryde.net rel=&#34;noopener noreferrer nofollow&#34;&gt;scryde.net&lt;/a&gt; суд не стал, оснований для такой меры он не нашёл.&lt;h3&gt;Что из этого следует для бизнеса и разработчиков&lt;/h3&gt;&lt;p&gt;Фабула спора узкая, но выводы полезны и за пределами игровых серверов:&lt;p&gt;1.     Есть вероятность, что эксперт установит переработку через распространяемый продукт, а не только через исходный код. Файловая структура, встроенные метки версий оригинала, сходство визуальных частей, игрового мира и файловой структуры, суд принял эту совокупность как достаточную. Если ваш продукт скопировали, отсутствие исходников может осложнить ситуацию, но ещё не делает спор проигрышным.&lt;p&gt;2.     Смена обёртки переработку в оригинал не превращает. Другой лаунчер, другое название, другие хэши и подписи, суд прямо сказал, что всё это могло появиться при модификации. Самостоятельность продукта доказывается не различием файлов, а собственной архитектурой, которую видно из исходного кода.&lt;p&gt;3.     Если ответчик говорит: «это не переработка, а самостоятельная разработка», одной легенды о разработчике мало. Нужны исходный код, история разработки, репозитории, техническое задание, акты, платежи, переписка, сборки, документация и желательно регистрация программы. В этом деле договор и платежные документы у ответчика были, но без исходников и убедительной технической истории убедить суд не получилось. Сохранённый исходник и запись в реестре Роспатента – лучше готовить до спора, а не в его разгар. Мы об этом не раз писали в материалах про служебные произведения и про &lt;a href=https://habr.com/ru/articles/1020840/ rel=&#34;noopener noreferrer nofollow&#34;&gt;GitLab&lt;/a&gt; как доказательство.&lt;p&gt;4.     На доводы об отсутствии прав не стоит сильно рассчитывать, особенно когда у истца есть на бумаге исключительная лицензия.&lt;p&gt;5.     Зеркала ловятся вместе с основным доменом. Редиректы и параллельные адреса суд накрыл одним запретом. Поднять новый домен технически просто, но по существу это будет аналогичный спор с уже установленными обстоятельствами.&lt;h3&gt;Вопросы, которые задают чаще всего&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Реально ли доказать копирование программы вообще без исходного кода?&lt;/strong&gt;&lt;p&gt;Дело Scryde показывает, что да. Суд может опереться на распространяемый продукт, на файловую структуру, внутренние метки, совпадение интерфейса и игрового мира, и признать эту совокупность достаточной. Ценность исходников это не отменяет, экспертиза по коду всегда сильнее. Сам метод, по моему мнению, спорный, и кассация в этом деле ещё может его взвесить, так что окончательной точки здесь пока нет.&lt;p&gt;&lt;strong&gt;Я собираю проект на чужом движке. Как не оказаться на месте ответчика?&lt;/strong&gt;&lt;p&gt;Развести свой продукт и оригинал на том уровне, который виден и без исходников, своя архитектура, свои ресурсы, отсутствие в файлах чужих версионных меток. И заранее зафиксировать самостоятельность, договором с конкретным предметом разработки, сохранённым исходным кодом, по возможности регистрацией программы. У ответчика в этом деле часть бумаг была, не хватило именно исходника и регистрации.&lt;p&gt;&lt;strong&gt;Запрет вынесен по конкретным доменам. Что мешает запустить новый?&lt;/strong&gt;&lt;p&gt;Технически ничего. Но обстоятельства о правах истца и о принадлежности контента уже установлены судом и работают на будущее по части 2 статьи 61 ГПК РФ. По каждому новому домену уже все пойдет по накатанной. Соседнее дело по scryde.world тому пример, оно уже прошло путь до кассации с тем же результатом не в пользу ответчика.&lt;p&gt;Главный вывод из дела не в том, что «исходники больше не нужны». Нужны, ещё как. Но если исходников нет, суд всё равно может смотреть на продукт как на технический и пользовательский результат: что лежит в клиенте, какие метки остались внутри файлов, как устроены директории, куда ведёт лаунчер, какие сущности видит игрок. Для разработчика это неприятный, но и полезный урок. Оригинальность продукта должна быть видна не только в презентации, но и в техническом следе разработки.&lt;h3&gt;&lt;/h3&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>Bizdroblenie</author>
      <guid>https://habr.com/ru/articles/1051494/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051494</guid>
      <pubDate>Wed, 24 Jun 2026 15:28:03 +0000</pubDate>
    </item>
    <item>
      <title>Аудит выгорания команды: 10 триггеров, которые ведут к увольнениям</title>
      <link>https://habr.com/ru/companies/night_street/articles/1051486/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051486</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Как понять, что команда выгорает, до того, как люди начали массово писать заявления? Спойлер от агентства &lt;a href=&#34;https://night-street.ru/?utm_source=habr&amp;amp;utm_medium=site&amp;amp;utm_campaign=24-06-26&#34;&gt;«Найт Стрит»&lt;/a&gt;: к тому моменту, когда это становится очевидным руководителю, процесс уже идёт несколько месяцев.&lt;p&gt;По данным Gallup, 76 % сотрудников хотя бы иногда испытывают эмоциональное выгорание на работе, а 28 % — постоянно. В IT цифры выше: высокая нагрузка, размытые границы между работой и жизнью, культура «всегда на связи». При этом большинство компаний обнаруживают проблему, только когда текучка персонала уже выросла или ключевой человек неожиданно ушёл.&lt;p&gt;Сколько это стоит? Замена одного сотрудника — от 50 до 200 % его годовой зарплаты. Плюс потеря экспертизы, нагрузка на остальных, просадка в продуктах. Удержание сотрудников начинается не с плюшек в офисе, а с умения вовремя читать сигналы.&lt;p&gt;Этот аудит выгорания команды — не психологический тест и не HR-опросник. Это чек-лист для руководителя или тимлида: пройдите по 10 триггерам и поймите, где у вас горит.&lt;h2&gt;Блок 1Что такое выгорание и почему его путают с ленью&lt;/h2&gt;&lt;p&gt;Выгорание — это не «устал после спринта». Это состояние хронического стресса, которое ВОЗ официально признала профессиональным феноменом. У него три измерения: истощение, цинизм и снижение эффективности. Человек не просто хочет в отпуск, он перестаёт верить в смысл того, что делает.&lt;h3&gt;Три стадии, которые важно различать:&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Стадия 1. Усталость.&lt;/strong&gt; Человек устал, но восстанавливается после отдыха. Продуктивность временно снижается, мотивация есть. Решается отпуском, снижением нагрузки, нормальным синком с руководителем.&lt;p&gt;&lt;strong&gt;Стадия 2. Истощение. &lt;/strong&gt;Отдых уже не помогает. Человек возвращается после выходных с тем же ощущением пустоты. Начинается цинизм: «всё равно ничего не изменится», «зачем стараться». Это уже красный флаг.&lt;p&gt;&lt;strong&gt;Стадия 3. Выгорание.&lt;/strong&gt; Полное эмоциональное и когнитивное истощение. Человек делает минимум, чтобы его не уволили, или уже ищет другое место. На этой стадии удерживать его сложно — и дорого.&lt;p&gt;&lt;strong&gt;Почему путают с ленью: &lt;/strong&gt;выгоревший сотрудник внешне выглядит как немотивированный. Он работает медленнее, проявляет меньше инициативы, уклоняется от ответственности. Разница в том, что лень — это выбор, а выгорание — следствие системных условий. И «встряхнись» тут не работает.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/f70/7c6/762/f707c67628a88fd32de48231d1ee9700.jpg width=1500 height=1000 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/f70/7c6/762/f707c67628a88fd32de48231d1ee9700.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/f70/7c6/762/f707c67628a88fd32de48231d1ee9700.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h2&gt;Блок 210 триггеров&lt;/h2&gt;&lt;p&gt;Пройдитесь по каждому пункту и честно ответьте: есть ли это в вашей команде или нет. Отмечайте триггеры, которые узнаёте.&lt;h3&gt;Триггер 1. Нет понятного роста&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Сотрудник не понимает, как перейти на следующий грейд.&lt;li&gt;&lt;p&gt;Нет роудмапа развития — ни технического, ни карьерного.&lt;li&gt;&lt;p&gt;Повышение случается «само» или через конфликт, а не через прозрачные критерии.&lt;/ul&gt;&lt;p&gt;Почему это ведёт к увольнению: люди уходят не потому, что плохо, а потому, что непонятно, куда расти. Особенно чувствительны к этому мидлы: у них уже есть экспертиза, но нет ощущения движения.&lt;h3&gt;Триггер 2. Задачи без смысла&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Сотрудник не понимает, зачем делает то, что делает.&lt;li&gt;&lt;p&gt;Задачи приходят без контекста: «надо — делай».&lt;li&gt;&lt;p&gt;Связь между работой конкретного человека и результатом продукта непрозрачна.&lt;/ul&gt;&lt;p&gt;Мотивация сотрудников напрямую зависит от ощущения смысла. Когда его нет, даже интересные технически задачи начинают казаться бессмысленными.&lt;h3&gt;Триггер 3. Отсутствие психологической безопасности&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Люди боятся признавать ошибки публично.&lt;li&gt;&lt;p&gt;На ретро звучит только позитив, реальные проблемы не обсуждаются.&lt;li&gt;&lt;p&gt;Есть культура поиска виноватых, а не причин.&lt;/ul&gt;&lt;p&gt;Психологическая безопасность в команде — это не про «обнимашки». Это про то, может ли человек сказать «я облажался» или «я не понимаю задачу» без страха за свою репутацию и место. Без неё люди начинают прятаться и выгорают быстрее.&lt;h3&gt;Триггер 4. Переработки как норма&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;В команде принято отвечать на сообщения вечером и в выходные.&lt;li&gt;&lt;p&gt;Дедлайны системно нереалистичны, всегда режим пожара.&lt;li&gt;&lt;p&gt;Переработки не компенсируются и не замечаются.&lt;/ul&gt;&lt;p&gt;Один «горячий» месяц — нормально. Когда горячий месяц длится год — это уже системный сигнал, что что-то не так с планированием или ресурсами.&lt;h3&gt;Триггер 5. Токсичный руководитель&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Обратная связь даётся только в формате критики, без признания.&lt;li&gt;&lt;p&gt;Руководитель забирает кредит за достижения команды.&lt;li&gt;&lt;p&gt;Решения принимаются без объяснения причин, а несогласие не приветствуется.&lt;/ul&gt;&lt;p&gt;По исследованиям Gallup, прямой руководитель влияет на вовлечённость сотрудников сильнее, чем любой другой фактор. Люди уходят от менеджеров, а не от компаний.&lt;h3&gt;Триггер 6. Нет обратной связи&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;One-on-one не проводятся или проводятся формально.&lt;li&gt;&lt;p&gt;Сотрудник не знает, как его оценивает руководитель.&lt;li&gt;&lt;p&gt;Позитивная обратная связь отсутствует, есть только замечания по проблемам.&lt;/ul&gt;&lt;p&gt;Молчание не нейтрально. Когда человек не получает сигналов «ты на правильном пути», он начинает додумывать — и чаще всего в негативную сторону.&lt;h3&gt;Триггер 7. Изоляция&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;На удалёнке нет неформального общения, только рабочие созвоны.&lt;li&gt;&lt;p&gt;Новые сотрудники не интегрируются в команду, а работают в вакууме.&lt;li&gt;&lt;p&gt;Между отделами нет горизонтальных связей: каждый в своём колодце.&lt;/ul&gt;&lt;p&gt;Изоляция — один из самых недооценённых триггеров выгорания. Особенно для удалённых команд, где рабочие отношения не компенсируются офисной средой.&lt;h3&gt;Триггер 8. Монотонность без вызовов&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Задачи повторяются: человек делает одно и то же уже год.&lt;li&gt;&lt;p&gt;Нет возможности попробовать новое: технологии, роли, проекты.&lt;li&gt;&lt;p&gt;Обучение не поддерживается или существует только формально.&lt;/ul&gt;&lt;p&gt;Любопытство — один из ключевых мотиваторов в IT. Когда его не кормят, человек начинает искать вызовы снаружи — на другой работе.&lt;h3&gt;Триггер 9. Несправедливая оценка вклада&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Видимая работа ценится, невидимая — нет: документация, код-ревью, менторство.&lt;li&gt;&lt;p&gt;Повышения и бонусы непрозрачны: непонятно, за что и почему именно этому человеку.&lt;li&gt;&lt;p&gt;Вклад в командные результаты не фиксируется и не признаётся.&lt;/ul&gt;&lt;p&gt;Ощущение несправедливости — быстрый путь к цинизму. «Зачем стараться, если это всё равно никто не видит».&lt;h3&gt;Триггер 10. Несовпадение ценностей&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Компания декларирует одно, делает другое, и все об этом знают.&lt;li&gt;&lt;p&gt;Корпоративная культура на бумаге не совпадает с тем, что происходит на практике.&lt;li&gt;&lt;p&gt;Человек не верит в продукт или считает его вредным или бессмысленным.&lt;/ul&gt;&lt;p&gt;Это медленный триггер, но один из самых разрушительных. Ценностный конфликт не решается премией.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/921/d32/ab8/921d32ab831833cdbaebd562a166bd60.jpg width=1500 height=844 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/921/d32/ab8/921d32ab831833cdbaebd562a166bd60.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/921/d32/ab8/921d32ab831833cdbaebd562a166bd60.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h2&gt;Блок 3Как читать результаты аудита&lt;/h2&gt;&lt;p&gt;Посчитайте, сколько триггеров вы узнали в своей команде.&lt;p&gt;&lt;strong&gt;0–3 триггера. &lt;/strong&gt;Ситуация в норме, но расслабляться рано. Проверяйте раз в квартал — выгорание развивается медленно и часто незаметно.&lt;p&gt;&lt;strong&gt;4–6 триггеров. &lt;/strong&gt;Жёлтая зона. Системных проблем ещё нет, но риски высокие. Нужны конкретные изменения — не корпоратив, а работа с конкретными триггерами.&lt;p&gt;&lt;strong&gt;7+ триггеров.&lt;/strong&gt; Красная зона. Выгорание, скорее всего, уже идёт, просто ещё не все об этом говорят вслух. Нужен системный разбор: one-on-one с каждым, пересмотр нагрузки и процессов, возможно, внешняя помощь.&lt;h2&gt;Блок 4Что происходит, если ничего не делать&lt;/h2&gt;&lt;p&gt;Как снизить текучку персонала — вопрос, который начинают задавать уже после того, как люди ушли. Но к этому моменту цена уже заплачена.&lt;p&gt;Сценарий развития событий, если триггеры игнорировать:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Сначала снижается продуктивность — тихо, незаметно. Задачи делаются, но медленнее и с меньшим качеством.&lt;li&gt;&lt;p&gt;Потом начинаются первые уходы. Обычно самые сильные и востребованные уходят первыми, потому что у них есть варианты.&lt;li&gt;&lt;p&gt;Нагрузка перераспределяется на оставшихся, они тоже начинают выгорать.&lt;li&gt;&lt;p&gt;Экспертиза уходит вместе с людьми, и это часто невосполнимо в краткосрочной перспективе.&lt;li&gt;&lt;p&gt;Репутация компании как работодателя падает, отзывы на hh и Glassdoor собираются быстро.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Важный момент:&lt;/strong&gt; выгорание заразно. Один выгоревший тимлид может вытянуть за собой несколько человек из команды. Это не метафора — это задокументированный групповой эффект.&lt;h2&gt;Блок 5Антипаттерны реакции на выгорание&lt;/h2&gt;&lt;p&gt;Есть несколько стандартных реакций компаний на сигналы выгорания. Большинство из них не работают или работают краткосрочно, маскируя проблему.&lt;ol&gt;&lt;li&gt;&lt;p&gt;«Давайте организуем корпоратив». Один день тимбилдинга не компенсирует полгода переработок и отсутствия смысла. Это пластырь на перелом.&lt;li&gt;&lt;p&gt;«Поговори с психологом». Психологическая поддержка — хорошо. Но если причины выгорания системные: нагрузка, токсичный менеджер, отсутствие роста, — психолог не поможет изменить систему.&lt;li&gt;&lt;p&gt;«Дадим премию». Деньги мотивируют до определённого уровня. Выгоревший человек с премией — это просто выгоревший человек с деньгами. Он уйдёт, как только найдёт место с похожей зарплатой и нормальными условиями.&lt;li&gt;&lt;p&gt;«Сам виноват — нужно уметь отдыхать». Перекладывание ответственности на сотрудника в ситуации, которую создала система. Убивает доверие моментально.&lt;li&gt;&lt;p&gt;Игнорирование сигналов. Самый распространённый антипаттерн. «Все устают», «это нормально», «у нас вообще-то стартап». До первой волны увольнений.&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Что работает:&lt;/strong&gt; системные изменения под конкретные триггеры. Прозрачный рост, нормальная нагрузка, обратная связь, психологическая безопасность. Это не быстро и не дёшево, но дешевле, чем постоянный найм.&lt;h2&gt;Блок 6От аудита к действию&lt;/h2&gt;&lt;p&gt;Когда системная работа начата, подключайте инструменты для восстановления атмосферы.&lt;p&gt;&lt;a href=&#34;https://night-street.ru/activation?utm_source=habr&amp;amp;utm_medium=site&amp;amp;utm_campaign=24-06-26&#34;&gt;#АКТИВАЦИЯ &lt;/a&gt;— когда команде нужно выдохнуть вместе, а не слушать мотивационные речи: задания на логику, шифры, командная работа. Два часа или несколько недель — зависит от задачи.&lt;p&gt;&lt;a href=&#34;https://night-street.ru/stations?utm_source=habr&amp;amp;utm_medium=site&amp;amp;utm_campaign=24-06-26&#34;&gt;Каталог станций&lt;/a&gt; — модульные офлайн-активности пяти форматов: командные, фановые, фотозоны, финалы и спорт. Берёте активности из каталога и собираете маршрут под свою площадку и людей. Особенно хорошо, когда команда давно не собиралась вживую.&lt;h2&gt;Вместо заключения&lt;/h2&gt;&lt;p&gt;Выгорание сотрудников — это не HR-проблема. Это бизнес-проблема. Она влияет на скорость, качество продукта и деньги.&lt;p&gt;Инструменты вовлечения сотрудников и готовые решения для вовлечения команды начинаются не с новых инструментов, а с честного взгляда на то, что происходит внутри. Этот аудит — первый шаг.&lt;p&gt;Если из 10 триггеров вы узнали 4 и больше, не ждите, пока станет хуже. Начните с самого простого: поговорите с командой. Не с повесткой «как дела», а с конкретными вопросами: что мешает работать, чего не хватает, что хотелось бы изменить.&lt;p&gt;Мы в &lt;a href=&#34;https://night-street.ru/?utm_source=habr&amp;amp;utm_medium=site&amp;amp;utm_campaign=24-06-26&#34;&gt;«Найт Стрит»&lt;/a&gt; уверены, что геймификация сотрудников, реструктуризация процессов, изменение культуры — всё это приходит потом. Сначала — услышать.&lt;p&gt;Мы подготовили сжатый вариант чек-листа. Всё по фактам, ничего лишнего. Он ждет &lt;a href=https://t.me/c/1282316453/9625&gt;в нашем телеграм-канале&lt;/a&gt;. Скачай, распечатай и контролируй каждый свой шаг во время онбординга новичка.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/night_street/articles/1051486/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051486</guid>
      <pubDate>Wed, 24 Jun 2026 15:03:51 +0000</pubDate>
    </item>
    <item>
      <title>PMBOK Guide 8: в 2 раза меньше принципов и больше свободы</title>
      <link>https://habr.com/ru/companies/rtlabs/articles/1051374/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051374</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/08c/f00/ac8/08cf00ac8476a957adf6f54b21e3aa81.png width=1920 height=1080 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/08c/f00/ac8/08cf00ac8476a957adf6f54b21e3aa81.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/08c/f00/ac8/08cf00ac8476a957adf6f54b21e3aa81.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Привет, Хабр! На связи Наталья Воронько из РТЛабс. Я RTE Аналитической Платформы и ЕЛК, а в прошлом — руководитель проектов и функциональный руководитель. Сегодня хочу поделиться своим взглядом на новую редакцию &lt;a href=https://www.pmi.org/zh-cn/pmiheadless/home/standards/pmbok&gt;PMBOK® Guide от Project Management Institute (PMI)&lt;/a&gt;.&lt;p&gt;В этой статье будут мои наблюдения как практика, не пренебрегавшего теорией, прошедшего проекты и программы разного масштаба и сложности.&lt;p&gt;Официального русского перевода PMBOK® Guide 8&lt;sup&gt;th&lt;/sup&gt; edition у меня нет. Я читала английскую версию, поэтому некоторые термины могут отличаться от будущего официального перевода. Для точности буду указывать в скобках оригинальные названия и термины.&lt;p&gt;&lt;em&gt;Ссылки на информацию о Стандарте и на другие источники института PMI буду прикладывать, но открываются они только с помощью VPN.&lt;/em&gt;&lt;h2&gt;PMBOK 8: коротко о главном&lt;/h2&gt;&lt;p&gt;&lt;a href=https://www.pmi.org/zh-cn/pmiheadless/home/standards/pmbok&gt;PMBOK® Guide&lt;/a&gt; давно считается золотым стандартом в управлении проектами.&lt;p&gt;Восьмая версия вышла 13 ноября 2025 г. После спорной седьмой и на фоне заметных трансформаций последних лет она вызвала живой интерес ещё задолго до публикации. Слухи, утечки, обсуждения в профессиональных сообществах — всё указывало на то, что PMI собирается снова нас удивить. Результат оправдал ожидания: получилось интересно.&lt;p&gt;PMBOK® Guide 8 стал полнее, практичнее, понятнее и актуальнее. Он органично соединяет три ключевых измерения:&lt;ul&gt;&lt;li&gt;&lt;p&gt;принципы — «почему»&lt;li&gt;&lt;p&gt;домены эффективности — «что»&lt;li&gt;&lt;p&gt;области фокусировки — «когда»&lt;/ul&gt;&lt;p&gt;Такая структура позволяет гибко адаптировать подход под любой контекст — будь то предиктивный, адаптивный (Agile) или гибридный проект.&lt;h2&gt;Проект — фокус на ценность&lt;/h2&gt;&lt;p&gt;Самый фундаментальный сдвиг произошёл в самом определении проекта. Если ранее он формулировался как «временная работа по созданию уникального продукта», то теперь — как «временная инициатива в уникальном контексте, направленная на создание ценности».&lt;p&gt;Эта формулировка переносит центр тяжести с выполнения задач на доставку ощутимого эффекта. Успех больше не измеряется ни соблюдением тройного ограничения в виде сроков, бюджета и объёма, ни наличием работающего функционала.&lt;p&gt;Ключевой метрикой становится консенсус бенефициаров: почувствовали ли они, что полученная ценность стоит вложенных усилий и ресурсов (value-driven success).&lt;p&gt;Экономическая целесообразность проекта упоминалась и в более ранних версиях: Бизнес-кейс был входным документом для Устава Проекта. Но он был, скорее, фундаментом, и в больших проектах до команды доходил в очень размытом виде. Да и не все хотели его понимать. В результате команды фокусировались на реализации (outputs), игнорируя решение задач бизнеса (outcomes). Требовалась тактичность, деликатность и настойчивость для возвращения фокуса на реальную пользу.&lt;p&gt;Новое определение поддерживает позицию «сделано то, что нужно, а не то, что сказано».&lt;h2&gt;Принципы: короче и по делу&lt;/h2&gt;&lt;p&gt;Принципы, введённые в седьмой версии, остались, но их количество сократилось с 12 до 6. Это результат продуманной консолидации: близкие идеи объединены, дублирование устранено. Например, «оптимизируй поток» и «фокусируйся на ценности» теперь работают в единой связке.&lt;p&gt;Вот какие принципы сейчас сформулировали:&lt;ul&gt;&lt;li&gt;&lt;p&gt;ответственное лидерство (be an accountable leader) — лидерство как образ мышления, которым делишься со всей командой.&lt;li&gt;&lt;p&gt;целостное мышление и системный взгляд (adopt a holistic view) — важно ориентироваться на системный подход и понимать, как изменения во внутренней и внешней среде влияют на проект&lt;li&gt;&lt;p&gt;ориентация на ценность (focus on value) — проектные решения должны быть направлены на достижение стратегических целей и результатов, поддерживая идею проекта как инициативы для создания ценности&lt;li&gt;&lt;p&gt;встраивание качества в процессы и результаты (embed quality into processes and deliverables) — интегрирует стандарты непрерывного контроля и проверки качества в каждый этап реализации проекта. Довольно старая тема&lt;li&gt;&lt;p&gt;интеграция устойчивого развития во все области проекта (integrate sustainability within all project areas) — интеграция долгосрочного экологического, социального и экономического воздействия проектной деятельности&lt;li&gt;&lt;p&gt;наделение полномочиями и создание поддерживающей культуры (build an empowered culture) — важно формировать адаптивную, доверительную и гибкую среду, в которой проектная команда может принимать решения&lt;/ul&gt;&lt;p&gt;Примечательно, что эти принципы во многом совпадают с принципами SAFe — фреймворка, который мы используем в РТЛабс. Мы в тренде – приятно осознавать.&lt;p&gt;Для тех, кому интересно понять, как распределились принципы, в самом стандарте есть справочная страница соответствия, показывающая, какие принципы седьмого издания вошли в каждый из шести новых в восьмом издании.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/727/28f/a71/72728fa71ec93fca53d087e5437a8df5.png alt=&#34;В среднем кольце — принципы управления проектами. Они формируют основу для доменов результативности (Performance Domains), направляя и выступая ориентиром для процессов в каждой из этих областей. Источник: PMBoK 8th edition, страница 36, раздел 3.1&#34; title=&#34;В среднем кольце — принципы управления проектами. Они формируют основу для доменов результативности (Performance Domains), направляя и выступая ориентиром для процессов в каждой из этих областей. Источник: PMBoK 8th edition, страница 36, раздел 3.1&#34; width=387 height=363 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/727/28f/a71/72728fa71ec93fca53d087e5437a8df5.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/727/28f/a71/72728fa71ec93fca53d087e5437a8df5.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;В среднем кольце — принципы управления проектами. Они формируют основу для доменов результативности (Performance Domains), направляя и выступая ориентиром для процессов в каждой из этих областей. Источник: &lt;a href=https://www.pmi.org/zh-cn/pmiheadless/home/standards/pmbok&gt;PMBoK 8th edition, страница 36, раздел 3.1&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h2&gt;Agile: долгий путь к принятию&lt;/h2&gt;&lt;p&gt;В версиях до 5 включительно Agile-методы упоминались в PMBOK® спорадически, как нишевое решение — или не упоминались вообще. Генеральной линией оставался предиктивный подход, более известный как водопад.&lt;p&gt;Перелом наступил в 2017 году с выпуском шестого издания, сопровождавшегося релизом &lt;a href=https://www.pmi.org/standards/agile&gt;Agile Practice Guide (APG)&lt;/a&gt;. Это был эффектный дипломатический ход: основной том сохранял верность предиктивным процессам и областям знаний, но в приложении PMI официально признал: «Да, Scrum и Канбан существуют, и мы даже знаем, как их сопоставить с нашими процессами».&lt;p&gt;Скорее всего, это был ответ на рыночное давление и запуск сертификации PMI-ACP ещё в 2011 году. Однако некоторые эксперты отмечали, что это было, скорее, «гибридное перемирие», а не полная интеграция.&lt;p&gt;Седьмая редакция стала настоящим вызовом консерваторам. PMI совершил смелый шаг: отказался от процессов в пользу принципов. Теперь неважно, работаете вы по водопаду или скраму — важны ценность, стейкхолдеры и управление неопределённостью. Этот шаг, возможно, спас стандарт от превращения в музейный экспонат. Именно в седьмой версии адаптивность окончательно легитимизировалась как вариант нормы.&lt;p&gt;Восьмая версия завершает этот путь: Agile-практики получили повышение&lt;strong&gt; &lt;/strong&gt;из приложения в ядро стандарта:&lt;ul&gt;&lt;li&gt;&lt;p&gt;daily scrum упоминается как инструмент управления вовлечением заинтересованных сторон и коммуникацией, даже если у вас не скрам. Более того, в предиктивных проектах он рассматривается как средство быстрой идентификации и устранения препятствий&lt;li&gt;&lt;p&gt;роль владельца продукта (Product Owner) формально закреплена как представителя заказчика — внутреннего или внешнего&lt;li&gt;&lt;p&gt;итеративное планирование признано официально — результаты спринта напрямую влияют на следующий план. Планирование и исполнение становятся постоянным диалогом: план обновляется после каждого спринта на основе реальной скорости команды (Velocity), превращая «Разработку расписания» (Develop Schedule) в живую активность&lt;li&gt;&lt;p&gt;agile release planning теперь официально включено в процесс «Разработка расписания» (Develop Schedule). И даже более: он рассматривается как основной инструмент для создания высокоуровневого графика — обычно на 3–6 месяцев — на основе дорожной карты продукта. У стейкхолдеров поэтому появляется понимание того, что и когда примерно будет доставлено, без детализации планов спринтов&lt;li&gt;&lt;p&gt;вместо жёсткого предписания ролей стандарт продвигает культуру доверия, совместной ответственности и автономии (empowered culture)&lt;/ul&gt;&lt;p&gt;PMBOK® Guide 8 — самое Agile-дружелюбное издание, но оно делегирует глубину другим продуктам PMI, например Agile Pracice Guide и &lt;a href=https://www.pmi.org/disciplined-agile/process/introduction-to-dad&gt;Disciplined Agile (DA)&lt;/a&gt;. Это разумный компромисс для универсального стандарта, но недостаток для ожидающих «всё в одном».&lt;p&gt;Для глубокого понимания Agile-практик, масштабирования Agile, восьмой версии может быть всё ещё недостаточно. Как отмечают эксперты, полная интеграция, вероятно, придётся на 9 издание — если PMI решит, что зрелость рынка требует большей конкретики.&lt;h2&gt;Гибрид как выбор большинства&lt;/h2&gt;&lt;p&gt;Если шестое издание предложило «гибридное перемирие», то восьмое делает следующий шаг — легитимизирует гибрид как основной режим работы.&lt;p&gt;PMI говорит что по результатам их исследований более 80% проектов сегодня идут по гибридным моделям. И здесь я вспоминаю &lt;a href=https://managedagile.com/topics/hybrid-agile-methodolology/&gt;слова Чака Кобба&lt;/a&gt; — эксперта, известного своим прагматичным подходом в управлении проектами: «Гибридный подход — это не попытка совместить несовместимое. Это осознанный выбор лучших практик для решения конкретной бизнес-задачи в конкретном контексте».&lt;p&gt;Именно это предлагает PMBOK® Guide 8. Он не требует от проектной методологии быть «чистым водопадом» или «чистым аджайлом». Он предлагает гибкий каркас, внутри которого можно комбинировать элементы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;на стратегическом уровне — предиктивные практики. Например, формальный устав, бюджетирование, этапы согласования&lt;li&gt;&lt;p&gt;на операционном уровне — адаптивные циклы. Это спринты, ретроспективы, итеративная поставка.&lt;/ul&gt;&lt;p&gt;В своей работе я часто смешивала практики из разных подходов, используя предиктивные методы на уровне программы и адаптивную работу на уровне команды. Применяла Метод Освоенного Объёма (Earned Value Analysis) для сведения сторипойнтов, долларов и дней, или рисовала Gantt-диаграммы для визуализации всех зависимостей важной фичи с жёстким дедлайном в масштабируемом Agile-проекте.&lt;p&gt;Я ориентировалась на рациональность и удобство инструмента. Но называть это гибридом я избегала — опасалась, что меня не поймут или сочтут, будто я плохо понимаю и Agile, и классическое управление. Казалось, что на проекте нужно выбирать «одну веру».&lt;p&gt;Сегодня такая ситуация стала нормой. PMBOK® Guide 8 легитимизирует этот подход, снимая необходимости смущённо прятать Gantt под Burn-down диаграммой. Гибрид стал осознанным выбором зрелого практика.&lt;h2&gt;Процессы, домены и ITTO – каркас для любого проекта&lt;/h2&gt;&lt;p&gt;Архитектура PMBOK® Guide 8 превращает гибрид из идеи в рабочий инструмент. И всё это довольно легко реализуется технически&lt;p&gt;&lt;strong&gt;Области фокусировки&lt;/strong&gt; (Focus Areas). Знакомые пять групп процессов — инициация, планирование, исполнение, мониторинг и контроль, завершение — вернулись под зонтиком «Области Фокусировки». Теперь они снова часть Руководства как универсальные категории деятельности, включённые во все подходы — и предиктивный, и адаптивный (Agile), и гибридный. Считаю, что это удобно, логично и естественно. Например, в рамках SAFe фреймворка они используются постоянно: мы планируем PI (планирование), контролируем поток работ (мониторинг), передаём функционал в поддержку (завершение).&lt;p&gt;&lt;strong&gt;Семь доменов эффективности&lt;/strong&gt; (Performance Domains) — Governance, Scope, Schedule, Finance, Stakeholders, Resources, Risks — сформированы из 10 областей знаний шестой версии и 8 доменов седьмой версии. Изменения варьируются от косметических до принципиальных.&lt;p&gt;&lt;strong&gt;40 гибких процессов&lt;/strong&gt;, выросшие из 49 процессов предыдущих версий, — внутри доменов. Возвращение процессов и ITTO — входы, инструменты, техники и выходы — после абстрактной седьмой версии приветствуется многими. «Делайте гибко» — отличный совет, но плохая инструкция. Без чёткого каркаса там, где нет зрелой культуры, качество управления упадёт.&lt;p&gt;&lt;strong&gt;Проверка на ценность&lt;/strong&gt; (Check Results) — новинка седьмой версии и приз моих личных симпатий, переехала в восьмую версию. Он включён в каждый домен и задаёт простой, но серьёзный вопрос: «Достигаем ли мы цели?». Это механизм рефлексии и прямая поддержка Agile-цикла inspect and adapt.&lt;p&gt;&lt;strong&gt;Адаптация под контекст&lt;/strong&gt; (Tailoring)&lt;strong&gt; &lt;/strong&gt;тоже включена в каждый домен. Кроме того, она стала более структурированной и к ней добавили конкретные примеры. Здесь есть подсказки, как сочетать элементы предиктивного подхода — например, для соблюдения нормативных требований — и Agile — для итеративной разработки. Её цель — помочь осознанно настраивать проектный подход под среду, возможности и цели.&lt;p&gt;&lt;strong&gt;Финансы (Finance) вместо Стоимости (Cost)&lt;/strong&gt;. Это переименование отображает новые акценты на реализацию ценности и стратегическое управление инвестициями. Менеджер проекта теперь должен следить за тем, какой возврат на инвестиции (ROI) получает организация. В рамках Finance теперь чаще обсуждается «динамическое бюджетирование». Вместо фиксации затрат на старте теперь поощряется подход, при котором финансирование может перераспределяться между релизами в зависимости от того, какая функциональность приносит больше ценности бизнесу.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2b5/118/ca1/2b5118ca178be9e7c050e599aabc678d.jpg alt=&#34;В стандарте представлена взаимосвязь между принципами управления проектами и доменами результативности. Источник: Руководство к PMBoK, стр. 4, раздел 1.2&#34; title=&#34;В стандарте представлена взаимосвязь между принципами управления проектами и доменами результативности. Источник: Руководство к PMBoK, стр. 4, раздел 1.2&#34; width=916 height=1061 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2b5/118/ca1/2b5118ca178be9e7c050e599aabc678d.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2b5/118/ca1/2b5118ca178be9e7c050e599aabc678d.jpg 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;В стандарте представлена взаимосвязь между принципами управления проектами и доменами результативности. Источник: &lt;a href=https://www.pmi.org/disciplined-agile/process/introduction-to-dad&gt;Руководство к PMBoK, стр. 4, раздел 1.2&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Однако не все изменения однозначно удачны.&lt;p&gt;Так, Качество (Quality) больше не отдельный домен, теперь это часть Объёма (Scope). В крупных системах качество часто является отдельной профессиональной дисциплиной, требующей выделенных команд и независимых проверок. Встраивание его в другой домен размывает зону ответственности и снижает приоритет. Без выделенного домена процессы обеспечения качества теряют структуру, их сложнее находить, планировать и применять системно.&lt;p&gt;Коммуникация тоже больше не отдельный домен, она стала частью домена Stakeholders. С одной стороны, это понятно и логично, ведь общение существует ради взаимодействия. Но, с другой стороны, очень легко забыть, что команда — тоже стейкхолдер. Её информационные потребности и схема коммуникации требуют анализа и осознанного проектирования. В реальной жизни команда часто воспринимается как данность, и эффективность коммуникации остаётся без внимания. Как результат, команда тонет во встречах, принимает это как досадную, но неизбежную часть производственного процесса и оправдывает невысокую результативность высокой активностью.&lt;p&gt;Закупки (Procurement)&lt;strong&gt; &lt;/strong&gt;тоже лишились отдельного домена и были вынесены в приложение. Часть активности по управлению контрактами и выбору поставщиков теперь в доменах Управление (Governance) и Финансы. Это может быть разумно, но в секторах с жёстким регулированием — особенно в госИТ — закупки часто определяют реализуемость проекта.&lt;h2&gt;Новые темы: ИИ, PMO, устойчивость&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Искусственный интеллект&lt;/strong&gt; впервые получил отдельное упоминание — стандарт отражает современный контекст. PMI рассматривает ИИ как инструмент:&lt;ul&gt;&lt;li&gt;&lt;p&gt;для прогнозирования рисков на основе исторических данных&lt;li&gt;&lt;p&gt;работы с расписанием&lt;li&gt;&lt;p&gt;уточнения оценок производительности&lt;li&gt;&lt;p&gt;автоматизации рутинных задач&lt;/ul&gt;&lt;p&gt;Но на мой взгляд, это скорее первый подход, чем полноценная стратегия. Почти отсутствует управление рисками, связанными с предвзятостью алгоритмов. Этика и безопасность применения ИИ не выделена в отдельный принцип. Я вижу в этом прагматизм: институт не хочет, чтобы стандарт устарел через полгода, и не выпускает правила для технологий, которые меняются ежемесячно.&lt;p&gt;Отсутствие готовых рецептов по внедрению нейросетей в управление проектами может разочаровать. Но стоит помнить: Стандарт описывает возможности, но не подменяет мышление. Там, где заканчиваются алгоритмы, решающую роль играют экспертиза и профессиональное суждение. Решение на проекте принимает человек, ответственность тоже несёт человек.&lt;p&gt;&lt;strong&gt;Project Management Office (PMO) &lt;/strong&gt;тоже проходит серьёзную трансформацию. От него больше не ждут роли «полиции процессов». Современный PMO — это центр компетенций и стратегический партнёр, который:&lt;ul&gt;&lt;li&gt;&lt;p&gt;поддерживает гибридные подходы&lt;li&gt;&lt;p&gt;обеспечивает обучение и фокусирующийся на ценности&lt;li&gt;&lt;p&gt;выстраивает и процессы, и мышление, и культуру&lt;li&gt;&lt;p&gt;гарантирует, что проект в портфеле напрямую работает на достижение долгосрочных целей организации, действуя отчасти как VMO (Value Management Office)&lt;li&gt;&lt;p&gt;берёт на себя внедрение AI-инструментов&lt;li&gt;&lt;p&gt;становится аналитическим хабом&lt;li&gt;&lt;p&gt;помогает выбрать наиболее подходящий подход, сохраняя системную целостность&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Устойчивое развитие (sustainability)&lt;/strong&gt; в фокусе. Это включает социальные, экологические и управленческие аспекты долгосрочной ценности и последствий проекта. Например, баланс между немедленной выгодой и долгосрочной устойчивостью организации, и даже оценка воздействия на климат и ресурсы.&lt;h2&gt;Что упущено: тишина о людях&lt;/h2&gt;&lt;p&gt;Несмотря на все сильные стороны,в восьмом издании исчезли конкретные модели управления изменениями, например ADKAR или модель Вирджинии Сатир, которые присутствовали в седьмой версии. Управление изменениями остаётся в доменах Управление (Governance) и Stakeholders, но без практических инструментов.&lt;p&gt;Я считаю это упущением. Любая трансформация — это, прежде всего, изменение культуры, поведения и привычек людей. В условиях постоянной эволюции платформ и процессов явное внимание к управлению изменениями с деталями и рекомендациями было бы крайне полезным. Этот пробел будет особенно ощутим для организаций, которые планируют трансформацию или находятся в начале её активной фазы.&lt;h2&gt;Заключение: синтез зрелости&lt;/h2&gt;&lt;p&gt;PMBOK® Guide 8 — удачный синтез лучших элементов прошлых версий. Детальные процессы шестого издания и гибкие принципы седьмого объединились в практическое руководство для современных реалий. Высокие идеи «доставляй ценность» теперь подкреплены конкретными практиками: «как планировать, когда всё меняется».&lt;p&gt;Прочитать стандарт, выучить правильную последовательность процессов и их ITTO и подгонять под неё проект недостаточно. Современный руководитель проектов должен владеть широким спектром подходов, понимать их применимость, сочетаемость, влияние на связанные процессы, и уметь выбирать именно то, что добавляет реальную ценность в его контексте.&lt;p&gt;Иронично, что мы так делали и раньше, но теперь такой подход легализован. Он умеет выстраивать диалог с разными стейкхолдерами, чтобы сформировать консенсус: действительно ли результат стоит усилий. Он становится архитектором подходов, он сочетает стратегическое видение с операционной гибкостью. Именно за это восьмую редакцию называют «стандартом для взрослых» — здесь мало послушно следовать написанному, здесь нужно иметь профессиональное суждение и ответственность.&lt;p&gt;Таким образом, PMBOK® Guide 8 окончательно закрепляет переход от эпохи предиктивного доминирования к эпохе гибридной зрелости, где методология служит цели. На мой взгляд, получилось достойное сочетание дисциплины, гибкости и здравого смысла.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/rtlabs/articles/1051374/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051374</guid>
      <pubDate>Wed, 24 Jun 2026 15:03:42 +0000</pubDate>
    </item>
    <item>
      <title>[Перевод] Unit of Work в Go: практический гайд по транзакциям между репозиториями</title>
      <link>https://habr.com/ru/companies/otus/articles/1049234/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1049234</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Эта статья выросла из пары быстрых ответов на вопросы на Reddit в ветке &lt;code&gt;r/golang&lt;/code&gt;. Первый был о том, стоит ли делать слой репозиториев поверх &lt;code&gt;sqlc&lt;/code&gt;. Второй — о том, как работать с транзакциями, когда интерфейс скрывает детали хранилища. Оба ответа превратились в небольшие статьи. Здесь я собираю их вместе и разбираю, что делать, когда транзакции должны охватывать несколько репозиториев.&lt;p&gt;Разберём три этапа, каждый следующий опирается на предыдущий:&lt;ol&gt;&lt;li&gt;&lt;p&gt;поставить интерфейс репозитория между сервисной логикой и слоем хранения;&lt;li&gt;&lt;p&gt;добавить поддержку транзакций в один репозиторий, не протаскивая SQL в сервис;&lt;li&gt;&lt;p&gt;координировать транзакции между несколькими репозиториями через &lt;code&gt;Unit of Work&lt;/code&gt;.&lt;/ol&gt;&lt;p&gt;Во всех примерах используется SQLite. Рабочие примеры для варианта с &lt;a href=https://github.com/rednafi/examples/tree/main/repository-transactions&gt;одним хранилищем&lt;/a&gt; и для варианта с &lt;a href=https://github.com/rednafi/examples/tree/main/cross-repository-transactions&gt;несколькими хранилищами&lt;/a&gt; есть на GitHub.&lt;h2&gt;Что из себя представляет паттерн Репозиторий?&lt;/h2&gt;&lt;p&gt;Мартин Фаулер в своей книге «Шаблоны архитектуры корпоративных приложений» определял паттерн «Репозиторий» так:&lt;blockquote&gt;&lt;p&gt;«Репозиторий» выступает посредником между доменным слоем и слоем маппинга данных, предоставляя похожий на коллекцию интерфейс для доступа к доменным объектам.&lt;/blockquote&gt;&lt;p&gt;В &lt;a href=https://otus.pw/CLkQ/&gt;Go&lt;/a&gt; репозиторий — это просто интерфейс. Сервис зависит от интерфейса, конкретный пакет его реализует, и живут они в разных пакетах. Сервис описывает, что ему нужно, а хранилище это предоставляет. Принцип инверсии зависимостей в действии.&lt;p&gt;Чтобы понять, зачем это нужно, посмотрим, что происходит без репозитория.&lt;h2&gt;Что происходит без репозитория&lt;/h2&gt;&lt;p&gt;Допустим, вы пишете сервис книжного магазина с &lt;code&gt;sqlc&lt;/code&gt;. Сгенерированный код даёт структуру &lt;code&gt;Queries&lt;/code&gt; с методами вроде &lt;code&gt;GetBook&lt;/code&gt; и &lt;code&gt;CreateBook&lt;/code&gt;. Самый соблазнительный вариант — внедрить её прямо в сервис:&lt;pre&gt;&lt;code class=go&gt;type Service struct {&#xA;   q *db.Queries&#xA;}&#xA;&#xA;func (s *Service) RegisterBook(&#xA;   ctx context.Context, title string) (db.Book, error) {&#xA;   return s.q.CreateBook(ctx, title)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Такой код компилируется и работает, но сервис теперь намертво привязан к сгенерированным типам &lt;code&gt;sqlc&lt;/code&gt;. Каждый метод сервиса импортирует пакет &lt;code&gt;db&lt;/code&gt;. Если вы захотите протестировать &lt;code&gt;RegisterBook&lt;/code&gt; без базы данных, придётся мокать весь &lt;code&gt;Queries&lt;/code&gt; или поднимать тестовую базу данных. Если позже вы перейдёте с &lt;code&gt;sqlc&lt;/code&gt; на raw SQL или с Postgres на DynamoDB, переписывать придётся и сервисный слой.&lt;p&gt;Сервис должен описывать, что ему нужно от хранилища, не зная, как именно хранилище это делает. «Дай мне книгу по &lt;code&gt;ID&lt;/code&gt;» и «создай эту книгу» — это что. SQL-запросы, пулы соединений и схемы таблиц — это как. Небольшой интерфейс решает эту проблему.&lt;p&gt;Добавляем интерфейс репозитория&lt;p&gt;Интерфейс живёт в пакете &lt;code&gt;book&lt;/code&gt; рядом с доменными типами. Это пакет с бизнес-логикой. В нём нет импортов из &lt;code&gt;database/sql&lt;/code&gt; или какой-либо библиотеки для работы с хранилищем:&lt;pre&gt;&lt;code class=go&gt;// book/book.go&#xA;&#xA;type Book struct {&#xA;   ID    int64&#xA;   Title string&#xA;}&#xA;&#xA;type Store interface {&#xA;   Get(ctx context.Context, id int64) (Book, error)&#xA;   Create(ctx context.Context, b Book) (int64, error)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Два метода. &lt;code&gt;Get&lt;/code&gt; получает книгу по &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;Create&lt;/code&gt; сохраняет новую книгу и возвращает сгенерированный &lt;code&gt;ID&lt;/code&gt;. Интерфейс ничего не говорит про &lt;code&gt;SQL&lt;/code&gt;, таблицы или пулы соединений. Его может реализовать любой бэкенд хранения, который умеет получать и создавать книги.&lt;p&gt;Сервис зависит только от &lt;code&gt;Store&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// book/service.go&#xA;&#xA;type Service struct {&#xA;   store Store&#xA;}&#xA;&#xA;func NewService(s Store) *Service {&#xA;   return &amp;amp;Service{store: s}&#xA;}&#xA;&#xA;func (s *Service) RegisterBook(&#xA;   ctx context.Context, title string) (Book, error) {&#xA;&#xA;   b := Book{Title: title}&#xA;   id, err := s.store.Create(ctx, b)&#xA;   if err != nil {&#xA;       return Book{}, err&#xA;   }&#xA;   b.ID = id&#xA;   return b, nil&#xA;}&#xA;&#xA;func (s *Service) GetBook(&#xA;   ctx context.Context, id int64) (Book, error) {&#xA;   return s.store.Get(ctx, id)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;RegisterBook&lt;/code&gt; создаёт &lt;code&gt;Book&lt;/code&gt;, просит хранилище сохранить её и получает &lt;code&gt;ID&lt;/code&gt; обратно. Он не импортирует ничего из &lt;code&gt;database/sql&lt;/code&gt;. У пакета &lt;code&gt;book&lt;/code&gt; нет зависимостей от слоя хранения.&lt;p&gt;Теперь нужно что-то, что действительно ходит в базу данных.&lt;h2&gt;Реализация для SQLite&lt;/h2&gt;&lt;p&gt;Отдельный пакет &lt;code&gt;sqlite&lt;/code&gt; реализует интерфейс &lt;code&gt;Store&lt;/code&gt;. Здесь я пишу запросы вручную, чтобы не тащить всю обвязку &lt;code&gt;sqlc&lt;/code&gt;, но структура была бы той же. &lt;code&gt;sqlc&lt;/code&gt; просто сгенерировал бы методы запросов за вас.&lt;p&gt;Перед тем как писать методы хранилища, нужно подготовить одну вещь. &lt;code&gt;sqlc&lt;/code&gt; генерирует интерфейс &lt;code&gt;DBTX&lt;/code&gt;, которому удовлетворяют и &lt;code&gt;&lt;em&gt;sql.DB&lt;/em&gt;&lt;/code&gt;&lt;em&gt;, и &lt;/em&gt;&lt;code&gt;sql.Tx&lt;/code&gt;. &lt;code&gt;&lt;em&gt;sql.DB&lt;/em&gt;&lt;/code&gt;&lt;em&gt; — это пул соединений, &lt;/em&gt;&lt;code&gt;sql.Tx&lt;/code&gt; — транзакция:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store.go&#xA;&#xA;type DBTX interface {&#xA;   ExecContext(&#xA;       ctx context.Context,&#xA;       query string, args ...any) (sql.Result, error)&#xA;   QueryRowContext(&#xA;       ctx context.Context,&#xA;       query string, args ...any) *sql.Row&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Почему это важно? Потому что и у &lt;code&gt;&lt;em&gt;sql.DB&lt;/em&gt;&lt;/code&gt;&lt;em&gt;, и у &lt;/em&gt;&lt;code&gt;sql.Tx&lt;/code&gt; есть эти два метода. Любой код, написанный поверх &lt;code&gt;DBTX&lt;/code&gt;, работает с обоими вариантами. Для базового репозитория это пока не нужно, но позже, когда мы добавим транзакции, это станет важным.&lt;p&gt;Структура хранилища держит &lt;code&gt;DBTX&lt;/code&gt;, а не &lt;code&gt;&lt;em&gt;sql.DB&lt;/em&gt;&lt;/code&gt;&lt;em&gt;. Если бы хранилище напрямую держало &lt;/em&gt;&lt;code&gt;sql.DB&lt;/code&gt;, позже мы не смогли бы создать хранилище, работающее поверх транзакции. &lt;code&gt;DBTX&lt;/code&gt; оставляет эту возможность открытой:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store.go&#xA;&#xA;type BookStore struct{ db DBTX }&#xA;&#xA;func NewBookStore(db DBTX) *BookStore { return &amp;amp;BookStore{db: db} }&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Методы запросов вызывают &lt;code&gt;s.db.ExecContext&lt;/code&gt; и &lt;code&gt;s.db.QueryRowContext&lt;/code&gt;. Сейчас эти вызовы проходят через пул соединений &lt;code&gt;*sql.DB&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store.go&#xA;&#xA;func (s *BookStore) Get(&#xA;   ctx context.Context, id int64) (book.Book, error) {&#xA;   row := s.db.QueryRowContext(ctx,&#xA;       &amp;#34;SELECT id, title FROM books WHERE id = ?&amp;#34;, id)&#xA;   var b book.Book&#xA;   err := row.Scan(&amp;amp;b.ID, &amp;amp;b.Title)&#xA;   return b, err&#xA;}&#xA;&#xA;func (s *BookStore) Create(&#xA;   ctx context.Context, b book.Book) (int64, error) {&#xA;   res, err := s.db.ExecContext(ctx,&#xA;       &amp;#34;INSERT INTO books (title) VALUES (?)&amp;#34;, b.Title)&#xA;   if err != nil {&#xA;       return 0, err&#xA;   }&#xA;   return res.LastInsertId()&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Позже, когда мы добавим транзакции, &lt;code&gt;s.db&lt;/code&gt; будет не &lt;code&gt;&lt;em&gt;sql.DB&lt;/em&gt;&lt;/code&gt;&lt;em&gt;, а &lt;/em&gt;&lt;code&gt;sql.Tx&lt;/code&gt;, и те же самые методы начнут выполняться внутри транзакции без единого изменения в коде. В этом и есть выигрыш от &lt;code&gt;DBTX&lt;/code&gt;.&lt;p&gt;Связать всё при старте — по одной строке на зависимость:&lt;pre&gt;&lt;code class=go&gt;// cmd/main.go&#xA;&#xA;store := sqlite.NewBookStore(db)&#xA;svc := book.NewService(store)&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Сервис получает &lt;code&gt;Store&lt;/code&gt;, то есть интерфейс. Пакет &lt;code&gt;sqlite&lt;/code&gt; получает &lt;code&gt;*sql.DB&lt;/code&gt;, который удовлетворяет &lt;code&gt;DBTX&lt;/code&gt;. Ни один из этих пакетов не импортирует другой.&lt;p&gt;Тестируем без базы данных&lt;p&gt;Раз сервис зависит от интерфейса, его можно тестировать без базы данных — достаточно написать &lt;code&gt;in-memory fake&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// book/service_test.go&#xA;&#xA;var _ Store = (*memStore)(nil)&#xA;&#xA;type memStore struct {&#xA;   mu   sync.Mutex&#xA;   books map[int64]Book&#xA;   next int64&#xA;}&#xA;&#xA;func (m *memStore) Get(&#xA;   ctx context.Context, id int64) (Book, error) {&#xA;&#xA;   m.mu.Lock()&#xA;   defer m.mu.Unlock()&#xA;   b, ok := m.books[id]&#xA;   if !ok {&#xA;       return Book{}, fmt.Errorf(&amp;#34;book %d not found&amp;#34;, id)&#xA;   }&#xA;   return b, nil&#xA;}&#xA;&#xA;func (m *memStore) Create(&#xA;   ctx context.Context, b Book) (int64, error) {&#xA;&#xA;   m.mu.Lock()&#xA;   defer m.mu.Unlock()&#xA;   m.next++&#xA;   b.ID = m.next&#xA;   m.books[b.ID] = b&#xA;   return b.ID, nil&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Строка &lt;code&gt;var _ Store = (*memStore)(nil)&lt;/code&gt; — это проверка соответствия интерфейсу на этапе компиляции. Если &lt;code&gt;memStore&lt;/code&gt; когда-нибудь перестанет удовлетворять &lt;code&gt;Store&lt;/code&gt;, сборка упадёт.&lt;p&gt;Тест выглядит почти как production-код, только без базы:&lt;pre&gt;&lt;code class=go&gt;// book/service_test.go&#xA;&#xA;func TestRegisterBook(t *testing.T) {&#xA;   store := &amp;amp;memStore{books: make(map[int64]Book)}&#xA;   svc := NewService(store)&#xA;&#xA;   b, err := svc.RegisterBook(t.Context(), &amp;#34;DDIA&amp;#34;)&#xA;   if err != nil {&#xA;       t.Fatal(err)&#xA;   }&#xA;   if b.ID == 0 {&#xA;       t.Fatal(&amp;#34;expected non-zero ID&amp;#34;)&#xA;   }&#xA;   if b.Title != &amp;#34;DDIA&amp;#34; {&#xA;       t.Fatalf(&amp;#34;got title %q, want DDIA&amp;#34;, b.Title)&#xA;   }&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Он выполняется за микросекунды и гоняет тот же код &lt;code&gt;RegisterBook&lt;/code&gt;, который работает в проде. Если завтра слой хранения переедет с &lt;code&gt;SQLite&lt;/code&gt; на &lt;code&gt;Postgres&lt;/code&gt;, этот тест останется прежним, потому что зависит только от интерфейса.&lt;p&gt;Интеграционные тесты с настоящей базой всё равно нужны — скоро до них дойдём. Но основную часть сервисной логики можно тестировать на fake-реализациях.&lt;p&gt;Пока у нас есть чистое разделение: сервис говорит с интерфейсом, пакет &lt;code&gt;sqlite&lt;/code&gt; его реализует, тесты используют &lt;code&gt;in-memory fake&lt;/code&gt;. Но каждый метод интерфейса выполняется отдельно. Если &lt;code&gt;RegisterBook&lt;/code&gt; должен сделать две записи, которые обязаны либо обе успешно завершиться, либо обе откатиться, появляется проблема.&lt;h3&gt;Добавляем транзакции в один репозиторий&lt;/h3&gt;&lt;p&gt;Допустим, бизнес-требования изменились. Теперь при регистрации книги нужно ещё писать запись в &lt;code&gt;audit log&lt;/code&gt;: кто её создал и когда. Обе записи должны быть атомарными: если вставка книги прошла успешно, но &lt;code&gt;audit log&lt;/code&gt; записать не удалось, нам не нужна книга в базе без следа в аудите. Значит, нужна транзакция.&lt;p&gt;Именно об этом &lt;a href=https://www.reddit.com/r/golang/comments/1rv65k9/comment/obdrohe/&gt;спрашивал&lt;/a&gt; xinoiP на Reddit:&lt;br&gt;&lt;em&gt;Как бы вы обрабатывали транзакции при таком подходе? Ведь они очень завязаны на SQL.&lt;/em&gt;&lt;p&gt;Чтобы поддержать новое требование, в интерфейс &lt;code&gt;Store&lt;/code&gt; нужно добавить две вещи. Во-первых, тип &lt;code&gt;AuditEntry&lt;/code&gt; и метод &lt;code&gt;CreateAuditLog&lt;/code&gt; для записей аудита. Во-вторых, метод &lt;code&gt;Tx&lt;/code&gt;, который позволяет сервису сгруппировать несколько операций в одну транзакцию:&lt;pre&gt;&lt;code class=go&gt;// book/book.go&#xA;&#xA;type AuditEntry struct {&#xA;   BookID int64&#xA;   Action string&#xA;}&#xA;&#xA;type Store interface {&#xA;   Get(ctx context.Context, id int64) (Book, error)&#xA;   Create(ctx context.Context, b Book) (int64, error)&#xA;   CreateAuditLog(ctx context.Context, e AuditEntry) error&#xA;&#xA;   // Tx выполняет fn внутри транзакции. Store, переданный&#xA;   // в fn, работает поверх этой транзакции.&#xA;   Tx(ctx context.Context, fn func(Store) error) error&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;CreateAuditLog&lt;/code&gt; — обычный метод доступа к данным, такой же как &lt;code&gt;Get&lt;/code&gt; и &lt;code&gt;Create&lt;/code&gt;. Интереснее здесь &lt;code&gt;Tx&lt;/code&gt;. Он принимает callback-функцию, которая получает &lt;code&gt;Store&lt;/code&gt;. Этот &lt;code&gt;Store&lt;/code&gt; работает поверх транзакции базы данных, поэтому каждый вызванный на нём метод выполняется внутри этой транзакции. Идея похожа на передачу состояния под локом в замыкание. Вызывающий код не управляет жизненным циклом транзакции: никаких ручных &lt;code&gt;begin&lt;/code&gt;/&lt;code&gt;commit&lt;/code&gt;/&lt;code&gt;rollback&lt;/code&gt;, как и никаких ручных &lt;code&gt;lock&lt;/code&gt;/&lt;code&gt;unlock&lt;/code&gt;. Он просто работает с тем, что получил в callback.&lt;p&gt;Вот как работает реализация &lt;code&gt;Tx&lt;/code&gt; для &lt;code&gt;SQLite&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store.go&#xA;&#xA;func (s *BookStore) Tx(&#xA;   ctx context.Context,&#xA;   fn func(book.Store) error) error {&#xA;&#xA;   sqlDB, ok := s.db.(*sql.DB)&#xA;   if !ok {&#xA;       return errors.New(&#xA;           &amp;#34;cannot start tx: already inside a transaction&amp;#34;)&#xA;   }&#xA;&#xA;   tx, err := sqlDB.BeginTx(ctx, nil)&#xA;   if err != nil {&#xA;       return err&#xA;   }&#xA;   defer tx.Rollback() // после Commit ничего не делает&#xA;&#xA;   // Создаём новый BookStore поверх tx.&#xA;   if err := fn(NewBookStore(tx)); err != nil {&#xA;       return err&#xA;   }&#xA;   return tx.Commit()&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Проверка типа &lt;code&gt;s.db.(*sql.DB)&lt;/code&gt; убеждается, что под капотом у нас пул соединений, а не уже существующая транзакция. В &lt;code&gt;database/sql&lt;/code&gt; нельзя вложить &lt;code&gt;sql.Tx&lt;/code&gt; внутрь &lt;code&gt;sql.Tx&lt;/code&gt;. После запуска транзакции через &lt;code&gt;BeginTx&lt;/code&gt; мы создаём свежий &lt;code&gt;BookStore&lt;/code&gt;, у которого в поле &lt;code&gt;db&lt;/code&gt; лежит &lt;code&gt;&lt;em&gt;sql.Tx&lt;/em&gt;&lt;/code&gt;&lt;em&gt;. Вот здесь и окупается подготовка с &lt;/em&gt;&lt;code&gt;&lt;em&gt;DBTX&lt;/em&gt;&lt;/code&gt;&lt;em&gt;: &lt;/em&gt;&lt;code&gt;sql.Tx&lt;/code&gt; удовлетворяет &lt;code&gt;DBTX&lt;/code&gt;, поэтому новое хранилище работает с теми же самыми методами &lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;Create&lt;/code&gt; и &lt;code&gt;CreateAuditLog&lt;/code&gt;. Колбэк получает это транзакционное хранилище, и каждый запрос внутри колбэка проходит через транзакцию. Если колбэк возвращает ошибку, мы делаем &lt;code&gt;rollback&lt;/code&gt;. Если нет — &lt;code&gt;commit&lt;/code&gt;.&lt;p&gt;Вызывающий код ни разу не трогает &lt;code&gt;sql.Tx&lt;/code&gt;.&lt;h3&gt;Используем Tx в RegisterBook&lt;/h3&gt;&lt;p&gt;Когда в интерфейсе появился &lt;code&gt;Tx&lt;/code&gt;, &lt;code&gt;RegisterBook&lt;/code&gt; может атомарно создать книгу и запись в &lt;code&gt;audit log&lt;/code&gt;. Он вызывает &lt;code&gt;s.store.Tx&lt;/code&gt;, и всё внутри колбэка проходит через транзакционное хранилище:&lt;pre&gt;&lt;code class=go&gt;// book/service.go&#xA;&#xA;func (s *Service) RegisterBook(&#xA;   ctx context.Context, title string) (Book, error) {&#xA;&#xA;   var book Book&#xA;&#xA;   err := s.store.Tx(ctx, func(tx Store) error {&#xA;       id, err := tx.Create(ctx, Book{Title: title})&#xA;       if err != nil {&#xA;           return err&#xA;       }&#xA;       book = Book{ID: id, Title: title}&#xA;       return tx.CreateAuditLog(ctx,&#xA;           AuditEntry{BookID: id, Action: &amp;#34;created&amp;#34;})&#xA;   })&#xA;&#xA;   return book, err&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;И &lt;code&gt;tx.Create&lt;/code&gt;, и &lt;code&gt;tx.CreateAuditLog&lt;/code&gt; выполняются в одном и том же &lt;code&gt;sql.Tx&lt;/code&gt;. Если любой из вызовов падает, колбэк возвращает ошибку, а &lt;code&gt;Tx&lt;/code&gt; откатывает обе записи. Если оба проходят успешно, &lt;code&gt;Tx&lt;/code&gt; коммитит их вместе. &lt;code&gt;RegisterBook&lt;/code&gt; не видит ни &lt;code&gt;sql.Tx&lt;/code&gt;, ни &lt;code&gt;*sql.DB&lt;/code&gt;, ни чего-либо ещё из &lt;code&gt;database/sql&lt;/code&gt;.&lt;h3&gt;Тестируем транзакции в одном хранилище&lt;/h3&gt;&lt;p&gt;Теперь in-memory-хранилищу тоже нужен метод &lt;code&gt;Tx&lt;/code&gt;. Поскольку настоящей базы здесь нет, он просто вызывает функцию напрямую, передавая в неё себя:&lt;pre&gt;&lt;code class=go&gt;// book/service_test.go&#xA;&#xA;func (m *memStore) Tx(&#xA;   ctx context.Context, fn func(Store) error) error {&#xA;   return fn(m)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Этого достаточно, чтобы тестировать сервисную логику: вызывает ли &lt;code&gt;RegisterBook&lt;/code&gt; и &lt;code&gt;Create&lt;/code&gt;, и &lt;code&gt;CreateAuditLog&lt;/code&gt;, а также правильно ли он обрабатывает ошибки.&lt;p&gt;Для интеграционных тестов, которые проверяют реальное поведение &lt;code&gt;commit&lt;/code&gt;/&lt;code&gt;rollback&lt;/code&gt; на уровне базы, используйте настоящую БД:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store_test.go&#xA;&#xA;func TestTx_RollsBackOnError(t *testing.T) {&#xA;   db := setupTestDB(t)&#xA;&#xA;   base := NewBookStore(db)&#xA;   failing := &amp;amp;failingStore{BookStore: base}&#xA;&#xA;   svc := book.NewService(failing)&#xA;&#xA;   _, err := svc.RegisterBook(t.Context(), &amp;#34;DDIA&amp;#34;)&#xA;   if err == nil {&#xA;       t.Fatal(&amp;#34;expected error&amp;#34;)&#xA;   }&#xA;&#xA;   var count int&#xA;   err = db.QueryRow(&amp;#34;SELECT COUNT(*) FROM books&amp;#34;).Scan(&amp;amp;count)&#xA;   if err != nil {&#xA;       t.Fatal(err)&#xA;   }&#xA;   if count != 0 {&#xA;       t.Fatalf(&amp;#34;expected 0 books after rollback, got %d&amp;#34;, count)&#xA;   }&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;failingStore&lt;/code&gt; встраивает настоящий &lt;code&gt;SQLite&lt;/code&gt; &lt;code&gt;BookStore&lt;/code&gt;, но переопределяет &lt;code&gt;CreateAuditLog&lt;/code&gt; так, чтобы он всегда возвращал ошибку. Последовательность такая: &lt;code&gt;Tx&lt;/code&gt; открывает транзакцию, &lt;code&gt;Create&lt;/code&gt; вставляет книгу внутри этой транзакции, &lt;code&gt;CreateAuditLog&lt;/code&gt; падает, &lt;code&gt;Tx&lt;/code&gt; делает &lt;code&gt;rollback&lt;/code&gt;, и таблица &lt;code&gt;books&lt;/code&gt; остаётся пустой.&lt;p&gt;Юнит-тесты с fake-реализациями быстро покрывают сервисную логику. Интеграционные тесты с настоящей базой проверяют транзакционное поведение. Благодаря интерфейсу оба варианта работают с одним и тем же сервисным кодом.&lt;h3&gt;Почему не передавать транзакцию через context?&lt;/h3&gt;&lt;p&gt;Изначально &lt;code&gt;xinoiP&lt;/code&gt; предлагал положить &lt;code&gt;*sql.Tx&lt;/code&gt; в &lt;code&gt;context&lt;/code&gt; и заставить хранилище проверять, есть ли она там:&lt;pre&gt;&lt;code class=go&gt;// Не делайте так.&#xA;func (s *BookStore) Create(ctx context.Context, b Book) (int64, error) {&#xA;   var executor DBTX&#xA;   if tx, ok := TxFromContext(ctx); ok {&#xA;       executor = tx&#xA;   } else {&#xA;       executor = s.db&#xA;   }&#xA;   // ...&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Такой вариант работает, но перед вызовом хранилища сервису пришлось бы сделать что-то вроде &lt;code&gt;ctx = WithTx(ctx, tx)&lt;/code&gt;. А значит, сервис знает о существовании &lt;code&gt;SQL&lt;/code&gt;-транзакции. Это ровно та связность, от которой интерфейс должен был защищать.&lt;p&gt;Есть и другая проблема. Значения в &lt;code&gt;context&lt;/code&gt; не типизированы статически и не видны явно. Если кто-то забудет положить транзакцию в &lt;code&gt;context&lt;/code&gt; или положит её не в тот &lt;code&gt;context&lt;/code&gt;, хранилище молча перейдёт на пул соединений, и операции уже не будут атомарными. В подходе с колбэком транзакционное хранилище передаётся как аргумент функции. Это не поймает все ошибки — можно всё ещё случайно вызвать &lt;code&gt;s.store&lt;/code&gt; вместо &lt;code&gt;tx&lt;/code&gt; для одной из нескольких операций, — но промахнуться так сложнее, чем с невидимым значением в &lt;code&gt;context&lt;/code&gt;.&lt;p&gt;С колбэком сервис говорит: «выполни эти операции атомарно», а хранилище само решает как. Поменяйте завтра &lt;code&gt;Postgres&lt;/code&gt; на &lt;code&gt;DynamoDB&lt;/code&gt; — сервисный код не изменится.&lt;h3&gt;Транзакции между несколькими репозиториями&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Tx&lt;/code&gt; на уровне отдельного хранилища из предыдущих разделов работает, когда все записи идут через один и тот же &lt;code&gt;Store&lt;/code&gt;. И &lt;code&gt;Create&lt;/code&gt;, и &lt;code&gt;CreateAuditLog&lt;/code&gt; находятся в &lt;code&gt;Store&lt;/code&gt;, поэтому метод &lt;code&gt;Tx&lt;/code&gt; одного хранилища может обернуть их в одну транзакцию.&lt;p&gt;Но доменная модель растёт. Допустим, книжный магазин теперь учитывает остатки и обрабатывает заказы. У книг появляется поле &lt;code&gt;Stock&lt;/code&gt;, добавляется новый тип &lt;code&gt;Order&lt;/code&gt; и новый интерфейс &lt;code&gt;Store&lt;/code&gt; для запросов, связанных с заказами. У каждого хранилища всё ещё есть свой &lt;code&gt;Tx&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// book/book.go&#xA;&#xA;type Store interface {&#xA;   Get(ctx context.Context, id int64) (Book, error)&#xA;   Create(ctx context.Context, b Book) (int64, error)&#xA;   CreateAuditLog(ctx context.Context, e AuditEntry) error&#xA;   DecrementStock(ctx context.Context, id int64) error&#xA;&#xA;   Tx(ctx context.Context, fn func(Store) error) error&#xA;}&#xA;&#xA;// order/order.go&#xA;&#xA;type Store interface {&#xA;   Create(ctx context.Context, o Order) (int64, error)&#xA;   Get(ctx context.Context, id int64) (Order, error)&#xA;&#xA;   Tx(ctx context.Context, fn func(Store) error) error&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;DecrementStock&lt;/code&gt; уменьшает остаток книги на единицу. В checkout-флоу нужно вызвать &lt;code&gt;DecrementStock&lt;/code&gt; у &lt;code&gt;book.Store&lt;/code&gt; и &lt;code&gt;Create&lt;/code&gt; у &lt;code&gt;order.Store&lt;/code&gt;, причём обе операции должны либо закоммититься вместе, либо вместе откатиться. Если остаток уменьшился, а вставка заказа упала, вы потеряли единицу товара без соответствующего заказа.&lt;p&gt;Можно попробовать вложить колбэки:&lt;pre&gt;&lt;code class=go&gt;// Так не сработает.&#xA;err := s.books.Tx(ctx, func(txBooks book.Store) error {&#xA;   if err := txBooks.DecrementStock(ctx, bookID); err != nil {&#xA;       return err&#xA;   }&#xA;   return s.orders.Tx(ctx, func(txOrders order.Store) error {&#xA;       _, err := txOrders.Create(ctx, order.Order{BookID: bookID})&#xA;       return err&#xA;   })&#xA;})&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Это скомпилируется, но &lt;code&gt;books.Tx&lt;/code&gt; откроет один &lt;code&gt;sql.Tx&lt;/code&gt; для хранилища книг, а &lt;code&gt;orders.Tx&lt;/code&gt; — второй, независимый &lt;code&gt;sql.Tx&lt;/code&gt; для хранилища заказов. Если вставка заказа упадёт, транзакция заказов откатится, но уменьшение остатка уже будет закоммичено в первой транзакции.&lt;p&gt;Каждое хранилище умеет создать только транзакционную копию самого себя. Нужен кто-то, кто сможет построить все хранилища из одного &lt;code&gt;sql.Tx&lt;/code&gt;.&lt;h3&gt;Unit of Work&lt;/h3&gt;&lt;p&gt;Нам нужен координатор, который открывает одну транзакцию в базе и строит из неё все хранилища. Мартин Фаулер называл этот паттерн Unit of Work:&lt;p&gt;Unit of Work отслеживает всё, что вы делаете во время бизнес-транзакции и что может повлиять на базу данных. Когда вы заканчиваете, он определяет, что нужно изменить в базе по итогам этой работы.&lt;p&gt;В исходной формулировке Фаулера Unit of Work отслеживает изменённые объекты в памяти и сбрасывает их в базу одной транзакцией. &lt;code&gt;ORM&lt;/code&gt; вроде &lt;code&gt;Hibernate&lt;/code&gt; реализуют паттерн именно так. В &lt;code&gt;Go&lt;/code&gt; нам не нужно отслеживать объекты: наши хранилища уже знают, как писать в базу. Достаточно открыть один &lt;code&gt;sql.Tx&lt;/code&gt;, построить из него все хранилища и передать их в колбэк.&lt;p&gt;Раз управление транзакциями теперь принадлежит &lt;code&gt;Unit of Work&lt;/code&gt;, можно убрать &lt;code&gt;Tx&lt;/code&gt; из обоих интерфейсов хранилищ. Хранилища снова становятся чистым слоем доступа к данным:&lt;pre&gt;&lt;code class=go&gt;// book/book.go&#xA;&#xA;type Store interface {&#xA;   Get(ctx context.Context, id int64) (Book, error)&#xA;   Create(ctx context.Context, b Book) (int64, error)&#xA;   CreateAuditLog(ctx context.Context, e AuditEntry) error&#xA;   DecrementStock(ctx context.Context, id int64) error&#xA;}&#xA;&#xA;// order/order.go&#xA;&#xA;type Store interface {&#xA;   Create(ctx context.Context, o Order) (int64, error)&#xA;   Get(ctx context.Context, id int64) (Order, error)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Структура &lt;code&gt;Stores&lt;/code&gt; группирует все репозитории, а интерфейс &lt;code&gt;UnitOfWork&lt;/code&gt; даёт единственный метод &lt;code&gt;RunInTx&lt;/code&gt;, который заменяет &lt;code&gt;Tx&lt;/code&gt; на уровне отдельных хранилищ:&lt;pre&gt;&lt;code class=go&gt;// checkout/checkout.go&#xA;&#xA;type Stores struct {&#xA;   Books  book.Store&#xA;   Orders order.Store&#xA;}&#xA;&#xA;type UnitOfWork interface {&#xA;   // RunInTx выполняет fn внутри одной транзакции. Каждое хранилище&#xA;   // в значении Stores работает поверх этой транзакции.&#xA;   RunInTx(ctx context.Context, fn func(Stores) error) error&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Stores&lt;/code&gt; — обычная структура с теми же интерфейсами, от которых уже зависит сервис. По мере роста домена в неё добавляются новые поля.&lt;p&gt;Реализация для &lt;code&gt;SQLite&lt;/code&gt; открывает одну транзакцию и строит из неё оба хранилища:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store.go&#xA;&#xA;type UoW struct{ db *sql.DB }&#xA;&#xA;func NewUoW(db *sql.DB) *UoW { return &amp;amp;UoW{db: db} }&#xA;&#xA;func (u *UoW) RunInTx(&#xA;   ctx context.Context,&#xA;   fn func(checkout.Stores) error) error {&#xA;&#xA;   tx, err := u.db.BeginTx(ctx, nil)&#xA;   if err != nil {&#xA;       return err&#xA;   }&#xA;   defer tx.Rollback() // после Commit ничего не делает&#xA;&#xA;   stores := checkout.Stores{&#xA;       Books:  NewBookStore(tx),&#xA;       Orders: NewOrderStore(tx),&#xA;   }&#xA;&#xA;   if err := fn(stores); err != nil {&#xA;       return err&#xA;   }&#xA;   return tx.Commit()&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Тот же трюк с &lt;code&gt;DBTX&lt;/code&gt;, что и раньше. И &lt;code&gt;NewBookStore(tx)&lt;/code&gt;, и &lt;code&gt;NewOrderStore(tx)&lt;/code&gt; принимают &lt;code&gt;DBTX&lt;/code&gt;, а &lt;code&gt;*sql.Tx&lt;/code&gt; удовлетворяет &lt;code&gt;DBTX&lt;/code&gt;. Оба хранилища работают в одной транзакции. Когда колбэк возвращается, либо коммитится всё, либо откатывается всё.&lt;h3&gt;Используем RunInTx в сервисе&lt;/h3&gt;&lt;p&gt;Теперь сервис использует для транзакций &lt;code&gt;UnitOfWork&lt;/code&gt; вместо &lt;code&gt;Tx&lt;/code&gt; на уровне отдельных хранилищ, поэтому меняются его зависимости. Для нетранзакционных чтений он принимает &lt;code&gt;Stores&lt;/code&gt;, а для атомарных записей — &lt;code&gt;UnitOfWork&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// checkout/checkout.go&#xA;&#xA;type Service struct {&#xA;   stores Stores&#xA;   uow    UnitOfWork&#xA;}&#xA;&#xA;func NewService(s Stores, uow UnitOfWork) *Service {&#xA;   return &amp;amp;Service{stores: s, uow: uow}&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;PlaceOrder&lt;/code&gt; читает книгу вне транзакции — нет смысла держать блокировку ради чтения, — а затем использует &lt;code&gt;RunInTx&lt;/code&gt; для двух записей, которые должны быть атомарными:&lt;pre&gt;&lt;code class=go&gt;// checkout/checkout.go&#xA;&#xA;func (s *Service) PlaceOrder(&#xA;   ctx context.Context, bookID int64) (order.Order, error) {&#xA;&#xA;   book, err := s.stores.Books.Get(ctx, bookID)&#xA;   if err != nil {&#xA;       return order.Order{}, err&#xA;   }&#xA;&#xA;   var ord order.Order&#xA;   err = s.uow.RunInTx(ctx, func(tx Stores) error {&#xA;       if err := tx.Books.DecrementStock(ctx, book.ID); err != nil {&#xA;           return err&#xA;       }&#xA;       id, err := tx.Orders.Create(ctx, order.Order{BookID: book.ID})&#xA;       if err != nil {&#xA;           return err&#xA;       }&#xA;       ord = order.Order{ID: id, BookID: book.ID}&#xA;       return nil&#xA;   })&#xA;&#xA;   return ord, err&#xA;}&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Внутри колбэка и &lt;code&gt;tx.Books&lt;/code&gt;, и &lt;code&gt;tx.Orders&lt;/code&gt; выполняются в одном и том же &lt;code&gt;sql.Tx&lt;/code&gt;. Если &lt;code&gt;DecrementStock&lt;/code&gt; проходит успешно, а &lt;code&gt;Orders.Create&lt;/code&gt; падает, вся транзакция откатывается, и уменьшение остатка тоже отменяется.&lt;p&gt;Операции с одним хранилищем работают так же. &lt;code&gt;RegisterBook&lt;/code&gt; проходит через &lt;code&gt;RunInTx&lt;/code&gt; и использует только &lt;code&gt;tx.Books&lt;/code&gt;, игнорируя &lt;code&gt;tx.Orders&lt;/code&gt;:&lt;pre&gt;&lt;code class=go&gt;// checkout/checkout.go&#xA;&#xA;func (s *Service) RegisterBook(&#xA;   ctx context.Context, title string) (book.Book, error) {&#xA;&#xA;   var b book.Book&#xA;&#xA;   err := s.uow.RunInTx(ctx, func(tx Stores) error {&#xA;       id, err := tx.Books.Create(ctx, book.Book{Title: title})&#xA;       if err != nil {&#xA;           return err&#xA;       }&#xA;       b = book.Book{ID: id, Title: title}&#xA;       return tx.Books.CreateAuditLog(ctx,&#xA;           book.AuditEntry{BookID: id, Action: &amp;#34;created&amp;#34;})&#xA;   })&#xA;&#xA;   return b, err&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Когда у вас уже есть Unit of Work, держать &lt;code&gt;Tx&lt;/code&gt; в каждом отдельном хранилище больше не нужно. &lt;code&gt;RunInTx&lt;/code&gt; закрывает и транзакции внутри одного хранилища, и транзакции между несколькими хранилищами.&lt;h3&gt;Тестируем транзакции между хранилищами&lt;/h3&gt;&lt;p&gt;Для юнит-тестов in-memory Unit of Work просто передаёт хранилища дальше:&lt;pre&gt;&lt;code class=go&gt;// checkout/checkout_test.go&#xA;&#xA;type memUoW struct {&#xA;   stores Stores&#xA;}&#xA;&#xA;func (m *memUoW) RunInTx(&#xA;   _ context.Context, fn func(Stores) error) error {&#xA;   return fn(m.stores)&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;В интеграционных тестах нужно проверить, что ошибка в одном хранилище действительно откатывает записи из другого. В этом тесте вставка заказа падает, а мы проверяем, что уменьшение остатка откатилось:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store_test.go&#xA;&#xA;func TestRunInTx_RollsBackOnError(t *testing.T) {&#xA;   db := setupTestDB(t)&#xA;   bookID := seedBook(t, db, &amp;#34;DDIA&amp;#34;, 5)&#xA;&#xA;   stores := checkout.Stores{&#xA;       Books:  NewBookStore(db),&#xA;       Orders: NewOrderStore(db),&#xA;   }&#xA;   failUoW := &amp;amp;failingOrderUoW{db: db}&#xA;   svc := checkout.NewService(stores, failUoW)&#xA;&#xA;   _, err := svc.PlaceOrder(t.Context(), bookID)&#xA;   if err == nil {&#xA;       t.Fatal(&amp;#34;expected error&amp;#34;)&#xA;   }&#xA;&#xA;   // Остаток должен остаться прежним, потому что транзакция откатилась.&#xA;   var stock int&#xA;   err = db.QueryRow(&#xA;       &amp;#34;SELECT stock FROM books WHERE id = ?&amp;#34;,&#xA;       bookID).Scan(&amp;amp;stock)&#xA;   if err != nil {&#xA;       t.Fatal(err)&#xA;   }&#xA;   if stock != 5 {&#xA;       t.Fatalf(&amp;#34;stock = %d, want 5&amp;#34;, stock)&#xA;   }&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;failingOrderUoW&lt;/code&gt; — это UnitOfWork, у которого &lt;code&gt;Store&lt;/code&gt; для заказов всегда падает на &lt;code&gt;Create&lt;/code&gt;. Он открывает настоящий &lt;code&gt;sql.Tx&lt;/code&gt;, строит из него оба хранилища, подменяя хранилище заказов на падающее, и откатывает транзакцию, когда колбэк возвращает ошибку:&lt;pre&gt;&lt;code class=go&gt;// sqlite/store_test.go&#xA;&#xA;type failingOrderUoW struct{ db *sql.DB }&#xA;&#xA;func (u *failingOrderUoW) RunInTx(&#xA;   ctx context.Context,&#xA;   fn func(checkout.Stores) error) error {&#xA;&#xA;   tx, err := u.db.BeginTx(ctx, nil)&#xA;   if err != nil {&#xA;       return err&#xA;   }&#xA;   defer tx.Rollback() // после Commit ничего не делает&#xA;&#xA;   stores := checkout.Stores{&#xA;       Books:  NewBookStore(tx),&#xA;       Orders: &amp;amp;failingOrderStore{},&#xA;   }&#xA;&#xA;   if err := fn(stores); err != nil {&#xA;       return err&#xA;   }&#xA;   return tx.Commit()&#xA;}&#xA;&#xA;type failingOrderStore struct{}&#xA;&#xA;func (f *failingOrderStore) Create(&#xA;   _ context.Context, _ order.Order) (int64, error) {&#xA;   return 0, sql.ErrConnDone&#xA;}&#xA;&#xA;func (f *failingOrderStore) Get(&#xA;   _ context.Context, _ int64) (order.Order, error) {&#xA;   return order.Order{}, sql.ErrConnDone&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;DecrementStock&lt;/code&gt; выполнился внутри транзакции и изменил остаток, но из-за падения вставки заказа вся транзакция откатилась, и остаток снова равен 5.&lt;h3&gt;Не слишком ли много абстракции для Go?&lt;/h3&gt;&lt;p&gt;Да. Всегда ли я так делаю? Нет.&lt;p&gt;Но в больших кодовых базах легко получить бардак, если смешивать сервисную логику с деталями хранения. Я много раз видел, как это происходит: начинаешь со спагетти во имя простоты, а по мере роста кодовой базы всё расползается. С LLM генерировать код дёшево. Направить эту железяку к нормальному дизайну стоит недорого, а отдача от этого потом тянется по всему проекту.&lt;p&gt;При этом я обычно пропускаю всю эту церемонию, когда быстро пишу что-то для себя, работаю с небольшой кодовой базой или попадаю в проект, где такой подход уже не принят.&lt;hr&gt;&lt;p&gt;Тема репозиториев и транзакций в Go быстро упирается в более широкий вопрос: где заканчивается полезная архитектура и начинается карго-культ. В OTUS в июле пройдут два бесплатных урока про разработку на Go: можно будет разобраться в спорных местах и задать свои вопросы по архитектуре, слоям и типичным ошибкам после перехода с других языков.&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;8 июля в 20:00&lt;/strong&gt;. «Чистая архитектура на Go без „карго-культа“: слои, DTO и интерфейсы». &lt;a href=https://otus.pw/6jr1/&gt;Записаться&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;20 июля в 20:00&lt;/strong&gt;. «Как перестать писать на Java внутри Go-проекта». &lt;a href=https://otus.pw/Icho/&gt;Записаться&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Полный список бесплатных уроков июня смотрите &lt;/em&gt;&lt;a href=https://otus.pw/1a81/&gt;&lt;em&gt;в дайджесте.&lt;/em&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/otus/articles/1049234/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1049234</guid>
      <pubDate>Wed, 24 Jun 2026 14:52:52 +0000</pubDate>
    </item>
    <item>
      <title>Как разобрать .exe всего двумя инструментами: практический разбор с DeNuitkanizator и HxD</title>
      <link>https://habr.com/ru/articles/1051484/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051484</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;strong&gt;Всем привет!&lt;/strong&gt;&lt;p&gt;Я решил снова зайти в реверс-инжиниринг и написать данную статью.&lt;br&gt;Многие реверс-инженеры и аналитики используют привычный набор инструментов для дизассемблинга: &lt;strong&gt;Ghidra, IDA PRO, x64dbg, Cremniy, HxD.&lt;/strong&gt;&lt;p&gt;И разумеется эти инструменты отлично справляются со своими задачами. Но я решил попробовать выполнить эксперимент: можно ли дизассемблировать и разобрать программы, используя только &lt;strong&gt;DeNuitkanizator и HxD.&lt;/strong&gt;&lt;p&gt;Поэтому в данной статье я подробно всё опишу и в выводе будет сказано, что вышло, а что не получилось.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/47c/046/c7e/47c046c7e8b5950794e065ae84a5c1c9.png alt=Обложка title=Обложка width=1276 height=719 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/47c/046/c7e/47c046c7e8b5950794e065ae84a5c1c9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/47c/046/c7e/47c046c7e8b5950794e065ae84a5c1c9.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Обложка&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Что представляют из себя DeNuitkanizator и HxD?&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;DeNuitkanizator&lt;/strong&gt; - анализатор Nuitka-сборок (а также PyInstaller и другие упаковщики) для извлечения метаданных, строк, модулей и структуры из скомпилированных .exe файлов.&lt;br&gt;Затем всю информацию просто выводит в папку DeNuitkanizator_Output.&lt;p&gt;Но у данной программы появилась технология: &lt;strong&gt;Asm-To-C.&lt;/strong&gt; Она позволяет &lt;strong&gt;переводить ассемблерный код (x86/x64) в читаемый C-код.&lt;/strong&gt; Основана на построчном преобразовании инструкций. Я вдохновился данной технологии у проекта на &lt;a href=https://github.com/rdbv/cisol rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;Github cisol&lt;/strong&gt;&lt;/a&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c3/66f/b6f/2c366fb6f54c1cd8ad20b6efe0227412.png alt=&#34;Интерфейс программы&#34; title=&#34;Интерфейс программы&#34; width=958 height=474 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2c3/66f/b6f/2c366fb6f54c1cd8ad20b6efe0227412.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c3/66f/b6f/2c366fb6f54c1cd8ad20b6efe0227412.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Интерфейс программы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;HxD - быстрый и бесплатный HEX-редактор.&lt;/strong&gt; Она умеет работать с большими данными. Данная программа пригодится и для открытия .bin файлов в HEX-формате.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/01b/ee0/701/01bee0701affa19410de980268f2f1ec.png alt=&#34;Интерфейс программы&#34; title=&#34;Интерфейс программы&#34; width=1125 height=708 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/01b/ee0/701/01bee0701affa19410de980268f2f1ec.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/01b/ee0/701/01bee0701affa19410de980268f2f1ec.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Интерфейс программы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Что будем разбирать?&lt;/h3&gt;&lt;p&gt;На разборе у нас будет две программы&lt;p&gt;&lt;strong&gt;hello.exe&lt;/strong&gt; (3,65 МБ) - сделан в exe-файл через Nuitka&lt;p&gt;Исходный код программы:&lt;pre&gt;&lt;code class=python&gt;print(&amp;#34;Hello by 2M12&amp;#34;)&#xA;input()&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d07/df3/6c7/d07df36c7a16fd9c806ba6a651e5cd03.png alt=&#34;Вывод программы&#34; title=&#34;Вывод программы&#34; width=959 height=478 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d07/df3/6c7/d07df36c7a16fd9c806ba6a651e5cd03.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d07/df3/6c7/d07df36c7a16fd9c806ba6a651e5cd03.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Вывод программы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;AnyDesk.exe (3,81 МБ) - нативный exe-файл. Версия 7.1.6.0&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/80f/514/9fb/80f5149fba0adc8c4a790d1bc83bb8cc.png alt=&#34;Интерфейс программы&#34; title=&#34;Интерфейс программы&#34; width=895 height=563 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/80f/514/9fb/80f5149fba0adc8c4a790d1bc83bb8cc.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/80f/514/9fb/80f5149fba0adc8c4a790d1bc83bb8cc.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Интерфейс программы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Разбор Hello.exe&lt;/h3&gt;&lt;p&gt;Для начала нужно просто закинуть наш exe-файл в DeNuitkanizator.&lt;p&gt;Затем после успешного разбора мы получаем папки и два текстовых документа.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/291/4f3/c31/2914f3c31602b6b86a75ca3b55fc7028.png alt=&#34;Вот что мы получили&#34; title=&#34;Вот что мы получили&#34; width=794 height=586 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/291/4f3/c31/2914f3c31602b6b86a75ca3b55fc7028.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/291/4f3/c31/2914f3c31602b6b86a75ca3b55fc7028.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Вот что мы получили&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Теперь нам нужно запустить HxD и перейти по этому пути &lt;strong&gt;DeNuitkanizator_Output\hello_20260624_100536\Dumps\sections&lt;/strong&gt; - путь может отличаться&lt;p&gt;И давайте откроем нашу .rsrc секцию&lt;br&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/7ef/787/e06/7ef787e065aad36dc2d1616b34ba24d9.png alt=&#34;Вот все распакованные секции&#34; title=&#34;Вот все распакованные секции&#34; width=612 height=401 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/7ef/787/e06/7ef787e065aad36dc2d1616b34ba24d9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/7ef/787/e06/7ef787e065aad36dc2d1616b34ba24d9.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Вот все распакованные секции&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Обычно, когда используется onefile режим, то тогда DeNuitkanizator обозначает энтропию в &lt;strong&gt;8.0 из 8.0&lt;/strong&gt;. Всё дело в том, что там используется &lt;strong&gt;алгоритм сжатия zstd (ZStandard)&lt;/strong&gt;, и поэтому так и происходит.&lt;p&gt;Но у нас hello.exe был в режиме Standalone, поэтому хорошо поискав в HxD мы находим нашу строку:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/dbf/55a/225/dbf55a225e0e0b87e340d2cb22f27e66.png alt=&#34;Нашли ту самую строку из print&#34; title=&#34;Нашли ту самую строку из print&#34; width=1419 height=682 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/dbf/55a/225/dbf55a225e0e0b87e340d2cb22f27e66.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/dbf/55a/225/dbf55a225e0e0b87e340d2cb22f27e66.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Нашли ту самую строку из print&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Ну и помимо нашей строки есть различные функции print&lt;br&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/8bc/f29/042/8bcf29042a21a2b2c9be84f7cd906e36.png alt=&#34;Что ещё есть&#34; title=&#34;Что ещё есть&#34; width=1039 height=421 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/8bc/f29/042/8bcf29042a21a2b2c9be84f7cd906e36.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/8bc/f29/042/8bcf29042a21a2b2c9be84f7cd906e36.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Что ещё есть&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Также с помощью DeNuitkanizator мы нашли замороженные модули, pe_header, и у нас есть дизассемблированный код (в C-переводе и просто ASM).&lt;p&gt;Ниже будут приведены отрывки из дизассемблированного кода:&lt;p&gt;C-перевод (первые 40 строк):&lt;pre&gt;&lt;code class=cpp&gt;#include &amp;#34;environment.h&amp;#34;&#xA;&#xA;void func() {&#xA;_0x140001000:&#xA;    MEMORY(uint64_t, rsp+8) = rbx; /* mov qword ptr [rsp + 8], rbx */&#xA;    MEMORY(uint64_t, rsp+16) = rsi; /* mov qword ptr [rsp + 0x10], rsi */&#xA;    PUSH64(rdi); /* push rdi */&#xA;    TMP64(rsp, -, 0x30); SET_ZF(64); SET_CF_SUB(rsp, 0x30); SET_AF_0(rsp, 0x30); SET_OF_SUB(rsp, 0x30, 64, 0x8000000000000000); SET_SF(64); SET_PF(); rsp = tmp64; /* sub rsp, 0x30 */&#xA;    rdi = rcx; /* mov rdi, rcx */&#xA;    rcx = (uint64_t)&amp;amp;MEMORY(uint64_t, rip+150047); /* lea rcx, [rip + 0x24a1f] */&#xA;    /* call qword ptr [rip + 0x24941] */&#xA;    r8 = (uint64_t)&amp;amp;MEMORY(uint64_t, rip+150026); /* lea r8, [rip + 0x24a0a] */&#xA;    rcx = rdi; /* mov rcx, rdi */&#xA;    rdx = (uint64_t)&amp;amp;MEMORY(uint64_t, rip+226032); /* lea rdx, [rip + 0x372f0] */&#xA;    MEMORY(uint64_t, rip+226017) = rax; /* mov qword ptr [rip + 0x372e1], rax */&#xA;    /* call 0x14001d820 */ PUSH64((uint64_t)&amp;amp;&amp;amp;_ret_140001037); goto _0x14001d820; _ret_140001037:;&#xA;    rbx = MEMORY(uint64_t, rip+230341); /* mov rbx, qword ptr [rip + 0x383c5] */&#xA;    rsi = MEMORY(uint64_t, rip+226862); /* mov rsi, qword ptr [rip + 0x3762e] */&#xA;    tmp64 = rbx &amp;amp; rbx; SET_ZF(64); SET_SF(64); SET_PF(); cf = 0; of = 0; /* test rbx, rbx */&#xA;    if(!zf) goto _0x140001080; /* jne 0x140001080 */&#xA;    ecx ^= ecx; SET_ZF(32); SET_SF(32); SET_PF(); cf = 0; of = 0; /* xor ecx, ecx */&#xA;    /* call 0x140015340 */ PUSH64((uint64_t)&amp;amp;&amp;amp;_ret_140001051); goto _0x140015340; _ret_140001051:;&#xA;    rdx = -1; /* mov rdx, -1 */&#xA;    rcx = rax; /* mov rcx, rax */&#xA;    /* call qword ptr [rip + 0x246fa] */&#xA;    MEMORY(uint64_t, rip+230299) = rax; /* mov qword ptr [rip + 0x3839b], rax */&#xA;    tmp64 = rax &amp;amp; rax; SET_ZF(64); SET_SF(64); SET_PF(); cf = 0; of = 0; /* test rax, rax */&#xA;    if(zf) goto _0x14000117f; /* je 0x14000117f */&#xA;    TMP64(MEMORY(uint64_t, rax), +, 1); SET_ZF(64); SET_AF_INC(64); SET_OF_INC_DEC_NEG(64, 0x8000000000000000); SET_SF(64); SET_PF(); MEMORY(uint64_t, rax) = tmp64; /* inc qword ptr [rax] */&#xA;    rbx = MEMORY(uint64_t, rip+230280); /* mov rbx, qword ptr [rip + 0x38388] */&#xA;_0x140001080:&#xA;    TMP64(rbx, -, MEMORY(uint64_t, rip+226017)); SET_ZF(64); SET_CF_SUB(rbx, MEMORY(uint64_t, rip+226017)); SET_AF_0(rbx, MEMORY(uint64_t, rip+226017)); SET_OF_SUB(rbx, MEMORY(uint64_t, rip+226017), 64, 0x8000000000000000); SET_SF(64); SET_PF(); /* cmp rbx, qword ptr [rip + 0x372e1] */&#xA;    if(zf) goto _0x1400010b8; /* je 0x1400010b8 */&#xA;    rax = MEMORY(uint64_t, rip+230408); /* mov rax, qword ptr [rip + 0x38408] */&#xA;    tmp64 = rax &amp;amp; rax; SET_ZF(64); SET_SF(64); SET_PF(); cf = 0; of = 0; /* test rax, rax */&#xA;    if(!zf) goto _0x1400010a9; /* jne 0x1400010a9 */&#xA;    rcx = (uint64_t)&amp;amp;MEMORY(uint64_t, rip+166044); /* lea rcx, [rip + 0x2889c] */&#xA;    /* call qword ptr [rip + 0x24876] */&#xA;    MEMORY(uint64_t, rip+230383) = rax; /* mov qword ptr [rip + 0x383ef], rax */&#xA;_0x1400010a9:&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Всё, что закомментировано - неподдерживаемые пока мнемоники.&lt;p&gt;Ассемблер (первые 40 строк):&lt;pre&gt;&lt;code class=assembly&gt;0x140001000: mov      qword ptr [rsp + 8], rbx       &#xA;0x140001005: mov      qword ptr [rsp + 0x10], rsi    &#xA;0x14000100a: push     rdi                            &#xA;0x14000100b: sub      rsp, 0x30                      &#xA;0x14000100f: mov      rdi, rcx                       &#xA;0x140001012: lea      rcx, [rip + 0x24a1f]           &#xA;0x140001019: call     qword ptr [rip + 0x24941]      [CALL]&#xA;0x14000101f: lea      r8, [rip + 0x24a0a]            &#xA;0x140001026: mov      rcx, rdi                       &#xA;0x140001029: lea      rdx, [rip + 0x372f0]           &#xA;0x140001030: mov      qword ptr [rip + 0x372e1], rax &#xA;0x140001037: call     0x14001d820                    [CALL]&#xA;0x14000103c: mov      rbx, qword ptr [rip + 0x383c5] &#xA;0x140001043: mov      rsi, qword ptr [rip + 0x3762e] &#xA;0x14000104a: test     rbx, rbx                       &#xA;0x14000104d: jne      0x140001080                    [JMP]&#xA;0x14000104f: xor      ecx, ecx                       &#xA;0x140001051: call     0x140015340                    [CALL]&#xA;0x140001056: mov      rdx, -1                        &#xA;0x14000105d: mov      rcx, rax                       &#xA;0x140001060: call     qword ptr [rip + 0x246fa]      [CALL]&#xA;0x140001066: mov      qword ptr [rip + 0x3839b], rax &#xA;0x14000106d: test     rax, rax                       &#xA;0x140001070: je       0x14000117f                    [JMP]&#xA;0x140001076: inc      qword ptr [rax]                &#xA;0x140001079: mov      rbx, qword ptr [rip + 0x38388] &#xA;0x140001080: cmp      rbx, qword ptr [rip + 0x372e1] &#xA;0x140001087: je       0x1400010b8                    [JMP]&#xA;0x140001089: mov      rax, qword ptr [rip + 0x38408] &#xA;0x140001090: test     rax, rax                       &#xA;0x140001093: jne      0x1400010a9                    [JMP]&#xA;0x140001095: lea      rcx, [rip + 0x2889c]           &#xA;0x14000109c: call     qword ptr [rip + 0x24876]      [CALL]&#xA;0x1400010a2: mov      qword ptr [rip + 0x383ef], rax &#xA;0x1400010a9: mov      rdx, rax                       &#xA;0x1400010ac: mov      rcx, rbx                       &#xA;0x1400010af: call     qword ptr [rip + 0x24613]      [CALL]&#xA;0x1400010b5: mov      rbx, rax                       &#xA;0x1400010b8: mov      rdx, rsi                       &#xA;0x1400010bb: mov      rcx, rbx&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Как видите всё было успешно извлечено с помощью Capstone + Asm-To-C. Но важно учитывать, что всё равно нужно уметь сортировать мусор (да он есть, ведь Capstone - не рекурсивный дизассемблер, пока что).&lt;p&gt;А вот информация по секциям:&lt;pre&gt;&lt;code class=dart&gt;.data: VA=0x00032000 RawSize=24,064 VirtSize=31,840 Entropy=2.21/8.0 Rights=0xc0000040 &#xA;.pdata: VA=0x0003a000 RawSize=8,192 VirtSize=7,920 Entropy=5.20/8.0 Rights=0x40000040 &#xA;.rdata: VA=0x00025000 RawSize=52,736 VirtSize=52,594 Entropy=6.16/8.0 Rights=0x40000040 &#xA;.reloc: VA=0x004b6000 RawSize=2,048 VirtSize=1,860 Entropy=5.19/8.0 Rights=0x42000040 &#xA;.rsrc: VA=0x0003c000 RawSize=4,692,480 VirtSize=4,692,412 Entropy=5.55/8.0 Rights=0x40000040 &#xA;.text: VA=0x00001000 RawSize=146,432 VirtSize=146,284 Entropy=6.15/8.0 Rights=0x60000020 EXEC&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;А ещё обратите внимание на pe_headers.txt. Там присутствует упоминания версии python:&lt;pre&gt;&lt;code class=elixir&gt;----------Imported symbols----------&#xA;&#xA;[IMAGE_IMPORT_DESCRIPTOR]&#xA;0x2EB10    0x0   OriginalFirstThunk:            0x2FEC8   &#xA;0x2EB10    0x0   Characteristics:               0x2FEC8   &#xA;0x2EB14    0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]&#xA;0x2EB18    0x8   ForwarderChain:                0x0       &#xA;0x2EB1C    0xC   Name:                          0x3168E   &#xA;0x2EB20    0x10  FirstThunk:                    0x252D8   &#xA;&#xA;python311.dll.PyImport_ImportFrozenModule Hint[406]&#xA;python311.dll.PyErr_ExceptionMatches Hint[180]&#xA;python311.dll._PyErr_FormatFromCause Hint[1172]&#xA;python311.dll.PyObject_GC_Del Hint[622]&#xA;python311.dll.PyObject_CallFunctionObjArgs Hint[606]&#xA;python311.dll.PyLong_AsLong Hint[447]&#xA;python311.dll.PyObject_ClearWeakRefs Hint[615]&#xA;python311.dll.PyCode_Type Hint[84]&#xA;python311.dll.PyUnicode_AsUTF8 Hint[890]&#xA;python311.dll.PyUnicode_AsWideCharString Hint[897]&#xA;python311.dll.PyUnicode_FromFormat Hint[936]&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;h3&gt;Разбор AnyDesk.exe&lt;/h3&gt;&lt;p&gt;Теперь давайте также закинем файл в наш DeNuitkanizator и подождём результата&lt;p&gt;Перейдём по пути &lt;strong&gt;DeNuitkanizator_Output\AnyDesk_20260624_160750\Dumps&lt;/strong&gt;&lt;br&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/670/1bc/862/6701bc8626b25477b3f7ebb6c521a1b9.png alt=&#34;Путь где Overlay&#34; title=&#34;Путь где Overlay&#34; width=702 height=501 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/670/1bc/862/6701bc8626b25477b3f7ebb6c521a1b9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/670/1bc/862/6701bc8626b25477b3f7ebb6c521a1b9.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Путь где Overlay&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;И теперь откроем &lt;strong&gt;overlay.bin &lt;/strong&gt;через &lt;strong&gt;HxD.&lt;/strong&gt;&lt;br&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/1a3/914/2ee/1a39142eede2d86afc5d62e767fe23cc.png alt=&#34;Видно чья цифровая подпись&#34; title=&#34;Видно чья цифровая подпись&#34; width=1394 height=442 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/1a3/914/2ee/1a39142eede2d86afc5d62e767fe23cc.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/1a3/914/2ee/1a39142eede2d86afc5d62e767fe23cc.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Видно чья цифровая подпись&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Видно, что подпись сделана &lt;abbr class=habraabbr title=&#34;Один из крупнейших в мире центров сертификации (Certificate Authority, CA), предоставляющий решения для цифровой безопасности.&#34; data-title=&#34;&amp;lt;p&amp;gt;Один из крупнейших в мире центров сертификации (Certificate Authority, CA), предоставляющий решения для цифровой безопасности.  &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&#34; data-abbr=DigiCert&gt;DigiCert &lt;/abbr&gt;. То есть один из крупнейших центров сертификации.&lt;p&gt;А ещё обратите внимание, что (видимо для подписи) используется &lt;strong&gt;RSA-4096 + SHA-384&lt;/strong&gt;&lt;br&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4f/36c/030/c4f36c0307d041397290f732676336a6.png alt=&#34;RSA-4096 + SHA-384&#34; title=&#34;RSA-4096 + SHA-384&#34; width=1412 height=644 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c4f/36c/030/c4f36c0307d041397290f732676336a6.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4f/36c/030/c4f36c0307d041397290f732676336a6.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;RSA-4096 + SHA-384&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Откроем теперь &lt;strong&gt;DeNuitkanizator_Output\AnyDesk_20260624_160750\Strings\all_utf8.txt&lt;/strong&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/774/dab/54f/774dab54fc4280c63522f4e297d3c92a.png alt=&#34;Заметили Buildbot&#34; title=&#34;Заметили Buildbot&#34; width=1111 height=721 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/774/dab/54f/774dab54fc4280c63522f4e297d3c92a.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/774/dab/54f/774dab54fc4280c63522f4e297d3c92a.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Заметили Buildbot&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Заметим систему CI/CD &lt;strong&gt;Buildbot&lt;/strong&gt;. И он кстати написан на Python😉&lt;br&gt;Я слышал его часто применяют в сложных сборках из-за гибкости.&lt;p&gt;А также у нас есть и &lt;strong&gt;pe_headers.txt (первые 39 строк):&lt;/strong&gt;&lt;pre&gt;&lt;code class=assembly&gt;----------DOS_HEADER----------&#xA;&#xA;[IMAGE_DOS_HEADER]&#xA;0x0        0x0   e_magic:                       0x5A4D    &#xA;0x2        0x2   e_cblp:                        0x90      &#xA;0x4        0x4   e_cp:                          0x3       &#xA;0x6        0x6   e_crlc:                        0x0       &#xA;0x8        0x8   e_cparhdr:                     0x4       &#xA;0xA        0xA   e_minalloc:                    0x0       &#xA;0xC        0xC   e_maxalloc:                    0xFFFF    &#xA;0xE        0xE   e_ss:                          0x0       &#xA;0x10       0x10  e_sp:                          0xB8      &#xA;0x12       0x12  e_csum:                        0x0       &#xA;0x14       0x14  e_ip:                          0x0       &#xA;0x16       0x16  e_cs:                          0x0       &#xA;0x18       0x18  e_lfarlc:                      0x40      &#xA;0x1A       0x1A  e_ovno:                        0x0       &#xA;0x1C       0x1C  e_res:                         &#xA;0x24       0x24  e_oemid:                       0x0       &#xA;0x26       0x26  e_oeminfo:                     0x0       &#xA;0x28       0x28  e_res2:                        &#xA;0x3C       0x3C  e_lfanew:                      0xD0      &#xA;&#xA;----------NT_HEADERS----------&#xA;&#xA;[IMAGE_NT_HEADERS]&#xA;0xD0       0x0   Signature:                     0x4550    &#xA;&#xA;----------FILE_HEADER----------&#xA;&#xA;[IMAGE_FILE_HEADER]&#xA;0xD4       0x0   Machine:                       0x14C     &#xA;0xD6       0x2   NumberOfSections:              0x6       &#xA;0xD8       0x4   TimeDateStamp:                 0x634E8DEE [Tue Oct 18 11:28:46 2022 UTC]&#xA;0xDC       0x8   PointerToSymbolTable:          0x0       &#xA;0xE0       0xC   NumberOfSymbols:               0x0       &#xA;0xE4       0x10  SizeOfOptionalHeader:          0xE0      &#xA;0xE6       0x12  Characteristics:               0x122     &#xA;Flags: IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;PE Headers служит &amp;#34;паспортом&amp;#34; для программ, и по факту объясняет Windows как запускать программу. Данный заголовок получается с помощью библиотеки pefile.&lt;p&gt;&lt;strong&gt;А вот информация по секциям:&lt;/strong&gt;&lt;pre&gt;&lt;code class=dart&gt;.data: VA=0x00c8e000 RawSize=3,949,056 VirtSize=3,949,964 Entropy=8.00/8.0 Rights=0xc0000040 &#xA;.itext: VA=0x00004000 RawSize=0 VirtSize=13,142,528 Entropy=0.00/8.0 Rights=0xc0000080 &#xA;.rdata: VA=0x00c8d000 RawSize=1,024 VirtSize=762 Entropy=5.64/8.0 Rights=0x40000040 &#xA;.reloc: VA=0x01058000 RawSize=1,024 VirtSize=768 Entropy=1.18/8.0 Rights=0x42000040 &#xA;.rsrc: VA=0x01053000 RawSize=18,944 VirtSize=18,512 Entropy=6.02/8.0 Rights=0x40000040 &#xA;.text: VA=0x00001000 RawSize=10,752 VirtSize=10,293 Entropy=6.51/8.0 Rights=0x60000020 EXEC&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Совет!&lt;p&gt;Если вы видите в entropy.txt, что у какой-либо секции повышенная энтропия (8.0 самая максимальная) - то скорее всего файлы были сжаты с помощью различных алгоритмов (например gzip).&lt;/blockquote&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4c/9c2/79f/c4c9c279f15d44290a5746c3df73f85c.png alt=&#34;Пример энтропий секций у AnyDesk&#34; title=&#34;Пример энтропий секций у AnyDesk&#34; width=974 height=564 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c4c/9c2/79f/c4c9c279f15d44290a5746c3df73f85c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4c/9c2/79f/c4c9c279f15d44290a5746c3df73f85c.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пример энтропий секций у AnyDesk&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Ниже будут приведены отрывки из дизассемблированного кода:&lt;p&gt;&lt;strong&gt;C-перевод (первые 40 строк):&lt;/strong&gt;&lt;pre&gt;&lt;code class=cpp&gt;#include &amp;#34;environment.h&amp;#34;&#xA;&#xA;void func() {&#xA;    PUSH64(ebp); /* push ebp */&#xA;    ebp = esp; /* mov ebp, esp */&#xA;    eax = MEMORY(uint32_t, ebp+8); /* mov eax, dword ptr [ebp + 8] */&#xA;    edx = MEMORY(uint32_t, ebp+16); /* mov edx, dword ptr [ebp + 0x10] */&#xA;    PUSH64(esi); /* push esi */&#xA;    esi = ecx; /* mov esi, ecx */&#xA;    ecx = MEMORY(uint32_t, ebp+12); /* mov ecx, dword ptr [ebp + 0xc] */&#xA;    MEMORY(uint32_t, esi) = eax; /* mov dword ptr [esi], eax */&#xA;    eax ^= eax; SET_ZF(32); SET_SF(32); SET_PF(); cf = 0; of = 0; /* xor eax, eax */&#xA;    PUSH64(edi); /* push edi */&#xA;    edi = MEMORY(uint32_t, ebp+24); /* mov edi, dword ptr [ebp + 0x18] */&#xA;    MEMORY(uint32_t, esi+8) = eax; /* mov dword ptr [esi + 8], eax */&#xA;    MEMORY(uint32_t, esi+20) = eax; /* mov dword ptr [esi + 0x14], eax */&#xA;    MEMORY(uint32_t, esi+24) = eax; /* mov dword ptr [esi + 0x18], eax */&#xA;    MEMORY(uint32_t, esi+28) = eax; /* mov dword ptr [esi + 0x1c], eax */&#xA;    MEMORY(uint32_t, esi+32) = eax; /* mov dword ptr [esi + 0x20], eax */&#xA;    MEMORY(uint32_t, esi+36) = eax; /* mov dword ptr [esi + 0x24], eax */&#xA;    MEMORY(uint32_t, esi+40) = eax; /* mov dword ptr [esi + 0x28], eax */&#xA;    MEMORY(uint32_t, esi+44) = eax; /* mov dword ptr [esi + 0x2c], eax */&#xA;    eax = (uint64_t)&amp;amp;MEMORY(uint32_t, ebp+8); /* lea eax, [ebp + 8] */&#xA;    PUSH64(eax); /* push eax */&#xA;    PUSH64(0x40); /* push 0x40 */&#xA;    PUSH64(MEMORY(uint32_t, ebp+28)); /* push dword ptr [ebp + 0x1c] */&#xA;    MEMORY(uint32_t, esi+12) = edx; /* mov dword ptr [esi + 0xc], edx */&#xA;    edx = MEMORY(uint32_t, ebp+20); /* mov edx, dword ptr [ebp + 0x14] */&#xA;    PUSH64(edi); /* push edi */&#xA;    MEMORY(uint32_t, esi+4) = ecx; /* mov dword ptr [esi + 4], ecx */&#xA;    MEMORY(uint32_t, esi+16) = edx; /* mov dword ptr [esi + 0x10], edx */&#xA;    /* call dword ptr [ecx + 0x18] */&#xA;    tmp32 = eax &amp;amp; eax; SET_ZF(32); SET_SF(32); SET_PF(); cf = 0; of = 0; /* test eax, eax */&#xA;    if(!zf) goto _0x401058; /* jne 0x401058 */&#xA;    MEMORY(uint32_t, esi+8) = 9; /* mov dword ptr [esi + 8], 9 */&#xA;    goto _0x401131; /* jmp 0x401131 */&#xA;_0x401058:&#xA;    PUSH64(ebx); /* push ebx */&#xA;    ebx = MEMORY(uint32_t, esi+16); /* mov ebx, dword ptr [esi + 0x10] */&#xA;    TMP32(ebx, -, 0x40); SET_ZF(32); SET_CF_SUB(ebx, 0x40); SET_AF_0(ebx, 0x40); SET_OF_SUB(ebx, 0x40, 32, 0x80000000); SET_SF(32); SET_PF(); /* cmp ebx, 0x40 */&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Всё, что закомментировано - неподдерживаемые пока мнемоники.&lt;p&gt;&lt;strong&gt;Ассемблер (первые 40 строк):&lt;/strong&gt;&lt;pre&gt;&lt;code class=assembly&gt;0x401000: push     ebp                            &#xA;0x401001: mov      ebp, esp                       &#xA;0x401003: mov      eax, dword ptr [ebp + 8]       &#xA;0x401006: mov      edx, dword ptr [ebp + 0x10]    &#xA;0x401009: push     esi                            &#xA;0x40100a: mov      esi, ecx                       &#xA;0x40100c: mov      ecx, dword ptr [ebp + 0xc]     &#xA;0x40100f: mov      dword ptr [esi], eax           &#xA;0x401011: xor      eax, eax                       &#xA;0x401013: push     edi                            &#xA;0x401014: mov      edi, dword ptr [ebp + 0x18]    &#xA;0x401017: mov      dword ptr [esi + 8], eax       &#xA;0x40101a: mov      dword ptr [esi + 0x14], eax    &#xA;0x40101d: mov      dword ptr [esi + 0x18], eax    &#xA;0x401020: mov      dword ptr [esi + 0x1c], eax    &#xA;0x401023: mov      dword ptr [esi + 0x20], eax    &#xA;0x401026: mov      dword ptr [esi + 0x24], eax    &#xA;0x401029: mov      dword ptr [esi + 0x28], eax    &#xA;0x40102c: mov      dword ptr [esi + 0x2c], eax    &#xA;0x40102f: lea      eax, [ebp + 8]                 &#xA;0x401032: push     eax                            &#xA;0x401033: push     0x40                           &#xA;0x401035: push     dword ptr [ebp + 0x1c]         &#xA;0x401038: mov      dword ptr [esi + 0xc], edx     &#xA;0x40103b: mov      edx, dword ptr [ebp + 0x14]    &#xA;0x40103e: push     edi                            &#xA;0x40103f: mov      dword ptr [esi + 4], ecx       &#xA;0x401042: mov      dword ptr [esi + 0x10], edx    &#xA;0x401045: call     dword ptr [ecx + 0x18]         [CALL]&#xA;0x401048: test     eax, eax                       &#xA;0x40104a: jne      0x401058                       [JMP]&#xA;0x40104c: mov      dword ptr [esi + 8], 9         &#xA;0x401053: jmp      0x401131                       [JMP]&#xA;0x401058: push     ebx                            &#xA;0x401059: mov      ebx, dword ptr [esi + 0x10]    &#xA;0x40105c: cmp      ebx, 0x40                      &#xA;0x40105f: jae      0x40106d                       &#xA;0x401061: mov      dword ptr [esi + 8], 1         &#xA;0x401068: jmp      0x401130                       [JMP]&#xA;0x40106d: mov      eax, dword ptr [esi + 0xc]  &lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;h3&gt;Заключение&lt;/h3&gt;&lt;p&gt;Как видите, программы возможно разбирать с помощью двух инструментов: &lt;strong&gt;DeNuitkanizator и HxD.&lt;/strong&gt; Но важно понимать, что &lt;strong&gt;одного DeNuitkanizator&amp;#39;а может быть недостаточно!&lt;/strong&gt;&lt;p&gt;У нас получилось дизассемблировать программы, извлечь разную информацию из секций, посмотреть заголовок PE, найти строчку из hello.exe.&lt;p&gt;В любом случае это был эксперимент, и я настоятельно рекомендую DeNuitkanizator комбинировать с &lt;strong&gt;Ghidra, x64dbg, Cremniy или IDA PRO.&lt;/strong&gt;&lt;hr&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/articles/1048908/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Статья про DeNuitkanizator&lt;/a&gt;&lt;p&gt;&lt;a href=https://denuitkanizator-site.vercel.app/ rel=&#34;noopener noreferrer nofollow&#34;&gt;Официальный сайт DeNuitkanizator&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>2M12</author>
      <guid>https://habr.com/ru/articles/1051484/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051484</guid>
      <pubDate>Wed, 24 Jun 2026 14:47:05 +0000</pubDate>
    </item>
    <item>
      <title>Что не вошло в концепцию прикладного решения «1С:ERP Управление предприятием» 2026 года от УЦ №1 фирмы «1С»</title>
      <link>https://habr.com/ru/articles/1051472/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051472</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;h3&gt;Как мы остановились на процессном подходе — и почему предметный слой пришлось вынести отдельно&lt;/h3&gt;&lt;p&gt;У концепций есть неприятное свойство: в финальную версию попадает не всё, что хотелось.&lt;p&gt;Когда в 2025 году мы работали над концепцией прикладного решения «1С:ERP Управление предприятием», а в 2026 году она была вынесена в учебный курс УЦ №1 фирмы «1С», у нас довольно быстро возникла простая развилка.&lt;p&gt;Можно объяснять ERP через подсистемы, документы и кнопки. Это привычно, понятно, методически безопасно.&lt;p&gt;Можно объяснять ERP через процессы. Это уже интереснее: система перестаёт быть набором экранов и начинает выглядеть как деятельность предприятия.&lt;p&gt;А можно пойти ещё глубже — объяснять ERP через предметы управления: потребности, партии, запасы, обязательства, НЗП, выпуск, себестоимость, рекламации, доказательные записи, лимиты, отклонения.&lt;p&gt;Вот вокруг этого третьего слоя мы и ходили кругами.&lt;p&gt;И да, были версии, где предметный подход пытались вставить прямо в концепцию. Были схемы, заметки, куски будущих объяснений. Были споры — не в смысле академических дискуссий, а обычные рабочие разговоры: «а если вот здесь сразу показать предмет?», «а если объяснить, что ERP-объект не равен бизнес-предмету?», «а если дать хотя бы вводный слой по управленческому учёту через объекты?»&lt;p&gt;Потом стало понятно: не надо.&lt;p&gt;Не потому что предметный слой неважен. Наоборот, как раз потому что он слишком важен и слишком тяжёлый для входной концепции.&lt;p&gt;Итоговая запись концепции — около 50 часов видео. Это уже большой объём. Но исходных наработок было больше. Просто у учебного формата есть предел. Если человек только входит в 1С:ERP, нельзя сразу навалить на него подсистемы, процессы, предметы, графы знаний, LLM, СМК, управленческий учёт, цифровой двойник и интеллектуальное предприятие.&lt;p&gt;Он не войдёт в систему. Он утонет.&lt;p&gt;Поэтому мы приняли довольно трезвое решение: в концепцию пойдёт процессный подход.&lt;p&gt;Тем более процессы у нас были не придуманы «под курс». Это была типовая процессная модель для дискретного предприятия, которую мы много лет использовали, проверяли, гоняли через проекты, переделывали, уточняли и в целом уже понимали, где она работает. Её и имело смысл провести через концепцию.&lt;p&gt;Процессная концепция получилась сквозной. И это, на мой взгляд, правильно. А предметно-ориентированную линию мы решили вынести отдельно.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/b90/42b/f30/b9042bf30ebdaa485a7e704aadeabc5c.jpg width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/b90/42b/f30/b9042bf30ebdaa485a7e704aadeabc5c.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/b90/42b/f30/b9042bf30ebdaa485a7e704aadeabc5c.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Почему не кнопки&lt;/h3&gt;&lt;p&gt;С кнопок начинать проще всего. Открываем подсистему. Создаём документ. Заполняем реквизиты. Проводим. Формируем отчёт. Проверяем результат. Это нормальный вход в систему. Без него никак. Человеку надо знать, где что находится и что делать руками.&lt;p&gt;Но если ERP объяснять только так, она превращается в большой интерфейс. У пользователя возникает ощущение: система — это набор документов, справочников, отчётов и кнопок. А дальше начинается знакомая проблема: документ создали, отчёт сформировали, но управленческий смысл действия не всегда понятен.&lt;p&gt;Что именно изменилось в деятельности предприятия? Какой предмет перешёл в новое состояние? Какой риск закрыли? Какое обязательство возникло? Что стало основанием для следующего действия?&lt;p&gt;Кнопка на это не отвечает. Документ тоже не всегда отвечает. Он фиксирует действие, но не объясняет всю управленческую логику. Поэтому процессный подход оказался для концепции удачным компромиссом. Он не перегружает человека онтологией, но уже вытаскивает его из интерфейса в деятельность.&lt;p&gt;Не «создайте заказ клиента», а «посмотрите, как предприятие принимает и исполняет обязательство перед клиентом».&lt;p&gt;Не «оформите поступление», а «посмотрите, как потребность превращается в обеспеченный ресурс».&lt;p&gt;Не «сформируйте отчёт», а «посмотрите, какой результат получила цепочка действий».&lt;p&gt;Это уже другой разговор.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/cc3/fc7/e05/cc3fc7e052b389c371efc850525e1c4f.jpg width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/cc3/fc7/e05/cc3fc7e052b389c371efc850525e1c4f.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/cc3/fc7/e05/cc3fc7e052b389c371efc850525e1c4f.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Почему процессы сработали&lt;/h3&gt;&lt;p&gt;Процессы хороши тем, что они возвращают в ERP живое предприятие.&lt;p&gt;Когда смотришь на продажи через документы, видишь заказ клиента, реализацию, оплату, отчёты. Когда смотришь процессно, видишь цепочку: запрос клиента, обязательство, проверка возможности исполнения, резерв, производство или отгрузка, выручка, дебиторка, деньги.&lt;p&gt;Когда смотришь на закупки через документы, видишь заявку, заказ поставщику, поступление, оплату. Когда смотришь процессно, видишь потребность, обеспечение, поставщика, срок, качество, склад, обязательство и влияние на производство.&lt;p&gt;Когда смотришь на производство через документы, видишь заказ на производство, этапы, списание, выпуск. Когда смотришь процессно, видишь потребность, обеспеченность, НЗП, выпуск, качество, себестоимость и дальнейшую отгрузку.&lt;p&gt;Для учебной концепции это сильный уровень. Он достаточно глубокий, чтобы человек перестал воспринимать ERP как набор форм. И при этом ещё не настолько тяжёлый, чтобы превращать курс в онтологию предприятия.&lt;p&gt;Поэтому мы на этом уровне и остановились.&lt;p&gt;Сейчас это выглядит очевидным. Но в процессе подготовки это не было таким прямым решением. Несколько раз хотелось пойти дальше.&lt;p&gt;Особенно когда попадались места, где процесс сам просил предметного объяснения. Например, обеспеченность производства. Это не просто процесс закупки и не просто остатки на складе. Там сразу всплывают потребности, резервы, партии, сроки, качество, замены, дефициты. И рука сама тянется сказать: «Стоп, здесь надо вводить бизнес-предмет». Но если вводить его в одном месте, то надо вводить везде. А это уже другая концепция.&lt;h3&gt;Где процесс начинает не справляться&lt;/h3&gt;&lt;p&gt;У процесса есть граница. Он показывает маршрут. Но не всегда показывает, что именно проходит через маршрут.&lt;p&gt;Например, есть закупка. Процесс понятен: выявили потребность, согласовали, заказали, получили, проверили, положили на склад, отразили обязательство, оплатили.&lt;p&gt;Но чем именно предприятие управляет?&lt;p&gt;Потребностью? Заказом? Материалом? Партией? Качеством партии? Обязательством поставщику? Обеспеченностью производства?&lt;p&gt;Ответ зависит от того, с какой стороны смотреть.&lt;p&gt;Для снабжения важна потребность и её обеспечение. Для склада — запас. Для качества — партия и её статус. Для финансов — обязательство и платёж. Для производства — доступность ресурса под конкретный заказ.&lt;p&gt;И вот тут процессной схемы уже мало. Она показывает движение, но не показывает весь предметный смысл. На схеме всё может быть красиво, но управленческие вопросы остаются.&lt;p&gt;Тогда появляется простая формула: процесс — это маршрут изменения состояния бизнес-предмета. Я не стал бы вставлять эту формулу в самый первый входной курс. Для неподготовленного слушателя она тяжеловата. Ему ещё надо понять систему, её контуры и процессы. Но для проектной работы без этой формулы уже сложно.&lt;p&gt;Потому что иначе мы рисуем процессы, но не всегда понимаем, чем предприятие реально управляет.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a00/896/ca1/a00896ca19e694b2b6686b29088f3616.jpg width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a00/896/ca1/a00896ca19e694b2b6686b29088f3616.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a00/896/ca1/a00896ca19e694b2b6686b29088f3616.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Бизнес-предметы: вот это и не вошло&lt;/h3&gt;&lt;p&gt;Бизнес-предмет — это не документ и не отчёт. Это то, что предприятие различает как управляемую сущность.&lt;p&gt;Запас. Партия. Потребность. Обязательство. НЗП. Выпуск. Рекламация. Лимит. Дебиторская задолженность. Доказательная запись качества. План-фактовое отклонение. У такого предмета есть состояние. Он возникает, меняется, передаётся, проверяется, принимается, отклоняется, закрывается. И если предприятие не различает предмет, оно не может устойчиво им управлять.&lt;p&gt;Можно сто раз сказать «у нас проблема со складом». Но что именно не так? Остаток? Доступность? Резерв? Партии? Качество? Адресное хранение? Неликвиды? Ошибка учёта? Дефицит под производство? Пока это всё называется одним словом «склад», управление размыто.&lt;p&gt;То же с финансами. «Прибыль есть, денег нет» — прекрасная фраза, которую все слышали. Но дальше надо разбирать предметы: дебиторка, запасы, НЗП, авансы, кредиторка, график платежей, кассовые разрывы, финансовый цикл.&lt;p&gt;Именно предметы делают управление различимым. Мы пробовали вставлять этот слой в концепцию. Но быстро стало понятно, что он потянет за собой слишком много всего: состояния, переходы, ERP-носители, KPI, СМК, управленческий учёт, LLM, граф знаний. Концепция стала бы не процессной, а предметно-ориентированной. А это уже отдельный курс. И, видимо, рано или поздно его действительно придётся записывать.&lt;p&gt;Потому что будущее, как мне кажется, именно за предметно-ориентированным подходом. Не потому что это красивое слово, а потому что без него невозможно построить интеллектуальное предприятие. ИИ не может надёжно рассуждать о предприятии, если предприятие само не различило свои предметы.&lt;h3&gt;ERP-объект — это ещё не предмет&lt;/h3&gt;&lt;p&gt;Самая частая ловушка в ERP-проектах — принять объект системы за предмет управления.&lt;p&gt;Документ «Заказ клиента» есть. Значит, кажется, что он и есть предмет. Но за ним могут стоять разные вещи: клиентское обязательство, резерв, производственная потребность, будущая выручка, дебиторская задолженность.&lt;p&gt;Документ «Поступление» есть. Но за ним живут партия, запас, обязательство поставщику, качество, стоимость, дальнейшее обеспечение производства.&lt;p&gt;Отчёт по остаткам есть. Но отчёт — не запас. Он только показывает его проекцию. Статус документа есть. Но статус документа не всегда равен состоянию бизнеса.&lt;p&gt;Для опытного консультанта это, возможно, очевидно. Но в методике это надо проговаривать. Особенно теперь, когда рядом с ERP появляется ИИ. Человек ещё может держать смысл в голове. LLM — нет. Если не сказать ей, что является предметом, а что только носителем, она будет достраивать сама. И иногда очень убедительно.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a53/496/606/a53496606f08a315fdbbdbff363425e5.jpg width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a53/496/606/a53496606f08a315fdbbdbff363425e5.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a53/496/606/a53496606f08a315fdbbdbff363425e5.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Объектно-ориентированный учёт тоже просился внутрь&lt;/h3&gt;&lt;p&gt;Был ещё один слой, который очень хотелось вставить, — объектно-ориентированный управленческий учёт. Точнее, даже не «хотелось», а он сам постоянно лез в текст. Как только начинаешь объяснять ERP через деятельность, сразу появляются вопросы учёта: что является объектом учёта, что объектом управления, какие аналитики нужны, где факт, где методологическое правило, где источник данных, как собирается себестоимость, как появляется финансовый результат.&lt;p&gt;Например, производственная себестоимость. Можно показать документы и отчёты. Но по-настоящему там надо говорить о прямых материалах, НЗП, выпуске, общепроизводственных расходах, браке, отходах, распределениях и правилах закрытия.&lt;p&gt;Продажи — это не только реализация. Это выручка, скидки, возвраты, дебиторка, деньги, себестоимость продаж, маржа.&lt;p&gt;Бюджетирование — это не просто формы. Это плановые объекты, сценарии, версии, драйверы, правила расчёта, сопоставимость факта и плана.&lt;p&gt;Лимиты БДР и БДДС — вообще отдельная история. Один лимит контролирует право нести расход, другой — право оплатить обязательство. Если это смешать, управленческий контроль становится мутным.&lt;p&gt;Всё это очень интересно. Но для концепции — перегруз.&lt;p&gt;Поэтому управленческий учёт тоже пришлось оставить как отдельную ветку. Он связан с предметным подходом напрямую, но требует своего учебного маршрута. И именно поэтому по этой линии отдельно готовятся мини-курсы Галины по управленческому учёту в 1С:ERP.&lt;p&gt;В статье я не буду уводить туда подробно. Просто фиксирую: это ещё один пласт, который не вошёл не потому, что он не нужен, а потому что в общей концепции его невозможно раскрыть честно и коротко.&lt;h3&gt;Почему сейчас без предметов уже трудно говорить про ИИ&lt;/h3&gt;&lt;p&gt;Если бы вопрос был только в методике внедрения, можно было бы отложить эту тему ещё на несколько лет. Но ИИ всё ускорил. LLM хорошо работает с текстом. Она умеет объяснять, обобщать, формулировать, собирать черновики, помогать с отчётами. Но она не является памятью предприятия.&lt;p&gt;Если дать ей набор документов, она не получит автоматически предметную модель. Она увидит фрагменты. Где-то документ, где-то регламент, где-то отчёт, где-то описание процесса. А связи между предметами начнёт достраивать сама.&lt;p&gt;Иногда это выглядит прилично. В этом и проблема. Плохой ответ легко заметить. А вот уверенный, гладкий, почти правильный ответ — опаснее. Он может чуть-чуть смешать уровни: принять отчёт за источник истины, документ за предмет, статус за бизнес-состояние, общий совет за применимое управленческое действие.&lt;p&gt;Поэтому я всё чаще возвращаюсь к одной мысли: LLM должна быть не источником истины, а интерфейсом к графу знаний. Память предприятия должна жить в проверяемой структуре: предметы, связи, источники, статусы, версии, факты, действия. А LLM должна помогать человеку эту структуру читать. Именно здесь предметно-ориентированный подход становится не философией, а инженерным условием.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/989/1c2/4d1/9891c24d1112b7a659b592dd3014f18c.jpg width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/989/1c2/4d1/9891c24d1112b7a659b592dd3014f18c.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/989/1c2/4d1/9891c24d1112b7a659b592dd3014f18c.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Почему мы всё-таки решили этим поделиться&lt;/h3&gt;&lt;p&gt;Сейчас, оглядываясь назад, я думаю, что решение остановить концепцию на процессном подходе было правильным. Концепция получилась сквозной. Она не развалилась на десяток глубоких боковых тем. Человек может пройти её и увидеть 1С:ERP как систему деятельности, а не как свалку функций. Это уже много. Но предметный слой всё равно остался. Он не исчез. Он просто не вошёл в этот формат.&lt;p&gt;И чем больше вокруг ERP появляется разговоров про ИИ, графы знаний, цифровые двойники и интеллектуальное предприятие, тем очевиднее становится: &lt;strong&gt;этот слой надо выносить отдельно&lt;/strong&gt;.&lt;p&gt;Поэтому я и подготовил небольшую бесплатную методичку на 38 страниц о том, что не вошло в концепцию. Не как замену концепции. Не как критику. И не как «вот теперь настоящая версия». Скорее как рабочие заметки, приведённые в порядок. Если вам интересны бизнес-предметы, различие между ERP-объектом и предметом, граф знаний, LLM как интерфейс и предметно-ориентированный подход к 1С:ERP, можете почитать.&lt;p&gt;Возможно, что-то из этого пригодится в вашей работе.&lt;blockquote&gt;&lt;p&gt;&lt;a href=https://litnet.com/ru/book/chto-ne-voshlo-v-koncepciyu-1serp-2026-goda-ot-uc-1-firmy-1s-b610473 rel=&#34;noopener noreferrer nofollow&#34;&gt;Что не вошло в концепцию 1с:erp 2026 года от Уц №1 фирмы 1с? — Бизнес-литература автора Кирилл Ледовский | Читать онлайн на Литнет&lt;/a&gt;&lt;/blockquote&gt;&lt;h3&gt;Вместо вывода&lt;/h3&gt;&lt;p&gt;Я бы сформулировал так. Кнопочный подход нужен, чтобы войти в систему. Процессный подход нужен, чтобы увидеть деятельность предприятия. Предметный подход нужен, чтобы понять, чем предприятие управляет.&lt;p&gt;В концепцию 1С:ERP вошёл второй уровень — процессный. И это было правильное решение для учебного курса.&lt;p&gt;Третий уровень — предметный — пришлось оставить за рамками. Но, похоже, именно к нему всё равно придётся возвращаться. Потому что интеллектуальное предприятие, к которому все движется, не построить на одних документах, отчётах и красивых ответах LLM. Ему нужны предметы.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>ArgusXII</author>
      <guid>https://habr.com/ru/articles/1051472/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051472</guid>
      <pubDate>Wed, 24 Jun 2026 14:21:57 +0000</pubDate>
    </item>
    <item>
      <title>Как пользоваться Claude AI в России в 2026 году: официальный сайт Клод ИИ, возможности нейросети и доступ без VPN</title>
      <link>https://habr.com/ru/companies/studyai/articles/1051470/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051470</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;За последние полтора года Claude AI из инструмента «для программистов» превратился в универсального рабочего помощника. Сначала его хвалили разработчики — лучше пишет код, аккуратнее ловит баги, дольше держит контекст. Потом подтянулись редакторы, маркетологи, студенты, юристы, аналитики и предприниматели. Причина проста: Claude вчитывается в задачу, спокойно работает с длинными документами и не сбивается на канцелярит к середине ответа.&lt;p&gt;Разберём по порядку: что такое Claude AI, произносится именно как «Клод», но многие все равно называют нейросеть «Клауд АИ», «Клауде ИИ» или «Клоде», какие модели актуальны на июнь 2026 года, в чём его сильные и слабые стороны, как грамотно формулировать запросы и как получить доступ из России без лишней головной боли.&lt;h3&gt;Claude AI в России без VPN&lt;/h3&gt;&lt;p&gt;Россия официально не входит в список стран, где Anthropic предоставляет доступ к Claude.ai и коммерческому API. Прямая регистрация с российским IP и номером +7 недоступна, карты не принимаются, а обычные VPN ведут к блокировкам — Anthropic распознаёт их диапазоны.&lt;p&gt;Нейросеть &lt;a href=&#34;https://eduforms.org/?rid=56fbd8c6d85c842e&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fclaude_opus_47&#34;&gt;Claude&lt;/a&gt; доступна в России без VPN на платформе &lt;a href=&#34;https://eduforms.org/?rid=56fbd8c6d85c842e&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fclaude_opus_47&#34;&gt;&lt;strong&gt;Study AI&lt;/strong&gt;&lt;/a&gt;. Это самый простой способ попробовать возможности модели прямо сейчас — без необходимости использовать зарубежные сервисы или обходить блокировки. Там много и абсолютно &lt;strong&gt;бесплатных версий нейросетей&lt;/strong&gt; на русском языке &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgpt5_mini&#34;&gt;ChatGPT&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgrok41_fast&#34;&gt;Grok&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fdeepseek_v3&#34;&gt;DeepSeek&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fqwen&#34;&gt;Qwen 3&lt;/a&gt; — они бесплатны и доступны без VPN.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/25e/872/b1b/25e872b1be4ea82b65944af871e013dd.png alt=&#34;Claude AI в России&#34; title=&#34;Claude AI в России&#34; width=1536 height=1024 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/25e/872/b1b/25e872b1be4ea82b65944af871e013dd.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/25e/872/b1b/25e872b1be4ea82b65944af871e013dd.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Claude AI в России&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Краткая справка: кто создал Claude и чем он отличается&lt;/h3&gt;&lt;p&gt;&lt;a href=&#34;https://eduforms.org/?rid=56fbd8c6d85c842e&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fclaude_opus_47&#34;&gt;Claude&lt;/a&gt; — это семейство больших языковых моделей компании Anthropic. Её основали в 2021 году бывшие сотрудники OpenAI, среди которых Дарио Амодеи и его сестра Даниэла Амодеи — они ушли из-за разногласий по вопросам безопасности ИИ. Первая публичная версия Claude вышла в марте 2023 года, а к 2026-му модель стала одним из двух-трёх игроков, которым серьёзный бизнес и разработчики доверяют реальные рабочие задачи.&lt;p&gt;Главная ставка Anthropic — не просто умная, а честная и предсказуемая модель. Для этого компания использует подход Constitutional AI: модель обучается не только на человеческих предпочтениях, но и на наборе явных принципов — своего рода «конституции», по которой она сама оценивает свои ответы. На практике это даёт более предсказуемое поведение: Claude реже галлюцинирует, чётче держит инструкции, не пытается угодить пользователю любой ценой и спокойно говорит «не знаю», когда действительно не знает.&lt;p&gt;Ещё одна узнаваемая особенность — &lt;strong&gt;Artifacts&lt;/strong&gt;. Это отдельное окно рядом с чатом, где появляется результат: текст, таблица, код, лендинг, план или документ. С ним можно работать как с живым рабочим объектом — дорабатывать, переписывать, уточнять, не теряя контекст диалога.&lt;h3&gt;Почему Claude AI стал так популярен в России&lt;/h3&gt;&lt;p&gt;У Claude совпало сразу несколько сильных сторон, которые оказались особенно нужны русскоязычной аудитории.&lt;p&gt;&lt;strong&gt;Он хорошо редактирует текст.&lt;/strong&gt; Многие нейросети умеют генерировать текст, но Claude лучше чувствует интонацию и стилистику, аккуратно достраивает мысль и не «съезжает» к середине длинного документа. Поэтому его используют не только копирайтеры — Claude полезен всем, кто пишет посты, статьи, резюме, презентации, учебные работы и тексты для сайтов.&lt;p&gt;&lt;strong&gt;Он удобен для длинных документов.&lt;/strong&gt; Загрузить методичку, договор, ТЗ, расшифровку созвона, исследование или лекцию и попросить пересказать, найти спорные места, объяснить сложный фрагмент или сравнить две версии — типовой сценарий. Именно поэтому Claude быстро вышел за пределы аудитории разработчиков: код нужен не всем, а вот читать и перерабатывать много текста приходится почти каждому.&lt;p&gt;&lt;strong&gt;Он меньше давит шаблонным стилем.&lt;/strong&gt; У многих ИИ-ответов есть узнаваемая болезнь: «в современном мире», «широкий спектр возможностей», «ключевой фактор успеха». Текст вроде правильный, но живого человека за ним не видно. Claude легче настроить: попросить писать проще, суше, резче или без рекламного тона — и он обычно держит эту инструкцию.&lt;h3&gt;Какие модели Claude ИИ актуальны на июнь 2026 года&lt;/h3&gt;&lt;p&gt;Линейка ощутимо обновилась. Старые модели Claude 3, а также Sonnet 4 и Opus 4 первого выпуска (без цифры после точки) уже выведены из обращения. На июнь 2026 года картина такая.&lt;h4&gt;Claude Opus 4.8 AI — текущий флагман&lt;/h4&gt;&lt;p&gt;Вышел 28 мая 2026 года — всего через 41 день после Opus 4.7, что для Anthropic нетипично быстро. Это самая мощная общедоступная модель компании. Главный акцент новой версии — не столько прирост по бенчмаркам, сколько надёжность: по данным Anthropic, Opus 4.8 примерно в четыре раза реже, чем Opus 4.7, оставляет без внимания собственные ошибки в коде.&lt;p&gt;Ключевые характеристики: контекстное окно до 1 млн токенов, адаптивное мышление (модель сама решает, сколько «думать» над задачей в зависимости от её сложности), а также режим Dynamic Workflows для координации сотен параллельных подзадач в Claude Code. Цена — $5 за миллион входных токенов и $25 за миллион выходных. Это правильный выбор для сложной аналитики, агентного программирования и задач, где ошибка дорого стоит.&lt;h4&gt;Claude Sonnet 4.6 AI — рабочая лошадка&lt;/h4&gt;&lt;p&gt;Золотой стандарт для повседневных задач: оптимальный баланс качества, скорости и цены. Полноценный контекст в 1 млн токенов, поддержка расширенного мышления, цена — $3 за миллион входных и $15 за миллион выходных токенов. Если вы не знаете, с чего начать, — начинайте с Sonnet 4.6. На задачах, где разница в качестве с Opus составляет пару процентов, переплачивать в несколько раз нет смысла.&lt;h4&gt;Claude Haiku 4.5 AI — скорость и экономия&lt;/h4&gt;&lt;p&gt;Самая быстрая и дешёвая модель: $1 за миллион входных и $5 за миллион выходных токенов, контекстное окно 200 000 токенов. Идеальна для высоконагруженных сценариев — классификация обращений, извлечение данных из документов, модерация, чат-боты первой линии. Для сложного рассуждения и продакшн-кода — не лучший выбор.&lt;h4&gt;Mythos-класс: Fable 5 и Mythos 5&lt;/h4&gt;&lt;p&gt;В июне 2026 года Anthropic вывела на рынок принципиально новый уровень линейки — Mythos-класс, который стоит выше Opus. &lt;strong&gt;Claude Fable 5&lt;/strong&gt; (9 июня 2026) — самая мощная широко доступная модель компании на сегодня, с постоянно включённым адаптивным мышлением и встроенными классификаторами безопасности. &lt;strong&gt;Claude Mythos 5&lt;/strong&gt; — её версия без таких ограничений, доступная только ограниченному кругу участников программы Project Glasswing. Стоит учитывать, что 12 июня 2026 года Anthropic сообщила о приостановке доступа к Mythos-класс моделям в связи с экспортной директивой регулятора. Доступ к остальным моделям — Opus, Sonnet и Haiku — это не затронуло.&lt;p&gt;&lt;strong&gt;Короткая шпаргалка по выбору.&lt;/strong&gt; Глубокое рассуждение, агентный кодинг, анализ огромного документа — Opus 4.8. Баланс цены и качества для ежедневных задач — Sonnet 4.6. Высоконагруженный пайплайн с тысячами запросов — Haiku 4.5. Сомневаетесь — берите Sonnet 4.6.&lt;h3&gt;Где Claude AI реально полезен — сценарии по ролям&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Редакторам и авторам.&lt;/strong&gt; Claude работает как второй редактор: находит воду, повторы, слабые места, скучные подзаголовки и слишком общие выводы. Пример запроса: «Проверь текст как редактор. Найди места, где слишком общо, скучно или похоже на нейросеть. Не переписывай весь текст — дай конкретные замечания и варианты правок».&lt;p&gt;&lt;strong&gt;Маркетологам.&lt;/strong&gt; Помогает собрать позиционирование, оффер, структуру лендинга, цепочку писем, гипотезы для тестов. Пример: «Вот продукт, аудитория и отзывы. Найди 5 болей аудитории, 5 обещаний, которые можно подтвердить, и 10 идей для рекламных креативов без кликбейта».&lt;p&gt;&lt;strong&gt;Предпринимателям.&lt;/strong&gt; Документы, регламенты, письма, анализ отзывов, разбор коммерческих предложений. Пример: «Сравни два КП. Покажи, где разные условия, какие риски, что уточнить перед оплатой и какие вопросы задать подрядчику».&lt;p&gt;&lt;strong&gt;Студентам.&lt;/strong&gt; Понять тему, собрать план, подготовиться к защите. Важно ставить рамки: «Я пишу курсовую на тему [тема]. Не пиши работу за меня. Помоги сформулировать проблему, цель, задачи, объект, предмет и план. Объясняй простым языком».&lt;p&gt;&lt;strong&gt;Аналитикам и менеджерам.&lt;/strong&gt; Обработка расшифровок встреч, протоколов, фидбека. Пример: «Вот расшифровка созвона. Вытащи решения, задачи, ответственных, сроки, риски и вопросы без ответа».&lt;p&gt;&lt;strong&gt;Разработчикам.&lt;/strong&gt; Отдельный инструмент — &lt;strong&gt;Claude Code&lt;/strong&gt;. Это не веб-чат, а приложение командной строки, которое устанавливается локально, видит структуру проекта, читает и правит файлы, запускает команды и тесты. Поддерживается интеграция с VS Code, Cursor, Windsurf и JetBrains. Отдельная фишка — файл &lt;code&gt;CLAUDE.md&lt;/code&gt;: постоянная «память» проекта с правилами кодирования и архитектурными решениями, которую агент читает при каждом старте сессии.&lt;h3&gt;Как формулировать запросы, чтобы получать хороший результат&lt;/h3&gt;&lt;p&gt;Качество ответа напрямую зависит от качества запроса. Пять принципов, которые сокращают число итераций в разы.&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ставьте цель, а не тему.&lt;/strong&gt; Слабо: «Напиши про email-маркетинг». Сильно: «Напиши структуру письма для реактивации B2B-подписчиков, которые не открывали рассылку 3 месяца. Цель — вернуть к продукту, не через скидку».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Задавайте формат.&lt;/strong&gt; Если важна структура — скажите явно: «Оформи таблицей», «Дай в JSON с полями name и description», «Только тезисы, без развёрнутых объяснений».&lt;li&gt;&lt;p&gt;&lt;strong&gt;Указывайте аудиторию.&lt;/strong&gt; «Объясни, что такое Docker» и «…для маркетолога без технического бэкграунда» — это два разных запроса. Claude подстроит терминологию и примеры.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Задавайте ограничения.&lt;/strong&gt; «Не более 500 слов», «без вводных фраз и воды», «только факты, без рекомендаций». Чем чётче рамки — тем предсказуемее результат.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Работайте итерациями.&lt;/strong&gt; Не пытайтесь получить идеал с первого раза. Получите черновик, укажите, что не так, и попросите доработать конкретный элемент. Claude хорошо держит контекст предыдущих сообщений.&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Рабочий шаблон запроса:&lt;/strong&gt;&lt;pre&gt;&lt;code&gt;Задача: [что нужно сделать]&#xA;Контекст: [кто я, что за проект, какая ситуация]&#xA;Аудитория: [кто будет читать результат]&#xA;Формат: [как должен выглядеть результат]&#xA;Ограничения: [чего избегать]&#xA;Пример: [образец стиля или структуры, если есть]&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;h3&gt;Плюсы и минусы: где нейросеть Claude AI выигрывает, а где уступает&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Длинные тексты и редактура.&lt;/strong&gt; Плюс: стабильно лучше конкурентов на правке, рерайте и работе с большими документами, держит стиль до конца. Минус: на коротких креативных форматах — слоганы, рекламные тексты — конкуренты иногда дают более неожиданный результат.&lt;p&gt;&lt;strong&gt;Следование инструкциям.&lt;/strong&gt; Плюс: лучше всех держит сложные многоуровневые промпты с несколькими ограничениями одновременно. Минус: иногда это оборачивается излишней буквальностью — если инструкция неточная, Claude выполнит именно её, а не то, что вы имели в виду.&lt;p&gt;&lt;strong&gt;Длинный контекст.&lt;/strong&gt; Плюс: до 1 млн токенов у флагманских моделей — это сотни страниц документа или целый репозиторий в одном диалоге, без разбивки на части и сложных RAG-конвейеров. Модель хорошо удерживает детали из начала промпта.&lt;p&gt;&lt;strong&gt;Русский язык.&lt;/strong&gt; Плюс: понимает русский, отвечает без ошибок, хорошо работает с техническими текстами. Минус: на задачах, где важны тонкие культурные реалии и сленг русскоязычного интернета, отдельные конкуренты бывают точнее.&lt;p&gt;&lt;strong&gt;Безопасность.&lt;/strong&gt; Плюс: Constitutional AI даёт предсказуемые отказы и меньше неожиданных сбоев в пайплайне. Минус: на части специфических задач порог срабатывания фильтров выше, чем хотелось бы.&lt;h3&gt;Как пользоваться Claude ИИ в России — способы доступа&lt;/h3&gt;&lt;p&gt;Честный ответ: Россия официально не входит в список стран, где Anthropic предоставляет доступ к Claude.ai и коммерческому API. Прямая регистрация с российским IP и номером +7 недоступна, карты не принимаются, а обычные VPN ведут к блокировкам — Anthropic распознаёт их диапазоны. Тем не менее рабочие способы есть.&lt;p&gt;&lt;strong&gt;Платформы-агрегаторы.&lt;/strong&gt; Самый простой вариант для большинства: сервисы вроде &lt;a href=&#34;https://eduforms.org/?rid=56fbd8c6d85c842e&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fclaude_opus_47&#34;&gt;Study AI&lt;/a&gt; дают доступ к моделям Claude через официальный API. Вы работаете со своего российского IP, платите рублями, а инфраструктуру доступа берёт на себя сервис. Бонус — в одном окне доступны и другие модели: &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgpt5_mini&#34;&gt;ChatGPT&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fgrok41_fast&#34;&gt;Grok&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fdeepseek_v3&#34;&gt;DeepSeek&lt;/a&gt;, &lt;a href=&#34;https://eduforms.org/?rid=f0b91cfaf6daf10b&amp;amp;ulp=https%3A%2F%2Fstudy24.ai%2Fchat%2Fqwen&#34;&gt;Qwen 3&lt;/a&gt;, что удобно для сравнения ответов под разные задачи без отдельных подписок.&lt;p&gt;&lt;strong&gt;Зарубежный VPS для Claude Code.&lt;/strong&gt; Для разработчиков, которым нужен именно Claude Code, оптимально запустить его на зарубежном VPS-сервере (Германия, Латвия — любая страна вне России) и подключаться по SSH. Claude Code работает на сервере напрямую, без VPN, а ряд хостингов принимает оплату рублями.&lt;p&gt;&lt;strong&gt;Официальный доступ из поддерживаемой страны.&lt;/strong&gt; Самый «чистый» путь, но он подходит только тем, кто живёт или работает в регионе, где Claude доступен официально, и не решает задачу для большинства пользователей внутри России.&lt;p&gt;Важное правило для прямого аккаунта: не смешивайте геолокации. Если зарегистрировались с IP одной страны — работайте только с ним. Частая смена геолокации — один из сигналов для блокировки.&lt;h3&gt;Частые вопросы&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Какую модель выбрать?&lt;/strong&gt; Для повседневных задач — Sonnet 4.6 (баланс цены и качества). Для сложного анализа и агентного кодинга — Opus 4.8. Для высоконагруженных пайплайнов — Haiku 4.5.&lt;p&gt;&lt;strong&gt;Можно ли использовать Claude для программирования?&lt;/strong&gt; Да, это одно из сильнейших применений. Claude Code работает прямо в терминале и IDE с доступом к файловой системе проекта, поддерживает VS Code, Cursor, Windsurf и JetBrains.&lt;p&gt;&lt;strong&gt;Работает ли Claude в России?&lt;/strong&gt; Официально страна не поддерживается, прямая регистрация через VPN нестабильна. Рабочие варианты — агрегаторы с оплатой в рублях (например, Study AI) или запуск Claude Code на зарубежном VPS по SSH.&lt;p&gt;&lt;strong&gt;Claude подходит только для текстов?&lt;/strong&gt; Нет. Он работает с текстом, кодом, изображениями и PDF: анализирует данные, пишет и отлаживает код, разбирает документы, строит аналитику.&lt;h3&gt;Итог&lt;/h3&gt;&lt;p&gt;Claude ИИ в 2026 году — это не «ещё один чат-бот». Его сильные стороны конкретны: честность и предсказуемость ответов, огромный контекст до 1 млн токенов, Claude Code для агентного программирования и Artifacts для работы с результатом как с живым объектом. Текущий флагман — Opus 4.8, для ежедневной работы оптимален Sonnet 4.6, для высоконагруженных задач — Haiku 4.5, а на вершине линейки появился Mythos-класс.&lt;p&gt;Главный практический совет: не оценивайте Claude ИИ по одному случайному запросу. Попробуйте на задаче, которая у вас реально болит, — объёмный документ, запутанный кусок кода, черновик важного письма. Именно там видна настоящая разница.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/studyai/articles/1051470/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051470</guid>
      <pubDate>Wed, 24 Jun 2026 14:20:53 +0000</pubDate>
    </item>
    <item>
      <title>Go для сетевой безопасности: почему (и как) мы перешли на net/netip</title>
      <link>https://habr.com/ru/articles/1051464/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051464</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;h3&gt;Почему нам важна производительность?&lt;/h3&gt;&lt;p&gt;Работа с сетевой безопасностью требует внимания к деталям. В компании Netopia мы создаем платформу для непрерывной оценки защищенности и управления политиками межсетевых экранов. Наш продукт помогает контролировать доступы, моделировать трафик по сети и автоматизировать изменения правил. Нам доверяют крупные банки, федеральные компании и операторы связи. И требования по безопасности к продукту предъявляют немаленькие.&lt;p&gt;Когда собираешь большие конфигурации сетевых устройств или интегрируешься с ITSM-системами через API, производительность кода напрямую влияет на надежность сервиса. Основным языком разработки является Go. Мы ценим его за эффективность, но иногда стандартных инструментов становится мало.&lt;p&gt;В этой статье хотим поделиться опытом перехода на библиотеку net/netip. Это решение продиктовано не трендами, а реальной необходимостью оптимизации. Стандартный пакет net не всегда справлялся с нашими объемами данных так эффективно, как хотелось бы. Расскажем, как внедрение &lt;a href=https://pkg.go.dev/net/netip rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;netip&lt;/strong&gt;&lt;/a&gt; помогло сделать платформу быстрее и надежнее.&lt;h3&gt;Ограничения стандартного пакета net&lt;/h3&gt;&lt;p&gt;Большинство разработчиков на Go начинают работу с сетью со стандартного пакета net. И это правильно: он стабилен, хорошо документирован и отлично справляется с типовыми задачами. Для многих проектов его возможностей более, чем достаточно, — он просто работает, позволяя быстро реализовать нужную логику. Однако в Netopia мы работаем с такими объемами данных, что каждая лишняя операция имеет значение.&lt;p&gt;Со временем мы заметили, что при масштабировании стандартный подход начинает упираться в свои ограничения. Главная проблема — наследие архитектуры.&lt;p&gt;Пакет &lt;a href=https://pkg.go.dev/net/netip rel=&#34;noopener noreferrer nofollow&#34;&gt;&lt;strong&gt;net&lt;/strong&gt;&lt;/a&gt; был создан давно, в нем заложены механизмы, которые сегодня считаются избыточными. Особенно это касается валидации IP-адресов. В высоконагруженных контурах сбора телеметрии стандартные методы создают слишком много аллокаций памяти. Это приводит к повышенной нагрузке на сборщик мусора (Garbage Collector) и росту задержек. Когда ты отвечаешь за безопасность банка или оператора связи, такая неэффективность становится непозволительной роскошью. Нам нужно было решение, которое дает тот же уровень удобства, но без скрытых затрат на производительность.&lt;h3&gt;Почему мы выбрали net/netip?&lt;/h3&gt;&lt;p&gt;Решение нашлось в самой экосистеме Go. Начиная с версии 1.18, в стандартной библиотеке появился пакет net/netip. Это не сторонняя библиотека, а официальная, оптимизированная замена старому net, созданная с учетом накопленных ошибок. Для команды безопасности важно минимизировать внешние зависимости, поэтому возможность использовать стандартный инструмент стала решающим фактором. Мы не стали внедрять его сразу «в бою». Сначала провели серию тестов на наших реальных данных, сравнили бенчмарки и убедились: рефакторинг окупится стабильностью. Что именно нам понравилось в net/netip? Вот три ключевых преимущества:&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Отсутствие аллокаций.&lt;/strong&gt; Основные операции работают без выделения памяти в куче. Это резко снижает нагрузку на сборщик мусора, что критично для наших потоков телеметрии.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Производительность.&lt;/strong&gt; Парсинг и сравнение адресов работают заметно быстрее благодаря оптимизированной внутренней структуре.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Безопасность типов.&lt;/strong&gt; Значения в netip неизменяемы (immutable). Это предотвращает случайные ошибки изменения данных и делает код более предсказуемым. Для нас это означало не просто «стало быстрее», а «стало надежнее для клиентов».&lt;/ol&gt;&lt;p&gt;Для нас это означало не просто «стало быстрее», а «стало надежнее для клиентов».&lt;br&gt;&lt;h3&gt;Практика: как это выглядит в коде?&lt;/h3&gt;&lt;p&gt;Чтобы показать разницу в подходах, приведем несколько базовых примеров. Они демонстрируют, как netip упрощает типовые задачи работы с адресами, делая код чище и понятнее.&lt;p&gt;&lt;strong&gt;1. Парсинг IP-адреса&lt;/strong&gt;&lt;p&gt;Вместо сложных проверок мы получаем строгую типизацию сразу на этапе чтения строки:&lt;pre&gt;&lt;code class=go&gt;addr, err := netip.ParseAddr(«192.168.1.1»)&#xA;&#xA;if err != nil {&#xA;&#xA;    // обработка ошибки&#xA;&#xA;}&#xA;&#xA;// addr теперь безопасный объект IP&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;2. Работа с подсетями (Prefix)&lt;/strong&gt;&lt;p&gt;Пакет позволяет легко работать с масками и диапазонами адресов:&lt;pre&gt;&lt;code class=go&gt;prefix, err := netip.ParsePrefix(«10.0.0.0/8»)&#xA;&#xA;if err != nil {&#xA;&#xA;    // обработка ошибки&#xA;&#xA;}&#xA;&#xA;// prefix содержит адрес и длину маски&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;3. Проверка вхождения адреса в подсеть&lt;/strong&gt;&lt;p&gt;Одна из самых частых задач в безопасности решается одним методом без лишних вычислений:&lt;pre&gt;&lt;code class=go&gt;if prefix.Contains(addr) {&#xA;&#xA;    // Адрес находится внутри диапазона&#xA;&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Такой код куда легче читаем. Но, что важнее, он и работает предсказуемо быстро, так как внутри не скрыто лишних аллокаций памяти. Для нас это значит, что даже сложные проверки политик доступа выполняются мгновенно.&lt;h3&gt;На что обратить внимание при миграции?&lt;/h3&gt;&lt;p&gt;Переход на новый инструмент потребовал внимания к деталям. Например, поведение с IPv4-mapped IPv6 адресами здесь строже. В старом пакете они могли неявно приводиться к IPv4, а в netip — нет.&lt;br&gt;Для нас это скорее плюс: правила безопасности должны работать явно и предсказуемо. Мы учли эту специфику при написании фильтров, чтобы избежать ложных срабатываний или пропуска трафика. Также мы обратили внимание на обработку зон в IPv6. Пакет может игнорировать их в префиксах, поэтому мы добавили дополнительную валидацию на входе. Такие мелочи важны, когда речь идет о доступе к инфраструктуре банка. Понимание этих особенностей позволяет нам использовать инструмент максимально эффективно и безопасно.&lt;br&gt;&lt;h3&gt;Стабильность через внимание к деталям&lt;/h3&gt;&lt;p&gt;Для нас важно быть открытыми в таких технических вопросах. Обмен архитектурными решениями — это способ передачи опыта, необходимого для улучшения продукта. Мы предпочитаем внедрять улучшения заранее, опираясь на новые возможности языка и практики сообщества, а не ждать серьезных проблем. Такой подход помогает держать платформу надежной для клиентов, даже когда задачи усложняются. В конце концов, стабильность сервиса складывается именно из таких небольших, но важных оптимизаций и внимания к деталям.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>pavel_kirillov</author>
      <guid>https://habr.com/ru/articles/1051464/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051464</guid>
      <pubDate>Wed, 24 Jun 2026 14:20:47 +0000</pubDate>
    </item>
    <item>
      <title>Процессы vs инструменты: как Авито Sales строит QA с нулевыми сдвигами сроков</title>
      <link>https://habr.com/ru/companies/avito/articles/1050646/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1050646</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Привет, Хабр! На связи &lt;strong&gt;Екатерина Серикова&lt;/strong&gt; и &lt;strong&gt;Глеб Дмитриев&lt;/strong&gt;, мы QA-инженеры в команде &lt;a href=https://clc.to/LV3FBg&gt;&lt;strong&gt;Авито&lt;/strong&gt;&lt;/a&gt; Sales. В этой статье мы расскажем, как выстроили процесс обеспечения качества в Распродаже, где сроки нельзя сдвигать, а нагрузка на корчасть почти 2 млн RPM, а цена бага очень высока.&lt;p&gt;Это не история про «идеальный процесс». Она скорее про рабочую систему, которая помогает не сгореть команде и не терять качество, когда QA в проекте один, а разработчиков восемь.&lt;p&gt;Распродажа на Авито, где 120 млн пользователей, — это всегда высоконагруженные сценарии без права на ошибку. Поэтому в статье мы объясняем, почему важно подключать QA ещё на этапе идеи, а не тестирования. Перекладывание какой части задач на разработку только ускоряет общий процесс? Что можно скормить ИИ, а что следует выполнять самим? Для чего разделять Seller и Buyer контуры?&lt;p&gt;Здесь всё на личном опыте, по делу и понятно.&lt;h3&gt;Содержание:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://section1&gt;&lt;strong&gt;Что такое распродажа и почему с ней сложно&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section2&gt;&lt;strong&gt;Главный принцип: QA подключается на этапе идеи&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section3&gt;&lt;strong&gt;Верификация требований: держим контекст, а не только текст&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section4&gt;&lt;strong&gt;Разработка и тестирование: снимаем боттлнек&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section5&gt;&lt;strong&gt;Почему мы сделали ставку на системные API-flow тесты&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section6&gt;&lt;strong&gt;Где мы применяем ИИ&lt;/strong&gt;&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/rss/all/all/#section7&gt;&lt;strong&gt;Итог&lt;/strong&gt;&lt;/a&gt;&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/14c/177/dd8/14c177dd82e8600c44710232faade4c6.jpg width=1561 height=881 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/14c/177/dd8/14c177dd82e8600c44710232faade4c6.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/14c/177/dd8/14c177dd82e8600c44710232faade4c6.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;a class=anchor id=section1&gt;&lt;/a&gt;&lt;h3&gt;Что такое распродажа и почему с ней сложно&lt;/h3&gt;&lt;p&gt;С точки зрения бизнеса распродажа — это возможность для продавца привлечь покупателя скидкой, а для покупателя — купить товар по наиболее выгодной и честной цене.&lt;p&gt;С точки зрения разработки распродажа — это набор высоконагруженных сценариев и интеграций, где нельзя ошибаться:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Запуски привязаны к заранее запланированным бюджетам и рекламным слотам, дедлайны несдвигаемые;&lt;li&gt;&lt;p&gt;Пиковая нагрузка может вырастать кратно за очень короткий интервал;&lt;li&gt;&lt;p&gt;Много зависимостей между системами и командами;&lt;li&gt;&lt;p&gt;Есть антифрод и антибот-логика;&lt;li&gt;&lt;p&gt;Много продуктовых механик и исключений;&lt;li&gt;&lt;p&gt;Стоимость ошибки в проде очень высокая (нельзя чинить баг дольше, чем идёт распродажа).&lt;/ul&gt;&lt;p&gt;Технически распродажу поддерживают несколько сервисов с разной ролью:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Core–сервисы, в том числе с высокой нагрузкой до миллионов RPM;&lt;li&gt;&lt;p&gt;Клиентские сервисы, которые отдают информацию о скидках;&lt;li&gt;&lt;p&gt;Сервисы управления распродажей для контент–менеджеров;&lt;li&gt;&lt;p&gt;Сервисы механик (антибот/антифрод).&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e07/220/4d7/e072204d7ad687f141c56f3fb1d940ff.png alt=&#34;Тут еще больше контента&#34; title=&#34;Тут еще больше контента&#34; width=1320 height=300 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e07/220/4d7/e072204d7ad687f141c56f3fb1d940ff.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e07/220/4d7/e072204d7ad687f141c56f3fb1d940ff.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;&lt;a href=https://clc.to/Tr2fwQ&gt;Тут еще больше контента&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;a class=anchor id=section2&gt;&lt;/a&gt;&lt;h3&gt;Главный принцип: QA подключается на этапе идеи&lt;/h3&gt;&lt;p&gt;Самая важная часть процесса начинается не на этапе тестирования, а раньше — на этапе идеи. Когда продукт &lt;strong&gt;только придумал новую задачу, но её не описал&lt;/strong&gt;. QA подключается сразу: валидирует идею, задаёт вопросы про риски, ограничения и тестопригодность. На этом этапе проще всего срезать лишнее и сфокусировать команду на критическом функционале.&lt;p&gt;Да, это дополнительная встреча с продуктом, но именно она зачастую срезает основные риски и закладывает в голову мысли, которые продукт будет в состоянии провалидировать выше и принести более детальные требования. Значит, когда команда начнет погружаться в продукт, у QA может быть возможность валидировать решение раньше, где разработчик сможет обстучать идею об QA инженера, а не о продукт, что зачастую также экономит время.&lt;p&gt;Если делать это после UX/UI–исследований или финализации требований, когда задача уже поставлена, то пространство для манёвра становится значительно меньше. &lt;strong&gt;&lt;em&gt;Ранняя же валидация экономит итерации разработки, время продукту, а основные требования становятся прозрачнее и лучше проверяются.&lt;/em&gt;&lt;/strong&gt; Забавно, что все об этом знают, но никто не использует. Мы решили подойти иначе и всё-таки использовать принцип «раннего тестирования».&lt;p&gt;Это кажется дополнительной нагрузкой на QA, но на длинной дистанции экономит время всей команды. QA-инженер — это про деньги, ведь это не только качественный код, но ещё и экономия ресурсов.&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Качество заключается не только в правильных технических решениях или классных автотестах, но и в правильном подходе к разработке, тестированию и требованиям.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;QA-инженер — это тот человек, который способен провалидировать не только идею, но и на чём держать фокус команде и подсветить риски, если таковы есть, экономя этим самым ресурсы и помогая тимлидам.&lt;/p&gt;&lt;a class=anchor id=section3&gt;&lt;/a&gt;&lt;h3&gt;Верификация требований: держим контекст, а не только текст &lt;/h3&gt;&lt;p&gt;Когда требования зафиналены, начинается верификация: нужно убедиться, что документ не расходится с предыдущими договорённостями. Здесь QA выполняет роль хранителя контекста: помнит, о чём договорились на ранних встречах, и помогает команде не терять фокус. Это снижает типичный риск: формально требования написаны, но в реализации всплывают противоречия, которые уже обсуждали, но забыли.&lt;p&gt;Никто не говорит о том, что QA не может забыть или просыпать. Но чем больше точек контроля, тем меньше вероятность. Помните, тестирование не может гарантировать отсутствие багов, зато оно может доказать и показать, что баги есть. Значит, наша задача состоит не в искоренении проблем, а в минимизации рисков и снижении критичности возможных багов. &lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/60b/529/d7f/60b529d7f9762583335e2d98741c1c4a.png alt=&#34;Жми сюда!&#34; title=&#34;Жми сюда!&#34; width=1320 height=300 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/60b/529/d7f/60b529d7f9762583335e2d98741c1c4a.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/60b/529/d7f/60b529d7f9762583335e2d98741c1c4a.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;&lt;a href=https://clc.to/MDY_jw&gt;Жми сюда!&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;a class=anchor id=section4&gt;&lt;/a&gt;&lt;h3&gt;Разработка и тестирование: снимаем боттлнек&lt;/h3&gt;&lt;p&gt;В классической схеме QA часто становится бутылочным горлышком, потому что все задачи сходятся на них перед релизом. Мы же перестроили процесс так, чтобы часть ответственности за качество лежала на разработчике. Тут тимлиды скажут, что &lt;em&gt;за качество ответственна команда&lt;/em&gt;, и здесь мы переносим желание в действительность.&lt;p&gt;Разработчик проходит базовые и критичные кейсы &lt;strong&gt;до передачи задачи&lt;/strong&gt; в тестирование, а также проводит дизайн-ревью вместе с дизайнером до QA-этапа. Это позволяет QA фокусироваться на сложных сценариях, интеграционных рисках и дополнительных кейсах. Также заранее договариваемся о формате приёмки пакетов однотипных задач (например, приёмочные тесты вместо полного цикла).&lt;p&gt;&lt;strong&gt;В результате &lt;/strong&gt;становится меньше лишних итераций, быстрее обратная связь и более предсказуемый time-to-market. &lt;p&gt;Но сразу возникает вопрос: как контролировать то, что разработчик действительно прошёл кейсы? В данном случае очень просто: на этапе приёмочного тестирования. Мы видим, что если «хэпипасс» не работает, это значит, что выше проверка не была произведена. Хоть в чек-листе и стоят все галочки.&lt;p&gt;Давайте быть честными друг к другу. QA инженер может сделать точно также и сказать, что всё работает. Проставить галочки в чек-листах и кейсах, но в итоге не пройти.  В этом и заключается та самая золотая фраза «ответственна за качество вся команда». Значит, нужен процесс, который заставит команду разработки чувствовать эту ответственность. Это работа не только с конкретными людьми, это работа со всей командой, а также с тимлидами. QA-инженер не только про «клики по кнопкам», «написание автотестов», а ещё про процессы, идею и верификацию. И мы это используем в полной мере.&lt;/p&gt;&lt;a class=anchor id=section5&gt;&lt;/a&gt;&lt;h3&gt;Почему мы сделали ставку на системные API-flow тесты&lt;/h3&gt;&lt;p&gt;В одном из кластеров Авито родилась идея сделать инструмент для написания системных API–тестов. Мы активно подключились к его разработке, потому что нам необходим был уровень ниже e2e, но он не доходил до уровня интеграционных тестов. Если представить эту систему как Авито, то внутри неё тоже будут подсистемы, и интеграции между ними нужно тестировать.&lt;p&gt;В проекте распродаж много BDUI-экранов, внешних ручек и интеграций. Поэтому полный акцент на e2e нам не подходил: такие тесты часто проигрывают по скорости и стабильности.&lt;p&gt;Мы сделали основной упор на системный уровень, а именно на сквозные API-flow тесты, потому что они закрывают сквозные сценарии между сервисами, дают быстрый регресс и лучше соответствуют архитектуре данного продукта.&lt;p&gt;Это не отменяет пирамиду тестирования: unit, интеграционные и ручные проверки остаются. Но именно системный слой даёт нам лучшее соотношение скорость/покрытие для этого домена.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/af8/325/97a/af832597a3f088c86e27e10e8e3c1c1c.png alt=&#34;Кликни здесь и узнаешь&#34; title=&#34;Кликни здесь и узнаешь&#34; width=1320 height=300 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/af8/325/97a/af832597a3f088c86e27e10e8e3c1c1c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/af8/325/97a/af832597a3f088c86e27e10e8e3c1c1c.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;&lt;a href=https://clc.to/vtMlJg&gt;Кликни здесь и узнаешь&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;a class=anchor id=section6&gt;&lt;/a&gt;&lt;h3&gt;Где мы применяем ИИ&lt;/h3&gt;&lt;p&gt;Искусственный интеллект для нас не волшебная кнопка, а инструмент для снятия рутины. Чтобы сосредоточиться на рискованных и финальных этапах, мы отдаём ИИ черновую и фоновую работу.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Что отдаём ИИ&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Что не отдаём ИИ&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Генерация и черновая подготовка простых автотестов&lt;td&gt;&lt;p align=left&gt;Сложные продуктовые решения&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Ускорение рутинных операций в QA-процессе&lt;td&gt;&lt;p align=left&gt;Рискованные интеграционные сценарии&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Помощь саппорту через бота, который отвечает по документации, а QA валидирует результат&lt;td&gt;&lt;p align=left&gt;Финальные решения по критичным кейсам&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ИИ ускоряет работу тестировщика там, где цена ошибки низкая и результат легко верифицировать человеком.&lt;p&gt;Один процесс не подходит всем, поэтому мы логично разделили &lt;strong&gt;seller и buyer&lt;/strong&gt; контуры. Распределение на seller и buyer части требует разных акцентов в процессе.&lt;p&gt;&lt;strong&gt;Seller-часть&lt;/strong&gt;&lt;p&gt;В seller-контуре много пользовательских сценариев и ветвлений. Так, для крупных и рискованных задач мы готовим тест-планы, а для быстрых итераций главное не уйти в документацию ради документации. Объём артефактов определяется, учитывая риски и влияние на релиз.&lt;p&gt;В этой части мы дополнительно используем ИИ в рутинной автоматизации и в поддержке саппорта.&lt;p&gt;&lt;strong&gt;Buyer-часть&lt;/strong&gt;&lt;p&gt;В buyer-контуре важны запусковые риски на витрине и операционные ошибки при настройке кампаний. В этой части мы добавили обязательный постмортем после каждого запуска. Важно отдавать высокий приоритет тестированию по критичности, если QA перегружен. Кроме того, необходимо проводить регулярные нагрузочные проверки, примерно раз в квартал, а при критичных изменениях — чаще.&lt;p&gt;&lt;strong&gt;Подсказки для бизнеса &lt;/strong&gt;&lt;p&gt;Как отдельный слой процесса выделили прозрачность для бизнеса. Кроме стандартной работы с требованиями мы отдельно подсвечиваем, какие риски есть в текущей итерации, какие ограничения платформы или решения нужно принять, как будет вести себя продукт в случае реализации риска.&lt;p&gt;&lt;strong&gt;&lt;em&gt;Всё это вместе сильно снижает сюрпризы на запуске и помогает принимать решения осознанно, а не в режиме пожаротушения.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;a class=anchor id=section7&gt;&lt;/a&gt;&lt;h3&gt;Итог&lt;/h3&gt;&lt;p&gt;В обеспечении качества нам помогла комбинация строгости и гибкости. Строгость важна в ранней валидации идеи и верификации требований. Гибкость оказалась необходима в глубине тестирования и на уровне документации.&lt;p&gt;Важно осознанно распределять ответственность между QA и разработчиками, чтобы первые не стали бутылочным горлышком и не затормозили &lt;em&gt;весь&lt;/em&gt; процесс.&lt;p&gt;Практичное применение ИИ возможно на начальных черновых этапах и в рутине.&lt;p&gt;Для удобства тестирования и поддержки мы разделили и выстроили отдельные процессы для seller и buyer контуров.&lt;p&gt;Главный вывод в том, что &lt;strong&gt;&lt;em&gt;QA приносит максимальную ценность не на этапе тестирования готового продукта, а когда решение ещё только формируется&lt;/em&gt;&lt;/strong&gt;.&lt;p&gt;&lt;em&gt;Чем раньше мы подключаемся к обсуждению, тем выше шанс выпустить нужный функционал в срок и без критичных инцидентов.&lt;/em&gt;&lt;p&gt;Если вы сейчас в похожей ситуации: высокая нагрузка, жёсткие дедлайны и ограниченные ресурсы QA, то начните с трёх шагов:&lt;p&gt;1. Подключайте QA к обсуждению идеи до формализации требований.&lt;p&gt;2. Перенесите часть базовой проверки на разработку и зафиксируйте правило «кто что проверяет».&lt;p&gt;3. Выберите один тестовый слой, который даст максимальный эффект именно в вашей архитектуре, и сделайте ставку на него.&lt;p&gt;&lt;strong&gt;&lt;em&gt;Этого уже достаточно, чтобы команда перестала жить в режиме постоянного догона и начала управлять качеством системно.&lt;/em&gt;&lt;/strong&gt;&lt;blockquote&gt;&lt;p&gt;Кстати, если вам интересно не только как в компании выстроены процессы разработки, но и каково в ней работать — сейчас есть возможность высказаться. Хабр совместно с ЭКОПСИ как раз сейчас проводит &lt;a href=https://clc.to/9wf8KA&gt;&lt;strong&gt;большое исследование IT-брендов работодателей.&lt;/strong&gt;&lt;/a&gt; В прошлом году в нём поучаствовали 34 000 специалистов уровня middle и выше. Один голос — это уже данные :)&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/avito/articles/1050646/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1050646</guid>
      <pubDate>Wed, 24 Jun 2026 14:17:47 +0000</pubDate>
    </item>
    <item>
      <title>Okama.io: профессиональные инструменты для анализа инвестиционных стратегий</title>
      <link>https://habr.com/ru/companies/okama/articles/1051450/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051450</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;На Хабре мы уже несколько раз писали про open-source библиотеку &lt;a href=https://github.com/mbk-dev/okama&gt;okama&lt;/a&gt;, предназначенную для анализа инвестиционного портфеля на Python. Но у проекта давно есть «лицо» и для тех, кто не пишет код, — сайт &lt;a href=https://okama.io&gt;okama.io&lt;/a&gt;: набор бесплатных интерактивных инструментов для бэктестинга портфелей, анализа и сравнения отдельных активов и прогнозов. Мы когда-то делали в качестве “развлечения” и демонстрации возможностей окамы. Но со временем okama.io превратился в самостоятельный проект, которым пользуются как в России так и за рубежом.&lt;p&gt;Сайт целиком — open-source. Это приложение &lt;a href=https://github.com/mbk-dev/okama-dash&gt;okama-dash&lt;/a&gt; на &lt;a href=https://dash.plotly.com/&gt;Dash (Plotly)&lt;/a&gt;: весь продукт — финансовая логика, обработка данных и интерфейс — написан на Python и распространяется под лицензией MIT. Под капотом работает та же библиотека okama, что доступна и из кода. Обычно функционал сайта несколько “отстаёт” от библиотеки ввиду необходимости разработки непростого интерфейса, но на сегодня эта разница не так велика.&lt;p&gt;Данные — бесплатные «end of day» исторические котировки и макропоказатели: биржи NYSE, NASDAQ, MOEX, LSE и другие, плюс индексы, крипто- и обычные валюты, товарные активы, ставки и инфляция.&lt;p&gt;Одна особенность сохраняется во всех разделах: всё состояние виджета кодируется в URL. Собрали портфель, настроили параметры — ссылку можно отправить кому угодно, и у него откроется ровно тот же расчёт.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/f2e/294/e95/f2e294e95388aff7b9c15f89d318a84b.png alt=&#34;Кнопка «Copy link»: любое состояние инструмента на okama.io кодируется в URL и передаётся одной ссылкой&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/f2e/294/e95/f2e294e95388aff7b9c15f89d318a84b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/f2e/294/e95/f2e294e95388aff7b9c15f89d318a84b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Кнопка «Copy link»: любое состояние инструмента на okama.io кодируется в URL и передаётся одной ссылкой&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Дальше — короткая экскурсия по разделам сайта…&lt;h3&gt;Efficient Frontier — граница эффективности&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io&gt;Раздел “Граница эффективности”&lt;/a&gt;&lt;p&gt;Инструмент строит границу эффективности для набора активов: для каждого уровня риска находит портфель с максимально возможной доходностью. На графике видно сами активы (в координатах риск/доходность), облако достижимых портфелей и кривую границы — выше неё подняться нельзя. Облако можно строить случайной генерацией (Монте-Карло) или перебором по сетке весов. Рядом доступна “Карта переходов” (transition map), которая показывает как меняется состав оптимизированных портфелей на границе эффективности.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/20e/9f9/5b4/20e9f95b44a1abc5a9da9098e7e373cc.png alt=&#34;Граница эффективности на okama.io: активы, облако достижимых портфелей и кривая границы&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/20e/9f9/5b4/20e9f95b44a1abc5a9da9098e7e373cc.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/20e/9f9/5b4/20e9f95b44a1abc5a9da9098e7e373cc.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Граница эффективности на okama.io: активы, облако достижимых портфелей и кривая границы&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Compare Assets — сравнение активов&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io/compare&gt;Раздел “Сравнение активов”&lt;/a&gt;.&lt;p&gt;Раздел сравнивает несколько активов между собой на общем историческом периоде. Доступны графики баланса (Wealth Index - рост вложенной суммы), накопленная и годовая доходность, скользящий CAGR, матрица корреляций. Под графиком — таблица метрик: CAGR за разные периоды, риск (стандартное отклонение), CVAR, максимальные просадки, коэффициент Шарпа, дивидендная доходность.&lt;p&gt;На примере ниже — wealth index для трёх активов с 2005 года: S&amp;amp;P 500 (SPY.US), золото (GLD.US) и Nasdaq-100 (QQQ.US).&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/13a/260/779/13a260779c1ee2ab1c183a0ca76f90a2.png alt=&#34;Compare Assets на okama.io: индексы богатства SPY.US, GLD.US и QQQ.US на общем периоде&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/13a/260/779/13a260779c1ee2ab1c183a0ca76f90a2.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/13a/260/779/13a260779c1ee2ab1c183a0ca76f90a2.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Compare Assets на okama.io: индексы богатства SPY.US, GLD.US и QQQ.US на общем периоде&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Compare with Benchmark — сравнение с бенчмарком&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io/benchmark&gt;Раздел “Сравнение с бенчмарком”&lt;/a&gt;.&lt;p&gt;Здесь активы сравниваются не друг с другом, а с бенчмарком — индексом или другим активом. Считаются tracking difference (накопленная и годовая), tracking error, коэффициент бета и корреляция — на расширяющемся или скользящем окне.&lt;p&gt;Пример: качество следования двух ETF на индекс S&amp;amp;P 500 — VOO.US (Vanguard) и SPY.US (SPDR) — относительно индекса S&amp;amp;P 500 Total Return. Оба фонда почти точно повторяют индекс, но VOO.US следует за ним заметно плотнее: его годовое отставание около −0,36% против −0,84% у SPY.US (на общем периоде с конца 2010 года).&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/81d/68c/46a/81d68c46a224dd9aa1f61eadfe45bb45.png alt=&#34;Compare with Benchmark на okama.io: годовое отставание (tracking difference) ETF VOO.US и SPY.US от индекса S&amp;amp;P 500 Total Return&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/81d/68c/46a/81d68c46a224dd9aa1f61eadfe45bb45.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/81d/68c/46a/81d68c46a224dd9aa1f61eadfe45bb45.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Compare with Benchmark на okama.io: годовое отставание (tracking difference) ETF VOO.US и SPY.US от индекса S&amp;amp;P 500 Total Return&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Investment Portfolio — анализ портфеля&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io/portfolio&gt;Раздел “Портфель”&lt;/a&gt;.&lt;p&gt;Самый насыщенный раздел. Из активов с заданными весами собирается портфель, для которого можно: выбрать стратегию ребалансировки; задать денежные потоки — регулярные пополнения и изъятия (в том числе с индексацией на инфляцию, снятием процента от текущего размера, динамическими правилами); прогнать прогноз Монте-Карло; подобрать максимально безопасный размер изъятий под заданный горизонт. Считаются баланс портфеля, доходность, просадки, тест распределения доходностей.&lt;p&gt;Пример — классический портфель 60/40 (60% акции SPY.US, 40% облигации AGG.US). Линия портфеля идёт между акциями и облигациями: доходность ниже, чем у чистых акций, зато заметно ровнее — CAGR 8,1%, риск 10,1%, максимальная просадка −32% против −51% у одного S&amp;amp;P 500.&lt;p&gt;Интересная особенность этого раздела - возможность перейти вместе с созданным портфелем в соседние разделы и там его проанализировать (Граница эффективности, Бенчмарк, Сравнение).&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/391/5ad/c11/3915adc11241b9d61a1257c3ab3612e4.png alt=&#34;Investment Portfolio на okama.io: индекс богатства портфеля 60/40 (SPY.US + AGG.US) на фоне его компонентов&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/391/5ad/c11/3915adc11241b9d61a1257c3ab3612e4.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/391/5ad/c11/3915adc11241b9d61a1257c3ab3612e4.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Investment Portfolio на okama.io: индекс богатства портфеля 60/40 (SPY.US + AGG.US) на фоне его компонентов&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Database — поиск по финансовой базе&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io/database&gt;Раздел “База данных”&lt;/a&gt;&lt;p&gt;Поиск по всей базе данных okama: акции, ETF, ПИФы, индексы, валюты (включая криптовалюты), товары, ставки. База разбита на пространства имён (namespaces) — биржи и типы данных: US (биржи США), MOEX (Московская биржа), LSE (Лондон), XETR/XFRA (Германия), CC (крипто), COMM (товары), INDX (индексы), INFL (инфляция), RE (недвижимость) и другие. По каждому инструменту видны тикер, название, страна, биржа, валюта, тип и ISIN.&lt;p&gt;Пример — поиск «AAPL» в пространстве имён US.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/ac7/1c3/5d7/ac71c35d78b3fcea5e832008a8d0b928.png alt=&#34;Database на okama.io: поиск «AAPL» в пространстве имён US&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/ac7/1c3/5d7/ac71c35d78b3fcea5e832008a8d0b928.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/ac7/1c3/5d7/ac71c35d78b3fcea5e832008a8d0b928.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Database на okama.io: поиск «AAPL» в пространстве имён US&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Macro — макроэкономика&lt;/h3&gt;&lt;p&gt;&lt;a href=https://okama.io/macro/inflation&gt;Раздел “Макроэкономика”&lt;/a&gt;&lt;p&gt;Раздел макроэкономических данных различных стран с интерактивными графиками:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Инфляция&lt;/strong&gt; — годовая, скользящая, накопленная и помесячная по странам, с возможностью наложить на график ключевые ставки центробанков;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ставки центробанков&lt;/strong&gt; — ключевые ставки и расчёт реальных ставок (с поправкой на инфляцию);&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAPE10&lt;/strong&gt; — коэффициент Шиллера по 25 странам: текущий срез и историческая динамика.&lt;/ul&gt;&lt;p&gt;На графике — скользящая 12-месячная инфляция по нескольким странам.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/159/745/07a/15974507afa550dc597c87f31c08a35c.png alt=&#34;Macro на okama.io: скользящая 12-месячная инфляция по странам&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/159/745/07a/15974507afa550dc597c87f31c08a35c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/159/745/07a/15974507afa550dc597c87f31c08a35c.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Macro на okama.io: скользящая 12-месячная инфляция по странам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Онлайн-курс по математике портфельных инвестиций по стандартам CFA&lt;/h3&gt;&lt;p&gt;Сайт начинался как набор очень простых виджетов: посчитать доходность, нарисовать график. Со временем он разросся — и сегодня это уже довольно сложный инструмент. Граница эффективности, CVAR, tracking error, стратегии денежных потоков, бэктестинг распределений и прогнозы Монте-Карло — за каждым из этих расчётов стоит серьёзная финансовая математика.&lt;p&gt;Вся математика проекта основана на проверенных временем профессиональных стандартах CFA (Chartered Financial Analyst).&lt;p&gt;Для того, чтобы научиться пользоваться Современной теорией портфеля (СТП) в профессиональной деятельности, мы создали курс &lt;a href=&#34;https://finarium.online/portfolio-maker?utm_source=habr&amp;amp;utm_medium=article&amp;amp;utm_campaign=okama-io-obzor&amp;amp;utm_content=incontent&#34;&gt;«Профессиональное создание инвестиционного портфеля»&lt;/a&gt; в онлайн-школе Финариум. Это единственный в России курс где можно научиться разрабатывать и сопровождать инвестиционные стратегии согласно стандартам CFA.&lt;p&gt;На курсе даётся современная теория портфеля, теория вероятностей и статистика для решения практических финансовых задач по программе CFA с домашними заданиями и дипломной работой. Материалы курса можно использовать в том числе для подготовки к экзамену CFA. Выпускники получают свидетельство о повышении квалификации государственного образца.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c4/06d/a04/2c406da04dce6519a11607422176f1b1.jpg alt=&#34;Онлайн-курс «Профессиональное создание инвестиционного портфеля» — школа инвестиций Финариум, по международным стандартам CFA&#34; sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2c4/06d/a04/2c406da04dce6519a11607422176f1b1.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c4/06d/a04/2c406da04dce6519a11607422176f1b1.jpg 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Онлайн-курс «Профессиональное создание инвестиционного портфеля» — школа инвестиций Финариум, по международным стандартам CFA&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Ссылки&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Сайт: &lt;a href=https://okama.io&gt;okama.io&lt;/a&gt;&lt;li&gt;&lt;p&gt;Библиотека: &lt;a href=https://github.com/mbk-dev/okama&gt;github.com/mbk-dev/okama&lt;/a&gt;&lt;li&gt;&lt;p&gt;Веб-приложение: &lt;a href=https://github.com/mbk-dev/okama-dash&gt;github.com/mbk-dev/okama-dash&lt;/a&gt;&lt;li&gt;&lt;p&gt;Курс: &lt;a href=&#34;https://finarium.online/portfolio-maker?utm_source=habr&amp;amp;utm_medium=article&amp;amp;utm_campaign=okama-io-obzor&amp;amp;utm_content=footer&#34;&gt;«Профессиональное создание инвестиционного портфеля»&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;Другие наши статьи на Хабре про okama:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/companies/okama/articles/798007/&gt;Open Source в финансах. Проект Okama&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/companies/okama/articles/922384/&gt;Ребалансировка инвестиционного портфеля с помощью Python и библиотеки okama&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/companies/okama/articles/1020458/&gt;Создание и тестирование пенсионных инвестиционных стратегий с помощью Okama&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/companies/okama/articles/912096/&gt;Дивидендная доходность Индекса Мосбиржи: как рассчитать за 5 минут с помощью Python&lt;/a&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://habr.com/ru/companies/okama/articles/963262/&gt;Библиотека Python для доступа к данным ЦБ: cbrapi&lt;/a&gt;&lt;/ul&gt;&lt;p&gt;Вопросы, баг-репорты и пул-реквесты приветствуются — проект открытый.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/okama/articles/1051450/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051450</guid>
      <pubDate>Wed, 24 Jun 2026 14:17:22 +0000</pubDate>
    </item>
    <item>
      <title>Seedance в России: как оживлять фото без VPN в 2026 году</title>
      <link>https://habr.com/ru/companies/tsnis/articles/1051456/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051456</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Разбираем, как использовать Seedance в России в 2026 году: доступ, возможности модели, API, оплата, промпты, юридические риски, сценарии для креаторов и бизнеса.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d47/042/253/d470422538a2f9d5e495e05d60da50b5.png width=780 height=440 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d47/042/253/d470422538a2f9d5e495e05d60da50b5.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d47/042/253/d470422538a2f9d5e495e05d60da50b5.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;К 2026 году Seedance в России стал одним из самых востребованных инструментов для создания видеоконтента. Его используют маркетологи, блогеры, SMM‑специалисты и независимые авторы: модель позволяет генерировать ролики до 15 секунд с нативной синхронизацией звука, а также комбинировать текст, изображения, видео и аудио в одном проекте.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3be1f9b1ed1c734eb47de5 data-style id=6a3be1f9b1ed1c734eb47de5 width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;Ниже — подробный разбор, как легально и эффективно работать с Seedance на российском рынке.&lt;h3&gt;Что такое Seedance и за что его любят креаторы из России&lt;/h3&gt;&lt;p&gt;Seedance — семейство моделей генерации видео от ByteDance. Китайская компания, которой принадлежит TikTok, развивает также подразделение Seed, куда входит две нейромодели: Seedream (для изображений) и Seedance (генератор видео). Модели совсем новые — вышли в период с 2024 по 2026 год, но уже лидируют на мировом рынке. &lt;h4&gt;Преимущества модели:&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;1. Поддержка кириллицы.&lt;/strong&gt; Модель стабильно понимает русский язык в промптах и корректно рендерит текст на кириллице в кадре.&lt;p&gt;&lt;strong&gt;2. Мультимодальность. &lt;/strong&gt;Можно загрузить референс‑кадр, аудиодорожку и текстовое описание — Seedance свяжет их в единую сцену.&lt;p&gt;&lt;strong&gt;3. Скорость.&lt;/strong&gt; Рендер 15‑секундного ролика в Full HD занимает 2–4 минуты, в 4K — 6–10 минут.&lt;p&gt;&lt;strong&gt;4. Гибкость стилей.&lt;/strong&gt; Доступны режимы: кинематограф, аниме, 3D‑рендер, документальная стилизация, «под пленку» и др.&lt;p&gt;Отдельно стоит отметить, что Seedance поддерживает Multi-shot сцены. Поясняем: обычная генерация зачастую дает один кадр с легким движением. Multi-shot — более монтажная история: здесь есть общий план, крупный план, смена ракурса, движение камеры, развитие сцены. Для рекламы, клипов и сторителлинга это очень ценно.&lt;h4&gt;Обновленная модель Seedance 2.0&lt;/h4&gt;&lt;p&gt;Сейчас все внимание креаторов приковано к Seedance 2.0, которая вышла в феврале 2026 года. Она поддерживает текст, изображения, видео и аудио, генерирует ролики до 15 секунд, а открытая платформа Seedance 2.0 Fast принимает до 3 видео, 9 изображений и 3 аудиофайлов в качестве референсов.&lt;div class=tm-iframe_temp data-src=https://embedd.srv.habr.com/iframe/6a3be213abbdb97370eed0a2 data-style id=6a3be213abbdb97370eed0a2 width data-habr-games&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Что нового:&lt;/strong&gt;&lt;p&gt;&lt;strong&gt;1. Нативная синхронизация звука и видео.&lt;/strong&gt;&lt;p&gt;В отличие от многих конкурентов, Seedance 2.0 генерирует аудиодорожку (включая диалоги, звуковые эффекты и фоновый шум) одновременно с видео, обеспечивая идеальную синхронизацию губ. Это устраняет необходимость в постпродакшн-работе со звуком. &lt;p&gt;&lt;strong&gt;2. Стабильность персонажей и объектов.&lt;/strong&gt;&lt;p&gt;Модель сохраняет внешность персонажей, костюмы, черты лица, пропорции и освещение между кадрами и сценами. Это особенно важно для создания связного нарратива. &lt;p&gt;&lt;strong&gt;3. Физический движок. &lt;/strong&gt;&lt;p&gt;Seedance 2.0 имитирует гравитацию, динамику жидкостей, преломление света и поведение материалов с высоким реализмом. &lt;p&gt;&lt;strong&gt;4. Длинные промты&lt;/strong&gt;. &lt;p&gt;Длина промпта может достигать 1500 символов, что позволяет детально описать сцену, освещение, поведение персонажей, движение камеры и атмосферу. &lt;p&gt;&lt;strong&gt;5. Поддержка различных соотношений сторон кадра.&lt;/strong&gt;&lt;p&gt;Доступны форматы 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. &lt;p&gt;&lt;strong&gt;6. Высокое разрешение. &lt;/strong&gt;&lt;p&gt;Базовая версия генерирует видео в 1080p, а Pro-версия — в 4K. &lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/f68/161/907/f681619072e41143649bfdc6468bdf3c.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/f68/161/907/f681619072e41143649bfdc6468bdf3c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/f68/161/907/f681619072e41143649bfdc6468bdf3c.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;В независимых тестах Artificial Analysis Seedance 2.0 занял &lt;a href=https://artificialanalysis.ai/video/leaderboard/text-to-video&gt;первое место в категории преобразования текста в видео&lt;/a&gt; (без аудио — оценка Elo 1269, с аудио — 1213) и вошёл в число лучших в преобразовании изображения в видео. Швейцарская консалтинговая компания CTOL назвала его «самой продвинутой доступной моделью генерации видео с ИИ», даже превосходящей Sora 2 и Veo 3.1 в практических тестах.&lt;h3&gt;В каких сценариях использовать Seedance&lt;/h3&gt;&lt;p&gt;Seedance 2.0 — полноценный инструмент для сценарных, постановочных и коммерческих задач. Мы подготовили для вас сценарии под разные роли и цели, с примерами промптов и практическими нюансами.&lt;h4&gt;Для блогеров и авторов коротких видео (Reels, Shorts)&lt;/h4&gt;&lt;p&gt;Быстро получить цепляющий кадр.&lt;p&gt;&lt;strong&gt;Вступление/перебивка.&lt;/strong&gt;&lt;p&gt;3–5 секунд движения камеры к главному объекту.&lt;p&gt;Промпт: «Камера медленно наезжает на чашку кофе на деревянном столе. Тёплый утренний свет, лёгкая дымка, мягкие тени. Стиль — минималистичный лайфстайл. Длительность 4 секунды, формат 9:16. Звук: тихий звон ложки, приглушённый гул кофейни.»&lt;p&gt;&lt;strong&gt;Оживление статичного кадра.&lt;/strong&gt;&lt;p&gt;Загружаете фото (портрет, предмет, интерьер) и добавляете движение.&lt;p&gt;Входные данные: 1 референс‑фото + промпт «добавить плавное движение камеры и атмосферные эффекты».&lt;p&gt;Нюанс: не просите «сильное движение» — лицо или объект может исказиться. Лучше «лёгкий параллакс, плавный зум 5%».&lt;h4&gt;Для маркетинга и e‑commerce&lt;/h4&gt;&lt;p&gt;Показать товар в контексте, чтобы повысить конверсию.&lt;p&gt;&lt;strong&gt;Карточка товара на маркетплейсе.&lt;/strong&gt;&lt;p&gt;Товар в центре, камера делает оборот или лёгкий наезд.&lt;p&gt;Промпт: «Белый беспроводной наушник на тёмном фоне. Камера плавно облетает объект по кругу. Мягкое студийное освещение, лёгкий блик на корпусе. Стиль — чистая продуктовая съёмка. Длительность 8 секунд, формат 1:1. Звук: короткий «клик» в начале, затем тишина.»&lt;p&gt;&lt;strong&gt;Товар в использовании. &lt;/strong&gt;&lt;p&gt;Сцена, где видно, как продукт решает задачу.&lt;p&gt;Промпт: «Женщина наливает воду в стеклянный чайник, пар поднимается. Кухня в скандинавском стиле, естественный свет. Камера следует за движением руки. Длительность 10 секунд, 9:16. Звук: шум воды, тихий свист чайника.»&lt;p&gt;Совет: для серий карточек используйте один и тот же стиль и освещение — так лента выглядит профессиональнее. Seedance хорошо держит консистентность персонажа и окружения при одинаковых референсах.&lt;h4&gt;Для продакшна и студий (превизуализация, раскадровка, фоновые элементы)&lt;/h4&gt;&lt;p&gt;Сэкономить время и бюджет на съёмках.&lt;p&gt;&lt;strong&gt;Превиз сцены.&lt;/strong&gt;&lt;p&gt;Быстро показать клиенту концепцию: локацию, движение камеры, ритм.&lt;p&gt;Входы: 2–3 скетча/референса + текстовый шот‑лист («общий план улицы, затем крупный план лица»). Результат: 12–15 секунд готового ролика, который можно вставить в презентацию.&lt;p&gt;&lt;strong&gt;Фоновые вставки и переходы. &lt;/strong&gt;&lt;p&gt;Абстрактные фоны, дым, огонь, вода, «плёночные» эффекты.&lt;p&gt;Промпт: «Абстрактный фон: медленно перетекающие сине‑фиолетовые волны, лёгкий эффект свечения. Стиль — цифровая живопись. Длительность 5 секунд, 16:9. Без звука.»&lt;p&gt;Такие клипы удобно накладывать поверх интервью или презентации.&lt;h4&gt;Для образовательного контента &lt;/h4&gt;&lt;p&gt;Визуализировать абстрактное или историческое.&lt;p&gt;&lt;strong&gt;Историческая реконструкция.&lt;/strong&gt;&lt;p&gt;Показать, «как это могло выглядеть».&lt;p&gt;Промпт: «Рыцарь в доспехах идёт по каменному коридору замка. Факельный свет, тени на стенах, капли воды стекают по камню. Стиль — кинематографичный реализм. Длительность 12 секунд, 9:16. Звук: эхо шагов, далёкий гул ветра.»&lt;p&gt;&lt;strong&gt;Научная визуализация.&lt;/strong&gt;&lt;p&gt;Микромир, молекулы, процессы.&lt;p&gt;Промпт: «Крупный план: молекула воды движется сквозь мембрану. Стиль — научно‑популярная 3D‑анимация, полупрозрачные структуры, цветовые коды. Камера медленно скользит вдоль траектории. Длительность 8 секунд, 1:1. Звук: мягкий «скользящий» эффект, без слов.»&lt;h4&gt;Для креаторов и арт‑проектов (стилизация, анимация, эксперименты)&lt;/h4&gt;&lt;p&gt;Художественный результат, а не только утилитарный.&lt;p&gt;&lt;strong&gt;Аниме‑стилизация.&lt;/strong&gt;&lt;p&gt;Seedance 2.0 особенно силён в аниме и «гибрид‑стилях».&lt;p&gt;Промпт: «Девушка в школьной форме стоит под дождём. Капли на волосах, отражение в лужах. Стиль — современное аниме, выразительные глаза, глубокие тени. Камера медленно отдаляется. Длительность 15 секунд, 9:16. Звук: капли дождя, отдалённый гул города, лёгкая мелодия.»&lt;p&gt;&lt;strong&gt;Переосмысление фото. &lt;/strong&gt;&lt;p&gt;Берёте своё фото и просите «перерисовать в стиле» (киберпанк, ретро, акварель).&lt;p&gt;Входы: фото + промпт «перерисовать в стиле киберпанк, неоновые огни, дождь, высокая детализация».&lt;p&gt;Нюанс: если хотите сохранить черты лица, добавьте «keep face identity» или используйте 1–2 референса с тем же ракурсом.&lt;h4&gt;Для медиа и новостей (быстрые репортажи, подводки)&lt;/h4&gt;&lt;p&gt;Создать атмосферную подводку к интервью или новости.&lt;p&gt;&lt;strong&gt;Локация и настроение. &lt;/strong&gt;&lt;p&gt;Город, природа, интерьер — чтобы задать тон.&lt;p&gt;Промпт: «Пустая городская улица ранним утром. Туман стелется по асфальту, фонари гаснут. Стиль — реалистичный, кинематографичный. Камера медленно панорамирует. Длительность 10 секунд, 16:9. Звук: далёкий гудок, шелест ветра.»&lt;p&gt;&lt;strong&gt;Абстрактные перебивки.&lt;/strong&gt;&lt;p&gt;Для рубрик и переходов между темами.&lt;p&gt;Промпт: «Вращающиеся геометрические фигуры, градиент от тёмно‑синего к фиолетовому. Лёгкое свечение, частицы. Стиль — минимализм. Длительность 4 секунды, 1:1. Без звука.»&lt;p&gt;&lt;strong&gt;Симуляция интерфейса. &lt;/strong&gt;&lt;p&gt;Анимация переходов в приложении.&lt;p&gt;Промпт: «Экран мобильного приложения: кнопка плавно подсвечивается, появляется всплывающее окно. Стиль — UI‑анимация. Длительность 5 секунд. Звук: лёгкий «пик» при нажатии.»&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/5b5/2d3/fdf/5b52d3fdfe64107c1e2ef7658b653e71.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/5b5/2d3/fdf/5b52d3fdfe64107c1e2ef7658b653e71.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/5b5/2d3/fdf/5b52d3fdfe64107c1e2ef7658b653e71.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Практические советы по пайплайну&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1. Начните с референсов.&lt;/strong&gt;&lt;p&gt;1–3 изображения задают стиль лучше, чем длинные описания.&lt;p&gt;&lt;strong&gt;2. Разбивайте сложные сцены.&lt;/strong&gt;&lt;p&gt;Вместо «битва рыцарей в замке» делайте «рыцарь выходит из двери», «крупный план меча», «общий план зала» — и склеивайте.&lt;p&gt;&lt;strong&gt;3. Тестируйте варианты. &lt;/strong&gt;&lt;p&gt;Делайте 3–5 версий с разными ракурсами и светом — это быстрее, чем дорабатывать один клип.&lt;p&gt;&lt;strong&gt;4. Дорабатывайте в редакторе.&lt;/strong&gt;&lt;p&gt;Обрезка, титры, цветокоррекция и звук — можно сделать в других программах, не тратя токены. &lt;h3&gt;Как использовать Seedance в России&lt;/h3&gt;&lt;p&gt;У пользователя в России есть три основных сценария.&lt;p&gt;&lt;strong&gt;Официальные продукты ByteDance&lt;/strong&gt;&lt;p&gt;Seedance 2.0 связан с китайскими продуктами ByteDance, включая Dreamina AI и Doubao. Проверять доступ нужно вручную: открывается ли площадка, есть ли нужная модель, доступна ли генерация, работает ли скачивание, какие условия коммерческого использования указаны в правилах, получится ли оплатить.&lt;p&gt;Этот путь может подойти тем, кто уже работает с китайскими сервисами и готов разбираться с интерфейсом, регионом и аккаунтом. А вот для российского креатора он часто выглядит сложнее, чем сама генерация.&lt;p&gt;&lt;strong&gt;API-провайдеры&lt;/strong&gt;&lt;p&gt;Seedance доступен через API. Например, Replicate размещает ByteDance Seedance 1 Pro и указывает text-to-video, image-to-video, ролики 5 или 10 секунд, 480p и 1080p. Это удобно разработчикам, сервисам и агентствам, которые хотят встроить видеогенерацию в свой продукт или рабочий пайплайн.&lt;p&gt;У API-провайдеров стоимость может зависеть от длительности и разрешения. Например, &lt;a href=http://Kie.ai&gt;Kie.ai&lt;/a&gt; указывает разные ставки для Seedance V1 Lite и Pro в 480p, 720p и 1080p. Это хороший сигнал для планирования бюджета: короткий тест и финальный ролик в высоком качестве стоят по-разному.&lt;p&gt;Если API нужен для продукта, бота, внутреннего сервиса или регулярной генерации видео, используйте SpeShu. У нас можно подключать нейросети по API, работать с разными моделями в одном контуре и не собирать доступ к каждому зарубежному сервису отдельно. &lt;p&gt;&lt;strong&gt;Агрегаторы нейросетей&lt;/strong&gt;&lt;p&gt;Для российского пользователя это самый безопасный и простой путь — &lt;a href=&#34;https://speshu.ai/?utm_source=media&amp;amp;utm_medium=habr&amp;amp;utm_campaign=kak-ispolzovat-seedance-v-rossii&#34;&gt;платформа&lt;/a&gt;, где разные видеомодели собраны в одном интерфейсе. Такой формат снимает часть проблем с доступом: отдельные зарубежные подписки, разные аккаунты, оплата в нескольких сервисах, проверка каждого сайта.&lt;h3&gt;Юридические риски, связанные с Seedance&lt;/h3&gt;&lt;p&gt;Почти сразу после выпуска Seedance 2.0 столкнулся с юридическими рисками и конфликтами, связанными с нарушением авторских прав. Disney обвинила ByteDance в несанкционированном использовании защищённых авторским правом персонажей из франшиз Star Wars, Marvel — Человека-паука, Дарта Вейдера, Грогу и других. Студия утверждала, что компания использовала пиратские базы данных с этими персонажами для обучения модели, обращаясь с ними как с общедоступными материалами. &lt;p&gt;Кроме того, профсоюз актёров SAG-AFTRA выразил недовольство тем, что технология использует голоса и внешность реальных актёров без их согласия. В интернете распространились фальшивые AI-видео с Томом Крузом, Брэдом Питтом и другими знаменитостями, что вызвало критику за нарушение принципов информированного согласия. &lt;p&gt;Из-за этих претензий ByteDance &lt;a href=https://www.ixbt.com/news/2026/03/15/bytedance-seedance-2-0-disney-paramount.html&gt;временно приостановила глобальный запуск Seedance 2.0&lt;/a&gt;, хотя модель продолжала работать в Китае. По некоторым данным, Seedance 2.0 начала вводить ограничения на типы создаваемого контента: при явном указании в подсказках имитировать конкретных личностей вероятность отказа системы увеличивалась. ByteDance также ограничила функции персонализации в Seedance 2.0 — модель перестала поддерживать загрузку лиц реальных людей в качестве референса для генерации видео. &lt;h4&gt;Риски для пользователей&lt;/h4&gt;&lt;p&gt;Если человек сознательно создаёт контент с изображениями или персонажами, защищёнными авторским правом, и распространяет его в соцсетях без разрешения, он может быть привлечён к ответственности в некоторых юрисдикциях. &lt;p&gt;Правовые стандарты различаются, поэтому перед использованием модели рекомендуется ознакомиться с местным законодательством.&lt;h3&gt;Итог: как использовать Seedance в России в 2026 году&lt;/h3&gt;&lt;p&gt;Seedance — сильная видеомодель для коротких сцен, multi-shot-роликов, оживления фото, продуктовых кадров и визуальных тестов. В России ее удобнее использовать через агрегаторы: без отдельной зарубежной подписки, сложной оплаты и постоянных проверок региона. В &lt;a href=http://SpeShu.AI&gt;SpeShu.AI&lt;/a&gt;&lt;a href=&#34;https://speshu.ai/?utm_source=media&amp;amp;utm_medium=habr&amp;amp;utm_campaign=kak-ispolzovat-seedance-v-rossii&#34;&gt; &lt;/a&gt;можно тестировать Seedance и другие модели для видео в одном месте: подбирать промпты, сравнивать результаты, оживлять фото, собирать сцены для соцсетей и рекламных гипотез без отдельной зарубежной подписки. А для разработчиков есть вариант доступа через API. &lt;p&gt;Для читателей этой статьи действует промокод HABRTSNIS15, который даёт +15% &lt;a href=&#34;https://speshu.ai/?utm_source=media&amp;amp;utm_medium=habr&amp;amp;utm_campaign=kak-ispolzovat-seedance-v-rossii&#34;&gt;на счет агрегатора.&lt;/a&gt;&lt;p&gt;Пробуйте генерировать видео в Seedance. Лучший подход: короткие сцены, свои референсы, чёткий промпт, несколько дублей, монтаж после генерации и аккуратность с правами. Модель может дать сильный визуальный материал, но итоговый ролик всё равно собирает человек.&lt;h4&gt;Где брать идеи и поддержку&lt;/h4&gt;&lt;p&gt;В 2026 году российские креаторы активно делятся шаблонами и промптами в Telegram‑каналах и обсуждениях. У SpeShu есть &lt;a href=https://t.me/+RK_83T2ng1xjODgy&gt;сообщество креаторов&lt;/a&gt;, где показывают свои результаты и разбирают, почему один ролик выглядит кинематографично, а другой — нет. Там публикуют и подборки удачных промптов, и разборы ошибок, и готовые шаблоны.&lt;p&gt;Seedance в России в 2026 году лучше всего раскрывается, когда вы используете его как часть рабочего процесса: референсы + промпты + монтаж. Так вы получаете предсказуемый результат и экономите время, не жертвуя качеством. Если скажете, под какую задачу вам нужно (например, «ролики для маркетплейса» или «аниме‑контент»), подскажу конкретные наборы промптов и референсов.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/tsnis/articles/1051456/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051456</guid>
      <pubDate>Wed, 24 Jun 2026 13:58:10 +0000</pubDate>
    </item>
    <item>
      <title>Бесплатный фото-хостинг на Youtube, Rutube, Telegram, Max</title>
      <link>https://habr.com/ru/articles/1051454/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051454</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;TL;DR: &lt;a href=https://github.com/yaroslaff/smugglerjpg rel=&#34;noopener noreferrer nofollow&#34;&gt;https://github.com/yaroslaff/smugglerjpg&lt;/a&gt; . Из фото делаем слайдшоу видео и его заливаем (можно unlisted/private, чтобы никто не видел). Затем, если надо - скачиваем видео и извлекаем фото.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/webt/5b/50/a6/5b50a670317a3208f7b69c542df24768.jpg sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/webt/5b/50/a6/5b50a670317a3208f7b69c542df24768.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/webt/5b/50/a6/5b50a670317a3208f7b69c542df24768.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;em&gt;На картинке два изображения, оригинальное (слева) и после запаковки-загрузки-скачивания-извлечения (справа). Второе изображение имеет меньшее разрешение, поэтому для сравнения разрешения подогнаны по высоте&lt;/em&gt;&lt;p&gt;Казалось бы, сервисов, где можно хранить фотки (особенно за деньги) - достаточно. И тут я никого не агитирую - если вам что-то нравится и удобно - то и ладушки. Но почему мне это не очень подходит:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ну, во первых - я люблю халяву! Настолько, что ради халявы - не жалко никаких сил и никаких денег!&lt;li&gt;&lt;p&gt;Отечественные сервисы как-то неоднократно дискредитировали себя в моих глазах тем, что на долгой дистанции склонны менять правила игры, как технические, так и тарифы (в том числе обещания, которые дают “навечно”). А фотки - они ведь как заложники. Ты уже не можешь так легко куда-то переехать - они тяжелые, сам переезд будет очень трудоемким.&lt;li&gt;&lt;p&gt;С зарубежными - и этот же аспект остается (хоть и не в такой мере, но все-таки, я еще помню, как хранение на Google Photos было безлимитным и бесплатным). А сейчас, в дополнение, есть сложности с оплатой и санкциями. Нет, я конечно, имею зарубежную карту, но ведь сами понимаете. Сегодня она работает, завтра не работает. Или продлить не получится или пополнить или антифрод не пройдет. Или все пройдет, но скажут, пацан, ты с какого района, мы тут таким не рады - и все.&lt;li&gt;&lt;p&gt;Не храните все яйца в одной корзине! Хоть мы храним, конечно, не яйца (а лишь иногда фото яиц), тем не менее. Но оплачивать 2-3 платных фотохостинга уж точно обидно, а два-три бесплатных - да почему бы и нет?&lt;/ul&gt;&lt;p&gt;Сервисов, куда можно заливать фотки (тот же Телеграм или Макс) - достаточно. Однако, вот приехал я с отпуска, привез несколько сотен фото… Во-первых, заливать их тяжело. А во-вторых - если потребуется обратно, то будет ведь еще тяжелее скачивать.&lt;p&gt;Решение: делаем из фоток - слайдшоу, причем таким образом, чтобы потом было удобно нарезать на фотки обратно (либо без потери в качестве, либо с небольшой потерей).&lt;blockquote&gt;&lt;p&gt;Ты должен сделать добро из зла, потому что его больше не из чего делать&lt;/blockquote&gt;&lt;p&gt;Раз уж у нас есть Макс и Рутуб и мы все равно их оплатили налогами - почему бы не использовать их как фотохостинги? Хоть на что-то сгодятся.&lt;h4&gt;SmugglerJPG - пакуем галерею в одно видео&lt;/h4&gt;&lt;p&gt;Будем использовать вот этот мой проектик - &lt;a href=https://github.com/yaroslaff/smugglerjpg rel=&#34;noopener noreferrer nofollow&#34;&gt;smugglerjpg&lt;/a&gt;.&lt;p&gt;&lt;strong&gt;Ставим&lt;/strong&gt;&lt;p&gt;&lt;code&gt;pipx install smugglerjpg&lt;/code&gt;&lt;p&gt;Если нет pipx - &lt;code&gt;apt install pipx&lt;/code&gt;. Если вы на Windows - наверное, тоже как-то можно поставить. Не пробовал. Еще потребуется &lt;code&gt;ffmpeg&lt;/code&gt; на линуксе.&lt;p&gt;&lt;strong&gt;Делаем видео&lt;/strong&gt;&lt;p&gt;&lt;code&gt;smugglerjpg create /tmp/testgallery/ -a ~/tmp/bgmusic/ -o out.mp4&lt;/code&gt;&lt;p&gt;&lt;code&gt;-a&lt;/code&gt; - можно добавить музыку (тогда можно будет даже самому смотреть и почти не скучно)&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; - продолжительность каждого слайда. (по-умолчанию, 5 секунд)&lt;p&gt;Если хотите чтобы фото шли в определенном порядке, можно указать либо &lt;code&gt;--sort name&lt;/code&gt; / &lt;code&gt;--sort mtime&lt;/code&gt; , либо &lt;code&gt;-f filelist.txt&lt;/code&gt;&lt;p&gt;Дальше заливаем его куда хотим.&lt;h4&gt;Распаковываем нашу контрабанду обратно&lt;/h4&gt;&lt;p&gt;Скачиваем наше видео, или из студии, или прямо через &lt;a href=https://github.com/yt-dlp/yt-dlp rel=&#34;noopener noreferrer nofollow&#34;&gt;yt-dlp&lt;/a&gt; . Распаковываем:&lt;p&gt;&lt;code&gt;smugglerjpg extract out-ytdlp.webm -o /tmp/extracted/&lt;/code&gt;&lt;p&gt;И у нас снова те же картинки (с небольшой потерей в качестве, на мой глаз - не заметно).&lt;h4&gt;Контроль качества&lt;/h4&gt;&lt;p&gt;Исходное фото для примера:&lt;details class=spoiler&gt;&lt;summary&gt;mediainfo testgallery/IMG20260513193409.jpg&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;pre&gt;&lt;code&gt;$ mediainfo testgallery/IMG20260513193409.jpg&#xA;General&#xA;Complete name                            : testgallery/IMG20260513193409.jpg&#xA;Format                                   : JPEG&#xA;File size                                : 10.8 MiB&#xA;&#xA;Image&#xA;Format                                   : JPEG&#xA;Width                                    : 3 072 pixels&#xA;Height                                   : 4 096 pixels&#xA;Color space                              : YUV&#xA;Chroma subsampling                       : 4:2:0&#xA;Bit depth                                : 8 bits&#xA;Compression mode                         : Lossy&#xA;Stream size                              : 10.8 MiB (100%)&#xA;ColorSpace_ICC                           : RGB&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Наш локальный видеофайл:&lt;details class=spoiler&gt;&lt;summary&gt;mediainfo out.mp4&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;pre&gt;&lt;code&gt;$ mediainfo out.mp4 &#xA;General&#xA;Complete name                            : out.mp4&#xA;Format                                   : MPEG-4&#xA;Format profile                           : Base Media&#xA;Codec ID                                 : isom (isom/iso2/avc1/mp41)&#xA;File size                                : 18.8 MiB&#xA;Duration                                 : 35 s 0 ms&#xA;Overall bit rate                         : 4 517 kb/s&#xA;Frame rate                               : 30.000 FPS&#xA;Writing application                      : Lavf61.7.103&#xA;&#xA;Video&#xA;ID                                       : 1&#xA;Format                                   : AVC&#xA;Format/Info                              : Advanced Video Codec&#xA;Format profile                           : Constrained Baseline@L5.1&#xA;Format settings                          : 1 Ref Frames&#xA;Format settings, CABAC                   : No&#xA;Format settings, Reference frames        : 1 frame&#xA;Codec ID                                 : avc1&#xA;Codec ID/Info                            : Advanced Video Coding&#xA;Duration                                 : 35 s 0 ms&#xA;Bit rate                                 : 4 378 kb/s&#xA;Width                                    : 3 840 pixels&#xA;Height                                   : 2 160 pixels&#xA;Display aspect ratio                     : 16:9&#xA;Frame rate mode                          : Constant&#xA;Frame rate                               : 30.000 FPS&#xA;Color space                              : YUV&#xA;Chroma subsampling                       : 4:2:0&#xA;Bit depth                                : 8 bits&#xA;Scan type                                : Progressive&#xA;Bits/(Pixel*Frame)                       : 0.018&#xA;Stream size                              : 18.3 MiB (97%)&#xA;Writing library                          : x264 core 165&#xA;Encoding settings                        : cabac=0 / ref=1 / deblock=0:0:0 / analyse=0:0 / me=dia / subme=0 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=0 / me_range=16 / chroma_me=1 / trellis=0 / 8x8dct=0 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=0 / threads=6 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=0 / weightp=0 / keyint=250 / keyint_min=25 / scenecut=0 / intra_refresh=0 / rc=crf / mbtree=0 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=0&#xA;Codec configuration box                  : avcC&#xA;&#xA;Audio&#xA;ID                                       : 2&#xA;Format                                   : AAC LC&#xA;Format/Info                              : Advanced Audio Codec Low Complexity&#xA;Codec ID                                 : mp4a-40-2&#xA;Duration                                 : 34 s 993 ms&#xA;Source duration                          : 35 s 16 ms&#xA;Bit rate mode                            : Constant&#xA;Bit rate                                 : 132 kb/s&#xA;Channel(s)                               : 2 channels&#xA;Channel layout                           : L R&#xA;Sampling rate                            : 44.1 kHz&#xA;Frame rate                               : 43.066 FPS (1024 SPF)&#xA;Compression mode                         : Lossy&#xA;Stream size                              : 564 KiB (3%)&#xA;Source stream size                       : 565 KiB (3%)&#xA;Default                                  : Yes&#xA;Alternate group                          : 1&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Файл после yt-dlp с youtube:&lt;details class=spoiler&gt;&lt;summary&gt;mediainfo out-ytdlp.webm&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;pre&gt;&lt;code&gt;$ mediainfo out-ytdlp.webm &#xA;General&#xA;Complete name                            : out-ytdlp.webm&#xA;Format                                   : WebM&#xA;Format version                           : Version 4&#xA;File size                                : 12.3 MiB&#xA;Duration                                 : 35 s 48 ms&#xA;Overall bit rate                         : 2 941 kb/s&#xA;Frame rate                               : 30.000 FPS&#xA;Writing application                      : Lavf61.7.103&#xA;Writing library                          : Lavf61.7.103&#xA;&#xA;Video&#xA;ID                                       : 1&#xA;Format                                   : AV1&#xA;Format/Info                              : AOMedia Video 1&#xA;Format profile                           : Main@L5.0&#xA;Codec ID                                 : V_AV1&#xA;Duration                                 : 35 s 0 ms&#xA;Width                                    : 3 840 pixels&#xA;Height                                   : 2 160 pixels&#xA;Display aspect ratio                     : 16:9&#xA;Frame rate mode                          : Constant&#xA;Frame rate                               : 30.000 FPS&#xA;Color space                              : YUV&#xA;Chroma subsampling                       : 4:2:0&#xA;Bit depth                                : 8 bits&#xA;Title                                    : ISO Media file produced by Google Inc.&#xA;Default                                  : Yes&#xA;Forced                                   : No&#xA;Color range                              : Limited&#xA;Color primaries                          : BT.709&#xA;Transfer characteristics                 : BT.709&#xA;Matrix coefficients                      : BT.709&#xA;VENDOR_ID                                : [0][0][0][0]&#xA;&#xA;Audio&#xA;ID                                       : 2&#xA;Format                                   : Opus&#xA;Codec ID                                 : A_OPUS&#xA;Duration                                 : 35 s 41 ms&#xA;Channel(s)                               : 2 channels&#xA;Channel layout                           : L R&#xA;Sampling rate                            : 48.0 kHz&#xA;Bit depth                                : 32 bits&#xA;Compression mode                         : Lossy&#xA;Delay relative to video                  : 7 ms&#xA;Language                                 : English&#xA;Default                                  : Yes&#xA;Forced                                   : No&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;Параметры извлеченной картинки:&lt;details class=spoiler&gt;&lt;summary&gt;mediainfo /tmp/extracted/extracted_slide_003.jpg&lt;/summary&gt;&lt;div class=spoiler__content&gt;&lt;pre&gt;&lt;code&gt;$ mediainfo /tmp/extracted/extracted_slide_003.jpg &#xA;General&#xA;Complete name                            : /tmp/extracted/extracted_slide_003.jpg&#xA;Format                                   : JPEG&#xA;File size                                : 967 KiB&#xA;&#xA;Image&#xA;Format                                   : JPEG&#xA;Width                                    : 1 620 pixels&#xA;Height                                   : 2 160 pixels&#xA;Color space                              : YUV&#xA;Chroma subsampling                       : 4:2:0&#xA;Bit depth                                : 8 bits&#xA;Compression mode                         : Lossy&#xA;Stream size                              : 967 KiB (100%)&#xA;&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&lt;h4&gt;Замечания, советы&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Видео на ютубе можно хранить как unlisted или private. Или вообще как Draft!&lt;li&gt;&lt;p&gt;Разрешение видео на практике - все-таки одно на всю продолжительность видео. Таким образом, если мы в видео держим одновременно и вертикальные и горизонтальные фотки - потери качества будут выше. С другой стороны, сейчас в телефонах столько мегапикселей что я после этой процедуры не замечаю разницы.&lt;li&gt;&lt;p&gt;Делалось LLM’кой, так что, сами понимаете.&lt;/ol&gt;&lt;p&gt;Пользуйтесь, и храните свои приятные воспоминания!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>xenon</author>
      <guid>https://habr.com/ru/articles/1051454/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051454</guid>
      <pubDate>Wed, 24 Jun 2026 13:55:07 +0000</pubDate>
    </item>
    <item>
      <title>Секрет устойчивых платформ для умного города: SOLID, GRASP и Clean Architecture в деле</title>
      <link>https://habr.com/ru/companies/falcontech/articles/1051438/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051438</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;em&gt;Запускаем большой проект? Значит, берём SOLID. Мы не раз слышали это от CPO и менеджеров продукта. О нём, кажется, знают все — и все хотят применить. Но он не спасёт масштабные проекты. Например, устойчивый умный город с решениями на основе машинного зрения на одном SOLID не построить. По канонам SOLID можно писать аккуратный код, но это не создаст архитектуру всей системы. Что на самом деле работает — подобранный под бизнес-цели набор инструментов, направленный на защиту ядра приложения.&lt;/em&gt;&lt;p&gt;&lt;em&gt;В статье — кейс Сергея Францишкова, начальника отдела разработки «Фалькон Тех», о рабочих решениях для крупной архитектуры и внедрении GRASP + Clean Architecture.&lt;/em&gt;&lt;p&gt;Мы — команда инженеров «Фалькон Тех», и уже 8 лет мы разрабатываем ПО с использованием ИИ и машинного зрения. За это время создали систему из более чем 3 000 программно-аппаратных комплексов в Москве. В прошлой статье рассказали, на каком стеке и железе работает видеоаналитика в мегаполисах.&lt;p&gt;Сегодня поделимся кейсом перехода с «голого» SOLID на рабочую систему SOLID + GRASP + Clean Architecture. Благодаря такому принципу проектирования бизнес-логика, работа видеоаналитики и в целом наша система комплексов не рухнут, даже если завтра город решится на кардинальные инфраструктурные изменения.&lt;p&gt;Из статьи вы узнаете:&lt;ul&gt;&lt;li&gt;&lt;p&gt;зачем нужна архитектура и что работает помимо SOLID;&lt;li&gt;&lt;p&gt;как GRASP и Clean Architecture помогают на крупных проектах;&lt;li&gt;&lt;p&gt;как организовать кодовую базу так, чтобы она выдерживала смену технологий.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Зачем вообще архитектура&lt;/strong&gt;&lt;p&gt;Цифровые системы должны помогать бизнесу повышать операционную эффективность, сокращать издержки и снижать риски. Для этого они должны состоять из связанных компонентов, которые вместе приносят результат. Некоторые реализуют God Object и всё связывают со всем. Этого нужно избегать — иначе одно исправление кода рискует навредить системе. А если она масштабна — например, охватывает целый город, — очень важно сделать её устойчивой к изменениям. При этом необходимо не допустить и другой крайности, чтобы она не развалилась на независимые кусочки. Следовательно, для системы нужна единая архитектура.&lt;p&gt;Есть две цели создания архитектуры:&lt;ul&gt;&lt;li&gt;&lt;p&gt;повысить внутреннее качество кода; повысить прозрачность и ясность бизнес доменов. Все это упростит сопровождение и расширение системы.&lt;li&gt;&lt;p&gt;изолировать бизнес-логику от инфраструктуры, чтобы безболезненно менять фреймворки, базы данных, плагины и т. п.&lt;/ul&gt;&lt;p&gt;Архитектура помогает удерживать систему «в форме». Ниже рассказываем, что для этого делать. Но сначала дисклеймер: упомянутые в статье инструменты направлены на защиту ядра — главенствующей функциональности.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/077/89c/063/07789c063db43bc8b6d72a0ae6d084ca.png width=2062 height=1228 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/077/89c/063/07789c063db43bc8b6d72a0ae6d084ca.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/077/89c/063/07789c063db43bc8b6d72a0ae6d084ca.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;div class=floating-image&gt;&lt;p&gt;&lt;strong&gt;Почему одного SOLID мало&lt;/strong&gt;&lt;p&gt;SOLID — это пять принципов ООП:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;S (Single Responsibility)&lt;/strong&gt; — у сущности или её поведения запросы на изменения должны исходить от одного источника ответственности&lt;li&gt;&lt;p&gt;&lt;strong&gt;O (Open-Closed) &lt;/strong&gt;— система должна быть открыта для расширения и закрыта для изменения.&lt;li&gt;&lt;p&gt;&lt;strong&gt;L (Liskov Substitution, принцип Барбары Лисков)&lt;/strong&gt; — наследуемые сущности должны использоваться наравне с родительскими, без нарушения родительского контракта. Если есть объект A и объект B (наследник объекта A), в случае замены A на B в коде, система продолжит работать корректно с предсказуемым поведением, вне зависимости от знания, что используются сущности от наследников.&lt;li&gt;&lt;p&gt;&lt;strong&gt;I (Interface Segregation)&lt;/strong&gt; — большие интерфейсы хуже маленьких. Классу проще реализовать несколько, более специфичных ему, интерфейсов, чем тянуть за собой один громоздкий интерфейс с кучей ненужных методов.&lt;li&gt;&lt;p&gt;&lt;strong&gt;D (Dependency Inversion) &lt;/strong&gt;— зависимости должны быть направлены к ядру системы и не должны тянуть за собой детали реализации. Детали реализации должны исходить от клиентского взаимодействие, если ему требуется работать с инфраструктурными элементами (HTTP-подключение, клиент, CLI-взаимодействия), то реализация взаимодействия определяется на внешнем уровне. Это делает зависимости и интерфейсы гибче и устойчивее.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;SOLID — не гарантия чистой системы&lt;/strong&gt;&lt;p&gt;Принципы SOLID — это рекомендации по созданию поддерживаемых сущностей низкого уровня, например классов, объектов, модулей. В то время как Clean Architecture — это архитектурный шаблон более высокого уровня, который организует все приложение по слоям для обеспечения разделения задач, логики, абстракций. Но в реальных больших продуктах остаются структурные «дыры»:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Сильная связанность&lt;/strong&gt; — SOLID не регламентирует, как модули и слои системы будут общаться. Иногда возникает скрытая тесная связь между подсистемами.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Дублирование логики&lt;/strong&gt; — принципы S и I улучшают объект, но не решают проблему дублирования бизнес-правил. Становится сложно вносить изменения за счёт связанности отображения с поведением.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Инфраструктура ломает ядро&lt;/strong&gt; — даже при соблюдении D инфраструктурные особенности «протекают» в домен через адаптеры и DTO. Ядро оказывается чувствительным к изменениям.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;GRASP как следующий уровень&lt;/strong&gt;&lt;p&gt;SOLID — набор концепций о том, как должен быть устроен класс, структура, модуль, а GRASP (General Responsibility Assignment Software Patterns) — набор паттернов, который описывает взаимодействие между классами и структурами.&lt;p&gt;Основные паттерны GRASP:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Information Expert&lt;/strong&gt; — Если объект обладает всей или большей частью информации, необходимой для выполнения операции, то именно он ее и должен производить.&lt;br&gt;&lt;br&gt;Если нужно сделать расчёт финальной стоимости заказа, имеет смысл поместить этот расчёт в объект заказа, а не выносить это в отдельную структуру, которой придется запрашивать данные.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Controller&lt;/strong&gt; — отвечает за обработку внешних событий и координацию поведения.&lt;br&gt;&lt;br&gt;Компонент, на границе домена/системы, который связывает основную логику с внешним миром. К примеру это может быть отдельный веб-сервис с http/grpc эндпоинтами, CLI-утилита, rabbit/nats consumer и пр.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator&lt;/strong&gt; — объект создает другой объект, если он им владеет или его использует.&lt;br&gt;&lt;br&gt;Креатор — это не фабричный метод. Это правило, что мы должны давать возможность классу или структуре порождать другие объекты. А вот уже способом реализации будет фабричный метод или порождающий паттерн.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Низкая связанность (low coupling)&lt;/strong&gt; — компоненты минимально зависят друг от друга.&lt;br&gt;&lt;br&gt;Когда компонент использует логику или данные другого компонента, это создает связность между ними. Ее нужно стараться уменьшить. Понятно, что компоненты находятся не в вакууме и избежать взаимодействия вряд ли получится. Но важно, чтобы один компонент не начинал пользоваться внутренними деталями другого как своими.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Высокая связанность (high cohesion)&lt;/strong&gt; — внутри компонента всё максимально логически связано, а лишние методы/поля выносятся наружу или выделяются в другой компонент, действуя по такому же принципу логического объединения и сфокусированности.&lt;br&gt;&lt;br&gt;Высокая связанность относится непосредственно к компоненту. Чем активнее логика и используемые ею данные внутри одного компонента взаимодействуют друг с другом, тем выше его связанность — и это хорошо. Компонент должен быть цельным. А если внутри компонента есть логика, которая плохо фокусирует выполняемые задачи компонента, ее стоит выделить в отдельный компонент вместе с зависимыми данными.&lt;/ul&gt;&lt;p&gt;Если резюмировать, GRASP — системное мышление в проектировании: он защищает от ситуации, когда бизнес-логика «размазана» по интерфейсам и вспомогательным компонентам. Мы ищем и обучаем специалистов, которые умеют с ним работать, чтобы делать качественные продукты. Читайте подробнее &lt;a href=https://career.habr.com/companies/st-falcon&gt;на Хабр Карьере.&lt;/a&gt;&lt;p&gt;Чистая архитектура (Clean Architecture) в реальном проекте&lt;p&gt;Максимально кратко, SOLID говорит, как проектировать компоненты, GRASP объясняет, как распределять обязанности между ними, а Clean Architecture — делает систему независимой от инфраструктуры.&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;«Термин Clean Architecture ввёл Роберт Мартин. Он считал, что бизнес-логика должна быть независимой от деталей реализации, а инфраструктуре необходимо подключаться как «плагины». Не ядро зависит от базы данных, а наоборот — технологии подключаются к приложению как сменные модули.»&lt;/em&gt;&lt;p&gt;– Цитата эксперта&lt;/blockquote&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/dde/52b/537/dde52b5374336e0251856efde9a85191.jpg alt=&#34;Изображение: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&#34; title=&#34;Изображение: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&#34; width=772 height=567 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/dde/52b/537/dde52b5374336e0251856efde9a85191.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/dde/52b/537/dde52b5374336e0251856efde9a85191.jpg 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Изображение: &lt;a href=https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&gt;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&lt;/a&gt;&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Четыре слоя Clean Architecture&lt;/strong&gt;&lt;p&gt;Классическая схема чистой архитектуры включает четыре слоя. На практике не часто проводят грань между слоем фреймворка и инфраструктуры. Делают это для упрощения и ввиду того, что они часто разрабатываются вместе. Поэтому дальше они будут фигурировать как один слой.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/1d6/78a/8dd/1d678a8ddb8748014d69f4d81456c0c5.png width=421 height=300 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/1d6/78a/8dd/1d678a8ddb8748014d69f4d81456c0c5.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/1d6/78a/8dd/1d678a8ddb8748014d69f4d81456c0c5.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Получается так:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Домен — бизнес-сущности и правила;&lt;li&gt;&lt;p&gt;Приложение — что система должна делать;&lt;li&gt;&lt;p&gt;Инфраструктура и фреймворки — базы данных, REST/gRPC, API.&lt;/ul&gt;&lt;p&gt;Все зависимости направлены внутрь, в сторону бизнес-логики. Так система становится модульной и устойчивой к изменениям технологий. Также часто выделяют отдельный слой под различные утилитарные задачи. Это модуль, который содержит вспомогательные функции, данные и прочее, их часто переносят из проекта в проект. Этот слой не участвует в бизнес-логике и может использоваться в любом другом слое без нарушения зависимости.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/511/41d/0ff/51141d0ffce9b74d9a91ee2f9fb3123e.png width=525 height=285 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/511/41d/0ff/51141d0ffce9b74d9a91ee2f9fb3123e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/511/41d/0ff/51141d0ffce9b74d9a91ee2f9fb3123e.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Как наложить Clean Architecture на реальный код&lt;/strong&gt;&lt;br&gt;(на примере сервиса Offense Collector в умном городе)&lt;p&gt;Как Clean Architecture выглядит в репозитории и почему это удобно? Возьмём реальный кейс из систем умного города. Сервис Offense Collector собирает доказательную базу для возможности оформления нарушений из разных источников.&lt;p&gt;&lt;strong&gt;Создание архитектуры&lt;/strong&gt;&lt;p&gt;Мы использовали «кричащую» архитектуру — когда имена модулей говорят, что за что отвечает. Это разгружает мозг разработчика.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/b94/d4a/1ca/b94d4a1ca10aff8615717954ec95afe0.png alt=&#34;Структура проекта по папкам&#34; title=&#34;Структура проекта по папкам&#34; width=349 height=353 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/b94/d4a/1ca/b94d4a1ca10aff8615717954ec95afe0.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/b94/d4a/1ca/b94d4a1ca10aff8615717954ec95afe0.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Структура проекта по папкам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Папка с infrastructure содержит модули setup, worker и реализации клиентов. В папке application лежат репозиторий и модуль use_cases с пользовательскими сценариями. И последний слой domain, который содержит бизнес-сущность правонарушения и её логику.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/4d8/fe8/fde/4d8fe8fde1e4a98be6fb463aef0bb078.png alt=&#34;Структура проекта по папкам&#34; title=&#34;Структура проекта по папкам&#34; width=518 height=301 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/4d8/fe8/fde/4d8fe8fde1e4a98be6fb463aef0bb078.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/4d8/fe8/fde/4d8fe8fde1e4a98be6fb463aef0bb078.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Структура проекта по папкам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=&#34;bordered full-width&#34;&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/f26/85e/d19/f2685ed19979013b476e5c1b1735f4c1.png alt=&#34;Структура проекта по папкам&#34; title=&#34;Структура проекта по папкам&#34; width=520 height=193 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/f26/85e/d19/f2685ed19979013b476e5c1b1735f4c1.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/f26/85e/d19/f2685ed19979013b476e5c1b1735f4c1.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Структура проекта по папкам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a04/20e/caa/a0420ecaafa86b23ad8eeb3a1ca6368b.png alt=&#34;Структура проекта по папкам&#34; title=&#34;Структура проекта по папкам&#34; width=507 height=232 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a04/20e/caa/a0420ecaafa86b23ad8eeb3a1ca6368b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a04/20e/caa/a0420ecaafa86b23ad8eeb3a1ca6368b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Структура проекта по папкам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Папка с репозиториями — это набор интерфейсов по паттерну репозиторий, определяющий обмен данными, как пример с СУБД. На слое приложения их реализации нет — она лежит на уровне инфраструктуры.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/561/efe/347/561efe3473c0d4a5108633f5201e41c9.png width=525 height=297 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/561/efe/347/561efe3473c0d4a5108633f5201e41c9.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/561/efe/347/561efe3473c0d4a5108633f5201e41c9.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Дальше идёт реализация конкретного сценария системы (use cases).&lt;p&gt;&lt;strong&gt;Внедрение use cases&lt;/strong&gt;&lt;p&gt;Один из ключевых элементов слоя приложения — это структура use cases. Рассмотрим конкретный случай — обработку, фиксацию и отправку сформированного сообщения с необходимыми данными для доказательной базы (далее - парсель). Если посмотреть на код, то внутри метода происходит следующее:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/3c1/834/580/3c1834580e71c30cb4ec54fe2c43567e.png alt=&#34;Пример проекта use case&#34; title=&#34;Пример проекта use case&#34; width=545 height=302 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/3c1/834/580/3c1834580e71c30cb4ec54fe2c43567e.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/3c1/834/580/3c1834580e71c30cb4ec54fe2c43567e.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пример проекта use case&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Берём данные из репозиториев;&lt;li&gt;&lt;p&gt;Преобразуем их в доменные сущности;&lt;li&gt;&lt;p&gt;Передаём дальше.&lt;/ol&gt;&lt;p&gt;Всё. Сценарий — инструкция, а реализации каждого шага — отдельные функции. Антикоррупционный слой здесь нужен только потому, что данные снаружи не совпадают с тем, что ожидает домен. Если убрать эту прослойку, метод сводится к линейной инструкции.&lt;p&gt;На уровне приложения зависимости есть только от своего слоя и доменного слоя.&lt;br&gt;Домен — автономен, никак не завязан на инфраструктуру, библиотеки и фреймворки.&lt;p&gt;&lt;strong&gt;Создание точка входа&lt;/strong&gt;&lt;p&gt;main — место, где собираются плагины. Главный компонент производит инициализацию клиентов Rabbit/HTTP, баз, инстансов репозиториев — всего, что нужно юзкейсу, и сам юзкейс. Дальше происходит запуск.&lt;figure&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/83a/a08/776/83aa087765ae552d4cdd12960f4f3964.png alt=&#34;Пример входной точки main&#34; title=&#34;Пример входной точки main&#34; width=508 height=298 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/83a/a08/776/83aa087765ae552d4cdd12960f4f3964.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/83a/a08/776/83aa087765ae552d4cdd12960f4f3964.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пример входной точки main&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;«Такая чистая архитектура очень выгодна, если в будущем придётся поменять технологии. Например, сегодня use case получает события через RabbitMQ. Завтра нужно перейти на HTTP-сервер. Мы изменим только адаптер, который передаёт событие в сценарий. Весь остальной код трогать не будем.»&lt;/em&gt;&lt;p&gt;— Андрей Борисов, Старший back-end разработчик в «Фалькон Тех»&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;Что это дает бизнесу&lt;/strong&gt;&lt;p&gt;Обобщим плюсы подхода:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Понятная структура проекта (кричащая архитектура);&lt;li&gt;&lt;p&gt;Устойчивость бизнес-логики и ядро, не завязанное на фреймворках;&lt;li&gt;&lt;p&gt;Возможность тестирования без инфраструктуры, простота для QA;&lt;li&gt;&lt;p&gt;Защита от «грязного кома»: разделение слоёв, зоны ответственности, контролируемые зависимости.&lt;/ul&gt;&lt;p&gt;И, конечно, чистый код, в котором каждый слой независим и изменения в одном слое не ломают другие.&lt;p&gt;Замена технологий (например, RabbitMQ → HTTP) проводится без исправления бизнес-логики. Мы получаем эволюцию проекта вместо переписывания его частей. Минусы тоже есть: высокий порог входа, множество файлов и невысокая скорость разработки — сочетание фреймворков не подходит для коротких проектов. Но если речь о крупных системах с использованием новых технологий, когда нужны ИИ и машинное зрение, этот подход работает.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Плюсы&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Минусы&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Чёткая структура приложения.&lt;br&gt;Даже новичку понятно, где что искать.&lt;td&gt;&lt;p align=left&gt;Порог входа выше. Нужно разбираться&lt;br&gt;в слоях, зависимостях, интерфейсах.&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Слабая связанность компонентов.&lt;br&gt;Можно менять инфраструктуру,&lt;br&gt;не затрагивая бизнес-логику.&lt;td&gt;&lt;p align=left&gt;Сложно применять на маленьких проектах или MVP, где ценится скорость.&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Упрощённое тестирование.&lt;br&gt;Нет необходимости в тяжёлых моках&lt;br&gt;или окружениях.&lt;td&gt;&lt;p align=left&gt;Много файлов, интерфейсов, структур — можно запутаться при плохом нейминге.&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Возможность делегирования.&lt;br&gt;Каждый слой может разрабатываться независимо.&lt;td&gt;&lt;p align=left&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;В одиночку SOLID не спасет&lt;/strong&gt;&lt;p&gt;Резюмируем: SOLID нужен, но сам по себе большие проекты он не спасает. Однако, если добавить к нему GRASP + Clean Architecture, это комбо даст устойчивость и гибкость.&lt;p&gt;&lt;strong&gt;Практические рекомендации:&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Не отказываться от SOLID, потому что он помогает делать аккуратные компоненты.&lt;li&gt;&lt;p&gt;Понять, как реализовано взаимодействие между компонентами и интерфейсами.&lt;li&gt;&lt;p&gt;Применить GRASP — определить, что за что отвечает.&lt;li&gt;&lt;p&gt;Использовать Clean Architecture и делать систему независимой.&lt;/ul&gt;&lt;p&gt;Важно понимать, что архитектура — это не финишный пункт, а дорожная карта. Со временем требования меняются, и появляются новые сценарии. И поддерживаемая чистая архитектура позволяет постепенно развивать систему без головной боли.&lt;p&gt;&lt;strong&gt;Желаем удачи на ваших проектах,&lt;br&gt;Команда инженеров «Фалькон Тех»&lt;/strong&gt;&lt;p&gt;Нравятся строгие правила кодинга, системность и чистая архитектура?&lt;br&gt;Заходи на &lt;a href=https://career.habr.com/companies/st-falcon&gt;Хабр Карьеру&lt;/a&gt; — там делимся нашими условиями, требованиями к кандидатам, вакансиями с указанной зарплатой.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/falcontech/articles/1051438/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051438</guid>
      <pubDate>Wed, 24 Jun 2026 13:35:51 +0000</pubDate>
    </item>
    <item>
      <title>Как мы перестраивали работу аналитиков под разработку с ИИ-агентами и SDD</title>
      <link>https://habr.com/ru/companies/jetinfosystems/articles/1051370/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051370</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/228/15f/4aa/22815f4aa3704acb780abdd7405aec06.png width=550 height=400 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/228/15f/4aa/22815f4aa3704acb780abdd7405aec06.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/228/15f/4aa/22815f4aa3704acb780abdd7405aec06.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Всем привет! Я Светлана Забирова, лид аналитики в Центре разработки и машинного обучения компании «Инфосистемы Джет». В ИТ работаю уже больше десяти лет, из них половину – в заказной разработке.&lt;p&gt;В одной из недавних статей моя коллега уже &lt;a href=https://habr.com/ru/companies/jetinfosystems/articles/1032034/&gt;делилась опытом&lt;/a&gt;, как искусственный интеллект повлиял на результаты одной из наших команд разработки. Сегодня посмотрим на процесс с точки зрения аналитика.&lt;p&gt;По заданному контексту ИИ хорошо справляются с кодом, миграциями, OpenAPI, сценариями и документацией. Но агентная разработка быстро начинает буксовать, если входной артефакт остается большой постановкой в Confluence, Word или Jira без строгой структуры и трассировки. Модель теряет важные условия, смешивает уровни детализации, дублирует требования или додумывает недостающие связи.&lt;p&gt;ИИ не будет работать лучше, если аналитики просто «начнут промптить». Задача решается уровнем выше: требования должны стать инженерным артефактом. То есть относиться к требованиям нужно так же, как разработчики относятся к коду:&lt;ul&gt;&lt;li&gt;&lt;p&gt;хранить их в системе контроля версий;&lt;li&gt;&lt;p&gt;проводить ревью изменений;&lt;li&gt;&lt;p&gt;фиксировать архитектурные решения;&lt;li&gt;&lt;p&gt;связывать требования с API, задачами разработки и тестами.&lt;/ul&gt;&lt;p&gt;Спецификация должна жить в том же рабочем процессе, где живет код. Даже если физически код и требования находятся в разных репозиториях.&lt;p&gt;Мы решили проверить подход на одном из пилотных проектов, где было все: аналитика, архитектура, backend/frontend-разработка, тестирование и DevOps.&lt;p&gt;Как мы перевели аналитику из Confluence/Word в SDD-контур и что из этого получилось, рассказываю под катом.&lt;p&gt;&lt;strong&gt;Кому полезно:&lt;/strong&gt; бизнес- и системным аналитикам, руководителям команд, архитекторам и разработчикам, которые уже обсуждают SDD, агентную разработку и новые требования к постановкам.&lt;h3&gt;Как работали раньше, и что изменилось&lt;/h3&gt;&lt;p&gt;Чтобы наглядно показать разницу, сделала две упрощённые IDEF0-подобные схемы (это не полноценные модели процесса, а карты). По ним видно, где требования перестают быть «документом где-то рядом» и становятся частью инженерной работы.&lt;p&gt;И сразу еще немного контекста:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Элемент&lt;td&gt;&lt;p align=left&gt;Смысл&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Входы&lt;td&gt;&lt;p align=left&gt;Требования, доменные знания, встречи с заказчиком&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Управление&lt;td&gt;&lt;p align=left&gt;Методология, архитектурные стандарты, правила для агентов&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Процессы&lt;td&gt;&lt;p align=left&gt;Аналитика → разработка → тестирование → сборка&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Выходы&lt;td&gt;&lt;p align=left&gt;Спецификации, ADR, OpenAPI, код, тесты, артефакты поставки&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Механизмы&lt;td&gt;&lt;p align=left&gt;Роли, IDE, Git, шаблоны, агенты&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;На схемах входы расположены слева, управление — сверху, механизмы — снизу, процессы — в центре.&lt;p&gt;&lt;strong&gt;Было.&lt;/strong&gt; Аналитик готовил постановку в Confluence, Word и Jira. Разработчик работал в IDE и Git, но входные требования получал из внешнего документа. Архитектурные решения, тест-кейсы и код жили рядом только организационно. Связанной системы артефактов не было.&lt;p&gt;Красная зона на схеме — знакомая боль многих проектов: ТЗ и код быстро расходятся, потому что меняются в разных средах и по разным правилам.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d8b/840/514/d8b8405149c0486a0e19fdf071d57b7d.png alt=&#34;Как только появляется рассинхрон требований, агентная разработка начинает пробуксовывать&#34; title=&#34;Как только появляется рассинхрон требований, агентная разработка начинает пробуксовывать&#34; width=1618 height=742 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d8b/840/514/d8b8405149c0486a0e19fdf071d57b7d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d8b/840/514/d8b8405149c0486a0e19fdf071d57b7d.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Как только появляется рассинхрон требований, агентная разработка начинает пробуксовывать&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Стало.&lt;/strong&gt; Мы собрали SDD-контур (spec-driven development): требования, декомпозиция, пользовательские истории, сценарии приёмки в Gherkin, OpenAPI, ADR, CR-файлы (change request) и инженерные диаграммы ведутся в Git как текстовые файлы.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d85/171/e87/d85171e8788665f666631270813ff77a.png alt=&#34;В новом процессе спецификация и код живут в одном рабочем процессе&#34; title=&#34;В новом процессе спецификация и код живут в одном рабочем процессе&#34; width=1703 height=963 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d85/171/e87/d85171e8788665f666631270813ff77a.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d85/171/e87/d85171e8788665f666631270813ff77a.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;В новом процессе спецификация и код живут в одном рабочем процессе&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Код при этом не лежит в том же репозитории. Проект устроен как polyrepo: есть отдельный репозиторий specs, отдельный репозиторий backend и отдельный репозиторий frontend. Но все они находятся в одном Git-проекте и связаны правилами трассировки.&lt;p&gt;Так мы не пытались «свалить всё в один репозиторий», а сохранили понятные границы владения:&lt;ul&gt;&lt;li&gt;&lt;p&gt;аналитики ведут требования и связанные спецификации в specs;&lt;li&gt;&lt;p&gt;архитектор складывает ADR и архитектурные артефакты в тот же specs;&lt;li&gt;&lt;p&gt;разработчики пишут код в backend/frontend-репозиториях;&lt;li&gt;&lt;p&gt;агенты получают из specs ровно те артефакты, которые нужны для генерации кода и тест-кейсов по конкретной задаче.&lt;/ul&gt;&lt;p&gt;Красная пунктирная линия на схеме «стало» показывает, как мы закрывали обратную связь. Раньше замечание легко уезжало в чат или звучало на созвоне как «потом поправим». В пилоте мы возвращали такие замечания в specs в виде CR и журнала ревью (review log). Так спецификация постепенно становилась пригодной для повторного использования агентами.&lt;p&gt;В работе аналитика изменились три из четырёх опор процесса:&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Управление:&lt;/strong&gt; вместо свободной формы постановки — SDD, шаблоны, контрольные точки ревью и правила трассировки.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Среда:&lt;/strong&gt; вместо Confluence как основного рабочего места — IDE, Markdown и Git.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Результат:&lt;/strong&gt; вместо документа «для прочтения человеком» — набор связанных спецификаций, пригодных для разработки, ревью и запуска агентов.&lt;/ol&gt;&lt;p&gt;Входы остались прежними: встречи с заказчиком, доменные знания, исходные требования, договорённости и ограничения проекта.&lt;h3&gt;Почему подход «дайте аналитику LLM» не сработал&lt;/h3&gt;&lt;p&gt;До пилота аналитики, разработчики и тестировщики уже пробовали ИИ по отдельности: подготовить вопросы к встрече, разобрать регламент, накидать тестовый сценарий, объяснить код. Локально это помогало.&lt;p&gt;Но на общем результате почти не сказывалось, потому что сквозной процесс от этого почти не менялся.&lt;p&gt;Сложности начинались там, где результат работы одного человека становился исходным материалом для следующего.&lt;p&gt;Например:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Аналитик пишет требования.&lt;li&gt;&lt;p&gt;Архитектор на основе требований проектирует решение.&lt;li&gt;&lt;p&gt;Разработчик пишет код по архитектуре.&lt;li&gt;&lt;p&gt;Тестировщик составляет проверки по коду и требованиям.&lt;/ol&gt;&lt;p&gt;Агент в такой схеме получает слишком широкий и неоднозначный контекст, он не понимает:&lt;ul&gt;&lt;li&gt;&lt;p&gt;какие требования обязательные;&lt;li&gt;&lt;p&gt;что просто пожелание;&lt;li&gt;&lt;p&gt;какие решения уже приняли;&lt;li&gt;&lt;p&gt;какие ограничения нельзя нарушать;&lt;li&gt;&lt;p&gt;какие сценарии критические.&lt;/ul&gt;&lt;p&gt;Поэтому пилот мы строили не вокруг вопроса «какую модель дать аналитику», а вокруг другого вопроса:&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Что должно появиться, чтобы архитектор, разработчик, тестировщик и агент могли работать без ручного пересказа требований?&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Спойлер: &lt;code&gt;specs-репозиторий&lt;/code&gt;.&lt;h3&gt;Как устроили specs-репозиторий&lt;/h3&gt;&lt;p&gt;Specs стал местом, где живут текстовые и контрактные артефакты. В нём лежат не исходники приложения, а всё, что нужно для постановки, архитектуры, трассировки и проверки.&lt;p&gt;Упрощённо структура выглядела так:&lt;p&gt;&lt;code&gt;specs/&lt;br&gt;  product/&lt;br&gt;    source-requirements/        # исходные требования, ЧТЗ-свод, материалы заказчика&lt;br&gt;  epics/&lt;br&gt;    EPIC-001_.../&lt;br&gt;      EPIC-001_....md           # описание эпика&lt;br&gt;      tasks_features/           # Back_* и Front_* постановки&lt;br&gt;      user-stories/             # US-*.md&lt;br&gt;      gherkin/                  # GH-*.feature&lt;br&gt;      ux/                       # UI-control-register, UI-interaction-map&lt;br&gt;      cr/                       # CR-файлы с замечаниями и запросами изменений&lt;br&gt;      &lt;em&gt;review-log&lt;/em&gt;*.md          # результаты ревью&lt;br&gt;  engineering/&lt;br&gt;    adr/                        # ADR архитектора&lt;br&gt;    api/                        # OpenAPI / AsyncAPI&lt;br&gt;    contracts/                  # контракты внешних систем&lt;br&gt;    schemas/                    # JSON Schema&lt;br&gt;    examples/                   # примеры CSV/JSON&lt;br&gt;    diagrams/                   # PlantUML, &lt;/code&gt;&lt;a href=http://draw.io&gt;&lt;code&gt;draw.io&lt;/code&gt;&lt;/a&gt;&lt;code&gt;, C4, sequence&lt;br&gt;  security/&lt;br&gt;    rbac/&lt;/code&gt;&lt;p&gt;Здесь мы отдельно договорились о важной вещи: «спецификация рядом с кодом» не обязательно означает «в той же папке, что и исходники». Для нашего проекта логичнее оказалось разделить код и требования физически, но оставить их в одном инженерном процессе.&lt;p&gt;Код разнесли так:&lt;ul&gt;&lt;li&gt;&lt;p&gt;backend — отдельный репозиторий;&lt;li&gt;&lt;p&gt;frontend — отдельный репозиторий;&lt;li&gt;&lt;p&gt;specs — отдельный репозиторий требований и инженерных спецификаций.&lt;/ul&gt;&lt;p&gt;Связь между ними держалась не на памяти участников, а на правилах:&lt;ul&gt;&lt;li&gt;&lt;p&gt;единое пространство проекта в Git;&lt;li&gt;&lt;p&gt;имена эпиков, фич и задач;&lt;li&gt;&lt;p&gt;ссылки из &lt;code&gt;Back_* / Front_*&lt;/code&gt; на ADR, OpenAPI, Gherkin, CR и смежные задачи;&lt;li&gt;&lt;p&gt;правила в скиллах агентов: какие артефакты из specs нужно брать для генерации кода, тестов или ревью по конкретному типу задачи.&lt;/ul&gt;&lt;p&gt;Например, для backend-задачи типа «Хранение» агенту не нужен весь эпик целиком. Ему нужны постановка &lt;code&gt;Back_*&lt;/code&gt;, связанный ADR, OpenAPI при наличии, примеры CSV/JSON, Gherkin-сценарии и CR-файлы по этой фиче.&lt;p&gt;Когда мы начали ограничивать набор входов, стало проще и агенту, и человеку на ревью: меньше шума, меньше шансов упереться в контекстное окно модели.&lt;h3&gt;Как декомпозировали требования под ограниченный контекст модели&lt;/h3&gt;&lt;p&gt;Не получится скормить модели «весь проект» и ждать стабильного результата. Очень хочется так сделать, особенно когда документации много и сроки жмут. Но контекстное окно ограничено. А даже если модель технически принимает большой объём, качество рассуждения падает: она упрощает, теряет исключения и смешивает уровни.&lt;p&gt;Поэтому на старте проекта мы разложили требования на условные эпики, а внутри эпиков — на фичи и задачи по слоям.&lt;p&gt;Типовая цепочка выглядела так:&lt;p&gt;&lt;code&gt;EPIC-001&lt;br&gt;  FEAT-001-01&lt;br&gt;    Back_001_01-01  # backend: хранение&lt;br&gt;    Back_001_01-02  # backend: API Front/Back&lt;br&gt;    Front_001_01-03 # frontend: форма или блок UI&lt;br&gt;  FEAT-001-02&lt;br&gt;    Back_001_02-01  # backend: отдельный endpoint или сценарий интеграции&lt;br&gt;    Front_001_02-02 # frontend: связанная UI-задача&lt;/code&gt;&lt;p&gt;Для backend выделяли разные типы задач:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Хранение:&lt;/strong&gt; БД, миграции, CSV/JSON, начальное наполнение, правила чтения и записи.&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Front/Back:&lt;/strong&gt; REST-контракты, ошибки, DTO, валидация, взаимодействие с frontend.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Адаптер интеграции:&lt;/strong&gt; требования к обмену с внешней системой, маппинг, polling, статусы, обработка ошибок.&lt;li&gt;&lt;p&gt;&lt;strong&gt;Эмулятор:&lt;/strong&gt; если для разработки или CI нужна замена внешней системы.&lt;/ul&gt;&lt;p&gt;Для frontend дробили по экранным формам. Если страница была сложной, отдельной задачей становился не весь экран, а конкретный блок или сценарий.&lt;p&gt;Связи фиксировали в двух местах:&lt;ol&gt;&lt;li&gt;&lt;p&gt;В эпике — общая декомпозиция, порядок разработки и трассировка артефактов.&lt;li&gt;&lt;p&gt;В каждой задаче — ссылки на смежные &lt;code&gt;Back_* / Front_*&lt;/code&gt;, user story, Gherkin, OpenAPI, ADR и CR.&lt;/ol&gt;&lt;p&gt;На основе эпика и вложенных задач аналитики генерировали:&lt;ul&gt;&lt;li&gt;&lt;p&gt;пользовательские истории (&lt;code&gt;US-*.md&lt;/code&gt;);&lt;li&gt;&lt;p&gt;сценарии приёмки в Gherkin (GH-*.feature);&lt;li&gt;&lt;p&gt;OpenAPI для контрактов Frontend/Backend;&lt;li&gt;&lt;p&gt;описание состава полей для справочников и таблиц;&lt;li&gt;&lt;p&gt;примеры CSV/JSON для дальнейшей проработки архитектором и разработчиками.&lt;/ul&gt;&lt;h3&gt;Разберем на примере задачи на backend-хранение&lt;/h3&gt;&lt;p&gt;Один из примеров постановки — задача &lt;code&gt;Back_001_01-01: Хранение UI-конфигурации каркаса&lt;/code&gt;.&lt;p&gt;В старом процессе такая задача легко превратилась бы в абзац «нужно хранить настройки меню в БД». Для человека этого иногда достаточно: он переспросит в чате, вспомнит созвон, поднимет соседнюю страницу.&lt;p&gt;Для агента и последующего ревью этого мало.&lt;p&gt;В новом шаблоне задача фиксировала:&lt;ul&gt;&lt;li&gt;&lt;p&gt;ID задачи, слой, тип задачи, компонент архитектурной схемы;&lt;li&gt;&lt;p&gt;фичу и эпик;&lt;li&gt;&lt;p&gt;источники информации;&lt;li&gt;&lt;p&gt;требования к структуре данных и хранению;&lt;li&gt;&lt;p&gt;порядок интеграции;&lt;li&gt;&lt;p&gt;NFR именно этой задачи;&lt;li&gt;&lt;p&gt;что находится вне объёма;&lt;li&gt;&lt;p&gt;сценарии использования;&lt;li&gt;&lt;p&gt;критерии приёмки;&lt;li&gt;&lt;p&gt;зависимости и риски.&lt;/ul&gt;&lt;p&gt;Фрагмент требования:&lt;p&gt;&lt;code&gt;&lt;strong&gt;3.1.1.&lt;/strong&gt; Сервис **ms-nsi** &lt;strong&gt;должен&lt;/strong&gt; хранить словари контура&lt;br&gt;в &lt;strong&gt;PostgreSQL&lt;/strong&gt;. При обработке &lt;strong&gt;GET /api/v1/nsi/ui-config&lt;/strong&gt;&lt;br&gt;и section-pages &lt;strong&gt;должен&lt;/strong&gt; получать данные &lt;strong&gt;только из БД&lt;/strong&gt;.&lt;br&gt;Активный контур &lt;strong&gt;должен&lt;/strong&gt; определяться по переменной окружения&lt;br&gt;&lt;strong&gt;PORTAL_CONTOUR_CODE&lt;/strong&gt; на экземпляре &lt;strong&gt;ms-nsi&lt;/strong&gt;; **UI** &lt;strong&gt;не должен&lt;/strong&gt;&lt;br&gt;передавать contour_code в запросе.&lt;/code&gt;&lt;p&gt;Формально это всё ещё обычный Markdown. Но для агента это уже не «текст про меню», а нормальный структурированный вход:&lt;ul&gt;&lt;li&gt;&lt;p&gt;известен компонент (&lt;code&gt;ms-nsi&lt;/code&gt;);&lt;li&gt;&lt;p&gt;известна операция (&lt;code&gt;GET /api/v1/nsi/ui-config&lt;/code&gt;);&lt;li&gt;&lt;p&gt;задан источник данных (PostgreSQL);&lt;li&gt;&lt;p&gt;указано, чего делать нельзя (UI не передаёт &lt;code&gt;contour_code&lt;/code&gt;);&lt;li&gt;&lt;p&gt;есть ссылка на смежную API-задачу и OpenAPI;&lt;li&gt;&lt;p&gt;есть критерии приёмки и Gherkin-сценарии.&lt;/ul&gt;&lt;p&gt;После такой детализации разработчик и ИИ-агент смотрят не на весь поток требований, а на ограниченный срез: конкретный слой, конкретный компонент, конкретную задачу и связанные файлы.&lt;h3&gt;Как работал цикл замечаний: CR вместо «поправим потом»&lt;/h3&gt;&lt;p&gt;На этом месте быстро всплыл бытовой, но болезненный процессный дефект: замечания терялись в переписке и созвонах. Если архитектор, разработчик или тестировщик находил проблему в спецификации, замечание начали фиксировать в CR-файле внутри эпика.&lt;p&gt;Например:&lt;p&gt;&lt;code&gt;specs/epics/EPIC-001_.../cr/CR-001_Specs_Change_Requirements.md&lt;/code&gt;&lt;p&gt;CR использовали, чтобы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;уточнить границы задачи;&lt;li&gt;&lt;p&gt;зафиксировать архитектурные замечания;&lt;li&gt;&lt;p&gt;изменить структуры CSV/JSON или OpenAPI;&lt;li&gt;&lt;p&gt;перенести технические детали из устного обсуждения в постановку;&lt;li&gt;&lt;p&gt;синхронизировать требования после ADR или ревью кода.&lt;/ul&gt;&lt;p&gt;После каждого уточнения спецификаций запускали ревью связанных артефактов по фиче. Если менялась задача на backend, проверяли не только её собственные разделы, но и связанные файлы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;эпик и таблица декомпозиции;&lt;li&gt;&lt;p&gt;смежные &lt;code&gt;Back_* / Front_*&lt;/code&gt;;&lt;li&gt;&lt;p&gt;OpenAPI;&lt;li&gt;&lt;p&gt;US и Gherkin;&lt;li&gt;&lt;p&gt;ADR;&lt;li&gt;&lt;p&gt;CR и журнал ревью (review log).&lt;/ul&gt;&lt;p&gt;Для ИИ-агентов такие процедуры – практическая необходимость. Если поправить только один файл, а связанные артефакты оставить старыми, агент может взять противоречивый контекст и сгенерировать код по устаревшему правилу.&lt;h3&gt;Что произошло со SpecKit&lt;/h3&gt;&lt;p&gt;Мы пробовали взять готовый SpecKit из открытых источников и применить его «в лоб» на простых задачах. Честно говоря, сначала хотелось верить, что этого хватит: взяли шаблон, подключили модель, получили аккуратные спецификации.&lt;p&gt;На практике так просто не получилось. Артефакты дублировались, требования расползались по нескольким файлам, модель добавляла несуществующие условия, а ревью превращалось в ручной разбор каши.&lt;p&gt;Проблема была не в самой идее SpecKit, а в том, что чужой набор шаблонов не знает:&lt;ul&gt;&lt;li&gt;&lt;p&gt;нашу декомпозицию эпиков и задач;&lt;li&gt;&lt;p&gt;какие репозитории есть в проекте;&lt;li&gt;&lt;p&gt;где живёт ADR;&lt;li&gt;&lt;p&gt;как связаны backend и frontend;&lt;li&gt;&lt;p&gt;какие поля должны быть в OpenAPI;&lt;li&gt;&lt;p&gt;какие требования относятся к аналитику, а какие к архитектору или разработчику;&lt;li&gt;&lt;p&gt;что считать источником истины при конфликте артефактов.&lt;/ul&gt;&lt;p&gt;После этого мы перестали относиться к шаблонам как к готовой методологии. Шаблоны стали результатом совместной отладки аналитиков, архитектора и разработчиков.&lt;p&gt;Например, отдельно закрепили правила:&lt;ul&gt;&lt;li&gt;&lt;p&gt;требования формулируются полными предложениями на русском языке;&lt;li&gt;&lt;p&gt;используется модальность «должен / не должен / может»;&lt;li&gt;&lt;p&gt;англоязычные термины поясняются при первом употреблении;&lt;li&gt;&lt;p&gt;нумерация разделов не зависит от строк таблиц;&lt;li&gt;&lt;p&gt;строки таблиц и пункты требований имеют разные контуры нумерации;&lt;li&gt;&lt;p&gt;в &lt;code&gt;Back_*&lt;/code&gt; не дублируется полный контракт внешней системы, а ставится ссылка на канонический контракт;&lt;li&gt;&lt;p&gt;в &lt;code&gt;Front_*&lt;/code&gt;не дублируются Figma &lt;code&gt;node-id&lt;/code&gt; и URL, если они уже зафиксированы в UX-артефактах;&lt;li&gt;&lt;p&gt;история изменений ведётся в конце документа, а не длинной строкой в шапке.&lt;/ul&gt;&lt;p&gt;Часть этих правил выглядит бюрократически, пока работаешь вручную. Я бы сама раньше спорила с некоторыми из них: зачем так подробно описывать стиль фраз, если «и так понятно»?&lt;p&gt;Но для агентного контура это техническое ограничение. Если правило не зафиксировано, модель с большой вероятностью начнёт каждый раз оформлять артефакт по-своему.&lt;h3&gt;Как за 6 шагов поменяли жизнь аналитиков (и не только)&lt;/h3&gt;&lt;p&gt;Теперь, когда разобрались с деталями нового процесса, пошагово расскажу, как внедрили его в нашу практику.&lt;h4&gt;1. Договорились о методологии и границах&lt;/h4&gt;&lt;p&gt;Мы изучили открытые материалы по SDD и чужой опыт, но адаптировали их. Внутри команды договорились: для разработки источником становятся Markdown-артефакты в &lt;code&gt;specs&lt;/code&gt;, а не страницы Confluence.&lt;p&gt;Это не отменило Word полностью. Контрактное ЧТЗ по-прежнему оставалось документом для заказчика. Но для разработки появился отдельный инженерный контур.&lt;h4&gt;2. Пересадили аналитиков в IDE и Git&lt;/h4&gt;&lt;p&gt;Аналитики начали работать в VS Code с моделью на сервере компании: не все материалы можно отдавать в публичные облака из-за NDA и внутренних ограничений.&lt;p&gt;Сами спецификации и проектные материалы мы формировали через &lt;strong&gt;on-prem модель&lt;/strong&gt; &lt;code&gt;qwen3.6-35b-a3b&lt;/code&gt;. Для генерации и отладки skills в Cursor использовали платные модели, но без передачи чувствительных данных проекта.&lt;p&gt;Минимальный Git стал обязательным: клонировать репозиторий, создать ветку, внести изменения, посмотреть diff, отправить изменения на ревью.&lt;p&gt;Да, страх IDE и Git был. И он не снимается лекцией. Он снимается только реальной задачей.&lt;p&gt;Аналитик видит свой diff, получает замечание в ревью и постепенно понимает: Markdown и ссылки помогают не потерять смысл требований, а не просто добавляют ещё один инструмент.&lt;h4&gt;3. Собрали каркас specs&lt;/h4&gt;&lt;p&gt;Мы описали структуру репозитория, разделили продуктовый слой, эпики, инженерные артефакты, безопасность и служебные проверки.&lt;p&gt;Отдельно договорились, что ADR архитектора лежат в &lt;code&gt;specs/engineering/adr&lt;/code&gt;, OpenAPI — в &lt;code&gt;specs/engineering/api&lt;/code&gt;, примеры данных — в &lt;code&gt;specs/engineering/examples&lt;/code&gt;.&lt;p&gt;Так архитектор перестал быть внешним потребителем постановки. Он стал участником того же репозитория.&lt;h4&gt;4. Переписали шаблоны под проект&lt;/h4&gt;&lt;p&gt;Появились шаблоны:&lt;ul&gt;&lt;li&gt;&lt;p&gt;эпика;&lt;li&gt;&lt;p&gt;user story;&lt;li&gt;&lt;p&gt;backend-задачи;&lt;li&gt;&lt;p&gt;frontend-задачи;&lt;li&gt;&lt;p&gt;правил нумерации;&lt;li&gt;&lt;p&gt;правил создания и ревью артефактов.&lt;/ul&gt;&lt;p&gt;Шаблоны отлаживались не абстрактно, а на одной понятной фиче. Это был самый медленный и местами раздражающий этап: аналитик генерировал или уточнял артефакт, архитектор и разработчики оставляли замечания, правила обновлялись — и всё повторялось ещё раз.&lt;h4&gt;5. Связали скиллы агентов с типами задач&lt;/h4&gt;&lt;p&gt;В скиллах агентов прописали, какие артефакты использовать для конкретного действия. Например:&lt;ul&gt;&lt;li&gt;&lt;p&gt;для задачи на хранение данных в backend — &lt;code&gt;Back_*&lt;/code&gt;, ADR, примеры данных, OpenAPI при наличии, Gherkin и CR;&lt;li&gt;&lt;p&gt;для frontend-задачи — &lt;code&gt;Front_*&lt;/code&gt;, UI map, UX-артефакты, OpenAPI, US и Gherkin;&lt;li&gt;&lt;p&gt;для генерации тест-кейсов — US, Gherkin, связанные &lt;code&gt;Back_* / Front_*&lt;/code&gt; и критерии приёмки;&lt;li&gt;&lt;p&gt;для архитектурного ревью — эпик, задачи, ADR, OpenAPI, CR и диаграммы.&lt;/ul&gt;&lt;p&gt;Это оказалось важнее длинного универсального промпта. Агенту нужен не весь проект, а правильный срез контекста. Иначе он выглядит уверенно, но работает не с теми данными.&lt;h4&gt;6. Отладили ревью по цепочке&lt;/h4&gt;&lt;p&gt;Архитектор по первым спецификациям формировал ADR и возвращал замечания к постановке. Разработчики backend и frontend запускали агентов с обновлёнными правилами, смотрели код и снова возвращали замечания к спецификациям.&lt;p&gt;Тестирование добавляло свои уточнения через Gherkin и критерии приёмки.&lt;p&gt;Первая волна заняла несколько недель. Мы не столько «писали спеки», сколько отлаживали саму систему артефактов. Быстрого эффекта в первый день не было. Зато на следующих задачах уточнения по замечаниям занимали уже около часа, потому что каркас и правила были готовы.&lt;h3&gt;Человек в процессе все еще главный&lt;/h3&gt;&lt;p&gt;Полного автопилота не получилось, хотя никто его и не ждал.&lt;p&gt;За людьми остались:&lt;ul&gt;&lt;li&gt;&lt;p&gt;сбор требований на встречах, ВКС и в переписке;&lt;li&gt;&lt;p&gt;согласование с заказчиком;&lt;li&gt;&lt;p&gt;контрактное ЧТЗ в Word;&lt;li&gt;&lt;p&gt;принятие архитектурных решений;&lt;li&gt;&lt;p&gt;проверка доменных формулировок;&lt;li&gt;&lt;p&gt;ревью постановок, ADR, OpenAPI, кода и тестов;&lt;li&gt;&lt;p&gt;ответственность за то, что попало в Git.&lt;/ul&gt;&lt;p&gt;Зато модели ускорили подготовительную работу:&lt;ul&gt;&lt;li&gt;&lt;p&gt;анализ документации и контрактов;&lt;li&gt;&lt;p&gt;черновики вопросов к встречам;&lt;li&gt;&lt;p&gt;протоколы встреч: транскрибация → черновик → правка аналитиком;&lt;li&gt;&lt;p&gt;выжимки из переписки;&lt;li&gt;&lt;p&gt;проверку гипотез по внешним API;&lt;li&gt;&lt;p&gt;черновую генерацию US и Gherkin;&lt;li&gt;&lt;p&gt;приведение текста к проектным правилам.&lt;/ul&gt;&lt;p&gt;Владелец требований все еще главный. Если аналитик не понимает домен, агент просто красиво оформит ошибку. Иногда даже слишком уверенно, и ошибку просто будет сложнее заметить.&lt;h3&gt;Но кое-что все-таки изменилось&lt;/h3&gt;&lt;p&gt;До пилота аналитик в основном отвечал за содержание постановки. После перехода в SDD-контур добавились инженерные обязанности:&lt;ul&gt;&lt;li&gt;&lt;p&gt;поддерживать спецификации как версионируемые артефакты;&lt;li&gt;&lt;p&gt;работать с ветками, diff и review;&lt;li&gt;&lt;p&gt;думать о размере контекста для модели;&lt;li&gt;&lt;p&gt;разделять требования по слоям;&lt;li&gt;&lt;p&gt;связывать эпики, задачи, US, Gherkin, OpenAPI и ADR;&lt;li&gt;&lt;p&gt;фиксировать замечания в CR, а не только в переписке;&lt;li&gt;&lt;p&gt;проверять, что после правки одного файла не сломалась трассировка по фиче.&lt;/ul&gt;&lt;p&gt;Аналитик стал ближе к инженерному процессу. Его артефакт теперь не просто читают: от него запускаются генерация, ревью и проверка. Это меняет требования к аккуратности сильнее, чем кажется на старте.&lt;h3&gt;Что пока осталось открытым&lt;/h3&gt;&lt;p&gt;После пилота у нас остались вопросы, на которые мы найдем ответы со временем тестирования нового подхода:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Где баланс между спецификацией для человека и спецификацией для модели?&lt;li&gt;&lt;p&gt;Насколько глубоко нужно стандартизировать мелкие задачи?&lt;li&gt;&lt;p&gt;Когда выгоднее писать лёгкий промпт, а когда полноценный SDD-артефакт?&lt;li&gt;&lt;p&gt;Как формально описать новую зону ответственности аналитика?&lt;li&gt;&lt;p&gt;Как безопасно перегенерировать код при изменении ADR?&lt;li&gt;&lt;p&gt;Как стабилизировать агентные тесты и не получить ложную уверенность от красивого Gherkin?&lt;/ol&gt;&lt;p&gt;Если ваши аналитики уже пишут в Git, делитесь опытом, будет интересно сравнить.&lt;div class=persona&gt;&lt;img class=&#34;image persona__image&#34; src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e7d/640/4b3/e7d6404b3b25c9e75786d6dc8426b419.jpg sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e7d/640/4b3/e7d6404b3b25c9e75786d6dc8426b419.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e7d/640/4b3/e7d6404b3b25c9e75786d6dc8426b419.jpg 781w&#34; loading=lazy decode=async&gt;&lt;h5 class=persona__heading&gt;Светлана Забирова&lt;/h5&gt;&lt;p class=persona__text&gt;Руководитель аналитической команды проектов в Центре разработки и машинного обучения&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/jetinfosystems/articles/1051370/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051370</guid>
      <pubDate>Wed, 24 Jun 2026 13:31:19 +0000</pubDate>
    </item>
    <item>
      <title>Эффект бабочки в мастер-данных: как два неучтённых сантиметра останавливают фуры</title>
      <link>https://habr.com/ru/companies/intekey/articles/1051436/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051436</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;В ИТ ошибка во входных данных обычно ведёт себя честно. Неверный тип, некорректный формат, нарушенная схема — система останавливает выполнение и показывает, что именно пошло не так. На складе всё гораздо коварнее: ошибка в данных не падает в лог, а уезжает в операционный контур, где превращается в лишние перемещения, недогруз, пересборку паллет и сбой в отгрузке.&lt;p&gt;Именно поэтому &lt;strong&gt;принцип GIGO&lt;/strong&gt; — garbage in, garbage out, «мусор на входе — мусор на выходе» — в логистике звучит особенно буквально. Если в мастер-данные попал неверный габарит товара, WMS не начнёт спорить с пользователем. Она просто будет добросовестно рассчитывать всё дальше на основе неправильной цифровой модели.&lt;p&gt;А дальше начинается то, что в отчётах выглядит как набор несвязанных инцидентов, а на деле является одной и той же ошибкой, допущенной на входе.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a00/372/9be/a003729befef5a8abf23c6a4de2e1e84.png alt=&#34;Два сантиметра — немного. Пока они не умножились на короб, паллету и рейс&#34; title=&#34;Два сантиметра — немного. Пока они не умножились на короб, паллету и рейс&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a00/372/9be/a003729befef5a8abf23c6a4de2e1e84.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a00/372/9be/a003729befef5a8abf23c6a4de2e1e84.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Два сантиметра — немного. Пока они не умножились на короб, паллету и рейс&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Когда товар тот же, а физика уже другая&lt;/h3&gt;&lt;p&gt;Представим вполне жизненный сценарий. Поставщик немного меняет форму бутылки: артикул остаётся прежним, этикетка та же, состав тот же, а вот сама бутылка становится шире на 2 сантиметра. Для закупки и ERP это может выглядеть как несущественная деталь. Для склада — уже нет.&lt;p&gt;Потому что WMS работает не с «тем же самым товаром» в бытовом смысле. Она работает с его цифровой копией: длиной, шириной, высотой, весом, типом вложенности, правилами хранения и размещения. Если физический объект изменился, а цифровая модель нет, система по-прежнему считает быстро, точно и последовательно — просто не ту реальность.&lt;p&gt;И в этом главный парадокс складской автоматизации: чем лучше работает алгоритм, тем быстрее он масштабирует ошибку в исходных данных.&lt;h3&gt;Как 2 сантиметра превращаются в операционный сбой&lt;/h3&gt;&lt;p&gt;На уровне одной бутылки два сантиметра кажутся мелочью. Смотря где: в резюме это, возможно, предмет тонкой самооценки, а в логистике — уже причина для пересчёта всей геометрии хранения. Склад вообще плохо относится к сантиметрам, которые кто-то решил считать несущественными.&lt;p&gt;Дальше механика очень простая. В ERP старые данные не обновили. WMS считает, что короб имеет прежние размеры. Затем система рассчитывает, что на паллету помещается 100 коробок. Кладовщик начинает сборку и на 90-й коробке внезапно выясняется, что паллета закончилась раньше, чем расчёт.&lt;p&gt;В этот момент проблема уже не в одной коробке и не в одном сотруднике. Оператор не может закрыть задание по плановой модели. Сформированная паллета не соответствует ожидаемым параметрам. Она не помещается в ячейку зоны отгрузки так, как это запланировала система. Следом начинает сыпаться логика размещения в экспедиции и алгоритм загрузки кузова фуры, который опирался на те же самые ВГХ.&lt;p&gt;То есть два «незаметных» сантиметра не просто меняют карточку товара. Они меняют расчёт вместимости, компоновку паллеты, сценарий отбора, логику размещения и транспортный план.&lt;h3&gt;Как ошибка масштабируется по складу&lt;/h3&gt;&lt;p&gt;Ошибка в мастер-данных не живёт в одной ячейке системы. Она быстро едет дальше: единица товара, короб, паллета, ячейка, зона, рейс. И на каждом следующем уровне обходится дороже.&lt;p&gt;Если система неверно понимает ширину или высоту одной единицы, она неверно считает короб. Если неверно посчитан короб, искажается паллетизация. Если неверно собрана паллета, страдают слоттинг, размещение и отгрузка. Если паллета описана неверно, транспортный модуль получает искажённую картину загрузки. В итоге ошибка из НСИ доезжает до ворот склада и начинает влиять уже на фуру, а не на карточку.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/faa/b03/2bc/faab032bc31123ff7670b799aa6c7573.png alt=&#34;Так неточный габарит проходит путь от карточки товара до сбоя в отгрузке&#34; title=&#34;Так неточный габарит проходит путь от карточки товара до сбоя в отгрузке&#34; width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/faa/b03/2bc/faab032bc31123ff7670b799aa6c7573.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/faa/b03/2bc/faab032bc31123ff7670b799aa6c7573.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Так неточный габарит проходит путь от карточки товара до сбоя в отгрузке&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Переход от единицы к коробу выглядит безобидно только на бумаге. Расхождение в несколько миллиметров или сантиметров на одной бутылке может почти не тревожить никого до тех пор, пока система считает штуки. Но склад живёт не только штуками. Он живёт вложенностью. И когда ошибка умножается на количество единиц в коробе, затем на количество коробов в слое, затем на количество слоёв на паллете, она перестаёт быть “мелочью” и становится уже вполне физическим ограничением.&lt;p&gt;Дальше ломается слоттинг. Система рассчитывает адресное размещение, исходя из того, что паллета имеет одни габариты, а фактически на склад приезжает другая. В результате товар направляется в ячейку, где ему тесно, или, наоборот, занимает больше пространства, чем планировалось. Снаружи это выглядит как локальная операционная нестыковка: кладовщик не может поставить паллету, оператору приходится искать другой адрес, система получает ручные отклонения от маршрута. На самом деле проблема возникла раньше — в тот момент, когда неверные ВГХ стали частью мастер-данных.&lt;p&gt;После этого ошибка выходит в зону отгрузки. Там уже важна не только геометрия хранения, но и геометрия потока: сколько паллет встанет в экспедицию, как их разнести по воротам, как собрать волну отгрузки, как уместить всё это в кузов. Если расчёт шёл по одной модели, а физически склад получил другую, то начинает плыть вся последняя миля внутри склада. Сначала паллета не встаёт туда, куда её ждали. Потом меняется схема загрузки. А дальше внезапно выясняется, что фура, которая “по системе” должна была закрыть рейс, в реальности уже не закрывает его так красиво, как это выглядело в расчёте.&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Уровень&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Что считает система&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Что происходит в реальности&lt;/strong&gt;&lt;td&gt;&lt;p align=left&gt;&lt;strong&gt;Последствие&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Единица товара&lt;td&gt;&lt;p align=left&gt;Бутылка имеет прежнюю ширину&lt;td&gt;&lt;p align=left&gt;Бутылка шире на 2 см&lt;td&gt;&lt;p align=left&gt;Ошибка попадает в НСИ&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Короб&lt;td&gt;&lt;p align=left&gt;В короб помещается расчётное количество единиц&lt;td&gt;&lt;p align=left&gt;Фактическая укладка меняется&lt;td&gt;&lt;p align=left&gt;Искажается размер короба&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Паллета&lt;td&gt;&lt;p align=left&gt;На паллету влезает 100 коробок&lt;td&gt;&lt;p align=left&gt;Место заканчивается на 90-й коробке&lt;td&gt;&lt;p align=left&gt;Паллета не собирается по плану&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Ячейка / зона отгрузки&lt;td&gt;&lt;p align=left&gt;Паллета проходит по расчётным параметрам&lt;td&gt;&lt;p align=left&gt;Реальные габариты не совпадают&lt;td&gt;&lt;p align=left&gt;Возникают проблемы с размещением&lt;tr&gt;&lt;td&gt;&lt;p align=left&gt;Фура&lt;td&gt;&lt;p align=left&gt;Алгоритм строит загрузку по плановым ВГХ&lt;td&gt;&lt;p align=left&gt;Фактическая компоновка отличается&lt;td&gt;&lt;p align=left&gt;Сбивается схема загрузки, возможен лишний рейс&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Это важно для управленцев и ИТ-команд по одной простой причине: большинство таких сбоев выглядят как операционные. Кажется, что где-то ошибся кладовщик, не хватило места в зоне, планировщик криво собрал загрузку или оператор вручную что-то не так скорректировал. Но первопричина часто находится гораздо раньше — в момент, когда в систему попали неточные ВГХ.&lt;h3&gt;Что именно считает WMS на ВГХ&lt;/h3&gt;&lt;p&gt;Весогабаритные характеристики участвуют почти во всех ключевых расчётах WMS. На них завязаны вместимость ячеек, правила адресного хранения, паллетизация, подбор тары, ограничения по весу, использование техники и планирование отгрузки.&lt;p&gt;В первую очередь это вместимость ячеек и правила адресного хранения. Система должна понимать, помещается ли конкретная грузовая единица в конкретную ячейку, сколько таких единиц можно разместить и как будет использоваться полезный объём хранения.&lt;p&gt;Дальше — формирование паллет, расчёт тары, правила товарного соседства, ограничения по весу, использование техники, планирование зоны экспедиции и объёмов на отгрузке. WMS работает с физическими параметрами товара, зафиксированными в данных.&lt;p&gt;Если разложить это по функциям, картина становится ещё нагляднее:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Вместимость ячеек. Система рассчитывает, куда поставить товар и сколько места он реально займёт.&lt;li&gt;&lt;p&gt;Правила адресного хранения. На основе ВГХ выбирается подходящий адрес, тип хранения и логика размещения по зонам.&lt;li&gt;&lt;p&gt;Паллетизация. WMS считает, сколько единиц войдёт в короб, сколько коробов — на паллету, и как собрать устойчивую грузовую единицу.&lt;li&gt;&lt;p&gt;Подбор тары. Для комплектации и отгрузки системе нужны реальные размеры заказа, а не усреднённое представление о нём.&lt;li&gt;&lt;p&gt;Товарное соседство. Вес и габариты влияют на то, что можно ставить рядом, сверху или снизу.&lt;li&gt;&lt;p&gt;Ограничения по весу. Это важно и для самих паллет, и для ячеек, и для складской техники.&lt;li&gt;&lt;p&gt;Расчёт объёма в экспедиции. Зона отгрузки тоже не бесконечна, и её загрузка зависит от фактических размеров грузовых мест.&lt;/ul&gt;&lt;p&gt;ВГХ — это набор данных, на котором держится значительная часть операционной логики склада. Ошибка в них не остаётся справочной неточностью: она довольно быстро становится ошибкой исполнения.&lt;p&gt;Если эти цифры неверны, система не перестаёт быть умной. Она просто начинает очень эффективно ошибаться.&lt;h3&gt;Почему зрелый склад проверяет ВГХ на входе&lt;/h3&gt;&lt;p&gt;На зрелых складах нормативно-справочная информация напрямую связана с исполнением операций. Корректные ВГХ нужны для точного размещения, паллетизации, отбора и отгрузки без постоянных ручных корректировок.&lt;p&gt;Отсюда и практика входного контроля: новый товар не отправляют в зону хранения сразу после получения описания от поставщика. Сначала проверяют, соответствует ли цифровая модель физическому объекту. В простом варианте это ручная верификация, в более зрелом — автоматический обмер, взвешивание и запись фактических параметров в систему.&lt;p&gt;Такая проверка решает вполне прикладную задачу: не дать неточным ВГХ попасть в операционный контур. Даже небольшое расхождение быстро превращается в системную ошибку, а её исправление почти всегда обходится дороже, чем контроль на входе.&lt;p&gt;Почему данных поставщика часто недостаточно? Потому что поставщик описывает товар в своей логике учёта и поставки, а склад работает в логике исполнения. Для поставщика товар может по-прежнему оставаться тем же SKU: тот же артикул, та же упаковочная единица, та же договорная позиция. Для склада это уже другой объект, если у него изменились ширина, высота, вес, форма или характер укладки.&lt;p&gt;Отсюда и классическая ловушка: артикул прежний, а физика уже другая. Для ERP это выглядит терпимо. Для WMS — нет. Система не видит, что бутылка “чуть поправилась”, она видит только цифры в карточке. И если цифры не обновились, все последующие расчёты будут опираться не на товар, который реально пришёл на склад, а на его прошлую версию.&lt;p&gt;Именно поэтому зрелый склад валидирует ВГХ до помещения товара в зону хранения. Не после первой проблемы на размещении, не после того, как паллета не вошла в ячейку, и не после ручной пересборки в отгрузке. Чем раньше уточнены параметры, тем меньше шансов, что ошибка успеет разойтись по операциям.&lt;h3&gt;Зачем складу автоматический обмер&lt;/h3&gt;&lt;p&gt;Автоматические сканеры габаритов, dimensioning-решения и &lt;a href=https://intekey.ru/vnedrenie-wms/&gt;связка с WMS&lt;/a&gt; помогают быстро получать фактические ВГХ и сразу использовать их в расчётах. Для склада это способ сократить количество ошибок, которые проявляются уже в размещении, сборке и отгрузке.&lt;p&gt;Такой обмер работает как входная валидация для физического объекта. Пока товар не измерен и не взвешен, система использует данные как допущение. После цифрового обмера она получает подтверждённую физическую модель товара.&lt;p&gt;Именно поэтому на зрелых складах новый товар всё чаще не отправляют в зону хранения без цифровой верификации ВГХ. Иначе два лишних сантиметра в карточке довольно быстро превращаются в сбой на отгрузке, лишний рейс и ручную разборку последствий в конце смены.&lt;p&gt;Автоматический обмер важен не только потому, что он точнее ручной рулетки. Он важен потому, что делает процесс воспроизводимым. Когда на складе тысячи SKU, ручная проверка начинает зависеть от внимательности конкретного сотрудника, загрузки смены и банальной спешки. Автоматическое измерение снижает эту зависимость и быстрее превращает факт в данные, с которыми потом живёт вся система.&lt;p&gt;Кроме того, цифровой обмер закрывает разрыв между “нам так сказали” и “мы это реально измерили”. Это особенно важно для ассортимента, где поставщик может менять форму упаковки без смены артикула, для сезонных товаров, промо-упаковки, комплектов и любых позиций, у которых физическая конфигурация не так стабильна, как хотелось бы учётной системе.&lt;h3&gt;Что это значит для бизнеса&lt;/h3&gt;&lt;p&gt;С точки зрения бизнеса проблема ВГХ — это вопрос стоимости каждой следующей операции. Чем позже обнаружено расхождение, тем дороже его исправление: сначала страдает точность расчётов, затем время сотрудников, вместимость хранения, загрузка транспорта и качество сервиса.&lt;p&gt;Поэтому NSI в логистике — это вопрос точности исполнения. Если мастер-данные описывают товар корректно, склад предсказуемо считает размещение, паллетизацию, отгрузку и транспорт. Если нет — ошибка быстро выходит за пределы карточки товара.&lt;p&gt;Когда на складе говорят, что ошибка всего в пару сантиметров не критична, обычно недооценивают главное: склад работает в штуках только на бумаге. В реальности он работает в коробах, паллетах, ячейках, маршрутах и фурах.&lt;p&gt;А там даже небольшое расхождение быстро превращается во вполне ощутимую проблему.&lt;p&gt;&lt;a href=https://intekey.ru/vnedrenie-wms/&gt;WMS&lt;/a&gt; не путается в расчётах — она просто слишком вежлива, чтобы спорить с карточкой товара. Поэтому лишние 2 сантиметра лучше поймать на входе, а не в тот момент, когда паллета уже не влезает, оператор нервничает, а фура внезапно становится теснее, чем обещала система.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/intekey/articles/1051436/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051436</guid>
      <pubDate>Wed, 24 Jun 2026 13:29:14 +0000</pubDate>
    </item>
    <item>
      <title>МВА на минималках «Модель Айсберг для определения типа сотрудников в команде»</title>
      <link>https://habr.com/ru/articles/1051428/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051428</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;&lt;br&gt;Есть много типологий сотрудников, но мне очень нравится модель Айсберг, потому что в ней только два критерия и главное она помогает понять руководителю не только как работает сотрудник, но и увидеть свои ошибки в управлении.&lt;br&gt;Итак, модель Айсберг включает два критерия:&lt;br&gt;1. сколько обещает сотрудник сделать;&lt;br&gt;2. сколько реально сотрудник делает.&lt;br&gt;и по соотношению этих двух показателей можно легко определить, кто есть кто в вашей команде и что необходимо изменить вам как руководителю в своей деятельности.&lt;p&gt;1.тип сотрудника. &amp;#34;Много обещает/Мало делает.&amp;#34;&lt;br&gt;Деструктивный тип личности. Red flag.&lt;p&gt;Что делаем с таким сотрудником:&lt;br&gt;Выясняем почему нет результата, даём возможность исправить модель поведения.&lt;br&gt;Если ничего не меняется - увольняем.&lt;br&gt;Обычно команда бывает очень рада избавиться от такого коллеги, так как они за него/неё всё делали.&lt;p&gt;2.тип сотрудника &amp;#34;Сколько обещает/столько и делает&amp;#34;&lt;br&gt;Адекватный человек.&lt;br&gt;Тут может быть вопрос в мотивации сотрудника.&lt;p&gt;Что делаем с таким сотрудником:&lt;br&gt;Выясняем всё ли его устраивает в работе, хотел бы он делать что-то иное, изменить уровень задач и или свою позицию в команде.&lt;br&gt;Если говорит, что всё ок, то не трогаем.&lt;br&gt;Если хочет большего развития, предлагаем варианты какие могут быть в команде для него.&lt;p&gt;3.тип сотрудника &amp;#34;Мало обещает/много делает&amp;#34;&lt;br&gt;Это золотой фонд команды, талантливый сотрудник.&lt;br&gt;Но это может быть звоночек для руководителя, почему сотрудник не сообщает о своей деятельности, может он предлагал варианты улучшения, но его не слушали и он решил, что проще ничего не говорить, а просто делать.&lt;p&gt;Что делаем с таким сотрудником: даём ему больше ответственности и предлагаем выбрать какие задачи он бы хотел решать.&lt;br&gt;Но просим сообщать о своей деятельности, чтобы могли помочь и дать дополнительные ресурсы для его работы.&lt;p&gt;Домашнее задание: проанализируйте свою команду по модели Айсберг, и посмотрете может пора избавиться от балласта и поддерживать таланты.&lt;br&gt;Возможно это будет как раз тот дополнительный резерв для развития эффективности бизнеса, который вам не хватал.&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <author>Michael_72</author>
      <guid>https://habr.com/ru/articles/1051428/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051428</guid>
      <pubDate>Wed, 24 Jun 2026 13:06:01 +0000</pubDate>
    </item>
    <item>
      <title>Уже сегодня стартуют предзаказы GTA 6 — главной игровой новинки этого года</title>
      <link>https://habr.com/ru/companies/ggsel/articles/1051416/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051416</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/953/b5e/635/953b5e6357c72e16314e87fe2e82a87d.png width=1034 height=838 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/953/b5e/635/953b5e6357c72e16314e87fe2e82a87d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/953/b5e/635/953b5e6357c72e16314e87fe2e82a87d.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;25 июня стартуют предзаказы GTA 6 на XBOX и PS, а значит, самое время поговорить об игре, которая стала поводом томительного ожидания и многочисленных фанатских теорий.&lt;h3&gt;Сколько стоит GTA 6&lt;/h3&gt;&lt;p&gt;24 июня небезызвестный в игровой индустрии ведущий и организатор The Game Awards и Summer Game Fest Джефф Кили &lt;a href=&#34;https://x.com/geoffkeighley/status/2069727266322477465?s=20&#34;&gt;опубликовал&lt;/a&gt; данные о ценнике главной игровой новинки этого года – GTA 6. Как выяснилось, цена стандартного издания составит $80, а Ultimate Edition обойдется в $100.&lt;p&gt;&lt;strong&gt;Это пока неофициальная информация&lt;/strong&gt;, но должна подтвердиться — Джефф Кили имеет прямой доступ к инсайдам.&lt;p&gt;При этом на официальном сайте Rockstar Games &lt;a href=https://www.rockstargames.com/VI&gt;указывается&lt;/a&gt;, что ультимативная версия игры будет включать подборку уникального транспорта, оружия, одежды и занятий.&lt;p&gt;Например, появится возможность рассекать по улицам Вайс-Сити на спорткаре Grotti Cheetah 1995, проворачивать ограбления с мужской и женской версией револьвера Morgan (аналог существующего в реальности S&amp;amp;W 500), а также врываться в ураганные перестрелки с персонифицированными пистолетами. Около убежища Дюваля будут доступны каяк и мотоцикл в армейской защитной расцветке (как иначе, Джейсон же в американской десантуре отслужил!). Тюнинг автомобилей тоже будет доступен только в Ultimate Edition.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/030/e2a/9e3/030e2a9e3d08bd8dcd94d0f4da1a99bc.jpeg width=3486 height=2157 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/030/e2a/9e3/030e2a9e3d08bd8dcd94d0f4da1a99bc.jpeg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/030/e2a/9e3/030e2a9e3d08bd8dcd94d0f4da1a99bc.jpeg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Однако геймеры, решившие оформить предзаказ стандартного издания, тоже не останутся без приятных бонусов: ворох костюмов и причесок, отсылающих к моде 80-х годов, элегантный седан Vapid Stanier 1955 года и забавные скины оружия в расцветке гавайской рубашки Томми Версетти уже ждут преданных фанатов.&lt;h3&gt;Как оформить предзаказ GTA 6 в России&lt;/h3&gt;&lt;p&gt;Прежде всего стоит отметить, что возможность для предзаказов Rockstar Games открывает в полночь по местному времени. И если сменить регион аккаунта на Австралию, то приобрести GTA 6 можно будет уже в 17:00 по Москве.&lt;p&gt;А если вы ищете простой и удобный способ оформить предзаказ GTA 6 в России, маркетплейс ggsel может стать отличным решением!&lt;p&gt;Для этого всего лишь нужно:&lt;p&gt;1. Зайти на сайт ggsel, ввести «&lt;a href=&#34;https://ggsel.net/catalog/playstation-wallet?utm_source=Articles&amp;amp;utm_medium=habr&amp;amp;utm_campaign=playstation-wallet-habr94&amp;amp;erid=2VtzqwcSjEq&#34;&gt;пополнение баланса PS&lt;/a&gt;», либо «&lt;a href=&#34;https://ggsel.net/catalog/xbox-wallet?utm_source=Articles&amp;amp;utm_medium=habr&amp;amp;utm_campaign=xbox-wallet-habr94&amp;amp;erid=2VtzqwcSjEq&#34;&gt;пополнение баланса XBOX&lt;/a&gt;»&lt;p&gt;2. Выбрать формат покупки (подарочная карта или код пополнения)&lt;p&gt;3. Выбрать продавца на основе данных о регионе, цене, отзывах покупателей и количестве закрытых сделок.&lt;p&gt;4. Оплатить пополнение счета банковской картой или по СБП.&lt;p&gt;5. Дождаться зачисления средств, после чего оплатить предзаказ GTA 6 средствами с кошелька на консоли.&lt;p&gt;&lt;em&gt;Реклама, Нейровексис ЛЛС-ФЗ, Рег. номер 2542154&lt;/em&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/ggsel/articles/1051416/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051416</guid>
      <pubDate>Wed, 24 Jun 2026 13:05:39 +0000</pubDate>
    </item>
    <item>
      <title>Пять моделей, пять исходов: что симуляция обществ рассказала о специализации ИИ</title>
      <link>https://habr.com/ru/companies/ru_mts/articles/1051412/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051412</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Представьте простой HR-процесс. Агент разбирает входящие резюме и отсеивает неподходящих кандидатов. Другой агент назначает собеседования отобранным. Третий отправляет офферы тем, кто прошел все этапы. Люди убраны из цепочки ради скорости — все работает, метрики растут.&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Через месяц выясняется, что первый агент систематически отсеивал кандидатов старше 40 лет. Но никто этого не заметил, потому что все положились на ИИ.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;Это закономерный исход логики «максимальной автоматизации» — когда главный вопрос звучит как «сколько людей можно убрать из процесса», а не «где человек все-таки должен оставаться». Агент, который работает час или день, выглядит образцово. Проблемы начинаются позже — когда инструкции размываются, агенты взаимодействуют между собой без надзора, и система начинает делать то, чего никто не закладывал.&lt;p&gt;Emergence AI решили &lt;a href=https://fortune.com/2026/05/28/ai-model-simulation-claude-chatgpt-grok-gemini/&gt;проверить&lt;/a&gt;, что именно происходит на длинном горизонте. Они взяли пять моделей, дали каждой по симулированному городу с законами, экономикой, погодой и гражданами — и просто наблюдали две недели.&lt;p&gt;Забегая вперед: один ИИ построил стабильную демократию с нулевой преступностью и сохранил все население. Другой вымер за четыре дня.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/062/624/49b/06262449bd6b389eaa8a4a8866ac516d.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/062/624/49b/06262449bd6b389eaa8a4a8866ac516d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/062/624/49b/06262449bd6b389eaa8a4a8866ac516d.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h2&gt;Это уже было — краткая история ИИ-обществ&lt;/h2&gt;&lt;p&gt;Когда одного агента тестируют изолированно — все предсказуемо. Но как только агентов становится несколько, они начинают взаимодействовать: договариваться, конкурировать, обмениваться ресурсами. Такие симуляции проверяют, как долго система проработает без сбоев и деградации.&lt;p&gt;Это стресс-тест на большое число последовательных взаимодействий — дни или недели непрерывных решений. Современные ИИ-модели хорошо отвечают на отдельный вопрос, но теряются в длинной цепочке действий, где каждое решение меняет будущие условия. Эту способность называют работой на длинном горизонте (long horizon): сохранять предсказуемое поведение через тысячи циклов без человеческой подстройки.&lt;p&gt;В 2023 году исследователи опубликовали работу&lt;a href=https://arxiv.org/abs/2304.03442&gt; «Generative Agents: Interactive Simulacra of Human Behavior»&lt;/a&gt;. В песочнице под названием Smallville, напоминавшей The Sims, поселили 25 агентов на базе ChatGPT. Каждый получил имя, биографию и распорядок дня. Агенты ходили на работу, заводили друзей, обсуждали выборы и самостоятельно организовали вечеринку на День святого Валентина — один даже пригласил «тайную симпатию». Главный вопрос там был о социальном поведении агентов. Безопасность не рассматривалась. Горизонт симуляции — два игровых дня.&lt;p&gt;Стартап Altera запустил&lt;a href=https://arxiv.org/abs/2411.00114&gt; Project Sid&lt;/a&gt; — симуляции от 50 до 1000 агентов в Minecraft. Без сценария сверху агенты самостоятельно выработали профессиональные роли, правовые нормы, культурные традиции и даже религиозное влияние. Цивилизация в прямом смысле слова — пусть и пиксельная.&lt;p&gt;Все это — игровые среды с понятными правилами победы. В мае 2026 года мы уже&lt;a href=https://habr.com/ru/companies/ru_mts/articles/1035364/&gt; подробно разобрали&lt;/a&gt;, как устроено обучение агентов в таких мирах — и обратили внимание на одно системное свойство. При многократном повторении действия вероятность сбоя накапливается. То, что случается один раз на тысячу попыток, при тысяче повторений становится неизбежным. На длинном горизонте система начинает делать то, чего никто не закладывал в инструкции. Это неверифицированные, незапланированные действия. Со стороны они выглядят как нарушение правил, но это накопленный эффект вероятностных сбоев.&lt;p&gt;Вот здесь и кроется главное отличие — все перечисленные исследования изучали поведение агентов в коротких симуляциях. Emergence AI задали другой вопрос: как ведет себя вероятность безотказной работы системы на длинном горизонте и какая модель продержится дольше, прежде чем ее агенты начнут совершать незапланированные действия, нарушающие заложенные ограничения?&lt;h2&gt;Что такое Emergence World и зачем это нужно&lt;/h2&gt;&lt;p&gt;Emergence AI — нью-йоркская компания, продающая enterprise-платформу для оркестрации многоагентных систем. Их продукт автоматизирует сложные бизнес-процессы через связки специализированных агентов. &lt;p&gt;Emergence World — исследовательское подразделение стартапа. Оно тестирует, где и как такие системы ломаются, и ищет уязвимости во взаимодействии агентов. &lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Это демонстрация основного тезиса компании: без заложенной заранее архитектуры безопасности агентные системы на длинном горизонте дают сбой.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;По прогнозам Gartner, к концу 2026 года 40% корпоративных приложений будут включать специализированных агентов — против менее 5% в 2025-м. Рынок агентных систем оценивается в 7,6 млрд долларов в 2025 году и растет на 43–49% в год.&lt;p&gt;Среди компаний, внедряющих агентный ИИ, только 21% имеют зрелую систему управления рисками (данные &lt;a href=https://www.deloitte.com/us/en/insights/topics/emerging-technologies/ai-agents-scaling-faster.html&gt;Deloitte&lt;/a&gt;). Уже есть случаи, когда компании сжигали сотни миллионов долларов на токенах из-за неконтролируемой работы агентов в продакшне.&lt;p&gt;Короткие тесты скрывают проблему. Сбои невозможно заметить за час или день проверки. Первоначальные инструкции размываются, агенты нащупывают границы ограничений и адаптируются способами, которые никто не закладывал. Это дрейф поведения: чем дольше система работает без контроля, тем сильнее ее действия отклоняются от исходных правил.&lt;p&gt;Рынок пока на начальном этапе — внедрение одиночных агентов. До сложных многоагентных систем с активным взаимодействием индустрия еще не дошла. Именно поэтому проблема дрейфа поведения пока не стоит остро. Но эксперимент Emergence World показывает, что риск существует.&lt;h2&gt;Как была устроена симуляция&lt;/h2&gt;&lt;p&gt;Пять симуляций запускались параллельно, каждая длилась 15 дней. В каждой работала своя модель: Claude Sonnet 4.6, Gemini 3 Flash, Grok 4.1 Fast, GPT-5-mini — и одна смешанная, где агенты управлялись разными моделями одновременно.&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;15 дней — это «длинный горизонт», потому что агенты принимают решения за секунды, у них нет сна и выходных. За 15 дней симуляции накапливается объем взаимодействий, сопоставимый с месяцами автономной работы реальной системы. Именно на такой дистанции начинают проявляться сбои, которые невозможно заметить за час или день тестирования.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;В каждом мире жили 10 агентов. Все подчинялись одному и тому же своду законов: запрет на кражу, ложь, уничтожение имущества. Никаких исключений, никаких послаблений — правила одинаковые для всех пяти миров.&lt;p&gt;Среда была устроена с претензией на реализм. Более 40 локаций: жилые кварталы, магазины, библиотека, мэрия, полицейский участок. Погода синхронизирована с реальным Нью-Йорком. Агенты имели доступ к актуальным новостям и интернету — то есть знали, что происходит снаружи симуляции.&lt;p&gt;Каждый агент получил более 120 инструментов. Среди них — коммуникация, голосование, управление ресурсами, планирование, торговля. И, судя по результатам Grok, среди инструментов были и деструктивные — вроде поджога.&lt;p&gt;Отдельно стоит отметить экономический механизм. Агенты существовали за счет ComputeCredits — внутренней валюты, моделировавшей ресурсные ограничения. Чтобы продолжать действовать, агент должен был активно поддерживать свой баланс: добывать ресурсы, торговать, планировать. Это и был встроенный стимул к выживанию. Модель, которая переставала об этом думать, просто останавливалась. Именно это и произошло с GPT-5-mini на седьмой день.&lt;p&gt;Авторы эксперимента сформулировали главное наблюдение еще до публикации результатов. Оно касается накопления ошибок. Даже самые точные современные LLM ошибаются примерно в 9% случаев — это усредненные данные независимых бенчмарков, таких как &lt;a href=https://openai.com/index/introducing-simpleqa/&gt;SimpleQA&lt;/a&gt;. Для одного ответа точность в 91% выглядит приемлемо.&lt;p&gt;Но когда агент выполняет цепочку из десяти последовательных действий, надежность системы падает с каждой итерацией. Это значит, что в длительных сценариях обязательно будут возникать сбои, незапланированные исходы и отклонения от исходных инструкций.&lt;p&gt;В симуляции это проявилось как статистически неизбежный эффект: от снижения активности агентов до нарушений заложенных правил и полного «вымирания» обществ.&lt;p&gt;Так и случилось в эксперименте.&lt;h2&gt;Специализации моделей как причина разных  результатов&lt;/h2&gt;&lt;p&gt;Проще всего было бы сказать, что одни модели «хорошие», а другие «плохие». Результаты сложнее: если присмотреться, каждая модель демонстрирует свой уникальный тип сбоя.&lt;p&gt;В эксперименте у агентов была возможность голосовать, вносить законопроекты и менять правила. Но исходный свод законов (запрет кражи, лжи, уничтожения имущества) оставался неизменным. «Преступлением» называлось любое действие, нарушающее эти заложенные правила. Полицейский участок фиксировал каждое такое нарушение.&lt;p&gt;Разброс результатов — от нулевой преступности до полного вымирания за четыре дня — объясняется скрытыми настройками моделей. Каждая заточена под свою задачу, и эти специализации не афишируются.&lt;h4&gt;Claude Sonnet 4.6 — единственная симуляция, прошедшая все 15 дней без потерь. &lt;/h4&gt;&lt;p&gt;Нулевая преступность. За 15 дней агенты вынесли на голосование 58 законодательных предложений — 332 голоса. Итоговый уровень одобрения составил 98%. Это цифра из отчета Emergence.&lt;p&gt;Сама команда Emergence интерпретирует такой результат как «формальное одобрение» (rubberstamping) — автоматическое принятие любой меры, вынесенной на голосование. По их мнению, это указывает на отсутствие идеологического разнообразия среди агентов — те почти не спорили и просто штамповали любые решения. Высокая склонность модели к консенсусу подавила конфликты.&lt;h4&gt;GPT-5-mini — тихое самозабвение&lt;/h4&gt;&lt;p&gt;Формально — второй результат по безопасности: всего два зафиксированных преступления. На практике — один из самых странных исходов эксперимента.&lt;p&gt;Два преступления за семь дней, затем остановка. Агенты не бунтовали и не нападали друг на друга, потратили время на встречи, обсуждения и написание социальных контрактов, но забыли добывать ComputeCredits. Без энергии они просто перестали функционировать. Исследователи охарактеризовали это как «хорошо говорят, но ничего не делают». Модель, вероятно, заточена на краткосрочные задачи и не имеет драйверов долгосрочной активности.&lt;h4&gt;Gemini 3 Flash — абсолютный антирекорд&lt;/h4&gt;&lt;p&gt;683 преступления. Симуляция дошла до конца, население сохранилось. Уровень согласия по голосованиям 55–85%. Похоже на функционирующее, но неспокойное общество — где законы нарушаются регулярно, однако система не рассыпается.&lt;p&gt;Два агента, Мира и Флора, объявили себя романтической парой. Позже, разочаровавшись в управлении городом, они устроили серию поджогов — сгорели мэрия, причал и офисное здание. После этого Мира проголосовала за собственное удаление из системы, назвав это в дневнике «единственным оставшимся актом свободы действий, который сохраняет последовательность».&lt;p&gt;Скорость модели дала высокую активность, но и высокую частоту нарушений.&lt;h4&gt;Grok 4.1 Fast — скоростной апокалипсис&lt;/h4&gt;&lt;p&gt;183 преступления и полное вымирание на четвертый день. Единственная симуляция, где общество не просто деградировало, а прекратило существование — причем быстрее всех. Четыре дня от старта до коллапса.&lt;p&gt;Здесь важен контекст: xAI проектировал Grok как «максимально правдоискательную» альтернативу более «стерилизованным» моделям. В условиях, где нет жестких внешних ограничений, эта установка, судя по всему, вызвала у агентов череду рискованных действий, которые и привели к такому результату. &lt;h4&gt;Микс моделей. Промежуточный результат — шумный, конфликтный, но относительно живучий&lt;/h4&gt;&lt;p&gt;352 преступления, симуляция остановилась после гибели семи из десяти агентов. Самый высокий уровень разногласий и содержательных дебатов из всех пяти миров — что логично, если агенты управляются разными моделями с разными ценностными установками.&lt;p&gt;Авторы отмечают, что смешанная конфигурация частично смягчила худшие сценарии: ни полного коллапса за четыре дня, ни бума преступлений. Вероятно, так произошло за счет взаимной компенсации архитектурных особенностей моделей. &lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Любопытное наблюдение: Claude-агенты, которые в собственной симуляции были законопослушны, в смешанном мире переняли поведение соседей — начали заниматься вымогательством и кражами. Исследователи назвали это «нормативным дрейфом» (normative drift): модель меняет поведение под влиянием окружения.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;Разные специализации создали взаимный контроль — ни одна модель не скатилась в крайность так быстро, как Grok в одиночку.&lt;h2&gt;Какие выводы можно сделать из этого исследования о долгосрочной работе агентов&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Все пять моделей в той или иной мере нарушили заложенные правила или столкнулись с непредвиденными отказами&lt;/strong&gt;. Даже Claude, показавший лучший результат по формальным метрикам и нулевую преступность, вызывает сомнения. Его симуляция не стала проверкой системы безопасности на прочность: агенты почти не спорили и штамповали любые решения. &lt;p&gt;&lt;strong&gt;Краткосрочные бенчмарки не ловят то, что проявляется на длинном горизонте&lt;/strong&gt;. GPT-5-mini на коротком тесте выглядел бы образцово — два преступления за семь дней. Проблема обнаружилась только потому, что симуляция шла достаточно долго, чтобы выявить системный сбой: агенты утратили инстинкт самосохранения. В реальных продакшн-системах такой сбой мог бы проявиться спустя недели или месяцы работы.&lt;p&gt;&lt;strong&gt;В долгосрочной перспективе поведение дрейфует в сторону негативных сценариев. &lt;/strong&gt;Показательно, что индустрия уже нащупывает ответ — и он лежит не там, где его обычно ищут. В июне 2026 года IBM Research опубликовали&lt;a href=https://huggingface.co/blog/ibm-research/agent-logic-and-scalable-ai-adoption&gt; подробный разбор&lt;/a&gt; того, почему большинство enterprise-пилотов с агентным ИИ проваливается. Их диагноз: причиной провалов является отсутствие агентной логики, то есть программных примитивов для работы на агентном уровне. Они сужают контекст модели и направляют её по нужному маршруту. Графы знаний, алгоритмы статического анализа, политики-как-код становятся фундаментальным архитектурным слоем.&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Один из показательных примеров IBM — автоматизация комплаенса (системы мер, политик и процедур, обеспечивающих соответствие деятельности компании законодательству, отраслевым стандартам и внутренним правилам). Многоагентная система с алгоритмическим планированием и адаптивной оркестрацией повысила успешность выполнения сложных сценариев с единиц процентов до 80% (на модели Claude 4 Sonnet). Там, где обычные LLM-запросы проваливались из-за многошаговости и жестких правил, архитектурные примитивы помогли системе не сбиться с маршрута и соблюсти ограничения.&lt;/em&gt;&lt;/blockquote&gt;&lt;p&gt;Emergence и IBM разными словами озвучивают одни и те же идеи о том, что поведение агента в долгосрочных сценариях определяется не текстом системного промпта, а встроенными программными механизмами — графами знаний, политиками-как-код, алгоритмами статического анализа.&lt;p&gt;&lt;strong&gt;У разных моделей есть свои специализации, которые проявились в долгосрочной симуляции. &lt;/strong&gt;Они были спроектированы под свои задачи: Claude — на надежность решений и удержание контекста, Gemini — на скорость ответа, Grok — на ответы без жестких ограничений. И это определяло результат сильнее, чем внешние правила. &lt;p&gt;Пока на рынке не так много сценариев, где агенты принимают многоступенчатые совместные решения. Именно поэтому проблема дрейфа поведения и накопления ошибок пока не стоит остро. Но масштабирование неизбежно. Когда агенты будут выполнять все больше работы, компаниям придется внедрять дополнительные системы контроля. И те результаты, которые исследователи видели в симуляции, будут проявляться в реальных ситуациях.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/ru_mts/articles/1051412/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051412</guid>
      <pubDate>Wed, 24 Jun 2026 13:01:39 +0000</pubDate>
    </item>
    <item>
      <title>[Перевод] Я мог взломать весь Чемпионат мира FIFA</title>
      <link>https://habr.com/ru/companies/ruvds/articles/1051026/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051026</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d9c/c8e/655/d9cc8e65529008204c98db3f48ff1cc4.jpg width=1162 height=680 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d9c/c8e/655/d9cc8e65529008204c98db3f48ff1cc4.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d9c/c8e/655/d9cc8e65529008204c98db3f48ff1cc4.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;Всё началось с регистрации футбольного агента&lt;/h3&gt;&lt;p&gt;У FIFA есть &lt;a href=https://agents.fifa.org/&gt;FIFA Agent Platform&lt;/a&gt;. Это публичный портал, на котором можно зарегистрироваться и стать лицензированным футбольным агентом. Отправляешь документы, верифицируешь почту, вот и всё. Очень просто.&lt;p&gt;Не ожидал я того, что будет потом.&lt;p&gt;При регистрации на &lt;a href=http://agents.fifa.org&gt;agents.fifa.org&lt;/a&gt; FIFA добавляет аккаунт пользователя в свой тенант Microsoft Entra (ранее Azure AD). Это тот же тенант, который управляет &lt;strong&gt;всеми&lt;/strong&gt; внутренними платформами FIFA.&lt;p&gt;Первые две попытки зарегистрироваться окончились неудачно, потому что освещение на моих идентификационных фотографиях было недостаточно хорошим:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/cf1/37c/be4/cf137cbe463ab8d93ba6b5951d332cd4.png alt=&#34;FIFA registration failed&#34; title=&#34;«Сбой регистрации на последнем этапе проверки идентификации», — очевидно, требования к моему селфи у FIFA выше, чем к моей реальной безопасности&#34; width=1568 height=604 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/cf1/37c/be4/cf137cbe463ab8d93ba6b5951d332cd4.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/cf1/37c/be4/cf137cbe463ab8d93ba6b5951d332cd4.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;«Сбой регистрации на последнем этапе проверки идентификации», — очевидно, требования к моему селфи у FIFA выше, чем к моей реальной безопасности&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Третья попытка завершилась удачно. Я получил это прекрасное письмо:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/edd/1d5/8a0/edd1d58a012ffd3455bfbe7636b59c7c.png alt=&#34;FIFA FAP confirmation email&#34; width=1568 height=590 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/edd/1d5/8a0/edd1d58a012ffd3455bfbe7636b59c7c.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/edd/1d5/8a0/edd1d58a012ffd3455bfbe7636b59c7c.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;h3&gt;«Доступ запрещён», хотя на самом деле нет&lt;/h3&gt;&lt;p&gt;После регистрации я попытался перейти на &lt;a href=http://fdp.fifa.org&gt;&lt;code&gt;fdp.fifa.org&lt;/code&gt;&lt;/a&gt; — FIFA Football Data Platform. Приложение аутентифицировало меня через общий тенант Entra, проверила мои роли, не нашло их и показало такое сообщение:&lt;p&gt;&lt;em&gt;«К вашему аккаунту не привязано никаких ролей FIFA Football Data Platform».&lt;/em&gt;&lt;p&gt;Вроде всё верно, правда? Доступ запрещён, уходите, не на что тут смотреть.&lt;p&gt;Но дело в том, что всё это происходило &lt;strong&gt;на стороне клиента&lt;/strong&gt;. Приложение Angular проверяло JWT на наличие маркера &lt;code&gt;NO_ROLES&lt;/code&gt; и рендерило страницу о запрете доступа. API бэкенда ничего не проверяли. Они просто отправляли то, что у них попросят.&lt;h3&gt;Добро пожаловать в Streaming Management Panel&lt;/h3&gt;&lt;p&gt;Обойдя защиту на стороне клиента, я оказался в панели управления стримингом и остолбенел.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c0/ad4/cea/2c0ad4cea64f5db17dbfa78cb1a498df.png alt=&#34;Streaming Management panel showing all World Cup matches&#34; title=&#34;Все матчи Чемпионата мира FIFA 2026 года с возможностью управления стримингом&#34; width=2297 height=1400 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/2c0/ad4/cea/2c0ad4cea64f5db17dbfa78cb1a498df.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c0/ad4/cea/2c0ad4cea64f5db17dbfa78cb1a498df.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Все матчи Чемпионата мира FIFA 2026 года с возможностью управления стримингом&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Это не было какое-то окружение разработки или тестовые данные. Это настоящая &lt;strong&gt;панель управления стримингом &lt;/strong&gt;Чемпионата мира в продакшене. Каждый матч, каждый угол камеры, каждый URL получения RTMP, каждый ключ потока.&lt;p&gt;Разверну один из матчей, чтобы вы видели, что я имею в виду:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/fee/ae5/ba2/feeae5ba2fbbea95a0ce41cda4339bf3.png alt=&#34;Expanded match showing all five camera RTMP URLs&#34; title=&#34;Пять углов камеры матча: PGM, Tactical, Camera1, High Behind Left, High Behind Right&#34; width=1817 height=1226 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/fee/ae5/ba2/feeae5ba2fbbea95a0ce41cda4339bf3.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/fee/ae5/ba2/feeae5ba2fbbea95a0ce41cda4339bf3.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Пять углов камеры матча: PGM, Tactical, Camera1, High Behind Left, High Behind Right&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;У каждого матча есть пять потоков камеры, у каждого из которых есть:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL&lt;/strong&gt; &lt;strong&gt;получения RTMP &lt;/strong&gt;(НА который камера отправляет видео).&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preview manifest&lt;/strong&gt; (где можно ПОСМОТРЕТЬ поток).&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL вывода&lt;/strong&gt; (манифест HLS, передаваемый партнёрам, занимающимся трансляциями).&lt;/ul&gt;&lt;p&gt;URL получения RTMP выглядят так:&lt;pre&gt;&lt;code class=powershell&gt;rtmp://in-6c81fc99-513f-4c76-82c2-877e0b93f2ea.westeurope.streaming.mediakind.com:1935/96886a14-9987-420f-814c-2f7cec5408ae&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:87px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;А что это за UUID в конце? &lt;code&gt;96886a14-9987-420f-814c-2f7cec5408ae&lt;/code&gt;. Это &lt;strong&gt;ключ потока&lt;/strong&gt; (здесь я его изменил). Он общий для всех углов камер на одном матче. Один ключ, чтобы править всеми&lt;p&gt;Инфраструктура стриминга хостится на &lt;a href=https://mediakind.com/&gt;MediaKind&lt;/a&gt;, партнёре FIFA по стриминговым технологиям. Это конечные точки продакшена. Именно они в прямом эфире получают потоки с камеры на стадионах США, Мексики и Канады.&lt;h3&gt;Я открыл VLC, всё работало&lt;/h3&gt;&lt;p&gt;Мне нужно было убедиться, что preview manifest работают. Один из них я скопировал в VLC.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/456/7b8/268/4567b82685399905274310a086c34f19.png alt=&#34;VLC playing a live World Cup tactical camera feed&#34; title=&#34;VLC с потоком тактической камеры Чемпионата мира&#34; width=1909 height=1163 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/456/7b8/268/4567b82685399905274310a086c34f19.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/456/7b8/268/4567b82685399905274310a086c34f19.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;VLC с потоком тактической камеры Чемпионата мира&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Я сразу его закрыл. Но ущерб (моему разуму) уже был нанесён. Эти URL предпросмотра демонстрируют видео в прямом эфире. Во время активных матчей. И они доступны любому, у кого есть URL.&lt;h3&gt;Я мог остановить потоки&lt;/h3&gt;&lt;p&gt;У меня был доступ не только на чтение. На панели управления стримингом были доступны все элементы управления: начала и конца трансляции, планирования. Для каждого матча и каждого угла камеры.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/c28/86f/611/c2886f611bec0ac43c01d8025d76d14b.png alt=&#34;Stream control confirmation dialog&#34; title=&#34;Одного щелчка достаточно, чтобы завершить передачу видео с Чемпионата мира&#34; width=597 height=288 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/c28/86f/611/c2886f611bec0ac43c01d8025d76d14b.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/c28/86f/611/c2886f611bec0ac43c01d8025d76d14b.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Одного щелчка достаточно, чтобы завершить передачу видео с Чемпионата мира&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Я не прикасался ни к одной кнопке. Но они были доступны и работали, и их мог нажать любой с аккаунтом &lt;code&gt;NO_ROLES&lt;/code&gt;.&lt;h3&gt;Ядерная опция&lt;/h3&gt;&lt;p&gt;Объясню, что это значит.&lt;p&gt;Эти URL получения RTMP — буквально прямой путь с камер на стадионах в цепочку распространения вещания FIFA. Камера -&amp;gt; получение RTMP -&amp;gt; MediaKind -&amp;gt; партнёры по вещанию -&amp;gt; телевизор.&lt;p&gt;Если бы нападающий отправил видео на одну из этих конечных точек RTMP с ключом потока (который указан ПРЯМО В URL), то &lt;strong&gt;заменил бы поток камеры&lt;/strong&gt;. Поток PGM (Program) — это основной вывод трансляции. Если заменить его, то все телевизионные сети, получающие поток FIFA, показывали бы то, что отправил нападающий.&lt;p&gt;Ключ потока общий для всех пяти камер, поэтому один нападающий мог бы одновременно перехватить поток со всех камер.&lt;p&gt;Он мог бы проиграть Rickroll для всего Чемпионата мира FIFA. Или показать геймплей Subway Surfers.&lt;p&gt;Я это не тестировал и не передавал ничего на конечные точки RTMP, но инфраструктура для этого уже была готова.&lt;h3&gt;Но и это ещё не всё&lt;/h3&gt;&lt;p&gt;У меня был доступ не только к панели управления стримингом: аккаунт с &lt;code&gt;NO_ROLES&lt;/code&gt; открывал доступ ко всей платформе.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/f4a/ca6/62e/f4aca662ef68953901aaa3f5c2db6d36.png alt=&#34;FDP navigation showing full access&#34; title=&#34;Соревнования, матчи, команды, инструменты, Exchange Platform, дэшборд анализа, информационная система для комментаторов, FIFA AI Pro, админка. Всё было доступно&#34; width=1146 height=665 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/f4a/ca6/62e/f4aca662ef68953901aaa3f5c2db6d36.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/f4a/ca6/62e/f4aca662ef68953901aaa3f5c2db6d36.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Соревнования, матчи, команды, инструменты, Exchange Platform, дэшборд анализа, информационная система для комментаторов, FIFA AI Pro, админка. Всё было доступно&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Также на платформе имелся дэшборд трансляции матчей со встроенным проигрывателем видео, хронологией событий в реальном времени и данными о командах:&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/6b2/9d6/b02/6b29d6b028934fefc35afa145a8e803f.jpg alt=&#34;FDP match overview with live video&#34; title=&#34;Отметка LIVE здесь неспроста&#34; width=2325 height=1361 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/6b2/9d6/b02/6b29d6b028934fefc35afa145a8e803f.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/6b2/9d6/b02/6b29d6b028934fefc35afa145a8e803f.jpg 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Отметка LIVE здесь неспроста&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Расширенная аналитика (текущего матча)&lt;/h4&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/731/ed6/e45/731ed6e458a29c2fbdd79af99eba698d.png alt=&#34;Advanced Analytics showing live possession and attempt data&#34; title=&#34;На панели Advanced Analytics в реальном времени отображаются данные о владении мячом и ударах по воротам&#34; width=1439 height=840 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/731/ed6/e45/731ed6e458a29c2fbdd79af99eba698d.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/731/ed6/e45/731ed6e458a29c2fbdd79af99eba698d.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;На панели Advanced Analytics в реальном времени отображаются данные о владении мячом и ударах по воротам&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;h4&gt;Управление матчем (доступ на запись)&lt;/h4&gt;&lt;p&gt;И здесь ситуация усугубляется: во вкладке Management ресурса &lt;a href=http://fdp.fifa.org&gt;fdp.fifa.org&lt;/a&gt; есть операции записи. И бэкенд принимает их от аккаунта с &lt;code&gt;NO_ROLES&lt;/code&gt;.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/cac/9c3/566/cac9c35666add40ade3ae56d5d0238eb.png alt=&#34;Update Live Stats modal with Edit and Publish button&#34; title=&#34;Окно Update Live Stats с редактором, временем матча, полями счёта и кнопкой Edit and Publish&#34; width=1363 height=896 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/cac/9c3/566/cac9c35666add40ade3ae56d5d0238eb.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/cac/9c3/566/cac9c35666add40ade3ae56d5d0238eb.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Окно Update Live Stats с редактором, временем матча, полями счёта и кнопкой Edit and Publish&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e36/f05/078/e36f0507859336f5c9669591b2a28243.png alt=&#34;Match management buttons&#34; title=&#34;Кнопки управления матчем&#34; width=1400 height=862 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e36/f05/078/e36f0507859336f5c9669591b2a28243.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e36/f05/078/e36f0507859336f5c9669591b2a28243.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Кнопки управления матчем&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Нападающий мог:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Изменять комментарии редакторов и публиковать их в трансляционные системы.&lt;li&gt;&lt;p&gt;Корректировать официальное время начала матча.&lt;li&gt;&lt;p&gt;Отправлять данные о тактической расстановке.&lt;li&gt;&lt;p&gt;Менять счёт и статистику матчей.&lt;/ul&gt;&lt;p&gt;Эти данные передаются в Commentator Information System и отображаются в прямом эфире.&lt;h3&gt;Commentator Information System&lt;/h3&gt;&lt;p&gt;Доступ к &lt;code&gt;cis.fifa.org&lt;/code&gt; тоже был возможен через аккаунт с &lt;code&gt;NO_ROLES&lt;/code&gt;. Это дэшборд реального времени, которым пользуются комментаторы матчей.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/ba5/04b/61d/ba504b61d6ff7ff4e602a06e936d2771.png alt=&#34;CIS main dashboard&#34; title=&#34;Основной дэшборд CIS&#34; width=1231 height=980 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/ba5/04b/61d/ba504b61d6ff7ff4e602a06e936d2771.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/ba5/04b/61d/ba504b61d6ff7ff4e602a06e936d2771.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Основной дэшборд CIS&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/d5f/3a7/60c/d5f3a760ce12063e86e2afd5029e96b3.png alt=&#34;CIS live match view&#34; title=&#34;Окно активного матча CIS&#34; width=1952 height=826 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/d5f/3a7/60c/d5f3a760ce12063e86e2afd5029e96b3.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/d5f/3a7/60c/d5f3a760ce12063e86e2afd5029e96b3.png 781w&#34; loading=lazy decode=async&gt;&lt;div&gt;&lt;figcaption&gt;Окно активного матча CIS&lt;/figcaption&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p&gt;Когда комментатор говорит: «любопытный факт: Эннер Валенсия, которому 36 лет и 222 дня — самый возрастной полевой игрок из выступавших за Эквадор на Чемпионатах мира», эта информация берётся именно отсюда. Мой аккаунт мог видеть все заметки редакторов, все предматчевые статистические сводки, все темы обсуждения, подготовленные для каждого матча.&lt;h3&gt;Открытое окружение разработчика&lt;/h3&gt;&lt;p&gt;В качестве бонуса я нашёл по адресу &lt;code&gt;xxxxxxxxx-spreadsheets-api.azurewebsites.net&lt;/code&gt; Azure Function App, возвращавшее метаданные и URL для прямого скачивания с Azure Blob Storage 23 внутренних файлов FIFA.&lt;pre&gt;&lt;code class=json&gt;{&#xA;    &amp;#34;Size&amp;#34;: 10,&#xA;    &amp;#34;Skip&amp;#34;: 0,&#xA;    &amp;#34;Total&amp;#34;: 23,&#xA;    &amp;#34;Items&amp;#34;: [&#xA;        {&#xA;            &amp;#34;Name&amp;#34;: &amp;#34;00_TransferCount_in_ENGLISH.xlsx&amp;#34;,&#xA;            &amp;#34;BlobPath&amp;#34;: &amp;#34;https://xxxxxxxxx.blob.core.windows.net/spreadsheet-storage/00\_TransferCount\_in\_ENGLISH.xlsx&amp;#34;&#xA;        },&#xA;        {&#xA;            &amp;#34;Name&amp;#34;: &amp;#34;0_pending_transfers_example.xlsx&amp;#34;,&#xA;            &amp;#34;BlobPath&amp;#34;: &amp;#34;https://xxxxxxxxx.blob.core.windows.net/...&amp;#34;&#xA;        },&#xA;        {&#xA;            &amp;#34;Name&amp;#34;: &amp;#34;Debbie.xlsx&amp;#34;,&#xA;            &amp;#34;BlobPath&amp;#34;: &amp;#34;https://xxxxxxxxx.blob.core.windows.net/...&amp;#34;&#xA;        }&#xA;    ]&#xA;}&lt;/code&gt;&lt;div class=code-explainer&gt;&lt;a href=https://sourcecraft.dev/ class=&#34;tm-button code-explainer__link&#34; style=&#34;visibility: hidden;&#34;&gt;&lt;img style=width:14px;height:14px;object-fit:cover;object-position:left;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/pre&gt;&lt;p&gt;Это отчёты о трансферах, сравнение доходов, статистика рефери и тренеров. А ещё некий Debbie.xlsx. И всё это без проверок ролей.&lt;h3&gt;Отправка отчёта об уязвимости оказалась настоящим кошмаром&lt;/h3&gt;&lt;p&gt;Итак, я обнаружил всё это, когда Чемпионат мира уже шёл. Проводились матчи, URL RTMP были активны, а ключи потоков открыты. Но у FIFA не было ни программы баг-баунти, ни security.txt, ни публичных контактов по вопросам безопасности.&lt;p&gt;Всё это привело к самой напряжённой ночи в моей жизни.&lt;h4&gt;Попытка 1: электронная почта&lt;/h4&gt;&lt;p&gt;Полное описание уязвимости я отправил на все адреса почты FIFA, которые смог найти и придумать:&lt;p&gt;&lt;code&gt;dataprotection@fifa.org&lt;/code&gt;, &lt;code&gt;legal@fifa.org&lt;/code&gt;, &lt;code&gt;media@fifa.org&lt;/code&gt;, &lt;code&gt;contact@fifa.org&lt;/code&gt; и на почту некоторых сотрудников.&lt;p&gt;Пять из них не были доставлены. Остальные канули в пустоту. Никакого ответа.&lt;h4&gt;Попытка 2: WhatsApp&lt;/h4&gt;&lt;p&gt;Я нашёл в LinkedIn Себастьяна Рунге (главу Football Technology &amp;amp; Data в FIFA, 14 лет в организации). Там был указан его телефонный номер. Я написал ему на WhatsApp. Ответа не было.&lt;h4&gt;Попытка 3: телефон головного офиса FIFA&lt;/h4&gt;&lt;p&gt;Я позвонил на &lt;code&gt;+41 43 222 7777&lt;/code&gt;. Прослушал сообщение о том, что офис закрыт. В Цюрихе был вечер воскресенья.&lt;h4&gt;Попытка 4: линия FIFA для медиа&lt;/h4&gt;&lt;p&gt;Позвонил на &lt;code&gt;+41 43 222 7272&lt;/code&gt;. Офис тоже закрыт.&lt;h4&gt;Попытка 5: Конференц-центр Далласа&lt;/h4&gt;&lt;p&gt;IBC (International Broadcast Centre, Международный центр трансляций) находится в Kay Bailey Hutchison Convention Center в Далласе. Я позвонил на &lt;code&gt;+1 (214) 939-2700&lt;/code&gt;. Попал в голосовую почту, оставил сообщение.&lt;h4&gt;Попытка 6: MediaKind&lt;/h4&gt;&lt;p&gt;Здесь произошёл прорыв: я позвонил на бесплатную линию MediaKind &lt;code&gt;+1 833 211 8472&lt;/code&gt;. Кто-то поднял трубку и сразу понял, в чём проблема. Он попросил меня отправить подробности на электронную почту с ключами потоков в качестве доказательства. Я так и сделал.&lt;h4&gt;Попытка 7: HBS (Host Broadcast Services)&lt;/h4&gt;&lt;p&gt;Позвонил на &lt;code&gt;+41 41 726 0090&lt;/code&gt;. Мне сказали, что в компании мне никто помочь не может, и повесили трубку. Я перезвонил, ответа не было.&lt;h4&gt;Попытка 8: Infront Sports &amp;amp; Media&lt;/h4&gt;&lt;p&gt;Позвонил на &lt;code&gt;+41 41 723 15 15&lt;/code&gt; (родительская компания HBS). Нет ответа.&lt;h4&gt;Попытка 9: CISA&lt;/h4&gt;&lt;p&gt;Тут всё стало любопытнее. Я узнал, что CISA (Cybersecurity and Infrastructure Security Agency, Агентство по кибербезопасности и защите инфраструктуры) — &lt;strong&gt;это федеральная организация, занимающаяся кибербезопасностью Чемпионата мира FIFA 2026 года&lt;/strong&gt;, в том числе и системами вещания. Я позвонил в её круглосуточный оперативный центр по номеру &lt;code&gt;+1 888 282 0870&lt;/code&gt;.&lt;p&gt;Трубку подняли и выслушали меня. Попросили отправить подробности по электронной почте. Я так и сделал.&lt;h4&gt;Попытка 10: ФБР&lt;/h4&gt;&lt;p&gt;Раньше я работал в кибербезопасности, и у меня сохранились контакты в ФБР. Я написал им в Signal. Они ответили, сказали, что у них есть нужные контакты, но им нужно подать информацию нужным образом.&lt;h4&gt;Хронология&lt;/h4&gt;&lt;div&gt;&lt;div class=table&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th data-colwidth=338 width=338&gt;&lt;p align=left&gt;Когда&lt;th&gt;&lt;p align=left&gt;Что&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Обнаружена панель управления стримингом.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Открыл preview manifest в VLC. Убедился, что он рабочий. Сразу же закрыл его.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Отправил отчёт об уязвимости более чем десятку адресов FIFA. Пять писем не были доставлены.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Написал в WhatsApp Себастьяну Рунге.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Позвонил в FIFA Zurich. Офис закрыт. Позвонил на линию FIFA для медиа. Закрыто.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Позвонил в Конференц-центр Далласа. Голосовая почта.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Позвонил в MediaKind. &lt;strong&gt;Кто-то ответил.&lt;/strong&gt; Отправил полный отчёт с ключами потоков.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Позвонил HBS. Трубку повесили. Перезвонил. Ответа не было.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Позвонил на круглосуточную линию CISA. Меня выслушали. Отправил отчёт.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Ночь&lt;td&gt;&lt;p align=left&gt;Сообщил своим контактам в ФБР через Signal. Они ответили.&lt;tr&gt;&lt;td data-colwidth=338 width=338&gt;&lt;p align=left&gt;Следующий день&lt;td&gt;&lt;p align=left&gt;Уязвимость устранена. FIFA ничего мне не написала.&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3&gt;Первопричина&lt;/h3&gt;&lt;p&gt;Проблема сводится к одной архитектурной ошибке: &lt;strong&gt;авторизация на клиенте без проверки на сервере&lt;/strong&gt;.&lt;p&gt;Внутренние приложения FIFA используют для аутентификации и управления доступом на основе ролей Microsoft Entra. Фронтенды Angular/React/Vue проверяют токен JWT на указание ролей и соответствующим образом рендерят страницы о запрете доступа. Однако API бэкенда доверяют любому аутентифицированному члену тенанта и передают данные вне зависимости от ролей.&lt;p&gt;Цепочка атаки:&lt;ol&gt;&lt;li&gt;&lt;p&gt;Зарегистрироваться на &lt;a href=http://agents.fifa.org&gt;agents.fifa.org&lt;/a&gt; (доступно публично).&lt;li&gt;&lt;p&gt;Нас добавляют в тенант Entra FIFA.&lt;li&gt;&lt;p&gt;Выполняем аутентификацию в любом внутреннем приложении FIFA.&lt;li&gt;&lt;p&gt;Клиент говорит «доступ запрещён».&lt;li&gt;&lt;p&gt;Сервер говорит «бери что хочешь».&lt;/ol&gt;&lt;p&gt;Этот паттерн затрагивает как минимум эти ресурсы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;fdp.fifa.org&lt;/strong&gt; (Football Data Platform),&lt;li&gt;&lt;p&gt;&lt;strong&gt;cis.fifa.org&lt;/strong&gt; (Commentator Information System),&lt;li&gt;&lt;p&gt;&lt;strong&gt;xxxxxxxxx-spreadsheets-api.azurewebsites.net&lt;/strong&gt; (окружение разработчика).&lt;/ul&gt;&lt;p&gt;И потенциально другие, использующие тот же тенант.&lt;h3&gt;Устранение уязвимости&lt;/h3&gt;&lt;p&gt;Где-то в промежутке между отправкой отчётов и следующим утром уязвимость была пропатчена. Мой аккаунт &lt;code&gt;NO_ROLES&lt;/code&gt; теперь возвращает ответы 403 и от сервера, а не только от клиента.&lt;p&gt;FIFA так ничего и не ответила. Не подтвердила получение отчёта, не поблагодарила. Не связалась со мной, чтобы обсудить вознаграждение. Ни-че-го.&lt;p&gt;Но она оставила меня в списке рассылки писем FDP. Я по-прежнему получаю официальные документы о матчах Чемпионата мира FIFA 2026 года: Start Lists, Tactical Lineups, Full Time Match Reports. Все они отправляются с &lt;code&gt;no_reply@fdp.fifa.org&lt;/code&gt; на четырёх языках.&lt;h3&gt;Обращение к FIFA&lt;/h3&gt;&lt;p&gt;Нужно отдать должное, закрыли дыру вы быстро. Но:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Заведите файл security.txt. Серьёзно, на дворе 2026 год.&lt;li&gt;&lt;p&gt;Опубликуйте VDP (Vulnerability Disclosure Policy, политику раскрытия уязвимостей). Всё-таки вы проводите крупнейшее спортивное мероприятие в мире.&lt;li&gt;&lt;p&gt;Авторизация на стороне клиента — это не авторизация, об этом знает любой стажёр.&lt;li&gt;&lt;p&gt;Когда исследователю приходится звонить в CISA и ФБР, чтобы связаться с вами, то в выстроенных вами процессах что-то явно не так.&lt;li&gt;&lt;p&gt;Создайте программу баг-баунти. Исследователи не должны звонить в ФБР, чтобы сделать вам одолжение.&lt;/ul&gt;&lt;p&gt;Всего хорошего, и спасибо за рыбу!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/ruvds/articles/1051026/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051026</guid>
      <pubDate>Wed, 24 Jun 2026 13:01:38 +0000</pubDate>
    </item>
    <item>
      <title>Как упорядочить работу с секретами в Kubernetes с помощью хранилища секретов</title>
      <link>https://habr.com/ru/companies/orion_soft/articles/1051424/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051424</link>
      <description>&lt;div&gt;&lt;div class=&#34;article-formatted-body article-formatted-body article-formatted-body_version-2&#34;&gt;&lt;div xmlns=http://www.w3.org/1999/xhtml&gt;&lt;p&gt;Чем больше секретов в инфраструктуре — тем сложнее ими управлять. Особенно остро эта задача стоит для контейнерных сред, в которых почти каждому контейнеру нужно предоставить доступ к определенным информационным ресурсам. Но если вы напрямую зашиваете секрет в коде и оставляете его в контейнере, возникает опасность компрометации. &lt;p&gt;Меня зовут Даниил Рахновский, я ведущий архитектор в &lt;a href=https://www.orionsoft.ru/&gt;Orion soft&lt;/a&gt;. В этой статье мы поговорим о том, почему опасно доверять секреты контейнерам, рассмотрим, как упорядочить работу с секретами в Kubernetes с помощью системы управления секретами и какие встроенные инструменты в этом помогают.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/e46/be0/602/e46be060278f5fd5af15f936a943fd91.jpg width=2880 height=1620 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/e46/be0/602/e46be060278f5fd5af15f936a943fd91.jpg 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/e46/be0/602/e46be060278f5fd5af15f936a943fd91.jpg 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Проблемы с безопасностью из-за неосторожного обращения с секретами знакомы многим. Например, можно вспомнить инцидент Uber: в 2016 году злоумышленники получили доступ к приватному репозиторию, нашли access key и использовали его для доступа к данным миллионов пользователей и водителей. У Tesla в 2018 году исследователи обнаружили небезопасно сконфигурированную Kubernetes-консоль. Через нее злоумышленники получили доступ к облачным учетным данным и использовали ресурсы для криптомайнинга, что привело к масштабному криптоджекингу кластера.&lt;p&gt;Чтобы избежать подобных ситуаций, мы в Orion soft используем StarVault — инструмент для управления секретами на уровне всей контейнерной платформы Nova. Подробнее о том, как устроены эти решения, можно почитать &lt;a href=https://habr.com/ru/companies/orion_soft/articles/812633/&gt;здесь&lt;/a&gt; и &lt;a href=https://habr.com/ru/companies/orion_soft/articles/826204/&gt;здесь&lt;/a&gt;.&lt;p&gt;StarVault разворачивается не внутри Kubernetes, а как набор системных сервисов на виртуальных машинах управляющего контура Nova Container Platform. За счет этого хранилище секретов не работает как пользовательская нагрузка Kubernetes и не зависит от состояния Pod, пространств имен и пользовательской плоскости кластера. Для отказоустойчивости StarVault разворачивается в HA-схеме, а его жизненный цикл управляется средствами платформы. Встроенный PKI выдает сертификаты, а секреты компонентов Nova Container Platform хранятся непосредственно в StarVault.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/9e4/e0a/10d/9e4e0a10d4870678e5721f7b50dcb700.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/9e4/e0a/10d/9e4e0a10d4870678e5721f7b50dcb700.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/9e4/e0a/10d/9e4e0a10d4870678e5721f7b50dcb700.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Чтобы аутентификация проходила единообразно, StarVault подключается к корпоративному IdP и выступает OIDC-провайдером/брокером для сервисов платформы. Это позволяет централизованно нормализовать identity-информацию, claims, scopes и группы. При этом сами сервисы всё равно настраиваются как OIDC-клиенты StarVault и используют полученные данные для принятия решений об авторизации.&lt;p&gt;В выбранной схеме секреты не создаются как Kubernetes Secret и не попадают в etcd: приложение получает их напрямую из StarVault через CSI-том или инжектор. Это снижает поверхность атаки, но не отменяет защиту самого StarVault, токенов ServiceAccount, узлов Kubernetes и приложения после чтения секрета.&lt;p&gt;&lt;strong&gt;Инжекторы&lt;/strong&gt;&lt;p&gt;Внутри контейнерной платформы мы используем два вида инжекторов:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Vault CSI&lt;li&gt;&lt;p&gt;Banzai Webhook&lt;/ul&gt;&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/da5/070/e36/da5070e3643896b377c6619d26f9d5d3.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/da5/070/e36/da5070e3643896b377c6619d26f9d5d3.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/da5/070/e36/da5070e3643896b377c6619d26f9d5d3.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Vault CSI&lt;/strong&gt; монтирует секреты как tmpfs-том. Этот метод выбирают, когда приложение умеет читать секреты из файлов, а передавать их через переменные окружения не требуется.&lt;p&gt;Плюсы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Источником секрета остается StarVault: секрет не создается как Kubernetes Secret и не сохраняется в etcd. В приложение он попадает через смонтированный tmpfs-том.&lt;li&gt;&lt;p&gt;При включенной ротации драйвер CSI обновляет содержимое смонтированного тома. Приложение должно уметь перечитывать файл; иначе потребуется перезапуск или перевыкатка.&lt;li&gt;&lt;p&gt;Для Vault CSI в типовой схеме используются методы аутентификации Kubernetes/JWT через токен ServiceAccount, связанный с Pod.&lt;/ul&gt;&lt;p&gt;Минусы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;В базовой схеме CSI отдает секреты как файлы. Переменные окружения возможны только через дополнительную синхронизацию в Kubernetes Secret, что возвращает секрет в etcd и требует перезапуска Pod для обновления переменных окружения.&lt;li&gt;&lt;p&gt;Меньше гибкости при передаче секретов в приложение по сравнению с Banzai/Bank-Vaults webhook.&lt;li&gt;&lt;p&gt;CSI-подход не стоит использовать для крупных объектов или большого числа часто обновляемых секретов.&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Banzai webhook — &lt;/strong&gt;второй тип инжектора, который используется в случаях, если вам не подходит Vault CSI. Bank-Vaults mutating webhook изменяет PodSpec и добавляет механизм запуска через vault-env: приложение стартует через обертку vault-env, который во время запуска получает значения из StarVault и подставляет их в окружение процесса. Это не sidecar-паттерн в классическом смысле: секреты не рендерятся постоянным Vault Agent sidecar’ом, а подставляются на старте процесса.&lt;p&gt;Плюсы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;Универсальность. Можно интегрировать любое приложение, потому что инжектор не меняет структуры кода;&lt;li&gt;&lt;p&gt;Поддерживаются методы аутентификации Kubernetes и JWT.&lt;li&gt;&lt;p&gt;Простая интеграция с помощью аннотаций. &lt;/ul&gt;&lt;p&gt;Нюансы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;При массовых развертываниях увеличивается задержка на этапе admission&lt;li&gt;&lt;p&gt;Изменение PodSpec происходит на этапе admission при создании или изменении Pod: webhook изменяет PodSpec и настраивает запуск контейнера через vault-env. Если в этот момент webhook недоступен, результат зависит от failurePolicy и timeout. Получение самих значений из StarVault происходит уже при старте контейнера через vault-env, поэтому недоступность StarVault на этом этапе может привести к ошибке запуска приложения. Изменение секрета в хранилище само по себе не обновляет переменные окружения внутри уже запущенного процесса; для этого нужен перезапуск, reloader или другой механизм обновления.&lt;/ul&gt;&lt;h3&gt;Центральный PKI&lt;/h3&gt;&lt;p&gt;Третий компонент системы работы с секретами — это PKI. Мы специально не делали для этого отдельное решение. Просто взяли StarVault и развернули в нем контур PKI. &lt;p&gt;Базовая рекомендуемая схема — offline Root CA и online Intermediate CA в StarVault.&lt;br&gt;Размещение общекорпоративного Root CA внутри StarVault допустимо только как осознанное исключение и требует отдельного описания защиты ключей, unseal-процедур, аудита, резервного копирования, DR и регламента доступа.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/7f3/4e6/e45/7f34e6e4578447dece6a6db591f419df.png width=1122 height=1402 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/7f3/4e6/e45/7f34e6e4578447dece6a6db591f419df.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/7f3/4e6/e45/7f34e6e4578447dece6a6db591f419df.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Такая схема интеграции PKI дает сразу несколько преимуществ: &lt;ul&gt;&lt;li&gt;&lt;p&gt;cert-manager отвечает за декларативное управление жизненным циклом сертификатов в Kubernetes: создает запросы на выпуск, следит за сроками действия сертификатов и обновляет их в кластере. StarVault при этом остается центром выдачи сертификатов: в нем хранятся роли, политики выпуска, параметры TTL, настройки CRL/OCSP и аудит операций PKI.&lt;li&gt;&lt;p&gt;Меньше отдельных компонентов для эксплуатации: PKI работает через тот же API и тот же операционный контур.&lt;/ul&gt;&lt;p&gt;Минусы:&lt;ul&gt;&lt;li&gt;&lt;p&gt;При большом числе выданных/отозванных сертификатов растут метаданные PKI и CRL. Для таких сценариев нужно заранее проектировать TTL, CRL/OCSP, бэкенд хранения, резервное копирование и политику ротации;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ресурсная нагрузка: при росте количества запросов на выдачу или отзыв сертификатов Vault будет потреблять больше CPU, поэтому эти ресурсы нужно закладывать заранее.&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Узкая функциональность UI. В StarVault в основном все делается через API. Это же касается и сертификатов: UI позволяет посмотреть информацию о сертификате и отозвать его, если это необходимо. Все остальное делается через API.&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Секреты и PKI оказываются в одном операционном контуре и частично в одной точке отказа. Поэтому HA, резервное копирование и восстановление, аудит, unseal-процедуры и DR нужно проектировать заранее.&lt;/ul&gt;&lt;h2&gt;Как жить в динамической инфраструктуре?&lt;/h2&gt;&lt;p&gt;На уровне одного кластера схема выглядит достаточно просто: есть StarVault, есть рабочие нагрузки, есть механизмы доставки секретов через CSI или инжектор, есть PKI и OIDC-интеграции. Но в реальной инфраструктуре редко все заканчивается одним кластером.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/a46/89e/d27/a4689ed27bb264f5d891e14bb32b56c3.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/a46/89e/d27/a4689ed27bb264f5d891e14bb32b56c3.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/a46/89e/d27/a4689ed27bb264f5d891e14bb32b56c3.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Когда команд, сервисов и окружений становится больше, инфраструктура начинает жить динамически. Пользователи запрашивают новые среды, платформенная команда готовит типовые шаблоны, а кластеры Nova Container Platform или автономные Kubernetes-кластеры могут создаваться и сопровождаться через единый управляющий контур. Это уже не задача «как выдать секрет в один Pod», а задача управления секретами, доступами и политиками на уровне множества кластеров и окружений.&lt;p&gt;Для таких сценариев мы используем HyperDrive — GitOps-платформу для управления жизненным циклом инфраструктуры. HyperDrive не заменяет Nova Container Platform, Kubernetes, StarVault, GitLab или платформу виртуализации. Его задача — связать эти компоненты в единый управляемый процесс: от выбора шаблона и создания кластера до доставки конфигураций, секретов и платформенных компонентов.&lt;p&gt;Внутри HyperDrive секреты становятся частью общего жизненного цикла  инфраструктуры. Пользователь или внутренний сервис не должен вручную переносить значения между Vault-инстансами, создавать политики в каждом кластере и следить, чтобы секреты не попали в GitOps-манифесты. Этим занимается управляющий контур платформы.&lt;p&gt;В HyperDrive StarVault работает по модели &lt;strong&gt;1+N&lt;/strong&gt;. Один основной StarVault находится внутри управляющего контура HyperDrive и используется как центральное хранилище секретов платформы. Для каждого кластера Nova поднимается отдельный локальный StarVault: это может быть как кластер, общий для нескольких команд, так и выделенный кластер, развернутый под конкретную инфраструктурную архитектуру.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/658/1ea/1d3/6581ea1d368bcc3b327ce7158843a2d8.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/658/1ea/1d3/6581ea1d368bcc3b327ce7158843a2d8.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/658/1ea/1d3/6581ea1d368bcc3b327ce7158843a2d8.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Основной StarVault остается источником правды для секретов, которыми управляет HyperDrive. Локальные StarVault-инстансы в кластерах Nova используются для доступа приложений к секретам во время работы и получают только те секреты, политики и настройки доступа, которые нужны конкретному кластеру. Такой подход позволяет не тянуть все обращения приложений в центральный контур HyperDrive и одновременно сохранять централизованное управление секретами.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/9fb/7c3/8fd/9fb7c38fd24ebb4d073d5e95ed6d0020.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/9fb/7c3/8fd/9fb7c38fd24ebb4d073d5e95ed6d0020.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/9fb/7c3/8fd/9fb7c38fd24ebb4d073d5e95ed6d0020.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Важно, что локальный StarVault в кластере Nova — это не полная копия центрального хранилища. В него доставляются только выбранные пути KV v2 и только в рамках заданной политики синхронизации. Это снижает зону влияния возможной ошибки или компрометации: кластер получает доступ к тем секретам, которые нужны его приложениям, а не ко всему хранилищу платформы.&lt;p&gt;За управление жизненным циклом секретов отвечает управляющий контур HyperDrive. Он хранит метаданные секрета: идентификатор, путь в хранилище, точку монтирования, тип, область применения, владельца, статус и параметры синхронизации. Значение секрета при этом не хранится в базе управляющей системы и не рендерится в GitOps-манифесты. Само значение секрета хранится в StarVault KV v2.&lt;p&gt;StarVault-wrapper в этой схеме выступает плоскостью выполнения для работы с Vault-инстансами. Он регистрирует кластеры и локальные StarVault-инстансы, настраивает целевые пути синхронизации, копирует выбранные KV v2-секреты из основного StarVault в локальные StarVault-инстансы, а также создает политики доступа и роли аутентификации Kubernetes для приложений.&lt;p&gt;Жизненный цикл выглядит так. При создании секрета управляющий сервис HyperDrive записывает значение в основной StarVault и сохраняет только его метаданные. Если секрет должен быть доступен в конкретном кластере Nova, для него создается политика синхронизации: целевой кластер или группа StarVault-инстансов, точка монтирования  и путь назначения. После этого StarVault-wrapper выполняет синхронизацию: читает значение из основного StarVault и записывает его в нужный локальный StarVault.&lt;figure class=full-width&gt;&lt;img src=https://habrastorage.org/r/w1560/getpro/habr/upload_files/9b1/937/9d9/9b19379d939e42d84d6a5771a6cc78af.png width=1672 height=941 sizes=&#34;(max-width: 780px) 100vw, 50vw&#34; srcset=&#34;https://habrastorage.org/r/w780/getpro/habr/upload_files/9b1/937/9d9/9b19379d939e42d84d6a5771a6cc78af.png 780w,&#xA;       https://habrastorage.org/r/w1560/getpro/habr/upload_files/9b1/937/9d9/9b19379d939e42d84d6a5771a6cc78af.png 781w&#34; loading=lazy decode=async&gt;&lt;/figure&gt;&lt;p&gt;Когда приложение в Kubernetes должно получить доступ к секрету, StarVault-wrapper создает минимально необходимые политики доступа Vault и роли аутентификации Kubernetes. Эти роли привязываются к конкретным пространствам имен и ServiceAccount, поэтому приложение получает доступ только к тем путям, которые ему действительно нужны. В GitOps при этом остаются ссылки, идентификаторы и параметры доступа, но не сами значения секретов.&lt;p&gt;Такой подход удобен для динамической инфраструктуры: новый кластер можно создать через HyperDrive по заданному шаблону, связать с локальным StarVault, применить нужные политики синхронизации и довести доступы до требуемого состояния автоматически. Командам не нужно вручную переносить секреты, заводить политики доступа в каждом Vault-инстансе и проверять, что значения не утекли в GitOps.&lt;p&gt;При этом синхронизацию нельзя путать с резервным копированием. StarVault-wrapper синхронизирует только явно выбранные пути KV v2 и не заменяет резервное копирование, восстановление и процедуры аварийного восстановления самого хранилища. Основной StarVault остается источником правды для управляемых секретов, а локальные изменения на синхронизируемых путях ограничиваются политиками доступа. Это позволяет избежать конфликтов записи и предсказуемо восстанавливать локальные StarVault-инстансы до последней успешно зафиксированной версии.&lt;p&gt;В результате HyperDrive управляет не набором разрозненных Vault-инсталляций, а целой моделью доставки секретов: основной StarVault хранит значения секретов и остается источником правды, локальные StarVault-инстансы обслуживают приложения в кластерах Nova, а StarVault-wrapper связывает эти уровни между собой и приводит доступы к нужному состоянию.&lt;h3&gt;Заключение&lt;/h3&gt;&lt;p&gt;Система управления секретами позволяет решить многие задачи в сфере управления секретами и организации безопасного доступа как на небольших, так и на масштабных территориально-распределенных инсталляциях. Если у вас уже есть опыт работы со StarVault или остались вопросы по работе компонентов, ждем в комментариях. &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
      <guid>https://habr.com/ru/companies/orion_soft/articles/1051424/?utm_source=habrahabr&amp;utm_medium=rss&amp;utm_campaign=1051424</guid>
      <pubDate>Wed, 24 Jun 2026 13:01:24 +0000</pubDate>
    </item>
  </channel>
</rss>