// Do not edit directly!
// This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
[id="extensions-langchain4j-embeddingstore"]
= LangChain4j Embedding Store
:linkattrs:
:cq-artifact-id: camel-quarkus-langchain4j-embeddingstore
:cq-native-supported: true
:cq-status: Preview
:cq-status-deprecation: Preview
:cq-description: Perform operations on the LangChain4jEmbeddingStores.
:cq-deprecated: false
:cq-jvm-since: 3.29.0
:cq-native-since: 3.29.0

ifeval::[{doc-show-badges} == true]
[.badges]
[.badge-key]##JVM since##[.badge-supported]##3.29.0## [.badge-key]##Native since##[.badge-supported]##3.29.0##
endif::[]

Perform operations on the LangChain4jEmbeddingStores.

[id="extensions-langchain4j-embeddingstore-whats-inside"]
== What's inside

* xref:{cq-camel-components}::langchain4j-embeddingstore-component.adoc[LangChain4j Embedding Store component], URI syntax: `langchain4j-embeddingstore:embeddingStoreId`

Please refer to the above link for usage and configuration details.

[id="extensions-langchain4j-embeddingstore-maven-coordinates"]
== Maven coordinates

https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-langchain4j-embeddingstore[Create a new project with this extension on {link-quarkus-code-generator}, window="_blank"]

Or add the coordinates to your existing project:

[source,xml]
----
<dependency>
    <groupId>org.apache.camel.quarkus</groupId>
    <artifactId>camel-quarkus-langchain4j-embeddingstore</artifactId>
</dependency>
----
ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
endif::[]

[id="extensions-langchain4j-embeddingstore-usage"]
== Usage
[id="extensions-langchain4j-embeddingstore-usage-named-embedding-stores-from-quarkus-langchain4j"]
=== Named embedding stores from Quarkus LangChain4j

When the https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[Quarkus LangChain4j] extensions are present, any `EmbeddingStore` CDI bean qualified with `@EmbeddingStoreName` is automatically bound into the Camel registry under its qualifier value.
This covers both stores declared through Quarkus LangChain4j named configuration (for example `quarkus.langchain4j.pgvector.products.\*`) and stores produced by your own `@Produces` methods.

Such a store can be referenced from a route by name, with no manual registry binding:

[source,java]
----
from("direct:ingest-products")
    .to("langchain4j-embeddingstore:products?embeddingStore=#products&embeddingModel=#embeddingModel");
----

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

=== Dependency management

In order to ensure alignment across all Quarkus and LangChain4j related dependencies, it is recommended to import the LangChain4j BOM as below:
[source,xml,subs=attributes+]
----
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-bom</artifactId>
      <version>{langchain4j-version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
  ...
</dependencyManagement>
----

Note that the import order is paramount when using maven `dependencyManagement`.
As such, one might need to import the `langchain4j-bom` before other related Camel and Quarkus BOMs.

=== Quarkus LangChain4j support

WARNING: At present, this extension is neither tested with nor intended to be used in conjunction with any Quarkus LangChain4j extensions.
Consequently, both JVM and native modes may exhibit unexpected behaviour or fail to function correctly in such configurations.
