VOOZH about

URL: https://dzone.com/articles/agentic-workflows-java-quarkus

โ‡ฑ Getting Started With Agentic Workflows in Java and Quarkus


Related

  1. DZone
  2. Coding
  3. Java
  4. Getting Started With Agentic Workflows in Java and Quarkus

Getting Started With Agentic Workflows in Java and Quarkus

A step-by-step tutorial on how to add agentic workflows to Quarkus applications with the Agentican framework via YAML and annotations.

By Jun. 03, 26 ยท Tutorial
Likes
Comment
Save
2.4K Views

Join the DZone community and get the full member experience.

Join For Free

This post walks through building and running a real-world agentic workflow with Agentican and Quarkus. Specifically, an agentic workflow to automate market research and information sharing:

  1. Identify the top vendors within a market category.
  2. Research the positioning and strengths of each vendor.
  3. Classify the findings as either standard or urgent.
  4. Draft a brief to share with others in the company.

Prerequisites

  • Quarkus
  • Java 25
  • Maven (or Gradle)
  • LLM provider API key

Step 1: Add the dependency

Create a Quarkus app, and add the Agentican Quarkus runtime module:

XML
<dependency>
 <groupId>ai.agentican</groupId>
 <artifactId>agentican-quarkus-runtime</artifactId>
 <version>0.1.0-alpha.3</version>
</dependency>


Step 2: Define Agents, Skills, and the Workflow

Create an `agentican-catalog.yaml` file on the classpath. 

This is where you describe:

  • Who does the work (agents)
  • What they need to do it (skills)
  • How they will do it (workflows)
YAML
agents:
 - id: researcher
 name: researcher
 role: |
 Expert at finding accurate, sourced information about companies and
 markets. Quotes sources. Distinguishes opinion from fact.
 
 - id: writer
 name: writer
 role: |
 Synthesizes research into structured, concise briefs. Avoids hedging
 language. Cites concrete evidence.

skills:
 - id: web-search
 name: web-search
 instructions: |
 When a question requires external information, call the search tool
      first. Quote sources in your answer.


Update the `agentican-catalog.yaml` file to define the workflow.

YAML
workflows:
 - id: market-brief
 name: market-brief
 description: Research vendors in a market and produce a structured brief
 outputStep: deliver
 params:
 - name: topic
 description: Market to research
 required: true
 
 - name: vendor_count
 description: Number of vendors
 defaultValue: "5"
 steps:
 - name: identify
 agent: researcher
 skills: [web-search]
 instructions: |
 Identify the top {{param.vendor_count}} vendors in {{param.topic}}.
 Return a JSON array of vendor names โ€” names only, no commentary.
 
 - name: deep-dive
 type: loop
 over: identify
 steps:
 - name: analyze
 agent: researcher
 skills: [web-search]
 instructions: |
 Deep-dive vendor {{item}}: positioning, key strengths, recent news.
 Quote sources.
 
 - name: classify
 agent: writer
 instructions: |
 Read the per-vendor deep-dives below. If any vendor has launched
 a competitive feature in the last 30 days, return the single word
 'urgent'. Otherwise return 'standard'.

 Deep-dives: {{step.deep-dive.output}}
 dependencies: [deep-dive]
 
 - name: deliver
 type: branch
 from: classify
 default: standard
 branches:
 - name: urgent
 steps:
 - name: urgent-brief
 agent: writer
 instructions: |
 Synthesize a vendor brief flagged URGENT for executive review.
 Lead with the recent competitive moves.

 Topic: {{param.topic}}
 Deep-dives: {{step.deep-dive.output}}

 - name: standard
 steps:
 - name: standard-brief
 agent: writer
 instructions: |
 Synthesize a vendor brief.

 Topic: {{param.topic}}
                  Deep-dives: {{step.deep-dive.output}}


A few things worth flagging:

  • agent: researcher references the agent for a step, skills referenced by name, too.
  • outputStep designates the step whose output becomes the workflow's typed result.
  • {{param.X}} interpolates workflow inputs into step instructions.
  • {{step.X.output}} interpolates an upstream step's output.
  • {{item}} is the current value inside a loop iteration.
  • type: loop steps take an over reference (a step that produced a list, or a list-typed param).
  • type: loop steps run their nested steps once per item, in parallel, and on virtual threads.
  • type: branch steps take a from reference (a step whose output is used to select a branch).
  • branches: mutually exclusive steps (or sets of steps) with default for unrecognized values.

