= LangChain4j Tools Component
:doctitle: LangChain4j Tools
:shortname: langchain4j-tools
:artifactid: camel-langchain4j-tools
:description: LangChain4j Tools and Function Calling Features
:since: 4.8
:supportlevel: Preview
:tabs-sync-option:
:component-header: Both producer and consumer are supported
//Manually maintained attributes
:group: AI
:camel-spring-boot-name: langchain4j-tools

*Since Camel {since}*

*{component-header}*

The LangChain4j Tools Component allows you to use function calling features from Large Language Models (LLMs) supported by https://github.com/langchain4j/langchain4j[LangChain4j].

Maven users will need to add the following dependency to their `pom.xml`
for this component:

[source,xml]
----
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-langchain4j-tools</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
----

== URI format

.Producer
----
langchain4j-tools:toolSet[?options]
----

.Consumer
----
langchain4j-tools:toolSet[?options]
----

Where *toolSet* can be any string to uniquely identify the endpoint


// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
include::partial$component-endpoint-headers.adoc[]
// component options: END

include::spring-boot:partial$starter.adoc[]

== Usage

This component helps to use function-calling features from LLMs so that models can decide what functions (routes, in case of Camel)
can be called (i.e.; routed).

Consider, for instance, two consumer routes capable of query an user database by user ID or by social security number (SSN).

.Queries user by ID
[source, java]
----
from("langchain4j-tools:userInfo?tags=users&description=Query database by user ID")
    .to("sql:SELECT name FROM users WHERE id = :#number");
----

.Queries user by SSN
[source, java]
----
from("langchain4j-tools:userInfo?tags=users&description=Query database by user social security ID")
    .to("sql:SELECT name FROM users WHERE ssn = :#ssn");
----

Now, consider a producer route that receives unstructured data as input. Such a route could consume
this data, pass it to a LLM with function-calling capabilities (such as https://huggingface.co/meta-llama/Meta-Llama-3.1-8B[llama3.1],
https://huggingface.co/ibm-granite/granite-20b-functioncalling[Granite Code 20b function calling, etc]) and have
the model decide which route to call.

Such a route could receive questions in english such as:

- _"What is the name of the user with user ID 1?"_
- _"What is the name of the user with SSN 34.400.96?"_

.Produce
[source, java]
----
from(source)
    .to("langchain4j-tools:userInfo?tags=users");
----

=== Tool Tags

Consumer routes must define tags that groups https://en.wikipedia.org/wiki/Set_theory[together]. The aforementioned routes would be
part have the `users` tag. The `users` tag has two routes: `queryById` and `queryBySSN`

=== Parameters

The Tool Input parameter can be defined as an Endpoint multiValue option in the form of `parameter.<name>=<type>`,
or via the endpoint option `camelToolParameter` for a programmatic approach.
The parameters can be found as headers in the consumer route, in particular, if you define `parameter.userId=5`,
in the consumer route `${header.userId}` can be used.

Parameters support optional metadata:

* `parameter.<name>=<type>` — defines the parameter type (`string`, `integer`, `number`, `boolean`)
* `parameter.<name>.description=<text>` — defines a description passed to the LLM
* `parameter.<name>.required=<true|false>` — marks the parameter as required (default: `false`)
* `parameter.<name>.enum=<value1,value2>` — restricts the parameter to a set of allowed values (comma-separated)

.Producer and consumer example:
[source, java]
----
from("direct:test")
    .to("langchain4j-tools:test1?tags=users");

from("langchain4j-tools:test1?tags=users&description=Query user database by user ID&parameter.userId=integer")
    .to("sql:SELECT name FROM users WHERE id = :#userId");
----

.Example with required parameters and descriptions:
[source, java]
----
from("langchain4j-tools:weather?tags=weather&description=Get weather forecast"
    + "&parameter.location=string"
    + "&parameter.location.description=The city and state"
    + "&parameter.location.required=true"
    + "&parameter.unit=string"
    + "&parameter.unit.description=Temperature unit"
    + "&parameter.unit.enum=celsius,fahrenheit")
    .process(exchange -> {
        String location = exchange.getIn().getHeader("location", String.class);
        // ...
    });
----

When using the programmatic `CamelSimpleToolParameter` approach, required parameters can be specified as a list of parameter names.
The full constructor also accepts `additionalProperties` (to restrict extra fields) and `definitions` (for recursive schemas using `JsonReferenceSchema`):

[source, java]
----
CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
    "Get weather forecast",
    List.of(
        new NamedJsonSchemaProperty("location",
            JsonStringSchema.builder().description("The city and state").build()),
        new NamedJsonSchemaProperty("unit",
            JsonEnumSchema.builder().enumValues("celsius", "fahrenheit")
                .description("Temperature unit").build())),
    List.of("location"),  // required parameter names
    false,                // additionalProperties
    null);                // definitions (for recursive schemas)
----

.Usage example:
[source, java]
----
List<ChatMessage> messages = new ArrayList<>();
        messages.add(new SystemMessage("""
                You provide information about specific user name querying the database given a number.
                """));
        messages.add(new UserMessage("""
                What is the name of the user 1?
                """));

        Exchange message = fluentTemplate.to("direct:test").withBody(messages).request(Exchange.class);
