本文同时提供 简体中文 版本。
TL;DR
经过一系列实验,我们对 Transformers Agents 构建代理系统的性能印象深刻,于是决定测试其实际表现!我们使用基于该库构建的 Code Agent 对 GAIA 基准进行了测试——GAIA 被公认为最具挑战性和全面性的代理基准……最终我们登顶了!
本博客中使用的
transformers.agents框架现已升级为独立库 smolagents!两个库的 API 高度相似,迁移非常简单。 请查看smolagents介绍博客 此处。
GAIA:代理的严苛基准
什么是代理?
简而言之:代理是基于 LLM 的系统,可根据当前用例需求决定是否调用外部工具,并根据 LLM 输出迭代后续步骤。工具可包括 Web 搜索 API、Python 解释器等。
可视化类比:所有程序都可视为图结构。先执行 A,再执行 B。if/else 分支是图的岔路,但不会改变其结构。我们将代理定义为 LLM 输出会改变图结构的系统。代理决定调用工具 A、工具 B 还是不调用,决定是否再运行一步:这些操作会改变图的结构。你可以将 LLM 集成到固定工作流(如 LLM judge)中,但这不构成代理系统,因为 LLM 输出不会改变图的结构。
以下是两种执行 检索增强生成 的系统示例:一种是经典 RAG,其图结构固定;另一种是代理式 RAG,图中的循环可按需重复。
代理系统赋予 LLM 超能力。更多细节请阅读我们之前关于 Transformers Agents 2.0 发布的博客。
GAIA 是最全面的代理基准。GAIA 中的问题极具难度,突显了基于 LLM 系统的诸多难点。
以下是一个棘手问题的示例:
2008 年画作《乌兹别克斯坦刺绣》中展示的水果,哪些被用作 1949 年 10 月远洋客轮的早餐菜单的一部分?该客轮后来被用作电影《最后航程》的漂浮道具。请以逗号分隔列表形式给出答案,按照画作中从 12 点钟位置开始的顺时针顺序排列,并使用每种水果的复数形式。
该问题涉及多项难点:
- 以受限格式作答。
- 从图像中识别水果的多模态能力
- 需收集多条信息,且部分信息相互依赖:
- 画作中的水果
- 用作《最后航程》漂浮道具的远洋客轮身份
- 上述客轮 1949 年 10 月的早餐菜单
- 上述要求迫使正确解决轨迹需采用多个串联步骤。
解决此问题需要高层次规划能力和严谨执行,这正是 LLM 擅长的两个薄弱环节。
因此,它是测试代理系统的绝佳数据集!
在 GAIA 的公开排行榜上,GPT-4-Turbo 平均得分未达 7%。目前(曾)排名第一的是基于 Autogen 的复杂多代理系统,利用 OpenAI 的工具调用功能,得分达 40%。
让我们来挑战他们。🥊
构建合适的工具 🛠️
我们使用了三个主要工具来解决 GAIA 问题:
a. Web 浏览器
对于网页浏览,我们主要复用了 Autogen 团队提交 中的 Markdown Web 浏览器。它包含一个存储当前浏览器状态的 Browser 类,以及多个用于网页导航的工具,如 visit_page、page_down 或 find_in_page。该工具返回当前视口的 Markdown 表示。使用 Markdown 可大幅压缩网页信息,但与截图并使用视觉模型等方案相比,可能导致部分信息遗漏。不过,我们发现该工具整体表现良好,且使用和修改复杂度适中。
注:我们认为未来改进此工具的一个好方法是使用 selenium 包而非 requests 加载页面。这将允许我们加载 JavaScript(许多页面需依赖 JavaScript 才能正常加载)并接受 Cookie 以访问部分页面。
b. 文件检查器
许多 GAIA 问题依赖于多种类型的附件文件,如 .xls、.mp3、.pdf 等。这些文件需要正确解析。我们再次使用了 Autogen 的工具,因为它表现优异。
非常感谢 Autogen 团队开源他们的工作!这些工具为我们节省了数周的开发时间!🤗
c. 代码解释器
由于我们的代理天然支持生成并执行 Python 代码,因此无需此工具:详见下文。
为何选择 Code Agent?
正如 Wang et al. (2024) 所示,让代理以代码形式表达其操作相比使用 JSON 等字典式输出具有多项优势。对我们而言,主要优势是代码是表达复杂操作序列的极优方式。如果存在比当前编程语言更严谨地表达详细操作的方式,它大概率已成为新的编程语言!
考虑论文中给出的示例:

