smolagents:一个用于构建代理的简单库
HF推出 smolagents
,一个非常简单的库,它能够解锁语言模型的代理功能。以下是它的简要介绍:
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel
agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=HfApiModel())
agent.run("How many seconds would it take for a leopard at full speed to run through Pont des Arts?")
目录
- 🤔 什么是代理?
- ✅ 何时使用代理 / ⛔ 何时避免使用代理
- 代码代理
- 介绍
smolagents
:让代理变得简单 🥳 - 建立代理
- 开放模型对于代理工作流程有多强大?
- 下一步
🤔 什么是代理?
任何使用人工智能的有效系统都需要为 LLM 提供某种形式的现实世界访问权限:例如,调用搜索工具获取外部信息,或执行某些程序以解决任务的可能性。换句话说,LLM 应该具有代理权。代理程序是 LLM 通往外部世界的门户。
AI 代理是 LLM 输出控制工作流程的程序。
任何利用 LLM 的系统都会将 LLM 输出集成到代码中。LLM 的输入对代码工作流程的影响是系统中 LLM 的代理级别。
请注意,根据此定义,“代理”不是一个离散的、0 或 1 的定义:相反,“代理”会在连续的范围内发展,因为您在工作流程中为 LLM 赋予或多或少的权力。
下表说明了代理在不同系统之间的差异:
机构级别 | 描述 | 怎么称呼 | 示例模式 |
---|---|---|---|
☆☆☆ | LLM 输出对程序流程没有影响 | 简单处理器 | process_llm_output(llm_response) |
★☆☆ | LLM 输出决定基本控制流 | 路由器 | if llm_decision(): path_a() else: path_b() |
★★☆ | LLM 输出决定函数执行 | 工具调用 | run_function(llm_chosen_tool, llm_chosen_args) |
★★★ | LLM 输出控制迭代和程序延续 | 多步代理 | while llm_should_continue(): execute_next_step() |
★★★ | 一个代理工作流可以启动另一个代理工作流 | 多代理 | if llm_trigger(): execute_agent() |
多步骤代理具有以下代码结构:
memory = [user_defined_task]
while llm_should_continue(memory): # this loop is the multi-step part
action = llm_get_next_action(memory) # this is the tool-calling part
observations = execute_action(action)
memory += [action, observations]
因此,该系统循环运行,在每个步骤执行新操作(该操作可能涉及调用一些预先确定的工具,这些工具只是函数),直到其观察结果表明已达到令人满意的状态以解决给定的任务。
✅ 何时使用代理 / ⛔ 何时避免使用代理
当你需要 LLM 来确定应用程序的工作流程时,代理很有用。但它们往往是多余的。问题是:我真的需要工作流程中的灵活性来有效地解决手头的任务吗?如果预先确定的工作流程经常失败,这意味着你需要更多的灵活性。
例如,假设你正在制作一个处理冲浪旅行网站上客户请求的应用程序。你可以提前知道请求将属于两个存储桶中的任一个(基于用户选择),并且你为这两个情况中的每一个都有一个预定义的工作流程。
- 想要了解一些旅行知识?⇒ 让他们访问搜索栏来搜索你的知识库
- 想与销售人员谈谈?⇒ 让他们输入联系表格。
如果确定性工作流程适合所有查询,那么就一定要编写所有内容!这将为您提供一个 100% 可靠的系统,并且不会因让不可预测的 LLM 干扰您的工作流程而引入错误的风险。为了简单和稳健,建议规范化为不使用任何代理行为。
但如果无法提前确定工作流程该怎么办?
例如,用户想要问:“I can come on Monday, but I forgot my passport so risk being delayed to Wednesday, is it possible to take me and my stuff to surf on Tuesday morning, with a cancellation insurance?” 这个问题取决于许多因素,并且上述预定的标准可能都不能满足这个请求。
如果预先确定的工作流程经常出现不足,则意味着您需要更大的灵活性。这正是代理设置能提供帮助的地方。
在上面的例子中,您可以创建一个多步骤代理,该代理可以访问天气 API 来获取天气预报、Google Maps API 来计算旅行距离、员工可用性仪表板以及知识库中的 RAG 系统。
直到最近,计算机程序还局限于预先确定的工作流程,试图通过堆积 if/else 开关来处理复杂性。它们专注于极其狭窄的任务,例如“计算这些数字的总和”或“在此图中查找最短路径”。但实际上,大多数现实生活中的任务,比如我们上面的旅行示例,并不适合预先确定的工作流程。代理系统为程序打开了广阔的现实世界任务世界!
代码代理
在多步骤代理中,LLM 可以在每一步中以调用外部工具的形式编写操作。编写这些操作的常见格式(由 Anthropic、OpenAI 和许多其他公司使用)通常是“将操作编写为包含工具名称和要使用的参数的 JSON,然后对其进行解析以了解要执行哪个工具以及使用哪些参数”的不同版本。
多篇研究论文表明,使用代码调用 LLM 的工具效果要好得多。
原因很简单,我们精心设计了代码语言,以便以最佳方式表达计算机执行的操作。如果 JSON 代码片段是一种更好的表达方式,那么 JSON 将成为顶级编程语言,而编程将成为人间地狱。
下图取自《可执行代码操作引出更好的 LLM 代理》,说明了用代码编写操作的一些优点:
用代码而不是类似 JSON 的代码片段来编写操作可以提供更好的效果:
- 可组合性:您是否可以将 JSON 操作嵌套在一起,或者定义一组 JSON 操作以供以后重复使用,就像定义一个 Python 函数一样?
- 对象管理:如何
generate_image
以 JSON 格式存储操作的输出? - 通用性:代码是为了简单表达计算机可以做的任何事情而构建的。
- LLM 训练数据中的表示:LLM 的训练数据中已经包含大量高质量的代码操作,这意味着它们已经接受过这方面的训练!
介绍 smolagents
:让代理变得简单 🥳
我们的建设 smolagents
目标是:
- ✨简单:代理逻辑只需几千行代码(参见此文件)。我们将抽象保持在原始代码之上的最小形状!
- 🧑💻一流支持代码代理,即以代码编写其操作的代理(而不是“用于编写代码的代理”)。为了确保安全,我们支持通过 E2B 在沙盒环境中执行。
- 🤗 Hub 集成:您可以与 Hub 共享工具并加载工具,未来还将有更多功能!
- 🌐支持任何 LLM:它支持在其版本中或通过我们的推理 API 加载的 Hub 上托管的模型
transformers
,但也通过我们的LiteLLM
集成支持来自 OpenAI、Anthropic 和许多其他的模型。
smolagents
是 transformers.agents
的后继者,并将在 transformers.agents
将来被弃用时替代它。
建立代理
要构建代理,至少需要两个元素:
- tools:代理有权访问的列表
- model:LLM 将成为您的代理人的引擎。
对于 model
,您可以使用任何 LLM,要么使用 HfApiModel
上面豹子示例中显示的类打开模型,利用 Hugging Face 的免费推理 API,要么利用 LiteLLMModel
litellm
从 100 多个不同的 LLM 列表中进行选择。
对于该工具,您可以创建一个函数,在输入和输出上使用类型提示,并使用文档字符串为输入提供描述,然后使用 @tool
装饰器使其成为一个工具。
下面介绍了如何制作一个自定义工具来获取 Google 地图的旅行时间,并将其用于旅行计划代理:
from typing import Optional
from smolagents import CodeAgent, HfApiModel, tool
@tool
def get_travel_duration(start_location: str, destination_location: str, departure_time: Optional[int] = None) -> str:
"""Gets the travel time in car between two places.
Args:
start_location: the place from which you start your ride
destination_location: the place of arrival
departure_time: the departure time, provide only a `datetime.datetime` if you want to specify this
"""
import googlemaps # All imports are placed within the function, to allow for sharing to Hub.
import os
gmaps = googlemaps.Client(os.getenv("GMAPS_API_KEY"))
if departure_time is None:
from datetime import datetime
monday = datetime(2025, 1, 6, 11, 0)
directions_result = gmaps.directions(
start_location,
destination_location,
mode="transit",
departure_time=departure_time
)
return directions_result[0]["legs"][0]["duration"]["text"]
agent = CodeAgent(tools=[get_travel_duration], model=HfApiModel(), additional_authorized_imports=["datetime"])
agent.run("Can you give me a nice one-day trip around Paris with a few locations and the times? Could be in the city or outside, but should fit in one day. I'm travelling only via public transportation.")
经过收集旅行时间和运行计算的几个步骤后,代理返回了最终建议:
Out - Final answer: Here's a suggested one-day itinerary for Paris:
Visit Eiffel Tower at 9:00 AM - 10:30 AM
Visit Louvre Museum at 11:00 AM - 12:30 PM
Visit Notre-Dame Cathedral at 1:00 PM - 2:30 PM
Visit Palace of Versailles at 3:30 PM - 5:00 PM
Note: The travel time to the Palace of Versailles is approximately 59
minutes from Notre-Dame Cathedral, so be sure to plan your day accordingly.
构建工具后,将其分享到 Hub 非常简单:
get_travel_duration.push_to_hub("{your_username}/get-travel-duration-tool")
您可以在此空间下看到结果。您可以在空间中的文件 tool.py
下检查该工具的逻辑。如您所见,该工具实际上被导出到从 class 继承的类 Tool
,这是我们所有工具的底层结构。
开放模型对于代理工作流程有多强大?
我们 CodeAgent
用一些领先的模型创建了实例,并在这个基准上对它们进行了比较,该基准收集了来自几个不同基准的问题,以提出各种各样的挑战。
在此处找到基准,了解所使用的代理设置的更多详细信息,并查看代码代理与工具调用代理的比较(剧透:代码效果更好)。
通过这一比较可以看出,开源模型现在可以与最好的封闭模型相媲美了!
下一步
- 从导游开始,熟悉图书馆。
- 学习更深入的教程以了解更多有关工具或一般最佳实践的知识。
- 深入研究示例来设置特定系统:文本到 SQL、代理 RAG 或多代理编排。
- 了解有关代理的更多信息:
- Anthropic 的这篇精彩博客文章提供了扎实的常识。
- 本合集汇集了有关代理商的最具影响力的研究论文。
# 参考资料
- https://huggingface.co/blog/smolagents