在前面的讨论中,我们通过AI助手快速浏览并分析了LlamaIndex的核心源码及其可视化部分。在上次的工作中,我们已基本完成了使用Java版本实现的可视化部分,尽管在工作流(workflow)的分析上只是进行了初步探讨。今天,我们将深入探讨一个关键问题:能否将LlamaIndex在Python中的业务流程和核心代码,成功迁移并转化为Java版本。

接下来,我们将直接进入正题。首先,我们回顾一下LlamaIndex的整体架构和核心功能,然后着手进行Java版本的开发实现。

Workflow

可能大家已经有些遗忘了之前的细节,因此仅通过文字描述并记录下来,可能无法像可视化图示那样快速有效地帮助我们回忆起关键内容。为了更清晰地梳理思路,并帮助大家更直观地理解和回顾,我绘制一张简要的总结框架图。

简要总结框架图

首先,我们将从一个简洁的角度,回顾几个关键的核心类,并详细分析它们各自的属性和方法。如图所示:

剩下的部分就是至关重要的业务流程类 workflow 了。为了确保我们对整体业务流程有一个清晰的认知,我们可以先对业务流程进行一个简要的梳理。这里不需要过多关注细节,细节部分可以通过查看源码来进一步探讨。

好的,接下来我们将逐一通过AI助手来帮助我们完成代码转化的工作。虽然我们清楚地知道,AI的输出可能无法达到100%的完美效果,但即便如此,借助AI的辅助,至少可以大幅度提高效率,预计能够节省大约50%的编码时间。我们现在就开始吧。

设计

Event

同样直接询问助手即可。

接下来,我将根据AI助手提供的初步方案进行进一步的优化和调整。得到最终结果代码如下:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class ToolEvent { /**
* 事件id
*/
private String eventId; /**
* 事件name
*/
private String eventName; /**
* 存储各节点数据,并暴露出方法供其他人调用
*/
private Map<String,Object> eventData = new HashMap<>(); public ToolEvent(Map<String, Object> params) {
this.eventData.putAll(params);
} public Object get(String key) {
key = this.getClass().getSimpleName() + "." + key;
if (this.eventData.containsKey(key)) {
return this.eventData.get(key);
} else {
throw new IllegalArgumentException("No such key: " + key);
}
} public void set(String key, Object value) {
key = this.getClass().getSimpleName() + "." + key;
this.eventData.put(key, value);
} public boolean containsKey(String key) {
key = this.getClass().getSimpleName() + "." + key;
return this.eventData.containsKey(key);
} public Set<String> keySet() {
return this.eventData.keySet();
} public Collection<Object> values() {
return this.eventData.values();
} public Set<Map.Entry<String, Object>> entrySet() {
return this.eventData.entrySet();
} public int size() {
return this.eventData.size();
} public boolean isEmpty() {
return this.eventData.isEmpty();
} public void clear() {
this.eventData.clear();
} public Map<String, Object> toMap() {
return this.eventData;
} /**
* eventName默认为类名
*/
public String getEventName() {
if (this.eventName == null) {
this.eventName = this.getClass().getSimpleName();
}
return this.eventName;
}
}

可以看到,在此代码中我实现的是一个最基础的版本。我们并不打算在初期阶段实现所有功能,而是先着手于构建一个简化版的工作流系统。这样做的目的是先实现一个基础的可运行版本,再在此基础上进行优化和改进,以便最终得到一个更加高效且符合需求的解决方案。

接下来,实现工作流中的开始节点和结束节点的生成,这一过程同样相对简单。以下是相应的代码实现:

@Data
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class StartEvent extends ToolEvent { private String eventName = "start";
public StartEvent(Map<String, Object> params) {
super(params);
}
} @Data
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class StopEvent extends ToolEvent { private String eventName = "end";
/**
* 结果返回
*/
private String result; public StopEvent(String params) {
result = params;
}
}

LlamaIndex的事件封装了很多其他功能和细节,这些内容虽然很有用,但在当前阶段我们先不深入探讨。

Step注解

然后我们看下注解,这部分也可以询问下AI助手,如图所示:

不过Python的装饰器并不和Java注解一样,所以我们先来自己实现一下。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Step { // String eventName();
Class<? extends ToolEvent>[] acceptedEvents();
int numWorkers() default 10; // Class<?>[] returnTypes();
// RetryPolicy retryPolicy() default RetryPolicy.DEFAULT;
}

workflow

接下来,我们将着手实现工作流的主要流程。这一部分相对较为复杂,主要因为涉及的业务流程非常庞大且复杂,因此需要一定的时间和精力进行处理。为了简化我们的工作,首先我们可以参考AI助手的实现方式,通过分析其设计思路和工作原理,帮助我们更好地理解如何进行具体的实现。

