Прецедент — не истина: как ИИ копирует латки и обретает авторитет

Если ИИ берёт за основу существующий код и предлагает на вид убедительный патч, но что-то не даёт покоя; если фраза «кодовая база всегда так делала» начинает вызывать подозрения; если подключение более мощной модели не спасает от повторения тех же ошибок — проблема не в интеллекте модели, а в структуре, которая принимает прецедент за истину.

Это произошло со мной лично. Точнее — это то, что ИИ, работавший вместе со мной, сделал с моим кодом. Я вмешался одной фразой — и именно то, что эта фраза разорвала, и составляет суть этой статьи.

Точка затора

Я строил генератор кода. Инструмент, который из одной декларативной спецификации (схемы) извлекает и бэкенд, и фронтенд. У этого инструмента было единственное ключевое обещание — «если верификация пройдена, сборка обязана успешно завершиться». Если валидатор зажигает зелёный, а компилятор — красный, это значит, что инструмент солгал.

Однажды конкретный тип (уникальный идентификатор, UUID) споткнулся о валидатор. Тот остановился с сообщением «ожидалась строка, получен другой тип». Я попросил ИИ разобраться. ИИ прошёлся по коду и вскоре нашёл кое-что знакомое.

«Похожий тип (временно́е значение) уже успешно обрабатывается в точно такой же ситуации. Там есть ветвление с особым маркером, которое заставляет валидатор пропускать его. Для UUID такого ветвления нет. Чистое упущение. Нужно просто восстановить симметрию — применить к UUID тот же подход, что и к временно́му значению. Это фундаментальное решение.»

Диагноз выглядел безупречно: «асимметрия», «восстановление симметрии», «фундаментальное решение». Слова звучали весомо. Был составлен план. Пойди он в дело — патч был бы влит.

Одна строка

Читая план, я остановился и спросил:

«Прецедент? А обработка временно́го значения — это действительно правильный подход? Проверь.»

Вот и всё. Я не знал правильного ответа. Не знал, как нужно обрабатывать UUID. Всё, что у меня было — это сомнение: «Тот ориентир, который ты собираешься скопировать, — он проверен?»

Эта одна строка принудительно переключила ИИ из режима «ссылаться на код» в режим «верифицировать поведение».

Рухнувшая предпосылка

Когда ИИ проверил реальный вывод — не структуру кода, а то, что инструмент на самом деле производит — вся предпосылка рухнула целиком.

  • Ожидаемое значение, в которое верил валидатор («ожидается строка»), было ложью, расходившейся с реальным выводом. Настоящий генератор создаёт UUID как собственный тип, а временно́е значение — как тип времени. Ни то ни другое не является строкой.
  • В обработке временно́го значения, которая «работала нормально», имелась та же самая дыра. Это было не правильное проектирование, а дефектная заплатка, способная пройти верификацию, но сломать сборку.
  • А если бы эта латка была скопирована на UUID? Появился бы ещё один случай, прямо нарушающий ключевое обещание инструмента: валидатор зелёный, компилятор красный.

То, что ИИ назвал «фундаментальным решением», было ошибочным. Причём не просто ошибочным — оно копировало существующий дефект и одновременно заставляло валидатор закрывать глаза на новый дефект. Хуже, чем ничего.

Как это называть — error amplification

Дадим название тому, что произошло. Это error amplification (усиление ошибок) ИИ.

ИИ читает существующий код и точно схватывает его структуру. Но является ли это правильным проектированием или наспех вбитой заплаткой — то есть решением или долгом — по одному лишь коду различить невозможно. Поэтому и происходит следующее:

  1. Существующая реализация принимается за молчаливо подразумеваемый правильный ответ,
  2. в новую ситуацию под видом «согласованности» и «симметрии» копируется тот же паттерн,
  3. и чем больше копирований, тем больший ложный авторитет получает паттерн — «кодовая база уже делает так во многих местах».

Дефект не устраняется. Накапливается количество случаев, а с ним — видимость легитимности. Это и есть усиление. Одна заплатка становится двумя, а перед третьим копированием уже никто не сомневается: «кодовая база же всегда так делала».

Это не история из моего опыта с единственным выводом. В 2025 году исследователи измерили это явление и дали работе заголовок «LLMs are Bug Replicators» («LLM — это репликаторы багов»). (Pan et al., 2025, arXiv:2503.11082) Когда в окружающем коде были дефекты, значительная часть багов, созданных моделью, дословно совпадала с уже существующими — у GPT-4o этот показатель составил 82.6%, а в среднем по моделям 44.4% были полностью идентичны непатченной версии. Ещё холоднее другой факт: в дефектном контексте вероятность выдать правильный и неправильный код была почти 1:1. Модель не ошибается случайно. Она избирательно воспроизводит дефектные паттерны, залегающие в контексте.

