[ 
https://issues.apache.org/jira/browse/CAMEL-24767?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18115936#comment-18115936
 ] 

Federico Mariani commented on CAMEL-24767:
------------------------------------------

h3. Usage examples

Option names below are illustrative, to make the proposal concrete — see open 
question 1 in the description. They assume {{searchable=true}} on the tool 
consumer and {{toolSearch=true}} on the producer.

h4. The situation today

{code:java}
// 150 tool routes across the estate
from("ai-tool:getOrder?tags=erp&description=Get an order by 
id&parameter.orderId=string").to("sql:...");
from("ai-tool:getInvoice?tags=erp&description=Get an invoice by 
id&parameter.invoiceId=string").to("sql:...");
// ... 148 more

// every one of them is serialised into every single request
from("direct:ask")
    .to("langchain4j-agent:ops?agentConfiguration=#cfg&tags=erp");
{code}

h4. 1. Mark tools searchable (consumer side, {{camel-ai-tool}})

{code:java}
// Entry-point tool: always visible, so the model knows the search space exists
from("ai-tool:listDomains?tags=erp&description=List the available business 
domains")
    .setBody(constant("orders, invoices, shipments, customers"));

// The long tail: indexed, not sent to the model until found
from("ai-tool:getOrder?tags=erp&searchable=true"
        + "&description=Get an order by id&parameter.orderId=string")
    .to("sql:select * from orders where id = :#orderId");

from("ai-tool:getInvoice?tags=erp&searchable=true"
        + "&description=Get an invoice by id&parameter.invoiceId=string")
    .to("sql:select * from invoices where id = :#invoiceId");
{code}

Tools without {{searchable=true}} keep today's behaviour and stay 
always-visible, so the change is opt-in and existing routes are unaffected.

h4. 2. camel-langchain4j-agent

{code:java}
from("direct:ask")
    .to("langchain4j-agent:ops?agentConfiguration=#cfg&tags=erp"
        + "&toolSearch=true"
        + "&toolSearchMaxResults=5");
{code}

Semantic search instead of keyword matching:

{code:java}
from("direct:ask")
    .to("langchain4j-agent:ops?agentConfiguration=#cfg&tags=erp"
        + "&toolSearch=true"
        + "&toolSearchStrategy=VECTOR"
        + "&embeddingModel=#embeddingModel");
{code}

This is already reachable today in the Java DSL with no Camel change, through 
the existing {{AgentConfiguration#withAiServicesCustomizer}} escape hatch — 
useful for validating the behaviour before settling on an API:

{code:java}
AgentConfiguration config = new AgentConfiguration()
    .withAiServicesCustomizer(ai ->
        ai.toolSearchStrategy(new VectorToolSearchStrategy(embeddingModel)));
{code}

h4. 3. camel-spring-ai-chat

{code:java}
from("direct:ask")
    .to("spring-ai-chat:ops?chatModel=#chatModel&tags=erp"
        + "&toolSearch=true"
        + "&toolSearchMaxResults=5");
{code}

Spring AI scopes the index per session and evicts it. The existing 
{{CamelSpringAiChatConversationId}} header is the natural session key, so a 
multi-turn conversation keeps the tools it discovered:

{code:java}
from("direct:ask")
    .setHeader("CamelSpringAiChatConversationId", header("userId"))
    
.to("spring-ai-chat:ops?chatModel=#chatModel&chatMemory=#chatMemory&tags=erp"
        + "&toolSearch=true");
{code}

h4. 4. camel-openai

{code:java}
from("direct:ask")
    .to("openai:chat-completion?model=gpt-4&tags=erp"
        + "&toolSearch=true"
        + "&toolSearchMaxResults=5");
{code}

h4. 5. Route tools and MCP tools in one index

Both are indexed together, so they rank against each other rather than one 
family being always-visible (see the MCP comment above):

{code:java}
from("direct:ask")
    .to("langchain4j-agent:ops?agentConfiguration=#cfg&tags=erp"
        + "&mcpClients=#githubMcp,#jiraMcp"
        + "&toolSearch=true");
{code}

h4. 6. What happens at runtime

With {{toolSearch=true}}, a turn looks like this:

# The model receives the always-visible tools plus one {{tool_search_tool}}, 
instead of all 150.
# User asks: _"what is the status of order 4711?"_
# The model calls {{tool_search_tool(query="look up an order")}}.
# Camel returns the matching tool names, e.g. {{getOrder}}, {{getOrderStatus}}.
# Those tools are added to the next request, and the model calls 
{{getOrder(orderId=4711)}}.
# The route runs and the answer comes back.

The cost is one extra model round trip per turn, against a much smaller prompt 
on every request. That trade favours search once the tool count is high; below 
roughly 15-20 tools it is likely a net loss, which is why this should stay 
opt-in and be documented as such.

h4. YAML

{code:yaml}
- route:
    from:
      uri: direct:ask
      steps:
        - to:
            uri: langchain4j-agent:ops
            parameters:
              agentConfiguration: "#cfg"
              tags: erp
              toolSearch: true
              toolSearchMaxResults: 5
{code}

_Claude Code on behalf of Croway_

> camel-ai-tool - reinstate tool search, shared by langchain4j-agent, 
> spring-ai-chat and openai
> ---------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24767
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24767
>             Project: Camel
>          Issue Type: Improvement
>            Reporter: Federico Mariani
>            Priority: Major
>
> h2. Context
> CAMEL-22851 added a native tool-search-tool to {{camel-langchain4j-tools}} 
> (shipped in 4.18.0). It added an {{exposed}} URI option: with 
> {{exposed=false}} a tool was not sent to the LLM on every request but placed 
> in a searchable registry, and a {{toolSearchTool}} was auto-exposed so the 
> LLM could discover it on demand.
> {{camel-langchain4j-tools}} was deprecated in 4.22 and removed in 4.23 
> (commit 2a2b0e1bb71c), replaced by {{camel-ai-tool}} for tool definition and 
> {{camel-langchain4j-agent}} for tool calling. The tool-search capability was 
> *not* ported: {{AiToolConfiguration}} has no {{exposed}}/searchable 
> equivalent, and none of the three AI producers that consume 
> {{AiToolRegistry}} support tool search today.
> So the feature regressed out of the project as a side effect of the 
> migration. The 4.22 and 4.23 upgrade guides document the 
> {{langchain4j-tools:}} -> {{ai-tool:}} route migration but do not mention 
> that {{exposed=false}} has no equivalent.
> h2. Why it matters
> All three producers select tools by {{tags}} and serialise every matching 
> {{ai-tool:}} route into every request:
> * {{camel-langchain4j-agent}} - via {{AiToolSpecToLangChain4j}} / 
> {{ToolProvider}}
> * {{camel-spring-ai-chat}} - {{SpringAiChatProducer#applyRequestOptions}} 
> puts all tag-matched callbacks into {{ToolCallingChatOptions}}
> * {{camel-openai}} - {{OpenAIEndpoint}} lines 283/366
> With a broad tag over a large route catalogue this consumes a significant 
> part of the context window on every call, and tool-selection accuracy 
> degrades well before the context limit is reached.
> h2. Proposal
> Reinstate tool search in {{camel-ai-tool}}, which is the shared abstraction 
> ({{AiToolRegistry}} / {{AiToolSpec}}), so the three consumers behave 
> consistently rather than each inheriting whatever its upstream framework does:
> # Consumer side: an option on {{ai-tool:}} marking a tool searchable rather 
> than always-visible (the {{exposed}} option from CAMEL-22851, or a clearer 
> name).
> # Producer side: a {{toolSearch}} option on {{langchain4j-agent}}, 
> {{spring-ai-chat}} and {{openai}} enabling the search tool for that endpoint.
> # A scoring/index implementation over {{AiToolSpec}} in {{camel-ai-tool}}, so 
> {{tags}} semantics and ranking are identical across the three.
> # Upgrade-guide entry noting the capability was absent between the removal 
> and this change.
> h2. Framework support now available
> This did not exist when CAMEL-22851 was implemented (it was hand-rolled in 
> Camel). Both frameworks now ship it, at versions Camel already depends on:
> * *LangChain4j 1.20.0* - {{dev.langchain4j.service.tool.search}} 
> ({{@Experimental}}, since 1.12.0): {{ToolSearchStrategy}} with 
> {{SimpleToolSearchStrategy}} (keyword) and {{VectorToolSearchStrategy}} 
> (embeddings, needs only an {{EmbeddingModel}}), wired with 
> {{AiServices.toolSearchStrategy(...)}}. Tools supplied through a 
> {{ToolProvider}} - which is how Camel passes route tools - are searchable: 
> {{ToolService#createContext}} builds {{availableTools}} from static tools and 
> providers first, then applies the search service. 
> {{AbstractAgent#configureBuilder}} already sets sibling options 
> ({{maxToolCallingRoundTrips}}, {{hallucinatedToolNameStrategy}}), so this is 
> a few lines. It is also reachable today without any Camel change through the 
> existing {{AgentConfiguration#withAiServicesCustomizer}} escape hatch, which 
> makes it easy to validate the behaviour before committing to an API.
> * *Spring AI 2.0.1* - {{spring-ai-tool-search-tool}} and 
> {{spring-ai-tool-search-advisor}}: {{ToolIndex}} (regex, Lucene, vector 
> store), {{ToolSearchToolCallingAdvisor}} with {{maxResults}} and 
> session-scoped LRU/TTL eviction. Session scoping maps onto the existing 
> {{CamelSpringAiChatConversationId}} header. Note this advisor extends 
> {{ToolCallingAdvisor}}, which replaces the model-internal tool-calling loop - 
> that is the main design consideration on this side.
> * *camel-openai* - no equivalent in the OpenAI Java SDK, but Camel owns the 
> agentic loop already ({{maxToolIterations}}), so the search tool has to be 
> driven directly. This is the strongest argument for putting the index in 
> {{camel-ai-tool}}: it gives the OpenAI component an implementation to reuse 
> instead of a bespoke one.
> h2. Open questions
> * Option naming, and whether searchable is opt-in on the tool 
> ({{exposed=false}}, as in CAMEL-22851) or opt-in on the producer 
> ({{toolSearch=true}}), or both.
> * Keyword matching (as the original implementation did, by tag) versus 
> embedding-based semantic search, which both frameworks now offer.
> * Whether to delegate to each framework's native implementation, or keep a 
> single Camel-owned index for consistent behaviour across the three 
> components. The frameworks differ in how discovered tools persist: 
> LangChain4j accumulates them through chat-memory message attributes, Spring 
> AI through a session-scoped index with eviction.
> Prior art for the design is in commit 5ef1539bacbb (CAMEL-22851), in 
> particular {{ToolSearchTool}} and the searchable registry in 
> {{CamelToolExecutorCache}}.
> _Claude Code on behalf of Croway_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to