- Дата публикации
Как ускорить regex-поиск для AI-агентов: индекс вместо бесконечного grep
Что появилось / что изменилось
Команды, которые разрабатывают агентные инструменты вроде Cursor, столкнулись с простой проблемой: обычный grep, даже в виде ripgrep, перестал успевать за размерами репозиториев. Агенту нужно много раз подряд искать по коду с помощью регулярных выражений, а монорепозитории в больших компаниях давно вышли за пределы «пара секунд на поиск».
Сценарий такой: большинство фреймворков для агентов по умолчанию дергают ripgrep. Сам ripgrep очень быстрый, его автор Эндрю Галлант много лет оптимизирует именно скорость поиска по регуляркам. Но у него фундаментальное ограничение: каждый запрос все равно должен пройтись по содержимому всех файлов.
В небольших проектах это терпимо. В огромных монорепозиториях, с которыми работает Cursor и его Enterprise‑клиенты, один вызов rg легко занимает больше 15 секунд. Если агент пишет код, а вы его активно направляете, такие задержки убивают весь интерактивный сценарий.
Ответ разработчиков — не пытаться еще раз разогнать grep, а индексировать текст под задачи агентов. То есть сделать для regex-поиска то же самое, что IDE уже много лет делает для «Go To Definition»: заранее построить индекс и ходить по нему, а не по всему диску.
Как это работает
Базовая идея не новая. Еще в 1993 году Зобел, Моффат и Сакс-Дэвис описали подход к ускорению regex-поиска через n‑граммы и инвертированные индексы. N‑грамма — это просто кусок строки фиксированной длины n символов. Например, для n=3 слово window превратится в win, ind, ndo, dow.
Из этих n‑грамм можно собрать инвертированный индекс. Он устроен так:
- Вы берете набор документов — файлы в репозитории.
- Разбиваете текст на токены. В самом простом случае это отдельные слова или n‑граммы.
- Каждый токен становится ключом в структуре вида «словарь → список документов».
- Для каждого токена храните «posting list» — список идентификаторов файлов, где он встретился.
Когда нужно найти несколько токенов сразу, вы берете их posting list и пересекаете. В результате получается набор документов, в которых есть все указанные токены.
Трюк с регулярными выражениями в том, что их можно разложить на набор n‑грамм, которые точно должны встретиться в любой строке, удовлетворяющей паттерну. Тогда агент сначала по индексу быстро сужает пул кандидатов, а уже потом запускает полноценный regex‑матч только по этим файлам или строкам. Вместо полного обхода монорепозитория вы получаете две стадии: быстрый фильтр по индексу и точная проверка по настоящей регулярке.
Идея, о которой многие узнали из поста Расса Кокса 2012 года после закрытия Google Code Search, до сих пор лежит в основе новых решений. Все современные варианты индексирования для regex‑поиска так или иначе опираются на инвертированные индексы и разбор регулярных выражений на дерево обязательных фрагментов.
Что это значит для вас
Если вы пишете или внедряете агентные инструменты поверх больших репозиториев кода, один вывод очевиден: полагаться только на ripgrep уже недостаточно. Агенту нужен быстрый способ многократно искать по коду с регулярками, иначе вы будете смотреть на прогрессбар вместо живого диалога с инструментом.
Практически это означает три вещи:
- Для монорепозитория стоит закладывать отдельный сервис или локальный индекс, который хранит n‑граммный или похожий инвертированный индекс для всех файлов. Агент сначала спрашивает его, а не бежит по диску.
- Для локальной разработки разумно комбинировать LSP‑сервер и regex‑индексирование. LSP дает быстрые переходы по типам и определениям, индекс по n‑граммам закрывает «грязные» текстовые запросы вроде поиска по логам, SQL, конфигам и шаблонам.
- Для небольших проектов можно ничего не менять. Если
rgотрабатывает за доли секунды, выгода от отдельного индекса может не окупить сложность поддержки.
Агентам все равно, каким именно бинарником вы ищете — им важна задержка между запросом и ответом. Если ваш типичный regex‑поиск живет в диапазоне 10–15 секунд, без индексирования вы упретесь в потолок комфортности работы, даже если используете самый быстрый grep.
Место на рынке
Поиск по коду для людей давно решен: есть JetBrains IDE, Visual Studio Code с LSP, встроенные навигаторы в GitHub и GitLab. Они держат синтаксические и типовые индексы и отлично справляются с задачами вроде «перейти к определению» или «показать все использования функции».
Агентам нужно другое. Им приходится выполнять десятки и сотни текстовых запросов подряд, в том числе с регулярными выражениями, и классические IDE‑индексы здесь мало помогают. Поэтому связка «агент + ripgrep» стала негласным стандартом, но упирается в масштаб монорепозиториев.
Отдельные решения вроде ripgrep остаются лучшим выбором, если вы ищете по файлам вручную или автоматизируете разовые задачи. Но как только кодом занимается агент, ключевое сравнение уже не между rg и классическим grep, а между «сырым» grep‑поиском и индексированным regex‑поиском поверх инвертированного индекса.
Цифр наподобие «в X раз быстрее, чем ripgrep» авторы не приводят, но сама архитектура понятна: вы платите временем и ресурсами за построение индекса, и взамен резко снижаете среднее время одного regex‑запроса по огромному репозиторию. Для агентных сценариев это часто важнее, чем еще одна микрооптимизация движка регулярных выражений.