用最强的ChatGPT o1-preview模型生成极轻量级流程引擎,可直接运行,可扩展多场景

文摘   2024-10-14 07:03   新加坡  

1. 背景与结论

自从ChatGPT o1-preview放出来,在网上时不时看到介绍说这模型会思考,武力值爆棚。于是就试试。

结论武力值的确是爆棚,起码理解设计意图,写代码,快速定位并解决问题的能力,远超一般程序员,起码超过我身边90%以上的中高级程序员。之所以限定中高级程序员,因为再往上还有架构能力我还无法测试验证,无法给出答案。

生成的这个流程引擎框架(代码)适合处理支付业务,也可继续扩展。当前驱动完成类似下面这样的配置:

whenOrderState(CommonOrderState.INIT) // 初始条件:主单状态INIT.onEvent(CommonEvent.CREATE) // 触发事件:创建.transitionOrderStateTo(CommonOrderState.PROCESS) // 推进到:支付中.request(CommonOperation.PAY) // 操作:外发银行   .when("subOrder.currentState == SubOrderState.S") // 银行返回成功推进主单成功      .transitionOrderStateTo(CommonOrderState.SUCCESS)   .when("subOrder.currentState == SubOrderState.F") // 银行返回失败推进主单失败      .transitionOrderStateTo(CommonOrderState.FAIL)   .when("subOrder.currentState == SubOrderState.U && subOrder.webForm != null") // 推进发消息      .notifyNode();

为什么选择这种配置形式?因为简单得像自然语言,看懂单词就知道什么意思。

软件行业应用非常广泛。

比如在知名的测试Mock框架Mockito中,我们这样使用:

when(mockedList.get(0)).thenReturn("first element");

在java的流式代码中,我们这样使用:

names.stream()    .filter(name -> name.startsWith("A"))    .collect(Collectors.toList());
在jQuery中,我们这样使用(很多年前我也写JQuery):
$('#element').css('color', 'red').show()  .click(function() { alert('Clicked!'); });

所有以上这些都有一个共同的特点:链式调用

链式调用有个好处:非常接近自然语言,容易理解。如果扩展一下,专门针对支付领域定制几个专用的语法,既可减少出错可能性,又能提高效率

为什么不使用Activiti、jBPM、liteflow这样成熟的流程引擎框架?原因在后面有详细说明。

2. 效果

核心代码99%都是ChatGPT生成,基本没有动。运行报错就把错误信息扔给GPT,都是秒定位,秒修复。

如果想获取ChatGPT已生成的源代码,请参考“结束语”部分。

支付成功测试:

支付失败测试:

自动生成的JAVA代码:

自动生成的测试用例:

其中一个测试方法示例:

3. 提示词

提供一篇提示词,可直接用于ChatGPT生成所有流程引擎代码,生成内容包括:可直接运行的核心代码,测试代码,常用配置等。生成的代码规范性和可读性都非常高。

这篇文章最有价值的就是这篇提示词。我先做了N轮对话,在生成了完整的可运行代码并验证通过后,再让ChatGPT根据我和它的交互,由它生成一份提示词给我,再做了几次调整后,发起多轮新的独立对话(没有使用以前的上下文)验证基本可行。

需要留意一点:AI每次生成的都不一样,所以仍然可能需要调整,如何调整参考后面的调优说明。

完整提示词如下,有点长,基本就是用自然语言写一篇设计。

