ariadne
Ariadne
Нить Ариадны — выход из лабиринта микросервисов.
Граф зависимостей API между сервисами и семантическая навигация по коду для микросервисной архитектуры. MCP stdio-сервер для ИИ-ассистентов (Claude Code, Cursor, Windsurf) с CLI-аналогом для скриптов. Статический анализ «только для чтения» на базе SQLite + TF-IDF + эмбеддингов.
Для кого это
ИИ-ассистенты (Claude Code, Cursor, Windsurf) — структурированное представление зависимостей между сервисами, подходящее для контекстного окна, вместо сырого вывода
grep.Backend-инженеры, отслеживающие функционал через 4+ сервиса — GraphQL, REST, Kafka и вызовы фронтенда, разрешаемые одним запросом.
Platform-инженеры и ревьюеры, выполняющие анализ влияния изменений — покажите полную цепочку вызовов, которую затрагивает изменение в одном сервисе, перед его деплоем.
Новые инженеры, изучающие топологию незнакомых микросервисов по одному бизнес-термину.
Related MCP server: TempoGraph
Зачем
Ariadne индексирует только слой контрактов — GraphQL-мутации, REST-эндпоинты, Kafka-топики, запросы фронтенда — и ничего больше. Эта узкая специализация позволяет результатам помещаться в контекстное окно ИИ.
Подход | Проблема, которую решает Ariadne |
| Тонет в DTO, тестах, конфигах |
IDE "Find Usages" | Останавливается на границах сервисов |
Дашборды сервис-меша | Требуют продакшн-трафика; нет привязки к фичам |
Инструменты полного AST / графа вызовов | Долго строятся; слишком много деталей |
Пример
Вы спрашиваете Claude: "где живет createOrder во всем стеке?" Claude вызывает query_chains в ходе диалога и получает:
Top Cluster #1 [confidence: 0.91]
Services: gateway, orders-svc, billing-svc, web
- [web] Frontend Mutation: createOrder
- [gateway] GraphQL Mutation: createOrder
- [orders-svc] HTTP POST /orders: createOrder
- [orders-svc] Kafka Topic: order-created
- [billing-svc] Kafka Listener: order-created → chargeCustomerClaude резюмирует: "createOrder — это GraphQL-мутация в gateway, которая перенаправляется в orders-svc через POST /orders, что публикует Kafka-событие order-created, которое потребляет billing-svc для списания средств с клиента."
~500 токенов на запрос-ответ. Эквивалентный grep -r createOrder по четырем репозиториям вернул бы 40+ совпадений в DTO, тестах и конфигах (~2000 токенов), при этом слой контрактов был бы скрыт.
Золотой путь
Рекомендуемый рабочий процесс, когда ИИ-ассистент управляет Ariadne через MCP-сервер.
1. query_chains(hint="createOrder")
→ ranked clusters across services. Start here for cross-service context.
2. expand_node(name="order-created")
→ one-hop neighbours of a known node. Within 10 min of a matching
query_chains, this auto-logs positive feedback — the expand IS the signal.
3. Read the files the returned clusters / neighbours point at.
4. log_feedback(hint, accepted=False, ...)
→ manual thumbs-down only. Positive feedback is captured in step 2.При получении stale_warning вызовите rescan() и повторите попытку. См. FAQ.
Быстрый старт
Три команды, затем перезапустите Claude Code.
pip install mcp onnxruntime tokenizers huggingface_hub
cp ariadne.config.example.json ariadne.config.json # edit repos inside
python3 main.py install ariadne.config.json ~/your-workspaceinstall идемпотентен — запускайте его повторно после получения нового кода или позвольте ассистенту вызвать rescan, когда он увидит stale_warning. См. --help для флагов (--no-scan, --force, --snippet, --marker).
Инструменты
Что видит ассистент после завершения install и перезапуска Claude Code:
Инструмент | Аргументы | Назначение |
|
| Бизнес-термин → кластеры между сервисами |
|
| Соседи известного узла в один прыжок |
| (нет) | Обновление индекса на месте при получении |
| (нет) | Руководство по настройке + диагностика конфигурации (отсутствие БД, пустой индекс, устаревшее сканирование) |
|
| Ручной дизлайк (позитивный фидбек неявный — см. Feedback boost в разделе Архитектура) |
Конфигурация
Формат конфига
{
"repos": [
{
"name": "gateway",
"path": "../gateway",
"scanners": ["graphql"]
},
{
"name": "orders-svc",
"path": "../orders-svc",
"scanners": [
"http",
"kafka",
{
"type": "backend_clients",
"client_target_map": { "billing": "billing-svc", "user": "user-svc" }
}
]
},
{
"name": "web",
"path": "../web",
"scanners": [
"frontend_graphql",
{
"type": "frontend_rest",
"base_class_service": { "OrdersApiService": "orders-svc" }
}
]
}
]
}Пути разрешаются относительно файла конфигурации. Каждый репозиторий перечисляет один или несколько сканеров — либо по имени (строка), либо как объект с дополнительными опциями.
Доступные сканеры
Сканер | Что ищет |
|
|
| Spring |
| Топики в Spring |
| Исходящие вызовы Spring |
| TypeScript |
| Вызовы |
| Определения |
Пользовательские сканеры
Любой язык или фреймворк, не охваченный выше, можно добавить, не меняя исходный код Ariadne. Реализуйте scanner.BaseScanner, поместите модуль туда, где Python может его импортировать, и укажите класс по точечному пути в ariadne.config.json:
{
"name": "my-go-service",
"path": "../my-go-service",
"scanners": [
{
"type": "my_scanners.go_scanner:GoRouteScanner",
"route_file": "cmd/server/routes.go"
}
]
}"type" — это "module.path:ClassName". Все остальные ключи передаются в __init__.
# my_scanners/go_scanner.py
from scanner import BaseScanner
class GoRouteScanner(BaseScanner):
def __init__(self, route_file: str = "routes.go"):
self.route_file = route_file
def scan(self, repo_path: str, service: str) -> list[dict]:
# parse repo_path/self.route_file, return node dicts
return [{"id": f"{service}::http::GET::/ping", "type": "http_endpoint",
"raw_name": "ping", "service": service,
"source_file": self.route_file,
"method": "GET", "path": "/ping", "fields": []}]FAQ
Требует ли Ariadne запущенного кластера, сервера или сети?
Нет. Чистый статический анализ. Исходный код → локальная SQLite (ariadne.db, embeddings.db, feedback.db). Никаких сетевых вызовов, никаких загрузок.
Как он понимает, когда нужно пересканировать?
Если самому старому скану >7 дней, ответы MCP включают поле stale_warning (CLI выводит то же предупреждение в stderr). Из диалога с ИИ вызовите rescan(); из терминала — python3 main.py scan --config <path>.
Результаты поначалу кажутся общими — станут ли они лучше?
Да. Последующие вызовы expand_node неявно записывают позитивный фидбек; шаг переранжирования (confidence + 0.15 * boost) продвигает кластеры, которые были полезны для похожих подсказок. Результаты в первый день — это чисто лексическое ранжирование; через несколько недель они будут отражать паттерны навигации вашей команды. Основано на подсчетах, а не на обученной модели.
Можно ли использовать его без ИИ-ассистента — просто как CLI?
Да. python3 main.py scan / query / expand / stats — ноль зависимостей, кроме Python 3.10. MCP по-прежнему рекомендуется как основной путь.
Архитектура
ariadne/
├── scanner/ # per-framework extractors → node dicts
├── normalizer/ # camelCase/snake/kebab → tokens
├── scoring/ # IDF-Jaccard engine + bge-small embedder
├── store/ # SQLite: ariadne.db / embeddings.db / feedback.db
├── query/ # query / expand entry points
├── mcp_server.py # MCP stdio server
├── main.py # CLI
└── tests/ # pytest suiteРанжирование
Математика основана на поиске информации, а не на теории графов. Имена узлов токенизируются (createOrder → ["create", "order"]) и сравниваются с помощью Jaccard с весами IDF:
idf_jaccard(A, B) = Σ idf(t) (t ∈ A ∩ B) / Σ idf(t) (t ∈ A ∪ B)
idf(t) = log(N / df(t))Редкие токены доминируют; высокочастотные доменные слова (task, id, service) подавляются, список стоп-слов не нужен.
base = idf_jaccard(name) * 0.55 + idf_jaccard(fields) * 0.45
score = min(base * role_mult * service_mult, 1.0)
role_mult = 1.3 for complementary pairs
(GraphQL Mutation ↔ Kafka topic ↔ HTTP POST,
GraphQL Query ↔ Cube Query ↔ HTTP GET)
service_mult = 1.25 cross-service / 0.8 same-serviceКластеризация
Двухэтапная, O(anchors × neighbours), не зависит от количества репозиториев.
Токенизация подсказки, оценка по всем узлам, сохранение топ-30 якорей с
score ≥ 0.15.Для каждого якоря извлечение его ребер из БД (один запрос
IN) и сохранение топ-12 соседей сedge_score ≥ 0.25.Объединение окрестностей якорей, которые пересекаются на ≥ 25%.
В каждом кластере берется топ-2 узла на
(service, type), ограничение 12.Confidence = средний edge score · 0.6 + разнообразие типов · 0.2 + разнообразие сервисов · 0.2.
Эмбеддинги
TF-IDF — основной канал поиска. bge-small-en-v1.5 (ONNX int8 квантованный) используется для двух узких задач:
Резервный поиск: когда лексическое пересечение слабое, найти синонимы (например,
assignHomework↔assignStudentsToTask) и добавить их в набор якорей.Переранжирование: сначала строятся
top_n × 2кластеров, затем они пересортировываются по0.6 · confidence + 0.4 · max_cos(hint, cluster_nodes)и обрезаются доtop_n.
Модель ONNX весит ~34 МБ (int8) и работает на CPU через onnxruntime. Холодный старт ~0.3с. Векторы кэшируются в embeddings.db; во время запроса эмбеддится только подсказка.
Усиление фидбеком
Финальный шаг переранжирования, который адаптирует ранжирование к словарю вашей команды — без обучения моделей, без загрузок. feedback.db локальна для каждого разработчика.
Каждый вызов query_chains кэширует возвращенные кластеры на 10 минут. Последующий expand_node(name), который совпадает с подстрокой узла в ожидающем кластере, автоматически записывает строку accepted=True — сам факт расширения является сигналом. log_feedback(hint, accepted, ...) — это ручной способ для дизлайка.
При следующем query() для той же подсказки:
final_score = confidence + 0.15 * sum(prior_accepted_count per node in cluster)Вес (0.15) и окно затухания (90 дней) намеренно консервативны — лексическая уверенность все еще доминирует. Отключить можно через export ARIADNE_FEEDBACK_BOOST=0.
Тесты
python3 tests/test_semantic_hint.py
python3 tests/test_feedback_boost.py
python3 tests/test_implicit_feedback.py
python3 tests/test_onnx_embedder.pyPre-commit хук в hooks/pre-commit запускает test_semantic_hint.py — включите его один раз после клонирования:
ln -sf ../../hooks/pre-commit .git/hooks/pre-commitДорожная карта
Больше источников Kafka, помимо
application.yaml+@KafkaListener+KafkaTemplate.sendНастройка весов TF-IDF для очень высокочастотных доменных токенов
Более сильный сигнал фидбека: настройка затухания, веса для сервисов, обобщение между подсказками (текущий буст основан на количестве внутри одной подсказки)
Режим наблюдения: хуки в git post-commit / событиях файлов для автоматического запуска
rescanвместо ожиданияstale_warningПолировка
expand_node: более четкие условия триггера, меньшая поверхность ввода, вывод, указывающий на следующий шагПередача параметров во все инструменты: имена, ориентированные на задачи, вместо имен реализации; унификация префиксов глаголов для согласованности именования
Не является целью
LLM как основной судья (медленно, дорого, невоспроизводимо)
Визуализация / бэкенд графовой БД
Извлечение полного графа вызовов AST
Лицензия
MIT — см. LICENSE.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/whyy9527/ariadne'
If you have feedback or need assistance with the MCP directory API, please join our Discord server