当前位置: 首页 > news >正文

聊聊Spring AI Alibaba的PlantUMLGenerator

本文主要研究一下Spring AI Alibaba的PlantUMLGenerator

DiagramGenerator

spring-ai-alibaba-graph/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/DiagramGenerator.java

public abstract class DiagramGenerator {public enum CallStyle {DEFAULT, START, END, CONDITIONAL, PARALLEL}public record Context(StringBuilder sb, String title, boolean printConditionalEdge, boolean isSubGraph) {static Builder builder() {return new Builder();}static public class Builder {String title;boolean printConditionalEdge;boolean IsSubGraph;private Builder() {}public Builder title(String title) {this.title = title;return this;}public Builder printConditionalEdge(boolean value) {this.printConditionalEdge = value;return this;}public Builder isSubGraph(boolean value) {this.IsSubGraph = value;return this;}public Context build() {return new Context(new StringBuilder(), title, printConditionalEdge, IsSubGraph);}}/*** Converts a given title string to snake_case format by replacing all* non-alphanumeric characters with underscores.* @return the snake_case formatted string*/public String titleToSnakeCase() {return title.replaceAll("[^a-zA-Z0-9]", "_");}/*** Returns a string representation of this object by returning the string built in* {@link #sb}.* @return a string representation of this object.*/@Overridepublic String toString() {return sb.toString();}}/*** Appends a header to the output based on the provided context.* @param ctx The {@link Context} containing the information needed for appending the* header.*/protected abstract void appendHeader(Context ctx);/*** Appends a footer to the content.* @param ctx Context object containing the necessary information.*/protected abstract void appendFooter(Context ctx);/*** This method is an abstract method that must be implemented by subclasses. It is* used to initiate a communication call between two parties identified by their phone* numbers.* @param ctx The current context in which the call is being made.* @param from The phone number of the caller.* @param to The phone number of the recipient.*/protected abstract void call(Context ctx, String from, String to, CallStyle style);/*** Abstract method that must be implemented by subclasses to handle the logic of* making a call.* @param ctx The context in which the call is being made.* @param from The phone number of the caller.* @param to The phone number of the recipient.* @param description A brief description of the call.*/protected abstract void call(Context ctx, String from, String to, String description, CallStyle style);/*** Declares a conditional element in the configuration or template. This method is* used to mark the start of a conditional section based on the provided {@code name}.* It takes a {@code Context} object that may contain additional parameters necessary* for the declaration, and a {@code name} which identifies the type or key associated* with the conditional section.* @param ctx The context containing contextual information needed for the* declaration.* @param name The name of the conditional section to be declared.*/protected abstract void declareConditionalStart(Context ctx, String name);/*** Declares a node in the specified context with the given name.* @param ctx the context in which to declare the node {@code @literal (not null)}* @param name the name of the node to be declared* {@code @literal (not null, not empty)}*/protected abstract void declareNode(Context ctx, String name);/*** Declares a conditional edge in the context with a specified ordinal.* @param ctx the context* @param ordinal the ordinal value*/protected abstract void declareConditionalEdge(Context ctx, int ordinal);/*** Comment a line in the given context.* @param ctx The context in which the line is to be commented.* @param yesOrNo Whether the line should be uncommented ({@literal true}) or* commented ({@literal false}).*/protected abstract void commentLine(Context ctx, boolean yesOrNo);/*** Generate a textual representation of the given graph.* @param nodes the state graph nodes used to generate the context, which must not be* null* @param edges the state graph edges used to generate the context, which must not be* null* @param title The title of the graph.* @param printConditionalEdge Whether to print the conditional edge condition.* @return A string representation of the graph.*/public final String generate(StateGraph.Nodes nodes, StateGraph.Edges edges, String title,boolean printConditionalEdge) {return generate(nodes, edges,Context.builder().title(title).isSubGraph(false).printConditionalEdge(printConditionalEdge).build()).toString();}/*** Generates a context based on the given state graph.* @param nodes the state graph nodes used to generate the context, which must not be* null* @param edges the state graph edges used to generate the context, which must not be* null* @param ctx the initial context, which must not be null* @return the generated context, which will not be null*/protected final Context generate(StateGraph.Nodes nodes, StateGraph.Edges edges, Context ctx) {appendHeader(ctx);for (var n : nodes.elements) {if (n instanceof SubGraphNode subGraphNode) {@SuppressWarnings("unchecked")var subGraph = (StateGraph) subGraphNode.subGraph();Context subgraphCtx = generate(subGraph.nodes, subGraph.edges,Context.builder().title(n.id()).printConditionalEdge(ctx.printConditionalEdge).isSubGraph(true).build());ctx.sb().append(subgraphCtx);}else {declareNode(ctx, n.id());}}final int[] conditionalEdgeCount = { 0 };edges.elements.stream().filter(e -> !Objects.equals(e.sourceId(), START)).filter(e -> !e.isParallel()).forEach(e -> {if (e.target().value() != null) {conditionalEdgeCount[0] += 1;commentLine(ctx, !ctx.printConditionalEdge());declareConditionalEdge(ctx, conditionalEdgeCount[0]);}});var edgeStart = edges.elements.stream().filter(e -> Objects.equals(e.sourceId(), START)).findFirst().orElseThrow();if (edgeStart.isParallel()) {edgeStart.targets().forEach(target -> {call(ctx, START, target.id(), CallStyle.START);});}else if (edgeStart.target().id() != null) {call(ctx, START, edgeStart.target().id(), CallStyle.START);}else if (edgeStart.target().value() != null) {String conditionName = "startcondition";commentLine(ctx, !ctx.printConditionalEdge());declareConditionalStart(ctx, conditionName);edgeCondition(ctx, edgeStart.target().value(), START, conditionName);}conditionalEdgeCount[0] = 0; // resetedges.elements.stream().filter(e -> !Objects.equals(e.sourceId(), START)).forEach(v -> {if (v.isParallel()) {v.targets().forEach(target -> {call(ctx, v.sourceId(), target.id(), CallStyle.PARALLEL);});}else if (v.target().id() != null) {call(ctx, v.sourceId(), v.target().id(), CallStyle.DEFAULT);}else if (v.target().value() != null) {conditionalEdgeCount[0] += 1;String conditionName = format("condition%d", conditionalEdgeCount[0]);edgeCondition(ctx, v.targets().get(0).value(), v.sourceId(), conditionName);}});appendFooter(ctx);return ctx;}/*** Evaluates an edge condition based on the given context and condition.* @param ctx the current context used for evaluation* @param condition the condition to be evaluated* @param k a string identifier for the condition* @param conditionName the name of the condition being processed*/private void edgeCondition(Context ctx, EdgeCondition condition, String k, String conditionName) {commentLine(ctx, !ctx.printConditionalEdge());call(ctx, k, conditionName, CallStyle.CONDITIONAL);condition.mappings().forEach((cond, to) -> {commentLine(ctx, !ctx.printConditionalEdge());call(ctx, conditionName, to, cond, CallStyle.CONDITIONAL);commentLine(ctx, ctx.printConditionalEdge());call(ctx, k, to, cond, CallStyle.CONDITIONAL);});}}

DiagramGenerator是个抽象类,定义了流程图生成的基类,它提供了appendHeader、appendFooter、call、declareConditionalStart、declareNode、declareConditionalEdge、commentLine抽象方法;它提供了generate方法根据nodes、edges、ctx生成图的文字表示。

PlantUMLGenerator

spring-ai-alibaba-graph/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/diagram/PlantUMLGenerator.java

public class PlantUMLGenerator extends DiagramGenerator {@Overrideprotected void appendHeader(Context ctx) {if (ctx.isSubGraph()) {ctx.sb().append(format("rectangle %s [ {{\ntitle \"%s\"\n", ctx.title(), ctx.title())).append(format("circle \" \" as %s\n", START)).append(format("circle exit as %s\n", END));}else {ctx.sb().append(format("@startuml %s\n", ctx.titleToSnakeCase())).append("skinparam usecaseFontSize 14\n").append("skinparam usecaseStereotypeFontSize 12\n").append("skinparam hexagonFontSize 14\n").append("skinparam hexagonStereotypeFontSize 12\n").append(format("title \"%s\"\n", ctx.title())).append("footer\n\n").append("powered by spring-ai-alibaba\n").append("end footer\n").append(format("circle start<<input>> as %s\n", START)).append(format("circle stop as %s\n", END));}}@Overrideprotected void appendFooter(Context ctx) {if (ctx.isSubGraph()) {ctx.sb().append("\n}} ]\n");}else {ctx.sb().append("@enduml\n");}}@Overrideprotected void call(Context ctx, String from, String to, CallStyle style) {ctx.sb().append(switch (style) {case CONDITIONAL -> format("\"%s\" .down.> \"%s\"\n", from, to);default -> format("\"%s\" -down-> \"%s\"\n", from, to);});}@Overrideprotected void call(Context ctx, String from, String to, String description, CallStyle style) {ctx.sb().append(switch (style) {case CONDITIONAL -> format("\"%s\" .down.> \"%s\": \"%s\"\n", from, to, description);default -> format("\"%s\" -down-> \"%s\": \"%s\"\n", from, to, description);});}@Overrideprotected void declareConditionalStart(Context ctx, String name) {ctx.sb().append(format("hexagon \"check state\" as %s<<Condition>>\n", name));}@Overrideprotected void declareNode(Context ctx, String name) {ctx.sb().append(format("usecase \"%s\"<<Node>>\n", name));}@Overrideprotected void declareConditionalEdge(Context ctx, int ordinal) {ctx.sb().append(format("hexagon \"check state\" as condition%d<<Condition>>\n", ordinal));}@Overrideprotected void commentLine(Context ctx, boolean yesOrNo) {if (yesOrNo)ctx.sb().append("'");}}

PlantUMLGenerator实现了DiagramGenerator的抽象方法

StateGraph

spring-ai-alibaba-graph/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/StateGraph.java

/*** Represents a state graph with nodes and edges.**/
public class StateGraph {public static String END = "__END__";public static String START = "__START__";final Nodes nodes = new Nodes();final Edges edges = new Edges();private OverAllState overAllState;private String name;public OverAllState getOverAllState() {return overAllState;}public StateGraph setOverAllState(OverAllState overAllState) {this.overAllState = overAllState;return this;}private final PlainTextStateSerializer stateSerializer;//....../*** Instantiates a new State graph.* @param overAllState the over all state* @param plainTextStateSerializer the plain text state serializer*/public StateGraph(OverAllState overAllState, PlainTextStateSerializer plainTextStateSerializer) {this.overAllState = overAllState;this.stateSerializer = plainTextStateSerializer;}public StateGraph(String name, OverAllState overAllState) {this.name = name;this.overAllState = overAllState;this.stateSerializer = new GsonSerializer();}/*** Instantiates a new State graph.* @param overAllState the over all state*/public StateGraph(OverAllState overAllState) {this.overAllState = overAllState;this.stateSerializer = new GsonSerializer();}public StateGraph(String name, AgentStateFactory<OverAllState> factory) {this.name = name;this.overAllState = factory.apply(Map.of());this.stateSerializer = new GsonSerializer2(factory);}public StateGraph(AgentStateFactory<OverAllState> factory) {this.overAllState = factory.apply(Map.of());this.stateSerializer = new GsonSerializer2(factory);}/*** Instantiates a new State graph.*/public StateGraph() {this.stateSerializer = new GsonSerializer();}public String getName() {return name;}/*** Key strategies map.* @return the map*/public Map<String, KeyStrategy> keyStrategies() {return overAllState.keyStrategies();}/*** Gets state serializer.* @return the state serializer*/public StateSerializer getStateSerializer() {return stateSerializer;}/*** Gets state factory.* @return the state factory*/public final AgentStateFactory<OverAllState> getStateFactory() {return stateSerializer.stateFactory();}/*** /** Adds a node to the graph.* @param id the identifier of the node* @param action the action to be performed by the node* @throws GraphStateException if the node identifier is invalid or the node already* exists*/public StateGraph addNode(String id, AsyncNodeAction action) throws GraphStateException {return addNode(id, AsyncNodeActionWithConfig.of(action));}/*** @param id the identifier of the node* @param actionWithConfig the action to be performed by the node* @return this* @throws GraphStateException if the node identifier is invalid or the node already* exists*/public StateGraph addNode(String id, AsyncNodeActionWithConfig actionWithConfig) throws GraphStateException {Node node = new Node(id, (config) -> actionWithConfig);return addNode(id, node);}/*** @param id the identifier of the node* @param node the node to be added* @return this* @throws GraphStateException if the node identifier is invalid or the node already* exists*/public StateGraph addNode(String id, Node node) throws GraphStateException {if (Objects.equals(node.id(), END)) {throw Errors.invalidNodeIdentifier.exception(END);}if (!Objects.equals(node.id(), id)) {throw Errors.invalidNodeIdentifier.exception(node.id(), id);}if (nodes.elements.contains(node)) {throw Errors.duplicateNodeError.exception(id);}nodes.elements.add(node);return this;}/*** Adds a subgraph to the state graph by creating a node with the specified* identifier. This implies that Subgraph share the same state with parent graph* @param id the identifier of the node representing the subgraph* @param subGraph the compiled subgraph to be added* @return this state graph instance* @throws GraphStateException if the node identifier is invalid or the node already* exists*/public StateGraph addNode(String id, CompiledGraph subGraph) throws GraphStateException {if (Objects.equals(id, END)) {throw Errors.invalidNodeIdentifier.exception(END);}var node = new SubCompiledGraphNode(id, subGraph);if (nodes.elements.contains(node)) {throw Errors.duplicateNodeError.exception(id);}nodes.elements.add(node);return this;}/*** Adds a subgraph to the state graph by creating a node with the specified* identifier. This implies that Subgraph share the same state with parent graph* @param id the identifier of the node representing the subgraph* @param subGraph the subgraph to be added. it will be compiled on compilation of the* parent* @return this state graph instance* @throws GraphStateException if the node identifier is invalid or the node already* exists*/public StateGraph addNode(String id, StateGraph subGraph) throws GraphStateException {if (Objects.equals(id, END)) {throw Errors.invalidNodeIdentifier.exception(END);}subGraph.validateGraph();OverAllState subGraphOverAllState = subGraph.getOverAllState();OverAllState superOverAllState = getOverAllState();if (subGraphOverAllState != null) {Map<String, KeyStrategy> strategies = subGraphOverAllState.keyStrategies();for (Map.Entry<String, KeyStrategy> strategyEntry : strategies.entrySet()) {if (!superOverAllState.containStrategy(strategyEntry.getKey())) {superOverAllState.registerKeyAndStrategy(strategyEntry.getKey(), strategyEntry.getValue());}}}subGraph.setOverAllState(getOverAllState());var node = new SubStateGraphNode(id, subGraph);if (nodes.elements.contains(node)) {throw Errors.duplicateNodeError.exception(id);}nodes.elements.add(node);return this;}/*** Adds an edge to the graph.* @param sourceId the identifier of the source node* @param targetId the identifier of the target node* @throws GraphStateException if the edge identifier is invalid or the edge already* exists*/public StateGraph addEdge(String sourceId, String targetId) throws GraphStateException {if (Objects.equals(sourceId, END)) {throw Errors.invalidEdgeIdentifier.exception(END);}// if (Objects.equals(sourceId, START)) {// this.entryPoint = new EdgeValue<>(targetId);// return this;// }var newEdge = new Edge(sourceId, new EdgeValue(targetId));int index = edges.elements.indexOf(newEdge);if (index >= 0) {var newTargets = new ArrayList<>(edges.elements.get(index).targets());newTargets.add(newEdge.target());edges.elements.set(index, new Edge(sourceId, newTargets));}else {edges.elements.add(newEdge);}return this;}/*** Adds conditional edges to the graph.* @param sourceId the identifier of the source node* @param condition the condition to determine the target node* @param mappings the mappings of conditions to target nodes* @throws GraphStateException if the edge identifier is invalid, the mappings are* empty, or the edge already exists*/public StateGraph addConditionalEdges(String sourceId, AsyncEdgeAction condition, Map<String, String> mappings)throws GraphStateException {if (Objects.equals(sourceId, END)) {throw Errors.invalidEdgeIdentifier.exception(END);}if (mappings == null || mappings.isEmpty()) {throw Errors.edgeMappingIsEmpty.exception(sourceId);}var newEdge = new Edge(sourceId, new EdgeValue(new EdgeCondition(condition, mappings)));if (edges.elements.contains(newEdge)) {throw Errors.duplicateConditionalEdgeError.exception(sourceId);}else {edges.elements.add(newEdge);}return this;}void validateGraph() throws GraphStateException {var edgeStart = edges.edgeBySourceId(START).orElseThrow(Errors.missingEntryPoint::exception);edgeStart.validate(nodes);for (Edge edge : edges.elements) {edge.validate(nodes);}}/*** Compiles the state graph into a compiled graph.* @param config the compile configuration* @return a compiled graph* @throws GraphStateException if there are errors related to the graph state*/public CompiledGraph compile(CompileConfig config) throws GraphStateException {Objects.requireNonNull(config, "config cannot be null");validateGraph();return new CompiledGraph(this, config);}/*** Compiles the state graph into a compiled graph.* @return a compiled graph* @throws GraphStateException if there are errors related to the graph state*/public CompiledGraph compile() throws GraphStateException {SaverConfig saverConfig = SaverConfig.builder().register(SaverConstant.MEMORY, new MemorySaver()).build();return compile(CompileConfig.builder().plainTextStateSerializer(new JacksonSerializer()).saverConfig(saverConfig).build());}/*** Generates a drawable graph representation of the state graph.* @param type the type of graph representation to generate* @param title the title of the graph* @param printConditionalEdges whether to print conditional edges* @return a diagram code of the state graph*/public GraphRepresentation getGraph(GraphRepresentation.Type type, String title, boolean printConditionalEdges) {String content = type.generator.generate(nodes, edges, title, printConditionalEdges);return new GraphRepresentation(type, content);}/*** Generates a drawable graph representation of the state graph.* @param type the type of graph representation to generate* @param title the title of the graph* @return a diagram code of the state graph*/public GraphRepresentation getGraph(GraphRepresentation.Type type, String title) {String content = type.generator.generate(nodes, edges, title, true);return new GraphRepresentation(type, content);}public GraphRepresentation getGraph(GraphRepresentation.Type type) {String content = type.generator.generate(nodes, edges, name, true);return new GraphRepresentation(type, content);}//......
}        

StateGraph提供了addNode、addEdge、addConditionalEdges等方法,其中getGraph方法根据指定GraphRepresentation.Type的DiagramGenerator来生成状态图

示例