在此基础上,我们再根据实际需求对流程进行必要的裁剪和优化。如下图所示:

最后,这部分代码有些多,我就简单的将主要流程写下来。代码如下:

@Data
@Slf4j
public abstract class Workflow { /**
* 工作流超时时间
*/
private int timeout = 10;
/**
* 是否输出详细日志
*/
private boolean verbose = false; /**
* 校验开关
*/
private boolean validation = false;
/**
* 校验开关
*/
private boolean showUI = false; /**
* 1:扫描当前类的所有带有 @Step 注解的方法
* 2:根据步骤顺序,依次执行各个步骤
*/
public String run(String jsonString) throws IOException{}
/**
*初始化工作流
*/
private WorkflowContext initialContext() {}

WorkflowContext

最关键的因素在于工作流上下文的设计,因为在这种架构下,所有节点都能够共享全局变量。这一特性保证了工作流中不同节点之间的数据传递和协调,从而提高了整个系统的灵活性和便利性。如果没有这样的共享机制,工作流的效率和可操作性将大大降低,失去其原本的优势。

我们先去询问下AI助手如何实现。如图所示:

由于LlamaIndex提供了许多功能,因此其实现显得相对复杂。为了简化开发过程,我们决定剔除一些不必要的功能,比如类的序列化,这一功能主要用于恢复和加载工作流。然而,我们的目标是实现一个最基本且可行的工作流。最终代码如下:

@Slf4j
@Data
public class WorkflowContext {
/**
* 是否是单步模式
*/
private boolean stepwise;
/**
* 是否正在运行
*/
private boolean isRunning; /**
* 当前运行的事件
*/
private ToolEvent stepEventHolding; /**
* 事件队列:k:方法名,v:队列
*/
private Map<String, ArrayBlockingQueue<ToolEvent>> eventQueue; private List<Thread> tasks = new ArrayList<>(); private Map<String,Object> globalContext; private String result;
//画图
private Graph graph = new MultiGraph("workflow");
public WorkflowContext(boolean stepwise){
System.setProperty("org.graphstream.ui", "swing");
this.stepwise = stepwise;
this.isRunning = false;
this.eventQueue = new ConcurrentHashMap<>();
this.stepEventHolding = null;
this.globalContext = new ConcurrentHashMap<>();
this.result = null;
//添加开始和结束节点
Node nodeA = graph.addNode("start");
Node nodeB = graph.addNode("end");
} public void addThread(Thread thread) {
tasks.add(thread);
} public void sendEvent(ToolEvent value) {}

我们去除了一些东西,加了一个上一章节我们讨论的流的可视化。并且需要实现发布事件功能。

WorkflowHandler

最后加一个处理类,同样直接问一下AI助手,帮助我们去实现一下基本业务逻辑,如图所示:

然后我把所有没有用的逻辑全都去除掉,最后剩下这些代码,如下所示:

@Slf4j
@Data
@AllArgsConstructor
public class WorkflowHandler { private WorkflowContext context; public void handleTask(int timeout){}

接下来,我们需要填充基本的业务逻辑部分,这一阶段的工作主要涉及实现具体的功能和处理流程,确保工作流能够按照预期正常运行。由于这部分代码涉及到特定的业务需求和内部实现细节,因此暂时不公开。工作流启动日志如下:

最终的效果如图所示:

总结

通过以上的分析和实践,我们成功地对LlamaIndex的核心功能进行了回顾,并逐步将其Python版的业务流程和核心代码迁移到Java实现。尽管在过程中遇到了一些挑战,如工作流的复杂性、事件和注解的差异等,但借助AI助手的辅助,我们能够高效地完成了代码转换和初步实现。

接下来的步骤,将是基于当前实现,进一步完善各个模块,优化工作流的执行效率,提升系统的可靠性和扩展性。


我是努力的小雨,一名 Java 服务端码农,潜心研究着 AI 技术的奥秘。我热爱技术交流与分享,对开源社区充满热情。同时也是一位腾讯云创作之星、阿里云专家博主、华为云云享专家、掘金优秀作者。

我将不吝分享我在技术道路上的个人探索与经验,希望能为你的学习与成长带来一些启发与帮助。

欢迎关注努力的小雨!

借助AI助手快速解析LlamaIndex的Workflow设计与Java迁移的更多相关文章

  1. 最佳案例 | 游戏知几 AI 助手的云原生容器化之路

    作者 张路,运营开发专家工程师,现负责游戏知几 AI 助手后台架构设计和优化工作. 游戏知几 随着业务不断的拓展,游戏知几AI智能问答机器人业务已经覆盖了自研游戏.二方.海外的多款游戏.游戏知几研发团 ...