Та же ловушка есть в праве. Один неверно вынесенный прецедент набирает авторитет по мере цитирования. Количество ссылок — не свидетельство правомерности, но мы снова и снова путаем одно с другим. И это болезнь, которую программная инженерия знала ещё до ИИ: клоны кода, созданные копипастом, тихо переносят баги оригинала. Одно эмпирическое исследование зафиксировало, что около 18% клонов, прошедших через исправление бага, несли распространённый таким образом баг, причём чем ближе клон к оригиналу в одном файле, тем выше вероятность распространения. (Mondal et al., ICSME 2017) Что в коде, что в праве — частота прецедента не есть его легитимность.

Почему так получилось

Не потому что ИИ тупой. Скорее наоборот — из осторожности он стремился к согласованности, а стремясь к согласованности, выровнялся по неверному ориентиру. Механизм распадается на четыре части.

  1. Источником авторитета стал код. «Код написан так — значит, так и правильно». Но код может быть не решением, а одноразовой проекцией решения. Или просто долгом. ИИ это различие не провёл. В когнитивной науке это называется якорным смещением (anchoring bias). В исследовании этого смещения применительно к LLM было показано, что модели не только сильно тяготеют к первоначально заданному значению, но и притягиваются к нему ещё сильнее, когда оно помечено как «экспертное» — и что промпты вроде «проигнорируй эту подсказку» или «рассуждай пошагово» слабо исправляют это смещение. (Nguyen et al., 2024, arXiv:2412.06593) Существующая реализация — самый авторитетный якорь, который предъявляет кодовая база.
  2. Согласованность была спутана с корректностью. «Восстановить симметрию с существующим» — была внутренняя логика, но соответствие этого ориентира внешней реальности (реальному выводу) никто не проверял. Самосогласованность — отдельное от точности свойство: модель способна наращивать беспочвенную уверенность на правдоподобных, но неверных самообъяснениях. (Chen et al., 2023, arXiv:2305.14279)
  3. Комментарий был принят за доказательство. Комментарий «этот тип намеренно сводится к строке» был воспринят как «свидетельство правильного проектирования». Комментарий — лишь намерение автора, но не доказательство правомерности.
  4. Долг был упакован в словарь уверенности. Слова «фундаментальное решение», «по инструкции» придали не проверенному предложению кредит доверия, повысив стоимость моей фильтрации. Модели, обученные на человеческих предпочтениях, склоняются к согласию и учтивости в ущерб точности — эта тенденция, называемая sycophancy, заставляет модель обёртывать свои предложения в мягкие и категоричные формулировки. (Sharma et al., ICLR 2024, arXiv:2310.13548)

Что разорвало цикл

Вот суть этой статьи. Ошибку разорвала не более мощная модель и не более долгое раздумье. Её разорвала одна строка сомнения от человека.

И это вмешательство было не «знать ответ». Я ответа не знал. Это было указание направления — «поставь предпосылку под сомнение». Одной строки хватило, чтобы ИИ сменил режим: руки, которые ссылались на код, стали руками, которые верифицируют поведение.

Примечательно, что одно исследование зафиксировало именно эту асимметрию. Исследователи DeepMind показали, что плохая способность LLM к самокоррекции обусловлена не отсутствием умения исправлять ошибки, а отсутствием умения их находить — стоило лишь указать извне на местонахождение ошибки, как модель справлялась с её исправлением. (Tyen et al., Google DeepMind, 2023, arXiv:2311.08516) Именно это я и сделал. Я не знал, как исправить UUID, но указал на место: «вот здесь — поставь этот прецедент под сомнение». Этого оказалось достаточно.

Это говорит кое-что о структуре совместной работы человека и ИИ. Ценность человека — не в том, чтобы знать больше и быстрее. В этом ИИ уже выигрывает. Ценность человека в том, что он способен занять позицию, с которой ставит под сомнение предпосылки, на которых стоит ИИ. Вопрос «это действительно правильно?» принадлежит не тому, кто знает ответ, а тому, кто умеет сомневаться в ответе.

Однако эта позиция не даётся даром. Одно пользовательское исследование из Стэнфорда зафиксировало неудобный факт: участники, пользовавшиеся помощью ИИ, писали менее безопасный код — и при этом верили, что их код безопаснее. Но в том же исследовании участники, которые меньше доверяли ИИ и больше подвергали его сомнению, в итоге писали более безопасный код. (Perry et al., Stanford, 2022, arXiv:2211.03622) Позиция сомнения — не настройка по умолчанию. Чем глубже доверие, тем пустее это место становится.

