吴恩达课程:Agentic AI

模块一:Agentic AI简介

1.0 简介

欢迎来到这门关于 Agentic AI 的课程。当我创造 “agentic” 这个词来描述我所看到的一种重要且快速增长的、人们构建基础应用的方式时,我没有意识到的是,一群营销人员会抓住这个词,把它当成一个标签,贴在几乎所有能看到的东西上。这导致了对 Agentic AI 的炒作急剧升温。不过,好消息是,抛开炒作不谈,使用 Agentic AI 构建的真正有价值和有用的应用数量也增长得非常迅速,即使没有炒作那么快。在本课程中,我想向您展示构建 Agentic AI 应用的最佳实践。这将在您现在可以构建什么方面,为您开启许多新的机会。

如今,agentic 工作流正被用于构建客户支持代理等应用,或进行深度研究以帮助撰写富有洞察力的研究报告,或处理棘手的法律文件,或查看患者输入信息并提出可能的医学诊断。在我带的许多团队中,我们构建的很多项目如果没有 agentic 工作流是根本不可能完成的。因此,知道如何用它们来构建应用是当今 AI 领域最重要和最有价值的技能之一。

我发现,真正懂得如何构建 agentic 工作流的人与那些效率较低的人之间,最大的区别之一是能否推动一个规范的开发流程,特别是专注于评估和错误分析的流程。在本课程中,我将告诉您这意味着什么,并向您展示如何才能真正擅长构建这些 agentic 工作流。能够做到这一点是当今 AI 领域最重要的技能之一,它将为您开启更多的机会,无论是工作机会,还是亲手打造出色软件的机会。

那么,让我们进入下一个视频,更深入地探讨什么是 agentic 工作流。

1.1 什么是 Agentic AI

那么,什么是 Agentic AI?为什么 Agentic AI 工作流如此强大?让我们来看一看。

如今,我们许多人使用大型语言模型(LLM)的方式是提示它,比如说,为我们写一篇关于某个主题 X 的文章。我认为这类似于去找一个人,或者在这种情况下,去找一个 AI,请它为我打出一篇文章,要求它从第一个词写到最后一个词,一气呵成,并且永远不能使用退格键。事实证明,我们人类并不能通过这种被迫以完全线性顺序写作的方式来完成我们最好的作品,AI 模型也是如此。但尽管受到这种写作方式的限制,我们的大语言模型表现得出奇地好。

相比之下,使用 agentic 工作流,过程可能是这样的:你可能会让它首先写一个关于某个主题的文章大纲,然后问它是否需要进行任何网络研究。在进行了一些网络研究并可能下载了一些网页之后,再让它撰写初稿,然后阅读初稿,看看哪些部分需要修改或做更多研究,接着修改草稿,如此循环。这种工作流更类似于先进行一些思考和研究,然后进行一些修改,再进行更多的思考,等等。通过这种迭代过程,事实证明,agentic 工作流可能需要更长的时间,但它能交付出质量好得多的工作成果。

所以,一个 Agentic AI 工作流是一个基于 LLM 的应用执行多个步骤来完成一项任务的过程。在这个例子中,你可能会使用一个 LLM 来撰写文章大纲,然后你可能会使用一个 LLM 来决定在网络搜索引擎中输入什么搜索词,或者说,用什么搜索词来调用网络搜索 API,以获取相关的网页。基于此,你可以将下载的网页输入到一个 LLM 中,让它撰写初稿,然后可能使用另一个 LLM 进行反思,并决定哪些地方需要更多修改。根据你设计这个工作流的方式,也许你甚至可以加入一个“人类在环”的步骤,让 LLM 可以选择请求人类审查某些关键事实。在此基础上,它可能会修改草稿,这个过程会产生一个好得多的工作输出。

你在本课程中学到的关键技能之一,就是如何将像写文章这样的复杂任务分解成更小的步骤,让 agentic 工作流一次执行一步,从而获得你想要的工作输出。事实证明,知道如何将任务分解为步骤,以及如何构建组件来很好地执行单个步骤,是一项棘手但重要的技能,它将决定你为各种激动人心的应用构建 agentic 工作流的能力。

在本课程中,我们将使用一个贯穿始终的例子,也是你将与我一起构建的东西——一个研究代理(research agent)。下面是它看起来的样子。你可以输入一个研究主题,比如“我如何建立一个新的火箭公司来与 SpaceX 竞争”。我个人不想与 SpaceX 竞争,但如果你想,你可以试着让研究代理帮助你做背景研究。

这个代理首先会规划要使用哪些研究方法,包括调用网络搜索引擎下载一些网页,然后综合和排序研究发现,起草大纲,让一个“编辑代理”审查其连贯性,最后生成一份全面的 Markdown 报告。它在这里已经完成了,报告标题是“建立一个新的火箭公司来与 SpaceX 竞争”,内容包括引言、背景、发现等等。我认为它恰当地指出,这将是一个很难创建的初创公司,所以我个人不打算这么做。但如果你想处理这样的事情,也许像这样的研究代理可以帮助你做一些初步研究。通过查找和下载多个来源并深入思考,这实际上最终会得到一份比仅仅提示一个 LLM 为你写一篇文章要深思熟虑得多的报告。

我对此感到兴奋的原因之一是,在我的工作中,我最终构建了不少专门的研究代理,无论是在法律文件领域用于冲突法合规性,还是在一些医疗健康领域,或是一些商业产品研究领域。因此,我希望通过这个例子,你不仅能学会如何为许多其他应用构建 agentic 工作流,而且在构建研究代理时的一些想法,在你将来需要自己构建一个定制的研究代理时,能对你直接有用。

现在,关于 AI 代理经常被讨论的领域之一是它们的自主性有多高?你刚才看到的是一个相对复杂、高度自主的 Agentic AI 工作流,但也有其他更简单的工作流,它们同样非常有价值。让我们在下一个视频中讨论 agentic 工作流可以达到何种程度的自主性,并为你提供一个框架来思考你可能如何构建不同的应用,以及它们的难易程度。我们在下一个视频见。

1.2 自主程度

代理(Agent)可以在不同程度上实现自主。几年前,我注意到在 AI 社区内部,关于什么是“代理”的争议日益激烈。有些人写论文说他们构建了一个代理,而另一些人则会说,不,那并不是一个真正的代理。我觉得这场辩论没有必要,所以我开始使用 “agentic” 这个词。因为我认为,如果我们把它当作一个形容词,而不是一个二元概念——要么是代理,要么不是——那么我们就必须承认系统可以在不同程度上是 agentic 的。让我们就都称之为 agentic,然后继续我们构建这些系统的实际工作,而不是去辩论“这个系统是否足够自主以至于能被称为代理”。

我记得当我准备一个关于 agentic 推理的演讲时,我的一个团队成员实际上来找我说:“嘿,Andrew,我们不需要再来一个新词了。我们已经有 agent 了,你为什么要造另一个词 agentic 呢?” 但我还是决定使用它。后来,我在一份名为 The Batch 的时事通讯中写了一篇文章,也在社交媒体上发帖说,与其争论哪个词应该被包含或排除为真正的代理,不如让我们承认系统可以有不同程度的 agentic 特性。我认为这帮助我们超越了关于什么是真正代理的辩论,让我们能够专注于实际地构建它们。

不同程度的自主性

有些代理可以不那么自主。以写一篇关于黑洞的文章为例,你可以有一个相对简单的代理来提出几个网络搜索词条或查询。然后你可以硬编码,让它调用网络搜索引擎,获取一些网页,然后用这些信息来写文章。这是一个自主性较低的代理的例子,它有一套完全确定的步骤序列。这样做效果还不错。

在整个课程中,我会用红色表示用户输入,比如这里的用户查询,或者在后面的例子中,可能是输入到 agentic 工作流的文档。灰色的框表示对 LLM 的调用,而绿色的框,比如你在这里看到的网络搜索和网页获取框,表示使用其他软件执行操作的步骤,比如调用网络搜索 API 或执行代码来获取网站内容。

然后,一个代理可以更加自主。当收到写一篇关于黑洞的文章的请求时,也许你可以让 LLM 自行决定,是想进行网络搜索,还是搜索最近的新闻源,或者是在网站 archive 上搜索最新的研究论文。基于此,也许在这个例子中,是 LLM 而不是人类工程师,选择了调用网络搜索引擎。之后,你可能会让 LLM 决定它想获取多少个网页,或者如果它获取了 PDF,是否需要调用一个函数或工具将 PDF 转换为文本。在这种情况下,也许它获取了前几个网页,然后它可以写一篇文章,决定是否要反思和改进,甚至可能返回去获取更多的网页,然后最终产生一个输出。

因此,即使是对于研究代理这个例子,我们也可以看到一些代理可以不那么自主,其执行的步骤是线性的,由程序员确定;而另一些则可以更自主,你信任 LLM 做出更多的决定,甚至确切的步骤顺序也可能由 LLM 决定,而不是由程序员预先设定。

自主性谱系

  • 自主性较低的系统:通常所有步骤都是预先确定的。它调用的任何函数,比如网络搜索(我们称之为“工具使用”),可能是由人类工程师(你或我)硬编码的。大部分的自主性体现在 LLM 生成的文本内容上。
  • 高度自主的代理:在谱系的另一端,代理会自主地做出许多决定,包括例如决定执行什么步骤序列来写文章。有些高度自主的代理甚至可以编写新的函数,或创建新的工具供自己执行。
  • 半自主代理:介于两者之间,它可以做出一些决定,选择工具,但这些工具通常是预先定义好的。

当你在本课程中看到不同的例子时,你将学会如何在这个从低自主到高自主的谱系中的任何位置构建应用。你会发现,在谱系的低自主端,有大量非常有价值的应用正在为无数企业构建。同时,在谱系的高自主端,也有应用正在开发中,但那些通常更难控制,有点更不可预测,并且也有大量的活跃研究在探索如何构建这些更高度自主的代理。

那么,让我们进入下一个视频,更深入地探讨这个话题,并听听使用代理的一些好处,以及为什么它们让我们能做到一些用前几代基础应用无法实现的事情。

1.3 Agentic 工作流的好处

我认为 agentic 工作流最大的一个好处是,它能让你有效地完成许多以前根本不可能完成的任务。但除此之外,还有其他好处,包括并行化,让你能非常快地完成某些事情,以及模块化,让你能将来自许多不同地方的最佳组件组合起来,构建一个高效的工作流。让我们来看一看。

性能提升

我的团队收集了一些关于一个编码基准测试的数据,该测试旨在检验不同 LLM 编写代码以执行特定任务的能力。这个基准测试叫做 Human Eval。结果显示,GPT-3.5(首个公开发布的 ChatGPT 版本所基于的模型),如果被要求直接编写代码,即一次性输出整个计算机程序,在这个基准测试上的正确率为 40%。而 GPT-4 是一个好得多的模型,它在使用同样的非 agentic 工作流时,性能跃升至 67%。

但事实证明,从 GPT-3.5 到 GPT-4 的提升虽然巨大,但与将 GPT-3.5 包装在一个 agentic 工作流中所能实现的提升相比,就相形见绌了。通过使用不同的 agentic 技术(你将在本课程后面学到),你可以提示 GPT-3.5 编写代码,然后或许让它反思代码并找出改进之处。使用这样的技术,你实际上可以让 GPT-3.5 达到高得多的性能水平。同样,在 agentic 工作流的背景下使用 GPT-4,其表现也会好得多。因此,即使是使用当今最好的 LLM,agentic 工作流也能让你获得更好的性能。实际上,我们在这个例子中看到,从一代模型到下一代模型的提升虽然巨大,但仍然不如在上一代模型上实施 agentic 工作流所带来的差异大。

并行化与效率

使用 agentic 工作流的另一个好处是它们可以并行化一些任务,从而比人类更快地完成某些事情。例如,如果你让一个 agentic 工作流写一篇关于黑洞的文章,你可能可以并行运行三个 LLM 来为搜索引擎生成搜索词的创意。基于第一次网络搜索,它可能会识别出,比如说,三个排名最靠前的结果来获取。基于第二次网络搜索,它可能会识别出第二组要获取的网页,以此类推。事实证明,如果一个人类来做这项研究,他将不得不按顺序或一次一个地阅读这九个网页。而当你使用 agentic 工作流时,你实际上可以并行化所有九个网页的下载,然后最终将所有这些信息输入一个 LLM 来撰写文章。所以,尽管 agentic 工作流确实比真正的非 agentic 工作流(即通过单次提示直接生成)花费更长的时间,但如果你将这种 agentic 工作流与人类完成任务的方式相比,其并行下载大量网页的能力实际上能让它比单一的人类以非并行的顺序方式处理这些数据要快得多。

模块化与灵活性

在这个例子的基础上,我经常在构建 agentic 工作流时做的一件事,就是审视像 LLM 这样的单个组件,并添加或替换组件。例如,我可能会审视我在这里使用的网络搜索引擎,然后决定换一个新的。在构建 agentic 工作流时,实际上有多个网络搜索引擎可供选择,包括可以通过服务器访问的 Google,以及像 Bing、DuckDuckGo、Tavily、you.com 等其他引擎。实际上,为 LLM 设计的网络搜索引擎有很多选择。或者,也许不仅仅是做三次网络搜索,我们可以在这一步换上一个新的新闻搜索引擎,这样我们就能找到关于黑洞科学最新突破的消息。最后,我通常会尝试不同的 LLM,而不是在所有不同步骤都使用同一个,我可能会尝试不同的 LLM 提供商,看看哪个能在系统的不同步骤中给出最好的结果。

总结一下,我使用 agentic 工作流的主要原因就是它在许多不同应用上都能提供更好的性能。但此外,它还可以并行处理一些人类必须按顺序完成的任务。而且,许多 agentic 工作流的模块化设计也让我们能够添加或更新工具,有时还能更换模型。我们已经谈了很多关于构建 agentic 工作流的关键组件。现在让我们来看一系列 Agentic AI 的应用,让你了解人们已经在构建什么样的东西,以及你将要亲手构建什么样的东西。让我们进入下一个视频。

1.4 Agentic AI 应用

让我们来看一些 Agentic AI 应用的例子。

示例一:发票处理(流程清晰)

许多企业都会执行的一项任务是发票处理。给定这样一张发票,你可能想编写软件来提取最重要的字段,对于这个应用来说,假设这些字段是:开票方(即 Tech Flow Solutions)、开票方地址、应付金额(3000美元)以及到期日(看起来是2025年8月20日)。在许多财务部门,可能是一个人查看发票并识别出最重要的字段——我们需要在何时向谁付款——然后将这些信息记录在数据库中,以确保按时付款。

如果你用 agentic 工作流来实现这个功能,你可能会这样做:输入一张发票,然后调用一个 PDF 到文本的转换 API,将 PDF 转换成可能是格式化的文本,比如 Markdown 文本,供 LLM 读取。然后 LLM 会查看 PDF 内容并判断这到底是不是一张发票,还是其他应该忽略的文档类型。如果是一张发票,它就会提取所需的字段,并使用一个 API 或工具来更新数据库,将最重要的字段保存在数据库记录中。这个 agentic 工作流的一个方面是,它有一个清晰的流程可以遵循:识别所需字段并在数据库中记录。像这样有清晰流程的任务,对于 agentic 工作流来说往往更容易执行,因为它导向了一种相对按部就班、可靠地执行任务的方式。

示例二:基础客户订单查询(流程清晰)

这里是另一个例子,可能稍微难一点。如果你想构建一个代理来回应基本的客户订单查询,那么步骤可能是:首先提取关键信息,弄清楚客户到底订购了什么,客户的名字是什么;然后查找相关的客户记录;最后起草一份回复,供人工审查,之后再将邮件发送给客户。

这里同样有一个清晰的流程,我们会按部就班地实现它:接收邮件,将其交给一个 LLM 来验证或提取订单详情。假设客户邮件是关于一个订单的,LLM 可能会选择调用订单数据库来调取信息。这些信息随后会交给 LLM,由它起草一封电子邮件回复。LLM 可能会选择使用一个“请求审查”的工具,比如将这封由 LLM 起草的邮件放入一个队列中供人工审查,以便在人工审查并批准后发送出去。像这样的客户订单查询代理如今正在许多企业中被构建和部署。

示例三:通用客户服务(更具挑战性)

来看一个更具挑战性的例子。如果你想构建一个客户服务代理,不仅能回答关于他们下的订单的问题,还能回应更广泛的问题,即客户可能问的任何事情。也许客户会问:“你们有黑色的牛仔裤或蓝色的牛仔裤吗?” 要回答这个问题,你可能需要多次调用你的数据库 API,先检查黑色牛仔裤的库存,再检查蓝色牛仔裤的库存,然后再回复客户。这是一个更具挑战性的查询的例子,给定一个用户输入,你实际上必须规划出一系列数据库查询的顺序来检查库存。

或者,如果一个用户问:“我想退回我买的沙滩巾。” 要回答这个问题,我们可能需要验证客户是否真的购买了沙滩巾,然后再次核对退货政策。也许我们的退货政策是购买后30天内且毛巾未使用过才可退货。如果允许退货,那么就让代理生成一个退货标签,并同时将数据库记录设置为“退货处理中”。在这个例子中,如果处理客户请求所需的步骤不是预先知道的,那么它就会导致一个更具挑战性的过程,基于 LLM 的应用必须自己决定需要这三个步骤才能对这个任务做出适当的回应。但你也会学到一些关于如何处理这类问题的最新方法。

示例四:计算机使用(前沿但困难)

最后一个例子,可能是一种特别难以构建的代理类型。有很多关于代理使用计算机的研究,在这种研究中,代理会尝试使用网络浏览器并阅读网页,以找出如何执行一项复杂的任务。

在这个例子中,我要求一个代理检查从旧金山到华盛顿特区(DCA机场)的两个特定美联航航班上是否有座位。该代理可以访问一个网络浏览器来执行此任务。在视频中,你可以看到它独立地浏览美联航网站,点击页面元素并填写页面上的文本字段,以执行我请求的搜索。在工作时,代理会推理页面内容,以确定完成任务需要采取的行动以及下一步该做什么。在这种情况下,它在美联航网站上检查航班时遇到了一些麻烦,于是决定转到谷歌航班网站搜索可用航班。在谷歌航班上,你看到它找到了几个符合用户查询的航班选项,然后代理选择了一个,并被带回到美联航网站,看起来它现在在正确的网页上了,因此能够确定我所询问的航班上确实有座位。

计算机使用是目前一个激动人心的前沿研究领域,许多公司都在努力让计算机使用代理能够正常工作。虽然你在这里看到的代理最终找到了答案,但我经常看到代理在使用网络浏览器时遇到困难。例如,如果一个网页加载缓慢,代理可能无法理解发生了什么,而且许多网页仍然超出了代理准确解析或阅读的能力范围。但我认为,计算机使用代理,尽管今天还不够可靠,无法用于关键任务应用,但它们是未来发展的一个激动人心且重要的领域。

难易度总结

