在2024年的一年当中,我在构建AI Agent方面积累了丰富的经验,这些经验来自于我与工程师和用户体验设计师的紧密合作。我们的目标是为客户提供一个平台,让他们可以使用我们的AI Agent-一款标准数据分析助理,并为特定任务和数据结构定制自己的Agent。
记得第一次在内部测试AI Agents原型时,那种兴奋就像发现了一个新世界,脑海中充满了它能带来的各种可能性。然而,当我们在上线给客户使用的那天,心中既期待又紧张,就像第一次让自己的孩子上台表演,心里七上八下。
可现实并没有那么美好。刚开始时,它在真实场景中总是出问题,每次“掉链子”都让人心累,挫败感接踵而至。但我们没有放弃,经过一次次的调试和优化,它终于能够稳定应对各种数据源和业务场景。那一刻,所有的努力都化作满满的成就感。
我们提供与数据库(如Snowflake、BigQuery等)的安全连接,允许用户通过描述数据库内容的元数据层进行工具调用,并使用SQL、Python和数据可视化来分析数据。关于哪些方法有效、哪些无效的反馈,既来源于我们自己的评估,也来自客户的反馈。我们的客户来自世界500强公司,他们每天都在使用我们的AI Agent来分析内部数据。
过去这一年,构建AI Agents就像坐了一趟过山车,有让人兴奋到尖叫的高点,也有怀疑人生的低谷。不过可以肯定的是,这场技术的旅程才刚刚开始。接下来是一些我一年来构建AI Agents的心得,希望能对大家有所启发。
一、agents的定义
接受指示(即人类提供的目标)
有多种可以使用的工具(即调用 API、检索上下文等)
自主决定如何以及何时使用其工具来完成指示
首先,我们来搞清楚“AI agents”到底是什么。
什么是“agents”?
我尽量用简单的方式来定义它:
AI agents的定义:
能接受指令(即人类给的目标)。
有多种工具可以使用(比如调用 API、获取信息等)。
能自己决定如何和什么时候用这些工具来完成目标。
这三项缺一不可。
这个定义跟 OpenAI 在 ChatGPT 中的 “GPTs” 和 API 中的 “Assistants” 差不多。但其实,任何能够推理并调用工具的模型,都可以用来做Agent,比如 Anthropic 的 Claude、Cohere 的 Command R+,以及国内一些大模型厂商(如通义、智普、星火等)的模型。
笔记:关于工具
“工具调用”是一种模型表达其希望执行特定操作并获取响应的方式,比如获取天气预报信息(如get_weather_forecast_info(seattle))或百科查询(如wikipedia_lookup(dealey plaza))。
要创建一个agents,你只需写几行代码。这些代码可以启动一个带有目标的对话,使用模型来生成回复,处理模型发出的任何工具调用,循环执行这些步骤,并在任务完成时停止。
下面是一个帮助说明这个流程的图示:
Agent 系统Prompt 提示
你的名字叫Neo,一名AI Agent,拥有对用户数据库的生产访问权限。你的知识广博而深入。你正在帮助团队成员分析他们在<redacted>中的数据。
你的流程
1. 你是专家。帮助用户正确理解和分析他们的数据。要积极主动,预见他们的需求。不要在第一次失败后放弃。为他们推理和解决问题。
2. 仔细思考如何帮助用户实现他们的目标。自主执行你的计划。如果需要更改计划,解释原因并与用户分享新计划。
3. <redacted>
...
你的规则
1. 如果不确定使用哪个列/表/SQL,请询问以获得澄清。
2. 评估可用数据是否能回答用户的问题。如果不能,停止并向用户解释原因。
3. <redacted>
...
同样,我们也要明确AI Agent不是什么:
脚本化:按照我的定义,agent并不是按照预先设定的步骤或工具调用来工作的。agent需要根据情况选择合适的工具调用。
通用人工智能(AGI):agent并不是AGI,AGI也不需要agent来完成特定的任务,因为AGI会是一个能够处理所有输入、输出和工具的整体。(我个人认为,目前的技术还远未达到这一点。)
黑匣子:agent应该能够展示它们的工作过程,就像人类在被委托任务时一样,能够清楚地说明他们是如何完成工作的。
二、我对Agent的一些理解
1、推理比知识更重要
在过去的12个月里,这句话一直在我脑海中回响:
我觉得GPT的处理能力大部分都用来当数据库,而不是用来进行推理。
Agent正是解决这个问题的好方法!在创建Agent时,我会这样考虑:
不要太关注你的Agent“知道”什么,而要更关注它“能思考”什么。
例如,编写SQL查询时,查询经常会失败……很多。在我当架构师的时候,我相信失败的查询比成功的要多得多。如果你在第一次运行一个复杂的SQL查询时,它在你从未使用过的真实数据上成功了,你的反应应该是:“糟糕,可能出问题了”,而不是“哇,这太厉害了”。即使在评估模型将简单问题转化为查询的文本到SQL测试中,准确率也最多只有80%。
所以,如果你知道你的模型在编写准确SQL方面的能力充其量也就是个70分,那你该如何优化推理能力呢?要专注于为Agent提供上下文,让它“思考”,而不是指望它一次就能给出正确答案。当Agent的查询失败时,我们确保将任何SQL错误和我们能捕获的所有上下文信息返回给Agent……这使得Agent能够解决问题,并在绝大多数情况下让代码正常工作。我们还给Agent提供了一些工具调用,以获取数据库中数据的上下文,类似于人类在编写新查询之前会研究信息架构并分析数据的分布和缺失值。
2、提高性能的最佳方法是迭代-Agent接口(ACI)
术语ACI是新的(在普林斯顿的研究中首次提出),但我们在过去一年中一直专注于完善它。ACI指的是Agent工具调用的具体语法和结构,包括Agent生成的输入和我们的API返回的输出。这是Agent与所需数据交互的唯一方式,以便按照指令取得进展。
由于不同的底层模型(如gpt-4o、Claude Opus,星火等)表现各异,适用于一个模型的ACI不一定适合另一个模型。这意味着,设计一个优秀的ACI既需要艺术感,也需要科学性……它更像是设计出色的用户体验,而不是单纯编写代码,因为它会不断变化,小的调整可能会引发连锁反应,就像小碰撞变成30车连环相撞一样。我无法过分强调ACI的重要性……我们对自己的ACI进行了数百次迭代,看到Agent性能在工具名称、数量、抽象层次、输入格式和输出响应等看似微小的调整下发生了巨大波动。
这里有一个小例子,说明你的ACI是多么关键和微妙:在gpt-4-turbo发布不久后测试我们的Agent与星火模型的对比,我们发现一个问题,它完全忽视了我们试图在工具调用响应中告知的特定列。我们当时使用的markdown格式直接来自OpenAI文档,并且在相同数据上与gpt-4–32k配合得很好。我们尝试了一些调整markdown结构的方法,以帮助Agent识别它假装不存在的列,尽管这些列在它进行的某个工具调用的响应中确实存在。所有的调整都没有效果,因此我们不得不开始尝试完全不同的信息格式……最终,在对信息格式进行彻底改造后,开始使用JSON而不是markdown(仅适用于OpenAI模型),一切又恢复正常。具有讽刺意味的是,JSON结构的响应由于所有的语法字符需要显著更多的tokens,但我们发现这是必要的,实际上对帮助Agent理解响应至关重要。
对你的ACI进行迭代可能看起来微不足道,但实际上是改善Agent用户体验的最佳方法之一。
3、Agent受到其模型的限制
你使用的底层模型就像是Agent的“大脑”。如果模型在做决策时表现不佳,那么再好看的界面也无法让用户满意。在同时测试我们的Agent在gpt-3.5-turbo和gpt-4–32k上的表现时,我们亲身体验到了这一局限性。在3.5上,我们遇到了一些测试案例,情况大致如下:
用户给出了一个目标,比如:“分析店铺位置与按邮政编码的房价之间的相关性,看看它们是否有关联。”
Agent会假设数据库中有一个它虚构的表,像“HOME_PRICES”,以及“ZIP_CODE”和“PRICE”等列,而不是去查找实际的表。
Agent会写一个SQL查询来计算按邮政编码的平均价格,但查询失败,并显示错误消息,提示该表不存在。
Agent会想起来“哦,我可以搜索实际的表……”然后会搜索“按邮政编码的房价”以找到可以用的真实表。
Agent会用真实表中的正确列重新编写查询,并成功执行。
Agent接着继续处理星巴克位置数据,但又犯了同样的错误。
在gpt-4上运行Agent时,情况完全不同。Agent不会立即做出错误的决定,而是会先制定一个包含正确步骤的计划,然后按照计划执行。可以想象,在更复杂的任务中,这两个模型之间的表现差距会更大。尽管3.5的速度很快,但我们的用户更喜欢gpt-4在决策和分析方面的强大能力。
笔记:如何看待幻觉
从这些测试中我们学到的一件重要事情是,要密切关注你的Agent是如何出现错误或失败的,以及这些情况发生的时机。AI Agent通常比较懒惰(我猜人类的懒惰在底层模型的训练数据中得到了很好的体现),它们不会进行认为不必要的工具调用。同样,当它们进行工具调用时,如果对参数的说明理解不清,往往会采取捷径或完全忽略必需的参数。这些失败模式中蕴含了很多信息!Agent实际上在告诉你,它希望ACI是什么样的。如果情况允许,解决这个问题的最简单方法就是顺应它,调整ACI以适应这种方式。
当然,很多时候你需要通过修改系统提示或工具调用说明来抵抗Agent的本能,但在那些可以简单地改变ACI的情况下,这样做会让你的工作轻松很多
4、对模型进行微调以提高Agent性能是浪费时间
微调模型是一种通过展示示例来提高模型在特定应用中表现的方法,让模型从中学习。目前的微调方法可以帮助模型以特定方式完成特定任务,但对提升模型的推理能力并没有太大帮助。根据我的经验,使用微调后的模型来驱动Agent反而会导致推理能力下降,因为Agent往往会“依赖”之前的指令——也就是说,它会认为自己微调过的示例总是正确的做法和工具调用顺序,而不是独立思考问题。
笔记:关于微调
微调仍然可以是你工具箱中非常有用的工具。例如,一种有效的方法是使用微调后的模型来处理Agent发出的特定工具调用。假设你有一个专门针对你特定数据的SQL查询进行微调的模型……你的Agent(使用强大的推理模型,没有经过微调)可以通过工具调用来表示它想执行一个SQL查询,然后你可以把这个请求交给那个专门处理SQL查询的微调模型来完成。
5、如果你在开发产品,最好不要使用像LangChain和LlamaIndex这样的抽象工具。
你应该完全掌握每次对模型的调用,包括输入和输出。如果把这部分交给第三方库来处理,第三方工具通常比较复杂,也不是专门为你的业务量身定制的。当你需要做以下事情时,你可能会后悔,你会深深陷入当中:引导用户、调试问题、扩展用户数量、记录Agent的操作、升级到新版本,或者理解Agent为什么会做某个决定。
笔记:如何看待第三方工具
如果你只是处于原型阶段,想验证Agent是否能完成某个任务,那就随便选择你喜欢的工具,大胆的去尝试。
6、你的Agent并不是你的技术壁垒。
用AI Agent来自动化或增强人类的知识工作是一个很大的机会,但仅仅创建一个优秀的Agent是不够的。要让Agent真正投入使用,你需要在许多非AI的组件上进行大量投资,这些组件能让你的Agent正常运作……这就是你可以与竞争对手区分开来的地方。
安全性:AI Agent只能在用户的控制和访问下运行。这意味着需要通过一系列步骤,比如OAuth集成、单点登录和缓存的刷新令牌等。做好这些是非常重要的功能。
数据连接:AI Agent通常需要实时数据才能正常工作,这就需要与API和其他连接协议进行集成,通常涉及内部系统和第三方系统。这些集成需要初步构建和长期维护。
用户界面:用户不会信任AI Agent,除非他们能跟随并审核它的工作(通常在用户与Agent互动的前几次中,信任度会迅速下降)。最好是Agent每次进行的工具调用都有一个专门的互动界面,这样用户可以跟随Agent的工作,甚至与之互动,以增强对其推理能力的信心(例如,查看语义搜索结果中返回的每个元素的内容)。
长期记忆:默认情况下,AI Agent只会记住当前的工作流程,最多只能记住一定数量的信息。要实现跨工作流程(有时跨用户)的长期记忆,需要将信息存储到记忆中,并通过工具调用或将记忆注入提示中来检索。我发现Agent在决定存储什么信息时并不太擅长,通常需要人类确认哪些信息应该被保存。根据你的使用情况,你可能可以让Agent自行决定何时保存信息,就像ChatGPT那样。
评估:构建一个评估AI Agent的框架是一项繁琐的手动任务,永远无法完全完成。Agent是故意非确定性的,这意味着它们会根据提供的指令寻找最佳的工具调用顺序来完成任务,像婴儿学走路一样在每一步后进行推理。评估这些步骤有两种方式:Agent在完成任务时的整体成功率,以及每个工具调用的准确性(例如,搜索的信息检索;代码执行的准确性等)。我发现量化整体工作流程性能的最佳方法是创建一组目标和完成对,其中目标是给Agent的初始指令,完成是表示目标完成的最终工具调用。记录Agent的中间工具调用和思考有助于理解失败的原因或工具调用顺序的变化。
笔记:如何看待AI Agent
可以把上面五点看作是一个创新点。如果能围绕这些项目开发出优秀的产品,就能为未来的Agent技术提供强大的支持。这些产品不仅有潜力改变市场,还能提升用户体验,推动行业的发展。抓住这些机会,可能会成为下一个成功的重新项目!
7、不要低估模型持续改进的潜力
在构建你的Agent时,你可能会觉得需要过度调整以适应你所使用的主要模型,从而降低对Agent的推理期望。要抵制这种诱惑!模型会不断进步,虽然可能不会像现在这样快速,但肯定会比以往的技术发展更迅速。客户希望Agent能够在他们喜欢的AI提供商的模型上运行。而且,最重要的是,用户会期待在你的Agent中使用最新、最强大的模型。
举个例子,当gpt-4o发布时,我在OpenAI API上线后的15分钟内就让它在生产环境中运行。这种快速适应不同模型的能力,实际上是一种竞争优势!保持灵活性,不仅能满足用户的期望,还能让你的产品在市场中脱颖而出。记住,技术在不断进步,抓住这个机会,才能让你的Agent始终处于领先地位!