LiteFlow Rule Engine Adds Full AI Agent Orchestration Support

This tutorial demonstrates how LiteFlow v2.16+ integrates AI agents as native components, enabling developers to orchestrate LLMs like DeepSeek, Qwen, and OpenAI models using familiar LiteFlow operators (THEN, WHEN, IF) within Spring Boot applications.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
LiteFlow Rule Engine Adds Full AI Agent Orchestration Support

LiteFlow, a modern rule engine framework for Java, introduced its AI Agent module ( liteflow-agent) starting from version 2.16.0. Unlike simple LLM wrappers, this module encapsulates a complete Agent (Reasoning + Acting) as a standard LiteFlow component, allowing developers to orchestrate AI nodes using the same operators — THEN, WHEN, IF, SWITCH, FOR — that have powered business logic flows for years.

Core Concept

An Agent becomes just another node in a LiteFlow chain. The framework handles model integration (OpenAI, Claude, Gemini, DeepSeek, DashScope, Kimi, GLM), namespaced AgentScope state, typed events, structured output, human-in-the-loop (HITL), skills, and optional Harness/sandbox filesystems. Switching models is essentially a one-line change in model().

Note: The AI Agent module is built on AgentScope Java 2.0.2 and compiled/validated on JDK 17. Guarded local filesystem access only provides path protection within the host JVM, not a security sandbox; untrusted workloads should use hardened Docker or remote backends.

Environment & Dependencies

Tested with Spring Boot 3.5.0 and LiteFlow 2.16.3. Required Maven dependencies:

<liteflow.version>2.16.3</liteflow.version>
<dependency>
  <groupId>com.yomahub</groupId>
  <artifactId>liteflow-spring-boot-starter</artifactId>
  <version>${liteflow.version}</version>
</dependency>
<dependency>
  <groupId>com.yomahub</groupId>
  <artifactId>liteflow-agent-core</artifactId>
  <version>${liteflow.version}</version>
</dependency>
<dependency>
  <groupId>com.yomahub</groupId>
  <artifactId>liteflow-agent-openai</artifactId>
  <version>${liteflow.version}</version>
</dependency>

For Spring Boot 4, use liteflow-spring-boot4-starter. All LiteFlow modules share the same version; AgentScope dependencies are pulled transitively.

Minimal Configuration

