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

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


The following commit(s) were added to refs/heads/main by this push:
     new c72c14faa8cf CAMEL-23953: Add batch operations for langchain4j 
embeddings
c72c14faa8cf is described below

commit c72c14faa8cf3541b40c56f12693fa6ece44b1f7
Author: Guillaume Nodet <[email protected]>
AuthorDate: Thu Sep 3 07:24:48 2026 +0200

    CAMEL-23953: Add batch operations for langchain4j embeddings
    
    Add batch embedAll/addAll/removeAll support to the LangChain4j embedding
    components for efficient RAG ingestion. The embeddings producer detects a
    List body and batches via embedAll, preserving text segments through the
    TEXT_SEGMENTS header. The embedding store producer gains batch ADD via the
    EMBEDDINGS header, caller-supplied IDs (EMBEDDING_ID/EMBEDDING_IDS), size
    validation across ids/embeddings/text segments, and batch REMOVE by
    Collection<String> body or Filter header. Null/empty REMOVE now throws
    IllegalArgumentException instead of clearing the store. Adds shared
    CAMEL_LANGCHAIN4J_EMBEDDINGS and CAMEL_LANGCHAIN4J_TEXT_SEGMENTS constants
    in core/camel-api, documentation, an upgrade-guide entry, and tests.
    
    Closes #25273
    
    Co-authored-by: Guillaume Nodet <[email protected]>
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../catalog/components/langchain4j-embeddings.json |   6 +-
 .../components/langchain4j-embeddingstore.json     |   4 +-
 .../docs/langchain4j-embeddingstore-component.adoc |  67 +++-
 .../embeddings/langchain4j-embeddings.json         |   6 +-
 .../embeddings/LangChain4jEmbeddingsHeaders.java   |   8 +
 .../embeddings/LangChain4jEmbeddingsProducer.java  |  80 +++-
 .../embeddings/LangChain4jEmbeddingsBatchTest.java |  93 +++++
 .../embeddingstore/langchain4j-embeddingstore.json |   4 +-
 .../docs/langchain4j-embeddingstore-component.adoc |  67 +++-
 .../LangChain4jEmbeddingStoreHeaders.java          |  13 +-
 .../LangChain4jEmbeddingStoreProducer.java         | 148 +++++++-
 ...ngChain4jEmbeddingStoreBatchOperationsTest.java | 416 +++++++++++++++++++++
 .../camel/ai/CamelLangchain4jAttributes.java       |  14 +
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  23 ++
 ...hain4jEmbeddingStoreEndpointBuilderFactory.java |  29 +-
 ...angChain4jEmbeddingsEndpointBuilderFactory.java |  28 ++
 16 files changed, 972 insertions(+), 34 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddings.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddings.json
index afc73dbfc056..4f3f59f79c5a 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddings.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddings.json
@@ -37,8 +37,10 @@
     "CamelLangChain4jEmbeddingsRequestModel": { "index": 4, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The request model name.", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#REQUEST_MODEL"
 },
     "CamelLangChain4jEmbeddingsResponseModel": { "index": 5, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The response model name.", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#RESPONSE_MODEL"
 },
     "CamelLangChain4jEmbeddingsEmbedding": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.data.embedding.Embedding", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Embedding representation of a text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#EMBEDDING"
 },
-    "CamelLangChain4jEmbeddingsVector": { "index": 7, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "float[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "A dense vector embedding of a text", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#VECTOR"
 },
-    "CamelLangChain4jEmbeddingsTextSegment": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": " dev.langchain4j.data.segment.TextSegment", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "A 
TextSegment representation of the vector embedding input text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENT"
 }
+    "CamelLangChain4jEmbeddingsEmbeddings": { "index": 7, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.List<dev.langchain4j.data.embedding.Embedding>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "List of embeddings from a batch embedAll operation", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#EMBEDDINGS"
 },
+    "CamelLangChain4jEmbeddingsVector": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "float[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "A dense vector embedding of a text", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#VECTOR"
 },
+    "CamelLangChain4jEmbeddingsTextSegment": { "index": 9, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": " dev.langchain4j.data.segment.TextSegment", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "A 
TextSegment representation of the vector embedding input text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENT"
 },
+    "CamelLangChain4jEmbeddingsTextSegments": { "index": 10, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.List<dev.langchain4j.data.segment.TextSegment>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "List of text segments from a batch embedAll operation", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENTS"
 }
   },
   "properties": {
     "embeddingId": { "index": 0, "kind": "path", "displayName": "Embedding 
Id", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The id" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddingstore.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddingstore.json
index 8be5095be6f8..055c5f8d1b88 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddingstore.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-embeddingstore.json
@@ -39,7 +39,9 @@
     "CamelLangchain4jEmbeddingStoreAction": { "index": 0, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "ADD", "REMOVE", "SEARCH" ], "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The action to be performed.", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#ACTION"
 },
     "CamelLangchain4jEmbeddingStoreMaxResults": { "index": 1, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": "5", "description": 
"Maximum number of search results to return", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#MAX_RESULTS"
 },
     "CamelLangchain4jEmbeddingStoreMinScore": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Double", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Minimum similarity score for search 
results", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#MIN_SCORE"
 },
-    "CamelLangchain4jEmbeddingStoreFilter": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.store.embedding.filter.Filter", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "Search filter for metadata-based constraints", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#FILTER"
 }
+    "CamelLangchain4jEmbeddingStoreFilter": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.store.embedding.filter.Filter", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "Filter for metadata-based constraints (used in SEARCH and 
REMOVE operations)", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#FILTER"
 },
+    "CamelLangchain4jEmbeddingStoreEmbeddingId": { "index": 4, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Caller-supplied embedding 
ID for single ADD operations", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#EMBEDDING_ID"
 },
