Solon AI —— 流程编排

说明

Solon 的流程编排,使用了 solon-flow 做流程编排,因此需要先对 solon-flow 有所了解,下面是 Solon flow的一些简单介绍,更具体的介绍可以参考官网 https://solon.noear.org/article/learn-solon-flow 。

solon-flow

Solon Flow 提供基础的流引擎能力,支持开放式的驱动定制(像 JDBC 有 MySQL 或 PostgreSQL 等不同驱动一样)。可用于业务规则、决策处理、计算编排、流程审批等场景。

核心概念:

  • 链、节点、连接。
  • 链上下文、链驱动器、任务组件接口、条件组件接口。
  • 流引擎。

概念关系:

  • 链(Chain),一个完整的流程,由多个节点(Node)连接(Link)组成。一个链有且只有一个 start 类型的节点。从 start 节点开始,顺着连接(Link)流出。
  • 节点(Node),流程处理的环节,会有多个连接(Link),有流入连接,流出连接。
  • 连接(Link),节点与节点之间的执行顺序。连接向其它节点,称为流出连接。被其它节点连接,称为流入连接。
  • 流引擎,提供执行时的环境(链上下文与对象引用等),驱动链的流动(执行)。链的流转过程,可以有上下文参数(ChainContext),可以被中断(可支持有状态的审批模式)。

通俗些,就是通过点(节点) + 线(连接)来描述一个流程图(链)。因此这里列出节点和连接的属性。

节点 Node 属性

属性数据类型需求描述
idString节点Id(要求链内唯一)。不配置时,会自动生成
typeNodeType节点类型,类型包括 start,execute,inclusive,exclusive,parallerl,end。不配置时,缺省为 execute 类型,
titleString显示标题
metaMap元信息(用于应用扩展)
linkString or Link String[] or Link[]连接(支持单值、多值),不配置时,会自动生成。link 全写配置风格为 Link 类型结构;简写配置风格为 Link 的 nextId 值(即 String 类型)
taskString任务描述(会触发驱动的 handleTask 处理)
whenString执行任务条件描述(会触发驱动的 handleTest 处理)

连接 Link 属性

通常可以不配置,或者用简写模式配置即可,只要当Node是包含网关(inclusive)或者排他网关(exclusive)时需要配置全选风格,从而配置条件。

属性数据类型需求描述
nextIdString必填后面的节点Id
titleString显示标题
metaMap元信息(用于应用扩展)
conditionString流出条件描述(会触发驱动的 handleTest 处理)

节点类型 NodeType

描述任务连接条件可流入 连接数可流出 连接数图例参考
start开始//01
execute执行节点(缺省类型)可有/1…n1
inclusive包容网关/支持1…n1…n
exclusive排它网关/支持1…n1…n
parallel并行网关//1…n1…n
end结束//1…n0

依赖

dependencies {
    implementation platform(project(":demo-parent"))

    implementation("org.noear:solon-web")
    implementation("org.noear:solon-view-enjoy")
    implementation("org.noear:solon-ai")
    implementation("org.noear:solon-logging-logback")
    implementation("org.noear:solon-openapi2-knife4j")
    implementation("org.noear:solon-web-rx")
    implementation("org.noear:solon-web-sse")
    implementation("org.noear:solon-flow")
    implementation("org.dromara.hutool:hutool-all")


    testImplementation("org.noear:solon-test")
}

配置

app.yml

这里需要指定配置的流配置文件的位置。

solon.flow:
  - "classpath:flow/*"

流配置

这里尝试用一个模拟一次简单的诊断,从诊断到治疗建议等流程。注意这里只是示例,并非真正的诊断流程,更完整的流程是还需要更多的病人信息(比如病史,检查,检验等),检索相关知识库等。这里只是为了 solon-flow 针对 ai 相关的编排的逻辑。

在诊断的节点,我们使用了deepseek-r1,在治疗环境,我们使用qwen2.5。

id: "ai-flow-01"
layout:
  - id: "开始"
    type: "start"
  - id: "诊断"
    type: "execute"
    meta.model: "deepseek-r1:32b"
    meta.apiUrl: "http://127.0.0.1:11434/api/chat"
    meta.provider: "ollama"
    meta.input: "prompt"
    meta.output: "intention"
    meta.system: "根据用户的描述,判断用户最可能的三个健康问题,只要诊断名称,不需要其他解释,用 Markdown 的列表格式返回。"
    task: "@intentionTask"
  - id: "治疗建议"
    type: "execute"
    meta.model: "qwen2.5:7b"
    meta.apiUrl: "http://127.0.0.1:11434/api/chat"
    meta.provider: "ollama"
    meta.input: "intention"
    meta.output: "suggestion"
    meta.system: "#角色\n你是一个经验丰富的医生\n\n#任务\n根据用户提供的诊断信息,提供治疗建议"
    task: "@suggestionTask"
  - type: "end"