liteflow:
  rule-source: agent/*.el.xml
  agent:
    openai:
      api-key: ${AI_LONGCAT_API_KEY}
      base-url: https://api.longcat.chat/openai

Session and chat history default to data/agent-state under the process working directory using a local file backend. The liteflow.agent.application-name property (defaults to spring.application.name) isolates agent data; it must not contain path characters like /, \, or ...

Creating an Agent Component

Extend HarnessAgentComponent and override three methods:

@Component("chatAgent")
public class ChatAgentCmp extends HarnessAgentComponent {
  @Override
  protected ModelSpec<?> model() {
    return OpenAI.of("LongCat-2.5-Preview")
      .stream(true);
  }
  @Override
  protected String systemPrompt() {
    return "你是一位专业的Java高级架构师;用中文回答。";
  }
  @Override
  protected String userPrompt(LiteFlowAgentContext context) {
    Object input = getSlot().getChainReqData(getSlot().getChainId());
    return input == null ? "" : input.toString();
  }
  @Override
  protected boolean enableShellTool() {
    return false;
  }
}
model()

selects the LLM and streaming mode. systemPrompt() defines the agent's fixed persona; the framework prepends default behavior instructions (answer in user's language, brief action description before tool calls). Use transformSystemPrompt(prompt, context) to augment per request. userPrompt(context) supplies the per-invocation input, typically read from the chain's request data slot. enableShellTool() controls local shell access; disabled here. process() is managed by the framework — do not override. The provided LiteFlowAgentContext holds conversation ID, node ID, request ID, and token usage; do not cache it across requests.

Flow Definition (EL)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE flow PUBLIC "liteflow" "liteflow.dtd">
<flow>
  <chain name="chatChain">
    THEN(chatAgent);
  </chain>
</flow>

The EL component name chatAgent must match the Spring bean name.

Executing the Flow

@RestController
@RequestMapping("/first-agent")
public class FirstAgentController {
  private final FlowExecutor flowExecutor;
  public FirstAgentController(FlowExecutor flowExecutor) {
    this.flowExecutor = flowExecutor;
  }
  @GetMapping
  public ResponseEntity<Object> execute(String message) {
    LiteflowResponse response = flowExecutor.execute2Resp("chatChain", message);
    if (!response.isSuccess()) {
      return ResponseEntity.ok("Agent 执行失败: %s".formatted(response.getCause().getMessage()));
    }
    String answer = response.getSlot().getResponseData();
    String conversationId = response.getConversationId();
    return ResponseEntity.ok(Map.of("conversationId", conversationId, "answer", answer));
  }
}

Capturing Agent Output in Business Context

Override handleReply(Msg reply, LiteFlowAgentContext context) to write the reply or token usage into a custom context bean:

@Component("chatAgent")
public class ChatAgentCmp extends HarnessAgentComponent {
  // ...
  @Override
  protected void handleReply(io.agentscope.core.message.Msg reply,
      LiteFlowAgentContext context) {
    super.handleReply(reply, context);
    Object result = context.getSlot().getResponseData();
    AgentContextData data = this.getContextBean(AgentContextData.class);
    data.setData(result.toString());
  }
}

Define a plain POJO for the shared data:

public class AgentContextData {
  private String data;
  public String getData() { return data; }
  public void setData(String data) { this.data = data; }
}

Add a regular NodeComponent to consume it:

@Component("chatResult")
public class ChatResultComponent extends NodeComponent {
  @Override
  public void process() {
    AgentContextData data = this.getContextBean(AgentContextData.class);
    System.err.println("最终结果:
%s".formatted(data.getData()));
  }
}

Update the chain to THEN(chatAgent, chatResult) and pass the context bean at execution:

AgentContextData data = new AgentContextData();
LiteflowResponse response = flowExecutor.execute2Resp("chatChain", message, data);

Multi-Agent Collaboration Example

Scenario: User asks an AI customer-service bot. A Question Classification Agent first categorizes the intent, then a After-Sales Agent generates a tailored reply.

Question Classification Agent

@Component("questionAgent")
public class QuestionComponentAgent extends HarnessAgentComponent {
  @Override
  protected ModelSpec<?> model() {
    return OpenAI.of("LongCat-2.5-Preview").stream(true);
  }
  @Override
  protected String systemPrompt() {
    return "你是智能问答小助手";
  }
  @Override
  protected String userPrompt(LiteFlowAgentContext context) {
    Object input = getSlot().getChainReqData(getSlot().getChainId());
    return """
      分析客户的问题:
      问题: %s
      最终输出只能是其中之一:QUALITY_ISSUE, PAYMENT_ISSUE, SERVICE_ISSUE
      说明:QUALITY_ISSUE: 质量问题,PAYMENT_ISSUE: 支付问题,SERVICE_ISSUE: 服务问题
      """.formatted(input == null ? "" : input.toString());
  }
}

After-Sales Agent

@Component("salesAgent")
public class AfterSalesAgent extends HarnessAgentComponent {
  @Override
  protected ModelSpec<?> model() {
    return OpenAI.of("LongCat-2.5-Preview").stream(true);
  }
  @Override
  protected String systemPrompt() {
    return """
      你是智能客服售后专家,专门处理用户售后问题。
      请根据用户的问题类型,给出专业、友好、简洁的回复。
      如果是质量问题,优先提供退换货方案;
      如果是支付问题,引导用户核对支付信息或联系支付渠道;
      如果是服务问题,表达歉意并提供后续改进承诺。
      不要编造未确认的信息,不确定时请引导用户联系人工客服。
      """;
  }
  @Override
  protected String userPrompt(LiteFlowAgentContext context) {
    Object input = getSlot().getChainReqData(getSlot().getChainId());
    String result = getSlot().getResponseData(); // output from previous agent
    IssueType issueType = IssueType.fromCode(result);
    String issueDesc = switch (issueType) {
      case QUALITY_ISSUE -> "用户反馈的是【质量问题】,例如商品破损、开胶、功能异常等,请给出退换货或补偿方案。";
      case PAYMENT_ISSUE -> "用户反馈的是【支付问题】,例如扣款异常、支付失败、退款未到账等,请给出排查建议。";
      case SERVICE_ISSUE -> "用户反馈的是【服务问题】,例如物流慢、客服态度差、承诺未兑现等,请安抚用户并给出改进说明。";
    };
    return """
      %s
      用户原始问题:%s
      请直接生成给用户的回复内容。
      """.formatted(issueDesc, input);
  }
}

Chain Definition

<chain name="customChain">
  THEN(questionAgent, salesAgent);
</chain>

The first agent's structured output (one of three enum values) drives the second agent's prompt construction, demonstrating typed inter-agent communication via the shared slot.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Rule EngineSpring BootAI AgentLiteFlowLLM IntegrationJava frameworkagent orchestration
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.