它凸显了使用代码的几项优势:
- 代码操作比 JSON 简洁得多。
- 需要并行运行 4 个各含 5 个连续操作的流?在 JSON 中需生成 20 个 JSON 对象,每个单独一步;而在代码中只需 1 步。
- 论文显示,代码操作平均比 JSON 少 30% 的步骤,这相当于生成 token 减少 30%。由于 LLM 调用通常是代理系统的成本瓶颈,这意味着代理系统运行成本可降低约 30%。
- 代码支持复用常用库中的工具
- 使用代码在基准测试中获得更好性能,原因有二:
- 它是更直观的表达操作的方式
- LLM 的训练数据中包含大量代码,这可能使它们在编写代码时比编写 JSON 更流畅。
我们在 agent_reasoning_benchmark 的实验中验证了这些观点。
从构建 transformers agents 的最新实验中,我们还观察到其他优势:
- 在代码中将元素存储为命名变量要容易得多。例如,需要存储由工具生成的岩石图像以供后续使用?
- 代码中毫无问题:使用 “rock_image = image_generation_tool(“A picture of a rock”)” 可将变量存储在变量字典的 “rock_image” 键下。之后 LLM 只需在代码块中再次引用 “rock_image” 即可使用其值。
- 在 JSON 中,你需进行复杂操作来创建存储该图像的名称,以便 LLM 之后知道如何再次访问。例如,将图像生成工具的所有输出保存为 “image_{i}.png”,并相信 LLM 之后能理解 image_4.png 是之前工具调用的输出?或者让 LLM 额外输出 “output_name” 键来选择存储变量的名称,从而使 action JSON 的结构复杂化?
- 代理日志的可读性显著提高。
Transformers Agents 的 CodeAgent 实现
LLM 生成的代码直接执行可能非常不安全。如果让 LLM 在无防护措施的情况下编写并执行代码,它可能会幻觉出任何内容:例如,所有个人文件需被《沙丘》传说的副本覆盖,或将你演唱《冰雪奇缘》主题曲的音频分享到博客上!
因此,我们必须使代码执行安全化。通常的方法是自顶向下:“使用功能齐全的 Python 解释器,但禁止某些操作”。
为了更安全,我们选择了相反方向,从零构建一个 LLM 安全的 Python 解释器。给定 LLM 提供的 Python 代码块,我们的解释器从 ast Python 模块生成的代码的 抽象语法树表示 开始。它按树结构逐个执行树节点,并在遇到任何未明确授权的操作时停止。
例如,import 语句会首先检查导入是否明确列在用户定义的 authorized_imports 列表中:若不在列表中,则不执行。我们包含一个默认的内置标准 Python 函数列表,例如 print 和 range。列表外的任何内容都不会执行,除非用户明确授权。例如,open(如 with open("path.txt", "w") as file:)未被授权。
遇到函数调用(ast.Call)时,如果函数名是用户定义的工具之一,则使用调用参数调用该工具。如果是之前定义并允许的其他函数,则正常运行。
我们还进行了多项调整以支持 LLM 使用解释器:
- 我们限制执行中的操作数量以防止 LLM 生成的代码导致无限循环:每个操作都会使计数器递增,若达到阈值则中断执行
- 我们限制 print 输出的行数,以避免用垃圾信息淹没 LLM 的上下文长度。例如,如果 LLM 读取 1M 行文本文件并决定打印每一行,输出将在某一点被截断,以免代理内存爆炸。
基础多代理编排
网页浏览是上下文丰富的活动,但检索到的大部分上下文实际上无用。例如,在上述 GAIA 问题中,唯一重要的信息是画作《乌兹别克斯坦刺绣》的图像。其周围内容(如我们找到它的博客内容)通常对更广泛的任务解决无用。
为此,使用多代理步骤有意义!例如,我们可以创建管理代理和 Web 搜索代理。管理代理应解决更高层次的任务,并将特定 Web 搜索任务分配给 Web 搜索代理。Web 搜索代理应仅返回其搜索的有用输出,以免管理代理被无用信息干扰。
我们在工作流中创建了正是这种多代理编排:
- 顶层代理是 ReactCodeAgent。它原生处理代码,因为其操作以 Python 形式表述和执行。它可访问以下工具:
file_inspector用于读取文本文件,带有可选的question参数,以不返回文件全部内容而仅返回基于内容对特定问题的答案visualizer用于专门回答有关图像的问题。search_agent用于浏览网页。更具体地说,此工具只是对 Web Search 代理的包装器,后者是一个 JSON 代理(JSON 仍适用于严格顺序的任务,如网页浏览:滚动、导航到新页面等)。该代理又可访问网页浏览工具:informational_web_searchpage_downfind_in_page- …(完整列表见 此行)
将代理嵌入为工具是一种朴素的多代理编排方式,但我们想看看能将其推进多远——结果证明它可以走得很远!
规划组件 🗺️
目前已有 一整套 规划策略,我们选择了一种相对简单的预先规划工作流。每 N 步我们生成两项内容:
- 我们已知或可从上下文中推导的事实摘要,以及我们需要发现的事实
- 基于新观察和上述事实摘要解决任务的逐步计划
参数 N 可针对目标用例进行调优:我们为管理代理选择 N=2,为 Web 搜索代理选择 N=5。
一个有趣的发现是,如果我们不提供计划的前一版本作为输入,得分会上升。一个直观的解释是,LLM 通常强烈偏向上下文中可用的任何相关信息。如果计划的前一版本出现在提示中,LLM 很可能大量复用它,而不是在需要时重新评估方法并重新生成计划。
事实摘要和计划随后用作生成下一步操作的附加上下文。规划通过在 LLM 面前呈现实现目标的所有步骤和当前状态,鼓励 LLM 选择更好的轨迹。
结果 🏅
我们在验证集上获得 44.2% 的得分:这意味着 Transformers Agent 的 ReactCodeAgent 现已整体排名第一,比第二名高 4 分!在测试集上,我们获得 33.3% 的得分,排名第 2,领先于 Microsoft Autogen 的提交,并在最困难的 Level 3 问题上获得最佳平均得分。