  2. 微软推出中文学习AI助手Microsoft Learn Chinese

    ​ 编者按:美国总统特朗普访华期间,他6岁的外孙女阿拉贝拉用中文普通话演唱和背诵传统诗歌的视频在中国社交媒体上引起广泛关注,可以感受得到,越来越多的人对中文学习充满了兴趣.智能私教微软小英帮助很多中国 ...

  3. 利用android studio gsonformat插件快速解析复杂json

    在android开发过程中,难免会遇到json解析,在这篇文章中为你快速解析复杂的json. 首先,在android studio中安装gsonformat插件. 点击File->Setting ...

  4. [Swift通天遁地]七、数据与安全-(2)对XML和HTML文档的快速解析

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  5. 1.svn 彻底clear时,注意代码备份 2.借助vc助手加头文件

    1.svn 彻底clear时,注意代码备份 2.不小心彻底clear可以在回收站找到 3.借助vc助手加头文件

  6. Ubuntu下借助URLOS实现快速安装DzzOffice企业办公套件

    如今,越来越多的个人.团队甚至企业都在使用GSuite或者Office365等网络办公套件,为什么人们越来越喜爱使用网络办公套件?一方面是考虑数字资产的安全性以及管理效率,另一方面则是日益增大的协同办 ...

  7. Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so)

    本文首发于 Ficow Shen's Blog,原文地址: Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so). 内容概览 前言 ...

  8. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  9. 开源一个CSV解析器(附设计过程 )

    在ExcelReport支持csv的开发过程中,需要一个NETStandard的csv解析器.在nuget上找了几个试用,但都不太适合. 于是,便有了:AxinLib.IO.CSV. 先看看怎么用: ...

  10. Atitit。Tree文件解析器的原理流程与设计实现  java  c# php js

    Atitit.Tree文件解析器的原理流程与设计实现  java  c# php js 1. 解析原理与流程1 1.1. 判断目录  ,表示服  dirFlagChar = "└├─&quo ...

随机推荐

  1. 普元中间件Primeton AppServer6.5安装(Windows)

    本文在Windows环境下安装普元中间件Primeton AppServer6.5(以下简称PAS) 一.安装前准备 1.1使用软件版本 Primeton_AppServer_6.5_Enterpri ...

  2. laravel框架中上传图片,并在本地显示

    1 //处理文件上传 2 if ($request->hasFile('image')&&$request->file('image')->isValid()){ 3 ...

  3. Android Qcom USB Driver学习(七)

    最近遇到了USB 插拔后,系统重启的问题,抓取串口log发现如下问题,log中查看trace分析就是空指针造成的panic Unable to handle kernel read from unre ...

  4. Android平台下的cpu利用率优化实现

    目录 背景 CPU调频 概念 实现 验证 线程CPU亲和性 概念 亲和性控制 API 应用层控制实现 验证 线程优先级 概念 实现 验证 背景 为了进一步优化APP性能,最近针对如何提高应用对CPU的 ...

  5. windows下配置pytorch环境

    借鉴了B站大佬的视频,自己总结安装如下. 首先安装anaconda 按照操作顺序,依次安装,按照我个人习惯,不喜欢讲文件安装在C盘,你们自己决定. 安装完毕之后. 之后打开Anaconda Promp ...

  6. OOOPS:零样本实现360度开放全景分割,已开源 | ECCV'24

    全景图像捕捉360°的视场(FoV),包含了对场景理解至关重要的全向空间信息.然而,获取足够的训练用密集标注全景图不仅成本高昂,而且在封闭词汇设置下训练模型时也受到应用限制.为了解决这个问题,论文定义 ...

  7. ADO.NET 事务 transaction

    事务回滚:

  8. vue中的prop组件封装

    学习vue有一段时间了,也写了一些东西.今天看文档突然看到了一个好玩的东西,那就是prop.prop的作用是父组件中引用了子组件并给子组件加了一个属性,这个属性可以是静态的,可以是动态的,可以是数字, ...

  9. 用JavaScriptt从一个路径字符串中获取文件名

    思路 1.通过'\'关键字用split分割成数组 2.取分割后数组的最后一个就是文件名 3.另外,字符串中\是没意义的,需要2个\\ 相关代码 <script> var a='C:\\Pr ...

  10. 搞人工智能开源大语言模型GPT2、Llama的正确姿势

    (如果想及时收到人工智能相关的知识更新,请点击关注!!) 序言:目前我们每一小节的内容都讲解得非常慢,因为这是人工智能研发中的最基础知识.如果我们不能扎实掌握这些知识,将很难理解后续更复杂且实用的概念 ...