  @Testpublic void testGraph() throws GraphStateException {OverAllState overAllState = getOverAllState();StateGraph workflow = new StateGraph(overAllState).addNode("agent_1", node_async(state -> {System.out.println("agent_1");return Map.of("messages", "message1");})).addNode("agent_2", node_async(state -> {System.out.println("agent_2");return Map.of("messages", new String[] { "message2" });})).addNode("agent_3", node_async(state -> {System.out.println("agent_3");List<String> messages = Optional.ofNullable(state.value("messages").get()).filter(List.class::isInstance).map(List.class::cast).orElse(new ArrayList<>());int steps = messages.size() + 1;return Map.of("messages", "message3", "steps", steps);})).addEdge("agent_1", "agent_2").addEdge("agent_2", "agent_3").addEdge(StateGraph.START, "agent_1").addEdge("agent_3", StateGraph.END);GraphRepresentation representation = workflow.getGraph(GraphRepresentation.Type.PLANTUML, "demo");System.out.println(representation.content());}

输出如下:

@startuml demo
skinparam usecaseFontSize 14
skinparam usecaseStereotypeFontSize 12
skinparam hexagonFontSize 14
skinparam hexagonStereotypeFontSize 12
title "demo"
footerpowered by spring-ai-alibaba
end footer
circle start<<input>> as __START__
circle stop as __END__
usecase "agent_1"<<Node>>
usecase "agent_2"<<Node>>
usecase "agent_3"<<Node>>
"__START__" -down-> "agent_1"
"agent_1" -down-> "agent_2"
"agent_2" -down-> "agent_3"
"agent_3" -down-> "__END__"
@enduml

小结

DiagramGenerator是个抽象类,定义了流程图生成的基类,它提供了appendHeader、appendFooter、call、declareConditionalStart、declareNode、declareConditionalEdge、commentLine抽象方法;它提供了generate方法根据nodes、edges、ctx生成图的文字表示。PlantUMLGenerator继承了DiagramGenerator,根据plantUML语法实现了抽象方法。

doc

