Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AI Services: added an option to configure tools programmatically (lan…
…gchain4j#1364) ## Issue Implements langchain4j#141 ## Change This PR introduces an option to configure tools programmatically when using AI Services. Tools can now be provided as a map of `ToolSpecification` to `ToolExecutor` pairs: ```java ToolSpecification toolSpecification = ToolSpecification.builder() .name("get_booking_details") .description("Returns booking details") .addParameter("bookingNumber", type("string")) .build(); ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> { Map<String, Object> arguments = toMap(toolExecutionRequest.arguments()); assertThat(arguments).containsExactly(entry("bookingNumber", "123-456")); return "Booking period: from 1 July 2027 to 10 July 2027"; }; Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(chatLanguageModel) .tools(singletonMap(toolSpecification, toolExecutor)) .build(); String answer = assistant.chat("When does my booking 123-456 starts?"); assertThat(answer).contains("2027"); ``` This approach offers a lot of flexibility, as tools can now be loaded from external sources such as databases and configuration files. Tool names, descriptions, parameter names, and descriptions can all be dynamically configured via `ToolSpecification`. For instance, one of the LC4j users wants to store tools (where each tool is an API endpoint) in a configuration file like this: ```json [ { "name": "get_order_details", "url": "https://url.com", "method": "POST", "description": "Get additional order details by providing an order ID" "parameters": { "order": { "type": "string", "description": "an order ID, for example: 300" } }, "examples": [ "Get additional details for order 300", "Show more information for order 301", "Show request delivery date for order 201" ] } ] ``` With this PR, this can be implemented like so: ```java List<ApiTool> apiTools = loadFromFile("tools.json"); Map<ToolSpecification, ToolExecutor> tools = new HashMap<>(); for (ApiTool apiTool : apiTools) { if ("GET".equals(apiTool.getMethod())) { ToolSpecification toolSpecification = ToolSpecification.builder() .name(apiTool.getName()) .description(apiTool.getDescription()) .build(); ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> httpClient.get(apiTool.getUrl()); tools.put(toolSpecification, toolExecutor); } else if ("POST".equals(apiTool.getMethod())) { ToolSpecification.Builder toolSpecificationBuilder = ToolSpecification.builder() .name(apiTool.getName()) .description(apiTool.getDescription); apiTool.getParameters().forEach((parameterName, parameterProperties) -> { toolSpecificationBuilder.addParameter(parameterName, type(parameterProperties.get("type")), description(parameterProperties.get("description"))); }); ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> httpClient.post(apiTool.getUrl(), toolExecutionRequest.arguments()); tools.put(toolSpecificationBuilder.build(), toolExecutor); } } ``` The drawback of this way of configuring tools is that it requires one to implement a rather low-level `ToolExecutor` interface and manually parse tool arguments. In future iterations, we could either automatically parse arguments into a `Map<String, Object>` tree and/or allow users to explicitly specify a `Class` to parse into. ## General checklist <!-- Please double-check the following points and mark them like this: [X] --> - [X] There are no breaking changes - [X] I have added unit and integration tests for my change - [x] I have manually run all the unit and integration tests in the module I have added/changed, and they are all green - [x] I have manually run all the unit and integration tests in the [core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core) and [main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j) modules, and they are all green <!-- Before adding documentation and example(s) (below), please wait until the PR is reviewed and approved. --> - [x] I have added/updated the [documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs) - [ ] I have added an example in the [examples repo](https://github.com/langchain4j/langchain4j-examples) (only for "big" features) - [ ] I have added/updated [Spring Boot starter(s)](https://github.com/langchain4j/langchain4j-spring) (if applicable)
- Loading branch information