инструменты / ai-data.json / как устроен файл
Как устроен файл ai-data.json
ai-data.json - JSON-файл в корне сайта: справка о компании
для нейросети, а не для поисковика. У формата нет ни одного официального
стандарта и ни одной публичной спецификации - имя файла и состав полей
задал GEO-аудит студии «Мегагрупп», это соглашение одной студии, принятое
де-факто. Рядом по другим адресам живут другие имена того же по смыслу
файла: ai.json, /.well-known/ai-agent.json,
agents.json. Общего между ними нет, кроме идеи. Здесь мы
описываем ровно то, что встречается на живых сайтах под именем
ai-data.json, - и ровно то, что проверяем сами.
Раз спеки нет, эталон - это наш собственный код: что кладёт в файл
генератор (yadro/ai_data.php) и что проверяет проверялка
(yadro/pravila_ai_data.php). На этой странице - оба, полями,
примером и правилами с весами. Судить чужой файл по правилам, которые
нигде не названы, нельзя - поэтому они названы здесь.
Десять полей верхнего уровня
Порядок в таблице - тот же, в котором поля кладёт функция
ai_data_sobrat(): это не список по алфавиту, а порядок,
в котором их встретит и человек, открывший файл текстом.
| Поле | Тип | Что в нём лежит |
|---|---|---|
name | строка | Имя компании: из разметки Organization, LocalBusiness, Store или HomeAndConstructionBusiness (берётся первый подходящий тип), а если разметки на главной нет - из заголовка страницы (title). |
description | строка | Описание компании из мета-тега description главной
страницы. Не из разметки - её описание может рассказывать не то же
самое, что заявлено посетителю. |
url | строка | Адрес сайта, каким он получился после редиректов, а не тот, что ввели в форму генератора. |
contact | объект | Три поля: phone (список телефонов из разметки и
ссылок tel:, без повторов одного номера в разной
записи), email (из разметки или первой ссылки
mailto:) и address (склеен из частей
почтового адреса разметки либо взят строкой как есть). |
logo | строка или null | Ссылка на логотип из разметки, приведённая к полному адресу:
относительный путь вроде /logo.png машине читать не от
чего. Не нашли или значение адресом не является - null,
а не пустая строка. |
social | список строк | Ссылки на соцсети - только на восемь известных хостов (vk.com, t.me, ok.ru, youtube.com, rutube.ru, dzen.ru, wa.me, telegram.me), из разметки и со страницы, тоже полными адресами. Ссылка на любой другой хост в файл не попадает, откуда бы она ни пришла. |
openingHours | объект или пустой список | Часы работы одной строкой в поле office, собранные
из openingHours либо, если его нет, из
openingHoursSpecification. Не нашли - пустой список
[], а не пустой объект: без данных это обычный пустой
PHP-массив, а json_encode() отдаёт его списком. |
areaServed | объект или пустой список | Город и, если он отличается от города, регион обслуживания - из
разметки адреса. Не нашли ничего - тот же пустой список
[], а не пустой объект, и по той же причине. |
advantages | список | Всегда пустой список. Генератор не заполняет его никогда - см. раздел ниже. |
services | список объектов | До двадцати услуг. У каждой - name (H1 страницы, а
если он пуст - title), description (мета-тег страницы
услуги), url, price (из разметки Offer,
Product или Service либо из текста вида «от 5 900 ₽», иначе
null) и faq (пары вопрос-ответ из
разметки FAQPage). |
Обязательный минимум
Прежде чем считать пользу, проверялка решает: формат вообще соблюдён?
Достаточно не любого непустого JSON-объекта, а трёх условий разом. У поля
name обязан быть виден хотя бы один значащий знак - и у
url тоже; число или список в этих полях в счёт не идёт,
такое значение проверялка считает отсутствующим, как будто поля не было
вовсе. И хотя бы одно из двух полей, contact или
services, обязано быть непустым массивом - строка вроде
"contact": "звоните нам" массивом не является, и это не
минимум, а его имитация.
Не хватает хотя бы одного из трёх условий - формат не проходит, и находка так и называется: «Нет обязательного минимума». Без имени и способа связаться со справкой нечего делать - на вопрос «кто это и как до них добраться» она не отвечает, а ради этого её и читают.
Как мы узнаём, что файл вообще наш
Это отдельная проверка, и ради неё страница вообще была написана.
У формата нет спецификации, значит нет и способа отличить настоящий
ai-data.json от чужого JSON-файла, кроме как по набору
полей. А поля вроде name и description есть
почти у любого манифеста в интернете - у .webmanifest,
у минимального package.json, у манифеста браузерного
расширения. Раньше проверялка признавала своим файлом любые два поля
из восьми - и все три перечисленных манифеста проходили как «наш»,
только неполный: человек получал «не заполнены услуги» про файл,
который вообще не пытался быть ai-data.json.
Теперь правило в три шага. Сначала грубый отсев: список верхнего уровня
(файл начинается с [, а не с {) - это не наш
формат вовсе, а любой из явно чужих ключей -
dependencies, devDependencies,
scripts, require, autoload,
items, offers, products,
@context, @type, @graph - сразу
останавливает разбор, ещё до подсчёта совпадений: это подписи
package.json, composer.json, товарных
выгрузок и куска собственной разметки JSON-LD, сохранённого в файл, -
каких у ai-data.json не бывает. Дальше проверялка
ищет совпадения среди восьми полей - name,
description, url, contact,
services, advantages, areaServed,
openingHours - и смотрит только на то, есть ли ключ, а не
на то, что в нём лежит: пустой contact всё ещё считается
совпадением. Совпадений нужно не меньше двух. А дальше - главное
условие: хотя бы одно из совпавших полей обязано быть из пятёрки
отличительных - contact, services,
advantages, areaServed или
openingHours. Их не бывает у чужих манифестов, а
name и description есть у всех подряд,
поэтому пары из этих двух общих полей мало.
Файл, который не набрал двух совпадений или набрал их только среди общих полей, получает не обвинение в неполноте, а честный ответ: «Это не похоже на ai-data.json». Мы не судим его как испорченный наш файл - мы прямо говорим, что не узнали в нём этот формат. Это наше отличие от типичного GEO-аудита: обвинять в недоделке файл, который и не пытался быть тем, что мы ищем, нечестно.
Пример
Сокращённый файл по образцу живого сайта - компания и адрес вымышленные, устройство настоящее: две услуги вместо двадцати, но с теми же полями и в том же порядке.
{
"name": "ООО «Пример»",
"description": "Производим и устанавливаем пластиковые окна и балконные рамы в Екатеринбурге с 2008 года.",
"url": "https://primer.ru/",
"contact": {
"phone": ["+7 (343) 200-00-00"],
"email": "info@primer.ru",
"address": "620000, Екатеринбург, ул. Заводская, 1"
},
"logo": "https://primer.ru/logo.png",
"social": ["https://vk.com/primer"],
"openingHours": {
"office": "Mo-Fr 09:00-18:00"
},
"areaServed": {
"city": "Екатеринбург"
},
"advantages": [],
"services": [
{
"name": "Монтаж пластиковых окон",
"description": "Устанавливаем окна по ГОСТу с гарантией три года и выездом на замер в день обращения.",
"url": "https://primer.ru/uslugi/montazh/",
"price": "от 5 900 ₽",
"faq": [
{
"question": "Сколько ждать окно после заказа?",
"answer": "От семи рабочих дней с момента замера."
}
]
},
{
"name": "Остекление балконов",
"description": "Остекляем балконы и лоджии под ключ, с отделкой или без неё.",
"url": "https://primer.ru/uslugi/osteklenie-balkonov/",
"price": null,
"faq": []
}
]
}
Второй услуге такой файл ничего не выдумывает: цены на странице не было,
поэтому price - null, а не «уточняйте» или
прочерк. Пустое поле в этом формате - честный ответ «мы не нашли»,
а не место для красивой фразы.
Семь правил проверки и их веса
Правила из следующего списка считаются только поверх файла, который уже
прошёл обязательный минимум и опознан как ai-data.json.
Шкала - десять баллов, вес каждого правила ниже - ровно тот, что
в коде (yadro/pravila_ai_data.php). Первые три весят по два
балла: это поля, ради которых нейросеть вообще открывает такую справку -
цена, готовый ответ и способ связаться. Остальные четыре весят по одному:
это не про содержание файла, а про его аккуратность.
- Цены, 2 балла. Цена - единственное число во всём файле, которое нейросеть может процитировать дословно и не соврать. Правило не требует цену у каждой услуги: балл берётся, если она указана хотя бы у трети списка - точнее, число услуг с ценой, умноженное на три, обязано быть не меньше общего числа услуг. Без неё на вопрос «сколько стоит» нейросеть либо промолчит, либо возьмёт чужую цифру - а это хуже, чем ничего не сказать.
- Вопросы и ответы, 2 балла. Готовая пара вопрос-ответ, собранная из разметки FAQPage на странице услуги, - текст, который нейросеть вставляет в ответ почти как есть, а не пересказывает своими словами. Правило бинарное: два балла, если в файле есть хотя бы одна пара, и ноль, если нет ни одной, - сколько бы услуг ни было в списке.
- Контакты, 2 балла. Единственное правило с настоящей частичной оценкой: заполнены два поля из трёх (телефон, почта, адрес) - один балл, заполнены все три - два, меньше двух - ноль. Вес такой же высокий, как у цен и вопросов: без способа связаться справка не выполняет свою главную работу, сколько бы услуг в ней ни было перечислено.
- Живые адреса, 1 балл. Проверяем, отвечают ли адреса услуг живым кодом, - но только если карта кодов ответа вообще передана: без неё правило засчитывает балл по умолчанию, а не штрафует за то, что не проверялось. Вес ниже первых трёх, потому что это не про содержание файла, а про его аккуратность. Услуг в файле нет вовсе - балл не даётся, см. оговорку под списком.
- Без повторов адресов, 1 балл. Если два разных пункта списка услуг ведут на один и тот же адрес, для нейросети это одна и та же страница под двумя именами - она их всё равно объединит. Правило ловит небрежность сборки файла, а не нехватку контента, вес поэтому такой же скромный, как у живых адресов. Услуг в файле нет вовсе - балл не даётся, см. оговорку под списком.
- Услуги не статьи, 1 балл. Отдельно смотрим, не
затесалась ли в список услуг статья или новость: по имени (начинается
со слова «статья», «новость» или «блог») либо по сегменту адреса
(
stati,statya,blog,news,novosti). Ошибка обидная - нейросеть предложит человеку почитать вместо того, чтобы продать услугу, - но она про один пункт списка, а не про весь файл, поэтому балл тоже один. Услуг в файле нет вовсе - балл не даётся, см. оговорку под списком. - Описания заполнены, 1 балл. Последнее правило ловит не отсутствие текста, а заглушки: описание компании и описание каждой услуги короче 40 знаков мы не признаём настоящим текстом - «Продажа окон» это ещё не описание. Порог низкий нарочно, чтобы не спорить о качестве текста и ловить только его полное отсутствие, поэтому и вес минимальный.
Файл, в котором услуг нет вовсе
Три правила из семи - живые адреса, повторы адресов и «услуги не
статьи» - судят не файл целиком, а список услуг. Когда список пуст
("services": [], ключа нет вовсе или в списке нет ни одного
объекта), каждое из них даёт ноль баллов и находку
«Услуг в файле нет» - спокойную, не красную: файл ничего не нарушил,
просто судить было не по чему.
Раньше эти три правила давали в такой пустоте полный балл: нарушать нечего, значит правило соблюдено. Файл без единой услуги набирал так 6 из 10 и получал три похвалы за то, чего в нём нет, - вплоть до «У каждой услуги свой адрес» про файл, где услуг ноль. Хвалить за отсутствующее для нас ровно то же самое, что обвинять за несуществующее, и запрещено по той же причине. Теперь файл с полными контактами и описанием, но без услуг, честно берёт 3 балла из 10.
Чего мы не требуем и почему
Дата обновления файла - в шкале ноль баллов, и поля для неё в самом формате тоже нет. У единственного живого образца, ради которого этот инструмент и делался, такого поля не оказалось вовсе - а требовать его значило бы навязывать чужому файлу свою же выдумку и потом судить его за то, что мы сами придумали.
По той же причине шкала пользы не смотрит на всё содержимое файла
разом: она читает только contact, description
и содержимое services (цену, вопросы, адрес, описание).
Логотип, ссылки на соцсети, часы работы и область обслуживания в десять
баллов не входят - это честные поля файла, но у нас нет способа
доказательно сказать, что их отсутствие ухудшает ответ нейросети.
Поле advantages (достоинства) генератор не заполняет
никогда и по той же причине не начисляет за него баллов проверялка:
доказанные фактом достоинства вроде «работаем с 2008 года» разметкой
не подтверждаются, а придумывать их за компанию нельзя. Пустой список
здесь - осознанный отказ, а не дыра в сборке.
Собрать такой файл по своему сайту можно генератором ai-data.json, а файл, который уже лежит на сайте, - нашей же проверкой. Соберём и внедрим файл за вас - это услуга студии.