Agent 智能体开发框架选型指南
编者按: 本文通过作者的实践对比发现,框架的选择应基于项目具体需求和团队特点,而不是简单追求某个特定框架。不同框架各有优势:
- 无框架方案实施最为简单直接,代码结构清晰,适合理解智能体原理,但随着项目复杂度增加可能变得难以维护。
- LangGraph提供完整的智能体结构规范,特别适合团队协作和智能体结构新手,但框架限制较多,如不认同其理念可能面临较大调试挑战。
- LlamaIndex Workflows采用事件驱动架构,在框架约束和开发自由度之间取得平衡,对框架依赖较少,但其固有的异步特性可能增加某些场景的复杂度。
框架选择需要考虑三个关键因素:项目是否已深度集成了特定框架、团队对智能体架构的熟悉程度、是否有可供参考的相似项目案例。
作者 | Aparna Dhinakaran
编译 | 岳扬
Image by author
智能体(Agents)正迎来辉煌时刻。伴随着众多新框架的涌现和对该领域的持续投资[1],现代 AI 智能体正在跨越起初的不稳定阶段[2],迅速取代 RAG 成为开发首选。那么,2024 年是否会成为 autonomous AI 系统全面接管撰写邮件、预订航班、数据分析等任务的一年呢?
也许吧,但要实现这一点还有很多工作要做。开发人员在构建智能体时,不仅要决定使用何种模型、应用场景和技术架构,还要挑选合适的开发框架。是坚持较为早期的 LangGraph,还是转向新兴的 LlamaIndex Workflows?或者走传统路线,自己编写全部代码呢?
这篇文章的目的就是让您更轻松地做出选择。在过去几周里,我使用多个主流框架构建了相同的智能体,并从技术角度分析了它们各自的优缺点。每个智能体的所有代码都可以在此代码仓库[3]中找到。
本文测试用智能体的基本概述
本次测试所采用的智能体整合了多项功能,包括执行函数调用(function calling)、使用多种工具或技能、与外部资源建立连接,以及实现状态或记忆的共享。
该智能体具备以下几项核心能力:
- 基于知识库进行问题解答
- 数据交互:针对 LLM 应用程序的数据进行问题解答
- 数据洞察:对获取的数据进行更高层次的趋势和模式分析
为了达成上述目标,智能体需要掌握三项基本技能:结合产品文档的 RAG、在相关数据库上生成 SQL 语句的能力,以及数据分析技巧。智能体的用户界面使用 gradio 搭建,而智能体本身则以聊天机器人(chatbot)的形式构建。
01 Code-Based Agent(不使用智能体框架)
在着手开发智能体时,您可以选择不依赖任何框架,而是完全自主构建。在启动这个项目之初,我首先采用了这种方法。
Image by author
1.1 纯代码架构
下面是基于纯代码构建的智能体,其核心是一个由 OpenAI 提供支持的技能路由器,它通过函数调用来确定使用哪项技能。技能执行完毕后,控制权将返回给技能路由器,以便调用其他技能或直接向用户作出回应。
智能体会持续记录用户消息和智能体响应,并在每次调用时将这一完整列表传递给技能路由器,确保在整个交互过程中保留上下文。
各项技能均在独立的类中进行定义(例如“GenerateSQLQuery”类),这些类都保存在 SkillMap 中。技能路由器仅与 SkillMap 进行交互,通过它来加载技能的名称、描述以及可调用的函数。这种设计理念使得向智能体中添加新技能变得非常简单:只需将该技能编写为一个独立的类,并将其加入到 SkillMap 的技能列表即可。这样做的目的是为了在不影响技能路由器代码的前提下,轻松实现新技能的添加。
总的来说,这种实现方式虽然简单易行,但仍然存在一些需要克服的难题。
1.2 使用纯代码智能体面临的挑战
第一个困难在于如何设计技能路由器的系统提示词(system prompt)。 在上面的例子中,技能路由器往往倾向于自行生成 SQL 语句,而不是交给相应的技能模块去处理。如果你有过试图让大语言模型停止执行某项任务的经历,那你可能深知这其中的挫败感;为了找到合适的提示词,我不得不进行了多次调试。此外,处理每个步骤产生的不同输出格式也是一项复杂的工作。 由于我选择不使用结构化输出,因此必须为技能路由器和各项技能中大语言模型的调用准备多种格式的应对策略。
1.3 纯代码智能体的优点
基于代码的方法提供了一个扎实的基础和出发点,是一种绝佳的学习途径,让我们可以在不依赖现成框架提供的智能体教程的情况下,了解智能体的运作原理。虽然引导大语言模型按既定行为模式运作确实存在难度,但代码结构本身简洁明了,易于操作,对于某些使用场景而言,这种做法是完全合理的(具体分析将在下文展开)。
02 LangGraph
LangGraph 是众多智能体框架中历史最为悠久的之一,它于 2024 年 1 月首次发布。该框架的设计初衷是为了解决现有流程和链条的非循环性问题,它通过采用 Pregel 图结构来解决这一问题。 LangGraph 通过引入节点(nodes)、边(edges)以及条件边(conditional edges)的概念,简化了在智能体中创建循环流程的过程,使得图的遍历变得更加直观。LangGraph 是基于 LangChain 构建的,它继承了后者的对象(objects)和类型(types)。
Image by author
2.1 LangGraph 架构
从表面上看,LangGraph 智能体与基于代码的智能体有相似之处,但它们的底层代码却有大不相同。虽然 LangGraph 在技术上也使用了“路由器(router)”这一概念,即通过代码函数调用 OpenAI 并利用其响应来推进到下一个步骤,但程序在不同技能之间的切换控制机制却完全不同。
在此定义的图(graph)中,包含了一个用于初始化 OpenAI 调用的节点,即上文中提到的“agent”,以及一个用于工具处理步骤节点,即“tools”。LangGraph 内置了一个名为 ToolNode 的对象,它能够接收一系列可调用的工具,并根据 ChatMessage 的响应来触发这些工具,完成操作后再次回到“agent”节点。
每当“agent”节点(也可以理解为基于代码的智能体中的技能路由器(router))被调用之后,should_continue 这条边将判断是将响应直接返回给用户,还是转给 ToolNode 来处理工具调用。
在每个节点中,“state” 负责保存与 OpenAI 的交互消息和响应列表,这一点与基于代码的智能体保持上下文的方式相似。
2.2 使用 LangGraph 面临的挑战
在处理 LangGraph 构建的智能体示例时,遇到的主要难题在于必须借助 Langchain 对象才能确保流程的顺畅。
挑战 1:函数调用的 validation 错误
为了能够使用 ToolNode 对象,我不得不对 Skill 代码进行大规模的重构。ToolNode 需要一组可调用的函数列表,我本以为可以直接使用现成的函数,但是函数参数配置出了问题,导致流程受阻。
这些技能(skills)是以类形式定义的,每个类都有一个可调用的成员函数,其中“self”是首个参数。GPT-4o 足够智能,能够在生成函数调用(function call)时自动排除“self”参数,但 LangGraph 却因此认为缺少了必要参数,从而抛出了 validation 错误。
这个问题让我摸索了好几小时才搞清楚,因为错误信息把函数里的第三个参数(数据分析技能中的“args”)错误地标记为缺失参数(missing parameter):
需要指出的是,这个误导性的错误信息其实来自 Pydantic,而非 LangGraph。
最后,我下定决心,改用 Langchain 的 @tool 装饰器将我的技能(skills)重新编写为基本方法,这样程序就能正常运行了。
挑战 2:Debugging
正如前文所述,在框架中调试非常困难。主要是因为错误信息混乱不清,以及框架中的抽象概念,它们使得追踪和查看变量变得非常复杂。
抽象概念主要体现在尝试跟踪智能体间传递的消息时。LangGraph 会将消息保存在 state[“messages”] 里。Graph 中的一些节点会自动从这些消息(messages)中提取信息,这样的自动化过程可能会让节点在访问消息(messages)时,我们难以把握消息(messages)的具体内容。
智能体行动的顺序视图(图片由作者提供)
2.3 LangGraph 的优点
LangGraph 的最大优势在于其易用性。它的图结构代码简洁且易于理解。对于那些拥有复杂节点逻辑的场景,LangGraph 能够提供一个清晰的图视图,让我们更轻松地把握智能体的连接方式。此外,LangGraph 还可以直接转换以 LangChain 构建的现有应用程序。
2.4 经验之谈
当我们只使用 LangGraph 框架的相关功能时,一切都会运行得非常流畅;但一旦我们尝试跳出框架,就要准备好进行一些令人头疼的调试了。
03 LlamaIndex Workflows
Workflows 是智能体框架领域的新晋成员,它于今年夏初首次亮相。与 LangGraph 类似,它的设计宗旨是简化可循环智能体的构建过程。此外,Workflows 特别强调其异步执行的能力。
在 Workflows 中,某些设计元素似乎是为了直接对标 LangGraph,尤其是它采用事件(events)而非边(edges)或条件边(conditional edges)作为连接逻辑的方式。在 Workflows 中,智能体逻辑被封装在“步骤(steps)”中(与 LangGraph 中的“节点(nodes)”相对应),而事件(events)的发出和接收则负责在不同的步骤(steps)间传递信息。
Image by author
上述框架与 LangGraph 的结构颇为相似,但有一点不同:我给 Workflow 增加了一个初始化步骤,用于准备智能体的环境上下文,稍后我会详细介绍这一点。尽管两者的结构相似,但它们所依赖的代码实现却截然不同。
3.1 Workflows 架构
以下代码段描绘了 Workflow 的架构。与 LangGraph 相仿,在这一部分,我配置了状态信息(state),并将各项技能(skills)绑定到了 LLM 对象上。
在这里,我还定义了一个额外的步骤——“prepare_agent”。该步骤负责将用户输入转换成 ChatMessage,并将其存储到工作流的记忆存储中。将这一过程作为一个独立的步骤分离出来,意味着智能体在遍历工作步骤(steps)时可以重复回到这一步,从而避免反复将用户信息加入到记忆存储中。
在 LangGraph 的实现案例中,我通过一个位于图(graph)之外的 run_agent 方法实现了相同的功能。这一改变主要是出于风格上的考虑,但我认为,将这一逻辑整合到 Workflow 和图(graph)中,会更加整洁和高效。
在 Workflow 配置完成后,我继续编写了路由代码:
以及工具调用处理代码:
它们的实现方式似乎更接近于纯代码的智能体,而非 LangGraph 智能体。这主要是因为 Workflows 选择在各步骤(steps)中维护条件路由(conditional routing)逻辑,而不是像 LangGraph 那样使用条件边(conditional edge)(第 18-24 行在 LangGraph 中是条件边,而现在它们只是路由步骤的一部分)。另外,LangGraph 中的 ToolNode 对象能够在 tool_call_handler 方法中自动处理大部分任务。
在路由步骤之后,我们能够将 SkillMap 以及基于纯代码的智能体中已有的技能(skills)直接应用于 Workflows。这些技能(skills)无需任何修改即可与 Workflows 配合使用,这大大简化了我的工作。
3.2 使用 Workflows 面临的挑战
挑战 1:Sync vs Async
尽管对于在线运行的智能体来说,异步执行是更优的选择,但调试同步执行的智能体通常更为简便。Workflows 本身是为了异步操作而设计的,因此尝试将其改为同步执行非常困难。
起初,我以为只需去掉“async”方法标识,并将函数名“achat_with_tools”改为“chat_with_tools”即可。但是,由于 Workflow 类内部的方法同样采用了异步标记,为了实现同步运行,我不得不重新定义这些方法。尽管如此,我最终还是选择了异步处理方式,幸运的是,这并没有增加调试的难度。
智能体行动的顺序视图(图片由作者提供)
挑战 2:Pydantic Validation Errors
与 LangGraph 的问题类似,在智能体的技能(skills)处也出现了令人困惑的 Pydantic Validation Errors。幸运的是,由于 Workflows 能够很好地处理成员函数,这些问题这次比较容易解决。最终,我不得不更加规范地为智能体技能(skills)创建 LlamaIndex FunctionTool 对象:
从构建 FunctionTools 的 AgentFlow.init 文件中摘录
3.3 Workflows 的优点
与 LangGraph 相比,我在使用 Workflows 构建智能体时要轻松得多,主要原因是 Workflows 并未提供内置功能,而是需要我自己编写路由逻辑和工具操作代码。 这也使得我的 Workflow 智能体与基于纯代码的智能体看起来极为相似。
最大的区别在于事件(events)的使用上。我使用两个自定义事件在智能体中的各个步骤之间移动:
这种基于事件的发射器-接收器架构(emitter-receiver),取代了直接调用智能体中某些方法的做法,例如工具调用处理(tool call handler)。
对于那些步骤(steps)更为复杂、异步触发且可能产生多个事件(events)的系统来说,这种架构就非常有助于干净利落地管理这些步骤。
Workflows 的其他优点还包括其轻量级特性,不会施加过多的结构限制(除了必须使用特定的 LlamaIndex 对象外),并且其基于事件(event-based)的架构为直接函数调用提供了一种有效的替代方案,这对于处理复杂、异步的应用场景尤为有益。
04 对这些方法进行比较
对比这三种方法,各有其独到之处。
无框架方法实施起来最简单。由于所有抽象层都是由开发者自行定义(如前例中的 SkillMap 对象),因此管理不同类型(types)和对象(objects)相对简单。但是,代码的可读性和易用性完全取决于开发者个人,可以预见,如果没有一定的智能体结构约束,智能体的复杂性增加后可能会变得难以驾驭。
LangGraph 提供了丰富的智能体结构支持,使得智能体的定义非常清晰。对于多人协作开发的智能体来说,这种智能体结构设定有助于统一架构规范。LangGraph 也为那些对智能体结构不太熟悉的开发者提供了帮助。不过,这样做也有代价 —— 由于 LangGraph 为你做了许多工作,如果你不完全认同这个框架,它可能会让你头疼不已;代码可能会非常简洁,但你可能要为此进行更多的调试工作。
Workflows 则处于两者之间。基于事件(event-based)的架构在某些项目中可能极具价值,而且因为它对 LlamaIndex 类型的使用要求不高,对于那些没有在应用程序中完全使用该框架的开发者来说,提供了更大的自由度。
Image created by author
归根结底,关键问题可能在于“你是否已经在使用 LlamaIndex 或 LangChain 来组织应用程序?” LangGraph 和 Workflows 都与它们所依赖的框架紧密集成,因此每个特定智能体框架的额外优势可能不足以成为转换使用的理由。
纯代码方法可能永远是一个有吸引力的选择。如果你能够严格地记录并执行所创建的任何抽象概念,那么确保外部框架不会成为你的阻碍就很容易了。
05 在选择智能体框架时需要考虑的关键问题
当然,单纯一句“具体情况具体分析”这样的回答总是让人不太满意。以下三个问题或许能帮你选择下一个智能体项目应该采用哪个框架。
你的项目是否已经深度集成了 LlamaIndex 或 LangChain?
如果是的话,不妨优先考虑这两个选项。
你对智能体的常见架构是否熟悉,还是更希望有人告诉你应该如何构建智能体结构?
如果你倾向于后者,那么 Workflows 可能是个不错的选择。如果你非常倾向于后者,那么 LangGraph 或许更适合你。
你要构建的智能体是否有参考样例?
框架的一个优势在于,每个框架都有大量的教程和实例供你参考。而纯代码构建智能体的参考实例相对较少。
Image created by author
06 Conclusion
选择一个智能体框架只是影响生成式人工智能系统在生产环境中表现众多决策中的一项,建立强大的安全保障和对大语言模型(LLM)的监控[4]是必要的 —— 同时,面对新智能体框架、研究成果和模型对传统技术的颠覆,我们还需保持灵活应对的态度。
Thanks for reading!
Hope you have enjoyed and learned new things from this blog!
About the authors
Aparna Dhinakaran
Co-Founder and CPO of Arize AI. Formerly Computer Vision PhD at Cornell, Uber Machine Learning, UC Berkeley AI Research.
END
本期互动内容 🍻
❓请分享一下你最常使用的智能体开发方式?为什么?
🔗文中链接🔗
[1]https://foundationcapital.com/goodbye-aiops-welcome-agentsres-the-next-100b-opportunity/
[2]https://arxiv.org/html/2405.13966v1
[3]https://github.com/Arize-ai/phoenix/tree/main/examples/agent_framework_comparison
[4]https://docs.arize.com/phoenix/tracing/llm-traces
原文链接:
https://towardsdatascience.com/choosing-between-llm-agent-frameworks-69019493b259
相关文章:

