Основы Эффективного Использования LLM В Разработке

Я постоянно ищу способы, как успевать больше за меньшее количество времени, и c восходом AI это наконец-то начало давать ощутимые плоды по части разработки; однако многие разработчики не видят (либо не хотят видеть) те возможности, которые открываются перед нами, и продолжают работать по старинке, невольно становясь кандидатами, которые могут и не выдержать конкуренции.

Ввиду того, что я все таки менеджер разработки, у меня много взаимодействия с разными разработчиками со всего мира, и я вижу их очень разное отношение к AI. В целом, готов его разделить на следующие категории:

  • Вдохновлены и активно используют AI в работе (до 20%);
  • Проявляют интерес, пробуют, но используют AI на 20% (около 60%);
  • Скептики, которые либо попробовали и это не оправдало их ожиданий, либо даже не пробовали (около 20%). Цифры довольно субъективны и скорее отражают мой личный опыт, нежели являются репрезентативными по всей индустрии.

Есть исследования, которые показывают, что уровень проникновения AI в разработку - порядка 60%, что может и правда. Но пока эта цифра скорее отражает количество разработчиков использующих ChatGPT, Perplexity и подобные AI-powered сервисы без глубокого применения на практике. На деле, LLM в основном используются очень поверхностно, хотя потенциал там огромный.

Про мой опыт

За последний год я попробовал разные редакторы и плагины для IDE powered by AI, но на данный момент остановился на Cursor AI, Github Copilot и JetBrains Junie как основных продуктах, которые применяю каждый день в разработке.

Я основательно не изучал ничего дополнительно, не читал как устроены LLM в деталях, но за счет переключения между разными инструментами, я начал замечать определенные паттерны, и в конечном счете пришел к определенным выводам, которые позволяют гораздо эффективнее использовать силу LLM’ок в инди-разработке (не вижу причин, почему это не будет работать в компании, но об этом в следующих постах).

Выводы могут быть неточными с точки зрения Data Science (буду рад услышать фидбек), однако в упрощенном виде оно так и работает. Надеюсь это будет полезно широкому кругу разработчиков, и в целом станет более понятно, как модели работают, почему глючат и что с этим можно сделать.

На что жалуются разработчики

В этой части я хочу разобрать несколько основных проблем, которые озвучивают разработчики, и объяснить, почему эти проблемы возникают.

Я буду разбирать только базовые принципы и ограничения, которые никуда не денутся в ближайшем будущем. А пока мы наблюдаем, как появляются различные способы обхода этих ограничений и используем это в своей работе.

Проблема №1: LLM галлюцинирует

Мне понравилась фраза - “LLM галлюцинирует в 100% случаев, но в 80% модель права”. Любая мне известная LLM всегда стремится вам предоставить ответ, пусть даже и неверный. Фундаментально это сложно решить. Однако, стоит понимать, что есть разные причины галлюцинаций, и по отдельности их решить можно. В этом параграфе я разберу одну из таких причин.

Начну с теории. У каждой модели есть ограниченное context window - это объем текста, который LLM может одновременно учитывать или “помнить” при генерации ответа. Размер context window считают в токенах, но все усложняет то, что токен - величина не постоянная. Для упрощения считают, что один токен (для английского языка) это 4 символа. То есть грубо говоря 100 токенов вмещает 75 английских слов.

Примеры размеров context window для разных моделей:

  • gpt-3 - 2,048 токенов (1,500 английских слов)
  • gpt-4o - 128,000 токенов (~96,000 английских слов)
  • gpt-4.1 - 1,000,000 (~750,000 английских слов).

Посчитать, сколько в вашем тексте токенов можно по ссылке https://platform.openai.com/tokenizer. Важная ремарка - размер контекста не определяет напрямую на сколько “умная” модель. Но способность держать больше контекста точно идет моделям на пользу.

Когда вы переписываетесь с ChatGPT, в рамках каждого диалога у вас есть этот самый лимит. Если лимит превышен - модели начинают забывать (вытеснять) факты из диалога и галлюцинировать.

