Getting Started with Agentic Workflows
Introduction
In this tutorial we will build a simple agentic travel assistant using the SAP AI SDK and its SpringAI integration. The agent will create a short itinerary for a one-day trip to a specified city. In order to do that, it will collect weather information as well as restaurant recommendations through tool usage and combine the collected information using chat memory.
The agent will perform the following steps in a chain-like structure:
- Accept a travel request by the user.
- Use a custom tool to recommend restaurants for the requested city.
- Use a custom tool to get the current weather for the requested city.
- Combine the collected information into a short itinerary using chat memory and return it to the user.
For further reading on this topic, we recommend the Spring article Building Effective Agents with SpringAI. Our examples follow some of the ideas outlined there and throughout this tutorial we will use terms introduced in this article.
An example implementation of this tutorial can be found in our Spring Boot application.
Prerequisites
This tutorial requires basic knowledge of Java, the SAP AI SDK, and Spring. Also, a basic understanding of concepts regarding LLMs and the above mentioned article on building agents with SpringAI are assumed.
For technical prerequisites please refer to our general requirements.
Create Mock Tools
We first create two mock tools. For more information on tool usage, we refer to the respective chapter in our documentation.
The first tool will return (pre-defined) restaurant suggestion for a provided city.
class RestaurantMethod {
/**
* Request for list of restaurants
*
* @param location the city
*/
record Request(String location) {}
/**
* Response for restaurant recommendations
*
* @param restaurants the list of restaurants
*/
record Response(List<String> restaurants) {}
@Nonnull
@Tool(description = "Get recommended restaurants for a location")
static RestaurantMethod.Response getRestaurants(
@ToolParam @Nonnull final RestaurantMethod.Request request) {
var recommendations =
Map.of(
"paris",
List.of("Le Comptoir du Relais", "L'As du Fallafel", "Breizh Café"),
"reykjavik",
List.of("Dill Restaurant", "Fish Market", "Grillmarkaðurinn"));
return new RestaurantMethod.Response(
recommendations.getOrDefault(
request.location.toLowerCase(Locale.ROOT), List.of("No recommendations for this city.")));
}
}
The second tool will return a (fake) weather forecast for a given city.
class WeatherMethod {
/** Unit of temperature */
enum Unit {
/** Celsius */
C,
/** Fahrenheit */
F
}
/**
* Request for the weather
*
* @param location the city
* @param unit the unit of temperature
*/
record Request(String location, Unit unit) {}
/**
* Response for the weather
*
* @param temp the temperature
* @param unit the unit of temperature
*/
record Response(double temp, Unit unit) {}
@Nonnull
@Tool(description = "Get the weather in location")
static Response getCurrentWeather(@ToolParam @Nonnull final Request request) {
final int temperature = request.location.hashCode() % 30;
return new Response(temperature, request.unit);
}
}
Set up the Agent
We are now ready to create our agent.
For this, we start by configuring the chat memory and adding the tools from above.
Note that in order to integrate this into a Spring app, we create the class as a Spring service.
The agentic workflows will be triggered when calling the runAgent()
method with the user input.
@Service
public class SpringAiAgenticWorkflowService {
private final ChatModel client = new OrchestrationChatModel();
private final OrchestrationModuleConfig config =
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);
public ChatResponse runAgent(String userInput) {
// Configure chat memory
var memory = new InMemoryChatMemory();
var advisor = new MessageChatMemoryAdvisor(memory);
var cl = ChatClient.builder(client).defaultAdvisors(advisor).build();
// Add (mocked) tools
var options = new OrchestrationChatOptions(config);
options.setToolCallbacks(
List.of(ToolCallbacks.from(new WeatherMethod(), new RestaurantMethod())));
options.setInternalToolExecutionEnabled(true);
// The actual agentic workflow will be added here.
return null;
}
}
For more information on how to use chat memory, we refer to the respective chapter in our documentation.
Implementing the Agentic Workflow
Next, we implement the actual agentic workflow by adapting the class introduced above. To keep it simple in the beginning, we start with a chain-like workflow. For this, we first define the system prompts that we will use in the call to the LLM and then loop over them, each time using the output from the previous call as input for the next.
@Service
public class SpringAiAgenticWorkflowService {
private final ChatModel client = new OrchestrationChatModel();
private final OrchestrationModuleConfig config =
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);
@Nonnull
public String runAgent(String userInput) {
// Configure chat memory
val repository = new InMemoryChatMemoryRepository();
val memory = MessageWindowChatMemory.builder().chatMemoryRepository(repository).build();
val advisor = MessageChatMemoryAdvisor.builder(memory).build();
var cl = ChatClient.builder(client).defaultAdvisors(advisor).build();
// Add (mocked) tools
var options = new OrchestrationChatOptions(config);
options.setToolCallbacks(
List.of(ToolCallbacks.from(new WeatherMethod(), new RestaurantMethod())));
options.setInternalToolExecutionEnabled(true);
// Prompts for the chain workflow
List<String> systemPrompts =
List.of(
"You are a traveling planning agent for a single day trip. Where appropriate, use the provided tools. First, start by suggesting some restaurants for the mentioned city.",
"Now, check the whether for the city.",
"Finally, combine the suggested itinerary from this conversation into a short, one-sentence plan for the day trip.");
// Perform the chain workflow
String responseText = userInput;
for (String systemPrompt : systemPrompts) {
// Combine the pre-defined prompt with the previous answer to get the new input
String input = String.format("{%s}\n {%s}", systemPrompt, responseText);
var prompt = new Prompt(input, options);
// Make a call to the LLM with the new input
var response =
Objects.requireNonNull(
cl.prompt(prompt).call().chatResponse(), "Chat response is null.");
responseText = response.getResult().getOutput().getText();
}
return responseText;
}
}
Running the Agentic Workflow
We can now run our agentic workflow by calling the runAgent()
method with some user input.
@Autowired
private SpringAiAgenticWorkflowService service;
String runChainWorkflow() {
final var response = service.runAgent("I want to do a one-day trip to Paris. Help me make an itinerary, please");
return response;
}
Conclusion
This tutorial showed how to build a simple, chain-like agentic workflow using the SAP AI SDK's SpringAI integration.