所以,当我在考虑构建 Agentic AI 工作流时:

  • 较容易的任务:往往是那些有清晰、按部就班流程的任务。如果一个企业已经有了标准的作业程序,那么将这个程序编码成一个 AI 代理虽然可能需要很多工作,但通常实现起来更容易。如果只使用纯文本资产,也会更容易,因为 LLM 就是在处理文本中成长起来的。
  • 较困难的任务:如果执行任务所需的步骤不是预先知道的,就像你看到的更高级的客户服务代理那样,那么代理可能需要边做边规划或解决问题,这往往更难、更不可预测、可靠性也更低。而且如前所述,如果需要接受丰富的多模态输入,如声音、视觉、音频,也往往比只处理文本更不可靠。

希望这能让你对可能用 agentic 工作流构建的应用类型有所了解。当你自己实现这些东西时,最重要的技能之一是审视一个复杂的工作流,并找出其中的各个步骤,以便你可以实现一个 agentic 工作流来一步步执行这些步骤。在下一个视频中,我们将讨论任务分解,也就是说,给定一个你想做的复杂事情,比如写一份研究报告或者让客户代理回复客户,你如何将其分解成离散的步骤来尝试实现一个 agentic 工作流。让我们在下一个视频中看看这个。

1.5 任务分解:识别工作流中的步骤

人和企业做很多事情。你如何将我们做的这些有用的事情分解成离散的步骤,供 agentic 工作流遵循呢?让我们来看一看。

以构建一个研究代理为例。如果你想让一个 AI 系统写一篇关于主题 X 的文章,一种方法是直接提示一个 LLM 让它生成输出。但如果你对想要深入研究的主题这样做,你可能会发现 LLM 的输出只涵盖了表面层次的观点,或者可能只涵盖了显而易见的事实,但没有像你希望的那样深入探讨主题。在这种情况下,你可能会反思一下,作为一个人,你会如何写一篇关于某个主题的文章。你会直接坐下来就开始写,还是会采取多个步骤,比如先写一个文章大纲,然后搜索网络,再根据网络搜索的输入来写文章。

当我将一个任务分解成步骤时,我总是在问自己一个问题:看看这第一、第二和第三个步骤,它们中的每一个是否都可以由一个 LLM,或者一小段代码,或者一个函数调用,或者一个工具来完成。在这种情况下,我认为一个 LLM 可以在很多我希望它帮助我思考的主题上写出一个不错的大纲。所以,第一步大概没问题。然后我知道如何使用一个 LLM 来生成搜索词以搜索网络。所以,我认为第二步也是可行的。然后基于网络搜索,我认为一个 LLM 可以输入网络搜索结果并写一篇文章。因此,这对于编写一篇比直接生成更深入的文章来说,会是一个合理的 agentic 工作流的初次尝试。

但是,如果我实现了这个 agentic 工作流并查看结果,也许我发现结果仍然不够好,它还不够深思熟虑,也许文章感觉有点脱节。这实际上发生在我身上过。我曾经用这个工作流构建了一个研究代理,但当我读输出时,感觉有点不连贯,文章的开头和中间部分感觉不完全一致,和结尾部分也不完全一致。

在这种情况下,你可能会反思,如果你作为一个人发现文章有点脱节,你会如何改变工作流。一种做法是,将第三步“写文章”进一步分解成额外的步骤。所以,你可能不会让它一次性写完文章,而是让它先写初稿,然后思考哪些部分需要修改,接着再修改草稿。这就像我作为一个人可能会做的那样,不是第一次尝试就写出最终的文章,而是先写初稿,然后再通读一遍——这是 LLM 相当擅长的另一步。然后基于我自己对我文章的批判,我会修改草稿。

回顾一下,我从直接生成开始,只有一个步骤,觉得不够好,所以把它分解成了三个步骤。然后可能觉得还是不够好,于是把其中一个步骤进一步分解成了三个更小的步骤,最终得到了这个更复杂、更丰富的文章生成过程。根据你对这个过程结果的满意度,你甚至可以选择进一步修改这个文章生成过程。

让我们看第二个关于如何将复杂任务分解成更小步骤的例子。以回应基本的客户订单查询为例。一个人类客户专员可能执行的第一步是先提取关键信息,比如这封邮件是谁发的,他们订了什么,订单号是多少。这些事情一个 LLM 都能做。所以我可以说,让一个 LLM 来做这件事。第二步是找到相关的客户记录。也就是编写并生成相关的数据库查询,来调取客户订购了什么、我什么时候发货等订单信息。我认为一个能够调用函数查询订单数据库的 LLM 应该能做到这一点。最后,调出客户记录或客户订单记录后,我可能会写一封回信发给客户。我认为有了我们调取的信息,如果我给它调用 API 发送邮件的选项,这第三步用 LLM 也是可行的。所以,这是另一个将回应客户邮件的任务分解成三个独立步骤的例子,我可以审视每个步骤然后说,是的,我认为一个 LLM,或者一个能调用函数查询数据库或发送邮件的 LLM,应该能做到。

最后一个例子,关于发票处理。在 PDF 发票被转换成文本后,第一步是提取所需信息:开票方名称、地址、到期日、应付金额等等。LLM 应该能做到。然后,如果我想检查信息是否被提取并将其保存在一个新的数据库条目中,那么我认为一个 LLM 应该能帮助我调用一个函数来更新数据库记录。所以要实现这个功能,我们实现一个 agentic 工作流来基本上执行这两个步骤。

在构建 agentic 工作流时,我把自己想象成拥有一些构建模块。一个重要的构建模块是大型语言模型,或者如果我想处理图像或音频,可能是大型多模态模型。LLM 擅长生成文本、决定调用什么、提取信息等。对于一些高度专业的任务,我也可能使用其他一些 AI 模型,比如用于将 PDF 转换为文本的模型,或用于文本转语音、图像分析的模型。

除了 AI 模型,我还可以使用一些软件工具,包括我可以调用的各种 API,用来进行语音搜索、获取实时天气数据、发送邮件、检查日历等等。我也可能有用于信息检索的工具,从数据库中提取数据,或者实现 RAG(检索增强生成),即我可以查询一个大型文本数据库并找到最相关的文本。或者我也可能有执行代码的工具,这个工具能让 LLM 编写代码,然后在你的计算机上运行这些代码,从而完成各种各样的事情。

如果这些工具对你来说有些陌生,别担心。我们会在后面的模块中更详细地介绍最重要的工具。但我认为,当我构建一个 agentic 工作流时,我的大部分工作就是观察一个人或一个企业正在做的事情,然后试图弄清楚,用这些构建模块,我如何将它们按顺序组合在一起,以执行我希望我的系统执行的任务。这就是为什么对有哪些可用的构建模块有一个很好的理解(我希望在本课程结束时你会有更好的了解)会让你能更好地构想出通过组合这些构建模块可以构建出什么样的 agentic 工作流。

总结一下,构建 agentic 工作流的关键技能之一,是审视一堆可能由某人完成的事情,并识别出可以用技术实现的离散步骤。当我看待单个离散步骤时,我总是在问自己一个问题:这个步骤能用一个 LLM,或者用我能接触到的一个工具(如 API 或函数调用)来实现吗?如果答案是否定的,我通常会问自己,我作为一个人会怎么做这一步?有没有可能把它进一步分解成更小的步骤,从而可能更容易用 LLM 或我拥有的某个软件工具来实现。

希望这能让你对如何思考任务分解有一个大致的了解。如果你觉得还没有完全掌握,别担心。我们将在本课程中讲解更多的例子,到课程结束时你会有更好的理解。但事实证明,当你构建 agentic 工作流时,你常常会先构建一个初步的任务分解和 agentic 工作流,然后你需要不断地迭代和改进它好几次,直到它达到你想要的性能水平。而要推动这个改进过程(我发现这对许多项目都很重要),关键技能之一就是知道如何评估你的 agentic 工作流。所以在下一个视频中,我们将讨论评估(evals)及其关键组成部分,以及你如何能够构建并持续改进你的工作流,以获得你想要的性能。让我们在下一个视频中讨论评估。

1.6 Agentic 评估 (Evals)

我曾与许多不同的团队合作构建 agentic 工作流,我发现,预测一个人能否做得非常好与效率较低的最大因素之一,就是他们是否能够推动一个非常规范的评估流程。所以,你为你的 agentic 工作流推动评估的能力,对你有效构建它们的能力有着巨大的影响。

在这个视频中,我们将快速概述如何构建评估,这个主题我们实际上会在本课程后面的一个模块中进行更深入的探讨。那么,让我们来看一看。

在构建了像这个用于回应客户订单查询的 agentic 工作流之后,事实证明,很难预先知道可能会出什么问题。因此,我建议不要试图预先构建评估,而是直接查看输出,并手动寻找你希望它做得更好的地方。

例如,也许你阅读了大量输出后发现,它出乎意料地提到了你的竞争对手,而且次数比应有的要多。许多企业不希望他们的代理提及竞争对手,因为这只会造成尴尬的局面。如果你读了其中一些输出,也许你会发现它有时会说:“很高兴您与我们购物,我们比我们的竞争对手 ComproCo 好得多。” 或者有时它会说:“当然,退货应该很有趣。不像 RivalCo,我们让退货变得简单。” 你看到这些可能会想,天啊,我真的不希望它提及竞争对手。

这是一个在构建此 agentic 工作流之前很难预见到的问题的例子。因此,最佳实践是先构建它,然后检查它以找出它还不令人满意的地方,接着找到评估以及改进系统的方法,以消除那些仍然不令人满意的地方。

假设你的企业认为以这种方式提及竞争对手是一个错误,那么当你努力消除这些提及竞争对手的言论时,一种跟踪进展的方法是添加一个评估(eval),来追踪这个错误发生的频率。所以,如果你有一个明确的竞争对手名单,比如 ComproCo、RivalCo、the other co,你实际上可以编写代码,在你的输出中搜索它多久会按名称提及这些竞争对手,并统计出一个数字,作为总回复数的一个比例,看它错误地提及竞争对手的频率是多少。

关于提及竞争对手这个问题,一个好处是它是一个客观的指标,意味着要么提到了竞争对手,要么没有。对于客观标准,你可以编写代码来检查这种特定错误发生的频率。

但因为 LLM 输出的是自由文本,你想要评估这个输出的标准中,也总会有一些更主观的,很难仅仅通过编写代码来输出一个非黑即白的分数。在这种情况下,使用 LLM 作为评判者(LLM as a judge)是一种评估输出的常用技术。

例如,如果你正在构建一个研究代理来对不同主题进行研究,那么你可以使用另一个 LLM,并提示它,比如说:“请为以下文章评定一个1到5分的质量分数,其中1分最差,5分最好。” 这里,我用一个 Python 表达式来表示把生成的文章复制粘贴到这里。所以,你可以提示 LLM 阅读文章并给它评定一个质量分数。然后我会让研究代理写几篇不同的研究报告,例如,关于黑洞科学的最新发展,或者用机器人收割水果。在这个例子中,也许评判 LLM 给关于黑洞的文章评了3分,给关于机器人收割的文章评了4分。随着你努力改进你的研究代理,希望你能看到这些分数随着时间的推移而上升。

顺便说一下,事实证明 LLM 实际上并不那么擅长这种1到5分的评级。你可以试一试,但我个人倾向于不怎么使用这种技术。但在后面的模块中,你会学到一些更好的技术,让 LLM 输出比要求它在1到5分制上输出分数更准确的分数,尽管有些人会这样做,可能作为一种初步的“LLM 作为评判者”类型的评估。

为了预告一下你将在本课程后面学到的一些 Agentic AI 评估方法:你已经听我谈过如何编写代码来评估客观标准,比如是否提到了竞争对手;或者使用 LLM 作为评判者来评估更主观的标准,比如一篇文章的质量。但之后,你会学到两种主要的评估类型:一种是端到端评估,你衡量整个代理的输出质量;以及组件级评估,你可能衡量 agentic 工作流中单个步骤的输出质量。事实证明,这些对于推动你开发过程的不同部分都很有用。

我经常做的另一件事是,检查中间输出,有时我们称之为 LLM 的“轨迹”(traces),以了解它在哪些方面没有达到我的期望。我们称之为错误分析,即我们通读每一步的中间输出,试图发现改进的机会。事实证明,能够进行评估和错误分析是一项非常关键的技能。所以我们将在本课程的第四个模块中对此有更多的阐述。

我们即将结束第一个模块。在继续之前,我只想与你分享我认为构建 agentic 工作流最重要的设计模式。让我们在下一个视频中看看它们。

1.7 Agentic 设计模式

我们通过将构建模块组合在一起,以序列化这些复杂的工作流来构建 agentic 工作流。在这个视频中,我想与你分享一些关键的设计模式,这些模式是关于你如何思考将这些构建模块组合成更复杂工作流的方法。让我们来看一看。

我认为构建 agentic 工作流的四个关键设计模式是:反思(reflection)、工具使用(tool-use)、规划(planning)和多代理协作(multi-agent collaboration)。让我简要介绍一下它们的含义,然后我们实际上会在课程的后面深入探讨其中的大部分内容。

1. 反思 (Reflection)

第一个主要的设计模式是反思。我可能会让一个 LLM 代理编写代码,结果 LLM 可能会生成像这样的代码。它在这里定义了一个 Python 函数来执行某个任务。然后我可以构建一个这样的提示:“这里是为某个任务编写的代码”,然后把 LLM 刚刚输出的内容复制粘贴到这个提示中。接着我让它“仔细检查代码的正确性、风格和效率,并给出建设性的批评”。事实证明,用这种方式提示的同一个 LLM 模型可能能够指出代码中的一些问题。如果我再把这个批评反馈给模型说:“看起来这里有个 bug,你能修改代码来修复它吗?” 那么它实际上可能会给出一个更好版本的代码。

预告一下工具使用,如果你能运行代码并看到代码在哪里失败,那么将这个信息反馈给 LLM 也能促使它迭代并生成一个好得多的,比如说,v3(第三版)的代码。所以,反思是一种常见的设计模式,你可以让 LLM 检查它自己的输出,或者可能引入一些外部信息源,比如运行代码看看是否会产生任何错误信息,并以此作为反馈再次迭代,从而得出其输出的一个更好版本。这种设计模式并非魔术,它不会导致所有事情百分之百成功,但有时它能很好地提升你系统的性能。

现在,我把它画得好像是我在提示单个 LLM,但为了预示多代理工作流,你也可以想象不是让同一个模型自我批评,而是可以有一个“批评家代理”。它就是一个被提示了类似指令的 LLM:“你的角色是批评代码,这里是为某个任务准备的代码,请仔细检查代码等等。” 第二个批评家代理可能会指出错误或运行单元测试。通过让两个模拟的代理(每个代理都只是一个被提示扮演特定角色的 LLM)来回交互,你可以让它们进行迭代,从而得到更好的输出。

2. 工具使用 (Tool Use)

除了反思模式,第二个重要的设计模式是工具使用。如今,LLM 可以被赋予工具,即它们可以调用的函数,以便完成工作。例如,如果你问一个 LLM:“根据评论者的说法,最好的咖啡机是什么?” 并给它一个网络搜索工具,那么它实际上可以搜索互联网来找到好得多的答案。或者一个代码执行工具,如果你问一个数学问题,比如:“如果我投资100美元并获得复利,最后我会有多少钱?” 那么它可以编写并执行代码来计算答案。

如今,不同的开发者已经给了 LLM 许多不同的工具,涵盖了从数学或数据分析,到通过从网络或各种数据库获取信息来收集信息,再到与生产力应用(如电子邮件、日历等)交互,以及处理图像等等。LLM 能够决定使用什么工具(即调用什么函数),这让模型能够完成更多的工作。

3. 规划 (Planning)

四个设计模式中的第三个是规划。这是一个来自一篇名为 Hugging GPT 的论文的例子。在这个例子中,如果你要求一个系统:“请生成一张图片,一个女孩在读书,姿势和一个男孩在图片中的姿势相同,然后请用你的声音描述新图片。” 那么一个模型可以自动决定,要执行这个任务,它首先需要找到一个姿态确定模型来弄清楚男孩的姿态;然后进行姿态到图像的转换,生成一个女孩的图片;接着是图像到文本的转换;最后是文本到语音的转换。

所以在规划中,LLM 决定了它需要采取的行动序列。在这种情况下,它是一个 API 调用的序列,以便它能够按正确的顺序执行正确的步骤序列,从而完成任务。所以,不是由开发者预先硬编码步骤序列,而是让 LLM 自己决定要采取哪些步骤。今天能够进行规划的代理更难控制,也更具实验性,但有时它们能给出非常令人惊喜的结果。

4. 多代理工作流 (Multi-agent Workflows)

最后是多代理工作流。就像一个人类经理可能会雇佣一些人来共同完成一个复杂的项目一样,在某些情况下,你可能会考虑雇佣一组多个代理,每个代理可能专注于不同的角色,并让它们共同协作来完成一个复杂的任务。

你在这里左边看到的图片来自一个名为 ChatDev 的项目,这是一个由钱晨(Chen Qian)及其合作者创建的软件框架。在 ChatDev 中,多个具有不同角色的代理,如首席执行官、程序员、测试员、设计师等,像一个虚拟软件公司一样协同工作,可以协作完成一系列软件开发任务。

让我们考虑另一个例子。如果你想写一本营销手册,你可能会考虑雇佣一个三人团队,比如一个研究员做在线研究,一个营销人员撰写营销文案,最后是一个编辑来编辑和润色文本。所以,类似地,你可能会考虑构建一个多代理工作流,其中你有一个模拟的研究代理,一个模拟的营销代理,和一个模拟的编辑代理,它们共同来为你执行这个任务。多代理工作流更难控制,因为你并不总能提前知道代理们会做什么,但研究表明,对于许多复杂的任务,包括像写传记或决定在棋局中下哪一步棋这样的事情,它们可以带来更好的结果。你也会在本课程的后面学到更多关于多代理工作流的内容。

那么,希望你现在对 agentic 工作流能做什么,以及找到构建模块并将它们(或许通过这些设计模式)组合在一起以实现 agentic 工作流所面临的关键挑战,有了一个概念。当然,还有开发评估方法,这样你就能看到你的系统表现如何,并不断改进它。

在下一个模块中,我想与你深入探讨这些设计模式中的第一个,即反思。你会发现,这是一种实现起来可能出乎意料地简单,但有时能给你的系统性能带来非常好的提升的技术。那么,让我们进入下一个模块,学习反思设计模式。

模块二:反思设计模式

2.1 通过反思改进任务输出

反思设计模式是我在许多应用中使用过的一种方法,而且它的实现惊人地简单。让我们来看一看。

正如人类有时会反思自己的成果并找到改进的方法一样,大型语言模型(LLM)也可以。例如,我可能会写这样一封电子邮件,如果我打字很快,我可能会写出一份不太好的初稿。如果我通读一遍,我可能会说:“嗯,‘下个月’这个说法对于 Tommy 什么时候有空吃晚饭来说不够清楚”,而且我还有一个拼写错误,也忘了署名。这会让我修改草稿,说得更具体一些:“嘿,Tommy,你 5 号到 7 号有空吃晚饭吗?”

类似的过程也能让 LLM 改进它们的输出。你可以提示一个 LLM 写出邮件的初稿,得到邮件版本1(email v1)后,你可以把它传递给也许是同一个模型,同一个大型语言模型,但使用不同的提示,告诉它进行反思并写一个改进的第二稿,从而得到最终的输出,即邮件版本2(email v2)。在这里,我只是硬编码了这个工作流:提示 LLM 一次,然后再次提示它进行反思和改进,从而得到邮件 v2。

事实证明,类似的过程可以用来改进其他类型的输出。例如,如果你让一个 LLM 编写代码,你可能会提示它为某个任务编写代码,它可能会给你代码的 v1 版本。然后,你可以将它传递给同一个或另一个 LLM,要求它检查错误并编写一个改进的代码第二稿。不同的 LLM 有不同的优势,所以我有时会为撰写初稿和进行反思改进选择不同的模型。例如,事实证明,推理模型(有时也称为思考模型)非常擅长发现错误,所以我有时会通过直接生成来编写代码的初稿,但随后使用一个推理模型来检查错误。

现在,事实证明,如果你能获得外部反馈,即来自 LLM 外部的新信息,而不仅仅是让 LLM 反思代码,那么反思会变得更加强大。在代码的例子中,你可以做的一件事就是直接执行代码,看看代码做了什么。通过检查输出,包括代码的任何错误信息,这对于 LLM 反思并找到改进其代码的方法来说,是极其有用的信息。

所以在这个例子中,LLM 生成了代码的初稿,但当我运行它时,它产生了一个语法错误。当你将这个代码输出和错误日志传回给 LLM,并要求它根据反馈进行反思并撰写新稿时,这给了它大量非常有用的信息,从而能够得出一个好得多的代码版本2。

所以,反思设计模式并非魔术。它不会让 LLM 每次都百分之百地做对所有事情,但它通常能给性能带来适度的提升。但需要记住的一个设计考虑是,当有新的、额外的外部信息可以被纳入反思过程时,反思会变得更加强大。所以在那个例子中,如果你能运行代码,并将代码输出或错误信息作为反思步骤的额外输入,那确实能让 LLM 更深入地反思,并找出可能出了什么问题(如果有的话),从而产生一个比没有这些可供吸收的外部信息时好得多的代码第二版。所以要记住一点,每当反思有机会获得额外信息时,它都会变得更加强大。

现在,让我们进入下一个视频,我想与你分享一个更系统的比较,关于使用反思与直接生成(我们有时称之为零样本提示)的对比。让我们进入下一个视频。

2.2 为什么不直接生成?

让我们来看一看,为什么我们可能更倾向于使用反思工作流,而不是仅仅提示一次 LLM,让它直接生成答案然后就此结束。

使用直接生成时,你只需用一条指令来提示 LLM,然后让它生成一个答案。所以你可以要求一个 LLM 写一篇关于黑洞的文章,然后让它直接生成文本;或者让它编写计算复利的 Python 函数,然后让它直接写出代码。你在这里看到的提示示例也被称为零样本提示(zero-shot prompting)。

让我解释一下“零样本”是什么意思。与零样本提示相对的一种相关方法是,在你的提示中包含一个或多个你希望输出看起来像的例子。这被称为单样本提示(one-shot prompting),如果你在提示中包含了一个期望的输入输出对的例子;或者双样本或少样本提示(two-shot or few-shot prompting),取决于你在提示中包含了多少这样的例子。因此,零样本提示指的是如果你包含了零个例子,也就是不包含任何你想要的期望输出的例子。但如果你还不熟悉这些术语,也别担心。重要的是,在你看到的这些例子中,你只是提示 LLM 一次性直接生成答案,我也称之为零样本提示,因为我们包含了零个例子。

事实证明,多项研究表明,在各种任务上,反思都能提升直接生成的性能。这张图改编自 Madaan 等人的研究论文,它展示了一系列不同的任务,在有和没有反思的情况下,使用不同模型实现的结果。解读这张图的方法是看这些相邻的浅色条和深色条对,其中浅色条显示的是零样本提示,深色条显示的是同一模型但带有反思。蓝色、绿色和红色的颜色显示了使用不同模型(如 GPT-3.5 和 GPT-4)进行的实验。你所看到的是,对于许多不同的应用,深色条(即带有反思)比浅色条要高出不少。但当然,具体到你的应用,你的情况可能会有所不同。

这里还有一些反思可能有所帮助的例子。

  • 生成结构化数据:如果你在生成结构化数据,比如一个 HTML 表格,有时输出的格式可能会不正确。所以一个验证 HTML 代码的反思提示可能会有帮助。如果是基础的 HTML,这可能帮助不大,因为 LLM 对基础 HTML 已经很擅长了。但特别是如果你有更复杂的结构化输出,比如一个有很多嵌套的 JSON 数据结构,那么反思就更有可能发现错误。
  • 生成指令序列:或者,如果你要求一个 LLM 生成一系列构成指令的步骤,比如如何冲泡一杯完美的茶,有时 LLM 可能会遗漏步骤,一个要求检查指令的连贯性和完整性的反思提示可能有助于发现错误。
  • 创意性任务:还有一些我实际做过的事情,就是使用 LLM 来生成域名,但有时它生成的名字有意外的含义或者很难发音。所以我用过反思提示来再次检查域名是否有任何有问题的内涵或意义,或者名字是否难读。我们实际上在我的一个团队 AI Fund 中用这个方法来为我们正在做的创业公司头脑风暴域名。

我想给你看几个反思提示的例子。

  • 为头脑风暴域名:你可能会要求它“审查你建议的域名”,然后要求它“检查每个名字是否容易发音”,“检查每个名字在英语或其他语言中是否可能有负面含义”,然后“输出一个只包含满足这些标准的名字的简短列表”。
  • 为改进电子邮件:你可以写一个反思提示,告诉它“审查邮件初稿”,“检查语气”,“验证所有陈述的事实和承诺是否准确”(这在 LLM 被输入了大量事实和日期等信息以撰写邮件草稿的背景下是有意义的,所有这些都会作为 LLM 上下文的一部分提供),然后“根据它可能发现的任何问题,撰写邮件的下一稿”。

所以,这里有一些编写反思提示的技巧。明确指出你希望它“审查”或“反思”输出的初稿,这很有帮助。如果你能指定一套明确的标准,比如域名是否易于发音、是否有负面含义,或者对于邮件,检查语气和验证事实,那么这能更好地引导 LLM 在你最关心的标准上进行反思和批判。我发现,我学会写出更好提示的方法之一,就是阅读大量其他人写的提示。有时我甚至会下载开源软件,去找到我认为做得特别好的软件中的提示,就为了去读读作者们写的提示。

希望你现在对如何编写一个基本的反思提示有了一定的了解,甚至可能会在你自己的工作中尝试一下,看看它是否能帮助你获得更好的性能。在下一个视频中,我想与你分享一个有趣的例子,我们将开始研究多模态的输入和输出。我们会让一个算法反思一个正在生成的图像或图表。让我们去看一看。

2.3 图表生成工作流

在本模块你将看到的编码实验中,你会体验一个图表生成工作流,在其中你使用一个代理来生成漂亮的图表。事实证明,反思可以显著提高这种输出的质量。让我们来看一看。

在这个例子中,我有一台咖啡机的数据,显示了拿铁、咖啡、热巧克力、卡布奇诺等不同饮品的销售时间以及价格。我们想让一个代理创建一个图表,比较2024年和2025年第一季度的咖啡销售情况。

一种方法是编写一个提示,要求一个 LLM“使用存储在电子表格(CSV文件,即逗号分隔值文件)中的数据,创建一个比较2024年和2025年第一季度咖啡销售情况的图表”。一个 LLM 可能会写出像这样的 Python 代码来生成图表。使用这个 v1 版本的代码,如果你执行它,它可能会生成一个像这样的图表。当我运行 LLM 输出的代码时,它第一次就生成了这个。这是一个堆叠条形图,这并不是一种非常容易可视化的方式,而且这个图看起来不太好。

但你可以做的是,将代码的 v1 版本以及这段代码生成的图表,都提供给一个多模态模型——也就是一个也能接受图像输入的 LLM——然后要求它检查这段代码生成的图像,接着对图像进行批判,找到一种方法来提出更好的可视化方案,并更新代码以生成一个更清晰、更好的图表。多模态 LLM 可以使用视觉推理,所以它实际上可以从视觉上审视图表,以找到改进它的方法。当我这样做时,它实际上生成了一个条形图,不是那种堆叠条形图,而是一种更常规的条形图,它将2024年和2025年的咖啡销售分开,我认为这种方式更美观、更清晰。当你进入编码实验时,请随意尝试这些问题,看看你是否能得到比这些更好看的图表。

因为不同的 LLM 有不同的优点和缺点,我有时会为初始生成和反思使用不同的 LLM。例如,你可能会用一个 LLM 来生成初始代码,也许是像 GPT-4o 或 GPT-5 这样的模型,然后用一个像这样的提示来让它编写 Python 代码生成可视化等等。然后,反思的提示可能是这样的,你告诉 LLM 扮演一个“提供建设性反馈的专家数据分析师”的角色,然后给它代码的版本1,即生成的部分,也许还有代码生成过程中的计算历史,并要求它根据特定的标准进行批判。记住,当你给出像“可读性”、“清晰度”和“完整性”这样的具体标准时,它能帮助 LLM 更好地弄清楚该做什么。然后要求它编写新的代码来实现你的改进。

你可能会发现的一件事是,有时使用一个推理模型进行反思,可能比使用一个非推理模型效果更好。所以,当你为初始生成和反思尝试不同的模型时,这些都是你可能需要调整或尝试不同组合的配置。

所以,当你进入编码实验时,我希望你在可视化咖啡销售数据时玩得开心。现在,当你构建一个应用时,你可能会想,反思是否真的能提高你特定应用的性能?从各种研究来看,反思在某些应用上能稍微提高性能,在另一些应用上能大幅提高,而在其他一些应用上可能几乎没有任何提升。因此,了解它对你应用的影响会很有用,这也能指导你如何调整初始生成或反思的提示,以尝试获得更好的性能。在下一个视频中,让我们来看一看针对反思工作流的评估(evals)。让我们进入下一个视频。

2.4 评估反思的影响

反思通常能提高系统的性能,但在我决定保留它之前,我通常会想再次确认它到底能提升多少性能,因为它确实需要一个额外的步骤,会稍微拖慢系统。让我们来看一看针对反思工作流的评估。

让我们看一个使用反思来改进 LLM 编写的数据库查询的例子,这个查询用于获取数据来回答问题。假设你经营一家零售店,你可能会收到这样的问题:“哪种颜色的产品总销售额最高?” 要回答这样的问题,你可能会让一个 LLM 生成一个数据库查询。如果你听说过像 SQL 这样的数据库语言,它可能会生成那种语言的查询。但如果你不熟悉 SQL,也别担心。但是在编写了数据库查询后,你可能不会直接用它从数据库中获取信息,而是让一个 LLM(同一个或不同的 LLM)反思版本一的数据库查询,并将其更新为可能改进过的版本,然后对数据库执行那个查询以获取信息,最后让一个 LLM 来回答问题。

所以问题是,使用第二个 LLM 来反思和改进数据库或 SQL 查询,是否真的能改善最终的输出?

为了评估这一点,我可能会收集一组问题或提示,以及它们的标准答案。所以可能有一个问题是:“2025年5月卖出了多少件商品?”“库存中最贵的商品是什么?”“我的店里有多少种款式?” 然后我为大约10到15个提示写下标准答案。

然后,你可以运行这个不带反思的工作流。不带反思意味着,取第一个 LLM 生成的 SQL 查询,然后直接看它给出了什么答案。而带反思则意味着,取第二个 LLM 反思后生成的数据库查询,看看它从数据库中获取了什么答案。然后我们可以测量在没有反思和有反思的情况下,正确答案的百分比。在这个例子中,没有反思时,答案的正确率为87%,而有反思时,正确率为95%。这表明,反思正在有意义地提高我能得到的数据库查询的质量,从而提取出正确的答案。

开发者们通常还会做的一件事是重写反思提示。例如,你是否想在反思提示中加入一条指令,让数据库查询运行得更快或更清晰?或者你可能对如何重写初始生成提示或反思提示有不同的想法。一旦你建立了像这样的评估体系,你就可以快速尝试关于这些提示的不同想法,并在你改变提示时测量你系统的正确率,从而了解哪些提示对你的应用效果最好。所以,如果你在尝试很多提示,建立评估体系是很重要的。它真的能帮助你有一种系统性的方法,来在你可能考虑的不同提示之间做出选择。

但这个例子是在你可以使用客观评估的情况下,因为有一个正确的答案。卖出的商品数量是1301件,答案要么对要么错。那么对于需要更主观而非客观评估的应用呢?

在我们上一个视频中看到的绘图例子里,没有反思我们得到了堆叠条形图,有反思我们得到了这个图。但我们怎么知道哪个图实际上更好呢?我知道我更喜欢后一个,但对于在不同维度上变化的各种图表,我们如何判断哪个更好?衡量这些图中哪个更好,更多的是一个主观标准,而不是一个纯粹的黑白分明的客观标准。

所以对于这些更主观的标准,你可以做的一件事是使用一个 LLM 作为评判者。也许一个基本的方法是,将两个图都输入到一个 LLM 中,一个可以接受两张图片作为输入的多模态 LLM,然后直接问它哪张图片更好。事实证明,这样做效果不是很好。我稍后会分享一个更好的主意。但你可以做的一件事可能是,也给它一些评估这两个图的标准,比如清晰度、美观度等等。

但事实证明,使用 LLM 来比较两个输入并告诉你哪个更好,存在一些已知的问题。首先,事实证明答案通常不是很好。它可能对作为评判者的 LLM 的提示的确切措辞很敏感,而且有时排名顺序与人类专家的判断并不十分吻合。这方面的一个表现是,许多 LLM 会有位置偏见。事实证明,许多 LLM 通常会更频繁地选择第一个选项而不是第二个选项。实际上,我用过的很多 LLM,给定两个选择,无论我把哪个选择放在前面,它都会说第一个选择更好。也许有些 LLM 偏爱第二个选项,但我认为大多数 LLM 偏爱第一个选项。

与其让一个 LLM 比较一对输入,不如使用评分标准进行评分能得到更一致的结果。例如,你可以提示一个 LLM,告诉它:“给定一张图片,根据质量评分标准评估附上的图片。” 这个评分标准或评分准则可能包含明确的标准,比如:图表是否有清晰的标题?坐标轴标签是否存在?图表类型是否合适?等等,包含几个类似这样的标准。事实证明,与其让 LLM 在1到5的等级上给某样东西打分(它在这方面往往校准得不好),不如给它比如说5个二元标准,5个0-1标准,让它给出5个二元分数,然后你把这些分数加起来得到一个从1到5的数字,或者如果你有10个二元标准,就是从1到10,这样做往往能得到更一致的结果。

因此,如果我们收集一些(比如10-15个)用户关于他们可能希望看到的咖啡机销售数据可视化的查询,那么你可以让它在没有反思的情况下生成图像,或者在有反思的情况下生成图像,然后用这样的评分标准给每张图像打分,从而检查有反思生成的图像在多大程度上或是否真的比没有反思生成的要好。然后,一旦你建立了这样一套评估体系,如果你想改变初始生成提示或反思提示,你也可以重新运行这个评估,看看比如说更新你的一个提示是否能让系统生成根据这个评分标准得分更高的图像。所以这也给了你一种方法,可以不断调整你的提示,以获得越来越好的性能。

你在为反思或其他 agentic 工作流构建评估时可能会发现,当存在客观标准时,基于代码的评估通常更容易管理。在我们看到的数据库查询的例子中,我们建立了一个标准答案和标准输出的数据库,然后直接编写代码来看系统生成正确答案的频率,这是一个非常客观的评估指标。相比之下,对于小型的主观任务,你可能会使用一个 LLM 作为评判者,但这通常需要多一点的调整,比如需要思考你可能想用什么评分标准来让作为评判者的 LLM 被很好地校准,或者输出可靠的评估结果。

希望这能让你对如何构建评估来评价反思,或者更普遍地,评价不同的 agentic 工作流,有了一定的了解。知道如何做好评估,对于你如何有效地构建 agentic 工作流非常重要,你也会在后面的视频中听到我更多地谈论这一点。但现在你已经对如何使用反思有了一定的了解,我希望在下一个视频中深入探讨它的一个方面,那就是当你能从外部获得额外信息时,这会使反思的效果好得多。所以在本模块的最后一个视频中,让我们来看一看那个能让你的反思工作流效果好得多的技术。我们下一个视频见。

2.5 使用外部反馈

带有外部反馈的反思,如果你能得到的话,比仅使用 LLM 作为唯一反馈来源的反思要强大得多。让我们来看一看。

当我构建一个应用时,如果我只是为直接生成(即零样本提示)进行提示工程,随着时间的推移,性能可能是这样的:一开始,随着我调整提示,性能会提升一段时间,但过了一段时间后,它就趋于平稳或停滞不前了,尽管我进一步设计提示,也很难再获得更好的性能水平。

所以,与其把所有时间都浪费在调整提示上,不如早一点在流程中开始加入反思,有时这会给性能带来一次提升。有时提升较小,有时较大,但这增加了复杂性。但如果我在流程的这个节点开始加入反思,然后开始调整反思提示,那么我最终得到的性能可能就是这样。但事实证明,如果我能获得外部反馈,使得新信息的来源不仅仅是 LLM 对它之前已有的相同信息进行反思,而是有一些新的外部信息,那么有时,随着我继续调整提示和外部反馈,你最终会得到一个高得多的性能水平。

所以,如果你正在进行提示工程,并且你觉得你的努力正在看到递减的回报,你调整了很多提示,但性能就是没有变得更好,那么可以考虑一下是否可以加入反思,或者更好的是,是否有某种外部反馈可以注入,从而让性能曲线摆脱那条趋于平缓的红线,走向一个可能更高的性能提升轨道。

提醒一下,我们之前看到,如果你在编写代码,一个反馈来源就是,如果你直接执行代码,看看它会生成什么输出——无论是输出结果还是错误信息——然后将该输出反馈给 LLM,让它获得新的信息进行反思,然后利用这些信息来编写新版本的代码。

这里还有几个例子,说明软件代码或工具何时可以创建新信息来帮助反思过程。

  • 模式匹配:如果你使用 LLM 来写邮件,而它有时会提到竞争对手的名字,那么如果你编写代码或构建一个软件工具来进行模式匹配(也许通过正则表达式模式匹配)来搜索输出中的竞争对手名字,那么每当你找到一个竞争对手的名字,你就把它作为批评或输入反馈给 LLM。这是非常有用的信息,可以告诉它在不提及那些竞争对手的情况下重写文本。
  • 事实核查:另一个例子,你可以使用网络搜索或查看其他可信来源来对一篇文章进行事实核查。所以,如果你的研究代理说“泰姬陵建于1648年”,技术上讲,泰姬陵实际上是在1631年受命建造,并于1648年完工。所以也许这不完全是错的,但它也没有准确地反映历史。为了更准确地表述这座美丽建筑的建造时间,如果你进行一次网络搜索,找到一段准确解释泰姬陵建造时期的片段,并将其作为额外的输入提供给你的反思代理,那么它也许能够利用这些信息来写出一个关于泰姬陵历史的更好版本的文本。
  • 约束检查:最后一个例子,如果你使用 LLM 来撰写文案,也许是为了一篇博客文章或一篇研究论文的摘要,但它写的内容有时会超过字数限制。LLM 在遵守确切的字数限制方面仍然不是很好。那么,如果你实现一个字数统计工具,就是编写代码来计算确切的单词数量,如果它超过了字数限制,那么就把这个字数反馈给 LLM,并让它再试一次。这有助于它更准确地达到你希望它生成的输出的期望长度。

在这三个例子中,你都可以编写一段代码来帮助找到关于初始输出的额外事实,然后将这些事实——无论是你找到了竞争对手的名字,还是网络搜索到的信息,或者是确切的字数——提供给进行反思的 LLM,以帮助它更好地思考如何改进输出。

反思是一个强大的工具,我希望你在自己的许多工作中都能发现它的用处。在下一个模块中,我们将在此基础上讨论工具使用,在那里,除了你看到的少数几个工具例子外,你将学会如何系统地让你的 LLM 调用不同的函数,这将使你的 agentic 应用变得更加强大。希望你喜欢学习关于反思的内容。我现在要反思一下你刚刚学到的东西。希望在下一个视频中见到你。

模块三:工具使用

3.1 什么是工具?

在本模块中,你将学习大型语言模型(LLM)的工具使用,这意味着让你的 LLM 决定何时可能需要请求调用一个函数来执行某些操作、收集一些信息或做其他事情。就像我们人类使用工具能比徒手做更多的事情一样,LLM 在获得工具后也能做更多的事情。不过,我们给 LLM 的工具不是锤子、扳手和钳子,而是函数,让它能够请求调用,从而完成更多任务。让我们来看一看。

如果你问一个可能在数月前训练好的 LLM:“现在几点了?” 那个训练好的模型并不知道确切的时间,所以它很可能会回答:“抱歉,我无法获取当前时间。” 但是,如果你编写一个函数并让 LLM 能够访问这个函数,那么它就能给出一个更有用的答案。

当我们让 LLM 调用函数,或者更准确地说,让 LLM 请求调用函数时,这就是我们所说的“工具使用”,而工具就是我们提供给 LLM、可供其请求调用的函数。

具体来说,工具使用是这样工作的。在这个例子中,我将把上一张幻灯片中展示的 getCurrentTime 函数提供给 LLM。当你接着提示它“现在几点了?”时,LLM 可以决定调用 getCurrentTime 函数。该函数将返回当前时间,这个时间随后会作为对话历史的一部分反馈给 LLM,最后 LLM 就可以输出,比如说,“现在是下午3点20分”。

所以,步骤顺序是:首先有输入提示。在这种情况下,LLM 查看可用的工具集(本例中只有一个工具),并决定调用该工具。这个工具是一个函数,它会返回一个值,该值被反馈给 LLM,然后 LLM 最终生成它的输出。

现在,工具使用的一个重要方面是,我们可以让 LLM 自行决定是否使用任何工具。所以在同样的设置下,如果我问它:“绿茶里有多少咖啡因?” LLM 不需要知道当前时间来回答这个问题,所以它可以直接生成答案:“绿茶通常含有这么多咖啡因”,并且它在这样做的时候没有调用 getCurrentTime 函数。

在我的幻灯片中,我将使用 LLM 上方带有虚线框的这个标记,来表示我们正在向 LLM 提供一组工具,供其在认为合适时选择使用。这与你在之前视频中看到的一些例子相反,在那些例子中,我作为开发者硬编码了,例如,在研究代理的某个特定点上总是进行网络搜索。相比之下,getCurrentTime 函数的调用并不是硬编码的,而是由 LLM 自行决定是否要请求调用 getCurrentTime 函数。再次强调,我们将使用这个虚线框标记来表示我们何时向 LLM 提供一个或多个工具,由 LLM 来决定它想调用哪些工具(如果有的话)。

这里还有一些工具使用可能帮助基于 LLM 的应用生成更好答案的例子:

  • 网络搜索:如果你问它:“你能找一些在加州山景城附近的意大利餐厅吗?” 如果它有一个网络搜索工具,那么 LLM 可能会选择调用一个网络搜索引擎来查询“加州山景城附近的餐厅”,并使用获取到的结果来生成输出。
  • 数据库查询:如果你经营一家零售店,并且希望能够回答像“给我看看购买了白色太阳镜的顾客”这样的问题,如果你的 LLM 被赋予了访问查询数据库工具的权限,那么它可能会在销售表中查找哪些条目是销售了一副白色太阳镜的,然后用这个信息来生成输出。
  • 计算:最后,如果你想进行利率计算:“如果我存入500美元,利率为5%,10年后我会得到多少钱?” 如果你恰好有一个利率计算工具,那么它就可以调用利率计算函数来计算出结果。或者,事实证明,你稍后会看到的一种方法是,让 LLM 编写代码,比如写一个这样的数学表达式,然后对它求值,这将是另一种让 LLM 计算出正确答案的方式。

因此,作为开发者,你需要思考你希望应用真正做什么样的事情,然后创建所需的函数或工具,并将它们提供给 LLM,让它能够使用适当的工具来完成任务,比如餐厅推荐器、零售问答系统或金融助手可能需要做的事情。所以,根据你的应用,你可能需要实现并向你的 LLM 提供不同的工具。

到目前为止,我们看过的大多数例子都只向 LLM 提供了一个工具或一个函数。但在许多用例中,你会希望向 LLM 提供多个工具或多个函数,供其选择调用哪一个(或不调用)。例如,如果你正在构建一个日历助手代理,你可能希望它能够满足这样的请求:“请在我的日历上找一个周四的空闲时段,并与 Alice 安排一个约会。”

在这个例子中,我们可能会向 LLM 提供一个用于“安排约会”(即发送日历邀请)的工具或函数,一个用于“检查日历”以查看我何时有空的工具,以及一个用于“删除约会”(如果它想取消现有的日历条目)的工具。因此,给定这些指令,LLM 首先会决定,在可用的不同工具中,它可能应该首先使用“检查日历”。所以它会调用一个 check_calendar 函数,该函数将返回我周四的空闲时间。基于这些信息(它们会被反馈给 LLM),它然后可以决定下一步是选择一个时间段,比如说下午3点,然后调用 make_appointment 函数来向 Alice 发送一个日历邀请,并将其添加到我的日历中。该操作的输出(希望是一个确认日历条目已成功发送的通知)被反馈给 LLM,最后,LLM 可能会告诉我:“你与 Alice 的约会已经安排在周四下午3点。”

能够让你的 LLM 访问工具是一件非常重要的事情。它将使你的应用变得更加强大。在下一个视频中,我们将看一看如何编写函数,如何创建工具,然后将它们提供给你的 LLM。让我们进入下一个视频。

3.2 创建一个工具

一个 LLM 决定调用函数的过程,一开始可能看起来有点神秘,因为 LLM 被训练的目的只是生成输出文本或输出文本的 token。那么这是如何工作的呢?在这个视频中,我想与你一步步地走过,让一个 LLM 能够调用函数的过程到底是什么样的。让我们来看一看。

所以,工具只是 LLM 可以请求执行的代码或函数,就像我们在上一个视频中看到的 getCurrentTime 函数一样。现在,当今领先的 LLM 都被直接训练来使用工具,但我想和你一起走一遍,如果你必须自己编写提示来告诉它何时使用工具,那会是什么样子。这是我们在 LLM 被直接训练来使用工具之前的早期时代必须做的事情。尽管我们现在不再完全这样做,但这希望能让你更好地理解这个过程,我们将在下一个视频中讲解更现代的语法。

如果你已经实现了这个 getCurrentTime 函数,那么为了把这个工具给 LLM,你可能会写一个像这样的提示。你可能会告诉它:“LLM,你可以访问一个名为 getCurrentTime 的工具。要使用它,我希望你打印出以下文本:全大写的 FUNCTION,然后打印出 getCurrentTime。如果我看到这个文本,即全大写的 FUNCTIONgetCurrentTime,我就知道你想让我为你调用 getCurrentTime 函数。”

当一个用户问:“现在几点了?” LLM 就会意识到它需要调用或请求调用 getCurrentTime 函数。所以 LLM 就会输出它被告知的内容,它会输出“FUNCTION: getCurrentTime”。现在,我必须已经写好代码来检查 LLM 的输出,看是否存在这个全大写的 FUNCTION。如果存在,那么我需要提取出 getCurrentTime 这个参数,来弄清楚 LLM 想调用哪个函数。然后我需要编写代码来实际调用 getCurrentTime 函数,并提取出输出,比如说,是早上8点。然后,是开发者编写的代码,也就是我的代码,必须把早上8点这个时间反馈给 LLM,作为对话历史的一部分。当然,对话历史包括了最初的用户提示、请求是函数调用的事实等等。最后,LLM 在知道了之前发生的一切——用户提问,它请求函数调用,然后我调用了函数并返回了早上8点——之后,最终可以查看所有这些信息并生成最终的回复,即“现在是早上8点”。

所以要明确一点,为了调用一个函数,LLM 并不直接调用函数。相反,它会以一种特定的格式输出一些内容,比如这样,来告诉我需要为 LLM 调用这个函数,然后告诉 LLM 它请求的函数输出了什么。

在这个例子中,我们只给了 LLM 一个函数,但你可以想象,如果我们给了它三四个函数,我们可以告诉它输出全大写的 FUNCTION,然后是它想调用的函数名,甚至可能还有这些函数的一些参数。实际上,现在让我们来看一个稍微复杂一点的例子,其中 getCurrentTime 函数接受一个时区作为参数,用于获取你想要的那个时区的当前时间。

对于第二个例子,我写了一个函数,用于获取指定时区的当前时间,这里的时区是 getCurrentTime 函数的输入参数。所以为了让 LLM 使用这个工具来回答问题,比如“新西兰现在几点了?”(因为我的阿姨在那里,所以在给她打电话之前,我确实会查一下新西兰的时间),为了让 LLM 使用这个工具,你可能会修改系统提示,说:“你可以使用 getCurrentTime 工具来获取特定时区的时间。要使用它,请输出如下内容:getCurrentTime,然后包含时区。” 这是一个简化的提示,在实践中,你可能会在提示中加入更多细节,告诉它函数是什么,如何使用等等。

在这个例子中,LLM 会意识到它需要获取新西兰的时间,所以它会生成这样的输出:“FUNCTION: getCurrentTime(Pacific/Auckland)”。这是新西兰的时区,因为奥克兰是新西兰的一个主要城市。然后,我必须编写代码来搜索 LLM 的输出中是否出现了这个全大写的 FUNCTION,如果出现了,我就需要提取出要调用的函数。最后,我将调用 getCurrentTime 并传入指定的参数,这个参数是由 LLM 生成的,即 Pacific/Auckland,也许返回的是早上4点。然后像往常一样,我把这个信息反馈给 LLM,LLM 输出:“新西兰现在是早上4点。”

总结一下,让 LLM 使用工具的过程如下:

  1. 提供工具:你必须向 LLM 提供工具,即实现函数,然后告诉 LLM 它是可用的。
  2. LLM 请求调用:当 LLM 决定调用一个工具时,它会生成一个特定的输出,让你知道你需要为 LLM 调用这个函数。
  3. 执行并返回结果:然后你调用函数,得到它的输出,把你刚刚调用的函数的输出反馈给 LLM。
  4. LLM 继续执行:LLM 接着用这个信息来决定下一步做什么,在我们这个视频的例子中,就是直接生成最终的输出,但有时它甚至可能决定下一步是去调用另一个工具,然后这个过程继续。

现在,事实证明,这种全大写 FUNCTION 的语法有点笨拙。这是我们在 LLM 被原生训练或自己知道如何请求调用工具之前所做的事情。对于现代的 LLM,你不需要告诉它输出全大写的 FUNCTION,然后去搜索全大写的 FUNCTION 等等。相反,LLM 被训练来使用一种特定的语法,来非常清楚地请求它何时想要调用一个工具。在下一个视频中,我想与你分享,让 LLM 请求调用工具的现代语法到底是什么样的。让我们进入下一个视频。

3.3 工具语法

让我们来看一看如何编写代码,让你的 LLM 能够调用工具。这是我们旧的、不带时区参数的 getCurrentTime 函数。让我向你展示如何使用 AI Suite 开源库来让你的 LLM 调用工具。顺便说一下,技术上讲,正如你在上一个视频中看到的,LLM 并不调用工具,LLM 只是请求你调用工具。但在构建 agentic 工作流的开发者中,我们许多人偶尔会直接说“LLM 调用工具”,尽管技术上并非如此,但这只是一个更简短的说法。

这里的语法与 OpenAI 调用这些 LLM 的语法非常相似,只不过在这里,我使用的是 AI Suite 库,这是一个我和一些朋友开发的开源包,它使得调用多个 LLM 提供商变得容易。所以代码语法是这样的,如果这对你来说看起来很多,别担心,你会在编码实验中看到更多。但简而言之,这与 OpenAI 的语法非常相似,你写 response = client.chat.completions.create,然后选择模型,在这种情况下,我们使用 OpenAI 的模型 GPT-4o,messages=messages,假设你已经把想传递给 LLM 的消息放进了一个数组里,然后你会写 tools=,后面跟着一个你希望 LLM 能够访问的工具列表。在这种情况下,只有一个工具,就是 getCurrentTime

然后,别太担心 max_turns 这个参数。包含这个参数是因为,在一个工具调用返回后,LLM 可能会决定调用另一个工具,而在那个工具调用返回后,LLM 可能又会决定调用再一个工具。所以 max_turns 只是一个上限,限制你希望 LLM 在停止之前连续请求工具多少次,以避免可能出现的无限循环。在实践中,除非你的代码在做一些异常雄心勃勃的事情,否则你几乎永远不会达到这个限制。所以我不担心 max_turns 参数,我通常只把它设置为5,但在实践中,它影响不大。

事实证明,使用 AI Suite,getCurrentTime 函数会自动以一种适当的方式被描述给 LLM,使得 LLM 知道何时调用它。所以,你不需要手动编写一个长长的提示来告诉 LLM getCurrentTime 是做什么的,AI Suite 中的这个语法会自动完成。为了让它看起来不那么神秘,它的工作方式是,它实际上会查看与 getCurrentTime 相关联的文档字符串(docstring),也就是 getCurrentTime 中的这些注释,以便弄清楚如何向 LLM 描述这个函数。

所以,为了说明这是如何工作的,这里再次是那个函数,这里是使用 AI Suite 调用 LLM 的代码片段。在幕后,这会创建一个详细描述该函数的 JSON schema。右边的这个东西,就是实际传递给 LLM 的内容。具体来说,它会提取函数名,即 getCurrentTime,然后还有函数的描述,这个描述是从文档字符串中提取出来的,用来告诉 LLM 这个函数是做什么的,这让它能够决定何时调用它。有些 API 要求你手动构建这个 JSON schema,然后再把这个 JSON schema 传递给 LLM,但 AI Suite 包会自动为你完成这个工作。

来看一个稍微复杂一点的例子,如果你有这个更复杂的 getCurrentTime 工具,它还有一个输入的 time_zone 参数,那么 AI Suite 会创建这个更复杂的 JSON schema。和之前一样,它会提取出函数名 getCurrentTime,从文档字符串中提取出描述,然后还会识别出参数是什么,并根据左边这里显示的文档向 LLM 描述它们,这样当它生成调用工具的函数参数时,它就知道参数应该是像 America/New_YorkPacific/Auckland 或其他时区这样的东西。

所以,如果你执行左下角的这段代码片段,它将使用 OpenAI 的 GPT-4o 模型,看 LLM 是否想调用这个函数,如果想,它就会调用这个函数,从函数中获取输出,将输出反馈给 LLM,最多这样做五轮,然后返回响应。请注意,如果 LLM 请求调用 getCurrentTime 函数,AI Suite 或这个 client 会为你调用 getCurrentTime,所以你不需要自己显式地去做。所有这些都在你必须编写的这一个函数调用中完成了。需要注意的是,其他一些 LLM 接口的实现中,你必须手动完成那一步,但对于这个特定的包,所有这些都封装在这个 client.chat.completions.create 函数调用中了。

所以,你现在知道了如何让一个 LLM 调用函数了。我希望你在实验中玩得开心,当你为 LLM 提供几个函数,然后 LLM 决定去现实世界中采取行动,去获取更多信息来满足你的请求时,这真的很神奇。如果你以前没有玩过这个,我想你会觉得这非常酷。

事实证明,在所有你可以给 LLM 的工具中,有一个有点特殊,那就是代码执行工具。它被证明非常强大。如果你能告诉一个 LLM:“你可以编写代码,我会有一个工具为你执行那些代码”,因为代码可以做很多事情,所以当我们给一个 LLM 编写和执行代码的灵活性时,这被证明是给予 LLM 的一个极其强大的工具。所以代码执行是特殊的。让我们在下一个视频中讨论 LLM 的代码执行工具。

3.4 代码执行

在我参与过的几个 agentic 应用中,我给了 LLM 编写代码来执行我希望它完成的任务的选项。有好几次,我真的对它为了解决我的各种任务而生成的代码解决方案的巧妙之处感到惊讶和欣喜。所以,如果你不怎么使用代码执行,我想你可能会对它能让你的 LLM 应用做什么感到惊讶和欣喜。让我们来看一看。

让我们以构建一个可以输入数学应用题并为你解答的应用为例。你可能会创建一些工具,用来做加法、减法、乘法和除法。如果有人说:“请计算13.2加18.9”,那么它会触发加法工具,然后给你正确的答案。但如果现在有人输入:“2的平方根是多少?” 嗯,一种方法是为平方根写一个新的工具,但接着可能又需要一个新的东西来做指数运算。实际上,如果你看看你现代科学计算器上的按钮数量,你难道要为每一个按钮以及我们想在数学计算中做的更多事情都创建一个单独的工具吗?

所以,与其试图一个接一个地实现工具,另一种方法是让它编写并执行代码。要告诉 LLM 编写代码,你可能会写一个像这样的提示:“编写代码来解决用户的查询。将你的答案以 Python 代码的形式返回,并用 <execute_python></execute_python> 标签界定。” 所以,给定一个像“2的平方根是多少”这样的查询,LLM 可能会生成这样的输出。然后你可以使用模式匹配,例如正则表达式,来寻找开始和结束的 execute_python 标签,并提取出中间的代码。所以在这里,你得到了绿色框中显示的两行代码,然后你可以为 LLM 执行这段代码,并得到输出,在这种情况下是 1.4142 等等。最后,这个数值答案被传回给 LLM,它就可以为原始问题写一个格式优美的答案。