Создатели популярных моделей используют один способ для обхода этого ограничения. Чтобы не передавать весь диалог вместе с каждым новым сообщением к модели, они создают краткую выжимку с основными фактами после каждого полученного нового сообщения, и используют эту выжимку как контекст вместо передачи всего диалога. Это позволяет вам вести диалог дольше, но некоторые факты все же теряются. Выжимки создаются теми же моделями, у которых те же ограничения. На ранних этапах зарождения LLM такой хак позволял увеличивать длину диалога. С ростом размера context window этот хак продолжает использоваться, но уже для оптимизации потребления вычислительных ресурсов (чем больше размер контекста, тем больше ресурсов требуется для обработки и генерации ответа).

Когда речь идет про разработку - принцип тот же. Однако я подозреваю, что Cursor и другие редакторы не создают выжимку из кода который вы шарите с ними, чтобы точность ответа была выше. И, как следствие, у вас быстрее заполняется контекстное окно.

Проблема №2: LLM использует устаревшую информацию

Каждая модель обучена на разных сетах данных, которые могут не включать в себя какие-то специфичные данные, такие как информация о последних версиях вашего любимого фреймворка. Да и в целом, могут и вовсе не знать о его существовании. Для не особо популярных технологий меньше информации в интернете, а следовательно и количество данных для обучения содержит меньше информации, что так же приводит к галлюцинациям, так как модели всегда стремятся дать какой-то ответ.

Модели широкого спектра очень популярны (GPT, Claude, Gemini и т.д.), но также набирают популярность и модели узкого спектра, натренированные на специализированных сетах данных. Например, модели конкретно для программирования (OpenAI Codex), или медицинские модели. Ввиду того, что обучаются такие модели на релевантном материале, их результаты работы - ощутимо лучше. Однако так же, как и в случае с общими моделями, их знания ограничиваются данными, включенными в обучение.

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

Также важно упомянуть, что модели не имеют доступа к интернету, однако все основные игроки на рынке AI внедрили возможность поиска в интернете и использования результатов поиска в рамках вашего диалога. Это позволяет получать доступ к свежей информации, даже несмотря на то, что модель была обучена на старых данных. Как наверняка это реализовано - сказать сложно, но один из способов этой реализации - это разработка агента на базе MCP протокола. В детали вдаваться тут не буду, но замечу, что проще всего думать, что MCP - это протокол, по которому модели могут взаимодействовать с внешними сервисами, понимать список их функций и выполнять их.

Проблема №3: Каждый раз приходится объяснять все по новой

Модель сама по себе не имеет памяти. Она не может записывать то, что вы в нее отправляете. Однако все крупные игроки внедрили эмуляцию “памяти” в свои официальные клиенты. Например, ChatGPT, по ходу ваших диалогов своими моделями определяет “факты” о вас, которые имеет смысл сохранить. А потом использует эти факты как часть контекста для ваших чатов. Это и создает иллюзию того, что модель кое-что знает о вас. Также, память можно реализовать с помощью упомянутого ранее MCP или RAG.

Так что, если при разработке вы устали повторять одно и тоже, придется найти механизм эмуляции “памяти” для модели. И такой способ есть, об этом будет ниже.

Как решать эти проблемы в Cursor AI

Описанные проблемы и способы обхода могут казаться очевидными и я уверен, что многие уже знакомы с ними так или иначе. Но с учетом того, что я регулярно объясняю одно и то же разным людям, есть пустота, которую хочется заполнить.

Давайте на примере Cursor AI разберемся, как можно решать перечисленные выше проблемы конкретно для разработки.

1. Ограничение Context Window

Любые ресурсы ограничены. И так же стоит относится к LLM, здесь нет никакой магии.

Вот несколько практик, которые помогут вам сталкиваться с галлюцинированием реже из-за размера Context Window:

Создавайте новые диалоги как можно чаще

Старайтесь следовать принципу: 1 проблема/задача/вопрос = 1 диалог. Когда диалог получается большим - просите создать выжимку для нового диалога и копируйте ее в новый диалог. Также вспомните ситуацию, когда во время разговора вы резко меняли тему и ваш собеседник отвечал что-то не по теме. С моделями такое тоже случается, когда вы смешиваете вопросы, поэтому стоит создавать новый диалог для обсуждения чего-то не связанного с предыдущей темой.

Передавайте в диалог только необходимый контекст