Agent 智能体开发框架选型指南
编者按: 本文通过作者的实践对比发现,框架的选择应基于项目具体需求和团队特点,而不是简单追求某个特定框架。不同框架各有优势: 无框架方案实施最为简单直接,代码结构清晰,适合理解智能体原理,…...

基于Zynq FPGA对雷龙SD NAND的测试
一、SD NAND 特征 1.1 SD 卡简介 雷龙的 SD NAND 有很多型号,在测试中使用的是 CSNP4GCR01-AMW 与 CSNP32GCR01-AOW。芯片是基于 NAND FLASH 和 SD 控制器实现的 SD 卡。具有强大的坏块管理和纠错功能,并且在意外掉电的情况下同样能保证数据的安全。 …...

AOSP沙盒android 11
这里介绍一下aosp装系统 什么是aosp AOSP(Android Open Source Project)是Android操作系统的开源版本。 它由Google主导,提供了Android的源代码和相关工具,供开发者使用和修改。 AOSP包含了Android的核心组件和API,使…...

【JWT】Asp.Net Core中JWT刷新Token解决方案
Asp.Net Core中JWT刷新Token解决方案 前言方案一:当我们操作某个需要token作为请求头的接口时,返回的数据错误error.response.status === 401,说明我们的token已经过期了。方案二:实现用户无感知的刷新token值,我们希望当响应返回的数据是401身份过期时,响应阻拦器自动帮我…...

