This is an automated email from the ASF dual-hosted git repository.

JiriOndrusek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new 2d6e024d43 Fixes #9013. Harden the RAG augmentor bridge
2d6e024d43 is described below

commit 2d6e024d43edbae2f0bd7b65ed504bd1af869a97
Author: Jiří Ondrušek <[email protected]>
AuthorDate: Mon Aug 17 07:44:30 2026 +0000

    Fixes #9013. Harden the RAG augmentor bridge
    
      A designated default augmentor instead of an ambiguous lookup that
      silently disabled RAG, plus a retrieval filter hook that fails closed.
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
---
 .../extensions/langchain4j-embeddingstore.adoc     |  73 +++++++
 extensions-support/langchain4j/deployment/pom.xml  |   5 +
 .../SupportQuarkusLangchain4jProcessor.java        | 224 +++++++++++++++++----
 .../RagAugmentorDefaultResolutionTest.java         |  88 ++++++++
 .../DefaultRetrievalAugmentorSupplier.java         |  39 +++-
 .../langchain4j/QuarkusLangchain4jRecorder.java    |   7 +-
 .../support/langchain4j/RagAugmentorName.java      |  42 ++++
 .../support/langchain4j/RagBridgeConfig.java       |  12 ++
 .../langchain4j/RagRetrievalFilterSupplier.java    |  65 ++++++
 .../runtime/src/main/doc/usage.adoc                |  71 +++++++
 .../ragbridge/it/RagBridgeResource.java            | 110 ++++++++++
 .../ragbridge/it/TestTenantFilterSupplier.java     |  70 +++++++
 .../ragbridge/it/MultiAugmentorProfile.java        |   7 +-
 .../ragbridge/it/MultiAugmentorTest.java           |  54 ++++-
 ...entorProfile.java => RagRetrievalFilterIT.java} |  13 +-
 .../ragbridge/it/RagRetrievalFilterTest.java       | 122 +++++++++++
 .../ragbridge/it/SingleAugmentorTest.java          |   6 +-
 17 files changed, 947 insertions(+), 61 deletions(-)

diff --git 
a/docs/modules/ROOT/pages/reference/extensions/langchain4j-embeddingstore.adoc 
b/docs/modules/ROOT/pages/reference/extensions/langchain4j-embeddingstore.adoc
index 70ebefe845..b1e1e1b927 100644
--- 
a/docs/modules/ROOT/pages/reference/extensions/langchain4j-embeddingstore.adoc
+++ 
b/docs/modules/ROOT/pages/reference/extensions/langchain4j-embeddingstore.adoc
@@ -62,6 +62,79 @@ from("direct:ingest-products")
 
 A store only referenced from routes does not need to be injected anywhere in 
Java code; it is retained and instantiated lazily on first use. If the Camel 
registry already resolves a different `EmbeddingStore` under the same name (for 
example a `@Named` bean), that existing bean keeps winning lookups and a 
warning is logged at startup.
 
+[id="extensions-langchain4j-embeddingstore-usage-retrieval-augmentors-for-registeraiservice"]
+=== Retrieval augmentors for `@RegisterAiService`
+
+With Quarkus LangChain4j present, a `RetrievalAugmentor` is produced 
automatically from the `@Default` `EmbeddingStore` and `EmbeddingModel` beans, 
so an `@RegisterAiService` interface answers from the same store a Camel route 
ingests into. Nothing is produced when the application declares its own 
`RetrievalAugmentor`.
+
+Augmentors can also be declared explicitly, one per store:
+
+[source,properties]
+----
+quarkus.camel.langchain4j.rag.augmentors.products.embedding-store-name=products
+quarkus.camel.langchain4j.rag.augmentors.products.default=true
+quarkus.camel.langchain4j.rag.augmentors.support.embedding-store-name=support-docs
+----
+
+Each entry produces a `@Named` `RetrievalAugmentor`. With more than one 
configured, exactly one must be marked `default=true`: that one serves the 
unqualified lookup `@RegisterAiService` performs, while the others remain 
selectable by name. Configuring several without marking one fails the build, 
because an ambiguous unqualified lookup disables RAG for every AI service 
without reporting anything. A single entry needs no marking.
+
+Selecting one of the others means naming it through a supplier, since 
`@RegisterAiService` either takes the unqualified augmentor or a `Supplier` 
class:
+
+[source,java]
+----
+public class SupportAugmentorSupplier implements Supplier<RetrievalAugmentor> {
+    @Inject
+    @Named("support")
+    RetrievalAugmentor augmentor;
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+}
+
+@RegisterAiService(retrievalAugmentor = SupportAugmentorSupplier.class)
+public interface SupportAssistant {
+    String chat(String question);
+}
+----
+
+[id="extensions-langchain4j-embeddingstore-usage-filtering-what-retrieval-may-see"]
+=== Filtering what retrieval may see
+
+Metadata stored next to a segment — a tenant key, a classification — isolates 
nothing unless retrieval filters on it. A single `RagRetrievalFilterSupplier` 
bean, if present, is consulted on every retrieval performed by a produced 
augmentor:
+
+[source,java]
+----
+@ApplicationScoped
+public class TenantFilterSupplier implements RagRetrievalFilterSupplier {
+    @Inject
+    CurrentTenant currentTenant; // request scoped
+
+    @Override
+    public Filter filter(Query query, String augmentorName, String 
embeddingStoreName) {
+        if (!"products".equals(embeddingStoreName)) {
+            return null; // only this store carries tenant metadata
+        }
+        String tenant = currentTenant.name();
+        if (tenant == null) {
+            // fail closed: returning null here would serve every tenant's 
documents
+            throw new IllegalStateException("No tenant in scope");
+        }
+        return metadataKey("tenant").isEqualTo(tenant);
+    }
+}
+----
+
+The one bean serves every produced augmentor, so it is told which augmentor 
retrieves and which store is being searched; both are `null` for the 
auto-produced default augmentor, which is backed by the `@Default` beans. 
Filtering on a metadata key a store does not carry matches nothing, so return 
`null` for the stores an implementation does not know about.
+
+Returning `null` means unfiltered retrieval, as it does in LangChain4j itself, 
so an implementation that cannot determine the caller must throw instead. The 
tenant may equally come from `query.metadata().chatMemoryId()`, which is the 
only source that still works when retrieval does not run on the caller's 
thread. At most one implementation may exist, and it must not be `@Dependent`; 
both are build failures.
+
+Two limits are worth knowing before treating this as an access control:
+
+* The filter reaches only the augmentors this extension produces. Easy RAG, or 
an application-provided `RetrievalAugmentor`, replaces them, and the filter is 
then never consulted — the build logs a warning when it detects that 
combination.
+* `EmbeddingStore` implementations are not required to support filtering. One 
that ignores the filter returns every match, so verify against the store 
actually in use.
+
 
 [id="extensions-langchain4j-embeddingstore-quarkus-langchain4j-bom"]
 == LangChain4j usage
diff --git a/extensions-support/langchain4j/deployment/pom.xml 
b/extensions-support/langchain4j/deployment/pom.xml
index d0e48ad94c..e5a8f024a1 100644
--- a/extensions-support/langchain4j/deployment/pom.xml
+++ b/extensions-support/langchain4j/deployment/pom.xml
@@ -47,6 +47,11 @@
             <artifactId>camel-ai-tool</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit-internal</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
index 9cfe643323..815265a93f 100644
--- 
a/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
+++ 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
@@ -16,11 +16,13 @@
  */
 package org.apache.camel.quarkus.component.support.langchain4j.deployment;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.stream.Collectors;
 
 import dev.langchain4j.guardrail.Guardrail;
