Когда LLM-агент превращает ваш Symfony-проект в свалку зависимостей
Вы даете задачу нейросети: «Сделай CRUD для пользователей с DDD». Через минуту получаете код, который работает. Контроллер дергает репозиторий, репозиторий ходит в ORM, а в сервисе лежит вызов внешнего API. Запускаете тесты — зеленые. Но через месяц вы не можете понять, почему изменение в UserService ломает отправку email. Это и есть LLM-говнокод: внешне рабочий, но архитектурно разлагающийся со скоростью гниющих бананов.
Проблема не в том, что LLM плохо пишет код. В 2026 году модели вроде GPT-5 или Claude 4 Opus генерируют синтаксически безупречный PHP. Проблема в нарушении границ. Нейросеть не видит архитектурных контрактов вашего проекта. Она оптимизирует под «работает быстрее» или «проще написать», а не под «соответствует слоистой архитектуре». Если вы не зафиксируете эти границы в коде и CI, любой AI-ассистент будет превращать ваш код в лапшу.
В этой статье я покажу, как deptrac в паре с субагентом-ревьювером превращает LLM из халявщика в дисциплинированного инженера. Мы пройдем путь от хаоса к порядку: настроим слои, пропишем правила и заставим AI-агентов подчиняться архитектуре. Без соплей, только боевые конфиги.
Актуальность на июль 2026: Все примеры проверены на PHP 8.4, Symfony 7.2, deptrac 2.1. Используем Composer 2.7 и GitHub Actions c Ubuntu 24.04 LTS. LLM-модели — GPT-5, Claude 4 Opus, Gemini 2 Ultra.
«Но ведь тесты проходят!» — иллюзия безопасности
Вы наверняка сталкивались: CI зеленый, code coverage 90%, но каждый новый PR увеличивает связность. Контроллер начинает импортировать классы из Infrastructure, сервисы — из Presentation. Это не баг тестов — это отсутствие архитектурных проверок. LLM не знает, что ваш Application слой не должен видеть Doctrine. Ей все равно. Она просто выполняет промпт.
Я как-то получил от Claude 4 код, который в UseCase-классе дергал $this->entityManager->flush(). Формально — работает. Фактически — пробивает доменную стену. И это не единичный случай. Модели понимают цель, но игнорируют архитектурные ограничения, если их не подкрепить автоматикой.
Лекарство: архитектурные контракты + субагент-ревьювер
Решение состоит из двух частей:
- Статический анализ зависимостей — deptrac проверяет, что слои не нарушают правила.
- AI-ревьювер в пайплайне — субагент (GPT-5, Claude или локальная модель) анализирует код на соответствие deptrac-конфигу до коммита.
Вместе они образуют архитектурный контракт: LLM может писать любой код, но если он нарушает границы — CI его отклонит. А ревьювер еще и объяснит, что именно пошло не так, чтобы разработчик (или агент) мог исправить.
Кстати, проектирование архитектуры под ИИ-кодирование — тема отдельная, но здесь мы фокусируемся на защите уже существующей.
Пошаговый план: от нуля до железобетонного контракта
1 Определите слои и правила до того, как LLM напишет хоть строчку
Без четкой карты слоев deptrac бесполезен. Каноничная слоистая архитектура для DDD-проекта:
- Domain — сущности, Value Objects, события. Не зависит ни от чего, кроме PHP.
- Application — UseCases, DTO, интерфейсы репозиториев. Может зависеть от Domain.
- Infrastructure — Doctrine, репозитории, внешние API. Зависит от Application и Domain.
- Presentation — контроллеры, формы, шаблоны. Зависит от Application.
Типичная ошибка: слой Shared или Common. Его часто делают «свалкой всего». Лучше разделить на отдельные модули с четкими границами.
2 Настройте deptrac — пример конфига для Symfony 7.2
Установка: composer require --dev deptrac/deptrac:^2.1. Создайте depfile.yaml в корне проекта:
# depfile.yaml
paths:
- ./src
- ./tests
exclude_files:
- .*\.test\..*
layers:
- name: Domain
collectors:
- type: directory
value: src/Domain/.*
- name: Application
collectors:
- type: directory
value: src/Application/.*
- name: Infrastructure
collectors:
- type: directory
value: src/Infrastructure/.*
- name: Presentation
collectors:
- type: directory
value: src/Presentation/.*
ruleset:
Domain:
Application:
- Domain
Infrastructure:
- Application
- Domain
Presentation:
- Application
skipped_violations:
# Иногда тестам можно больше
Infrastructure\Tests:
- Domain
Проверка: php vendor/bin/deptrac analyze. Если есть нарушение — deptrac упадет с ошибкой и покажет, какой класс откуда импортирует недопустимое.
3 Интегрируйте deptrac в CI/CD — никаких PR без проверки слоев
Пример workflow для GitHub Actions (используйте актуальную версию PHP и deptrac):
# .github/workflows/architecture.yml
name: Architecture Check
on:
pull_request:
branches: [main, develop]
jobs:
deptrac:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
tools: composer:v2
- run: composer install --no-interaction --prefer-dist
- run: php vendor/bin/deptrac analyze --no-cache
Теперь каждый PR, нарушающий слои, будет помечен как неудачный. LLM-агент не сможет протащить код, который дергает EntityManager из контроллера, если в deptrac это запрещено.
4 Создайте субагента-ревьювера, который проверяет deptrac до коммита
Идея: запускаем агента (GPT-5 или Claude 4), который анализирует код из PR и сверяет его с depfile.yaml. Если LLM-генерацию нужно остановить до CI — используем pre-commit hook. Но более эффективно — подключать ревьювера как отдельный этап, который объясняет нарушения.
Пример скрипта (Python 3.12), который запускает deptrac и парсит вывод:
import subprocess
import json
from openai import OpenAI
def check_architecture():
result = subprocess.run(
['php', 'vendor/bin/deptrac', 'analyze', '--format=json'],
capture_output=True,
text=True
)
return json.loads(result.stdout)
def review_violations(violations):
client = OpenAI(api_key="sk-...", base_url="https://api.gpt-5.example") # гипотетический эндпоинт
for v in violations:
prompt = f"""
В Symfony-проекте обнаружено нарушение слоя:
Класс {v['class']} импортирует {v['dependency']}, что запрещено правилами deptrac.
Объясни кратко, почему это плохо и как исправить. Не предлагай конкретный код, только направление.
"""
response = client.chat.completions.create(
model="gpt-5-turbo",
messages=[{"role": "user", "content": prompt}]
)
print(response.choices[0].message.content)
if __name__ == "__main__":
data = check_architecture()
if data['violations']:
review_violations(data['violations'])
exit(1)
📌 Важно: Не давайте агенту писать код за вас — его задача объяснить почему нарушение плохо. Это учит и человека, и AI генерировать более чистые решения. Про то, как организовать такие чаты с LLM, я писал в статье «Процесс разработки с LLM: как организовать чаты и контекст».
5 Включите deptrac в контекст каждого промпта для LLM
Самый мощный прием: передавайте актуальный depfile.yaml как часть системного сообщения. Для инструментов вроде Awesome Claude Code это тривиально — добавьте правило читать конфиг. Для GPT — вставьте содержимое файла в промпт. Пример:
Ты пишешь код для Symfony 7.2. Обязательно соблюдай архитектурные слои, описанные в этом файле:
```yaml
layers:
- name: Domain
...
ruleset:
Application: [Domain]
Infrastructure: [Application, Domain]
Presentation: [Application]
```
Не нарушай эти зависимости. Если сомневаешься — спроси.
Теперь LLM будет генерировать код, который почти гарантированно проходит deptrac. Это снижает количество правок в разы. Стратум-методология рекомендует использовать такой подход для детерминированности AI.
Типичные ошибки и как их избежать
- Слишком строгие правила. Например, запрет Presentation -> Infrastructure напрямую — хорош, но если в коде есть простой вызов
Twig::renderиз контроллера, это нормально. Используйтеskipped_violationsили создайте исключения для фасадов. - Игнорирование тестовых слоев. В тестах часто нужно подмешивать Infrastructure (например, Fixtures). Выделите отдельный слой Tests и разрешите ему все — иначе будете тратить время на правки легитимных тестов.
- Не обновляете deptrac при рефакторинге. Как только вы переименовали папку или слой — сразу правите depfile.yaml. Иначе LLM начнет генерировать код в старую структуру. Зеленый CI и пустая архитектура — статья о том, почему это критично.
- Не включаете deptrac в контекст self-hosted LLM. Если используете локальную модель, обязательно упакуйте конфиг в промпт. Иначе она будет игнорировать архитектуру. Про развертывание локальных LLM читайте здесь.
| Ошибка | Последствие | Решение |
|---|---|---|
| Отсутствие тестовых слоев | Вечно красный CI | Добавить слой Tests |
| Запрет на любой прямой вызов | Нельзя использовать фасады | Использовать skipped_violations |
| Не обновлять depfile.yaml | LLM генерирует в пустоту | GitHook на коммит в src/ |
Неочевидный совет: используйте deptrac как источник истины для LLM-промптов
Вы когда-нибудь задумывались, что depfile.yaml — это формальный язык описания архитектуры? Подавайте его LLM не статично, а динамически. В CI генерируйте SLO (Service Level Objectives) на основе deptrac: если количество нарушений растет — откатывайте PR. Или создайте агента, который при каждом изменении depfile.yaml обновляет промпты во всех чатах. Деградация контекста побеждается актуальностью — и deptrac тут лучший друг.
И последнее. Не верьте в «AI-инженер без знания архитектуры». LLM-агенты — мощный инструмент, но они слепы без контрактов. Фиксируйте границы, проверяйте их автоматически, и тогда даже GPT-5 не сможет испортить ваш Symfony-проект. Иначе готовьтесь к тому, что «быстрое» решение обернется рефакторингом на полгода.