Я проверил семь советов по видимости в нейросетях на 73 страницах, которые модели сами поставили в источники. Я прогнал каждый совет через две группы страниц из собственных логов и посчитал разницу точным тестом Фишера: 34 страницы против 39, различие по авторству 100% против 82%. Это лишь эксперимент на небольшой выборке, но всё же.
Чек-лист, который я взял для проверки
Список советов по повышению видимости у меня получился из того, что повторяется почти в любом материале про GEO (Generative Engine Optimization, оптимизацию под ответы нейросетей):
структурированный текст с подзаголовками,
блок вопросов и ответов,
разметка Schema.org,
чистый адрес без параметров и расширений,
ключевое слово в заголовке,
свежая дата публикации,
достаточный объём текста.
Восьмой я добавил сам — видимый автор. В разговорах про E-E-A-T (сигналы опыта, экспертности, авторитетности и доверия к странице) он звучит постоянно, но в технические перечни требований к странице попадает реже, чем блок вопросов и ответов или разметка. Раз уж я всё равно разбирал HTML, посчитать заодно и его легко.
Откуда данные и как я разделил страницы на две группы

У меня есть логи собственного прогона: шесть моделей — ChatGPT, Claude, Perplexity, Gemini, GigaChat и Алиса AI, — по 20 запросов, по три повтора каждый. Для этой проверки я взял семь запросов про выбор подрядчика по продвижению в нейросетях. В источниках этих ответов набралось 199 читаемых адресов страниц.
Я разбил их на две группы. Первая — страницы, которые попали в источники минимум двух разных моделей: таких оказалось 36, из них при скачивании открылось 34. Вторая — страницы, процитированные ровно один раз одной моделью, я взял первые 40 по алфавиту, открылось 39. Итого 73 живые страницы для анализа. Ещё 160 адресов я вообще не рассматривал — это редиректы Gemini через vertexaisearch.cloud.google.com, за которыми не виден реальный адрес страницы.
Самые частые находки в кросс-модельной группе — рейтинговые и обзорные материалы, а не сайты самих агентств: страница с независимым рейтингом на dtf.ru набрала 27 упоминаний у четырёх моделей, материал про 12 агентств на vc.ru — 25 у четырёх, подборка на sostav.ru — 24 у трёх. Это уже намекает, что цитируется не столько сама компания, сколько чужой текст о рынке компаний — к этому наблюдению я вернусь при разборе JSON-LD.
Вот как это выглядит в коде — фрагмент функции, которая читает логи и режет ссылки на страницы редиректов:
def read_logs(logs: Path, prompts): """URL из sources_cited: сколько раз процитирован и сколькими платформами.""" hits = collections.Counter() plats = collections.defaultdict(set) titles = {} for f in logs.glob("*/*.json"): d = json.loads(f.read_text(encoding="utf-8")) if prompts and d.get("prompt_id") not in prompts: continue sc = d.get("sources_cited") if isinstance(sc, str): try: sc = ast.literal_eval(sc) except Exception: sc = [] for s in sc or []: u = (s.get("url") or "").split("?")[0] # редирект Gemini прячет реальный адрес — такие URL не анализируем if not u or "vertexaisearch" in u: continue hits[u] += 1 plats[u].add(d["platform"]) titles.setdefault(u, (s.get("title") or "")[:120]) return hits, plats, titles
А вот как из счётчика цитирований получаются те самые две группы:
cross = sorted(u for u in hits if len(plats[u]) >= args.min_platforms) once = sorted(u for u in hits if hits[u] == 1 and len(plats[u]) == 1)[:args.control]
min_platforms у меня стоит 2 — минимум две разные модели должны сослаться на страницу, чтобы она попала в кросс-модельную группу. Порог небольшой, и это первое слабое место метода: страница из кросс-модельной группы могла набрать всего два упоминания, а не двадцать.
Здесь я чуть не обманул себя названием собственной переменной. Вторую группу в коде я назвал once, в тексте — разовой. Но процитировано один раз и не цитируется вообще — это разные вещи, а привычка называть вторую группу контрольной незаметно склеивает их в голове. Настоящий контроль для такого эксперимента — страницы, которые модели по этим семи запросам не поставили в источники ни разу. Собрать такую группу из sources_cited нельзя: лог фиксирует то, что модель показала, и молчит о том, что она видела и отвергла. Значит, я сравниваю не цитируемые против нецитируемых, а цитируемые часто против цитируемых один раз.
Что именно я считал по HTML
Для каждой открывшейся страницы я скачивал HTML через curl и разбирал — без браузера, который выполняет скрипты страницы. Считались только признаки, видимые в той разметке, что сервер отдаёт сразу:
длина title,
стоит ли тематическое слово в первых 40 знаках title и h1,
объём текста без тегов,
число подзаголовков h2–h4,
число пунктов списков, наличие таблиц,
признаки блока вопросов и ответов,
наличие и типы JSON-LD,
чистота и глубина адреса,
видимая дата и видимый автор.
Как я считал значимость различий

