Tool Calling & Programmatic Prompts
Tools let the LLM call methods in your application during a conversation — query a database, look up an order, send an email, or any other action you want the assistant to be able to perform. Vaadin supports two ways to expose tools: registered tool objects (covered on this page) and framework-agnostic Controllers.
A third source of tools sits outside the orchestrator: an MCP server, whose tools the AI framework’s own client contributes to each request. See Framework Features.
Tool Calling
Register objects with vendor-specific @Tool annotations that the LLM can invoke:
Source code
Java
public class WeatherTools {
// Spring AI: org.springframework.ai.tool.annotation.Tool
@Tool(description = "Get current weather for a city")
public String getWeather(String city) {
return weatherService.getCurrentWeather(city);
}
}
var orchestrator = AIOrchestrator
.builder(provider, systemPrompt)
.withMessageList(messageList)
.withInput(messageInput)
.withTools(new WeatherTools())
.build();The annotation comes from the framework the provider wraps, and the two spell the description differently. For Spring AI, use @org.springframework.ai.tool.annotation.Tool with a description attribute, as above. For LangChain4j, use @dev.langchain4j.agent.tool.Tool, whose description is the annotation’s value:
Source code
Java
// LangChain4j: dev.langchain4j.agent.tool.Tool
@Tool("Get current weather for a city")
public String getWeather(String city) {
return weatherService.getCurrentWeather(city);
}|
Note
|
Tool Threading
With a streaming provider or background execution, tool methods are invoked off the request thread, where UI.getCurrent() and other Vaadin thread locals are not available. Wrap component access in ui.access(), or capture the needed state before the turn starts.
|
|
Tip
|
Framework-Agnostic Tools via Controllers
For a reusable set of tools that does not depend on a specific LLM framework’s annotations, or when a lifecycle hook is needed after each LLM request cycle, implement AIController instead. GridAIController and ChartAIController are built-in examples. Controllers and tool objects can be combined on the same orchestrator.
|
|
Note
|
Tool Errors
Tool objects registered via withTools() are executed by the vendor framework, whose own error handling decides what the LLM sees when a tool throws — by default, both LangChain4j and Spring AI relay the raw message of any exception. To control what the LLM learns about failures, define the tool through a controller instead and throw a ToolException for messages the LLM is meant to see; see Tool Error Handling.
|
|
Note
|
Tool Call Limits
The tool-calling loop of a turn is bounded: by default, the model may call any single tool at most 40 times and all tools together at most 150 times in one turn. Exceeding a limit fails the turn with a ToolCallLimitExceededException, with either built-in provider. See Tool Call Limits.
|
Programmatic Prompts
Send prompts without a Message Input component using prompt(). This is useful for triggering AI interaction from button clicks or other events:
Programmatic prompts go through the same pipeline as chat submits: a configured request interceptor can change or reject them before anything is sent.
|
Note
|
One Request at a Time
The orchestrator processes one prompt at a time. If prompt() is called while a previous request is still streaming, the new call is logged as a warning and silently dropped. Wait for the current response to complete before sending another prompt.
|
|
Important
|
UI Context Required
prompt() requires an active UI context. If called from a background thread or outside a Vaadin request, it throws an IllegalStateException. Always call prompt() from within a UI event handler or wrap the call in ui.access().
|