Я поломался, поломался — и поломался на осколки. Признаю́: железные помощники Т9 действительно могут приносить пользу в разработке. Единственное, что мне не нравилось — то, что весь проект большой и хорошо натренированной модели не скормишь, а значит — неизбежны потери контекста, размывание смыслов и джойсовские галлюцинации.
Я уже давно понял: если мне нужно, чтобы что-то было сделано хорошо, — делегирование отпадает, придётся брать в руки молоток самому. Это касается любых жизненных аспектов: варки борща, замены сантехники, перевода Эдгара Аллана По или Антонио Мачадо на русский, или, там, программирования.
Когда БЯМ научились подключать сторонние MCP-сервера, произошел качественный скачок. Теперь не нужно файнтьюнить модель, можно файнтьюнить буковку «R» из акронима «RAG». Я-то лучше знаю, как правильно извлекать смыслы из моего личного контента. Если речь про код — лучше всего искать правду в AST.
Так и был зачат Ragex — MCP-сервер для семантического анализа кодовых баз с элементами чёрной магии. Проект, понятно, написан на Elixir, потому что ну а на чем еще?
Ragex — это (вроде, довольно успешная) попытка объединить статический анализ кода с векторными представлениями и графами знаний. В результате получается система, которая может ответить на вопросы типа «где у меня функция, которая парсит JSON?» не хуже, чем ваш коллега, который неделю назад это писал, но уже всё забыл.
Занахрена́?
Я задумывал всё это как retrieval engine для передачи в какой-нибудь клод, но, поскольку сам я ассистентами не пользуюсь, в результате получилось решение, подходящее и для подключения к БЯМ, и для помощи (если не замены) обычному LSP.
Три кита, на которых держится Ragex:
Local-first: Никаких внешних API. Всё работает локально. Код не отправляется в облако на растерзание корпоративным серверам. Параноики оценят. Кроме того, использовать БЯМ для извлечения контекста из кода — глупо, когда у нас есть AST. Но простенький локальный семантический поиск я тоже, конечно, прикрутил.
Гибридный поиск: Символьный анализ (AST) + семантический поиск (эмбеддинги) + графы знаний. Это как смотреть в тринокль: один окуляр видит близко, другой далеко, третий вообще смотрит в прошлое.
Производительность: Запросы выполняются за разумное время, иногда — в ущерб качеству. Потому что жизнь коротка, а ждать результатов анализа кода — это издевательство и вообще прерогатива создателей IDE корпоративного масштаба.
Архитектура
Ragex состоит из нескольких слоёв, каждый из которых старается не испортить работу остальных:
┌─────────────────────────────────────┐
│ MCP Server (JSON-RPC 2.0) │
│ stdio + Unix Socket │
└──────────────┬──────────────────────┘
│
┌───────┴────────┐
▼ ▼
┌─────────────┐ ┌──────────────┐
│ Анализаторы │ │ Graph Store │
│ (AST) │ │ (ETS) │
└──────┬──────┘ └──────┬───────┘
│ │
│ ┌──────┴───────┐
│ ▼ ▼
│ ┌──────────┐ ┌─────────────┐
└──►│ Vector │ │ Bumblebee │
│ Store │ │ (ML Model) │
└──────────┘ └─────────────┘
Компоненты
1. MCP Server
Реализация Model Context Protocol — протокола, который позволяет AI-ассистентам общаться с внешними инструментами. JSON-RPC 2.0 через stdio (для интеграции) и Unix-сокет (для интерактивного использования). Люди, использующие ассистентов могут подключить этот MCP туда, я просто добавил его в свой LunarVim (см. ниже).
2. Анализаторы
Парсеры готовы для Elixir, Erlang, Python (частично), JavaScript/TypeScript (наброски), скоро добавлю раст и го, наверное. Каждый парсер извлекает AST, модули, функции, вызовы. Elixir и Erlang используют нативные парсеры, Python вызывает через порт в питоновский модуль ast, JavaScript использует регулярные выражения (потому что жизнь — боль).
3. Graph Store
Граф знаний на основе ETS (Erlang Term Storage). Узлы: модули, функции, вызовы. Рёбра: :calls, :imports, :defines. Поверх графа работают алгоритмы: PageRank, поиск путей, метрики центральности, детекция сообществ.
4. Embeddings & Vector Store
Локальная ML-модель (по умолчанию — sentence-transformers/all-MiniLM-L6-v2, настраивается в конфигах) через Bumblebee. Генерирует 384-мерные векторные представления для каждой функции и модуля. Косинусная близость для семантического поиска. Всё работает без интернета.
5. Hybrid Retrieval
Reciprocal Rank Fusion (RRF) — алгоритм объединения результатов символьного и семантического поиска. Три стратегии: fusion (RRF), semantic-first, graph-first.
6. Editor System
Безопасное редактирование кода с атомарными операциями, бэкапами, валидацией синтаксиса, форматированием. Поддержка multi-file транзакций и семантического рефакторинга через AST.
Зачем это вообще нужно?
1. Семантический поиск по кодовой базе
Проблема: Вы помните, что где-то была функция для работы с HTTP-запросами, но где именно — забыли. Название тоже не помните. Grep не поможет.
Решение: Семантический поиск, да.
# Подключаемся к Ragex
alias Ragex.VectorStore
# Ищем функцию
{:ok, results} = VectorStore.search("HTTP request handler",
limit: 5,
threshold: 0.7,
node_type: :function
)
# Результаты отсортированы по релевантности
Enum.each(results, fn {node, similarity} ->
IO.puts("#{node.name} (#{similarity})")
IO.puts(" File: #{node.metadata.file}")
IO.puts(" Line: #{node.metadata.line}")
end)
2. Анализ зависимостей и вызовов
Проблема: Нужно понять, откуда вызывается функция process_data/2, и что она сама вызывает. Рефакторинг без такой информации — русская рулетка (которая в запутанных случаях с макросами — до сих пор лучше удается^W удавалась эвристикам из навороченных IDE, чем БЯМ).
Решение: Граф вызовов.
alias Ragex.Graph.Store
alias Ragex.Graph.Algorithms
# Найти все функции, которые вызывают process_data/2
callers = Store.get_callers({:function, "MyModule.process_data/2"})
IO.puts("Callers:")
Enum.each(callers, fn caller ->
IO.puts(" - #{caller.id}")
end)
# Найти все функции, которые вызывает process_data/2
callees = Store.get_callees({:function, "MyModule.process_data/2"})
IO.puts("\nCallees:")
Enum.each(callees, fn callee ->
IO.puts(" - #{callee.id}")
end)
# Найти все пути между двумя функциями (с лимитом)
paths = Algorithms.find_all_paths(
{:function, "MyModule.start/0"},
{:function, "MyModule.process_data/2"},
max_depth: 10,
max_paths: 100
)
IO.puts("\nFound #{length(paths)} paths")
Защита от плотных графов: Если у узла >10 рёбер, Ragex предупредит о потенциальных проблемах с производительностью. Параметр max_paths предотвращает зависание на экспоненциальных взрывах. Не вижу проблемы дать этот параметр на откуп разработчику.
3. Поиск бутылочных горлышек в архитектуре
Проблема: Какие функции являются критичными для всей системы? Если они упадут — всё рухнет.
Решение: Betweenness Centrality (метрика центральности по посредничеству — если кто знает, как перевести менее коряво, свистните, пожалуйста).
alias Ragex.Graph.Algorithms
# Вычислить betweenness centrality для всех функций
scores = Algorithms.betweenness_centrality(
max_nodes: 1000,
normalize: true
)
# Отсортировать по убыванию
top_bottlenecks = scores
|> Enum.sort_by(fn {_node, score} -> score end, :desc)
|> Enum.take(10)
IO.puts("Top 10 bottleneck functions:")
Enum.each(top_bottlenecks, fn {node_id, score} ->
IO.puts(" #{node_id}: #{Float.round(score, 4)}")
end)
4. Определение (извлечение) архитектурных модулей
Проблема: Код разросся, структура неочевидна. Хотелось бы понять, какие модули логически связаны и образуют кластеры.
Решение: Community Detection (алгоритм Louvain).
alias Ragex.Graph.Algorithms
# Найти сообщества (кластеры модулей)
communities = Algorithms.detect_communities(
algorithm: :louvain,
hierarchical: true,
resolution: 1.0
)
IO.puts("Found #{map_size(communities)} communities")
# Группировка по сообществам
grouped = Enum.group_by(communities, fn {_node, community} -> community end)
Enum.each(grouped, fn {community_id, members} ->
IO.puts("\nCommunity #{community_id} (#{length(members)} nodes):")
Enum.each(members, fn {node_id, _} ->
IO.puts(" - #{node_id}")
end)
end)
5. Безопасный рефакторинг
Проблема: Нужно переименовать функцию old_function/2 в new_function/2 во всём проекте. Ручной рефакторинг — это ошибки и страдания.
Решение: Семантический рефакторинг через AST. Да, даже для питона.
alias Ragex.Editor.Refactor
# Переименовать функцию во всём проекте
result = Refactor.rename_function(
:MyModule,
:old_function,
:new_function,
2, # arity
scope: :project,
validate: true,
format: true
)
case result do
{:ok, details} ->
IO.puts("Success! Updated files:")
Enum.each(details.edited_files, &IO.puts(" - #{&1}"))
{:error, reason} ->
IO.puts("Rollback performed. Error: #{inspect(reason)}")
end
Через граф знаний нашли все места, откуда вызывается функция, заменили AST по месту (то есть, работает даже для сгенерированного мюнхгаузен-кода), форматирует результат, валидирует синтаксис, и (!) атомарно применяет изменения (или откатывает всё при ошибке).
6. Multi-File транзакции
Проблема: Нужно одновременно изменить несколько файлов. Если хоть одно изменение невалидно — откатить всё.
Решение: Атомарные транзакции.
alias Ragex.Editor.{Transaction, Types}
# Создать транзакцию
txn = Transaction.new(validate: true, format: true)
|> Transaction.add("lib/module_a.ex", [
Types.replace(10, 15, "def new_version do\n :ok\nend")
])
|> Transaction.add("lib/module_b.ex", [
Types.insert(20, "@doc \"Updated documentation\"")
])
|> Transaction.add("test/module_test.exs", [
Types.replace(5, 5, "# Updated test")
])
# Применить все изменения атомарно
case Transaction.commit(txn) do
{:ok, result} ->
IO.puts("Edited #{result.files_edited} files successfully")
{:error, result} ->
IO.puts("Transaction rolled back!")
IO.puts("Errors: #{inspect(result.errors)}")
end
Тут важна атомарность: при любой ошибке — автоматический откат всех изменений, все бэкапы хранятся (в ~/.ragex/backups/<project_hash>/) и т. д.
7. Бонус-трек — экспорт в DOT и D3.js
Интеграция с LunarVim
LunarVim — это мой редактор кода, Neovim на стероидах. Ragex интегрируется через MCP и предоставляет команды для семантического поиска прямо из редактора.
Установка
Скопируйте конфигурационные файлы:
cp ragex/lvim.cfg/lua/user/*.lua ~/.config/lvim/lua/user/
Добавьте в ~/.config/lvim/config.lua:
-- Ragex integration
local ragex = require("user.ragex")
local ragex_telescope = require("user.ragex_telescope")
-- Setup
ragex.setup({
ragex_path = vim.fn.expand("~/Proyectos/Ammotion/ragex"),
enabled = true,
debug = false,
})
-- Keybindings (using "r" prefix)
lvim.builtin.which_key.mappings["r"] = {
name = "Ragex",
s = { function() ragex_telescope.ragex_search() end, "Semantic Search" },
w = { function() ragex_telescope.ragex_search_word() end, "Search Word" },
f = { function() ragex_telescope.ragex_functions() end, "Find Functions" },
m = { function() ragex_telescope.ragex_modules() end, "Find Modules" },
a = { function() ragex.analyze_current_file() end, "Analyze File" },
d = { function() ragex.analyze_directory(vim.fn.getcwd()) end, "Analyze Directory" },
c = { function() ragex.show_callers() end, "Find Callers" },
r = { function()
vim.ui.input({ prompt = "New name: " }, function(name)
if name then ragex.rename_function(name) end
end)
end, "Rename Function" },
g = { function() ragex.graph_stats() end, "Graph Stats" },
b = { function() ragex.show_betweenness_centrality() end, "Betweenness" },
n = { function() ragex.show_communities("louvain") end, "Communities" },
e = { function() ragex.export_graph("graphviz") end, "Export Graph" },
}
Использование

Пример Workflow
Типичный сценарий работы с Ragex в LunarVim:
1. Открыли проект: <leader>rd (анализировать директорию, по умолчанию — автоматом)
2. Нужно найти функцию: <leader>rs → "database connection"
3. Нашли функцию, открыли файл <Enter> в телескопе
4. Хотим узнать, кто вызывает: <leader>rc
5. Решили переименовать: <leader>rr → "connect_to_db"
6. Проверили статистику: <leader>rg
7. Экспортировали граф для визуализации: <leader>re
Настройка Auto-Analyze
Ragex может автоматически анализировать код при сохранении файлов:
ragex.setup({
auto_analyze = true,
auto_analyze_on_start = true,
auto_analyze_dirs = { "/path/to/project" },
})
Инкрементальные обновления: Ragex отслеживает изменения через SHA256-хеширование и перегенерирует эмбеддинги только для изменённых файлов.
Память
На совсем жиденьких лэптопах я бы не стал пользоваться Ragex.
ML-модель: ~400 MB RAM
ETS-таблицы: линейный рост, ~400 bytes на узел
Эмбеддинги: ~400 bytes на вектор (384 float32)
Кеш-файлы: ~15 MB на 1000 сущностей
Настройка
Поддержка пользовательских Embedding-Моделей
Ragex поддерживает 4 предконфигурированных модели, но не для смены на лету:
# config/config.exs
config :ragex, :embedding_model, "sentence-transformers/all-MiniLM-L6-v2"
# Альтернативы:
# - "sentence-transformers/all-MiniLM-L12-v2" (больше точность)
# - "sentence-transformers/paraphrase-MiniLM-L3-v2" (быстрее)
# - "sentence-transformers/multi-qa-MiniLM-L6-cos-v1" (для Q&A)
Миграция моделей:
mix ragex.embeddings.migrate --from old_model --to new_model
File Watching
Автоматическое переиндексирование при изменении файлов:
# Через MCP
{"method": "tools/call", "params": {
"name": "watch_directory",
"arguments": {"path": "/project/lib"}
}}
# В коде
Ragex.FileWatcher.watch("/project/lib")
Экспорт Графа для Визуализации
alias Ragex.Graph.Algorithms
# Graphviz DOT format
{:ok, dot} = Algorithms.export_graphviz(
color_by: :betweenness,
include_communities: true
)
File.write!("graph.dot", dot)
# Рендерим через Graphviz
System.cmd("dot", ["-Tpng", "graph.dot", "-o", "graph.png"])
# D3.js JSON format (для веб-визуализации)
{:ok, json} = Algorithms.export_d3_json(include_communities: true)
File.write!("graph.json", json)
Ух, обожаю картинки и D3.js-диаграммки, которые можно пошевелить мышкой.
Ограничения и подводные камни
Потому что честность — моё третье «я»:
JavaScript/TypeScript анализатор: Использует регулярные выражения. Работает для «простых» случаев. Когда-нибудь, может быть, руки дойдут.
Семантический рефакторинг: Пока только для Elixir. Erlang/Python/JS в планах, но не сегодня.
Плотные графы: Если у функции >100 вызовов, поиск путей может занять вечность. Используйте
max_pathsиmax_depth.Память: 400 MB для модели — это цена локального ML. Если RAM критична, можно отключить эмбеддинги (но зачем тогда вообще Ragex?).
Cold start: Первая генерация эмбеддингов занимает время. После этого — кеширование спасает.
В общем
Ragex — это попытка сделать анализ кода менее болезненным и более семантическим. Граф знаний + векторные эмбеддинги + алгоритмы на графах = инструмент, который может ответить на вопросы типа «где это используется?», «что это делает?», «почему всё сломалось?». А еще это MCP-сервер, который можно подключить к вашему ассистенту кода, чтобы тому тоже было проще ответить на эти вопросы.
MCP-протокол, потому что AI-ассистенты — будущее (или настоящее, в зависимости от того, насколько вы параноик).
Интеграция с LunarVim превращает рефакторинг в нечто почти приятное. Семантический поиск работает, граф не врёт, рефакторинг никогда не ломает код. В теории.
P. S. Если возникло желание попробовать, скачайте проект, скачайте зависимости, запустите ./start_mcp.sh и наслаждайтесь. Если что-то сломается — issue в GitHub. Если всё заработало — это, конечно, тоже можно написать в issue, но кто так делает?
P. P. S. Проект open-source, лицензия MIT. Делайте что хотите, на свой страх и риск. Автор не несёт ответственности за потерянное время, сломанный код и экзистенциальные кризисы, вызванные чтением чужих графов вызовов.
Репозиторий: https://github.com/am-kantox/ragex
Комментарии (23)

whoisking
02.01.2026 14:12Выглядит интересно. А планируется статья на elixirforum или чём-то подобном? Было бы интересно почитать мнения и, возможно, какие-то отзывы от потенциальной аудитории бетатестеров.

cupraer Автор
02.01.2026 14:12Да, конечно, на выходных напишу на elixirforum, мне хотелось понять по реакции аудитории, что подсветить, что — наоборот — затенить, и главное — что переделать. А то ко мне там относятся слишком уж уважительно, и конструктивную критику я услышу вряд ли.

vkni
02.01.2026 14:12Как всегда, есть вопросы:
1. Аналоги - вы их искали/сравнивали или нет? (только не понимайте, пожалуйста, это как агрессию — один умный и крайне успешный человек из нашей общей Alma Mater упоминал, что часто правильно не делать "поиск по литературе", а пытаться решить задачу самому, а уже после решения искать. А второй момент — если вы нашли своё решение, то нельзя отчаиваться — большой вероятностью оно другое).
2. Как насчёт комментариев? В них часто дофига информации.
3. Обычно канонического AST нет, а есть разные Parsetree, в зависимости от ситуации. Это вы рассматривали? Или на данном этапе это слишком дотошно?
4. А сколько вы это херачили по времени?
cupraer Автор
02.01.2026 14:12Какая агрессия, вы чего? Вот уж кому-кому, а вам такие оговорки точно не требуются.
Искал. Не нашел. Похоже, идея доставать AST для RAG для MCP пришла (в мире опенсорса, по крайней мере) мне в голову первому.
Да, в планах есть. Для эликсира и эрланга они причем фактически рядом с AST в формализованных чанках лежат.
Расматривал. Я питон, например, поддерживаю — и в планах раст. У них нативного AST нет, но есть библиотеки, которые «строят» этот AST, и я вызываю их через шелл.
Да сложно сказать, я месяц потратил на пережевывание идеи, прикидывал варианты, то-сё; а сам код дней за пять написал.

vkni
02.01.2026 14:121 — Тогда есть https://glean.software/ — это родственный проект, крайне не рекомендую пытаться развернуть у себя — потратите массу времени, т.к. это продукт кровавого хаскельного ынтерпрайза. Но документацию проглядеть, кмк, полезно. MCP к нему, кажется, уже прикручен коллегой месяц назад. Там к базе данных добавлен собственный велосипед аля типизированный Пролог для запросов. Как всегда, с косяками.
То есть, у вас система состоит из нескольких компонент: парсер (внешний), база данных, язык «запросов» поверх языка базы данных, внешний интерфейс.2 — Круто.
--------------------------------------
Неповоротливость Glean'а отчасти обусловлена тем, что он сделан для Экстремистской Организации с её объёмами кода и клиент-серверной архитектурой. У вас, насколько я понимаю, проект как Git по сравнению с SVN.
cupraer Автор
02.01.2026 14:12Ух ты, спасибо. Завтра посмотрю. Меня не пугает хаскель, в принципе :)
парсер (внешний), база данных, язык «запросов» поверх языка базы данных, внешний интерфейс
Я думал изначально именно о такой архитектуре — и отмел её ровно потому, что это не то, что я хочу разворачивать у себя вместо LSP.
Я допишу генерацию escript + elixir archive, и моя балалайка будет разворачиваться в один клик.

vkni
02.01.2026 14:12Ещё есть тема для раздумий про эволюцию. Очевидно, что в том наборе, который вы сделали, это надо обсуждать, т.к. языки, особенно Питон, всё время меняются. Какие-то конструкции приходят, какие-то уходят...
Да и код меняется. Причём меняется быстрее. И в какой-то момент у нас может возникнуть ситуация, когда «исторический» код не разбирается современным парсером.И ещё в какой-то момент может быть придётся мигрировать с парсера на парсер для того же Питона, скажем. Или держать 2 парсера.

cupraer Автор
02.01.2026 14:12Да, спасибо, над этим я пока не думал.Подумал: не будет никаких проблем; я ничего не делаю с питоном сам, я делегирую (через erlang port, то есть, через шелл) — питоновской родной библиотеке, которая строит их AST. На машине разработчика ожидается тот питон, с которым он работает именно в этом проекте, так что если проект компилируется — я и AST получу без сучка и задоринки.

funca
02.01.2026 14:12Для синтаксического разбора часто используют tree-sitter (например https://aider.chat/2023/10/22/repomap.html, https://ast-grep.github.io/), который поддерживает кучу языков. Но он больше оптимизирован на скорость, нежели полноту.
Более глубокий анализ можно выдрать из LSP (например https://github.com/axivo/mcp-lsp). Но здесь могут быть сложности с развертыванием и вопросы к перфомансу.
Из взрослого есть CodeQL от GitHub https://codeql.github.com. Он кроме AST поддерживает разные варианты графов: call graph, control flow graph, data flow graph, api graph. Из минусов сложные настройки и никакущая документация, которой много, но она ни чего не объясняет.

cupraer Автор
02.01.2026 14:12Про схожие проекты с tree-sitter’ом я знаю, конечно; вот самый перспективный, на мой взгляд: https://github.com/vitali87/code-graph-rag
За CodeQL спасибо, прошел мимо меня, гляну.А, так это гитхабовский query language, я его не опознал по названию. Он во-первых делает немного иное, а во-вторых (и в-главных) — у него ровно та же родовая травма, что у всех остальных: они с кодом, как с текстом работают (в лучшем случае — с внутренним представлением tree-sitter’а или LSP). А я — напрямую с нативным AST.Более глубокий анализ можно выдрать из LSP
Вот это я не очень понял: а LSP его откуда возьмет?
В каком-то смысле Ragex уже сейчас может на 90% заменить LSP, причем сделает это лучше (например, он понимает сгенерированный макросами код by design, а LSP и tree-sitter — нет, и никогда не научатся).

funca
02.01.2026 14:12Вот это я не очень понял: а LSP его откуда возьмет?
Под капотом конкретных реализаций LSP уже наворотили не только синтаксический анализ, но и поддержку различных библиотек, фреймворков, пакетеых менеджеров, систем сборки и т.п. специфики, которая не считывается с уровня лишь синтаксиса языка программирования.
CodeQL для компилируемых языков вообще по умолчанию пытается делать сборку проекта, чтобы получить еще больше данных.

cupraer Автор
02.01.2026 14:12Под капотом конкретных реализаций LSP уже наворотили не только синтаксический анализ, но и […]
Ну не надо со мной, как с ребенком-то разговаривать. Я не с нуля взялся такой проект делать, я как бы сначала в LSP нашего стека покоммитил, примерно представляю себе, как оно там внутри.
не считывается с уровня лишь синтаксиса языка программирования
Что именно не считывается с уровня синтаксиса языка программирования? Если можно, конкретный пример: вот LSP, вот кусок кода в нем, который пользуется ×××, потому что с уровня синтаксиса данную необходимую LSP информацию не получить.
CodeQL для компилируемых языков вообще по умолчанию пытается делать сборку проекта, чтобы получить еще больше данных.
Им это нужно, чтобы расширить семантическое поле на вопросы типа «какая библиотека у меня парсит json» — в RAG для MCP это бессмысленно.

funca
02.01.2026 14:12Ну не надо со мной, как с ребенком-то разговаривать.
В каждом из нас живёт внутренний ребёнок, который умеет радоваться, огорчаться, а порой даже капризничать)
Что именно не считывается с уровня синтаксиса языка программирования?
Например, для построения графа зависимостей между модулями TypeScript требуется анализ файлов конфигурации компилятора где могут быть определены кастомные пути и алиасы https://www.typescriptlang.org/tsconfig/#paths. Такие конфиги можно раскидать по разным папкам. Это может использоваться и внутри одного проекта (разные конфиги для кода и тестов), и для разных в случае монорепозиториев. Не могу рассказать, как это реализовано у них в LSP, я тут больше юзер.

cupraer Автор
02.01.2026 14:12анализ файлов конфигурации компилятора где могут быть определены кастомные пути и алиасы
Ух. Спасибо. Хотя, признаться, я не понимаю, как это можно упаковать в RAG (LSP) — выставлен некий environment, в нем какие-то свои конфиги, пути и алиасы как-то разрешены уже — вот по ним RAG/LSP и должен шарашить, как иначе-то? Сразу писать код для трёх окружений? А переключать как?

funca
02.01.2026 14:12Это был лишь один из примеров. Часто можно встретить проекты, где разные кусоки пишутся на разных языках. При этом они тесно связаны какими-то общими соглашениями. Это может быть специфичная структура директорий, соглашения по именованию, конфиги, аннотации, типы, API или даже все вместе. Код может лежать как в одном репозитории, так и в разных. Где-то зависимости прописаны строго (варианты .lock файлов), а где-то результат становится известен лишь после установки. Могут использоваться разные библиотеки или разные версии одной и той же библиотеки, порой несовместимые друг с другом.
Короче, код анализ в общем случае это сложная проблема, решение которой не сводится к одному лишь AST. У вас логичная идея - построить граф зависимостей. Но как добывать для него данные это креативная часть.
Dhwtj
:
Если бы текст начинался с:
"Я использую Ragex уже 6 месяцев. Вот три конкретных проблемы, которые он решил, и сколько времени я сэкономил"
...это была бы полезная статья.
Вместо этого — glorified portfolio project с оправданиями типа "параноики оценят" и "MCP-протокол, потому что AI-ассистенты — будущее".
Ну и статья написана LLM из обрывочных мыслей,
говна и палокриторики и раздувания важности без конкретики.