The framework loads agentican-catalog.yaml from the classpath, or you can define where it's loaded from:

Properties files
agentican.catalog-config=/etc/agentican/agentican-catalog.yaml


Note: Agents, skills, and workflows can be defined via a fluent builder API as well.

Step 3: Configure the Models

Agentican reads the engine configuration from `application.properties`. The minimum is one LLM:

Properties files
agentican.llm[0].api-key=${ANTHROPIC_API_KEY}


The provider defaults to `anthropic`, and the model defaults to `claude-sonnet-4-5`.

Want OpenAI instead?

Properties files
agentican.llm[0].provider=openai
agentican.llm[0].api-key=${OPENAI_API_KEY}
agentican.llm[0].model=gpt-4o-mini


Want to mix and match? Configure `name`s and reference them per-agent in the YAML catalog:

Properties files
agentican.llm[0].name=default
agentican.llm[0].api-key=${ANTHROPIC_API_KEY}

agentican.llm[1].name=efficient
agentican.llm[1].provider=openai
agentican.llm[1].api-key=${OPENAI_API_KEY}
agentican.llm[1].model=gpt-4o-mini


Step 4: Create a Typed Workflow Instance

Define the workflow input and output records:

Java
public record ResearchParams(String topic, int vendorCount) {}

public record VendorBrief(String topic, List<Vendor> vendors) {

 public record Vendor(String name, String positioning, List<String> strengths) {}
}


Then inject the typed workflow, and call it from a REST endpoint:

Java
@Path("/market-brief")
public class VendorBriefResource {

 @Inject
 @AgenticanWorkflow(name = "market-brief")
 Workflow<ResearchParams, VendorBrief> brief;

 @POST
 @Path("/{topic}")
 public VendorBrief generate(@PathParam("topic") String topic) {

 return brief.start(new ResearchParams(topic, 5)).await();
 }
}


Now, test the endpoint:

Shell
curl -X POST http://localhost:8080/market-brief/data%20observability%20platforms 


A few things worth flagging โ€” they're what set this apart from a generic "call an LLM" library:

  • ResearchParams.vendorCount becomes the workflow parameter vendor_count via SNAKE_CASE mapping.
  • start() returns a WorkflowRun<VendorBrief> and await() parses the output step's text into a VendorBrief.
  • @AgenticanWorkflow(name = "vendor-brief") resolves the registered workflow at injection time.

Note: WorkflowRun itself exposes future() for a CompletableFuture<R>, and there's a ReactiveWorkflow<P, R> Mutiny variant for Vert.x stacks.

Step 5: Add Agent Tools

Agentican ships two integrations out of the box:

MCP (Model Context Protocol)

There is one config block per server. Tools are auto-discovered:

Properties files
agentican.mcp[0].slug=github
agentican.mcp[0].name=GitHub
agentican.mcp[0].url=https://mcp.github.com/sse
agentican.mcp[0].headers.Authorization=Bearer ${GITHUB_TOKEN}


Composio

100+ SaaS toolkits โ€” Slack, Notion, Linear, Salesforce, GitHub, Google Workspace:

Properties files
agentican.composio.api-key=${COMPOSIO_API_KEY}
agentican.composio.user-id=user-123


Tools are referenced by name within agent steps:

YAML
steps:
 - name: research
 agent: researcher
 tools: [github_search_repositories]
    instructions: "Profile open-source vendors in {{param.topic}}."


Structured agentic workflows for the JVM.

Where to Go Next

Quarkus Java (programming language) workflow

Opinions expressed by DZone contributors are their own.

Related

  • Rethinking Java Web UIs With Jakarta Faces and Quarkus
  • The Future of Java and AI: Coding in 2025
  • Recurrent Workflows With Cloud Native Dapr Jobs
  • Build a REST API With Just 2 Classes in Java and Quarkus

Partner Resources

ร—

Comments

The likes didn't load as expected. Please refresh the page and try again.

Let's be friends: