AI в разработке ПО: от чат-бота до агента
Практическое руководство для C++ инженеров
Введение: Смена парадигмы
LLM изменили разработку, но наибольший профит приносит не копирование кода из чата, а встраивание ИИ в пайплайн разработки. Простой чат эффективен для сниппетов, но пасует перед большими кодовыми базами и многофайловым рефакторингом.
Ключевой переход: от “Chat” (человек копирует/вставляет) к “Agent” (ИИ сам читает файлы, ищет ошибки и правит код).
Часть 1. Использование LLM через чаты (Chat Interface)
Для начала рассмотрим chat-интерфейсы. Это база, без понимания которой работать с агентами бессмысленно.
1. Как правильно формулировать задачи
LLM не читают мысли. Принцип “Garbage In, Garbage Out” работает здесь как никогда.
- Контекст важен: Не пишите “Почини баг”. Пишите: “У меня есть функция parse_config, она падает с segmentation fault когда файл пуст. Вот код и backtrace от gdb.”
- Задавайте роль: “Ты — Senior C++ Engineer, специалист по низкоуровневой оптимизации и конкурентности. Перепиши этот код с использованием std::atomic.”
- Явно указывайте границы: “Не меняй сигнатуру функции, редактируй только внутреннюю логику. Не удаляй существующие #include.”
2. Рефакторинг и исправление багов
- Метод “Провал теста → Исправление”: Если сгенерированный код упал на тесте или выдал ошибку компиляции, скопируйте вывод компилятора обратно в чат и скажите: “Твой код не компилируется с этой ошибкой. Найди проблему и исправь её”.
- Итеративные уточнения: Не просите идеальный код сразу. Сначала каркас класса, потом реализация методов, потом оптимизация.
3. Проблема “галлюцинаций” (Hallucinations)
LLM склонны выдумывать несуществующие методы STL или неправильные сигнатуры.
- Решение: Всегда запрашивайте код, соответствующий конкретному стандарту (C++17/20). Используйте плагины с актуальной документацией. После генерации проверяйте код через компилятор с флагами -Wall -Wextra.
Часть 2. “Потолок” чата и необходимость агентов
Чат имеет жесткие ограничения, делающие его непригодным для серьезной разработки:
- Контекстное окно (Context Window): Даже модели с большим окном не могут держать в уме архитектуру всего проекта. Вы упретесь в лимит токенов.
- “Слепота” к файловой системе: Вы должны вручную открыть .cpp и .h, скопировать код, вставить в чат, получить ответ, скопировать обратно, сохранить. Это медленно и чревато ошибками (потеряете изменения или перепутаете файлы).
- Многофайловые изменения: Чат не может атомарно изменить 5-10 файлов (например, переименовать класс в заголовке и во всех .cpp, где он используется). Вы будете делать это по одному, рискуя сломать зависимости.
Вывод: Чат — это “слепой наборщик”. Агент — это разработчик, имеющий доступ к среде.
Часть 3. Что такое ИИ-агенты? (Простое определение)
Агент — это LLM, “обернутая” в цикл управления (Runtime), которая может использовать инструменты и память для достижения цели, а не просто генерации текста.
- Чат: Ввод → LLM → Вывод.
- Агент: Цель → LLM (Планирование) → Выбор инструмента (grep, edit, shell) → Выполнение → Анализ результата → LLM (Следующий шаг) → Цель достигнута.
Почему LLM сама по себе не агент? LLM — это только “мозг”. Агенту нужны “руки” (инструменты) и “память” (контекстное окно + внешнее хранилище), чтобы взаимодействовать с реальным миром.
Часть 4. Внутреннее устройство ИИ-агентов (Технический минимум)
Чтобы эффективно использовать агентов, нужно понимать их архитектуру:
- Context Window (Рабочая память): Это “лист бумаги”, на котором LLM пишет свои мысли. Он ограничен. Если весь код не влезает, агент использует суммаризацию (сжать старые сообщения) или Retrieval (RAG) (найти релевантные куски кода и загрузить только их).
- External Memory (Долговременная память): База знаний проекта, эмбеддинги кода. Агент “вспоминает” архитектуру, перечитывая файлы через grep или find.
- Tools / Function Calling (Инструменты): Это API агента.
- read_file("src/network.cpp")
- run_command("make")
- str_replace_edit("file.h", "old_string", "new_string")
- Orchestration (Оркестратор / Runtime): Это бесконечный цикл, который говорит: “У нас есть цель. LLM сказала вызвать grep. Выполняем. Получили результат. Отдаем результат обратно LLM. Что теперь?”
- Важный нюанс: LLM не имеет памяти
Модель не помнит предыдущие запросы. При каждом вызове API вы отправляете ей ровно тот контекст, который считаете нужным, и получаете ответ.
Для агента это означает, что перед каждым запросом к LLM оркестратор собирает контекст заново:
- Системный промпт — инструкции агенту (фиксирован)
- История действий — что агент уже сделал в этой сессии (может быть суммаризирована, если выросла)
- Релевантные файлы/код — найденные через grep, find или RAG (не вся кодовая база!)
- Результаты предыдущих инструментов — вывод make, ошибки компиляции, вывод grep
- Текущая задача — ваш запрос
Что НЕ отправляется:
- Вся история переписки, если она не нужна
- Файлы, которые не относятся к задаче
- Предыдущие версии кода (только текущие)
Как агент решает, что отправить:
- RAG (Retrieval) — векторный поиск по эмбеддингам кода находит релевантные функции/классы
- Суммаризация — если история выросла, старое сжимается в краткий пересказ
- Инструменты — агент сам вызывает grep, чтобы найти нужные файлы, и читает их выборочно
Таким образом, агент не “запоминает” всё подряд. Он каждый раз заново решает, что ему нужно знать, чтобы ответить на текущий запрос.
Часть 5. Почему агент лучше чата? Сравнение возможностей
|
Функция |
Чат (ChatGPT/Web) |
ИИ-Агент (Aider/OpenCode) |
|
Доступ к ФС |
Нет (копипаста вручную) |
Да (read, write, edit) |
|
Работа с Git |
Нет (ручной коммит) |
Да (авто-коммиты, просмотр diff) |
|
Multi-file правки |
Крайне сложно |
Автоматически (агент сам найдет зависимости) |
|
Контекст |
Фиксированный |
Динамический (подгружает нужные файлы через поиск) |
Часть 6. Бесплатные и Open-Source агенты (Практика)
6.1. Aider (Терминальный парный программист)
Aider — это “рабочая лошадка”. Он интегрируется прямо в терминал и работает с вашим Git-репозиторием.
- Git-based подход: Перед каждым изменением Aider делает коммит. Если сгенерированный код сломал сборку, вы просто откатываетесь (git revert).
- Diff-патчи: Aider не отправляет весь файл целиком. Он отправляет только измененные блоки. Это экономит тонны токенов.
- Работа через терминал: ```bash # Установка pip install aider-chat
- Сильные стороны: Идеален для рефакторинга. Он понимает структуру репозитория через карту, что позволяет ему не теряться в больших проектах.
- Стадии работы Aider
- Анализ и генерация — Aider анализирует ваш запрос и генерирует изменения
- Показ diff-а — Aider показывает вам точные изменения в виде патча (.diff)
- Ваше решение — вы смотрите на изменения и решаете:
- Принять → Aider применяет изменения И делает коммит
- Попросить переделать → Aider пробует другой вариант
- Отказаться → изменений не происходит
- Коммит происходит только после принятия
- Работа с незакоммиченными изменениями
- Сначала коммитит ваши изменения (отдельным коммитом)
- Потом показывает свой diff
- После вашего согласия коммитит свои изменения
- Как Aider управляет коммитами:
- Каждое принятое изменение → отдельный коммит с автоматическим осмысленным сообщением (например, “refactor: rename NetworkManager to ConnectionManager”)
- /undo в чате Aider откатывает последний коммит Aider (выполняет git reset --hard HEAD~1)
- Все коммиты Aider — обычные git-коммиты. Вы можете сделать git rebase -i перед PR, чтобы собрать 5-10 мелких коммитов в один логический (см. раздел “Практические методики работы”)
- Если вы хотите коммитить вручную, запустите aider --no-auto-commits. Aider будет менять файлы, но не создавать коммиты
# Запуск в репозитории export OPENAI_API_KEY=… aider –model claude-3-5-sonnet-20241022
# Внутри чата (прямо в терминале):
Добавь обработку ошибок в функцию parse_config в файле src/config.cpp Напиши юнит-тест для этого модуля в tests/test_config.cpp /commit # Aider сам соберет изменения ```
Важный нюанс про “грязные” файлы:
“Aider takes special care before editing files that already have uncommitted changes (dirty files). Aider will first commit any preexisting changes with a descriptive commit message.”
То есть перед тем, как применить изменения, Aider проверяет, есть ли у вас незакоммиченные правки в файлах, которые он собирается трогать. Если есть — он:
Важно: Aider никогда не смешивает ваш код со своим. Коммит с вашими незакоммиченными правками и коммит с изменениями от Aider — всегда разные коммиты.
Коротко: Вы сначала видите diff, соглашаетесь, и только тогда → коммит.
6.2. OpenCode (Более автономный агент)
OpenCode — это следующий уровень агентности.
- Инструментальный подход: Он не просто правит код. Он может анализировать кодовую базу перед изменениями.
- Пример работы: Вы даете задачу “Переименуй везде m_userId на m_accountId в папке src/”.
- Aider: Спросит, какие именно файлы трогать.
- OpenCode: Выполнит grep -r "m_userId" --include="*.cpp" --include="*.h", сам найдет все файлы, прочитает их, сгенерирует изменения и попросит подтверждения.
- Multi-step reasoning: Может выполнять цепочки: анализ → поиск зависимостей → изменение → проверка сборки → исправление ошибок.
Часть 7. Сравнение подходов
|
Критерий |
Ручное прогр. |
Чат |
Агент (Aider) |
Автономный агент (OpenCode) |
|
Контроль |
Полный |
Низкий |
Средний (Git как защита) |
Высокий (утверждение действий) |
|
Скорость |
Низкая |
Средняя (но много копипасты) |
Высокая |
Очень высокая |
|
Качество кода |
Высокое |
Низкое (вырезки из кода) |
Среднее (требует код-ревью) |
Среднее (нужны тесты) |
|
Масштаб |
Любой |
Мелкие скрипты/функции |
Крупные проекты |
Огромные монолиты |
|
Стоимость |
З/П разработчика |
$20/мес (подписка) |
$0.01-0.10 за задачу (API) |
$0.05-0.50 за задачу |
Часть 8. Практические методики работы
- Git как “сейф”: Всегда работайте в отдельной ветке. Если агент “сходит с ума”, просто git checkout . и git clean -fd.
- Разбивайте задачи: Не давайте агенту “Перепиши весь проект на C++20”. Давайте: “Обнови CMakeLists.txt на C++20”, потом “Замени std::auto_ptr на std::unique_ptr в модуле network”.
- Давайте контекст сборки: Показывайте агенту не только код, но и compile_commands.json или флаги компилятора.
- Валидация через shell: Учите агента запускать сборку и тесты. В Aider это команда /run make. Агент увидит ошибки компиляции и сам попытается их исправить.
- Squash перед ревью: Aider по умолчанию создаёт отдельный коммит на каждое принятое изменение. Это удобно для отката, но загрязняет историю. Перед отправкой Pull Request выполните git rebase -i HEAD~N (где N — число коммитов Aider) или git reset --soft HEAD~N и соберите их в один логический коммит с хорошим описанием.
Часть 9. Реальный workflow разработчика
- Инициализация: Открываете терминал в корне C++ проекта, запускаете aider.
- Постановка задачи: Пишете четкую инструкцию: “Рефактори: вынеси логику парсинга из src/main.cpp в отдельный класс ConfigParser в файлы src/config_parser.h и src/config_parser.cpp. Напиши конструктор и метод load().”
- Выполнение: Агент начинает работу. Он читает main.cpp, создает новые файлы, изменяет импорты (#include), обновляет вызовы.
- Review (Критический шаг): Вы командуете /diff. Агент показывает изменения построчно. Вы видите, что он забыл добавить #include <fstream>.
- Коррекция: “Добавь #include <fstream> в config_parser.cpp.” Агент правит.
- Сборка и тестирование: /run mkdir -p build && cd build && cmake .. && make && ./tests. Сборка проходит.
- Коммит: Агент создает коммит с сообщением: “refactor: extract config parsing to ConfigParser class”.
- Следующий шаг: “Теперь добавь поддержку вложенных секций в INI-файлах.”
Заключение
ИИ-агенты перестают быть просто “генераторами кода”. Они становятся исполнителями задач. Ваша роль смещается от написания кода к управлению агентом: постановка задачи, проверка diff, финальная сборка и тестирование.
Используйте Aider для быстрых изменений в больших проектах через терминал. Используйте OpenCode для исследования и правки больших кусков кода, где нужен автономный поиск.
И помните: агент — это мощный джуниор-разработчик, которому нужен четкий TZ и код-ревью. Он не заменит вас, но сделает в 5-10 раз быстрее.

Комментариев нет:
Отправить комментарий