AI 联动-工作流
什么是工作流函数
工作流函数(FlowFunctionCalling)是基于 Flowable 工作流引擎的智能函数,允许用户通过自然语言描述自动发起工作流程。系统会自动提取流程参数、匹配流程定义并完成流程启动,实现办公流程的智能化操作。
💡应用场景
支持请假申请、报销审批、采购申请等各类工作流场景。用户只需用自然语言描述需求,如"明天帮我请一天假,好兄弟结婚",系统会自动提取参数并发起流程。
演示视频
业务场景说明
通过自然语言告诉大模型"帮我明天请一天假,明天家里有事",大模型会自动识别意图、提取流程参数(请假天数、开始日期、请假事由),并调用 Flowable 引擎发起请假流程。
执行流程
工作流函数的执行流程包括用户输入、流程匹配、参数提取、权限校验和流程启动五个阶段:
配置工作流程
创建请假流程
进入【协同办公】>【流程管理】>【创建流程】,创建名称为"请假"的流程。
流程表单参数配置
⚠参数ID必须匹配
表单参数的ID必须与代码中定义的参数名称完全一致,否则参数提取会失败。
| 参数名称 | 参数ID | 说明 |
|---|
| 天数 | days | 请假天数,整数类型 |
| 开始日期 | startDate | 请假开始日期,格式 yyyy-MM-dd |
| 事由 | reason | 请假原因,文本类型 |
使用AI助手发起流程
在AI对话界面中,使用自然语言描述请假需求,例如"明天帮我请一天假,好兄弟结婚"。系统会自动提取参数并发起流程。
实现原理
FunctionCalling 接口说明
所有函数必须实现 FunctionCalling<T> 接口,该接口定义了函数调用的核心能力:
showFunction(): 是否在前端展示此函数
showInfo(): 前端显示的函数名称和描述
functionName(): 函数的唯一标识符
routePath(): 点击函数卡片后的跳转路径
接口定义与执行流程
public interface FunctionCalling<T extends BaseAiRequest> extends ToolExecutor {
// 参数校验,子类必须实现
R checkParams(T t, PigxUser userDetails, ChatMessageDTO.ExtDetails extDetails);
// 业务处理,子类必须实现
R<String> handle(T t, PigxUser userDetails, ChatMessageDTO.ExtDetails extDetails);
// 构建工具规格,供大模型理解函数能力
default ToolSpecification buildToolSpecification() {
ToolSpecification.Builder builder = ToolSpecification.builder();
builder.name(this.functionName());
builder.description(this.functionDesc());
Field[] fields = ReflectUtil.getFields(getGenericType());
builder.parameters(ToolSpecificationsUtils.parametersFrom(fields));
return builder.build();
}
// 预处理逻辑,自动完成上下文设置和参数校验
default R preHandle(T t) {
// 1. 验证messageKey
// 2. 查询聊天记录
// 3. 设置上下文(租户、用户、token)
// 4. 调用checkParams校验参数
// 5. 调用handle执行业务逻辑
}
}
ℹ预处理机制
preHandle() 方法会自动处理上下文设置、用户认证、租户隔离等通用逻辑,子类只需实现 checkParams() 和 handle() 两个业务方法。
工作流函数实现
@Component
@RequiredArgsConstructor
public class FlowFunctionCalling implements FunctionCalling<FlowRequest> {
private final RemoteFlowApiFlowService flowService;
// 点击函数卡片后跳转到已发起的流程列表
@Override
public String routePath() {
return "/flow/task/started";
}
// 前端展示的函数说明
@Override
public String showInfo() {
return "请假助手,能根据您的描述帮您发起请求流程调用flowable。比如:明天帮我请一天假,好兄弟结婚";
}
// 参数校验,当前示例直接返回成功
@Override
public R<String> checkParams(FlowRequest request, PigxUser userDetails,
ChatMessageDTO.ExtDetails extDetails) {
return R.ok();
}
// 业务处理:匹配流程并启动
public R<String> handle(FlowRequest request, PigxUser user,
ChatMessageDTO.ExtDetails extDetails) {
// 获取用户有权限启动的流程列表
R<List<FormGroupVo>> listR = flowService.listCurrentUserStartGroup();
if (Objects.isNull(listR.getData())) {
return R.failed("创建失败,权限不足");
}
// 根据流程名称匹配流程ID
String flowId = "";
for (FormGroupVo formGroupVo : listR.getData()) {
for (FormGroupVo.FlowVo item : formGroupVo.getItems()) {
if (StrUtil.containsAnyIgnoreCase(request.getFlowName(), item.getName())) {
flowId = item.getFlowId();
}
}
}
if (StrUtil.isBlank(flowId)) {
return R.failed("创建失败,流程不存在");
}
// 构建流程启动参数
ProcessInstanceParamDto processInstanceParamDto = new ProcessInstanceParamDto();
processInstanceParamDto.setFlowId(flowId);
processInstanceParamDto.setStartUserId(String.valueOf(user.getId()));
Map<String, Object> paramMap = new HashMap<>();
Dict rootUser = Dict.create()
.set("id", processInstanceParamDto.getStartUserId())
.set("name", user.getUsername())
.set("type", NodeUserTypeEnum.USER.getKey());
paramMap.put("root", CollUtil.newArrayList(rootUser));
paramMap.put("days", request.getDays());
paramMap.put("reason", request.getReason());
paramMap.put("startDate", request.getStartDate());
processInstanceParamDto.setParamMap(paramMap);
// 调用Flowable引擎启动流程
flowService.startProcessInstance(processInstanceParamDto);
return R.ok(StrUtil.format("流程发起成功,流程名称:{}", request.getFlowName()));
}
}
请求参数定义
@Data
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonClassDescription("流程信息")
class FlowRequest extends BaseAiRequest {
@FieldPrompt("流程名称:请假流程")
private String flowName;
@FieldPrompt("原因:请假原因")
private String reason;
@FieldPrompt("天数:请假天数")
private Integer days;
@FieldPrompt("开始日期:请假开始日期,格式为 yyyy-MM-dd")
private String startDate;
}
💡注解说明
@FieldPrompt 注解用于提示大模型该字段的含义和格式要求,直接影响参数提取的准确性。描述要清晰明确,必要时提供示例格式。
关键技术点
流程匹配机制
系统通过模糊匹配的方式查找流程:用户输入的流程名称只要包含在实际流程名称中即可匹配成功。例如用户说"请假",可以匹配到"员工请假流程"。
if (StrUtil.containsAnyIgnoreCase(request.getFlowName(), item.getName())) {
flowId = item.getFlowId();
}
⚠匹配精度
如果存在多个名称相似的流程(如"请假流程"和"事假流程"),可能会匹配到第一个符合条件的流程。建议流程命名具有明显区分度。
权限控制
函数会自动获取当前用户有权限启动的流程列表,确保用户只能发起授权范围内的流程。
参数映射
大模型提取的参数会自动映射到 FlowRequest 对象,并通过 paramMap 传递给 Flowable 引擎。参数名称必须与流程表单定义保持一致。