吴恩达】2026年公认最好的【Agent智能体】教程!大模型入门到进阶,一套全解决!Agentic AI—附带课件代码
目录
- P1 【模块1:智能体工作流简介】1-Welcome!
- P2 2-什么是智能体AI?
- P3 3-自主性程度
- P4 4-智能体AI的优势
- P5 5-智能体AI应用
- P6 6-任务分解:识别工作流中的步骤
- P7 7-智能体AI评估(evals)
- P8 8-智能体设计模式
- P9 【模块2:反射设计模式】1-通过反射提升任务输出质量
- P10 2-为什么不直接生成呢?
- P11 3-图表生成工作流程
- P12 4-评估反射的影响
- P13 5-使用外部反馈
- P14 【模块3:工具使用】1-什么是工具?
- P15 2-创建工具
- P16 3-工具语法
- P17 4-代码执行
- P18 5-MCP
- P19 【模块4:构建智能体AI的实用技巧】1-评估(evals)
- P20 2-误差分析与确定后续步骤优先级
- P21 3-更多误差分析示例
- P22 4-组件级评估
- P23 5-如何解决你发现的问题
- P24 6-延迟、成本优化
- P25 7-开发过程总结
- P26 【模块5:高度自主智能体的模式】1-规划工作流
- P27 2-创建和执行LLM计划
- P28 3-结合代码执行的规划
- P29 4-多智能体工作流
- P30 5-多智能体系统的通信模式
- P31 6-结论
- P32 【模块6:Agent知识图谱】Introduction 介绍
- P33 1-什么是知识图谱
- P34 2-多智能体系统的架构
- P35 3-1 Google ADK简介 Part1
- P36 3-2 Google ADK简介 Part2
- P37 4-了解用户意图
- P38 5-文件建议
- P39 6-结构化数据的架构建议
- P40 7-非结构化数据的模式建议
- P41 8-1 知识图谱构建 Part1
- P42 8-2 知识图谱构建 Part2
- P43 Conclusion 结束
P1 【模块1:智能体工作流简介】1-Welcome!
人工智能课程。当我提出这个术语来描述我观察到的重要且快速发展的趋势时。在人们基于现有应用进行构建的过程中。我没有意识到一群营销人员会抓住这个术语。将其作为标签贴在几乎所有可见的事物上。这导致生成式 AI的炒作迅速飙升。好消息。是尽管存在炒作。真正有价值且实用的应用程序数量也快速增长。即使不如炒作的速度快。而在本课程中。我想展示构建生成式 AI应用的最佳实践。并为您打开更多今天可以构建的新机会。生成式工作流正被用于构建客户支持代理。或进行深度研究。帮助撰写深刻的研究报告。或处理复杂的法律文件。或分析患者输入并生成。或在我团队中为许多项目提供可能的医学诊断建议。我们构建的许多项目仅靠传统工作流根本不可能完成。因此。掌握如何构建这些应用是当今AI领域最重要的技能之一。事实证明,我观察到的最大差异之一。在于真正懂得构建生成式工作流的人。与效果较差者之间的区别在于能否驱动严谨的开发流程。特别是注重错误分析。evals 和错误分析。在本课程中。我将解释这意味着什么。并展示如何成为构建生成式工作流的高手。我们想要。这是当今AI领域最重要的技能之一。并将带来更多就业机会或机会。或自行构建令人惊叹的软件。进入下一视频,深入了解生成式工作负载。
P2 2-什么是智能体AI?
人工智能到底是什么。为什么生成式 AI工作流如此强大。看看大多数人使用大型语言模型或LLM的方式。今天通常是通过提示它说。为我们撰写一篇关于某个主题的论文。我认为这类似于求助于人类。或者在这个案例中向AI提出。请从第一个字到最后一个字完整写出一篇论文。一次性完成且永不回退。事实证明,作为人类。我们不会在这种完全线性的方式下写出最佳内容。AI模型也是如此。尽管被限制采用这种方式写作存在困难。但我们的算法表现惊人。相比之下,生成式工作流。这个过程可能如下所示。你可以先让它撰写某个主题的论文大纲。询问是否需要进行词汇研究。在完成网络研究并可能下载网页后。再撰写初稿。阅读初稿并确定需要修订或更多研究的部分。接着修改草稿并如此往复。这种工作流更类似于先思考再研究。修改并继续思考。通过这种迭代过程。生成式工作流可能需要更长时间。但产出质量显著提升。因此AI工作流是一个流程。或基于LLM的应用执行多步骤任务。在这个例子中。你可能用LLM撰写论文首段。使用LLM决定输入搜索引擎的关键词。或调用网络搜索API的关键词。以获取相关网页。基于此。可将下载的网页输入LLM撰写初稿。再用另一个LLM进行反思并确定修订需求。根据工作流设计。甚至可能加入人工审核环节。让AI可请求人类复核。例如关键事实部分。基于此再修改内容。这一过程产生更优质成果。本课程的核心技能之一是将复杂任务。如写论文拆解为更小步骤。供生成式工作流逐步执行。从而获得所需成果。并掌握任务拆解方法。以及构建执行各步骤的组件。这就是。结果发现这是一个既棘手又重要的技能。这将决定你构建工作流程的能力。适用于本课程中众多令人兴奋的应用场景。我们将使用的运行示例。你将与我一起构建的项目是一个研究代理。这就是它的外观示例,你可以输入研究主题。
比如如何建立新火箭公司与SpaceX竞争。我个人并不想与SpaceX竞争。但如果你想的话。可以尝试让研究代理帮助你进行背景研究。这个代理首先规划所需的研究内容。包括调用搜索引擎下载网页资料。综合整理关键发现。绘制大纲。生成编辑版代理。进行连贯性审查。最后生成完整的Markdown报告。它已经完成了这里。建立新火箭公司。与SpaceX竞争。包含引言部分。背景与发现等内容。我认为这确实是一个需要巨大投入的创业项目。我个人并不打算这样做。但如果你想挑战此类项目。这样的研究代理或许能帮你完成初步研究。通过查找、下载多源资料并深入思考。最终产出更严谨的报告。相比直接让LLM撰写论文。我之所以对此感到兴奋是因为在工作中。我已构建了许多专用研究代理。例如在法律文件中。处理复杂法律合规。或某些医疗领域、商业产品研究领域。因此希望通过这个示例。你不仅能学习构建多种应用的工作流程。还能掌握构建研究代理的核心思路。当你需要自行开发定制研究代理时。关于AI 智能体的一个常被讨论话题是。你刚才看到的相对复杂。高度自主的生成式 AI工作流。但也存在许多更简单的流程同样有价值。进入下一视频。讨论生成式工作流的自主程度。这将为你构建不同应用提供框架。并帮助你评估其难易程度,我们下一视频见。
P3 3-自主性程度
代理可以具有不同程度的自主性。几年前。我注意到人工智能社区中出现了一场日益激烈的争议,关于什么是代理。有些人正在撰写论文。声称我有一个代理。而另一些人则会反对。这并不算是真正的代理。我觉得这场辩论毫无必要。因此我开始使用这个术语。我认为如果我们将其作为形容词使用。而非非此即彼的二元对立。要么是代理要么不是。我们可以承认系统可以具有不同程度的自主性。并明确这一点后继续推进构建这些系统的实际工作。而非争论。这个是否足够自主以成为代理。我还记得准备关于遗传推理的演讲时。我的团队成员曾过来对我说嘿。安德鲁。我们不需要另一个新词。你知道我们已经有代理这个词了。你为什么非要创造新词。但我还是决定使用这个术语。之后我在debian di的通讯中发表了一篇文章。专题栏目。并在社交媒体上发布了相关帖子。主张与其争论哪些工作应被包含或排除在真正代理之外。不如承认系统在自主性上的不同层次。我认为这帮助我们超越了这场争论。关于什么是真正的代理。专注于实际构建它们。有些代理的自主性较低。例如撰写关于黑洞的论文。可以有一个相对简单的代理。生成几个网络搜索关键词或查询。硬编码调用网络搜索引擎。获取网页内容。再利用这些内容撰写论文。这就是一个自主性较低的代理示例。具有完全确定性的步骤序列。这在功能上是可行的。在整个课程中的符号约定。我会用左侧的红色标注表示用户输入。例如此处的用户查询。或后续示例中。可能是输入到enic流程的文档。灰色方框表示调用语言模型。绿色方框如网络搜索。以及此处的网页获取方框。这些步骤表示调用其他软件执行操作。例如网络搜索。API调用。或者执行代码获取网站内容。代理可以更加自主,当需要撰写关于黑洞的论文时。或许让语言模型自行决定。是否需要进行网络搜索。或者查询近期新闻来源。
或者搜索网站存档中的最新研究论文。基于此。也许在这个例子中。不是人类工程师。但语言模型在此选择调用网络搜索引擎。之后可能让算法决定需要抓取多少网页。或者如果获取PDF文件。是否需要调用函数。或调用工具将PDF转换为文本。在此案例中可能抓取前几页网页。可以撰写论文。决定是否反思并改进。甚至返回抓取更多网页。最后生成输出。即使以研究代理为例。我们可以看到某些代理自主性较低。执行由程序员确定的线性步骤序列。而有些则更自主,信任模型做出更多决策。具体步骤序列可能由代理自行决定。而非预先由程序员设定。对于低自主性系统。通常所有步骤都预先确定。包括调用的函数如网络搜索。并在第三模块中称为’用中学’。在本课程中可能由人类工程师硬编码。由你和我。大部分自主性体现在生成的文本内容。在高自主性端。代理能自主做出多项决策。包括。例如。决定撰写论文的步骤序列。甚至能编写新函数。或创建可执行的新工具。中间则是半自主系统。我们可以做出部分决策。选择工具。但工具通常更预定义。在本课程中。学习如何构建介于低到高自主性之间的应用。发现低自主性端的应用非常广泛。为众多企业构建极具价值。同时。在更高度自主的一端也有相关应用正在开发中。但这些通常更难以控制。稍显不可预测。同时也有大量活跃的研究。以探索如何构建这些更高度自主的代理。好了,我们进入下一个视频。深入探讨这一主题。并了解使用代理的一些优势。以及为何它们使我们能够完成早期基础应用无法实现的任务。
P4 4-智能体AI的优势
我认为自主工作流最大的优势在于。它能有效完成仅靠个人电脑无法实现的多项任务。当然还有其他优势。包括并行处理能力,能让某些任务快速完成。以及模块化设计,可整合不同组件的最佳部分。从多个来源构建高效工作流。看看具体案例。我的团队收集了一些编码基准测试数据。用于测试不同模型编写代码完成特定任务的能力。这个基准测试称为Human evals。结果显示GPT-3.5。这是首个公开版本的Chi GPU所基于的模型。若直接要求它编写代码。计算机程序在该基准测试中正确率仅40%。这是Parse K指标。GPT-4表现更优。准确率跃升至67%。即使使用非自主工作流。但改进幅度如此之大。从GPT-3.5到GPT-4。这种提升可通过包装GPT-3.5。并结合自主工作流技术实现。这部分内容稍后会讲到。在本课程中。可提示GPT-3.5编写代码。反思代码并优化改进。通过这类技术。实际上能让GPT-3.5达到更高性能。同样GPT-4在自主工作流中表现更佳。即使使用当今最佳语言模型。自主工作流仍能显著提升性能。事实上我们在此例中看到的。模型迭代带来的改进。仍不及在旧模型上应用自主工作流。另一个优势是能并行处理任务。从而比人类更快完成某些工作。例如。要求自主工作流撰写黑洞论文。可同时运行三个模型生成搜索关键词。输入搜索引擎。基于首次搜索结果。筛选出。三个最佳结果。根据第二次搜索识别第二组网页。依此类推。结果发现。人类需按顺序阅读九个网页。或逐一处理。可并行下载所有九个网页。最后将所有这些内容输入现在来撰写一篇论文。因此尽管工作流确实比纯非生成式工作流耗时更长。或者通过直接生成。并且只需提示一次。如果要比较这种生成式工作流。与人类完成任务的方式。瘫痪能力。下载大量网页实际上可以让它完成某些任务。
比单个人类按顺序处理数据构建的方式快得多。在这个示例中。我发现构建工作流时经常做的一件事。是查看各个组件。比如语言模型并添加或替换组件。例如。我可能会检查这里使用的网络搜索引擎。并决定替换为新的网络搜索引擎。在构建通用工作流时。实际上存在多个网络搜索引擎。包括谷歌。可通过Surper访问。以及如必应、DuckDuckGo、TiYu.com等。实际上有很多专为MS设计的网络搜索引擎选项。或者除了进行三次网页搜索。或许在此步骤可替换为新的新闻搜索引擎。以便获取近期突破的最新新闻。关于黑洞信号。最后,不再使用同一语言模型处理所有步骤。我通常会尝试不同的大型语言模型。并尝试不同的模型提供商。以观察哪个在系统不同步骤中效果最佳。总结来说。我使用生成式工作流的主要原因。是显著提升多种应用的性能。此外。还能并行处理人类需按顺序完成的任务。许多生成式工作流的模块化设计也允许我们添加更新工具。有时替换模型。我们将详细讨论构建工作流的关键组件。看看一系列AI应用。让你了解人们已构建的类型。以及你可以自行构建的类型。我们进入下一视频。
P5 5-智能体AI应用
来看一些Enic AI应用的例子。许多企业执行的任务之一是发票处理。给定这样一张发票。你可能需要编写软件提取最重要的字段,对于这个应用场景。支柱可能是技术解决方案。公司地址。应付金额为三千美元。并到期日看起来是2025年8月。在许多财务部门。也许人工会查看发票并识别最重要的字段。我们需要在。何时记录这些信息以确保及时付款。如果使用Enic工作流实现。你可以这样做。你可能输入一张发票。调用PDF转文本API将PDF转换为格式化文本。例如Markdown文本供语言模型处理。语言模型会分析PDF并判断这是否是实际发票。或是否为其他类型的文档应忽略。如果是发票。则提取所需字段。同时调用API或工具更新数据库。以保存最重要的字段到数据库记录。此工作流的一个方面是存在明确的流程遵循。识别所需字段并记录到数据库。这类有明确流程的任务。可能更适合由自主工作流执行。因为它能可靠地分步完成任务。这里还有一个稍难的例子。如果你想构建处理基础客户订单查询的代理。可能需要提取关键信息。确定客户具体订购了什么。客户的姓名是什么。查找相关客户记录。最后草拟回复供人工审核后再发送邮件。同样。这里存在明确的流程。我们将分步实施:接收邮件。输入语言模型进行验证。或提取订单详情,假设客户邮件涉及订单。语言模型可能调用数据库获取信息。这些信息再传递给语言模型草拟邮件回复。语言模型可能使用请求-响应工具。将草拟的邮件放入人工审核队列。审核通过后即可发送。这类客户订单查询代理正在许多企业中部署。来看一个更具挑战性的例子。如果你想构建客服代理回应。不仅仅是客户下单的提问。而是回应更广泛的问题集。客户可能提出的问题。也许客户会询问。你们有黑色牛仔裤或蓝色牛仔裤吗。要回答这个问题。可能需要多次调用数据库API。检查黑色牛仔裤库存。
检查蓝色牛仔裤库存。再向客户作出回应。这是一个需要更复杂查询的例子,根据用户输入。实际上需要规划数据库查询的顺序以检查库存。或者当用户询问。我要退货我买的沙滩毛巾。要回答这个问题。可能需要验证客户是否确实购买了沙滩毛巾。再次核对退货政策。可能您的退货政策仅限购买后30天内。且毛巾必须未使用。如果允许退货。则让代理开具退货凭证。并将数据库记录设为退货待处理。在这个例子中。如果处理客户请求所需的步骤事先未知。就会导致更复杂的流程。LLM基应用需自行决定。这些是完成任务所需的关键步骤。但你将了解最新研究如何解决此类问题。太。再举一个例子。这可能是最难构建的视觉类型。有很多关于代理使用的计算机研究。其中代理会尝试使用网页浏览器和阅读网页。以执行复杂任务。在这个例子中。我让代理检查两家特定联合航空公司的座位是否可用。从旧金山到华盛顿特区的航班。或DCA机场。代理可以访问网页浏览器来执行此任务。在视频中可以看到代理独立浏览联合网站。点击页面元素并填写文本。查看页面内容以执行我的搜索请求。代理分析页面内容。确定完成任务所需的操作及下一步行动。在此案例中联合网站查询遇到困难。于是转而访问Google航班网站搜索可用航班。这里发现多个符合用户查询的航班选项。代理选择其中一个并返回联合网站。此时显示在正确网页上。因此能确定。我询问的航班座位有空位。计算机使用是当前激动人心的研究前沿领域。许多公司正试图让计算机使用代理发挥作用。而你刚才看到的代理最终还是找到了答案。我经常看到代理在使用网页浏览时遇到困难。例如。如果网页加载速度慢。代理可能无法理解发生了什么。许多网页仍超出代理准确处理或阅读的能力。但我觉得计算机使用代理虽然目前还不足以可靠应用。关键应用领域今天仍是未来发展的激动人心且重要方向。
当我考虑构建遗传AI工作流时。顶部也会更简单。通常会是步骤最明确的流程。或者企业已有标准操作程序需要遵循。需要将该流程。编码成AI 智能体。但这样往往能实现更易实施。使用纯文本资产会更容易。因为大型语言模型擅长处理文本。如果需要处理其他输入模态。可能也是可行的。但可能难度稍高。如果任务步骤无法提前预知。如更高级客服代理所需步骤。代理可能需要边执行边规划。这往往更难且不可预测。正如我之前提到的。如果需要处理丰富多模态输入。如声音和视觉。音频处理可靠性通常低于纯文本。这能让你了解可能构建的工作流类型。在自行实现这类应用时。最重要的技能是分析复杂工作流。并拆解出具体步骤。以便在遗传工作流中逐个执行。视频我们将一步步讲解。我们将讨论任务分解,即面对复杂任务。如撰写研究报告或让客服代理回复客户。如何将其拆解为离散步骤以实现工作流。进入下一视频看看。
P6 6-任务分解:识别工作流中的步骤
人们和企业做了很多事情。如何将我们所做的这些有用的事情。分解成离散步骤供enworkflow执行。看看。以构建研究代理为例。如果你想让AI系统撰写某个主题的论文。你可以直接提示它生成输出结果。但若处理需要深度研究的主题时。可能会发现输出仅涵盖表面内容。或者只包含显而易见的事实。但未能深入探讨你希望的层面。在这种情况下。你可能会反思作为人类。我们如何撰写特定主题的论文。我们只需坐下开始写作。还是需要分步骤进行。例如先撰写论文大纲。进行网络搜索。根据网络搜索结果。撰写论文。当我拆解任务为步骤时。我始终在问自己。如果观察这些步骤。每个步骤(一、二、三)是否。可以由语言模型处理。或由简短代码完成。或通过工具调用函数。在这种情况下,我认为语言模型可能能生成不错的提纲。对于我需要它协助分析的许多主题。在第一步。我知道如何用语言模型生成搜索关键词。因此第二步也是可行的。基于网络搜索结果。我认为大型语言模型可以输入搜索结果并撰写论文。这将是撰写论文的合理初步工作流。比直接生成更深入。但当我实施此工作流并查看结果时。可能会发现结果仍不够理想。思考深度仍不足。论文可能显得有些零散。实际上,当我曾构建过使用此工作流的研究代理时。但当我阅读输出结果。感觉有些零散。文章开头与中间部分不完全连贯。与整体内容不完全一致。此时你可能需要反思如何调整工作流。作为人类发现论文略显零散时。可以将第三步进一步拆解。将论文撰写分解为更多步骤。因此不再一次性完成整篇论文撰写。你可能拥有另一种方式。先写出初稿。考虑哪些部分需要修改。接着修订以推进。这就是我作为人类可能处理的方式。不仅仅在第一次尝试就写出最终论文。而是先写初稿然后通读。这也是相当有效的一个步骤。基于我对自己的论文的批判。我会修订草稿。回顾开始时我直接生成。仅一步完成。
但觉得还不够好。于是分解为三个步骤。可能仍觉得不够完善。将其中一个步骤进一步拆分。或分解为三个更细的步骤。形成更复杂的。更丰富的论文生成流程。根据对这一流程结果的满意度。甚至可能进一步调整生成流程。看第二个分解复杂任务的例子。以处理基本客户订单咨询为例。人类客服机构可能执行的第一步。可能是提取关键信息。例如发件人是谁。他们订购了什么。以及订单号是什么。这些都可以处理。我可以直接这样做。第二步是查找相关客户记录。编写并生成相关数据库查询。调取客户的订单信息。以及发货时间等。我认为在具备函数调用能力的LLM中。执行查询。应能直接调用订单数据库。最后在获取客户记录或订单记录后。我可能撰写并回复客户。结合我们获取的信息。第三步也能用LLM完成。如果提供调用API发送邮件的选项。这就是分解客户邮件回复任务的例子。拆分为三个独立步骤。我可以逐一检查这些步骤。我认为具备函数调用能力的LLM。能查询数据库或发送邮件。应能完成这些操作。最后一个发票处理示例。PDF发票转换为文本后。第一步是提取所需信息。账单名称。地址。到期日期。应付金额等等。我应该能够完成这个操作。如果我想检查信息是否已提取。并保存到新数据库条目中。我认为语言模型应该能帮助我调用函数。更新数据库记录。因此要实现这个功能。我们实现一个工作流来执行这两个步骤。在构建工作流时。我把自己视为拥有多个构建模块。一个重要构建模块是大型语言模型。或者可能是大型多模态模型。如果我想处理图像或音频。并且擅长生成文本。决定调用什么。可能提取高度专业任务的信息。我可能还会使用其他AI模型。例如PDF转文本的AI模型。或文本转语音、图像分析模型。除了AI模型。我还拥有多个软件工具。包括可调用的API进行语音搜索获取。可能实时天气数据。发送邮件。查看日历等。
我还可能有信息检索工具。从数据库提取数据。或实现RAG检索。增强生成。可查询大型文本数据库并找到最相关文本。或者我可能有代码执行工具。这是一个让ELM编写代码的工具。在电脑上运行代码完成各种任务。如果这些工具对你来说有些陌生。不用担心。我们将在后续模块详细讲解重要工具。但我认为构建新工作流时。需要观察个人或企业的日常工作。尝试用这些构建模块。如何将这些模块组合起来。以完成系统需要执行的任务。这也是为什么了解可用构建模块。希望到课程结束时你已有更清晰认知。也将帮助你更好地规划。通过结合这些构建模块。构建出所需的ELM工作流。因此,总结其中一个构建基因工作流的关键技能。是观察某人可能执行的一系列操作。并识别可以拆分为独立步骤的部分。当我分析这些独立步骤时。我始终在问自己一个问题。这一步能否通过语言模型或现有工具实现。比如API或我可调用的函数。如果答案是否定的。我通常会继续思考。作为人类我会如何完成这一步。是否可以进一步拆解或细化为更小的步骤。这样。可能更容易通过语言模型或软件工具实现。语言模型或我拥有的软件工具。希望这能让你初步了解任务分解思路。如果你还没完全掌握。不必担心。本课程中我们将通过更多示例讲解。课程结束时你会对此有更深入的理解。但当你构建工作流时。往往需要先构建初始任务。创建初始基因型工作流。多次迭代优化。直到达到预期性能水平。要推动这一改进过程。我发现这对许多项目都很重要。关键技能之一是学会评估工作流。下一视频我们将讨论评估方法。这将是构建工作流的核心组件。同时持续优化你的工作流。以达到所需性能。在下一视频讨论评估方法。
P7 7-智能体AI评估(evals)
我曾与多个团队合作构建基因工作流。我发现其中一个最大预测因素是。能否真正做好某件事。与效率低下形成对比。是否能够驱动严格的评估流程。因此你推动评估的能力。对基因工作流的构建效果影响巨大。在本视频中。我们将快速概述如何构建评估。这将是课程后续模块深入探讨的主题。因此让我们看看构建一个enworkflow后。比如这个用于处理客户订单查询的工作流。实际上很难预先知道。可能出现哪些问题。因此不如在构建评估时。我建议。只需查看输出结果并手动寻找改进空间。例如。你可能阅读大量输出内容。发现它意外提及竞争对手的情况过多。许多企业不希望员工提及竞争对手。因为这会制造尴尬局面。当你阅读这些输出时。可能会发现中心提到。我很高兴你们的产品远优于竞争对手。竞品代码。或有时说当然应该退款。不同于竞品代码。我们退货流程更便捷。你可能会看到这并感叹。我真的不希望它提及竞争对手。这就是一个典型问题。这类问题很难在构建工作流前预见。最佳实践是先构建系统。检查找出不足之处。并找到评估和改进的方法。消除仍不满意的环节。假设企业认为提及竞争对手是错误。在消除这些竞争维度时。一种跟踪进展的方式是添加评估。统计此类错误发生频率。如果你有竞争对手名单如竞品公司。竞对代码。其他公司。则可编写代码在输出中搜索。统计提及竞争对手名称的频率。并计算为整体响应的比例。统计误提竞争对手的频率。关于竞争维度的问题有一个客观指标。这意味着要么提到了竞争对手,要么没有提到。而对于客观标准。你可以编写代码检查该特定错误发生的频率。但因为Elm的输出。自由文本也将成为你评估此输出的标准之一。这可能更具主观性。而编写代码生成黑白评分会更困难。在这种情况下。使用LLM作为裁判是评估输出的常见技术。例如。如果你在构建一个研究代理来处理不同主题的研究。
可以使用另一个LLM并提示它。也许说。为以下文章分配1到5分的质量评分。其中1分是最差,5分是最好的文章。我用Python表达式表示。你知道的。将生成的文章复制粘贴到这里。因此可以提示LLM阅读文章并为其分配质量评分。我让研究代理撰写多份不同研究报告。例如关于黑洞科学的最新进展。或使用机器人采摘水果。在这个例子中。裁判LLM可能给黑洞文章打3分。机器人采摘文章得4分。当你不断改进研究代理时。希望这些分数会随时间逐渐提升。顺便说一句,Ohm实际上在这方面并不太擅长。至少在1到5分的评分尺度上。你可以试试看。但我个人很少使用这种技术。但在后续模块中你会学到更好的方法来评估输出。获得比1到5分评分更准确的分数。尽管有些人会这样做。或许作为初步筛选。作为裁判类型的评估。仅作为后续将学习的AI评估方法的预览。在这门课程中。你已经听过我如何编写代码评估客观标准。例如是否提及了竞争对手。或使用LLM作为更主观标准的裁判。例如这篇文章的质量如何。但后续你将学习两种主要评估方法。一种是端到端评估。测量整个代理的输出质量。以及组件级评估。我们可能测量工作流程中单一步骤的输出质量。这些方法对驱动开发过程不同部分非常有用。而我经常做的一件事。就是检查中间输出或称为LLM的追踪记录。为了理解它未能达到我的预期之处。我们称之为错误分析。我们只需通读中间输出结果。每一步都尝试发现改进机会。结果发现能够执行恶行。evals 和错误分析是一项关键技能。在第四模块中我们将更深入探讨这一点。在这门课程中。我们即将完成第一模块的内容再继续前进。我想与大家分享。我认为构建工作流最重要的设计模式。在下一视频中一探究竟。
P8 8-智能体设计模式
我们通过组合构建模块来创建工作流程。在本视频中我们将这些复杂工作流程进行序列化处理。我想与大家分享几个关键设计模式。这些是关于如何将构建模块组合成更复杂工作流程的思考模式。先看看。我认为构建通用工作流程的四大关键设计模式是反射。使用规划和多协作。让我简要解释它们的含义。我们将深入探讨这些模式的详细内容。主要设计模式之一是反射。我可能会向语言模型代理请求编写代码。结果语言模型可能生成如下代码。这里定义了一个用于特定任务的Python函数。我随后可以构建如下提示。这里提供了一段用于特定任务的代码。复制粘贴。将语言模型刚刚输出的内容放入此处。我要求它。仔细检查代码是否正确。注重效率并给出建设性批评。结果采用这种方式提示的语言模型。可能能指出代码中的问题。如果我将这些反馈重新输入模型。说看起来存在一个错误。能否修改代码修复它。它可能会提供改进后的代码预览。如果你能运行代码并查看执行结果。将反馈输入语言模型。也能使其迭代生成更优版本。例如生成v3版本的代码。因此反射是一种常见设计模式。可让语言模型审查自身输出。或引入外部信息源。例如运行代码查看是否报错。并将其作为反馈进行迭代。从而生成更优的输出版本。这种设计模式并非万能。并不能保证百分之百成功。但有时能显著提升系统性能。我画出这个示意图。显示为单一语言模型被调用。但为预示多代理工作流程。也可以想象让不同模型互相 critique。可以设想使用专门的批评代理。它只是被提示指令的组件。例如你的角色是代码审查。这里提供任务目标代码。仔细检查代码并如此类推。第二个批评代理可能指出错误或运行单元测试。通过让两个模拟代理协作。每个代理只是一个被提示扮演特定角色的语言模型。你需要让他们来回迭代以获得更好的输出。除了反思模式之外。第二个重要的设计模式是使用。
今天可以赋予它们可以调用的功能来完成任务。例如。如果你询问。你知道的。什么是最好的咖啡机。根据评测者。并提供网络搜索功能。它可以真正搜索互联网找到更优答案。或者代码执行工具。如果你问一个数学问题。比如我投资一百美元。复利计算。无论你结束。它可以编写并执行代码计算答案。今天。不同开发者为数学或数据分析提供了多种工具。收集信息。通过从网页获取内容。或各种数据库。与邮件等生产力应用交互。日历等等。以及处理图像。等等更多。语言模型决定使用哪些工具的能力。即。调用哪些函数让模型能完成更多任务。第四种设计模式是规划。这是来自《Hugging GPT》论文的例子。当要求系统。请生成一张女孩读书的图像。图像中的男孩姿势相似。请用你的声音描述新图像。模型可以自动决定执行此任务。需要找到姿势检测模型确定男孩姿势。调整图像生成女孩画面。并生成图像。文本描述。最后文本转语音。因此在规划中,语言模型决定所需行动序列。在此为API调用序列。从而按正确顺序执行步骤。完成任务。而非开发者预先硬编码步骤。这允许模型决定代理规划的步骤。虽然更难控制且更具实验性。但有时能产生惊艳结果。最后是多智能体工作流。就像人类经理可能会雇佣多人协作完成复杂项目。在某些情况下,雇佣多个智能体可能更合理。每个可能专注于不同领域。并共同完成复杂任务。你看到的这张图来自名为Chat Dev的项目。这是陈倩及其合作者开发的软件框架Chat Dev。具有不同角色的多个智能体,如首席执行官。程序员。测试员。设计师等协同合作。如同虚拟软件公司般协作完成各类软件开发任务。考虑另一个例子。如果你想撰写营销手册。或许会组建三人团队。比如研究员进行网络调研。营销人员撰写文案。最后由编辑润色文本。类似地。你可以考虑构建多智能体工作流。其中包含模拟研究智能体。
模拟营销智能体。以及模拟编辑智能体共同执行任务。多智能体工作流更难控制。因为你无法提前预知智能体的具体行为。但研究表明它们能为许多复杂任务带来更好结果。包括撰写传记或决定国际象棋走法等。课程后续还会深入讲解多智能体工作流。希望你已了解智能体工作流的能力。以及构建模块和整合的关键挑战。或许通过这些设计模式实现智能体工作流。当然还包括开发评估系统。以便观察系统表现并持续优化。在下一模块。我将与你深入探讨首个设计模式。即反射机制。你会发现这可能是实现起来相对简单的技术。有时能显著提升系统性能。进入下一模块学习反射设计模式。
P9 【模块2:反射设计模式】1-通过反射提升任务输出质量
反射设计模式是我曾在许多应用中使用过的一种模式。而且实现起来意外地简单。看看。就像人类有时会反思自己的输出并找到改进方法。可以。例如。我可能会写这样一封邮件。如果我快速打字。可能会得到一个质量不高的初稿。当我通读一遍时。可能会说下个月的日期表述不够清晰。汤米可能有空吃晚餐。这里有一个我打错的单词。还忘记签上我的名字。这将让我修改草稿,使其更明确地表达问候。汤米。你五号到七号有空吃晚饭吗。类似的流程。也让语言模型改进输出。你可以提示它们先写邮件初稿并提供邮件版本。邮件版本一。可以将其传递给同一模型。同一个大型语言模型。但使用不同提示并要求其反思并撰写改进后的第二稿。获取最终输出。邮件版本二。我已硬编码了这个提示流程。先提示生成初稿,再提示反思改进。从而得到邮件版本二。类似的流程可用于改进其他类型输出。例如。如果你需要编写代码。可以提示它们编写代码。完成特定任务。可能会得到代码版本一。传递给同一语言模型。或不同模型检查漏洞。并撰写改进后的代码第二稿。不同模型各有优势。因此有时我会选择不同模型处理初稿。以及反思改进环节。例如。推理模型。有时也称为思考模型。在发现漏洞方面表现优异。因此我通常先直接生成代码初稿。使用推理模型检查漏洞。而不是仅仅生成代码。反思代码逻辑。实际上如果能获取外部反馈。来自外部的新信息。在代码情况下,LLM反射能力会变得更强。你可以直接执行代码查看其功能。并通过检查输出结果。包括代码的任何错误信息。这对LLM进行反思提供了极其有用的信息。并找到改进代码的方法。在这个例子中。生成了代码的初稿。但当我运行时。生成了语法错误。当传递这段代码输出。错误日志返回给LLM并要求其反思反馈。并编写新代码。这为其生成更优版本提供了大量有用信息。两段代码。反思设计模式并非魔法。它并不能保证。
我总能百分之百正确。但它可能带来适度的性能提升。需要牢记的设计要点是完美性更具威力。当有新的外部信息补充时。这些信息可以被纳入反思过程。在这个例子中。如果能够运行代码。并将代码输出或错误信息作为反思步骤的额外输入。这能让反思更深入地分析问题所在。发现问题并生成更优的第二版代码。相比没有外部信息输入的情况。需要记住的一点。每当反思有机会获取增强其能力的额外信息时。进入下一视频。我想与大家分享使用反思与直接生成的系统性对比。我们有时称为零样本。提示。进入下一视频。
P10 2-为什么不直接生成呢?
看看为什么我们可能更倾向于使用反射工作流。而不是一次性提示并直接生成答案。通过直接生成完成任务。你只需向语言模型提供指令并让其生成答案。当被要求写一篇关于黑洞的论文时,它会直接生成文本。或者编写计算复利的Python函数。直接输出代码。这里看到的提示示例也被称为零样本提示。让我解释什么是零样本。与零样本提示相比。相关的方法是包含一个或多个所需输出的示例。在提示中展示期望的输出格式。这种方法称为单样本提示。如果在提示中。包含一个所需输入输出对的示例,或双样本、多样本提示。根据在提示中包含的示例数量。因此零样本提示指的是不包含任何示例。如果不包含任何所需输出的示例。但不用担心。如果你还不熟悉这些术语。重要的是这里看到的示例。你只需直接生成一个答案。这也是我所说的零样本提示。提示。因为我们不包含任何示例。多项研究表明反射能提升直接生成的性能。在各种任务中。此图改编自Madan等人的研究论文。展示了不同模型和宽度下实现的不同任务。在没有反射的情况下。阅读此图需观察相邻的浅色条。后跟深色条。浅色条表示零样本提示。深色条表示相同模型。但使用反射,蓝色、绿色和红色表示不同模型实验。如GPT-3.5和GPT-4。以及GPT-3.5和GPT-4。和GPT-4。可以看到对于许多应用。带有反射的深色条显著高于浅色条。但。当然具体应用的知识可能有所不同。这里还有一些生成结构化数据时可能有帮助的例子。例如HTML表格。有时输出格式可能不正确。因此验证模型代码的反射提示会很有帮助。如果是基础HTML。这可能帮助不大。因为大多数模型已擅长基础HTML。但尤其是对于更复杂的结构化输出。可能像一个包含大量嵌套结构的JSON数据。他们的感情可能更容易发现错误。或者让你让模型生成步骤序列。组成一组指令。去做某件事。
例如如何冲泡一杯完美茶。有时可能会漏掉步骤。并使用反思提示让你检查指令。确保连贯性和完整性可能有助于发现错误。或者我实际做过的项目是用语言模型生成域名。但生成的名称有时会有意外含义。或者发音非常困难。因此我使用反思提示双重检查域名。是否有不当含义或问题。或者名称是否难以发音。我们团队确实使用过这个方法。AI助手帮助初创公司 brainstorm 域名需求。我想展示几个反思提示的例子。用于 brainstorming 域名。你可以让它审核你建议的域名。检查每个名称是否易读。检查名称在英语或其他语言中是否有负面含义。输出符合这些标准的简短列表。或优化一封邮件。可以编写反思提示。要求它先审阅邮件初稿。检查语气。验证所有事实。确保声明和承诺准确。这在模型上下文中会更合理。因为已输入大量事实和日期等。为了撰写邮件草稿。所有内容将作为模型上下文提供。根据发现的问题。撰写邮件的下一稿。编写反思提示的小技巧。反思提示。需明确指示要进行审阅。或反思输出初稿。如果能明确设定评估标准。例如域名是否易读。是否可能有负面含义或对邮件。检查语气并验证事实。这能更好地引导模型反思和批判。针对你最关注的标准。我发现提升提示写作的方法之一。是大量阅读他人编写的提示。有时我会下载开源软件并查找提示。在某些特别优秀的软件中。直接阅读作者编写的提示。希望你能理解如何撰写一个基本的反思提示。你甚至可以尝试在自己的工作中应用。看看是否能帮助你在下一个视频中获得更好的表现。我想和大家分享一个有趣的例子。我们将开始探讨。多模态输入和输出将会。算法会反思正在生成的图像或图表。一起去看看。
P11 3-图表生成工作流程
在本模块中你看到的编码实验室。你将体验图表生成工作流。这里使用代理生成美观的图表。结果发现反思能显著提升输出质量。看看。在这个示例中。我有咖啡机的数据显示不同饮品如拿铁。咖啡或热巧克力。或卡布奇诺等的销售情况。以及对应的价格。我们希望代理生成一张图表。比较2024和2025年第一季度咖啡销量。一种方法是编写提示词给arin。LLM。要求生成比较2024和2025年Q1咖啡销量的图表。使用存储在电子表格中的数据。作为CSV文件或逗号分隔值。这里有电子表格文件。LLM可能写出类似这样的Python代码生成图表。使用这段v1代码。如果执行它。可能会生成这样的图表。当我运行这段代码时实际生成的结果。这是第一次运行。这是一个堆叠柱状图。这不是很好的可视化方式。图表看起来并不理想。但你可以将v1代码。连同生成的图表一起输入多模态模型。即m。它们也能接受图像输入。并要求分析这段代码生成的图像。对图像进行批评。找到更好的可视化方法。并更新代码生成更清晰的图表。多模态语言模型具备视觉推理能力。你可以直观查看这个图表。寻找改进方法。当我这样做时。生成了一个堆叠柱状图。但常规柱状图将2024和2025年咖啡销量分开。我认为这是更美观清晰的方式。当你进入编码实验室。请随意尝试解决问题。看看能否生成更优质的图表。因为不同元素各有优劣。有时我会在初始生成和反思时使用不同元素。例如可能用一个m生成初始代码。比如OpenAI。Gb四或Gb五。或者像这样的模型并进行提示。比如像这样的提示。编写生成可视化图表的Python代码等。反思提示可能像这样。要求其扮演专家数据分析师角色并提供建设性反馈。提供代码版本。可能是生成代码的一部分。可能还需包含代码生成的历史记录。并要求其针对特定标准进行批判。记得我们给出具体标准如可读性。
清晰度和完整性。这能帮助你更好地确定下一步行动。要求其编写新代码实现改进。你可能会发现使用推理模型进行反思。可能比非推理模型效果更好。当你尝试不同模型进行初始生成和反思时。这些是你可以切换或组合的不同配置。当你进入代码实验室时。希望你现在能愉快地可视化咖啡销售数据。在构建应用程序时。你可能会想知道反思是否真的提升了你的应用性能。根据多项研究。在某些情况下反思能小幅提升性能。在某些情况下则显著提升。而在其他应用中可能几乎没有效果。因此了解其对应用的影响很有必要。同时也能指导你如何调整初始生成或反思提示。以在下一视频中获得更好性能。看看反思工作流的评估。我们进入下一视频继续。
P12 4-评估反射的影响
反思通常能提升系统的性能。但在决定保留它之前。我通常会先检查它实际提升了多少性能。因为它需要多一步操作,可能会稍微拖慢系统。看看反射工作流的弊端。看一个使用反射的例子。为了改进语言模型生成的数据库查询以获取数据回答问题。假设你经营一家零售店。可能会收到类似哪种颜色产品总销量最高的问题。你可能让语言模型生成一个数据库查询。如果你了解数据库语言如SQL。SQL。它可能会生成类似这种语言的查询。但如果你不熟悉SQL。不用担心。但在编写数据库查询后。而不是直接使用它从数据库获取信息。你可能会有一个M。版本不同。对版本进行反思。对一个数据库查询进行反思并改进为更好的版本。执行该数据库查询从数据库获取信息。最终由语言模型回答问题。问题在于使用第二个语言模型进行反思和优化数据库。或SQL查询。是否真正提升了最终输出。为了评估这一点。我可能会收集一组问题或提示连同真实答案。例如:2025年5月售出多少件商品。库存中最贵的商品是什么。我的店铺中有哪些款式在售。可能准备十到十五个。提示的真实答案。运行无反射的工作流。无反射意味着直接使用第一个语言模型生成的SQL查询。并查看其返回的答案。有反射则使用第二个模型优化后的查询。M已对其进行了反思。查看从数据库获取的答案。测量无反射和有反射的正确率。在这个例子中。无反射正确率87%。八七成时间正确。有反射正确率95%。这表明反射显著提升了数据库查询质量。我能准确提取正确答案。开发者常做的另一件事是修改反射提示。例如。是否添加反射提示和指令以加快数据库查询速度。或使其更清晰。或者你可能有不同的改写思路。无论是初始生成提示还是反思提示。一旦你设置了这样的恶意内容。你可以快速尝试不同提示并测量系统正确率。当你调整提示时。为了了解哪些提示最适合你的应用。如果你在尝试大量提示。
构建恶意内容。S非常重要。这能帮助你系统化选择不同候选提示。但这个例子展示了如何使用客观评估。因为存在正确答案。物品数量是1201。答案要么正确要么错误。对于需要主观而非客观评估的应用。在上期视频中未使用反思的绘图示例。我们有带反思的柱状图。我们得到了这个图表。但如何确定哪个图表更好。我知道我更喜欢后者。但不同图表在不同维度上变化。如何判断哪个更好并衡量这些图表的优劣。这更为主观。而非纯粹黑白的客观标准。对于这些主观标准。你可以使用语言模型作为裁判。一个基本方法可能是将两个图表输入模型。一个多模态模型可接受两张图像输入。只需询问哪个图像更好。结果发现这并不奏效。稍后我会分享更好的方法。但你可以同时提供评估标准。用于比较两个图表。例如清晰度。美观程度等。但使用模型比较两个输入存在已知问题。判断哪个更好。发现答案往往不够理想。可能过度依赖裁判模型的提示词。有时排名与专家判断不一致。其中一个表现是多数模型存在位置偏见。许多模型更倾向于选择第一个选项。而非第二个选项。实际上我在多个案例中发现。无论呈现哪个选项。模型会判定第一个更好。而有些模型偏好第二个选项。但大多数更倾向第一个选项。与其让模型比较输入对。使用评分量表能获得更一致的结果。例如,你可以提示模型执行某项任务。给定一张单张图像。根据质量评估标准评估附图。该评估标准或评分准则可能包含明确指标。比如情节是否有明确标题。坐标标签是否齐全,图表类型是否恰当。等等类似此类少量评估标准。结果发现。与其让模型在1到5分间评分。它往往难以准确校准。如果你改为提供。五个二元判断标准。五个0-1分项标准。并让其给出五个二元评分。将这些分数相加得到1到5或1到10的数值。若使用十个二元标准则结果更稳定。因此若收集若干。例如十个。十五个用户针对不同可视化图表的查询。
用户可能需要展示咖啡机销售数据。则可生成无反射或带反射的图像。并使用此类评估标准对每个图像评分。检查。或带反射生成的图像是否显著优于无反射版本。一旦构建好此类图像集。若需修改初始生成提示。或调整反思提示。也可重新运行评估以验证。更新某个提示是否能让系统生成。更符合评分标准的图像。从而获得更多分数。这也为持续优化提示提供了方法。以实现持续性能提升。在构建评估系统时。对于反思任务或其他工作负载。基于代码的评估通常更易管理。在数据库查询示例中。我们建立了真实示例和输出的数据库。并通过代码统计系统正确率,形成客观评估指标。相比之下。对于主观性任务。可能需要人工裁判参与。但通常需要更多调优。例如需设计合适的评估标准。使裁判判断更准确可靠。确保输出结果可信有效。因此我希望这能帮助你理解如何构建评估系统。用于评估反思过程。或更广泛地评估不同自主工作流。掌握有效构建评估系统的方法对优化工作流至关重要。而在后续视频中我还会进一步详细讲解这一点。但现在你已经了解了如何使用反射的基本方法。在接下来的视频中,我希望能深入探讨其中一个方面。那就是能够从外部获取额外信息。而这会让反射功能表现得更好。在本模块的最后一个视频中。看看如何通过这项技术使反射任务更高效。我们下期视频再见。
P13 5-使用外部反馈
外部反馈的反思。如果你能获取到这会比反思更强大。仅使用语言模型作为反馈来源。看看当我构建应用程序时。如果我只是进行直接生成的提示工程。或者使用零样本提示。随着时间推移性能可能呈现这样的表现。最初当我调整提示时。性能会有所提升一段时间。但随后逐渐趋于平缓或停滞。尽管继续优化提示。却很难达到更高水平的性能。与其浪费时间在。调整提示上。有时反而更好。如果在早期阶段。就开始加入反思机制。有时能带来性能提升。有时提升较小。有时提升更大。但这会增加复杂度。但如果从这时开始加入反思。可能在流程中这个阶段。开始优化反思部分。或许最终性能会呈现这样的曲线。但事实证明如果能获取外部反馈。使得新信息来源不再仅依赖语言模型。基于之前的信息进行反思。而是加入新的外部信息。随着持续优化提示和外部反馈。甚至能实现更高水平的性能。这是提示工程中值得考虑的因素。当你感到投入产出比下降时。发现大量调整提示效果有限。或许可以考虑是否存在。甚至更好的外部反馈。能够提升性能曲线。将平缓的红线转向更高性能轨迹。再次提醒我们之前提到的反馈来源。对于。如果是编写代码的话。只需执行代码查看输出。生成输出或错误信息。并将输出反馈给语言模型以获取新信息。再利用这些信息编写新版本代码。以下是更多软件示例。代码或工具可生成新信息辅助反思。如果你在撰写邮件时。有时提及竞争对手名称。则可通过编写代码或工具进行模式匹配。或许通过正则表达式模式匹配来搜索输出中的竞争名称。每当发现竞争对手的名字。只需将其反馈给ELM。作为批评或输入。这是非常有用的信息需要告知它。只需重写文本而不提及这些竞争对手。或者另一个例子。你可能会使用网络搜索或查阅其他可信来源以验证事实。检查一篇论文。如果你是研究代理并声称泰姬陵建于1648年。从技术角度。
泰姬陵实际上是在1631年被委托建造。并于1648年完工。这可能并不完全错误。但也没有准确反映历史事实。为了更准确地描述。这座美丽建筑的建造时间。如果进行网络搜索获取相关片段。解释泰姬陵建造的具体时期。并将这些作为额外输入提供给反思代理。可能用这些信息撰写更完善的文本。关于泰姬陵的历史。最后一个例子。如果你用LLM撰写文案。比如博客文章或研究论文摘要。但生成的内容有时会超出字数限制。ELM仍然不太擅长严格遵循字数限制。编写代码统计精确的单词数量。如果超过字数限制。将这些数据。返回给LLM并要求重新尝试。这有助于更准确地达到所需输出长度。在这些三个示例中。你可以编写代码获取初始输出的额外信息。无论是发现竞争对手名称还是网络搜索结果。或是精确的字数统计。并将其输入反思环节。以帮助提升输出质量。反思功能非常强大。同样。希望你在后续工作中发现其价值。在下一模块我们将基于此讨论工具使用。除了之前看到的两个示例。你将学习如何系统调用不同函数。这将使应用功能更强大。希望你喜欢学习反思相关内容。我现在将总结你刚刚学到的内容。希望在下一视频见到你。
P14 【模块3:工具使用】1-什么是工具?
在本模块中,你将学习如何使用LMS。这意味着允许你的模型自行决定何时可能需要请求调用函数。以执行某些操作。或获取某些信息。或执行其他操作。就像我们。人类可以借助工具完成远超自身能力的事。仅凭双手无法做到。手臂。也是如此。同样,通过访问工具也能完成更多任务。但与其使用锤子、扳手和钳子。当我们提供工具时。即让模型请求调用的函数。正是这使得模型能实现更多功能。来看一个例子。如果你想询问一个已训练的LLM。可能是在几个月前训练的。时间是什么。该训练模型并不确切知道当前时间。因此希望你的回应。抱歉。我没有当前时间的访问权限。但如果你编写一个函数并赋予模型调用该函数的权限。则能让模型生成更有用的回答。当我们允许模型调用函数时。或更准确地说,允许请求调用函数。这就是我们所说的工具使用。而工具仅仅是提供给模型的函数。模型可以详细请求调用。这就是本例中的工具使用方式。我将向模型提供获取当前时间的函数。如之前幻灯片中展示的那样。当你随后提示模型。几点了。模型可以决定调用获取当前时间的函数以返回当前时间。该结果将反馈到对话历史中供模型使用。最终模型输出可能是’下午3:20’。步骤序列如下。输入提示是否。在此案例中,模型会查看可用工具集。本例中仅有一个工具。但会检查所有可用工具。并决定在此例中调用该工具。该工具是一个函数。随后返回一个值。该值被反馈给模型。最后模型生成输出。工具使用的一个重要方面。我们可以让模型自行决定是否使用任何工具。对于相同的设置。如果我要问绿茶中的咖啡因含量是多少。模型不需要知道当前时间就能回答这个问题。因此可以直接生成答案。绿茶含有这种量的咖啡因。并且无需调用我幻灯片中的获取当前时间函数。我将使用这个带横线的方框标注在模型上方。表示我们为模型提供了一组工具。供模型在适当时候选择使用。
这与之前视频中的一些示例不同。作为开发者我已硬编码了。例如在研究代理的这个阶段我总是进行网络搜索。与获取当前时间函数调用不同。是否请求调用取决于你的决定。向获取当前时间函数发起调用。同样。我们将使用这个方框标注表示。当我们提供一个或多个工具给模型。让模型决定是否调用。这里还有一些更多示例。何时使用。可能帮助应用生成更好的答案。如果你询问它。能否在加州山景城找到意大利餐厅。如果它具备网络搜索工具。模型可能会选择调用网络搜索引擎。查询山景城的餐厅。并利用获取的结果生成输出。或者如果你经营零售店。是否希望回答问题。例如展示购买过白色太阳镜的客户。如果模型被授予访问数据库查询权限。则可以查询销售表中的相关条目。查找购买过白色太阳镜的记录。利用这些数据生成输出。最后。如果你想进行利率计算。如果我存入五百美元。十年后利率为百分之五。我会得到多少。如果你拥有利率计算工具。则可以调用该函数进行计算。或者你会发现后续内容中让模型编写代码。我们只需编写这样的数学表达式。进行计算。这也是让模型计算正确答案的方式。作为开发者。你需要思考应用需要实现哪些功能。应用程序真正需要执行的任务。需要创建所需的函数或工具,使其对语言模型可用。让其能够调用合适的工具完成任务。比如餐厅推荐或零售问答系统。或者财务助手可能需要这样做。根据你的应用场景,可能需要实现并提供不同的工具给语言模型。到目前为止。我们之前讨论的示例大多只提供一个。或两个/一个函数供语言模型使用。但在许多用例中需要为语言模型提供多个工具或函数。以便它能够选择调用其中任意一个。例如。如果你在构建日历助手代理。可能需要让它执行请求处理。比如请在日历中查找周四的空闲时段。并与艾丽丝预约。在这个例子中,我们可以为语言模型提供。创建预约的工具,即发送日历邀请。检查日历状态。
查看何时有空闲时间,以及删除预约。如果需要取消现有日历条目。根据指令集。系统会首先决定从可用工具中。最可能首先使用的是检查日历。调用检查日历函数以返回周四的空闲时间。基于这些信息。将反馈结果返回给语言模型。可以决定下一步选择时段。比如下午三点,再调用预约函数。发送日历邀请。同时邀请艾丽丝并添加到我的日历。该操作的输出应为确认信息。表明日程已成功发送。反馈给语言模型。最后语言模型会告知用户。您的预约已与艾丽丝在周四下午三点安排妥当。赋予语言模型工具访问权限非常重要。这将显著增强应用功能。在下一视频中。我们将学习如何编写函数。如何创建工具。并使其对语言模型可用。进入下一视频。
P15 2-创建工具
大型语言模型决定调用函数的过程可能显得有点神秘。最初因为语言模型只是被训练生成输出文本或文本标记。这个过程在这个视频中是如何运作的。我想一步步带你们了解。让机械臂能够调用函数的过程到底是什么样子的。先看看。工具其实就是代码或函数。一个元素可以像这样请求执行。我们之前视频中看到的获取当前时间函数。当今领先的模型都是直接训练使用工具的。但我想带你们了解。如果需要自己编写。提示指令来告诉它何时使用工具。这就是我们早期需要做的事情。在模型直接训练使用工具之前。尽管我们现在不再完全这样操作。这能帮助你更好地理解整个过程。视频会讲解更现代的语法。如果你已经实现了获取当前时间的函数。为了将这个工具提供给语言模型。你可能会写出这样的提示。你告诉模型:你有一个名为获取当前时间的工具可以使用。请输出以下文本。打印全部大写函数。打印获取当前时间。如果我看到这段全部大写函数和获取当前时间。这就表明你需要调用获取当前时间函数。当用户询问时间时。模型将意识到需要调用获取当前时间的请求。因此模型会输出被指示的全部大写函数。调用获取当前时间。我不需要编写代码检查模型输出。查看是否存在全部大写函数。如果存在则需要提取参数。通过获取当前时间确定要调用的函数。需要编写代码实际调用该函数。并提取输出结果。例如输出为八点。这属于开发者编写的代码。我的代码需要将八点时间处理。将八点返回给模型作为计算历史的一部分。并记录对话历史。当然包括初始提示内容。函数调用请求等信息。最后需要知道之前发生了什么。你是否提出了这个问题。请求函数调用。调用函数并返回八点。最后可以综合所有信息生成最终回复。因此现在时间是八点,明确说明。为了调用一个函数。语言模型不会直接调用函数。相反。输出特定格式的内容。比如这样来告诉我需要调用该函数。
告知函数的输出结果是什么。在这个例子中我们只提供了一个函数。但可以想象如果提供三个或四个函数。可以让它输出全大写的函数名称。是被调用的函数名称。甚至可能包含这些函数的参数。实际上现在让我们看一个稍微复杂一点的例子。获取当前时间函数接受时区参数。以获取所需时区的当前时间。在第二个例子中。我编写了一个获取指定时区当前时间的函数。此处时区是传递给获取当前时间函数的输入参数。为了让模型使用此工具回答问题。比如新西兰现在几点。因为我的答案在那里。如果查询。我会查找新西兰当前时间。为了让模型使用此工具。你可能需要修改系统提示。你可以使用获取当前时间工具指定时区。使用时需输出以下内容获取当前时间。包含时区信息。这是一个简化的提示。实际上。你可能需要在提示中添加更多细节。说明函数使用方法等。在这个例子中。模型将意识到需要获取新西兰时间。因此会生成输出。例如函数:获取当前时间。太平洋/奥克兰。这是新西兰时区。因为奥克兰是新西兰主要城市。我需要编写代码检查。输出中是否全大写出现函数。如果出现则提取需要调用的函数。随后调用带有指定参数的获取当前时间。该参数由模型生成。可能是奥克兰并返回凌晨四点。像往常一样。将结果输入模型并处理。总结为新西兰现在四点。以下是让模型使用工具的流程。必须向模型提供这两部分。实现该函数。告诉LLM该功能可用。当机械臂决定调用它时。生成特定输出提示你需要调用该函数。对于机械臂。你需要调用该函数。获取此输出。将刚调用的函数输出取回并返回给LLM和机械臂。利用该输出继续执行下一步操作。在本视频示例中则是生成最终输出。但有时你甚至可能决定下一步再调用另一个工具。这种全大写函数语法。显得有点笨拙。这是我们过去在elm未原生训练前的做法。或让模型自行知晓如何请求工具。符合现代规范。
无需告知它输出所有猫函数。搜索所有猫函数等。而是训练使用特定语法明确请求。当需要调用工具时。在下一视频中讲解。我想与你分享现代语法的实际形式。让elm的工具请求被调用。我们进入下一视频。
P16 3-工具语法
看看如何编写代码来拥有自己的get工具。这里是我们之前的。不带时区参数的获取当前时间函数。让我展示如何使用ai套件开源库。顺便说一下,要拥有自己的调用工具。从上一个视频中可以看到。语言模型不会调用工具。语言模型只是请求你调用工具。但在构建生成工作流的开发者中。我们很多人偶尔会直接说语言模型调用工具。尽管这在技术上并不准确。但因为这是更简洁的说法。这里的语法与调用语言模型的OpenAI语法非常相似。不过这里我使用的是ai套件库。这是一个我和一些朋友开发的开源包。它能轻松调用多个语言模型提供商。代码语法。如果你觉得这看起来很多。不用担心。在代码实验室中你会看到更多。但简而言之这与OpenAI语法非常相似。你会说。响应等于客户端检查完成。创建。选择模型。这里我们将使用OpenAI模型。Gp四消息等于消息假设你已将其放入数组。要传递给语言模型的消息。等于。你希望语言模型访问的工具列表。这里只有一个工具。即获取当前时间。无需过多担心最大轮次参数。这是因为工具调用返回后。模型可能会决定再次调用工具。之后工具调用返回后。模型可能再次调用另一个工具。最大轮次只是设置一个上限。你希望语言模型连续调用工具的次数。在无限循环中停止。实际上你几乎不会遇到这个限制。除非代码有非常激进的操作。我通常不关心最大轮次参数,一般设为五。但实际上这并不重要。使用ai套件后发现。获取当前时间函数会自动描述给语言模型。以便模型知道何时调用它。无需手动编写长提示。告诉模型获取当前时间。ai套件的语法会自动处理。为了让它看起来不那么神秘。其实它是通过查看与get_current_time关联的文档字符串来实现的。通过这些注释。获取当前时间以便向语言模型描述此函数。为了说明它是如何工作的。这里是函数代码。这里是一段代码片段。
使用AI套件在后台调用语言模型。这将创建一个详细描述函数的JSON模式。而这里右侧实际传递的是。并将提取函数名称。即当前时间。从文档字符串中提取函数描述。告知语言模型此函数的功能。使其能决定何时调用。有些API需要手动构建此JSON模式。将JSON模式传递给。但该包会自动为您处理以展示更复杂的示例。如果你有包含输入时区参数的复杂get_current_time工具。AI套件将创建更复杂的JSON模式。同样提取函数名称get_current_time。从文档字符串中提取描述。并识别参数并描述给语言模型。基于左侧显示的文档。因此在生成函数调用参数时。它知道应使用类似美国。纽约或太平洋奥克兰。或其他时区。如果执行左侧下方的代码片段。将使用OpenAI GPT-4模型调用函数。如果需要则调用该函数。获取函数输出并反馈给模型。最多进行五轮交互。返回响应注意当语言模型请求调用get_current_time函数。AI套件或客户端。将自动调用get_current_time函数。无需手动执行。所有操作均在单个函数调用中完成。需注意其他实现可能需要手动完成此步骤。但使用此特定包。所有操作均封装在客户端中。聊天完成。创建函数调用。您已了解如何让语言模型调用函数。希望您在实验室中尝试并享受这个过程。当提供几个函数时效果尤为惊人。模型会采取行动获取更多信息以满足需求。如果您之前未尝试过。相信您会发现这非常酷。事实证明所有工具中最强大的是。这里有一个。这有点特别。这是一个代码执行工具。结果非常强大。如果你能开启。你可以编写代码。我将为你提供一个执行代码的工具。因为代码能做很多事情。我们赋予它编写代码并执行代码的灵活性。这实际上极其强大。提供一个工具给手臂。代码执行很特别。进入下一视频,讨论警报的代码执行工具。
P17 4-代码执行
在几个我参与的项目中。我提供了编写代码的选项。执行任务。我希望它能够。我已经尝试过几次。我对生成的代码解决方案的巧妙程度感到非常惊讶和欣喜。为了完成各种任务而生成的代码。如果你还没有经常使用代码执行功能。你可能会对这个能让你的应用实现的功能感到惊喜和欣喜。看看。以构建一个能处理数学题的应用为例。文字问题并为你解答。你可能会创建加法工具。减法工具。乘法工具和定义数字工具。如果有人要求请计算十三点二加十八点九。就会触发加法工具。得到正确答案。但假如有人输入。什么是√2的平方根。你可以编写一个新的平方根工具。但可能还需要处理指数运算。事实上。观察现代科学计算器的按键数量。需要为每个按键创建单独的工具。以及我们想要进行的更多数学计算。与其逐一实现这些功能。另一种方法是让系统自动生成并执行代码来指导算法。你可以这样编写提示。编写代码解决用户的查询。将答案作为Python代码返回。用执行python和闭合标签包裹。例如当用户询问√2的值时。使用模式匹配。例如。用正则表达式查找起始和结束标签。提取中间的代码。这里可以看到绿色方框中的两行代码。接着执行这段代码并获取结果。在这种情况下得到1.4。一。四二。依此类推。最后。这个数值结果会返回给主程序。生成格式美观的答案。代码执行步骤有多种实现方式。一种方法是使用Python的exec函数。这是Python内置函数。将执行你传入的任何代码。这对于编写自己的正确代码非常强大。并让你执行这段代码。尽管存在一些安全影响,我们稍后会在视频中看到。还有一些工具可以让你在更安全的沙盒环境中运行代码。而且。当然。平方根二是一个相对简单的例子。我也能准确编写代码来。例如。进行利息计算并解决比这更复杂的数学问题。这一理念的一个改进。正如我们在反射部分看到的,如果代码执行失败。
如果出于某种原因。生成的代码并不完全正确。将错误信息返回给语言模型,让它进行反思。并可能修改代码再试一两次。这有时也能得到更准确的答案。运行任意代码确实存在小概率引发问题。最近我的团队成员使用了一个高度编码器。它实际上选择删除了项目目录中的星号派。确实有一个真实案例。最终该解码器确实道歉了。确实没错。这真是个极其愚蠢的错误。可能吧。我很高兴这个代理解码器真的道歉了。但我已经删除了很多Python文件。不幸的是团队成员有GitHub仓库备份。没有造成实际损害。但这样会很糟糕。如果这个。你知道的。任意代码。因错误删除大量文件的代码被执行且没有备份。代码执行的最佳实践是运行在沙盒环境中。实际上单行代码的风险并不高。如果我说实话。许多开发者会未经仔细检查就执行来自语言模型的代码。但如果你想更安全。最佳实践是创建沙盒,以防语言模型生成的代码有误。可降低数据丢失或敏感数据泄露等风险。沙盒环境如Docker。或e2b是轻量级沙盒环境。可降低任意代码执行的风险。避免损害系统或环境。事实证明代码执行非常重要。许多语言模型的训练师实际上在做特殊工作。确保代码执行在其应用中运行良好。但我希望。当你将其作为另一个工具添加到可提供给。或让你的应用程序变得远更强大。而我们讨论的内容。你需要创建工具并逐步将其提供给你的语言模型。结果发现许多团队在构建类似的工具。不得不完成构建函数并使其对应用可用的所有工作。但最近出现了一个新标准,称为MCP模型上下文协议。这让开发者更容易访问大量工具集。供ELM使用。这是一个越来越被团队采用的重要协议,用于开发基于语言模型的应用。在下一视频中学习MCP。
P18 5-MCP
Mccp。模型上下文协议。是由Anthropic提出的一项标准。但现在被众多公司和开发者采用。作为让语言模型访问更多上下文和工具的方式。因此了解这一协议将为你的应用提供更多资源访问。一起来看看。这是MCCP试图解决的痛点。当一位开发者正在编写一个需要整合Slack数据到Google Drive的应用。还有GitHub。或者从PostgreSQL数据库获取数据。他们需要编写代码来封装Slack接口。提供API以供应用程序调用函数。编写代码封装Google Drive接口。提供API传递给应用程序。同样适用于这些其他工具或数据源。在开发社区中发生的事情是。如果另一个团队在构建不同的应用程序。他们也会自行集成Slack、Google Drive和GitHub。依此类推。因此许多开发者都在围绕这些类型的数据源构建自定义包装器。因此如果有m个应用程序正在开发,同时存在n种工具。社区完成的总工作量是m乘以n。mcb提出了一种标准,使应用程序能够访问工具和数据源。因此社区现在需要完成的工作量变为m加n。而非m乘以。mcscp的初始设计重点是如何提供更多信息。给LLM或如何获取数据。许多初始工作只是单纯的数据获取。如果你阅读提到这些资源的mscp文档。但mcscp可以访问两者的数据。以及应用程序可能需要调用的更通用功能。事实证明存在许多MCP客户端。这些是需要访问工具或数据的应用程序。以及服务器。通常是软件封装层。随后可访问Slack、GitHub或Google Drive中的数据。或允许在不同类型的资源上执行操作。因此今天已有大量mccp客户端在使用这些工具。或者资源。以及提供工具和资源的MVP服务器。我希望你能用它来构建自己的MSCP客户端。你的应用也许有一天会成为MCC客户端。
如果你想为其他开发者提供资源。或许你可以搭建自己的MCP服务器。将来让我展示一下使用MCCP客户端的快速示例。这是一个Claude桌面应用。并且已连接到GitHub的MCCP服务器。我输入了这个查询。总结了GitHub仓库的read me talk markdown文件。这个网址。这实际上是一个AI套件仓库。是这个MCCP客户端应用。使用GitHub的MCCP服务器进行请求。请从仓库获取reboot markdown文件。来自该仓库的AI套件。获取这个响应。内容相当长。这随后反馈到最后的上下文。语言模型生成markdown文件的摘要。我输入另一个请求。让我输入最新的拉取请求是什么。这促使语言模型使用MCCP服务器发起不同请求。列出拉取请求。这是GitHub MCCP服务器提供的另一个工具。因此使用repo ai suite sort发起请求。将更新为二十并以此类推。推测这个响应被反馈到。语言模型随后生成该仓库最新拉取请求的简洁文本摘要。MCCP是一个重要标准。如果你想了解更多。深度学习AI还有一门深入讲解的简短课程。关于MCCP协议,课程结束后可进一步学习。如果你感兴趣的话。希望这段视频能简要介绍。为什么它有用。以及为何许多开发者现在采用这一标准。这带我们进入使用教程的最后一个视频。希望通过提供工具访问权限。你能构建更强大的应用。在下一模块中表现更出色。我们将讨论评估与错误分析。我发现的一个关键区别点。能高效执行工作流的人。与效率较低的团队相比。在于能否严格执行评估流程。我认为这是本课程最重要的模块。希望分享一些最佳实践,如何通过评估。驱动enic工作流开发。期待在下一模块与你相见。
P19 【模块4:构建智能体AI的实用技巧】1-评估(evals)
在本模块中。我想分享几个构建高效AI工作流的实用技巧。我希望这些技巧能让你在构建这类系统时效率大幅提升。相比普通开发者更具优势。我发现开发AI系统时。很难预先知道。哪些地方会有效哪些地方效果不佳。这才是你应该重点投入的地方。非常常见的建议是尝试构建一个快速简易的系统作为起点。这样你就可以实际测试并观察。看看哪些部分尚未达到预期效果。以便后续能更有针对性地进行深入开发。相比之下。我发现有时。你知道的。不要花太多周时间。空谈假设。如何构建。通常更好的做法是用安全合理的方式快速构建系统。以合理的方式。处理泄漏数据。以负责任的方式。但只需快速构建。这样你就可以查看。利用这个初始原型来优先级排序并推动进一步开发。从构建原型后的示例开始。我想用第一个例子。之前展示过的发票处理工作流。包含提取四个必填字段的任务。保存到数据库记录。在构建此类系统后。你可以找到十几张或二十张发票。可能十张或二十张发票。逐一查看输出结果并检查哪些部分有效。以及是否存在任何错误。查看两张发票。发现第一张发票正常。第二张发票的输出看起来正确。可能混淆了发票日期。即发票的开具日期和到期日期。在这个任务中我们需要提取到期日期。以便后续按时付款。因此我可能在文档或表格中记录。或在电子表格中注明对于第二张发票。日期存在混淆。第三张发票正常。第四张发票正常等等。但当我继续这个示例时。发现有很多类似日期混淆的例子。这正是通过此类示例进行分析的基础。这。在这种情况下,你可能会得出一个常见错误模式,即系统在处理日期时存在困难。在这种情况下。你可以考虑的一个方法是。当然,首先要弄清楚如何改进你的系统。使其更好地提取到期日期。同时可能需要编写评估指标来衡量提取准确性。与实际提取的到期日期进行对比。如果你发现系统错误提取了账单地址。
谁知道也许你有发音奇特的账单名称。因此系统可能在处理账单时遇到困难。尤其是当国际账单方名称可能包含非英文字母时。这时你可能需要专注于构建账单地址的评估系统。之所以快速构建简易系统。并检查输出结果非常有帮助。因为它能帮助你决定当前应优先评估哪些环节。如果你决定修改系统以提高准确性。在提取发票到期日期时的准确性。要推进下一步。创建评估指标可能是个好主意。以衡量数据提取的准确性。可能有多种方法可以实现。但让我分享。我是如何操作的。创建测试集或评估集。我可能会找到10到20张发票并手动记录。正确的到期日期是什么。例如某张发票的到期日期是八月。2025年20日。并以标准年月日格式记录。以便后续代码评估更方便。我会编写提示语让语言模型始终按。年月日格式输出到期日期。编写代码提取模型输出中的日期部分。这就是我们需要关注的到期日期。因此只需关注这个日期。这需要正则表达式模式匹配。你知道的。四位数字表示年份。两位数字表示月份。两位数字表示日期。提取这部分内容。接着编写代码进行测试。判断提取日期是否等于实际日期。即我手动标注的真实日期。因此使用包含。约20张发票的评估集。通过修改系统观察正确提取日期的比例。是否有所提升。随着我调整提示或系统其他部分。总结一下我们到目前为止看到的内容。我们构建了一个系统。分析输出结果。以发现系统可能存在的不足之处。例如截止日期错误。针对这个重要输出进行改进。实施。一个小规模评估只需两个示例来帮助我们跟踪进展。这让我可以回到两个优点。尝试不同算法等以提升截止日期准确性这一指标。这就是改进整个工作流程通常的感觉。查看输出结果。发现问题所在。如果你知道如何修复。直接进行修正。但如果需要更长的改进过程。则建立评估并以此驱动进一步开发。另一个需要考虑的是工作一段时间后。
如果最初两个示例不够理想。可能无法覆盖所有需求场景。或者二十个示例数量太少。可以随时扩展评估集以确保更全面。反映系统性能是否达到满意标准的个人判断。这只是第二个示例。构建一个Instagram文案助手。保持内容同步。假设营销团队要求我们生成的文案需。最多十词以内。展示产品图片。比如我们要推广的太阳镜。用户查询如。请为这些太阳镜撰写销售文案。使用语言模型或大型多模态模型。分析图片和查询生成产品描述。营销文案可能出错的方式有很多。但假设查看输出结果。发现生成的文案大部分听起来正常。但有时可能过长。对于太阳镜输入。生成十七词若咖啡机则无问题。时尚。可以。蓝衬衫十四词。搅拌机十一词。看起来在这个例子中。模型难以遵循长度限制。营销文案助手可能出现很多问题。但若发现输出长度不达标。则可建立评估指标进行跟踪。以便持续改进。确保它在听力长度指南上有所改进。因此创建一个评估来衡量文本长度。你可以创建一组测试任务。标记一副太阳镜。一台咖啡机等等。可能创建十个到二十个示例。将每个示例输入系统。编写代码测量输出的词数。这是测量文本词数的Python代码。最后比较生成文本与十词目标限制的长度。如果词数等于十。正确计数加一。这与之前的发票处理示例不同之处在于没有每个示例。真实标注。目标对每个示例都相同。相比之下在发票处理示例中。需要生成自定义目标标签。即发票的正确到期日期。并将其与每个示例的真实标注进行对比。我知道我使用了非常简单的流程生成这些标题。但这类方法也可应用于更复杂的生成流程。让我再讲一个最终示例。我们将重新审视之前研究的代理。查看研究代理在不同输入提示下的输出。假设要求它撰写关于黑洞研究的最新突破文章。在黑洞领域。发现它遗漏了新闻报道中的一些重大成果。这是令人不满意的结果。或者当你要求它研究。西雅图租房与购房。
或在机器人采摘水果方面表现良好。未提及领先设备公司。基于此评估。看起来有时会遗漏人类专家会捕捉到的重要点。因此我将创建评估来衡量其捕捉关键点的频率。例如为黑洞、机器人采摘等主题准备多个示例提示。以及相关领域。并对每个示例。为每个主题列出三到五个黄金标准讨论点。注意这里需要每个示例的标注。因为黄金标准讨论点。即最重要的讨论点。每个示例不同。通过这些真实标注。可以使用语言模型统计提及的黄金标准讨论点数量。例如提示可能要求。确定提供的文章中包含多少个五项黄金标准讨论点。你有可选提示。文章。采用标准评分点等。并返回包含两个键的JSON对象。有分数。有多少个0到5的评分点对应分数。以及解释说明。这允许为评估集中的每个提示获取分数。我用om作为评判者统计提到的要点数量。因为这些要点的讨论方式多种多样。因此简单的正则表达式或模式匹配可能效果不佳。这也是为何可能使用a作为评判者。并将其视为更主观的评估标准,例如。事件视界是否被充分提及。这是构建评估指标的第三个示例。在思考如何构建评估系统时。S针对您的应用场景。您构建的评估系统通常需要反映实际需求。或您在应用中可能出现的错误。实际上,评估存在两大维度,顶部维度。是评估输出的方式。有时通过编写代码进行客观评估。有时则使用o作为评判者进行主观评估。S另一维度是是否具有单例真实标签。例如检查发票数据提取。我们编写代码验证是否获取实际日期。这具有单例真实标签。因为每张发票的实际日期不同。但在检查营销文案长度时。每个示例都有10字限制,无需单例真实标签。相比之下,统计标准要点。存在单例真实标签。因为每篇文章的重要要点不同。但我们使用元素作为评判者阅读文章。判断是否充分提及这些主题。因为提及要点的方式多种多样。四个象限的最后一类是消息评判者。无需单例真实标签。
例如在按评分标准批改图表时。我们正在可视化咖啡机销售数据。若要求根据评分标准生成图表。如是否标注清晰等。所有图表使用相同的评分标准。这将使用元素作为评判者。但无需单例真实标签。我发现这个二维网格。可能是思考不同评估类型的有效方式。S您可能为应用构建的评估系统。顺便说这些有时也称为端到端评估S。因为一端是输入和用户查询提示。另一端是最终输出。因此这些都是完整端到端系统的评估指标。总结一下这个视频。我想分享几个设计端到端评估的最终建议。快速粗糙的评估是完全可以起步的。我觉得看到很多团队几乎陷入瘫痪。因为他们认为构建评估是需要数周的巨大工程。因此他们花费了理想时间之外的更久才开始。但正如你迭代优化代理工作流并逐步改进。你也应该计划迭代优化你的评估系统。如果你准备十个、十五个或二十个示例。作为你的首个评估测试并编写和编码。或尝试以裁判身份进行提示测试。只需做些事情开始获取指标数据。这可以补充人工观察输出结果。两者结合能驱动你的决策过程。随着评估系统逐渐智能化。你可以逐步将更多信任交给基于指标的评估。而非每次都要查看数百个输出结果。你只需调整某个参数。在这一过程中。你可能会找到持续改进评估的方法。如果你最初有二十个示例。可能会遇到评估无法捕捉系统优劣判断的情况。因此你更新系统并观察结果。感觉这应该能显著提升效果。但旧评估未能显示新系统得分更高。如果出现这种情况。这通常是机会。或许扩大评估样本集。或改变评估输出的方式。使其更符合你的判断标准。以准确反映哪个系统更有效。因此你的评估会随时间提升。最后关于利用评估获取灵感。以确定下一步工作方向。许多创新工作流被用于自动化人类可完成的任务。因此对于此类应用。我会寻找性能较差的环节。而作为专家人类。这常为我提供专注方向的灵感。或者哪些类型的示例。
可能让我的代理工作流表现更优。希望你在搭建快速系统后。思考何时开始。引入评估以跟踪系统潜在问题。这将帮助你推动系统改进。同时帮助你驱动系统优化。此外还有一种评估方法。能帮助你聚焦整个系统核心。哪些组件最值得投入注意力。系统中最值得专注的组件是什么。因为基因系统通常包含许多组件。哪个组件将是最具生产力的,值得你投入时间改进。事实证明,能够做好这一点是一项对驾驶至关重要的技能。在下一视频中高效开发enic工作流程。我想深入探讨这一主题。因此让我们进入下一视频。
P20 2-误差分析与确定后续步骤优先级
假设你构建了一个工作流程。但它还没有达到你期望的效果。这种情况我经常遇到。顺便说一句。我通常会快速搭建一个简易系统。但它表现不如我预期。问题在于你要将精力集中在哪些环节才能改进。事实证明,基因工作流程包含许多不同组件。优化某些组件可能比其他组件更有效。你选择专注方向的能力对改进速度影响巨大。能让你在系统中实现改进的速度。我发现其中一个最大预测因素。团队效率和质量如何。是否能有效执行纪律性错误分析流程。以确定改进方向。这是一个重要技能。看看如何在研究代理示例中执行错误分析。我们在前一视频中进行了错误分析。发现经常遗漏关键点。就像人类专家撰写特定主题文章时。你已发现有时会遗漏关键点的问题。该如何着手解决。在工作流程的众多步骤中。几乎任何步骤都可能导致遗漏关键点的问题。例如。可能第一个语言模型生成的搜索词不够优质。导致搜索内容不准确。未能找到正确文章。或者使用的网络搜索引擎效果不佳。市面上存在多种网络搜索引擎。实际上我常用多个搜索引擎处理个人应用。有些效果更好。或者网络搜索本身并无问题。但将搜索结果列表交给语言模型时。可能处理不当。未能选出最佳文档下载。可能网络抓取环节问题较少。在这种情况下。假设你能准确获取网页内容。但将网页内容输入语言模型后。模型可能忽略部分已抓取文档中的要点。事实证明有些团队会凭直觉选择组件改进。有时这种方法奏效。但有时会导致数月工作却进展甚微。因此不应依赖直觉选择组件改进。与其凭感觉决定改进哪个组件。我认为进行系统性错误分析更好。以更深入理解工作流程各环节。特别是我会经常检查执行轨迹。即每个步骤后的中间输出。为了了解哪些组件的性能不佳。意思。说。远不如人类专家的表现。因为这可能表明存在显著改进的空间。看一个例子。如果我们让研究代理撰写一篇关于黑洞信号最新新闻的论文。
也许输出结果。像这样的搜索关键词。搜索黑洞理论。爱因斯坦事件视界。望远镜。无线电等。我会让专家查看这些内容并判断。这些是否是撰写黑洞信号最新发现论文的合理网络搜索关键词。在这种情况下专家可能认为这些搜索结果看起来没问题。它们与我作为人类的做法非常相似。我查看网页搜索结果并检查返回的网址。网页搜索会返回许多不同网页。也许其中一个网页显示。一名小学生声称破解了天体物理学领域三十年的黑洞之谜。儿童新闻。这看起来不像经过严格同行评审的文章。或许检查所有网页搜索返回的文章。会让你得出返回过多博客或通俗新闻文章的结论。而不足以撰写高质量的研究报告。最好也检查其他步骤的输出结果。也许代理筛选出最佳五篇资料。最终可能得到。天体儿童新闻。太空球。二千空间趣味新闻。等等。正是通过查看这些中间输出。才能初步判断每个步骤输出的质量。引入一些术语。所有中间步骤的输出集合。通常被称为该代理运行的轨迹。其他资料中也会见到的术语。单个步骤的输出有时称为片段。来自计算机可观测性领域的术语。用于分析计算机行为。在这门课中我多次使用了’轨迹’一词。我会较少使用’片段’这个词。但你可能在互联网上看到这两个术语。通过阅读轨迹。可以初步判断哪些组件可能存在最大问题。为了更系统地进行分析。关注系统表现不佳的案例会很有帮助。也许有些论文完全符合要求。我可以把这些放在一边,尝试构建一组示例,其中。无论什么原因,你的研究代理的最终输出并不令人满意。专注于这些示例。这就是我们称之为错误分析的原因之一。因为我们想关注系统出错的案例。并深入分析找出哪些组件。最负责研究代理输出中的错误。为了使这一过程更严谨。而不是随意阅读并获得模糊感。你可能会建立一个电子表格,更明确地统计错误位置。而这里的错误。我指的是。当某一步骤输出的结果显著劣于。
可能人类专家在相同输入下会给出的内容。我通常会自己在电子表格中进行这项工作。因此我可能会构建一个这样的电子表格。对于第一个查询。我会查看黑洞科学的最新进展。发现搜索结果中有太多博客文章。通俗读物文章。科学论文不足。基于此,确实这五个最佳来源并不理想。但这里我不说这五个最佳来源做得不好。因为输入到TM选择五个最佳来源的参数。全是非严谨文章。因此不能归咎于此。选择五个最佳来源未能挑选更好文章。因为它已经尽力而为。或几乎达到同样效果。人类可能也会做出相同选择。你可以为不同提示重复此过程。西雅图租房 vs 买房。可能遗漏了知名博客。用于水果采摘的机器人技术。在此案例中我们观察到。哦。搜索关键词过于宽泛。搜索结果也不佳等等。基于此我在电子表格中统计。不同组件出现错误的频率。在此例中对搜索关键词不满。五分之一的时间。但对搜索结果不满四。五分之一的时间。如果实际观察到这种情况。我可能会仔细检查搜索关键词。确保搜索关键词确实合适。确认并非搜索关键词选择不当导致结果差。但我确实认为搜索关键词没问题。但搜索结果却不理想。我会仔细检查我使用的网络搜索引擎。如果存在可以调整的参数。使其返回更相关或更高质量的结果。这种分析在这个例子中告诉我。也许我真的应该专注于改进搜索结果。而不是这个工作流程的其他组件。总结这段视频内容。我发现养成查看追踪记录的习惯很有用。在构建ENIC工作流程后。请查看中间输出结果。以了解每个步骤实际执行的情况。这样可以更好地理解。不同步骤的表现优劣情况。通过电子表格进行更系统的错误分析。可以帮助收集统计数据或统计哪些组件最常表现不佳。通过观察哪些组件表现较差。以及我对高效改进不同组件的想法。这样就能确定优先处理哪个组件。也许某个组件存在问题。但我没有改进它的想法。这可能意味着不需要优先处理。
但如果某个组件产生大量错误。并且我有改进的方法。这就成为优先处理该组件的理由。我想强调错误分析是你非常有用的输出。帮助你决定努力方向。因为在复杂系统中有很多可以改进的地方。很容易选择一个方向投入数周甚至数月。最终发现并未提升整体系统性能。通过错误分析决定努力方向。实际上能极大提升效率。在这段视频中。我们以研究代理为例讲解了错误分析。但我觉得错误分析是一个重要主题。我想和你探讨更多示例。我们进入下一视频。继续探讨更多错误分析案例。
P21 3-更多误差分析示例
我发现对于许多开发者来说,只有通过观察多个示例。你才能进行练习并磨练自己对错误分析的直觉。再看看两个更多示例。我们将分析发票处理和回复客户邮件的场景。这是我们设计的发票处理流程。其中包含明确的步骤遵循特征化工作流,识别四个必要字段。将数据录入数据库。在示例中。从本模块的第一个视频。我们提到系统经常在发票到期日判断上出错。因此我们可以进行分析。试图确定可能出错的组件。例如。PDF转文本是否出错。或是否出错。语言模型是否提取了错误日期。所有来自PDF转文本组件的输出。传递给卡尔并进行错误分析。我会寻找数据提取错误的多个示例。如同前一视频所示,重点分析表现不佳的案例。试图找出这些案例出错的原因。忽略日期正确的示例。但需收集十到一百份发票。其中日期有误。我会逐一检查以确定。问题根源是否是PDF转文本获取日期错误。或是语言模型在处理PDF转文本输出时。提取了错误日期。或许可以制作类似表格并分析两份发票。统计PDF转文本。是否错误提取日期或文本。导致人类也无法辨认到期日。与PDF文本清晰可辨的情况相比。但语言模型却错误提取了日期。比如误将发票日期识别为到期日。在此示例中。数据提取环节导致了更多错误。这表明我应优先优化数据提取组件。而非PDF转文本环节。这一点至关重要,因为若没有错误分析。某些团队可能耗费数周甚至数月调优PDF转文本。最终发现这些努力对系统性能影响微乎其微。哦。顺便说一句。底部的百分比可能不加到100%。因为这些错误并非互斥。最后看一个案例。回到客户邮件回复的工作流。其中语言模型接收客户邮件。像这样。下达指令。调取订单详情。从数据库获取信息。草拟供人工审核的回复。我又找到了一些例子。无论出于什么原因。最终输出结果令人不满意。尝试找出哪里出错了。可能出现的问题包括。
可能模型生成了错误的数据库查询。当查询发送到数据库时。未能成功获取客户信息。或者数据库存在数据损坏。即使模型编写了完全合适的SQL查询。查询语言部分。数据库没有正确信息。或者根据客户订单的正确信息。模型编写了邮件内容却有所偏差。再次说明。我会查看几封邮件。最终输出不满意的案例并分析问题。比如一封邮件。发现模型在查询中调用了错误的表。在邮件二中错误查询了数据。可能发现数据库本身存在错误。在给定输入的情况下。模型甚至编写了子邮件等。在这个案例中。经过多封邮件分析后。可能发现最常见的错误在于。模型编写数据库查询的方式。你说SQL查询。为了获取相关数据。而数据库本身基本正确。仅存在少量数据错误。模型生成邮件的方式也有问题。可能表达不够准确。大约30%的时间。这表明改进方向。可能需要优化模型的查询编写方式。其次。最关键的是。可能需优化高阶提示词。撰写最终邮件。此类分析能显示75%的错误。系统多数情况下表现正确。但所有未达标的案例中。75%的问题源于数据库查询。这些信息能精准指导改进方向。我正在开发AI工作流程。我经常会使用这种错误分析来告诉我该将注意力集中在何处。关于接下来该做什么工作。当你做出那个决定时。事实证明,为了补充我们之前在本模块中讨论的端到端元音。评估整个端到端系统往往很有用。但也需要单独分析各个组件。因为这能让你在改进过程中更高效。那个通过错误分析让你决定重点关注的组件。进入下一个视频学习组件层面。邪恶的s。
P22 4-组件级评估
看看如何构建和使用组件级评估。在我们的研究代理示例中。我们提到研究代理有时会遗漏关键点。但如果问题是网络搜索。每次我们更换网络搜索引擎时。需要重新运行整个工作流程以获得性能指标。但这种评估成本很高。此外这是一个相当复杂的流程。即使网络搜索有所改善。其他组件的随机性引入的噪声。会让观察网络搜索质量的小改进变得更困难。作为仅使用端到端评估的替代方案。我会考虑构建专门评估网络搜索组件质量的评估。例如。衡量网络搜索结果的质量。可以创建一组黄金标准网络资源。对于少数查询。让专家指出这些是最权威的资源。如果有人在搜索互联网时。应该找到这些网页。或者这些网页中的任何一个都很好。可以编写代码捕获。网络搜索输出与黄金标准资源的匹配程度。信息检索的标准指标。F1分数。无需在意细节。如果你不了解这些术语。但存在标准指标可衡量网页列表。由网络搜索返回。与专家确定内容的重叠程度。是否与这些黄金标准资源匹配。你已掌握评估网络搜索组件质量的方法。当你调整网络搜索的相关参数或超参数时。例如切换不同的网络搜索引擎。比如尝试谷歌、必应和Dr。Go和Tville。以及Com和其他引擎。或者调整结果数量。或日期范围。这些变化能让YaSa网络搜索引擎快速判断。网络搜索组件质量是否提升并实现渐进改进。当然。在宣布完成之前。最好运行端到端评估。确保经过长时间调优网络搜索系统后。整体系统性能确实提升。但在调整这些超参数过程中。可以逐个进行。只需专注于单个组件即可大幅提升效率。与其每次都需要重新运行端到端测试。因此组件级测试可以更清晰地定位特定错误。它能明确告诉你是否在提升网页搜索组件性能。或者你正在开发的任何组件。并避免整体系统复杂性中的干扰噪声。如果你在涉及不同团队的项目中工作。专注于不同组件。单个团队也可以拥有自己。
非常明确的优化指标无需考虑其他组件。这能让团队专注于更小的。更具针对性的问题。从而加快进度,当你决定改进某个组件时。考虑是否值得建立组件。智能评估。以及这是否能更快提升该组件性能。你可能想知道如果决定改进某个组件。如何实际让该组件表现更好。在下一视频中看一些实例。
P23 5-如何解决你发现的问题
一个充满活力的工作流程可能包含多种不同类型的组件。因此,改进不同组件的工具会大不相同。但我想与大家分享一些通用模式。我发现某些组件可能不基于语言模型。这可能像网络搜索引擎或文本检索组件。如果这是你检索增强生成系统的一部分。可能需要代码执行功能。或者一个单独训练的机器学习模型。可能是语音识别或图片中人物检测等功能。这些非语言模型组件可能有可调参数或超参数。对于网络搜索。可以调整结果数量等参数。或设置网络搜索引擎考虑的时间范围。对于文本检索组件。可能改变相似度阈值以确定文本相似性。或调整分块大小。通常检索系统会进行分块处理。将其拆分为更小块以便匹配。这些超参数可能适用于人物检测。可以调整检测阈值。影响其敏感度。以及识别人物的可能性。这会在假阳性和假阴性之间权衡。如果你没有完全理解我刚才提到的超参数细节。不必担心。细节并不重要。但组件参数通常可调。当然,你也可以尝试替换组件。我在自动生成工作流中经常这样做。我会切换不同的检索增强生成引擎。或更换不同的检索服务提供商等。只需测试其他提供商是否因非语言模型组件多样性表现更好。我认为改进技术会更多样化且依赖于。具体组件的功能,对于语言模型组件。这里有一些可考虑的选项。其中一个可能是尝试优化你的。或许添加更明确的指令。如果你了解少样本提示法。指添加输入和期望输出的具体示例。少样本提示。你可以在深度端眼短课程中学习。是一种提供示例以。帮助生成更优输出的技术。或者尝试不同的AI工具。套件或其他工具。尝试多种语言模型其实很容易。使用评估选择最佳模型。如果单步操作对单一模型太复杂。可以考虑将任务分解为更小步骤。或拆分为生成步骤和反思步骤。但更一般地说。如果你有非常复杂的指令。全部在一个步骤内。可能单个模型难以完成所有指令。你可以将任务分解为更小的步骤。
比如两到三次调用以准确执行最后。当其他方法不起作用时可以尝试。充分考虑微调模型。这通常比其他选项复杂得多。在开发时间投入上也会更昂贵。但如果你有可用于微调模型的数据。这可能比单纯提示更有效。我通常在耗尽其他选项后才微调模型。因为微调通常较为复杂。但对于应用而言。尝试过所有其他方法后。如果我仍然处于。你知道的。比如达到90%或95%的性能。我需要挤出最后几个百分点的提升。有时微调自定义模型是很好的技术。我通常只在成熟应用上这样做。因为成本很高。事实证明当你。选择专辑时有一件事对你很有帮助。作为开发者是。如果你对不同大型语言模型的智能或能力有良好直觉。你可以尝试大量模型并看哪个效果最好。但随着使用不同模型。我开始形成哪些模型适合何种任务的直觉。并保持这些直觉。在编写有效问题时也会更高效。以及为任务选择合适模型。我想与大家分享一些想法。关于如何磨练直觉。哪些模型适合你的应用。通过使用模型执行指令的例子说明。以删除或屏蔽pii(个人身份信息)。删除私密敏感信息。例如使用模型总结客户通话。则可能生成七月十四日的摘要。第二第三条涉及杰西卡·阿尔瓦雷斯的社会安全号码及地址。支持工单等信息。这段文本包含大量敏感。个人身份信息现在。假设我们需要从此类摘要中移除所有pii。因为我们需要用于下游客户分析。并保护客户信息。在下游分析前需先清除pii。因此你可以提示模型识别以下文本中的所有pii。返回带有删除标记的文本,包括删除冒号等。事实证明,更大的前沿模型往往更能遵循指令。而较小的模型则擅长回答简单事实性问题。但不太擅长执行指令。如果在较小模型上运行此提示。使用八亿参数的开源llama3.1模型。则可能生成如下输出。它指出识别出的PI是社会保障号和地址。按如下方式处理并继续。实际上存在几处错误。未正确遵循指令。
显示了列表。对文本进行删除处理。返回不应生成的另一列表。在PII列表中遗漏了姓名。我认为它也没有读取该部分。地址信息。细节并不重要。但未完全遵循这些指令。可能遗漏了部分PII。相比之下。如果使用更智能的模型。一个更擅长执行指令的模型。可能会得到更好的结果如。正确列出了所有PII信息。并正确删除了所有PI。我发现自己不同语言模型提供商专注于不同任务。不同模型确实适合不同任务。有些擅长代码编写。有些更擅长执行指令。有些擅长特定领域的事实。你可以根据直觉判断模型的智能程度。以及指令的可遵循性。从而做出更优模型选择。分享几个实用技巧。建议尝试不同模型。每当有新模型发布时。我通常会测试并尝试不同查询。两者。开源模型。专有模型及开源模型。我发现有时建立个人测试集。可能也很有帮助。准备一组固定问题。测试多个不同模型。有助于评估它们在不同任务中的表现。我经常做的一件事。希望对您有所帮助。我会花大量时间阅读他人提示。有时人们会在互联网上发布他们的提示。经常去阅读它们以了解最佳实践和提示的写法。或者经常与不同公司的朋友交流。包括一些前沿模型公司。并向他们分享我的问题。观察他们是如何提示的。有时我也去查看他人编写的开源包。我非常尊重并下载这些开源包。深入研究这些开源包中作者写的提示。为了阅读它们。为了培养自己编写优质提示的直觉。这是我建议你考虑的一种技巧。通过阅读大量他人的提示。这能帮助你提升自己编写提示的能力。我确实经常这样做。我也鼓励你这样做。这能帮你培养关于指令类型的直觉。模型擅长执行哪些指令。何时对不同模型说特定内容。除了与模型互动和阅读他人提示。如果你在工作流中尝试多种不同模型。也能帮助你培养这种直觉。从而了解哪些模型最适合哪些任务。或者通过查看追踪记录获得初步感受。或从组件级或端到端进行分析。
这能帮助你评估不同模型在工作流各环节的表现。你开始培养关于。不仅仅是性能。可能还包括不同模型的价格与速度权衡。我之所以开发我的工作流。AI套件是因为它能轻松切换和尝试不同模型。这让我在测试和评估时更高效。从而确定哪些模型最适合我的工作流。我们已经讨论了很多如何提升各组件性能。以期提高整个端到端系统的整体性能。除了提升输出质量。在工作流中你可能还需要。同时优化延迟和成本。我发现很多团队在开发初期。通常最担心的是输出质量是否足够高。但当系统运行良好并投入生产后。往往也有价值使其运行更快且成本更低。在下一视频。我们将看看如何优化工作负载的成本和延迟。
P24 6-延迟、成本优化
我们已经探讨了许多关于构建高效AI系统时如何驱动流程管理的技巧。做一个总结与大家分享。分享这个过程中的感受。当我构建这些工作流程时。我感觉主要有两项核心活动。我经常投入时间在。一个是构建。因此编写软件。努力编写代码。以提升我的系统。而第二个看似没有进展。但我认为同样重要的是分析工作帮助我确定构建方向。我常常在构建与分析之间来回切换。包括错误分析等环节。例如在构建新工作流程时。我通常会快速搭建端到端系统。甚至采用快速简易的实现方案。这让我能够开始检查端到端系统的最终输出。或查阅追踪日志。了解系统表现良好的环节。以及表现不佳的部分。仅通过查看追踪日志。有时就能直观判断哪些组件需要改进。我可能想要优化的组件。因此可能会调整个别组件或持续优化整体系统。当系统逐渐成熟后。除了手动检查少量输出和阅读追踪日志。我可能会开始构建评估集并准备小数据集。可能仅用十到二十个示例计算指标。至少评估端到端性能。这进一步帮助我更精准地定位系统改进方向。或优化个别组件。分析工作变得更加系统化。开始进行错误分析并检查各组件。统计各组件导致次优输出的频率。这种严谨的分析。让我能更精准地决定下一步优化哪些组件。或激发系统整体改进的思路。最终当系统高度成熟时可更高效地进行组件级改进。这时我可能会构建组件级评估。构建AI系统的过程往往循环往复。并非线性流程。我们有时会调整系统。进行错误分析。接着优化某个组件。再调整组件细节。评估与分析技术在两者间反复切换。而经验不足的团队往往投入大量时间在构建上。却较少进行基于错误分析的深度分析。构建恶行及相关内容。这将是理想的选择。因为这种分析能帮助你真正聚焦时间投入的方向。还有一个小建议。市面上其实有不少工具可以帮助追踪监控。记录运行时日志。计算成本等操作。这些工具都很有帮助。
我有时会使用其中几个,而许多didized短课程合作伙伴也提供这些工具。它们确实效果很好。我发现对于工作流程。我最终处理的。大多数工作流程都很定制化,所以我最终构建了相当定制化的。恶行系统。因为我需要捕捉系统中出错的部分。尽管我使用了一些工具。我也需要构建大量自定义恶行。这些工具非常适合我的具体应用及遇到的问题。感谢你们坚持看到第五模块的结尾。如果你能实现本模块中哪怕一部分理念。我相信你将远超大多数开发者的水平。在实现工作流程的复杂度上。希望这些内容对你们有帮助。期待在最终模块与你们相见。我们将讨论更多高级设计模式用于构建。雇佣自主代理。课程最后一模块我们再见。
P25 7-开发过程总结
在构建基因工作流时。我通常会建议团队专注于获取高质量输出。并优化成本和延迟。但后来发现延迟成本并不那么重要。但我认为提升性能或输出质量通常是最难的部分。直到它真正运行起来。那时或许可以关注其他方面。我曾多次遇到团队构建了一个基因工作流。并将其交付给用户使用。幸运的是有大量用户使用它。导致成本实际成为问题。我们不得不。你知道的。匆忙降低成本。但这也是个好问题。我通常会把成本放在次要位置。嗯,不是完全忽视。只是优先级较低需要关注。直到用户量庞大到需要降低人均成本。而延迟问题我会稍加关注。但同样。不如确保输出质量重要。但当你达到目标时。优化延迟和成本的工具会很有用。看看如何实现这些优化。若要优化基因工作流的延迟。我通常会先进行基准测试或计时。在这个研究代理中包含多个步骤。如果我要计时。每个步骤。生成搜索可能需要七秒。网络搜索耗时五秒。这一步三秒。这一步十一秒。最后撰写论文平均十八秒。通过观察整体时间线。可以判断哪些组件有优化空间。在此例中。可能有多种改进方案。如果尚未利用并行处理。对于某些步骤。比如数据获取。或许可以尝试部分操作并行化。或发现某些步骤耗时过长。如果第一步耗时七秒。最后一步十八秒。我可能考虑使用更小的模型。尝试稍低智能的模型看是否仍有效。或寻找更快的语言模型提供商。API的损失在线不同接口。有些公司有专用硬件以实现更快处理特定元素。因此有时尝试不同服务商以找到最快返回令牌的更值得。但至少。进行此类时间分析可帮助确定需重点优化的组件。在降低延迟方面。在优化成本方面。类似的计算需评估每一步的成本。也能帮助基准测试并确定需优化的步骤。许多服务商按令牌计费。基于输入和输出长度。许多API服务商按调用次数计费。计算步骤成本可能因服务器容量付费方式不同而异。以及服务费用。对于此类流程。
在此例中可能决定该步骤平均每个令牌成本为零点零。四美分。每次网络搜索。API可能成本一点。六美分令牌成本如此。API调用成本如此。PDF转文本成本如此。最终论文生成令牌成本如此。这将再次帮助您了解。是否存在更便宜的组件可用。或寻找成本优化最大机会所在。我发现这些基准测试非常清晰。有时会明确告知某些组件无需过多关注。因为它们影响不大。并非成本或延迟的主要因素。当成本或延迟成为问题时。只需测量每一步的成本或延迟。通常能为您提供优化组件的依据。我们即将结束本模块。我知道我们已涵盖很多内容。感谢您的坚持。继续本模块最后一节收尾。
P26 【模块5:高度自主智能体的模式】1-规划工作流
本模块的最后一部分。在这里你将学习设计模式,让你能够构建高度自主的智能体。无需预先硬编码具体步骤。需要执行的步骤序列。它们可以更灵活地自主决定所需采取的步骤。以完成某项任务。我们将讨论规划设计模式。随后在本模块中讲解如何构建多智能体系统。开始探索。假设你经营一家太阳镜零售店。并拥有库存中太阳镜的信息。存储在数据库中。你可能需要客服智能体回答问题。比如是否有库存的圆形太阳镜或价格低于一百美元。这是一个较为复杂的查询。因为需要浏览产品描述以确定相关太阳镜。查看库存情况。最后确认价格是否低于一百美元以告知客户。我们有经典款太阳镜。如何构建能够回答此类广泛客户查询的智能体。以及处理许多其他类似查询。我们将为语言模型提供一组工具,使其能够获取商品描述。例如查询不同款式太阳镜、检查库存。可能处理商品退货。这在当前查询中并不需要。但对其他查询是必需的。获取商品价格。查看历史交易记录。处理商品销售。等等。为了让语言模型确定使用工具的正确顺序。以响应客户请求。你可能会编写如下提示。你拥有以下工具。为每个工具(如六个工具)提供描述。或更多智能体可用的工具。并指示其返回逐步执行用户请求的计划。在此案例中回答特定查询。一个合理的计划可能是。使用获取商品描述检查不同描述。以找到圆形太阳镜。使用检查库存确认存在并停止。使用获取商品价格确认价格是否低于一百美元。当语言模型输出包含三个步骤的计划后。可以提取第一步文本。即此处红色标注的文本传递给语言模型。可能附加用户查询的工具信息。结合背景上下文和任务指令执行第一步。在此情况下希望智能体会调用获取商品描述。为了获取物品的适当描述。第一步的输出可以让它选择圆形太阳镜。第一步的输出随后与第二步结合。这些就是指令。我在这里用蓝色标注给LLM执行计划第二步。
希望它会调取上一张幻灯片找到的两副圆形太阳镜。并检查库存。第二步的输出随后用于另一个LLM调用。包含第二步的输出结果。以及第三步的执行指令。传递给LLM使其。获取物品价格。最终这个输出再次反馈生成最终用户答案。在本张幻灯片中。我简化了很多细节。LLM实际编写的计划比简单指令更详细。但基本流程是让LLM。写出多步骤计划。执行计划的每个步骤。并结合任务相关上下文。可用工具等信息。使用elm进行这种规划的亮点。是我们无需预先决定。工具调用的顺序。以回答较为复杂的客户请求。如果客户提出不同请求。例如我想退购之前购买的金框眼镜。但不是金属框的。可以想象LLM同样能制定不同计划。根据之前购买记录判断。用户购买了哪些眼镜。基于获取金框眼镜的描述。可能调用处理退货流程。因此具备此类规划能力的代理。可执行更广泛的任务并调用多种工具。在不同顺序下。另一个规划示例。看看邮件助手。如果你想让我告诉助手。请回复来自纽约鲍勃的邮件邀请。十点十刻并归档他的邮件。邮件助手可能拥有搜索邮件工具。移动邮件。删除邮件和发送邮件。系统提示可能说明你拥有以下工具。再次请返回分步计划。在此案例中。代理可能会说步骤是使用搜索邮件。找到来自鲍勃提及晚餐和纽约的邮件。生成并发送确认出席的邮件。最后将这封邮件移动到存档文件夹。基于此计划。这看起来是一个合理的方案。你需要分步执行这个计划。因此这里红色显示的第一步文本。将被输入LMS并附加背景上下文。希望你的触发搜索邮件。可以将该输出结果提供给。我又回到第二步指令,发送恰当的回复。最后假设邮件发送成功。你可以将该输出结果执行。第三步将邮件从Bob移动到存档文件夹。规划设计模式已在许多高效编码系统中成功应用。如果你让它编写构建某个复杂应用的软件。它可能会制定一个构建该组件的计划。构建这个组件。
构建这个组件以形成类似清单。依次执行这些步骤。逐步构建许多其他应用的复杂软件。规划的使用仍可能处于实验阶段。尚未广泛普及。规划的一个挑战是。有时会让系统控制变得复杂。作为开发者。在运行时你并不清楚。它会生成什么计划。因此我认为在高度编码系统中效果显著。规划在其他领域的采用仍在增长。但这是一项令人兴奋的技术。我相信它会不断改进。并将出现在更多应用中。构建能够自主规划的代理的酷处在于。无需预先硬编码。复杂任务的具体步骤序列。我知道在这段视频中我已从较高层次讲解了规划过程。输出步骤列表。让LMS执行。分步执行计划中的步骤。但实际是如何运作的呢?下个视频见。我们将深入探讨。进一步了解这些计划的实际结构。以及如何整合它们。让L计划并为你执行计划。在下一视频中查看。
P27 2-创建和执行LLM计划
在这个视频中。我们将详细探讨如何提示模型生成计划。学习如何阅读。解读并执行该计划。深入探讨,这是上一个视频中展示的计划。针对客户服务代理。我已经以高层次进行了说明。使用简单的文本描述。看看如何让模型写出非常清晰的计划。这些计划会超越简单的高层次文本描述。许多开发者会让模型将计划格式化。以JSON格式执行。因为这能让后续代码更清晰解析。计划的具体步骤以明确无歧义的方式呈现。目前所有主流模型都能很好地生成JSON输出。系统提示可能像这样。你拥有访问查找工具。这些房间工具。以JSON格式创建分步计划。并详细描述JSON格式。目标是让模型输出类似右侧所示的计划。在此JSON输出中,第一个列表项包含明确的键值对。例如。计划的第一步描述如下。并应使用以下工具。向该工具传递以下参数。计划执行此任务。使用此工具,依此类推。因此这个JSON格式。相比用英文编写计划,能让后续代码更清晰解析。计划的具体步骤是什么。从而可靠地逐步执行而非JSON。我也看到有些开发者使用XML。或用XML标签明确指定。计划的步骤及步骤编号。一些开发者。我觉得较少开发者会用Markdown。因其在解析时稍显模糊。而纯文本可能是最不可靠的选择。但我认为JSON。如我此处展示的。或XML。都是让模型无歧义生成计划的好选项。因此通过JSON格式化。后续流程可以更系统地解析计划。分步执行计划中的不同步骤。关于生成计划。还有一种非常巧妙的思路是让模型输出复杂计划。并可靠执行。那就是编写代码并让代码执行。表达计划。我们下期视频再详细看看这个。
P28 3-结合代码执行的规划
通过代码执行进行规划的核心思想是。与其让算法输出JSON格式的计划。逐步执行每个步骤。为什么不让机械臂。直接尝试编写代码。而这段代码可以涵盖计划的多个步骤。比如调用这个函数。调用这个函数和这个函数。通过执行语言模型生成的代码。我们实际上可以执行较为复杂的计划。看看何时需要使用这种技术。假设要构建一个回答咖啡机销售问题的系统。基于包含历史销售数据的电子表格。可能有一个配备这些工具的语言模型,比如获取列最大值。查看特定列并获取最大值。这有助于回答最贵的咖啡或获取列平均值、过滤行。获取列最小值。获取列中位数。某些行等等。这些都是各类工具的示例。可能让语言模型处理这个电子表格。或以不同方式处理这些行列数据。如果用户询问哪种热巧克力销量最高。发现可以使用这些工具回答此问题。但过程相当复杂。需用过滤行提取1月热巧克力交易数据。进行统计分析。接着对2月重复操作。计算该月统计结果。接着对3月重复操作。对4月重复操作。对5月到12月全部重复。取最大值。因此可以结合这些工具完成复杂流程。但这并非理想方案。更糟糕的是。若有人询问上周唯一交易量。这些工具无法获取答案。可能需要创建新工具。获取唯一条目。或遇到另一个查询。最后五笔交易的金额是多少。则需创建新工具获取数据。实际中团队遇到更多查询时。会不断创建更多工具。试图覆盖所有需求。有人可能询问类似数据集。这种方法易碎且低效。我见过团队持续处理边界情况并创建新工具。但事实证明还有更好的方法。那就是提示LLM生成代码。请编写代码解决用户的查询。并将答案以Python代码返回。可能用这些开头和结尾包裹。执行Python XML标签。只需加载电子表格到数据处理库。这里使用pandas库。它实际上正在制定计划。计划是在加载CSV后。必须确保日期列以正确方式处理。按日期排序。
选择最后五笔交易。仅显示价格列等内容。但这些就是步骤。第一步。第二步。第三、第四和第五步。说明这个计划。因为像Python这样的编程语言。在这个例子中。同时导入了pandas数据处理库。因为其中包含大量内置函数。数百甚至数千个函数。而且这些函数LLM见过大量调用数据。当让自己的模型编写代码时。可以从数百或数千个相关函数中选择。这些函数已有大量数据表明何时使用。因此可以组合不同函数调用来自大型库。从而为回答复杂查询制定计划。就像这样。再举一个例子。如果有人询问上周有多少笔唯一交易。它可以制定读取CSV文件的计划。处理日期列。定义时间窗口过滤行。删除重复行。这些细节并不重要。但希望从注释中可以看出。LLM正在制定四步计划。并将每一步用可执行代码表达。这样就能得到用户答案。对于可通过编写代码完成的任务。让算法用可执行代码表达计划。对LLM来说是一种强大方式。当然还需考虑模块和工具使用时的注意事项。如果需要安全执行环境。如沙盒运行代码并应用限制。虽然我知道即使这可能不是最佳实践。我也知道很多开发者不使用沙盒环境。从这个图表可以看出,基于代码的规划效果很好。改编自孙耀王等人的研究论文。可以看到对于他们研究的多种任务模型,代码作为行动。其中让语言模型编写代码并通过代码执行操作。这比让其生成JSON再转换为行动或文本更优。你也看到编写代码表现更优的趋势。编写JSON计划同样更好,而纯文本计划效果也不错。他们开始用纯文本编写计划。当然有些场景需要提供自定义工具供模型学习使用。因此编写代码并非适用于所有场景。但当适用时。这对神经网络表达计划非常有效。今天的规划部分到这里就结束了。AI最强大的应用场景之一。就是高度软件编码规划。事实证明。如果你询问顶尖的软件编码辅助工具。让它为你编写复杂软件。
它可能会先制定构建软件组件的详细计划。构建第二个组件,再构建第三个。甚至可能计划测试组件的进展。随后形成检查清单逐步执行。这对构建日益复杂的软件应用非常有效。我认为规划的使用仍在增长。规划的一个缺点是。由于开发者未明确指示系统具体操作。控制起来稍显困难。且无法预知运行时的具体情况。但放弃部分控制。显著扩展了模型可尝试的范围。这项关键技术仍处于前沿。在某些领域尚未完全成熟。可能在特定场景中表现良好。尽管仍有很大发展空间。但希望你在应用中能享受其价值。今天的规划部分到此结束。还有一个最后的设计模式。希望在这模块与你分享。如何构建多智能体系统。我们不仅有一个智能体。而是多个协作完成任务的智能体。在下一视频中了解。
P29 4-多智能体工作流
我们已经讨论了很多如何构建单个代理来完成你的任务。在多代理或多工作流系统中。我们拥有一系列多个代理协作为你处理事务。当一些人第一次听说多代理系统时。他们会疑惑为什么需要多个代理。难道只是反复提示同一个语言模型或仅仅是一台电脑。为什么需要多个代理。我发现一个有用的类比是。尽管我可能在单台电脑上处理事务。我们也会将单台电脑的工作分解为多个进程或线程。作为一名开发者思考时。尽管它很完善。一台计算机上的CPU。比如说。思考如何将工作拆解成多个进程或多台计算机程序来运行。这对我来说更轻松。作为开发者编写代码。同样地。如果你有一个复杂的任务需要执行。有时与其考虑雇佣一个人来为你完成。你可能会考虑组建一个小团队。来为你完成任务的不同部分。而在实际操作中。我发现对于许多ensystems的开发者来说,保持这样的思维框架——不问。我需要雇佣哪个人来完成这件事。而是相反。雇佣具备三到四个不同角色的人来整体完成这项任务是否合理。这希望能提供另一种方法来处理复杂事物。并将其分解为子任务。为这些独立的子任务进行构建。一次一个。看看这是如何运作的一些例子。以创建营销素材的任务为例。你想推广太阳镜。你能为那制作一份营销手册吗。你可能需要团队中的研究员分析太阳镜趋势。以及竞争对手的 offerings。你可能还需要团队中的平面设计师制作图表。或为太阳镜设计精美的视觉图形。还需要一名撰稿人整理调研资料。将图形素材整合起来。制作成精美的宣传册。或者撰写研究论文。可能需要研究人员进行在线调研。需要统计师计算统计数据。由主笔和编辑润色成最终报告。或者准备法律案件。真正的律所通常会有助理律师。法务助理。或许还需要调查员。而我们自然会因为人类团队的工作方式。能够想到将复杂任务分解为不同角色人员执行的不同方法。这些是复杂任务的示例。
我们已经自然将其分解为不同子任务,不同技能的人可以执行。以创建营销素材为例。详细探讨研究人员。图形设计师和撰稿人可能的工作。研究人员的任务可能是分析市场趋势和研究竞争对手。在设计研究代理时。需要记住的问题是研究人员可能需要哪些工具。以便撰写关于市场趋势和竞争对手分析的报告。一个自然需要的工具是网络搜索。就像人类研究人员需要完成这些任务。可能需要在线搜索以完成报告。对于图形设计代理。他们可能被 tasked with 创建可视化和艺术作品。因此软件图形设计师需要哪些工具呢。可能需要图像生成和处理API。或者类似于咖啡机示例。可能需要代码执行来生成图表。最后撰稿人将研究转化为报告文本和营销文案。在这种情况下。他们不需要除现有工具外的其他工具来生成文本。在下一视频中。我将用紫色方框表示代理。构建个体代理的方法。是通过提示LLM扮演研究人员或图形设计师角色。或撰稿人。根据代理类型而定。例如对于研究代理。可以提示其扮演市场趋势和竞争对手分析的研究代理。执行在线研究以分析太阳镜产品市场趋势。并提供竞争对手的总结。这样就能构建研究代理。代理。同样地。通过提示LLM扮演具备相应工具的图形设计师。并扮演撰稿人角色。这就是如何构建图形设计师和撰稿人代理。构建这三个代理后。要生成最终报告的一种方法是使用简单。线性有序工作流或线性计划。如果你想为太阳镜创建夏季营销活动。可以给研究代理下达提示。研究代理随后撰写报告说明当前太阳镜。趋势。及竞争对手产品。这份研究报告随后可提供给图形设计师分析数据。并创建几组数据。可视化与艺术选项。所有这些资源随后可以传递给撰写者。撰写者将结合研究结果和图形输出撰写最终营销手册。构建多智能体工作流的优势。在这种情况下体现在设计研究员或平面设计师时。当你可以专注于单一任务。
我可以花时间打造最佳的图形设计智能体。而我的合作者可能在构建研究智能体和写作智能体。最终我们将所有环节整合成一个多智能体系统。在某些情况下我看到开发者也开始复用部分智能体。在构建了营销手册的图形设计智能体后。或许我可以考虑打造更通用的图形设计智能体。它们不仅能帮助撰写营销手册还能制作社交媒体内容。还能协助设计在线网页的插图。通过思考。你可能会雇佣哪些智能体来完成任务。这有时对应于需要雇佣的人类员工类型。你可以据此构建这样的工作流程。甚至可能构建可复用于其他场景的智能体。这里展示的是线性计划。其中单个智能体。研究员完成这项工作。由平面设计师。最后由撰写智能体。你也可以选择替代线性计划。还可以让智能体以更复杂的方式交互。让我通过多智能体规划示例说明。之前你看到我们可能基于一组工具。调用以执行不同任务。在接下来要展示的内容中。我们将为语言模型提供调用不同智能体的选项。要求不同智能体协助完成各项任务。具体来说你可能会编写提示。例如你的营销经理拥有以下智能体团队。描述这些智能体的功能。这与规划和使用工具的方式非常相似。不同的是。绿色方框被替换为智能体。这些紫色方框可供调用。要求其返回分步计划。以执行用户的请求。在此案例中系统可能要求研究员研究当前太阳镜。趋势并反馈结果。随后要求图形设计师创建图像。并反馈结果。再要求撰写智能体生成报告。可能选择审核或反思。最后对报告进行最终优化。你将获取。研究者的文本内容。开展研究工作。传递给平面设计师。再转交给撰稿人。之后可能进行最终反思步骤。你就完成了。这个工作流程的一个有趣视角是,仿佛这里有三个代理。但左侧的元素实际上像第四个代理。有一位市场经理,负责管理市场团队。负责设定方向。将任务分配给研究者。平面设计师和撰稿人代理。因此实际上形成了由市场经理协调的四个代理集合。
代理协调研究者的工作。平面设计师和撰稿人。在这段视频中你看到了两种通信模式。其中一种是线性模式。你的代理依次执行动作直到结束。第二种则由市场经理协调其他代理的活动。事实证明,在构建多智能体系统时,你可能需要做出的关键设计决策之一。就是不同代理之间的通信模式。这是一个研究难点领域,多种模式正在涌现。但在下一个视频中我想展示。哪些是最常见的代理协作通信模式。去下一视频看看。
P30 5-多智能体系统的通信模式
当有一群人共同工作时。他们之间的沟通模式可能相当复杂。事实上设计组织架构图其实相当复杂。试图确定人们如何最有效地沟通协作。设计多智能体系统的通信模式同样复杂。但让我展示一些最常见的设计模式。我看到不同团队今天都在使用。在采用线性计划的营销团队中。是研究员与平面设计师协作。撰写者进行沟通,模式呈线性。研究员会与平面设计师沟通。研究员和平面设计师可能传递输出结果。再传递给撰写者。因此这是一个非常线性的沟通模式。这是目前我看到的两种最常见沟通方案之一。第二种最常见的沟通方案与此类似。在使用多智能体的规划示例中。存在一名经理与多名团队成员沟通并协调工作。在此示例中。营销经理决定调用研究员完成任务。若将营销经理视为接收报告。发送给平面设计师。接收报告后发送给撰写者。这将是层级式沟通模式。若实际实施层级式沟通模式。可能更简单让研究员将报告返回营销经理。而非直接将结果传递给平面设计师和撰写者。这种层级结构也是常见的沟通规划方式。我们有一个经理协调多个其他智能体的工作。再与大家分享一些更高级且较少使用的。但实践中仍会被采用的沟通模式。一种是更深的层级结构,与之前相同。当营销经理分配任务时。研究员。平面设计师。撰写者。但研究员需调用其他智能体。如网络研究员和事实核查员。可能平面设计师独立工作。而撰写者则有初始风格。撰写者还需调用引用核查员。因此这是智能体的层级组织结构。某些智能体可能调用子级智能体。我也在某些应用中看到这种模式。但相比单层层级复杂得多,使用较少。最后一种执行难度较高的模式。但少数实验项目会采用。这就是全连接通信模式。在此模式下任何人可随时与任何人沟通。实现方式是。你提示所有四个代理。在这种情况下告知它们还有三个其他代理可能需要调用。每当其中一个代理决定向另一个代理发送消息时。
该消息会被添加到接收代理的上下文中。接收代理可以思考一段时间并决定何时回复第一个代理。因此如果你们在群体中协作并互相交流一段时间。直到每个代理声明完成此任务。它开始发言。也许当所有人都认为已完成时。或者当作者认为已足够好时。这就是实际生成最终输出的时刻。因此某些应用不需要高度控制。你可以运行它并查看营销手册的效果不佳。也许这没关系。你只需再次运行。看看是否能得到不同结果。但我认为。对于可以容忍一定混乱和不可预测性的应用。我确实看到一些开发者在使用这种通信模式。希望这能传达多代理系统的丰富性。如今已有许多软件框架支持轻松构建多代理系统。它们也使得实现这些通信模式相对容易。如果你使用自己的多代理系统。可能会发现这些框架有助于探索不同通信模式。我们进入本模块的最终视频。以及本课程的最终视频,让我们继续收尾。
P31 6-结论
本课程的最终视频。感觉我们一路走来经历了许多。只有你和我。我们在亚洲人工智能领域探讨了许多主题。先看看第一模块。我们讨论了可以构建哪些以前不可能实现的AI应用。开始探讨关键设计模式。包括完美设计模式。这是一种简单有效的方法有时能提升应用性能。是工具使用或函数调用。这扩展了语言模型应用的功能,代码执行是其中重要案例。我们还花了大量时间讨论评估与错误分析。以及如何建立严谨的开发流程。同时分析以提高效率。如何持续提升AI系统的性能。第四模块包含我认为最有价值的内容。在持续构建AI系统的过程中。本模块将讨论规划与多智能体系统。可构建更强大的系统。虽然有时更难控制和预测。以及更复杂的系统类型。掌握本课程技能后。我相信你已掌握构建许多酷炫。令人兴奋的AI应用。当我或团队观察其他团队时。也会面试求职者。我发现面试。往往试图评估。候选人是否具备本课程所学技能。希望本课程能为你开启新的职业机会。你应该继续努力。无论是出于兴趣还是专业实践。相信你会享受现在能构建的新事物。最后总结一下。再次感谢你全程陪伴。希望你能运用这些技能。负责任地使用并开始构建酷炫项目。
P32 【模块6:Agent知识图谱】Introduction 介绍
由neo Neo4j联合打造的基因知识草稿构建课程。你将设计一个多智能体系统。将结构化和非结构化数据转化为知识图谱。我发现知识草稿在高风险应用中非常实用。信息存储和检索的准确性至关重要时。本课程将教你为何如此。同时提供构建这些知识图谱的强大工具。我感到非常高兴。本课程讲师是安德烈·阿尔杰。他是neo Neo4j的AI开发者。担任neo Neo4j的AI布道师。谢谢安德鲁。我很高兴再次回到这里与大家共同学习。类似于RAG。知识图谱系统。将文本文档拆分为块并存储在向量数据库中。但除此之外。还将块放入图结构中。每个块包含从块中提取的实体。例如。产品评论中的文本块。可能包含产品订单、配送问题或产品缺陷等实体以构建知识图谱。从块中提取相关实体。通过边将块与图中的实体连接。每条边代表一种关系。例如。可能表示该块提到了某个产品。或该产品存在问题。实体会与红色块一同被检索。为大型语言模型提供更相关的上下文以生成更精准的答案。你还可以将此类图连接到包含结构化数据提取信息的其他图。例如CSV文件。在本课程中。安德烈将引导你构建一个多。智能体系统。帮助完成构建此类知识图谱的工作。将结构化和非结构化数据转化为知识图谱。需要确定图结构模式。即从数据中可提取的实体或节点类型。以及它们之间的关系。确定模式后。即可构建实际图谱并存储于图数据库。无需主要依赖数据寻找图模式。你将设计一个多智能体系统来完成此任务。使用谷歌的A K或智能体开发工具包。学习ADK基础语法后。你将设计系统。逐步构建每个智能体。首个智能体将与你对话。提取目标及所需构建的图类型。基于这一目标。一组代理将专门从您的结构化数据中提取实体和关系。另一组代理将处理您的非结构化数据。最后一组代理将连接两个模型并构建知识图谱。相应地。许多人参与了这门课程的创建。
我想代表自己致谢。A Neo4j Martin。O’hanlon 和 Adam Cowley。来自深度学习。AI Christopher。Polycastro 和 Hara Salami 也为此课程做出了贡献。在第一课中。您将更深入了解知识图谱的底层结构。以及如何构建并利用它来识别根本原因。产品问题的根本原因听起来很棒。开始吧。
P33 1-什么是知识图谱
在本节课中。我们将讲解知识图谱的概念。以及它们如何帮助表示和检索数据中的关系。你将探索数据集。你将动手构建一个知识图谱。开始吧。什么是知识图谱。我们暂时退后一步,回顾关系型数据库。以及关系型模式的结构。我们可能都熟悉这样的场景。左边有一个表格,右边也有一个表格。中间这个表格。这是连接表,允许人员与产品之间建立多对多关系。在本例中。考虑这两个表格和连接表。如果你提出一个问题。比如这个人购买了哪些产品。你会先从人员表开始,选择此处的人员。其标识为abk。当然你需要通过连接到人员产品表。你会看到人员产品表中存在abk与某把椅子的关联。a k与一盏台灯。abk与一张书桌。太棒了,一个词。从人员表跨连接到人员产品表再到产品表。你已得到完整答案。从abk可以看到这里是他购买的产品,包括椅子。台灯和书桌。你可以获取这些购买的详细信息。如果扩展这个问题。并询问还有谁购买了abk购买的产品。你从相同的连接开始。从abk到产品。连接回人员产品表。再从那里回到人员表。你会得到购买了abk同类产品的人员ee。但注意ee还多买了一个产品。这很有趣。因此我们可以进一步扩展这个问题。哪种产品。我们应该推荐abk下次购买。这就是推荐查询的基础。如果你发现abk的购买模式。与其他人或群体的购买模式匹配。想要推荐给abk的是其他人购买的产品。而abk尚未购买的,因此同样的连接步骤。从abk通过产品连接到购买同类产品的其他人员。连接次数太多。这有点复杂。其实有一个更优雅的方式来思考这个问题。来执行这个查询。将其转换为图形结构。第一步是删除所有无关记录。所有那些未参与原始查询的优质记录。暂时将这些记录搁置一旁,专注于已知记录。属于数据集的部分。到目前为止。这对推荐给abk的内容查询至关重要。移除中间所有联合表记录。将这些转换为箭头。
直接连接abk到他购买的产品。同样处理ee到他们购买的产品。稍微调整记录位置。这样abk在一边,另一边。看起来整洁多了。更容易理解其中逻辑。a k和e都连接到中间产品。但此人还连接到与abk无关的另一产品。可以通过模式匹配将其转化为查询。以abk在左侧开始。可以用名为cipher的查询语言描述。看起来类似sql。如果sql具备模式匹配能力。这里描述要查找的数据记录模式。从我们将称为abk的数据记录开始。具有person标签。并有一个名为key的属性。其值为abk。这部分用圆括号表示。在图论中这是一个节点。有一个右向箭头带purchased。这是关系类型。即为购买行为。匹配abk购买到其他括号中的模式。我们称之为abk产品。从abk到匹配产品的模式。可以直接返回这些结果。对应中间部分。可扩展该模式包含其他购买者。从abk到其购买产品。还可关联到产品并说明。有其他人购买了这些产品。该模式会找到与abk共有的产品。可进一步扩展以解决推荐问题。而不仅仅是寻找其他产品。其他产品具有独特属性。这些是abk尚未拥有的。保持相同模式从abk到产品再到他人。并扩展到其他产品。我们添加了一个谓词,表示我们实际上希望一个负模式为真。Abk 没有购买那些其他产品。Abk 没有购买那些其他产品的地方。下方那个虚线部分。从Abk 到沙发。我们希望这个不存在。我们正在描述一个模式。同时包含应该存在的记录。某些不应该存在的事物。其他产品现在将缩减为Abk 未购买的产品。这就是我们要使用的。作为他购买的推荐。知识图谱到底是什么。它是一种以节点表示信息的数据库。代表人物等实体。产品。博客。任何你想在数据库中记录的内容。但同时也包含非简单连接表的关联关系。而是作为一等公民存在。数据库中实际存在具有语义含义的数据记录。
它们真正表示两个节点的连接方式。并添加关于这两个节点的信息。因此节点和关系都具有键值属性。节点有多个标签。关系始终有方向性。且具有单一类型。用于模式匹配的查询语言称为Cypher。结果发现这对映射自然语言非常方便。也非常适合与生成式 AI和LLM协作。因为LLM擅长自然语言处理。如果我们回到之前的查询。你可以朗读并理解它。匹配Abk 这个名为。Abk 购买了一些其他人也购买的产品。他购买了其他产品,而Abk 未购买这些产品。知识图谱的另一个有趣之处。在于它能方便整合非结构化数据。与结构化数据结合。无论是我们的产品还是人物。任何结构化数据中的内容。可以添加任意文本块。将其向量化存储在数据库中。结合向量相似度搜索和模式匹配实现多种强大查询。例如。如果你想进行根本原因分析。假设你是一家家具制造商,想要了解客户投诉。关于你们的产品。于是你召集专家团队。你知道数据工程和数据分析团队。说嘿。你能做一下根本原因分析吗。我听说网上有很多关于我们产品的投诉。我们得想办法找出问题所在。根本原因分析会包含类似哪些产品问题最多的问题。根据这些产品。产品哪个部分才是实际问题所在。你可能需要问一个问题。比如该部件本身有问题吗。或许还有其他因素在起作用。人们可能就是不喜欢这个产品。但如果你能采取纠正措施。可能是因为制造流程存在问题。这里需要寻找可采取的纠正措施。针对可以改进的问题进行根本原因分析。如果是设计问题。可以转交给设计团队处理。他们可以分析用户的投诉内容。但如果是制造问题或部件问题。可以在相关环节进行分析。找出部件问题。要么更换新部件。要么优化生产流程。作为数据工程师。如果接到这项任务。你会从常规步骤开始。提出澄清问题。我们为什么要做这件事。需要理解供应链可能存在制造问题。明白了。第二个问题是。或者要确定可用数据。
以便进行分析。在这个场景中我们需要构建材料。连接产品到供应商的CSV文件。可能来自某些电子表格。可能来自不适合分析的关系型数据库。没关系。太。同时还有用户评论数据。从互联网上抓取的网站数据。需要整合成一个数据集。便于后续分析。为了进行分析。需要构建知识图谱连接所有数据。这就是目标数据模型的左侧视图。大致呈米色方框。在那边你可以看到可用的CSV文件。每个都会转化为图中的节点。或者图中的关系。这就是我们所说的领域图。在右侧。底部还有一些米色方框代表Markdown文件。这些Markdown文件将会被分块处理。它们也会在图中创建文档。所有内容都将相互连接。在实际描述代理时我们会详细讲解。但我要重点指出的是这些部分高度互联。同时又是图中非常独立的部分。我们有数据源。一侧是结构化数据。那里将形成我们所说的领域图。这就是我们可以查询的结构化数据。另一侧是模式匹配。非结构化数据源不会以相同方式查询。也不会以相同方式导入。它们将形成我们所说的词汇图。代表原始文本数据。同时连接文本数据的结构以关联两者。非结构化数据与结构化数据之间。中间部分称为主题图。主题图包含从分块中提取的主题或实体。分块将包含一些文本。可能讨论产品。可能提到用户名等。这些都是可能的实体。我们将识别这些并称为主题。这些主题将连接到对象。主题会描述某些内容。例如某个用户。假设是本人。用户abk喜爱这张表格。主题图中会出现主题谓词对象结构。描述abk喜爱某张表格。因为abk喜爱某张表格。该表格可对应结构化数据中的产品。如果abk提到一张表格。而该表格是结构化数据中的产品。我们可以将从文本中提取的实体连接起来。一直连接到CSV文件中的结构化数据。来自CSV文件。不用担心。我们将逐步在高层次进行讲解。最终你会得到一个包含子图的图。领域图。
主题图和词汇图。
P34 2-多智能体系统的架构
你已经了解了要构建的知识图谱的目标。详细探讨多智能体系统的设计。你将首先设计图模型。为大量定义构建图结构。这是我的定义。我喜欢从工程角度思考智能体。对我来说这就像一种新型的控制流操作符。基本上你有一个循环结构。循环内部会调用LLM来确定下一步行动。根据确定的行动目标。将结果返回到计算机端。传回客户端。真正执行到一个开关语句处理潜在操作。在这个循环中这就是真正的智能行为。这一切都得益于LLM 调用。但智能行为的执行仍通过代码完成。这种架构的优势。当然在于智能体非常强大。因为LLM能进行推理并调用各种工具。可以执行任何代码操作。并且具备灵活性。因为LLM拥有记忆功能。能够学习已发生事件。无论是通过对话还是存储的重要信息。这些信息对决定未来结果至关重要。并且非常容易上手。因为你只需用自然语言描述。通过提示定义智能体的任务。但这种强大与便捷也存在缺点。使用智能体可能会很缓慢。因为需要远程调用。LLM 调用既昂贵又耗时。这也是非确定性的。因为LLM本身具有不确定性。长期来看。每次调用的token成本会累积很高。如果在生产环境中持续运行智能体。处理成千上万次调用。token成本会迅速飙升。这就是采用多智能体系统的优势之一。可以改善这些缺点。什么是多智能体系统。本质上是多个智能体协作完成单一目标的系统。智能体通常按层级结构组织。顶层智能体负责整体流程管理。可以添加任意数量的子级智能体。负责不同工作阶段或特定任务。智能体通过多种方式交互。存在主要的对话线程与用户交互。用户可能发起启动工作的消息。每个代理都可以决定。这是我可以做的工作还是应该由别人来做。我可以将这项任务委派给其他代理。你可以在这张示意图中看到。根代理能够内部委派给代理A或代理B。代理A和代理B可以使用分配给它们的工具执行任务。
代理B中的一个工具是独特的。这里的P代理。这个P函数实际上会成为另一个代理。但被调用时像工具一样使用。工具之间有两种交互方式。要么代理之间互相委派任务。或者作为工具的代理被另一个代理调用。过程中还会有与用户的特定检查点。每当发生这些转换时。你构建的多代理系统是什么。你将构建知识图谱代理的部分。专注于执行知识图谱构建的子代理。你将学习使用谷歌ADK构建代理的基础。你将了解记忆是什么以及如何记录关键信息。你将找到一些工具。当然这一切都将从开放式对话转化为可执行代码。这张精美的示意图展示了所有代理及其交互流程。我们逐步解析这个整体结构。这是管理用户整体介绍的代理。代理的责任是什么。并帮助用户理解。这里可能的工作流程是什么。从知识图谱构建。一直到图检索。这实际上是一个不会执行任务的对话代理。但它会引导用户完成各个工作阶段。真正管理具体工作流程的是下一层代理。这里有三个主要工作流。在左侧。我们有两个工作流。结构化数据代理和非结构化数据代理。它们负责引导用户从想法到构建图谱。比如他们可能想要完成的目标到构建图谱。如果这些工作完成。第三个代理。右侧的图RAG代理。负责帮助用户利用该图回答问题。但结构化和非结构化数据代理是工作流代理。它们通过与用户互动完成工作。并协助用户完成所需步骤。从用户目标到描述图谱。它们通过委派专门处理各阶段的子代理来实现。这里会有一些重复。结构化和非结构化数据共享一些共同代理。在深入一级时我会提到这些。这些子代理实际上正在处理结构化数据的工作流程。我们逐个分析这些内容。需要特别注意的是。这是这些亚洲团队实际工作的输出结果。如果你把自己想象成数据工程师。被赋予执行这项工作的任务。每个代理都相当于你自己会做的事情。你正在参与这项工作。第一个代理。用户意图代理。
当你被要求执行数据分析任务时会做的事。并需要向提问者回应。嘿。你能澄清我需要做什么吗。给我。你知道的。你追求的目标是什么。你希望我进行哪种分析。必须尽早明确这一点。这是任务的整体要求或方向。因此用户意图代理。尽管是协作且对话式的。这个输出非常重要。我们正在捕捉用户的最终目标。基于用户目标,他们希望通过这项工作得到什么。是文件建议代理。将综合用户意图代理确定的方向和目标。作为工作的方向和目标。查看可用的数据文件。从这些文件中找出对实现目标有用的。可能还有更多可用文件。甚至可能存在多个数据源。我们简化为仅建议磁盘上的可用文件。输出是用户批准的建议文件列表。输入到下一个代理。即模式提案代理。模式提案代理实际上是采用批评模式的双代理组合。其中一个代理负责提出可能的模式方案。下一个代理则作为批评者。比如。或许这样修改不太合适。或者我们可以稍后再讨论细节。核心思想是这些代理会内部循环评估。自我批评。最终产出良好的图模式。使用前代理批准的文件。并符合首个代理设定的用户目标。生成能回答用户问题的图模式。因此,所有这些输出我们称之为图构建计划。它本身并不是一个图。但它是关于如何构建该图的描述。中间的第二个工作流程。该工作流程的前两部分与结构化数据工作流程完全相同。在这里我们处理的是非结构化数据。但仍需首先理解用户引入非结构化数据的意图。这里的数据是markdown文件。如果你理解用户为何要引入某些markdown文件。可以再次识别相关文件。文件建议代理会执行与结构化数据相似的行为。但第三步在此有所不同。不再基于csv文件设计模式。你只有纯文本。从文本中。如何创建一个图。此处的方法是使用两个专门的代理分析文本。并识别所谓的实体。如人物。文本中出现的地点和事物。同时为这些实体识别描述性事实。文本中关于这些实体的事实。
例如文本中提到。我知道我在文本中。我有一些本地咖啡店的评论。可能会发现。阿布克非常喜爱飞利浦咖啡。因为谁不喜欢呢。这些可能是从文本中提取的事实。该代理的目标是确定可提取的事实类型。而不是实际提取。只是描述可能性。因此我们将称之为知识提取计划。知识提取计划与结构化数据的图构建计划结合。提供所需的所有规则。通过图构建计划和知识提取计划。角落的红色方框。只是一个包含多个工具的单一工具。能够执行这些计划并完成提取与构建。遍历所有构建规则。生成领域图。遍历所有markdown文件。进行分块处理。对内容进行向量嵌入。同时提取实体和事实。并将它们连接到结构化数据。在第四至第八课中。你将完整体验结构化数据的工作流程。从用户意图文件建议到模式提案。我们将转向非结构化数据。仅进行实体事实类型提案。最后我们将查看第八课中的特定工具。该工具负责执行图结构构建。它完成了所有繁重工作。之前代理已在此课中完成对后续工作的推理。我们将实际进行编码实践。构建你的第一个代理。我们将使用Google ADK。如果你已熟悉谷歌ADK。可以跳过该课直接构建多代理系统。但我认为这是一个很好的概述。同时帮助你理解我的思考方式。以及我在该多代理系统中的实现方法。因此值得逐步讲解。我们那时见。
P35 3-1 Google ADK简介 Part1
要构建多智能体系统。你将使用Google ADK或智能体开发工具包。这是一个用于开发智能体的框架。在本课中。你将学习如何创建和运行单个智能体以及整个智能体团队。开始本课的学习。你将熟悉谷歌的智能体开发工具包。并将使用它来构建整个多智能体系统。在本课中。你将学习如何使用ADK创建和运行智能体。以及我们正在导入的内容。当然包括标准的os模块。是从谷歌ADK本身导入的大量内容。我们将导入这个智能体。这将是描述智能体核心功能的关键。与大型语言模型交互。我们将使用LiteLLM库。在这里进行导入。这是一个让谷歌80K与OpenAI通信的小封装。同时我们还需要为智能体准备记忆功能。我们将使用记忆会话服务。最后智能体还需要一个运行方式。因此导入运行器。我们还有一些类型相关的代码。这些对整体功能影响不大。确保所有导入都正确。所有库都已导入。是定义将要使用的模型。本课程将使用OpenAI。开始导入。我们将定义模型本身为GPT-4o。再次使用GPT-4o。我们将通过LiteLLM调用OpenAI API。尝试一个简单的聊天完成示例。如果你查看这里的聊天内容。你会注意到我们正在设置一条消息。即将发送给OpenAI。并询问。你准备好了吗。如果一切顺利。我们将收到OpenAI的成功响应。确认系统正常运行并查看响应模型。这里包含大量信息。但关键部分是响应包含OpenAI的消息。回答是。我已准备就绪。今天如何协助您。OpenAI已就绪。我们今天还将使用Neo4j。因此导入辅助库。这将新Neo4j与谷歌avk以优雅的方式结合。这个库是我们可以查看以了解细节的。正在发生的具体细节。我们将要使用的导入内容。仅从新Neo4j for eighty k导入图数据库库。看看这些细节。我们进入了新Neo4j for ADK。
你可以看到它开始得相当简单。我们从操作系统导入了一些内容。当然加载了环境。从you for j的python包。我们加载了图数据库。你还会得到一个结果类定义。这里许多函数都非常适合。封装如何与meNeo4j交互。并以Google ADK喜欢的方式呈现结果。其中一个关键。点是结果应返回字典形式,状态为成功。或作为错误。这两个辅助函数可帮助实现,你可以调用success或error。连同其他参数。并从任何调用中获取格式良好的结果。我们随后整合了由谷歌ADK处理的辅助库结果。需要易于持久化。此处调用python的函数。遍历新Neo4j返回的各种结果类型。并将其转换为谷歌ADK可读的序列化格式。你可以查看细节以了解具体情况。关键部分。当然。是这个处理新Neo4j结果的函数。基本调用python包。将其整合为谷歌ADK可轻松使用的结果。每个辅助函数也被上层类使用。名为dNeo4j for ADK。这实际上是一个包装器。整合新Neo4j驱动程序,初始化环境变量。提供驱动程序访问权限。有一个特殊函数用于发送查询。可以发送任何类型的查询。但使用这些辅助函数重新格式化结果。最终生成Google ADK友好的结果。由于我们只有一个驱动和连接。我们将使用该类的单例。这是我们将暴露的图数据库变量。并通过所有笔记本使用。我们查看了新Neo4j for eighty k。我们继续使用笔记本。一切已就绪,我们可以开始定义智能体本身。我们的新Neo4j包装器已准备就绪。我们继续尝试一下。你可以输入类似Neo4j查询语句。只要这里语法正确。我们发送的Neo4j语句是一个非常简单的声明。除了直接返回结果外不做其他操作。在这里返回结果。结果是一个字符串。新Neo4j已就绪。将结果作为消息变量返回。如果我们运行这个。打印结果。
你会看到它被封装成一个整洁的字典。包含状态成功。以及包含数据库返回所有行的数组的查询结果。太好了,OpenAI已就绪。Neo4j已就绪。我们可以开始定义工具和智能体。最终工具定义是定义无工具智能体的重要部分。智能体可以进行大量思考。也许进行一些对话。但无法与环境或周围世界交互。我们将创建一个非常简单的工具。仅用于说明智能体能做什么。Hello World是经典示例。当然。我们将开发智能体工具的Hello World版本。并命名为say_hello。工具可以简单定义为函数。函数只需说Hello。接受单个参数person_name作为字符串。并返回一个字典。当然这个字典是符合Google AK规范的。其中包含几个重要部分。这里有一个文档字符串。编写代码时总是有用的。在开发Google ADK工具时尤其关键。这个文档字符串让Google ADK理解工具功能。会传递给语言模型。当模型被告知。这里列出所有可用工具。以及这些工具的功能描述。我们需要了解几个重要部分。在这里描述工具功能。仅格式化给定姓名的欢迎消息。当然,输入的person_name参数。你描述了正在传递的参数。还有结果。这里的结果在所有工具中保持一致。因为结果是一个谷歌喜欢看到的字典。但你可以在这里添加一些额外细节。例如。如果你知道可能出现的错误类型。也可以在函数内解释这些错误。函数内部操作非常简单。我们将调用Neo4j发送查询。我们仍然返回一个问候语给你。将其与这个人名连接。这个人名作为函数参数传入。这将作为查询参数传递。每当在Neo4j语句中看到美元符号时。这意味着这是一个查询参数。在这个传递的字典数组中。你会看到人名被传入为person name。这里会被替换为该变量。并非模板替换。而是作为变量值传递。整个查询将执行。我们定义这个函数。
当然因为这是一个普通函数。我们可以尝试运行它。我们可以打印’向abk问好’。预期看到格式良好的谷歌ADK成功结果。发送到four的查询结果。J有回复。向你问好abk完成拼接真棒。关于查询参数的补充说明。我们这样做部分原因。这对任何查询语言都是良好规范。大多数查询语言。都支持查询参数。这样做原因之一是避免注入攻击。防止用户传入类似sql或cipher语句的值。或任何查询语言语句作为值。并将其拼接到字符串中。可能导致各种混乱。因此传入查询参数。在这里。例如。如果传入名称并说实际名称是hey。此处返回字符串。这可能被恶意代码替换。如果直接拼接为字符串。各种坏事可能发生。因为它是一个仍然作为变量行为的查询参数。它会被传递进来。它会与其他字符串进行字符串拼接。结果就是简单的hello对稍显友好的恶意注入攻击。当然这已经被避免了。我们有了一个基础工具。我们可以定义一个使用该工具的代理。定义代理有几个组件。所有框架中都有共同点。它们会以相同理念的不同变体实现。看看谷歌内部的情况。今天定义一个代理。如果你还记得之前。我们从Google ADK导入了这个代理类。我们将创建该类的实例。它需要大量参数。重要的是每个代理都需在此命名。我们将其命名为hello。Agent_v_one。以防同时需要多个版本代理。或需要不同版本的指令。明确代理版本对调试非常有帮助。稍后。你还需要传入使用的模型。如果你还记得。我们之前定义llm为通过light调用。Llm连接到OpenAI。这里我们将使用该模型。这两个对谷歌ADK的协调执行至关重要。和执行代理。是代理的描述。类似于工具的文档字符串。描述该代理的功能。让谷歌ADK。也让其他代理理解该代理的目的。以及何时应调用该代理。而非自行处理。这称为代理委派。
这是其他代理如何处理该代理的依据。对于代理本身。需提供一些指令。指令与你在提示工程中所做的类似。当你进行提示工程时。并定义系统提示。这是为llm设定的提示。与你在那里的操作相同。这是一个hello world代理。当然非常有用。这是一个乐于助人的助手将与用户聊天。它实际上只有一个想要使用的工具。在这里描述这个工具。因此代理不仅从工具定义中理解。还要从你的指令中了解如何思考该工具。以及何时使用该工具,所以在这里。如果用户提供他们的姓名。你知道。使用say hello工具提供个性化问候。哀悼。最后一部分。当然我们需要让这些工具可用。工具作为函数名数组传递。我们需要传入。Say hello。拥有该工具的代理。知道如何使用该工具。因为我们提供了指令。和其他代理。如果有其他代理现在知道这个代理的角色。代理拥有一个工具。并且有关于如何使用该工具的指令。我们需要运行代理。这是创建基础遗传系统最后一步。代理必须有一个执行环境。你看这个图表。你会看到在这个框里。这就是执行环境发生的地方。有一个运行器类管理所有事件循环。基本上用于调用LLM。将LLM结果传递给特定代理。并协调所有代理本身。以及它们的执行方式。每个运行器还访问各种服务。无论是内存服务例如。进行实际内存存储。或者可以使用数据库技术作为记忆。这提供存储访问。执行逻辑在执行循环内。这里是实际运行和协调代理的步骤。代理是并行、顺序还是循环执行。所有这些共同构成代理的执行环境。我们将手动实现这一点。展示如何封装为便捷方法。在使用Google ADK进行开发时。Google ADK提供了优秀的工具定义代理。并运行代理的实际工具。并提供所需完整执行环境。我们将手动完成这些步骤。在笔记本中进行。我们一步一步来。将其封装成一个小助手。
你需要准备几个实际设置执行环境的事项。每个运行时实际上都在一个会话中运行。当然。当然可以有多个在生产环境中运行的会话。我们将使用单一会话。我们将设置内存服务。为代理提供上下文和状态。在运行过程中。我们可以基于该内存创建会话服务。以及针对我们编写的特定代理。同时假设我们有一个用户。我们将假设只有一个用户。一个在单一会话中运行的应用程序。所有这些都将在这里使用。在创建会话时用于生成可执行状态。运行器将运行该状态。基于它拥有的代理。这里运行器结合了我们要运行的hello world代理。应用名称将与我们传递给会话的名称相同。同时会话服务将是该代理运行的会话。在生产环境中。可能会有多个会话。可能会有多个使用该代理的应用程序。这就是这些运行参数的不同之处。有很多内容需要讲解。仅为了实际运行代理。逐步进行,慢慢来。我们知道已经有了这个运行器。我们刚刚定义的。我们将进行一次单循环处理单用户消息。让运行器执行代理以响应用户消息。我们将定义用户消息。我简单说一声’你好’。我可能是K,然后以友好方式打印该消息。这样我们可以看到运行过程。了解发生了什么。这个纯文本消息。需要打包成Google ADK运行时期望的数据结构。运行时环境需要。通常这是后台自动处理的。当然。但我们手动进行。我们将在此创建内容类。我们创建的内容角色来自用户。这是一个用户消息。内容可以包含多个部分。我们将创建一个部分数组。其中一个部分包含一些文本。这里的文本是用户消息。这些内容被打包起来以便执行更复杂的操作。我们只是尝试运行单个用户的单条消息。当有大量额外操作时,这能提供很大灵活性。这基本上是在创建内容事件。需要由代理运行时系统处理。我们还将设置代理系统的响应。以防它没有执行任何操作。输入一条消息后。我们将实际执行。运行该消息并让代理有机会响应。
但代理可能不会响应。存在最终响应的概念。这是代理通过不同方式设置的标志以表明。我已完成对此的思考。或已完成处理。如果代理无反应,可返回用户。最终响应可能未设置。因此我们预先设置默认值以表明无操作。目前可以不显示详细输出。稍后您可以看到。详细输出可能是什么样子。这就是事件循环本身。应该说明事件的一个步骤。比如针对这条用户消息。我们将异步使用运行器并调用LLM。使用传入的代理和指定模型。以及所有提供的指令。注意到当我们调用此异步方法时。我们还传递了创建会话时的所有信息。这是因为可以重复运行。可能存在多个会话。因此多个事件循环在异步运行时传递。这是当前的操作上下文。针对该用户和会话。这是传入的内容。使用LLM执行一次。在此进行处理。这在循环内部。因为这是一个事件系统。当代理收到此消息后。可能在最终响应前执行多项操作。事件循环在此提取代理的异步事件。每个事件是代理的更新信息。当事件到来时。如果启用了详细模式。我们将打印。这里发生了一个事件,这是谁创建的事件。初始事件。当然应该传递用户消息。我们应该看到该事件。作者是用户自己。你也会看到事件内容。你可以查看调试语句中的情况。大量信息被打印出来。有助于理解当前状态。这是保持事件循环运行的关键概念。只要你想让它运行。希望代理只会执行必要操作。但每个事件到来时。有一个标志表明。这是最终事件。我已完成处理。代理已完成处理。如果它设置了这个。你就知道。处理已完成。可以查看内容。决定最终响应可能是什么,我们查看内容。如果存在多个部分。如果返回的文本数组非空。我们将取第一个消息部分。提取该部分的文本。这里我们做了一些假设。第一部分的文本响应实际上是正确的,转换为最终响应文本。或者代理可能决定这就是最终响应。顺便说一句,我实际上没有响应。我要求运行时系统执行的是升级。
升级最终结束。意味着代理正在运行。知道它是子代理。无法处理。或无法继续处理现有内容。基本上在说。将此升级给他人。可能是上级或其他代理。可能更合适。在这种情况下。最终响应文本将基于此。我们将说。亚洲团队决定升级当前消息处理。我们没有具体消息。或存在错误消息。如果有则返回该消息作为最终结果。所有操作是为了继续一轮事件循环。由单个用户消息触发。最后我们将打印出最终的代理响应。这有点内容需要处理。但请稍微记住这一点。在浏览所有内部笔记本时。这正是让所有运行的机器实际运作的关键。所有这些工作。我们进入简单聊天。你好。我是abk。你好abk。当然。因为我们将会大量手动调用代理。我们将设置一个辅助类来帮助我们。更轻松地完成这些操作。我将其命名为代理调用器。这个代理调用器封装了我们之前讨论的那些函数。这里逐一处理每个函数。并将事件循环本身整合到一个类中。如果你查看细节。它完成了我们之前看到的所有操作。保存单个用户ID。单个会话ID。当前要运行的代理。以及已设置的运行器。它可以访问用于内部管理的会话。这里的调用函数会触发一次事件循环往返。基于用户消息。它执行我们之前看到的操作。接收用户消息。将其打包。使其可被代理处理。运行事件循环。同样可用调试选项。这纯粹是风格选择。我不是原生Python开发者。我喜欢这样操作。偏好为复杂构造创建工厂方法。而不是在类中使用复杂构造器。我创建了一个单独的构造类。这里的实用函数make_agent_caller。将创建代理调用器实例。你需要传入所有必要信息。指定要运行的代理。以及代理的初始状态。其中状态是代理的内部记忆。所有内容应与之前运行的一致。但现在封装成不同组件。应整合到代理调用器中的主要组件。当前应用是什么。会话ID的使用者。为内存创建会话服务。同时用于管理会话本身。
最后还要创建一个运行器。在构建完所有组件后。将它们传递给代理外壳。该外壳将所有内容整合到执行循环中。我们有了运行代理的实用函数。可以运行一个问候对话。我们之前创建的代理。要为我们的问候代理创建新代理调用器。代理。我们将调用辅助函数。创建代理调用器并传入问候代理。我们将其命名为问候代理调用器。要运行对话。我们将创建一个异步函数。传入多个用户消息到代理调用器。使用call方法。我说你好。我可能在。我说我很兴奋。我们运行这个对话并查看效果,太棒了。我们创建了一个友好的聊天代理。做得很好。你已经学到这里。已经掌握了使用Google ASDK的基础。如何创建代理。如何为代理添加可用工具。同时如何为代理创建执行环境。最终掌握这些内容后。可以在笔记本中编写与代理的交互脚本。传入用户消息以测试代理的工作方式。我们创建的这个优秀的代理调用器类。以及工厂方法make_agent_caller。我们将在后续笔记本中使用它以简化操作。找到代理后。可以轻松使用该函数创建运行时环境。你会频繁使用这个功能。
P36 3-2 Google ADK简介 Part2
上节课你学习了如何使用Google ADK创建一个代理。我们将创建多个代理。一组协同工作的代理团队。我们将有一个根代理。构建两个子代理,基于之前的内容。我们需要说。你好。代理。我们将引入一个新代理来执行告别。我们将创建另一个代理,将其整合为一个完整的多代理系统。我们开始导入所需的库。当然。设置我们将继续使用的语言模型。这是OpenAI。我们定义语言模型。并通过传递消息进行快速验证。确保系统已就绪。总是有趣看看OpenAI当天会说什么。通常会发送友好消息。它会友好回应。可以设置代理调用器。我们将使用之前定义的同一类。在第三课第一部分。无需重复定义所有内容。只需导入所需工具。如果你还记得第一部分。我们有一个辅助函数。创建代理颜色。将生成包含运行所需功能的代理颜色类。所有准备就绪。开始构建多代理系统。创建多个专业代理。每个负责特定功能。创建一个负责问候的代理。即说你好。之前的代理负责问候,新代理将处理告别。通过根代理将两者结合。你会听到协调者或调度者等术语。顶层代理。本质上是封装其他代理的代理。并管理其执行。根代理将接收初始用户请求。无论是问候还是用户指定的内容。决定如何处理,自行执行或委托。转交给子代理处理。因此根代理。这个顶层协调者将委托问候和告别任务。希望由专门处理这些任务的子代理执行。开始组装我们的多代理系统。我们将使用之前提到的打招呼代理。我们现在要添加一个道别代理。我们将它们结合起来。定义子代理的工具。第一个工具是来自前一课的相同打招呼工具。这是hello world函数。接收人名并生成问候消息作为响应。我们将加入道别函数。这个工具比打招呼更简单。因为它不接受任何参数。无论什么情况都会返回固定的回复。无论你想做什么。你将得到这样的响应。用这两个工具向用户道别。可以定义使用这些工具的代理。
我们将创建专门的问候代理和道别代理。但你会发现非常简单。在定义这些子代理时。我特别强调最佳实践。每个代理的详细描述非常重要。以及传递给它们的指令。一旦建立多代理系统。大部分时间将用于。在设置任何多代理系统后。大部分时间将用于。优化这些指令。这回到经典提示工程。同时重复前一课的内容。描述让其他代理知道。这个代理的功能。以及何时调用该代理进行委派。指令是让代理自身理解。其目的。要实现的目标。可用的工具。以及何时使用它们。这是问候子代理。它只能访问打招呼工具。我们将添加道别代理。与问候代理类似。可以查看这里的指令描述。这些指令值得仔细研究。看起来很明显。你的任务是作为道别代理回应。当用户以某种方式说再见时。人们用各种方式道别。这是一个在代理指令中进行少量学习的小例子。这里括号内有示例。例如当用户使用像’再见’这样的词。再见。谢谢再见。或者下次见。这些都是告别的方式。大多数LLM不需要额外的例子。但总体来说这是一个好习惯,需要思考。我该如何帮助LLM理解这个代理的目的。以及何时执行和在角色中该做什么。当然我们要交给它说再见。我们之前定义的工具很棒。你知道的。我有两个子模块准备就绪。我们需要将它们合并。我们将通过定义根代理来实现。它将理解这两个子代理。并判断何时委派任务。类似于调用工具。但代理知道在与另一个代理对话。因此整个对话历史会被传递。并且对话控制权会转交给子代理。这与调用略有不同。但核心思想相同。当前工作流将从负责的代理开始。根代理到子代理之一。这类似于调用工具。但让我们仔细看看代理委派如何运作。我们知道代理自身已描述了角色。它们会说。你好。亚洲代理与告别代理。两者都清楚自身职责。它们的描述告知其他代理职责。他们的工作是。我们将进一步强调这一点。在给根代理的指令中。
根代理需被告知其职责是协调子代理团队。你可以在指令中看到这一点。其主要目标是保持友好。为了保持友好。它拥有两个专用子代理。因此需描述这些子代理。以便代理知道何时使用子代理。这类似于描述。何时使用特定工具。问候代理用于处理简单问候如你好或嗨。当然告别代理用于说再见。无论是’再见’或其他表达。这里明确说明。当收到用户消息时。请委派子代理实际回应用户。与其直接作为协调者回应。如果这个方案有效。协调者只需回答一般性问题。当你说问候或告别时。应转交给子代理执行响应。或生成对用户的回复。顶层协调者没有任何工具可用。只能进行对话或转交子代理。我们也将在此分发子代理列表。在子代理的键中。因此子代理包括问候子代理和告别子代理。我们将所有代理整合成一个多代理系统。开始与之互动。这与第三课第一部分类似。我们有一个管理对话的异步函数。因此对话可以和之前一样。你好。我 abbk。稍后。而不是说。我很兴奋。这段转录将显示。谢谢再见。这将是第二个用户消息。我们还添加了这个true。当你调用这个代理调用者时。传入的第二个参数是是否开启详细响应。我们将启用详细模式。这样可以看到后台运行情况。可以理解用户输入信息。观察转交过程。查看工具调用。并看到响应结果。内容较多需要梳理。但至少走一遍有助于熟悉。在调试代理时。交互过程。这开始看起来很正常。接收用户消息。你好。我可能k,可以看到初始事件来自友好代理团队。这就是顶层协调者。将调用子代理的团队协调者。可以看到它的第一个动作是转接到代理。即转交或委托给子代理。并将转接到问候子代理。完美对应问候回应。我可能k 顶层协调者意识到。我有一个擅长问候的代理。让我将控制权转交给那个代理。响应的转移没有任何。你知道的价值。whatsoever。它只是一个修女。
但接下来我们需要看到问候子代理接管控制。这里又有一个事件。但现在由问候子代理处理。它将查看对话记录并分析用户消息。并意识到。我需要实际处理这个问题。问候子代理将通过调用工具进行响应。你可以看到此处的函数调用及目标函数名称。Called。Say hello。并将传递一些参数。其中传入的参数是人员名称为abk。代理已从当前语句中识别出。当然。你好。我是abk。它成功提取了abk应为人员姓名。并将调用工具函数传入该名称。接收响应。这里是函数响应,回复是向abk问好完美。问候子代理已完成。继续执行,最终消息为true。这是表示已完成处理的标志。我们可以终止此事件循环。最终代理响应即为工具返回的结果。向你问好abk。我们发送第二个查询。或用户的留言,用户说谢谢再见。顶层代理将继续处理。哦其实不是。仍由问候子代理控制。问候子代理自身会意识到。这不是我该处理的内容。请转交给告别子代理。它已知晓可用的其他代理。转交给告别子代理。此处函数响应结束。是告别子代理的留言。再次查看对话记录。在接管当前对话后。会意识到。用户说了再见。我将调用说再见工具来生成响应。这就是用于道别的函数调用。当然它像预期的那样不接受任何参数。但它的响应是我们之前在工具定义中看到的常量。它将获取告别信息。这是来自cipher的再见。这再次是此事件循环的最终响应。因此这将是最终的代理响应。来自cypher的再见。刚才讲解的内容很多。花时间理解这些内容对后续工作很有帮助。你可以看到所有工具调用的交互过程。代理委托机制。以及整体状态的变化和响应。非常值得这样做。我们不会在每个笔记本中都这样做。但如果你有时间。请务必花时间深入理解背后的原理。因为幕后发生的事情会影响。当然整体架构的定义方式。以及代理编排流程。你将在多代理系统中再进一步。
我们有一个代理的执行环境。我们拥有多代理团队协同工作。它们可以互相委托任务。每个代理还拥有工具。所有代理系统最重要的组件是记忆功能。记忆就是内部状态。在特定会话中涉及的任何代理之间持续存在。当然还有用户自己。什么是会话状态。在Google ADK中默认的会话状态其实就是一个可用字典。你可以更新该字典中的键值。当你更新这些键的值时。Google ADK会追踪这些变化。基本追踪状态的增量变化。并更新整体会话状态以保持一致性。无论代理是并行还是顺序运行。因为系统本质上是异步的。它管理所有状态更新。代理有几种不同的状态交互方式。其中一种我更推荐的方式。与状态交互的主要方法是通过工具上下文。每当调用工具时。会有一个额外的参数可用。即该工具被调用时的上下文。基于此工具上下文。工具本身可以访问当前状态或代理的记忆。并利用这些记忆做出不同决策。生成不同输出。无论对内存是否合适。代理还可以通过使用输出键与状态交互。因此无需使用工具调用来更新某些内存。以及访问内存时。你可以获取代理最终响应的实际输出。而不是仅将此结果作为代理的响应返回。你可以通过定义输出键保存中间状态。当你看到这个最终结果时。与最终结果相关的信息。此处应为文本内容。再见信息可用于更新自身状态。这有时非常方便。稍后在这些笔记本中我们会稍作演示。在下一步中我们将设置一些内存。我们始终使用当前的内存会话。因此内存仅保存在RAM中。并未持久化到数据库。当然这是生产系统的最佳做法。但出于便利性。使用内存状态完全没问题。我们将更新两个工具以利用内存状态。无论是打招呼还是道别。我们将更新这些工具以利用工具上下文。用于更新会话状态或内存。应逐一进行并仔细对比差异。你会发现我们导入了Google ADK的工具上下文。工具上下文是管理会话状态的类。
除了其他对工具有用的功能。我们将更新打招呼函数为状态化版本。状态化。仍接受用户姓名参数。但新增了工具上下文参数。工具上下文将让我们访问会话状态。由执行环境传递的会话参数。在工具上下文中有一个状态字典。我们将更新用户名键。使用函数传入的名称。用于更新会话内存。或会话状态中的用户名键。这非常直接,用户名用户名。有一个所有代理共享的字典。所有工具均可访问此函数传入的值。这是一种通过函数自然使用来跟踪信息的方式。同时为后续调试保留这些信息。当调用此工具时。我们将打印会话状态的更新。特别是用户名键。当然我们仍将执行之前的操作。说 hello。我们将向near发送一个查询请求,使用查询参数j。这就是用户名。你已经定义了,我们继续定义这个。你可以为say goodbye定义相同的内容,再次操作。在定义这个过程中。这只是对say goodbye的更新。我们之前定义的那个。不同的是这个say goodbye。尽管它不接受任何与用户相关的参数。这里没有自定义参数。但它会接收工具上下文。我需要说明这是Google ADK自动处理的。当检测到工具的最后一个参数是工具上下文时。会自动注入该上下文到工具调用中。当执行say goodbye。Stateful被调用时。将获取工具上下文但无其他内容。但因为say hello。Stateful设置了状态。将用户名存入状态。say goodbye。可以实际访问用户名。我们记住了用户的姓名。可以访问状态键为username的值。并设置默认值以防用户未自我标识。但可以从字典中获取。用户名或默认值。赋值给用户名变量。用于生成告别语句。你可以定义新的stateful代理处理告别。这与之前的联邦代理相同。但现在会调用say goodbye stateful工具。如同之前。
可通过根代理或协调者将它们组合成多代理系统。由根代理或协调者使用这两个子代理。这与之前的根代理完全相同。仅使用核心基于状态的子代理。这些具有状态管理的工具。拥有利用记忆的多代理系统。你可以尝试一下。使用朋友创建代理调用者,传入新root代理stateful。这是协调者的顶层。为该代理创建调用者以观察会话变化。我们直接从调用者获取会话。记得有获取会话的实用函数。查看亚洲调用者类。我们获取会话。基于该会话。打印创建时的初始状态。应看到当前状态为空。正如预期的那样。初始状态为空。你现在可以定义一个对话。这是我们一直在进行的对话,比如说你好。说再见。看看会发生什么。实际上我现在要移除这些冗长的语句。你可以选择保留这些或添加它们。如果你想的话可以任选其一运行。但为了减少输出内容。我们先不带调试语句运行这段代码。这里真正重要的是我们看到初始状态为空。并且在这些调用完成后。初始状态应变为最终状态。我们再次获取它。最终状态应包含由调用定义的用户姓名。说你好。太棒了。我们的工具函数在这里打印了用户名更新。当我们获取会话时。从会话中获取状态,最终状态包含用户名abk。一切按预期运行。如果你想的话。你可以在交互环境中运行这段代码。甚至在这个笔记本中。可以设置一个小的辅助函数。用于循环获取用户输入的消息。调用我们的caller函数传入该消息。只要用户不输入退出消息就会持续运行。当你设置好并运行它时。会弹出一个小窗口。当你运行交互会话时。可以输入消息并观察结果。我先不透露我的名字。看看会发生什么。这有点有趣。语言模型推断出我的名字在这里。基于这条消息。这并不理想。纠正它。说。只需传入我的名字是abb。K 工具上下文已更新为abk。有一个名为say hello的工具。针对abk。因此语言模型正确识别。我的名字是abk。
将此保存到内存中。这太棒了。如果我说再见。我们应该通过abk收到一条好消息。和之前一样。试试这个。与它互动并看看你能想到什么。而且。当然。如果你想修改代码结尾并观察其影响。你已经完成了第三课的所有内容。你创建了一个基本的单体代理,它会说你好。你创建了一个多代理系统。包含两个子代理,分别擅长说你好或再见。根代理负责协调与用户的交互。有了这些。你已准备好继续进行遗传知识图谱构建。
P37 4-了解用户意图
你现在可以开始定义系统中的第一个代理。用户意图代理。其主要目标是帮助你构思可以构建的知识图谱类型。以及你希望从图中回答的问题。开始编码。回想一下我们在第二课中看到的示意图。该图展示了整体知识图谱代理架构。我们将逐步讲解结构化数据代理。这是负责从CSV文件提取信息的子代理。将数据转换为图谱。我们将逐步完成这一过程。我们将以这种方式逐步推进。第一步是理解用户意图,这一阶段会发生什么。当我们建立。用户的目标是什么。用户描述的意图将影响所有后续代理的操作。这将为我们的目标设定总体方向。所有代理都会据此做出响应。这个代理只有一个主要任务。其输出是保存到记忆中。已批准的用户目标是什么。为此它有两个工具可用。它有一个工具用于初步感知。用户的意图是什么。基于与用户的对话互动。根据其理解。用户希望。它只能回应。这就是我感知到的需求。因此它会调用工具来捕捉这一信息。告知用户。这就是我理解的需求。用户可以选择确认。正确或不正确。不太准确。再试一次。如果你想重新尝试。代理需要继续使用感知到的用户目标。直到用户认为。这就是正确答案。我批准了。只有当用户批准时。代理应调用已批准的感知用户目标。我们将看到这些工具如何协作。更新记忆并捕获已批准的用户目标。注意我通过批判性思考设定感知用户目标。无法直接设定已批准用户目标。只能通过调用此工具。这个机制最终起到守门员作用。确保我们有一个与用户确认的检查点。用户是否明确亲自表示同意。这很好。我们就这样做吧。考虑到代理的详细信息。我们将继续进行常规设置并导入所需库。并设置ln和快速验证检查。看看。这次它的回应如何。相当一致。我准备好了。今天我能为您做些什么。因此我们可以定义用户意图代理本身。我们将从逐步描述开始。我们实际想要的提示是什么。这个代理的指令是什么。需要定义的第一个提示部分。
这个代理的角色是什么。还有它的目标是什么。在这里我们将说明。这个代理是知识图谱用例专家。主要目标是帮助用户构思知识图谱用例。这基本上说明你的职责。代理的任务是帮助用户进行创意构思。它试图实现什么。用户试图实现什么。代理的目标是帮助用户明确自身目标。要添加的提示部分。我称之为。对话提示。这有助于代理理解。在其角色和目标的背景下。应该如何开展工作。在此情境下我们正在确定用户意图。致力于与用户进行创意协作。我们有一些基本想法。如果用户不确定该怎么做。可以提供建议。特别是关于知识图谱的经典用例。因为。当然这个代理现在是知识图谱用例专家。也许LMS已经了解很多知识图谱用例。但如果你在构建内部生产系统。某些企业L1可能不了解你的业务。这是一个绝佳机会。向代理解释你们业务的运作方式。以及什么重要什么不重要。在这里我列举了几种知识图谱的用例。你可以将它们用于社交网络。物流。推荐系统。欺诈检测。或者。当然像流行文化这类事物。如果你想追踪电影。书籍或音乐。因为这对确定多亚洲系统的整体方向至关重要。我进一步强化了。比如。用户目标实际上由什么构成。在这里我通过提示描述用户目标包含两个组成部分。一个是图的类型。你是在创建社交图谱吗。还是在创建物流图谱。这可能是什么。因此图的类型需用最多三个词描述。我们正在创建的图是什么。除了你创建的图的类型外。还有描述该图的组件。请提供几句话说明该图的意图。例如。如果我们说美国货运物流。描述可能是动态路由和货物配送系统。这是通过少量示例学习实现的。明确向代理及语言模型强调。你试图实现的目标是什么。因为这非常重要。值得重复强调。既在提示中也将在后续工具描述中。这些工具将实际使用用户目标。在定义其内容时。同时确认理解是否正确。我们将整合提示的最后部分。是思维链的指导方向。
思维链可以很简单,比如。仔细思考,分步分析。但这里需要更具体。我们希望语言模型执行某些步骤。因此我们将明确说明。我需要你一步步执行以下操作。代理可能会有不同变体。但通过具体说明。当我们明确。希望代理执行的内容。有助于集中注意力并确定处理方式。根据用户的初始互动。最重要的是需再次理解用户目标。我们将再次强调。这就是那种图表。连同描述一起。如果不能确定代理是否需要询问澄清问题。只有当代理认为自己理解了用户目标时才调用集合。感知用户目标工具。这就是实际要记录到内存中的内容。用户目标的理解包含两种组件的图表。连同描述一起。最后呈现这个感知用户目标。通过让用户确认。这就是我刚才听到的内容。我说对了吗。如果用户同意。代理可以调用批准的流程目标工具吗。我们提供了大量关于调用此工具的额外说明。以便代理真正理解这个工具的作用。调用此工具时当前感知目标将保存到状态。在批准用户目标键下。所有这些部分将组成提示。我们将提供给代理以整合这些内容。我们将使用Python字符串模板。直接插入之前定义的变量。代理角色和目标。对话提示。输出定义。还有思维链指导。我们将其打印到屏幕。你可以看到整体结构。可以定义这些工具。第一个工具是设置感知用户目标。在这里的注释中可以看到。这是通过工具设置来促进与用户的协作。仅通过该工具将感知值保存到内存。我们真正帮助代理聚焦。比如如何理解用户目标。因为它必须调用此工具。它知道需要这两个组件。我们在提示中已说明。在工具定义中。可以看到这两个参数。必须传入图表类型。以及图表描述。同时注意到工具上下文作为最后一个参数。如果你记得之前的课程。当最后一个参数是工具上下文时。ADK会自动注入。当此工具在工具描述中被调用时。我们再次说明这是在保存感知用户目标。包括这种类型的图表。以及对其的描述。
我们还会描述这些参数。这些必须与我们告诉代理的内容完全一致。在之前的指令中。这将成为提示的一部分。工具定义本身会再次说明。重复的次数越多。语言模型越不可能出错。在调用工具和工具内部。其实很简单。它只需组装一个小字典。这是由这两个组件组成的用户目标数据。这种类型的图表。以及传入工具的图表描述。这实际上只是简单封装如何访问记忆的方法。同时聚焦记忆访问。上下文状态会更新该字典。因为这是更新操作。ADK会检测到状态变化。会将该差异传递给需要感知的其他方。在运行时环境中。定义下一个工具。用于批准感知到的用户目标。这应在设置感知用户目标后触发。用户也明确同意。如果这两项都成立。应调用此工具。在可以时。在可行且合理时。在工具内部。值得信任。但需验证语言模型在此工具中的正确性。这仅在用户批准后调用。我们将再次迭代。与语言模型。嘿。仅在用户批准后调用。如果用户通过调用此工具批准。工具将记录感知目标为已批准目标。再次告知代理。仅调用此工具。若用户已在工具内明确批准感知目标。因为我们已设置流程。可在执行其他操作前先检查是否已设置。如何处理此设置至关重要。因为工具调用可能成功或出错。这里我们可能返回特定错误。如果感知到的用户目标不在当前上下文中。如果它不在工具上下文状态中。因此,代理的记忆。如果感知到的用户目标不存在。我们将继续从该工具返回错误。我们将提供的错误信息旨在帮助语言模型理解。这就是哪里出错了。这就是你应该如何解决问题。因此我们告知LLM过程用户目标未被设置。并应先设置感知用户目标或询问澄清问题。如果不确定用户的意图。因此在所有这些地方反复强调给代理。从提示到工具的定义。再到工具返回的错误信息。鼓励LLM根据实际情况采取正确行动。如果成功的话。我们只需将感知用户目标的状态复制到批准用户目标。
请注意只有在以下情况下才会发生。由于我们没有向批准感知用户目标传递参数。批准用户目标仅会被设置。如果存在感知用户目标。则会被复制。此时感知和批准用户目标都应在状态中可用。我们将这两个都添加到列表中。因为我们知道在创建实际代理时需要传递列表。我们有两个工具:设置感知用户目标和批准感知用户目标。因此你可以定义用户意图代理。你需要为其命名。使用唯一的版本名称。我们将使用之前定义的LLM。这将是所有笔记本中相同的LLM。未来可以直接跳过这一步。描述非常重要。该用户意图代理的目的是帮助用户构思知识图谱用例。这有助于整个多代理系统。判断何时使用该代理。你之前从图表中回忆。通过描述匹配该代理在工作流中的角色。这将帮助协调者管理整个工作流。我们使用之前组装的完整代理指令。我们将传入这些指令。当然我们还会传入。可用的工具。你已准备好完整的用户代理。与之交互。你可以导入你的朋友。创建代理调用器。为用户意图代理创建一个调用器。我们将调用用户意图调用器。你可以注意这里的这个便签。当然。如果你要多次运行这个流程。值得回来重新初始化状态。如果事情有点失控的话。我们来设置一个与用户意图代理的对话。在实际交互前先获取会话。这样可以看到当前会话状态。这应该为空。最初就像往常一样。我们将创建一个脚本化对话。这里只有两个调用步骤。第一个调用。这将是用户。声明用户想要物料清单图或BM图。并包含物料清单的所有层级。从供应商到成品。用户还指定需要这个物料清单图。能够支持根本原因分析。我现在去掉详细输出。但你可以保留。如果你想的话。这是对话的重要部分。有时当代理收到用户的初始消息时。它可能会决定。我需要进一步澄清。如果发生这种情况。则用户目标未被设置。代理可能回应说嘿。告诉我更多关于你的需求。我们在此做假设。如果会话状态中用户目标未设置。
假设LLM被要求提出澄清问题。我们以用户身份提供澄清回答。我担心可能的制造或供应商问题。希望这些细节足够让代理满意。并促使它调用用户目标工具。乐观地。如果我们走到这一步。则流程目标已设置。我们将说。听起来不错。我批准这个目标。你可能需要多次运行以防代理未设置用户目标。它可能在某天决定先与用户多交流。确定真正需要什么。用户目标没问题。我在最终调用批准目标时启用了调试。但你可以看到我们在此会话中的过程。会话开始时会话为空。内存状态为空。用户发送了初始消息并收到代理回应。实际上在询问澄清问题。它说嘿。你是在尝试从供应商追溯产品的组件。通过制造过程的各个阶段。这是代理的相当长的回答。这没问题。由于我们设置了检查机制。我们继续决定。我们意识到用户的感知目标未设置。我们发送了额外消息给。我担心可能出现制造或供应问题。看来代理随后回应并决定。这已足够继续。理解了我们的目标。并告诉我们。这就是你想要的图表类型。我想你在尝试构建。这就是我的理解。你希望该图表描述的内容。最后它说道。正确。嘿。这是否符合你的意图。正是我们想要做的。我们想说。这就是我认为你在询问的内容。这正确吗。作为用户我们将批准该目标。这是我们之前决定的对话记录。可以看到在优化目标时。用户意图代理设置了感知用户目标。实际上尚未设置流程目标。或再次调用它。看起来实际上。在设定感知用户目标后。因为用户已批准。调用已批准的感知用户目标。你可以看到底部的最终回复。用户目标已成功批准。一切正常。工作流程现在明确了用户的目标方向。在多代理系统中构建知识图谱。
P38 5-文件建议
你现在将设置系统中的第二个代理。文件建议代理。该代理将帮助你从结构化数据中选择相关文件以构建领域图。进入你正在处理的工作流程。你正在第四课中构建结构化数据代理工作流程。你在此第五课中创建了用户意图代理。你将创建文件建议代理。你将采用与第四课用户意图代理类似的模式。该代理本身有一个主要目标。创建此批准文件列表。这将是代理自身需要查看的文件列表。并决定这些文件对用户要完成的任务是否相关。询问用户。你批准这些吗。如果同意,输出将是执行该操作的批准文件。文件建议代理包含许多工具。用于查看可用的文件。这是所有文件的列表。它可以对文件进行采样,进行少量读取。它只能读取约一百行。基于此使用该工具进行推荐。称为设置建议文件工具。如果用户批准。将调用批准建议文件工具。这将更新记忆。以便在上下文中包含批准文件。而不仅仅是建议文件。所有这些。当然受前一代理工作的指导。所有操作均基于用户要完成的整体目标。该代理从记忆中获取这些信息而非对话历史。因此不依赖于该工具被调用前的对话记录。或该代理被调用前的对话。此代理将使用获取批准用户目标工具。确定用户要完成的任务是什么。查看文件。确定哪些相关。并向用户提出建议。看看代码。你将从常规设置开始。导入所需库和之前定义的辅助函数。已有这些库。我们将连接OpenAI并确保其正常运行。哦。今天非常稳定。我准备好了。如何帮助您。你将开始构建代理自身的指令。我们将逐步进行。你想要定义代理的角色。同时也要设定其目标。对于负责建议相关文件的代理。我们将称其为建设性批评者。正在审查文件列表。其目标是建议可用于构建知识图谱的相关文件。你可以提供一些执行任务的提示。特定的任务。当然就是审查文件列表并查看其中。哪些文件对基于已批准用户目标的描述中的图谱相关。对于每个文件。有一个名为样本文件的工具可用。
可以让代理实际查看该文件内容。以确认文件是否包含对实现目标有用的信息。我们正在提供。同时提示它只需查看结构化数据文件。如csv或json。可以用思维链方向收尾。此处的思维链包含两个部分。是准备阶段。先调用获取已批准用户目标工具。从会话记忆中获取用户目标。我们将调用该工具。而非直接将信息传递到提示中。这鼓励代理使用工具。在获取这些信息后。我们将提供思维链指令。仔细重复这些步骤直到完成。以下是代理需要遵循的步骤。获取所有可用文件的列表。针对该文件列表。评估每个文件的相关性。使用建议文件工具将建议文件记录到记忆中。此步骤。第三步。鼓励八和二。使用获取建议文件工具获取建议文件列表非常重要。代理可能在自身推理和对话历史中意识到。文件列表可能是什么以及它认为的建议文件。但与其依赖这一点。我们希望代理仅使用已保存到建议文件的记忆。此处的记忆。获取建议文件工具会访问该记忆。完成此循环实际上促使模型专注于记忆内容。而非对话历史中的记忆。从工具调用返回的结果是。将呈现给用户供其审批。如果用户批准。则继续说这很棒。通常建议的文件。但如果用户有反馈。返回步骤一并根据反馈重复流程。可以定义代理使用的工具。第一个工具是获取已批准用户目标。此功能在提供的工具模块中定义。它仅返回存储在状态中的已批准用户目标。我们还将导入一个小助手函数。这些即将定义的工具。将使用这些工具与文件系统交互。但并非整个文件系统。它们仅限于查看可导入的文件。新Neo4j本身可以访问导入目录。这个助手将告知导入目录的位置。所有工具均可使用该导入目录确定可用文件。并在这些文件中选择需要使用的。定义列出导入文件的工具。并将结果保存到此键。所有可用文件。工具调用需要工具上下文。因为我们将使用一些辅助工具。实际获取磁盘上的目录。这些文件存储的位置。
因此列出的文件仅为相对路径而非绝对路径。在实现部分可以看到。我们将获取此辅助函数。获取Neo4j导入器。这是Neo4j可访问的数据导入目录。数据无法访问整个磁盘空间。因此不能使用绝对路径。必须基于此导入目录。在此处获取该目录。列出所有文件。这只是一个使用导入目录的字符串。我们继续对目录进行全局列表。从该目录递归向下。并通过列表推导生成相对文件列表。将结果保存到当前状态的可用文件。将此作为工具调用结果返回。定义样本文件工具调用。样本文件工具同样使用工具上下文。并使用文件路径。这是目标文件的相对路径。语言模型决定要查看的文件。可能调用操作系统执行类似cat的操作。我们将全部用Python实现。此工具调用结果仅为文本前100行。假设为文本文件。获取100行文本。返回该结果。这个工具调用的值。这里我们设置了几个防护措施。因为语言模型可能生成路径。它可以生成各种不同的内容。当它调用这个功能时。我们将对传入的文件路径进行合理性检查。确保它不是绝对路径。如果它是绝对路径。我们将返回一个错误。因为它必须是相对文件。并且预期这些文件相对于导入目录。最后这部分。我们也鼓励代理记住传入的文件路径。应出现在可用文件列表中。它应该实际检查这一点。基于导入目录。我们获取该文件的完整路径。再次确认文件存在。返回有用的错误信息。如果文件不存在。以便各方采取纠正措施。如果文件存在。我们将读取前100行并保存到内容中。作为成功的工具调用返回。如果发生任何错误。我们将传递该错误作为对黄色语言模型的响应。代理可以决定是否能处理。或只需向用户报错。你已赋予代理列出所有文件的能力。查看这些文件。它能基于这些文件和内容提出建议。但代理认为用户需要的相关文件。我们有一组工具实现此功能。第一个是设置建议文件列表。接受应为文件路径的字符串列表。
你可以在此添加额外检查。确保传入的列表都是实际存在的文件。我们在此稍作信任处理。这个工具存在一定的冒险性。当然可以改进。你可以添加此检查。另一方面。我们将有一个获取建议文件的工具。查看已建议的文件列表。当代理成功确定相关文件后。并向用户提出建议。如果用户已批准。当然。将调用批准建议文件工具进行状态转移。将建议文件状态转为已批准。正如上一课中。在调用此功能前我们将再次确认。确保建议的文件确实存在于状态中。若未建议则需让代理先查明情况再调用此工具。如果已设置。我将复制建议文件到批准文件并返回结果。作为此工具调用的成功响应。你可以将所有工具定义。整理成列表。并保存为文件建议代理工具。我们将用于代理定义。稍后即会看到。你可以定义你的代理。代理定义非常直接。我们已完成了工具设置和提示定义。只需将这些内容传入并创建代理。拥有代理后。可以与代理交互。导入。我们之前定义的make agent color助手。使用该助手创建调用者。这里只有一个细微不同之处。当我们使用make agent color时。只需直接调用代理。我们想要执行。注意这里我们用批准的用户目标初始化状态。正如之前所说。在工作流程开始时。批准的用户目标。是所有代理的总体方向。以及它们要完成的任务。因此在最终生产系统和多代理系统中必须设置此内容。到此工作流程阶段时。状态中已包含用户目标。因为我们已完成了前期工作流程。而此处尚未经历该阶段。通过设置初始状态模拟此过程。如同已批准一个需要进行供应链分析的用户目标。描述涉及制造产品的多层次物料清单。可以运行简短对话。用户询问可用文件用于导入。文件建议代理将执行所有处理。确定可用文件及相关文件。最终可用文件列表应包含目录中所有文件。建议文件是其中子集。希望仅为CSV文件。这可能需要几秒钟处理。因为语言模型。
当然。正在分析所有找到的文件以判断相关性。我们可以看到这个响应做得相当不错。它已经识别出这些装配件的csv文件。一些组件。从零件到供应商的映射。一些产品本身。供应商本身。还有一些完美的零件。如果查看可用文件。有很多额外文件。特别是所有这些markdown文件。它已经忽略了这些。并正确建议了这些装配文件。组件文件。所有的csv文件。太棒了。由于代理提出了这些优秀建议。你可以继续向代理发送新消息。只需说同意。我们来做吧。可以重新表述这句话。或许根据代理的回应。这可能不是批准的好方法。试试这个。代理对此非常满意。应该调用工具以批准这些文件。从会话状态可见,已批准文件与之前一致。建议文件成功通过。你现在已构建了两个代理。构建结构化数据知识图谱的流程。第一个确定用户意图。下一个基于用户意图。寻找可用的数据文件。支持用户意图的文件。在下一课中。你将进行下一步操作。在给定用户意图的情况下。文件已可用。知识图谱可能是什么样子。
P39 6-结构化数据的架构建议
你已经定义了目标并指定了文件。下一步是确定结构化数据的图模型。即确定构成领域图的节点和边的类型。你将设置一个子代理循环来优化模型。深入探讨。你正在使用结构化数据代理。通过从用户意图开始的工作流程。是文件建议。我们准备好提出图模式的可能方案。这就是这个代理的任务。这个代理在代理组合方式上引入了一些新思路。这个代理实际上包含多个内部代理。其中有一个代理负责提出方案。这里显示我建议构建的图模型。另一个代理会检查并批评该方案。这是一种在多代理系统中常见的批评模式。在顶层协调器中。这里只使用了少数几个工具。有一个我们称为细化循环的工具。还有两个常规工具:获取建议构建计划。以及批准建议构建计划。这些与之前看到的文件建议和批准工具类似。但这个细化循环非常有趣。实际上是一个包含多个协作组件的代理。看看内部结构。细化循环是一个协调子代理的代理。该循环代理包含三个子代理。模式提案代理。模式批评代理。以及状态检查模块。升级代理。这些代理会持续循环运行。直到得到最终结果。模式提案代理生成提案。模式批评代理进行批评。状态检查和升级代理负责分析批评结果。判断批评是否满意。或是否需要重新尝试。如果批评满意。正是这个代理触发最终确认。从而终止循环代理。这个过程可能无限循环。当你调用循环代理时。我们可以设置循环迭代次数限制。若无法达成共识。将返回用户请求。说。我们对此不确定。顶层协调器将负责获取更多用户输入。你将从常规导入开始。当这些准备就绪。你可以定义我们将要使用的llm并查看它。所有准备就绪,太好了。我们现在可以开始工具定义。可以开始编写代理的指令。我们将重点研究的代理。或者模式提案代理。是批评者。看看我们将提供给它们的指令。对于提案代理在其角色和目标。我们将告诉它擅长图数据建模。使用属性图建模。你可以在这里查看详细描述。
但这里的新颖部分。在这段提示中真正关键的是我们将注入。反馈初始为空。因此我们告诉代理仅在反馈可用时考虑。但由于可能为空。我们不希望混淆其余提示成为反馈部分。因此我们在此处用xml包裹。使用伪xml表示此处的反馈。是反馈结束标记。因为大多数llm能很好地理解这种分隔符。我们在此处使用分隔符。这些花括号反馈成为模板变量。由Google ADK Google ADK注入。在组装时。提示内容。会查找这些文本部分并替换为上下文。一个上下文变量。如果在工具上下文状态。如果状态中定义了反馈变量。该变量的值将被注入此处。如果上下文中有反馈。将传递到此提示部分。你已为目标代理设定了目标和角色。我们将提供执行任务的提示。这里的提示比之前更长。原因在于大多数llm包括GPT。在图数据建模方面表现良好。但并非特别擅长。我们将提供额外的思考指导。如何处理可用的数据文件。以及这些数据文件可能呈现的图结构。你可以查看所有指导内容。并注意到我们包含了知识图谱构建的最佳实践。这些最佳实践已编码在提示中。因此所有批准文件列表中的文件都应成为图的一部分。在这些文件中这些是csv文件。通常你会看到唯一的标识符。我们让它去查找这些唯一标识符。尝试识别这些标识符是什么。并利用它们来理解该文件在构建图中的作用。我们提供一些指导。基本是一些设计规则,用于思考某个文件是否可能代表节点。或可能代表关系。你可以查看具体细节。但文件本身的命名通常包含语义提示。出现的标识符数量。这些标识符是否真正唯一属于该文件。或是否唯一属于其他文件。所有这些都需要我们或我来做。当我们作为数据工程师工作时。当我们收到一堆数据文件时。我们基本上用grep和cat处理。也许我们会将其导入编辑器查看文件。这就是我们现在要做的。这些内容在提示中明确表述。
帮助代理理解如何进行相同的数据建模。这是我们已知的,将其分解。是节点还是关系特定。你知道的。节点的设计规则。节点通常有单个标识符。而非多个标识符。但如果文件包含多个标识符。X光标识符可能是引用关系。这在关系数据库中会发生。图中可能会有外键关系。这些将转化为关系。如果关系本身。它们有两种表现方式。这里我们称之为。完整关系和引用关系。进一步分解。我们向LLM描述。什么是完整关系。什么是引用关系。这里有两个组成部分。我们解释如何识别它们。但在识别后。如何将它们转化为图。最后在提供所有设计指导后。建议生成的模式应为完整连接的图。这很重要,因为显然可能导入大量数据。却无法连接。就不是真正的图。此时几乎无用。因此必须完全连接。如果存在任何孤立组件。这很可能是一个问题,需要考虑。可以给代理一些思维链指导方向。这也是比之前更复杂的步骤。可以逐步查看这个过程。让代理为即将进行的任务做准备。我们知道该任务基于已建立的用户目标和批准文件列表。同时还要检查是否有批准的施工计划或现行施工计划。即使提出这个建议。这可能不是该代理首次提出施工计划。如果已有现有计划。可以获取当前施工计划。并决定是否需要修改。思维链过程与常规相同。鼓励其仔细思考,分步使用可用工具。对于任何操作需逐个检查批准文件。判断是否为节点或关系。这呼应了我们之前的架构指导。每次发现标识符时。或认为发现了标识符时。应使用工具验证是否找到唯一标识符。使用名为搜索文件工具。这相当于基于Python的grep工具。对于刚发现的标识符。可尝试验证其是否唯一。通过检查同一文件中的重复出现。我们鼓励其考虑我们之前提供的指导。以判断是否为节点或关系。对于节点文件。有专门工具用于提出如何处理该节点文件。我们称之为施工操作。有特殊工具可记录特定文件的处理方式。
如何将该文件转化为图中的节点。同样如果认为发现关系。可调用名为提议关系构建工具。用于提议关系构建。使用这两个工具。将遍历所有文件。无论是节点还是关系。调用相应工具生成构建规则。将文件转化为图的一部分。如有必要还可移除构建规则。完成后。使用获取提议施工计划工具向用户展示最终方案。获取提议施工计划工具将包含所有构建规则的完整列表。可将所有内容整合为最终指令。可以开始定义工具。我们已在之前的笔记本中定义了许多常用工具。因此直接导入这些工具,如获取批准用户目标、批准文件等。以及示例文件工具。代理的指令还提到了一个搜索文件工具。这个搜索文件工具本质上是一个类似grep的功能,可以读取文件。浏览文件的几行内容并查找特定模式。这不是一个非常复杂的查询。就像grep的工作方式。但足以让LLM实际查找可能出现的内容。例如。用于唯一标识符。可以将这个常量传入此处。在文件中查找该常量是否存在。该工具的结果将包含行数以及包含该内容的行。要定义的工具是提议的节点构建。这描述了如何从源数据文件。我们传入一个改进后的文件。文件路径。基于该文件路径。我们需要在图中创建一个节点。我们描述节点应具备的特征。通过几个不同方面来描述节点。是应应用的标签是什么。节点标签通常用于描述节点类型,如是否为人物。地点。或事物,描述节点代表的类型。此外还需确定唯一列名称。因此在导入的CSV文件中。某一列应为唯一列。如果我们识别出该列并传入此处。最后可能不会接受所有列作为有效构建节点的属性。提议的属性实际描述了CSV文件。哪些列需要导入并作为节点属性创建。查看该函数的实际实现非常直接。会进行常规的合理性检查。如果我们通过了合理性检查。将描述或构建构造规则。这实际上是一个描述数据对象的工厂函数。此处的数据对象是一个构造规则,类型为节点。
基于已传入的源文件生成。赋予一个标签。具有唯一列名称。并创建一组属性。将其添加到现有构造规则列表中。为明确说明。我们之前已从内存中获取当前构造计划。如果不存在。这将是一个空字典。但若存在时添加。我们将使用标签进行添加。因为所有标签应唯一。使用标签作为键。我们将添加该构造规则。因此,整体构建计划将是一组唯一键。其中每个键都是一条规则,要么是节点构建,要么是关系构建。包含所需信息。你可以定义一个用于创建关系构建规则的类似工具。如果你查看传入的参数。这些参数与节点类似,是关系特有的。它以文件名开头,表示关系将从中提取的位置。而不是使用标签。它们使用类型。将传入建议的关系类型。由于关系连接其他节点。你需要知道该关系可能来自的节点标签是什么。以及它连接到什么。因此你会得到来源节点和目标节点的标签。对于来源节点和目标节点。你也需要知道其唯一标识。在用于创建关系构建的CSV文件中。应有一个列标识来源节点。该节点的唯一标识是什么。来源节点列。还有一个目标节点列。应包含节点的唯一标识。关系连接的目标节点及其相关信息。你可以像节点实现一样构建关系。如果来源和目标节点都存在。我们可以继续创建构建规则本身。该构建将再次是一个字典。字典类型表明它是关系。因此这是一个关系构建规则。它包含源文件、关系类型、来源节点、目标节点。以及可能应用于关系本身的属性集合。所有内容也添加到关系构建计划中。根据关系类型。如同节点标签。在数据导入过程中,我们期望关系类型唯一。因为该代理将在精炼循环中运行。可能需要移除之前创建的构建规则。因此我们将提供移除工具。适用于节点构建和关系构建。这是节点版本。你也可以定义移除关系构建的类似工具。基于关系类型。而非节点标签。代理与这些工具交互以提议构建规则的结果。移除这些构建规则。
形成完整的构建计划,将CSV数据文件转换为知识图谱。因此,通过让LLM了解其构建的整体计划。我们将创建知识图谱。我们也为此提供工具。获取提议的构建计划工具。我们将从这里获取当前的施工计划。它将继续使用之前使用的同一密钥。用于之前施工计划的构建。如果没有进行任何操作,默认值为空。但当前的施工计划可能已经。没有计划。就像你之前做的那样。结合用户意图和文件建议生成架构提案。你还有一个专门处理基于施工计划提出的或建议的架构方案的工具。批准该方案。将所有这些工具添加到列表中。这就是你要使用的列表。在定义实际提供所有工具的代理时使用。你可以看到工具集合随着时间推移在这里逐渐增加。因为它结合了我们之前达成的共识。在工作流程的前期阶段。与当前代理在当前工作阶段的任务相结合。其意图。当然。是创建图结构模式。你现在可以定义代理本身。负责执行架构提案。你将在此处添加一个新的实用函数。在创建代理时使用。该实用函数仅记录代理被调用的情况。并打印代理名称到屏幕。这里处理当前对话的内容。稍后创建代理时你会看到添加位置。可以定义架构提案代理。如果你直接说。代理在这里。这是一个语言模型代理。即推理代理。能够基于现有工具做出决策。和之前一样,我们需要为其命名。为其添加描述。我们将传入指令。但这次调用的独特之处在于代理实际被调用前。有一个回调函数。在调用前。并希望回调指向我们刚刚定义的日志代理函数。这将让我们看到。当代理被调用时的下一步操作。你需要继续使用我们的老朋友。创建代理调用器。如同工作流程的前期部分。需要设置代理的初始状态。如同前期工作流程已完成。因此需要获取已批准的用户目标。还需要获取已批准的文件。因为这个代理将在反馈循环中运行。我们将初始化反馈机制。同时保持为空白。这能让代理顺利运行而无任何问题。可以调用这个代理。
通过用户消息提示如何将这些文件导入构建知识图谱。我们将查看会话内容。完成后打印会话状态。预期看到提出的构建计划。这里已经给出。最终结果再次呈现。我们获得了最终状态为真的事件。看看。它决定创建组装相关的节点。基于组装数据。Csv文件。为零件创建节点。为产品创建节点。为供应商创建节点。非常直接。它在这方面做得很好。它开始建立关系。看看它的决策。它认为从组装。Csv文件中存在从组装到产品的关联。可以说明组装包含在某个产品中。将创建从组装到产品的关联。两个产品。并称这些关系为’包含’。属性将包括组装名称。以及数量。当前处理的产品是家具。例如桌腿。这可能是一个组装组件。可能存在四个这样的组件。这样数量看起来合理。它对零件也做了类似决策。零件Csv似乎指向组装。因此零件属于某个组装。包含零件名称和合理数量。还完成了供应商映射。注意这些关系。这里有两种不同类型的关系。前两个是定义节点的源文件。但由于节点存在外键关联。得益于我们的精准提示。它决定一切顺利。我将定义创建关系的规则。其中’supplied by’稍有不同。因为零件供应商映射Csv只是简单映射。从零件到供应商。这就像关系型数据库中的联合表。零件表和供应商表。而这里的零件供应商是连接这两张表的关联表,形成关系。而不是关联表。这非常完美。它还解释了所有这些内容。并且显得非常满意。这很好。会话状态相当复杂。你可以查看其中内容。如果你想查看所有细节。但代理生成的markdown输出已很好地表达了这些信息。一个提出模式的代理已完成。我们将转向批评者。这是优化循环的第二部分。模式批评者与提案代理类似。作为知识图谱建模专家。但它的任务不是创建模型。而是批评已创建的模型。因此批评者有特殊角色和目标。当然它就是个批评者。我们将定义其角色为。同样精通属性图知识图谱建模。
就像提案代理一样。但它的任务是批评已提出的方案。因此这是它的目标:批评提议的模式。确保其与用户目标及可用文件相关。还会为该代理提供执行任务的提示。在批评提议的模式时。需要检查哪些内容。这实际上是关于。如何进行良好的知识图谱建模。但现在从批评他人模型的角度。如果你要批评他人的模型。会提出哪些意见。需要关注哪些方面。唯一标识符是否真正唯一。可以使用搜索工具验证这一点。已定义的节点是否可能为关系。需再次确认这一点。如果这是一个连通图。应能手动从源数据追溯到构建的图。确保所有源CSV文件都映射到图中。并保证图本身完全连通。还有一些其他提示。当然还包括层级容器关系是否存在。是否存在冗余关系。方案提案可能过于激进,创建了不必要的关系。或者那些在实际实现结果时逻辑上必需的部分。这也需要检查一下。提示的下一部分是思维链方向。和之前一样,我们要向批评者解释如何准备任务。它拥有。它使用哪些工具来实际准备执行任务。应该如何执行任务。一如既往,它应该仔细思考。并使用工具执行操作。你应该检查每个构造规则。包括节点构造规则和关系构造规则。使用工具验证构造规则是否相关且正确。如果所有检查都通过且一切正常。只需回复单个词valid。如果架构存在任何问题。回复retry并提供反馈。这里的反馈要求简洁的项目符号列表。如果批评者对提案有任何疑虑。我们应该看到这个清晰的项目符号列表。说明需要做出哪些修改。这些反馈将最终进入循环。并返回给提案代理以调整其操作。并尝试考虑任何反馈意见。可以将所有提示部分合并为单一提示。这就是批评者代理。稍后我们将用此定义代理的指令。架构批评者也需要工具。但架构批评者没有新工具。它可以使用提案代理相同的工具。我们只需将其包含在此列表中。获取已批准的用户目标。已批准的文件。是采样文件或搜索文件等实用工具。
你已具备批评者代理所需的所有组件。可以创建该代理。它将是一个LLM代理。其名称为架构批评者代理。版本一。这个代理有一个之前未见过的新特性。与其他只需完成工作的代理不同。使用工具进行。你知道的。产生某些输出。这个代理只需返回文本。该文本将通过此输出键存入状态。因此此输出键我们称为反馈。当此代理完成时。当收到此代理的最终消息时。最终消息将使用反馈键存入状态。将包含由批评者生成的值。因为这会在之后出现。如果你回到提案者那里。提案将能够从状态中获取该信息。你需要定义两个关键组件。这是此细化循环中的两个关键子代理。我们必须定义细化循环本身。在我们这样做之前。还会有最后一个代理。这将是我们自定义的代理。如果我们回到架构图。我们有提案代理。批评代理。我们要添加这个检查状态和升级代理。这个代理只有一个任务。它的任务是决定循环是否完成。看看它是如何工作的。这是一个名为base agent的基础类,我们将继承它。我们将其命名为检查状态和升级类。这将是一个自定义代理,带有自定义运行函数。运行函数将被调用。它会获取被调用时的当前上下文。我们不必过多关注这一点。除了查看当前会话状态。因此从该上下文中查找当前会话。查看状态。并获取反馈。如果有任何反馈。如果没有则假设反馈有效。如果批评代理没有反馈。我们将假设其有效。或者代理已声明有效。结果将是反馈有效,因此应停止。标志将根据。反馈是否包含有效内容。这是一个非常简单的检查。我们可以对此更复杂。但这样已经可行。对于大多数代理来说已经足够。如果所有条件成立。我们将生成一个由。当然这是我们构建的特殊代理。它将执行一个非常具体的操作。我们将在事件中添加一个名为升级的动作。升级的值将基于。是否应停止。应停止为真。如果当前反馈有效或为空。如果非空。则升级为假。这意味着我们仍会发出此事件。
但升级不会发生,因为我们设置了升级为假。这足以跳出循环或继续循环。你现在可以创建循环代理了。循环代理是一个特殊的工作流代理,这里接收子代理列表。提案代理。评审代理。以及自定义检查状态和升级代理。并将它们放入循环中。这个过程完全不需要推理。它只是协调这些其他代理的执行。你可以看到这里有一个有趣的地方。它有一个新参数叫最大迭代次数。我们将其设为两。这意味着循环最多执行两次。因此要么我们已达成共识。评审代理同意提案有效。或若未达成则退出循环。我们不会无限循环。当执行完成后。结果将是确认的架构方案。或若未确认可能需要用户提供更多关于如何处理架构的输入。你可以创建这个代理二。可以为该代理创建执行环境。调用它并传入用户消息。这些文件现在如何导入与之前相同。当我们创建执行环境时。将初始化状态包含一些反馈。即为空。用户目标和已批准的文件。这里要运行的代理。不过。是将细化方案纳入细化循环。调用者。我们将传入用户消息。等待其执行完成。获取会话状态并查看。你可以看到这需要一些时间。因为我们实际会在最多两次迭代中循环。同时为了进行评估。有两个代理会检查这些文件。是。当然。提案代理会分析每个文件。并决定如何构建知识图谱。评审代理会查看相同文件集。判断提案是否有效。你可以看到我们从细化循环开始。进入提案代理v一。评审代理最终回到提案代理。再次回到评审代理。这位评论家在这里仍不满意。最终回复是评论家表示反对。你必须重试。它对提案内容的某些方面感到不满。它认为存在关系重叠问题。数据可能不完整。我不打算全部阅读这些反馈。但这些反馈正是应回传给提案代理的。以真正提升结果。在此次调用中。尽管我们进行了两次迭代。通过优化循环。评论家仍未满意。这在整体架构中意味着循环终止。整体控制流程将返回给模式提案协调者。这是需要人类参与的代理。
因此协调者可以对人类说。不确定该生成什么模式。这是我目前的成果。你觉得我们下一步该怎么做。是否继续尝试。或者你有无需人类介入的建议吗。你可以再次运行此流程。你可以进入笔记本。重置这些单元格并重新运行。你可以尝试调整此处传递的信息。这些是你直接操作时会做的事。将有一个可选版本。你将直接进行。并整合这个顶层协调器供你交互。并实际看到通过单次优化或多轮优化。或你的建议。如何达成评论家和你都认可的模式提案。从而推进构建知识图谱。
P40 7-非结构化数据的模式建议
专注于非结构化数据。你将设计两个专家代理来决定图模型。可以从markdown文件中提取的模型。我们开始吧。你已经构建了一个完整的流程来定义施工计划。可以从csv文件构建知识图谱。你可以转向非结构化数据流程。这个流程以类似方式开始,包含用户意图和文件建议代理。但现在针对markdown文件。这些代理是完整解决方案所需。但在本课中将模拟它们的输出。你将专注于新概念。实体和事实类型提案代理。实体和事实提案代理本身由两个专用子代理组成。命名实体识别或nr架构代理和事实类型提取代理。请注意这些代理的输出是知识提取的执行计划。并非执行提取本身。架构代理将读取markdown文件。寻找命名实体。这些是人物。文本中突出的事物或地点。在我们的示例中。你应期待与家具和评论相关的内容。事实类型提取代理是文本的二次分析。寻找关于这些事物的陈述类型。例如。某些家具存在共同问题。这些代理将制定支持用户目标的初始信息提取计划。它将打开。AI设置并检查是否正常运行。看起来不错。我们也将检查Neo4j是否可用。也准备好了现在。你首先要定义的代理是命名实体识别代理。命名实体识别是常见的自然语言处理操作,存在于许多框架中。事实证明。当然。大型语言模型在语言处理方面非常出色。因此也非常擅长此任务。命名实体识别。正如所说。是指识别实体并为其命名。确实。这就是正在发生的事情。实体可以是任何人、地点或事物。一个地点或物品。在这里我们将要求llm寻找与。用户目标相关的文本中可发现的内容。你将从定义代理的指令开始。和之前一样。我们将将其拆分为几个不同部分,这些部分随后将组合在一起。定义亚洲的角色和目标。在这里你要描述代理是一个顶级算法。专为进行自然语言处理而设计。其目标是在文本中找到命名实体。但它实际上不会提取这些实体。
这里的目的是让其识别可用的实体类型。你可以给代理更多提示。让它明确我们在这里寻找的内容,再次。我们将描述什么是实体。将其分为两类实体。我们将描述这里所说的知名实体。这些是众所周知的。因为它们存在于我们之前课程中描述的结构化数据中。如果该结构化数据。如果其中定义的某些实体出现在文本中。我们希望文本中的这些部分也被提取。此外我们还有所谓的发现实体。这些实体可能不存在于我们描述的图数据中。但可能符合用户的使用目标。如果它们频繁出现。可能就有用处。我们提供更多细节关于。了解什么是知名实体的设计规则。以及什么是发现实体。和之前一样通常给出几个例子帮助代理理解目的。最终需要整合的指令部分是思维链方向。这里我们将描述如何准备执行当前任务。即识别这些实体。这里需要使用的工具来确定其职责。提供完整上下文。是建议的步骤序列。它知道可用的文件。有一个文件采样工具。先使用该工具查看部分文件。并发现已知实体。同时发现频繁提及的新实体。通过这些整理出所有合适的实体列表。使用建议实体工具获取该列表。和之前一样返回用户确认。这看起来正确吗。会调用单独的审批工具。这里称为审批建议实体工具。将所有内容组合成单个字符串。这将成为命名实体识别代理的指令。定义完指令后。再提供工具本身的定义。这些将非常直接。这里并没有太多巧妙的操作。我们将要定义的工具。遵循我们之前课程中的相同模式。我们将让代理首先提出一些内容。有其他工具将这些提案转化为批准版本。在这里。我们提出的事项是首先提案然后批准的实体列表。你也可以。当然。获取这些提案或批准结果。下一个需要的工具稍有不同。这将是另一个获取工具。它将从提议的方案中获取已知类型。在之前的课程中。从结构化数据中。因此已知类型最终将成为节点定义的标签。在之前的提议方案中。它们将作为批准标签使用。
我们将从建设计划中提取并返回为列表。你可以导入之前课程中定义的预设工具。并将此处的新增工具合并为单个列表。这就是我们在代理定义中使用的内容。为了了解代理的工作内容。可以使用样本文件函数。直接调用其中一个可用文件并查看内容。查看这个markdown文件。可以看到这是大量以markdown格式的评论。包含标题。还有一些嵌入在此处的值。比如评分。可以看到有用户名。地点。还有。当然还有评论本身的内容。这里只有少量评论。但足以演示整个流程。你已定义好指令。也定义好了工具。可以构建代理本身来运行此代理。因为它属于更长的工作流程。它对状态中已积累的内容有假设。因此需要创建初始状态来测试代理。初始状态需要包含批准后的用户目标。此处的批准文件。可以看到markdown文件。它将查看。还需要建设计划。建设计划用于已知实体类型。注意我们省略了关系建设部分。仅仅因为这一步不需要那个内容。这只是在模拟你现在需要的操作。你已经准备好运行这个代理了。我们将使用helper模块中的make_agent_caller。并发送一个简单请求。我们只需告诉它。你知道的。嘿,代理。你能完成你的工作吗。将产品评论添加到知识图谱中,将产品投诉反馈到制造流程。如果在这里遇到任何问题。当然你可以运行这个替代版本。这是一个非常简短的句子。但这里包含debug逗号true。这会显示所有输出。当代理完成时。大致展示它想要提出的方案。并生成提案。我们将检查会话状态以确认已生成提案。并且。希望它不会自动批准。它应该在等待我们确认。看起来不错。这个过程需要几分钟。因为代理会离开。查看这些不同文件。并尝试推断。认为最适合实体的标签集合。完成得相当不错。它识别出这里有产品。存在报告的问题。对常规体验的投诉。组装说明。以及可能的客户反馈。可能存在一点冗余。
但对我来说已经足够好了。这也是重要的。不仅响应良好。还正确更新了会话状态。记忆记录正确。我们有了提议的实体。但我们尚未获得批准。我得到了良好的结果。如果还没运行过请随时再次执行该单元。看看是否能得到更好的实体集合。所有设置均假设在交互式环境中。但如果有效。你可以继续向同一代理发送新消息。我批准这些提议的实体。完成这一步后。我们应该确认能够将提议的实体转换为已批准实体。并在会话状态中完美呈现这一点。已批准实体与之前提议的内容完全匹配。可以继续处理第二个代理。这将是我们的事实类型提取子代理。正如名称所示。当然。与前一个代理类似。我们将寻找可提取的事物类型。我们不会实际执行提取操作。可以先从指令开始。因为这是这两个代理最重要的部分。对于这个代理。角色和目标再次说明。我们将称这个代理为顶层算法。它将进行文本分析。但目标略有不同。它将寻找可提取的事实类型。不要实际提取这些事实。只需确定可能的事实类型。以帮助下级代理理解我们讨论的内容。这里。我们将提供一些提示。这里的关键部分是。与之前代理的指令类似。前一个代理不要提出具体事实。而是提出与用户目标相关的一般事实类型。在此处提供示例总是个好主意。我的示例是不要提出abk喜欢咖啡。而是提出一个人喜欢饮料的一般事实类型。这些形成非常简洁的句子。我们将这些句子称为三元组。它们的形式为主语。谓语-宾语。在这里我们将其放在括号中。这是常见做法。我们将观察代理是否采用此格式并返回结果。在响应中。我们提供额外的设计规则以指导思考和查找内容。同时说明如何使用工具与前一个代理不同。前一个代理在此处有一个完整的提议实体列表。针对每个独立事实。我们将逐一添加为独立事实。一次一个。而非提供一组提议的事实集合。关键在于代理的行为方式。以及token成本,更多往返次数。会增加一定费用。
但如果结果更好。那或许是个不错的权衡。最后你可以继续添加思维链方向。和之前一样,我们将遵循这些方向的固定模式。这是任务准备方法。这是我们建议的分步执行方案。以这种方式使用工具。抽样部分文件。寻找与文本相关的主体和客体。为这些主体和客体添加建议事实。最终你会得到几句话。三词短句。将所有内容整合成一个字符串。我们现在准备进入工具定义。我将花更多时间分析工具定义。针对事实类型提取代理。因为它在过程中会做一些合理性检查。这也是将它们分代理的意图之一。在之前的代理中。命名实体识别代理。我们给了它如何查找实体的指导。但并未严格限制其发现内容。我们将非常严格。所提议的事实必须与已有实体类型匹配。由前代理定义的类型。这种拆分方式。能提供更好的保障。确保事实与实体类型一致。正如我们所希望的。查看提议事实的定义时。我们得到的是。甚至通过参数名称。是已批准的主体标签。提议的谓词标签。是已批准的客体标签。这再次形成三元组结构。主体和客体应已由前代理生成。我们将在此设置一些限制。我们将进行检查。已批准的实体。从状态中获取。确保传入的主体和客体标签。在列表中存在。若不存在则触发工具调用错误。并提示标签不存在。让它重新尝试。我们分步处理的原因之一。以便逐步调整。逐步修正代理行为。如果这些内容看起来都没问题。我们将其重新整理成一个三元组。将其保存到当前谓词列表并生成事实列表。这里的另外两个函数只是遵循常规模式。获取提议的事实列表。将提议的事实添加到已批准的事实列表。你可以将这些工具列表整合起来。随时可供事实代理使用。我们可以开始构建了。构建代理。既然我们已经完成了所有繁重工作。真正定义事物其实非常直接。你可以运行它了。这个代理的初始状态与之前代理相同。我们将利用这一点。直接复制前代理的最终状态作为当前代理。
在完整的多代理系统中。这些操作会按顺序执行。它们会共享同一状态。但你也可以单独运行它们。我们将进行复制。创建代理的调用者。我们将使用的启动消息。是要求其生成提议。这里输出内容很多。我将改用这种方式。去掉末尾的逗号true。这样代理可以正常工作而不显示全部输出。如果遇到问题。使用带有逗号true的版本。当代理完成所有事实提议后。我们将检查会话状态。假设它已生成提议。若未生成则发出警告。同时假设未批准该提议。希望一切顺利。查看它生成的提议。提出的事实。例如产品存在问题及收到客户反馈。产品有组装时间。这很有趣。这里有很多不同内容。看起来是个不错的列表。检查会话状态啊。这里出现了问题。它确实返回了提议。但未将其保存到会话状态。为什么会这样。看看是否有投诉。这确实令人遗憾。因此决定正式提出这个提案并采用纯文本。但它并未真正实现我们预期的工具调用功能。我提议。你继续运行这个流程。当然在完整的智能体系统中。当它提出这种建议时。最终我们发现没有生成事实提案。我们将自动重新尝试。这次重运行应该能顺利执行。因为它会重新初始化状态。按相同步骤继续。我们看到效果类型与之前基本一致。符合用户目标。询问我们是否继续。看看是否真的。已正确提出这些事实。但仍在等待批准。智能体干得好。加一分。这次同样。如果这次不成功。只需再次运行。取决于OpenAI的状态。在任何一天。可能第一次或第二次成功。通常不需要三次。我将发送另一条消息。批准该提案。这将直接转为已批准事实。查看会话状态。最终看到已批准的事实类型,完美。这次运行效果很好。
P41 8-1 知识图谱构建 Part1
你拥有了构建知识图谱的完整规范。进入这最后一课。在这里你将定义执行构建计划的工具。按照代理工作流中已有的图谱构建计划和知识抽取计划。你现在已准备好构建图谱。在本课中。你将深入探讨知识图谱构建工具的细节。如果你慷慨大方。可以称其为神经符号代理。语言模型与基于规则系统的混合体。暂时后退一步看看这些计划将产生什么。图谱构建计划。将加载CSV文件生成领域图。几乎每个CSV文件都对应一个节点类型。通过额外映射创建关系。你可以让拥有大上下文窗口的LLM执行此任务。但这是一个非常直接的机械过程你已转化为代码。这项工作将由你定义的单一工具完成。称为构建领域图。该工具将包含大量辅助函数。用于图构建的不同部分。我们将逐一讲解这些工具。一如既往。我们导入一些库。检查OpenAI是否运行。同时确保Neo4j仍存在完美现在。开始构建领域图的工具。我们可以创建一系列工具。每个工具职责明确。为数据库创建唯一性约束。我们从。仅思考数据文件。必须准备数据库以应对即将进行的数据导入。数据库准备的第一步是确保唯一性约束。在最终的数据库中。对于具有特定标签的节点。当该标签出现时。某个标签属性需要唯一。这与具有唯一列的CSV文件完全对应。ID。将成为每个的唯一约束。此实用函数将处理此事。只需传入标签和唯一属性键。将自动在Neo4j创建约束。下方的Cypher查询。可以看到创建约束。传入的约束名称仅在不存在时创建。为特定标签创建。在该标签下要求此唯一属性键唯一。在此之前我们大量使用查询参数。当我们设置这样的约束时,而不是新的Neo4j。无法为此传递查询参数。我们将在这里进行一些不安全的操作。通过实际进行字符串拼接。我们知道这不是推荐的做法。我们应该在此处有一个净化函数以确保安全。这就是。你知道这是不好的。但暂时这样就可以了。
下一个函数你想要。如果你有能力为节点创建唯一性约束。我们接下来需要能够从CSV文件加载节点。你可以为此定义一个函数。这里就是加载节点的CSV函数,它接受源文件。该源文件的标签。CSV文件中哪个列是唯一的。还需要一个包含所有应从源文件创建的属性列表。看下面生成的Cypher。有专门的语法用于从CSV文件加载。位于导入目录中的CSV文件。这就是为什么我们处理的都是相对路径。当我们使用load cas fee在uNeo4j中时,此文件URL。这里的路径将相对于新Neo4j的导入目录。我们将从该目录加载带标题的CSV文件。对于该文件中的每一行。我们将在此调用子查询。在子查询中。它将执行这些行的合并操作。当然会先检查节点是否存在。如果不存在。将根据传入的唯一列创建该节点。的这行代码。四。each是一种利用传入属性列表的独特方式。它只是某些属性的名称。我们最终会遍历每个属性。对于每个属性名称。我们将为刚创建的节点设置属性值。来自CSV文件的行值。实际上我们将遍历所有名称并继续。逐步设置这些值。通过在子查询中使用此方法。我们能够批量处理。因此我们将分批次处理,每次一千行。无论CSV文件多大。我们将分批处理,每次一千行。你可以看到我们将调用的新Neo4j。传入查询。我们将传递该查询。并附带大量查询参数以供使用。对于你拥有的每个CSV文件。你实际上需要执行我们刚刚定义的两个函数。我们首先要调用这两个函数。调用创建唯一性约束的功能。以确保每个节点都有唯一值。这样ID才能被正确识别。在为每个CSV文件创建唯一性约束后。我们将继续执行实际的数据导入。使用我们刚才看到的从CSV加载节点工具。这就是当前发生的情况。在导入节点过程中。只是应用构建规则。基于构建规则中的值。将调用创建唯一性约束工具。如果没有错误发生。
将继续从CSV文件导入节点。这里只是从构建规则中提取。需要传递给函数的不同值。可以更简单地导入关系。在关系中不需要为它们应用唯一性约束。因为它们本身没有独立标识。它们将直接连接到两侧的节点。无论是来源节点还是目标节点。这些节点应该是唯一的。但关系本身也会是唯一的。因为每行只有一个对应关系。在导入的文件中。这特别适用于我们当前的数据文件。如果需要的话需要更加谨慎。你知道的。数据文件可能设置得更复杂。但对于本例中的数据文件。这种方法无法正确完成导入。如同节点加载一样。我们将使用导入目录中的带标题的LOAD CSV。并将所有内容作为行加载。对于每一行。我们需要在子查询中进行更多处理。找到之前加载的现有节点。找到来源节点和目标节点。在使用MATCH子句找到这些节点后。将使用MERGE子句创建关系。从来源节点到目标节点。这样只会为每对来源和目标创建一个关系。以及特定类型的关系。例如如果有两个ABK喜欢咖啡的关系。玫瑰咖啡的情况只会出现一次。即使CSV文件中有重复数据。MERGE会检查节点。两侧的节点已经是唯一的。并且该关系已有abk的点赞。点赞已经存在了。不会创建另一个关系。节点的情况也是如此。我们将在关系上设置属性。如果存在可用属性。我们将使用这里的每个循环结构遍历它们。并将所有可用值设置好。继续调用查询。并将所有查询参数直接从构造规则传入。所有这些函数都完成了大部分实际工作。构建主图本身。实际上只需接收一个参数。完整的构造计划。按顺序先构建所有节点。节点已存在。可以使用已定义的主图创建关系。我们现在可以尝试运行此代码。当然我们需要完整的构造计划。这里是完整的构造计划。这将与之前的课程不同。取决于LLM的决定。当此笔记本创建时。这里是有效的构造计划。你可以查看其中内容。这有点预期中的结果。
我认为这里需要重点关注。稍后检查创建的关系。存在一个包含关系。从产品出发。包含一个装配组件,听起来合理。这是一个部分关系,从零件出发。零件属于一个装配组件。这有点冗长。但这是正确的。这里的源节点是零件,由供应商提供。看起来完全合理。这将成为我们主图函数的输入。运行该函数。当函数执行完毕。没有输出结果。可以添加打印语句提示完成。已完成所有工作。我们将实际操作图数据。就像仍在进行查询一样。用更复杂的查询语句检查领域图。我们将首先查找构造计划中的所有关系规则。我们使用列表来实现。Python中的表达式理解。我们现在只需遍历所有构造计划值。每当构造类型是关系时。就会被放入这个列表。这里是我们之前看到的所有构造。但不包括节点构造。我们在这里进行一点Cypher 查询。我将逐步解释这个过程。在这复杂的Cypher查询中。我们的目标是大致对图进行采样。我们不会获取整个图来查看。但我们要做的是我们期望。对于这里所有的关系构造规则。结果图中至少应存在该关系类型。如果我们收集所有不同的关系类型。并对它们进行模式匹配。查看输出结果。应该能看到所有预期创建的内容都已创建。我不确定我是否表达正确。但让我们实际走一遍看看计划如何。第一步我们将传入这个构造规则列表。在Cypher中。你可以将列表展开为多行数据。原本是一个包含规则的列表。我们将其转换为多行。每行包含单个规则元素。这样关系构造列表将被拆分为多行。每行包含单个构造值。我们要对构造规则。进行从某个节点的模式匹配且无条件。这里。关系类型来自构造规则。提取构造规则的关系类型值。在这里。美元符号引用查询参数。我们将提取该值到此关系类型。如果这里。你会看到有’supplied by’关系类型。该值将由查询参数替换。从某个节点通过’supplied by’连接另一节点。
我们将返回来源节点的标签。以及目标节点的标签。以及关系本身的类型。最终应得到一个三元组。仅包含关系标签和两侧节点标签。我们限制为仅一条结果。因为我们不需要查看整个图。只需验证存在性。我们将将其放入子查询中。这样我们只需在此处应用一次匹配。对之前展开的每个元素进行操作。这就是这里发生的情况。在这一部分我们将调用子查询。并将刚刚定义的匹配路径放入其中。在完全组装的Cypher中展开列表。在子查询内执行匹配。从所有结果中返回源节点关系和两个节点的三元组。这将是标签。它们的类型。以及两个节点上的标签。你可以看到这将打印出值。你可以看到运行前的Cypher结构。我们将最终运行Cypher。这里是完整的Cypher语句。这里是我们从plotter找到的关系。包含组装。零件属于组装部件。零件由供应商提供。完美,这与之前构造池中的结果一致。看来这个图以良好的方式构建完成。
P42 8-2 知识图谱构建 Part2
在本节课中。你将继续构建知识图谱。上一节课根据构建计划从CSV文件创建了领域图。你将处理Markdown文件。将其切分为词汇图并提取实体到主体图。你将学习如何使用新的vj图RAG库。执行切分和实体提取操作。你还将学习实体解析技术。最终这不会是工作流程的遗传部分。这将完全由工具处理。因此我们将定义一些工具。并编写这些工具所需的一些辅助函数。我们需要的两个工具之一是实际构建知识图谱的工具。我们将为每个文件创建一个构建器。并让其处理文件进行切分和提取。你将定义的另一个函数是关联主体与领域节点。这两个工具将从Markdown文件构建图谱。获取提取的实体结果。并在主体图之间进行关联。与之前从CSV文件创建的领域图。可能有点难以理解。随着逐步讲解会更清晰。如同之前的笔记本教程。你将首先导入所需库。进行常规设置。所有需要的库。等待导入完成。确保OpenAI已就绪。并检查新Neo4j是否准备就绪。一切正常。在此设置中。我们需要的不仅仅是前几课创建的初始状态。因为现在我们不再只是执行工作流程。上一课实际上在eNeo4j中创建了部分图谱。由于新Neo4j加载时会是全新状态。我们需要添加。之前课程中创建的部分产品节点。我们有一个辅助函数用于此。这个辅助函数是load_product_nodes。我们可以直接调用它。执行调用。我们预期的是。图中仅存在标签为product的节点。操作正确。你需要为代理准备初始状态。初始状态应包含工作流程前期创建的部分。与之前加载的内容类似,我们需要构建计划。我实际处理的已批准文件。此外我们已完成实体提取的初步规划。我们需要已批准的实体和事实类型。我们将创建这些初始状态。这是已批准的施工计划。这是已批准的文件。已批准的实体和事实类型。可以开始定义创建管道所需的各种功能。
这将处理所有Markdown文件。进行分块处理。提取实体。Neo4j图RAG库有一个便捷的简单知识图谱管道。可用于处理分块和实体提取。对于所有要处理的Markdown文件。需要创建辅助函数正确配置。但首先让我们看看简单知识图谱管道的接口。这只是示例代码。当然无法运行。因为此处没有有效值。但仅展示结构。实际创建简单知识图谱管道实例的过程。需要一个m。当然进行实体提取时。需要Neo4j的驱动程序以输出图谱。需要更好的接口,可能是同一LLM或其他模型。如果需要的话。由于我们处理的是Markdown文件而非PDF。通常设置为处理PDF为false。但实际上并非如此。我们将使用自定义PDF加载器而非加载PDF。我们将加载Markdown文件。这只是接口设计的一个小细节。但最终我们会设为true。在这里。我们将定义自定义加载器并集成到此部分。对于PDF加载器部分。还需要自定义分块器。因为我们了解Markdown的结构。如果你有分块处理经验。知道纯文本分割本身就是一门艺术。可能有很多深度学习课程。可以深入学习该主题。这里有很多深度学习课程。我们将采用简化版本。基于现有数据做出假设。还可以传入模式。而模式是。当然。将基于前一课设置的建议模式。关于能从文本中提取的事实和实体类型。当然还有。将所有这些内容整合起来。我们将有一个自定义提示输入。这将明确告知语言模型我们需要查找的内容。以及如何进行提取思考。逐步讲解新Neo4j KG构建器的端到端流程。帮助你理解这些组件的功能。每个文档都会被加载。内置支持PDF格式。但你会使用自定义Markdown加载器。文本分块组件将执行分块处理。这是许多框架中常见的分块方法。对于每个分块。分块嵌入将计算向量。嵌入。对分块进行分析。使用语言模型按实体和关系提取器的指令。
此组件将配置以匹配我们的知识提取计划。图谱构建完成后。可选的图谱清理器用于优化图谱。所有操作都在内存中完成。KG写入器负责将内存中的图谱保存到Neo4j系统。最后。实体解析组件将合并可能相同的实体节点。你可以开始定义这些自定义函数。需要输入到流程中。设置自定义文本分块器。如果你还记得我们之前的火星飞行员Markdown文件。开头有一个H1标题。有这些分页符。主要用于分割评论内容。因此我们将使用简单正则表达式分块器。在新Neo4j中。有一个名为文本分块器的基础类。可扩展自定义功能。这就是我们要做的。我们将扩展文本分块器。在文本分块器的运行函数中。因为它是流程的一部分。这里将放置自定义功能。只需使用正则表达式进行文本分割。基于已定义的正则表达式。将其传递给函数本身。对于任何传入的正则表达式。均可作为文本的分割点。最后一步是继续。使用列表推导将每个纯文本分块。转换为Neo4j图谱RAG库期望的对象。称为文本块。文本块仅包含字符串本身的文本内容。该文本段落的索引。这将生成包含这些文本块对象的单个列表。该列表将被命名为文本块。你还将使用特殊的数据加载器加载Markdown文件。与文本分割器类似。这将继承新vj grarag库的基类。这里有几个可用的选项。但我们自己会找到一个特殊版本。我们将导入数据加载器基类。这些操作类型需要用于输出。我们将模拟解析PDF文档的过程。在Markdown数据加载器中加载PDF文档类型。这里最关键的是。我们知道Markdown中包含某些元数据。我们需要提取并添加到数据加载的上下文中。在分块处理时。类中有一个名为提取标题的辅助函数。将使用非常基础的正则表达式。假设首次找到单个H1标题。将其作为文档标题。当调用运行函数时。运行函数将从数据源加载数据。将从文件系统加载。
读取整个Markdown文件。提取标题。将其转换为此文档信息。文档信息才是关键部分。这是与文档文本结合的元数据。我们已将Markdown文本加载到此PDF文档类中。构建知识图谱管道还需。当然需要一个语言模型。我们准备好了。我们已有。但我们将继续使用OpenAI。当然也会使用OpenAI。获取新的Neo4j驱动器。这里使用。j graph rag库。Neo4j支持。当然也支持OpenAI和其他模型。我们将使用OpenAI作为语言模型。同时用于嵌入生成。创建新Neo4j的语言模型实例。以及Neo4j better。从图数据库获取Neo4j驱动器。我们一直使用的单例,用于发送查询。该单例允许获取内部驱动器。这就是我们在这里的操作。你已经定义了知识图谱管道所需的一些实用函数。同时也定义了其他组件,比如语言模型和嵌入器。我们将转向实际进行知识图谱实体提取所需的上下文。我们首先从实体模式开始。新Neo4j图RAG包所需的实体模式包含几个不同组件。其中一个是要知道应在文本中查找的节点类型。这里我们只需复制或创建approved_entities的别名。我们还将获取关系类型模式。为此我们将从批准的事实类型中提取。所有批准的事实类型实际上都存在于字典中。字典的键正是关系类型本身。因此我们只需提取所有键。这将成为关系类型模式。你可以在这里看到。你还会使用批准的事实类型。作为知识图谱构建管道所说的模式模式。这其实只是信息的重新包装。从每个事实中。我们将生成包含主语标签的列表。谓词标签和宾语标签。我们将处理谓词标签。将其转换为大写。这是Neo4j的约定。知识图谱构建所需的完整模式在此。包含节点类型。关系类型。这些如何组合的模式。并将此标志设为false。仅使用我们定义的这些类型。不要添加新内容。
获取实体提取上下文的重要部分。我们将创建自定义提示。将每个块内的文本注入其中。同时还会添加模式。我们还将使用特殊实用函数。用于添加文件上下文。管道将处理单个块。文件的整体上下文将添加到提示中。以便LLM在查看该块时。知道它所属的文档是什么。因此对于文件上下文我们创建这个小辅助函数。所有操作其实只是。获取文件文本的前几行。包含文件标题。以及一些简介和信息。为每个块提供足够上下文。定义提示本身。我们来看这个提示。作为一大段文本。它将大致遵循我们之前采用的相同格式。我们有一些关于。当前工作中LLM的角色是什么。以及实际追求的目标是什么。但其中大部分是搭建。一些设计提示。同时也包括上下文和上下文包含模式定义。以及我们将要提取的文件部分内容。当你查看这个提示时。你会发现它包含。关于角色和目标的说明。这里还有一些设计指令。关于它应该执行什么。还包含输出格式的具体要求。在这里以及每个片段的模式都将被注入。一旦所有内容就位。作为输出的一部分。我们将要求它为每个节点生成独特想法。在创建这些节点时。同时我们还会给出此处的指令。关于如何处理输出中的每个属性。我们需要节点输出包含某些ID。我们需要知道标签是什么。它所选择的内容。以及应分配给该实体的属性是什么。是来自文件的上下文。文档级上下文将被注入。在这里因为这是一个辅助函数。用于创建整体提示。我们将直接将其作为静态文本注入。因此不会被注入。每次创建片段时。它将是静态文本的一部分。最后将把片段数据放入此模板格式。整合所有已设置的上下文。结合知识图谱构建器所需的各类辅助函数。我们可以创建知识图谱构建器。使用它。因为我们将为每个文件创建知识图谱构建器。从而生成针对文件的专用提示。基于文件内容。这里是我们在辅助函数中设置的方法。我们将创建一个生成知识图谱构建器的辅助函数。
其输出是一个简单的知识图谱处理管道。这是图RAG类的新功能。在该辅助函数内部。获取文档级上下文。使用我们创建的文件上下文工具。再次获取数据文件的前几行内容。从这里生成上下文化的提示。传递该上下文。这是我们能得到的完整提示。因此当我们创建简单的知识图谱管道。我们将获取定义的LLM模型。我们使用的驱动程序是embe。我们将假装在处理PDF文件。因为我们有一个自定义的PDF加载器。实际上会加载Markdown文件。我们的自定义分词器。将使用正则表达式。在这里正则表达式只是向前查找。短横线。这就是Markdown页面。如果查看之前看到的Markdown文件。这就是每个评论的分割方式。因此我们将使用这些文本。将组装的模式拆分为实体模式。最终构建的上下文化提示。将所有内容整合。得到一个完整的管道进行分块。进行实体提取。你有了生成知识图谱v管道的辅助函数。针对特定文件。只需遍历导入目录中的所有文件。为每个文件获取完整路径。输出提示语句。告知当前进度。创建知识图谱构建器。运行知识图谱构建器。这需要几分钟时间。我们有。我想处理大约十个文件。每个文件将需要。根据OpenAI的响应速度。可能需要一分钟。完成文档的自然语言处理和提取。同时进行分块处理。当循环完成后。将得到完整的词汇图。这是图的组成部分。包含相互连接的块。并连接到文档注释。同时还有主体图。包含所有提取的实体。以及它们之间的关系。已完成。你拥有了一个词典图。一个主体图和一个领域图。然而知识图谱并不完整。因为主体图和领域图尚未连接。而且如果你还记得领域图是基于CSV文件创建的。而我们刚刚从Markdown文件中提取数据生成了主体图。下一步是将从Markdown文件中提取的实体连接起来。整合到主体图中。我们希望将这些与领域图连接。
如果领域图中存在与主体图提取实体相同的产品。作为主体图中的提取实体。我们希望将它们连接。因此我们将定义几个工具来实现这一目标。对于主体图中的每种实体类型。你需要制定与领域图中正确节点关联的策略。例如。你应该预期主体图中的产品名称实体存在。这些应与领域图中的产品对应。为了做到这一点。你将首先进行几项操作。找到主体图中所有唯一的实体标签。同样找到领域图中所有唯一的节点标签。尝试在这两个标签集合之间关联属性键。这样你可以确定。如果主体图中有产品具有多个属性。如何与领域图中具有多个属性的产品对应。最终步骤是执行实体解析。通过分析属性值的相似性。第一步是找到主体图中的唯一实体标签。查看主体图。观察节点的结构。在新的j grafrag库完成工作后。主体图中的节点将带有额外标识标签。它们将被标记为双下划线实体。下划线标签。你还会看到额外标签标识实体类型。如果我们运行匹配任意节点的查询。并查找具有该标签的节点。即可返回不同标签的集合并称为实体标签。查看结果。可以看到这里添加了几个特殊标签。有双下划线实体标签。还有双下划线kg builder。表明kg builder负责创建这些节点。但我们真正关心的是看到产品位置。问题和功能。我们已经知道这一点,因为这是我们从之前的步骤中预期的结果。但重要的是,这些步骤可能原本试图寻找类似位置之类的信息。但这些可能实际上未能在图中发生。因为语言模型未能真正找到它们。因此我们将采取以下做法。我们将查询图中实际发生的内容。根据我们在图中找到的标签。我们将这些称为主体图中的唯一实体标签。通过几个查询示例来详细说明。如果你查看这些行,你会发现每一行。实际上是一个标签列表。对于每一行。如果我们继续使用展开子句。在这里,我们说要展开实体标签,这些标签将属于每个节点。
并将这些单独的行称为实体标签。我们可以返回唯一的实体标签。我们应该看到所有相同的值。但现在不再是多个列表。我们将看到一个包含所有值的单一列表。列表实际上只是几行。每行只有一个标签。知识图谱构建器。产品实体你可以直接看到。进一步详细说明这个查询。我们需要过滤掉这些下划线标签。我们只需通过相同的查询来实现。我们从匹配开始。仅针对实际是实体的项设置谓词。展开所有这些。这些只是单独的实体标签。我们添加另一个谓词。删除所有以下划线开头的实体。这将移除知识图谱构建器和下划线实体。这就是我们想要的产品位置列表。问题和功能。你可以定义一个实用函数来封装对Neo4j的调用。如果你尝试使用这个实用函数。你应该看到。当然。仅仅这个列表。正是我们现在需要的内容。对于每个唯一的实体标签。我们也想找到每个标签的唯一键。对于每一个,我们将执行类似的操作。我们将定义一个实用函数。用于查找具有该特定标签的所有节点。但一旦找到这些样本集合。我们将仅提取这些节点上出现的唯一键。看看这个效用函数在这里是什么样子的。它将接收一个参数。也就是我们正在寻找的实体标签是什么。进行匹配。而不是查找所有节点。我们只查找具有该特定实体标签的节点。在这里我们将稍微调整一下思路。我们实际上想要查找。当然。仅在该标签与下划线实体共同出现的位置。而不是查找不同的标签集合。我们将查找这些节点的唯一键并返回。和之前类似。我们将将这些键列表展开为几行键。这就是展开操作在这里的作用。我们将这些全部收集回列表。将其作为单个结果返回。定义这个函数。运行它。仅查找与主体图中产品相关的唯一键。看起来我们。在进行实体提取时并没有太多限制。这次语言模型实际上发现了许多不同键。在创建这些实体时。在不同产品之间。这里展示了从评论中推导出的不同属性。它识别出了材料等信息。
关于不同特征的。我不确定书架深度似乎出现在某个地方。必须查看Markdown文本。才能看到语言模型为何发现这些不同属性。根据提取时使用的具体评论。有些评论可能提到了这些属性。其他则没有。因此这些不会在所有属性中一致。但其中一些可能是特别的。我认为名称会共同出现。稍后你会看到我们如何将这个键列表。与领域图中的可用键进行关联。这就是我们如何同步所有内容的方法。定义的效用函数非常相似。但现在我们将注意力转向领域图。在领域图中我们已经知道如何查找领域图中的标签。我们知道存在没有实体标签的标签。如果我们匹配特定标签。比如产品。要查找产品的唯一领域键。我们将进行头部匹配。过滤掉带有实体的项。因为这些属于主体图。我们按照之前处理函数的方法。我们将获取这些域节点的唯一键。将这些键收集到列表中。因此如果我们查找域标签的唯一属性键。这应该是一致的,因为这些都来自同一个CSV文件。这是一个更小的列表。它很可能与CSV文件中的内容完全对应。这是产品名称。价格描述。产品ID。为了辅助这一过程。我们将定义一个名为normalize_key的辅助函数。你可以为特定标签。输入需要归一化的键是什么。这个函数的作用。会将键转为小写。去除多余空格。这没什么帮助。如果存在前缀的话。其中前缀是标签本身。将其移除。例如产品名称会变为name。这样可以轻松与主体图的name键关联。项目名称会变为name。产品空间名称也会变为name。当然像价格这样的属性键仍保持price。不会被改变,所以再次。实现非常直接。但这样做的目的是让属性键更容易比较。查看一些示例。仅作合理性检查看起来正常。要编写的实用函数是用于关联特定标签的键。这将利用我们已有的实用函数。看看实现代码。我们将在这里导入Python的新库rapidfuzz。主要用于文本相似度评分。
这是基于编辑距离的简单评分。实际上有多种方法来判断。文本字符串是否高度相似。rapidfuzz是该领域功能强大的库。给定特定标签。实体节点和域节点的键。我们将查看相似度阈值。这些键如何相互关联。根据rapidfuzz的fuzz函数评分。对于高度相关的键。我们将配对并说明。这些键值得比较值。详细看一下。相关键。我们想要配对的键。初始状态为空。我们将遍历实体键集合中的所有键。采用经典风格。我们将使用for循环。在for循环中遍历所有实体键。在其中遍历所有域键。对于每一对组合。我们将考虑它们的相关性程度。我们将对每个键进行归一化处理。由于快速模糊相似度分数从0到100。我们将反转这个值使其更像相似度评分。我们现在。计算归一化域键与实体键的比率。这应该就是模糊相似度。我们希望模糊相似度超过相似度阈值。这是传递给函数的参数。当前默认值设为0.9。如果超过该阈值。我们将将其添加到相关键。作为有效配对。我们继续对这些键进行排序。以便更容易查看高度相关的项。Verse的相关性较低。我们将取最高相关性的一项后续使用。在定义该函数后。我们将继续。这部分只是尝试演示。定义产品函数。将查找所有唯一实体键。查找域键。将其传递给此函数并查看结果。对于产品。可以看到名称与产品名称完全匹配。价格与价格完全匹配。描述与描述完全匹配。但设计描述的相关性较低。尺寸与描述的相关性低。这些效果不佳。我们设置的阈值是多少。我们要求相似度为0.5。可以尝试不同值查看结果差异。你得到。默认值0.9。是经典高阈值设置。这里还有一个背景信息。我们将把这些内容整合起来。我们现在能够关联特定标签。在主体图和领域图中。这些标签的键值。这些良好配对的作用。实际判断两个节点是否为同一节点。这一切都是基于实体解析技术。这是一种实现目标的技术方法。
这是一个不错的基准方案。它完美适配当前数据集,可能对其他数据集也有效。你需要采用多种技术手段。当然可以想象构建一个完整代理系统。只需针对现有数据。确定最适合的解析技术。但今天我们。需要做出一些假设。要使用的函数是。在处理Neo4j数据时调用Cypher 方法。加密库也支持字符串比较方法。可用的值相似度函数之一是jo winkler距离。这本质上是一种字符串比较方法。类似于。你可能使用向量相似度需要计算嵌入向量。也可以通过多种方式计算文本距离。gerald winkler通过计算两字符串的编辑距离。主要评估需要进行的微小修改次数。只需比较字符串a和字符串b。需要进行多少次编辑使两者相同。结果值介于0到1之间。数值呈反向关系。0表示完全匹配。意味着精确一致。1表示完全无匹配。near for j的技术相似度库。包含gerald winkler计算方法。还可以使用汉明距离。莱文斯坦距离。还有瑟尔森-迪斯相似度。以及模糊匹配。当然如果需要。也可以使用向量嵌入进行余弦相似度。这些各有不同。特征特性。就像我们之前所做的所有工作。在日志raft构建过程中。可以自行选择最适合的方案。如果。针对特定数据集的数据。jo winkler距离完全适用。你可以看看杰瑞·温克勒在行动中的样子。仅使用纯Cypher。如果你查看此处匹配子句中的Cypher查询。实际上我们将匹配特定标签下的实体和域名对。这里我们将寻找双方具有相同实体标签。当然实体节点还带有额外标签_实体。结合实体和域名。计算这个乔温克勒距离得分。我们将通过过滤器传递该得分。得分必须小于0.4。如果你记得得分为零表示完美匹配。我们在这里采用相反的评分方式。我们寻找低值。在此进行过滤。返回这些值进行查看。在这个例子中。我们将传入一些查询参数。
我们寻找实体标签为产品。在主体图和域名图上均适用。在主体图中。我们将查找实体键名。域名键将为产品_名称。可以看到这些是完美得分。哥德堡桌子和哥德堡桌子。这些完全相同。当然你会预期它们得分很低。你可以尝试不同值。观察效果。如果使用稍低的阈值。比如0.5。可以看到哥德堡电缆和沃斯塔书架。显然并不差。哥德堡桌子和斯德哥尔摩椅子。我不确定文本上有多相似。但距离计算显示如此。这就是为什么实践中通常需要。设置非常低的阈值。比如1.1。使结果尽可能接近完全相同。详细解释这个查询。这正是相同的查询。我们添加了一个额外部分。当我们找到两个低阈值实体时。我们稍作调整。在实体与域名节点的配对中。我们将使用where子句。仅对温克勒距离进行约束。将阈值设为0.1。对于通过对应关系的任何配对。我们将实际创建从实体到域节点的关系。因此我们将使用固定类型。它不会参数化,对应于。因此关系将是该实体节点与该域节点对应。我们将使用两个子句。以防您多次运行此操作。在执行合并时这非常有用。Merge在Neo4j中类似于Upsert操作。它实际上基于行为有两个子句。如果合并找到匹配项。实际上你所描述的内容。则存在匹配时的子句。后续操作将被执行。或者首次创建时。当执行合并后会调用创建子句。如果首次运行时。将调用创建操作。我们将设置此值。创建时间并添加时间戳。如果已创建过。再次进行匹配时。我们将为更新时间添加时间戳。每次运行都会更新。此查询覆盖所有对应产品效果良好。此Cypher查询完全符合需求。将其封装为函数调用。传入实体键和域键。以及所需的相似度阈值。此处查询基本相同。可以看到参数作为查询参数传递。从函数参数中传入。同样。我们直接运行此操作测试产品名称。这两个实体的不同键。以及域图中的对应键。很好。在主体图和域图间找到十项合理关系。
为完整性考虑。虽然我们知道可以连接所需产品。对所有可用实体执行此操作。以关联并连接所有主体节点。到对应域节点。我们只需添加循环。遍历所有唯一实体标签。从实体侧关联到域侧。主体节点与域节点将被连接。可以看到产品已成功连接。当然。位置实际上没有关联。它确实可以发行了。或者两者都没有功能。但这是我们预期的。发生了什么。经过所有这些工作。你终于得到了一个完整的领域图,它是从CSV文件构建的。你还拥有一个词汇图和一个主题图,它们是由Markdown文件创建的。随着这最后一步。你已将主题图中的实体与领域节点中的实体连接。你拥有了完全连接的知识图谱。做得很好。
P43 Conclusion 结束
在这个课程中。你学会了如何构建一个多。代理系统,将重构和非结构化数据转化为知识图谱。你学会了如何在系统中设置每个专用代理。你使用的提示词。以及需要定义的工具。以及如何在代理之间共享上下文。祝贺你完成本课程。我期待看到你自己的创作。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)