[nevr]
· 7 мин чтения

Contradiction detection: когда AI замечает что ты противоречишь сам себе

Contradiction detection in knowledge graph

“Рынок — миллиард долларов.” Неделю спустя, тот же человек, тот же проект: “Рынок стагнирует на уровне $500M.” Человек не заметил. AI — заметил.

Это не баг и не придирка. Это одна из самых ценных функций AI-продуктового инструмента — обнаружение противоречий в собственных данных пользователя.

Почему противоречия неизбежны

Продуктовое исследование — это месяцы диалогов. 50, 100, 200 сообщений. Информация приходит из разных источников: интервью с клиентами, статьи, собственные расчёты, конкурентный анализ. Человек обновляет свою картину мира постоянно — но не возвращается к сообщению #14, чтобы вычеркнуть устаревшую цифру.

Типичные сценарии:

  1. Рыночные данные. “TAM = $2B” в первом интервью → “$800M” после уточнения с аналитиком. Оба факта остаются в контексте, оба влияют на артефакты.
  2. Сегментация. “Наш клиент — малый бизнес до 10 человек” → через две недели: “Фокусируемся на командах 50-200”. Pivot произошёл, но первый факт не отменён.
  3. Конкурентный ландшафт. “X — главный конкурент” → “X закрылся, теперь главный — Y”. Если старый факт не инвалидирован, AI продолжит строить артефакты с упоминанием мёртвого конкурента.
  4. Ценообразование. “Будем брать $99/мес” → “Переходим на freemium”. Два взаимоисключающих подхода.

Без автоматического обнаружения — мусор в данных накапливается. Артефакты генерируются на противоречивой базе. Рекомендации теряют смысл.

Как это работает: pipeline в четыре шага

Шаг 1: Извлечение факта

Каждое сообщение проходит через FactExtractorService. LLM извлекает структурированные факты с весами и типами:

Сообщение: "Рынок стагнирует, реально не больше $500M"

Извлечено:
  Fact(dimension: economics, type: market_size)
  content: "рынок стагнирует, не больше $500M"
  weight: 70

Факт сохраняется в workspace_context_facts и уходит дальше по пайплайну.

Шаг 2: Embedding и поиск похожих

Новый факт получает векторное представление через EmbeddingService. Затем SemanticSearchService ищет существующие факты с высоким cosine similarity — обычно порог 0.75-0.85 для той же dimension.

Новый факт: "рынок стагнирует, не больше $500M"
  ↓ embedding → vector [0.23, -0.41, 0.67, ...]
  ↓ cosine similarity search в фактах проекта
  ↓ Найдено: "рынок оценивается в $1B" (similarity: 0.82)

Высокая похожесть по теме + разные утверждения = кандидат на противоречие.

Шаг 3: LLM-подтверждение

Semantic search находит кандидатов, но не может отличить уточнение от противоречия. “Рынок $1B” и “рынок $1B, из которых $300M — наш сегмент” — это не противоречие, а детализация.

Поэтому кандидаты проверяются через LLM:

System: You are a fact-checker. Compare two facts from the same project.
        Classify: CONTRADICTION, REFINEMENT, or COMPATIBLE.

Fact A (message #14, 2 weeks ago): "рынок оценивается в $1B"
Fact B (message #67, today): "рынок стагнирует, не больше $500M"

→ CONTRADICTION
  Reason: market size estimates differ by 2x ($1B vs $500M)
  Suggested action: ask user which estimate is current

Groq на Llama 3.3 обрабатывает такую пару за 200ms. Дёшево, быстро, точно.

Шаг 4: Реакция

При подтверждённом противоречии система делает три вещи:

  1. Инвалидирует старый факт. В KG2 это TemporalManager — старый edge получает invalid_at = now(). Факт не удаляется из истории, но перестаёт влиять на артефакты.
  2. Алертит пользователя. В следующем сообщении бот говорит: “Ранее вы указали, что рынок — $1B. Сейчас — $500M. Что изменилось? Я обновил данные на актуальные.”
  3. Помечает артефакты как stale. Все артефакты, которые использовали инвалидированный факт, получают статус stale — жёлтый баннер “Данные обновились”.

Bi-temporal граф: зачем хранить историю

Knowledge Graph v2 хранит каждый факт с двумя временными метками:

  • valid_at — когда факт стал актуальным
  • invalid_at — когда факт был отменён (null = актуален)

Это не просто аккуратность. Это позволяет отвечать на вопрос: “Что мы думали о рынке месяц назад?” Полная история решений — для ретроспектив, для аудита, для понимания, как менялась картина.

kg2_nodes timeline для "market_size":
  [March 1 → March 20]  "$1B" (invalidated)
  [March 20 → current]  "$500M" (active)

Когда менеджер спрашивает “почему мы изменили стратегию” — система показывает конкретный момент, когда оценка рынка упала вдвое, и какие артефакты были пересгенерированы.

Типы противоречий

Не все противоречия одинаковы. Система различает:

Числовые расхождения. $1B vs $500M. Самый простой тип — LLM сравнивает значения. Высокая точность обнаружения.

Категориальные конфликты. “B2B” vs “B2C”. “Freemium” vs “Premium-only”. Взаимоисключающие стратегии.

Временные сдвиги. “Запуск в Q3” vs “Запуск в Q1 следующего года”. Не ошибка, а изменение плана — но артефакты должны отразить новые сроки.

Мягкие противоречия. “Клиенты довольны UX” vs “Главная жалоба — сложный интерфейс”. Разные источники, разные сегменты? Или реальное противоречие? LLM классифицирует как CONTRADICTION с пометкой “possible segment difference”.

Что это даёт на практике

Чистая база фактов. Артефакты строятся на актуальных, непротиворечивых данных. Никаких призраков из первого созвона, которые тихо портят PRD.

Принудительная рефлексия. Когда бот спрашивает “раньше вы говорили X, сейчас Y” — пользователь вынужден осознать, что его понимание изменилось. Это один из самых ценных моментов в продуктовом исследовании.

Аудитный след. Для команд и инвесторов — полная история, как менялись ключевые предположения. Не “мы решили”, а “7 марта мы считали рынок в $1B, 20 марта скорректировали до $500M на основании отчёта X”.

Защита от garbage in, garbage out. AI-генерация только настолько хороша, насколько хороши входные данные. Contradiction detection — это фильтр на входе.

Почему этого нет в обычных AI-чатах

ChatGPT, Claude, Gemini — все работают с плоской историей сообщений. Они могут заметить противоречие, если оба факта попадают в контекстное окно. Но при 200 сообщениях первые 50 уже за пределами окна.

Для системного обнаружения нужно:

  1. Извлечение фактов — а не просто хранение сообщений
  2. Векторные представления — для семантического поиска по всей истории
  3. Граф знаний — для понимания связей между фактами
  4. Bi-temporal хранение — для управления жизненным циклом факта

Это инфраструктура. Четыре сервиса, три типа хранилища, два уровня верификации. Не “фича за вечер”, а архитектурное решение, которое пронизывает весь стек.


Противоречие — не ошибка пользователя. Это сигнал, что понимание эволюционирует. Задача AI — не наказать за непоследовательность, а помочь осознать изменение и обновить все зависимые выводы.


Попробуйте contradiction detection в действии — AICPO или напишите nevr@aicpo.com