内容概述
前一篇(spring-ai-alibaba 1.0.0.2 学习(十七)——初识graph-CSDN博客)初步介绍了graph:
概念:图、边、节点、状态等,及其核心类和衍生类
使用流程:
1)定义流程图:添加节点,添加边
2)使用流程图:编译图,执行图
但是在定义流程图时,省略了图初始化的过程;
在使用流程图时,省略了参数设置的过程
本篇会补充对应的内容
简单样例
图初始化
KeyStrategyFactory keyStrategyFactory = () -> {HashMap<String, KeyStrategy> keyStrategyHashMap = new HashMap<>();// 用户输入keyStrategyHashMap.put("query", new ReplaceStrategy());keyStrategyHashMap.put("documents", new AppendStrategy());return keyStrategyHashMap;};StateGraph stateGraph = new StateGraph(keyStrategyFactory)...
在新版本1.0.0.3中,状态图StateGraph的初始化不再建议使用OverAllStateFactory,而是改用KeyStrategyFactory
KeyStrategyFactory实际就是一个 Supplier<Map<String, KeyStrategy>>,一个Map<String, KeyStrategy>的提供者
而其提供的Map<String, KeyStrategy>,key是参数名,value是该参数的更新策略,用来指定全局状态类OverAllState的某个参数的更新策略
提到KeyStrategy,就需要先了解OverAllState,全局状态类OverAllState,内部维护了一个Map<String, Object> data 用来保存各种状态参数,如果将该类提炼为一个接口,那对外提供的最主要的方法其实就是一个:
OverAllState updateState(Map<String, Object> nodeOutput);
也就是用节点的输出来更新全局状态的data,并返回一个新的全局状态
而 KeyStrategy 就是在这个环节中生效,用来指定 OverAllState 中某个参数,是如何与节点输出进行合并的
比如常见的ReplaceStrategy,就是直接用nodeOutput中的值替换掉data中的值,例如样例中的query参数
另一个 KeyStrategy 的子类 AppendStrategy,主要用于参数的类型是List的时候,是将nodeOutput和data的某个参数的元素进行去重生成新 List,例如样例中的documents参数
子类MergeStrategy,主要用于参数的类型是Map的时候,用节点输出结果nodeOutput覆盖全局状态中data的值(如果存在的话)
所以KeyStrategyFactory最终就是负责提供状态参数的更新策略
在并行节点中,若某个结果的key不设置更新策略,那即使节点输出中包含该key,也不会被更新进入全局状态OverAllState中(普通节点不存在这个问题,会默认使用覆盖策略,不知道是不是bug)
ps:graph默认会为“input”添加一个ReplaceStrategy的更新策略
参数设置(可选参数)
编译图的参数
SaverConfig saverConfig = SaverConfig.builder().register(SaverConstant.MEMORY, new MemorySaver()).build();
CompileConfig complieConfig = CompileConfig.builder().saverConfig(saverConfig).interruptBefore("humanfeedback").build(); //CompileConfig 参数可省略
//CompiledGraph compiledGraph = stateGraph.compile();
CompiledGraph compiledGraph = stateGraph.compile(compileConfig);
...
编译图时,有一个可选参数 CompileConfig,编译参数,主要是用来生成 CompiledGraph,内部包含如下属性:
SaverConfig:保存各种类型的检查点保存器,缺省状态下,CompileConfig会创建一个MemorySaver放到SaverConfig中
Map<String, BaseCheckpointSaver>:key 为保存器的类型,如Memory
String type:默认类型,调用无参的 get 方法时,从Map中获取该默认类型对应的BaseCheckpointSaver
lifecycleListeners:图生命周期监听器的队列,处理时先进后出,目前支持开始节点、结束节点、报错、节点前、节点后等几种触发情景。
interruptsBefore:Set<String> 类型,值为nodeId,表示在该 node 之前加入中断
interruptsAfter:Set<String> 类型,值为nodeId,表示在该 node 之后加入中断
ps:除了这些,CompiledGraph 还有个设置,即最大执行步骤数,代表图中节点总共的可执行次数,每执行一个节点算一次,需要调用 CompiledGraph.setMaxIterations 方法设置,不在 CompileConfig 中
执行图的参数
RunnableConfig runnableConfig = RunnableConfig.builder().threadId(threadId).build();Map<String, Object> objectMap = new HashMap<>();objectMap.put("query", query);objectMap.put("documents", List.of(document));//RunnableConfig 参数可以省略//AsyncGenerator<NodeOutput> resultFuture = compiledGraph.invoke(objectMap);AsyncGenerator<NodeOutput> resultFuture = compiledGraph.invoke(objectMap, runnableConfig);...
CompiledGraph执行时,需要两个参数
Map<String, Object>:对应全局状态中的data,是执行图时传入的初始参数
该Map的 key 需要对应前面的 KeyStrategyFactory 中 返回Map的 key,否则该参数无法更新
RunnableConfig:运行时配置,是一个可选参数,主要存放线程id threadId、检查点id checkPointId,下一节点id nextNode,metaData 等信息。
threadId: 主要是用来区分会话的,在前端另开一个会话,就会新建一个 threadId,不同会话之间状态(OverAllState)不共享
checkPointId:猜测是用于时间旅行,即重新回到某个节点,错误恢复和人工介入目前不需要传递该参数,会自动获取最新存档
metaData:运行时的其他配置,比如llm中实际使用的大模型型号,不想污染OverAllState时可以在这里设置