@@ -33,9 +35,11 @@ import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
 import io.quarkus.arc.deployment.BeanDiscoveryFinishedBuildItem;
 import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
 import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
+import io.quarkus.arc.deployment.QualifierRegistrarBuildItem;
 import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
 import io.quarkus.arc.deployment.SyntheticBeansRuntimeInitBuildItem;
 import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
+import 
io.quarkus.arc.deployment.ValidationPhaseBuildItem.ValidationErrorBuildItem;
 import io.quarkus.arc.processor.BeanInfo;
 import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
@@ -51,15 +55,19 @@ import io.quarkus.gizmo.ClassCreator;
 import io.quarkus.gizmo.MethodCreator;
 import io.quarkus.gizmo.MethodDescriptor;
 import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.runtime.configuration.ConfigurationException;
 import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.context.Dependent;
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
 import 
org.apache.camel.quarkus.component.support.langchain4j.AiToolSpecConverter;
 import 
org.apache.camel.quarkus.component.support.langchain4j.CamelAiToolProvider;
 import 
org.apache.camel.quarkus.component.support.langchain4j.CamelAiToolsInterceptor;
 import 
org.apache.camel.quarkus.component.support.langchain4j.QuarkusLangchain4jRecorder;
+import org.apache.camel.quarkus.component.support.langchain4j.RagAugmentorName;
 import org.apache.camel.quarkus.component.support.langchain4j.RagBridgeConfig;
 import 
org.apache.camel.quarkus.component.support.langchain4j.RagBridgeConfig.AugmentorConfig;
+import 
org.apache.camel.quarkus.component.support.langchain4j.RagRetrievalFilterSupplier;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRegistryBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRuntimeTaskBuildItem;
 import org.jboss.jandex.AnnotationInstance;
@@ -84,6 +92,9 @@ class SupportQuarkusLangchain4jProcessor {
             
.createSimple("org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools");
     private static final DotName EMBEDDING_STORE_NAME_DOTNAME = DotName
             .createSimple("io.quarkiverse.langchain4j.EmbeddingStoreName");
+    private static final DotName RAG_RETRIEVAL_FILTER_SUPPLIER_DOTNAME = 
DotName
+            .createSimple(RagRetrievalFilterSupplier.class.getName());
+    private static final DotName DEPENDENT_DOTNAME = 
DotName.createSimple(Dependent.class.getName());
 
     private static final Logger LOG = 
Logger.getLogger(SupportQuarkusLangchain4jProcessor.class);
 
@@ -242,6 +253,55 @@ class SupportQuarkusLangchain4jProcessor {
                 .build());
     }
 
