agentic-rag
agentic-rag
Цитируемый поиск с учётом ревизий по реальному корпусу, взятому из экосистемы IETF RFC — полные тексты RFC, реальный граф замещений Obsoletes/Obsoleted-by/Updates из индекса RFC, реальные исправления RFC, присланные сообществом, и реальные реестры параметров протоколов IANA — загружается по HTTPS (corpus_fetch/) и обрабатывается через ragpack в поисковое векторное хранилище (321 124 реальных чанка), затем маршрутизируется и проходит проверку цитирования через ядро consilium.
Задайте реальный вопрос о спецификации протокола IETF, об авторстве/статусе RFC, о реальном исправлении errata или о записи в реестре IANA — и получите ответ, полностью построенный из реальных цитируемых чанков — или честное воздержание от ответа. Единственное исключение — вопрос об устаревании («что заменило RFC 2616?»): у самого текста RFC 2616 нет «текущей ревизии» (он полностью заменён шестью более поздними документами, RFC 7230–7235 — знаменитый случай многостороннего устаревания в IETF), поэтому на него отвечает SupersessionModule — детерминированный поиск по графу реальных связей Obsoletes/Obsoleted-by, а не поиск по корпусу. Никакой LLM нигде в пути ответа.
Быстрый старт
git clone https://github.com/trentmilam/agentic-rag
cd agentic-rag
py -3.12 -m venv .venv
.venv\Scripts\python -m pip install -r requirements.txt
.venv\Scripts\python -m pip install -e .
.venv\Scripts\python scripts\verify.pyЭто весь процесс начальной настройки. Именно редактируемая установка обеспечивает разрешение import consilium, import ragpack, import linkgraph, import activerag и import chainrag — package-dir в pyproject.toml сопоставляет каждое имя с packages/.
Для ответа на реальный вопрос дополнительно нужен обработанный корпус; см. Корпус и Проверка.
Related MCP server: 3GPP Evidence Graph
Один репозиторий, пять объединённых инструментов
agentic-rag раньше импортировал consilium и linkgraph из соседних репозиториев, вставляя их корни в sys.path, и требовал, чтобы RAGpack был установлен в редактируемом режиме из третьего репозитория. Клонирование означало клонирование четырёх репозиториев с тремя коммитами, зафиксированными в трёх отдельных файлах — которые уже разошлись друг с другом. linkgraph также читал файл данных этого репозитория, так что эти два инструмента импортировали друг друга через границу репозиториев.
Теперь это один репозиторий. Каждый объединённый инструмент сохранил всё своё дерево в packages/<name>/, так что всё, что он разрешает относительно своего корня, по-прежнему разрешается, и каждый сохранил свою собственную историю коммитов, а не был сжат в один импортирующий коммит:
пакет | что это | тесты |
ядро маршрутизации / проверки цитирования: Registry, Router, compose, контроль целостности, ComputeModule | 5 наборов eval | |
загрузка, разбиение на чанки, эмбеддинги, обёртка хранилища Qdrant | 20 | |
граф связей между документами, лежащий в основе инструментов MCP для связей | 50 | |
обнаружение недостаточности доказательств и ограниченный поиск с повторами | 54 | |
второй вертикальный срез по документации протоколов блокчейна, доказывающий, что ядро не привязано к конкретному корпусу | -- |
Они вложены в packages/, а не лежат в корне репозитория, по конкретной причине: каталог верхнего уровня с именем consilium затеняет пакет consilium как неявный пакет пространства имён, потому что рабочая директория предшествует редактируемой установке в sys.path. Тогда импорт разрешается в пустое пространство имён, и consilium.__file__ становится None. CI проверяет, что каждый пакет разрешается в файл внутри этого репозитория, так что такой класс молчаливой неправильной привязки приводит к сбою сборки, а не к прохождению всех тестов против неправильной копии.
rag-reliability — единственная зависимость, которая всё ещё находится вне этого репозитория. Она поставляет graphrx, headroom, vecstamp, chunkledger, plumbline и legigate трём из перечисленных выше инструментов и сегодня разрешается по пути; упаковка её так, чтобы она могла быть объявленной зависимостью, — это следующая задача. CI проверяет её с зафиксированной версией и падает, если эти интеграционные тесты пропускаются, так что единственная оставшаяся зависимость по пути не может незаметно сгнить.
Корпус
тип источника | что это | реальных чанков | текущих (не устаревших) |
| полный текст RFC без изменений | 306 939 | 225 809 |
| карточка индекса для каждого RFC (название/авторы/дата/статус/obsoletes/updates) | 5 854 | 4 663 |
| реальные исправления RFC, присланные сообществом | 7 295 | 7 295 (н/д — нет понятия ревизии) |
| 7 реальных реестров параметров протоколов IANA, представленных в виде таблиц Markdown | 1 036 | 1 036 (н/д — нет понятия ревизии) |
Всего 321 124 реальных чанка, встроенных с помощью реальной модели BAAI/bge-base-en-v1.5. Только rfc_text/rfc_index имеют понятие ревизии — is_current там является реальным структурным фактом (см. проверка ревизий), а не догадкой.
Пять модулей, один маршрутизатор
agenticrag/bootstrap.py::build_registry собирает реальный Registry из 5 модулей consilium: 4 модуля поиска, перечисленных выше (каждый загружается прямо из Qdrant, по умолчанию current_only=True — см. agenticrag/registry_loader.py), плюс SupersessionModule (agenticrag/supersession.py) — ComputeModule, который один раз при конструировании разбирает data/entities/revisions.json — реальный граф Obsoletes/Obsoleted-by для всех 9 794 RFC в живом индексе — и отвечает на вопросы об устаревании с помощью детерминированного обхода графа, безопасного для циклов (ограничен 50 посещёнными узлами — защитный предел, а не ожидаемый реальный лимит; реальные компоненты устаревания в IETF малы).
build_registry также громко завершается с ошибкой, если настроенный эмбеддер процесса не совпадает с тем, который обработал хранилище (verify_embedder_marker, вызывается первым) — иначе косинусные оценки были бы молча бессмысленными — и закрывает любой клиент Qdrant, который он сам открыл, после загрузки модулей (поиск после этого полностью в памяти), так что он не удерживает блокировку локального хранилища на всё время жизни процесса вызывающего.
trust_tier у errata (0.55, значительно ниже 0.9–0.95 у rfc_text/rfc_index/iana_registry) измерен, а не угадан: из 5 061 реальной записи errata, загруженных в систему, только 2 400 (47.4%) имеют статус Verified от редактора RFC — 1 781 (35.2%) — Held for Document Update, 679 (13.4%) — outright Rejected, и 201 (4.0%) — всё ещё Reported. Менее половины реально присланных исправлений подтверждены редактором RFC, поэтому этот модуль корректирует основной текст, не будучи сам по себе полностью авторитетным.
MCP-сервер
agenticrag/mcp/server.py предоставляет путь ответа как сервер Model Context Protocol через stdio (mcp>=1.28.1, FastMCP). Четыре инструмента:
search(query)— полный путь ответа с цитированием/воздержанием (consilium.compute.answer_v3), передаётся без изменений (честное воздержание остаётся воздержанием);get_obsoletion_chain(rfc_id)/get_corrections(rfc_id)/get_related(entity_id)— граф связей, через соседнийlinkgraph(agenticrag/relationships.py); каждый возвращает документированную обёртку{"ok": false, "fallback": ...}, если этот соседний пакет отсутствует.
Запуск: .venv\Scripts\python -m agenticrag.mcp.server (транспорт stdio — MCP-клиент запускает его и общается по протоколу через stdin/stdout). Логика инструментов слабо зависит от импортов и не требует mcp/Qdrant, поэтому она тестируется без них (agenticrag/mcp/test_server.py).
Проверка
Быстрая проверка (быстро, без корпуса — не нужен обработанный корпус):
verify.bat :: or: .venv\Scripts\python -m pytest -qЗапускает тесты обёрток MCP-инструментов и набор проверок безопасности циклов при обходе графа замещений. Именно это CI запускает при каждом push (см. значок выше).
Полная проверка (требует обработанный корпус из 321k чанков из быстрого старта):
.venv\Scripts\python eval\eval_agenticrag.pyДетерминирована при уже обработанном корпусе; повторная обработка не требуется. Использует реальный эмбеддер — тот самый, который обработал корпус, — так что это доказывает настоящий семантический поиск от начала до конца, а не только связность. Занимает ~3.3 минуты на этом оборудовании (измерено, полный прогон: 196 с): разовое ~60-секундное построение реестра (один проход по корпусу для небольшого набора карантина ядовитых данных — не загрузка всех 321k векторов), затем проходы маршрутизатора/ответа по ~12 с каждый. Каждый проход выполняет маршрутизацию и поиск как нативные векторные поиски Qdrant; встроенный локальный режим Qdrant — это точный перебор (без ANN-индекса), поэтому поиск всё равно сканирует отфильтрованное подмножество — но в нативном коде, материализуя только top-k, что ~16 раз быстрее старого чисто Python-сканирования по чанкам. (Поиск за доли секунды потребовал бы HNSW-индекса серверного режима Qdrant; локальный режим сохраняет репозиторий самодостаточным — не нужно запускать сервер.) Проверяет: один запрос в области действия для каждого типа источника (разумный модуль + >=1 реальная цитата); запрос об устаревании RFC 2616 (множество преемников — точно {7230, 7231, 7232, 7233, 7234, 7235}); один запрос вне области действия (честное воздержание); структурное исключение проверки ревизий (ниже); действительно текущий RFC (791), разрешающийся в current; и отсутствующий номер RFC (99999), разрешающийся в not_found, а не в сбой.
eval/prove_revision_guard.py — то же структурное доказательство в виде отдельного повествовательного скрипта. eval/smoke_ingest_real.py доказывает связность fetch->ingest->Qdrant с помощью нулевого по стоимости HashEmbedder (требует, чтобы corpus_fetch.fetch_all был запущен, но не требует GPU/модели эмбеддинга).
Проверка ревизий, доказанная
RFC 2616 (HTTP/1.1) — это реальный, единый, цельный документ; у него нет «текущей ревизии»; он полностью заменён шестью разными документами. Свойство защиты здесь — это два реальных, проверяемых факта, а не одно «исправленное значение»:
Структурное исключение. Собственные чанки
rfc_textRFC 2616 существуют в Qdrant (повторная загрузка модуляrfc_textсcurrent_only=Falseдоказывает, что они там), но отсутствуют в модуле по умолчаниюcurrent_only=True, который фактически использует каждый запрос — потому чтоdata/entities/revisions.json["RFC2616"]["obsoleted_by"]реален и не пуст. Данные существуют; они структурно отфильтрованы, а не случайно отсутствуют.Правильный путь к ответу.
SupersessionModule— это явный способ узнать, что случилось с RFC 2616 — запрос, называющий его, возвращает реальный список из 6 преемников (RFC 7230–7235).
Калибровка маршрутизатора — измерено, а не угадано
Заявленные библиотечные значения по умолчанию consilium.router.Router (floor=0.11, anchor_centroid=0.25, anchor_best_chunk=0.25) предполагают почти нулевой базовый косинус между несвязанными текстами — это верно для мешка слов HashEmbedder, но не обязательно для реального плотного эмбеддера по корпусу из 321k чанков (тот же разрыв проявляется даже на гораздо меньшем масштабе ~1 100 чанков). agenticrag/calibrate.py измеряет это напрямую на реальном корпусе + реальном эмбеддере, а не предполагает; см. agenticrag/bootstrap.py::ROUTER_KWARGS для итоговых kwargs для каждого экземпляра и реальных чисел, обосновавших решение.
.venv\Scripts\python agenticrag\calibrate.pyПримечание о GPU (только при загрузке)
GPU важен ровно для одного шага: загрузки корпуса (ingest/run_ingest.py), которая встраивает ~321k чанков с помощью BAAI/bge-base-en-v1.5 через onnxruntime. Во время запроса вы встраиваете только (короткую) строку запроса, поэтому лаунчеры отлично работают на CPU без настройки GPU — именно поэтому они больше не касаются никакой конфигурации GPU.
Ожидаемое и безвредное предупреждение: если onnxruntime-gpu установлен, но соответствующие DLL-библиотеки CUDA runtime отсутствуют в пути поиска, вы увидите пугающий красный блок CUDAExecutionProvider / Error loading ... cublasLt64_*.dll ... missing — при любом запуске, ingest или query, не только при ingest. Это не сбой: onnxruntime переключается на CPU и продолжает работу (для query эмбеддинг — одна короткая строка, так что откат на CPU мгновенный). Игнорируйте это или установите DLL-библиотеки, указанные ниже, чтобы убрать предупреждение.
Для быстрого ingest исполнитель CUDA в onnxruntime-gpu требует, чтобы эти DLL-библиотеки CUDA runtime были в пути поиска DLL. Один только pip install onnxruntime-gpu не включает их, и без них onnxruntime переключается на CPU (измерено: ~6 чанков/сек — расчётно: ≈14,9 часов для полного корпуса из 321 124 чанков), а не вызывает ошибку. Чтобы получить реальное выполнение на GPU (измерено: ~650 чанков/сек на RTX 5090, т.е. ≈8 минут для полного корпуса), установите соответствующие wheels CUDA runtime в собственное виртуальное окружение этого репозитория, например:
.venv\Scripts\python -m pip install nvidia-cublas-cu13 nvidia-cudnn-cu13(сопоставьте суффикс -cuNN с основной версией CUDA вашей сборки onnxruntime-gpu),
или поместите каталог torch/lib любой установки PyTorch с поддержкой CUDA в PATH
перед запуском ingest. В любом случае это необязательное ускорение одноразового ingest,
никогда не требуется для запуска демо или обработки запросов.
Повторные запуски ingest (известное ограничение)
ingest/run_ingest.py поддерживает полную пересборку с нуля через --recreate и быстрый
инкрементальный путь (повторно эмбеддит только те исходные файлы, чей хэш содержимого изменился).
У инкрементального пути есть два известных ограничения, которые намеренно не замаскированы: (1) он
считает файл "изменённым" исключительно по байтовому хэшу каждого исходного файла, поэтому если RFC
становится устаревшим в более позднем обновлении rfc-index.txt без изменения самого текстового файла,
его флаг is_current может устареть; и (2) он не удаляет осиротевшие точки Qdrant для документа,
который повторно индексируется в меньшее количество чанков. Для гарантированно согласованного хранилища
запустите ingest/run_ingest.py --recreate (полная пересборка). Закрытие обоих ограничений в
инкрементальном пути — задача на будущее.
Структура
agenticrag/
embed_config.py shared Settings (model/qdrant path) + embedder-consistency guard
registry_loader.py loads a consilium Module's chunks straight from Qdrant (current_only guard)
bootstrap.py build_registry(embedder, client=None) -> Registry; the 5 Descriptors; ROUTER_KWARGS
supersession.py SupersessionModule -- real Obsoletes/Obsoleted-by graph walk, cycle-safe
relationships.py thin bridge into linkgraph (get_related / _obsoletion_chain / _corrections)
calibrate.py real router-score measurement script
mcp/
server.py FastMCP server: search + the 3 relationship tools (stdio)
test_server.py fixture-only tests for the tool logic (no mcp package, no Qdrant)
corpus_fetch/ real HTTPS fetch of RFC full text / rfc-index.txt / errata / IANA registries
ingest/
connectors/ per-source-type extract() -> ExtractedDoc (+ the revisions-index builder)
run_ingest.py raw files -> chunk -> embed -> Qdrant, real is_current currency check
eval/
smoke_ingest_real.py corpus_fetch -> ingest -> Qdrant wiring smoke (HashEmbedder)
eval_agenticrag.py production eval (full verify; needs the ingested corpus)
prove_revision_guard.py standalone, narrated revision-guard proof
test_supersession_cycle_safety.py cycle-safety unit tests (synthetic graph; corpus-free)
tests/ unit tests for connectors / registry_loader / bootstrap (corpus-free)
packages/ the five merged tools, each keeping its own tree and history
consilium/ routing / citation-gating spine (+ its 5 eval suites)
ragpack/ ingest / chunk / embed / Qdrant store (src-layout)
linkgraph/ cross-document relationship graph
activerag/ evidence-thinness detection and bounded hunt-and-retry
chainrag/ the blockchain-docs vertical
app.py gr.ChatInterface chat UI
run_demo.py scripted 3-question narrated transcriptЛицензия
Код: MIT (c) 2026 Trent Milam.
Корпус не включён в этот репозиторий (data/ в gitignore); он загружается
во время сборки с rfc-editor.org и iana.org. Тексты IETF RFC/errata подпадают под
Правовые положения IETF Trust
(при загрузке сохраняется уведомление об авторских правах/Trust каждого документа);
данные реестра IANA публикуются IANA. Этот проект ничего из этого не распространяет —
он загружает это локально, на вашей машине.
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Read-only hosted MCP over CanonicAI's cited Answers corpus on canonicai.com.
Page-cited retrieval for embedded docs, datasheets, MISRA, CMSIS, and RTOS references.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server that parses 3GPP .docx specifications into structured sections with full-text search, letting LLMs browse, search, and follow cross-references without a vector database.1319MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to retrieve and explore evidence from 3GPP meeting documents through MCP, including temporal knowledge graph queries, document section navigation, and citation-backed answers.-
- FlicenseNot gradedqualityBmaintenanceEnables retrieval-augmented question answering with source-grounded citations, document retrieval, and idempotent ingestion through MCP tools.-
- AlicenseNot gradedqualityCmaintenanceEnables any MCP-capable LLM client to search self-hosted long-term memory over markdown and PDF documents, combining dense semantic vectors with BM25 keyword retrieval and optional cross-encoder reranking. Exposes a read-only tool surface for querying incidents, runbooks, and other knowledge-base content, while writes happen out-of-band through ingestion jobs or a token-gated internal API.2MIT