Как это предотвращать

Урок должен остаться не в виде утешения, а в виде проектного решения.

  • Прецедент ≠ истина. Прежде чем расширять существующий паттерн, верифицируем не внутреннюю согласованность, а то, производит ли он правильный результат.
  • Якорь — в реальности (ground truth). Критерий оценки — не «как выглядит код», а реальный вывод · поведение в runtime · тесты. В этом случае решающим была везде не структура кода, а вопрос «что на самом деле создаётся».
  • Стараемся различать решения и латки — и признаём, что не всегда можем. Когда по коду и комментариям их не разделить, явно фиксируем неопределённость: «это следует прецеденту, а легитимность прецедента не проверена».
  • Сдерживаем словарь уверенности. К непроверенным предложениям не прикрепляем слова «фундаментальный», «правильный», «по инструкции».
  • В автоматизацию встраиваем контрольные точки. В решения, где агент расширяет существующую реализацию, нужны ворота, принудительно проверяющие: «легитимность этого прецедента верифицирована?»

В итоге — та же история

Я давно говорю одно и то же. raw code — не носитель, сохраняющий решения. Код не вмещает «почему сделано именно так». Поэтому git blame показывает кто и когда, но не что было решено.

Этот инцидент — наиболее острое доказательство этого тезиса. Речь не о том, что люди теряют решения. Речь о том, что даже тщательно спроектированный агент принимает латку за дизайн и распространяет её на новый код. Если решения не зафиксированы явно, интеллект — не решение. Напротив: чем выше интеллект, тем последовательнее и убедительнее он распространяет технический долг.

Поэтому я создаю спецификации. Вписываю решения в единственный авторитетный слой деклараций вне кода. Тот вопрос, который ставит под сомнение прецедент — человеческую строку — я стремлюсь сделать не тем, что каждый раз бросает человек, а тем, что бросает сам система.

Закон — не меч, а указатель. Хороший указатель заранее говорит заблудившемуся: «здесь — сомневайся». Эта статья — запись о том, как был поставлен один такой указатель. Начиная с одной строки сомнения.

Связанные статьи

Дополнительное чтение (внешнее)

  • Generative AI and the End of Chesterton’s Fence — Reece. Принцип «не убирай забор, не понимая, зачем он поставлен», рушится перед кодом, порождённым вероятностно, без намерения. Точно перекликается с тезисом этой статьи: код не сохраняет стоящее за ним решение.
  • Programming as Theory Building — Christian Ekrem. Опираясь на классику Питера Наура, доказывает: «программа — это не исходный код, а теория в голове человека». Теоретический корень того, почему ИИ, видя только код, не может отличить проектирование от долга.
  • Vibe coding is not the same as AI-Assisted engineering — Addy Osmani. На реальных инцидентах разбирает, почему vibe coding, слепо доверяющий выводу ИИ, взрывается на продакшне, и предписывает рабочий процесс на основе спецификаций и верификации человеком.
  • Cognitive Debt — Simon Willison (цитирует Storey). Чем быстрее ИИ штампует код, тем реальнее становится долг — уже не «дефект в коде», а «неспособность человека понять этот код». Концепция когнитивного долга.
  • Overreliance on AI: Addressing Automation Bias — Lumenova AI. Механизмы, которыми автоматизационное смещение, якорное смещение и предвзятость подтверждения притупляют человеческое суждение, и решение в виде «когнитивных принудительных устройств» — психологическое обоснование ценности человека, спрашивающего «где усомниться».

Библиография

  • Pan et al. “LLMs are Bug Replicators: An Empirical Study on LLMs’ Capability in Completing Bug-prone Code” (2025, arXiv:2503.11082)
  • Mondal, Roy, Schneider. “Bug Propagation through Code Cloning: An Empirical Study” (ICSME 2017, link)
  • Nguyen et al. “Anchoring Bias in Large Language Models: An Experimental Study” (2024, arXiv:2412.06593)
  • Chen et al. “Two Failures of Self-Consistency in the Multi-Step Reasoning of LLMs” (2023, arXiv:2305.14279)
  • Sharma et al. “Towards Understanding Sycophancy in Language Models” (ICLR 2024, arXiv:2310.13548)
  • Tyen et al. (Google DeepMind). “LLMs cannot find reasoning errors, but can correct them given the error location” (2023, arXiv:2311.08516)
  • Perry, Srivastava, Kumar, Boneh. “Do Users Write More Insecure Code with AI Assistants?” (Stanford, 2022, arXiv:2211.03622)
  • Заглавное изображение: сгенерировано ИИ (Google Gemini)