Claude-skill-registry langchain4j-tool-function-calling-patterns
Tool and function calling patterns with LangChain4j. Define tools, handle function calls, and integrate with LLM agents. Use when building agentic applications that interact with tools.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/langchain4j-tool-function-calling-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-langchain4j-tool-function-calling-patterns && rm -rf "$T"
skills/data/langchain4j-tool-function-calling-patterns/SKILL.mdLangChain4j Tool & Function Calling Patterns
Define tools and enable AI agents to interact with external systems, APIs, and services using LangChain4j's annotation-based and programmatic tool system.
When to Use This Skill
Use this skill when:
- Building AI applications that need to interact with external APIs and services
- Creating AI assistants that can perform actions beyond text generation
- Implementing AI systems that need access to real-time data (weather, stocks, etc.)
- Building multi-agent systems where agents can use specialized tools
- Creating AI applications with database read/write capabilities
- Implementing AI systems that need to integrate with existing business systems
- Building context-aware AI applications where tool availability depends on user state
- Developing production AI applications that require robust error handling and monitoring
Setup and Configuration
Basic Tool Registration
// Define tools using @Tool annotation public class CalculatorTools { @Tool("Add two numbers") public double add(double a, double b) { return a + b; } } // Register with AiServices builder interface MathAssistant { String ask(String question); } MathAssistant assistant = AiServices.builder(MathAssistant.class) .chatModel(chatModel) .tools(new CalculatorTools()) .build();
Builder Configuration Options
AiServices.builder(AssistantInterface.class) // Static tool registration .tools(new Calculator(), new WeatherService()) // Dynamic tool provider .toolProvider(new DynamicToolProvider()) // Concurrent execution .executeToolsConcurrently() // Error handling .toolExecutionErrorHandler((request, exception) -> { return "Error: " + exception.getMessage(); }) // Memory for context .chatMemoryProvider(userId -> MessageWindowChatMemory.withMaxMessages(20)) .build();
Core Patterns
Basic Tool Definition
Use
@Tool annotation to define methods as executable tools:
public class BasicTools { @Tool("Add two numbers") public int add(@P("first number") int a, @P("second number") int b) { return a + b; } @Tool("Get greeting") public String greet(@P("name to greet") String name) { return "Hello, " + name + "!"; } }
Parameter Descriptions and Validation
Provide clear parameter descriptions using
@P annotation:
public class WeatherService { @Tool("Get current weather conditions") public String getCurrentWeather( @P("City name or coordinates") String location, @P("Temperature unit (celsius, fahrenheit)", required = false) String unit) { // Implementation with validation if (location == null || location.trim().isEmpty()) { return "Location is required"; } return weatherClient.getCurrentWeather(location, unit); } }
Complex Parameter Types
Use Java records and descriptions for complex objects:
public class OrderService { @Description("Customer order information") public record OrderRequest( @Description("Customer ID") String customerId, @Description("List of items") List<OrderItem> items, @JsonProperty(required = false) @Description("Delivery instructions") String instructions ) {} @Tool("Create customer order") public String createOrder(OrderRequest order) { return orderService.processOrder(order); } }
Advanced Features
Memory Context Integration
Access user context using
@ToolMemoryId:
public class PersonalizedTools { @Tool("Get user preferences") public String getPreferences( @ToolMemoryId String userId, @P("Preference category") String category) { return preferenceService.getPreferences(userId, category); } }
Dynamic Tool Provisioning
Create tools that change based on context:
public class ContextAwareToolProvider implements ToolProvider { @Override public ToolProviderResult provideTools(ToolProviderRequest request) { String message = request.userMessage().singleText().toLowerCase(); var builder = ToolProviderResult.builder(); if (message.contains("weather")) { builder.add(weatherToolSpec, weatherExecutor); } if (message.contains("calculate")) { builder.add(calcToolSpec, calcExecutor); } return builder.build(); } }
Immediate Return Tools
Return results immediately without full AI response:
public class QuickTools { @Tool(value = "Get current time", returnBehavior = ReturnBehavior.IMMEDIATE) public String getCurrentTime() { return LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } }
Error Handling
Tool Error Handling
Handle tool execution errors gracefully:
AiServices.builder(Assistant.class) .chatModel(chatModel) .tools(new ExternalServiceTools()) .toolExecutionErrorHandler((request, exception) -> { if (exception instanceof ApiException) { return "Service temporarily unavailable: " + exception.getMessage(); } return "An error occurred while processing your request"; }) .build();
Resilience Patterns
Implement circuit breakers and retries:
public class ResilientService { private final CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("external-api"); @Tool("Get external data") public String getExternalData(@P("Data identifier") String id) { return circuitBreaker.executeSupplier(() -> { return externalApi.getData(id); }); } }
Integration Examples
Multi-Domain Tool Service
@Service public class MultiDomainToolService { public String processRequest(String userId, String request, String domain) { String contextualRequest = String.format("[Domain: %s] %s", domain, request); Result<String> result = assistant.chat(userId, contextualRequest); // Log tool usage result.toolExecutions().forEach(execution -> analyticsService.recordToolUsage(userId, domain, execution.request().name())); return result.content(); } }
Streaming with Tool Execution
interface StreamingAssistant { TokenStream chat(String message); } StreamingAssistant assistant = AiServices.builder(StreamingAssistant.class) .streamingChatModel(streamingChatModel) .tools(new Tools()) .build(); TokenStream stream = assistant.chat("What's the weather and calculate 15*8?"); stream .onToolExecuted(execution -> System.out.println("Executed: " + execution.request().name())) .onPartialResponse(System.out::print) .onComplete(response -> System.out.println("Complete!")) .start();
Best Practices
Tool Design Guidelines
- Descriptive Names: Use clear, actionable tool names
- Parameter Validation: Validate inputs before processing
- Error Messages: Provide meaningful error messages
- Return Types: Use appropriate return types that LLMs can understand
- Performance: Avoid blocking operations in tools
Security Considerations
- Permission Checks: Validate user permissions before tool execution
- Input Sanitization: Sanitize all tool inputs
- Audit Logging: Log tool usage for security monitoring
- Rate Limiting: Implement rate limiting for external APIs
Performance Optimization
- Concurrent Execution: Use
for independent toolsexecuteToolsConcurrently() - Caching: Cache frequently accessed data
- Monitoring: Monitor tool performance and error rates
- Resource Management: Handle external service timeouts gracefully
Reference Documentation
For detailed API reference, examples, and advanced patterns, see:
- API Reference - Complete API documentation
- Implementation Patterns - Advanced implementation examples
- Examples - Practical usage examples
Common Issues and Solutions
Tool Not Found
Problem: LLM calls tools that don't exist
Solution: Implement hallucination handler:
.hallucinatedToolNameStrategy(request -> { return ToolExecutionResultMessage.from(request, "Error: Tool '" + request.name() + "' does not exist"); })
Parameter Validation Errors
Problem: Tools receive invalid parameters
Solution: Add input validation and error handlers:
.toolArgumentsErrorHandler((error, context) -> { return ToolErrorHandlerResult.text("Invalid arguments: " + error.getMessage()); })
Performance Issues
Problem: Tools are slow or timeout
Solution: Use concurrent execution and resilience patterns:
.executeToolsConcurrently(Executors.newFixedThreadPool(5)) .toolExecutionTimeout(Duration.ofSeconds(30))
Related Skills
langchain4j-ai-services-patternslangchain4j-rag-implementation-patternslangchain4j-spring-boot-integration