Skip to content

Commit 1c0de00

Browse files
committed
code refactoring
1 parent 8106d80 commit 1c0de00

File tree

13 files changed

+226
-102
lines changed

13 files changed

+226
-102
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@
55

66
Reference implementation of [Agentic Patterns](https://javaaidev.com/docs/agentic-patterns/intro/)
77

8-
This reference implementation is designed to be reusable.
8+
This reference implementation is designed to be reusable.
9+
10+
Requirements:
11+
12+
- Java 21
13+
- Spring AI

evaluator-optimizer/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<artifactId>agentic-patterns-evaluator-optimizer</artifactId>
1313
<name>Agentic Patterns :: Evaluator-Optimizer</name>
14+
<description>Evaluator-Optimizer agent</description>
1415

1516
<properties>
1617
<maven.compiler.source>21</maven.compiler.source>

examples/src/main/java/com/javaaidev/agenticpatterns/examples/parallelizationworkflow/AlgorithmArticleGenerationAgent.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.javaaidev.agenticpatterns.examples.parallelizationworkflow.SampleCodeGenerationAgent.SampleCodeGenerationRequest;
77
import com.javaaidev.agenticpatterns.examples.parallelizationworkflow.SampleCodeGenerationAgent.SampleCodeGenerationResponse;
88
import com.javaaidev.agenticpatterns.parallelizationworkflow.PromptBasedAssembling;
9+
import com.javaaidev.agenticpatterns.parallelizationworkflow.SubtaskCreationRequest;
10+
import com.javaaidev.agenticpatterns.parallelizationworkflow.TaskExecutionResults;
911
import io.micrometer.observation.ObservationRegistry;
1012
import java.util.List;
1113
import java.util.Map;
@@ -37,7 +39,7 @@ protected String getPromptTemplate() {
3739
}
3840

3941
@Override
40-
protected @Nullable Map<String, Object> getParentPromptContext(
42+
protected @Nullable Map<String, Object> getRequestPromptContext(
4143
@Nullable AlgorithmArticleGenerationRequest request) {
4244
return Map.of("algorithm",
4345
AgentUtils.safeGet(request, AlgorithmArticleGenerationRequest::algorithm, ""));

parallelization-workflow/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<artifactId>agentic-patterns-parallelization-workflow</artifactId>
1313
<name>Agentic Patterns :: Parallelization Workflow</name>
14+
<description>Parallelization Workflow agent</description>
1415

1516
<properties>
1617
<maven.compiler.source>21</maven.compiler.source>

parallelization-workflow/src/main/java/com/javaaidev/agenticpatterns/parallelizationworkflow/DirectAssembling.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
* A {@linkplain ParallelizationWorkflowAgent} which directly assembles subtask execution results
1010
* without using LLM
1111
*
12-
* @param <Request>
13-
* @param <Response>
12+
* @param <Request> Task input type
13+
* @param <Response> Task output type
1414
*/
1515
public abstract class DirectAssembling<Request, Response> extends
1616
ParallelizationWorkflowAgent<Request, Response> {

parallelization-workflow/src/main/java/com/javaaidev/agenticpatterns/parallelizationworkflow/ParallelizationWorkflowAgent.java

Lines changed: 36 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -7,95 +7,26 @@
77
import java.lang.reflect.Type;
88
import java.time.Duration;
99
import java.util.List;
10-
import java.util.Map;
11-
import java.util.Map.Entry;
12-
import java.util.Objects;
1310
import java.util.concurrent.CopyOnWriteArrayList;
14-
import java.util.concurrent.ExecutionException;
1511
import java.util.concurrent.ExecutorService;
1612
import java.util.concurrent.Executors;
17-
import java.util.concurrent.Future;
18-
import java.util.concurrent.TimeUnit;
19-
import java.util.concurrent.TimeoutException;
2013
import java.util.function.Function;
2114
import java.util.stream.Collectors;
2215
import org.jspecify.annotations.Nullable;
2316
import org.slf4j.Logger;
2417
import org.slf4j.LoggerFactory;
2518
import org.springframework.ai.chat.client.ChatClient;
2619

20+
/**
21+
* Parallelization Workflow agent, refer to <a
22+
* href="https://javaaidev.com/docs/agentic-patterns/patterns/parallelization-workflow">doc</a>
23+
*
24+
* @param <Request>
25+
* @param <Response>
26+
*/
2727
public abstract class ParallelizationWorkflowAgent<Request, Response> extends
2828
TaskExecutionAgent<Request, Response> {
2929

30-
public record SubtaskCreationRequest<Request>(
31-
String taskId,
32-
TaskExecutionAgent<?, ?> task,
33-
Function<Request, ?> requestTransformer
34-
) {
35-
36-
}
37-
38-
public record TaskExecutionContext(
39-
Future<?> job,
40-
Duration maxWaitTime,
41-
@Nullable Object result,
42-
@Nullable Throwable error
43-
) {
44-
45-
public TaskExecutionContext(Future<?> job, Duration maxWaitTime) {
46-
this(job, maxWaitTime, null, null);
47-
}
48-
49-
public TaskExecutionContext collectResult() {
50-
try {
51-
var result = job().get(maxWaitTime().toSeconds(), TimeUnit.SECONDS);
52-
return new TaskExecutionContext(job(), maxWaitTime(), result, null);
53-
} catch (InterruptedException | ExecutionException | TimeoutException e) {
54-
return new TaskExecutionContext(job(), maxWaitTime(), null, job().exceptionNow());
55-
}
56-
}
57-
}
58-
59-
public record SubtaskContext<Request>(
60-
SubtaskCreationRequest<Request> creationRequest,
61-
@Nullable TaskExecutionContext taskExecutionContext
62-
) {
63-
64-
public static <Request, TaskRequest, TaskResponse> SubtaskContext<Request> create(String taskId,
65-
TaskExecutionAgent<TaskRequest, TaskResponse> task,
66-
Function<Request, TaskRequest> requestTransformer) {
67-
return create(new SubtaskCreationRequest<>(taskId, task, requestTransformer));
68-
}
69-
70-
public static <Request> SubtaskContext<Request> create(
71-
SubtaskCreationRequest<Request> creationRequest) {
72-
return new SubtaskContext<>(creationRequest, null);
73-
}
74-
75-
public SubtaskContext<Request> taskStarted(Future<?> job, Duration maxWaitTime) {
76-
return new SubtaskContext<>(this.creationRequest(),
77-
new TaskExecutionContext(job, maxWaitTime));
78-
}
79-
80-
public SubtaskContext<Request> collectResult() {
81-
return new SubtaskContext<>(creationRequest(),
82-
Objects.requireNonNull(taskExecutionContext(), "task execution context cannot be null")
83-
.collectResult());
84-
}
85-
86-
public String taskId() {
87-
return creationRequest().taskId();
88-
}
89-
90-
public @Nullable Object result() {
91-
return taskExecutionContext() != null ? taskExecutionContext().result() : null;
92-
}
93-
94-
public @Nullable Throwable error() {
95-
return taskExecutionContext() != null ? taskExecutionContext().error() : null;
96-
}
97-
}
98-
9930
public ParallelizationWorkflowAgent(ChatClient chatClient,
10031
@Nullable ObservationRegistry observationRegistry) {
10132
super(chatClient, observationRegistry);
@@ -111,40 +42,49 @@ public ParallelizationWorkflowAgent(ChatClient chatClient,
11142

11243
private static final Logger LOGGER = LoggerFactory.getLogger(ParallelizationWorkflowAgent.class);
11344

45+
/**
46+
* Add new subtask
47+
*
48+
* @param taskId Task id
49+
* @param subtask Subtask implemented as {@linkplain TaskExecutionAgent}
50+
* @param requestTransformer Transform request to task's input
51+
* @param <TaskRequest> Task input type
52+
* @param <TaskResponse> Task output type
53+
*/
11454
protected <TaskRequest, TaskResponse> void addSubtask(String taskId,
11555
TaskExecutionAgent<TaskRequest, TaskResponse> subtask,
11656
Function<Request, TaskRequest> requestTransformer) {
11757
subtasks.add(SubtaskContext.create(taskId, subtask, requestTransformer));
11858
}
11959

60+
/**
61+
* Max duration of a subtask execution
62+
*
63+
* @return Max duration
64+
*/
12065
protected Duration getMaxTaskExecutionDuration() {
12166
return Duration.ofMinutes(3);
12267
}
12368

69+
/**
70+
* Create a list of subtasks from request. Subtasks added by
71+
* {@linkplain #addSubtask(String, TaskExecutionAgent, Function)} will be merged into this list.
72+
*
73+
* @param request Request
74+
* @return Subtasks
75+
*/
12476
@Nullable
12577
protected List<SubtaskCreationRequest<Request>> createTasks(@Nullable Request request) {
12678
return List.of();
12779
}
12880

129-
public record PartialResult(@Nullable Object result, @Nullable Throwable error) {
130-
131-
public boolean hasResult() {
132-
return result() != null;
133-
}
134-
135-
public boolean hasError() {
136-
return error() != null;
137-
}
138-
}
139-
140-
public record TaskExecutionResults(Map<String, PartialResult> results) {
141-
142-
public Map<String, Object> allSuccessfulResults() {
143-
return results().entrySet().stream().filter(entry -> entry.getValue().hasResult())
144-
.collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().result()));
145-
}
146-
}
147-
81+
/**
82+
* Create the {@linkplain ExecutorService} to execute subtasks.
83+
* <p>
84+
* The default executor service uses virtual threads.
85+
*
86+
* @return executor service
87+
*/
14888
protected ExecutorService getTaskExecutorService() {
14989
var executor = Executors.newThreadPerTaskExecutor(
15090
Thread.ofVirtual().name("agent-task-", 1).factory());
@@ -170,7 +110,7 @@ protected TaskExecutionResults runSubtasks(@Nullable Request request) {
170110
LOGGER.info("All subtasks completed, assembling the results");
171111
var results = jobs.stream().map(SubtaskContext::collectResult)
172112
.collect(Collectors.toMap(SubtaskContext::taskId,
173-
(task -> new PartialResult(task.result(), task.error())), (a, b) -> b));
113+
(task -> new SubtaskResult(task.result(), task.error())), (a, b) -> b));
174114
return new TaskExecutionResults(results);
175115
}
176116
}

parallelization-workflow/src/main/java/com/javaaidev/agenticpatterns/parallelizationworkflow/PromptBasedAssembling.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
import org.jspecify.annotations.Nullable;
88
import org.springframework.ai.chat.client.ChatClient;
99

10+
/**
11+
* A {@linkplain ParallelizationWorkflowAgent} which uses an LLM to generate the final result using
12+
* results from subtasks
13+
*
14+
* @param <Request> Task input type
15+
* @param <Response> Task output type
16+
*/
1017
public abstract class PromptBasedAssembling<Request, Response> extends
1118
ParallelizationWorkflowAgent<Request, Response> {
1219

@@ -21,16 +28,28 @@ public PromptBasedAssembling(ChatClient chatClient,
2128
super(chatClient, responseType, observationRegistry);
2229
}
2330

31+
/**
32+
* Get values for prompt template variables from results of subtasks
33+
*
34+
* @param results Subtask execution results
35+
* @ Values of template variables
36+
*/
2437
protected abstract @Nullable Map<String, Object> getSubtasksPromptContext(
2538
TaskExecutionResults results);
2639

27-
protected @Nullable Map<String, Object> getParentPromptContext(@Nullable Request request) {
40+
/**
41+
* Get values for prompt template variables from request
42+
*
43+
* @param request Request
44+
* @return Values of template variables
45+
*/
46+
protected @Nullable Map<String, Object> getRequestPromptContext(@Nullable Request request) {
2847
return Map.of();
2948
}
3049

3150
@Override
3251
protected @Nullable Map<String, Object> getPromptContext(@Nullable Request request) {
33-
return AgentUtils.mergeMap(getParentPromptContext(request),
52+
return AgentUtils.mergeMap(getRequestPromptContext(request),
3453
getSubtasksPromptContext(runSubtasks(request)));
3554
}
3655

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.javaaidev.agenticpatterns.parallelizationworkflow;
2+
3+
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
4+
import java.time.Duration;
5+
import java.util.Objects;
6+
import java.util.concurrent.Future;
7+
import java.util.function.Function;
8+
import org.jspecify.annotations.Nullable;
9+
10+
/**
11+
* Subtask context for management
12+
*
13+
* @param creationRequest Subtask creation request
14+
* @param executionContext Subtask execution context
15+
* @param <Request> Request type
16+
*/
17+
public record SubtaskContext<Request>(
18+
SubtaskCreationRequest<Request> creationRequest,
19+
@Nullable SubtaskExecutionContext executionContext
20+
) {
21+
22+
public static <Request, TaskRequest, TaskResponse> SubtaskContext<Request> create(String taskId,
23+
TaskExecutionAgent<TaskRequest, TaskResponse> task,
24+
Function<Request, TaskRequest> requestTransformer) {
25+
return create(new SubtaskCreationRequest<>(taskId, task, requestTransformer));
26+
}
27+
28+
public static <Request> SubtaskContext<Request> create(
29+
SubtaskCreationRequest<Request> creationRequest) {
30+
return new SubtaskContext<>(creationRequest, null);
31+
}
32+
33+
public SubtaskContext<Request> taskStarted(Future<?> job, Duration maxWaitTime) {
34+
return new SubtaskContext<>(this.creationRequest(),
35+
new SubtaskExecutionContext(job, maxWaitTime));
36+
}
37+
38+
public SubtaskContext<Request> collectResult() {
39+
return new SubtaskContext<>(creationRequest(),
40+
Objects.requireNonNull(executionContext(), "task execution context cannot be null")
41+
.collectResult());
42+
}
43+
44+
public String taskId() {
45+
return creationRequest().taskId();
46+
}
47+
48+
public @Nullable Object result() {
49+
return executionContext() != null ? executionContext().result() : null;
50+
}
51+
52+
public @Nullable Throwable error() {
53+
return executionContext() != null ? executionContext().error() : null;
54+
}
55+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.javaaidev.agenticpatterns.parallelizationworkflow;
2+
3+
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
4+
import java.util.function.Function;
5+
6+
/**
7+
* Request to create a subtask
8+
*
9+
* @param taskId Task id
10+
* @param task Task, see {@linkplain TaskExecutionAgent}
11+
* @param requestTransformer Transform request to task inpu
12+
* @param <Request> Request type
13+
*/
14+
public record SubtaskCreationRequest<Request>(
15+
String taskId,
16+
TaskExecutionAgent<?, ?> task,
17+
Function<Request, ?> requestTransformer
18+
) {
19+
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.javaaidev.agenticpatterns.parallelizationworkflow;
2+
3+
import java.time.Duration;
4+
import java.util.concurrent.ExecutionException;
5+
import java.util.concurrent.Future;
6+
import java.util.concurrent.TimeUnit;
7+
import java.util.concurrent.TimeoutException;
8+
import org.jspecify.annotations.Nullable;
9+
10+
/**
11+
* Task execution context
12+
*
13+
* @param job Job
14+
* @param maxWaitTime Max wait time for the task to finish
15+
* @param result Successful result
16+
* @param error error
17+
*/
18+
public record SubtaskExecutionContext(
19+
Future<?> job,
20+
Duration maxWaitTime,
21+
@Nullable Object result,
22+
@Nullable Throwable error
23+
) {
24+
25+
public SubtaskExecutionContext(Future<?> job, Duration maxWaitTime) {
26+
this(job, maxWaitTime, null, null);
27+
}
28+
29+
public SubtaskExecutionContext collectResult() {
30+
try {
31+
var result = job().get(maxWaitTime().toSeconds(), TimeUnit.SECONDS);
32+
return new SubtaskExecutionContext(job(), maxWaitTime(), result, null);
33+
} catch (InterruptedException | ExecutionException | TimeoutException e) {
34+
return new SubtaskExecutionContext(job(), maxWaitTime(), null, job().exceptionNow());
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)