LangChain与LangGraph实战:从零构建智能体应用与RAG系统

news2026/4/27 21:36:07
1. 项目概述从零构建你的第一个智能体应用如果你对AI应用开发感兴趣尤其是想亲手打造一个能调用工具、有记忆、能自主决策的智能体Agent那么LangChain和LangGraph这两个框架是你绕不开的利器。我最近花了大量时间系统梳理了LangChain 1.0和LangGraph 1.0的最新变化并整理了一套从入门到实战的完整学习路径。这个仓库就是我的学习笔记和实践成果它不是一个简单的代码合集而是一个结构化的、可复现的“学习引擎”。LangChain 1.0在2025年10月正式发布它不再仅仅是一个胶水框架而是构建在LangGraph运行时之上带来了持久化、流式处理和更精细的控制能力。而LangGraph 1.0则专注于用“图”的思维来编排复杂的工作流让多智能体协作、条件分支等高级功能变得直观。这套组合拳正是开发现代化、生产级AI应用的核心。无论你是想做一个能联网查资料的问答机器人一个自动处理文档的智能助手还是一个由多个“专家”协作的客服系统这里的内容都能给你提供清晰的实现路径。这个指南适合所有层次的开发者如果你是AI应用开发的新手可以跟着第一阶段从“Hello World”开始一步步理解核心概念如果你已有一些经验可以直接跳到第二、三阶段的实战和高级主题学习如何优化RAG效果、设计多智能体系统如果你想挑战综合项目第四阶段提供了三个完整的项目蓝图涵盖了从数据准备、智能体构建到前后端集成的全流程。接下来我将为你详细拆解这个学习体系的每一个环节并分享我在实践中踩过的坑和总结出的最佳实践。2. 学习路径设计与核心思路解析2.1 为什么选择四阶段渐进式学习法设计学习路径时我摒弃了直接堆砌代码片段的方式而是采用了“概念-技能-高级主题-综合项目”的四阶段模型。这是因为智能体开发涉及的概念链较长从基础的模型调用到复杂的状态图编排如果跳跃学习很容易陷入“代码能跑但不知其所以然”的困境。第一阶段“基础知识”的目标是建立直觉。我们不过多涉及底层原理而是通过六个模块快速让你看到成果如何调用模型、如何格式化提示词、如何让AI记住对话历史、如何给它“安装”一个获取天气的工具以及如何将这些组合成一个能自主调用工具的简单智能体。这个阶段的关键是建立正反馈让你快速感受到LangChain 1.0 API的简洁性特别是新的create_agent函数它极大简化了智能体的创建流程。第二阶段“实战技能”开始深入核心机制。当你有了一个能跑的智能体后自然会产生疑问对话长了怎么办如何把对话状态存到数据库里以便下次恢复AI的输出格式乱七八糟怎么让它乖乖地返回结构化的JSON这就是本阶段要解决的问题。我们会学习内存管理、状态持久化、中间件拦截、结构化输出和RAG检索。这个阶段是承上启下的关键你会开始理解框架背后的设计哲学。第三阶段“高级主题”面向复杂场景。当单个智能体不够用时就需要LangGraph登场了。我们将学习如何用“图”来定义工作流让不同的智能体或功能节点协同工作并根据条件动态选择执行路径。同时我们也会处理图像、文件等多模态输入并集成LangSmith来监控和调试整个系统的运行。这一阶段的内容能让你有能力设计企业级的复杂AI应用。第四阶段“综合项目”是成果验收。我们将前三个阶段的知识点融合构建三个典型的应用一个带优化技巧的RAG文档问答系统、一个能自动分流和协作的多智能体客服系统、一个能自动搜集资料并撰写报告的研究助手。通过项目实战你将真正掌握如何将分散的知识点串联成一个可交付的产品。2.2 环境配置与工具选型的深层考量工欲善其事必先利其器。在环境配置上我做了几个关键选择背后都有其考量。首先强制要求Python 3.10。这是因为LangChain 1.0大量使用了Python的新类型注解特性如TypedDict,Annotated这些特性在3.9中要么不支持要么不够完善。使用3.10能确保最佳的开发体验和代码提示。其次模型提供商首选Groq。在示例和项目中我大量使用了Groq的API如groq:llama-3.3-70b-versatile。这不仅仅是因为它提供免费的额度更重要的是它的推理速度极快对于学习和快速迭代体验非常好。当然框架本身是模型无关的你可以轻松替换为OpenAI、Anthropic或本地部署的Ollama模型。在.env.example中预留多个API Key位置正是为了这种灵活性。再者向量数据库选择Pinecone。在RAG相关模块中我使用Pinecone作为示例。原因在于它是一款完全托管的云服务无需自己搭建和维护数据库对于学习者来说门槛最低。它的免费层足够完成所有实验。在实际生产项目中你可以根据数据量、隐私要求和成本选择ChromaDB本地、Weaviate或Qdrant等。最后强烈建议配置LangSmith。虽然它是可选的但我认为对于任何严肃的开发者都是必选项。LangSmith是LangChain官方出品的监控调试平台。它能可视化你的智能体每一步的思考过程、工具调用、token消耗和耗时。当你的智能体行为不符合预期时LangSmith是排查问题的“终极武器”。在“LangSmith集成”模块中我会详细展示如何通过几行代码接入并利用它来优化提示词和工具设计。注意在克隆仓库并安装依赖后第一件事就是复制.env.example为.env并填入你的API密钥。特别是GROQ_API_KEY没有它大部分示例都无法运行。获取方式是免费的只需在Groq官网注册即可。3. 核心概念与新版API深度剖析3.1 LangChain 1.0 的核心变革从链Chain到运行时RuntimeLangChain早期版本的核心抽象是“链”Chain它将多个组件线性串联。而LangChain 1.0一个根本性的转变是其核心构建在LangGraph的“运行时”之上。这意味着什么这意味着状态管理、持久化、流式输出、人工干预human-in-the-loop这些高级功能现在成为了框架的一等公民。最直观的体现就是新的create_agentAPI。在旧版本中创建一个智能体可能需要组合initialize_agent、AgentExecutor等多个对象配置繁琐。而在1.0中它被极大地简化了from langchain.chat_models import init_chat_model from langchain.agents import create_agent from langchain_core.tools import tool # 1. 初始化模型 - 注意新的 init_chat_model 入口 model init_chat_model(groq:llama-3.3-70b-versatile, temperature0) # 2. 定义工具 - 使用 tool 装饰器描述docstring至关重要 tool def search_web(query: str) - str: 当用户需要获取最新的、搜索引擎中的信息时使用此工具。输入应为一个明确的搜索查询词。 # 模拟搜索实际应调用Serper或Tavily等API return f关于{query}的搜索结果... # 3. 创建智能体 - 一行代码搞定 agent create_agent( modelmodel, tools[search_web], system_prompt你是一个有帮助的助手可以联网搜索最新信息。, # 关键参数system_prompt checkpoint_saverNone, # 可配置持久化 stream_modevalues # 启用流式输出 ) # 4. 调用智能体 - 输入必须是包含消息列表的字典 result agent.invoke({ messages: [{role: user, content: 今天科技圈有什么大新闻}] })这段代码包含了几个关键点模型初始化init_chat_model是新的统一入口它支持多种提供商格式provider:model-name。工具定义工具的docstring不再是可有可无的注释而是AI决定是否调用该工具的“说明书”。描述必须清晰、具体。系统提示词system_prompt参数直接设置在create_agent中这比旧版本中通过消息传递更直观。输入格式输入必须是一个字典且包含messages键其值是一个消息对象列表。这是为了兼容LangGraph的状态管理。实操心得create_agent返回的对象本身就是一个可运行的LangGraph“图”。这意味着你可以直接对它使用.stream()方法进行流式输出也可以使用.get_state()和.update_state()来手动管理其状态这为构建更复杂的交互界面如WebSocket提供了便利。3.2 消息Messages与对话历史智能体的记忆基石在LangChain 1.0中消息Message是对话的基本单元而对话历史本质上就是一个消息列表。理解不同的消息类型及其用途是构建有效对话系统的关键。from langchain_core.messages import HumanMessage, AIMessage, SystemMessage, ToolMessage # 构建一段对话历史 conversation_history [ SystemMessage(content你是一个专业的翻译助手。), HumanMessage(content请将‘Hello, world!’翻译成中文。), AIMessage(content你好世界), HumanMessage(content再翻译成法语。) ] # 将历史传递给模型 model init_chat_model(groq:llama-3.3-70b-versatile) response model.invoke(conversation_history) print(response.content) # 应输出法语翻译核心消息类型解析SystemMessage设定AI的角色和全局行为指令。通常在对话开始时注入一次对后续所有交互都有影响。HumanMessage用户输入的内容。AIMessageAI的回复。它可能包含tool_calls字段如果AI决定调用工具也可能包含content字段最终答案。ToolMessage当AI调用工具后你需要用此消息类型将工具的执行结果返回给AI以便它进行下一步推理。这个消息必须包含对应的tool_call_id。对话历史管理的常见陷阱与解决方案上下文窗口溢出大语言模型有token限制。当对话历史很长时直接传入会导致API调用失败。解决方案使用ChatMessageHistory或InMemorySaver来管理历史并搭配“消息修剪”策略。例如可以只保留最近N轮对话或者使用更智能的“摘要”方式将久远的历史压缩成一段摘要。状态丢失在Web服务中每次请求都是无状态的。如果不持久化智能体会“失忆”。解决方案使用checkpoint_saver参数。create_agent支持传入一个Saver对象如SqliteSaver它会自动将每次交互后的完整状态包括所有消息保存到数据库。下次通过thread_id恢复对话时智能体能完全接上之前的上下文。工具调用结果格式错误AI调用工具后你必须以ToolMessage格式返回结果否则AI无法处理。# 假设AI的响应中包含了工具调用response.tool_calls [{‘id’: ‘call_123’, ‘name’: ‘search_web’, ‘args’: {‘query’: ‘...’}}] # 你执行工具后需要构造ToolMessage tool_result search_web.invoke(“LangChain 1.0”) tool_message ToolMessage(contenttool_result, tool_call_id“call_123”) # 然后将此 tool_message 加入到历史中再次调用agent3.3 结构化输出Structured Output让AI返回规整的数据让大语言模型自由发挥返回的文本格式可能千奇百怪。但在实际应用中我们往往需要结构化的数据比如JSON以便后续的程序处理。LangChain 1.0通过与Pydantic模型深度集成提供了优雅的结构化输出解决方案。from pydantic import BaseModel, Field from langchain.chat_models import init_chat_model from langchain_core.output_parsers import PydanticOutputParser # 1. 定义你期望的数据结构 class PersonalInfo(BaseModel): name: str Field(description人物的全名) birth_year: int Field(description出生年份) occupation: str Field(description职业) summary: str Field(description一段简短的人物介绍) # 2. 创建输出解析器 parser PydanticOutputParser(pydantic_objectPersonalInfo) # 3. 构建提示词将格式要求告诉模型 prompt_template 请从以下文本中提取信息。 文本{text} 请严格按照以下格式输出{format_instructions} prompt PromptTemplate( templateprompt_template, input_variables[“text”], partial_variables{“format_instructions”: parser.get_format_instructions()} ) # 4. 组合成链并调用 model init_chat_model(“groq:llama-3.3-70b-versatile”) chain prompt | model | parser # 使用LCEL语法 text_input “爱因斯坦Albert Einstein1879年出生于德国是一位理论物理学家以其相对论闻名于世。” result chain.invoke({“text”: text_input}) print(type(result)) # class ‘__main__.PersonalInfo’ print(result.name) # 爱因斯坦 print(result.birth_year) # 1879关键优势类型安全输出的结果直接是一个Pydantic模型实例你可以使用.操作符访问属性IDE会有代码提示。自动重试如果AI第一次输出不符合格式PydanticOutputParser可以配置重试逻辑自动用错误信息修正提示词让模型再试一次。无缝集成这个PersonalInfo对象可以直接被序列化成JSON存入数据库或者传递给下一个处理环节。注意事项结构化输出会消耗更多的token因为提示词中需要包含格式说明。对于非常简单的字段提取有时手动编写正则表达式或使用更轻量的JsonOutputParser可能更高效。但对于复杂、嵌套的数据结构Pydantic方案在可维护性和稳定性上具有绝对优势。4. 实战进阶构建生产可用的RAG与智能体系统4.1 RAG系统构建从基础检索到高级优化检索增强生成RAG是将外部知识库与大模型结合的核心技术。一个基础的RAG流程包括加载文档、分割文本、向量化、存储到向量数据库、检索、最后将检索到的上下文与问题一起交给大模型生成答案。LangChain为此提供了完整的工具链。from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_pinecone import PineconeVectorStore from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough # 1. 加载与分割文档 loader PyPDFLoader(“path/to/your/document.pdf”) documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size1000, chunk_overlap200) splits text_splitter.split_documents(documents) # 2. 创建向量存储 embeddings HuggingFaceEmbeddings(model_name“BAAI/bge-small-zh-v1.5”) # 中文嵌入模型 vectorstore PineconeVectorStore.from_documents( documentssplits, embeddingembeddings, index_name“my-knowledge-base” ) # 3. 构建检索链 retriever vectorstore.as_retriever(search_kwargs{“k”: 4}) # 检索最相关的4个片段 # 4. 定义提示词模板 template “”“你是一个专业的问答助手。请根据以下上下文来回答问题。 上下文{context} 问题{question} 如果上下文不包含答案请如实回答‘我不知道’。答案”“” prompt ChatPromptTemplate.from_template(template) # 5. 初始化模型 model init_chat_model(“groq:llama-3.3-70b-versatile”) # 6. 使用LCEL组合成RAG链 rag_chain ( {“context”: retriever, “question”: RunnablePassthrough()} | prompt | model ) # 7. 提问 answer rag_chain.invoke(“LangChain是什么”) print(answer.content)基础RAG的痛点与高级优化技巧基础的RAG经常面临“检索不准”和“生成幻觉”的问题。以下是几个经过实战检验的优化方向分块Chunking策略优化RecursiveCharacterTextSplitter是通用选择但对于特定文档如代码、Markdown效果可能不佳。尝试语义分块使用SemanticChunker它尝试在语义边界如句子结束处进行分割能更好地保持语义完整性。采用小尺寸重叠chunk_overlap设置过小可能导致关键信息被割裂通常设置为chunk_size的10%-20%。检索Retrieval优化简单向量相似度搜索可能召回不相关文档。混合搜索Hybrid Search结合向量搜索语义相似和关键词搜索如BM25。Pinecone等数据库原生支持。这能同时捕捉语义和精确词汇匹配。重排序Re-ranking先用向量搜索召回较多文档如k20再用一个更小、更快的重排序模型如BGE Reranker对结果进行精排只保留最相关的3-5个传给大模型。这能显著提升精度。元数据过滤在存储文档时为其添加元数据如来源、章节、日期。检索时可以添加过滤器如filter{“source”: “user_manual.pdf”}实现更精准的检索。提示词Prompt工程清晰的指令能减少幻觉。强制引用在提示词中加入“请根据上下文回答并引用相关的原文片段”可以引导模型更忠实于上下文。多步推理对于复杂问题可以设计两个步骤的链第一步让模型根据检索到的上下文先提取或总结出关键事实第二步基于这些事实组织语言生成最终答案。4.2 利用LangGraph构建多智能体协作系统当任务变得复杂单个智能体力不从心时就需要多个智能体分工协作。LangGraph通过“状态图”的概念让这种协作变得可编程、可视化。一个经典的模式是“主管-工作者”模式。假设我们要构建一个智能客服系统用户的问题可能涉及“技术咨询”、“订单查询”和“投诉建议”三类。我们可以设计一个主管智能体Supervisor来识别意图并路由给三个专业的子智能体。from typing import TypedDict, Annotated, List from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages from langchain.chat_models import init_chat_model from langchain_core.messages import BaseMessage # 1. 定义共享状态 class AgentState(TypedDict): messages: Annotated[List[BaseMessage], add_messages] # 核心消息列表会自动累加 next: str # 用于决定下一个执行节点 # 2. 初始化各个智能体这里简化实际每个agent可能有不同工具和提示词 model init_chat_model(“groq:llama-3.3-70b-versatile”) tech_agent create_agent(model, tools[], system_prompt“你是技术专家解答产品使用和技术问题。”) order_agent create_agent(model, tools[query_order_tool], system_prompt“你是订单专员处理订单查询和物流问题。”) complaint_agent create_agent(model, tools[], system_prompt“你是客服经理处理用户投诉和建议态度需诚恳。”) # 3. 定义各个节点函数 def supervisor_node(state: AgentState): 主管节点分析用户最新消息决定路由到哪个专业agent last_message state[“messages”][-1].content # 简单的关键词路由逻辑实际可使用一个分类LLM if “怎么用” in last_message or “故障” in last_message: return {“next”: “tech_agent”} elif “订单” in last_message or “物流” in last_message: return {“next”: “order_agent”} elif “投诉” in last_message or “建议” in last_message: return {“next”: “complaint_agent”} else: return {“next”: “general_agent”} # 默认通用agent def tech_agent_node(state: AgentState): 技术agent节点调用技术agent处理 agent_response tech_agent.invoke(state) return {“messages”: [agent_response[“messages”][-1]]} # 将AI回复添加到状态 def order_agent_node(state: AgentState): 订单agent节点 agent_response order_agent.invoke(state) return {“messages”: [agent_response[“messages”][-1]]} def complaint_agent_node(state: AgentState): 投诉agent节点 agent_response complaint_agent.invoke(state) return {“messages”: [agent_response[“messages”][-1]]} # 4. 构建图 workflow StateGraph(AgentState) # 添加节点 workflow.add_node(“supervisor”, supervisor_node) workflow.add_node(“tech_agent”, tech_agent_node) workflow.add_node(“order_agent”, order_agent_node) workflow.add_node(“complaint_agent”, complaint_agent_node) workflow.add_node(“general_agent”, general_agent_node) # 省略定义 # 5. 定义边路由逻辑 workflow.add_edge(START, “supervisor”) # 从开始到主管 # 根据主管节点的“next”决定动态路由 workflow.add_conditional_edges( “supervisor”, lambda state: state[“next”], # 根据state[“next”]的值选择下一个节点 { “tech_agent”: “tech_agent”, “order_agent”: “order_agent”, “complaint_agent”: “complaint_agent”, “general_agent”: “general_agent”, } ) # 各专业agent处理完后都回到主管准备处理用户下一条消息 workflow.add_edge(“tech_agent”, “supervisor”) workflow.add_edge(“order_agent”, “supervisor”) workflow.add_edge(“complaint_agent”, “supervisor”) workflow.add_edge(“general_agent”, “supervisor”) # 6. 编译图得到可执行的应用 app workflow.compile() # 7. 运行多智能体系统 initial_state {“messages”: [{“role”: “user”, “content”: “我的订单号12345到哪里了”}], “next”: “”} final_state app.invoke(initial_state) for msg in final_state[“messages”]: print(f”{msg.type}: {msg.content}”)设计多智能体系统的核心要点状态设计AgentState是所有节点共享的“白板”。Annotated[List[BaseMessage], add_messages]是一个魔法注解它告诉LangGraph自动将每个节点返回的messages列表合并到总状态中无需手动拼接历史。条件路由add_conditional_edges是实现动态工作流的关键。主管节点根据分析结果修改state[“next”]图就会根据这个值决定下一步走向哪个节点。循环与终止在这个例子中专业agent处理完后会回到主管节点形成一个循环等待用户的下一条输入。你也可以设计一个节点在满足某个条件如用户说“谢谢”时将边指向END来结束会话。可视化调试LangGraph一个强大的功能是可视化。使用from langgraph.graph import draw然后draw(app)可以生成一张Mermaid格式的流程图让你对整个工作流一目了然极大方便了调试和沟通。5. 开发避坑指南与性能优化实战5.1 常见问题与排查技巧实录在实际开发中你会遇到各种各样的问题。以下是我总结的一些高频问题及其解决方案希望能帮你节省大量调试时间。问题1智能体不调用工具。症状无论你怎么问AI都只用自己的知识回答从不触发你定义的工具。排查步骤检查工具描述docstring这是最常见的原因。描述必须清晰、具体地说明工具的功能和使用时机。模糊的描述如“一个有用的工具”是无效的。好的描述如“当用户询问特定城市的实时天气时使用此工具。输入参数应为城市名称的字符串。”检查系统提示词system_prompt系统提示词中是否鼓励或授权AI使用工具例如可以加上“你可以使用可用的工具来获取最新信息。”检查模型能力有些轻量级模型如较小的本地模型工具调用能力较弱。尝试换用GPT-4、Claude或Groq上的大模型如Llama 3.3 70B。使用LangSmith追踪打开LangSmith的追踪查看AI在每一步的思考过程。你会发现模型是否生成了工具调用的意图但格式不对或者根本没有考虑工具。问题2对话历史丢失AI没有记忆。症状在多轮对话中AI不记得之前说过的话。解决方案确保传入完整历史每次调用agent.invoke()时messages字段必须包含从对话开始到当前的所有消息而不仅仅是最后一句。使用状态管理对于Web应用强烈建议使用SqliteSaver或RedisSaver。为每个会话分配一个唯一的thread_id每次调用时传入框架会自动加载和保存状态。from langgraph.checkpoint.sqlite import SqliteSaver saver SqliteSaver.from_conn_string(“:memory:”) # 或你的数据库路径 agent create_agent(…, checkpoint_saversaver) # 第一次调用 config {“configurable”: {“thread_id”: “user_123_session_1”}} agent.invoke({“messages”: [msg1]}, configconfig) # 第二次调用自动恢复之前的状态 agent.invoke({“messages”: [msg2]}, configconfig)问题3RAG检索结果不相关。症状AI生成的答案与问题无关或者没有用到检索到的文档。排查与优化检查嵌入模型对于中文文档使用针对中文优化的嵌入模型如BAAI/bge-*zh*系列比通用模型如text-embedding-ada-002效果通常更好。调整分块大小chunk_size是关键参数。太小会失去上下文太大会引入噪声。对于一般文档500-1500是常见范围。需要通过实验确定。增加检索数量尝试增加search_kwargs{“k”: 4}中的k值比如到8或10看看是否有更相关的片段被召回。优化查询可以对用户原始问题进行“查询重写”或“查询扩展”。例如用一个轻量级模型将问题改写成更利于检索的形式或添加同义词。问题4API调用速度慢或成本高。症状应用响应慢或者token消耗大导致费用高。优化策略使用流式输出对于长文本生成使用agent.stream()并将stream_mode设置为“values”或“messages”可以实现逐词输出提升用户体验感知速度。缓存嵌入向量文档的嵌入向量生成是计算密集型操作。对于静态知识库预计算并存储好所有块的向量避免每次启动都重新计算。精简上下文在将检索到的上下文和问题一起发给大模型前可以尝试对多个检索片段进行摘要或去重减少输入的token数量。选择性价比模型对于不需要极强推理的环节如查询重写、意图分类可以使用更小、更快的模型如Groq的mixtral-8x7b只在最终答案生成时使用大模型。5.2 部署与监控最佳实践当你完成开发准备将应用部署到生产环境时以下几点至关重要异步Async支持LangChain完全支持异步。在FastAPI等异步Web框架中务必使用ainvoke,astream,abatch等方法避免阻塞事件循环提升并发能力。from fastapi import FastAPI app FastAPI() app.post(“/chat”) async def chat_endpoint(request: ChatRequest): result await agent.ainvoke({“messages”: request.messages}) return result配置管理不要将API密钥硬编码在代码中。使用.env文件和环境变量。在部署平台如Docker、Kubernetes、云服务器上妥善管理这些机密。全面启用LangSmith在生产环境LangSmith是你的“黑匣子飞行记录仪”。它能记录每一次调用、每一次工具使用、每一次流式输出块。当用户报告问题时你可以通过trace_id快速定位到完整的执行链路查看模型的原始思考过程、工具输入输出这对于排查复杂问题不可或缺。实施速率限制和重试对于外部API调用如模型API、工具API一定要实现速率限制和带有退避策略的重试机制如tenacity库以提高应用的健壮性。编写全面的测试为你的智能体和工具编写单元测试和集成测试。测试应包括正常功能测试、边缘案例测试如空输入、异常工具响应、以及模拟长时间对话的状态一致性测试。学习LangChain和LangGraph是一个螺旋上升的过程。从最初调用一个API到构建一个简单的工具调用智能体再到设计一个由多个智能体组成的复杂工作流每一步都会遇到新的挑战和收获。这个仓库的路径设计正是我走过这条路后总结出的相对平滑的攀登路线。最重要的是动手实践运行每一个示例修改它打破它再修复它。在这个过程中你会逐渐形成自己的理解和最佳实践。

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