+    "CamelLangchain4jEmbeddingStoreEmbeddingIds": { "index": 5, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "java.util.List<java.lang.String>", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Caller-supplied embedding IDs for batch ADD operations", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#EMBEDDING_IDS"
 }
   },
   "properties": {
     "embeddingStoreId": { "index": 0, "kind": "path", "displayName": 
"Embedding Store Id", "group": "producer", "label": "", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
id of the embedding store" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/langchain4j-embeddingstore-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/langchain4j-embeddingstore-component.adoc
index b31d314d4e12..73ff5410428b 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/langchain4j-embeddingstore-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/langchain4j-embeddingstore-component.adoc
@@ -30,8 +30,8 @@ The LangChain4j Embedding Store component offers the 
following key features:
 
 The component supports three main operations controlled by the 
`CamelLangchain4jEmbeddingStoreAction` header:
 
-* **ADD** - Store embeddings with optional text segments and metadata
-* **REMOVE** - Delete embeddings by their unique identifier
+* **ADD** - Store embeddings with optional text segments and metadata. 
Supports single and batch operations, as well as caller-supplied IDs.
+* **REMOVE** - Delete embeddings by single ID, collection of IDs, or metadata 
filter.
 * **SEARCH** - Perform similarity search with configurable filters and scoring
 
 == URI format
@@ -151,6 +151,39 @@ YAML::
 
 The response body contains the generated embedding ID.
 
+==== ADD with Caller-Supplied ID
+
+You can provide your own embedding ID using the 
`CamelLangchain4jEmbeddingStoreEmbeddingId` header:
+
+[source,java]
+----
+from("direct:store-with-id")
+    .to("langchain4j-embeddings:embed")
+    .setHeader("CamelLangchain4jEmbeddingStoreEmbeddingId", 
constant("my-custom-id"))
+    .to("langchain4j-embeddingstore:myStore?action=ADD");
+----
+
+When both a caller-supplied ID and a text segment are present, the component 
preserves both using `addAll` with singleton lists.
+
+==== Batch ADD (addAll)
+
+For RAG ingestion pipelines, batch adding is significantly more efficient. 
Send a `List<String>` or `List<TextSegment>` as the body to the 
`langchain4j-embeddings` component to produce batch embeddings:
+
+[source,java]
+----
+from("direct:batch-store")
+    // Body is a List<String> or List<TextSegment>
+    .to("langchain4j-embeddings:embed")
+    // After batch embed, the CamelLangChain4jEmbeddingsEmbeddings header 
contains List<Embedding>
+    // and the CamelLangChain4jEmbeddingsTextSegments header preserves the 
original text segments
+    .to("langchain4j-embeddingstore:myStore?action=ADD");
+// Body: List<String> of generated IDs
+----
+
+You can also supply caller-supplied IDs for the batch via the 
`CamelLangchain4jEmbeddingStoreEmbeddingIds` header.
+
+NOTE: The sizes of `EMBEDDING_IDS`, `EMBEDDINGS`, and text segments must all 
match. A size mismatch throws `IllegalArgumentException`.
+
 === Searching Embeddings (SEARCH Operation)
 
 Perform similarity search to find relevant content. Without `embeddingModel`, 
a pre-computed query embedding must be provided:
@@ -226,7 +259,11 @@ YAML::
 
 === Removing Embeddings (REMOVE Operation)
 
-Delete embeddings by their ID:
+The REMOVE operation supports multiple strategies:
+
+==== Remove by Single ID
+
+Delete a single embedding by its ID (body is a `String`):
 
 [tabs]
 ====
@@ -258,6 +295,30 @@ YAML::
 ----
 ====
 
+==== Remove by Collection of IDs
+
+Delete multiple embeddings by passing a `Collection<String>` as the body:
+
+[source,java]
+----
+from("direct:remove-batch")
+    .setBody(constant(List.of("id-1", "id-2", "id-3")))
+    .to("langchain4j-embeddingstore:myStore?action=REMOVE");
+----
+
+==== Remove by Metadata Filter
+
+Delete all embeddings matching a metadata filter using the 
`CamelLangchain4jEmbeddingStoreFilter` header:
+
+[source,java]
+----
+from("direct:remove-by-filter")
+    .setHeader("CamelLangchain4jEmbeddingStoreFilter", 
constant(metadataFilter))
+    .to("langchain4j-embeddingstore:myStore?action=REMOVE");
+----
+
+NOTE: A REMOVE with no body and no filter throws `IllegalArgumentException`. 
This is intentional — destructive "clear all" operations require explicit 
intent.
+
 === Complete RAG Pipeline Example
 
 A complete example showing document ingestion and retrieval:
diff --git 
a/components/camel-ai/camel-langchain4j-embeddings/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddings/langchain4j-embeddings.json
 
b/components/camel-ai/camel-langchain4j-embeddings/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddings/langchain4j-embeddings.json
index afc73dbfc056..4f3f59f79c5a 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddings/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddings/langchain4j-embeddings.json
+++ 
b/components/camel-ai/camel-langchain4j-embeddings/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddings/langchain4j-embeddings.json
@@ -37,8 +37,10 @@
     "CamelLangChain4jEmbeddingsRequestModel": { "index": 4, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The request model name.", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#REQUEST_MODEL"
 },
     "CamelLangChain4jEmbeddingsResponseModel": { "index": 5, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The response model name.", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#RESPONSE_MODEL"
 },
     "CamelLangChain4jEmbeddingsEmbedding": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.data.embedding.Embedding", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Embedding representation of a text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#EMBEDDING"
 },
-    "CamelLangChain4jEmbeddingsVector": { "index": 7, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "float[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "A dense vector embedding of a text", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#VECTOR"
 },
-    "CamelLangChain4jEmbeddingsTextSegment": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": " dev.langchain4j.data.segment.TextSegment", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "A 
TextSegment representation of the vector embedding input text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENT"
 }
+    "CamelLangChain4jEmbeddingsEmbeddings": { "index": 7, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.List<dev.langchain4j.data.embedding.Embedding>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "List of embeddings from a batch embedAll operation", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#EMBEDDINGS"
 },
+    "CamelLangChain4jEmbeddingsVector": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "float[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "A dense vector embedding of a text", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#VECTOR"
 },
+    "CamelLangChain4jEmbeddingsTextSegment": { "index": 9, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": " dev.langchain4j.data.segment.TextSegment", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "A 
TextSegment representation of the vector embedding input text", "constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENT"
 },