AJ-Report:一款开源且非常强大的数据可视化大屏和报表工具
嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和工作学习方法 AJ-Report是一个基于Java的开源报表工具,它集成了ECharts、Ant Design Vue等前端技术,致力于为企业提供一站式的数据可视化解决方案…...

stm32不小心把SWD和JTAG都给关了,程序下载不进去,怎么办?
因为想用STM32F103的PA15引脚,调试程序的时候不小心把SWD和JTAD接口都给关了,先看下罪魁祸首 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关掉JTAG,不关SWGPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//关掉SW&am…...

【UE5】在材质中实现球形法线技术,常用于改善植物等表面的渲染效果
在材质中实现球形法线,这种技术常用于植被渲染等场景。通过应用球形法线可以显著提升植物再低几何体情况下的光照效果。 三二一上截图! 当然也可以用于任何你希望模型圆润的地方,下图中做了一个Cube倒角...

【MATLAB源码-第210期】基于matlab的OFDM电力线系统仿真,不同梳状导频间隔对比。三种信道估计,三种插值误码率对比
操作环境: MATLAB 2022a 1、算法描述 OFDM电力线通信系统(PLC)是一种通过电力线传输数据的通信技术,利用了OFDM(Orthogonal Frequency Division Multiplexing,正交频分复用)技术的优势来提高…...

