跳到主要内容

Chain Workflow

To use this agent, add the Maven dependency to your project, replacing ${agentic-patterns.version} with the latest version.

Latest version: Maven Central Version

<dependency>
<groupId>com.javaaidev.agenticpatterns</groupId>
<artifactId>chain-workflow</artifactId>
<version>${agentic-patterns.version}</version>
</dependency>

See Javadoc here: javadoc

ChainWorkflow

A ChainWorkflow has multiple steps. Each step is a ChainStep.

ChainStep

ChainStep extends the Spring Ordered interface. This order determines its position in the chain. A ChainStep must implement the call method. In the call method, a ChainStep can return the task output directly, or use the callNext method of WorkflowChain to call the next ChainStep in the chain.

The call method has a parameter context of type Map<String, Object>. This Map can be used to share data between different steps.

ChainStepAgent

ChainStepAgent is an implementation of ChainStep and a subclass of TaskExecutionAgent.

Example

The example is an agent to write an article about a topic. It first uses an agent to generate the initial content, then it uses a chain workflow to improve the content from different aspects.

articleGenerationAgent is a simple TaskExecutionAgent to generate content by given topic.

articleImprovementWorkflow is a ChainWorkflow to improve content using multiple steps. It has three steps. Each step is a ChainStepAgent. Each step calls the next step using the improved content.

articleWritingWorkflow is a custom AgenticWorkflow. In its action, it uses articleGenerationAgent to generate the initial article, then uses articleImprovementWorkflow to improve the quality of article content.

Article writing workflow configuration
package com.javaaidev.agenticpatterns.examples.chainworkflow;

import com.javaaidev.agenticpatterns.chainworkflow.ChainStepAgent;
import com.javaaidev.agenticpatterns.chainworkflow.ChainWorkflow;
import com.javaaidev.agenticpatterns.core.AgentUtils;
import com.javaaidev.agenticpatterns.core.AgenticWorkflow;
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
import io.micrometer.observation.ObservationRegistry;
import java.util.List;
import java.util.Map;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ArticleWritingConfiguration {

@Bean
@Qualifier("articleWritingWorkflow")
public AgenticWorkflow<ArticleWritingRequest, ArticleWritingResponse> articleWritingWorkflow(
ObservationRegistry observationRegistry,
@Qualifier("articleGenerationAgent") TaskExecutionAgent<ArticleWritingRequest, ArticleWritingResponse> articleGenerationAgent,
@Qualifier("articleImprovementWorkflow") ChainWorkflow<ArticleImprovementRequest, ArticleImprovementResponse> articleImprovementWorkflow
) {
return AgenticWorkflow.<ArticleWritingRequest, ArticleWritingResponse>custom()
.name("ArticleWritingWorkflow")
.observationRegistry(observationRegistry)
.action(request -> {
var initialArticle = articleGenerationAgent.call(request);
var improved = articleImprovementWorkflow.execute(
new ArticleImprovementRequest(initialArticle.article()));
return new ArticleWritingResponse(improved.article());
})
.build();
}

@Bean
@Qualifier("articleGenerationAgent")
public TaskExecutionAgent<ArticleWritingRequest, ArticleWritingResponse> articleGenerationAgent(
ChatClient.Builder chatClientBuilder,
SimpleLoggerAdvisor simpleLoggerAdvisor,
ObservationRegistry observationRegistry) {
var chatClient = chatClientBuilder.defaultAdvisors(simpleLoggerAdvisor).build();
return TaskExecutionAgent.<ArticleWritingRequest, ArticleWritingResponse>defaultBuilder()
.name("ArticleGeneration")
.chatClient(chatClient)
.responseType(ArticleWritingResponse.class)
.observationRegistry(observationRegistry)
.promptTemplate("Write an article about {topic}")
.build();
}

@Bean
@Qualifier("articleImprovementWorkflow")
public ChainWorkflow<ArticleImprovementRequest, ArticleImprovementResponse> articleImprovementWorkflow(
ChatClient.Builder chatClientBuilder,
SimpleLoggerAdvisor simpleLoggerAdvisor,
ObservationRegistry observationRegistry) {
var chatClient = chatClientBuilder.defaultAdvisors(simpleLoggerAdvisor).build();
var instructions = List.of(
"""
Review the Structure
- Ensure the article has a clear introduction, body, and conclusion.
- Check if ideas flow logically from one section to another.
- Ensure paragraphs are well-organized and each one has a clear purpose.
""",
"""
Improve Clarity and Conciseness
- Remove unnecessary words and redundant phrases.
- Simplify complex sentences for better readability.
- Use active voice where possible.
""",
"""
Enhance Readability
- Break long paragraphs into shorter ones.
- Use bullet points or subheadings for easier scanning.
- Vary sentence length to maintain reader interest.
"""
);

var builder = ChainWorkflow.<ArticleImprovementRequest, ArticleImprovementResponse>builder();
for (int i = 0; i < instructions.size(); i++) {
var instruction = instructions.get(i);
builder.addStepAgent(
ChainStepAgent.<ArticleImprovementRequest, ArticleImprovementResponse>builder()
.name("ArticleImprovement#" + i)
.chatClient(chatClient)
.responseType(ArticleImprovementResponse.class)
.nextRequestPreparer(response -> new ArticleImprovementRequest(response.article()))
.promptTemplate("""
Goal: Improve an article by following the instruction:

{instruction}

Article content:
{article}
""")
.promptTemplateContextProvider(request -> Map.of(
"instruction", instruction,
"article",
AgentUtils.safeGet(request, ArticleImprovementRequest::article, "")
))
.order(100 + i)
.observationRegistry(observationRegistry)
.build());
}
return builder
.name("ArticleWritingWorkflow")
.observationRegistry(observationRegistry)
.build();
}
}