Вы можете выбрать весь проект в качестве контекста и получить хороший результат. И такое возможно, но в основном только для маленьких проектов. Для средних и больших, увы, придется выбирать контекст вручную.

Переключайтесь на модель с бОльшим context window

Иногда требуется загрузить больше контекста, и в этом случае вы можете попробовать переключиться на модель с большим размером context window. Но для этого придется познакомиться с теми моделями, которые представлены в Cursor и изучить их характеристики. Тут вы можете познакомится с описанием моделей от OpenAI.

Ограничьте индексацию проекта

У Cursor есть механизм .cursorignore. Он позволяет Cursor’у игнорировать и не индексировать определенные части вашего проекта. Тем самым сужая scope проекта и увеличивая скорость при поиске. Это актуально для монорепозиториев и больших проектов. Подробнее тут.

2. Доступ к актуальной информации

Досадно, когда ты уже используешь React 19, а Cursor подсказывает только по 18 версии, так как модель была обучена на данных, когда 19 версии еще не было.

Разработчики Cursor предлагают несколько способов, как решить эту проблему.

Используйте тег @docs

При использовании тега @docs <url> и предоставления ему ссылки на актуальную документацию, Cursor запустит индексацию страниц, и по завершении будет помогать вам уже с полным пониманием новых фишек фреймворка.

Точно так же решается проблема с внутренней документацией. Строго говоря, вы можете скормить и swagger документацию от вашей внутренней апишки.

Используйте тег @web

Для поиска другой информации в сети, не покидая вашей IDE, воспользуйтесь тегом @web запрос. Казалось бы ничего особенного, загуглить можно и без этого, но тут можно работать с этой информацией в рамках того же чата. Так могут подтягиваться решения со StackOverflow, например.

Используйте MCP

Cursor позволяет подключить любые MCP, которые потом будут использоваться в ваших чатах при необходимости. Один из примеров - MCP context7 который как раз помогает получать актуальную документацию.

3. Учим Cursor запоминать

Что может быть интереснее, чем каждый раз объяснять Cursor, как у вас организованы файлы и методы? Или как создать новый API в вашем проекте? Или стоит ли использовать внешние библиотеки, либо ограничиваться стандартной библиотекой? Или может как устроена межсервисная архитектура и в чем основная цель проекта?

Ссылаемся на старые чаты

Cursor недавно добавил возможность ссылаться на ваши старые чаты. Это можно использовать в формате “сделай так же, как и в том чате”, либо как продолжение связанной задачи.

Ссылаемся на файлы

Неочевидно, но тоже можно использовать в формате “проанализируй этот файл/папку и сделай так же”.

Cursor Rules

У Cursor и других IDE уже есть ответ по части организации памяти - cursor rules. Это файл (либо набор файлов в случае Cursor), которые передаются автоматически (или вручную) в рамках вашего контекста. Таким образом, при наличии документации в формате cursor rules, вам не придется больше повторять себя, а Cursor будет ориентироваться на ваши существующие стандарты.

Да, это по факту документация, и да, ее нужно писать. Cursor, как и junior разработчик нуждается в объяснениях и руководстве. Хотя некоторые агенты (например JetBrains Junie) делают успехи в анализе существующего кода, пытаясь сделать так же. Такой подход хоть и удобен, но не всегда эффективен, особенно, когда работаешь со старым кодом.

Хорошие новости в том, что всегда можно попросить Cursor сгенерировать и сохранить правила на основе вашего чата (прям так и спросить). А буквально несколько дней назад они реализовали команду /Generate Cursor Rules, которая именно это и делает. Да, результат придется поревьювить и, возможно, попросить пару раз внести правки, но это значительно сокращает трудозатраты на описание.

И как приятное дополнение - новички в вашей команде смогут читать ваши cursor rules как документацию и стандарты.

В заключении

В заключении, предлагаю вам подумать и ответить на следующие вопросы:

  1. Сколько токенов в этой статье?
  2. Как потенциально себя будет вести Cursor при работе с файлом на 10 тысяч строк?
  3. Что требуется сделать, чтобы эффективно провести рефакторинг с помощью Cursor?
  4. Как заставить Cursor запускать линтеры или сборку в конце каждого чата и исправлять ошибки автоматически?

Эффективное использование вполне возможно при понимании, какие ограничения есть у LLM.