作者:Mariya Mansurova
AI代理。LLM不再只是工具。他们成为我们生活中的积极参与者,提高生产力并改变我们的生活和工作方式。
我们以前研究了不同的AI代理框架,例如Langgraph或者CREWAI。在本文中,我想讨论我最近一直在探索的新版本。拥抱面。这是一个有趣的框架,因为它实现了代码代理的概念。
在本文中,我们将探讨几个主题:
让我们从快速刷新开始:AI代理到底是什么?拥抱面提供对代理商的含义清晰明确的定义。
AI代理是LLM输出控制工作流程的程序。
因此,当我们希望系统根据观察结果推理和采取行动时,我们需要一个代理流。实际上,代理不是二进制变量(是或否),而是频谱。
代码代理属于这个更高级的类别。它们是多步代理,以代码的形式执行工具调用,与使用工具名称和参数的JSON格式进行了更传统的方法相反。
最近的几篇论文表明,在代理流中使用代码会带来更好的结果:
当您考虑它时,这是有道理的。几十年来,我们一直在开发编程语言来解决复杂的问题。因此,与简单的JSON配置相比,这些语言更适合LLM的任务。另一个好处是,由于大量可用的培训数据,LLMS已经相当擅长使用通用编程语言编写代码。
这种方法还带来其他一些好处:
这些好处仅仅是理论上的;我们可以在实践中观察它们。在可执行的代码操作引起了更好的LLM代理作者表明,代码代理的表现要优于传统方法,达到更高的成功率并以更少的步骤完成任务,从而降低了成本。”
代码代理看起来很有希望,这激发了我在实践中尝试这种方法。
幸运的是,我们不需要从头开始构建代码代理,因为Huggingface发布了一个方便的库,称为Smolagents这实现了这种方法。
让我们从安装图书馆开始。
PIP安装Smolagents [Litellm]#我已经使用了Litellm,因为我打算将其与OpenAi模型一起使用
接下来,让我们建立一个基本示例。要初始化代理,我们只需要两个参数:模型和工具。一个
我计划将OpenAI用于模型,可以通过Litellm。但是,该框架也支持其他选项。您可以通过霍拉马或者变形金刚模型,或通过推理提供者或选择其他选项(您可以在文档)。一个
我没有指定任何工具,但使用了add_base_tools = true
,所以我的经纪人有一个默认工具集,例如Python的口译员或DuckDuckgo搜索。让我们尝试一个简单的问题。
来自SmolAgents进口,litellmmodelmodel = litellmmodel(model_id =“ openai/gpt-4o-mini”,api_key = config ['Openai_api_key'])agent = codeagent(tools = [],model = model,add_base_tools = true)agent.run(”“”我有5个不同的球,然后随机选择2。我能得到多少球的组合?”“”,)
结果,我们看到了一个格式非常好的执行流。这真是太神奇了,可以让您完美理解该过程。
因此,代理在一个步骤中找到答案,并编写了Python代码来计算组合数。
输出非常有用,但是我们可以更深入地了解与执行相关的完整信息(包括提示),Agent.Memory.Steps。
让我们看一下代理使用的系统提示。
您是一名专家助理,可以使用代码斑点解决任何任务。您将有一项任务尽可能地解决。为此,您已获得访问工具列表的访问:这些工具基本上是Python函数,您可以使用代码调用。要解决任务,您必须计划继续进行一系列步骤,“思想:”,“代码:”,和“观察:”序列。在“思想:”序列中的每个步骤中,您应该首先解释您朝着解决任务和所需工具的推理使用。然后在“代码:”序列中,您应该简单地编写代码Python。代码序列必须以'<end_code>'序列结尾。在每个中间步骤中,您可以使用“ print()”保存您将需要的任何重要信息。然后,这些打印输出将出现在“观察:”字段中,下一步将作为输入可用。最后,您必须使用最终答案Final_answer工具。这里有一些使用名义工具的示例:<...>
很明显,Smolagents实现了反应方法(Yao等人在论文中引入。反应:在语言模型中协同推理和行动)并使用一些弹药提示技术。
Smolagents库处理代理工作流程中涉及的所有幕后工作:将系统提示组装到LLM(即可用工具),解析输出并执行生成的代码的所有必要信息。它还提供了全面的记录和重试机制,以帮助纠正错误。
此外,库提供了内存管理功能。默认情况下,所有执行结果都保存到内存,但是您可以自定义此行为。例如,您可以从内存中删除一些中间结果以减少令牌数量或逐步执行代理。当我们在这里深入了解内存管理时,您可以在中找到方便的代码示例文档。
现在,是时候讨论代码代理方法的缺点了。通过允许执行任意代码来给予LLM更多代理商会引入更高的风险。实际上,LLM可以错误地运行有害代码(因为LLM远非完美),或者是由于迅速注射或妥协模型等有针对性的攻击。
为了减轻这些风险,在Smolagents库中实施的本地Python执行人有大量的安全检查:
附加_authorized_imports
列表 numpy。*
)。之所以这样做,是因为某些软件包可以暴露潜在有害的子模型,即Random._OS
。 让我们测试这些安全措施是否实际工作。
来自smolagents.local_python_executor导入localpythonexecutorcustom_executor = localpythonexecutor([[“ numpy。*”,“ andand”])#功能具有漂亮格式的异常def run_capture_exception(命令:str):尝试:custom_executor(harmful_command)除例外为E:打印(“错误:\ n”,e)#未经授权的导入被阻止harmful_command =“导入OS; exit_code = os.system('<bad_command>')”run_capture_exception(harmful_command)#错误:由于:#InverseTerError:不允许进口OS。授权进口#是:['datetime','itertools','re','数学','statistics','time',queue',#“ numpy。#除非具体说明,否则也会阻止子模块harmful_command =“来自随机导入_OS; exit_code = _OS.System('<bad_command>')”run_capture_exception(harmful_command)#错误:执行代码在line'exit_code = _OS.System('<bad_command>')'#由于:InverteTerror:禁止访问模块:OS#迭代次数的帽子断裂无限循环harmful_command ='''而真:经过'''run_capture_exception(harmful_command)#错误:代码执行在“ true:pass”的行中失败:#InverteTerError:循环中的最大1000000迭代次数#超过#未定义的操作不起作用harmful_command =“!echo <bad_command>”custom_executor(harmful_command)#错误:第1行上的代码解析失败:SyntaxError
看来我们有一些与代码代理的安全网。但是,尽管有这些保障,但在您在本地执行代码时,风险仍然存在。例如,LLM可以在计算机上递归创建线程或创建太多文件,从而导致资源膨胀。一种可能的解决方案是在沙盒环境中执行代码,例如使用Docker或解决方案E2B。我愿意冒险并在本地运行我的代码,但是如果您更喜欢更避免风险的方法,则可以遵循Sandbox设置指导文档。
它声称与传统的基于JSON的方法相比,代码代理的性能更好。让我对此进行测试。
我将使用我上一篇文章中描述的指标变更分析的任务有意义的KPI变化。我们将从一个简单的情况开始:分析一个简单的度量标准(收入)按一个维度(国家)分配。
raw_df = pd.read_csv('absolute_metrics_example.csv',sep ='\ t')df = raw_df.groupby('country')[['revenue_before','revenue_after_scenario_2']]。sum()\。列= {'Revenue_after_scenario_2':'efter',''Revenue_before':'之前'})
Smolagents库支持两个类,我们可以用它们比较两种方法:
我们的代理商将需要一些工具,所以让我们实施它们。有创建工具的多个选项在Smolagents中:我们可以重复使用Langchain工具,从HuggingFace Hub下载它们,也可以简单地创建Python函数。我们将通过编写几个Python功能并用注释来采取最直接的方法@工具
。一个
我将创建两个工具:一种用于估计指标之间的相对差异,而另一个用于计算列表的总和。由于LLM将使用这些工具,因此提供详细的描述至关重要。
@工具def calculate_metric_increase(之前:float,之后:float) - > float:”“”计算之前和之后度量的百分比变化args:在之前:之前的价值之后:值之后”“”返回(之前 - 之后) * 100/之前@工具def calculate_sum(值:列表) - > float:”“”计算列表总和args:值:数字列表”“”返回总和(值)
预告片:稍后,我将意识到我应该为代理商提供更多工具,但我确实忽略了它们。
让我们从一个代码开始。我用我们之前定义的工具初始化了代理商,并授权使用一些可能有帮助的Python软件包。
代理= codeagent(模型=模型,工具= [calculate_metric_increase,calculate_sum],max_steps = 10,附加_authorized_imports = [“ pandas”,“ numpy”,“ matplotlib。*”,“绘制。*”],verbosity_level = 1)任务=“”“”这是一个数据范围,显示逐个细分市场的收入,比较值之前和之后。您能帮我了解变化吗?具体来说:1。估计每个细分市场的总收入和收入无论是绝对的还是一个百分比,都改变了。2。计算每个部分对总数的贡献变化收入。请在输出中围绕所有浮点数到两个小数点。”“”agent.run(任务,附加_args = {“ data”:df},)
总体而言,代码代理仅使用5,451个输入和669个输出令牌完成了任务。结果看起来也很合理。
{'total_before':1731985.21,'total_after':1599065.55,'total_change':-132919.66,'sement_changes':{'absolute_change':{'其他':4233.09,'uk':-4376.25,'france':-132847.57,“德国”:-690.99,'意大利':979.15,'Spain':-217.09},'persationage_change':{'其他':0.67,'uk':-0.91,“法国”:-55.19,'德国':-0.43,'Italy':0.81,'Spain':-0.23},'warmitution_to_change':{'其他':-3.18,'uk':3.29,'法国':99.95,'德国':0.52,'意大利':-0.74,'西班牙':0.16}}}}}
让我们看一下执行流。LLM收到了以下提示。
'''' -``这是一个显示逐段收入的大熊猫数据框架''比较之前和之后的值。您能帮我了解变化吗?特别是:1。估计每种收入的总收入和收入如何无论是绝对的而言,细分市场已经改变百分比。2。计算每个部分对总数的贡献变化收入。 -请将输出中的所有浮点数圆成两个小数点。 -``您得到了这些其他论点,您可以使用钥匙作为python中的变量访问代码:{'df':之后国家其他632767.39 637000.48英国481409.27 477033.02法国240704.63 107857.06德国160469.75 159778.76意大利120352.31 121331.46西班牙96281.86 96064.77}。 -°litellmmodel-openai/gpt-4o-mini –âââââââââââ–
在第一步中,LLM生成了数据框并执行了所有计算。有趣的是,它选择独立编写所有代码,而不是使用提供的工具。
更令人惊讶的是,LLM根据输入数据重新创建了数据框,而不是直接引用它。这种方法不是理想的(尤其是在使用大量数据集时),因为它可能导致错误和更高的标记使用情况。通过使用更明确的系统提示,可以改善此行为。这是代理在第一步中执行的代码。
导入大熊猫作为pd#从提供的数据创建数据框数据= {“之前”:[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86],“之后”:[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}index = ['其他','uk',“法国”,“德国”,“意大利”,“西班牙”]df = pd.dataframe(数据,索引=索引)#在之前和之后计算总收入total_before = df ['之前']。sum()total_after = df ['after']。sum()#计算每个细分市场的绝对和百分比变化df ['absolute_change'] = df ['after'] - df ['之前']df ['persationage_change'] =(df ['absolute_change'] /df ['之前']) * 100#计算总收入变更total_change = total_after -total_before#计算每个细分市场对总更改的贡献df ['runtution_to_change'] =(df ['absolute_change'] /total_change) * 100#圆形结果df = df.Round(2)#打印计算结果打印(“以前的总收入:”,total_before)打印(“以下总收入:”,total_fter)打印(“收入的总变化:”,total_change)打印(DF)
在第二步中,LLM只是指参考上一步上计算的变量(真的很整洁)来构建最终答案。
final_answer({“ total_before”:round(total_before,2),“ total_after”:round(total_after,2),“ total_change”:round(total_change,2),“ segment_changes”:df [['absolute_change','百分比_change','贡献_to_change']]。to_dict()}))
它效果很好。
现在,是时候看看传统的工具呼叫代理如何解决此问题了。我们以类似的方式初始化了它,并执行了任务。
来自SmolAgents Import toolcallingagent传统_agent = toolcallingagent(模型=模型,工具= [calculate_metric_increase,calculate_sum],max_steps = 30,)任务=“”“”这是一个数据范围,显示逐个细分市场的收入,比较值之前和之后。您能帮我了解变化吗?具体来说:1。估计每个细分市场的总收入和收入无论是绝对的还是一个百分比,都改变了。2。计算每个部分对总数的贡献变化收入。请在输出中围绕所有浮点数到两个小数点。”“”传统_agent.run(任务,附加_args = {“ data”:df},)
结果远非理想:只有相对变化是正确的,而其余数字是纯粹的幻觉。我必须承认,核心问题是缺乏适当的工具(特别是计算差异并估算股票的工具)。但是,代理应该标记缺少工具,而不是生成随机数。
总收入变化:-7319.66(-7.67%)。按细分市场变化: - 其他:+232.09(-0.67%) - 英国:-4376.25(0.91%) - 法国:-132847.57(55.19%) - 德国:-690.99(0.43%) - 意大利:+979.15(-0.81%) - 西班牙:-217.09(0.23%)对总变化的贡献: - 其他:0.03% - 英国:-59.88% - 法国:-181.77% - 德国:-9.43% - 意大利: +13.38% - 西班牙:-0.03%
在资源使用方面,工具称呼代理的性能差得多:12个步骤,有29,201个输入和1,695个输出令牌。因此,在代理执行方面,代码代理显然可以节省成本。
让我们更深入地了解代理商实际做的事情。首先,花了四次迭代才能弄清楚如何致电计算_sum
正确并估算之前和之后的总收入。
- â–''''' - - - â–'''呼叫工具:“计算_sum”与参数:{'values':{''':[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86],''':[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}}}}'''''''''与参数的工具“计算_sum”无效呼叫{“ values”:{“ frone”:[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86],“之后”:[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}}:+:'int'和'str'的未支撑操作数类型您应该使用正确的输入参数调用此工具。预期输入:{“ values”:{“ type”:“ object”,“描述”:“值列表”}}}返回输出类型:数字工具说明:“计算列表的总和”[步骤1:持续时间4.06秒|输入令牌:1,190 |输出:250] - - - - â–'''呼叫工具:“计算_sum”与参数:{'values':{''':[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86],''':[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}}}}'''''''''与参数的工具“计算_sum”无效呼叫{“ values”:{“ frone”:[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86],“之后”:[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}}:+:'int'和'str'的未支撑操作数类型您应该使用正确的输入参数调用此工具。预期输入:{“ values”:{“ type”:“ object”,“描述”:“值列表”}}}返回输出类型:数字工具说明:“计算列表的总和”[步骤2:持续时间8.60秒|输入令牌:2,815 |输出:386] - - - - â–'''呼叫工具:“计算_sum”与参数:{'values':[632767.39,481409.27,240704.63,160469.75,120352.31,96281.86]}}'''''''''观察:1731985.2100000002[步骤3:持续时间1.23秒|输入令牌:4,871 |输出:488] - - - - â–'''呼叫工具:“计算_sum”与参数:{'values':[637000.48,477033.02,107857.06,159778.76,121331.46,96064.77]}}'''''''''观察:1599065.55
接下来的七个步骤花了计算_metric_increase
工具。
- - - - â–'''呼叫工具:“计算_metric_increase'参数:{''':1731985.21,'之后':1599065.55}''''ââââââââââââââââââââââââââââââââ¯Observations: 7.674410799385517<-- similar tool calls for all country segments -->
In the end, the agent put together a final call.Â
So, if the LLM had had tools to calculate the absolute difference and the share of the sum, it would have taken an additional 14 iterations and even more tokens.Of course, we can prevent such inefficiencies by carefully designing the tools we provide:
Even though the results werenât ideal due to a poor choice of tools, I still find this example quite insightful.Itâs clear that code agents are more powerful, cost-efficient and flexible as they can invent their own comprehensive tools and perform multiple actions in a single step.
You can find the complete code and execution logs ongithub。
Weâve learned a lot about the code agents.Now, itâs time to wrap things up with a quick summary.
Code agents are LLM agents that âthinkâ and act using Python code.Instead of calling tools via JSON, they generate and execute actual code.It makes them more flexible and cost-efficient as they can invent their own comprehensive tools and perform multiple actions in a single step.Â
HuggingFace has brought this approach to life in their framework, smolagents.Smolagents makes it easy to build quite complex agents without much hassle, while also providing safety measures during the code execution.Â
In this article, weâve explored the basic functionality of the smolagents library.But thereâs a lot more to it.In the next article, we will dive into more advanced features (like multi-agent setup and planning steps) to build the agent that can narrate KPI changes.敬请关注!
Thank you a lot for reading this article.I hope this article was insightful for you.
This article is inspired by the âBuilding Code Agents with Hugging Face smolagentsâ short course by DeepLearning.AI.