Глава 1
Можно ли верить reward
Обозначения
| картинка (или видео) и запрос | |
| reward-модель с весами : число для одной картинки | |
| картинка, которую предпочли, и та, которая проиграла | |
| вероятность, с которой VLM отвечает «yes» на вопрос о картинке | |
| ответ на -й вопрос чеклиста и его вес | |
| -й reward у -го rollout в группе | |
| advantage: насколько rollout лучше среднего по группе | |
| порог отбора |
В первой части мы допустили, что хорошая reward-модель (оценщик: смотрит на готовую картинку и возвращает число) у нас уже есть, и разбирали, как довести её сигнал до генератора. Путей два. Если reward дифференцируем, его градиент протаскивают назад через генерацию. Если reward — просто число, работают с вероятностями: online policy gradient вроде Flow-GRPO.
Второй путь победил в том числе из-за доверия. Градиентам reward-модели верить трудно, и reward hacking в них сложно контролировать. Скаляр, который понятен и проверяем, обмануть намного сложнее. Но это переносит весь вопрос на сам reward: что он измеряет и насколько точно.
Возьмём запрос «корова на луне». Хочется, чтобы reward был высоким, только когда на картинке есть и корова, и луна, и при этом картинка нормального качества: без лишних ног, без каши в текстурах. Хочется и обратного: чтобы reward нельзя было поднять, не нарисовав корову на луне.
Дальше два вопроса. Как построить reward-модель, которой можно верить: от разметки людьми до VLM-судьи, который сам запускает инструменты. И как свести несколько reward в один сигнал, не потеряв ни один из них.
Сначала договориться с разметчиками
Любая хорошая reward-модель начинается не с архитектуры, а с разговора с разметчиками. Нужно сесть и аккуратно обсудить, что вы хотите от этой модели и как оцениваете картинку. Цель — процедура с хорошей согласованностью: тогда модель получит чётко определённые критерии, и именно их вы потом будете максимизировать.
Хороший пример — ImageReward. Критериев три: соответствие текста и картинки (alignment), качество изображения (fidelity: текстуры, свет, тонкие детали) и безвредность. Важен и порядок работы разметчика.
Сначала разметчик отсматривает все картинки по запросу и оценивает каждую отдельно. Только потом ранжирует их, и ранжирование обязано совпадать с выставленными оценками. Человек сначала понимает, что здесь лучше, а что хуже, и лишь затем расставляет порядок.
Спорные случаи решают явные правила. Картинка ближе к запросу, но искажённая, проигрывает чистой. Картинка с мелким дефектом, но с нужным объектом выигрывает у той, где объекта нет. Если обе картинки потенциально вредные, а насколько — неясно, ставится ничья [ImageReward, прил. B].
Для каждого случая в инструкции расписано, что такое хорошо и что такое плохо. Например, запрос — портрет женщины с осенними листьями. Объясняется, почему одна картинка намного лучше другой: у второй артефакты анатомии, сумбурный кроп, детали не на своих местах. Разметчику должно быть понятно, что именно он ищет на картинке.
Так же аккуратно подбирают сами запросы. Они должны быть разнообразными и осмысленными. Если приходит запрос вроде «4k, high quality», по нему непонятно, что вообще должно сгенерироваться. В ImageReward такие запросы разметчики помечают отдельным флагом ещё до оценки картинок, а мы такие просто выкидываем.
Из ранжирования — reward-модель
Дальше обучение простое. Ранжирование превращается в пары «эта картинка лучше той», а на парах учится модель Bradley–Terry, как в DPO:
Здесь — картинка, которую разметчик поставил выше, — ниже. Модель учится выдавать первой большее число. После обучения она оценивает любую одну картинку, и это число уже можно оптимизировать.
Масштаб у ImageReward такой: 8 878 запросов и 136 892 пары сравнений [ImageReward, разд. 2.1].
Где эта схема ломается
Даже с подробной инструкцией люди плохо сходятся во мнении, какая картинка лучше. Если посчитать согласие разных разметчиков на одних и тех же парах, оно выходит низким: 65,3% [ImageReward, табл. 2]. Примерно треть пар разные люди решают по-разному. Собрать по такой выборке модель, которая поймёт, что от неё хотят, очень сложно.
Многое зависит и от того, кто размечает. Случайные люди воспринимают картинки очень по-разному: одному нравится зелёненькое, другому яркое, и reward съезжает в сторону slop. У профессионалов в голове уже зашиты композиция, свет, детальность текстур, и они ставят уверенные оценки, а не «где-то 0,5».
Вторая проблема — основа оценщика. Популярные метрики вроде CLIPScore построены на CLIP, а его текстовый энкодер читает запрос почти как мешок слов [VQAScore, аннотация]. «Машина ест траву» и «трава ест машину» для него почти одно и то же, хотя картинки должны быть совсем разными. Корову на луне и луну на корове такой reward тоже не различит.
Получается, нужны вопрос, на который люди отвечают одинаково, и оценщик, который понимает структуру фразы.
Глава 2
Вместо «какая лучше» — вопросы да/нет
Самый простой проверяемый вопрос — есть ли на картинке то, что просили. Есть ли на ней корова? Есть ли луна? Такой верификатор глупый, но на него люди почти не спорят, и его можно задать VLM.
VQAScore спрашивает про весь запрос сразу. VLM, в отличие от CLIP, читает фразу целиком, поэтому отличает корову на луне от луны на корове.
Берём VLM, даём ей картинку и вопрос «Does this figure show "{запрос}"? Please answer yes or no» и смотрим не на сгенерированный ответ, а на вероятность токена «Yes» [VQAScore, рис. 1]:
VLM, в отличие от CLIP, понимает, как построено предложение: кто кого ест и что где стоит. Только за счёт того, что reward лучше понимает запрос, можно сильно поднять prompt following генератора. По сути это предшественник всех современных VLM-оценщиков.1 Вопрос до картинки. В обычной decoder-only VLM сначала идёт картинка, потом вопрос, и токены картинки не знают, о чём спросят. VQAScore берёт encoder-decoder (CLIP-FlanT5), где картинка и вопрос читаются вместе с двунаправленным вниманием. Сейчас эта деталь уже не так важна.
Но у вероятности «Yes» свои проблемы. Это просто какая-то вероятность, а не интерпретируемая оценка: две очень разные по качеству картинки могут получить одинаково высокую вероятность. Модели к тому же склонны говорить «yes» и соглашаться. Чтобы reward был честным, VLM нужно отдельно калибровать.
Есть и ограничение посерьёзнее. Для видео важны физика и сложное движение. Если reward-модель этого не видит, такие проблемы вы RL не решите: оптимизировать можно только то, что оценщик умеет различить.
Случаев, когда VLM на видео почти ничего не дают, достаточно много. Хуже всего с 3D и движением камеры: модель уверенно опишет, что в кадре, но часто не отличит наезд камеры от зума, панораму от движения самого объекта и не заметит, что геометрия сцены поплыла между кадрами.
Чеклист вместо одного вопроса
Один вопрос «есть ли корова» — слишком грубо. VisionReward раскладывает качество на измерения: соответствие запросу, композиция, качество, достоверность, безопасность и эмоции. У видео к ним добавляются стабильность, динамика, физика и сохранение формы объекта. Каждое измерение делится на подызмерения, и по каждому задаётся отдельный вопрос да/нет.
Не «оцени движение от 1 до 7», а «движение плавное, не дёрганое?», «камера стабильна?». На такие вопросы люди отвечают намного согласнее: 89% совпадающих ответов [VisionReward, разд. 3.1] против 65% на «какая лучше» у ImageReward. Датасеты разные, так что сравнение примерное.
Остаётся превратить кучу размеченных ответов в одно число. VLM отвечает на каждый вопрос, ответы (здесь это ответ, а не картинка) складываются с весами:
Веса учатся логистической регрессией на разнице ответов в уже готовых парах человеческих предпочтений: какая картинка понравилась больше [VisionReward, разд. 3.2]. Часть коэффициентов выходит отрицательной. Их итеративно обнуляют и пересчитывают регрессию, пока все веса не станут неотрицательными [VisionReward, прил. 7]. Каждый признак либо добавляет reward, либо не влияет.
Если хороших признаков набралось много, reward высокий: картинка или видео уже достаточно хорошие. Мне этот подход очень нравится тем, что такой reward сложно хакнуть. Есть конкретный признак, который легко проверить: качественный свет или нет. И ты знаешь, какой фактор максимизируешь, — значит, можешь его найти, поправить и сделать RL качественнее.
Насколько адекватна такая модель? Многое решают данные под регрессию. Для картинок VisionReward взяла 44 тысячи готовых пар из HPDv2 и ImageRewardDB [VisionReward, разд. 4.1]. Пары, где одна картинка лучше по одним критериям, а другая по другим, тянут в разные стороны.
Поэтому, когда VisionReward сама собирает пары для DPO, она берёт пару, только если одна картинка не хуже другой по каждому измерению [VisionReward, разд. 3.3].
Чеклист разделил качество на проверяемые признаки. Но каждый признак по-прежнему проверяет одна VLM за один вопрос. Что будет, если судью увеличить и дать ему больше контекста?
Глава 3
Судья побольше и с контекстом
Есть три способа сделать reward из картинки и текста. Сравнить эмбеддинги CLIP. Поставить на VLM голову регрессии и учить её выдавать скаляр. Или, как в VQAScore, взять генеративную вероятность ответа «yes».
RewardDance доводит третий вариант до полноценного LLM-уровня. Вместо одного вопроса «есть ли на картинке луна» перед ответом пишется длинный контекст: инструкция задачи с конкретными критериями, при необходимости референсная картинка, рассуждение (chain-of-thought). Reward — по-прежнему вероятность токена «yes»:
Генеративная постановка совпадает с задачей претренинга VLM, поэтому модель не нужно переучивать под новую голову. Рассуждение полезно и людям: можно прочитать, почему судья решил так, и разобраться, где он ошибается.
И это суперски работает: качество генератора растёт просто от того, что вы берёте судью побольше. У FLUX.1-dev после RL с судьёй на 1B оценка соответствия запросу (alignment score авторов) 67,0, а с судьёй на 26B — уже 73,6 [RewardDance, табл. 2].
Дисперсия как датчик reward hacking
Самое интересное в RewardDance — как ведёт себя reward во время RL. У маленького судьи дисперсия reward по rollouts быстро падает и выходит на плато. Это обычный признак reward hacking: генератор нашёл shortcut и просто по нему следует, у модели даже нет сомнений.
У судей побольше дисперсия заметно выше и держится дольше [RewardDance, рис. 5]. Генератор не так однозначно понимает, почему этот объект лучше другого, и продолжает исследовать. Отсюда практическое правило: следите за дисперсией reward в группе. Если она схлопнулась, а картинки не стали лучше, оценщик обманут.
Сколько данных нужно, чтобы выучить хорошую reward-модель? По моему опыту — достаточно мало, порядка десяти тысяч примеров хватает. Многое зависит от того, сколько критериев и насколько выразительной должна быть модель, но масштабируется это плюс-минус линейно.
Pointwise: оценка без пары
Последний вопрос про устройство судьи — что он видит. Можно показать пару и спросить, какая картинка лучше, а можно показать одну и попросить оценку. В Qwen-Image-2.0-RL выбрали pointwise. Судья смотрит на одну картинку и оценивает её по шкале: насколько нравится освещение, цвет неба и так далее. Reward — матожидание оценки по вероятностям судьи:
Так модель устойчивее. Когда сравниваешь две почти одинаковые качественные картинки, pairwise-судья вряд ли даст осмысленный сигнал. Pointwise оценивает каждую картинку на абсолютной шкале, и на этом сигнале можно учиться всегда [Qwen-Image-2.0-RL, разд. 3.1].
Ещё одно, что стоит взять из этого отчёта: критерии в инструкции для разметчиков явно приоритизированы. Соответствие картинки тексту важнее структурных искажений, искажения важнее качества текстур, а оно важнее эстетики [Qwen-Image-2.0-RL, разд. 3.1]. Порядок здесь другой, чем у ImageReward: там искажения важнее соответствия запросу.
Но главное сходится: согласованность от большого числа людей получить очень сложно, если не прописать, что важнее.
В online RL VLM-оценщик обычно работает как верификатор, а не как дифференцируемая reward-модель: градиент от него не берут, нужна только оценка.
Но есть свойства, которые VLM, даже большая, не видит надёжно. «Корова слева от луны», «кот за чашкой», «три шага до стены» — пространственные отношения на глаз проверяются плохо.
Глава 4
Судья, который проверяет инструментами
Следующий шаг — не обучать одну VLM говорить «хорошо» или «плохо», а сделать агентную reward-модель. Вместо вердикта на глаз она сама сходит в инструменты: построит карту глубины, запустит детектор объектов, сегментацию, и уже по результатам скажет, выполнено ли условие. Это движение к максимальной проверяемости reward.
Так устроен SpatialCritic из Getting Space Right. Судья раскладывает запрос на пространственные утверждения, планирует, какие инструменты вызвать, запускает их и сводит улики в вердикт.
Сам критик тоже учится RL — на проверяемых метках, где правильный ответ известен заранее [Getting Space Right, разд. 3.3]. С инструментами критик на 8B верно оценивает 95,1% пространственных пар — на уровне обычной VLM на 320B без инструментов, у которой 94,5%, при модели в 40 раз меньше [Getting Space Right, табл. 1].
Как это сочетается с остальным? Тяжёлую универсальную reward-модель удобно использовать широко, в том числе чтобы фильтровать данные. Агентный reward дорогой, и его ставят на узкие критерии, которые без инструментов не проверить.
Теперь у нас не один reward, а несколько: чеклист, эстетика, пространственный критик, OCR. Их нужно свести в один advantage.
Глава 5
Много reward в одном advantage
Оценить картинку в целом по одному критерию не получается. Критериев много, и они в целом независимы: качество текстур может быть никак не связано с соответствием тексту. Если просто усреднить много компонент в один reward, сигналу очень трудно пройти: улучшение по одному критерию тонет в шуме остальных.
Вспомним, как в GRPO считается advantage: reward нормируется внутри группы rollouts на один запрос. С несколькими reward естественно сначала сложить их, а потом нормировать:
Сумма склеивает разные случаи
У суммы две проблемы. Первая — очень много разных случаев попадают в одну группу. Пусть reward два, оба бинарные, и в группе два rollouts. Суммы (0, 1) и (0, 2) после нормировки дают одинаковые advantages. То, что один rollout выполнил оба условия, а не одно, теряется. С (1, 2) то же самое [GDPO, рис. 2].
На корове на луне это выглядит так. Два бинарных reward: есть ли корова, есть ли луна. В одной группе rollout без коровы и rollout с одной коровой: суммы 0 и 1. В другой — без коровы и с коровой на луне: суммы 0 и 2. Advantages в обеих группах одинаковые: rollout, который выполнил всё, получает столько же, сколько тот, что выполнил половину.
Вторая — у reward разные шкалы. Один меняется от 0 до 1, другой от 1 до 10, и в сумме второй просто задавит первый. Добавим к корове эстетику по шкале от 1 до 10 — и она задавит чеклист: модель научится рисовать красивую луну, а корова станет необязательной.
Чтобы это сбалансировать, нормировать нужно внутри каждого отдельного reward и только потом взвешивать и суммировать. Это и есть GDPO:
После суммы advantage ещё раз нормируют по батчу, чтобы его масштаб не рос с числом reward; без этого обучение иногда не сходится [GDPO, разд. 3.1].
В примере с коровой GRPO даёт обеим группам advantages (−0,71; +0,71). GDPO для группы с коровой на луне даёт (−1,41; +1,41): выполнить оба условия теперь вдвое выгоднее, чем одно.
Лёгкий reward не должен задавить трудный
Многие reward нечестно конкурируют. Лёгкий reward (в GDPO, сделанном для LLM, это длина и формат ответа) растёт быстро, и модель гонится за ним, а трудный (корректность, соответствие запросу) отстаёт. Подбором весов это обычно не лечится [GDPO, разд. 4.2.1]. Помогает гейтинг: лёгкий reward засчитывается, только если прошёл трудный.
Для коровы на луне это значит: эстетику засчитываем, только если чеклист «корова, луна» пройден. Красивый лунный пейзаж без коровы не получает за красоту ничего.
Если картинка не прошла базовую проверку, остальное в ней и правда нет смысла учитывать. В целом балансировку многих reward можно сравнить с искусством: всё тонко подбирается под конкретный случай. Это довольно интуитивный процесс, в котором просто набиваешь руку и смотришь, что работает, а что нет.
Rollouts, в которых сигналы гасят друг друга
Даже с раздельной нормировкой остаются rollouts, где advantage по одному reward сильно положительный, а по другому сильно отрицательный. В сумме они дают почти ноль и лишь добавляют шум. GD²PO, сделанный для LLM, предлагает два решения. Жёсткое — выкидывать любой rollout, где знаки advantage расходятся. Мягкое терпит частичное расхождение и считает для каждого rollout отношение сигнала к шуму:
Если по всем критериям advantage одного знака, SNR равен единице. Если сигналы гасят друг друга, SNR близок к нулю, и rollout в обучение не идёт: оставляем только те, где по большей части критериев мы выигрываем или проигрываем согласованно. В статье порог τ = 0,8 [GD²PO, разд. 3.1].
Пример: корова на луне есть, чеклист доволен, но у коровы пять ног, и reward за качество сильно ниже среднего. Сумма около нуля, SNR тоже, и такой rollout ничему не учит: непонятно, хвалить его или ругать.
Группа без разброса
Отдельный случай — группа, в которой все rollouts получили одинаковый или почти одинаковый reward. Например, все шестнадцать коров на луне в группе одинаково хорошие. Advantage на них около нуля, std тоже близка к нулю, и деление на неё раздувает любой шум.
Это не про несколько reward, но встречается постоянно. Два приёма отсюда взяты из DAPO, который делали для LLM. Первый — dynamic sampling: группы без разброса просто выкидывают [DAPO, разд. 3.2]. У диффузии reward непрерывный, поэтому выкидывают группы, где разница между лучшим и худшим reward меньше порога. Так делают и в Qwen-Image-2.0-RL [Qwen-Image-2.0-RL, разд. 4.2].
Второй — Clip-Higher. В PPO-подобном loss отношение вероятностей новой и старой модели обрезают окном. DAPO делает окно несимметричным: снизу 0,2, а сверху 0,28 [DAPO, разд. 3.1, 4.1]. Редким удачным вариантам разрешено расти быстрее, и exploration по высокому reward становится больше. Rollouts разнообразнее, и групп без разброса меньше.
Что делать, если std маленькая
Нормировка на std в целом помогает: сигнал становится сопоставимым между запросами. А группы, где std маленькая, просто выкидывают. Дальше два варианта. Либо повышать вариативность rollouts — и проверить, получается ли. Либо, если не получается, reward уже максимальный, а картинки и правда хорошие, признать, что по этому запросу всё сошлось: reward схлопнулся, больше мы его не используем.
То есть это не просто фильтр, а умное отбрасывание.
Зачем при этом KL к reference-модели? Чтобы модель обновлялась аккуратнее, без резких скачков, которые невозможно интерпретировать. Без неё один плохой сэмпл — и модель разошлась, и всё нужно делать заново.
Все детали по отдельности понятны. Как они собираются в одном промышленном запуске?
Глава 6
Рецепт целиком: Qwen-Image-2.0-RL
Хороший сквозной пример — технический отчёт Qwen-Image-2.0-RL. Там видно, что многие идеи выше используются вместе.
Reward подобраны под задачи. Для text-to-image — соответствие запросу по рубрике, эстетика и отдельный reward для портретов. Для редактирования — выполняется ли инструкция (с делением на главную и второстепенную часть) и сохраняется ли лицо.
Каждый reward нормируется внутри группы отдельно, как в GDPO, а потом reward взвешиваются по категории запроса: портрет, пейзаж, текст, общее [Qwen-Image-2.0-RL, разд. 4.1–4.2].
CFG только в rollouts
Отдельный вопрос — как генерировать сами rollouts: с CFG или без. На rollouts считается reward, и по ним же идёт обновление. Обычно модель запускают с CFG, а без него картинки заметно хуже — значит, reward оценивает не то, что потом увидит пользователь. С CFG rollouts такие же, как при обычной генерации, но тогда надо решить, что делать с CFG в loss.
В DiffusionNFT, например, rollouts идут без CFG, и там об этом вообще не нужно задумываться. Но если так делать, заметишь, что некоторые концепты становятся хуже.
В Qwen-Image-2.0-RL сравнили три варианта. CFG и в rollouts, и в loss — обучение нестабильно и разваливается. Без CFG вообще — модель теряет стиль и знания о мире. CFG только в rollouts — стабильно [Qwen-Image-2.0-RL, разд. 4.1]. Reward считается на хороших картинках с CFG, а учится только conditional-ветка.
Мой совет: аккуратно учите в основном conditional-ветку. Rollouts без CFG, как в DiffusionNFT, обычно нормально. Если отдельные концепты проседают, подмешайте немного rollouts с CFG. Свой CFG под каждый reward мы не подбираем — особой проблемы в этом нет.
Отдельные RL и слияние через дистилляцию
Можно учить всё одним запуском с несколькими reward. А можно сделать отдельные RL под каждую задачу и потом слить их в одну модель. В Qwen так и сделали: отдельный RL на text-to-image и отдельный на редактирование, потом оба учителя дистиллируются в одного студента через on-policy distillation. Такой merge оказался лучше общего RL на смеси задач [Qwen-Image-2.0-RL, разд. 4.3].
Это прямо common practice, по сути умная замена model soup. В soup ты учишь SFT и усредняешь веса, а тут сливаешь модели через on-policy distillation.
Сама on-policy distillation пришла из LLM — см. On-Policy Distillation от Thinking Machines. Там учителем служит ранняя версия модели, и дистилляция возвращает навыки, потерянные при дообучении на новом домене. Model soup, насколько я вижу, реально уже никто не использует, рецептом стал такой merge.
Что лучше — один запуск с несколькими reward или отдельные RL с последующим слиянием? Зависит от числа reward. Если их два-три, их можно учить вместе в одном multi-reward запуске. Если много, проще развести по отдельным запускам и слить.
Сколько стоит RL
На RL сейчас тратят заметно больше compute, чем на SFT. RL жёстко решает одну конкретную проблему, но под неё нужна куча GPU: rollouts, reward-модели, несколько копий модели. SFT в сравнении дешёвый: взял одну ноду — и по сути готово.
При этом сходится RL достаточно быстро. По моему опыту и по тому, что я видел, это плюс-минус до тысячи шагов.
Ещё совет: если можете, делайте full fine-tune, а не LoRA. LoRA в bf16 может неправильно смержиться, и появится разрыв между тем, что вы учили, и тем, что получили.
Для обычного fine-tuning это терпимо, а для RL очень влияет. У full fine-tune просто меньше точек отказа.
И про дистилляцию после RL. Обычно берёшь модель после RL, дистиллируешь её и иногда докидываешь в оптимизацию RL-score. Например, рендеринг текста при дистилляции может сильно развалиться, и если добавить reward за них прямо в обучение студента, результат получается лучше.
Reward решает, чему научится модель
RL — очень тонкое искусство, в котором важен каждый аспект: формула reward, вопросы к судье, данные, разметчики. Мастерство здесь не берётся из статей. Его получаешь, только когда активно итерируешься и собираешь своё понимание.
Следите за данными, разметчиками и reward. Это окупится с лихвой.
Источники
- Reward-модели
- ImageReward (2023)Процедура разметки: оценки, ранжирование, правила компромиссов (разд. 2, прил. B); согласие разметчиков (табл. 2); Bradley–Terry loss. Главный источник главы 1.
- VQAScore (2024) · VisionReward (2024)Вероятность «Yes» как reward (VQAScore, рис. 1, разд. 3); чеклист да/нет, логистическая регрессия и обнуление отрицательных весов (VisionReward, разд. 3, прил. 7).
- RewardDance (2025)Генеративный судья P(yes), контекст и масштабирование до 26B; дисперсия reward как признак reward hacking.
- Getting Space Right (2026)SpatialCritic: агентный судья с инструментами зрения, обученный RL на проверяемых метках (разд. 3, табл. 1).
- Несколько reward в одном advantage
- GDPO (2026) · GD²PO (2026)Нормировка каждого reward в группе и условный reward (GDPO, разд. 3); фильтр rollouts по SNR (GD²PO, разд. 3.1). Оба сделаны для LLM.
- DAPO (2025)Dynamic sampling и Clip-Higher, разд. 3.1–3.2. Сделан для LLM, приёмы переносятся на диффузию.
- Рецепт
- Qwen-Image-2.0-RL (2026)Pointwise-судьи, набор reward и веса по категориям, CFG только в rollouts, слияние через on-policy distillation. Главный источник главы 6.
- On-Policy Distillation (Thinking Machines, 2025)On-policy distillation на LLM: ранняя версия модели как учитель возвращает потерянные навыки.
Весь сайт для LLM-агентов:The full site for LLM agents: /llms.txt, /llms-full.txt.