Доли в двух маленьких группах нельзя сравнивать на глаз: 100% на 34 страницах и 82% на 39 могут быть и настоящим различием, и совпадением. Сам collect.py сравнение долей не делает — он только считает признаки и складывает их в JSON. Для семи булевых признаков (автор, JSON-LD, чистый адрес, ключ в h1, ключ в title, блок вопросов и ответов, дата) я отдельным скриптом прогнал точный тест Фишера: он подходит для маленьких выборок и таблиц сопряжённости 2×2, где обычный хи-квадрат уже начинает врать.
import json from scipy.stats import fisher_exact data = json.load(open("research/citation-anatomy/2026-08-17.json")) cross = [r for r in data["groups"]["cross"] if r["ok"]] once = [r for r in data["groups"]["once"] if r["ok"]] def p_value(feature): a = sum(1 for r in cross if r[feature]) b = len(cross) - a c = sum(1 for r in once if r[feature]) d = len(once) - c , p = fisherexact([[a, b], [c, d]]) return a, len(cross), c, len(once), p for feature in ("has_author", "jsonld", "clean_url", "h1_key_at_start", "title_key_at_start", "faq_block", "has_date"): a, n1, c, n2, p = p_value(feature) print(f"{feature}: {a}/{n1} vs {c}/{n2}, p={p:.4f}")
Запуск из корня проекта печатает семь строк:
has_author: 34/34 vs 32/39, p=0.0127 jsonld: 29/34 vs 27/39, p=0.1646 clean_url: 34/34 vs 36/39, p=0.2432 h1_key_at_start: 32/34 vs 32/39, p=0.1615 title_key_at_start: 33/34 vs 34/39, p=0.2058 faq_block: 26/34 vs 31/39, p=0.7837 has_date: 20/34 vs 20/39, p=0.6383
Таблица сопряжённости строится напрямую из счётчиков — сколько страниц группы имеют признак, сколько не имеют, — без нормировки и без поправок на множественные сравнения. Про поправку — отдельно в ограничениях: семь проверок подряд на одних и тех же данных повышают шанс словить значимый результат случайно.
Пункт 1: ключевое слово в начале заголовка
Совет из чек-листа: тематическое слово должно стоять в начале title и h1, чтобы модель сразу понимала, о чём страница. У меня key_at_start проверяет первые 40 знаков строки на вхождение любого из десяти корней темы:
KEYWORDS = ("нейросет", "geo", "aeo", "ии", "искусственн", "chatgpt", "алис", "продвижен", "агентств", "ai")
В h1 ключ в начале стоит у 32 из 34 кросс-модельных страниц (94%) и у 32 из 39 разовых (82%), p = 0,162. В title разница ещё меньше: 33 из 34 (97%) против 34 из 39 (87%), p = 0,206. Оба значения выше принятого порога значимости 0,05 — статистически группы по этому признаку не различаются.
Вердикт: не различает.
Пункт 2: свежая дата публикации
Совет: держать видимую дату публикации или обновления, желательно свежую, — модели такие страницы предпочитают. Признак has_date ловит datePublished, dateModified, published_time в разметке и слово обновлено в тексте.
Дата видна у 20 из 34 кросс-модельных страниц (59%) и у 20 из 39 разовых (51%), p = 0,638. Разница в 8 процентных пунктов при таком p — это шум, не сигнал. Заодно тут видно, насколько слаб сам признак: даты нет почти у половины страниц в обеих группах.
Вердикт: не различает.
Пункт 3: блок вопросов и ответов
Совет один из самых частых: добавь блок вопросов и ответов, модели любят вытаскивать оттуда короткие самодостаточные ответы. Признак faq_block ищет слова «частые вопросы», «вопросы и ответы», «faq» в тексте или тип FAQPage в JSON-LD.
Блок есть у 26 из 34 кросс-модельных страниц (76%) и у 31 из 39 разовых (79%), p = 0,784. Разовые страницы даже немного чаще держат такой блок, хотя разница совсем не значима. Это самое высокое p из семи — то есть признак, который советуют чаще прочих, разделяет группы хуже прочих.
Вердикт: не различает.
Пункт 4: разметка Schema.org
Совет: разметка application/ld+json помогает модели понять структуру страницы. Признак jsonld — булев флаг наличия хотя бы одного блока такой разметки; отдельно я вытащил jsonld_types — набор типов из @type.
По самому факту наличия разница есть, но порога значимости не проходит: 29 из 34 (85%) против 27 из 39 (69%), p = 0,165. А вот состав типов расходится заметнее. У кросс-модельных страниц в топе ListItem (23 упоминания), BreadcrumbList (22), затем Article (12) и Person (12), ImageObject (12), Answer (7), FAQPage (7). У разовых — тоже BreadcrumbList (16) и ListItem (16), но следом идёт Organization (15), ImageObject (14), Person (9), WebPage (7), Article (7).
Формально это качественное наблюдение, а не проверенная гипотеза с p-значением: теста на распределение типов я не считал, только доли по каждому типу отдельно. Но смещение видно. Кросс-модельная группа чаще размечена как материал с автором (Article плюс Person), разовая — чаще как карточка организации (Organization плюс WebPage). Совпадает с тем, что дальше выйдет по признаку авторства.
Вердикт по факту наличия: не различает. По составу типов: заметное качественное смещение, без формального теста.
Пункт 5: чистый адрес страницы
Совет: адрес без расширения файла и без параметров запроса читается лучше и обходится роботами охотнее. Признак clean_url проверяет две вещи: заканчивается ли путь расширением и есть ли в адресе вопросительный знак.
Чистый адрес у 34 из 34 кросс-модельных страниц (100%) и у 36 из 39 разовых (92%), p = 0,243. Разница есть, но контрольная группа и так почти вся на чистых адресах — современные системы управления сайтом давно не плодят .php в адресной строке, так что это, скорее, общий сдвиг рынка, а не отличие цитируемых страниц.
Вердикт: не различает.
Пункт 6: объём текста и число подзаголовков