基于SpringBoot的城镇保障性住房管理策略
3系统分析 3.1可行性分析 通过对本城镇保障性住房管理系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本城镇保障性住房管理系统采用SSM框架,JA…...

支持高性能结构化数据提取的 Embedding 模型——NuExtract-v1.5
NuExtract 是一个用户友好型模型,设计用于从长文档中提取信息。它可以处理长达 20,000 个标记的输入,是合同、报告和其他商业通信的理想选择。NuExtract 的与众不同之处在于它能够处理和理解文档的整个上下文。这意味着它可以捕捉到可能分散在长文本不同…...

【C#】设计一个选购计算机配置的应用程序
文章目录 1. 创建新的 Windows Forms 应用程序项目2. 设计界面2.1 添加控件和设置属性 3. 编写事件处理代码4. 运行和测试应用程序 1. 创建新的 Windows Forms 应用程序项目 打开 Visual Studio。选择“创建新项目”。在项目类型中选择“Windows Forms 应用程序”(…...

solo博客源码使用idea编译运行
solo博客源码使用idea编译运行 solo博客开源地址本地运行IDEA 编译执行默认直接编译jar 包编译 solo博客开源地址 项目地址:GitHub - 88250/solo: 🎸 B3log 分布式社区的 Java 博客端节点系统,欢迎加入下一代社区网络。B3log distributed co…...

VBA07-方法
一、方法的定义 方法指对象所能执行的动作,它是一个动词。 二、方法的表达方式 三、关于工作簿的方法操作 3-1、新增一个工作簿 示例1: 此时,新增的工作簿的名字是系统默认的。 示例2: 【注意】: 当你尝试将工作簿…...
spring boot 统一异常处理
在 Spring Boot 应用中实现统一异常处理是非常重要的,它可以帮助我们更好地管理和响应应用程序中的错误。通过使用 ControllerAdvice 和 ExceptionHandler 注解,我们可以创建一个全局的异常处理器来捕获并处理不同类型的异常。 步骤 1: 创建一个异常处理…...
跟着小土堆学习pytorch(六)——神经网络的基本骨架(nn.model)
文章目录 一、model介绍二、Module三、张量3.1 定义3.2 用法 一、model介绍 容器 Containers 卷积层 Convolution Layers 池化层 Pooling layers 填…...
数字化落地过程中的研发效能治理如何开展?
数字化落地过程中,针对数字化识别到的问题和短板进行专项治理,是通过数字化手段持续提升研发效能非常重要的一环。组织级的数字化专项治理需要组织级团队和技术团队共同配合协同来完成。其中组织级团队负责制定整体的治理目标、流程和策略,根…...

Windows安装配置node.js
下载安装 下载 访问下载 | Node.js 中文网,下载 推荐使用长期支持版本,但是此次是学习用的,使用最新版本试一下 安装 其实一路next基本就可以了,注意调整下安装目录 查看版本 C:\Users\PC>node -v v22.11.0 C:\Users\PC>…...

Javaweb梳理9——JDBC
Javaweb梳理9——JDBC 1.JDBC概述1.1 JDBC概念1.2 JDBC本质1.3 JDBC好处 2.JDBC快速入门2.1 编写代码步骤2.2 具体操作 3 JDBC API详解3.1 DriverManager3.2 Connection3.2.1 获取执行对象3.2.2 事务管理 3.3 Statement3.3.1 概述3.3.2 代码实现 3.4 ResultSet3.4.1 概述3.4.2 …...

逆向CTF入门(如何找main)
Hello, world of reverse! start函数它在执行一些初始化操作,如获取命令行参数、获取环境变量值、初始化全局变量等,一切准备工作完成之后,再调用main函数 快速定位关键函数: 长驱直入法:当程序功能非常明确时,从程序…...

c语言归并排序
归并排序思想: 归并排序可以解释为是将放在数组里的一串数字进行拆分,拆分之后再判断大小合并的过程,每次都是从中间位置拆分,例如有七个数,第一次拆分就将它们分成前三个数为一个数组,后四个数为一个数组&…...

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

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...