+    // The retrieval filter supplier is only resolved programmatically at 
augmentor creation
+    // time, so ArC would remove a user's implementation as unused.
+    @BuildStep
+    UnremovableBeanBuildItem retainRagRetrievalFilterSuppliers() {
+        return 
UnremovableBeanBuildItem.beanTypes(RAG_RETRIEVAL_FILTER_SUPPLIER_DOTNAME);
+    }
+
+    /**
+     * The retrieval filter is an access control, so every way of disabling it 
silently is a build
+     * failure or a warning: two implementations make the lookup ambiguous, a 
{@code @Dependent}
+     * one is resolved once and never destroyed, and a filter no produced 
augmentor will ever
+     * consult isolates nothing.
+     */
+    @BuildStep
+    void validateRagRetrievalFilterSupplier(BeanDiscoveryFinishedBuildItem 
beanDiscovery,
+            RagBridgeConfig ragBridgeConfig,
+            BuildProducer<ValidationErrorBuildItem> validationErrors) {
+        BeanCensus census = BeanCensus.of(beanDiscovery);
+        if (census.filterSuppliers().isEmpty()) {
+            return;
+        }
+
+        if (census.filterSuppliers().size() > 1) {
+            validationErrors.produce(new ValidationErrorBuildItem(new 
ConfigurationException(
+                    "Found " + census.filterSuppliers().size() + " 
RagRetrievalFilterSupplier beans ("
+                            + census.filterSuppliers().stream().map(bean -> 
bean.getBeanClass().toString())
+                                    .collect(Collectors.joining(", "))
+                            + "). Exactly one is allowed: an ambiguous lookup 
would leave every retrieval "
+                            + "unfiltered instead of failing.")));
+            return;
+        }
+
+        BeanInfo supplier = census.filterSuppliers().get(0);
+        if (DEPENDENT_DOTNAME.equals(supplier.getScope().getDotName())) {
+            validationErrors.produce(new ValidationErrorBuildItem(new 
ConfigurationException(
+                    "RagRetrievalFilterSupplier bean " + 
supplier.getBeanClass()
+                            + " is @Dependent. Use @ApplicationScoped, 
@RequestScoped or @Singleton: the supplier "
+                            + "is resolved once per augmentor, so a @Dependent 
instance would never be destroyed.")));
+            return;
+        }
+
+        if (!census.producesAugmentor(ragBridgeConfig, new 
EasyRagPresent().getAsBoolean())) {
+            LOG.warnf("RagRetrievalFilterSupplier bean %s will never be 
consulted: it filters only the "
+                    + "RetrievalAugmentors produced by this extension, and 
none is produced here (Easy RAG or an "
+                    + "application-provided RetrievalAugmentor takes over). 
Retrieval is NOT filtered.",
+                    supplier.getBeanClass());
+        }
+    }
+
     // A store declared only for use from a Camel route is never injected 
anywhere in Java,
     // so ArC would remove it as unused and registerNamedEmbeddingStores would 
find nothing.
     @BuildStep
@@ -296,6 +356,16 @@ class SupportQuarkusLangchain4jProcessor {
         }
     }
 
+    // RagAugmentorName carries @Qualifier, but it lives in the support 
runtime artifact, which
+    // ships no Jandex index. Without this registration ArC does not know the 
annotation at all
+    // and the synthetic bean below fails the build with
+    // "Annotation class not available: @RagAugmentorName".
+    @BuildStep
+    QualifierRegistrarBuildItem registerRagAugmentorNameQualifier() {
+        return new QualifierRegistrarBuildItem(
+                () -> 
Map.of(DotName.createSimple(RagAugmentorName.class.getName()), Set.of()));
+    }
+
     /**
      * Produces {@link RetrievalAugmentor} CDI beans that bridge Camel 
ingestion routes with
      * {@code @RegisterAiService} RAG.
@@ -304,8 +374,9 @@ class SupportQuarkusLangchain4jProcessor {
      * Two modes:
      * <ul>
      * <li><b>Explicit config</b> — each entry under {@code 
quarkus.camel.langchain4j.rag.augmentors.<name>}
-     * produces a {@code @Named("<name>")} RetrievalAugmentor backed by the 
configured store.
-     * If only one entry exists, it is also marked as {@code defaultBean()} 
for auto-discovery.</li>
+     * produces a {@code @Named("<name>")} RetrievalAugmentor backed by the 
configured store. The entry
+     * marked {@code default=true} also serves the unqualified lookup; with a 
single entry that marking
+     * is optional, with several it is required.</li>
      * <li><b>Auto-detection</b> — when no config entries exist, at least one 
EmbeddingStore and one
      * EmbeddingModel are present, and no RetrievalAugmentor exists yet, a 
default one is produced
      * backed by the {@code @Default} CDI bean.</li>
@@ -319,49 +390,43 @@ class SupportQuarkusLangchain4jProcessor {
             QuarkusLangchain4jRecorder recorder,
             BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {
 
-        DotName embeddingStoreDN = 
DotName.createSimple(EmbeddingStore.class.getName());
-        DotName embeddingModelDN = 
DotName.createSimple(EmbeddingModel.class.getName());
-        DotName retrievalAugmentorDN = 
DotName.createSimple(RetrievalAugmentor.class.getName());
-
-        int embeddingStoreCount = 0;
-        int embeddingModelCount = 0;
-        boolean hasRetrievalAugmentor = false;
-
-        for (BeanInfo bean : 
beanDiscovery.beanStream().collect(Collectors.toList())) {
-            for (Type type : bean.getTypes()) {
-                DotName typeName = type.name();
-                if (typeName.equals(embeddingStoreDN)) {
-                    embeddingStoreCount++;
-                } else if (typeName.equals(embeddingModelDN)) {
-                    embeddingModelCount++;
-                } else if (typeName.equals(retrievalAugmentorDN)) {
-                    hasRetrievalAugmentor = true;
-                }
-            }
+        BeanCensus census = BeanCensus.of(beanDiscovery);
+
+        // Effective augmentors: one per explicit config entry. Sorted, so 
that a message naming
+        // them reads the same on every build - SmallRye's map is not 
declaration-ordered.
+        Map<String, AugmentorDefinition> effective = new TreeMap<>();
+        for (Map.Entry<String, AugmentorConfig> entry : 
ragBridgeConfig.augmentors().entrySet()) {
+            AugmentorConfig cfg = entry.getValue();
+            effective.put(entry.getKey(), new AugmentorDefinition(
+                    cfg.embeddingStoreName(), 
cfg.embeddingModelName().orElse(null), cfg.defaultAugmentor()));
         }
 
-        Map<String, AugmentorConfig> augmentors = ragBridgeConfig.augmentors();
+        if (!effective.isEmpty()) {
+            String designatedDefault = resolveDesignatedDefault(effective, 
census.retrievalAugmentor());
 
-        if (!augmentors.isEmpty()) {
-            for (Map.Entry<String, AugmentorConfig> entry : 
augmentors.entrySet()) {
+            for (Map.Entry<String, AugmentorDefinition> entry : 
effective.entrySet()) {
                 String name = entry.getKey();
-                AugmentorConfig cfg = entry.getValue();
+                AugmentorDefinition def = entry.getValue();
 
-                LOG.debugf("Registering named RetrievalAugmentor '%s' backed 
by EmbeddingStore '%s'",
-                        name, cfg.embeddingStoreName());
+                LOG.debugf("Registering named RetrievalAugmentor '%s' backed 
by EmbeddingStore '%s'%s",
+                        name, def.embeddingStoreName(), 
name.equals(designatedDefault) ? " (default)" : "");
 
                 SyntheticBeanBuildItem.ExtendedBeanConfigurator configurator = 
SyntheticBeanBuildItem
                         .configure(RetrievalAugmentor.class)
                         .scope(ApplicationScoped.class)
                         
.addQualifier().annotation(Named.class).addValue("value", name).done()
                         .setRuntimeInit()
-                        
.supplier(recorder.createDefaultRetrievalAugmentorSupplier(
-                                cfg.embeddingStoreName(), 
cfg.embeddingModelName().orElse(null)));
+                        .supplier(recorder.createRetrievalAugmentorSupplier(
+                                def.embeddingStoreName(), 
def.embeddingModelName(), name));
 
-                // Single augmentor configured and no user/Easy-RAG augmentor 
present:
-                // mark as defaultBean() so @RegisterAiService discovers it 
without a qualifier
-                if (augmentors.size() == 1 && !hasRetrievalAugmentor) {
+                if (name.equals(designatedDefault)) {
+                    // keeps @Named only: the implicit @Default makes it the 
one candidate the
+                    // unqualified Instance<RetrievalAugmentor> lookup of 
Quarkus LangChain4j sees
                     configurator.defaultBean();
+                } else {
+                    // a real qualifier suppresses the implicit @Default (CDI 
rule), so this bean
+                    // stays selectable by name without making the unqualified 
lookup ambiguous
+                    
configurator.addQualifier().annotation(RagAugmentorName.class).addValue("value",
 name).done();
                 }
 
                 syntheticBeans.produce(configurator.done());
@@ -369,11 +434,11 @@ class SupportQuarkusLangchain4jProcessor {
             return;
         }
 
-        if (hasRetrievalAugmentor) {
+        if (census.retrievalAugmentor()) {
             return;
         }
 
-        if (embeddingStoreCount >= 1 && embeddingModelCount >= 1) {
+        if (census.embeddingStores() >= 1 && census.embeddingModels() >= 1) {
             LOG.debug("EmbeddingStore and EmbeddingModel CDI beans detected"
                     + " - registering default RetrievalAugmentor backed by 
@Default store");
             syntheticBeans.produce(SyntheticBeanBuildItem
@@ -381,8 +446,97 @@ class SupportQuarkusLangchain4jProcessor {
                     .scope(ApplicationScoped.class)
                     .defaultBean()
                     .setRuntimeInit()
-                    
.supplier(recorder.createDefaultRetrievalAugmentorSupplier(null, null))
+                    .supplier(recorder.createRetrievalAugmentorSupplier(null, 
null, null))
                     .done());
         }
     }
+
+    /**
+     * Decides which augmentor is the unqualified default, or fails the build: 
silence here would
+     * mean an ambiguous CDI lookup and RAG silently switched off for every AI 
service.
+     */
+    static String resolveDesignatedDefault(Map<String, AugmentorDefinition> 
effective,
+            boolean hasRetrievalAugmentor) {
+        List<String> marked = effective.entrySet().stream()
+                .filter(e -> e.getValue().markedDefault())
+                .map(Map.Entry::getKey)
+                .toList();
+
+        if (marked.size() > 1) {
+            throw new ConfigurationException(
+                    "Multiple retrieval augmentors are marked default: " + 
marked + ". Mark exactly one with "
+                            + 
"quarkus.camel.langchain4j.rag.augmentors.<name>.default=true");
+        }
+
+        if (hasRetrievalAugmentor) {
+            // a user-provided RetrievalAugmentor bean already serves the 
unqualified lookup
+            if (marked.size() == 1) {
+                throw new ConfigurationException(
+                        "Retrieval augmentor '" + marked.get(0) + "' is marked 
default, but the application "
+                                + "already provides a RetrievalAugmentor bean. 
Remove the default marking — "
+                                + "produced augmentors remain selectable by 
name.");
+            }
+            return null;
+        }
+
+        if (marked.size() == 1) {
+            return marked.get(0);
+        }
+
+        if (effective.size() == 1) {
+            return effective.keySet().iterator().next();
+        }
+
+        throw new ConfigurationException(
+                effective.size() + " retrieval augmentors are configured (" + 
String.join(", ", effective.keySet())
+                        + ") but none is marked default. An unmarked ambiguity 
would silently disable RAG for "
+                        + "every AI service, so the build stops instead. Mark 
exactly one with "
+                        + 
"quarkus.camel.langchain4j.rag.augmentors.<name>.default=true");
+    }
+
+    record AugmentorDefinition(String embeddingStoreName, String 
embeddingModelName, boolean markedDefault) {
+    }
+
+    /** One pass over the discovered beans, answering everything the RAG 
bridge decides on. */
+    record BeanCensus(int embeddingStores, int embeddingModels, boolean 
retrievalAugmentor,
+            List<BeanInfo> filterSuppliers) {
+
+        static BeanCensus of(BeanDiscoveryFinishedBuildItem beanDiscovery) {
+            DotName embeddingStoreDN = 
DotName.createSimple(EmbeddingStore.class.getName());
+            DotName embeddingModelDN = 
DotName.createSimple(EmbeddingModel.class.getName());
+            DotName retrievalAugmentorDN = 
DotName.createSimple(RetrievalAugmentor.class.getName());
+
+            int embeddingStores = 0;
+            int embeddingModels = 0;
+            boolean retrievalAugmentor = false;
+            List<BeanInfo> filterSuppliers = new ArrayList<>();
+
+            for (BeanInfo bean : 
beanDiscovery.beanStream().collect(Collectors.toList())) {
+                for (Type type : bean.getTypes()) {
+                    DotName typeName = type.name();
+                    if (typeName.equals(embeddingStoreDN)) {
+                        embeddingStores++;
+                    } else if (typeName.equals(embeddingModelDN)) {
+                        embeddingModels++;
+                    } else if (typeName.equals(retrievalAugmentorDN)) {
+                        retrievalAugmentor = true;
+                    } else if 
(typeName.equals(RAG_RETRIEVAL_FILTER_SUPPLIER_DOTNAME)) {
+                        filterSuppliers.add(bean);
+                    }
+                }
+            }
+            return new BeanCensus(embeddingStores, embeddingModels, 
retrievalAugmentor, filterSuppliers);
+        }
+
+        /** Whether {@link #registerDefaultRetrievalAugmentor} will produce an 
augmentor to filter. */
+        boolean producesAugmentor(RagBridgeConfig ragBridgeConfig, boolean 
easyRagPresent) {
+            if (easyRagPresent) {
+                return false;
+            }
+            if (!ragBridgeConfig.augmentors().isEmpty()) {
+                return true;
+            }
+            return !retrievalAugmentor && embeddingStores >= 1 && 
embeddingModels >= 1;
+        }
+    }
 }
diff --git 
a/extensions-support/langchain4j/deployment/src/test/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/RagAugmentorDefaultResolutionTest.java
 
b/extensions-support/langchain4j/deployment/src/test/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/RagAugmentorDefaultResolutionTest.java
new file mode 100644
index 0000000000..fbd3d3afe4
--- /dev/null
+++ 
b/extensions-support/langchain4j/deployment/src/test/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/RagAugmentorDefaultResolutionTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.support.langchain4j.deployment;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import io.quarkus.runtime.configuration.ConfigurationException;
+import 
org.apache.camel.quarkus.component.support.langchain4j.deployment.SupportQuarkusLangchain4jProcessor.AugmentorDefinition;
+import org.junit.jupiter.api.Test;
+
+import static 
org.apache.camel.quarkus.component.support.langchain4j.deployment.SupportQuarkusLangchain4jProcessor.resolveDesignatedDefault;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The designated-default rules: two augmentors with no default marked must 
fail the build —
+ * an unmarked ambiguity would make the unqualified {@code 
Instance<RetrievalAugmentor>} lookup
+ * unresolvable and silently disable RAG for every AI service.
+ */
+class RagAugmentorDefaultResolutionTest {
+
+    @Test
+    void singleAugmentorIsImplicitlyDefault() {
+        assertEquals("products", 
resolveDesignatedDefault(augmentors("products", false), false));
+    }
+
+    @Test
+    void multipleAugmentorsWithOneMarkedResolveToIt() {
+        Map<String, AugmentorDefinition> effective = augmentors("products", 
false, "support", true);
+        assertEquals("support", resolveDesignatedDefault(effective, false));
+    }
+
+    @Test
+    void multipleAugmentorsWithNoneMarkedFailTheBuild() {
+        Map<String, AugmentorDefinition> effective = augmentors("products", 
false, "support", false);
+        ConfigurationException e = assertThrows(ConfigurationException.class,
+                () -> resolveDesignatedDefault(effective, false));
+        assertTrue(e.getMessage().contains("none is marked default"), 
e.getMessage());
+        assertTrue(e.getMessage().contains(".default=true"), e.getMessage());
+    }
+
+    @Test
+    void multipleAugmentorsMarkedDefaultFailTheBuild() {
+        Map<String, AugmentorDefinition> effective = augmentors("products", 
true, "support", true);
+        ConfigurationException e = assertThrows(ConfigurationException.class,
+                () -> resolveDesignatedDefault(effective, false));
+        assertTrue(e.getMessage().contains("Multiple retrieval augmentors are 
marked default"), e.getMessage());
+    }
+
+    @Test
+    void userProvidedAugmentorSuppressesAnyDefault() {
+        assertNull(resolveDesignatedDefault(augmentors("products", false, 
"support", false), true));
+    }
+
+    @Test
+    void userProvidedAugmentorConflictsWithMarkedDefault() {
+        ConfigurationException e = assertThrows(ConfigurationException.class,
+                () -> resolveDesignatedDefault(augmentors("products", true), 
true));
+        assertTrue(e.getMessage().contains("already provides a 
RetrievalAugmentor"), e.getMessage());
+    }
+
+    private static Map<String, AugmentorDefinition> augmentors(Object... 
nameAndDefaultPairs) {
+        Map<String, AugmentorDefinition> map = new LinkedHashMap<>();
+        for (int i = 0; i < nameAndDefaultPairs.length; i += 2) {
+            String name = (String) nameAndDefaultPairs[i];
+            boolean markedDefault = (Boolean) nameAndDefaultPairs[i + 1];
+            map.put(name, new AugmentorDefinition(name + "-store", null, 
markedDefault));
+        }
+        return map;
+    }
+}
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/DefaultRetrievalAugmentorSupplier.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/DefaultRetrievalAugmentorSupplier.java
index b60cd2d82b..99c2455371 100644
--- 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/DefaultRetrievalAugmentorSupplier.java
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/DefaultRetrievalAugmentorSupplier.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.quarkus.component.support.langchain4j;
 
+import java.util.List;
 import java.util.function.Supplier;
 
 import dev.langchain4j.data.segment.TextSegment;
@@ -26,6 +27,7 @@ import 
dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
 import dev.langchain4j.store.embedding.EmbeddingStore;
 import io.quarkiverse.langchain4j.EmbeddingStoreName;
 import io.quarkus.arc.Arc;
+import io.quarkus.arc.InstanceHandle;
 import jakarta.enterprise.inject.literal.NamedLiteral;
 import jakarta.enterprise.util.TypeLiteral;
 import org.jboss.logging.Logger;
@@ -42,6 +44,7 @@ public class DefaultRetrievalAugmentorSupplier implements 
Supplier<RetrievalAugm
     private static final TypeLiteral<EmbeddingStore<TextSegment>> 
EMBEDDING_STORE_TYPE = new TypeLiteral<>() {
     };
 
+    private final String augmentorName;
     private final String embeddingStoreName;
     private final String embeddingModelName;
 
@@ -50,8 +53,14 @@ public class DefaultRetrievalAugmentorSupplier implements 
Supplier<RetrievalAugm
     }
 
     public DefaultRetrievalAugmentorSupplier(String embeddingStoreName, String 
embeddingModelName) {
+        this(embeddingStoreName, embeddingModelName, null);
+    }
+
+    public DefaultRetrievalAugmentorSupplier(String embeddingStoreName, String 
embeddingModelName,
+            String augmentorName) {
         this.embeddingStoreName = embeddingStoreName;
         this.embeddingModelName = embeddingModelName;
+        this.augmentorName = augmentorName;
     }
 
     @Override
@@ -95,11 +104,33 @@ public class DefaultRetrievalAugmentorSupplier implements 
Supplier<RetrievalAugm
                 + " (store=%s, model=%s)", embeddingStoreName != null ? 
embeddingStoreName : "@Default",
                 embeddingModelName != null ? embeddingModelName : "@Default");
 
+        EmbeddingStoreContentRetriever.EmbeddingStoreContentRetrieverBuilder 
retriever = EmbeddingStoreContentRetriever
+                .builder()
+                .embeddingStore(store)
+                .embeddingModel(model);
+
+        // The retrieval-side isolation hook: segment metadata written at 
ingestion time becomes
+        // an actual access control. Resolved with listAll rather than 
instance(), which matches
+        // on @Default only and answers "unavailable" for an ambiguity - 
either would drop the
+        // filter silently and serve every tenant's documents. The build 
rejects both cases; this
+        // is the second line of defence.
+        List<InstanceHandle<RagRetrievalFilterSupplier>> filterSuppliers = 
Arc.container()
+                .listAll(RagRetrievalFilterSupplier.class);
+        if (filterSuppliers.size() > 1) {
+            throw new IllegalStateException("Found " + filterSuppliers.size()
+                    + " RagRetrievalFilterSupplier beans, expected at most 
one: "
+                    + filterSuppliers.stream().map(handle -> 
handle.getBean().getBeanClass().getName()).toList());
+        }
+        if (!filterSuppliers.isEmpty()) {
+            RagRetrievalFilterSupplier filterSupplier = 
filterSuppliers.get(0).get();
+            retriever.dynamicFilter(query -> filterSupplier.filter(query, 
augmentorName, embeddingStoreName));
+            LOG.debugf("Retrieval filter %s active for augmentor '%s' over 
store '%s'",
+                    filterSupplier.getClass().getName(), augmentorName,
+                    embeddingStoreName != null ? embeddingStoreName : 
"@Default");
+        }
+
         return DefaultRetrievalAugmentor.builder()
-                .contentRetriever(EmbeddingStoreContentRetriever.builder()
-                        .embeddingStore(store)
-                        .embeddingModel(model)
-                        .build())
+                .contentRetriever(retriever.build())
                 .build();
     }
 }
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
index 9c72c20d1a..7b80f57df8 100644
--- 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
@@ -96,8 +96,9 @@ public class QuarkusLangchain4jRecorder {
         }
     }
 
-    public Supplier<RetrievalAugmentor> 
createDefaultRetrievalAugmentorSupplier(
-            String embeddingStoreName, String embeddingModelName) {
-        return new DefaultRetrievalAugmentorSupplier(embeddingStoreName, 
embeddingModelName);
+    /** @param augmentorName {@code null} for the auto-produced default 
augmentor. */
+    public Supplier<RetrievalAugmentor> createRetrievalAugmentorSupplier(
+            String embeddingStoreName, String embeddingModelName, String 
augmentorName) {
+        return new DefaultRetrievalAugmentorSupplier(embeddingStoreName, 
embeddingModelName, augmentorName);
     }
 }
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagAugmentorName.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagAugmentorName.java
new file mode 100644
index 0000000000..8d8ac05aef
--- /dev/null
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagAugmentorName.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.support.langchain4j;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Qualifier;
+
+/**
+ * Qualifies a produced {@link dev.langchain4j.rag.RetrievalAugmentor} bean by 
name.
+ *
+ * <p>
+ * Used only internally to mark RagAugmentors, which are not default. See
+ * SupportQuarkusLangchain4jProcessor.registerDefaultRetrievalAugmentor
+ * Named annotation cannot be used, as it makes beans default.
+ */
+@Qualifier
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, 
ElementType.PARAMETER })
+public @interface RagAugmentorName {
+
+    String value();
+}
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagBridgeConfig.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagBridgeConfig.java
index 4744841a31..9f81a76545 100644
--- 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagBridgeConfig.java
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagBridgeConfig.java
@@ -22,6 +22,8 @@ import java.util.Optional;
 import io.quarkus.runtime.annotations.ConfigPhase;
 import io.quarkus.runtime.annotations.ConfigRoot;
 import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
+import io.smallrye.config.WithName;
 
 // BUILD_AND_RUN_TIME_FIXED: augmentor bean definitions are baked in at build 
time and cannot change at runtime
 @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
@@ -54,5 +56,15 @@ public interface RagBridgeConfig {
          * When not set, the default (unnamed) EmbeddingModel is used.
          */
         Optional<String> embeddingModelName();
+
+        /**
+         * Marks this augmentor as the one {@code @RegisterAiService} AI 
services use when they
+         * do not select an augmentor explicitly. Exactly one augmentor must 
be marked when more
+         * than one is configured — otherwise the build fails, because an 
unmarked ambiguity
+         * would silently disable RAG for every AI service in the application.
+         */
+        @WithName("default")
+        @WithDefault("false")
+        boolean defaultAugmentor();
     }
 }
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagRetrievalFilterSupplier.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagRetrievalFilterSupplier.java
new file mode 100644
index 0000000000..a8e403b034
--- /dev/null
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/RagRetrievalFilterSupplier.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.support.langchain4j;
+
+import dev.langchain4j.rag.query.Query;
+import dev.langchain4j.store.embedding.filter.Filter;
+
+/**
+ * The retrieval-side isolation hook: implemented as a CDI bean, consulted on 
<em>every</em>
+ * retrieval performed by a {@link dev.langchain4j.rag.RetrievalAugmentor} 
produced by this
+ * extension. Segment metadata written at ingestion time (a tenant key, a 
classification, an
+ * owner) isolates nothing on its own; this is what turns it into an access 
control.
+ *
+ * <p>
+ * Typical implementation: derive the caller's tenant from the request and 
return
+ * {@code metadataKey("tenant").isEqualTo(tenant)}.
+ *
+ * <p>
+ * At most one implementation may exist and it must not be {@code @Dependent} 
— both are build
+ * failures. Declare it {@code @ApplicationScoped}, {@code @RequestScoped} or 
{@code @Singleton};
+ * it is resolved once per augmentor, so per-request state belongs in an 
injected request-scoped
+ * bean rather than in a field.
+ *
+ * <p>
+ * <strong>The filter is only as strong as the store.</strong> {@code 
EmbeddingStore}
+ * implementations are not required to support filtering, and one that ignores 
the filter returns
+ * every match. Verify against the store actually in use before relying on 
this for isolation.
+ */
+public interface RagRetrievalFilterSupplier {
+
+    /**
+     * @param  query              the retrieval query, whose {@link 
Query#metadata()} carries the
+     *                            {@code chatMemoryId} of the calling AI 
service when there is one
+     * @param  augmentorName      the name of the augmentor performing the 
retrieval, as configured
+     *                            under {@code 
quarkus.camel.langchain4j.rag.augmentors.<name>};
+     *                            {@code null} for the auto-produced default 
augmentor
+     * @param  embeddingStoreName the store being searched, named by
+     *                            {@code 
quarkus.camel.langchain4j.rag.augmentors.<name>.embedding-store-name};
+     *                            {@code null} when the augmentor is backed by 
the {@code @Default}
+     *                            store. The same supplier serves every 
produced augmentor, so this
+     *                            is what tells a filter written for one 
store's metadata whether it
+     *                            applies at all — return {@code null} for the 
stores it does not
+     *                            know, since filtering on an absent metadata 
key matches nothing.
+     * @return                    the filter to apply, or {@code null} for 
unfiltered retrieval, as
+     *                            in LangChain4j itself. {@code null} 
therefore means "no
+     *                            restriction", never "deny": an 
implementation that cannot
+     *                            determine the caller must throw, so that 
retrieval fails instead
+     *                            of returning every tenant's documents.
+     */
+    Filter filter(Query query, String augmentorName, String 
embeddingStoreName);
+}
diff --git 
a/extensions/langchain4j-embeddingstore/runtime/src/main/doc/usage.adoc 
b/extensions/langchain4j-embeddingstore/runtime/src/main/doc/usage.adoc
index 46609a802e..daf2cf98c1 100644
--- a/extensions/langchain4j-embeddingstore/runtime/src/main/doc/usage.adoc
+++ b/extensions/langchain4j-embeddingstore/runtime/src/main/doc/usage.adoc
@@ -12,3 +12,74 @@ from("direct:ingest-products")
 ----
 
 A store only referenced from routes does not need to be injected anywhere in 