Controller

package com.example.demo.ai.llm.controller;

import com.example.demo.ai.llm.service.LlmService;
import com.jfinal.kit.Kv;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.noear.solon.annotation.*;

/**
 * @author airhead
 */
@Controller
@Mapping("/llm")
@Api("聊天")
public class LlmController {
  @Inject private LlmService service;

  @ApiOperation("flow")
  @Post
  @Mapping("flow")
  public Kv flow(String prompt) {
    return service.flow(prompt);
  }

  @ApiOperation("aiFlow")
  @Post
  @Mapping("aiFlow")
  public Kv aiFlow(String prompt) {
    return service.aiFlow(prompt);
  }
}

这里的 flow 是演示基础的 solon flow 的调用,是我学习solon flow 时编写的一个简单例子,不熟悉的可以先看看这个示例的编写。

aiFlow 是对大模型的一个编排的调用。

Service

这里的重点就是注入 FlowEngine

package com.example.demo.ai.llm.service;

import com.jfinal.kit.Kv;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.flow.ChainContext;
import org.noear.solon.flow.FlowEngine;

/**
 * @author airhead
 */
@Component
public class LlmService {
  @Inject private FlowEngine flowEngine;

  public Kv flow(String prompt) {

    try {
      ChainContext chainContext = new ChainContext();
      chainContext.put("prompt", prompt);
      Kv kv = Kv.create();
      chainContext.put("result", kv);
      flowEngine.eval("c1", chainContext);

      return kv;
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }

  public Kv aiFlow(String prompt) {
    try {
      ChainContext chainContext = new ChainContext();
      chainContext.put("prompt", prompt);
      Kv kv = Kv.create();
      chainContext.put("result", kv);
      flowEngine.eval("ai-flow-01", chainContext);

      return kv;
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }
}

IntentionTask

这里是诊断节点的处理,根据 meta 信息和用户的输入构建大模型,然后进行调用,并将结果通过 ChainContext 进行传递。

package com.example.demo.ai.llm.service;

import com.jfinal.kit.Kv;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.noear.solon.ai.chat.ChatConfig;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.annotation.Component;
import org.noear.solon.flow.ChainContext;
import org.noear.solon.flow.Node;
import org.noear.solon.flow.TaskComponent;

/**
 * @author airhead
 */
@Component("intentionTask")
public class IntentionTask implements TaskComponent {
  @Override
  public void run(ChainContext context, Node node) throws Throwable {
    Kv meta = Kv.create().set(node.meta());
    ChatConfig chatConfig = new ChatConfig();
    chatConfig.setModel(meta.getStr("model"));
    chatConfig.setProvider(meta.getStr("provider"));
    chatConfig.setApiUrl(meta.getStr("apiUrl"));
    chatConfig.setTimeout(Duration.ofSeconds(600));
    ChatModel chatModel = ChatModel.of(chatConfig).build();

    List<ChatMessage> chatMessageList = new ArrayList<>();
    ChatMessage system = ChatMessage.ofSystem(meta.getStr("system"));
    chatMessageList.add(system);

    Kv model = Kv.create().set(context.model());
    String inputKey = meta.getStr("input");
    ChatMessage userMessage = ChatMessage.ofUser(model.getStr(inputKey));
    chatMessageList.add(userMessage);
    ChatResponse response = chatModel.prompt(chatMessageList).call();
    String content = response.getMessage().getContent();

    // 去掉think的部分。
    String pattern = "<think>.*?</think>";
    Pattern p = Pattern.compile(pattern, Pattern.DOTALL);
    content = StrUtil.trim(ReUtil.replaceAll(content, p, ""));

    String outputKey = meta.getStr("output");
    context.put(outputKey, content);

    Kv result = context.get("result");
    result.set("data", content);
  }
}

SuggestionTask

这里是治疗节点的处理,根据 meta 信息和上一级节点的输入构建大模型,然后进行调用,并将结果通过 ChainContext 进行返回。

package com.example.demo.ai.llm.service;

import com.jfinal.kit.Kv;
import java.util.ArrayList;
import java.util.List;
import org.noear.solon.ai.chat.ChatConfig;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.annotation.Component;
import org.noear.solon.flow.ChainContext;
import org.noear.solon.flow.Node;
import org.noear.solon.flow.TaskComponent;

/**
 * @author airhead
 */
@Component("suggestionTask")
public class SuggestionTask implements TaskComponent {
  @Override
  public void run(ChainContext context, Node node) throws Throwable {
    Kv meta = Kv.create().set(node.meta());
    ChatConfig chatConfig = new ChatConfig();
    chatConfig.setModel(meta.getStr("model"));
    chatConfig.setProvider(meta.getStr("provider"));
    chatConfig.setApiUrl(meta.getStr("apiUrl"));
    ChatModel chatModel = ChatModel.of(chatConfig).build();

    List<ChatMessage> chatMessageList = new ArrayList<>();
    ChatMessage system = ChatMessage.ofSystem(meta.getStr("system"));
    chatMessageList.add(system);

    Kv model = Kv.create().set(context.model());
    String inputKey = meta.getStr("input");
    ChatMessage userMessage = ChatMessage.ofUser(model.getStr(inputKey));
    chatMessageList.add(userMessage);
    ChatResponse response = chatModel.prompt(chatMessageList).call();
    String content = response.getMessage().getContent();

    String outputKey = meta.getStr("output");
    context.put(outputKey, content);

    Kv result = context.get("result");
    result.set("data", content);
  }
}

验证

通过 swagger 直接调用aiFlow。

在这里插入图片描述

这里是中间环节的输出。

在这里插入图片描述

小结

Solon AI 通过 Solon Flow 进行编排。通过编排,我们可以整合普通的业务逻辑和大模型的生成式功能实现更复杂、更人性化的业务逻辑,当然要实现真实可用的业务逻辑,需要自己进一步的摸索。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980900.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

性能调优-cpu的性能指标【经典篇】

一 cpu查看core数命令 1.1 查看物理core数 1.查看物理CPU的个数&#xff1a;cat /proc/cpuinfo 这个虚拟机的物理cpu2个&#xff0c;每个物理cpu的逻辑CPU个数为1个&#xff0c;所以逻辑CPU的个数就是2个。 1.2 查看逻辑cpu个数 cat /proc/cpuinfo| grep "processo…

Unity中动态切换光照贴图LightProbe的方法

关键代码&#xff1a;LightmapSettings.lightmaps lightmapDatas; LightmapData中操作三张图&#xff1a;lightmapColor,lightmapDir,以及一张ShadowMap 这里只操作前两张&#xff1a; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;public cl…

计算机毕业设计Python+DeepSeek-R1大模型微博舆情分析系统 微博舆情预测 微博爬虫 微博大数 据(源码+LW文档+PPT+详细讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

[Computer Vision]实验八:图像分割

目录 一、实验内容 二、实验过程 2.1 交互式分割实验 2.1.1 交互式分割 实验代码 2.1.2 实验结果 2.2 聚类算法实现图像分割 2.2.1 聚类算法实现分割 实验代码 2.2.2 实验结果 三、实验总结 一、实验内容 了解图割操作&#xff0c;实现用户交互式分割&#xff0c;通过…

Django与数据库

我叫补三补四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲alpha策略制定后的测试问题 mysql配置 Django模型体现了面向对象的编程技术&#xff0c;是一种面向对象的编程语言和不兼容类型能相互转化的编程技术&#xff0c;这种技术也叫ORM&#…

命名管道——进程间通信

个人主页&#xff1a;敲上瘾-CSDN博客 匿名管道&#xff1a;进程池的制作&#xff08;linux进程间通信&#xff0c;匿名管道... ...&#xff09;-CSDN博客 一、命名管道的使用 1.创建命名管道 1.1.在命令行中&#xff1a; 创建&#xff1a; mkfifo 管道名 删除&#xff1a…

摄像头应用编程(三):多平面视频采集

文章目录 1、前言2、环境介绍3、步骤4、应用程序编写5、测试5.1、编译应用程序5.2、运行应用程序 6、总结 1、前言 在查看摄像头类型时&#xff0c;大致可以分为两类&#xff1a;Video Capture 和 Video Capture Multiplanar。 本次应用程序主要针对类型为Video Capture Multi…

QT实现计算器

1&#xff1a;在注册登录的练习里面&#xff0c; 追加一个QListWidget 项目列表 要求&#xff1a;点击注册之后&#xff0c;将账号显示到 listWidget上面去 以及&#xff0c;在listWidget中双击某个账号的时候&#xff0c;将该账号删除 Widget.h #ifndef WIDGET_H #define…

Spring IoC配置(xml+组件类的生命周期方法)

文末有本篇文章对应的项目源码文件可供下载 生命周期方法概念 我们可以在组件类中定义一个或者两个方法&#xff0c;然后当Spring IoC容器实例化和销毁组件类对象的时候进行自动调用.我们定义的方法就叫做组件的生命周期方法. 类似于Servlet的init/destroy方法,Tomcat可以在…

一篇吃透模型:all-MiniLM-L6-v2

MiniLM 是什么&#xff1f; MiniLM 是微软研究院开发的一种轻量级的语言模型&#xff0c;旨在以较小的参数量和计算成本实现与大型语言模型&#xff08;如 BERT&#xff09;相当的性能。它是基于 Transformer 架构的预训练模型&#xff0c;通过深度自注意力蒸馏&#xff08;De…

vue3之echarts仪表盘

vue3之echarts仪表盘 效果如下&#xff1a; 版本 "echarts": "^5.5.1" 核心代码&#xff1a; <template><div ref"chartRef" class"circle"></div> </template> <script lang"ts" setup>…

【C语言初阶】操作符_作业详解的一些疑问

前言&#xff1a; b站鹏哥视频&#xff0c;来源以下链接 76. 【C语言初阶】操作符_作业讲解_哔哩哔哩_bilibili 目的&#xff1a; 记录视频里面没有理解的相关知识 疑惑的地方&#xff1a; 对c语言的那个&#xff0c;\n不是特别了解&#xff0c;就是输入了一个字符&#x…

本地部署 DeepSeek:从 Ollama 配置到 Spring Boot 集成

前言 随着人工智能技术的迅猛发展&#xff0c;越来越多的开发者希望在本地环境中部署和调用 AI 模型&#xff0c;以满足特定的业务需求。本文将详细介绍如何在本地环境中使用 Ollama 配置 DeepSeek 模型&#xff0c;并在 IntelliJ IDEA 中创建一个 Spring Boot 项目来调用该模型…

【网络编程】之TCP实现客户端远程控制服务器端及断线重连

【网络编程】之TCP实现客户端远程控制服务器端及断线重连 TCP网络通信实现客户端简单远程控制主机基本功能演示通信过程代码实现服务器模块执行命令模块popen系列函数 客户端模块服务器主程序 windows作为客户端与服务器通信#pragma comment介绍 客户端使用状态机断线重连代码实…

ROS环境搭建

ROS首次搭建环境 注&#xff1a;以下内容都是在已经安装好ros的情况下如何搭建workplace 一、创建工作空间二、创建ROS包三、注意 注&#xff1a;以下内容都是在已经安装好ros的情况下如何搭建workplace 如果没有安装好&#xff0c;建议鱼香ros一步到位:鱼香ROS 我也是装了好久…

centos7操作系统下安装docker,及查看docker进程是否启动

centos7下安装docker&#xff0c;需要用到的yun命令 &#xff08;yum命令用于添加卸载程序&#xff09; 1.设置仓库&#xff1a; yum-config-manager \--add-repo \http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 2.安装 Docker Engine-Community yum in…

IO基础知识和练习

一、思维导图 二、练习 1.使用标准IO函数&#xff0c;实现文件的拷贝 #include <head.h> int main(int argc, const char *argv[]) {FILE *pfopen("./one.txt","r");FILE *fpfopen("./two.txt","r");if(pNULL)PRINT_ERROR(&qu…

Linux驱动开发之串口驱动移植

原理图 从上图可以看到RS232的串口接的是UART3&#xff0c;接下来我们需要使能UART3的收发功能。一般串口的驱动程序在内核中都有包含&#xff0c;我们配置使能适配即可。 设备树 复用功能配置 查看6ull如何进行uart3的串口复用配置&#xff1a; 设备树下添加uart3的串口复用…

2.css简介

什么是css&#xff1a; CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档&#xff08;如 HTML 文档或 XML 应用&#xff09;添加样式&#xff08;字体、间距和颜色等&#xff09;的计算机语言&#xff0c;CSS 文件扩展名为 .…

数据可视化02-PCA降维

一、PCA PCA做什么&#xff1f;找坐标系。 目标&#xff1f;二维降到一维&#xff0c;信息保留最多。 怎么样最好&#xff1f;数据分布最分散的方向&#xff08;方差最大&#xff09;&#xff0c;作为主成分&#xff08;坐标轴&#xff09;。 二、怎么找主成分&#xff1f; …