这是一个支持 代码操作效果更好 的数据点。鉴于其效率,我们认为代码操作很快将取代 JSON/OAI 格式,成为代理编写操作的标准。
据我们所知,LangChain 和 LlamaIndex 不原生支持代码操作;Microsoft 的 Autogen 对代码操作有一定支持(在 docker 容器 中执行代码),但它看起来像是 JSON 操作的附录。因此,Transformers Agents 是唯一将此格式置于核心的库!
后续步骤
希望你喜欢阅读这篇博客!工作才刚刚开始,我们将继续从多个方向改进 Transformers Agents:
- LLM 引擎:我们的提交使用了 GPT-4o(遗憾的是),未进行任何微调。我们的假设是,使用微调的开源模型将使我们摆脱解析错误,并获得稍高的得分!
- 多代理编排:我们的是朴素的编排,通过更无缝的编排,我们可能会走得更远!
- Web 浏览器工具:使用
selenium包,我们可以构建一个能通过 Cookie 横幅并加载 JavaScript 的 Web 浏览器,从而允许我们读取目前无法访问的许多页面。 - 进一步改进规划:我们正在使用文献中的其他选项进行消融测试,以确定哪种方法效果最佳。我们计划尝试现有组件的替代实现以及一些新组件。当我们获得更多见解时,我们将发布更新!
请关注未来几个月的 Transformers Agents!🚀
欢迎随时与我们联系,分享你的用例!现在我们已在代理方面积累了内部专业知识,很乐意提供帮助!🤝


0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.