ADR-050: Retrieval and embedding scope — the boundary with nr_ai_search
- Status
-
Accepted
- Date
-
2026-07-11
- Authors
-
Netresearch DTT GmbH
Context
ADR-049 shipped lexical site-search tools
(site_rag_query / site_fetch_source, the rag group) that read
whichever TYPO3 search index is installed (EXT:solr, ke_search,
indexed_search) with an always-available pages/tt_content
database fallback. A sibling extension, netresearch/nr_ai_search,
owns vector RAG for TYPO3: content chunking, a persistent vector
store, an indexing pipeline, a retrieval-augmented query flow with an
anti-hallucination gate, and frontend chat/search — and it already
depends on nr_llm for embeddings and chat.
Two questions follow, and answering them keeps both extensions from growing into each other:
- Does retrieval belong in
nr_llmat all, or is it out of scope for an "LLM provider" extension? - Where is the line — which retrieval work is
nr_llm's and which isnr_ai_search's?
nr_llm is not an LLM SDK; it is the LLM-to-TYPO3 integration
layer. Its forty-plus built-in tools marry the model to TYPO3 core
APIs (TCA, TypoScript, FAL, pages/content, logs). Grounding a model in
the site's own content sits squarely in that mission — it is the same
category as search_records and get_page_content, not a foreign
concern. Waiting for search-extension maintainers to contribute their
own nr_llm.tool implementations is not a viable adoption path; the
capability has to work out of the box.
Decision
Retrieval grounding over TYPO3 content is in scope for nr_llm as a primitive, on the same footing as the content and introspection tools. The boundary is drawn by one operational rule:
nr_llm may read from indexes that others own and maintain — TYPO3 search extensions, or a transient embed-and-compare — but it must never own a persistent index it has to keep synchronised with content.
In scope for nr_llm:
site_rag_query/site_fetch_sourceand theraggroup (ADR-049).- The lexical search-backend adapters (Solr, ke_search, indexed_search): they read indexes those extensions own and keep fresh; nr_llm owns none of them.
- The always-available
pages/tt_contentdatabase fallback: it queries live tables, there is no index. EmbeddingService::embed()as a stateless capability (string in, vector out) and ad-hoc embed-and-rank over a caller-supplied candidate set (for example: rank twenty link-target pages by similarity to a paragraph). No persistent index is involved.
Out of scope for nr_llm — this is nr_ai_search:
- A persistent vector store, chunking strategy, a reindex-on-change pipeline, chunk-level access control, dimension and compaction management. There is no "small" vector store; it grows into exactly the pipeline nr_ai_search already maintains.
Stopping rule for future tools. The line is capability / primitive
versus vertical domain, not core-versus-extension. nr_llm ships tools
for TYPO3 core APIs and for retrieval as a cross-cutting primitive; it
does not accrete domain tools for vertical extensions (news,
commerce, and so on). The adoption argument — "cannot wait for
maintainers" — justifies shipping the capability out of the box, which
the nr_llm.retrieval_backend tag (ADR-049) already enables; it does
not justify hard-coding every search engine into the core forever. A
niche engine's adapter registers through that tag without a core
release.
Sibling and third-party tools are contributed into nr_llm's runtime,
not built here. When nr_ai_search (or any extension) wants to expose a
semantic-retrieval or other tool, it registers it via the nr_llm.tool
tag under its own group (recommended value: the providing extension's
key, per ADR-043). nr_llm owns the tool runtime; each
extension owns its tools.
Decision (2026-07): no nr_llm-owned persistent index
The previously deferred question — whether site-wide semantic
retrieval for backend/API consumers (semantic auto-linking, "related
content" suggestions for editors, thematic matches for other extensions)
is primitive enough to justify a minimal nr_llm-owned vector store — is
now decided: it is not. nr_llm never owns a persistent vector store.
Such retrieval always routes through nr_ai_search, which owns the
persistent semantic index and the pipeline that keeps it correct.
nr_llm's contribution stays stateless: EmbeddingService embeds a
string on demand, and a small or dynamic candidate set may be ranked in
memory (embed-and-rank), but nothing is persisted or kept synchronised
with content. A consumer that needs site-wide semantic answering installs
nr_ai_search on top of nr_llm. nr_ai_search records the same
decision from its side in ADR-028.
Consequences
site_rag_querystays in nr_llm on principle, not as a temporary convenience: it is retrieval-as-primitive for every backend and API consumer (editorial content-finding, admin debugging, extensions that need to locate matching content), none of which should have to pull in a vector-store product.- nr_llm carries a hard guardrail: no chunking, no persistent vector index, no reindex pipeline. The moment a feature needs one, it is nr_ai_search.
- The two extensions compose cleanly: nr_llm provides embeddings as a capability and the tool runtime; nr_ai_search consumes both and owns the persistent vector RAG product. Neither duplicates the other.