What You’ll Build
A series of workflows that progressively introduce every DSL primitive: sequential pipelines, conditional branching, error recovery, loops, parallel execution, LLM-driven routing, quality gates, and supervised agent delegation. Each step is a real integration test validated against GPT-4.1.Prerequisites
- Java 21+
- An OpenAI API key (
OPENAI_API_KEYenvironment variable) - Agent Workflow 0.10.0:
Setup
All examples share aChatClient configured for GPT-4.1 with low temperature for test stability:
Step 1: Define a Step and Chain a Pipeline
AStep is the building block — a named function that takes context and input, produces output. Chain steps with .then() and each step’s output flows into the next.
Workflow.define() + .run() pattern compiles the graph and executes it in one call.
View source: SequentialDemo.java
Step 2: Branch on Classification
Route to different steps based on a predicate applied to the previous step’s output..strip().toLowerCase() on the classify output matters — LLMs sometimes return trailing whitespace or mixed case. The branch() predicate is a plain Java Predicate<Object>, so you can test any condition.
View source: BranchDemo.java
Step 3: Handle Errors
Route exceptions to a recovery step instead of crashing the workflow. The recovery step’s output flows into the next step as if the risky step had succeeded..onError() clause is type-specific — you can attach different recovery steps for different exception types. The workflow graph wires the recovery path at compile time, not at catch time.
View source: ErrorRecoveryDemo.java
Step 4: Loop Until Quality Converges
Iterate a block of steps until a predicate on the output is satisfied. This is the most complex primitive — LLM score parsing needs care.editor (generate) and scorer (evaluate) until the score reaches the threshold. GPT-4.1 returns clean decimal numbers with the “Reply with ONLY a decimal number” prompt — the regex fallback is there for other models.
View source: LoopDemo.java
Step 5: Fan Out in Parallel
Run steps concurrently and collect results into a list, ordered to match step order..parallel() — they all receive the same input and their outputs are collected in order.
View source: ParallelDemo.java
Step 6: LLM-Driven Routing
Let the LLM choose which step to execute. Unlikebranch() (predicate-based), decision() gives the LLM a menu of labeled options and it picks one.
decision() when the routing logic is semantic (the LLM needs to understand the input to choose) rather than structural (a simple predicate suffices).
View source: DecisionDemo.java
Step 7: Quality Gate
Evaluate output quality and route to pass or fail paths. The gate is a function that returnsGateDecision.PASS or GateDecision.FAIL.
JudgeGate backed by a jury for multi-judge evaluation with voting strategies.
View source: GateDemo.java
Step 8: Supervisor
The LLM autonomously selects which sub-agent to invoke each iteration, terminating when a condition is met..until() predicate reads from context — ITERATION_COUNT is automatically maintained, but you can use any context key.
View source: SupervisorDemo.java
Runnable Code
Every step in this tutorial has a corresponding runnable module in the workflow-dsl-examples repository. Clone it and run any module with./mvnw exec:java -pl module-NN-name.
What’s Next
Annotation Model
Declarative workflows with @Agent, @ExceptionHandler, and AgentRegistry
Parameterization
4 patterns for getting data into steps
Durability
Crash recovery with CheckpointingStepRunner and Temporal
All Examples
Complete reference with all 9 patterns plus sub-workflow composition