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.
Install with Tessl CLI
npx tessl i github:giuseppe-trisciuoglio/developer-kit --skill langchain4j-tool-function-calling-patternsOverall
score
74%
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
Define tools and enable AI agents to interact with external systems, APIs, and services using LangChain4j's annotation-based and programmatic tool system.
Use this skill when:
// 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();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();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 + "!";
}
}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);
}
}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);
}
}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);
}
}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();
}
}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);
}
}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();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);
});
}
}@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();
}
}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();executeToolsConcurrently() for independent toolsFor detailed API reference, examples, and advanced patterns, see:
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");
})Problem: Tools receive invalid parameters
Solution: Add input validation and error handlers:
.toolArgumentsErrorHandler((error, context) -> {
return ToolErrorHandlerResult.text("Invalid arguments: " + error.getMessage());
})Problem: Tools are slow or timeout
Solution: Use concurrent execution and resilience patterns:
.executeToolsConcurrently(Executors.newFixedThreadPool(5))
.toolExecutionTimeout(Duration.ofSeconds(30))langchain4j-ai-services-patternslangchain4j-rag-implementation-patternslangchain4j-spring-boot-integrationIf you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.