Java code; it is retained and instantiated lazily on first use. If the Camel 
registry already resolves a different `EmbeddingStore` under the same name (for 
example a `@Named` bean), that existing bean keeps winning lookups and a 
warning is logged at startup.
+
+=== Retrieval augmentors for `@RegisterAiService`
+
+With Quarkus LangChain4j present, a `RetrievalAugmentor` is produced 
automatically from the `@Default` `EmbeddingStore` and `EmbeddingModel` beans, 
so an `@RegisterAiService` interface answers from the same store a Camel route 
ingests into. Nothing is produced when the application declares its own 
`RetrievalAugmentor`.
+
+Augmentors can also be declared explicitly, one per store:
+
+[source,properties]
+----
+quarkus.camel.langchain4j.rag.augmentors.products.embedding-store-name=products
+quarkus.camel.langchain4j.rag.augmentors.products.default=true
+quarkus.camel.langchain4j.rag.augmentors.support.embedding-store-name=support-docs
+----
+
+Each entry produces a `@Named` `RetrievalAugmentor`. With more than one 
configured, exactly one must be marked `default=true`: that one serves the 
unqualified lookup `@RegisterAiService` performs, while the others remain 
selectable by name. Configuring several without marking one fails the build, 
because an ambiguous unqualified lookup disables RAG for every AI service 
without reporting anything. A single entry needs no marking.
+
+Selecting one of the others means naming it through a supplier, since 
`@RegisterAiService` either takes the unqualified augmentor or a `Supplier` 
class:
+
+[source,java]
+----
+public class SupportAugmentorSupplier implements Supplier<RetrievalAugmentor> {
+    @Inject
+    @Named("support")
+    RetrievalAugmentor augmentor;
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+}
+
+@RegisterAiService(retrievalAugmentor = SupportAugmentorSupplier.class)
+public interface SupportAssistant {
+    String chat(String question);
+}
+----
+
+=== Filtering what retrieval may see
+
+Metadata stored next to a segment — a tenant key, a classification — isolates 
nothing unless retrieval filters on it. A single `RagRetrievalFilterSupplier` 
bean, if present, is consulted on every retrieval performed by a produced 
augmentor:
+
+[source,java]
+----
+@ApplicationScoped
+public class TenantFilterSupplier implements RagRetrievalFilterSupplier {
+    @Inject
+    CurrentTenant currentTenant; // request scoped
+
+    @Override
+    public Filter filter(Query query, String augmentorName, String 
embeddingStoreName) {
+        if (!"products".equals(embeddingStoreName)) {
+            return null; // only this store carries tenant metadata
+        }
+        String tenant = currentTenant.name();
+        if (tenant == null) {
+            // fail closed: returning null here would serve every tenant's 
documents
+            throw new IllegalStateException("No tenant in scope");
+        }
+        return metadataKey("tenant").isEqualTo(tenant);
+    }
+}
+----
+
+The one bean serves every produced augmentor, so it is told which augmentor 
retrieves and which store is being searched; both are `null` for the 
auto-produced default augmentor, which is backed by the `@Default` beans. 
Filtering on a metadata key a store does not carry matches nothing, so return 
`null` for the stores an implementation does not know about.
+
+Returning `null` means unfiltered retrieval, as it does in LangChain4j itself, 
so an implementation that cannot determine the caller must throw instead. The 
tenant may equally come from `query.metadata().chatMemoryId()`, which is the 
only source that still works when retrieval does not run on the caller's 
thread. At most one implementation may exist, and it must not be `@Dependent`; 
both are build failures.
+
+Two limits are worth knowing before treating this as an access control:
+
+* The filter reaches only the augmentors this extension produces. Easy RAG, or 
an application-provided `RetrievalAugmentor`, replaces them, and the filter is 
then never consulted — the build logs a warning when it detects that 
combination.
+* `EmbeddingStore` implementations are not required to support filtering. One 
that ignores the filter returns every match, so verify against the store 
actually in use.
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagBridgeResource.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagBridgeResource.java
index b0ef892923..b653357fdd 100644
--- 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagBridgeResource.java
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagBridgeResource.java
@@ -16,17 +16,28 @@
  */
 package org.apache.camel.quarkus.component.langchain4j.ragbridge.it;
 