你可以用几种不同的方式为 LLM 执行代码。一种是使用 Python 的 exec 函数。这是一个内置的 Python 函数,它会执行你传入的任何代码。这对于让你的 LLM 真正编写代码并让你执行这些代码来说非常强大,尽管这有一些安全隐患,我们稍后会在这个视频中看到。还有一些工具可以让你在更安全的沙箱环境中运行代码。当然,2的平方根是一个相对简单的例子。一个 LLM 也可以准确地编写代码来做,例如,利率计算,并解决比这难得多的数学计算问题。

对这个想法的一个改进,你在我们关于反思的部分中已经有所了解,那就是如果代码执行失败——比如说,LLM 出于某种原因生成的代码不完全正确——那么将那个错误信息传回给 LLM,让它反思并可能修改它的代码,再试一两次。这有时也能让它得到一个更准确的答案。

现在,运行 LLM 生成的任意代码确实有很小的可能会导致不好的事情发生。最近,我的一个团队成员正在使用一个高度 agentic 的编码器,它竟然选择在一个项目目录内执行 rm *.py(删除所有 .py 文件)。所以这实际上是一个真实的例子。最终那个 agentic 编码器确实道歉了,它说:“是的,那确实是对的,那是一个极其愚蠢的错误。” 我想我很高兴这个 agentic 编码器真的很抱歉,但它已经删除了一堆 Python 文件。幸运的是,团队成员在 GitHub 仓库里有备份,所以没有造成真正的损害,但如果这段错误地删除了一堆文件的任意代码在没有备份的情况下被执行了,那就不太好了。

所以,代码执行的最佳实践是在沙箱环境中运行它。在实践中,任何单行代码的风险都不是那么高。所以如果我坦率地说,许多开发者会直接执行来自 LLM 的代码,而不会做太多检查。但如果你想更安全一点,那么最佳实践是创建一个沙箱,这样如果 LLM 生成了糟糕的代码,数据丢失或敏感数据泄露等的风险就会降低。像 Docker 或 E2B 这样的沙箱环境(E2B 是一个轻量级的沙箱环境)可以降低任意代码以损害你的系统或环境的方式被执行的风险。

事实证明,代码执行是如此重要,以至于许多 LLM 的训练者实际上会做一些特殊的工作,来确保代码执行在他们的应用上能良好运行。但我希望,当你把这个作为你可以提供给 LLM 的又一个工具时,能让你的应用变得更加强大。

到目前为止,在我们讨论的内容中,你必须一个一个地创建工具并将它们提供给你的 LLM。事实证明,许多不同的团队正在构建类似的工具,并且不得不做所有这些构建函数并将它们提供给 LLM 的工作。但最近出现了一个名为 MCP(模型上下文协议)的新标准,它使得开发者更容易地获得一大套可供 LLM 使用的工具。这是一个越来越重要的协议,越来越多的团队正在使用它来开发基于 LLM 的应用。让我们在下一个视频中了解一下 MCP。

3.5 MCP

MCP,即模型上下文协议(Model Context Protocol),是 Anthropic 提出的一个标准,但现在已被许多其他公司和许多开发者采纳,作为一种让 LLM 访问更多上下文和更多工具的方式。有许多开发者正在围绕 MCP 生态系统进行开发,因此了解这一点将让你为你的应用获得更多的资源。让我们来看一看。

这是 MCP 试图解决的痛点。如果一个开发者正在编写一个应用,想要与来自 Slack、Google Drive 和 GitHub 的数据集成,或者访问来自 Postgres 数据库的数据,那么他们可能必须编写代码来包装 Slack 的 API,以提供函数给应用;编写代码来包装 Google Drive 的 API,以解析给应用;对于其他这些工具或数据源也类似。然后,在开发者社区中一直发生的情况是,如果一个不同的团队在构建一个不同的应用,那么他们也会自己与 Slack、Google Drive、GitHub 等进行集成。所以许多开发者都在为这些类型的数据源构建自定义的包装器。因此,如果有 M 个应用正在开发,而市面上有 N 个工具,那么社区完成的总工作量就是 M 乘以 N。

MCP 所做的是,为应用获取工具和数据源提出了一个标准,这样社区需要完成的总工作量现在是 M 加 N,而不是 M 乘以 N。MCP 的初始设计非常关注如何为 LLM 提供更多上下文,或者如何获取数据。所以很多初始的工具都是只获取数据的。如果你阅读 MCP 的文档,它将这些称为“资源”(resources)。但 MCP 既提供了对数据的访问,也提供了应用可能想调用的更通用的函数。

事实证明,有许多 MCP 客户端(clients),这些是想要访问工具或数据的应用;也有许多 MCP 服务器(servers),这些通常是软件包装器,它们提供对 Slack、GitHub 或 Google Drive 中数据的访问,或者允许你在这些不同类型的资源上执行操作。所以今天,MCP 客户端(消费工具或资源的应用)和 MCP 服务器(提供工具和资源的服务)的列表正在迅速增长。我希望你会发现构建自己的 MCP 客户端很有用,你的应用也许有一天会成为一个 MCP 客户端。如果你想为其他开发者提供资源,也许你有一天也可以构建自己的 MCP 服务器。

让我给你看一个使用 MCP 客户端的快速例子。这是一个云桌面应用,它已经连接到了一个 GitHub MCP 服务器。所以当我输入这个查询:“总结这个 URL 处的 GitHub 仓库中的 readme.md 文件”(这实际上是一个 AI Suite 的仓库),这个应用(它是一个 MCP 客户端)就会使用 GitHub MCP 服务器,并发出请求:“请从这个仓库的 AI Suite 中获取 readme.md 文件”。然后它得到这个响应,内容很长。所有这些都被反馈到 LLM 的上下文中,然后 LLM 生成这个 markdown 文件的摘要。

现在让我输入另一个请求:“最新的拉取请求(pull requests)是什么?” 这反过来又导致 LLM 使用 MCP 服务器发出一个不同的请求,即“列出拉取请求”。这是 GitHub 的 MCP 服务器提供的另一个工具。所以它发出这个请求,带有仓库名 AI Suite,排序方式为更新时间,列出20个等等。然后它给出这个响应,这个响应被反馈给 LLM,LLM 接着写出这个关于该仓库最新拉取请求的漂亮的文本摘要。

MCP 是一个重要的标准。如果你想了解更多,DeepLearning.ai 也有一个短期课程,专门更深入地讲解 MCP 协议,如果你感兴趣的话,可以在完成本课程后去看看。我希望这个视频能让你简要地了解它为什么有用,以及为什么现在许多开发者都在按照这个标准进行构建。

这把我们带到了关于工具使用的最后一个视频。我希望通过让你的 LLM 访问工具,你能构建出更强大的 agentic 应用。在下一个模块中,我们将讨论评估和错误分析。事实证明,我所看到的,区分那些能非常好地执行 agentic 工作流的人和那些效率不高的团队的事情之一,就是你推动一个规范的评估流程的能力。在下一组视频中,我认为这可能是整个课程中最重要的一个模块,我希望能与你分享一些关于如何使用评估来推动 agentic 工作流开发的最佳实践。期待在下一个模块见到你。

模块四:构建 Agentic AI 的实用技巧

4.1 评估(Evals)

在本模块中,我想与你分享一些构建 Agentic AI 工作流的实用技巧。我希望这些技巧能让你在构建这类系统时,比普通开发者效率高得多。

我发现,在开发一个 Agentic AI 系统时,很难预先知道它在哪里能行得通,又在哪里效果不佳,因此也很难知道应该将精力集中在哪里。所以一个非常普遍的建议是,先尝试构建一个哪怕是粗糙的系统,这样你就可以试用它,观察它,看看在哪些地方它可能还没有达到你期望的效果,从而能够更有针对性地进行进一步的开发。相比之下,我发现花好几周时间坐着理论化和假设如何构建它,有时效果反而不佳。通常更好的做法是,以一种安全、合理、不泄露数据的方式,负责任地快速构建一些东西,这样你就可以观察它,然后利用这个初始原型来确定优先级并尝试进一步的开发。

让我们从一个例子开始,看看在你构建了一个原型之后可能会发生什么。

示例一:发票处理

我想用我们之前见过的发票处理工作流作为第一个例子,其任务是提取四个必需的字段,然后将它们保存到数据库记录中。在构建了这样一个系统之后,你可能会做的一件事是,找几张发票,也许是10或20张,然后过一遍,看看它们的输出,看看哪些处理得好,是否有任何错误。

假设你检查了20张发票,你发现第一张发票没问题,输出看起来是正确的。对于第二张发票,它可能混淆了发票日期(即发票开具的日期)和发票的到期日。在这个任务中,我们想要提取的是到期日,这样我们才能按时付款。于是,我可能会在一个文档或电子表格中记下,对于第二张发票,日期搞混了。也许第三、第四张发票都没问题,依此类推。但当我过完这些例子后,我发现有很多例子都混淆了日期。

正是基于对这样一些例子的检查,在这种情况下,你可能会得出结论:一个常见的错误模式是,它在处理日期方面有困难。那样的话,你可能会考虑的一件事,当然是找出如何改进你的系统,让它能更好地提取到期日,但同时,也许也可以编写一个评估(eval)来衡量它提取到期日的准确性。相比之下,如果你发现它错误地提取了开票方地址——谁知道呢,也许你的开票方有不寻常的名字,所以它可能在处理开票方上遇到困难,特别是如果你有国际开票方,他们的名字甚至可能不全是英文字母——那么你可能会转而专注于为开票方地址构建一个评估。

所以,为什么构建一个粗糙的系统并查看其输出如此有帮助,原因之一是,它甚至能帮助你决定,你最想投入精力去评估的是什么。

现在,如果你已经决定要修改你的系统,以提高它提取发票到期日的准确性,那么为了跟踪进展,创建一个评估来衡量日期提取的准确性可能是个好主意。实现这一点可能有多种方法,但我来分享一下我可能会怎么做。

为了创建一个测试集或评估集,我可能会找10到20张发票,并手动写下它们的到期日。所以,也许一张发票的到期日是2025年8月20日,我把它写成标准的“年-月-日”格式。然后,为了便于稍后在代码中进行评估,我可能会在给 LLM 的提示中告诉它,总是将到期日格式化为这种“年-月-日”的格式。这样,我就可以编写代码来提取 LLM 输出的那个日期,也就是到期日,因为那是我们关心的唯一日期。这是一个正则表达式,用于模式匹配,你知道的,四位数的年份,两位数的月份,两位数的日期,然后把它提取出来。接着我就可以直接编写代码来测试提取出的日期是否等于实际日期,也就是我写下的标准答案。

所以,有了一个包含大约20张发票的评估集,我就可以进行构建和修改,看看随着我调整提示或系统的其他部分,它正确提取日期的百分比是否在希望中上升。

总结一下我们到目前为止看到的内容:我们构建一个系统,然后查看输出以发现它可能表现不佳的地方,比如到期日错误。然后,为了推动对这个重要输出的改进,我们建立一个小型的评估,比如说只有20个例子,来帮助我们跟踪进展。这让我可以回头去调整提示,尝试不同的算法等等,看看我是否能提升“到期日准确性”这个指标。这就是改进一个 Agentic AI 工作流通常的感觉:查看输出,看哪里错了,如果你知道怎么修复,就直接修复它。但如果你需要一个更长的改进过程,那就建立一个评估,并用它来推动进一步的开发。

另外需要考虑的一件事是,如果工作了一段时间后,你认为最初的那20个例子不够好,也许它们没有覆盖你想要的所有情况,或者20个例子实在太少,那么你可以随时向评估集中添加更多的例子,以确保它能更好地反映你个人对于系统性能是否足够满意的判断。

示例二:营销文案助手

这只是一个例子。对于第二个例子,让我们来看构建一个用于为 Instagram 撰写标题的营销文案助手。为了保持简洁,假设我们的营销团队告诉我们,他们希望标题最多不超过10个单词。所以我们会有一张产品图片,比如说一副我们想推广的太阳镜,然后有一个用户查询,比如“请写一个标题来销售这副太阳镜”,接着让一个 LLM 或大型多模态模型来分析图片和查询,并生成对太阳镜的描述。

一个营销文案助手可能会出错的方式有很多种,但假设你看了输出后发现,生成的文案或文本大体上听起来还行,但有时就是太长了。对于太阳镜的输入,它生成了17个词;对于咖啡机,没问题;对于时尚夹克,没问题;对于蓝衬衫,14个词;对于搅拌机,11个词。所以看起来在这个例子中,LLM 在遵守长度准则方面有困难。

再次强调,一个营销文案助手可能会出错的地方有很多。但如果你发现它在输出的长度上挣扎,那么你可能会构建一个评估来跟踪这个问题,以便你能做出改进,并确保它在遵守长度准则方面做得越来越好。

所以,为了创建一个评估来衡量文本长度,你可能会创建一个测试任务集,比如推广一副太阳镜、一台咖啡机等等,也许创建10到20个例子。然后,你会让你的系统处理每一个任务,并编写代码来测量输出的单词数。这是测量一段文本单词数的 Python 代码。最后,你会将生成文本的长度与10个单词的目标限制进行比较。所以,如果单词数小于等于10,那么正确数就加一。

这个例子与之前的发票处理例子的一个区别是,这里没有每个样本的标准答案。目标就是10,对每个例子都一样。相比之下,对于发票处理的例子,我们必须为每个样本生成一个自定义的目标标签,即发票的正确到期日,然后我们用这个每个样本的标准答案来测试输出。

我知道我用了一个非常简单的工作流来生成这些标题,但这类评估也可以应用于更复杂的生成工作流。

示例三:研究代理

让我谈谈最后一个例子,我们将重温我们一直在研究的研究代理。如果你查看研究代理在不同输入提示下的输出,假设当你要求它写一篇关于黑洞科学最新突破的文章时,你发现它遗漏了一些备受瞩目且新闻报道很多的研究成果。这是一个不理想的结果。或者当你要求它研究在西雅图租房与买房的对比时,它似乎做得很好。或者关于用机器人收割水果,嗯,它没有提到一家领先的设备公司。

基于这个评估,看起来它有时会遗漏一些人类专家作者会捕捉到的非常重要的观点。于是,我会创建一个评估来衡量它捕捉到最重要观点的频率。

例如,你可能会想出一些关于黑洞、机器人收割等主题的示例提示。对于每一个主题,都想出,比如说,三到五个“黄金标准”的讨论要点。请注意,这里我们确实有每个样本的标注,因为“黄金标准”的谈话要点,也就是最重要的谈话要点,对于每个例子都是不同的。

有了这些标准答案的标注,你接下来可能会使用一个“LLM作为评判者”(LLM-as-a-judge)来计算提到了多少个“黄金标准”的谈话要点。一个示例提示可能是:“请确定所提供的文章中出现了五个‘黄金标准’谈话要点中的多少个。” 你会提供提示、文章文本、黄金标准要点等等,然后让它返回一个 JSON 对象,其中包含一个从0到5的分数,以及一个解释。这让你能为你评估集中的每个提示得到一个分数。

在这个例子中,我使用 LLM 作为评判者来计算提到了多少个谈话要点,因为谈论这些要点的方式多种多样,所以使用正则表达式或简单的模式匹配代码可能效果不佳。这就是为什么你可能会使用 LLM 作为评判者,并将其视为一个稍微主观一些的评估,用来判断比如说,事件视界是否被充分提及。

这是你如何构建评估的第三个例子。

评估的两个维度

为了思考如何为你的应用构建评估,你构建的评估通常必须反映你在应用中看到或担心的任何可能出错的地方。事实证明,广义上讲,评估有两个维度。

  • 评估方法:在上面的轴上,是你评估输出的方式。在某些情况下,你通过编写代码进行客观评估;有时你使用 LLM 作为评判者进行更主观的评估。
  • 标准答案:在另一个轴上,是看你是否有每个样本的标准答案。
    • 对于检查发票日期提取,我们编写代码来评估是否得到了实际日期,这有每个样本的标准答案,因为每张发票的实际日期都不同。
    • 但在我们检查营销文案长度的例子中,每个例子的长度限制都是10,所以那个问题没有每个样本的标准答案。
    • 相比之下,对于计算“黄金标准”谈话要点,则有每个样本的标准答案,因为每篇文章都有不同的重要谈话要点。但我们使用 LLM 作为评判者来阅读文章,看那些主题是否被充分提及,因为提及这些谈话要点的方式太多了。
    • 最后一个象限是“LLM作为评判者”且“没有每个样本的标准答案”。我们在用评分标准给图表打分时看到了这一点。这是当我们看咖啡机销售数据可视化时,如果你要求它根据一个评分标准(比如是否有清晰的坐标轴标签等)来创建图表,那么每个图表都使用相同的评分标准,那将是使用 LLM 作为评判者但没有每个样本的标准答案。

我发现这个二乘二的网格,可能是思考你可能为你的应用构建的不同类型评估的一种有用方式。顺便说一下,这些有时也被称为端到端评估,因为一端是输入端,即用户查询提示,另一端是最终输出。所以所有这些都是对整个端到端系统性能的评估。

总结与技巧

在结束这个视频之前,我想分享一些设计端到端评估的最后几点技巧。

  • 快速开始:首先,快速粗糙的评估对于起步来说是可以的。我感觉我看到相当多的团队几乎陷入瘫痪,因为他们认为构建评估是一项需要数周的大工程,所以他们花了比理想中更长的时间才开始。但我认为,就像你迭代一个 agentic 工作流并随着时间的推移让它变得更好一样,你也应该计划着迭代你的评估。所以,如果你先用10、15、20个例子作为你评估的初稿,写一些代码或者尝试提示一个 LLM 作为评判者,总之先做点什么,得到一些可以补充人眼观察输出的指标,然后结合这两者来驱动你的决策。
  • 迭代改进评估:随着评估随着时间的推移变得越来越复杂,你就可以把越来越多的信任转移到基于指标的评估上,而不是每次调整某个地方的提示时都需要通读数百个输出。在你经历这个过程时,你很可能也会找到不断改进你评估的方法。所以,如果你一开始有20个例子,你可能会遇到你的评估无法捕捉到你关于哪个系统更好的判断的情况。也许你更新了系统,你看了看觉得这个肯定好多了,但你的评估却未能显示新系统取得了更高的分数。如果是这样,这通常是一个机会,去收集一个更大的评估集,或者改变你评估输出的方式,让它更好地与你关于哪个系统实际上工作得更好的判断相对应。所以你的评估会随着时间的推移而变得更好。
  • 从评估中获取灵感:最后,关于利用评估来获得下一步工作灵感方面,许多 agentic 工作流被用来自动化,比如说,人类可以完成的任务。所以我发现对于这类应用,我会寻找那些性能比人类专家差的地方,这通常会给我灵感,让我知道该把精力集中在哪里,或者我应该让我的 agentic 工作流在哪些类型的例子上做得比现在更好。

我希望在你构建了那个粗糙的系统之后,你能思考一下,在什么时候开始加入一些评估来跟踪系统潜在的有问题的方面是有意义的,并且这会帮助你推动系统的改进。除了帮助你推动改进之外,事实证明,有一种评估方法可以帮助你精确地定位,在你整个 agentic 系统中,哪些组件最值得你关注。因为 agentic 系统通常有很多部分,那么花时间去改进哪个部分会最有成效呢?事实证明,能够做好这一点是推动 agentic 工作流高效开发的一项非常重要的技能。在下一个视频中,我想深入探讨这个主题。那么,让我们进入下一个视频。

4.2 错误分析与确定下一步的优先级

假设你已经构建了一个 agentic 工作流,但它的效果还没有达到你的期望——顺便说一句,这在我身上经常发生,我常常会构建一个粗糙的系统,而它的表现不如我所愿。问题是,你应该把精力集中在哪里来让它变得更好?事实证明,agentic 工作流有许多不同的组件,而改进某些组件可能比改进另一些组件要有成果得多。所以,你选择将精力集中在哪里的能力,对你改进系统的速度有着巨大的影响。

我发现,预测一个团队效率和能力高低的最大因素之一,就是他们是否能够推动一个规范的错误分析流程,来告诉你应该将精力集中在哪里。所以,这是一项重要的技能。让我们来看一看如何进行错误分析。

在研究代理的例子中,我们在上一个视频中进行了一次错误分析,我们看到它在撰写某些主题的文章时,常常遗漏了人类专家会提到的关键点。所以,现在你发现了这个问题——有时会遗漏关键点——你怎么知道该做什么呢?

事实证明,在这个工作流的众多不同步骤中,几乎任何一步都可能导致“遗漏关键点”这个问题。例如,也许是第一个 LLM 生成的搜索词不够好,所以它搜索了错误的东西,没有发现正确的文章。或者,也许你用的网络搜索引擎本身就不太好。市面上有多个网络搜索引擎,实际上我自己在我的基础应用中倾向于使用的就有好几个,有些比其他的要好。或者,也许网络搜索没问题,但是当我们把网络搜索结果的列表给 LLM 时,它可能在选择最好的几个来下载方面做得不好。网页获取在这个案例中问题可能较少,假设你能准确地获取网页内容。但在把网页内容扔给 LLM 后,也许 LLM 忽略了我们获取的文档中的一些要点。

事实证明,有些团队有时看到这种情况,会凭直觉选择其中一个组件来改进,有时这能奏效,但有时这会导致数月的工作却在系统整体性能上收效甚微。所以,与其凭直觉来决定在这么多组件中改进哪一个,我认为进行错误分析以更好地理解工作流中的每一步,要好得多。

特别是,我经常会检查“轨迹”(traces),也就是每一步之后的中间输出,以便了解哪个组件的性能不佳——比如说,比人类专家在类似情况下会做的要差得多——因为这指出了哪里可能有安全改进的空间。

让我们来看一个例子。如果我们要求研究代理写一篇关于黑洞科学最新新闻的文章,也许它输出的搜索词是这样的:“黑洞理论 爱因斯坦”、“事件视界望远镜 射电”等等。然后我会让一个人类专家看看这些,判断这些对于撰写关于黑洞科学最新发现的文章来说,是不是合理的网络搜索词。也许在这种情况下,专家说,这些网络搜索看起来还行,和我作为人类会做的差不多。

然后,我查看网络搜索的输出,看看返回的 URL。网络搜索会返回许多不同的网页,也许返回的一个网页是来自“天文小天才新闻”的《一名小学生声称解开了一个30年之久的黑洞之谜》。这看起来不像是一篇最严谨的、经过同行评审的文章。也许检查完网络搜索返回的所有文章后,你得出结论,它返回了太多的博客或大众媒体类型的文章,而没有足够多的科学文章来撰写你所期望质量的研究报告。

最好也检查一下其他步骤的输出。也许 LLM 尽其所能找到了最好的五个来源,结果你得到的是“天文小天才新闻”、“太空机器人2000”、“太空趣闻”等等。正是通过查看这些中间输出,你才能对每一步输出的质量有一个概念。

介绍一些术语,所有中间步骤的整体输出集合通常被称为这次代理运行的“轨迹”(trace)。你在其他资料中可能还会看到一个术语,单一步骤的输出有时被称为“跨度”(span)。这个术语来自计算机可观测性文献,人们试图弄清楚计算机在做什么。在本课程中,我用“轨迹”这个词比较多,用“跨度”这个词会少一些,但你可能在网上看到这两个术语。

所以,通过阅读轨迹,你开始对哪里可能是最有问题的组件有了一个非正式的感觉。为了更系统地做到这一点,将你的注意力集中在系统表现不佳的案例上是很有用的。也许它写的一些文章很好,输出完全令人满意,那么我会把那些放在一边,试着找出一些例子,在这些例子中,由于某种原因,你的研究代理的最终输出不尽如人意,然后只关注那些例子。这就是我们称之为错误分析的原因之一,因为我们想关注系统出错的案例,我们想通过分析来找出哪些组件对研究代理输出的错误负有最大责任。

为了让这个过程更严谨,而不是仅仅通过阅读来获得一个非正式的感觉,你实际上可以建立一个电子表格,来更明确地统计错误出在哪里。我所说的“错误”,指的是当一个步骤输出的东西,其表现显著差于一个人类专家在给定类似输入时可能会给出的结果。我经常自己用电子表格来做这件事。

所以,我可能会建立一个这样的电子表格。对于第一个查询,我会看“黑洞科学的最新发展”。我看到搜索结果中有太多的博客文章、大众媒体文章,没有足够的科学论文。然后基于此,确实,最好的五个来源也不怎么样。但在这里我不会说选择最好的五个来源这一步做得不好,因为如果输入给 LLM 用于选择最好五个来源的都是不严谨的文章,那么我不能责怪这一步没有选出更好的文章,因为它已经尽力了,或者说,在给定同样的选择范围下,它做得和任何人类可能做的差不多好。

然后你可能会为不同的提示重复这个过程。“在西雅图租房与买房”,也许它错过了一个知名的博客。“用机器人收割水果”,也许在这种情况下,我们看了看然后说:“哦,搜索词太笼统了”,然后搜索结果也不好,等等。然后基于此,我会在我的电子表格中统计我观察到不同组件出错的频率。

所以在这个例子中,我对搜索词不满意的比例是5%,但我对搜索结果不满意的比例是45%。如果我真的看到这个结果,我可能会仔细检查一下搜索词,确保搜索词真的没问题,并且搜索词选择不佳不是导致搜索结果差的原因。但如果我真的认为搜索词没问题,但搜索结果不行,那么我就会仔细看看我正在使用的网络搜索引擎,以及是否有任何参数可以调整,让它返回更相关或更高质量的结果。正是这类分析告诉我,在这个例子中,我真的应该把注意力集中在修复搜索结果上,而不是这个 agentic 工作流的其他组件上。

在结束这个视频之前,我发现养成查看轨迹的习惯是很有用的。在你构建了一个 agentic 工作流之后,去看看中间的输出,感受一下它在每一步实际上在做什么,这样你就能更好地理解不同步骤的表现是好是坏。而一个更系统的错误分析,也许用电子表格来做,可以让你收集统计数据或计算出哪个组件最常表现不佳。所以,通过查看哪些组件表现不佳,以及我有哪些能有效改进不同组件的想法,这会让你能够优先处理哪个组件。也许一个组件有问题,但我没有任何改进它的想法,那这可能意味着不要把它放在那么高的优先级。但如果有一个组件产生了很多错误,并且我有如何改进它的想法,那么这将是优先处理该组件的一个很好的理由。

我只想强调,错误分析对于你决定将精力集中在哪里,是一个非常有帮助的输出。因为在任何复杂的系统中,你可以做的事情太多了。很容易就选择一件事去做,然后花上几周甚至几个月,结果后来发现那并没有给你的整个系统带来性能上的提升。所以,利用错误分析来决定将精力集中在哪里,对于提高你的效率来说,被证明是极其有用的。

在这个视频中,我们用研究代理的例子讲解了错误分析,但我认为错误分析是如此重要的一个主题,我想和你再看一些其他的例子。那么,让我们进入下一个视频,在那里我们将看到更多的错误分析例子。

4.3 更多错误分析示例

我发现,对于许多开发者来说,只有通过看多个例子,你才能练习并磨练出如何进行错误分析的直觉。所以,让我们再看两个例子,我们将看看发票处理和回应客户邮件。

示例一:发票处理

这是我们用于发票处理的工作流,我们有一个清晰的流程,让一个 agentic 工作流遵循,即识别四个必需的字段,然后将它们记录在数据库中。在本模块的第一个视频的例子中,我们说过系统经常在发票的到期日上犯错。所以我们可以进行错误分析,试图找出这可能是由哪个组件造成的。

例如,是 PDF 到文本的转换出了错,还是 LLM 从 PDF 到文本组件的输出中提取了错误的日期?

为了进行错误分析,我会尝试找一些提取日期不正确的例子。和上一个视频一样,关注那些性能不佳的例子是很有用的,这样可以试图找出那些例子出了什么问题。所以,忽略那些日期正确的例子,试着找10到100张日期错误的发票。然后我会仔细检查,试图弄清楚问题的原因是 PDF 到文本转换把日期搞错了,还是 LLM 在给定 PDF 到文本输出的情况下,提取了错误的日期。

所以,你可能会建立一个像这样的小电子表格,过一遍20张发票,然后统计一下,PDF 到文本转换错误地提取了日期或文本,以至于即使是人类也无法判断到期日是什么的情况有多频繁,相对于 PDF 到文本看起来足够好,但 LLM 在被要求提取日期时,不知何故提取了错误的日期,比如可能把发票日期识别成了发票的到期日。

在这个例子中,看起来 LLM 的数据提取导致了更多的错误。这告诉我,也许我应该把精力集中在 LLM 数据提取组件上,而不是 PDF 到文本转换上。这一点很重要,因为如果没有这个错误分析,我可以想象一些团队会花上几周甚至几个月的时间来调整 PDF 到文本转换,结果在那个时间之后才发现,这对最终系统的性能并没有产生多大影响。哦,顺便说一下,底部的这些百分比加起来可以不等于100%,因为这些错误不是相互排斥的。

示例二:回应客户邮件

最后一个例子,让我们回到用于回应客户邮件的 agentic 工作流。在这个工作流中,LLM 在收到像这样询问订单的客户邮件后,会提取订单详情,从数据库中获取信息,然后起草一份供人工审查的回复。

同样,我会找一些例子,在这些例子中,由于某种原因,最终的输出不尽人人意,然后试图找出哪里出了问题。一些可能出错的地方包括:

  • 也许 LLM 写了一个不正确的数据库查询,所以当查询发送到数据库时,它没有成功地提取出客户信息。
  • 也许数据库的数据本身是损坏的,所以即使 LLM 写了一个完全合适的数据库查询(也许是用 SQL 或其他查询语言),数据库也没有正确的信息。
  • 也许在给定关于客户订单的正确信息后,LLM 写的邮件不知何故不太对劲。

所以,我会再次查看几封最终输出不理想的邮件,并试图找出哪里出了问题。也许在第一封邮件中,我们发现 LLM 在查询中请求了错误的表,也就是在创建数据库查询的方式上请求了错误的数据。在第二封邮件中,也许我发现数据库实际上有一个错误,并且在给定那个输入的情况下,LLM 不知何故也写了一封不太理想的邮件,等等。

在这个例子中,在过了一遍许多邮件之后,也许我发现最常见的错误是 LLM 编写数据库查询(比如说 SQL 查询)以获取相关信息的方式。而数据库大部分是正确的,尽管那里有一点数据错误。并且 LLM 写邮件的方式也有一些错误,也许它在30%的情况下写得不太对。

这告诉我,最值得我花力气改进的,可能是 LLM 编写查询的方式。第二重要的大概是改进我如何编写最终邮件的提示。像这样的分析可以告诉你,75% 的错误——也许系统在很多事情上都做对了,但在所有它做得不太对的事情中,75% 的问题都来自数据库查询。这是极其有用的信息,可以告诉你应该把精力集中在哪里。

当我在开发 Agentic AI 工作流时,我经常会使用这种类型的错误分析来告诉我下一步应该把注意力集中在什么上。当你做出了那个决定后,事实证明,为了补充我们在本模块前面谈到的端到端评估,通常评估的不仅仅是整个端到端系统,还有单个组件,这样做是很有用的。因为这可以让你更有效地改进那个,比如说,错误分析让你决定把注意力集中在其上的组件。

所以,让我们进入下一个视频,学习关于组件级评估。

4.4 组件级评估

让我们来看一看如何构建和使用组件级评估。

在我们研究代理的例子中,我们说过研究代理有时会遗漏关键点。但如果问题出在网络搜索上,如果我们每次更换网络搜索引擎,都需要重新运行整个工作流,那虽然能给我们一个很好的性能指标,但那种评估的成本很高。此外,这是一个相当复杂的工作流,所以即使网络搜索让事情好了一点点,也许其他组件的随机性引入的噪音,会使得更难看出网络搜索质量的微小改进。

所以,作为只使用端到端评估的替代方案,我会考虑构建一个专门用来衡量网络搜索组件质量的评估。例如,要衡量网络搜索结果的质量,你可能会创建一个“黄金标准”网络资源列表。对于少数几个查询,让一个专家说:“这些是最权威的来源,如果有人在网上搜索,他们真的应该找到这些网页,或者这些网页中的任何一个都是好的。” 然后你可以编写代码来捕捉网络搜索输出中有多少与“黄金标准”网络资源相对应。信息检索领域的标准指标,F1 分数——如果你不知道那是什么意思,别担心细节——但有一些标准指标可以让你衡量,在网络搜索返回的一系列网页中,有多少与专家确定的“黄金标准”网络资源重叠。

有了这个,你现在就有了评估网络搜索组件质量的方法。所以,当你改变你如何进行网络搜索的参数或超参数时,比如当你换入换出不同的网络搜索引擎——也许试试 Google、Bing、DuckDuckGo、Tavily 和 You.com 等等——或者当你改变结果数量,或者当你改变你要求搜索引擎搜索的日期范围时,这可以让你非常迅速地判断网络搜索组件的质量是否在提升,并且能做出更具增量性的改进。

当然,在你宣布工作完成之前,最好还是运行一次端到端评估,以确保在调整了你的网络搜索系统一段时间后,你确实在提升整个系统的性能。但在一次次调整这些超参数的过程中,通过只评估一个组件,而不是每次都需要重新运行端到端评估,你可以做得更有效率得多。

所以,组件级评估可以为特定的错误提供更清晰的信号。它实际上能让你知道你是否在改进网络搜索组件或你正在处理的任何组件,并避免整个端到端系统的复杂性所带来的噪音。如果你在一个项目中,有不同的团队专注于不同的组件,那么让一个团队只拥有自己非常明确的优化指标,而无需担心所有其他组件,也可能更有效率。这让团队能够更快地处理一个更小、更有针对性的问题。

所以,当你决定要改进一个组件时,可以考虑一下是否值得建立一个组件级别的评估,以及这是否能让你在提升该组件性能方面走得更快。现在,你可能在想的一件事是,如果你决定要改进一个组件,你到底该如何让那个组件工作得更好呢?让我们在下一个视频中看一些这方面的例子。

4.5 如何解决你发现的问题

一个 agentic 工作流可能包含许多不同类型的组件,因此你用于改进不同组件的工具也会大相径庭。但我想与你分享一些我看到的通用模式。

改进非 LLM 组件

你 agentic 工作流中的一些组件将是非基于 LLM 的,所以它可能是像网络搜索引擎或文本检索组件(如果那是你 RAG 或检索增强生成系统的一部分),或者是用于代码执行的东西,或者也许是一个单独训练的机器学习模型,比如用于语音识别或在图片中检测人等等。有时这些非基于 LLM 的组件会有你可以调整的参数或超参数。

  • 网络搜索:你可以调整像结果数量或你要求搜索引擎考虑的日期范围这样的东西。
  • RAG 文本检索:你可能会改变决定哪些文本片段被认为是相似的相似度阈值,或者块大小(chunk size)。RAG 系统通常会将文本切成更小的块进行匹配,所以这些都是你可以使用的主要超参数。
  • 人体检测:你可能会改变检测阈值,即它的敏感度以及它有多大可能宣布发现了人,这将在误报和漏报之间进行权衡。

如果你没有跟上我刚才讨论的所有超参数的细节,别担心。细节不是那么重要,但通常组件都会有你可以调整的参数。当然,你也可以尝试替换组件。我在我的 agentic 工作流中经常这样做,我会换入不同的 RAG 搜索引擎或换入不同的 RAG 提供商等等,只是为了看看是否有其他提供商可能效果更好。由于非基于 LLM 的组件的多样性,我认为如何改进它的技术会更加多样化,并且取决于该组件具体在做什么。

改进 LLM 组件

对于一个基于 LLM 的组件,这里有一些你可能会考虑的选项。

  • 改进你的提示:一个方法是尝试改进你的提示。也许可以尝试添加更明确的指令。或者,如果你知道什么是少样本提示(few-shot prompting),那指的是添加一个或多个具体的例子,即一个输入示例和一个期望的输出。所以,少样本提示(你也可以从一些深度学习的短期课程中学到)是一种技术,可以给你的 LLM 一些例子,希望能帮助它写出性能更好的输出。
  • 尝试不同的 LLM:你也可以尝试一个不同的 LLM。使用 AI Suite 或其他工具,尝试多个 LLM 可能相当容易,然后你可以用评估来为你的应用挑选最好的模型。
  • 分解任务:有时,如果一个步骤对于一个 LLM 来说太复杂,你可以考虑是否要将任务分解成更小的步骤。或者也许把它分解成一个生成步骤和一个反思步骤。但更普遍的是,如果你在一个步骤内有非常复杂的指令,也许单个 LLM 很难遵循所有这些指令。你可以把任务分解成更小的步骤,这样可能更容易让,比如说,连续两三次的调用准确地执行。
  • 微调模型:最后,当其他方法效果不够好时,可以考虑微调一个模型。这通常比其他选项要复杂得多,所以在开发者实现的时间成本上也可能昂贵得多。但如果你有一些数据可以用来微调一个 LLM,那可能会给你带来比单独使用提示好得多的性能。所以我倾向于在真正用尽了其他选项之前,不去微调模型,因为微调通常相当复杂。但对于一些应用,在尝试了所有其他方法后,如果我仍然停留在,比如说,90% 或 95% 的性能,而我真的需要挤出最后那几个百分点的改进,那么有时微调我自己的定制模型是一个很好的技术。我倾向于只在更成熟的应用上这样做,因为它成本很高。

磨练你对 LLM 的直觉

事实证明,当你在尝试选择一个 LLM 来使用时,如果你对不同大型语言模型的智能程度或能力有很好的直觉,这对你作为开发者来说是非常有帮助的。一种方法就是尝试很多模型,看看哪个效果最好。但我发现,随着我与不同模型的合作,我开始磨练出关于哪些模型对哪些类型的任务效果最好的直觉。当你磨练出那些直觉时,你在为模型编写好的提示以及为你的任务选择好的模型方面也会更有效率。所以我想与你分享一些关于如何磨练你对哪些模型将对你的应用效果良好的直觉的想法。

