Monday, 22 December 2025

Sequential Workflow in GenAI: Building Step-by-Step Agent Pipelines

When working with Generative AI (GenAI) applications, tasks are often broken into multiple steps. Instead of asking a single agent to handle everything at once, you can chain smaller, focused agents together. This chaining forms a sequential workflow, a simple but powerful pattern where each agent’s output is passed as input to the next agent, like links in a chain.

This approach makes the system easier to design, debug, and extend. For beginners, sequential workflows are the best place to start before moving into more advanced workflow patterns like branching or parallel execution.

 


What is a Sequential Workflow?

A sequential workflow is a pipeline of agents, executed in order.

 

·      Each agent performs one clear task.

·      The output of one agent becomes the input to the next.

·      The flow continues until the final output is ready.

 

Think of it like a factory assembly line, where each worker (agent) does their part, and the product (data) moves to the next worker until it’s finished.

 

Let's understand this with an example.

 

Step 1: Let's define three agents.

 

Poet.java

package com.sample.app.agents;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface Poet {

  @UserMessage(
      """
            You are a poet.
            Write a short poem of no more than
            4 lines about the given theme.
            Return only the poem and nothing else.
            The theme is {{theme}}.
            """)
  @Agent(description = "Generates a short poem based on the given theme", name = "Poet")
  String generatePoem(@V("theme") String theme);
}

PoemEditor.java

package com.sample.app.agents;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface PoemEditor {

  @UserMessage("""
          You are a professional Poem Editor.
         Analyze and rewrite the following {{poem}} to better align
      with the target theme of {{theme}}.

      Return only the poem and nothing else.
          """)
  @Agent(description = "Generates a short poem based on the given theme", name = "Poet")
  String generatePoem(@V("poem") String poemToEdit, @V("theme") String targetTheme);
}

PoemInUppercase.java

package com.sample.app.agents;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface PoemInUppercase {

  @UserMessage("""
      Return the following {{editedPoem}} in uppercase and nothing else.
          """)
  @Agent(description = "Convert the Poem to Uppercase", name = "PoemInUppercase")
  String generatePoem(@V("editedPoem") String poem);
}

 

Step 2: Let's combine these three agents, where the output of the Poet is passed as input to the PoemEditor, and the output of PoemEditor is passed as input to the PoemInUppercase, and the final output is the edited poem in uppercase.

 

SequentialWorkflow.java

package com.sample.app.agents.workflows;

import com.sample.app.agents.PoemEditor;
import com.sample.app.agents.PoemInUppercase;
import com.sample.app.agents.Poet;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.model.ollama.OllamaChatModel;
import java.util.Map;

public class SequentialWorkflow {
  public static void main(String[] args) {
    // Initialize LLM model
    OllamaChatModel chatModel =
        OllamaChatModel.builder().baseUrl("http://localhost:11434").modelName("llama3.2").build();

    Poet poet =
        AgenticServices.agentBuilder(Poet.class).chatModel(chatModel).outputName("poem").build();
    PoemEditor poemEditor =
        AgenticServices.agentBuilder(PoemEditor.class)
            .chatModel(chatModel)
            .outputName("editedPoem")
            .build();

    PoemInUppercase poemInUppercase =
        AgenticServices.agentBuilder(PoemInUppercase.class)
            .chatModel(chatModel)
            .outputName("poemInCapitalLetters")
            .build();

    UntypedAgent untypedAgent=
        AgenticServices.sequenceBuilder()
            .subAgents(poet, poemEditor, poemInUppercase)
            .outputName("poemInCapitalLetters")
            .build();

    Map<String, Object> input = Map.of("theme", "Robots");

    String poem = (String) untypedAgent.invoke(input);
    System.out.println(poem);
  }
}

 

The workflow can be visualized like below.

 


Output

METAL HEARTS BEAT WITH COLD DESIGN,
GEARS TICK ON, ELECTRONIC MIND,
IN METALLIC FLESH, NO HEARTBEAT'S FOUND,
A SYNTHETIC HEART BEATS ALONE, PROFOUND.

 

We defined three agents in our workflow:

 

·      Poet

·      PoemEditor

·      PoemInUppercase

 

The Poet agent takes a theme as input and generates a poem related to that theme.

 

The PoemEditor agent receives both the theme and the poem generated by the Poet agent, then refines it and returns the result as editedPoem.

 

The PoemInUppercase agent takes the editedPoem as input and transforms it into uppercase text. The final output is stored in the variable poemInCapitalLetters.

 

Previous                                                    Next                                                    Home

No comments:

Post a Comment