Java多智能体协作框架copaw-java:从原理到实战应用

news2026/5/3 11:53:32
1. 项目概述一个Java版的多智能体协作框架最近在开源社区里我注意到一个挺有意思的项目叫liupengpop/copaw-java。光看这个名字可能有点摸不着头脑但如果你对AI智能体Agent开发或者多智能体系统Multi-Agent System, MAS感兴趣那这个项目绝对值得你花时间研究一下。简单来说这是一个用Java语言实现的多智能体协作框架你可以把它理解为一个“舞台”或者“沙盒”在这个环境里你可以创建多个具备不同能力的“虚拟员工”也就是智能体让它们按照你设定的规则和目标相互沟通、协作共同完成一个复杂的任务。为什么这件事有价值在传统的软件开发里一个功能模块通常是被动执行的你调用它它给你结果。但智能体的思路不一样它更强调“主动性”和“协作性”。想象一下你要处理一个客户工单可能需要先由“分类智能体”判断问题类型然后“查询智能体”去数据库找历史记录接着“分析智能体”给出初步解决方案最后“回复智能体”生成一封友好的邮件。如果这些步骤都靠你手动写死流程代码会非常僵化。而多智能体框架就是让这些“虚拟员工”能自主地、灵活地配合起来整个系统的智能性和适应性会大大提升。copaw-java这个项目就是为Java开发者打开这扇大门的钥匙。它不只是一个玩具从项目结构和设计上看它考虑了消息路由、状态管理、并发控制等生产级应用需要面对的问题。无论你是想研究多智能体系统的学术原理还是打算在实际业务中比如智能客服、自动化流程编排、复杂决策支持引入这种架构这个项目都能提供一个扎实的起点。接下来我就带你深入拆解一下这个框架的核心设计、怎么上手使用以及在实际编码中会遇到哪些“坑”。2. 核心架构与设计思想拆解要玩转copaw-java首先得理解它背后的设计哲学。一个好的框架其价值往往体现在它对复杂问题的抽象能力上。多智能体系统本身涉及通信、协调、资源管理等多个维度copaw-java是如何将它们优雅地封装起来的呢2.1 核心组件与角色定义框架的核心可以抽象为几个关键角色理解了它们就理解了整个系统的运行脉络。智能体 (Agent)这是最基本的执行单元。在copaw-java中一个智能体通常是一个Java类它封装了特定的能力比如调用一个API、执行一段逻辑、访问数据库。每个智能体都有唯一的标识符ID并且维护着自己的内部状态。最关键的是智能体具备“感知-决策-行动”的循环能力它能接收来自其他智能体或环境的消息感知根据内部逻辑和状态进行处理决策然后发出新的消息或执行动作行动。框架并不强制智能体的实现方式你可以用简单的POJO也可以用更复杂的、内置了推理逻辑的类。环境 (Environment)环境是所有智能体共存和交互的上下文。你可以把它想象成一个虚拟的“办公室”或“消息总线”。它主要提供两大功能一是注册与管理所有智能体知道谁是谁能提供什么服务二是路由消息当一个智能体发出消息时环境负责根据消息头比如目标接收者ID、消息类型将消息准确投递给目标智能体。环境还常常负责维护一些全局状态或共享资源。消息 (Message)这是智能体之间沟通的“语言”。一个设计良好的消息结构至关重要。通常一个消息对象会包含以下几个部分发送者 (Sender)消息来源的智能体ID。接收者 (Receiver)目标智能体ID可以是具体的某个ID也可以是广播地址。会话ID (Conversation ID)用于关联同一任务或对话中的所有消息这对于追踪复杂的工作流非常有用。消息类型 (Performative)定义了消息的意图比如是“请求”、“告知”、“承诺”、“拒绝”等。这借鉴了Agent通信语言如FIPA ACL的思想是高效协作的基础。内容 (Content)消息的实际负载可以是字符串、JSON、甚至是序列化的Java对象。行为 (Behaviour)这是控制智能体如何响应消息和执行任务的逻辑单元。一个智能体可以拥有多个行为。框架通常会提供一些基础的行为类比如CyclicBehaviour循环执行的行为适合用于持续监听消息。OneShotBehaviour只执行一次的行为。SequentialBehaviour按顺序执行一系列子行为。ParallelBehaviour并发执行多个子行为。 通过组合这些行为你可以构建出非常复杂的智能体逻辑。2.2 通信模型与协作机制智能体之间如何“说话”是框架设计的精髓。copaw-java这类框架通常采用基于消息的异步通信模型。发布-订阅与直接通信框架一般会支持两种模式。一是直接通信就像发邮件指定明确的收件人。这种方式简单直接适合点对点的任务委派。二是发布-订阅模式智能体可以向某个“主题”发布消息而关心这个主题的其他智能体会自动收到消息。这种方式非常适合实现事件驱动架构比如一个“任务完成”事件发布后多个下游智能体可以同时被触发。合同网协议 (Contract Net Protocol)这是多智能体系统中一个经典且高效的协作协议常用于任务分配。它的流程很像招标招标 (Call for Proposal, CFP)管理者智能体招标方向多个潜在的执行者智能体投标方广播一个任务。投标 (Proposal)有能力且愿意执行的投标方会评估任务并向招标方回复一个投标包含执行条件、预计成本等。授标 (Award)招标方评估所有投标选择最合适的一个并向其发送授标消息。执行与汇报中标方执行任务完成后向招标方汇报结果。copaw-java很可能内置或可以方便地实现此类协议这是实现动态、优化任务分配的关键。共享黑板 (Blackboard)另一种常见的协作机制是提供一个共享的、结构化的数据空间——黑板。智能体们不直接对话而是把问题、部分解决方案、数据都写在黑板上。其他智能体观察黑板的变化当发现自己能贡献时就去更新黑板内容。这种方式解耦更彻底特别适合解决那些没有明确分解步骤的、探索性的问题比如诊断、设计。注意选择哪种通信协作机制取决于你的应用场景。对于流程清晰的任务链直接通信更高效对于事件驱动的系统发布-订阅更灵活对于复杂问题求解合同网或黑板模型可能更合适。在项目初期就要想清楚。3. 从零开始环境搭建与第一个智能体理论说得再多不如动手跑一遍。我们来一步步搭建一个基于copaw-java的极简多智能体系统。假设你已经有了Java开发环境JDK 8和Maven。3.1 项目初始化与依赖引入首先创建一个标准的Maven项目。在pom.xml文件中你需要添加copaw-java的依赖。由于它可能不在中央仓库你需要确认其来源。通常作者会发布到GitHub Packages或某个私有Maven仓库。这里假设我们已经配置好了仓库地址。dependencies !-- copaw-java 核心框架 -- dependency groupIdcom.github.liupengpop/groupId artifactIdcopaw-java-core/artifactId version最新版本号/version !-- 例如 1.0.0 -- /dependency !-- 可能还需要日志依赖如SLF4J Logback -- dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.2.11/version /dependency /dependencies引入依赖后一个基础的框架环境就准备好了。框架的核心启动类通常是一个Runtime或Container它负责初始化环境并启动智能体。3.2 创建你的第一个智能体问候者 (GreeterAgent)让我们创建一个最简单的智能体它唯一的行为就是启动后向控制台打印一句问候语。package com.example.agent; import io.github.liupengpop.copaw.agent.Agent; import io.github.liupengpop.copaw.behaviour.OneShotBehaviour; public class GreeterAgent extends Agent { Override protected void setup() { // 当智能体被启动时这个方法会被自动调用 System.out.println(智能体 getAID().getName() 已启动); // 添加一个一次性行为 addBehaviour(new OneShotBehaviour(this) { Override public void action() { // 这是该行为要执行的动作 System.out.println(你好世界来自 myAgent.getAID().getName()); } }); } }代码解读我们的GreeterAgent继承了框架提供的基类Agent。重写了setup()方法。这是智能体生命的起点用于初始化。在setup()中我们使用addBehaviour()方法为智能体添加了一个OneShotBehaviour一次性行为。在行为的action()方法里我们定义了具体的逻辑打印一条消息。getAID()用于获取本智能体的唯一标识对象。3.3 启动环境并运行智能体现在我们需要一个“主程序”来创建环境并把我们的智能体放进去运行。package com.example; import com.example.agent.GreeterAgent; import io.github.liupengpop.copaw.runtime.Runtime; public class Main { public static void main(String[] args) { // 1. 创建或获取一个运行时环境例如一个本地容器 Runtime runtime Runtime.createLocalRuntime(); // 假设框架提供此方法 // 2. 从运行时环境中获取主容器环境 Environment mainEnvironment runtime.getMainEnvironment(); // 3. 创建智能体描述并指定其实现类 AgentDescriptor descriptor new AgentDescriptor(); descriptor.setName(greeterlocalhost); // 智能体唯一名称 descriptor.setClassName(GreeterAgent.class.getName()); // 4. 在环境中启动这个智能体 mainEnvironment.startAgent(descriptor); // 5. 保持主线程运行一段时间以便观察输出 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 6. 关闭运行时环境 runtime.shutdown(); } }运行这个Main类你应该能在控制台看到类似以下的输出智能体 greeterlocalhost 已启动 你好世界来自 greeterlocalhost恭喜你已经成功创建并运行了你的第一个智能体。虽然它现在还很“孤独”但我们已经搭建好了最基础的单智能体环境。接下来我们要让智能体们“交流”起来。4. 实现智能体间的对话与协作单个智能体能力有限多智能体的魅力在于协作。我们来实现一个经典的“请求-响应”场景一个RequesterAgent请求者向一个ResponderAgent响应者发送一个问题响应者回答后请求者打印出答案。4.1 定义消息格式与协议在开始编码前我们需要约定好消息的格式。为了简单我们定义消息类型Performative为“QUERY”查询和“INFORM”告知。消息内容Content就是普通的字符串。4.2 创建响应者智能体 (ResponderAgent)响应者的职责是监听“QUERY”类型的消息并根据问题内容生成回复。public class ResponderAgent extends Agent { Override protected void setup() { // 添加一个循环行为持续监听消息 addBehaviour(new CyclicBehaviour(this) { Override public void action() { // 1. 接收消息blockingReceive会阻塞直到收到消息 Message receivedMsg blockingReceive(); // 2. 检查消息类型 if (receivedMsg ! null “QUERY”.equals(receivedMsg.getPerformative())) { String question (String) receivedMsg.getContent(); System.out.println(getAID().getName() “ 收到问题” question); // 3. 构造回复消息 Message reply new Message(); reply.setSender(getAID()); // 发送者是自己 reply.addReceiver(receivedMsg.getSender()); // 接收者是原消息的发送者 reply.setPerformative(“INFORM”); // 简单的回复逻辑 String answer “关于 ‘“ question “’ 的答案是42。”; reply.setContent(answer); // 4. 发送回复 send(reply); System.out.println(getAID().getName() “ 已发送回复。”); } } }); } }4.3 创建请求者智能体 (RequesterAgent)请求者的职责是启动后主动向响应者发送一个查询然后等待并处理回复。public class RequesterAgent extends Agent { Override protected void setup() { // 添加一个一次性行为用于发起请求并等待回复 addBehaviour(new OneShotBehaviour(this) { Override public void action() { // 1. 构造查询消息 Message queryMsg new Message(); queryMsg.setSender(getAID()); // 假设我们知道响应者的名字是 “responderlocalhost” queryMsg.addReceiver(new AID(“responderlocalhost”, AID.ISGUID)); queryMsg.setPerformative(“QUERY”); queryMsg.setContent(“生命、宇宙以及任何事情的终极答案是什么”); System.out.println(getAID().getName() “ 发送问题” queryMsg.getContent()); // 2. 发送消息 send(queryMsg); // 3. 等待回复设置一个超时时间比如5000毫秒 Message reply blockingReceive(5000); // 4. 处理回复 if (reply ! null “INFORM”.equals(reply.getPerformative())) { String answer (String) reply.getContent(); System.out.println(getAID().getName() “ 收到答案” answer); } else { System.out.println(getAID().getName() “ 等待回复超时或收到无效消息。”); } } }); } }4.4 编排与运行多智能体系统现在我们需要修改主程序同时启动这两个智能体并确保它们能在同一个环境中找到彼此。public class MultiAgentMain { public static void main(String[] args) { Runtime runtime Runtime.createLocalRuntime(); Environment env runtime.getMainEnvironment(); // 启动响应者 AgentDescriptor responderDesc new AgentDescriptor(); responderDesc.setName(“responderlocalhost”); responderDesc.setClassName(ResponderAgent.class.getName()); env.startAgent(responderDesc); // 稍等片刻确保响应者先启动并开始监听 try { Thread.sleep(500); } catch (InterruptedException e) {} // 启动请求者 AgentDescriptor requesterDesc new AgentDescriptor(); requesterDesc.setName(“requesterlocalhost”); requesterDesc.setClassName(RequesterAgent.class.getName()); env.startAgent(requesterDesc); // 主线程等待足够长时间让对话完成 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } runtime.shutdown(); } }运行这个程序预期的输出应该是responderlocalhost 已启动 requesterlocalhost 已启动 requesterlocalhost 发送问题生命、宇宙以及任何事情的终极答案是什么 responderlocalhost 收到问题生命、宇宙以及任何事情的终极答案是什么 responderlocalhost 已发送回复。 requesterlocalhost 收到答案关于 ‘生命、宇宙以及任何事情的终极答案是什么’ 的答案是42。至此你已经实现了一个完整的、双向通信的多智能体对话系统。这虽然简单但包含了消息发送、接收、处理的完整闭环是构建更复杂工作流的基础。5. 进阶实战构建一个任务协调工作流现在我们来挑战一个更贴近实际业务的场景一个简单的订单处理工作流。假设有一个OrderAgent订单智能体收到新订单后需要协调InventoryAgent库存智能体检查库存再由PaymentAgent支付智能体处理支付最后ShippingAgent物流智能体安排发货。我们将使用合同网协议的思想来模拟这个流程。5.1 设计智能体角色与交互协议OrderAgent (管理者/招标方) 接收新订单向库存和支付智能体发起“招标”CFP。InventoryAgent (投标方/执行者) 接收库存检查CFP检查库存后回复“投标”Proposal包含是否有货。PaymentAgent (投标方/执行者) 接收支付处理CFP模拟支付验证后回复“投标”Proposal包含是否成功。OrderAgent 收集所有投标进行决策例如库存和支付都成功才算通过向成功的投标方发送“授标”Award消息并触发物流。ShippingAgent 接收来自OrderAgent的“发货”指令执行发货逻辑。为了简化我们省略真正的网络通信细节用本地方法调用模拟库存检查和支付验证。5.2 实现基于消息的合同网流程这里我们重点展示OrderAgent和InventoryAgent的核心交互逻辑支付智能体类似。InventoryAgent 的实现投标方public class InventoryAgent extends Agent { private MapString, Integer stock new HashMap(); // 模拟库存 public InventoryAgent() { stock.put(“item_001”, 10); } Override protected void setup() { addBehaviour(new CyclicBehaviour(this) { Override public void action() { Message msg blockingReceive(); if (msg ! null “CFP”.equals(msg.getPerformative())) { String orderId (String) msg.getContent(); System.out.println(getAID().getName() “ 收到订单 ” orderId “ 的库存检查请求。”); // 模拟库存检查逻辑 boolean inStock checkStock(orderId); // 构造投标消息 Message proposal new Message(); proposal.setSender(getAID()); proposal.addReceiver(msg.getSender()); proposal.setPerformative(“PROPOSE”); proposal.setContent(inStock ? “IN_STOCK” : “OUT_OF_STOCK”); proposal.setConversationId(msg.getConversationId()); // 保持会话ID一致 send(proposal); System.out.println(getAID().getName() “ 发送投标” (inStock ? “有货” : “缺货”)); } // 还可以处理 AWARD 消息这里省略 } }); } private boolean checkStock(String orderId) { // 简化总是返回有货 return true; } }OrderAgent 的核心决策逻辑管理者public class OrderAgent extends Agent { Override protected void setup() { addBehaviour(new OneShotBehaviour(this) { Override public void action() { String orderId “ORDER_” System.currentTimeMillis(); System.out.println(“[OrderAgent] 收到新订单” orderId); // 1. 创建会话ID用于关联此次招标的所有消息 String convId “conv_” orderId; // 2. 向 InventoryAgent 和 PaymentAgent 发送 CFP Message cfpToInventory createCFPMessage(“inventorylocalhost”, orderId, convId); Message cfpToPayment createCFPMessage(“paymentlocalhost”, orderId, convId); send(cfpToInventory); send(cfpToPayment); // 3. 收集投标简化等待固定数量的回复 ListMessage proposals new ArrayList(); int expectedProposals 2; long deadline System.currentTimeMillis() 10000; // 10秒超时 while (proposals.size() expectedProposals System.currentTimeMillis() deadline) { Message reply receive(); // 非阻塞接收 if (reply ! null convId.equals(reply.getConversationId()) “PROPOSE”.equals(reply.getPerformative())) { proposals.add(reply); System.out.println(“[OrderAgent] 收到投标来自” reply.getSender().getName() “, 内容” reply.getContent()); } else if (reply ! null) { // 忽略不相关的消息 block(); // 暂时阻塞等待下一条消息 } } // 4. 决策逻辑 boolean inventoryOk proposals.stream().anyMatch(m - m.getSender().getName().contains(“inventory”) “IN_STOCK”.equals(m.getContent())); boolean paymentOk proposals.stream().anyMatch(m - m.getSender().getName().contains(“payment”) “SUCCESS”.equals(m.getContent())); if (inventoryOk paymentOk) { System.out.println(“[OrderAgent] 订单 ” orderId “ 检查通过通知发货。”); // 5. 发送授标消息此处简化直接通知发货 Message award new Message(); award.setSender(getAID()); award.addReceiver(new AID(“shippinglocalhost”, AID.ISGUID)); award.setPerformative(“INFORM”); award.setContent(orderId); send(award); } else { System.out.println(“[OrderAgent] 订单 ” orderId “ 检查失败。库存状态” inventoryOk “ 支付状态” paymentOk); } } private Message createCFPMessage(String receiver, String orderId, String convId) { Message msg new Message(); msg.setSender(getAID()); msg.addReceiver(new AID(receiver, AID.ISGUID)); msg.setPerformative(“CFP”); msg.setContent(orderId); msg.setConversationId(convId); return msg; } }); } }这个例子展示了如何用消息驱动的方式组织一个包含竞争和协作的分布式决策流程。OrderAgent作为协调者并不需要知道InventoryAgent和PaymentAgent的内部实现细节它只通过标准的消息协议与它们交互这极大地降低了系统耦合度。6. 性能调优、问题排查与生产级考量当你开始用copaw-java构建更复杂、更高并发的系统时就会遇到一些工程上的挑战。下面分享一些从实践中总结的经验和避坑指南。6.1 并发与资源管理智能体线程模型框架底层是如何调度智能体行为的是每个智能体一个独立线程还是一个线程池共享这直接影响系统的吞吐量和资源消耗。你需要查阅copaw-java的文档或源码来确认。如果是单线程顺序执行所有智能体的行为那么一个行为中的长时间阻塞操作如网络IO会拖垮整个系统。在这种情况下你需要将阻塞操作异步化在行为内部使用Future或回调避免阻塞行为线程。使用非阻塞接收优先使用receive()而非blockingReceive()并结合wait()或超时机制。消息队列深度与背压如果消息生产速度远大于消费速度内存中的消息队列会不断增长最终导致内存溢出OOM。你需要监控队列大小框架可能提供相关API如果没有需要考虑自己实现监控。实施背压策略当队列超过阈值时让发送方智能体暂停发送或丢弃低优先级消息。使用有界队列如果框架支持配置消息队列的最大容量。6.2 常见问题与排查技巧在实际开发中你肯定会遇到智能体“失联”、消息丢失、死锁等问题。下面是一个快速排查清单问题现象可能原因排查步骤与解决方案智能体启动失败1. 依赖缺失或冲突。2. 智能体类未正确注册或类路径错误。3. 环境容器未正确初始化。1. 检查pom.xml依赖树确保框架核心包存在。2. 确认主程序中使用的是智能体的全限定类名。3. 查看启动日志通常框架会输出详细的错误信息。消息发送后接收方无反应1. 接收方AID错误名称或主机不对。2. 接收方智能体未添加监听消息的行为如CyclicBehaviour。3. 消息类型Performative不匹配接收方过滤掉了。4. 发送方和接收方不在同一个环境/容器中。1.打印日志在发送前后打印发送者、接收者、消息内容。这是最有效的调试手段。2. 检查接收方setup()方法确认添加了CyclicBehaviour并正确解析了Performative。3. 确认环境配置分布式环境下需要正确配置通信通道如HTTP, RMI。系统运行一段时间后变慢或卡死1.内存泄漏行为或消息未被正确释放。2.死锁两个或多个智能体互相等待对方的消息。3.线程池耗尽大量阻塞操作耗尽了框架的工作线程。1. 使用JProfiler等工具分析内存堆转储查看Agent、Behaviour、Message对象的数量是否异常增长。2. 检查代码逻辑避免循环等待。为blockingReceive设置合理的超时时间。3. 优化行为逻辑将耗时IO操作移到智能体外部或使用异步方式。分布式环境下通信失败1. 网络防火墙或端口未开放。2. 序列化/反序列化问题如果消息内容包含自定义对象。3. 不同主机上的时钟不同步影响基于超时的逻辑。1. 使用ping、telnet检查网络连通性。2. 确保消息内容中的自定义对象实现了Serializable接口且所有节点都有相同的类定义。3. 考虑在关键逻辑中使用逻辑时间或向量时钟而非完全依赖物理时间。实操心得日志是你的第一道防线。务必为每个智能体的关键动作如setupaction开始/结束 发送/接收消息添加详细的日志输出并带上智能体ID和会话ID。这能在出现问题时帮你快速追踪消息流和智能体状态。可以考虑使用MDCMapped Diagnostic Context将会话ID自动注入到每行日志中。6.3 状态持久化与容错生产系统必须考虑故障恢复。如果JVM崩溃所有在内存中的智能体状态和消息都会丢失。智能体状态持久化你需要定期将智能体的关键状态如任务进度、内部数据保存到数据库或文件中。可以在行为的action()方法中或在智能体内设置一个定时持久化行为。消息持久化对于不能丢失的重要消息框架可能不支持原生持久化。一种方案是实现一个“持久化代理”智能体所有重要消息都先发给它由它负责写入可靠存储如Kafka、RabbitMQ后再转发给目标智能体。检查点与恢复实现一个机制定期为整个多智能体系统创建检查点快照。当系统重启时可以从最近的检查点恢复智能体状态并重新投递未处理的消息。这通常需要框架层面的支持或大量的自定义开发。7. 扩展思路与外部世界连接一个封闭的多智能体系统价值有限真正的威力在于它能与现有的企业系统集成。集成外部API与服务你的智能体可以很容易地调用外部REST API、gRPC服务或数据库。只需在相应的行为Behaviour中使用常用的HTTP客户端如OkHttp、Apache HttpClient或数据库连接池如HikariCP即可。重要的是处理好异步调用避免阻塞行为线程。作为微服务的一部分你可以将整个copaw-java运行时环境嵌入到一个Spring Boot微服务中。让这个微服务作为“智能体托管平台”通过REST接口接收外部请求然后将其转化为内部智能体间的消息进行协调处理最后再将结果通过API返回。这样你的多智能体系统就成为了一个具有智能决策能力的后台服务。前端可视化监控为了运维方便可以开发一个简单的Web控制台通过框架可能提供的管理API或自己暴露JMX Bean实时展示所有运行的智能体、它们的状态、消息队列深度等信息。这对于调试和监控复杂的工作流至关重要。经过以上几个章节的拆解我们从概念到实践从简单对话到复杂工作流再到生产级问题的考量对liupengpop/copaw-java这个Java多智能体框架有了一个比较立体的认识。它的核心价值在于提供了一套用于构建高内聚、低耦合、自适应软件系统的编程模型和运行时。虽然入门需要理解一些新的概念如Agent、Behaviour、ACL但一旦掌握你在处理复杂业务流程自动化、分布式决策等问题时手中就多了一件非常犀利的武器。在实际使用中多写日志、重视消息协议的设计、提前考虑状态持久化是保证项目成功的关键。这个领域还在不断发展希望这个框架和这篇分享能成为你探索多智能体世界的一块坚实垫脚石。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2578169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…