让我们用一个例子来说明这一点,即使用 LLM 来遵循指令以删除或编辑个人可识别信息(PII),也就是移除私密的敏感信息。例如,如果你正在使用一个 LLM 来总结客户电话,那么一个总结可能是:“在2023年7月14日,杰西卡·阿尔瓦雷斯,社会安全号码为 XXX,地址在 YYY,提交了一个业务支持工单,等等。” 这段文本含有很多敏感的、个人可识别的信息。现在,假设我们想从这类总结中移除所有的 PII,因为我们想用这些数据进行下游的统计分析,了解客户来电的原因。为了保护客户信息,我们想在进行下游统计分析之前,剥离掉那些 PII。

所以你可能会用一些指令来提示一个 LLM,比如:“请识别下面文本中所有 PII 的情况,然后返回编辑后的文本,用‘[已编辑]’等代替。” 事实证明,规模更大的前沿模型在遵循指令方面往往要好得多,而较小的模型在回答简单的、事实性的问题上往往相当不错,但在遵循指令方面就不那么擅长了。

如果你在一个较小的模型上运行这个提示,比如 OpenWay Llama 3.1 8B 参数模型,那么它可能会生成一个像这样的输出。它说:“识别出的 PII 是社会安全号码和地址”,然后它如下编辑:“……”。它实际上犯了几个错误。它没有正确地遵循指令,它先显示了列表,然后编辑了文本,然后又返回了另一个它不应该返回的列表。在这个 PII 列表中,它漏掉了名字。然后我想它也没有完全编辑掉地址的一部分。所以细节不重要,但它没有完美地遵循这些指令,而且可能漏掉了一点 PII。

相比之下,如果你使用一个更智能的模型,一个更擅长遵循指令的模型,你可能会得到一个更好的结果,像这样,它实际上正确地列出了所有的 PII,并正确地编辑了所有的 PII。

所以我发现,随着不同的 LLM 提供商专注于不同的任务,不同的模型确实在不同的任务上表现更好。有些更擅长编码,有些更擅长遵循指令,有些更擅长某些特定领域的事实。如果你能磨练出对哪些模型或多或少更智能,以及它们或多或少能遵循哪种类型的指令的直觉,那么你就能在选择使用哪个模型上做出更好的决定。

所以分享几个如何做到这一点的技巧:

  • 经常试用不同的模型:我鼓励你经常试用不同的模型。每当有新模型发布时,我常常会去试用它,在上面尝试不同的查询,包括闭源的专有模型和开源的模型。我发现有时拥有一个私人的评估集也可能很有帮助,就是你向很多不同模型都问的一系列问题,这可能帮助你校准它们在不同类型任务上的表现。
  • 阅读他人的提示:我经常做的另一件事,我希望对你有用,就是我花很多时间阅读别人写的提示。有时人们会在网上公布他们的提示,我常常会去读它们,以了解提示的最佳实践是什么样的。或者我常常会和我朋友们聊天,他们在各种公司,包括一些前沿模型公司,我会和他们分享我的提示,看看他们是怎么提示的。有时我也会去找一些我非常尊敬的人写的开源包,下载那个开源包,然后深入挖掘那个开源包,找到作者们写的提示,为了阅读它,为了磨练我关于如何写好提示的直觉。这是我鼓励你考虑的一个技巧,就是通过阅读大量别人写的提示,这将帮助你自己写得更好。我当然经常这样做,我也鼓励你这样做。这将磨练你关于模型擅长遵循哪种类型的指令,以及何时对不同模型说某些话的直觉。
  • 在你的工作流中测试:除了试用模型和阅读别人的提示,如果你在你的 agentic 工作流中尝试很多不同的模型,那也能让你磨练直觉。所以你会看到哪些模型对哪些类型的任务效果最好,无论是通过查看轨迹来获得一个非正式的感觉,还是通过查看组件级或端到端的评估,都可以帮助你评估不同模型在你工作流的不同部分表现如何。然后你开始磨练出不仅是关于性能,也可能是关于使用不同模型的成本和速度权衡的直觉。我倾向于用 AI Suite 来开发我的 agentic 工作流的原因之一,就是因为它使得快速换出和尝试不同模型变得容易。这让我在尝试和评估哪个模型对我的工作流效果最好方面更有效率。

我们已经谈了很多关于如何提升不同组件的性能,以期提升你端到端系统的整体性能。除了提升输出的质量,你在你的工作流中可能还想做的另一件事,是优化延迟和成本。我发现,对于很多团队来说,当你开始开发时,通常第一件要担心的事就是输出的质量是否足够高。但当系统工作良好并投入生产后,让它运行得更快以及成本更低,通常也很有价值。所以在下一个视频中,让我们来看一些关于为 agentic 工作流提升成本和延迟的想法。

4.6 延迟与成本优化

在构建 agentic 工作流时,我常常会建议团队先专注于获得高质量的输出,而只在稍后才去优化成本和延迟。这并不是说成本和延迟不重要,而是我认为让性能或输出质量达到高水平通常是最难的部分,只有当它真的能工作时,才或许该关注其他事情。

有几次发生在我身上的事是,我的团队构建了一个 agentic 工作流,我们把它交付给用户,然后我们很幸运地有那么多用户使用它,以至于成本真的成了一个问题,然后我们不得不手忙脚乱地把成本降下来。但这是一个好问题,所以我倾向于不那么担心成本。不是说我完全忽略它,只是它在我担心的事情清单上排名较低,直到我们有了那么多用户,以至于我们真的需要降低每个用户的成本。然后是延迟,我倾向于会担心一点,但同样,不如确保输出质量高那么担心。但当你真的到了那个阶段,拥有优化延迟和成本的工具将会很有用。让我们来看一些关于如何做到这一点的想法。

优化延迟

如果你想优化一个 agentic 工作流的延迟,我常常会做的一件事是,对工作流进行基准测试或计时。所以在这个研究代理中,它需要多个步骤,如果我为每个步骤计时,也许 LLM 需要7秒来生成搜索词,网络搜索需要5秒,这个需要3秒,这个需要11秒,然后写最终的文章平均需要18秒。正是通过看这个整体的时间线,我才能知道哪些组件有最大的提速空间。

在这个例子中,你可能可以尝试多种方法。如果你还没有利用某些步骤的并行性,比如网页获取,也许值得考虑并行执行其中一些操作。或者,如果你发现某些 LLM 步骤耗时太长,比如第一个步骤需要7秒,最后一个 LLM 步骤需要18秒,我也可能会考虑尝试一个更小的、也许智能程度稍低的模型,看看它是否仍然能足够好地工作,或者我是否能找到一个更快的 LLM 提供商。网上有很多不同 LLM 接口的 API,有些公司有专门的硬件,让他们能够更快地提供某些 LLM 服务,所以有时值得尝试不同的 LLM 提供商,看看哪些能最快地返回 token。但至少,做这种类型的计时分析可以让你知道该把降低延迟的重点放在哪些组件上。

优化成本

在优化成本方面,一个类似的计算,即你计算每一步的成本,也能让你进行基准测试并决定该关注哪些步骤。许多 LLM 提供商根据输入和输出的长度按 token 收费。许多 API 提供商按 API 调用次数收费,而计算步骤的成本可能根据你如何支付服务器容量以及服务成本而有所不同。

所以对于这样一个流程,你可能会在这个例子中确定,这个 LLM 步骤的 token 平均花费0.04美分,每次网络搜索 API 可能花费1.6美分,token 花费这么多,API 调用花费这么多,PDF 到文本转换花费这么多,最终文章生成的 token 花费这么多。这也许会再次让你知道,是否有更便宜的组件或更便宜的 LLM 可以使用,看看哪里是优化成本的最大机会。

我发现这些基准测试练习可以非常清晰地揭示问题,有时它们会明确地告诉我,某些组件根本不值得担心,因为它们对成本或延迟的贡献不大。所以我发现,当成本或延迟成为问题时,通过简单地测量每一步的成本和/或延迟,通常能给你一个基础,让你决定该重点优化哪些组件。

我们即将结束本模块。我知道我们讲了很多,但感谢你坚持到现在。让我们进入本模块的最后一个视频来做个总结。

4.7 开发流程总结

我们已经讲了很多关于推动一个规范、高效的流程来构建 Agentic AI 系统的技巧。我想通过分享一下经历这个过程的感觉来做个总结。

当我在构建这些工作流时,我觉得我常常花时间在两大活动上:

  1. 构建:即编写软件,尝试编写代码来改进我的系统。
  2. 分析:这有时感觉不像是在取得进展,但我认为它同样重要,即进行分析以帮助我决定下一步该把构建的精力集中在哪里。

我常常在构建和分析(包括像错误分析这样的事情)之间来回切换。例如,当构建一个新的 agentic 工作流时,我常常会从快速构建一个端到端系统开始,也许甚至是一个粗糙的实现。这让我可以接着开始检查端到端系统的最终输出,或者通读轨迹,来感受一下它在哪里做得好,在哪里做得差。

仅仅通过看轨迹,有时这会给我一个直观的感觉,让我知道可能想改进哪些单个组件。所以,我可能会去调整一些单个组件,或者继续调整整个端到端系统。随着我的系统开始变得更成熟一些,那么除了手动检查几个输出和通读轨迹之外,我可能会开始构建评估,并拥有一个小的数据集,也许只有10-20个例子,来计算指标,至少是关于端到端性能的指标。这会进一步帮助我对如何改进端到端系统或如何改进单个组件有一个更精细的看法。

随着它进一步成熟,我的分析可能会变得更加规范,我会开始做错误分析,检查各个组件,并尝试统计单个组件导致不佳输出的频率。这种更严谨的分析会让我能够更专注地决定下一步要处理哪些组件,或者激发改进整个端到端系统的想法。然后最终,当它变得更加成熟,为了推动在组件层面更有效的改进时,那时我也可能会构建组件级的评估。

所以,构建一个 agentic 系统的工作流常常是来回往复的,它不是一个线性的过程。我们有时会调整端到端系统,然后做一些错误分析,然后改进一下某个组件,接着调整组件级的评估。我倾向于在这两种技术之间来回切换。

我看到经验较少的团队常常做的是,花大量的时间去构建,而在用错误分析、构建评估等方面进行分析的时间可能远少于理想情况。这并不理想,因为正是这种分析能帮助你真正地把构建的时间花在刀刃上。

还有一个技巧。实际上有很多工具可以帮助监控轨迹、记录运行时间、计算成本等等。那些工具可能很有用。我有时会用其中的一些,而且 DeepLearning.ai 的不少短期课程合作伙伴都提供那些工具,它们确实很好用。我发现,对于我最终处理的 agentic 工作流来说,大多数 agentic 工作流都非常定制化。所以我最终会自己构建非常定制化的评估,因为我想捕捉到我的系统中那些不正确工作的地方。所以,即使我确实使用了一些那些工具,我最终也还是会构建很多非常适合我特定应用以及我所看到的其中问题的定制化评估。

感谢你坚持到现在,看完了五分之四的模块。如果你能实现本模块中哪怕是一小部分的想法,我想你在实现 agentic 工作流的成熟度方面,就已经远远领先于绝大多数的开发者了。希望你觉得这些材料有用,我期待在最后一个模块见到你。我们将讨论一些用于构建高度自主代理的更高级的设计模式。我们在本课程的最后一个模块见。

模块五:高度自主代理的设计模式

5.1 规划工作流

欢迎来到最后一个模块,在这里你将学习一些设计模式,让你能够构建高度自主的代理。在使用这些模式时,你无需预先硬编码要采取的步骤顺序,代理可以更灵活地自行决定要采取哪些步骤来完成任务。我们将讨论规划设计模式,以及在本模块后面部分,如何构建多代理系统。让我们开始吧。

示例一:零售客户服务

假设你经营一家太阳镜零售店,并且你的库存中有哪些太阳镜的信息都存储在数据库中。你可能希望有一个客户服务代理能够回答像“你们有库存的圆形太阳镜吗?价格在100美元以下”这样的问题。这是一个相当复杂的查询,因为你必须查看产品描述,看哪些太阳镜是圆形的,然后查看哪些有库存,最后再看哪些价格低于100美元,才能告诉顾客:“是的,我们有经典款太阳镜。” 你如何构建一个能回答像这样以及许多其他各种客户查询的代理呢?

为了做到这一点,我们将给 LLM 一套工具,让它能够:

  • 获取商品描述(比如查找不同的眼镜是否是圆形的)
  • 检查库存
  • 处理商品退货(这个查询不需要,但其他查询可能需要)
  • 获取商品价格
  • 检查过去的交易记录
  • 处理商品销售等等。

为了让 LLM 弄清楚响应客户请求应该使用什么正确的工具顺序,你可能会写一个这样的提示:“你可以使用以下工具…”,然后给它每个工具(比如说六个或更多工具)的描述,接着告诉它“返回一个执行用户请求的逐步计划”。

在这种情况下,为了回答这个特定的查询,一个 LLM 可能输出的合理计划可能是:

  1. 首先,使用 get_item_descriptions 检查不同的描述以找到圆形太阳镜。
  2. 然后,使用 check_inventory 查看它们是否有库存。
  3. 再使用 get_item_price 查看有库存的结果是否低于100美元。

在 LLM 输出了这个包含三个步骤的计划之后,我们可以将第一步的文本(即这里用红色写的文本)传递给一个 LLM,可能还会附加上下文,比如有哪些工具、你的用户查询是什么、以及其他背景信息,然后让 LLM 执行第一步。在这种情况下,希望 LLM 会选择调用 get_item_descriptions 来获取相应的商品描述,该步骤的输出能让它选出哪些是圆形太阳镜。

然后,第一步的输出会连同第二步的指令(即我这里用蓝色标出的指令)一起传递给一个 LLM,以执行计划的第二步。希望它会接着处理我们在上一张幻灯片中找到的两副圆形太阳镜并检查库存。

第二步的输出随后会用于另一次 LLM 调用,其中包含了第二步的输出以及第三步要做什么的指令。将这些传递给 LLM,让它获取商品价格,最后这个输出会最后一次反馈给 LLM,以生成给用户的最终答案。

在这张幻灯片中,我稍微简化了很多细节。LLM 实际编写的计划通常比这些简单的一行指令更详细,但基本的工作流程是,让一个 LLM 写出一个包含多个步骤的计划,然后让它在适当的上下文(比如任务是什么、有哪些可用工具等)中,依次执行计划的每一步。

使用 LLM 以这种方式进行规划的激动人心之处在于,我们不必预先决定调用工具的顺序,就能回答一个相当复杂的客户请求。如果客户提出一个不同的请求,比如“我想退回我购买的金色镜框眼镜,而不是金属镜框的”,那么你可以想象一个 LLM 同样能够想出一个不同的计划,根据他们之前购买的记录,通过 get_item_descriptions 找出他们买了哪些眼镜,哪些是他们想退回的金色镜框眼镜,然后可能调用 process_item_return。所以,有了一个能像这样进行规划的代理,它就能执行更广泛的任务,这些任务可能需要以许多不同的顺序调用许多不同的工具。

示例二:邮件助手

再看一个规划的例子,让我们来看一个邮件助手。如果你想告诉你的助手:“请回复纽约的 Bob 发来的那封邮件邀请,告诉他我会参加,并把他的邮件归档。” 那么,一个邮件助手可能会被赋予像这样的工具:搜索邮件、移动邮件、删除邮件和发送邮件。你可能会写一个助手提示,说:“你可以使用以下工具,…请返回逐步的计划。” 在这种情况下,LLM 可能会说,完成这个任务的步骤是:

  1. 使用 search_email 找到 Bob 发来的那封提到“晚餐”和“纽约”的邮件。
  2. 然后生成并发送一封邮件以确认参加。
  3. 最后将那封邮件移动到归档文件夹。

鉴于这个计划看起来是合理的,你接下来会再次让一个 LLM 按部就班地执行这个计划。所以,第一步的文本(这里用红色显示)会被连同额外的背景上下文一起提供给 LLM,希望它会触发 search_email。然后,该操作的输出可以再次连同第二步的指令一起提供给一个 LLM,以发送一个适当的回复。最后,假设邮件已成功发送,你可以取那个输出,让 LLM 执行第三步,将 Bob 的邮件移动到归档文件夹。

总结

规划设计模式已经在许多高度 agentic 的编码系统中成功使用。如果你要求它编写一个软件来构建某个相当复杂的应用,它实际上可能会想出一个计划来先构建这个组件,再构建那个组件,几乎形成一个清单,然后一步步地执行这些步骤,来构建一个相当复杂的软件。

对于许多其他应用,规划的使用可能仍然更具实验性,尚未被非常广泛地使用。规划的挑战之一是,它有时会让系统有点难以控制,因为作为开发者,你并不知道在运行时它会想出什么样的计划。所以我认为,除了在高度 agentic 的编码系统中(它在那里确实工作得很好),规划在其他领域的采用仍在增长。但这是一项激动人心的技术,我认为它会不断进步,我们将在越来越多的应用中看到它。

构建能够自己规划的代理的酷炫之处在于,你不需要预先硬编码 LLM 为完成一个复杂任务可能采取的确切步骤顺序。现在,我知道在这个视频中,我以一个相当高的层次讲解了规划过程,即列出步骤列表,然后让一个 LLM 一步步地执行计划。但这到底是如何工作的呢?在下一个视频中,我们将更深入地探讨,看看这些计划的内部到底是什么样的,以及如何将它们串联起来,让一个 LLM 为你规划并执行计划。让我们在下一个视频中看一看。

5.2 创建和执行 LLM 计划

在这个视频中,我们将详细探讨如何提示一个 LLM 来生成一个计划,以及如何读取、解释和执行那个计划。让我们开始吧。

这是你在上一个视频中看到的客户服务代理的计划,我用简单的文本描述以一个较高的层次呈现了这个计划。让我们来看一看,你如何能让一个 LLM 写出非常清晰的、超越这些简单高层次文本描述的计划。

事实证明,许多开发者会要求一个 LLM 以 JSON 格式来格式化它想要执行的计划,因为这能让下游的代码以相对清晰和明确的方式解析出计划的具体步骤是什么,而且目前所有领先的 LLM 都非常擅长生成 JSON 输出。

所以,系统提示可能会这样说:“你可以使用以下工具…”,然后“以 JSON 格式创建一个逐步的计划”,你可能会足够详细地描述这个 JSON 格式,目的是让它输出一个像右边这里展示的计划。

在这个 JSON 输出中,它创建了一个列表,列表的第一个项目有清晰的键和值,说明计划的第一步有如下描述,并且应该使用如下工具,并向该工具传递如下参数。然后,计划的第二步是执行这个任务,然后使用这个工具,等等。所以,这种 JSON 格式,相对于用英语写计划,能让下游代码更清晰地解析出计划的确切步骤,以便能够可靠地一步步执行。

