ADR 0100 — rag_search для агентов и модели Ollama, гарантированные при загрузке
- Статус: Принят
- Дата: 2026-08-20
- Контекст: фундамент графа знаний (RN-413/414/415), компаньон ADR 0099
Контекст
RAG (pgvector, гибридный поиск вектор+лексика, ADR 0079/0080/0082) существует
полностью в api с Волны 4/направления G2 Программы 28 — но
grep -rn "rag" apps/engine/lib давал НОЛЬ вхождений до этой поставки.
Ни один агент ни разу не обращался к RAG собственного проекта. Это самый большой
пробел текущего дизайна: продукт строит индекс, а читает его лишь web-вкладка "Chat
RAG".
Вторая находка, тоже реальная и не из этой функции: nomic-embed-text
(RAG_EMBEDDING_MODEL в rag-search-limits.ts) никогда не скачивается
автоматически. Entrypoint сервиса ollama в docker-compose.yml
скачивает лишь llama3.2:1b. В любом чистом окружении RAG молча деградирует
до чисто лексического поиска, пока кто-нибудь вручную не выполнит
ollama pull nomic-embed-text, — никто этого не замечал, потому что
у продукта до сих пор никогда не было программного потребителя поиска, который
сделал бы деградацию видимой рано.
Решение
Новый инструмент rag_search (apps/engine/lib/engine/harness/tools/rag_search.ex),
категория :direct (чтение, не проходит через ActionPipeline/
proposed_action — чтение не является внешним эффектом, уже установленное правило).
Вызывает POST /internal/rag/search (новый маршрут api, переиспользующий
HybridSearchUseCase без дублирования логики поиска) и форматирует попадания с
явным ЦИТИРОВАНИЕМ (path + фрагмент), чтобы модель могла ссылаться на
источник прочитанного. Когда ответ приходит с degraded: true (embedding
недоступен, поиск упал до чисто лексического), это появляется в начале
текста, возвращаемого модели, — никогда не спрятано в конце, где обрезка по
пределу байтов могла бы стереть предупреждение.
Собственные пределы, в духе RN-150 (у каждого инструмента чтения, который
может переполниться, СВОЯ переменная, никогда не переиспользуемая от другого):
top_k ограничивается максимумом (10) в самом инструменте, и предел
БАЙТОВ форматированного текста (16 KiB, меньше 32 KiB у
search_workspace/read_file — каждое попадание RAG уже является целым chunk+excerpt,
накапливает байты быстрее на элемент).
Зарегистрирован в реестре по умолчанию (Engine.Harness.Tools, обслуживает
PO/Arquiteto/разговорных) и в реестре dev agent
(Engine.Dev.Tools). Расширен также на читающие gates, которые уже цитируют
проиндексированные ADR/соглашения (QaTools, QaEstrategiaAgent, AppSecAgent,
QaPerformanceSegurancaAgent), — но не на Infra.WorkflowsAgent (намеренно
узкий, сегодня без ReadFile/SearchWorkspace) и не на
Psicólogo/Anamnese (рассуждают об event log, а не о документации/коде
проекта).
ollama-model-loader: новый одноразовый сервис в docker-compose.yml
(dev и prod), который скачивает gemma:1b, yi-coder:1.5b и nomic-embed-text
через OLLAMA_REQUIRED_MODELS — аддитивно к существующему сервису ollama
(чей entrypoint продолжает скачивать llama3.2:1b для собственного использования
engine, нетронутым). Закрывает реальный баг, когда nomic-embed-text никогда не появлялся
сам, а не только потребность этой функции.
Последствия
- Capability RAG для агентов объявляется только при задействовании —
реальный обмен с
POST /internal/rag/searchзависит от того, поднят ли маршрут api; инструмент деградирует с понятной модели ошибкой (никогда не обрушиваетToolLoop, RN-163), когда api недоступна. deploy/k8s/получает минимальные манифесты для Neo4j и model-loader, ОБЪЯВЛЕННЫЕ как не проверенные на реальном кластере (та же дисциплина, что у остальногоdeploy/k8s/: capability объявляется лишь при доказательстве).- Стоимость embedding
rag_searchпока не проходит через metering — тот же пробел, уже объявленный в ADR 0075 для RAG в целом (token_usage.session_id—NOT NULL, индексация не происходит внутри сессии).