+import java.util.List;
+import java.util.Map;
+
+import dev.langchain4j.data.document.Metadata;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.rag.AugmentationRequest;
+import dev.langchain4j.rag.AugmentationResult;
 import dev.langchain4j.rag.RetrievalAugmentor;
 import dev.langchain4j.store.embedding.EmbeddingStore;
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.MediaType;
 import org.apache.camel.CamelContext;
 import org.apache.camel.ProducerTemplate;
@@ -41,6 +52,19 @@ public class RagBridgeResource {
     @Named("products")
     Instance<RetrievalAugmentor> namedAugmentorInstance;
 
+    // the augmentor that is NOT the designated default, so it carries 
@RagAugmentorName on top
+    // of @Named - the qualifier that must keep it selectable by name
+    @Inject
+    @Named("support")
+    Instance<RetrievalAugmentor> supportAugmentorInstance;
+
+    @Inject
+    @Named("defaultStore")
+    EmbeddingStore<TextSegment> defaultStore;
+
+    @Inject
+    EmbeddingModel embeddingModel;
+
     @Inject
     ProducerTemplate producerTemplate;
 
@@ -97,4 +121,90 @@ public class RagBridgeResource {
     public String ask(String question) {
         return aiService.chat(question);
     }
+
+    @GET
+    @Path("/support-augmentor-present")
+    @Produces(MediaType.TEXT_PLAIN)
+    public boolean isSupportAugmentorPresent() {
+        return supportAugmentorInstance.isResolvable();
+    }
+
+    // --- retrieval filter hook 
-----------------------------------------------------------
+
+    /** Seeds the default store with a tenant-tagged segment, like the ingest 
extension does. */
+    @POST
+    @Path("/seed/{tenant}")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String seed(@PathParam("tenant") String tenant, String text) {
+        TextSegment segment = TextSegment.from(text, 
Metadata.from(Map.of("cq_tenant", tenant)));
+        defaultStore.add(embeddingModel.embed(segment).content(), segment);
+        return "seeded";
+    }
+
+    /** Lets a test start from a known store, since the default store is 
shared with other tests. */
+    @DELETE
+    @Path("/seed")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String clearSeeds() {
+        defaultStore.removeAll();
+        return "cleared";
+    }
+
+    @POST
+    @Path("/tenant-filter/{tenant}")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String setTenantFilter(@PathParam("tenant") String tenant) {
+        TestTenantFilterSupplier.tenant = "none".equals(tenant) ? null : 
tenant;
+        return "ok";
+    }
+
+    @GET
+    @Path("/filter/last-augmentor")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String lastFilteredAugmentor() {
+        return String.valueOf(TestTenantFilterSupplier.lastAugmentorName);
+    }
+
+    @GET
+    @Path("/filter/last-store")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String lastFilteredStore() {
+        return String.valueOf(TestTenantFilterSupplier.lastEmbeddingStoreName);
+    }
+
+    /**
+     * Runs a produced augmentor directly, returning the retrieved segment 
texts. {@code memoryId}
+     * travels in the query metadata, the only tenant source that survives 
retrieval running off
+     * the caller's thread.
+     */
+    @POST
+    @Path("/augment")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<String> augment(@QueryParam("augmentor") String augmentor,
+            @QueryParam("memoryId") String memoryId, String question) {
+        UserMessage userMessage = UserMessage.from(question);
+        AugmentationResult result = augmentorFor(augmentor)
+                .augment(new AugmentationRequest(userMessage,
+                        dev.langchain4j.rag.query.Metadata.from(userMessage, 
memoryId, null)));
+        return result.contents().stream().map(content -> 
content.textSegment().text()).toList();
+    }
+
+    private RetrievalAugmentor augmentorFor(String augmentor) {
+        return switch (augmentor == null ? "default" : augmentor) {
+        case "products" -> namedAugmentorInstance.get();
+        case "support" -> supportAugmentorInstance.get();
+        default -> retrievalAugmentorInstance.get();
+        };
+    }
+
+    @DELETE
+    @Path("/filter/last-call")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String forgetLastFilterCall() {
+        TestTenantFilterSupplier.forgetLastCall();
+        return "forgotten";
+    }
+
 }
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/TestTenantFilterSupplier.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/TestTenantFilterSupplier.java
new file mode 100644
index 0000000000..8d737a3909
--- /dev/null
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/main/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/TestTenantFilterSupplier.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.langchain4j.ragbridge.it;
+
+import dev.langchain4j.rag.query.Query;
+import dev.langchain4j.store.embedding.filter.Filter;
+import dev.langchain4j.store.embedding.filter.MetadataFilterBuilder;
+import jakarta.enterprise.context.ApplicationScoped;
+import 
org.apache.camel.quarkus.component.support.langchain4j.RagRetrievalFilterSupplier;
+
+/**
+ * The retrieval-side isolation hook under test: every retrieval through a 
produced augmentor is
+ * filtered to one tenant's documents. The tenant comes either from state set 
out of band (via
+ * REST) or from the query's {@code chatMemoryId} — the second source is the 
one that keeps
+ * working when retrieval runs off the caller's thread, so both are exercised.
+ *
+ * <p>
+ * The bean stays inert until a test switches it on: this is the only 
implementation in the
+ * application, so a filter applied by default would silently strip the 
context out of every
+ * other test's AI service call.
+ */
+@ApplicationScoped
+public class TestTenantFilterSupplier implements RagRetrievalFilterSupplier {
+
+    /** Set to this instead of a tenant to take the tenant from the query's 
chat memory id. */
+    static final String FROM_QUERY = "from-query";
+    /** Tells "the hook ran and was handed null" apart from "the hook never 
ran". */
+    static final String NOT_CALLED = "<not-called>";
+
+    static volatile String tenant;
+    static volatile String lastAugmentorName;
+    static volatile String lastEmbeddingStoreName;
+
+    static void forgetLastCall() {
+        lastAugmentorName = NOT_CALLED;
+        lastEmbeddingStoreName = NOT_CALLED;
+    }
+
+    @Override
+    public Filter filter(Query query, String augmentorName, String 
embeddingStoreName) {
+        lastAugmentorName = augmentorName;
+        lastEmbeddingStoreName = embeddingStoreName;
+        if (tenant == null) {
+            return null;
+        }
+        String effectiveTenant = FROM_QUERY.equals(tenant) ? 
chatMemoryId(query) : tenant;
+        return effectiveTenant == null
+                ? null
+                : 
MetadataFilterBuilder.metadataKey("cq_tenant").isEqualTo(effectiveTenant);
+    }
+
+    private static String chatMemoryId(Query query) {
+        Object memoryId = query.metadata() == null ? null : 
query.metadata().chatMemoryId();
+        return memoryId == null ? null : memoryId.toString();
+    }
+}
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
index 112155722d..0f5cff5848 100644
--- 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
@@ -23,8 +23,13 @@ import io.quarkus.test.junit.QuarkusTestProfile;
 public class MultiAugmentorProfile implements QuarkusTestProfile {
     @Override
     public Map<String, String> getConfigOverrides() {
+        // Two augmentors require exactly one designated default — without the 
marking the build
+        // fails (see 
SupportQuarkusLangchain4jProcessor.resolveDesignatedDefault and its test)
         return Map.of(
                 
"quarkus.camel.langchain4j.rag.augmentors.products.embedding-store-name", 
"products",
-                
"quarkus.camel.langchain4j.rag.augmentors.support.embedding-store-name", 
"support");
+                "quarkus.camel.langchain4j.rag.augmentors.products.default", 
"true",
+                // the same store on purpose: this augmentor is here to prove 
that the non-default
+                // one stays selectable by name, so creating it must not fail 
on a missing store
+                
"quarkus.camel.langchain4j.rag.augmentors.support.embedding-store-name", 
"products");
     }
 }
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorTest.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorTest.java
index 60845f0cbe..1f044e848e 100644
--- 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorTest.java
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorTest.java
@@ -19,14 +19,16 @@ package 
org.apache.camel.quarkus.component.langchain4j.ragbridge.it;
 import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.TestProfile;
 import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.Matchers.is;
 
 /**
- * Verifies that when multiple augmentors are configured, no default 
(unqualified)
- * RetrievalAugmentor bean is produced. Each augmentor should only be 
resolvable
- * via its {@code @Named} qualifier to prevent silent auto-selection.
+ * Verifies that with multiple augmentors configured and one marked {@code 
default=true}, the
+ * designated one serves the unqualified lookup (RAG stays on) while the 
others remain
+ * resolvable by name. Two augmentors with no default marked fail the build 
instead of silently
+ * disabling RAG — covered by {@code RagAugmentorDefaultResolutionTest} in the 
support module.
  *
  * <p>
  * No {@code @QuarkusIntegrationTest} counterpart exists because this test uses
@@ -41,12 +43,12 @@ import static org.hamcrest.Matchers.is;
 class MultiAugmentorTest {
 
     @Test
-    void noDefaultAugmentorWithMultipleConfigured() {
+    void designatedDefaultAugmentorResolvableWithMultipleConfigured() {
         RestAssured.given()
                 .get("/rag-bridge/augmentor-present")
                 .then()
                 .statusCode(200)
-                .body(is("false"));
+                .body(is("true"));
     }
 
     @Test
@@ -57,4 +59,46 @@ class MultiAugmentorTest {
                 .statusCode(200)
                 .body(is("true"));
     }
+
+    /**
+     * The augmentor that is not the designated default: it carries {@code 
@RagAugmentorName} to
+     * suppress the implicit {@code @Default}, and the whole design depends on 
that qualifier
+     * leaving {@code @Named} lookup intact.
+     */
+    @Test
+    void nonDefaultAugmentorStillResolvableByName() {
+        RestAssured.given()
+                .get("/rag-bridge/support-augmentor-present")
+                .then()
+                .statusCode(200)
+                .body(is("true"));
+    }
+
+    /**
+     * The retrieval filter is one application-wide bean shared by every 
augmentor, so it is told
+     * both which augmentor retrieves and which store is being searched.
+     */
+    @Test
+    void retrievalFilterReceivesTheAugmentorAndStoreNames() {
+        
RestAssured.delete("/rag-bridge/filter/last-call").then().statusCode(200);
+
+        RestAssured.given()
+                .contentType(ContentType.TEXT)
+                .queryParam("augmentor", "support")
+                .body("anything")
+                .post("/rag-bridge/augment")
+                .then()
+                .statusCode(200);
+
+        RestAssured.get("/rag-bridge/filter/last-augmentor")
+                .then()
+                .statusCode(200)
+                .body(is("support"));
+
+        // the store this augmentor is configured with, not the augmentor's 
own name
+        RestAssured.get("/rag-bridge/filter/last-store")
+                .then()
+                .statusCode(200)
+                .body(is("products"));
+    }
 }
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterIT.java
similarity index 66%
copy from 
integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
copy to 
integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterIT.java
index 112155722d..ddb7fe2688 100644
--- 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/MultiAugmentorProfile.java
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterIT.java
@@ -16,15 +16,8 @@
  */
 package org.apache.camel.quarkus.component.langchain4j.ragbridge.it;
 