----

=== Using a specific Model

The Camel LangChain4j tools component provides an abstraction for interacting with various types of Large Language Models (LLMs)
supported by https://github.com/langchain4j/langchain4j[LangChain4j].

==== Integrating with specific LLM

To integrate with a specific LLM, users should follow the steps described below, which explain
how to integrate with OpenAI.

Add the dependency for LangChain4j OpenAI support:

.Example
[source,xml]
----
<dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
    <version>x.x.x</version>
</dependency>
----

Initialize the OpenAI Chat Language Model, and add it to the Camel Registry:

[source, java]
----
ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("NO_API_KEY")
                .modelName("llama3.1:latest")
                .temperature(0.0)
                .timeout(ofSeconds(60000))
                .build();
context.getRegistry().bind("chatModel", model);
----

Use the model in the Camel LangChain4j Chat Producer

[source, java]
----
 from("direct:chat")
      .to("langchain4j-tools:test?tags=users&chatModel=#chatModel");
----

[NOTE]
====
To switch to another Large Language Model and its corresponding dependency, replace the `langchain4j-open-ai` dependency with the appropriate dependency for the desired model. Update the initialization parameters accordingly in the code snippet provided above.
====


==== Handling no Tools Called

In some circumstances, the LLM may decide not to call a tool.
This is a valid scenario that needs to be handled by application developers.
To do so, developers can get the `LangChain4jTools.NO_TOOLS_CALLED_HEADER` from the exchange.

=== Tool Search Tool

The Tool Search Tool is a native feature that allows LLMs to discover and access tools dynamically without consuming the entire context window with tool definitions.

==== Overview

When you have many tools available, exposing all of them to the LLM in every request can:

* Consume significant context window space
* Reduce the space available for actual conversation
* Potentially confuse the LLM with too many options

The Tool Search Tool solves this by allowing you to mark certain tools as "searchable" (non-exposed). These tools are not automatically sent to the LLM but can be discovered when needed.

==== Using the `exposed` Parameter

By default, all tools are exposed to the LLM (`exposed=true`). To make a tool searchable instead:

[source, java]
----
from("langchain4j-tools:queryBySSN?tags=users&description=Query user database by social security number&parameter.ssn=string&exposed=false")
    .to("sql:SELECT name FROM users WHERE ssn = :#ssn");
----

==== How It Works

1. When you define tools with `exposed=false`, they are added to a searchable tool registry
2. A native `toolSearchTool` is automatically exposed to the LLM when searchable tools exist
3. The LLM can invoke `toolSearchTool` with tags to discover available tools
4. The search results are returned to the LLM, which can then decide which tools to use

==== Example: Mixed Exposed and Searchable Tools

[source, java]
----
// This tool is immediately available to the LLM
from("langchain4j-tools:queryById?tags=users&description=Query user database by user ID&parameter.userId=integer")
    .to("sql:SELECT name FROM users WHERE id = :#userId");

// This tool is searchable but not immediately exposed
from("langchain4j-tools:queryBySSN?tags=users&description=Query user database by social security number&parameter.ssn=string&exposed=false")
    .to("sql:SELECT name FROM users WHERE ssn = :#ssn");

// Another searchable tool with different tags
from("langchain4j-tools:sendEmail?tags=users,email&description=Send email to a user&parameter.email=string&parameter.message=string&exposed=false")
    .to("smtp://mailserver");
----

In this example:

* The `queryById` tool is immediately available to the LLM
* The `queryBySSN` and `sendEmail` tools can be discovered by searching for tags like "users" or "email"
* The LLM can use the `toolSearchTool` to find these additional capabilities when needed

==== Benefits

* *Reduced Context Usage*: Only expose the most commonly used tools initially
* *Scalability*: Support hundreds or thousands of tools without overwhelming the LLM
* *Dynamic Discovery*: Let the LLM discover tools as needed based on the conversation
* *Better Organization*: Group related tools by tags for easier discovery

==== Best Practices

When using the Tool Search Tool feature, consider the following best practices:

* *Tag Strategy*: Use meaningful, hierarchical tags (e.g., "users", "users.admin", "database.users") to organize tools logically
* *Expose Common Tools*: Keep frequently used tools exposed (`exposed=true`) and make specialized tools searchable (`exposed=false`)
* *Performance Considerations*: While the search is efficient, having thousands of searchable tools may impact search performance. Consider grouping tools by functional area
* *LLM Guidance*: In your system message, inform the LLM about the availability of the `toolSearchTool` and when to use it
* *Tag Naming*: Use consistent, lowercase tag names without special characters for best compatibility
* *Tool Descriptions*: Write clear, descriptive tool descriptions as they are returned in search results to help the LLM choose the right tool
* *Testing*: Test your tool organization with real queries to ensure the LLM can discover and use tools effectively

==== Limitations

* The LLM must be instructed to use the `toolSearchTool` - it won't automatically know to search for tools
* Search is based on exact tag matching - fuzzy matching or semantic search is not currently supported
* The feature requires an LLM with good function-calling capabilities to work effectively
