Ваш ИИ-агент не понимает код, он уверенно угадывает
- title
- Ваш ИИ-агент не понимает код, он уверенно угадывает
- type
- summary
- summary
- Статья разработчика о CodeSlicer - графе влияния, разделяющем доказанные вызовы и правдоподобные догадки
- tags
- agentic-coding, static-analysis, code-review, impact-analysis
- sources
- slicer-agents-guess-code
- created
- 2026-07-29
- updated
- 2026-07-29
- lang
- ru
- translation_of
- slicer-agents-guess-code
- source_updated
- 2026-07-29
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Статья на Хабре за июль 2026 года от artemidoor с представлением CodeSlicer - инструмента, созданного автором. Это анонс продукта, и приведённые в нём результаты бенчмарков получены самим разработчиком на его собственных фикстурах. Саму постановку задачи всё равно полезно зафиксировать: описанный режим сбоя очень точен, а предложенные правила честности можно протестировать. (В заголовке написано "SLICER", но по всему тексту инструмент называется CodeSlicer, как и репозиторий.)
В начале приводится цитата Мо Битара (Mo Bitar), создателя Standard Notes, после двух лет разработки с помощью ИИ: агенты пишут изолированные изменения, которые выглядят хорошо сами по себе, согласуются со своим контекстом и вашим промптом, но оставляют целостность всей системы без внимания. Список примеров того, как это выглядит на практике, вполне конкретен. Один агент выбирает провайдер, не заметив вторую реализацию. Другой меняет HTTP-обёртку, но не видит бэкенд-роут. Третий правит сервис, не зная, что фоновый потребитель читает из него данные. Четвёртый обновляет фронтенд-клиент и оставляет устаревший barrel export. Каждый diff проходит ближайшие проверки; ломается всё именно на стыке модулей.
Вероятное - не значит доказанное
Главный пример в статье - четыре строки на Python:
class OrderService:
def __init__(self, repository):
self.repository = repository
def create_order(self, order):
return self.repository.save(order)
Очевидная интерпретация: self.repository -> OrderRepository -> OrderRepository.save. Сам вызов этого не доказывает. В проекте могут существовать OrderRepository.save, PaymentRepository.save, AuditRepository.save и MockRepository.save, а объект может передаваться через внедрение зависимостей в конструкторе, провайдер, фабрику, реестр или конфигурацию во время выполнения. Экстрактор на самом деле видит только receiver: self.repository, method: save. Чтобы связать это с конкретным методом, нужно пройти цепочку: параметр конструктора, привязку провайдера, конкретный тип, присваивание поля и поиск метода. Формулировка статьи на этот счёт: уверенность без доказательств - это просто красиво оформленная догадка.
Поэтому главное правило архитектуры инструмента: факты и гипотезы разделяются на каждом этапе. Экстрактор извлекает то, что буквально написано в коде. Резолвер пытается связать этот факт с символом. Пакеты поддержки (support packs) добавляют правила для конкретных фреймворков. Контроль качества (quality guard) проверяет происхождение данных и отсутствие противоречий. Запрос влияния (impact query) обходит граф и помечает слабые участки. ИИ использует граф как контекст, но не может добавить в него подтверждённое ребро.
На выходе формируется GraphDocument, где у каждого ребра есть собственный журнал доказательств (audit trail):
{
"from": "OrderService.create_order",
"to": "OrderRepository.save",
"kind": "CALLS",
"resolution_status": "resolved",
"evidence_class": "static_inferred",
"validation_status": "not_validated",
"confidence": 0.86,
"resolver_id": "typed_receiver_resolver",
"evidence": [
"constructor parameter repository: OrderRepository",
"self.repository = repository",
"self.repository.save(order)"
]
}
Три оси остаются независимыми. resolution_status может быть resolved, ambiguous или unresolved. evidence_class принимает значения static_proven, static_inferred или support_pack. validation_status - not_validated или runtime_observed. Уверенность (confidence) отражает силу цепочки доказательств; валидация показывает, наблюдалось ли выполнение в рантайме. Путь из нескольких рёбер наследует статус своего самого слабого звена, что не даёт цепочке из четырёх надёжных связей и одной догадки выдать себя за подтверждённую. Когда цель выбрать невозможно, допустимыми ответами остаются ambiguous, unresolved, unsupported_semantics и quarantine. Нарисовать лишнюю стрелку выглядело бы красивее, но на деле было бы хуже.
Конвейер и бенчмарк
Девять этапов включают инвентаризацию (языки, манифесты, локальные модули, классификация зависимостей), планирование сканирования (исключение node_modules, артефактов сборки, вендорных и сгенерированных файлов), извлечение через AST Python и экстракторы на базе парсеров, нормализацию в стабильные канонические идентификаторы с сохранением происхождения, семантическую привязку импортов, параметров, полей и получателей, точное разрешение до конкретной цели или явный отказ от ответа, пакеты поддержки для FastAPI, React, SQLAlchemy и Celery, проверки качества (quality gates) со статусами, лимитами уверенности и висячими рёбрами, и, наконец, ограниченный обход вверх и вниз для запроса влияния.
Пакеты поддержки - это версионированные правила с атрибуцией, а не регулярные выражения. Ребро FastAPI сохраняет свои rule_id, rule_version, trust_level, совпавший шаблон и доказательства - декоратор локального роута, префикс родительского роутера, префикс app.include_router. Агент может предложить пакет правил, но только валидация переводит его в статус подтверждённого.
Подход к валидации - пожалуй, самая интересная идея для заимствования. Каждая фикстура объявляет expected_edges и forbidden_edges, поэтому прогон оценивается как по найденным правильным связям, так и по предотвращённым ложным. Для фулстек-фикстуры сценария заказа OrderRepository.save должен связываться с OrderService.create_order и POST /api/v1/shop/orders, тогда как маршрут пользователей и saveOrderDraft должны оставаться исключёнными, несмотря на сходство имён. Мутационное тестирование затем намеренно ломает доказательную базу: удаляется привязка в конструкторе, подменяется провайдер, добавляется второй кандидат, удаляется импорт, меняется тип получателя, убирается HTTP-обёртка, меняется префикс маршрута. Корректная реакция - ребро исчезает, цель меняется, статус падает до ambiguous, создаётся карантинная запись или снижается уверенность. Ребро не может оставаться подтверждённым только потому, что имя метода всё ещё совпадает.
Честность анализа удерживается ещё двумя правилами. Детерминизм: один и тот же проект и конфигурация должны выдавать одинаковые канонические идентификаторы, логические рёбра и семантический отпечаток, при этом временные метки и временные пути не влияют на результат. А наблюдение во время выполнения не считается абсолютной истиной. Тест, в котором вызов действительно выполнился, доказывает лишь то, что вызов произошёл именно в этом сценарии, окружении и конфигурации, не более, поэтому наивысший доступный статус - STATIC_RESOLVED + RUNTIME_OBSERVED. Отсутствие вызова в одном тесте также не является доказательством его невозможности: ветка могла не выполниться, объект мог быть замоккан, а инструментация могла не отследить подпроцесс или асинхронную границу.
Заявленные результаты на размеченных сценариях автора: семантическое разрешение для Python на 21 тестовом и 29 мутационных сценариях с 20 размеченными обязательными семантическими рёбрами показало 20 true positive, 0 false positive, 0 false negative. TypeScript и мост между фронтендом и бэкендом на 12 тестовых сценариях, 15 мутационных сценариях и 4 межъязыковых сценариях дали точность эндпоинтов 1.0 и 0 нарушений запрещённых связей. В статье прямо указаны ограничения: высокая точность на небольшой фикстуре означает лишь доказанную поддержку конкретного паттерна, а не понимание любой реальной кодовой базы. Там же открыто говорится, что итоговый анализ вовсе не должен быть полностью зелёным: confirmed, inferred, ambiguous, unresolved и unsupported_semantics являются равноправными результатами, а неизвестные области - это часть ответа, а не дефект интерфейса.
Место среди инструментов
Сравнительная таблица разделяет инструменты, использующие слово "граф". Sourcegraph - это размещённая на сервере навигация по коду в масштабах организации; Joern - Code Property Graph для исследований безопасности; Semgrep и CodeQL - движки правил для SAST и поиска потоков данных; Graphify - локальный граф знаний о коде для ассистентов; CodeSee - визуальные карты кодовой базы для онбординга. Заявленная ниша CodeSlicer уже: что именно затронет изменение, почему анализатор в этом уверен и где его знания заканчиваются. Предлагаемые на этой базе продукты - это отчёты о рисках в PR, разделяющие обязательные правки и места для ревью; выбор тестов по реальной цепочке вызовов, а не по совпадению имён файлов; оценка радиуса поражения при рефакторинге и миграциях; расследование инцидентов с прослеживанием от симптома назад через обработчик и сервис; и разделение крупной задачи между несколькими агентами, чтобы каждый получал свой срез и явный список границ, которые нельзя считать подтверждёнными.
В статье открыто описана бизнес-модель: бесплатный локальный движок (CLI, MCP-сервер, парсер, GraphDocument, базовые публичные пакеты поддержки, визуальный интерфейс) и платный верифицированный реестр валидированных пакетов для фреймворков, приватные реестры, проверки влияния в CI и enterprise-развёртывание на своих серверах. Заявленное ограничение - платный реестр не должен требовать загрузки исходного кода: правила спускаются на клиент, код остаётся локальным. Насколько это соблюдается, предстоит проверить позже.
Проблема, которую пытается решить инструмент, описана со стороны проверяющего в agent-principal-agent-problem. Мысль Крошоу (Crawshaw) в том, что ревьюер больше не может судить о затраченных усилиях по diff'у; автоматически проверяемый радиус влияния - попытка дать ревьюеру другой сигнал, не зависящий от догадок о том, сколько сил вложил автор. Это также перекликается с how-do-we-stop-vibe-coding, где Scryer делает похожую ставку со стороны модели: показать изменение как diff над структурой, понятной и человеку, и агенту, вместо того чтобы заставлять кого-либо вычитывать каждую строчку. reviewing-ai-code объясняет, почему проверяющему вообще нужна помощь, а clean-code-coding-agents - почему компактный, заранее разрешённый срез выигрывает у передачи агенту всего репозитория целиком.
Репозиторий: artemnoor/CodeSlicer. Один автор, ранняя стадия проекта, а единственные опубликованные цифры принадлежат самому автору - стоит вернуться позже, но не внедрять прямо сейчас.