+    "CamelLangChain4jEmbeddingsTextSegments": { "index": 10, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.List<dev.langchain4j.data.segment.TextSegment>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "List of text segments from a batch embedAll operation", 
"constantName": 
"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders#TEXT_SEGMENTS"
 }
   },
   "properties": {
     "embeddingId": { "index": 0, "kind": "path", "displayName": "Embedding 
Id", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The id" },
diff --git 
a/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsHeaders.java
 
b/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsHeaders.java
index 0849a3cbcd21..c18162c78aa5 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsHeaders.java
+++ 
b/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsHeaders.java
@@ -41,10 +41,18 @@ public class LangChain4jEmbeddingsHeaders {
     @Metadata(description = "Embedding representation of a text", javaType = 
"dev.langchain4j.data.embedding.Embedding")
     public static final String EMBEDDING = 
CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDING;
 
+    @Metadata(description = "List of embeddings from a batch embedAll 
operation",
+              javaType = 
"java.util.List<dev.langchain4j.data.embedding.Embedding>")
+    public static final String EMBEDDINGS = 
CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDINGS;
+
     @Metadata(description = "A dense vector embedding of a text", javaType = 
"float[]")
     public static final String VECTOR = 
CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDING_VECTOR;
 
     @Metadata(description = "A TextSegment representation of the vector 
embedding input text",
               javaType = " dev.langchain4j.data.segment.TextSegment")
     public static final String TEXT_SEGMENT = 
CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_TEXT_SEGMENT;
+
+    @Metadata(description = "List of text segments from a batch embedAll 
operation",
+              javaType = 
"java.util.List<dev.langchain4j.data.segment.TextSegment>")
+    public static final String TEXT_SEGMENTS = 
CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_TEXT_SEGMENTS;
 }
diff --git 
a/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsProducer.java
 
b/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsProducer.java
index c34424024f91..308ad54740ed 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsProducer.java
+++ 
b/components/camel-ai/camel-langchain4j-embeddings/src/main/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsProducer.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.langchain4j.embeddings;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import dev.langchain4j.data.embedding.Embedding;
 import dev.langchain4j.data.segment.TextSegment;
 import dev.langchain4j.model.embedding.EmbeddingModel;
@@ -42,9 +45,26 @@ public class LangChain4jEmbeddingsProducer extends 
DefaultProducer {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public void process(Exchange exchange) throws Exception {
-        final TextSegment in = 
exchange.getMessage().getMandatoryBody(TextSegment.class);
         final EmbeddingModel model = 
getEndpoint().getConfiguration().getEmbeddingModel();
+        final Message message = exchange.getMessage();
+        Object body = message.getBody();
+
+        if (body instanceof List) {
+            List<Object> bodyList = (List<Object>) body;
+            if (bodyList.isEmpty()) {
+                throw new IllegalArgumentException(
+                        "Batch embedding requires a non-empty List body");
+            }
+            processBatch(exchange, model, message, bodyList);
+        } else {
+            processSingle(exchange, model, message);
+        }
+    }
+
+    private void processSingle(Exchange exchange, EmbeddingModel model, 
Message message) throws Exception {
+        final TextSegment in = 
exchange.getMessage().getMandatoryBody(TextSegment.class);
         GenAiObservationContext observationContext = 
GenAiObservationContext.builder()
                 .operationName(GenAiOperationName.EMBEDDINGS)
                 
.system(GenAiModelResolver.resolveSystem(exchange.getContext().getClassResolver(),
 model))
@@ -54,7 +74,41 @@ public class LangChain4jEmbeddingsProducer extends 
DefaultProducer {
         GenAiObservation observation = GenAiObservability.start(exchange, 
observationContext);
         try {
             final Response<Embedding> result = model.embed(in);
-            populateHeaders(exchange.getMessage(), result, in, 
observationContext.requestModel());
+            populateHeaders(message, result, in, 
observationContext.requestModel());
+            observation.recordSuccess(GenAiUsage.of(
+                    result.tokenUsage() != null ? 
result.tokenUsage().inputTokenCount() : null,
+                    result.tokenUsage() != null ? 
result.tokenUsage().outputTokenCount() : null,
+                    result.finishReason(),
+                    null));
+        } catch (RuntimeException e) {
+            GenAiErrorSupport.apply(exchange, e);
+            observation.recordError(e);
+            throw e;
+        } finally {
+            observation.close();
+        }
+    }
+
+    private void processBatch(Exchange exchange, EmbeddingModel model, Message 
message, List<Object> bodyList)
+            throws Exception {
+        // Convert each element to TextSegment using the type converter
+        List<TextSegment> segments = new ArrayList<>(bodyList.size());
+        for (Object item : bodyList) {
+            TextSegment segment = 
exchange.getContext().getTypeConverter().mandatoryConvertTo(TextSegment.class, 
item);
+            segments.add(segment);
+        }
+
+        GenAiObservationContext observationContext = 
GenAiObservationContext.builder()
+                .operationName(GenAiOperationName.EMBEDDINGS)
+                
.system(GenAiModelResolver.resolveSystem(exchange.getContext().getClassResolver(),
 model))
+                
.requestModel(GenAiModelResolver.resolveModelName(exchange.getContext().getClassResolver(),
 model))
+                .componentScheme("langchain4j-embeddings")
+                .build();
+        GenAiObservation observation = GenAiObservability.start(exchange, 
observationContext);
+        try {
+            final Response<List<Embedding>> result = model.embedAll(segments);
+
+            populateBatchHeaders(message, result, segments, 
observationContext.requestModel());
             observation.recordSuccess(GenAiUsage.of(
                     result.tokenUsage() != null ? 
result.tokenUsage().inputTokenCount() : null,
                     result.tokenUsage() != null ? 
result.tokenUsage().outputTokenCount() : null,
@@ -89,4 +143,26 @@ public class LangChain4jEmbeddingsProducer extends 
DefaultProducer {
         message.setHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENT, 
textSegment);
         message.setHeader(LangChain4jEmbeddingsHeaders.EMBEDDING, 
result.content());
     }
+
+    private static void populateBatchHeaders(
+            Message message, Response<List<Embedding>> result, 
List<TextSegment> segments, String requestModel) {
+        if (requestModel != null) {
+            message.setHeader(LangChain4jEmbeddingsHeaders.REQUEST_MODEL, 
requestModel);
+        }
+
+        if (result.finishReason() != null) {
+            message.setHeader(LangChain4jEmbeddingsHeaders.FINISH_REASON, 
result.finishReason());
+        }
+
+        if (result.tokenUsage() != null) {
+            message.setHeader(LangChain4jEmbeddingsHeaders.INPUT_TOKEN_COUNT, 
result.tokenUsage().inputTokenCount());
+            message.setHeader(LangChain4jEmbeddingsHeaders.OUTPUT_TOKEN_COUNT, 
result.tokenUsage().outputTokenCount());
+            message.setHeader(LangChain4jEmbeddingsHeaders.TOTAL_TOKEN_COUNT, 
result.tokenUsage().totalTokenCount());
+        }
+
+        List<Embedding> embeddings = result.content();
+        message.setHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, embeddings);
+        // Preserve text segments so downstream embedding store can associate 
them with embeddings
+        message.setHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENTS, 
segments);
+    }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsBatchTest.java
 
b/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsBatchTest.java
new file mode 100644
index 000000000000..081c32195367
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsBatchTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.component.langchain4j.embeddings;
+
+import java.util.Arrays;
+import java.util.List;
+
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import 
dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Message;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class LangChain4jEmbeddingsBatchTest extends CamelTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        LangChain4jEmbeddingsComponent component
+                = context.getComponent(LangChain4jEmbeddings.SCHEME, 
LangChain4jEmbeddingsComponent.class);
+        component.getConfiguration().setEmbeddingModel(new 
AllMiniLmL6V2EmbeddingModel());
+
+        return context;
+    }
+
+    @Test
+    @DisplayName("Batch embedding with List<String> body produces EMBEDDINGS 
and TEXT_SEGMENTS headers")
+    @SuppressWarnings("unchecked")
+    void batchEmbeddingFromStringList() {
+        List<String> texts = Arrays.asList("hello world", "goodbye world");
+
+        Message result = fluentTemplate.to("langchain4j-embeddings:batch")
+                .withBody(texts)
+                .request(Message.class);
+
+        List<Embedding> embeddings = 
result.getHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, List.class);
+        assertThat(embeddings).hasSize(2);
+        assertThat(embeddings.get(0).vector()).hasSize(384);
+        assertThat(embeddings.get(1).vector()).hasSize(384);
+
+        List<TextSegment> segments = 
result.getHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENTS, List.class);
+        assertThat(segments).hasSize(2);
+        assertThat(segments.get(0).text()).isEqualTo("hello world");
+        assertThat(segments.get(1).text()).isEqualTo("goodbye world");
+    }
+
+    @Test
+    @DisplayName("Batch embedding sets token usage headers")
+    void batchEmbeddingTokenUsage() {
+        List<String> texts = Arrays.asList("test one", "test two");
+
+        Message result = fluentTemplate.to("langchain4j-embeddings:batch")
+                .withBody(texts)
+                .request(Message.class);
+
+        // Token usage should be reported for batch operations
+        
assertThat(result.getHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS)).isNotNull();
+        
assertThat(result.getHeader(LangChain4jEmbeddingsHeaders.INPUT_TOKEN_COUNT, 
Integer.class)).isNotNull().isPositive();
+        
assertThat(result.getHeader(LangChain4jEmbeddingsHeaders.TOTAL_TOKEN_COUNT, 
Integer.class)).isNotNull().isPositive();
+    }
+
+    @Test
+    @DisplayName("Single item still uses single path")
+    void singleItemStillUsesSinglePath() {
+        Message result = fluentTemplate.to("langchain4j-embeddings:single")
+                .withBody("hello")
+                .request(Message.class);
+
+        // Single path should set EMBEDDING header (not EMBEDDINGS)
+        assertThat(result.getHeader(LangChain4jEmbeddingsHeaders.EMBEDDING, 
Embedding.class)).isNotNull();
+        
assertThat(result.getHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS)).isNull();
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddingstore/langchain4j-embeddingstore.json
 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddingstore/langchain4j-embeddingstore.json
index 8be5095be6f8..055c5f8d1b88 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddingstore/langchain4j-embeddingstore.json
+++ 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/embeddingstore/langchain4j-embeddingstore.json
@@ -39,7 +39,9 @@
     "CamelLangchain4jEmbeddingStoreAction": { "index": 0, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "ADD", "REMOVE", "SEARCH" ], "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The action to be performed.", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#ACTION"
 },
     "CamelLangchain4jEmbeddingStoreMaxResults": { "index": 1, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": "5", "description": 
"Maximum number of search results to return", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#MAX_RESULTS"
 },
     "CamelLangchain4jEmbeddingStoreMinScore": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Double", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Minimum similarity score for search 
results", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#MIN_SCORE"
 },
-    "CamelLangchain4jEmbeddingStoreFilter": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.store.embedding.filter.Filter", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "Search filter for metadata-based constraints", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#FILTER"
 }
+    "CamelLangchain4jEmbeddingStoreFilter": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "dev.langchain4j.store.embedding.filter.Filter", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "Filter for metadata-based constraints (used in SEARCH and 
REMOVE operations)", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#FILTER"
 },
+    "CamelLangchain4jEmbeddingStoreEmbeddingId": { "index": 4, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Caller-supplied embedding 
ID for single ADD operations", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#EMBEDDING_ID"
 },
+    "CamelLangchain4jEmbeddingStoreEmbeddingIds": { "index": 5, "kind": 
"header", "displayName": "", "group": "producer", "label": "", "required": 
false, "javaType": "java.util.List<java.lang.String>", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Caller-supplied embedding IDs for batch ADD operations", "constantName": 
"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreHeaders#EMBEDDING_IDS"
 }
   },
   "properties": {
     "embeddingStoreId": { "index": 0, "kind": "path", "displayName": 
"Embedding Store Id", "group": "producer", "label": "", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
id of the embedding store" },
diff --git 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/docs/langchain4j-embeddingstore-component.adoc
 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/docs/langchain4j-embeddingstore-component.adoc
index b31d314d4e12..73ff5410428b 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/docs/langchain4j-embeddingstore-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/docs/langchain4j-embeddingstore-component.adoc
@@ -30,8 +30,8 @@ The LangChain4j Embedding Store component offers the 
following key features:
 
 The component supports three main operations controlled by the 
`CamelLangchain4jEmbeddingStoreAction` header:
 
-* **ADD** - Store embeddings with optional text segments and metadata
-* **REMOVE** - Delete embeddings by their unique identifier
+* **ADD** - Store embeddings with optional text segments and metadata. 
Supports single and batch operations, as well as caller-supplied IDs.
+* **REMOVE** - Delete embeddings by single ID, collection of IDs, or metadata 
filter.
 * **SEARCH** - Perform similarity search with configurable filters and scoring
 
 == URI format
@@ -151,6 +151,39 @@ YAML::
 
 The response body contains the generated embedding ID.
 
+==== ADD with Caller-Supplied ID
+
+You can provide your own embedding ID using the 
`CamelLangchain4jEmbeddingStoreEmbeddingId` header:
+
+[source,java]
+----
+from("direct:store-with-id")
+    .to("langchain4j-embeddings:embed")
+    .setHeader("CamelLangchain4jEmbeddingStoreEmbeddingId", 
constant("my-custom-id"))
+    .to("langchain4j-embeddingstore:myStore?action=ADD");
+----
+
+When both a caller-supplied ID and a text segment are present, the component 
preserves both using `addAll` with singleton lists.
+
+==== Batch ADD (addAll)
+
+For RAG ingestion pipelines, batch adding is significantly more efficient. 
Send a `List<String>` or `List<TextSegment>` as the body to the 
`langchain4j-embeddings` component to produce batch embeddings:
+
+[source,java]
+----
+from("direct:batch-store")
+    // Body is a List<String> or List<TextSegment>
+    .to("langchain4j-embeddings:embed")
+    // After batch embed, the CamelLangChain4jEmbeddingsEmbeddings header 
contains List<Embedding>
+    // and the CamelLangChain4jEmbeddingsTextSegments header preserves the 
original text segments
+    .to("langchain4j-embeddingstore:myStore?action=ADD");
+// Body: List<String> of generated IDs
+----
+
+You can also supply caller-supplied IDs for the batch via the 
`CamelLangchain4jEmbeddingStoreEmbeddingIds` header.
+
+NOTE: The sizes of `EMBEDDING_IDS`, `EMBEDDINGS`, and text segments must all 
match. A size mismatch throws `IllegalArgumentException`.
+
 === Searching Embeddings (SEARCH Operation)
 
 Perform similarity search to find relevant content. Without `embeddingModel`, 
a pre-computed query embedding must be provided:
@@ -226,7 +259,11 @@ YAML::
 
 === Removing Embeddings (REMOVE Operation)
 
-Delete embeddings by their ID:
+The REMOVE operation supports multiple strategies:
+
+==== Remove by Single ID
+
+Delete a single embedding by its ID (body is a `String`):
 
 [tabs]
 ====
@@ -258,6 +295,30 @@ YAML::
 ----
 ====
 
+==== Remove by Collection of IDs
+
+Delete multiple embeddings by passing a `Collection<String>` as the body:
+
+[source,java]
+----
+from("direct:remove-batch")
+    .setBody(constant(List.of("id-1", "id-2", "id-3")))
+    .to("langchain4j-embeddingstore:myStore?action=REMOVE");
+----
+
+==== Remove by Metadata Filter
+
+Delete all embeddings matching a metadata filter using the 
`CamelLangchain4jEmbeddingStoreFilter` header:
+
+[source,java]
+----
+from("direct:remove-by-filter")
+    .setHeader("CamelLangchain4jEmbeddingStoreFilter", 
constant(metadataFilter))
+    .to("langchain4j-embeddingstore:myStore?action=REMOVE");
+----
+
+NOTE: A REMOVE with no body and no filter throws `IllegalArgumentException`. 
This is intentional — destructive "clear all" operations require explicit 
intent.
+
 === Complete RAG Pipeline Example
 
 A complete example showing document ingestion and retrieval:
diff --git 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreHeaders.java
 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreHeaders.java
index e40318d9db5c..cd5370181676 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreHeaders.java
+++ 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreHeaders.java
@@ -41,8 +41,17 @@ public class LangChain4jEmbeddingStoreHeaders {
     @Metadata(description = "Minimum similarity score for search results", 
javaType = "Double")
     public static final String MIN_SCORE = 
"CamelLangchain4jEmbeddingStoreMinScore";
 
-    /** Filter to apply to search operations for metadata-based filtering */
-    @Metadata(description = "Search filter for metadata-based constraints",
+    /** Filter to apply to search and remove operations for metadata-based 
filtering */
+    @Metadata(description = "Filter for metadata-based constraints (used in 
SEARCH and REMOVE operations)",
               javaType = "dev.langchain4j.store.embedding.filter.Filter")
     public static final String FILTER = "CamelLangchain4jEmbeddingStoreFilter";
+
+    /** Caller-supplied embedding ID for single ADD operations */
+    @Metadata(description = "Caller-supplied embedding ID for single ADD 
operations", javaType = "String")
+    public static final String EMBEDDING_ID = 
"CamelLangchain4jEmbeddingStoreEmbeddingId";
+
+    /** Caller-supplied embedding IDs for batch ADD operations */
+    @Metadata(description = "Caller-supplied embedding IDs for batch ADD 
operations",
+              javaType = "java.util.List<java.lang.String>")
+    public static final String EMBEDDING_IDS = 
"CamelLangchain4jEmbeddingStoreEmbeddingIds";
 }
diff --git 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreProducer.java
 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreProducer.java
index 94d00b908083..a6ef24df2525 100644
--- 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreProducer.java
+++ 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/main/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreProducer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.langchain4j.embeddingstore;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
@@ -109,55 +110,168 @@ public class LangChain4jEmbeddingStoreProducer extends 
DefaultProducer {
     }
 
     /**
-     * Adds an embedding to the store with optional text segment.
+     * Adds embeddings to the store with optional text segments and 
caller-supplied IDs.
      *
      * <p>
-     * Expects the following headers:
+     * Supports both single and batch operations:
+     * </p>
+     *
+     * <p>
+     * <b>Single operation</b> - when the {@code 
CamelLangChain4jEmbeddingsEmbedding} header contains a single
+     * {@link Embedding}:
      * </p>
      * <ul>
-     * <li>{@code CamelLangchain4jEmbeddingEmbedding} - The embedding vector 
(required)</li>
-     * <li>{@code CamelLangchain4jEmbeddingTextSegment} - Associated text 
segment (optional)</li>
+     * <li>With caller-supplied ID header ({@code 
CamelLangchain4jEmbeddingStoreEmbeddingId}) and text segment: calls
+     * {@code addAll(singletonList(id), singletonList(embedding), 
singletonList(textSegment))}</li>
+     * <li>With caller-supplied ID header but no text segment: calls {@code 
add(id, embedding)}</li>
+     * <li>With text segment header: calls {@code add(embedding, 
textSegment)}</li>
+     * <li>Without text segment: calls {@code add(embedding)}</li>
      * </ul>
      *
      * <p>
-     * Returns the generated embedding ID in the message body.
+     * <b>Batch operation</b> - when the {@code 
CamelLangChain4jEmbeddingsEmbeddings} header contains a
+     * {@code List<Embedding>}:
      * </p>
+     * <ul>
+     * <li>With IDs header ({@code 
CamelLangchain4jEmbeddingStoreEmbeddingIds}) and text segments: calls
+     * {@code addAll(ids, embeddings, textSegments)}</li>
+     * <li>With IDs header but no text segments: loops with {@code add(id, 
embedding)}</li>
+     * <li>With text segments: calls {@code addAll(embeddings, 
textSegments)}</li>
+     * <li>Without text segments: calls {@code addAll(embeddings)}</li>
+     * </ul>
      *
      * @param  exchange  the Camel exchange containing the embedding data
      * @throws Exception if the add operation fails
      */
+    @SuppressWarnings("unchecked")
     private void add(Exchange exchange) throws Exception {
+        final Message in = exchange.getMessage();
         LangChain4jEmbeddingStoreConfiguration config = 
getEndpoint().getConfiguration();
+        EmbeddingStore<TextSegment> store = config.getEmbeddingStore();
+
+        // Check for batch embeddings header first
+        List<Embedding> embeddings = 
in.getHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, List.class);
+        if (embeddings != null) {
+            addBatch(in, store, embeddings);
+            return;
+        }
 
+        // Single embedding path — use resolveEmbedding for auto-embedding 
support
         EmbeddingResult resolved = resolveEmbedding(exchange);
 
+        // Check for caller-supplied ID
+        String callerId = 
in.getHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_ID, String.class);
         String id;
-        if (resolved.textSegment() != null) {
-            id = config.getEmbeddingStore().add(resolved.embedding(), 
resolved.textSegment());
+
+        if (callerId != null) {
+            if (resolved.textSegment() != null) {
+                // Use addAll with singleton lists to preserve both ID and 
text segment
+                store.addAll(List.of(callerId), List.of(resolved.embedding()), 
List.of(resolved.textSegment()));
+            } else {
+                store.add(callerId, resolved.embedding());
+            }
+            id = callerId;
+        } else if (resolved.textSegment() != null) {
+            id = store.add(resolved.embedding(), resolved.textSegment());
         } else {
-            id = config.getEmbeddingStore().add(resolved.embedding());
+            id = store.add(resolved.embedding());
         }
 
-        exchange.getMessage().setBody(id);
+        in.setBody(id);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void addBatch(Message in, EmbeddingStore<TextSegment> store, 
List<Embedding> embeddings) {
+        List<String> callerIds = 
in.getHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_IDS, List.class);
+
+        // Resolve text segments from header (set by batch embeddings 
producer) or body
+        List<TextSegment> textSegments = 
in.getHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENTS, List.class);
+        if (textSegments == null) {
+            Object body = in.getBody();
+            if (body instanceof List && !((List<?>) body).isEmpty() && 
((List<?>) body).get(0) instanceof TextSegment) {
+                textSegments = (List<TextSegment>) body;
+            }
+        }
+
+        // Validate sizes match when caller IDs are provided
+        if (callerIds != null && callerIds.size() != embeddings.size()) {
+            throw new IllegalArgumentException(
+                    "EMBEDDING_IDS size (" + callerIds.size() + ") must match 
EMBEDDINGS size (" + embeddings.size() + ")");
+        }
+        if (textSegments != null && textSegments.size() != embeddings.size()) {
+            throw new IllegalArgumentException(
+                    "TEXT_SEGMENTS size (" + textSegments.size() + ") must 
match EMBEDDINGS size (" + embeddings.size() + ")");
+        }
+
+        List<String> ids;
+        if (callerIds != null && textSegments != null) {
+            store.addAll(callerIds, embeddings, textSegments);
+            ids = callerIds;
+        } else if (callerIds != null) {
+            // No addAll(ids, embeddings) overload in langchain4j, so loop 
with add(id, embedding)
+            for (int i = 0; i < embeddings.size(); i++) {
+                store.add(callerIds.get(i), embeddings.get(i));
+            }
+            ids = callerIds;
+        } else if (textSegments != null) {
+            ids = store.addAll(embeddings, textSegments);
+        } else {
+            ids = store.addAll(embeddings);
+        }
+
+        in.setBody(ids);
     }
 
     /**
-     * Removes an embedding from the store by its ID.
+     * Removes embeddings from the store. Supports multiple removal strategies:
      *
-     * <p>
-     * Expects the embedding ID as the message body (String).
-     * </p>
+     * <ul>
+     * <li><b>By filter</b>: when the {@code 
CamelLangchain4jEmbeddingStoreFilter} header is set, removes all embeddings
+     * matching the filter via {@code removeAll(Filter)}</li>
+     * <li><b>By ID list</b>: when the body is a {@code Collection<String>}, 
removes all specified embeddings via
+     * {@code removeAll(Collection)}</li>
+     * <li><b>By single ID</b>: when the body is a single {@code String}, 
removes that embedding via
+     * {@code remove(id)}</li>
+     * </ul>
      *
-     * @param  exchange  the Camel exchange containing the embedding ID to 
remove
+     * @param  exchange  the Camel exchange containing removal parameters
      * @throws Exception if the remove operation fails
      */
+    @SuppressWarnings("unchecked")
     private void remove(Exchange exchange) throws Exception {
         final Message in = exchange.getMessage();
-        String id = in.getBody(String.class);
+        EmbeddingStore<TextSegment> store = 
getEndpoint().getConfiguration().getEmbeddingStore();
+
+        // Check for filter-based removal first
+        Filter filter = in.getHeader(LangChain4jEmbeddingStoreHeaders.FILTER, 
Filter.class);
+        if (filter != null) {
+            store.removeAll(filter);
+            return;
+        }
 
-        getEndpoint().getConfiguration().getEmbeddingStore().remove(id);
+        Object body = in.getBody();
 
-        Message out = exchange.getMessage();
+        // Batch removal by collection of IDs
+        if (body instanceof Collection) {
+            Collection<String> ids = (Collection<String>) body;
+            if (ids.isEmpty()) {
+                throw new IllegalArgumentException(
+                        "REMOVE action requires a non-empty Collection<String> 
body for batch ID removal");
+            }
+            store.removeAll(ids);
+            return;
+        }
+
+        // Single ID removal
+        String id = in.getBody(String.class);
+        if (id != null && !id.isEmpty()) {
+            store.remove(id);
+            return;
+        }
+
+        throw new IllegalArgumentException(
+                "REMOVE action requires either: a String body (single ID), a 
Collection<String> body (batch IDs), "
+                                           + "or a 
CamelLangchain4jEmbeddingStoreFilter header (filter-based removal)");
     }
 
     /**
diff --git 
a/components/camel-ai/camel-langchain4j-embeddingstore/src/test/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreBatchOperationsTest.java
 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/test/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreBatchOperationsTest.java
new file mode 100644
index 000000000000..b8e79ccbf660
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-embeddingstore/src/test/java/org/apache/camel/component/langchain4j/embeddingstore/LangChain4jEmbeddingStoreBatchOperationsTest.java
@@ -0,0 +1,416 @@
+/*
+ * 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.component.langchain4j.embeddingstore;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.store.embedding.filter.Filter;
+import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import 
org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsHeaders;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class LangChain4jEmbeddingStoreBatchOperationsTest extends CamelTestSupport {
+
+    private RecordingEmbeddingStore embeddingStore;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        embeddingStore = new RecordingEmbeddingStore();
+
+        LangChain4jEmbeddingStoreComponent component = context.getComponent(
+                LangChain4jEmbeddingStore.SCHEME, 
LangChain4jEmbeddingStoreComponent.class);
+        component.getConfiguration().setEmbeddingStore(embeddingStore);
+
+        return context;
+    }
+
+    // ---- ADD: caller-supplied ID ----
+
+    @Test
+    @DisplayName("ADD with caller-supplied ID uses add(id, embedding)")
+    void addWithCallerSuppliedId() {
+        Embedding embedding = Embedding.from(new float[] { 0.1f, 0.2f, 0.3f });
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDING, embedding)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_ID, 
"my-custom-id")
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        
assertThat(result.getMessage().getBody(String.class)).isEqualTo("my-custom-id");
+        assertThat(embeddingStore.getAddWithIdInvocations()).isEqualTo(1);
+        
assertThat(embeddingStore.getLastCallerSuppliedId()).isEqualTo("my-custom-id");
+    }
+
+    // ---- ADD: caller-supplied ID with text segment ----
+
+    @Test
+    @DisplayName("ADD with caller-supplied ID and text segment uses 
addAll(singletonList) to preserve both")
+    void addWithCallerSuppliedIdAndTextSegment() {
+        Embedding embedding = Embedding.from(new float[] { 0.1f, 0.2f, 0.3f });
+        TextSegment segment = TextSegment.from("hello world");
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDING, embedding)
+                .withHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENT, segment)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_ID, 
"my-custom-id")
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        
assertThat(result.getMessage().getBody(String.class)).isEqualTo("my-custom-id");
+        // Should use addAll with singleton lists to preserve text segment 
with caller ID
+        assertThat(embeddingStore.getAddAllWithIdsInvocations()).isEqualTo(1);
+    }
+
+    // ---- ADD: batch operations ----
+
+    @Test
+    @DisplayName("ADD with EMBEDDINGS header and no body calls 
addAll(embeddings)")
+    void addBatchEmbeddingsOnly() {
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.1f, 0.2f }),
+                Embedding.from(new float[] { 0.3f, 0.4f }));
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        assertThat(embeddingStore.getAddAllInvocations()).isEqualTo(1);
+
+        @SuppressWarnings("unchecked")
+        List<String> ids = result.getMessage().getBody(List.class);
+        assertThat(ids).hasSize(2);
+    }
+
+    @Test
+    @DisplayName("ADD with EMBEDDINGS header and TextSegment body calls 
addAll(embeddings, textSegments)")
+    void addBatchEmbeddingsWithTextSegments() {
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.1f, 0.2f }),
+                Embedding.from(new float[] { 0.3f, 0.4f }));
+        List<TextSegment> segments = Arrays.asList(
+                TextSegment.from("hello"),
+                TextSegment.from("world"));
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .withBody(segments)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        
assertThat(embeddingStore.getAddAllWithSegmentsInvocations()).isEqualTo(1);
+
+        @SuppressWarnings("unchecked")
+        List<String> ids = result.getMessage().getBody(List.class);
+        assertThat(ids).hasSize(2);
+    }
+
+    @Test
+    @DisplayName("ADD with EMBEDDINGS header and TEXT_SEGMENTS header calls 
addAll(embeddings, textSegments)")
+    void addBatchEmbeddingsWithTextSegmentsHeader() {
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.1f, 0.2f }),
+                Embedding.from(new float[] { 0.3f, 0.4f }));
+        List<TextSegment> segments = Arrays.asList(
+                TextSegment.from("hello"),
+                TextSegment.from("world"));
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .withHeader(LangChain4jEmbeddingsHeaders.TEXT_SEGMENTS, 
segments)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        
assertThat(embeddingStore.getAddAllWithSegmentsInvocations()).isEqualTo(1);
+    }
+
+    @Test
+    @DisplayName("ADD with EMBEDDINGS header, caller IDs, and TextSegment body 
calls addAll(ids, embeddings, textSegments)")
+    void addBatchWithCallerIdsAndTextSegments() {
+        List<String> callerIds = Arrays.asList("id-1", "id-2");
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.1f, 0.2f }),
+                Embedding.from(new float[] { 0.3f, 0.4f }));
+        List<TextSegment> segments = Arrays.asList(
+                TextSegment.from("hello"),
+                TextSegment.from("world"));
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_IDS, 
callerIds)
+                .withBody(segments)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        assertThat(embeddingStore.getAddAllWithIdsInvocations()).isEqualTo(1);
+
+        @SuppressWarnings("unchecked")
+        List<String> ids = result.getMessage().getBody(List.class);
+        assertThat(ids).containsExactly("id-1", "id-2");
+    }
+
+    @Test
+    @DisplayName("ADD with EMBEDDINGS header and caller IDs but no text 
segments loops with add(id, embedding)")
+    void addBatchWithCallerIdsNoTextSegments() {
+        List<String> callerIds = Arrays.asList("id-a", "id-b");
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.5f, 0.6f }),
+                Embedding.from(new float[] { 0.7f, 0.8f }));
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_IDS, 
callerIds)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        // Should call add(id, embedding) for each pair, not addAll(embeddings)
+        assertThat(embeddingStore.getAddWithIdInvocations()).isEqualTo(2);
+        assertThat(embeddingStore.getAddAllInvocations()).isEqualTo(0);
+
+        @SuppressWarnings("unchecked")
+        List<String> ids = result.getMessage().getBody(List.class);
+        assertThat(ids).containsExactly("id-a", "id-b");
+    }
+
+    // ---- ADD: size mismatch validation ----
+
+    @Test
+    @DisplayName("ADD with mismatched EMBEDDING_IDS and EMBEDDINGS sizes 
throws IllegalArgumentException")
+    void addBatchSizeMismatchThrows() {
+        List<String> callerIds = Arrays.asList("id-1"); // 1 ID
+        List<Embedding> embeddings = Arrays.asList(
+                Embedding.from(new float[] { 0.1f }),
+                Embedding.from(new float[] { 0.2f })); // 2 embeddings
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.ADD)
+                .withHeader(LangChain4jEmbeddingsHeaders.EMBEDDINGS, 
embeddings)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.EMBEDDING_IDS, 
callerIds)
+                .request(Exchange.class);
+
+        
assertThat(result.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(result.getException().getMessage()).contains("EMBEDDING_IDS 
size");
+    }
+
+    // ---- REMOVE: batch by ID list ----
+
+    @Test
+    @DisplayName("REMOVE with Collection<String> body calls removeAll(ids)")
+    void removeBatchByIds() {
+        // Pre-populate
+        String id1 = embeddingStore.add(Embedding.from(new float[] { 0.1f }));
+        String id2 = embeddingStore.add(Embedding.from(new float[] { 0.2f }));
+        embeddingStore.resetCounters();
+
+        List<String> ids = Arrays.asList(id1, id2);
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.REMOVE)
+                .withBody(ids)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        assertThat(embeddingStore.getRemoveAllByIdsInvocations()).isEqualTo(1);
+    }
+
+    // ---- REMOVE: by filter ----
+
+    @Test
+    @DisplayName("REMOVE with FILTER header calls removeAll(filter)")
+    void removeByFilter() {
+        Filter filter = new Filter() {
+            @Override
+            public boolean test(Object object) {
+                return true;
+            }
+        };
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.REMOVE)
+                .withHeader(LangChain4jEmbeddingStoreHeaders.FILTER, filter)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        
assertThat(embeddingStore.getRemoveAllByFilterInvocations()).isEqualTo(1);
+    }
+
+    // ---- REMOVE: null body and no filter throws ----
+
+    @Test
+    @DisplayName("REMOVE with null body and no filter throws 
IllegalArgumentException")
+    void removeWithNoBodyOrFilterThrows() {
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.REMOVE)
+                .request(Exchange.class);
+
+        
assertThat(result.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(result.getException().getMessage()).contains("REMOVE action 
requires");
+    }
+
+    // ---- REMOVE: single ID still works ----
+
+    @Test
+    @DisplayName("REMOVE with single String body still calls remove(id)")
+    void removeSingleIdStillWorks() {
+        String id = embeddingStore.add(Embedding.from(new float[] { 0.9f }));
+        embeddingStore.resetCounters();
+
+        Exchange result = fluentTemplate.to("langchain4j-embeddingstore:test")
+                .withHeader(LangChain4jEmbeddingStoreHeaders.ACTION, 
LangChain4jEmbeddingStoreAction.REMOVE)
+                .withBody(id)
+                .request(Exchange.class);
+
+        assertThat(result.getException()).isNull();
+        assertThat(embeddingStore.getRemoveSingleInvocations()).isEqualTo(1);
+    }
+
+    /**
+     * Extended recording store that tracks which method variants are called.
+     */
+    private static final class RecordingEmbeddingStore extends 
InMemoryEmbeddingStore<TextSegment> {
+
+        private int addWithIdInvocations;
+        private int addAllInvocations;
+        private int addAllWithSegmentsInvocations;
+        private int addAllWithIdsInvocations;
+        private int removeSingleInvocations;
+        private int removeAllByIdsInvocations;
+        private int removeAllByFilterInvocations;
+        private int removeAllInvocations;
+        private String lastCallerSuppliedId;
+
+        @Override
+        public String add(Embedding embedding) {
+            return super.add(embedding);
+        }
+
+        @Override
+        public void add(String id, Embedding embedding) {
+            addWithIdInvocations++;
+            lastCallerSuppliedId = id;
+            super.add(id, embedding);
+        }
+
+        @Override
+        public List<String> addAll(List<Embedding> embeddings) {
+            addAllInvocations++;
+            return super.addAll(embeddings);
+        }
+
+        @Override
+        public List<String> addAll(List<Embedding> embeddings, 
List<TextSegment> embedded) {
+            addAllWithSegmentsInvocations++;
+            return super.addAll(embeddings, embedded);
+        }
+
+        @Override
+        public void addAll(List<String> ids, List<Embedding> embeddings, 
List<TextSegment> embedded) {
+            addAllWithIdsInvocations++;
+            super.addAll(ids, embeddings, embedded);
+        }
+
+        @Override
+        public void remove(String id) {
+            removeSingleInvocations++;
+            super.remove(id);
+        }
+
+        @Override
+        public void removeAll(Collection<String> ids) {
+            removeAllByIdsInvocations++;
+            super.removeAll(ids);
+        }
+
+        @Override
+        public void removeAll(Filter filter) {
+            removeAllByFilterInvocations++;
+            super.removeAll(filter);
+        }
+
+        @Override
+        public void removeAll() {
+            removeAllInvocations++;
+            super.removeAll();
+        }
+
+        void resetCounters() {
+            addWithIdInvocations = 0;
+            addAllInvocations = 0;
+            addAllWithSegmentsInvocations = 0;
+            addAllWithIdsInvocations = 0;
+            removeSingleInvocations = 0;
+            removeAllByIdsInvocations = 0;
+            removeAllByFilterInvocations = 0;
+            removeAllInvocations = 0;
+            lastCallerSuppliedId = null;
+        }
+
+        int getAddWithIdInvocations() {
+            return addWithIdInvocations;
+        }
+
+        int getAddAllInvocations() {
+            return addAllInvocations;
+        }
+
+        int getAddAllWithSegmentsInvocations() {
+            return addAllWithSegmentsInvocations;
+        }
+
+        int getAddAllWithIdsInvocations() {
+            return addAllWithIdsInvocations;
+        }
+
+        int getRemoveSingleInvocations() {
+            return removeSingleInvocations;
+        }
+
+        int getRemoveAllByIdsInvocations() {
+            return removeAllByIdsInvocations;
+        }
+
+        int getRemoveAllByFilterInvocations() {
+            return removeAllByFilterInvocations;
+        }
+
+        int getRemoveAllInvocations() {
+            return removeAllInvocations;
+        }
+
+        String getLastCallerSuppliedId() {
+            return lastCallerSuppliedId;
+        }
+    }
+}
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/ai/CamelLangchain4jAttributes.java
 
b/core/camel-api/src/main/java/org/apache/camel/ai/CamelLangchain4jAttributes.java
index d0bc0d11a8be..1b5d2550e585 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/ai/CamelLangchain4jAttributes.java
+++ 
b/core/camel-api/src/main/java/org/apache/camel/ai/CamelLangchain4jAttributes.java
@@ -25,4 +25,18 @@ public interface CamelLangchain4jAttributes {
     String CAMEL_LANGCHAIN4J_EMBEDDING = "CamelLangChain4jEmbeddingsEmbedding";
     String CAMEL_LANGCHAIN4J_EMBEDDING_VECTOR = 
"CamelLangChain4jEmbeddingsVector";
     String CAMEL_LANGCHAIN4J_TEXT_SEGMENT = 
"CamelLangChain4jEmbeddingsTextSegment";
+
+    /**
+     * List of embeddings from a batch embedAll operation.
+     *
+     * @since 4.23
+     */
+    String CAMEL_LANGCHAIN4J_EMBEDDINGS = 
"CamelLangChain4jEmbeddingsEmbeddings";
+
+    /**
+     * List of text segments from a batch embedAll operation.
+     *
+     * @since 4.23
+     */
+    String CAMEL_LANGCHAIN4J_TEXT_SEGMENTS = 
"CamelLangChain4jEmbeddingsTextSegments";
 }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index df7de54e3453..14da60b11062 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -670,6 +670,29 @@ Camel then no longer controls how the payload is read.
 The legacy `sse` `transportType` has been removed. It follows the support 
removal in 
 
https://github.com/langchain4j/langchain4j/commit/7f4e99fd637137ab9d3bf116eb62047ac757a818[langchain4j-core
 1.19.0].
 
+=== camel-langchain4j-embeddings
+
+The `langchain4j-embeddings` component now supports **batch embedding**. When 
the message body is a `List`
+(of `String` or `TextSegment`), the producer calls `model.embedAll()` instead 
of `model.embed()`.
+The resulting `List<Embedding>` is set in the 
`CamelLangChain4jEmbeddingsEmbeddings` header, and the
+original text segments are preserved in the 
`CamelLangChain4jEmbeddingsTextSegments` header for downstream
+use by the embedding store component.
+
+=== camel-langchain4j-embeddingstore
+
+The ADD operation now supports **batch operations** (via `addAll`) and 
**caller-supplied IDs**.
+When the `CamelLangChain4jEmbeddingsEmbeddings` header is present with a 
`List<Embedding>`,
+the component uses batch operations. Caller-supplied IDs are provided via the
+`CamelLangchain4jEmbeddingStoreEmbeddingId` (single) or 
`CamelLangchain4jEmbeddingStoreEmbeddingIds`
+(batch) headers.
+
+The REMOVE operation now supports **batch removal by collection of IDs** (pass 
a `Collection<String>`
+as the body) and **filter-based removal** (set a `Filter` in the
+`CamelLangchain4jEmbeddingStoreFilter` header). Previously, passing a null or 
empty body to REMOVE
+would pass `null` to the underlying store's `remove()` method, which threw an 
opaque exception
+from langchain4j. It now throws `IllegalArgumentException` with a clear 
message listing the
+expected inputs.
+
 === camel-ftp, camel-sftp, camel-ftps, camel-mina-sftp, camel-azure-files, 
camel-smb
 
 The remote-file consumers now ensure the path resolved for a polled file stays 
within the directory being
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingStoreEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingStoreEndpointBuilderFactory.java
index b1f863714ebf..976676bc233c 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingStoreEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingStoreEndpointBuilderFactory.java
@@ -430,7 +430,8 @@ public interface 
LangChain4jEmbeddingStoreEndpointBuilderFactory {
             return "CamelLangchain4jEmbeddingStoreMinScore";
         }
         /**
-         * Search filter for metadata-based constraints.
+         * Filter for metadata-based constraints (used in SEARCH and REMOVE
+         * operations).
          * 
          * The option is a: {@code
          * dev.langchain4j.store.embedding.filter.Filter} type.
@@ -443,6 +444,32 @@ public interface 
LangChain4jEmbeddingStoreEndpointBuilderFactory {
         public String langchain4jEmbeddingStoreFilter() {
             return "CamelLangchain4jEmbeddingStoreFilter";
         }
+        /**
+         * Caller-supplied embedding ID for single ADD operations.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code
+         * Langchain4jEmbeddingStoreEmbeddingId}.
+         */
+        public String langchain4jEmbeddingStoreEmbeddingId() {
+            return "CamelLangchain4jEmbeddingStoreEmbeddingId";
+        }
+        /**
+         * Caller-supplied embedding IDs for batch ADD operations.
+         * 
+         * The option is a: {@code java.util.List<java.lang.String>} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code
+         * Langchain4jEmbeddingStoreEmbeddingIds}.
+         */
+        public String langchain4jEmbeddingStoreEmbeddingIds() {
+            return "CamelLangchain4jEmbeddingStoreEmbeddingIds";
+        }
     }
     static LangChain4jEmbeddingStoreEndpointBuilder endpointBuilder(String 
componentName, String path) {
         class LangChain4jEmbeddingStoreEndpointBuilderImpl extends 
AbstractEndpointBuilder implements LangChain4jEmbeddingStoreEndpointBuilder, 
AdvancedLangChain4jEmbeddingStoreEndpointBuilder {
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingsEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingsEndpointBuilderFactory.java
index 13151faabfde..3672e2d13884 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingsEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jEmbeddingsEndpointBuilderFactory.java
@@ -295,6 +295,20 @@ public interface 
LangChain4jEmbeddingsEndpointBuilderFactory {
         public String langChain4jEmbeddingsEmbedding() {
             return "CamelLangChain4jEmbeddingsEmbedding";
         }
+        /**
+         * List of embeddings from a batch embedAll operation.
+         * 
+         * The option is a: {@code
+         * java.util.List<dev.langchain4j.data.embedding.Embedding>} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code
+         * LangChain4jEmbeddingsEmbeddings}.
+         */
+        public String langChain4jEmbeddingsEmbeddings() {
+            return "CamelLangChain4jEmbeddingsEmbeddings";
+        }
         /**
          * A dense vector embedding of a text.
          * 
@@ -321,6 +335,20 @@ public interface 
LangChain4jEmbeddingsEndpointBuilderFactory {
         public String langChain4jEmbeddingsTextSegment() {
             return "CamelLangChain4jEmbeddingsTextSegment";
         }
+        /**
+         * List of text segments from a batch embedAll operation.
+         * 
+         * The option is a: {@code
+         * java.util.List<dev.langchain4j.data.segment.TextSegment>} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code
+         * LangChain4jEmbeddingsTextSegments}.
+         */
+        public String langChain4jEmbeddingsTextSegments() {
+            return "CamelLangChain4jEmbeddingsTextSegments";
+        }
     }
     static LangChain4jEmbeddingsEndpointBuilder endpointBuilder(String 
componentName, String path) {
         class LangChain4jEmbeddingsEndpointBuilderImpl extends 
AbstractEndpointBuilder implements LangChain4jEmbeddingsEndpointBuilder, 
AdvancedLangChain4jEmbeddingsEndpointBuilder {

Reply via email to