Совет про объём звучит примерно так: длинный, подробно структурированный текст с множеством подзаголовков модель цитирует охотнее короткого. У меня для этого есть медианы по обеим группам: объём текста, число h2–h4, число пунктов списков, доля страниц с таблицей, длина title, глубина адреса.
Показатель | Кросс-модельные (34) | Разовые (39) |
Объём текста | 17 366 знаков | 18 021 знак |
Число h2–h4 | 14,5 | 15 |
Пунктов списков | 65,5 | 78 |
Есть таблица | 21% | 31% |
Длина title | 85,5 знака | 75 знаков |
Глубина адреса | 2 | 2 |
Разницы почти нет, а там, где она есть, — она в обратную сторону. По объёму текста, числу подзаголовков, пунктам списков и доле страниц с таблицей разовые страницы немного обгоняют кросс-модельные. Разрыв по спискам самый заметный: 65,5 против 78 пунктов на страницу.
Единственный показатель, где впереди кросс-модельные, — длина title: 85,5 знака против 75. Десять знаков разницы на медиане около восьмидесяти. Отдельного теста я под него не подводил и находкой это не называю.
Для всех шести показателей точный тест Фишера не применяется — он годится для долей, то есть для признаков вида есть или нет, а не для сравнения медиан. Формальной значимости здесь нет ни в одну сторону, но и намёка на подтверждение совета про объём и подзаголовки тоже нет.
Вердикт по обоим показателям: не различает.
Сводная таблица: что у нас по итогу
Пункт | Кросс-модельные (34) | Разовые (39) | p (Фишер) | Вердикт |
Ключ в начале h1 | 32 (94%) | 32 (82%) | 0,162 | не различает |
Ключ в начале title | 33 (97%) | 34 (87%) | 0,206 | не различает |
Свежая дата | 20 (59%) | 20 (51%) | 0,638 | не различает |
Блок вопросов и ответов | 26 (76%) | 31 (79%) | 0,784 | не различает |
Разметка Schema.org | 29 (85%) | 27 (69%) | 0,165 | не различает |
Чистый адрес | 34 (100%) | 36 (92%) | 0,243 | не различает |
Объём и структура текста | медиана 17 366 знаков, 14,5 подзаголовка | медиана 18 021 знак, 15 подзаголовков | тест не считался | не различает |
Видимый автор — мой восьмой пункт | 34 (100%) | 32 (82%) | 0,013 | различает |
Семь верхних строк — это и есть чек-лист, который я взял на проверку. Ни одна из них группы не разделила: p от 0,16 до 0,78, а по объёму и структуре разовые страницы даже впереди. Разошлась восьмая строка — признак, которого в чек-листе не было.
Единственный признак, который различает группы
Видимый автор — единственное, где p опустилось ниже общепринятого порога 0,05. У всех 34 кросс-модельных страниц (100%) есть распознаваемый признак авторства: itemprop="author", поле "author" в JSON-LD, rel="author" или слово автор рядом с текстом. У разовых страниц — 32 из 39 (82%). Разница в 18 процентных пунктов при p = 0,013.
Это корреляция на 73 страницах в одной узкой нише — продвижение в нейросетях. Из неё не следует, что если добавить подпись автора на случайную страницу, она начнёт цитироваться моделями чаще. Возможно, страницы с видимым автором в среднем более проработаны по десятку других параметров, которые я не считал, и цитируется именно это, а подпись — сопутствующий признак зрелого материала. Проверить причинность на этих данных нельзя, только на других.
В таблице две строки выглядят почти одинаково. Разметка Schema.org: 85% против 69%, разрыв 16 процентных пунктов. Видимый автор: 100% против 82%, разрыв 18 пунктов. А p отличается на порядок — 0,165 против 0,013.
Дело не в ширине разрыва. У авторства доля в кросс-модельной группе упирается в край шкалы: исключений нет вообще, 34 из 34. Доля вблизи 100% случайно колеблется меньше, чем доля около 85%, поэтому одинаковый на глаз разрыв набирает разную статистическую опору. Вывод простой: если читать такую таблицу по ширине разрыва в процентах и не смотреть на p, легко объявить находкой не ту строку — примерно так и заводятся рекомендации, под которыми нет проверки.
Ограничения моего эксперимента
Выборка ну очень маленькая: 34 против 39 страниц. Различие меньше 15 процентных пунктов такой выборкой не ловится — часть пунктов чек-листа могла отличаться и в реальности, просто эксперимент слишком мал, чтобы это увидеть.
Ниша одна. Перенос результата на другие рынки не проверялся и может не сработать.
Признаки считаются по тому HTML, который сервер отдаёт сразу. Часть сайтов устроена иначе: сервер отдаёт почти пустой каркас, а текст, заголовки и даже разметку JSON-LD дорисовывает JavaScript уже в браузере читателя.
curlбраузер не изображает и скрипты не выполняет, поэтому у таких страниц часть признаков занижена: и автор, и таблица, и блок вопросов там могут быть, просто не в той разметке, которую получил скрипт.Признак авторства распознаётся по паттернам в HTML, а не по строгой семантической разметке, и, как показано выше, путает подпись под материалом с любым вхождением слова
авторна странице.Страницы с автором чаще попадают в источники нескольких моделей, но из этого не следует, что добавление подписи повышает цитируемость. Причинно-следственную связь этот эксперимент не проверяет и не может проверить по своей конструкции.
Я проверял семь признаков на одной и той же паре групп без поправки на множественные сравнения. При семи проверках с порогом 0,05 шанс словить хотя бы одну случайно значимую разницу выше пяти процентов. Порог Бонферрони для такой серии — 0,05 / 7 ≈ 0,007, и результат по авторству его не проходит, хотя и остаётся заметно ниже остальных шести p-значений. При чтении таблицы целиком это стоит учитывать.
Что по итогу эксперимента
Я взял страницы, которые уже существуют и уже процитированы, и сравнил их постфактум. Чтобы проверить и установить реальные причины, нужен другой дизайнэкспертимента: взять набор страниц без видимого автора, на части из них добавить подпись и больше ничего не менять, а через несколько недель посмотреть, изменилась ли частота цитирования у изменённых страниц относительно нетронутых. Это уже эксперимент со сравнением групп на живом трафике моделей, а не разовый срез логов, и он займёт не один прогон, а несколько месяцев наблюдений.
Пока такого эксперимента нет, итог держится в двух строках. Из семи пунктов чужого чек-листа не выжил ни один: ни блок вопросов и ответов, ни разметка, ни длина, ни подзаголовки, ни дата, ни чистый адрес, ни ключевое слово в заголовке цитируемые страницы от разово процитированных не отличают. Сработал восьмой признак, который я добавил в список сам, — и по нему у меня есть только совпадение, а не механизм.
