|
2 | 2 |
|
3 | 3 | # Sequential workflow |
4 | 4 | ### Common part: |
| 5 | +<details><summary>Click to expand</summary> |
| 6 | + |
5 | 7 | ```java |
6 | 8 | public interface AudienceEditor { |
7 | 9 |
|
@@ -65,33 +67,53 @@ Map<String, Object> input = Map.of( |
65 | 67 | "audience", "young adults" |
66 | 68 | ); |
67 | 69 | ``` |
68 | | - |
69 | | -### LangChain4j |
70 | | -```java |
71 | | -UntypedAgent novelCreator = AgenticServices |
72 | | - .sequenceBuilder() |
73 | | - .subAgents(creativeWriter, audienceEditor, styleEditor) |
74 | | - .outputName("story") |
75 | | - .build(); |
| 70 | +</details> |
| 71 | + |
| 72 | +<table style="table-layout:fixed; width:100%;"> |
| 73 | + <tr> |
| 74 | + <th style="width:50%; text-align:left;">LangChain4j</th> |
| 75 | + <th style="text-align:left;">Serverless Workflow</th> |
| 76 | + </tr> |
| 77 | + <tr> |
| 78 | + <td style="vertical-align:top;"> |
| 79 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 80 | +<code class="language-java" style="background:none;white-space:pre;">UntypedAgent novelCreator = AgenticServices |
| 81 | + .sequenceBuilder() |
| 82 | + .subAgents(creativeWriter, audienceEditor, styleEditor) |
| 83 | + .outputName("story") |
| 84 | + .build(); |
76 | 85 |
|
77 | 86 | String story = (String) novelCreator.invoke(input); |
78 | | -``` |
79 | 87 |
|
80 | | -### Serverless Workflow |
| 88 | +</code> |
| 89 | +</pre> |
| 90 | +</td> |
81 | 91 |
|
82 | | -```java |
83 | | -Workflow wf = workflow("seqFlow").sequence("process", creativeWriter, audienceEditor, styleEditor).build(); |
| 92 | +<td style="vertical-align:top;"> |
| 93 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 94 | +<code class="language-java" style="background:none;white-space:pre;">Workflow wf = workflow("seqFlow") |
| 95 | + .sequence(creativeWriter, audienceEditor, styleEditor) |
| 96 | + .build(); |
| 97 | + |
| 98 | + |
84 | 99 |
|
85 | 100 | try (WorkflowApplication app = WorkflowApplication.builder().build()) { |
86 | 101 | String result = app.workflowDefinition(wf).instance(input).start().get().asText().orElseThrow(); |
87 | 102 | } catch (Exception e) { |
88 | 103 | throw new RuntimeException("Workflow execution failed", e); |
89 | 104 | } |
90 | | -``` |
| 105 | + |
| 106 | +</code> |
| 107 | +</pre> |
| 108 | +</td> |
| 109 | + </tr> |
| 110 | +</table> |
91 | 111 |
|
92 | 112 |
|
93 | 113 | ### Loop workflow |
94 | 114 | ### Common part: |
| 115 | +<details><summary>Click to expand</summary> |
| 116 | + |
95 | 117 | ```java |
96 | 118 | interface StyleEditor { |
97 | 119 |
|
@@ -136,38 +158,58 @@ StyleScorer styleScorer = AgenticServices |
136 | 158 |
|
137 | 159 | ``` |
138 | 160 |
|
139 | | -### LangChain4j |
140 | | -```java |
| 161 | +</details> |
| 162 | + |
| 163 | +<table style="table-layout:fixed; width:100%;"> |
| 164 | + <tr> |
| 165 | + <th style="width:50%; text-align:left;">LangChain4j</th> |
| 166 | + <th style="text-align:left;">Serverless Workflow</th> |
| 167 | + </tr> |
| 168 | + <tr> |
| 169 | + <td style="vertical-align:top;"> |
| 170 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 171 | +<code class="language-java" style="background:none;white-space:pre;"> |
| 172 | + |
| 173 | + |
141 | 174 | StyledWriter styledWriter = AgenticServices |
142 | | - .sequenceBuilder(StyledWriter.class) |
143 | | - .subAgents(creativeWriter, styleReviewLoop) |
144 | | - .outputName("story") |
145 | | - .build(); |
| 175 | + .sequenceBuilder(StyledWriter.class) |
| 176 | + .subAgents(creativeWriter, styleReviewLoop) |
| 177 | + .outputName("story") |
| 178 | + .build(); |
146 | 179 |
|
147 | 180 | String story = styledWriter.writeStoryWithStyle("dragons and wizards", "comedy"); |
148 | | -``` |
149 | | - |
150 | | -### Serverless Workflow |
151 | | -```java |
152 | | -Predicate<AgenticScope> until = s -> s.readState("score", 0).doubleValue() >= 0.8; |
153 | 181 |
|
154 | | -Workflow wf = workflow("retryFlow").loop(until, scorer, 5, editor).build(); |
| 182 | +</code> |
| 183 | +</pre> |
| 184 | +</td> |
155 | 185 |
|
| 186 | +<td style="vertical-align:top;"> |
| 187 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 188 | +<code class="language-java" style="background:none;white-space:pre;">Map<String, Object> input = Map.of("story", "dragons and wizards","style", "comedy"); |
| 189 | +Predicate<AgenticScope> until = s -> s.readState("score", 0).doubleValue() >= 0.8; |
156 | 190 |
|
157 | | -Map<String, Object> input = |
158 | | - Map.of( |
159 | | - "story", "dragons and wizards", |
160 | | - "style", "comedy"); |
161 | | - |
| 191 | +Workflow wf = workflow("retryFlow") |
| 192 | + .loop(until, scorer, editor) |
| 193 | + .build(); |
| 194 | + |
| 195 | + |
| 196 | + |
162 | 197 | try (WorkflowApplication app = WorkflowApplication.builder().build()) { |
163 | | - String result = app.workflowDefinition(wf).instance(input).start().get().asText().orElseThrow(); |
| 198 | + String result = app.workflowDefinition(wf).instance(input).start().get().asText().orElseThrow(); |
164 | 199 | } catch (Exception e) { |
165 | | - throw new RuntimeException("Workflow execution failed", e); |
| 200 | + throw new RuntimeException("Workflow execution failed", e); |
166 | 201 | } |
167 | | -``` |
| 202 | + |
| 203 | +</code> |
| 204 | +</pre> |
| 205 | +</td> |
| 206 | + </tr> |
| 207 | +</table> |
168 | 208 |
|
169 | 209 | ### Parallel workflow |
170 | 210 | ### Common part: |
| 211 | +<details><summary>Click to expand</summary> |
| 212 | + |
171 | 213 | ```java |
172 | 214 | public interface FoodExpert { |
173 | 215 |
|
@@ -206,65 +248,81 @@ MovieExpert movieExpert = AgenticServices |
206 | 248 | .outputName("movies") |
207 | 249 | .build(); |
208 | 250 | ``` |
209 | | - |
210 | | -### LangChain4j |
211 | | -```java |
| 251 | +</details> |
| 252 | + |
| 253 | + |
| 254 | +<table style="table-layout:fixed; width:100%;"> |
| 255 | + <tr> |
| 256 | + <th style="width:50%; text-align:left;">LangChain4j</th> |
| 257 | + <th style="text-align:left;">Serverless Workflow</th> |
| 258 | + </tr> |
| 259 | + <tr> |
| 260 | + <td style="vertical-align:top;"> |
| 261 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 262 | +<code class="language-java" style="background:none;white-space:pre;"> |
212 | 263 | EveningPlannerAgent eveningPlannerAgent = AgenticServices |
213 | | - .parallelBuilder(EveningPlannerAgent.class) |
214 | | - .subAgents(foodExpert, movieExpert) |
215 | | - .executor(Executors.newFixedThreadPool(2)) |
216 | | - .outputName("plans") |
217 | | - .output(agenticScope -> { |
218 | | - List<String> movies = agenticScope.readState("movies", List.of()); |
219 | | - List<String> meals = agenticScope.readState("meals", List.of()); |
220 | | - |
221 | | - List<EveningPlan> moviesAndMeals = new ArrayList<>(); |
222 | | - for (int i = 0; i < movies.size(); i++) { |
223 | | - if (i >= meals.size()) { |
224 | | - break; |
225 | | - } |
226 | | - moviesAndMeals.add(new EveningPlan(movies.get(i), meals.get(i))); |
227 | | - } |
228 | | - return moviesAndMeals; |
229 | | - }) |
230 | | - .build(); |
| 264 | + .parallelBuilder(EveningPlannerAgent.class) |
| 265 | + .subAgents(foodExpert, movieExpert) |
| 266 | + .executor(Executors.newFixedThreadPool(2)) |
| 267 | + .outputName("plans") |
| 268 | + .output(agenticScope -> { |
| 269 | + List<String> movies = agenticScope.readState("movies", List.of()); |
| 270 | + List<String> meals = agenticScope.readState("meals", List.of()); |
| 271 | + List<EveningPlan> moviesAndMeals = new ArrayList<>(); |
| 272 | + for (int i = 0; i < movies.size(); i++) { |
| 273 | + if (i >= meals.size()) { |
| 274 | + break; |
| 275 | + } |
| 276 | + moviesAndMeals.add(new EveningPlan(movies.get(i), meals.get(i))); |
| 277 | + } |
| 278 | + return moviesAndMeals; |
| 279 | + }) |
| 280 | + .build(); |
231 | 281 |
|
232 | 282 | List<EveningPlan> plans = eveningPlannerAgent.plan("romantic"); |
233 | | -``` |
234 | 283 |
|
235 | | -### Serverless Workflow |
236 | | -```java |
237 | | -Workflow wf = workflow("forkFlow").parallel("fanout", foodExpert, movieExpert).build(); |
| 284 | +</code> |
| 285 | +</pre> |
| 286 | +</td> |
| 287 | + |
| 288 | +<td style="vertical-align:top;"> |
| 289 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 290 | +<code class="language-java" style="background:none;white-space:pre;"> |
| 291 | +Workflow wf = workflow("forkFlow") |
| 292 | + .parallel(foodExpert, movieExpert) |
| 293 | + .build(); |
| 294 | + |
| 295 | + |
| 296 | + |
| 297 | + |
| 298 | + |
| 299 | + |
| 300 | + |
| 301 | + |
| 302 | + |
| 303 | + |
| 304 | + |
| 305 | + |
| 306 | + |
| 307 | +Map<String, Object> input = Map.of("mood", "I am hungry and bored"); |
238 | 308 |
|
239 | | -Map<String, Object> input = Map.of("mood", "I am hungry and bored"); |
240 | | - |
241 | | -Map<String, Object> result; |
242 | 309 | try (WorkflowApplication app = WorkflowApplication.builder().build()) { |
243 | | - result = app.workflowDefinition(wf).instance(input).start().get().asMap().orElseThrow(); |
| 310 | + Map<String, Object> result = app.workflowDefinition(wf).instance(input).start().get().asMap().orElseThrow(); |
244 | 311 | } catch (Exception e) { |
245 | | - throw new RuntimeException("Workflow execution failed", e); |
| 312 | + throw new RuntimeException("Workflow execution failed", e); |
246 | 313 | } |
247 | | -``` |
248 | | - |
249 | | -### Error handling |
250 | | -### Common part: |
251 | | -```java |
252 | | - |
253 | | -``` |
254 | | - |
255 | | -### LangChain4j |
256 | | -```java |
257 | | - |
258 | | -``` |
259 | 314 |
|
260 | | -### Serverless Workflow |
| 315 | +</code> |
| 316 | +</pre> |
| 317 | +</td> |
| 318 | + </tr> |
| 319 | +</table> |
261 | 320 |
|
262 | | -```java |
263 | | - |
264 | | -``` |
265 | 321 |
|
266 | 322 | ### Human-in-the-loop |
267 | 323 | ### Common part: |
| 324 | +<details><summary>Click to expand</summary> |
| 325 | + |
268 | 326 | ```java |
269 | 327 | public record HumanInTheLoop(Consumer<String> requestWriter, Supplier<String> responseReader) { |
270 | 328 |
|
@@ -302,28 +360,46 @@ HumanInTheLoop humanInTheLoop = AgenticServices |
302 | 360 | .responseReader(() -> System.console().readLine()) |
303 | 361 | .build(); |
304 | 362 | ``` |
305 | | - |
306 | | -### LangChain4j |
307 | | -```java |
| 363 | +</details> |
| 364 | + |
| 365 | +<table style="table-layout:fixed; width:100%;"> |
| 366 | + <tr> |
| 367 | + <th style="width:50%; text-align:left;">LangChain4j</th> |
| 368 | + <th style="text-align:left;">Serverless Workflow</th> |
| 369 | + </tr> |
| 370 | + <tr> |
| 371 | + <td style="vertical-align:top;"> |
| 372 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 373 | +<code class="language-java" style="background:none;white-space:pre;"> |
308 | 374 | SupervisorAgent horoscopeAgent = AgenticServices |
309 | 375 | .supervisorBuilder() |
310 | 376 | .chatModel(PLANNER_MODEL) |
311 | 377 | .subAgents(astrologyAgent, humanInTheLoop) |
312 | 378 | .build(); |
313 | 379 |
|
314 | 380 | horoscopeAgent.invoke("My name is Mario. What is my horoscope?") |
315 | | -``` |
316 | 381 |
|
317 | | -### Serverless Workflow |
| 382 | +</code> |
| 383 | +</pre> |
| 384 | +</td> |
318 | 385 |
|
319 | | -```java |
320 | | -Workflow wf = workflow("seqFlow").sequence("process", astrologyAgent, humanInTheLoop).build(); |
| 386 | +<td style="vertical-align:top;"> |
| 387 | +<pre style="background:none; margin:0; padding:0; font-family:monospace; line-height:1.4;"> |
| 388 | +<code class="language-java" style="background:none;white-space:pre;"> |
| 389 | +Workflow wf = workflow("seqFlow") |
| 390 | + .sequence(astrologyAgent, humanInTheLoop) |
| 391 | + .build(); |
321 | 392 |
|
322 | 393 | Map<String, Object> input = Map.of("request", "My name is Mario. What is my horoscope?"); |
323 | 394 |
|
324 | 395 | try (WorkflowApplication app = WorkflowApplication.builder().build()) { |
325 | | - String result = app.workflowDefinition(wf).instance(input).start().get().asMap().orElseThrow(); |
| 396 | + String result = app.workflowDefinition(wf).instance(input).start().get().asMap().orElseThrow(); |
326 | 397 | } catch (Exception e) { |
327 | | - throw new RuntimeException("Workflow execution failed", e); |
| 398 | + throw new RuntimeException("Workflow execution failed", e); |
328 | 399 | } |
329 | | -``` |
| 400 | + |
| 401 | +</code> |
| 402 | +</pre> |
| 403 | +</td> |
| 404 | + </tr> |
| 405 | +</table> |
0 commit comments