-import java.util.Map;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
 
-import io.quarkus.test.junit.QuarkusTestProfile;
-
-public class MultiAugmentorProfile implements QuarkusTestProfile {
-    @Override
-    public Map<String, String> getConfigOverrides() {
-        return Map.of(
-                
"quarkus.camel.langchain4j.rag.augmentors.products.embedding-store-name", 
"products",
-                
"quarkus.camel.langchain4j.rag.augmentors.support.embedding-store-name", 
"support");
-    }
+@QuarkusIntegrationTest
+class RagRetrievalFilterIT extends RagRetrievalFilterTest {
 }
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterTest.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterTest.java
new file mode 100644
index 0000000000..60037e8945
--- /dev/null
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/RagRetrievalFilterTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.langchain4j.ragbridge.it;
+
+import java.util.List;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The retrieval-side isolation hook: a {@code RagRetrievalFilterSupplier} 
bean filters every
+ * retrieval through the produced augmentor — tenant metadata written at 
ingestion time becomes
+ * an actual access control.
+ *
+ * <p>
+ * Each test starts from an emptied default store. That store is shared with 
the other tests in
+ * this profile, and the retriever returns its top 3 matches: without the 
reset, whether an
+ * assertion holds would depend on how many documents earlier tests happened 
to leave behind.
+ */
+@QuarkusTest
+class RagRetrievalFilterTest {
+
+    private static final String QUESTION = "What does the clause say about the 
quota?";
+
+    @BeforeEach
+    void emptyStore() {
+        RestAssured.delete("/rag-bridge/seed").then().statusCode(200);
+    }
+
+    @Test
+    void tenantFilterIsolatesRetrieval() {
+        seedBothTenants();
+
+        // unfiltered: both tenants' documents are retrievable
+        List<String> unfiltered = augment(QUESTION, null);
+        assertTrue(unfiltered.stream().anyMatch(text -> 
text.contains("ALPHA-ONLY")), "got: " + unfiltered);
+        assertTrue(unfiltered.stream().anyMatch(text -> 
text.contains("BETA-ONLY")), "got: " + unfiltered);
+
+        // filtered to alpha: beta's documents must be invisible
+        
RestAssured.post("/rag-bridge/tenant-filter/alpha").then().statusCode(200);
+        List<String> filtered = augment(QUESTION, null);
+        assertTrue(filtered.stream().anyMatch(text -> 
text.contains("ALPHA-ONLY")), "got: " + filtered);
+        assertFalse(filtered.stream().anyMatch(text -> 
text.contains("BETA-ONLY")),
+                "the tenant filter must isolate retrieval, got: " + filtered);
+    }
+
+    /**
+     * The tenant taken from the {@code Query} the augmentor passes in, rather 
than from state the
+     * supplier reads elsewhere: this is what makes the hook usable when 
retrieval does not run on
+     * the caller's thread.
+     */
+    @Test
+    void tenantIsDerivedFromTheQuery() {
+        seedBothTenants();
+        
RestAssured.post("/rag-bridge/tenant-filter/from-query").then().statusCode(200);
+
+        List<String> filtered = augment(QUESTION, "beta");
+        assertTrue(filtered.stream().anyMatch(text -> 
text.contains("BETA-ONLY")), "got: " + filtered);
+        assertFalse(filtered.stream().anyMatch(text -> 
text.contains("ALPHA-ONLY")),
+                "the chat memory id must select the tenant, got: " + filtered);
+    }
+
+    /**
+     * The auto-produced default augmentor has neither a name nor a configured 
store — it is backed
+     * by the {@code @Default} beans — and the SPI is told exactly that rather 
than something made
+     * up.
+     */
+    @Test
+    void defaultRagHasEmptyStoreAndAugmentor() {
+        
RestAssured.delete("/rag-bridge/filter/last-call").then().statusCode(200);
+
+        augment(QUESTION, null);
+
+        RestAssured.get("/rag-bridge/filter/last-augmentor")
+                .then().statusCode(200).body(is("null"));
+        RestAssured.get("/rag-bridge/filter/last-store")
+                .then().statusCode(200).body(is("null"));
+    }
+
+    static void seedBothTenants() {
+        seed("alpha", "The ALPHA-ONLY clause: tenants of type alpha may exceed 
the quota.");
+        seed("beta", "The BETA-ONLY clause: tenants of type beta must not 
exceed the quota.");
+    }
+
+    static void seed(String tenant, String text) {
+        RestAssured.given().contentType(ContentType.TEXT).body(text)
+                .post("/rag-bridge/seed/" + tenant)
+                .then().statusCode(200);
+    }
+
+    static List<String> augment(String question, String memoryId) {
+        RequestSpecification request = 
RestAssured.given().contentType(ContentType.TEXT).body(question);
+        if (memoryId != null) {
+            request = request.queryParam("memoryId", memoryId);
+        }
+        return request.post("/rag-bridge/augment")
+                .then().statusCode(200)
+                .extract().jsonPath().getList("", String.class);
+    }
+}
diff --git 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/SingleAugmentorTest.java
 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/SingleAugmentorTest.java
index 54000a4dd9..0a07c3a1ca 100644
--- 
a/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/SingleAugmentorTest.java
+++ 
b/integration-tests/langchain4j-rag-bridge-ql4j/src/test/java/org/apache/camel/quarkus/component/langchain4j/ragbridge/it/SingleAugmentorTest.java
@@ -27,9 +27,9 @@ import static org.hamcrest.Matchers.not;
 
 /**
  * Verifies explicit single-augmentor configuration: a single named augmentor 
is
- * configured via {@code quarkus.camel.langchain4j.rag.augmentors.products}, so
- * it is also marked as {@code defaultBean()} for auto-discovery by
- * {@code @RegisterAiService}.
+ * configured via {@code quarkus.camel.langchain4j.rag.augmentors.products}, 
and with
+ * nothing to be ambiguous with it serves the unqualified lookup of
+ * {@code @RegisterAiService} without needing {@code default=true}.
  *
  * <p>
  * No {@code @QuarkusIntegrationTest} counterpart exists because this test uses

Reply via email to