除了 JSON,我也看到一些开发者使用 XML,你可以使用 XML 分隔符,用 XML 标签来清晰地指定计划的步骤是什么以及步骤编号。有些开发者,我感觉比较少,会使用 Markdown,它在解析方面有时会稍微模糊一些,而我认为纯文本可能是这些选项中最不可靠的。但我认为,要么是 JSON(我这里展示的),要么是 XML,都会是要求 LLM 以明确的方式格式化计划的好选择。

就是这样。通过以 JSON 格式打开计划,你就可以解析它,并让下游的工作流更有系统地执行计划的不同步骤。

现在,在让 LLM 进行规划方面,事实证明还有一个非常巧妙的想法,能让一个 LLM 输出非常复杂的计划并可靠地执行它们,那就是让它们编写代码,并让代码来表达计划。让我们在下一个视频中看一看这个。

5.3 通过代码执行进行规划

通过代码执行进行规划,这个想法是,与其要求一个 LLM 以,比如说,JSON 格式输出一个计划来一步步执行,为什么不让 LLM 直接尝试编写代码呢?这些代码可以包含计划的多个步骤,比如调用这个函数,然后调用那个函数,再调用这个函数。通过执行 LLM 生成的代码,我们实际上可以执行相当复杂的计划。让我们来看一看你可能想在什么时候使用这个技术。

假设你想构建一个系统,根据一个包含像这样过往销售数据的电子表格,来回答关于咖啡机销售的问题。你可能会给一个 LLM 一套工具,比如:

  • get_column_max: 查看某一列并获取最大值(这样可以回答“最贵的咖啡是什么?”)
  • get_column_mean
  • filter_rows
  • get_column_min
  • get_column_median
  • sum_rows 等等。这些是你可能给一个 LLM 的一系列工具,用来以不同方式处理这个电子表格或这些行列数据。

现在,如果一个用户问:“哪个月份的热巧克力销量最高?” 事实证明,你可以用这些工具来回答这个查询,但这相当复杂。你必须用 filter_rows 来提取一月份热巧克力的交易,然后对它做统计,然后对二月重复这个过程,算出统计数据,然后对三月、四月、五月,一直到十二月都重复一遍,然后取最大值。所以你实际上可以用一个相当复杂的过程,把这些工具串联起来,但这并不是一个很好的解决方案。

更糟糕的是,如果有人问:“上周有多少笔独立交易?” 嗯,这些工具不足以得到那个答案,所以你可能最终会创建一个新工具 get_unique_entries。或者你可能会遇到另一个查询:“最后五笔交易的金额是多少?” 那你就得再创建一个工具来获取数据以回答那个查询。在实践中,我看到一些团队,当他们遇到越来越多的查询时,最终会创建越来越多的工具,试图给 LLM 足够多的工具来覆盖某人可能对这样一个数据集提出的所有问题。所以这种方法是脆弱、低效的,我看到一些团队不断地处理边缘情况并试图创建更多的工具。

但事实证明,有一种更好的方法,那就是如果你提示 LLM 说:“请编写代码来解决用户的查询,并将你的答案以 Python 代码的形式返回”,也许用 <execute_python></execute_python> 这些 XML 标签来界定,那么 LLM 就可以直接编写代码,将电子表格加载到一个数据处理库中(这里它使用的是 pandas 库),然后它实际上是在构思一个计划。这个计划是,在加载了 CSV 文件之后,首先它必须确保日期列以某种方式被解析,然后按日期排序,选择最后五笔交易,只显示价格列,等等。但这些就是计划的第一、二、三、四、五步。

因为像 Python 这样的编程语言,在这个例子中还导入了 pandas 数据处理库,它有许多内置的函数,成百上千甚至上万个函数。而且,这些是 LLM 在何时调用方面已经看过大量数据的函数。通过让你的 LLM 编写代码,它可以从这成百上千个它已经看过大量数据知道何时使用的相关函数中进行选择,这让它能够将不同选择的函数调用串联起来,从而为回答像这样相当复杂的查询想出一个计划。

再举一个例子。如果有人问:“上周有多少笔独立交易?” 嗯,它可以想出一个计划:读取 CSV 文件、解析日期列、定义时间窗口、筛选行、删除重复行、然后计数。这个的细节不重要,但希望你能看到的是,如果你读这里的注释,LLM 大致上是在想出一个四步计划,并用你可以直接执行的代码来表达每一步,这将为用户得到他们的答案。

所以,对于那些任务可以合理地通过编写代码来完成的应用,让一个 LLM 用你可以为它执行的软件代码来表达它的计划,可以是一种非常强大的方式,让它能够编写丰富的计划。当然,我在关于工具使用的模块中提到的那个警告,即考虑是否需要找到一个安全的执行环境(如沙箱)来运行代码,这里也适用。尽管我知道,即使这可能不是最佳实践,我也知道很多开发者不使用沙箱。

最后,事实证明,用代码进行规划效果很好。从这张改编自王新宇(Xinyao Wang)等人研究论文的图中,你可以看到,对于他们研究的任务,在许多不同的模型上,“代码即行动”(即邀请 LLM 编写代码并通过代码采取行动)都优于让它编写 JSON 然后将 JSON 转换为行动或文本。你也看到了一个趋势,即编写代码优于让 LLM 以 JSON 编写计划,而以 JSON 编写计划也比以纯文本编写计划要好一些。

当然,有些应用你可能想给你的自定义工具让 LLM 使用,所以编写代码并不适用于每一个应用。但当它适用时,它可以是 LLM 表达计划的一种非常强大的方式。

这就结束了关于规划的部分。今天,规划型 Agentic AI 最强大的用途之一是高度 agentic 的软件编码器。事实证明,如果你要求一个高度 agentic 的软件编码辅助工具为你编写一个复杂的软件,它可能会想出一个详细的计划,先构建软件的这个组件,然后构建第二个组件,第三个,甚至可能计划在进行过程中测试这些组件。然后它形成一个清单,接着按部就班地执行。所以它在构建日益复杂的软件方面实际上工作得非常好。

对于其他应用,我认为规划的使用仍在增长和发展中。规划的一个缺点是,因为开发者不告诉系统具体要做什么,所以控制它有点难,而且你事先并不知道运行时会发生什么。但放弃一些这种控制,确实显著地增加了模型可能决定尝试的事情的范围。所以这项重要的技术有点前沿,在 agentic 编码(它在那里工作得很好)之外,感觉还不完全成熟,尽管我确定还有很大的发展空间。但希望你有一天能在你的一些应用中享受使用它。

这就结束了规划部分。在本模块中,我希望与你分享最后一个设计模式,那就是如何构建多代理系统。我们不是只有一个代理,而是有多个代理协同工作来为你完成任务。让我们在下一个视频中看一看。

5.4 多代理工作流

我们已经谈了很多关于如何构建单个代理来为你完成任务。在一个多代理或多 agentic 工作流中,我们转而让多个代理集合协作来为你做事。

有些人第一次听说多代理系统时会想,我为什么需要多个代理?它不就是我一遍遍提示的同一个 LLM,或者只是一台电脑吗?我为什么需要多个代理?

我发现一个有用的类比是,即使我可能在一台电脑上做事,我们也会把一台电脑上的工作分解成多个进程或多个线程。作为一名开发者,思考如何将工作分解成多个进程和多个计算机程序来运行——即使电脑上只有一个 CPU——这让我作为开发者更容易编写代码。同样地,如果你有一个复杂的任务要执行,有时,与其思考如何雇佣一个人来为你做,你可能会思考雇佣一个由几个人组成的团队,来为你完成任务的不同部分。

所以在实践中,我发现对于许多 agentic 系统的开发者来说,拥有这样的心智框架——不是问“我可能雇佣哪一个人来做某事”,而是“雇佣三四个不同角色的人来为我完成这个整体任务是否有意义”——这有助于提供另一种方式,将一个复杂的事情分解成子任务,并一次一个地为那些独立的子任务进行构建。

让我们来看一些这是如何工作的例子。

  • 创建营销材料:以创建营销材料为例,假设你想推广太阳镜,你能为此制作一份营销手册吗?你可能需要团队里有一个研究员,来研究太阳镜的趋势和竞争对手提供什么。你可能还需要团队里有一个平面设计师,来渲染图表或你的太阳镜的好看图形。然后还需要一个写手,来把研究成果和图形资产整合在一起,制作成一份漂亮的宣传册。
  • 撰写研究文章:或者,要写一篇研究文章,你可能需要一个研究员做在线研究,一个统计学家计算统计数据,一个主笔,然后一个编辑来完成一份润色过的报告。
  • 准备法律案件:或者,要准备一个法律案件,真正的律师事务所通常会有助理、律师助理,也许还有一个调查员。

我们很自然地,因为人类团队的工作方式,可以想到各种复杂任务被分解给具有不同角色的不同个体的方式。所以这些例子说明了,复杂任务已经被自然地分解成了可以由具有不同技能的不同人来执行的子任务。

让我们以创建营销材料为例,详细看看研究员、平面设计师和写手可能会做什么。

  • 研究员:研究员的任务可能是分析市场趋势和研究竞争对手。在设计研究代理时,需要记住的一个问题是,研究员可能需要哪些工具,才能就市场趋势和竞争对手的情况拿出一份研究报告。所以,一个 agentic 研究员可能需要使用的一个自然工具就是网络搜索。因为一个人类研究员,被要求做这些任务时,可能需要在线搜索才能完成他们的报告。
  • 平面设计师:对于一个平面设计师代理,他们的任务可能是创作可视化图表和艺术作品。那么,一个 agentic 软件平面设计师可能需要哪些工具呢?嗯,他们可能需要图像生成和处理的 API。或者也许,类似于你在咖啡机例子中看到的,它可能需要代码执行来生成图表。
  • 写手:最后,写手将研究成果转化为报告文本和营销文案。在这种情况下,除了 LLM 已经能做的生成文本的功能外,他们不需要任何工具。

在这个和下一个视频中,我将用这些紫色的框来表示一个代理。你构建单个代理的方式,就是提示一个 LLM 扮演研究员、平面设计师或写手的角色,取决于它是哪个代理的一部分。

例如,对于研究代理,你可能会提示它说:“你是一个研究代理,擅长分析市场趋势和竞争对手。请进行在线研究,为太阳镜产品分析市场趋势,并总结竞争对手的情况。” 这将让你能够构建一个研究员代理。同样地,通过提示一个 LLM 扮演一个带有适当工具的平面设计师,以及扮演一个写手,你就可以构建一个平面设计师代理和一个写手代理。

在构建了这三个代理之后,一种让它们协同工作以生成你最终报告的方式,是使用一个简单的线性顺序工作流,或者说,在这种情况下,一个线性计划。所以,如果你想为太阳镜创建一个夏季营销活动,你可能会把那个提示给研究代理。研究代理然后写一份报告说:“这是当前的太阳镜趋势和竞争产品。” 这份研究报告可以接着被提供给平面设计师,它查看研究发现的数据,并创作一些数据可视化图表和艺术作品选项。所有这些资产可以接着被传递给写手,它接着将研究成果和图形输出整合起来,撰写最终的营销手册。

在这种情况下,构建一个多代理工作流的优势是,在设计研究员、平面设计师或写手时,你可以一次只专注于一件事。所以我可以花些时间来构建我能做的最好的平面设计师代理,而也许我的合作者正在构建研究员代理和写手代理。最后,我们将它们串联起来,得到这个多代理系统。在某些情况下,我看到开发者们也开始复用一些代理。所以,为营销手册构建了一个平面设计师之后,也许我会考虑是否能构建一个更通用的平面设计师,既能帮我写营销手册,也能写社交媒体帖子,还能帮我为网页配图。所以,通过想出你可能雇佣哪些代理来完成一个任务——这有时会对应于你可能雇佣哪类人类员工来完成一个任务——你可以想出像这样的一个工作流,甚至可能构建出你可以在其他应用中选择复用的代理。

现在,你在这里看到的是一个线性计划,即一个代理(研究员)完成他的工作,然后是平面设计师,然后是写手。对于代理,作为线性计划的替代方案,你也可以让代理以更复杂的方式相互交互。

让我用一个使用多个代理进行规划的例子来说明。之前,你看到了我们如何可能给一个 LLM 一套它可以调用来执行不同任务的工具。在我将要向你展示的内容中,我们将转而给一个 LLM 调用不同代理的选项,请求不同的代理帮助完成不同的任务。

具体来说,你可能会写一个提示,比如:“你是一个营销经理,有以下代理团队可以合作”,然后给出代理的描述。这与我们用规划和使用工具所做的非常相似,只不过工具(绿色的框)被替换成了代理(这些紫色的框),LLM 可以调用它们。你也可以要求它返回一个执行用户请求的逐步计划。在这种情况下,LLM 可能会:

  1. 要求研究员研究当前的太阳镜趋势并报告。
  2. 然后它会要求平面设计师创作图像并报告。
  3. 接着要求写手创建一份报告。
  4. 然后也许 LLM 会选择最后一次审查或反思并改进报告。

在执行这个计划时,你会接着取第一步研究员的文本,执行研究,然后把它传递给平面设计师,再传递给写手,然后可能做最后一次反思步骤,然后就完成了。

对这个工作流一个有趣的看法是,就好像你上面有这三个代理,但左边的这个 LLM 实际上就像第四个代理,一个营销经理,它是一个营销团队的管理者,负责设定方向,然后将任务委派给研究员、平面设计师和写手代理。所以这实际上变成了一个由四个代理组成的集合,一个营销经理代理协调着研究员、平面设计师和写手的工作。

在这个视频中,你看到了两种沟通模式。一种是线性的,你的代理一次只执行一个动作,直到你到达终点。第二种有一个营销经理协调着其他几个代理的活动。事实证明,在构建多 agentic 系统时,你可能最终必须做出的关键设计决策之一,就是你不同代理之间的沟通模式是什么。这是一个艰难的研究领域,并且正在涌现多种模式,但在下一个视频中,我想向你展示一些让你的代理相互合作的最常见的沟通模式。让我们在下一个视频中看看。

5.5 多代理系统的沟通模式

当你有一个团队的人一起工作时,他们沟通的模式可能相当复杂。实际上,设计一个组织结构图是相当复杂的,需要试图找出人们沟通、协作的最佳方式。事实证明,为多代理系统设计沟通模式也相当复杂。但让我向你展示一些我今天看到的不同团队使用的最常见的设计模式。

1. 线性模式

在一个带有线性计划的营销团队中,首先是研究员工作,然后是平面设计师,然后是写手,其沟通模式是线性的。研究员会与平面设计师沟通,然后研究员和平面设计师或许都会把他们的输出传递给写手。所以这是一个非常线性的沟通模式。这是我今天看到正在使用的两种最常见的沟通计划之一。

2. 层级模式

两种最常见的沟通计划中的第二种,类似于你在这个例子中看到的,即使用多个代理进行规划,其中有一个管理者与一些团队成员沟通并协调他们的工作。所以在这个例子中,营销经理决定调用研究员来做一些工作。然后,如果你把营销经理想象成接收报告,然后把它发送给平面设计师,再接收报告,然后发送给写手,这将是一种层级式的沟通模式。如果你真的在实现一个层级式的沟通模式,让研究员把报告传回给营销经理,可能会比让研究员直接把结果传递给平面设计师和写手更简单。所以这种类型的层级结构也是一种相当常见的规划沟通模式的方式,即你有一个管理者协调着其他一些代理的工作。

3. 深度层级模式

为了与你分享一些更高级、使用频率较低,但有时在实践中仍会使用的沟通模式,一种是更深的层级结构。和之前一样,如果你有一个营销经理向研究员、平面设计师、写手发送任务,但也许研究员自己有两个其他的代理可以调用,比如一个网络研究员和一个事实核查员。也许平面设计师就自己工作,而写手有一个初稿风格写手和一个引文检查员。这将是一个代理的层级组织,其中一些代理可能自己会调用其他的子代理。我也看到这在一些应用中使用,但这比一层层级结构要复杂得多,所以今天用得比较少。

4. 全连接模式

最后一个模式,执行起来相当有挑战性,但我看到一些实验性的项目在使用它,那就是全连接(all-to-all)的沟通模式。在这种模式中,任何人都可以在任何时候与任何其他人交谈。你实现这个的方式是,你提示你所有的四个代理(在这个例子中),告诉它们还有另外三个代理它们可以决定调用。每当你的一个代理决定向另一个代理发送消息时,那条消息就会被添加到接收方代理的上下文中。然后接收方代理可以思考一会儿,并决定何时回复第一个代理。所以,如果它们都能在一个群体中协作,互相交谈一会儿,直到,比如说,它们中的每一个都宣布自己完成了这个任务,然后它停止交谈。也许当每个人都认为完成了,或者也许当写手断定已经足够好了,那时你才生成最终的输出。

在实践中,我发现全连接沟通模式的结果有点难以预测。所以有些应用不需要高度的控制,你可以运行它,看看会得到什么。如果营销手册不好,也许没关系,你再运行一次,看看是否会得到不同的结果。但我认为,对于那些你愿意容忍一点混乱和不可预测性的应用,我确实看到一些开发者在使用这种沟通模式。

所以,我希望这传达了多代理系统的一些丰富性。今天,也有相当多的软件框架支持轻松地构建多代理系统,它们也使得实现其中一些沟通模式相对容易。所以,也许如果你使用你自己的多代理系统,你会发现一些这些框架对于探索这些不同的沟通模式很有帮助。

这就把我们带到了本模块和本课程的最后一个视频。让我们进入最后一个视频做个总结。

5.6 结论

欢迎来到本课程的最后一个视频。感觉我们一起经历了很多,就你和我,我们在 Agentic AI 领域探讨了许多主题。让我们回顾一下。

  • 在第一个模块中,我们谈到了你可以用 Agentic AI 构建哪些以前不可能实现的应用。然后我们开始看关键的设计模式。
  • 我们探讨了反思设计模式,这是一个简单的方法,有时能给你的应用带来不错的性能提升。
  • 然后是工具使用或函数调用,它扩展了你的 LLM 应用能做的事情,其中代码执行是一个重要的特例。
  • 接着我们花了很多时间讨论评估以及错误分析,以及如何推动一个规范的构建与分析流程,从而高效地不断提升你的 agentic AI 系统的性能。这第四个模块中的一些材料,我认为在你持续构建 Agentic AI 系统的过程中,你会发现它们是最有用的,我希望会是这样很长一段时间。
  • 然后在这个模块中,我们谈到了规划和多代理系统,它们能让你构建更强大,尽管有时更难控制、更难预先预测的系统类型。

所以,凭借你从本课程学到的技能,我想你现在知道如何构建很多酷炫、激动人心的 Agentic AI 应用了。当我的团队,或者我看到其他团队,面试求职者时,我发现面试官常常试图评估候选人是否具备你在这门课程中学到的大部分技能。所以我希望这门课程也能为你开启新的职业机会,并且你会做得更多。无论你是为了好玩,还是为了专业的实际应用场景而做这些事,我想你会享受你现在可以构建的这一系列新事物。

最后,我想再次感谢你花这么多时间和我在一起。我希望你能带着这些技能,负责任地使用它们,然后去创造一些酷炫的东西。