在前面的讨论中,我们通过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. OData – 坑

    前言 OData 有很多很多的坑,我的主张是能少用一样是一样,比如 Batch Processing 不要用,Inheritance 不要用,除了 GET 其它 PUT POST DELETE 都不要 ...

  2. Angular 18+ 高级教程 – Component 组件 の Angular Component vs Shadow DOM (CSS Isolation & slot)

    前言 要掌握 Angular,最好先掌握原生. 全局 CSS 的问题,还有如何用原生 CSS 来管理全局 CSS,看这篇. 利用 Shadow Dom 来隔离 CSS 看这篇. CSS Global ...

  3. QT框架实现自定义形状截图效果

    文章目录 QT框架普通截图运行效果 QT框架系统级热键的原理 注册热键 反注册热键 获取系统级唯一的整数ID 删除系统级唯一整数ID 原生事件过滤器 QT框架截图的原理 截图窗口 拉框操作 系统剪切板 ...

  4. [OI] 容斥原理拓展

    10.容斥原理拓展 10.1 二项式反演 \[P.10.1(1) \] 设 \(U=\{S_1,S_2,S_3...S_n\}\),且任意 \(i\) 个元素的交集都相等 定义 \(g(x)\) 为 ...

  5. 如何使用hardware breakpoint

    要使用内核的硬件断点(hardware breakpoint)来定位内核模块中的内存访问问题,你可以通过以下步骤进行设置和调试. 1. 确定要监控的内存地址 首先,你需要确定你想要监控的内存地址.这可 ...

  6. Javascript的基本数据类型和引用数据类型有哪些?null 和 undefined的区别

    基本数据类型 : number string boolean null undefined 引用数据类型: object   -->  function array function and a ...

  7. 018 人生中第一次用 Python 写的一个小程序_猜年龄(再次强调,重视基础)

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  8. 为什么科技企业都在建设API开放平台?

    一.API开发者门户的兴起 随着数字化转型的推进,越来越多的企业开始依赖 API 来实现内部系统的连接与外部服务的集成.然而,企业在API管理方面面临着复杂且繁琐的挑战:API的调用关系混乱.难以追踪 ...

  9. WebAssembly 基础以及结合其他编程语言

    0x00 WebAssembly 基础 详情参考<WebAssembly | MDN> (1)概述 WebAssembly 简称 WASM 或 WA,是一种新的编码方式,可以在现代的 We ...

  10. DiTAC:不知如何提升性能?试试这款基于微分同胚变换的激活函数 | ECCV'24

    非线性激活函数对深度神经网络的成功至关重要,选择合适的激活函数可以显著影响其性能.大多数网络使用固定的激活函数(例如,ReLU.GELU等),这种选择可能限制了它们的表达能力.此外,不同的层可能从不同 ...