Вы открыли страницу конкурента и хотите быстро увидеть, что именно он обещает: сроки, цены, условия и гарантии. Читать и сводить всё вручную долго.
Семантический триплет записывает одно утверждение в трёх частях: субъект → связь (предикат) → объект. Субъект — о ком или о чём говорится; связь — что о нём утверждается; объект — другая сущность или значение. Например: «Apple производит iPhone» → «Apple → производит → iPhone».
Условие не является четвёртой частью классического триплета. В рабочей SEO-таблице я добавляю его отдельной колонкой, потому что без условия смысл легко исказить. Фраза «Доставка бесплатна при заказе от 5000 рублей» даёт запись «доставка → является → бесплатной» и отдельное условие «при заказе от 5000 рублей».
Триплет — не сам факт, а запись, которую составил человек, скрипт или нейросеть. Она может выглядеть правдоподобно и всё же обманывать. Ниже — три способа получить такие строки, проверить их и превратить в список правок или ТЗ. Цифры точности получены на 400 реальных предложениях; ответы оценивала нейросеть-судья, поэтому ограничения проверки указаны отдельно.
Зачем SEO-специалисту триплеты
На выходе у вас будет проверенная таблица утверждений страницы и список вопросов к своей странице. В каждой строке три основных поля — субъект, связь и объект или значение; условие хранится отдельно и не прячется внутри объекта.
Реальное предложение со страницы letbefit.ru: «Оплата списывается каждые 7 дней».
Что с ними делать
- Карта фактов конкурентов. Выписать факты 3–5 лидеров выдачи по типам (цена, срок, оплата, доставка, гарантия) и увидеть, чего нет у вас.
- Аудит своей страницы. Найти факты, у которых потеряно условие или нет явного субъекта.
- ТЗ копирайтеру. Дать блок «Факты и условия» с конкретными пунктами вместо «напишите убедительно».
Чего от них ждать не стоит
- Что поисковик ранжирует по числу триплетов. Публичного подтверждения такого фактора я не нашёл. В основном контрасте плотность слабо различалась между топ-20 и позициями 21–50: 51,03 из 100. При сравнении страниц близкой длины оценка — 50,32, её 95% интервал включает 50. Это не устанавливает ни причинного влияния плотности на позиции, ни порога «нормы»; шкала ниже показывает величину результата, а полное исследование — в отдельной статье.
- Что в исследованной выборке было связано с цитированием: слабые положительные связи обнаружены для определения в первом предложении и первого абзаца, понятного без остального текста. Для цифры в первом абзаце убедительной связи не обнаружено; большее число названий (имена, бренды, города) было связано с меньшими шансами цитирования в Google. Эти наблюдения не показывают эффект от правок страницы; подробности и ограничения — в статье о замере.
- Что автоматическое извлечение точно: без проверки на ваших данных ему верить нельзя.
Разница по плотности — около одного пункта; шкала не задаёт норму
Число показывает, как часто в случайной паре страниц одна из топ-20 имеет более высокую плотность триплетов, чем страница с позиций 21–50 того же запроса; ничья считается за половину. 50 — равные шансы, а не целевая плотность.
| Сравнение страниц | Градация результата от 50 до 55 и 95% интервал |
|---|---|
| Основной контраст2 378 запросов | 51,03 из 10095% интервал: 50,61–51,45 |
| Близкая длинасопоставленные страницы | 50,32 из 10095% интервал: 49,81–50,82 |
У оценки для страниц близкой длины нижняя граница 49,81 выходит левее шкалы; стрелка показывает, что отрезок обрезан у 50. Интервалы рассчитаны бутстрепом по запросам. 55 — только край рисунка, не SEO-цель.
В основном расчёте оценка на 1,03 пункта выше равной базы, но это небольшая наблюдаемая разница, а не доказательство влияния на ранжирование. После сопоставления страниц близкой длины интервал включает 50; в модели с поправкой на длину и ссылки отдельной связи плотности не обнаружено (отношение шансов 1,000; 95% интервал 0,964–1,038). Поэтому из этих данных нельзя вывести норматив плотности или обещать рост позиций.
Как выглядят хорошие и плохие триплеты
Правило простое: один факт, явный субъект, число с единицей, условие остаётся рядом. Ниже реальные предложения со страниц выдачи. Цветом показаны только три части триплета; условие оставлено обычным текстом и вынесено в отдельную строку расшифровки.
Хороший триплет
Оплата списывается каждые 7 дней.
Субъект назван, число дано вместе с единицей, дополнительного условия нет.
Точную цену мастер рассчитает после осмотра объекта и согласования перечня работ.
Условие вынесено отдельной строкой и не смешивается с объектом.
Плохой триплет: условие потеряно
Если работник приступил к выполнению работ даже без заключения договора, это свидетельствует о возникновении трудовых отношений.
Правила записали: работник — приступить — к выполнению работ. Ошибка в том, что условная часть превратилась в самостоятельный факт.
Плохой триплет: главное утверждение пропало
Если при покупке недвижимости налогоплательщик взял ипотеку, он может дополнительно вернуть НДФЛ со средств, направленных на выплату процентов по кредиту.
Правила выписали только условие: налогоплательщик — взять — ипотеку. Главное утверждение про возврат НДФЛ в триплет не попало.
Пять признаков хорошего триплета
- Субъект назван в триплете
Если в тексте «это занимает три дня», в триплете субъектом должно стать существительное из контекста («изготовление окна»), а не слово «это».
- Один факт в триплете
«Повара готовят в 2 смены» и «ночью для утренних заказов» — разные факты, лучше разные строки.
- Число с единицей
«от 4000 рублей за сеанс», а не «от 4000».
- Условие рядом
«При заказе от 5000 рублей», «после осмотра», «только для постоянных клиентов».
- Отрицание сохранено
«не содержит сахара» не должно превратиться в «содержит сахар».
Как достать триплеты: три способа
А. Нейросеть с промптом
- Рабочий промпт проверен на 400 отдельных предложениях: строго верны 90,2% триплетов у Sonnet и 82,8% у Opus. Исторический тест другой инструкции оставлен только в исследовательской части. данные
- Подходит для 5–50 страниц; нужен доступ к модели.
Б. Скрипт на Python
- Бесплатно и локально, но грубо: у публикуемого скрипта строго верны 32% триплетов на 400 отдельных предложениях и 37% на фрагментах 30 страниц длиной до 700 слов. данные
- Для поиска пробелов не годится; только как грубый счётчик синтаксических конструкций. Нужен Python.
В. Вручную в таблице
- Каждый триплет видно и можно сверить с исходником; точность определяется вниманием проверяющего. практика
- Для самых важных страниц и для проверки двух других способов.
Что выбрать
- Конкуренты и своя страница: способ А, затем проверка 20 триплетов руками.
- Тысячи страниц: массовый показатель требует измеренной точности на выборке; способ Б даёт только грубый счётчик.
Способ А: нейросеть. Шаги
- Возьмите основной текст страницы
Без меню, подвала и рекламы. Разбейте на предложения и пронумеруйте.
- Вставьте промпт и текст
Промпт ниже. Просите таблицу: так проще проверять.
- Сверьте цитаты
Колонка «Цитата» должна дословно совпадать с исходником. При расхождении хотя бы в одной строке разбор отбросьте.
- Проверьте 20 триплетов
По списку из раздела про проверку ниже. Особенно условия и типы фактов.
- Сохраните таблицу
Один файл на страницу: удобно сводить в общую карту.
Показать промпт целиком (скопируйте и вставьте вместе с текстом)
Колонки URL, «Вопрос покупателя» и «Статус проверки» добавляете вы: модель их не заполняет. Статус ставит человек: верно, частично, неверно, не факт.
Ты извлекаешь факты из текста страницы сайта для SEO-анализа. Для каждого предложения выпиши все проверяемые факты строками таблицы с колонками: № фрагмента | Цитата (предложение целиком) | Контекст | Субъект | Связь | Объект | Условие | Тип факта | Пометка для проверки.
- Извлекай только то, что сказано в тексте. Чтобы раскрыть местоимение или найти пропущенный субъект, используй заголовок и соседние предложения, но ничего не добавляй из своих знаний. Если субъект или условие взяты из соседнего фрагмента, запиши этот фрагмент в колонку «Контекст»; если однозначно восстановить нельзя, напиши в «Пометке» слово «проверить».
- Условия («если», «при», «после», «от», «до», «только», «в пределах») не теряй: вынеси в колонку «Условие». Если условия нет, поставь «—»; если не уверен, поставь «?».
- Числа и единицы измерения сохраняй как в тексте.
- Отрицание сохраняй в связи («не содержит»).
- Связь пиши глаголом в начальной форме или короткой фразой.
- Тип факта выбери из списка: цена, срок, доставка, оплата, гарантия, состав, процесс, масштаб/опыт, прочее.
- Если в предложении нет проверяемого факта (призыв, вопрос, заголовок), пропусти его.
- Одно утверждение — одна строка; составное раскладывай на несколько строк.
- В колонке «Цитата» повтори предложение целиком без изменений. В «Пометке» пиши «проверить» для местоимений, модальности («может», «должен») и всего, в чём не уверен.
ТЕКСТ: (вставьте нумерованные фрагменты страницы вместе с заголовками)
Что ответила модель на реальном тексте
Я дал Claude Sonnet семь предложений со страницы letbefit.ru (13-е место в Google по запросу «доставка вкусной еды») и более раннюю версию этого промпта без колонки «Начало предложения» (рабочий промпт проверен отдельно, см. раздел ниже). Таблица ниже перенесена из рабочего разбора. Исходный ответ модели для посимвольной сверки найти не удалось, поэтому точное воспроизведение оформления и орфографии не подтверждено; содержание строк сверено с предложениями страницы.
| № | Субъект | Связь | Объект | Условие | Тип |
|---|---|---|---|---|---|
| 1 | Повара | готовить | в 2 смены | — | процесс |
| 1 | Ночная смена | готовить | для утренних заказов | ночью | процесс |
| 1 | Дневная смена | готовить | для вечерних заказов | днем | процесс |
| 2 | Оплата | списываться | каждые 7 дней | — | оплата |
| 3 | Компания | списывать | оплату за следующую неделю | на 5-й день действия рациона питания | оплата |
| 4 | Клиент | выбирать | любой удобный двухчасовой интервал доставки | — | доставка |
| 4 | Компания | привозить | заказ по адресу | — | доставка |
| 4 | Заказ | доставляться | в удобных пищевых контейнерах | — | состав |
| 5 | Рыба и морепродукты | составлять | до 50% меню | в премиум-рационах | состав |
| 5 | Доля рыбы и морепродуктов в премиум-рационах | быть больше | в 2 раза, чем в стандартных программах | — | состав |
| 6 | Компания | гарантировать | расчет каждого блюда по КБЖУ | — | гарантия |
| 6 | Каждое блюдо | не содержать | сахар | — | гарантия |
| 7 | Компания | осуществлять | бесплатную доставку питания | по Москве (в пределах МКАД) и МО | доставка |
Хорошо. Условия вынесены отдельно («на 5-й день», «в пределах МКАД»), отрицание сохранено («не содержать сахар»), составные факты разложены.
Плохо. Строка про пищевые контейнеры помечена как «состав»: это доставка. Модель придумала субъекты «Ночная смена» и «Дневная смена», которых в тексте нет. Остальные триплеты соответствуют тексту: в исходном предложении сказано «Мы гарантируем, что каждое блюдо рассчитано по КБЖУ и не содержит сахара […]», и триплет «компания — гарантировать — расчет каждого блюда по КБЖУ» это передаёт.
Ограничения способа А: страницу конкурента можно отправлять во внешнюю модель, а закрытые документы клиента и текст под NDA нельзя. Стоимость зависит от числа предложений и модели, лимиты запросов задаёт сервис; на сотнях страниц считайте расходы заранее.
Способ Б: скрипт на Python
Скрипт использует бесплатную библиотеку Natasha и работает на вашем компьютере. Генеративная языковая модель не используется.
Natasha использует модели Slovnet для морфологического и синтаксического разбора, а простые правила поверх результата находят, кто делает, что делает и с чем. Затем скрипт выписывает связку «подлежащее — глагол — дополнение». Это упрощённая версия правил: в ней нет ограничения на длину объекта и шаблонов «X — это Y» и «у нас есть X».
На том же предложении правила из теста нашли один триплет: «мастер — рассчитать — точную цену».
- «Точную цену мастер рассчитает после осмотра объекта и согласования перечня работ».
- мастер — рассчитать — Точную цену
мастер — рассчитать — после осмотра объекта и согласования перечня работ
Условие превратилось в отдельный «факт»: так скрипт обычно теряет условия. Пересоберите их вручную или отдайте нейросети.
Показать скрипт целиком (Python, библиотека Natasha)
Установка в терминале: pip install natasha
from natasha import (Segmenter, MorphVocab, NewsEmbedding,
NewsMorphTagger, NewsSyntaxParser, Doc)
segmenter, morph_vocab = Segmenter(), MorphVocab()
emb = NewsEmbedding()
morph_tagger, syntax_parser = NewsMorphTagger(emb), NewsSyntaxParser(emb)
def subtree(tok, tokens):
"""Слово и всё, что от него зависит, в порядке текста."""
ids, stack = set(), [tok.id]
while stack:
cur = stack.pop()
if cur in ids: # защита от цикла в дереве разбора
continue
ids.add(cur)
stack += [t.id for t in tokens if t.head_id == cur]
return " ".join(t.text for t in tokens if t.id in ids)
def triples(text):
doc = Doc(text)
doc.segment(segmenter)
doc.tag_morph(morph_tagger)
doc.parse_syntax(syntax_parser)
for sent in doc.sents:
toks = sent.tokens
for v in (t for t in toks if t.pos == "VERB"):
v.lemmatize(morph_vocab)
subj = [t for t in toks if t.head_id == v.id and t.rel in ("nsubj", "nsubj:pass")]
objs = [t for t in toks if t.head_id == v.id and t.rel in ("obj", "obl", "iobj")]
for s in subj:
for o in objs:
neg = any(t.head_id == v.id and t.text.lower() in ("не", "нет", "ни") for t in toks)
yield subtree(s, toks), ("не " if neg else "") + v.lemma, subtree(o, toks)
for t in triples("Точную цену мастер рассчитает после осмотра объекта и согласования перечня работ."):
print(t)
Отрицание в проверенных конструкциях скрипт сохраняет: «Компания не доставляет заказы» даёт «не доставлять». Условия, модальность («может вернуть») и местоимения он не разбирает: такие предложения получают пометку и идут на ручную проверку. Предложение без извлечённой записи остаётся в таблице с пометкой «нет записи» — это сигнал проверить его вручную.
Способ Б, полная версия: страница → CSV
Эта версия начинает с адреса страницы. Скрипт скачивает её, отбрасывает меню, подвал и рекламу с помощью trafilatura. Затем он отдельно разбирает абзацы и заголовки, чтобы заголовок не склеился с первым предложением, и выгружает CSV-таблицу.
Колонки type, buyer_question и manual_status заполняйте вручную. Само условие скрипт не извлекает. Он только ставит «ПРОВЕРИТЬ» у предложений со словами «если», «при», «после», «от» или «до». Если страница не загрузилась или основной текст не найден, скрипт сообщает об ошибке. Это пропуск, а не «утверждений нет».
Локальная проверка. Страница из трёх абзацев дала 9 строк: 8 с триплетом и 1 без него — заголовок. Отдельно проверены отрицание, условие, модальный глагол, местоимение, недоступная страница и страница без основного текста.
Три реальных адреса. Страница услуг sk-seo.ru дала 23 строки, из них 4 с триплетом. Ячейки таблиц скрипт не разбирает и помечает «таблица: разберите вручную». Длинная статья Википедии не уложилась в 150 секунд. Закрытый защитой интернет-магазин дал сообщение «страница не загружена». Склеившиеся заголовки и ячейки помечаются «склейка?».
Итог. На фрагментах первых 700 слов 30 страниц строго верны 37% триплетов скрипта (31–42%) и 67% триплетов Sonnet (58–75%). Скрипт делает черновик: все триплеты, которые попадут в аудит или ТЗ, сверяйте с исходником.
Установка в терминале: pip install natasha trafilatura. Запуск: python page_to_csv.py https://адрес-страницы результат.csv
Показать скрипт «страница → CSV»
import csv
import re
import sys
import trafilatura
from natasha import (Segmenter, MorphVocab, NewsEmbedding,
NewsMorphTagger, NewsSyntaxParser, Doc)
segmenter, morph_vocab = Segmenter(), MorphVocab()
emb = NewsEmbedding()
morph_tagger, syntax_parser = NewsMorphTagger(emb), NewsSyntaxParser(emb)
COLUMNS = ["url", "fragment_id", "quote", "context", "subject", "predicate", "object",
"condition", "type", "buyer_question", "check_flags", "manual_status"]
CONDITION_MARKERS = re.compile(r"\b(если|при|после|до|от|только|когда|кроме|в пределах|в случае|за исключением)\b", re.I)
MODAL_LEMMAS = {"мочь", "уметь", "должен", "обязан"}
MODAL_MARKERS = re.compile(r"\b(может|могут|мог|могла|могли|должен|должна|должны|обязан|обязана|обязаны|умеет|вправе|возможно)\b", re.I)
def subtree(tok, children, by_id):
ids, stack = set(), [tok.id]
while stack:
cur = stack.pop()
if cur in ids: # защита от цикла в дереве разбора
continue
ids.add(cur)
stack += [c.id for c in children.get(cur, [])]
return " ".join(by_id[i].text for i in sorted(ids, key=lambda i: by_id[i].start) if i in by_id)
def is_negated(verb, children):
return any(t.text.lower() in ("не", "нет", "ни") for t in children.get(verb.id, []))
def page_to_rows(text, url):
n, context = 0, ""
for line in text.splitlines(): # абзацы и заголовки обрабатываем отдельно
line = line.strip()
if not line:
continue
if line.startswith("|"): # строка таблицы: ячейки не разбираем, их заполняют вручную
n += 1
if not set(line) <= set("|-: "): # строку-разделитель |---|---| пропускаем
yield [url, n, line, context, "", "", "", "", "", "", "таблица: разберите вручную", ""]
continue
if len(line) < 100 and not line.endswith((".", "!", "?", "…")):
context = line # короткая строка без точки: заголовок, это контекст следующих предложений
doc = Doc(line)
doc.segment(segmenter)
doc.tag_morph(morph_tagger)
doc.parse_syntax(syntax_parser)
for sent in doc.sents:
n += 1
toks = sent.tokens
children = {}
for t in toks:
children.setdefault(t.head_id, []).append(t)
by_id = {t.id: t for t in toks}
has_marker = bool(CONDITION_MARKERS.search(sent.text))
has_modal_marker = bool(MODAL_MARKERS.search(sent.text))
glued = bool(re.search(r"[а-яёa-z][А-ЯЁA-Z]", sent.text)) # слова слиплись: заголовок или ячейки таблицы
found = False
for v in (t for t in toks if t.pos == "VERB"):
v.lemmatize(morph_vocab)
kids = children.get(v.id, [])
subj = [t for t in kids if t.rel in ("nsubj", "nsubj:pass")]
objs = [t for t in kids if t.rel in ("obj", "obl", "iobj")]
for s in subj:
for o in objs:
found = True
flags = []
if v.lemma in MODAL_LEMMAS or has_modal_marker:
flags.append("модальность")
if s.pos == "PRON":
flags.append("местоимение-субъект")
if has_marker:
flags.append("условие")
if glued:
flags.append("склейка?")
pred = ("не " if is_negated(v, children) else "") + v.lemma
# condition: ПРОВЕРИТЬ = в предложении есть маркер условия, скрипт его не извлекает;
# пусто = маркеров условия нет
yield [url, n, sent.text, context, subtree(s, children, by_id), pred, subtree(o, children, by_id),
"ПРОВЕРИТЬ" if has_marker else "", "", "", "; ".join(flags), ""]
if not found: # предложение без записи тоже попадает в таблицу: для ручной разметки
review = ["нет записи"]
if has_marker:
review.append("условие")
if has_modal_marker:
review.append("модальность")
if glued:
review.append("склейка?")
yield [url, n, sent.text, context, "", "", "", "", "", "", "; ".join(review), ""]
if __name__ == "__main__":
url, out = sys.argv[1], sys.argv[2]
html = trafilatura.fetch_url(url)
if not html:
sys.exit("ОШИБКА: страница не загружена. Это пропуск, а не «утверждений нет».")
text = trafilatura.extract(html, include_tables=True, favor_recall=True)
if not text:
sys.exit("ОШИБКА: основной текст не извлечён (JS-страница, защита от ботов или нестандартная вёрстка). "
"Это пропуск, а не «утверждений нет».")
rows = list(page_to_rows(text, url))
with open(out, "w", encoding="utf-8-sig", newline="") as f:
w = csv.writer(f, delimiter=";")
w.writerow(COLUMNS)
w.writerows(rows)
print("строк: %d, из них с записью: %d" % (len(rows), sum(1 for r in rows if r[4])))Способ В: вручную в таблице
Создайте таблицу с колонками: URL | № фрагмента | Цитата | Контекст | Субъект | Связь | Объект | Условие | Тип факта | Вопрос покупателя | Пометка для проверки | Статус проверки.
Скопируйте исходное предложение целиком в колонку «Цитата». Затем выпишите триплет. В «Условии» ставьте «—» только тогда, когда условия действительно нет.
Идите по тексту сверху вниз и берите только проверяемые утверждения. Начните со страниц лидеров. В первую очередь собирайте цены, сроки, условия, гарантии и показатели масштаба: стаж, число клиентов, размер автопарка.
Быстрая проверка: 20 случайных триплетов
- Возьмите 20 случайных триплетов
Не первые 20, а разбросанные по всей странице.
- Сверьте каждый триплет с предложением
Метка: верно, приблизительно (суть та же, но объект обрезан), неверно, не факт (в предложении нет утверждения).
- Отдельно посмотрите условия
Есть ли в предложении «если», «при», «после», «от», «до»? Попало ли это в колонку «Условие»? Это самая частая потеря.
- Примите решение
Любой триплет с потерянным отрицанием, придуманным субъектом или чужим значением: перепроверьте вручную триплеты того же типа на этой странице. Если 6 или больше из 20 записей не проходят строгую сверку с исходной цитатой, смените промпт или модель. Это редакторский сигнал остановить запуск, а не статистическая оценка точности. 20 триплетов — быстрая проверка на глаз, она решает, продолжать ли обработку дальше; в аудит и ТЗ попадают только триплеты, сверенные вручную. Способы между собой по 20 триплетам не сравнивают; пороги редакторские.
- Сохраните проверенные триплеты
Они пригодятся как пример для следующего прогона. Для сравнения способов нужен отдельный эталон из 300–500 триплетов.
Как работает правило «шесть неточных из 20». Если на самом деле верны 90 триплетов из 100, правило зря забракует прогон в 1 случае из 100. При 80 верных из 100 оно забракует прогон в 20 случаях из 100, при 70 из 100 — в 58, при 60 из 100 — в 87. На данных теста правило забраковало бы 2 выборки из 100 у Opus, 10 у Sonnet, 61 у Haiku и все 100 у правил Natasha. Это грубое сито, а не гарантия: 14 верных из 20 не значит, что у вас ровно 70% точности, потому что на 20 триплетах ошибка слишком велика.
Быстрая проверка: 20 триплетов
- Это быстрая проверка на глаз, а не точное измерение: на 20 триплетах случайная ошибка слишком велика.
- Нужен для одной страницы или нескольких конкурентов.
- Решение по порогам из шага «Примите решение».
Оценка качества: 300–500 триплетов
- Нужна для массовых показателей и сравнения способов.
- Оценка вслепую (проверяющий не знает, какой способ выдал триплет), два проверяющих и число, которое показывает, насколько они согласны друг с другом (коэффициент согласия, каппа).
- Точность измеряют отдельно по тем группам, которые будете сравнивать.
Если вы просите модель разобрать сотни строк, она может сбиться в нумерации, и триплеты окажутся под соседними номерами. В моём тесте у Haiku со 109-го предложения триплеты стояли под номером на единицу больше; в итоговых цифрах сдвиг исправлен. Поэтому просите вернуть вместе с триплетом первые слова предложения и сверяйте их с исходником кодом. Сначала убедитесь, что оцениваете ответ на правильный исходник, и только потом судите о модели.
Что делать с готовыми триплетами
1. Карта фактов лидера
Сгруппируйте триплеты по типам. Вот как это выглядит для страницы letbefit.ru (13-е место по запросу «доставка вкусной еды», 35 триплетов из 1164 слов). Колонка справа — вопрос, который стоит задать своей странице.
Оплата
«Оплата списывается каждые 7 дней»; «На 5-й день действия вашего рациона питания мы списываем оплату за следующую неделю»
Когда и как списываются деньги? Есть ли предупреждение?
Процесс
«Наши повара готовят в 2 смены — ночью для утренних заказов и днем для вечерних»
Как устроено производство и почему заказ свежий?
Доставка
«Мы осуществляем бесплатную доставку питания по Москве […] и МО»; «Выбирайте любой удобный двухчасовой интервал […]»
Зона, цена, интервал: что именно обещаете?
Состав
«Мы гарантируем, что каждое блюдо рассчитано по КБЖУ и не содержит сахара […]»
Какие измеримые свойства состава можете подтвердить?
Сравнение
«В премиум-рационах рыба и морепродукты составляют до 50% меню — это в 2 раза больше, чем в стандартных программах»
Чем ваша версия отличается от обычной, в числах?
Предложения со страницы letbefit.ru, снимок выдачи от 2 октября 2026, дословно с точностью до знаков очистки текста; […] — пропуск. Типы фактов выбраны мной.
Теперь возьмите ещё лидеров (в примере это выбранные результаты топ-20): 3–5 страниц того же типа из топ-10 вашего запроса (если подходящих мало, из топ-20), без агрегаторов и маркетплейсов. В примере для компактности взяты страницы с 13-го и 16-го мест. Например, nam-nyam.ru (16-е место) заявляет масштаб: «Мы работаем более 20 лет […]», «Минимальная сумма заказа составляет 4000 рублей», «Автопарк состоит из более чем 30 специализированных автомобилей».
2. Список пропусков
Сведите карты трёх-пяти лидеров в одну таблицу «тип факта × сайт». Строки, которые есть у большинства лидеров и нет у вас, — кандидаты в правки, а не готовый список. Добавляйте ответ, только если вопрос относится к вашему предложению, значение вы получили у бизнеса и подтвердили документом; отсутствие ответа бывает нормальным. Решение по пробелу принимайте по правилам из статьи про замер. Строки, которые есть только у одного, — возможные преимущества. Переносите вопрос («как у вас устроена оплата?»), а не чужое значение.
3. Блок «Факты и условия» для ТЗ
Блок для ТЗ копирайтеру (шаблон)
- Выпишите вопросы покупателя по типам: цена, срок, оплата, доставка, гарантия, состав, масштаб. Если у значения есть число, укажите единицу. Если факт действует при условии, условие не должно теряться на странице: оно стоит в той же фразе, в той же строке таблицы или в сноске рядом.
- Субъект должен однозначно читаться из контекста. Местоимение заменяйте, только если человек без контекста не поймёт, о чём речь.
- Каждое значение можно подтвердить документом, прайсом или скриншотом; приложите источник. Заявления о составе и пользе публикуйте только при наличии документа и согласуйте с юристом.
- Проверьте применимость и закройте подтверждённые пропуски из таблицы «тип факта × конкуренты» (приложена).
- Приёмка: каждое значение (цена, срок, сумма, гарант) сверено с документом-источником из приложения. Каждое условие из источника есть на странице. Ни одно значение не взято у конкурента.
Законченный пример: от исходника до ТЗ
Полностью вымышленный учебный случай: страница поставщика оборудования. Исходный фрагмент конкурента:
Оборудование под заказ поставляется за 6–8 недель после предоплаты. Гарантию на оборудование предоставляет производитель; условия указаны в паспорте модели.
На вашей странице:
Поставляем оборудование со склада и под заказ. Предоставляем гарантию.
| Вопрос покупателя | Что сообщает конкурент | Что есть у вас | Решение для ТЗ |
|---|---|---|---|
| Сколько ждать оборудование под заказ? | 6–8 недель после предоплаты | Срок не указан | Запросить собственные сроки у отдела поставок. Чужие не переносить |
| Кто предоставляет гарантию? | Производитель | Неясное «предоставляем» | Уточнить гаранта и условия |
| Где проверить условия? | В паспорте модели | Источник не назван | Добавить доступный источник собственных условий |
Готовый фрагмент ТЗ
В блоке поставки указать подтверждённые сроки для оборудования под заказ и событие, от которого начинается отсчёт. Значения согласовать с отделом поставок. В блоке гарантии назвать гаранта и дать ссылку на действующие условия. Не использовать сроки и обещания конкурента.
Один формат для промпта, скрипта и ручной таблицы: URL | № фрагмента | Цитата | Контекст | Субъект | Связь | Объект | Условие | Тип факта | Вопрос покупателя | Пометка для проверки | Статус проверки. В тест вошли колонки от номера фрагмента до пометки; URL, вопрос покупателя и статус проверки добавляет SEO-специалист. В скрипте пустое «Условие» значит «маркеров условия в предложении нет», а «ПРОВЕРИТЬ» — «маркер есть, заполните вручную». Две компании могут отвечать на один вопрос разными утверждениями: для поиска одинаковых фактов это несовпадение, для аудита полноты ответа — одна и та же тема, которую стоит проверить.
Проблема текста или ошибка извлечения: как отличить
Не переписывайте страницу только потому, что программа извлечения её не поняла. Сначала проверьте, сохранились ли заголовки, границы блоков, таблицы и контекст. Если исходный текст понятен, а триплет неверен, проблема в обработке. Такие правки на улучшение позиций не тестировались.
Непонятно, к какой услуге относится цена; условие действительно трудно найти; местоимение неоднозначно даже с контекстом. Правят содержание.
Программа потеряла заголовок, разорвала таблицу, склеила карточки, отбросила придаточное или обрезала объект. Правят извлечение.
| Что обнаружено | Что делать |
|---|---|
| «Цена от 4000», непонятны услуга и единица оплаты | Найти эти сведения в контексте страницы или запросить у бизнеса. Не додумывать |
| Скидка связана с получением нескольких товаров | Сохранить именно условие из источника; отдельно уточнить у бизнеса, что оно означает на практике |
| «Это занимает три дня» | Проверить предыдущую фразу. Заменять местоимение только при реальной неоднозначности |
| Условие не попало в извлечённый триплет | Свериться с исходником. Не объявлять исходный текст плохим автоматически |
Сложные случаи: таблицы, динамические страницы, список адресов, бюджет
Базовый сценарий выше рассчитан на обычный текст одной страницы. Четыре ситуации требуют дополнительных шагов.
Таблицы и карточки товаров
Правила на Natasha разбирают предложения, а в таблице предложений нет: скрипт «страница → CSV» помечает такую строку «таблица: разберите вручную». Хуже другое: ячейка «5 мм» без названия столбца и товара ничего не утверждает. Чтобы характеристика не оторвалась от объекта, перепишите каждую строку таблицы как «объект — столбец: значение; столбец: значение». Это делает скрипт tables_to_facts.py: он принимает URL или сохранённый HTML, берёт таблицы прямо из разметки и печатает такие строки. Пример на странице услуг этого сайта (4 октября 2026):
# заголовки столбцов (сверьте с видимой таблицей): Формат | Когда нужен | Что на выходе | Срок | Стоимость
Технический SEO-аудит — Когда нужен: Причина в технической части; Что на выходе: Причины проблем, оценка влияния и приоритизированный план исправлений; Срок: от 1 недели; Стоимость: от 50 000 ₽
Таблицы читаются прямо из HTML: очистка может потерять заголовки столбцов. Скрипт берёт их из thead; если его нет, считает заголовком первую строку и выводит предупреждение. Если заголовок пустой, число ячеек не совпадает или есть объединённые ячейки (rowspan, colspan), скрипт не превращает их в правдоподобные факты: неподдерживаемые строки или таблицу нужно проверить и собрать вручную. Строки заголовка не обрабатываются как данные повторно — в том числе если в HTML нет tbody. Перед передачей результата модели сверьте заголовки с таблицей на странице.
Показать скрипт tables_to_facts.py (Python, lxml и trafilatura)
# -*- coding: utf-8 -*-
"""Таблицы страницы -> строки «объект — столбец: значение», чтобы характеристика не оторвалась от товара или тарифа.
python tables_to_facts.py URL > facts.txt
python tables_to_facts.py page-rendered.html > facts.txt
Таблицы берутся прямо из HTML, а не из очищенного текста: очистка может потерять строку заголовков.
Заголовки столбцов берутся из первой строки <thead>; если <thead> нет, первая строка
принимается за заголовок и явно помечается для проверки. Первая ячейка строки — объект.
Перед фактами печатается принятая строка заголовков. Объединённые ячейки, вложенные
таблицы и строки с неожиданным числом ячеек не преобразуются в факты: для них выводится
предупреждение, и таблицу нужно обработать вручную.
"""
import re
import sys
from collections.abc import Iterator
from pathlib import Path
import trafilatura
from lxml import html as lh
from lxml.html import HtmlElement
def text(cell: HtmlElement) -> str:
return re.sub(r"\s+", " ", cell.text_content()).strip()
def table_facts(table: HtmlElement) -> Iterator[str]:
# Разбираем только строки этой таблицы. Вложенные таблицы выводятся отдельно ниже.
if table.xpath(".//table"):
yield "# ПРЕДУПРЕЖДЕНИЕ: вложенная таблица; внешнюю таблицу соберите вручную"
return
for cell in table.xpath(".//th|.//td"):
for attr in ("rowspan", "colspan"):
value = cell.get(attr)
if value is not None:
try:
merged = int(value) != 1
except ValueError:
merged = True
if merged:
yield "# ПРЕДУПРЕЖДЕНИЕ: обнаружена объединённая ячейка (%s); таблицу соберите вручную" % attr
return
head_rows = table.xpath("./thead/tr")
if len(head_rows) > 1:
yield "# ПРЕДУПРЕЖДЕНИЕ: многострочный заголовок; таблицу соберите вручную"
return
body_rows = table.xpath("./tbody/tr") or table.xpath("./tr")
if head_rows:
head = [text(c) for c in head_rows[0].xpath("./th|./td")]
else:
if not body_rows:
yield "# ПРЕДУПРЕЖДЕНИЕ: строки таблицы не найдены"
return
head = [text(c) for c in body_rows[0].xpath("./th|./td")]
body_rows = body_rows[1:]
yield "# ПРЕДУПРЕЖДЕНИЕ: <thead> отсутствует; первая строка принята за заголовок — проверьте её"
if len(head) < 2 or any(not label for label in head):
yield "# ПРЕДУПРЕЖДЕНИЕ: заголовки пустые или не позволяют связать значение с объектом; таблицу соберите вручную"
return
yield "# заголовки столбцов (сверьте с видимой таблицей): " + " | ".join(head)
for row_number, tr in enumerate(body_rows, start=2 if not head_rows else 1):
cells = [text(c) for c in tr.xpath("./th|./td")]
if not any(cells):
continue
if len(cells) != len(head):
yield "# ПРЕДУПРЕЖДЕНИЕ: строка %d содержит %d ячеек, а заголовок — %d; строка пропущена" % (
row_number, len(cells), len(head)
)
continue
obj = cells[0] or "строка без названия"
parts = ["%s: %s" % (h, v) for h, v in zip(head[1:], cells[1:]) if v]
if not parts:
yield "# ПРЕДУПРЕЖДЕНИЕ: строка %d не содержит значений для объекта %r" % (row_number, obj)
continue
yield "%s — %s" % (obj, "; ".join(parts))
if __name__ == "__main__":
source = sys.argv[1]
source_path = Path(source)
if source_path.is_file():
page = source_path.read_text(encoding="utf-8")
else:
page = trafilatura.fetch_url(source)
if not page:
sys.exit("ОШИБКА: страница не загружена. Это пропуск, а не «таблиц нет».")
tables = lh.fromstring(page).xpath("//table")
if not tables:
sys.exit("На странице нет HTML-таблиц. Если таблица нарисована скриптом, сохраните отрисованный HTML через render_to_text.py.")
for t in tables:
for line in table_facts(t):
print(line)
print()
Страницы, где текст появляется после загрузки скриптов
Если в скачанном HTML нет нужного текста, скрипт «страница → CSV» останавливается с сообщением, что основной текст не извлечён. Это пропуск, а не «утверждений нет». Дальше два шага. Сначала откройте страницу в браузере: виден ли нужный текст без кликов и прокрутки? Если виден, получите страницу после работы скриптов. Команда python render_to_text.py URL page-rendered.html > page.txt сохранит и основной текст, и отрисованный HTML. Текст из page.txt можно передать обычному разбору, а динамические таблицы извлечь командой python tables_to_facts.py page-rendered.html > facts.txt. Если текст появляется только после клика (вкладки, «показать ещё», калькуляторы), скрипт его не увидит: раскройте блоки вручную и сохраните текст. Страницы за защитой от ботов этим способом не берите: защиту не обходят, нужное выписывают вручную из открытой страницы.
Показать скрипт render_to_text.py (Python, Playwright и trafilatura)
# -*- coding: utf-8 -*-
"""Страница, где текст появляется после загрузки скриптов -> текст и, при необходимости, отрисованный HTML.
pip install playwright trafilatura && playwright install chromium
python render_to_text.py URL > page.txt
python render_to_text.py URL page-rendered.html > page.txt
"""
import sys
from pathlib import Path
import trafilatura
from playwright.sync_api import Error as PlaywrightError
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
from playwright.sync_api import sync_playwright
# The command's main output is meant to be redirected to a UTF-8 text file.
# Windows consoles otherwise may choose a legacy code page and fail on Russian text.
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
if hasattr(sys.stderr, "reconfigure"):
sys.stderr.reconfigure(encoding="utf-8")
if len(sys.argv) < 2:
sys.exit("Использование: python render_to_text.py URL [page-rendered.html]")
url = sys.argv[1]
html_path = Path(sys.argv[2]) if len(sys.argv) > 2 else None
with sync_playwright() as p:
browser = p.chromium.launch()
try:
page = browser.new_page()
try:
page.goto(url, wait_until="domcontentloaded", timeout=60000)
except PlaywrightError as exc:
sys.exit("ОШИБКА: страница не открылась в браузере: %s" % exc)
try:
page.wait_for_load_state("networkidle", timeout=12000)
except PlaywrightTimeoutError:
print("ПРЕДУПРЕЖДЕНИЕ: сеть продолжает работать; сохранён DOM после начальной загрузки и ожидания.", file=sys.stderr)
page.wait_for_timeout(1500) # даём завершиться обычной отрисовке и ленивой подгрузке
rendered_html = page.content()
finally:
browser.close()
if html_path is not None:
html_path.write_text(rendered_html, encoding="utf-8")
text = trafilatura.extract(rendered_html, include_tables=True, favor_recall=True)
if not text:
sys.exit("ОШИБКА: основной текст не извлечён даже после рендера. Это пропуск, а не «утверждений нет».")
print(text)
Список из сотен страниц
Скрипт «страница → CSV» принимает один адрес. Для списка используйте pages_to_csv_batch.py: он читает URL по одному в строке, обрабатывает каждый уникальный адрес один раз и складывает результаты в CSV с колонкой URL. Повторный URL помечается в журнале как дубль и не загружается снова. Уникальные адреса с ошибкой загрузки скрипт повторяет один раз. В журнале записаны статус, число строк и причина пропуска. Между попытками выдерживается пауза 1,5 секунды. Порядок работы:
- Соберите файл
urls.txt. - Запустите
python pages_to_csv_batch.py urls.txt result.csv journal.csv. - Откройте журнал. Адреса со статусом «ошибка» получите другим способом (отрисованный текст, вручную) или признайте пропуском. Пропуск не означает, что утверждений на странице нет.
- Проверяйте таблицу как обычно: 20 случайных триплетов для разбора, эталон на 300–500 триплетов для массового показателя.
Проверка скрипта: три адреса (две рабочие страницы и один несуществующий домен), рабочие обработаны, несуществующий попал в журнал со статусом «ошибка». На разбор страницы скриптом уходит около 0,2 секунды (медиана по 12 страницам, без скачивания), так что основное время занимают скачивание и пауза: при паузе 1,5 секунды на 300 страниц одни паузы займут 7,5 минуты.
Показать скрипт pages_to_csv_batch.py (Python)
# -*- coding: utf-8 -*-
"""Список адресов -> одна таблица для ручной проверки + журнал ошибок.
python pages_to_csv_batch.py urls.txt result.csv [journal.csv]
urls.txt: один адрес в строке, пустые строки и строки с # пропускаются.
Каждая страница обрабатывается как в page_to_csv.py. Неудачные адреса повторяются один раз в конце.
Страница, которая не загрузилась или не дала основной текст, попадает в журнал как пропуск, а не как «утверждений нет».
"""
import csv
import sys
import time
import trafilatura
from page_to_csv import COLUMNS, page_to_rows
def fetch_rows(url):
html = trafilatura.fetch_url(url)
if not html:
return None, "страница не загружена"
text = trafilatura.extract(html, include_tables=True, favor_recall=True)
if not text:
return None, "основной текст не извлечён (JS-страница, защита от ботов или нестандартная вёрстка)"
return list(page_to_rows(text, url)), ""
def main():
src, out = sys.argv[1], sys.argv[2]
journal = sys.argv[3] if len(sys.argv) > 3 else "journal.csv"
with open(src, encoding="utf-8") as f:
input_urls = [u.strip() for u in f if u.strip() and not u.strip().startswith("#")]
# Один URL может случайно повториться в списке. Не загружаем его повторно и
# не дублируем строки результата; повторную строку отмечаем в журнале.
urls = list(dict.fromkeys(input_urls))
status = {}
with open(out, "w", encoding="utf-8-sig", newline="") as f:
w = csv.writer(f, delimiter=";")
w.writerow(COLUMNS)
for attempt in (1, 2): # второй проход только для неудач
todo = [u for u in urls if status.get(u, ("", 0, 0, ""))[0] != "ok"]
for u in todo:
try:
rows, err = fetch_rows(u)
except Exception as e: # сеть или разбор: страница пропущена, прогон продолжается
rows, err = None, "%s: %s" % (type(e).__name__, e)
if rows is None:
status[u] = ("ошибка", 0, 0, err)
else:
w.writerows(rows)
status[u] = ("ok", len(rows), sum(1 for r in rows if r[4]), "")
time.sleep(1.5) # пауза, чтобы не нагружать чужие сайты
with open(journal, "w", encoding="utf-8-sig", newline="") as f:
w = csv.writer(f, delimiter=";")
w.writerow(["url", "статус", "строк", "строк с триплетом", "причина"])
seen = set()
for u in input_urls:
if u in seen:
w.writerow([u, "дубль", 0, 0, "повтор URL не обрабатывался"])
continue
seen.add(u)
w.writerow([u] + list(status[u]))
bad = [u for u in urls if status[u][0] != "ok"]
print("строк адресов: %d, уникальных адресов: %d, обработано: %d, пропущено: %d (см. %s)" % (
len(input_urls), len(urls), len(urls) - len(bad), len(bad), journal
))
if __name__ == "__main__":
main()
Сколько стоит прогон через нейросеть: считаем до запуска
Цены меняются, поэтому в статье их нет, есть способ расчёта. Если тариф указан за миллион токенов, бюджет равен число страниц × ((средние входные токены на страницу × цена входа + средние выходные токены на страницу × цена выхода) / 1 000 000) × (1 + доля повторов). Цены за миллион токенов берите на странице тарифов провайдера в день расчёта. Токены считайте на пробе, а не по числу слов: русский текст токенизируется по-разному в разных моделях.
- Возьмите 5 случайных страниц разной длины.
- Прогоните их рабочим промптом и запишите по каждой число входных и выходных токенов (его возвращает API в поле
usage, а для входа есть счётчик токенов у провайдера). - Возьмите средние и умножьте на число страниц.
- Добавьте запас на повторы и перепроверку: 10–20% — мой практический ориентир, а не измерение.
Условный пример (числа не из моих замеров): пять пробных страниц израсходовали в среднем 4 000 входных и 3 000 выходных токенов. Для 300 страниц это 1,2 млн входных и 0,9 млн выходных токенов, с запасом 15% — около 1,38 млн и 1,04 млн. Подставьте цены своей модели и получите бюджет. Модель влияет и на результат: Opus находит больше фактов, Sonnet точнее (таблица выше), поэтому дороже не значит нужнее. Заложите также время человека: проверка 20 случайных триплетов на каждую важную страницу и эталон для массового показателя стоят часов работы, а не только токенов.
Какой способ выбрать под задачу
Одна коммерческая страница
- Способ
- Рабочий промпт; для 5–10 важных страниц подойдёт ручная таблица.
- Результат
- Список утверждений с цитатами и условиями.
- Контроль
- Каждую запись сверить вручную.
Несколько конкурентов
- Способ
- Рабочий промпт для каждой страницы, затем свести ответы по одинаковым вопросам в общую таблицу.
- Результат
- Таблица вопросов и ответов по каждому сайту.
- Контроль
- Сопоставимость предложений и отсутствие придуманных сведений.
Массовые показатели
- Способ
- После пилота выбрать инструмент и запускать пакетно; качество сначала проверить вручную на выборке.
- Результат
- Сопоставимые показатели по набору страниц.
- Контроль
- Точность, полнота, различия между группами и пропуски.
Общие и уникальные утверждения
- Способ
- Сначала извлечь записи, затем сверять совпадения вручную; для небольшого набора — сразу сравнить цитаты.
- Результат
- Список подтверждённых совпадений и различий.
- Контроль
- Автоматическое сопоставление в исследовании не подтвердилось; его качество оценивайте отдельно.
Это предлагаемая организация работы, а не результат сравнительного теста.
Что показали два разных теста
Сначала каждый способ получил 400 отдельных предложений. Затем рабочий промпт Sonnet и скрипт проверили на фрагментах: первых 700 слов каждой из 30 страниц вместе с заголовками. Это другой тест с иным контекстом; его проценты нельзя напрямую сравнивать с результатом на отдельных предложениях.
На предложениях Sonnet точнее, Opus полнее
Точность — доля полностью верных триплетов. Полнота — доля найденных фактов из заранее составленного списка из 646 фактов. Это разные показатели с разными знаменателями.
Строгая точность
- Sonnet 5.590,2% 87,1–93,2
- Opus82,8% 79,3–86,0
- Скрипт32,4% 26,3–39,3
Полнота по 646 эталонным фактам
- Sonnet 5.573,4% 69,0–77,5
- Opus92,9% 90,5–95,1
- Скрипт16,9% 13,5–20,7
оценка 95% доверительный интервал
Практический выбор. Для карты фактов конкурента важнее полнота: в этом тесте Opus нашёл 92,9% эталонных фактов, но его строгая точность — 82,8%. Для короткого списка кандидатов в ТЗ Sonnet дал более высокую строгую точность — 90,2%, но нашёл 73,4% фактов. Скрипт можно использовать как бесплатный черновик: строго верны 32,4% результатов, а доля найденных фактов — 16,9%. Любой вариант требует сверки с цитатой.
Два способа дали 2 604 уникальных триплета; во фрагментах страниц каждый пятый триплет Sonnet — «не факт»
От 30 случайных страниц взяли первые 700 слов с заголовками. Полосы показывают состав выданных триплетов; каждый тип оценки подписан и приведён числом.
- Полностью верно
- Частично
- Неверно
- Не факт
Sonnet + рабочий промпт
1 850 триплетов · 9,5 на 100 слов- Полностью верно
- 1 235 · 66,8%
- Частично
- 214 · 11,6%
- Неверно
- 14 · 0,8%
- Не факт
- 387 · 20,9%
Строгая точность: 66,8% (95% интервал 58,3–75,4); полностью или приблизительно верно — 78,3%.
Скрипт page_to_csv
774 триплета · 4,0 на 100 слов- Полностью верно
- 283 · 36,6%
- Частично
- 232 · 30,0%
- Неверно
- 220 · 28,4%
- Не факт
- 39 · 5,0%
Строгая точность: 36,6% (95% интервал 30,9–42,2); полностью или приблизительно верно — 66,5%.
Это отдельная проверка первых 700 слов, а не полного содержимого страниц. Для работы используйте её как предупреждение о служебных фрагментах, не как универсальный процент точности на сайте.
Показать методику проверки, таблицы и найденные дефекты скрипта
Проверка рабочего промпта и скрипта на тех же 400 предложениях
Рабочий промпт из этой статьи проверен отдельно от тестовой инструкции. Sonnet 5.5, Opus и исправленный скрипт получили одни и те же 400 предложений, каждое без заголовка и соседнего текста.
Claude Sonnet проверил триплеты вслепую: он не знал, какой способ выдал строку. Codex независимо перепроверил 240 из 1456 триплетов. В 76 случаях из 100 оценки совпали; коэффициент согласия с поправкой на случайные совпадения равен 0,52, то есть согласие умеренное. На этой подвыборке строго верны 90% триплетов Sonnet, 86% Opus и 38% скрипта; у первого судьи — 93%, 87% и 32% соответственно.
| Способ | Триплетов на предложение | Предложений без триплета | Строго верных триплетов | Верных или приблизительно верных | Полнота по эталонным фактам, строго |
|---|---|---|---|---|---|
| Sonnet 5.5, рабочий промпт | 1,10 | 100 | 90,2% (87,1–93,2) | 97,5% | 73,4% (69,0–77,5) |
| Opus, рабочий промпт | 1,89 | 36 | 82,8% (79,3–86,0) | 95,9% | 92,9% (90,5–95,1) |
| Скрипт page_to_csv | 0,94 | 221 | 32,4% (26,3–39,3) | 56,8% | 16,9% (13,5–20,7) |
Полнота показывает, сколько из 646 заранее составленных фактов нашёл каждый способ; это оценивал Opus. Диапазоны погрешности рассчитаны на случайных подвыборках предложений (бутстреп). Точность оценивал Sonnet, в том числе у самого Sonnet: независимая перепроверка дала близкие цифры, но возможную поблажку к собственным ответам полностью не исключает.
Те же способы на фрагментах 30 страниц, до 700 слов
Чтобы проверить работу на реальной странице, я случайно выбрал 30 страниц. От каждой взял первые 700 слов вместе с заголовками. Один и тот же текст получили Sonnet с рабочим промптом и скрипт. Sonnet выдал 1 850 триплетов, скрипт — 774; после объединения результатов и удаления дублей осталось 2 604 уникальных триплета. Затем Sonnet-судья оценил их вслепую, не зная, какой способ выдал каждую запись.
Скрипт: 774 триплета, или 4,0 на 100 слов. Полностью верны 36,6% (30,9–42,2%), полностью или приблизительно — 66,5%.
Sonnet: 1850 триплетов, или 9,5 на 100 слов. Полностью верны 66,8% (58,3–75,4%), полностью или приблизительно — 78,3%. Неверных триплетов у модели всего 14. Ещё 387 строк (21%) взяты из навигации, призывов и обрывков, где нет проверяемого факта.
В тесте первых 700 слов 30 страниц строгая точность Sonnet составила 66,8% (58,3–75,4%), а в отдельном тесте предложений — 90,2%. Условия тестов различались, поэтому это сравнение не устанавливает причину разницы. При этом 387 из 1850 строк Sonnet (21%) на фрагментах страниц были оценены как «не факт» — навигация, призывы или обрывки. Перед переносом в ТЗ такие строки нужно отсеивать.
Что из этого следует. На этих предложениях рабочий промпт почти втрое точнее скрипта и находит в 4–5,5 раза больше эталонных фактов.
Sonnet точнее, но находит меньше: 73% эталонных фактов против 93% у Opus. Opus при этом выписывает почти вдвое больше триплетов. Разница точности 90% против 83% не окончательная: диапазоны почти соприкасаются, а судья Sonnet мог быть мягче к собственным ответам.
Для карты фактов конкурента важнее полнота. Для готовых формулировок в ТЗ важнее точность и ручная сверка. Скрипт подходит как бесплатный черновик, но не как источник окончательных выводов.
При прогоне найдены и исправлены два дефекта скрипта. Первый: на одном предложении функция сборки поддерева уходила в цикл (добавлена проверка «уже посещено»). Второй: на длинных строках сборка поддерева работала за квадратичное время, и страница на 15 887 слов обрабатывалась 611 секунд; после замены перебора словарём детей той же страницы хватает 4,5 секунд. На 400 предложениях вывод до и после исправления совпал побайтно. Опубликована исправленная версия.
Что показал тест четырёх способов
Строгая точность — оценённая доля полностью корректных триплетов среди выданных системой на этом наборе: у моих правил на Natasha 26%, у Claude Haiku 70%, у Sonnet 83%, у Opus 89%. Это не значит, что система достала 89% информации с любой страницы, и не подтверждает истинность заявлений компании. Результат даёт основание включить Sonnet или Opus в локальную проверку на ваших данных, но не заменяет её. Оценку выставляла модель того же семейства; второй судья из другого семейства (Codex) дал близкие цифры при умеренном согласии, поэтому абсолютные значения могут быть завышены.
Один режим работы не должен подменять другой: человеку, разбирающему одну страницу, не нужен эталон на 500 триплетов; тому, кто собирает массовый отчёт, не хватит проверки трёх удачных примеров.
Контрольный список
- Сохраните контекст
Заголовки, границы блоков, таблицы и подписи под кнопками должны попасть в текст, который вы отдаёте модели или скрипту.
- Просите условия отдельной колонкой
Так потеря условия видна сразу.
- Проверьте 20 случайных триплетов
Если «верно» не больше 14 из 20 (шесть и более триплетов неточны), меняйте промпт или модель.
- Отделите проблему текста от ошибки обработки
Не правьте страницу, пока не проверили исходник.
- Не переносите чужие значения
Переносите вопрос: «как у вас устроена оплата?».
- Не ставьте автоподсчёт в KPI
Для массовых показателей сначала измерьте точность на выборке.
Исследование под капотом
Откуда взяты цифры про точность способов: 400 предложений, четыре способа, слепая оценка, проверка вторым судьёй, типичные ошибки, шесть шагов от страницы до триплета и литература. Раскройте, если нужны методика и доказательства.
Показать исследование: методика, результаты, ошибки, литература
Как я сравнивал способы на 400 предложениях
Ниже: кто участвовал, как оценивалась точность и что получилось. Данные проверены языковой моделью-судьёй, часть триплетов — вторым судьёй.
Кто участвует: четыре способа в двух словах
- Natasha — бесплатная библиотека на Python. Она разбирает русское предложение по грамматике: находит части речи и определяет, какое слово от какого зависит. Поверх неё я написал свой набор правил: найти глагол, подлежащее и дополнение и записать их тройкой, плюс шаблоны «X — это Y» и «у нас есть X». Смысл такой способ не «понимает», он работает по грамматике. Так я извлёк 1 000 358 триплетов в исследовании про позиции.
- Младшая из трёх моделей Claude (нейросеть Anthropic). Читает предложение и сама выписывает факты по инструкции.
- Та же задача и та же инструкция, модель мощнее.
- Старшая из трёх. Она же составила список эталонных фактов для проверки полноты (об этом ниже).
Я взял 400 случайных предложений с читаемых страниц выдачи Google (по 200 из топ-20 и из позиций 21–50, с 390 различных хостов; поддомены считаются отдельно). Отбор был такой: русский текст (доля кириллицы не меньше 80% букв), длина 6–45 слов, начинается с заглавной буквы и заканчивается знаком конца предложения, цифр меньше 20% символов, без таблиц и ссылок, страница не короче 100 слов; запросы пилота исключены. Отбор не зависел от того, нашли ли правила триплет, поэтому можно оценить и полноту.
Четыре системы получили одни предложения. Правила Natasha работали без изменений. Три модели Claude (Haiku 4.5, Sonnet 5.5 и Opus) получили одну инструкцию без примеров: извлекай только то, что явно сказано; отрицание сохраняй; числа, единицы и условия оставляй в триплете; одно утверждение — одна тройка; если утверждения нет, верни строку с дефисами. Opus вызывался по плавающему имени «opus», поэтому точную версию выбирал поставщик.
Все триплеты (1505 уникальных после склейки дублей) я перемешал и отдал на слепую оценку: судья не знал, какая система дала триплет. Метки четыре:
| Метка | Что значит | Иллюстрация (придуманный пример) |
|---|---|---|
| CORRECT | Субъект, связь и объект точно передают смысл, отрицание сохранено | «Доставка бесплатна при заказе от 5000 рублей» → «доставка — быть бесплатной — при заказе от 5000 рублей» |
| PARTIAL | Суть верна, но объект обрезан или потеряно уточнение | → «доставка — быть бесплатной — при заказе» |
| WRONG | Смысл искажён: роли перепутаны, потеряно или добавлено отрицание | → «заказ — быть бесплатным — доставка» |
| NOTFACT | В предложении нет проверяемого утверждения | «Оставьте заявку на сайте!» (призыв) |
Строгая точность — доля триплетов с меткой CORRECT, мягкая — доля CORRECT и PARTIAL. Полноту я мерил отдельно. Claude Opus составил список из 646 простых фактов в 366 предложениях; каждый такой факт нельзя без потери смысла разделить ещё мельче. В 34 предложениях утверждений не было. Другой запуск Opus отметил, нашла ли каждая система каждый факт: полностью (Y), частично (P) или нет (N). Строгая полнота — доля Y, мягкая — Y и P.
Результаты
Яркая полоса — строгая оценка, бледная — мягкая. Чем длиннее полоса, тем лучше.
Точность: какая доля триплетов верна
Полнота: какая доля фактов найдена
Мои правила на Natasha
178 триплетов · в 281 предложении триплетов нет (70%)
- Точность, строго
- 26%20–34%
- Точность, мягко
- 76%67–84%
- Полнота, строго
- 5%4–7%
- Полнота, мягко
- 18%15–22%
Claude Haiku 4.5
474 триплета · без триплетов 32 предложения (8%)
- Точность, строго
- 70%65–74%
- Точность, мягко
- 93%90–95%
- Полнота, строго
- 24%20–28%
- Полнота, мягко
- 71%67–75%
Claude Sonnet 5.5
447 триплетов · без триплетов 28 предложений (7%)
- Точность, строго
- 83%80–87%
- Точность, мягко
- 95%93–97%
- Полнота, строго
- 88%85–91%
- Полнота, мягко
- 93%90–95%
Claude Opus
537 триплетов · без триплетов 39 предложений (10%)
- Точность, строго
- 89%86–92%
- Точность, мягко
- 97%96–99%
- Полнота, строго
- 92%89–95%
- Полнота, мягко
- 94%92–96%
Под каждой цифрой указан диапазон погрешности: он рассчитан на 2000 случайных подвыборках предложений (бутстреп). Строгая точность — доля полностью верных триплетов (CORRECT), мягкая — доля полностью и приблизительно верных (CORRECT или PARTIAL). Если один триплет выдали несколько систем, его оценивали один раз и засчитывали каждой системе. Полнота считается по всем 646 эталонным фактам; частично найденный факт при мягком подсчёте считается найденным.
Правила находят мало, и верна из найденного лишь четверть. Триплеты нашлись в 30% предложений, и из 178 триплетов полностью верен примерно каждый четвёртый.
Haiku находит много, но поверхностно. Хотя бы частично он покрывает 71% фактов, а полностью — только 24%: чаще всего факт засчитан лишь частично.
Sonnet и Opus различаются мало. Различие между ними этим тестом не установлено.
Доля предложений без триплетов — не оценка качества. В 34 предложениях из 400 утверждений нет, и пустой ответ там правилен.
Инструкция, которую получили модели
Показать архивную инструкцию теста (восстановленная редакция)
Архив, не рабочий промпт. В тестовом TSV были только поля «id», «субъект», «связь» и «объект»; условие оставалось внутри объекта или связи. Для аудита используйте рабочий формат выше: отдельные колонки «Условие» и «Цитата».
Для каждого предложения извлеки утверждения в виде троек.
Определение. Триплет — запись утверждения в форме «субъект → связь (предикат) → объект». Связь может обозначать действие, свойство или отношение; объектом может быть другая сущность или значение. Условие не входит в классическую тройку. В этой тестовой инструкции его сохраняли внутри объекта или связи; отдельная колонка «Условие» есть в рабочем формате аудита выше.
- Извлекай только то, что явно сказано в предложении. Ничего не додумывай и не добавляй из своих знаний.
- Отрицание сохраняй в связи («не X»). Числа, единицы измерения, условия («если…», «от…», «при…») оставляй в объекте или в связи.
- Одно утверждение — одна тройка. Составное утверждение разложи на несколько троек, если в нём несколько самостоятельных фактов.
- Если в предложении нет проверяемого утверждения (вопрос, призыв, заголовок, обрывок), не выдумывай тройку: напиши для него одну строку с дефисами вместо субъекта, связи и объекта.
- Язык троек — русский, слова из предложения, связь в начальной форме глагола.
Формат ответа. Файл с табуляциями: id, субъект, связь, объект; первая строка заголовок; для одного предложения может быть несколько строк. Каждый id должен встретиться хотя бы один раз.
Чему можно верить в этих оценках
Разметку делали модели двух семейств (Claude и Codex). Основной судья точности — Claude Sonnet — оценивал в том числе триплеты самого Sonnet, а список фактов для полноты составил Opus, который тоже участвует в сравнении. Три из четырёх участников принадлежат одному семейству. Исследование судей-моделей отмечает смещение в пользу собственных ответов [16].
Часть оценок повторил Codex от OpenAI. На 246 триплетах правил, Sonnet и Opus он совпал с основным судьёй в 79% случаев. Коэффициент согласия с поправкой на случайные совпадения равен 0,57: согласие неполное. Порядок «правила хуже Sonnet, Sonnet хуже Opus» при этом сохранился.
На 80 триплетах Haiku судьи разошлись сильнее: коэффициент согласия 0,27. Codex оценил строгую точность Haiku в 0,21, основной судья — в 0,58; мягкая точность ближе: 0,79 и 0,85. Поэтому точное число для Haiku зависит от судьи; надёжен только вывод, что по мягкой оценке Haiku лучше правил.
Полноту Codex подтвердил почти без расхождений: 60 предложений, 98 фактов, коэффициент согласия 0,94. Но он проверял уже готовый список фактов, а не составлял независимый список с нуля.
Ещё один контроль: 300 триплетов отложенной части эталона я перечитал отдельным проходом модели, не показывая ей прежних меток. Строгая точность получилась 32% против 41% у основного судьи, мягкая 75% против 78%, совпадение по четырём классам 76%, коэффициент согласия 0,64. Основной судья мягче на 9 пунктов по строгой границе. Оговорка: эти 300 триплетов принадлежат правилам из пилота, а не четырём системам теста, поэтому перенести разницу на строгие цифры Sonnet и Opus из таблицы выше напрямую нельзя. Она показывает, что строгая точность чувствительна к разметчику и основной судья мог её завысить; размер смещения для Sonnet и Opus здесь не установлен.
Как ломаются правила
Чтобы понять, что именно ломается, я проверил 3154 триплета с 2964 страниц пилота. Я взял примеры из каждой группы триплетов, включая редкие, а при итоговом подсчёте вернул группам их реальный вес. Такой отбор называется стратифицированным.
Полностью верны 44,6% триплетов; с учётом погрешности — от 42,1% до 47,4%. Полностью или приблизительно верны 79,2% (76,9–81,5%). В 6,5% случаев исходное предложение вообще не содержало проверяемого утверждения. У 1626 приблизительно верных или неверных триплетов причины ошибок такие:
Пример из основного набора страниц, со страницы КонсультантПлюс: из предложения «Если работник приступил к выполнению работ даже без заключения договора, это свидетельствует о возникновении трудовых отношений» правила получили «работник — приступить — к выполнению работ». Потеряно не только уточнение: исходник описывает условие, а триплет читается как сообщение о состоявшемся событии. По моим правилам оценки такой триплет был бы приблизительно верен, но использовать его как самостоятельный факт нельзя. Явная ошибка в том же предложении: два триплета с подлежащим «Проспект», слово из пометки перед предложением, которое разбор принял за подлежащее.
Обрезка бывает опасной
Иногда пропадает второстепенная подробность, а иногда условие, отрицание, возможность или указание, кто сделал заявление. Во втором случае триплет утверждает то, чего исходный текст не утверждал. Работа MinIE выделяет полярность, модальность, принадлежность утверждения источнику и количественные характеристики в отдельные аннотации [24]. Учебные примеры (придуманные, не из моих данных):
| Исходная фраза | Опасное упрощение | Что изменилось |
|---|---|---|
| «Доставка бесплатна при заказе от 5000 рублей» | «Доставка бесплатна» | Убрано условие |
| «Поставщик может увеличить срок» | «Поставщик увеличивает срок» | Возможность превратилась в действие |
| «Производитель заявляет о ресурсе 10 лет» | «Ресурс составляет 10 лет» | Потеряна принадлежность заявления |
Мягкая точность поэтому — оценка по принятым правилам, а не гарантия, что триплет можно использовать как самостоятельный факт.
Точность зависит и от типа объекта. Триплеты с условиями («если», «не менее», «при заказе») строго верны в 13% случаев, верны или приблизительно верны в 68%. С ценами строго 39%, верно или приблизительно 82%. Поэтому «цена» и «срок» на таком извлечении приблизительные признаки, а «условие» для анализа непригодно.
От страницы до триплета: шесть шагов
- Получить страницу
Часть сайтов вместо содержимого отдаёт заглушку или проверку на бота. При обычном запросе у меня не читалась треть позиций. Непрочитанная страница — пропуск, а не страница без фактов.
- Выделить основной текст
Надо отбросить меню, подвал и рекламу. Я использовал библиотеку trafilatura. Цифры F1 (одна цифра, сводящая полноту и точность вырезания текста) из трёх источников нельзя ставить в один ряд: наборы и метрики разные.
Качество выделения основного текста у trafilatura Источник Набор F1 Автор библиотеки [6] собственный тестовый набор 0,912 Независимое сравнение [7] наборы, ориентированные в основном на английский 0,883 в среднем Многоязычная проверка 2025 года [8] русские новости 0,759 (точность 0,729, полнота 0,856) В той же проверке хотя бы одна из трёх программ получила F1 не выше 0,3 на 51% русских страниц [8]. F1 сводит в одно число две ошибки: сколько нужного текста программа потеряла и сколько лишнего захватила. Значение 0,3 означает слабый результат.
На моих 300 случайных страницах из 16 ниш Trafilatura обычно сохраняет 53% слов, видимых на странице. У 10% страниц остаётся не больше 15% слов, у 10% — не меньше 82%. По нишам типичное значение меняется от 34% у стройматериалов и товаров для дома до 69% у IT-услуг. Но оставшаяся разница смешивает меню, подвалы и формы с возможной потерей основного текста, поэтому эти проценты нельзя считать точностью.
- Разбить на предложения
Тестовый набор нарезан по знакам конца предложения («.!?…»). Абзац без точки на конце сливается со следующим, и такие склейки в наборе возможны; на правила они влияют сильнее, чем на модели. В основной цепочке исследования переводы строк заменены на точки, и абзацы разделены.
- Синтаксический разбор
Определение, какое слово от какого зависит. Natasha использует модель Slovnet, обученную на новостях. Качество разбора по таблице проекта (LAS, доля слов, у которых верно найден и родитель, и тип связи) падает от новостей к поэзии [9]. Страниц сайтов в таблице нет, собственных измерений на них у меня тоже нет.
Новости0,880Википедия0,718Тексты из соцсетей0,656Поэзия0,469Авторы проекта предупреждают, что модели настроены на новости [9].
- Правила или модель
Мои правила ищут глагол с подлежащим и дополнением, конструкции «X — это Y» и «у нас есть X» и записывают тройку. Ошибки ниже — ошибки этих правил, а не самой библиотеки. Другой путь — попросить языковую модель выписать утверждения. Что известно об обоих подходах, в разделе про литературу ниже.
- Привести слова к начальной форме
Глагол-связку приводят к начальной форме («списывается» → «списываться»), «не» сохраняют, а числа и единицы оставляют в части «с чем». В этой простой схеме объект собирается из зависимых слов предложения без фиксированного лимита по длине. Придаточное условие отдельно не извлекается, поэтому его нужно сверить с исходной цитатой и вынести в колонку «Условие».
Можно ли сопоставлять факты между страницами
Если триплеты работают как проверяемые факты, их можно сравнивать между страницами и искать общие и уникальные. Я пробовал три способа, и в проверенной конфигурации измеримого сигнала они не дали.
- Совпадение начальных форм слов субъекта, связи и объекта нашлось у 2,1% сочетаний хотя бы на двух сайтах (пилот, 100 запросов).
- Во втором способе модель e5 превращала фразу в числовой «отпечаток смысла». Я вручную разметил вслепую 450 пар с разной степенью сходства. Способ нашёл только 11–13 пар с одним и тем же утверждением. Пары заранее выбирались по уровню сходства отпечатков, поэтому эту долю нельзя переносить на весь набор текстов.
- Сравнение целых предложений при строгом пороге близости нашло подтверждение тремя другими сайтами у 0,036% предложений (200 контрольных запросов). Критерий качества при настройке был выполнен на 29 размеченных парах (доля подтверждённых 0,69, интервал 0,52–0,85), но сам сигнал почти пуст: различать им страницы нечем.
В прочитанной аннотации отчёта по e5 [17] нет проверки, различает ли эта числовая мера сходства пересказ одного факта и разные факты на русском. Поэтому границу «это один и тот же факт» нужно подбирать на собственных примерах, проверенных вручную. Подробнее о том, как это сказалось на исследовании позиций, в соседней статье.
Что известно из литературы и чего в ней нет
Часть источников ниже я прочитал целиком, у части открыл только аннотацию; это помечено в списке ссылок.
- О языковых моделях: ChatGPT показал слабые результаты в стандартном извлечении, но сильные в открытом по оценке людей, и был излишне уверен в ответах [12]; GPT-4 заметно отставал от лучших специализированных методов [13] (обе оценки по аннотациям). Похожую на мои правила идею ограничений над синтаксисом использует ReVerb [10]; создатели Stanford OpenIE называли большие наборы шаблонов хрупкими на текстах вне домена и заменили их классификатором самостоятельных клауз (клауза — часть сложного предложения со своим сказуемым) [11].
- Единого стандарта оценки у задачи нет. Авторы английского эталона 2016 года писали, что формального определения и большого набора для проверки не было, а оценки делались на малых ручных выборках [2]. Следующая работа нашла шум в самом эталоне, а на одной паре систем порядок по старому эталону оказался обратным порядку по новому [3]. BenchIE показал, что эталоны неполны: в них нет всех допустимых формулировок одного факта [4]. Ручная проверка «верно или неверно» на выборке остаётся распространённой практикой [5]. Моя схема продолжает её, добавляя четыре метки.
- Русского тестового набора Open IE я не нашёл (граница моего поиска, не доказательство отсутствия). Русские наборы FactRuEval [18], NEREL [19] и RuREBus [20] размечены под заранее заданные типы сущностей и отношений; на RuREBus лучшая система показала 0,44 по извлечению отношений [20]. Многоязычные OIE-работы, которые я открыл, русский не включают [21].
- Рецензируемой статьи о Natasha и Slovnet я не нашёл, есть README проекта; его авторы пишут, что Natasha — не исследовательский проект [9].
- Работ, где на веб-страницах целиком проверена цепочка «загрузить страницу → выделить основной текст → разобрать предложение → получить триплет», я не нашёл. Программы выделения текста обычно проверяют по совпадению текста, а не по тому, как их ошибки меняют итоговые триплеты.
- Стандартной шкалы «частично верно» и «не факт» в прочитанной литературе нет.
- Публичного подтверждения, что поисковики ранжируют страницы по числу триплетов, я не нашёл. Google пишет, что не раскрывает деталей ранжирования, чтобы их нельзя было использовать для манипуляций [22]. Исследования Google по извлечению и проверке фактов (Knowledge Vault, Knowledge-Based Trust) публиковались как научные работы; применение их в поиске в аннотациях, которые я открыл, не показано [23].
Как проверялись рабочий промпт, скрипт и правило 20 триплетов
Рабочий промпт. Текст из этой статьи без изменений; 400 предложений из основного теста подавались пакетами по 40, каждое как отдельный фрагмент без заголовка и соседних предложений (колонка «Контекст» — «—»). Один прогон Sonnet 5.5 и один Opus (версия Opus не зафиксирована). Условие, если оно было, дописывалось к объекту при оценке.
Скрипт. Функция page_to_rows из этой статьи (без загрузки страницы), предложения подавались по одному. Триплетами считались только строки с субъектом.
Фрагменты страниц. Я случайно выбрал 30 страниц основного замера длиной 300–1500 слов и взял первые 700 слов каждой вместе с заголовками. Рабочий промпт Sonnet и скрипт получили один и тот же подготовленный фрагмент — целиком, но не всю исходную страницу. Sonnet выдал 1 850 триплетов, скрипт — 774; после объединения результатов и удаления дублей осталось 2 604 уникальных триплета. Их перемешали, чтобы проверяющий не знал источник, и оценили вслепую. Интервалы рассчитаны бутстрепом по страницам (2000 повторов).
Точность. Триплеты трёх систем объединили, дубли склеили: осталось 1456 разных строк. Их перемешали и скрыли источник. Sonnet присвоил каждой строке одну из четырёх меток: полностью верно (CORRECT), приблизительно верно (PARTIAL), неверно (WRONG) или исходное предложение не содержит факта (NOTFACT). Codex независимо проверил 240 триплетов — по 80 на систему; начальное число случайного отбора 20261012.
Полнота. Opus проверил, сколько из 646 эталонных фактов нашла каждая система; названия систем были заменены случайными буквами. Диапазоны погрешности рассчитаны на 2000 случайных подвыборках предложений. Важная оговорка: Sonnet оценивал в том числе триплеты самого Sonnet.
Правило 20 триплетов. Я 10 000 раз случайно брал по 20 уже размеченных триплетов, не повторяя один триплет внутри выборки. Правило браковало прогон, если полностью верными были 14 или меньше строк. Вероятности для разных уровней точности дополнительно посчитаны стандартной формулой для числа успехов в 20 независимых попытках (биномиальная модель). Это показывает поведение правила, а не точность конкретной страницы.
Время работы. Скрипт: типичное время — 0,2 секунды на страницу (12 случайных страниц), страница на 15 887 слов — 4,5 секунды. Языковая модель: пакет из 40 предложений Sonnet обрабатывал за 34–74 секунды, Opus за 42–107 секунд.
Как это считалось
Данные. 400 предложений из основного текста читаемых страниц выдачи Google (Москва, десктоп, 2 октября 2026), по 200 из топ-20 и из позиций 21–50, не больше одного на страницу, с 390 различных хостов (поддомены считаются отдельно). Длина 6–45 слов, доля кириллицы не менее 80% букв, цифр меньше 20% символов, начинается с заглавной буквы и заканчивается знаком конца предложения, без таблиц, ссылок и разметки; пилотные запросы исключены. Хеш списка предложений: 9db0914c957c0ffc….
Системы. Мои правила поверх Natasha без изменений. Модели Claude Haiku 4.5, Sonnet 5.5 и Opus получили одну инструкцию без примеров. Итоговый прогон Haiku повторён с теми же правилами извлечения, но с дополнительной колонкой начала предложения (по ней код проверяет, что ответ относится к этому предложению): в первом прогоне нумерация у Haiku сдвигалась. Sonnet и Opus отвечали по базовой инструкции.
Точность. Все триплеты (1505 уникальных после склейки дублей) перемешаны, источник судье не показывался. Метки ставил Claude Sonnet; для триплетов, общих с другими системами, метки засчитывались каждой из них. Проверка судьёй другого семейства: Codex на 246 триплетах правил, Sonnet и Opus и на 80 триплетах Haiku.
Полнота. Claude Opus составил эталонный список из 646 простых фактов, каждый из которых нельзя без потери смысла разделить ещё мельче; они встретились в 366 предложениях. Другой запуск Opus отметил, нашла ли каждый факт каждая из четырёх систем со скрытыми названиями: полностью (Y), частично (P) или нет (N). Повторная оценка полноты для правил, Sonnet и Opus совпала с первой в 98,3% ячеек. Проверка Codex: 60 предложений, 98 фактов. Список фактов — тоже работа модели, и независимость его от участников сравнения проверкой Codex не доказана.
Диапазоны погрешности. Я 2000 раз пересчитывал результат на случайных подвыборках предложений. Такой способ называется бутстрепом.
Данные и код. Тексты инструкций судьям и данные планирую приложить к препринту на Zenodo; сейчас они не опубликованы. Инструкция теста приведена в разделе «Исследование под капотом» в близкой к исходной редакции.
Список ссылок
Ссылки открыты 3 октября 2026. Для источников [12], [13], [15], [16], [17], [19], [23], [24], [25] прочитаны только аннотации, у Cohen сверены только метаданные.
- Banko M., Cafarella M., Soderland S., Broadhead M., Etzioni O. Open Information Extraction from the Web. IJCAI 2007. ijcai.org
- Stanovsky G., Dagan I. Creating a Large Benchmark for Open Information Extraction. EMNLP 2016. aclanthology.org/D16-1252
- Bhardwaj S., Aggarwal S., Mausam. CaRB: A Crowdsourced Benchmark for Open IE. EMNLP-IJCNLP 2019. aclanthology.org/D19-1651
- Gashteovski K., Yu M., Kotnis B., Lawrence C., Niepert M., Glavaš G. BenchIE. ACL 2022. aclanthology.org/2022.acl-long.307
- Lechelle W., Gotti F., Langlais P. WiRe57: A Fine-Grained Benchmark for Open Information Extraction. LAW 2019. aclanthology.org/W19-4002
- Barbaresi A. Trafilatura. ACL-IJCNLP 2021 (demo). aclanthology.org/2021.acl-demo.15
- Bevendorff J., Gupta S., Kiesel J., Stein B. An Empirical Comparison of Web Content Extraction Algorithms. SIGIR 2023. doi.org/10.1145/3539618.3591920
- Bournonville и др. Multilingual Evaluation of Main Content Extractors for Web Pages. SIGIR 2025. doi.org/10.1145/3726302.3730234
- Проект Natasha: README natasha и slovnet (раздел Evaluation). github.com/natasha/natasha; github.com/natasha/slovnet
- Fader A., Soderland S., Etzioni O. Identifying Relations for Open Information Extraction (ReVerb). EMNLP 2011. aclanthology.org/D11-1142
- Angeli G., Johnson Premkumar M., Manning C. Leveraging Linguistic Structure For Open Domain Information Extraction. ACL-IJCNLP 2015. aclanthology.org/P15-1034
- Li и др. Evaluating ChatGPT's Information Extraction Capabilities. arXiv 2304.11633 (аннотация). arxiv.org/abs/2304.11633
- Han и др. An Empirical Study on Information Extraction using Large Language Models. arXiv 2305.14450 (аннотация). arxiv.org/abs/2305.14450
- McHugh M. L. Interrater reliability: the kappa statistic. Biochemia Medica 22(3), 2012. pmc.ncbi.nlm.nih.gov/articles/PMC3900052. Оригинал коэффициента: Cohen J., Educational and Psychological Measurement 20(1), 1960, doi.org/10.1177/001316446002000104 (сверены только метаданные)
- Efron B. Bootstrap Methods: Another Look at the Jackknife. Annals of Statistics 7(1), 1979 (аннотация). doi.org/10.1214/aos/1176344552
- Zheng и др. Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena. arXiv 2306.05685 (аннотация). arxiv.org/abs/2306.05685
- Wang и др. Multilingual E5 Text Embeddings: A Technical Report. arXiv 2402.05672 (аннотация). arxiv.org/abs/2402.05672
- Starostin и др. FactRuEval 2016. Dialogue 2016. dialogue-conf.org
- Loukachevitch и др. NEREL: A Russian Dataset with Nested Named Entities, Relations and Events. arXiv 2108.13112 (аннотация). arxiv.org/abs/2108.13112
- Ivanin и др. RuREBus-2020 Shared Task. Dialogue 2020. dialogue-conf.org
- Kolluru и др. Alignment-Augmented Consistent Translation for Multilingual Open Information Extraction. ACL 2022. aclanthology.org/2022.acl-long.179
- Google. How Search Works: Detecting Spam. google.com
- Dong и др. Knowledge Vault. KDD 2014 (аннотация), doi.org/10.1145/2623330.2623623; Knowledge-Based Trust. PVLDB 2015 (аннотация), doi.org/10.14778/2777598.2777603
- Gashteovski K., Gemulla R., Del Corro L. MinIE: Minimizing Facts in Open Information Extraction. EMNLP 2017 (аннотация). aclanthology.org/D17-1278
- Owen A. B., Eckles D. Bootstrapping data arrays of arbitrary order. Annals of Applied Statistics 6(3), 2012 (аннотация). arxiv.org/abs/1106.2125
Частые вопросы
Тремя способами: нейросеть с промптом (на 400 предложениях строго верны 90% триплетов у Sonnet и 83% у Opus, скрипт — 32%), скрипт на Python с библиотекой Natasha (бесплатно, грубо) и вручную в таблице (для 5–10 важных страниц). Во всех случаях просите условие отдельной колонкой и проверяйте 20 случайных триплетов как быструю проверку на глаз.
Только после проверки. В тесте на 400 предложениях полностью верны 83% триплетов у Sonnet и 89% у Opus (тестовая инструкция; с рабочим промптом 90% и 83%): примерно каждый шестой и каждый девятый триплет верен не полностью. Оценку выставляла модель из того же семейства, другой судья проверил часть триплетов, и его согласие неполное (коэффициент согласия 0,57 — совпадение оценок умеренное).
Сверить его с исходным предложением и контекстом страницы. Если исходный текст понятен, а триплет неверен, проблема в обработке: правят извлечение, а не страницу. Если текст действительно неоднозначен, правят содержание.
Для разбора одной страницы нет: 20 случайных триплетов — быстрая проверка на глаз, а в аудит и ТЗ попадают только триплеты, сверенные вручную. Для массового отчёта по сотням страниц нужен эталон 300–500 триплетов, измерение точности и проверка отдельно по группам.
Да, часто. На эталоне из страниц пилота строго верны 44,6% триплетов, верны или приблизительно верны 79,2%. На 400 случайных предложениях строгая точность 26%: выборки устроены по-разному. Эти цифры относятся только к моим правилам и страницам из 16 проверенных ниш.
Измерение не устанавливает причинную связь и не задаёт норматив. В основном контрасте топ-20 и позиций 21–50 оценка составила 51,03 из 100 (95% интервал 50,61–51,45); при сопоставлении страниц близкой длины — 50,32 (49,81–50,82), то есть интервал включает базу 50. Это слабая связь в конкретной выборке, а не доказательство фактора ранжирования. Триплеты здесь полезнее как способ сравнить утверждения конкурентов, сохранить условия и найти вопросы покупателя без ответа на своей странице.
Переписать каждую строку как «объект — столбец: значение». Это делает скрипт tables_to_facts.py: он берёт таблицы из HTML, печатает принятые заголовки столбцов (их нужно сверить с видимой таблицей) и по строке на объект. Объединённые ячейки скрипт не раскрывает, такие таблицы собирают вручную.
Используйте pages_to_csv_batch.py: он читает адреса из файла, пропускает повторы, собирает CSV и журнал, а уникальные URL с ошибкой повторяет один раз. Ошибка или пустой результат — это пропуск для ручной проверки, не доказательство отсутствия утверждений. Для массового показателя нужна отдельная проверка качества на 300–500 триплетах.
Зависит от числа страниц, длины текста и модели. На пробе из 5 страниц берут среднее число входных и выходных токенов на страницу, умножают каждое на соответствующую цену за миллион токенов, сумму делят на 1 000 000, затем умножают на число страниц и добавляют запас 10–20% на повторы. Цены проверяют у провайдера в день расчёта.
Разобрать утверждения вашей страницы и страниц конкурентов
Если нужна проверенная карта утверждений лидеров выдачи и ТЗ с блоком «Факты и условия», это SEO-аудит сайта. Результаты замера по позициям Google — в соседней статье.