=============提示词开始(没有换行,建议使用电脑打开,或向左滑动屏幕=============
提示:角色:你是一位支付领域的java技术专家,同时精通java,架构设计知识,领域驱动设计知识,设计模式知识,代码简洁之道知识,DSL,支付业务,与外部银行渠道的交互流程。任务:请帮助我根据以下详细要求,生成一个流程引擎项目的完整Java代码。
任务概述:● 目标:实现一个可以处理链式请求和操作的流程引擎,例如在进行支付之前先刷新令牌(Token)。● 功能:引擎应支持通过配置状态、事件、操作和转换来定义流程。它应通过构建处理节点的链表并按顺序执行,来处理包括链式在内的操作。● 原子操作:像 SubOrderSendHandler 和 SubOrderCallbackHandler 这样的操作是原子性的,不应处理链式操作。链式应在更高层次(特别是在 FlowEngineServiceImpl 中)管理。● 可扩展性:设计应允许未来的扩展,例如添加新的原子操作如发送通知等。● 测试:提供测试类来验证流程引擎的功能,确保所有代码正确执行。● 可读性:代码可读性强,所有代码要有合适的包名,类注释,属性注释,方法注释,关键代码的注释。所有注释使用中文。● 完整性:代码完整,可直接运行。
详细要求:1. 流程引擎采用DSL设计思路。比如java的流式处理,或者Mockitor的测试条件处理等。
2. 流程引擎脚本涉及的关键字: ○ whenOrderState:初始条件,主订单状态要满足给定条件。比如:whenOrderState(CommonOrderState.INIT)。 ○ onEvent:触发事件。比如:onEvent(CommonEvent.CREATE)。 ○ transitionOrderStateTo:推进主订单状态。比如:transitionOrderStateTo(CommonOrderState.PROCESS)。 ○ request:请求操作。比如:request(CommonOperation.PAY)。when:判断request返回的数据,比如:when("subOrder.currentState == SubOrderState.S")。 ○ notify:发出订单消息给其它域。比如:notify()。 ○ then:进入子流程。比如:when("subOrder.currentState == SubOrderState.S").then(xxx)。 ○ subFlow:子流程标识。比如subFlow().request(xxx)。
3. 流程引擎脚本配置: ○ 要求所有流程脚本不要修改。 ○ 发起支付:whenOrderState(CommonOrderState.INIT) .onEvent(CommonEvent.CREATE) .transitionOrderStateTo(CommonOrderState.PROCESS) .request(CommonOperation.PAY).when("subOrder.currentState == SubOrderState.S").transitionOrderStateTo(CommonOrderState.SUCCESS).when("subOrder.currentState == SubOrderState.F").transitionOrderStateTo(CommonOrderState.FAIL).when("subOrder.currentState == SubOrderState.U && subOrder.webForm != null").notify(); ○ 发起刷新TOKEN后支付:super.whenOrderState(CommonOrderState.INIT) .onEvent(CommonEvent.CREATE) .transitionOrderStateTo(CommonOrderState.PROCESS) .request(CommonOperation.REFRESH_TOKEN) .when("subOrder.currentState == SubOrderState.F").transitionOrderStateTo(CommonOrderState.FAIL) .when("subOrder.currentState == SubOrderState.S").then(subFlow() .request(CommonOperation.PAY) .when("subOrder.currentState == SubOrderState.S") .transitionOrderStateTo(CommonOrderState.SUCCESS) .when("subOrder.currentState == SubOrderState.F") .transitionOrderStateTo(CommonOrderState.FAIL)); ○ 发起支付查询:super.whenOrderState(CommonOrderState.PROCESS) .onEvent(CommonEvent.QUERY) .request(CommonOperation.QUERY).when("subOrder.currentState == SubOrderState.S").transitionOrderStateTo(CommonOrderState.SUCCESS).when("subOrder.currentState == SubOrderState.F").transitionOrderStateTo(CommonOrderState.FAIL).when("subOrder.currentState == SubOrderState.U && subOrder.webForm != null").notify(); ○ 渠道发起支付回调通知:super.whenOrderState(CommonOrderState.PROCESS) .onEvent(CommonEvent.CALLBACK) .request(CommonOperation.PARSE).when("subOrder.currentState == SubOrderState.S").transitionOrderStateTo(CommonOrderState.SUCCESS).when("subOrder.currentState == SubOrderState.F").transitionOrderStateTo(CommonOrderState.FAIL).when("subOrder.currentState == SubOrderState.U && subOrder.webForm != null").notify(); ○ 要注意脚本的层级。比如上面的 .request(CommonOperation.PAY)后面的.when("subOrder.currentState == SubOrderState.S").transitionOrderStateTo(CommonOrderState.SUCCESS)和.when("subOrder.currentState == SubOrderState.F").transitionOrderStateTo(CommonOrderState.FAIL),两者是平级的,不能生成F为S的子结点。
4. groovy脚本支持: ○ 需要支持配置中的groovy脚本。比如.when("subOrder.currentState == SubOrderState.F")中"subOrder.currentState == SubOrderState.F"就是groovy脚本,当脚本结果为真,就执行后面的操作。 ○ 需要在groovy脚本引擎上下文中导入必要的类,包括但不限于 SubOrderState等类,确保脚本不会出错。
5. 包、类、导入和代码规范: ○ 将代码组织到适当的包中,包结构: ■ 包名为 com.yinmo.flowengine,包含以下子包: ● config:用于存放流程配置类。 ● context:用于存放流程上下文类。 ● enums:用于存放枚举类型。 ● handler:用于存放处理器类。 ● model:用于存放模型类。 ● service:用于存放服务类。有子包impl存放实现类。 ● test:用于存放测试类。 ○ 在每个类中包含所有必要的import语句。 ○ 使用标准注解,如 @Service@Component@Slf4j,以及适当的自定义注解。如果是PO类,加上@Builder@Data@ToString@AllArgsConstructor@NoArgsConstructor等。使用lombok取代所有通用的get/set方法。 ○ 注释要求:所有文件要求有类注释,方法注释,属性注释,关键逻辑的注释。类注释要求有作者:隐墨星辰。 ○ 代码风格参考Springboot框架。 ○ 所有类的属性名和方法不能一样。比如不能定义一个属性isCallback,有一个方法也是isCallback(); ○ 除了测试类外,其它正式代码不能有魔法值。
6. 模型: ○ Order 模型,属性包括:String orderId, FlowState previousState, FlowState currentState, Money transactionAmount, List subOrders, String webForm等,增加一个方法transitionToState(FlowState)。 ○ SubOrder 模型,属性包含String subOrderId, String parentOrderId,SubOrderState previousState, SubOrderState currentState, Money transactionAmount, String channelResponseCode, String channelResponseMessage, String standardResponseCode, String standardResponseMessage, String webForm, String sendToChannelContext, String receiveFromChannelContext等,增加一个方法transitionToState(SubOrderState)。 ○ Money 模型。属性:金额、币种。方法:加、减、乘、除等操作。
7. 枚举: ○ 所有枚举全部继承于interface,方便扩展。所有枚举要有description字段,description的内容使用中文描述。 ○ 定义interfaceFlowState ○ 定义interfaceFlowEvent ○ 定义interfaceFlowOperation。包含方法 String name()、String getMethod() 和 boolean isCallback()。isCallback()用于表示是否是一个外部渠道回调操作,回调是直接解析,不需要发给渠道。getMethod()获取方法名,会发给网关,网关根据这个参数组装发给外部渠道的参数。 ○ 定义:CommonOrderState继承FlowState,有INIT, PROCESS, SUCCESS, FAIL。 ○ 定义:SubOrderState继承FlowState,有I(Init), U(Unkown), S(Success), F(Fail)。 ○ 定义:CommonOperation继承FlowOperation,有PAY("pay", false), PAY_QUERY("payQuery", false), REFUND("refund", false), REFRESH_TOKEN("refreshToken", false), PARSE("parse", true)等,需要补充完整其它操作。PAY("pay", false)为例:说明是一个支付操作,“pay"会发给网关,网关根据这个参数组装发给外部渠道的参数,“false"表示是否是一个回调。 ○ 定义:CommonEvent继承FlowEvent,有CREATE(订单创建事件,驱动系统向渠道发起支付退款等操作), QUERY(订单查询事件,驱动系统向渠道发起查询操作), CALLBACK(外部渠道主动回调通知事件,驱动系统直接解析网关接收到的报文)。 ○ 定义节点处理器类型枚举:HandlerNodeType,不需要继承接口。有:TRANSITION(推进主订单状态变更),REQUEST(向外部渠道发送请求,或解析外部渠道回调报文),NOTIFY(发送消息通知其他域)

8. FlowContext 和GatewayCallbackContext: ○ FlowContext 类,包含channelName、 order、event、configName、gatewayCallbackContext 和 subOrder 等属性。 ○ GatewayCallbackContext 类应包含 subOrderId、state、callbackMessage、channelResponseCode 、 channelResponseMessage 、standardResponseCode 、 standardResponseMessage 等属性。 ○ 确保上下文在处理器和服务之间适当传递。
9. AbstractConfig 和 配置实现类: ○ 定义接口:FlowConfig ○ 实现一个 AbstractConfig 类,实现FlowConfig,允许使用构建器模式来定义流程。 ○ AbstractConfig 维护一个 Map<FlowState, Map<FlowEvent, HandlerNode>> 来存储配置。AbstractConfig定义abstract initConfig()让子类实现,在@PostConstruct init()调用initConfig进行初始化,子类在initConfig()配置脚本。 ○ 提供方法来定义状态、事件、转换、请求和通知。 ○ 所有流程配置类继续自AbstractConfig。所有流程配置类提供String name()方法,返回当前的类简要名称用于标识流程名称。示例:getClass().getSimpleName()。 ○ 定义子类:CommonPayConfig ,RefreshTokenPayConfig ,CommonPayQueryConfig,CommonPayCallbackConfig ,全部继承自 AbstractConfig。配置内容见前面的“流程引擎脚本配置”描述,不要修改。
10. 处理节点: ○ 创建一个 HandlerNodeType 枚举,值包括 TRANSITION(推进主订单状态变更)、REQUEST (向外部渠道发送请求,或解释外部渠道主动回调通知的报文)和 NOTIFY(发送消息通知其它域)。 ○ 定义一个 HandlerNode 类,表示流程中的一个节点,包含节点类型、下一个状态、操作、回调处理器和子节点列表等字段。 ○ 确保 HandlerNode 能通过其子节点来完成链式操作。
11. 处理器和服务: ○ 创建一个 SubOrderHandler 类,根据操作委托给 SubOrderSendHandler 或 SubOrderCallbackHandler。 ○ SubOrderSendHandler 和 SubOrderCallbackHandler 只处理原子操作,不处理链式操作。 ○ SubOrderHandler:负责子订单业务。 ○ SubOrderSendHandler:创建子订单,保存到数据库,组装网关报文,发送给网关,由网关发送给外部渠道,解析渠道返回的报文,更新子订单,保存子订单最新数据到数据库。把子订单放到FlowContext中。 ○ SubOrderCallbackHandler:创建子订单,解析渠道主动回调通知返回的报文,更新子订单,保存子订单最新数据到数据库。把子订单放到FlowContext中。 ○ 定义HandlerNode用于节点处理。 ○ 定义FlowEngineService 和“FlowEngineServiceImpl”,有方法execute(FlowContext)。 ○ FlowEngineServiceImpl 类通过执行从配置生成的处理节点列表来处理流程。 ○ FlowEngineServiceImpl 的 execute() 方法应迭代处理节点,并根据需要处理链式操作,通过递归处理子节点来实现。 ○ FlowEngineServiceImpl不需要带参构造函数。增加属性@Autowired List configs, Map<String, Config> configMap; 提供一个@PostConstruct init()方法用于初始化,在init()方法中,把自动装配的List configs转存到configMap,在execute方法中直接使用configMap.get(context.getConfigName())获取配置。初始化完成后,使用fastjson格式化打印configMap的内容。
12. 日志: ○ 在需要日志的类中使用 @Slf4j ○ 以下情况需要打印日志:关键处理,状态变更,只写了空方法还没有具体实现的方法。
13. 测试: ○ 编写测试类:CommonPayTest, CommonPayQueyTest,CommonPayCallbackConfig ,RefreshTokenPayTest。 ○ 所有测试类使用Mockitor进行mock子订单的返回值。数据校验使用断言。 ○ 所有测试类需要有三个方法:testSubOrderSuccess(), testSubOrderSuccessFail(),testSubOrderUnkown()。分别是子订单返回成功,返回失败,返回未知。 ○ 使用注解的形式使用Mock。

14. 代码质量: ○ 确保所有类都有完整的包名和导入语句。 ○ 方法和属性应有清晰简洁的注释,解释其用途。 ○ 代码应组织良好、可读,并遵循Java最佳实践。 ○ 整个代码库应编译并运行无误。
注意:请提供所有类的完整代码,包括包声明、导入语句、类定义、方法,以及任何必要的辅助类或接口。确保代码是自包含的,不依赖于标准Java库和常用框架(如Spring)之外的外部依赖,如果有,需要给出maven配置,比如groovy,junit等。
示例结构:● com.yinmo.flowengine.enums ● com.yinmo.flowengine.handler ● com.yinmo.flowengine.config● com.yinmo.flowengine.context● com.yinmo.flowengine.model● com.yinmo.flowengine.service● com.yinmo.flowengine.test
指示:● 参考使用上述结构和要求,生成流程引擎项目的完整Java代码。● 确保所有类都完整实现了必要的逻辑,import正确,并正确交互。● 按照指定添加注释、注解和日志。● 提供测试类,包含适当的测试方法以验证流程。

=============提示词结束=============


4. 调优

因为AI每次生成的东西都或多或少有一些不一样,所以需要调优,直到满足自己的设计意图为止

好在调优不需要自己写代码,直接把想做的,想优化的,或者出错信息给ChatGPT,基本都是秒定位,秒解决。

还会给出思考过程,比如:

5. 为何重复造流程引擎的轮子

一是本人乐意,可以学点新东西。二是这个轮子核心代码只有几百行,极其轻量级。三是在支付系统中,流程编排随处可见,比如调用外部的渠道进行支付。而市场上的流程引擎因为考虑通用性,配置都较为复杂。像Activiti、jBPM、liteflow都试用过。

Activiti和jBPM:配置文件非常繁琐。

liteflow:配置文件很简单,但是配置上只知道节点的流转,核心业务逻辑在代码里面,比如什么条件下推进到成功在配置上是看不出来的。

下面是一个支付流程编排图:

想要这样的配置

whenOrderState(CommonOrderState.INIT) // 初始条件:主单状态INIT.onEvent(CommonEvent.CREATE) // 触发事件:创建.transitionOrderStateTo(CommonOrderState.PROCESS) // 推进到:支付中.request(CommonOperation.PAY) // 操作:外发银行   .when("subOrder.currentState == SubOrderState.S") // 银行返回成功推进主单成功      .transitionOrderStateTo(CommonOrderState.SUCCESS)   .when("subOrder.currentState == SubOrderState.F") // 银行返回失败推进主单失败      .transitionOrderStateTo(CommonOrderState.FAIL)   .when("subOrder.currentState == SubOrderState.U && subOrder.webForm != null") // 推进发消息      .notifyNode();

通过这个配置,知道初始状态,触发条件,如何推进。

Activiti和jBPM类似,配置差不多长这样:

liteflow大概长这样:

配置简单,但是需要配合代码才知道怎么做了推进。无法在配置上看清楚,如何怎么推进到成功。

6. 结束语

如果要我说说感想,我只能说,AI的发展是“日新月异”。

我不知道AI后面会不会让我丢了工作,起码目前为止,我们需要好好利用AI来提高工作效率,多一些工作产出,倒是更现实一点。

最后想重复提一句,ChatGPT的o1-preview真是强到离谱,文章中涉及的代码99%都是AI生成的,我基本只描述需求,ChatGPT生成代码,我拿到代码去跑一下,跑不过就把错误信息抛给GPT,如果跑得过但是觉得设计不好,也再提需求。基本都是秒解决,还给出详细分析。

如果想要本次ChatGPT o1-preview模型生成的源代码,可加个人微信,添加备注:gpt。

欢迎关注公众号“隐墨星辰”,和我一起深入解码支付系统设计与实现的方方面面。

隐墨星辰
支付/投资/成长,随手记录点滴,待它日回望,知我曾来过。