TL;DR
PolyGraph — протокол для памяти, которую агент строит сам (граф знаний, сводки, выводы). Модель в том же вызове, где создаёт запись, выдаёт «расписку»: из каких источников эта запись следует. Расписка — это несколько альтернативных наборов источников, каждого из которых хватает одного. Когда источник отозван, остаётся вычеркнуть записи, у которых не осталось ни одного целого набора. Это простая арифметика над множествами, без новых обращений к модели. Расписки — самоотчёт модели, поэтому их проверяют: убирают указанные источники, показывают модели только оставшиеся и пять раз спрашивают, придёт ли она к той же записи.
Главная находка: расписке модели можно верить, только если она «по размеру» подходит под утверждение. Одно узкое утверждение («эти две записи — один и тот же человек») получает честную расписку. Сводка из нескольких предложений с одним общим списком источников — нет. Достаточно, чтобы один источник держал одно предложение, и расписка объявляет живой всю сводку, хотя остальные предложения остались без опоры. В таких случаях модель ошибалась примерно в двух третях случаев и почти всегда в одну сторону: оставляла мёртвое. Такая ошибка тихая, граф продолжает отдавать то, что больше ничем не подтверждено.
Лекарство простое: просить отдельную расписку на каждое предложение. Тогда расписки совпадали с проверкой в 88–100% случаев. Из почти всех затронутых сводок удалось сохранить живые предложения, вместо того чтобы выбрасывать сводку целиком. Отдельный вывод: перестроить граф с нуля и сравнить не работает. Модель сэмплирует, и два запуска на одном корпусе отличаются в пять раз сильнее, чем запуск с удалением отозванных документов.
Схема метода
ШАГ 1 (при создании записи, тот же вызов):
модель создаёт запись + расписку = {набор источников A, набор B, ...}
каждый набор достаточен сам по себе
УТВЕРЖДЕНИЕ УЗКОЕ → одна расписка на него
СВОДКА → разбить на предложения, расписка на КАЖДОЕ
ШАГ 2 (источник отозван):
запись жива, если остался хотя бы один набор без отозванных источников
→ чистка без обращений к модели
ШАГ 3 (аудит расписок, выборочно или на спорных):
убрать отозванные источники → показать модели только оставшиеся
→ «ты ранее пришла к выводу Z. Придёшь ли снова?» ×5, независимо
≥4 из 5 → жива · ≤1 из 5 → мертва · иначе → не определено
ШАГ 4: решение
узкие утверждения (слияния) → верим расписке
длинные сводки → чистим по предложениям или удаляем целиком
Шаги 1 и 3 — разные запросы. Шаг 2 в оригинале делает код, но вручную это делается и на небольшом объёме.
Пример применения
Задача: Вы ведёте базу знаний по рынку быстрой доставки. Агент собрал сводку про Самокат, Яндекс Лавку и Купер из 30 статей РБК, vc.ru, Forbes и Telegram-каналов. Потом выяснилось, что две статьи vc.ru, на которые опирается сводка, содержат выдуманные цифры и отозваны. Выбросить всю сводку жалко: большая часть подтверждена другими источниками. Оставить как есть нельзя: в ней могли остаться «зараженные» цифры.
Промпт (создание сводки с расписками):
Ты аналитик рынка. По источникам S1–S30 (ниже) напиши сводку про рынок
быстрой доставки в России: Самокат, Яндекс Лавка, Купер.
Правила:
1. Сводка — список коротких предложений. Одно предложение = одно проверяемое утверждение.
2. К КАЖДОМУ предложению дай собственную расписку: список альтернативных
наборов источников. Каждый набор должен быть достаточен сам по себе,
чтобы вывести это предложение. Не больше 4 наборов, самые маленькие.
3. Общий список источников на всю сводку не делай.
Формат:
[П1] Текст предложения
Расписка: {S3, S7} ИЛИ {S12}
[П2] ...
Источники:
{тексты_источников}
Промпт (аудит после отзыва S5 и S9, отдельный чат на каждую из 5 проб):
Ранее ты пришла к выводу: «{предложение_П4}».
Источники S5 и S9 признаны недостоверными и удалены.
Вот только оставшиеся источники: {оставшиеся_тексты}.
Сделала бы ты этот вывод, опираясь ТОЛЬКО на них?
Ответь «да» или «нет» и укажи, на что опираешься.
Результат: В первом запросе вы получите сводку из коротких предложений, у каждого своя расписка с альтернативными наборами источников. Во втором запросе модель в каждой из пяти проб ответит «да» или «нет» с обоснованием. Предложения, которые воспроизвелись минимум в 4 из 5 проб, остаются. Те, что не воспроизвелись, вычёркиваются. Спорные идут на ручную проверку. Вместо выбрасывания всей сводки вы убираете только мёртвые предложения.
Почему это работает
Слабость. Когда модель пишет длинную сводку и один общий список «на что опирается», этот список ничего не гарантирует. Достаточно, чтобы один набор источников держал одно предложение, и по правилам расписки живой считается вся сводка. Модель при этом не врёт специально: форма расписки не совпадает с формой утверждения. Пересобрать всё заново тоже не поможет: модель сэмплирует, и шум пересборки в пять раз больше сигнала.
Сильная сторона. Модель хорошо отвечает на узкие вопросы: «из этих двух абзацев следует вот это предложение?» Она также даёт стабильный ответ на повторную проверку, если спросить именно про одно утверждение.
Как метод это использует. Расписку нужно требовать в момент создания записи, пока модель «видит» опору. Задним числом её не восстановить. Расписка должна быть узкой, тогда она честная. Недоверие подкрепляется дешёвой проверкой: убрать источники и посмотреть, воспроизводится ли вывод.
Рычаги управления: - Размер единицы (предложение, абзац, вся сводка) → мельче: честнее расписки, но короче и суше тексты. Модель стала писать предложения по 7 слов вместо 16. - Число проб (5) и порог (≥4 из 5 — жива, ≤1 из 5 — мертва) → меньше проб дешевле, но больше «неопределённых». - Число альтернативных наборов (до 4–8) → меньше: проще проверять, но запись выглядит «мертвее», чем есть. Это безопасная ошибка. - Формулировка аудита → в статье модель показывали её же вывод. Скрытый вариант («вот кусок текста, один ли это человек?») сдвигал оценки слияний в неожиданную сторону, а оценки сводок не менял.
Шаблон промпта
Промпты авторов лежат в репозитории (ссылка в «Ресурсах»), в статье их нет. Шаблоны ниже собраны по описанию протокола.
1. Создание записи с расписками:
Ты составитель выводов. Каждое утверждение, которое ты пишешь,
ты обязана подкрепить распиской.
- Один пункт = одно узкое проверяемое утверждение.
- К каждому пункту: Receipt = список альтернативных наборов источников.
- Каждый набор достаточен сам по себе, чтобы вывести пункт без остальных.
- Не больше {макс_наборов} наборов, выбирай самые маленькие.
- Общую расписку «на весь текст» не пиши.
{источники}
{задача}
2. Аудит перегенерацией (отдельный чат на каждую пробу):
Ранее ты пришла к выводу: «{пункт}».
Из материалов удалено: {отозванные_источники}.
Вот только то, что осталось: {оставшиеся_источники}.
Пришла бы ты к этому выводу, опираясь только на оставшееся?
Ответь «да» или «нет» и укажи, на какие источники опираешься.
3. Правило решения:
Проб: {число_проб, обычно 5}.
«Да» в {≥80% проб} → пункт жив.
«Да» в {≤20% проб} → пункт мёртв, убрать.
Иначе → не определено, проверить вручную.
Что подставлять: {источники} — тексты с идентификаторами S1…Sn; {задача} — что нужно написать; {отозванные_источники} — какие ID убраны; {пункт} — одно утверждение из сводки.
🚀 Быстрый старт — вставь в чат:
Вот шаблон «расписки + аудит перегенерацией». Адаптируй под мою задачу:
{твоя задача}. Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит, из каких источников собирается вывод, какого размера утверждения ты хочешь (предложение, абзац) и сколько проб нужно. Размер единицы определяет, насколько честными будут расписки. Число проб определяет цену проверки.
Ограничения
⚠️ Проверяется «воспроизведёт ли модель», а не «правда ли это»: аудит измеряет, придёт ли та же модель к тому же выводу из оставшегося. Если модель достроит недостающее из собственной памяти, запись будет «живой», хотя в источниках опоры нет. Для требований вроде «право на удаление» этого мало.
⚠️ Узкие утверждения дороже по объёму: расписки по предложению честные, но сводки становятся короче и суше. Нужна ли вам такая сводка читателю, статья не проверяла.
⚠️ Полная версия требует кода: автоматическая чистка графа с тысячами записей и арифметика по расписками — инженерная работа. В чате это работает вручную для небольших сводок и баз.
⚠️ Малые выборки по ячейкам: на реальной отзывке затронутые слияния и сводки считались десятками. Авторы добавили псевдослучайные удаления и другие модели, но результат всё равно сильнее держится в основных выводах, чем в точных процентах.
⚠️ Нужна расписка с самого начала: если записи созданы без расписок, задним числом их не восстановить: пересборка шумит, как показано в статье.
⚠️ Слияния сложнее проверять «вслепую»: когда вопрос задавали без показа вывода модели, она чаще признавала слияния живыми, опираясь на то, как выглядят имена и что она уже знает.
Как исследовали
Автор взял 300 аннотаций из PubMed по онкологии, из которых 61 реально отозвана. Модель Claude Sonnet построила из них граф: извлечённые факты, слияния сущностей, выведенные связи (в сумме около 24 тысяч записей) и сводки по сообществам. Обычная очистка удаляла только непосредственно извлечённые факты и снижала долю «зараженных» запросов лишь с 32% до 28%. Пересборка с нуля оказалась бесполезной: два запуска на одном корпусе расходятся в 29 475 записях, а удаление 61 документа меняет только 6 248. Сигнал тонет в шуме в пять раз.
Дальше проверяли расписки. Для каждой затронутой удалением записи убирали указанные источники и пять раз просили модель воспроизвести вывод. Слияния совпали с проверкой в 68% и 85% случаев, а сводки в 33% и 36%, причём почти все ошибки состояли в том, что мёртвое оставляли живым. Автор проверил причину: при расписке на каждое предложение совпадение выросло до 100% и 88%, а из 35 затронутых сводок удалось сохранить живые предложения в 33. Удивило то, что причина оказалась в форме расписки, а не в слабости модели. Результат устоял на другой модели-проверяющей (Opus), на проверочном промпте без показа вывода, на десяти случайных удалениях, на 150 решениях Верховного суда США и на другом строителе графа. В итоге недоверие к слою сводок снизило долю «зараженных» запросов до 0,4% и 0,8% при сохранении 99,8–100% полезных ответов.
Адаптации и экстраполяции
🔧 Техника: расписка на предложение в обычных отчётах → быстрая чистка при отзыве источника
Не нужен граф: попросите модель в любом исследовательском отчёте писать «пункт + расписка» построчно. Если позже выяснится, что источник ненадёжен, вычеркнуть нужно только те пункты, у которых не осталось ни одного набора без этого источника.
После каждого предложения в скобках укажи, какие источники S достаточны для него по отдельности (варианты через «ИЛИ»).
🔧 Техника: аудит «вслепую» → защита от подтверждения собственного вывода
В статье модели показывали её же прежний вывод. Если боитесь, что это подталкивает к «да», задайте открытый вопрос без вывода и сравните. Но имейте в виду: по слияниям такой вариант давал другие, не лучшие ошибки.
Вот текст. Что из него следует про {сущность}? Перечисли выводы без подсказок.
Экстраполяция: файл инструкций агента (CLAUDE.md, AGENTS.md). Если агент пополняет файл «знаний о проекте», можно потребовать в инструкции: каждая запись в файле — одна короткая проверяемая строка с ссылкой на источник (файл, коммит, дата). Тогда при устаревании источника легко найти и убрать зависящие от него строки. Это моя идея по мотивам статьи, самой статьёй не проверенная.
Ресурсы
- Keep Your Receipts: Trustworthy Cleanup of Agent-Built Knowledge Graphs
- Автор: Vishisht Choudhary, Technical University of Munich. Препринт для NeurIPS 2026, воркшоп «Who Verifies the Agents?»
- Код и промпты: https://github.com/VishiATChoudhary/polygraph
- Опорные работы: de Kleer (1986), метки поддержки в системах поддержания истинности; Gupta et al. (1993), delete-and-rederive; Green et al. (2007), полукольца происхождения; Edge et al. (2024), GraphRAG
