Files
gh-giuseppe-trisciuoglio-de…/skills/langchain4j/langchain4j-tool-function-calling-patterns/references/implementation-patterns.md
2025-11-29 18:28:30 +08:00

478 lines
14 KiB
Markdown

# LangChain4j Tool & Function Calling - Implementation Patterns
Comprehensive implementation patterns for tool and function calling with LangChain4j.
## Core Tool Definition Patterns
### Basic Tool Definition with @Tool Annotation
The `@Tool` annotation converts regular Java methods into tools that LLMs can discover and execute.
**Basic Tool Definition:**
```java
public class CalculatorTools {
@Tool("Adds two given numbers")
public double add(double a, double b) {
return a + b;
}
@Tool("Multiplies two given numbers")
public double multiply(double a, double b) {
return a * b;
}
@Tool("Calculates the square root of a given number")
public double squareRoot(double x) {
return Math.sqrt(x);
}
@Tool("Calculates power of a number")
public double power(double base, double exponent) {
return Math.pow(base, exponent);
}
}
```
**Advanced Tool with Parameter Descriptions:**
```java
public class WeatherService {
@Tool("Get current weather conditions for a specific location")
public String getCurrentWeather(@P("The name of the city or location") String location) {
try {
WeatherData weather = weatherClient.getCurrentWeather(location);
return String.format("Weather in %s: %s, %.1f°C, humidity %.0f%%, wind %.1f km/h",
location, weather.getCondition(), weather.getTemperature(),
weather.getHumidity(), weather.getWindSpeed());
} catch (Exception e) {
return "Sorry, I couldn't retrieve weather information for " + location;
}
}
}
```
### Parameter Handling and Validation
**Optional Parameters:**
```java
public class DatabaseTools {
@Tool("Search for users in the database")
public List<User> searchUsers(
@P("Search term for user name or email") String searchTerm,
@P(value = "Maximum number of results to return", required = false) Integer limit,
@P(value = "Sort order: ASC or DESC", required = false) String sortOrder) {
int actualLimit = limit != null ? limit : 10;
String actualSort = sortOrder != null ? sortOrder : "ASC";
return userRepository.searchUsers(searchTerm, actualLimit, actualSort);
}
}
```
**Complex Parameter Types:**
```java
public class OrderManagementTools {
@Description("Customer order information")
public static class OrderRequest {
@Description("Customer ID who is placing the order")
private Long customerId;
@Description("List of items to order")
private List<OrderItem> items;
@Description("Shipping address for the order")
private Address shippingAddress;
@Description("Preferred delivery date (optional)")
@JsonProperty(required = false)
private LocalDate preferredDeliveryDate;
}
@Tool("Create a new customer order")
public String createOrder(OrderRequest orderRequest) {
try {
// Validation and processing logic
Order order = orderService.createOrder(orderRequest);
return String.format("Order created successfully! Order ID: %s, Total: $%.2f",
order.getId(), order.getTotal());
} catch (Exception e) {
return "Failed to create order: " + e.getMessage();
}
}
}
```
## Memory Context Integration
### @ToolMemoryId for User Context
Tools can access conversation memory context to provide personalized and contextual responses:
```java
public class PersonalizedTools {
@Tool("Get personalized recommendations based on user preferences")
public String getRecommendations(@ToolMemoryId String userId,
@P("Type of recommendation: books, movies, restaurants") String type) {
UserPreferences prefs = preferenceService.getUserPreferences(userId);
List<String> history = historyService.getSearchHistory(userId, type);
return recommendationEngine.getRecommendations(type, prefs, history);
}
}
```
## Dynamic Tool Provisioning
### ToolProvider for Context-Aware Tools
```java
public class DynamicToolProvider implements ToolProvider {
@Override
public ToolProviderResult provideTools(ToolProviderRequest request) {
String userId = extractUserId(request);
UserPermissions permissions = permissionService.getUserPermissions(userId);
String userMessage = request.userMessage().singleText().toLowerCase();
ToolProviderResult.Builder resultBuilder = ToolProviderResult.builder();
// Always available tools
addBasicTools(resultBuilder);
// Conditional tools based on permissions
if (permissions.canAccessFinancialData()) {
addFinancialTools(resultBuilder);
}
if (permissions.canModifyUserData()) {
addUserManagementTools(resultBuilder);
}
return resultBuilder.build();
}
}
```
### Programmatic Tool Definition
```java
public class ProgrammaticToolsService {
public Map<ToolSpecification, ToolExecutor> createDatabaseTools(DatabaseConfig config) {
Map<ToolSpecification, ToolExecutor> tools = new HashMap<>();
// Query tool
ToolSpecification querySpec = ToolSpecification.builder()
.name("execute_database_query")
.description("Execute a SQL query on the database")
.parameters(JsonObjectSchema.builder()
.addStringProperty("query", "SQL query to execute")
.addBooleanProperty("readOnly", "Whether this is a read-only query")
.required("query", "readOnly")
.build())
.build();
ToolExecutor queryExecutor = (request, memoryId) -> {
Map<String, Object> args = fromJson(request.arguments());
String query = args.get("query").toString();
boolean readOnly = (Boolean) args.get("readOnly");
return databaseService.executeQuery(query, readOnly);
};
tools.put(querySpec, queryExecutor);
return tools;
}
}
```
## AI Services as Tools
AI Services can be used as tools by other AI Services, enabling hierarchical architectures:
```java
// Specialized Expert Services
interface DataAnalysisExpert {
@UserMessage("You are a data analysis expert. Analyze this data and provide insights: {{data}}")
@Tool("Expert data analysis and insights")
String analyzeData(@V("data") String data);
}
// Router Agent that delegates to experts
interface ExpertRouter {
@UserMessage("""
Analyze the user request and determine which expert(s) should handle it:
- Use the data analysis expert for data-related questions
- Use the security expert for security-related concerns
User request: {{it}}
""")
String routeToExperts(String request);
}
@Service
public class ExpertConsultationService {
public ExpertConsultationService(ChatModel chatModel) {
// Build expert services
DataAnalysisExpert dataExpert = AiServices.create(DataAnalysisExpert.class, chatModel);
// Build router with experts as tools
this.router = AiServices.builder(ExpertRouter.class)
.chatModel(chatModel)
.tools(dataExpert)
.build();
}
}
```
## Advanced Tool Patterns
### Immediate Return Tools
```java
public class DirectResponseTools {
@Tool(value = "Get current user information", returnBehavior = ReturnBehavior.IMMEDIATE)
public String getCurrentUserInfo(@ToolMemoryId String userId) {
User user = userService.findById(userId);
return String.format("""
User Information:
Name: %s
Email: %s
Role: %s
""", user.getName(), user.getEmail(), user.getRole());
}
}
```
### Concurrent Tool Execution
```java
public class ConcurrentTools {
@Tool("Get stock price for a company")
public String getStockPrice(@P("Stock symbol") String symbol) {
try {
Thread.sleep(1000);
return stockApiService.getPrice(symbol);
} catch (InterruptedException e) {
return "Error retrieving stock price";
}
}
@Tool("Get company news")
public String getCompanyNews(@P("Company symbol") String symbol) {
// Similar implementation
}
}
// Configure for concurrent execution
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(chatModel)
.tools(new ConcurrentTools())
.executeToolsConcurrently() // Execute tools in parallel
.build();
```
## Error Handling and Resilience
### Tool Execution Error Handling
```java
public class ResilientTools {
private final CircuitBreaker circuitBreaker;
private final RetryTemplate retryTemplate;
@Tool("Get external data with resilience patterns")
public String getExternalData(@P("Data source identifier") String sourceId) {
return circuitBreaker.executeSupplier(() -> {
return retryTemplate.execute(context -> {
try {
return externalApiService.fetchData(sourceId);
} catch (ApiException e) {
if (e.isRetryable()) {
throw e; // Will be retried
}
return "Data temporarily unavailable: " + e.getMessage();
}
});
});
}
}
```
### Graceful Degradation
```java
public class FallbackTools {
@Tool("Get weather information with fallback providers")
public String getWeather(@P("Location name") String location) {
// Try primary provider first
for (DataProvider provider : dataProviders) {
try {
WeatherData weather = provider.getWeather(location);
if (weather != null) {
return formatWeather(weather, provider.getName());
}
} catch (Exception e) {
// Continue to next provider
}
}
return "Weather information is currently unavailable for " + location;
}
}
```
## Streaming and Tool Execution
### Streaming with Tool Callbacks
```java
interface StreamingToolAssistant {
TokenStream chat(String message);
}
StreamingToolAssistant assistant = AiServices.builder(StreamingToolAssistant.class)
.streamingChatModel(streamingChatModel)
.tools(new CalculatorTools(), new WeatherService())
.build();
TokenStream stream = assistant.chat("What's the weather in Paris and calculate 15 + 27?");
stream
.onToolExecuted(toolExecution -> {
System.out.println("Tool executed: " + toolExecution.request().name());
System.out.println("Result: " + toolExecution.result());
})
.onPartialResponse(partialResponse -> {
System.out.print(partialResponse);
})
.start();
```
### Accessing Tool Execution Results
```java
interface AnalyticsAssistant {
Result<String> analyze(String request);
}
AnalyticsAssistant assistant = AiServices.builder(AnalyticsAssistant.class)
.chatModel(chatModel)
.tools(new DataAnalysisTools(), new DatabaseTools())
.build();
Result<String> result = assistant.analyze("Analyze sales data for Q4 2023");
// Access the response
String response = result.content();
// Access tool execution details
List<ToolExecution> toolExecutions = result.toolExecutions();
for (ToolExecution execution : toolExecutions) {
System.out.println("Tool: " + execution.request().name());
System.out.println("Duration: " + execution.duration().toMillis() + "ms");
}
```
## Complete Tool-Enabled Application
### Spring Boot Integration
```java
@RestController
@RequestMapping("/api/assistant")
@RequiredArgsConstructor
public class ToolAssistantController {
private final ToolEnabledAssistant assistant;
@PostMapping("/chat")
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
try {
Result<String> result = assistant.chat(request.getUserId(), request.getMessage());
ChatResponse response = ChatResponse.builder()
.response(result.content())
.toolsUsed(extractToolNames(result.toolExecutions()))
.tokenUsage(result.tokenUsage())
.build();
return ResponseEntity.ok(response);
} catch (Exception e) {
return ResponseEntity.badRequest().body(
ChatResponse.error("Error processing request: " + e.getMessage())
);
}
}
}
interface ToolEnabledAssistant {
Result<String> chat(@MemoryId String userId, String message);
List<ToolInfo> getAvailableTools(String userId);
}
```
## Performance Optimization
### Tool Performance Monitoring
```java
@Component
public class ToolPerformanceMonitor {
@EventListener
public void handleToolExecution(ToolExecutionEvent event) {
// Record execution metrics
Timer.Sample sample = Timer.start(meterRegistry);
sample.stop(Timer.builder("tool.execution.duration")
.tag("tool", event.getToolName())
.tag("success", String.valueOf(event.isSuccessful()))
.register(meterRegistry));
// Record error rates
if (!event.isSuccessful()) {
meterRegistry.counter("tool.execution.errors",
"tool", event.getToolName(),
"error_type", event.getErrorType())
.increment();
}
}
}
```
## Testing Framework
```java
@Component
public class ToolTestingFramework {
public ToolValidationResult validateTool(Object toolInstance, String methodName) {
try {
TestAssistant testAssistant = AiServices.builder(TestAssistant.class)
.chatModel(testChatModel)
.tools(toolInstance)
.build();
String response = testAssistant.testTool(methodName);
return ToolValidationResult.builder()
.toolName(methodName)
.isValid(response != null && !response.contains("Error"))
.response(response)
.build();
} catch (Exception e) {
return ToolValidationResult.builder()
.toolName(methodName)
.isValid(false)
.error(e.getMessage())
.build();
}
}
}
```