LangGraph与ChatChat集成:构建可编排智能体应用框架的实践指南

news2026/5/3 6:24:17
1. 项目概述当LangGraph遇上ChatChat构建新一代智能体应用框架最近在开源社区里一个名为“chatchat-space/LangGraph-Chatchat”的项目引起了我的注意。简单来说这是一个将LangChain生态中的LangGraph框架与ChatChat项目深度集成的成果。如果你正在探索如何构建更复杂、更可控、更接近人类工作流的AI智能体应用那么这个项目绝对值得你花时间研究。它本质上提供了一个基于LangGraph的、可编排的智能体应用开发框架特别适合那些不满足于简单问答而是希望AI能够按照预设流程执行多步骤任务、具备记忆和状态管理能力的开发者。LangGraph本身是LangChain推出的一个用于构建有状态、多智能体应用的库它用“图”的概念来定义智能体的工作流节点代表操作或工具调用边代表控制流。而ChatChat则是一个知名的、功能丰富的开源对话应用项目。两者的结合意味着你可以利用ChatChat已有的对话界面、知识库管理、工具集成等能力再赋予其LangGraph强大的流程编排和状态管理功能。这解决了传统对话系统在应对复杂、长链条任务时逻辑分散、状态难以维护的痛点。无论是想开发一个能帮你完成从需求分析、代码编写到测试部署全流程的编程助手还是一个能理解多轮对话上下文、主动调用外部API完成订票、查询、汇总的智能客服这个项目都提供了一个高起点的实现方案。2. 核心架构与设计思想拆解2.1 为什么是LangGraph图计算与智能体工作流要理解这个项目的价值首先得弄明白LangGraph解决了什么问题。在传统的基于LangChain的智能体开发中我们常用的是AgentExecutor它内部是一个循环思考LLM决定下一步行动- 执行调用工具- 观察获取工具结果- 再思考……这个模式对于简单任务没问题但一旦流程变复杂比如需要条件分支、循环、并行执行或者维护一个跨越多个步骤的共享状态时就显得力不从心了。LangGraph引入了“图”Graph作为一等公民。你可以把整个智能体的工作流程画成一张有向图。图中的每个节点Node是一个函数它执行特定的操作比如调用LLM、运行工具、更新状态。节点之间的边Edge定义了流程的走向可以是固定的执行完A就到B也可以是基于条件的根据上一步的结果决定去往C还是D。更重要的是整个图共享一个持久化的“状态”State这个状态对象会在节点间传递和修改完美地记录了任务执行的上下文。这种设计带来了几个核心优势显式的工作流定义流程一目了然不再是“黑盒”循环便于调试、优化和向他人解释。复杂逻辑支持轻松实现if-else分支、for/while循环、甚至子图嵌套能建模非常复杂的业务逻辑。持久化与可恢复性由于状态被显式管理理论上可以随时保存和加载任务执行快照实现长时任务的暂停与恢复。多智能体协作可以很方便地在图中定义多个具备不同能力的“智能体”节点让它们通过共享状态协同工作。2.2 ChatChat的基石为何选择它作为集成平台ChatChat本身是一个成熟的开源项目它已经解决了AI应用开发中的许多基础设施问题。集成LangGraph相当于为一座功能完备的大楼ChatChat安装了一套先进的中央控制系统LangGraph。ChatChat主要提供了以下关键能力使其成为LangGraph的理想载体开箱即用的Web对话界面提供了类似ChatGPT的聊天界面省去了前端开发的麻烦。多模型支持与统一接口可以方便地接入OpenAI、Azure、国内各大模型厂商的API以及本地部署的Ollama等模型通过统一的配置进行管理。知识库RAG集成内置了从文档上传、向量化存储到检索增强生成RAG的完整链路。这对于需要基于私有知识进行问答的智能体至关重要。工具Function Calling管理已经有一套机制来定义、注册和管理可供LLM调用的外部工具如搜索、计算、API调用。项目结构与配置管理提供了清晰的项目目录结构和配置系统便于扩展和维护。因此LangGraph-Chatchat项目所做的就是在ChatChat的架构之上引入LangGraph作为新的“智能体引擎”替换或增强原有的简单对话或Agent执行器。开发者可以在享受ChatChat便利性的同时获得LangGraph带来的强大流程编排能力。2.3 项目融合的核心思路扩展而非颠覆这个项目的设计哲学很清晰不是重写ChatChat而是扩展它。通常集成会遵循以下路径创建LangGraph图定义在ChatChat的项目结构中新增一个模块例如graphs/目录用于存放不同业务场景的LangGraph图定义。每个图定义文件会描述节点、边、初始状态和状态结构。封装图执行器编写一个统一的GraphRunner类或函数。它负责初始化LangGraph图实例处理输入用户问题、当前会话等运行图并返回最终结果和可能的新状态。这个执行器需要与ChatChat的API路由或对话处理逻辑对接。工具集成将ChatChat已有的工具系统“暴露”给LangGraph的节点。LangGraph的节点函数可以调用这些已注册的工具实现能力复用。状态与会话管理将LangGraph的State与ChatChat的对话会话Session关联起来。可能将会话ID作为状态的一部分或者将图的状态存储在对话相关的上下文中以实现多轮对话的状态保持。配置化与动态加载通过ChatChat的配置系统允许用户选择对不同类型的问题使用不同的预定义图实现动态工作流路由。注意在集成过程中一个关键决策是如何处理“流式输出”。原生LangGraph支持流式返回每个节点的结果而ChatChat的对话接口也可能支持流式响应。需要将两者结合实现边执行、边返回的体验例如先返回“我正在思考”然后“正在搜索…”最后给出完整答案。3. 核心细节解析与实操要点3.1 状态State的设计智能体的记忆核心在LangGraph中State是一个TypedDict或Pydantic模型它定义了在整个图执行过程中流转和变化的数据结构。设计一个好的State是成功的关键。在LangGraph-Chatchat的上下文中一个典型的State可能包含以下字段from typing import TypedDict, List, Annotated from langgraph.graph.message import add_messages import operator class AgentState(TypedDict): # 消息历史LangGraph内置的“消息”处理便于LLM理解上下文 messages: Annotated[List, add_messages] # 用户输入的原始问题 user_input: str # 从知识库检索到的相关文档片段 retrieved_docs: List[str] # 当前步骤的中间思考或指令 current_directive: str # 已调用工具的历史记录用于自我检查或复盘 tool_calls_history: List[dict] # 最终生成的答案 final_answer: str # 标记流程是否应该继续 should_continue: bool设计要点职责分离messages字段专用于和LLM交互的历史通常由add_messages这个Reducer自动处理追加。其他业务状态如retrieved_docs、tool_calls_history应单独定义。可序列化确保State中所有数据类型都是可JSON序列化的这对于状态持久化保存到数据库或文件至关重要。精简与必要不要把所有数据都塞进State。只放入需要在多个节点间共享和修改的数据。节点内部的临时变量应作为局部变量处理。3.2 节点Node函数编写单一职责与纯净性每个节点都是一个普通的Python函数或可调用对象它接收当前的State作为参数返回一个包含对State所做更新的字典。def retrieve_node(state: AgentState) - dict: 检索节点根据用户问题从知识库获取相关文档 user_question state[“user_input”] # 调用ChatChat已有的知识库检索接口 # 假设有一个全局可用的retriever对象 docs retriever.get_relevant_documents(user_question) return {“retrieved_docs”: docs, “current_directive”: “已获取相关背景知识。”} def llm_plan_node(state: AgentState) - dict: 规划节点让LLM基于问题和检索结果制定下一步计划 from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI prompt ChatPromptTemplate.from_messages([ (“system”, “你是一个任务规划助手。请根据用户问题和已有信息决定下一步做什么。可以直接回答或者建议调用某个工具。”), (“human”, “用户问题{question}\n相关背景{docs}”) ]) model ChatOpenAI(model“gpt-4”, temperature0) chain prompt | model # 注意这里从state[‘messages’]中获取历史对话可能更佳 response chain.invoke({“question”: state[“user_input”], “docs”: state[“retrieved_docs”]}) # 解析response判断是直接回答还是调用工具 # 这里简化处理将LLM的回复放入消息历史并更新指令 new_messages [response] # 实际应追加到state[‘messages’] return {“messages”: new_messages, “current_directive”: “已生成初步计划。”}实操心得保持节点纯净节点函数应尽量是“无副作用”的纯函数逻辑。如果需要调用外部服务数据库、API最好通过依赖注入或全局可访问的、已初始化的客户端对象来进行而不是在函数内部创建连接。错误处理在节点内进行细致的错误处理try-except。当发生错误时可以更新State中的一个error字段并引导流程走向一个专门的“错误处理节点”而不是让整个图崩溃。日志记录在每个节点的关键步骤添加日志记录输入、输出和耗时。这对于调试复杂的工作流非常有帮助。可以将日志信息也写入State的一个特定字段便于前端展示执行轨迹。3.3 边Edge与路由逻辑控制流程的缰绳边定义了节点执行完毕后接下来该执行哪个节点。边可以是固定的也可以由“路由函数”动态决定。from langgraph.graph import END, StateGraph def should_continue(state: AgentState) - str: 路由函数根据状态决定下一步是调用工具还是结束 last_message state[“messages”][-1] # 假设我们通过一个工具解析函数来判断LLM是否想调用工具 if hasattr(last_message, ‘tool_calls’) and last_message.tool_calls: return “call_tool_node” # 前往工具调用节点 else: return “generate_final_answer_node” # 前往最终答案生成节点 # 构建图 builder StateGraph(AgentState) builder.add_node(“retrieve”, retrieve_node) builder.add_node(“plan”, llm_plan_node) builder.add_node(“call_tool”, tool_call_node) builder.add_node(“generate_answer”, final_answer_node) # 设置边 builder.set_entry_point(“retrieve”) builder.add_edge(“retrieve”, “plan”) # plan节点之后由路由函数决定去向 builder.add_conditional_edges( “plan”, should_continue, # 路由函数 { “call_tool_node”: “call_tool”, “generate_final_answer_node”: “generate_answer” } ) builder.add_edge(“call_tool”, “plan”) # 调用工具后返回规划节点重新评估 builder.add_edge(“generate_answer”, END) graph builder.compile()注意事项避免循环当设计“工具调用 - 规划 - 工具调用”这样的循环时必须设置明确的终止条件例如最大迭代次数、LLM明确表示不再需要工具否则可能陷入死循环。可以在State中增加一个iteration_count字段并在路由函数中检查。条件边的映射add_conditional_edges中路由函数返回的字符串必须与后续节点的名称完全匹配否则会运行时错误。入口与出口set_entry_point和add_edge(…, END)定义了图的开始和结束。一个图可以有多个结束路径。4. 在ChatChat中的集成与工程化实践4.1 项目结构规划在ChatChat项目中集成LangGraph建议采用以下目录结构保持清晰和可维护性chatchat/ ├── server/ │ ├── graph_runner.py # 图执行器封装 │ ├── graphs/ # 存放所有图定义 │ │ ├── __init__.py │ │ ├── base_graph.py # 基础图类封装公共逻辑 │ │ ├── qa_agent_graph.py # 一个具体的问答智能体图 │ │ ├── data_analysis_agent_graph.py # 数据分析智能体图 │ │ └── ... │ └── ... ├── webui_pages/ │ └── dialogue.py # 修改对话处理逻辑调用graph_runner └── configs/ └── graph_config.yaml # 图的配置文件如图与路由的映射4.2 图执行器GraphRunner封装GraphRunner是整个集成的枢纽它负责图的加载、配置、执行和状态管理。# server/graph_runner.py import asyncio from typing import Any, Dict, Optional from langgraph.graph import StateGraph from .graphs.qa_agent_graph import create_qa_agent_graph from .graphs.data_analysis_agent_graph import create_data_analysis_graph class GraphRunner: _graph_registry {} classmethod def init_graphs(cls, config): 初始化所有图实例。 # 可以根据配置动态加载 cls._graph_registry[“qa_agent”] create_qa_agent_graph(config) cls._graph_registry[“data_analyst”] create_data_analysis_graph(config) classmethod async def run_graph( cls, graph_name: str, input_state: Dict[str, Any], stream_mode: bool False, config: Optional[Dict] None ) - Any: 运行指定的图。 if graph_name not in cls._graph_registry: raise ValueError(f”Graph ‘{graph_name}’ not registered.”) graph: StateGraph cls._graph_registry[graph_name] compiled_graph graph.compile() if stream_mode: # 流式执行返回一个异步生成器 async for event in compiled_graph.astream(input_state, configconfig): yield event else: # 非流式直接返回最终结果 final_state await compiled_graph.ainvoke(input_state, configconfig) return final_state classmethod def predict_graph_for_query(cls, user_query: str) - str: 根据用户查询预测应该使用哪个图。可以基于规则或一个简单的分类模型。 if “数据分析” in user_query or “统计” in user_query: return “data_analyst” # 默认返回通用问答图 return “qa_agent”4.3 与ChatChat对话API的对接需要修改ChatChat处理对话请求的入口通常是webui_pages/dialogue.py或类似的API路由文件将原本直接调用LLM或简单Agent的逻辑替换为调用GraphRunner。# 在对话处理函数中示例 async def chat_stream(graph_runner, query, history, knowledge_base_name): 流式对话处理 # 1. 根据查询和知识库决定使用哪个图 graph_name graph_runner.predict_graph_for_query(query) # 2. 构建初始状态 initial_state { “messages”: history, # ChatChat的历史消息格式可能需要转换 “user_input”: query, “knowledge_base_name”: knowledge_base_name, “retrieved_docs”: [], “final_answer”: “”, “should_continue”: True } # 3. 流式执行图 async for event in graph_runner.run_graph(graph_name, initial_state, stream_modeTrue): # 处理不同类型的事件例如新的消息、工具调用开始/结束、状态更新等 if “messages” in event: new_message event[“messages”][-1] # 将新的消息内容可能是思考过程或部分答案流式返回给前端 yield f”data: {json.dumps({‘text’: new_message.content})}\n\n” elif “final_answer” in event: # 最终答案生成完毕 yield f”data: {json.dumps({‘final’: True, ‘text’: event[‘final_answer’]})}\n\n” yield “data: [DONE]\n\n”工程化要点状态持久化对于需要跨会话保持状态的长时间任务需要将compiled_graph.get_state(config)获取的状态序列化后存储到数据库如Redis、PostgreSQL并在下次请求时通过compiled_graph.update_state(config)恢复。这需要将会话ID与图状态ID关联。并发与线程安全GraphRunner和底层的LangGraph图需要处理并发请求。确保图本身是无状态的状态由每次调用传入或者使用线程安全的机制管理共享资源如模型客户端。配置热更新图的结构如提示词、工具列表可能需要动态调整。可以考虑将图定义的关键部分参数化并通过配置文件管理支持不重启服务的热更新。5. 典型应用场景与图设计案例5.1 场景一复杂问答与决策支持智能体需求用户提出一个复杂问题需要结合知识库检索、多步骤推理和可能的外部数据验证。图设计节点1问题分析与拆解。LLM节点将用户复杂问题拆解成若干子问题或明确信息需求。节点2并行知识检索。针对拆解出的多个子问题并行调用向量检索工具从不同知识库或文档集合中查找信息。节点3信息综合与矛盾检测。LLM节点评估检索到的多条信息解决可能的冲突进行初步综合。条件边判断信息是否充足是 - 节点5否 - 节点4。节点4主动追问。LLM节点基于缺失或模糊的信息生成追问语句与用户交互。更新状态等待用户下一轮输入这需要将会话暂停状态保存。节点5生成结构化报告。LLM节点使用思维链Chain-of-Thought提示生成包含结论、依据和推理过程的最终答案。实操技巧在“并行知识检索”节点可以使用LangGraph的async支持并发调用多个检索工具显著提升效率。状态中需设计字段如sub_questions,retrieved_results_per_subq来存储中间结果。5.2 场景二自动化数据分析与报告生成智能体需求用户上传一个数据集CSV要求智能体完成数据清洗、分析和可视化并生成报告。图设计节点1需求理解与方案制定。LLM节点分析用户指令生成一个详细的数据分析计划如需要计算哪些统计量、绘制哪类图表、检查哪些异常值。节点2数据加载与探查。工具节点调用Python代码执行工具如pandas加载数据执行.info(),.describe()等将结果摘要返回给状态。节点3数据清洗。LLM节点根据探查结果和计划生成数据清洗代码处理缺失值、异常值、类型转换。工具节点执行该代码。循环边清洗后返回节点2进行再次探查评估清洗效果。可设置最大清洗轮次。节点4分析与可视化。根据计划循环调用“LLM生成分析/绘图代码 - 工具执行”这对节点将每个分析结果统计表、图表图片路径存入状态。节点5报告合成。LLM节点汇总所有分析结果生成一份包含文字描述、关键发现和图表引用的Markdown格式报告。注意事项执行任意代码存在安全风险。必须在一个严格的沙箱环境如Docker容器、restrictedpython中运行工具节点生成的代码并对可导入的模块、可访问的资源进行严格限制。5.3 场景三多角色协作的创意生成智能体需求模拟一个创意团队生成一个营销方案。图设计定义状态包含brief需求简报、brainstorm_ideas头脑风暴点子、critiques批评意见、final_plan最终方案等字段。节点A创意师。LLM节点角色扮演天马行空的创意师基于brief生成若干brainstorm_ideas。节点B分析师。LLM节点角色扮演严谨的分析师对brainstorm_ideas进行挑剔生成critiques。节点C经理。LLM节点角色扮演决策经理综合考虑ideas和critiques提炼修改意见更新brief。编排流程可以设计为A - B - C - A的循环进行多轮迭代。在C节点设置路由函数当final_plan达到满意标准如经理节点认为无需再修改时跳转到结束节点。节点D文案。最终由文案角色节点根据确定的final_plan生成完整的营销文案。心得这种多智能体协作图关键在于设计好各角色节点的系统提示词System Prompt让它们具有鲜明且稳定的“人格”。同时状态的设计要能清晰地区分不同角色的产出避免混淆。6. 性能优化、调试与监控6.1 性能优化策略图的编译与缓存graph.compile()有一定开销。对于预定义的图应在服务启动时编译好并缓存起来而不是每次请求都编译。流式处理与中间输出充分利用LangGraph的astream或astream_eventsAPI将中间思考过程、工具调用状态实时返回给前端提升用户体验同时避免等待最终结果时的超时。LLM调用优化批处理对于图中可以并行且使用相同提示词的LLM调用可以考虑合并成批处理请求如果底层API支持。缓存对LLM的相同输入进行缓存特别是那些在图中可能被重复计算的步骤如固定的指令解析。模型分级对于决策、规划等需要较强推理能力的节点使用大模型如GPT-4对于简单的文本格式化、信息提取节点可以使用小模型或快速模型降低成本与延迟。工具调用异步化确保工具节点特别是涉及网络IO的如调用外部API使用异步函数async def并在图中使用aiohttp等异步客户端避免阻塞事件循环。6.2 调试与问题排查调试一个运行中的图比调试线性代码更复杂。以下是一些有效方法可视化图结构使用graph.get_graph().draw_mermaid_png()或graph.get_graph().to_json()导出图的结构用Mermaid或Graphviz可视化直观理解流程。详细日志记录在每个节点的入口和出口打印State的关键快照。使用LangGraph的astream_eventsAPI它可以产生更精细的事件流包括“节点开始”、“节点结束”、“边触发”等是调试的神器。async for event in compiled_graph.astream_events(input_state, version“v1”): event_type event[“event”] node_name event.get(“name”) print(f”{event_type} - {node_name}”) if event_type “on_chain_end” and node_name “some_node”: print(“State after node:”, event[“data”].get(“output”))状态检查点在关键节点后将State序列化保存到文件。当流程出现意外结果时可以加载检查点复现问题。单元测试单个节点为每个节点函数编写单元测试模拟输入State验证输出State的更新是否符合预期。6.3 监控与可观测性在生产环境中需要对智能体工作流的运行情况进行监控。关键指标执行耗时整个图及每个节点的平均执行时间、P95/P99耗时。节点调用次数与成功率统计每个节点的被调用次数、成功完成次数和异常次数。工具调用统计各个工具被调用的频率、耗时和成功率。LLM Token消耗记录每次LLM调用的输入/输出token数用于成本分析。实现方式可以在GraphRunner.run_graph方法中或每个节点函数内部添加埋点将指标发送到监控系统如Prometheus。也可以利用LangGraph的astream_events事件流在特定事件如on_chain_end中收集数据。链路追踪为每个用户请求生成唯一的trace_id并贯穿整个图执行过程。将所有日志、工具调用、LLM请求都与该trace_id关联便于在分布式系统中追踪一个请求的完整生命周期。7. 常见问题与排查技巧实录在实际开发和运维基于LangGraph-Chatchat的应用时会遇到一些典型问题。以下是我总结的“避坑指南”。问题现象可能原因排查步骤与解决方案图执行陷入死循环1. 条件边路由逻辑有误导致在两个或多个节点间无限循环。2. 未设置最大迭代次数限制而LLM始终无法给出结束信号。1.检查路由函数打印路由函数的输入State和输出下一个节点名确认逻辑正确。2.添加安全阀在State中增加iteration_count字段每次循环递增。在路由函数开头检查若超过阈值如10次则强制返回END或一个“失败处理”节点。3.优化提示词在系统提示中明确要求LLM在适当时候给出“任务完成无需再调用工具”的指示。State字段更新不生效1. 节点函数返回的字典键名与State中定义的字段名不匹配。2. 使用了错误的Reducer。例如对于列表追加应使用add_messages或operator.add而不是直接赋值。1.仔细核对字段名确保返回字典的键与TypedDict或Pydantic模型中的字段名完全一致。2.理解Reducer对于Annotated[List, add_messages]修饰的字段节点返回{“messages”: [new_message]}即可框架会自动追加。对于Annotated[int, operator.add]修饰的字段返回{“count”: 1}会使state[‘count’]增加1。直接赋值会覆盖。流式输出卡顿或中断1. 某个节点执行时间过长如调用慢速API阻塞了整个事件流。2. 网络问题或前端处理逻辑有误。1.异步化所有阻塞操作确保图中所有涉及IO网络、磁盘、数据库的节点函数都是async def并使用异步客户端。2.设置超时在工具调用或LLM调用处设置合理的超时时间避免单个节点挂起。3.分块输出对于LLM生成的长文本可以利用模型本身的流式输出能力或者手动将文本分块通过yield逐步返回而不是等全部生成完再返回。工具调用结果无法被LLM理解1. 工具返回的数据结构太复杂或非结构化LLM无法有效解析。2. 系统提示词中未明确说明工具返回数据的格式和含义。1.规范化工具输出设计工具时其返回结果应尽量简洁、结构化如JSON。可以在工具节点中增加一个后处理步骤将原始结果转换成LLM容易理解的文本摘要。2.在上下文中提供示例在给LLM的提示词中包含几个工具调用和结果解析的示例Few-shot指导它如何利用返回信息。多轮对话中状态混乱1. 图的状态没有正确与会话关联不同用户或不同轮次的状态互相污染。2. 状态中积累了过多历史信息导致后续节点处理变慢或LLM上下文超长。1.会话隔离确保每次对话请求GraphRunner都使用基于会话ID的唯一状态进行初始化或加载。在ChatChat集成时将session_id作为State的一个必填字段。2.状态压缩与清理设计一个“状态整理”节点在对话轮次过多时对state[‘messages’]进行摘要或选择性遗忘只保留最近几轮和关键信息避免上下文爆炸。集成后ChatChat原有功能异常1. 修改了ChatChat的核心对话处理逻辑影响了非LangGraph路径的请求。2. 资源如模型客户端初始化冲突。1.渐进式集成不要一次性替换所有对话逻辑。可以增加一个配置开关或路由规则只有匹配特定条件的请求才走LangGraph路径其他请求仍走原有流程。2.依赖注入确保LangGraph图和ChatChat其他部分共享相同的、正确初始化的资源实例如模型客户端、数据库连接池避免重复创建或配置不一致。最后一点个人体会LangGraph-Chatchat这个组合的强大之处在于它将智能体应用的开发从“脚本编写”提升到了“工作流设计”的层面。初期学习曲线确实比直接写链Chain或简单Agent要陡峭需要理解图、状态、节点、边这些概念。但一旦掌握其带来的清晰度、可维护性和对复杂逻辑的掌控力是巨大的。建议从实现一个简单的、线性的问答图开始逐步增加条件判断、循环和多智能体协作。多使用astream_events来观察执行过程它是最好的调试和学习工具。记住设计图就是设计你希望AI如何思考和工作这本身就是一个极具创造性和价值的过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2577422.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;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…