9.3 KiB
9.3 KiB
LangChain4j Tool & Function Calling - API References
Complete API reference for tool and function calling with LangChain4j.
Tool Definition
@Tool Annotation
Purpose: Mark methods that LLM can call.
@Tool(value = "Description of what this tool does")
ReturnType methodName(ParameterType param) {
// Implementation
}
// Examples
@Tool("Add two numbers together")
int add(int a, int b) { return a + b; }
@Tool("Query database for user information")
User getUserById(String userId) { ... }
@Tool("Send email to recipient")
void sendEmail(String to, String subject, String body) { ... }
@P Annotation
Purpose: Describe tool parameters for LLM understanding.
@Tool("Transfer money between accounts")
void transfer(
@P("source account ID") String fromAccount,
@P("destination account ID") String toAccount,
@P("amount in dollars") double amount
) { ... }
Builder Configuration
AiServices Builder Extensions for Tools
AiServices.builder(AssistantInterface.class)
// Register tool objects
.tools(Object... tools) // Multiple tool objects
.tools(new Calculator()) // Single tool
.tools(new Calculator(), new DataService()) // Multiple
// Dynamic tool provider
.toolProvider(ToolProvider toolProvider)
// Error handlers
.toolExecutionErrorHandler(ToolExecutionErrorHandler)
.toolArgumentsErrorHandler(ToolArgumentsErrorHandler)
.build();
Error Handlers
ToolExecutionErrorHandler
Purpose: Handle errors during tool execution.
@FunctionalInterface
interface ToolExecutionErrorHandler {
String handle(ToolExecutionRequest request, Throwable exception);
}
// Usage
.toolExecutionErrorHandler((request, exception) -> {
logger.error("Tool " + request.name() + " failed", exception);
return "Error executing " + request.name() + ": " + exception.getMessage();
})
ToolArgumentsErrorHandler
Purpose: Handle errors in tool argument parsing/validation.
@FunctionalInterface
interface ToolArgumentsErrorHandler {
String handle(ToolExecutionRequest request, Throwable exception);
}
// Usage
.toolArgumentsErrorHandler((request, exception) -> {
logger.warn("Invalid arguments for " + request.name());
return "Invalid arguments provided";
})
Tool Provider
ToolProvider Interface
Purpose: Dynamically select tools based on context.
@FunctionalInterface
interface ToolProvider {
List<Object> getTools(ToolProviderContext context);
}
// Context available
interface ToolProviderContext {
UserMessage userMessage();
List<ChatMessage> messages();
}
Dynamic Tool Selection
.toolProvider(context -> {
String message = context.userMessage().singleText();
if (message.contains("calculate")) {
return Arrays.asList(new Calculator());
} else if (message.contains("weather")) {
return Arrays.asList(new WeatherService());
} else {
return Collections.emptyList();
}
})
Tool Execution Models
ToolExecutionRequest
interface ToolExecutionRequest {
String name(); // Tool name from @Tool
String description(); // Tool description
Map<String, String> arguments(); // Tool arguments
}
ToolExecution (for streaming)
class ToolExecution {
ToolExecutionRequest request(); // The tool being executed
String result(); // Execution result
}
Return Types
Supported Return Types
Primitives:
@Tool("Add numbers")
int add(@P("a") int x, @P("b") int y) { return x + y; }
@Tool("Compare values")
boolean isGreater(@P("a") int x, @P("b") int y) { return x > y; }
@Tool("Get temperature")
double getTemp() { return 22.5; }
String:
@Tool("Get greeting")
String greet(@P("name") String name) { return "Hello " + name; }
Objects (will be converted to String):
@Tool("Get user")
User getUser(@P("id") String id) { return new User(id); }
@Tool("Get user list")
List<User> listUsers() { return userService.getAll(); }
Collections:
@Tool("Search documents")
List<Document> search(@P("query") String q) { return results; }
@Tool("Get key-value pairs")
Map<String, String> getConfig() { return config; }
Void:
@Tool("Send notification")
void notify(@P("message") String msg) {
notificationService.send(msg);
}
Parameter Types
Supported Parameter Types
Primitives:
int, long, float, double, boolean, byte, short, char
Strings and wrapper types:
String, Integer, Long, Float, Double, Boolean
Collections:
List<String>, Set<Integer>, Collection<T>
Custom objects (must have toString() that's meaningful):
@Tool("Process data")
void process(CustomData data) { ... }
Dates and times:
@Tool("Get events for date")
List<Event> getEvents(LocalDate date) { ... }
@Tool("Schedule for time")
void schedule(LocalDateTime when) { ... }
Annotation Combinations
Complete Tool Definition
class DataService {
// Basic tool
@Tool("Get user information")
User getUser(@P("user ID") String userId) { ... }
// Tool with multiple params
@Tool("Search users by criteria")
List<User> search(
@P("first name") String firstName,
@P("last name") String lastName,
@P("department") String dept
) { ... }
// Tool returning collection
@Tool("List all active users")
List<User> getActiveUsers() { ... }
// Tool with void return
@Tool("Archive old records")
void archiveOldRecords(@P("older than days") int days) { ... }
// Tool with complex return
@Tool("Get detailed report")
Map<String, Object> generateReport(@P("month") int month) { ... }
}
Best Practices for API Usage
Tool Design
- Descriptive Names: Use clear, actionable names
// Good
@Tool("Get current weather for a city")
String getWeather(String city) { ... }
// Avoid
@Tool("Get info")
String getInfo(String x) { ... }
- Parameter Descriptions: Be specific about formats
// Good
@Tool("Calculate date difference")
long daysBetween(
@P("start date in YYYY-MM-DD format") String start,
@P("end date in YYYY-MM-DD format") String end
) { ... }
// Avoid
@Tool("Calculate difference")
long calculate(@P("date1") String d1, @P("date2") String d2) { ... }
- Appropriate Return Types: Return what LLM can use
// Good - LLM can interpret
@Tool("Get user role")
String getUserRole(String userId) { return "admin"; }
// Avoid - hard to parse
@Tool("Get user info")
User getUser(String id) { ... } // Will convert to toString()
- Error Messages: Provide actionable errors
.toolExecutionErrorHandler((request, exception) -> {
if (exception instanceof IllegalArgumentException) {
return "Invalid argument: " + exception.getMessage();
}
return "Error executing " + request.name();
})
Common Patterns
Validation Pattern:
@Tool("Create user")
String createUser(@P("email") String email) {
if (!email.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
return "User created: " + email;
}
Batch Pattern:
@Tool("Bulk delete users")
String deleteUsers(@P("user IDs comma-separated") String userIds) {
List<String> ids = Arrays.asList(userIds.split(","));
return "Deleted " + ids.size() + " users";
}
Async Pattern (synchronous wrapper):
@Tool("Submit async task")
String submitTask(@P("task name") String name) {
// Internally async, but returns immediately
taskExecutor.submitAsync(name);
return "Task " + name + " submitted";
}
Integration with AiServices
Complete Setup
interface Assistant {
String execute(String command);
}
public class Setup {
public static void main(String[] args) {
var chatModel = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.temperature(0.0) // Deterministic
.build();
var assistant = AiServices.builder(Assistant.class)
.chatModel(chatModel)
// Register tools
.tools(
new Calculator(),
new WeatherService(),
new UserDataService()
)
// Error handling
.toolExecutionErrorHandler((request, exception) -> {
System.err.println("Tool error: " + exception.getMessage());
return "Tool failed";
})
// Optional: memory for context
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
// Use the assistant
String result = assistant.execute("What is the weather in Paris?");
System.out.println(result);
}
}