diff --git a/docs-java/tutorials/agentic-workflows.mdx b/docs-java/tutorials/agentic-workflows.mdx new file mode 100644 index 000000000..9a10a0834 --- /dev/null +++ b/docs-java/tutorials/agentic-workflows.mdx @@ -0,0 +1,230 @@ +--- +id: agentic-workflows +title: Getting Started with Agentic Workflows +hide_title: false +hide_table_of_contents: false +description: A tutorial on how to build agentic workflows using the SAP AI SDK. +keywords: + - sap + - ai + - sdk + - cloud + - orchestration + - agentic +--- + +## 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](https://spring.io/blog/2025/01/21/spring-ai-agentic-patterns). +Our examples follow some of the ideas outlined there and throughout this tutorial we will use terms introduced in this article. + +:::info +An example implementation of this tutorial can be found in [our Spring Boot application](https://github.com/SAP/ai-sdk-java/tree/main/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/SpringAiAgenticWorkflowService.java). +::: + +## 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](https://spring.io/blog/2025/01/21/spring-ai-agentic-patterns) are assumed. + +For technical prerequisites please refer to our [general requirements](../overview-cloud-sdk-for-ai-java#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](../spring-ai/orchestration#tool-calling). + +The first tool will return (pre-defined) restaurant suggestion for a provided city. + +```java +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 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. + +```java +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. + +```java +@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](../spring-ai/orchestration#chat-memory). + +## 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. + +```java +@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 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. + +```java +@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. diff --git a/sidebarsDocsJava.js b/sidebarsDocsJava.js index 8f01d35ac..8ff195e7c 100644 --- a/sidebarsDocsJava.js +++ b/sidebarsDocsJava.js @@ -36,6 +36,11 @@ module.exports = { 'ai-core/prompt-registry' ] }, + { + type: 'category', + label: 'Tutorials', + items: ['tutorials/agentic-workflows'] + }, 'release-notes', 'frequently-asked-questions', { diff --git a/styles/config/vocabularies/SAP/accept.txt b/styles/config/vocabularies/SAP/accept.txt index 55a96e9e4..0201693f7 100644 --- a/styles/config/vocabularies/SAP/accept.txt +++ b/styles/config/vocabularies/SAP/accept.txt @@ -149,4 +149,5 @@ pseudonymization LLM LLMs AIMessage -[Oo]penai +[Aa]gentic +[Oo]penai \ No newline at end of file