  • spring-ai-alibaba

相关文章:

聊聊Spring AI Alibaba的PlantUMLGenerator

序 本文主要研究一下Spring AI Alibaba的PlantUMLGenerator DiagramGenerator spring-ai-alibaba-graph/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/DiagramGenerator.java public abstract class DiagramGenerator {public enum CallStyle {…...

借助Spring AI实现智能体代理模式:从理论到实践

借助Spring AI实现智能体代理模式&#xff1a;从理论到实践 前言 在人工智能领域&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用愈发广泛&#xff0c;如何高效构建基于LLM的系统成为众多开发者关注的焦点。Anthropic的研究报告《构建高效代理》为我们提供了新的思…...

【图片识别成表格】批量图片识别成excel表格,批量识别图片区域文字保存到excel表格,基于WPF和腾讯OCR的识别方案

​​ 应用场景 该项目适用于需要从大量图片中提取文字信息的场景,例如: ​​发票识别​​:批量扫描发票并提取金额、日期、发票号等信息。​​证件识别​​:批量处理身份证、护照等证件,提取姓名、身份证号等信息。​​文档数字化​​:将纸质文档扫描成图片后,批量提取…...

使用Qt QAxObject解决Visual Fox Pro数据库乱码问题

文章目录 使用Qt QAxObject解决Visual Fox Pro数据库乱码问题一、问题背景&#xff1a;ODBC读取DBF文件的编码困境二、核心方案&#xff1a;通过QAxObject调用ADO操作DBF1. 技术选型&#xff1a;为什么选择ADO&#xff1f;2. 核心代码解析&#xff1a;QueryDataByAdodb函数3. 连…...

Manus AI多语言手写识别技术全解析:从模型架构到实战部署

简介 Manus AI作为当前多语言手写识别领域的领军技术&#xff0c;其核心创新在于融合三维卷积网络、动态特征融合引擎和混合解码系统&#xff0c;实现了对112种语言的98.7%识别准确率和8ms延迟的实时处理能力。本文将深入探讨Manus AI的架构设计、特征提取方法、数据预处理策略…...

MYSQL三大日志、隔离级别(MVCC+锁机制实现)

MySQL三大日志 ​Undo Log&#xff08;回滚日志&#xff09; 作用 事务回滚时恢复数据到修改前的状态。 支持 ​​MVCC​​&#xff0c;为读操作提供历史版本数据。 存储 存放在 undo tablespace 中&#xff0c;通过回滚段管理。 格式 undo log 格式都有一个 roll_point…...

聚焦智能体未来,领驭科技在微软创想未来峰会大放异彩

2025年4月23日&#xff0c;微软创想未来峰会在北京中关村国际创新中心盛大举行。作为微软中国南区核心合作伙伴及HKCSP 1T首批授权云服务商&#xff0c;深圳领驭科技有限公司受邀参会&#xff0c;携瀚鹏工业AI应用解决方案亮相峰会&#xff0c;与全球AI领袖及行业精英共话智能体…...

043-代码味道-循环依赖

代码味道-循环依赖 代码异味之循环依赖&#xff1a;定义、特征与解决方案 一、循环依赖的定义与特征 循环依赖&#xff08;Cyclic Dependencies&#xff09;是指两个或多个软件模块之间形成相互依赖的闭环关系。这种代码味道会导致&#xff1a; 编译/构建困难&#xff1a;模…...

技术沙龙:Mybatis中resultMap使用案例分享

目录 一、联表查询和单表查询优劣分析 1.1 联表查询的优缺点 优点&#xff1a; 缺点&#xff1a; 1.2 单表查询的优缺点 优点&#xff1a; 缺点&#xff1a; 1.3 适用场景建议 联表查询更适合&#xff1a; 单表查询更适合&#xff1a; 1.4 优化建议 1.5 总结 …...

Linux基础篇、第一章_01_3安装虚拟机手动安装部署Ubuntu22.04服务器

题目安装部署Ubuntu22.04服务器 版本号: 1.0,0 作者: 老王要学习 日期: 2025.04.29 适用环境: Ubuntu22.04 文档说明 本文档聚焦 Ubuntu 22.04 服务器的安装部署&#xff0c;详细介绍了从虚拟机创建、系统安装、基础配置&#xff08;如更新国内源、安装常用软件、修改静态 IP、…...

dma_request_slave_channel_compat 与 dma_request_channel 的区别

1.代码示例 dma_request_channel #define dma_request_channel(mask, x, y) \__dma_request_channel(&(mask), x, y, NULL)struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,dma_filter_fn fn, void *fn_param,struct device_node *np) {struct dma_d…...

【论文阅读】Partial Retraining Substitute Model for Query-Limited Black-Box Attacks

摘要 针对深度神经网络(DNN)分类器的黑盒攻击正受到越来越多的关注,因为它们在现实世界中比白盒攻击更实用。在黑盒环境中,对手对目标模型的了解有限。这使得难以估计用于制作对抗示例的梯度,从而无法将强大的白盒算法直接应用于黑盒攻击。因此,一种著名的黑盒攻击策略会…...

JAVA---集合ArrayList

集合 1. 自动扩容 &#xff0c;集合长度可变 2. 只可以存引用数据类型&#xff0c;如果要存基本数据类型&#xff0c;需要将其转换成对应的包装类 ArrayList 定义在 java.util 下的&#xff0c;实现了 List 接口。ArrayList 内部以动态数组的形式存储元素&#xff0c;这意…...

快速了解Go+微服务(概念和一个例子)

更多个人笔记&#xff1a;&#xff08;仅供参考&#xff0c;非盈利&#xff09; gitee&#xff1a; https 文章目录 基本概念grpc和简单demo 基本概念 特点&#xff1a; 单一职责&#xff1a;一个服务用来解决一个业务问题面向服务&#xff1a;一个服务封装并对外提供服务&am…...

MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - sleep 是怎样练成的?

接上文MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - sleep 探究sleep.c是如何’炼成’的? 老实讲&#xff0c;我不熟悉Makefile&#xff0c;最多写过简单的编译和辅助脚本&#xff0c;拿到Xv6的Makefile是一脸懵的&#xff0c;至今还是一脸懵&#xff0c;那么我们上篇中新加的…...

4月28号

初认web前端: web标准: HTML:...

React Native 太慢:kotlin-gradle-plugin-2.0.21-gradle76.jar 下载太慢

React Native 初次运行&#xff08;已经连接手机USB调试&#xff09;。 运行的命令&#xff1a;npx react-native run-android。 一直卡在jar包的下载部分&#xff0c;总是几十kb的速度。 > Evaluating settings > :gradle-plugin > Resolve files of :gradle-plug…...

面试篇 - Transformer前馈神经网络(FFN)使用什么激活函数?

1. FFN结构分解 原始Transformer的FFN层 FFN(x) max(0, xW₁ b₁)W₂ b₂ # 原始论文公式 输入&#xff1a;自注意力层的输出 x&#xff08;维度 d_model512&#xff09; 扩展层&#xff1a;xW₁ b₁&#xff08;扩展为 d_ff2048&#xff09; 激活函数&#xff1a;Re…...

Lua 第14部分 数据结构

14.1 数组 Lua 语言中的表并不是一种数据结构&#xff0c;它们是其他数据结构的基础。我们可以用 Lua 语言中的表来实现其他语言提供的数据结构&#xff0c;如数组、记录、列表、队列、集合等。而且&#xff0c;用Lua 语言中的表实现这些数据结构还很高效。 在像 C 和…...

杭州数据库恢复公司之Dell服务器RAID5阵列两块硬盘损坏报警离线

外地客户寄过来六块SAS服务器硬盘&#xff0c;说是组了RAID5磁盘阵列的戴尔DELL服务器突然崩溃了&#xff0c;更换阵列卡后开始可以进入系统&#xff0c;不过有一块盘亮黄灯报警&#xff0c;工程师打算把服务器放回机柜后更换新硬盘&#xff0c;但再重启就无法进系统了&#xf…...

linux 内核 debugfs 使用介绍

一&#xff1a;概述 debugfs 是 Linux 内核提供的一个特殊的虚拟文件系统&#xff0c;用于 暴露内核模块&#xff08;如驱动&#xff09;内部的调试信息或控制接口&#xff0c;供开发者、调试人员实时查看和排查问题。即 debugfs 就是一个“调试专用的 /proc 或 /sys”&#xf…...

MarkItDown:如何高效将各类文档转换为适合 LLM 处理的 Markdown 格式

MarkItDown&#xff1a;如何高效将各类文档转换为适合 LLM 处理的 Markdown 格式 引言项目概述分析基本信息主要功能支持的文件格式技术架构 为什么选择 Markdown&#xff1f;核心功能详解1. 文档转换机制2. LLM 集成能力3. 多种转换选项4. 插件系统 安装和使用教程安装可选依赖…...

解锁未来工作方式:什么是 AI Agent?| Unlocking the Future of Work: What Are AI Agents?

&#x1f1e8;&#x1f1f3; 解锁未来工作方式&#xff1a;什么是 AI Agent&#xff1f;| &#x1f1fa;&#x1f1f8; Unlocking the Future of Work: What Are AI Agents? 关键词提示&#xff1a;本文将介绍 AI agents, knowledge graph, LangChain, Graphiti 等相关术语&am…...

8分钟快速掌握Markdiwn

文档说明:本文档适合有编程基础的专业人士快速学习Markdown语法,从而立即上手使用Markdown来记笔记,新手可移步至Markdown入门到精通实战教程:使用Typora快速构建编辑MD文档_md文件编辑器typora-CSDN博客 进行入门学习 Markdown文档的元素包括块级元素、内联元素、HTML元素…...

多维驱动:负载均衡何以成为现代系统架构的基石

负载均衡的引入是现代网络架构和分布式系统发展的必然需求&#xff0c;除了上述提到的原因&#xff0c;还涉及以下多个关键层面&#xff0c;共同推动其成为复杂系统不可或缺的组成部分&#xff1a; 一、提升服务质量&#xff08;QoS&#xff09; 响应时间优化&#xff1a;用户…...

本地知识库工具FASTGPT的安装与搭建

FastGPT 是一个基于 LLM 大语言模型的知识库问答系统&#xff0c;将智能对话与可视化编排完美结合&#xff0c;让 AI 应用开发变得简单自然。无论您是开发者还是业务人员&#xff0c;都能轻松打造专属的 AI 应用。 今天来试着搭建下&#xff0c;使用docker安装比较简单&#x…...

【嘉立创EDA】如何找到曲线和直线的交点,或找到弧线和直线的交点

文章路标👉 :one: 文章解决问题:two: 主题内容:three: 参考方法be end..1️⃣ 文章解决问题 操作环境:嘉立创EDA专业版 V2.2.38 本文使用嘉立创EDA,描述如何快速找到曲线和直线交点的方法,这里的曲线包括了弧线等。本文将此过程记录,以供有需要的读者参考。 2️⃣ 主题…...

余额分账和代付有什么区别?

余额分账和代付有什么区别&#xff1f;余额分账是把钱存到一起&#xff0c;但代付是把钱分开。看似简单的一字之差&#xff0c;却有着本质的区别。 余额分账是一种财务管理手段&#xff0c;在一个账户或平台上&#xff0c;根据一定的规则将账户内的余额进行划分&#xff0c;形…...

【Stable Diffusion】文生图进阶指南:采样器、噪声调度与迭代步数的解析

在Stable Diffusion文生图(Text-to-Image)的创作过程中,采样器(Sampler)、噪声调度器(Schedule type)和采样迭代步数(Steps)是影响生成效果的核心参数。本文将从技术原理、参数优化到实践应用,深入剖析DPM++ 2M采样器、Automatic噪声调度器以及采样步数的设计逻辑与协…...

1.1探索 LLaMA-Factory:大模型微调的一站式解决方案

探索 LLaMA-Factory&#xff1a;大模型微调的一站式解决方案 引言 在大模型的时代&#xff0c;微调技术是将预训练模型适配到特定任务的关键。LLaMA-Factory 作为一款强大的工具&#xff0c;为开发者提供了便捷且高效的大模型微调解决方案。本文将深入介绍 LLaMA-Factory 的基…...

嵌入式开发面试常见编程题解析:pthread_join 与 pthread_detach 详解

一、引言 在多线程编程中&#xff0c;线程的资源管理至关重要。pthread_join 和 pthread_detach 是用于线程资源管理的两个重要函数。正确使用它们可以确保线程资源的合理回收&#xff0c;避免出现资源泄漏等问题。本文将详细介绍这两个函数的区别、使用方法、常见易错点以及拓…...

C#里嵌入lua脚本的例子

由于lua脚本比较小,并且适用性很强,非常适合嵌入式系统里加入。 比如在GD32的MCU里运行lua脚本,又者在ESP32里运行它,都是比较方便的。 当脚本要发送给MCU运行之前,我们需要在PC的软件里对脚本进行编译, 以便发现脚本有什么问题,不能在MCU里去发现问题,否则那样会比…...

git配置SSH KEY

1. 生成SSH密钥 ssh-keygen一直按回车 2.查看密钥 去.ssh目录查看生成的密钥文件 .pub结尾的文件即是密钥文件 3.配置SSH KEY 到代码仓库如GitHub&#xff0c;gitlab等配置SSH KEY&#xff0c;将密钥复制上去添加即可...

js day9

js当中与滚动相关的属性 <div>haha</div> <script>let boxdocument.querySelector("div")box.addEventListener("scoll",function(e)){console.log(window.scrolltop) }//往上走了 </script> ,box.scrollHeight——获取元素内容…...

【docker】启动临时MongoDB容器、挂载数据卷运行数据库服务,并通过备份文件恢复MongoDB数据库备份数据

‌启动临时 MongoDB 容器、挂载数据卷运行数据库服务&#xff0c;并通过备份文件恢复数据 1.命令分解与功能说明1.1.启动一个临时 MongoDB 容器‌&#xff0c;并进入交互式终端&#xff08;1&#xff09;执行命令&#xff08;2&#xff09;实现功能‌&#xff08;3&#xff09;…...

20_大模型微调和训练之-基于LLamaFactory+LoRA微调LLama3后格式合并

1. 什么是 GGUF GGUF 格式的全名为(GPT-Generated Unified Format)&#xff0c;提到 GGUF 就不得不提到它的前身 GGML(GPT-Generated Model Language)。GGML 是专门为了机器学习设计的张量库&#xff0c;最早可 以追溯到 2022/10。其目的是为了有一个单文件共享的格式&#xf…...

LLamaFactory如何在Windows系统下部署安装训练(保姆级教程)

注意&#xff1a;以下教程编写和灵感来源均来自eogee开源作者&#xff08;EOGEE_岳极技术_大模型与AI知识技术共享社区&#xff09;&#xff0c;大家有需要学习AI方面的知识可以关注他。 另我个人此次环境部署所用的显卡是5070ti16G显存&#xff0c;系统是Windows11。 如有问题…...

数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记7

前言 在前面文章的介绍中&#xff0c;已经介绍了数据定义、数据更新、数据查询&#xff0c;关于SQL语句的标准语言已经基本上介绍完毕&#xff0c;本文接下来将介绍另外两种便于操作的操作模式——视图与索引。其大致的语句代码与前文其实并无大的区别&#xff0c;在了解基本语…...

【LeetCode】彩灯装饰记录 III

题目 题目链接 一棵圣诞树记作根节点为 root 的二叉树&#xff0c;节点值为该位置装饰彩灯的颜色编号。请按照如下规则记录彩灯装饰结果&#xff1a; 第一层按照从左到右的顺序记录 除第一层外每一层的记录顺序均与上一层相反。即第一层为从左到右&#xff0c;第二层为从右到左…...

MongoDB的图形化工具robo3t,navicat

MongoDB 常用的两个图形化工具 —— Robo 3T 和 Navicat 的详细介绍、区别和基本使用方法&#xff1a; &#x1f9f0; 一、Robo 3T&#xff08;原 Robomongo&#xff09; &#x1f4cc; 简介 Robo 3T 是一款专注于 MongoDB 的轻量级可视化客户端。由原 Robomongo 团队开发&am…...

python celery框架结合django的使用

学习目标&#xff1a; 通过文章了解celery的运行机制以及如何结合django去使用 熟悉celery的运行原理属性celery在django项目当中的配置如何启动运行celery框架 学习内容&#xff1a; 熟悉celery的运行原理&#xff0c;简单来说 Celery 是一个“任务排队机后台处理器”。帮你…...

Ansible 守护 Windows 安全(Ansible Safeguards Windows Security)

Ansible 守护 Windows 安全&#xff1a;自动化基线检查与加固 在当今网络威胁日益严峻的形势下&#xff0c;保障 Windows 系统安全至关重要。Ansible 作为一款强大的自动化运维工具&#xff0c;可通过自动化脚本实现 Windows 安全基线检查和加固&#xff0c;大幅提升运维效率并…...

【计算机架构】CISC(复杂指令集计算机)架构

一、引言 在计算机技术领域中&#xff0c;计算机架构是基石&#xff0c;决定着计算机系统的性能、功能和效率。CISC&#xff08;复杂指令集计算机&#xff09;架构作为一种经典的计算机架构&#xff0c;自诞生以来就在计算机发展历程中扮演着举足轻重的角色。从早期的大型计算机…...

【学习资源】知识图谱与大语言模型融合

知识图谱与大型语言模型结合参数知识和明确知识的可用性会带来一些机会和愿景。分享一些知识图谱和大语言模型融合的论文和文章、实践案例、关键技术和实用工具。 1 模型库获取 https://modelscope.cn/models 注 下载模型需运行 git lfs instal 2 论文和文章 2.1 大型语言模…...

探索微服务入口:Spring Cloud Gateway 实战指南

在微服务架构中&#xff0c;网关&#xff08;Gateway&#xff09;扮演着“请求入口”的角色。它不仅帮助我们统一入口、路由转发&#xff0c;还可以承担限流、安全认证、权限校验、熔断等功能。 本文将系统介绍 Spring Cloud Gateway 的基础概念、快速上手指南&#xff0c;以及…...

python的turtle库实现四叶草

实现代码&#xff1a; import turtle turtle.pencolor(‘green’) turtle.fillcolor(‘green’) turtle.begin_fill() turtle.circle(100,90) turtle.left(90) turtle.circle(100,90) turtle.right(180) turtle.circle(100, 90) turtle.left(90) turtle.circle(100,90) tu…...

医疗生态全域智能化:从技术革新到价值重塑的深度探析

引言 医疗人工智能正在经历从单一技术应用向全域生态系统演进的关键转折点。随着深度学习、自然语言处理和计算机视觉等技术的成熟,AI不再局限于辅助诊断等单一功能,而是逐渐渗透到医疗健康服务的全生命周期。从传统设备制造商向智慧医疗转型的东软医疗,正在构建"AI大…...

Rust 的 Web 世界:actix_web 轻松接收 JSON 请求体

前言 在现代 Web 世界,数据传输早已从“你问我答”的问卷时代,迈入“你扔我接”的快节奏赛道。其中最火的“传球”方式,非 JSON 请求体莫属。Rust 这门以高性能和强类型著称的语言,也不甘人后,推出 actix_web 框架,力求在 Web 世界中杀出一条血路。 今天我们不讲玄学,…...

1.3 点云数据获取方式——ToF相机

图1-3-1TOF相机 ToF 相机作为新兴的 3D 感知设备,凭借独特的技术优势崭露头角。其工作原理基于光飞行时间(Time of Flight)技术,通过测量光信号从发射到被物体反射后返回传感器的时间差,直接且快速地获取物体的深度信息。这种直接测量深度的方式使得 ToF 相机具备…...

数据结构每日一题day13(链表)★★★★★

题目描述&#xff1a;采用尾插法在头指针L处建立一个带头结点的单链表,输入-1表示结束结果返回建立的单链表。 算法思想&#xff1a; 1.初始化链表&#xff1a;创建一个头结点&#xff08;不存储实际数据&#xff09;&#xff0c;头指针 L 指向该头结点。初始时&#xff0c;头…...