企业就绪的生成式人工智能系统构建指南-全-

企业就绪的生成式人工智能系统构建指南(全)

原文:zh.annas-archive.org/md5/0a9b1a8ef3a839e749d0326d81ce940a

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

在快速发展的 AI 领域中,仅仅依靠独立的大型语言模型LLMs)并不能带来商业价值。本全面指南使您能够成为一名生成式 AI 架构师,从头开始构建适应任何平台的强大 ChatGPT 级系统。您将超越基本的聊天机器人,开发具有语义和情感分析能力的系统,其核心是具有上下文感知的 AI 控制器。

您将经历设计具有多用户记忆保持的 AI 控制器架构的完整旅程,使系统能够适应各种用户和系统输入。在此基础上,您将使用 Pinecone 构建一个动态的检索增强生成RAG)系统,旨在智能地结合指令场景。

通过强大的多模态能力——包括图像生成、语音交互和机器驱动推理——您将使用思维链编排扩展您系统的智能,以应对真实商业环境要求的跨领域自动化挑战。您还将完全准备好将 OpenAI 的 LLMs 和 DeepSeek-R1 等前沿模型集成到您的 AI 系统中——有信心即使在今天 AI 生态系统的动荡步伐中,它也能保持稳定、可扩展和适用于生产。

到最后,您的生成式 AI 系统GenAISys)将能够进行轨迹分析和人类移动预测,即使在处理不完整数据的情况下也能做到。它将为您的营销信息带来神经科学启发的洞察力,无缝集成到人类工作流程中,可视化复杂的交付和移动场景,并连接到实时外部数据——所有这些都被包裹在一个光鲜亮丽的、投资者准备就绪的界面中。

本书面向的对象

本书面向 AI 和机器学习工程师、软件架构师和企业开发者,他们希望从头开始构建一个全面的 GenAISys 用于企业应用。它将特别有益于那些对构建 AI 代理、创建高级编排系统以及利用 AI 在营销、生产和物流中实现自动化感兴趣的人。希望构建可扩展的 AI 驱动系统的软件架构师和企业开发者也将在这本指南中找到巨大的价值。不需要有超智能经验,但建议熟悉 AI 概念。

本书涵盖的内容

第一章定义一个适用于商业的生成式 AI 系统,解释了如何设计针对商业使用的稳健、ChatGPT 级 AI 系统,包括 AI 控制器、代理、上下文感知、高级记忆保持和战略性的团队合作。您将探索如何超越基本的模型集成,构建能够为各行业带来实际业务成果的 AI 解决方案,并成为能够适应任何环境的架构师。

第二章构建生成式 AI 控制器,深入实际开发适应性 AI 控制器,结合对话代理和编排器。你将熟练构建一个能够动态响应用户输入、利用高级记忆管理并编排如情感和语义分析等任务的 GenAISys,这些任务对于现实世界、数据密集型应用至关重要。

第三章将动态 RAG 集成到 GenAISys 中,教你如何使用 Pinecone 构建一个可扩展、动态的 RAG 系统,有效地结合指令场景和经典数据。你将发现如何构建能够快速响应现实世界商业中断和特定领域挑战的适应性生成式 AI 解决方案。

第四章构建 AI 控制器编排界面,展示了如何构建一个协作的、事件驱动的生成式 AI 界面,旨在快速响应现实世界的商业需求。我们将创建一个实用的、多用户的对话式 AI,它能够无缝集成到人类工作流程中,在关键场景中增强决策能力。

第五章通过思维链添加多模态、多功能推理,利用 OpenAI 强大的多模态能力增强我们的 GenAISys,包括图像生成、语音交互和机器驱动推理。我们将通过思维链编排扩展我们系统的智能——使智能自动化能够适应复杂的多领域商业场景。

第六章推理电子营销 AI 代理,利用 AI 驱动的记忆分析能力来创建客户能记住的营销信息。我们将构建一个消费者记忆代理,它能够智能地分析评论和情感,生成由多模态推理增强的个性化营销内容——将神经科学洞察直接带入我们的 GenAISys。

第七章使用 DeepSeek 增强 GenAISys,在保持稳定性的同时导航 AI 的快速演变。你将学习如何战略性地将如 DeepSeek-R1 等前沿模型集成到我们的 GenAISys 中,使用灵活的处理器选择机制——使我们的系统在快速变化的市场中保持适应性、可扩展性和生产就绪。

第八章GenAISys 用于轨迹模拟和预测,将先进的 AI 驱动的轨迹分析引入我们的 GenAISys,以精确预测人类移动性和配送,即使是不完整的数据也能做到。我们将构建一个直观的管道,利用 LLMs 来模拟、分析和可视化复杂的配送和移动场景,将空间数据转化为可操作的见解。

第九章通过数据安全和客户服务升级 GenAISys,通过集成实时天气信息、旅行信息、强大的审查工具和高级安全功能,将我们的 GenAISys 安全地连接到现实世界的数据。您将发现如何安全地扩展我们 AI 的能力,使其超越内部数据,实现个性化营销、动态活动推荐和实时客户互动。

第十章展示您的商业就绪生成式 AI 系统,将向您展示如何将您的 GenAISys 原型转变为一个引人注目、投资者就绪的展示。我们将学习如何通过清晰的信息、实用的演示和精炼的用户界面有效地展示我们的 AI 系统,吸引观众注意力,展示价值,并在拥挤的 AI 市场中证明其扩展的可行性。

要充分利用本书

您不需要成为 AI 专家就能从本指南中受益,只需对人工智能和编程的基本知识有所了解即可。如果您使用过 Python 或探索过像 ChatGPT 这样的 LLMs,您会感到非常自在。

本书以清晰、实用的步骤介绍了 AI 代理编排、记忆保留和 RAG 等概念。无论您是开发者、工程师还是好奇的技术人员,您都会找到旨在支持实际应用的工具、代码和解释。

不需要深入的数学或理论背景,只需有构建解决商业问题并在生产环境中扩展的有意义的人工智能系统的愿望。

代码可在 Google Colab 笔记本中找到,带有自动安装,或者您也可以本地下载代码。

下载示例代码文件

本书代码包托管在 GitHub 上,网址为github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems。我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing找到。查看它们吧!

下载彩色图像

我们还提供了一份包含本书中使用的截图/图表彩色图像的 PDF 文件。您可以从这里下载:packt.link/gbp/9781837020690

使用的约定

本书使用了多种文本约定。

CodeInText:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter/X 账号。例如:“接下来,我们将instruct_selector集成到现有的界面布局(VBox)中。”

代码块设置如下:

# Ensure 'Instructions' exists in the memory_selector options
instruct_selector = Dropdown(
    options=["None","Analysis", "Generation"],
    value="None",  # Ensure default active_memory is in the options
    description='Reasoning:',
    layout=Layout(width='50%')
) 

任何命令行输入或输出都按以下方式编写:

Response: The dialog begins by explaining the formation of Hawaii's volcanic islands as the Pacific Plate moves over a stationary hotspot, leading to active volcanoes like Kilauea…. 

粗体:表示新术语、重要词汇或屏幕上出现的词汇。例如,菜单或对话框中的文字会以这种方式显示。例如:“用户随后重新输入句子,但这次选中了生成选项和文件选项,以便显示带有文本的图像。”

警告或重要注意事项会以这种方式显示。

小技巧和窍门会以这种方式显示。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果您对本书的任何方面有疑问或有任何一般反馈,请通过customercare@packt.com发送电子邮件,并在邮件主题中提及本书的标题。

勘误:尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在此书中发现错误,我们将不胜感激,如果您能向我们报告,我们将不胜感激。请访问www.packt.com/submit-errata,点击提交勘误,并填写表格。

盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过copyright@packt.com与我们联系,并提供材料的链接。

如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为本书做出贡献,请访问authors.packt.com/

分享您的想法

一旦您阅读了《构建商业就绪的生成式 AI 系统》,我们很乐意听听您的想法!请点击此处直接访问亚马逊评论页面并分享您的反馈。

您的评论对我们和科技社区都很重要,并将帮助我们确保我们提供高质量的内容。

加入我们的 Discord 和 Reddit 空间

您不是唯一在导航碎片化工具、不断更新和不确定的最佳实践的人。加入一个不断壮大的专业社区,交流那些没有进入文档的见解。

保持最新信息,了解我们的作者在幕后讨论和洞察。加入我们的 Discord packt.link/z8ivB 或扫描下面的二维码: 与同行建立联系,分享想法,并讨论实际的生成式 AI 挑战。在 Reddit packt.link/0rExL 上关注我们或扫描下面的二维码:

您的书籍附带独家优惠 – 这是如何解锁它们的

|

现在解锁本书的独家优惠

扫描此二维码或访问packtpub.com/unlock,然后通过名称搜索此书。确保是正确的版本。 | |

注意:在开始之前,请准备好您的购买发票。

电脑屏幕上有文字 AI 生成的内容可能不正确。

使用我们的下一代阅读器增强阅读体验:

多设备进度同步:在任何设备上无缝同步进度进行学习。

高亮和笔记:将您的阅读转化为持久的知识。

书签功能:随时回顾您最重要的学习内容。

暗黑模式:切换到暗色或棕褐色模式,以最小化眼睛疲劳。

使用我们的 AI 助手(测试版)更智能地学习:

总结内容:总结关键部分或整章内容。

AI 代码解释器:在下一代 Packt 阅读器中,点击每个代码块上方的解释按钮,获取 AI 驱动的代码解释。

注意:人工智能助手是下一代 Packt 阅读器的一部分,目前处于测试版。

随时随地学习:

黑色背景上的黑色方块 AI 生成的内容可能不正确。使用无 DRM 的 PDF 和 ePub 版本离线访问您的内容——与您喜欢的电子阅读器兼容。

解锁您的书籍独家优惠

您的这本书包含以下独家优惠:

下一代 Packt 阅读器

人工智能助手(测试版)

无 DRM 的 PDF/ePub 下载

如果您尚未解锁,请使用以下指南进行解锁。此过程只需几分钟,并且只需进行一次。

如何通过三个简单步骤解锁这些优惠

第一步

准备好这本书的购买发票,因为在第三步中您将需要它。如果您收到的是实物发票,请用手机扫描,并准备好作为 PDF、JPG 或 PNG 格式。

如需查找发票的更多帮助,请访问 www.packtpub.com/unlock-benefits/help

注意:您是否直接从 Packt 购买了这本书?您不需要发票。完成第二步后,您可以直接跳转到您的独家内容。

|

第二步

扫描此二维码或访问 packtpub.com/unlock。 | |

在打开的页面(如果您在桌面,将类似于图 0.1),通过书名搜索这本书。确保您选择了正确的版本。图 0.1:桌面上的 Packt 解锁着陆页面

第三步

登录您的 Packt 账户或免费创建一个新账户。登录后,上传您的发票。可以是 PDF、PNG 或 JPG 格式,且大小不能超过 10 MB。按照屏幕上的其余说明完成此过程。

|

需要帮助?

如果您遇到困难需要帮助,请访问 www.packtpub.com/unlock-benefits/help 查看如何找到您的发票等详细 FAQ。以下二维码将直接带您到帮助页面:| |

注意:如果您仍然遇到问题,请联系 customercare@packt.com

第一章:定义一个适合商业应用的生成性 AI 系统

在组织中实施生成性 AI 系统GenAISys)不仅仅是通过 API 集成一个独立的模型,如 GPT、Grok、Llama 或 Gemini。虽然这通常是起点,但我们常常错误地将其视为终点。随着 AI 在所有领域的扩展,对 AI 的需求不断上升,需要实施超越简单集成预建模型的先进 AI 系统。

一个适合商业应用的 GenAISys 应在组织中提供 ChatGPT 级别的功能,但也要超越它。其能力和功能必须包括自然语言理解NLU)、通过对话中的记忆保持实现情境意识,以及自主图像、音频和文档分析和生成的代理功能。将生成性 AI 模型视为一个具有广泛功能的实体,包括作为代理同事的 AI 代理。

我们将首先定义什么是适合商业应用的 GenAISys。从那里,我们将关注生成性 AI 模型(如 GPT-4o)的核心作用,这种模型既能协调也能执行任务。在此基础上,我们将为情境意识和记忆保持奠定基础,讨论四种生成性 AI 记忆类型:无记忆、短期、长期和多会话。我们还将定义一种新的检索增强生成RAG)方法,它为数据检索引入了一个额外的维度:指令和代理推理场景。通过检索存储在向量存储中的指令,将 RAG 提升到另一个层次,我们可以将这些指令添加到提示中。同时,我们将检查 GenAISys 的一个关键组件:人类角色。我们将看到在其生命周期中,一个 AI 系统如何需要人类的专业知识。此外,我们还将定义几个实施级别,以适应 GenAISys 的范围和规模,不仅适应商业需求,还要适应可用的预算和资源。

最后,我们将通过 OpenAI 的 LLM 和多功能 API 展示如何实现情境意识和记忆保持。一个 GenAISys 系统如果没有坚实的记忆保持功能是无法工作的——没有记忆就没有情境,没有情境就没有可持续的生成。在本章中,我们将根据任务需求创建无记忆、短期、长期和多会话类型的模块。到本章结束时,你将获得一个清晰的框架,了解什么使 AI 系统适合商业应用,并在构建 AI 控制器的第一块砖石方面获得实践经验。

简而言之,本章涵盖了以下主题:

  • 适合商业应用的 GenAISys 组件

  • AI 控制器和代理功能(模型无关)

  • 混合人类角色与 AI 协作

  • 商业机会和范围

  • 通过记忆保持实现情境意识

让我们从定义什么是适合商业应用的 GenAISys 开始。

商业就绪的 GenAISys 的组成部分

一个商业就绪的 GenAISys 是一个模块化的编排器,它无缝地将标准人工智能模型与多功能框架集成,以提供混合智能。通过结合生成式人工智能与代理功能、RAG、机器学习ML)、网络搜索、非人工智能操作和多个会话记忆系统,我们能够为各种复杂任务提供可扩展和自适应的解决方案。以 ChatGPT 为例;人们将“ChatGPT”这个名称交替用于生成式人工智能模型以及该应用程序本身。然而,在聊天界面背后,ChatGPT 和 Gemini 等工具是更大系统——在线副驾驶的一部分,这些系统由智能人工智能控制器完全集成和管理,以提供流畅的用户体验。

是 Tomczak(2024)将我们从将生成式人工智能模型视为一个集体实体转变为考虑复杂的 GenAISys 架构。他的论文使用“GenAISys”这个术语来描述这些更复杂的平台。本书中的方法将扩展 GenAISys 的视野,包括商业就绪生态系统中高级人工智能控制器功能和人类角色。GenAISys 没有单一的银弹架构。然而,在本节中,我们将定义实现 ChatGPT 级别功能所需的主要组件。这些包括生成式人工智能模型、记忆保持功能、模块化 RAG 和多功能能力。每个组件如何贡献于 GenAISys 框架在 图 1.1 中得到了说明:

图 1.1:GenAISys,人工智能控制器和人类角色

图 1.1:GenAISys,人工智能控制器和人类角色

现在我们来定义构成 GenAISys 的 AI 控制器和人类角色的架构。

人工智能控制器

商业就绪的 GenAISys 的核心是一个 人工智能控制器,它根据输入上下文激活定制的 ChatGPT 级别功能。与传统具有预定任务序列的管道不同,人工智能控制器没有固定的顺序,根据每个输入的具体上下文动态地调整任务——如网络搜索、图像分析和文本生成。这种代理上下文驱动的方法使人工智能控制器能够无缝地编排各种组件,确保生成式人工智能模型的有效和连贯性能。

要实现有效的结果,需要大量工作来定制 ChatGPT 级别的 AI 控制器。然而,回报是能够承受现实世界压力并产生实际业务成果的新一代 AI 系统。一个稳固的 AI 控制器生态系统可以支持多个领域的用例:客户支持自动化、销售线索生成、生产优化(服务和制造)、医疗响应支持、供应链优化以及市场将带你去到的任何其他领域!因此,GenAISys 需要一个 AI 控制器来协调多个管道,例如上下文感知来理解提示的意图和记忆保持以支持会话间的连续性。

GenAISys 还必须定义人类角色,这些角色决定了哪些功能和数据可以访问。然而,在我们继续讨论人类角色之前,让我们首先分解驱动 AI 控制器的关键组件。如图1.1所示,生成式 AI 模型、记忆、模块化 RAG 和多功能能力在实现灵活、上下文驱动的协调中发挥着至关重要的作用。让我们探索这些元素如何协同工作来构建一个业务就绪的 GenAISys。我们首先定义生成式 AI 模型的角色。

生成式 AI 的无模型方法

当我们构建一个可持续的 GenAISys 时,我们需要模型互操作性——根据需要替换底层模型的灵活性。生成式 AI 模型应作为系统中的一个组件,而不是作为系统围绕其构建的核心。这样,如果我们的模型被弃用或需要更新,或者我们只是找到一个性能更好的模型,我们可以简单地用另一个更适合我们项目的模型来替换它。

因此,生成式 AI 模型可以是 OpenAI 的 GPT、Google 的 Gemini、Meta 的 Llama、xAI 的 Grok 或任何 Hugging Face 模型,只要它支持所需的任务。理想情况下,我们应该选择一个多用途、多模态模型,它包括文本、视觉和推理能力。Bommasani 等人(2021 年)对这些基础模型进行了全面分析,其范围超越了 LLMs。

生成式 AI 模型有两个主要功能,如图1.2所示:

  • 协调通过确定基于输入需要触发哪些任务。这个输入可以是一个用户提示或来自管道中另一个功能的系统请求。协调功能代理可以触发网络搜索、文档解析、图像生成、RAG、ML 函数、非 AI 函数以及任何集成到 GenAISys 中的其他功能。

  • 执行协调层请求的任务或直接根据输入执行任务。例如,一个简单的查询,如请求美国的首都,可能不需要复杂的功能。然而,对文档分析的要求可能需要几个功能(分块、嵌入、存储和检索)。

图 1.2:一个生成式 AI 模型来协调或执行任务

图 1.2:一个用于协调或执行任务的生成式 AI 模型

注意到图 1.2有一个独特功能。没有箭头指向输入、协调和执行组件。与传统硬编码的线性管道不同,灵活的 GenAISys 组件是无序的。我们构建组件,然后让由协调函数选定的自动化场景动态排序任务。

这种灵活性确保了系统对各种任务的适应性。我们可能无法构建一个解决所有任务的系统,但我们可以构建一个满足公司内广泛任务需求的系统。以下两个示例工作流程说明了 GenAISys 如何根据涉及的角色动态排序任务:

  • 可以配置人类角色,在某些情况下,用户输入执行一个简单的 API 调用以提供直接响应,例如请求一个国家的首都。在这种情况下,生成式 AI 模型直接执行请求。

  • 系统角色可以动态配置,以协调一系列指令,例如先搜索网页,然后总结网页内容。在这种情况下,系统会经过协调过程以生成输出。

可能性无限;然而,所有场景都将依赖于记忆以确保一致、上下文感知的行为。让我们看看记忆。

构建 GenAISys 的记忆

高级生成式 AI 模型,如 OpenAI 的 GPT、Meta 的 Llama、xAI 的 Grok、Google 的 Gemini 以及许多 Hugging Face 变体,无论其具体版本或性能水平如何,都是以上下文驱动的。您将根据您的项目选择模型,但基本规则仍然简单:

无上下文 => 无意义生成

当我们使用 ChatGPT 或任何其他合作者时,我们无需担心,因为上下文记忆由我们处理。我们只需开始对话,然后根据我们获得的响应级别调整提示,事情就会顺利运行。然而,当我们从头开始开发一个使用生成式 AI API 的系统时,我们必须明确构建上下文意识和记忆保留。

在众多可能的记忆保留策略中,有四种方法脱颖而出:

  • 无状态和无记忆会话:向 API 发送请求,并返回响应,没有记忆保留功能。

  • 短期记忆会话:在会话期间,请求和响应之间的交换存储在记忆中,但不会超出会话范围。

  • 多个会话的长期记忆:请求和响应之间的交换存储在记忆中,并在会话结束后被记住。

  • 多个跨主题会话的长期记忆:此功能将多个会话的长期记忆链接到其他会话。每个会话都分配了一个角色:系统或多个用户。此功能在 ChatGPT 等平台上不是标准功能,但在组织内部的流程管理中至关重要。

图 1.3总结了这四种记忆架构。我们将在接下来的章节上下文意识和记忆保持中,使用 GPT-4o 在 Python 中演示每个配置。

图 1.3:四种不同的 GenAISys 内存配置

图 1.3:四种不同的 GenAISys 内存配置

这四种记忆类型可以作为开发 GenAISys 时的起点,根据需要可以进一步扩展。然而,实际实现通常需要额外的功能,包括以下内容:

  • 人类角色来定义可以访问会话历史或多个主题的会话集的用户或用户组。这将使我们超越 ChatGPT 级别的平台。我们将在第二章中介绍这一方面,构建生成式 AI 控制器

  • 存储策略来定义我们需要存储什么,以及我们需要丢弃什么。我们将在第第三章中介绍存储策略,并在第三章中进一步探讨这个概念,即将动态 RAG 集成到 GenAISys 中

在生成模型中,两种关键的记忆类别之间有本地的区别:

  • 语义记忆,包含如硬科学等事实

  • 情景记忆,包含个人时间戳记忆,如时间中的个人事件和商务会议

我们可以看到,构建 GenAISys 的内存需要仔细的设计和深思熟虑的开发来实现 ChatGPT 级别的记忆和额外的内存配置,如长期、跨主题会话。然而,这个高级记忆系统的最终目标却是增强模型的上下文意识。虽然像 GPT-4o 这样的生成式 AI 模型具有内置的上下文意识,但要扩展我们正在构建的以上下文驱动的系统(如 GenAISys)的范围,我们需要集成高级 RAG 功能。

RAG 作为一个多功能的代理协同调度器

在本节中,我们解释了在 GenAISys 内部使用 RAG 进行三个核心功能的动机:

  • 知识检索:检索有针对性的、细微的信息

  • 上下文窗口优化:工程优化的提示

  • 多功能能力的代理调度:动态触发功能

让我们从知识检索开始。

1. 知识检索

生成式 AI 模型在揭示它们所学习的参数化知识方面表现出色,这些知识嵌入在其权重中。这种知识是在训练期间学习的,并嵌入到 GPT、Llama、Grok 和 Gemini 等模型中。然而,当没有向模型提供更多数据时,这种知识就停止在截止日期。在那个时刻,为了更新或补充它,我们有两个选择:

  • 隐式知识:微调模型,以便将更多训练知识添加到其权重(参数化)。如果你正在处理每天都会变化的数据,如天气预报、新闻源或社交媒体消息,这个过程可能会很具挑战性。如果微调过程对你的数据效果不佳,这也伴随着成本和风险。

  • 显式知识:将数据存储在文件中或将数据嵌入到向量存储中。知识将因此结构化、可访问、可追溯和更新。然后我们可以使用高级查询检索信息。

这里需要特别注意的是,没有动态显式知识的支持,静态隐式知识无法有效扩展。更多内容将在后续章节中介绍。

2. 上下文窗口优化

生成式 AI 模型正在扩展上下文窗口的边界。例如,在撰写本文时,以下为支持的上下文长度:

  • Llama 4 Scout:1,000 万个标记

  • Gemini 2.0 Pro 实验:2,000,000 个标记

  • Claude 3.7 诗篇:200,000 个标记

  • GPT-4o:128,000 个标记

虽然这些大的上下文窗口令人印象深刻,但在标记成本和计算方面可能会很昂贵。此外,主要问题是当上下文变得过大时,它们的精度会降低。而且,我们不需要最大的上下文窗口,只需要最适合我们项目的那个。这可以证明在必要时实施 RAG 以优化项目是有道理的。

RAG 的分块过程将大型内容拆分为更细致的标记组。当我们嵌入这些块时,它们变成了可以存储和从向量存储中高效检索的向量。这种方法确保我们只为每个任务使用最相关的上下文,最小化标记使用并最大化响应质量。因此,我们可以依赖生成式 AI 的参数化隐式知识能力,以及 RAG 在向量存储中的大量显式非参数数据。我们可以进一步扩展 RAG 并将其用作编排者。

3. 多功能能力的代理编排者

AI 控制器通过生成式 AI 模型与 RAG 互通。RAG 用于通过灵活的指令范围增强模型的输入。现在,使用 RAG 检索指令可能一开始看起来有些反直觉——但想想看。如果我们把指令存储为向量,并为一项任务检索最佳集合,我们就能得到一种快速、灵活的方法来启用代理功能,生成有效结果,并避免每次更改我们希望其表现的行为的指令策略时都需要微调模型。

这些指令作为优化的提示,针对当前任务量身定制。从这个意义上说,RAG 成为了 AI 系统编排层的一部分。如 图 1.4 所示,Pinecone 这样的向量存储可以存储并返回此功能信息:

图 1.4:RAG 编排功能

图 1.4:RAG 编排功能

这些场景的编排通过以下方式执行:

  • 场景检索:AI 控制器将从向量数据库(如 Pinecone)接收结构化指令(场景),这些指令是根据用户的查询进行适配的

  • 动态任务激活:每个场景指定了一系列任务,例如网络搜索、机器学习算法、标准 SQL 查询或我们需要的任何功能

将经典功能和机器学习功能添加到 GenAISys 中,可以显著增强其功能。GenAISys 的模块化架构使得这种多功能方法有效,如下面的用例所示:

  • 网络搜索进行实时搜索以增强输入

  • 文档分析以处理文档并填充向量存储库

  • 文档搜索从向量存储库中检索处理过的文档的部分

  • 机器学习,例如 K-means 聚类KMC)用于分组数据,以及 k 近邻KNN)用于相似性搜索

  • SQL 查询以在结构化数据集上执行基于规则的检索

  • 您项目或工作流程所需的其他任何功能

RAG 仍然是 GenAISys 的一个关键组件,我们将在 第三章 中将其构建到我们的 GenAISys 中,将动态 RAG 集成到 GenAISys 中。在 第三章**将动态 RAG 集成到 GenAISys 中 中,我们还将增强系统的多功能特性。

现在我们将转向人类角色,它们是任何 GenAISys 的骨架。

人类角色

与公众普遍的看法相反,GenAISys(如 ChatGPT 平台)的成功部署和运营在其整个生命周期中高度依赖于人类参与。虽然这些工具可能看起来可以轻松处理复杂任务,但在幕后有多个层次的人类专业知识、监督和协调,使得它们能够平稳运行。

软件专业人员必须首先设计架构,处理大量数据集,并在配备尖端计算资源的百万美元服务器上微调系统。部署后,需要大型团队来监控、验证和解释系统输出——持续适应错误、新兴技术和监管变化。此外,当涉及到在组织内部部署这些系统时——无论是在企业内部网、面向公众的网站、研究环境还是学习管理系统——需要跨多个领域的跨职能协调努力。

这些任务需要高水平的专业知识和合格的团队。因此,人类不仅不可替代,而且是至关重要的!他们是他们创建和维护的 AI 系统的建筑师、监督者、馆长和守护者。

GenAISys 的实施和管理团队

实施 GenAISys 需要技术技能和团队合作来获得最终用户的支持。这是 AI 控制器设计、用户角色和期望之间的协作挑战。对于任何认为部署现实世界 AI 系统只是获取模型——如最新的 GPT、Llama 或 Gemini——的人来说,仔细查看所需资源将揭示真正的挑战。可能需要大量的人力资源来开发、部署和维护 AI 系统。当然,并非每个组织都需要所有这些角色,但我们必须认识到涉及的技能范围,如下所示:

  • 项目经理PM

  • 产品经理

  • 项目经理

  • 机器学习工程师MLE)/数据科学家

  • 软件开发员/后端工程师BE

  • 云工程师CE

  • 数据工程师DE)和隐私经理

  • UI/UX 设计师

  • 合规和监管官员

  • 法律顾问

  • 安全工程师SE)和安全官

  • 每个特定部署领域的主题专家

  • 质量保证工程师QAE)和测试员

  • 技术文档编写员

  • 系统维护和支持技术人员

  • 用户支持

  • 训练员

这些只是例子——仅足够展示在构建和运营一个全规模 GenAISys 中涉及多少不同的角色。图 1.5显示,设计和实施 GenAISys 是一个持续的过程,每个阶段都需要人力资源。

图 1.5:GenAISys 生命周期

图 1.5:GenAISys 生命周期

我们可以看到,GenAISys 生命周期是一个永无止境的过程:

  • 业务需求将随着市场约束不断演变

  • GenAISys的设计必须随着每个业务转变而适应

  • AI 控制器规范必须适应技术进步

  • 实施必须适应不断变化的企业规范

  • 用户反馈将推动持续改进

现实世界的 AI 严重依赖人类能力——那种 AI 本身无法复制的情境和技术理解。AI 可以有效地自动化广泛的任务。但正是人类带来了与真实业务目标对齐所需的深刻洞察。

让我们进一步探讨,看看 RACI 热图来展示为什么人类是 GenAISys 的一个关键组成部分。

GenAISys RACI

组织 GenAISys 项目需要的人力资源远远超出了仅靠 AI 自动化所能提供的。RACI是一个责任分配矩阵,通过确定谁负责(Responsible)、负责(Accountable)、咨询(Consulted)和通知(Informed),帮助定义每个任务或决策的角色和责任。RACI 非常适合管理构建 GenAISys 的复杂性。它为系统生命周期中所需的人类角色增长列表增添了结构,并为协调他们的参与提供了一个实用框架。

与任何复杂项目一样,在 GenAISys 上工作的团队需要在多个学科之间进行协作,RACI 有助于定义谁做什么。RACI 中的每个字母代表一种特定的角色类型:

  • R(责任人):积极从事任务的人。他们负责工作的适当完成。例如,MLE 可能负责使用机器学习算法处理数据集。

  • A(问责人):对任务的成功或失败负责的人。他们监督其他人负责执行的任务。例如,产品负责人PO)必须确保 MLE 的任务按时并符合规格完成。如果没有,PO 将对失败负责。

  • C(咨询者):向团队中的其他人提供输入、建议和反馈以帮助他们的人。他们不负责执行工作。例如,零售领域的专家可能帮助 MLE 理解机器学习算法的目标。

  • I(知情者):被保持在任务进度或结果循环中的人。他们不参与任务,但只想简单地了解或需要做出决定。例如,数据隐私官DPO)可能希望了解系统的安全功能。

RACI 热图通常包含项目中每个人类角色的图例。让我们构建一个包含以下角色的热图:

  • MLE 开发和集成 AI 模型

  • 数据工程师DE)设计数据管理管道

  • BE 构建 API 交互

  • 前端工程师FE)开发面向最终用户的功能

  • UI/UX 设计师设计用户界面

  • CE/DevOps 工程师管理云基础设施

  • 提示工程师PE)设计最佳提示

  • SE 处理安全数据和访问

  • DPO 管理数据治理和法规遵从性

  • 法律/合规官LC)审查项目的法律范围

  • QAE 测试 GenAISys

  • 产品负责人PO)定义产品的范围和规模

  • 项目经理PM)协调资源和时间表

  • 技术文档编写者TW)制作文档

  • 供应商经理VM)与外部供应商和服务提供商沟通

并非每个 GenAISys 项目都会包含所有这些角色,但根据项目的范围和规模,其中许多角色将是关键的。现在,让我们列出在典型的生成式 AI 项目中定义的角色的关键职责:

  • 模型:AI 模型开发

  • 控制器:API 和多模态组件的编排

  • 管道:数据处理和集成工作流程

  • UI/UX:用户界面和体验设计

  • 安全:数据保护和访问控制

  • DevOps:基础设施、扩展和监控

  • 提示:设计和优化模型交互

  • QA:测试和质量保证

我们已经定义了角色和任务。现在,我们可以展示它们如何映射到现实世界场景。图 1.6展示了 GenAISys 的一个示例 RACI 热图。

图 1.6:RACI 热图示例

图 1.6:RACI 热图示例

例如,在这个热图中,MLE 有以下职责:

  • R)对模型负责,该模型可能是 GPT-4o。

  • R)对模型的提示负责和(A)负责

  • C)作为控制器、管道和测试(QA)的专家咨询

  • I)了解 UI/UX、安全和 DevOps

我们可以用一条简单的规则来总结 GenAISys:

没有人 -> 没有系统!

我们可以看到,我们在整个 GenAISys 的生命周期中都是必要的,从设计到维护和支持,包括持续进化以跟上用户反馈。人类已经在这里,并将长期存在!接下来,让我们探索 GenAISys 可以解锁的商业机会。

商业机会和范围

更多的时候,我们无法获得 OpenAI、Meta、xAI 或 Microsoft Azure 等不可思议的数十亿美元资源来构建类似 ChatGPT 的平台。上一节展示了,在类似 ChatGPT 的看似简单、无缝的界面之下,有一个复杂的、昂贵的基础设施层、罕见的人才以及持续改进和演变,这些都需要只有大公司才能负担的资源。因此,从一开始就选择一条更聪明的路径,确定我们处于哪个项目类别,并利用现有模块和库的力量来构建我们的 GenAISys。无论用例如何,如营销、金融、生产或支持,我们都需要找到合适的范围和规模来实现一个现实的 GenAISys。

任何 GenAISys 的第一步是定义项目的目标(机会),包括其范围和规模,正如我们提到的。在这一步中,你将评估风险,如成本、机密性和资源可用性(风险管理)。

我们可以根据我们的资源、我们的目标、用例的复杂性和我们的预算,将 GenAISys 项目分为三种主要业务实现类型。这些在图 1.7中展示:

  • 混合方法:利用现有的 AI 平台

  • 小范围和规模:一个专注的 GenAISys

  • 全面生成式多智能体 AI 系统:一个完整的 ChatGPT 级生成式 AI 平台

图 1.7:三个主要的 GenAISys 业务实现

图 1.7:三个主要的 GenAISys 业务实现

让我们从混合方法开始,这是一种在不过度建设的情况下实现业务成果的实用方法。

混合方法

混合框架允许你通过结合现成的 SaaS 平台和仅在必要时定制的组件(如网络搜索和数据清洗)来最小化开发成本和时间。这样,你可以在不从头开始开发一切的情况下利用生成式 AI 的力量。让我们通过关键特性和一些示例用例来探讨。

关键特性

  • 依赖于经过验证的云服务,如 OpenAI 的 GPT API、AWS、Google AI 或 Microsoft Azure。这些平台提供了核心的生成功能。

  • 通过整合特定领域的向量存储和你的组织专有的数据集来定制你的项目。

  • 专注于开发目标功能,例如客户支持自动化或营销活动生成。

用例示例

  • 实施特定领域的向量存储以处理法律、医疗或产品相关的客户查询。

  • 在社交媒体平台上构建具有实时功能的客户支持系统。

这个类别提供了以更少的成本和开发努力做更多的事情的能力——在成本和开发努力方面。一个混合系统可以是独立的 GenAISys,也可以是更大生成式 AI 平台内的子系统,其中不需要全面开发。现在让我们看看一个小范围、小规模的 GenAISys 如何能带我们更进一步。

小范围和规模

一个小规模的 GenAISys 可能包括一个智能的、由 GenAI 驱动的 AI 控制器,连接到向量存储。这种配置允许系统检索数据、触发指令并调用额外的功能,如网络搜索或机器学习——而不需要全规模的基础设施。

关键特性

  • 一个明确定义的盈利系统,旨在通过最优的开发时间和成本实现合理的目标。

  • 人工智能控制器协调指令场景,进而触发 RAG、网络搜索、图像分析和符合你需求的额外自定义任务。

  • 重点是高优先级、高效能的特性

用例示例

  • 一个用于文档检索和摘要的 GenAISys,可以对任何类型的文档进行细微的分析,通过分块和嵌入的内容进行。

  • 通过实时网络搜索增强 GPT 或 Llama 等模型,以绕过其数据截止日期——非常适合需要不断微调的应用,如天气预报或新闻监控。

这个类别将我们带入了混合方法的更高层次,同时仍然保持对中小型企业或大型组织内部部门来说既现实又可管理的状态。

全规模 GenAISys

如果你在一个拥有大量预算和先进基础设施的组织中的专家团队工作,这个类别适合你。你的团队可以构建一个全规模的 GenAISys,开始接近 ChatGPT 级平台的性能。

关键特性

  • 一个完整的 AI 控制器,可以管理和协调复杂的自动化工作流程,包括 RAG、指令场景、多模态功能和实时数据。

  • 需要大量的计算资源和高度熟练的开发团队

将本书中构建的 GenAISys 视为一个 alpha 版本——一个可以克隆、配置并在组织中的任何地方按需部署的模板。

用例示例

  • GenAISys 已经在医疗保健领域出现,用于协助患者诊断和疾病预防。例如,巴黎的居里研究所拥有一个非常先进的 AI 研究团队:institut-curie.org/.

  • 许多大型组织已经开始实施 GenAISys 用于欺诈检测、天气预报和法律专业知识。

您可以加入这些大型组织之一,它们拥有构建可持续 GenAISys 的资源,无论是在云平台上、本地服务器上还是在两者上。

这三个类别——混合型、小规模和大规模——为构建 GenAISys 提供了不同的路径,具体取决于您组织的目标、预算和技术能力。在本书中,我们将探讨构成 GenAISys 的关键组件。到结束时,您将能够为这些类别中的任何一个做出贡献,并为您正在工作的项目提供现实、技术基础的建议。

现在让我们揭开盖子,开始构建代码中的情境意识和记忆保持。

情境意识和记忆保持

在本节中,我们将开始使用 Python 实现情境意识和记忆保持的模拟,以说明在 构建 GenAISys 的记忆 部分中引入的概念。目标是展示管理情境和记忆的实用方法——这两个功能随着生成式 AI 平台的演变变得越来越重要。

打开位于 GitHub 存储库 chapter01 文件夹中的 Contextual_Awareness_and_Memory_Retention.ipynb 文件(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。您会看到笔记本被分为五个主要部分:

  • 设置环境,构建可重用函数,并将它们存储在存储库的 commons 目录中,这样我们就可以在整本书中必要时重复使用它们

  • 无状态和无记忆会话具有语义和情景记忆

  • 短期记忆会话用于会话期间的情境意识

  • 跨多个会话的长期记忆用于跨不同会话的情境保留

  • 多个跨主题会话的长期记忆,扩展长期记忆覆盖以前分开的会话

目标是明确地展示每种记忆类型的过程。这些示例目前故意保持手动,但它们将被自动化并由我们在下一章开始构建的 AI 控制器管理。

由于生成模型的概率性质,您可能会在不同的运行中观察到相同的提示符产生不同的输出。请确保在单个会话中运行整个笔记本,因为在这个笔记本中,内存保留在不同单元格中是明确的。在第二章中,此功能将变得持久并由 AI 控制器完全管理

第一步是安装环境。

设置环境

我们需要一个commons目录来存放我们的 GenAISys 项目。此目录将包含本书 GitHub 存储库中所有笔记本所需的主要模块和库。动机是专注于设计维护和支持的系统。因此,通过将主要模块和库分组在一个目录中,我们可以专注于需要我们注意的资源,而不是在每个笔记本中重复设置步骤。此外,本节将作为本书 GitHub 存储库中所有笔记本的参考点。我们将只描述下载每个资源一次,然后在全书各处重用它们来构建我们的教育 GenAISys。

因此,我们可以从commons目录下载笔记本资源并安装需求。

第一步是下载grequests.py,这是一个我们将全书使用的实用脚本。它包含一个函数,可以直接从 GitHub 下载我们需要的文件:

!curl -L https://raw.githubusercontent.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/master/commons/grequests.py --output grequests.py 

快速提示:使用AI 代码解释器快速复制功能增强您的编码体验。在下一代 Packt Reader 中打开此书。点击复制按钮

1)快速将代码复制到您的编码环境,或点击解释按钮

2)让 AI 助手为您解释代码块。

一个白色背景上带有黑色文字的 AI 生成内容可能不正确。

下一代 Packt Reader随本书免费赠送。扫描二维码或访问packtpub.com/unlock,然后使用搜索栏通过名称查找此书。请仔细检查显示的版本,以确保您获得正确的版本。

一个白色背景上的二维码 AI 生成内容可能不正确。

该脚本的目的是通过调用grequests中的download函数从存储库的任何目录下载文件:

import sys
import subprocess 
from grequests import download
download([directory],[file]) 

此函数使用curl命令从指定的目录和文件名下载文件。它还包括基本的错误处理,以防命令执行失败。

代码首先导入subprocess来处理路径和命令。download函数包含两个参数:

def download(**directory**, **filename**): 
  • directory:存储文件的 GitHub 存储库子目录

  • filename:要下载的文件名

然后定义 GitHub 存储库的基本 URL,指向我们将需要的原始文件:

base_url = 'https://raw.githubusercontent.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/main/' 

我们现在需要使用directoryfilename参数定义文件的完整 URL:

file_url = f"{base_url}{directory}/{filename}" 

函数现在定义了curl命令:

curl_command = f'curl -o {filename} {file_url}' 

最后,执行download命令:

subprocess.run(curl_command, check=True, shell=True) 
  • check=Truecurl命令失败时激活异常

  • shell=True通过 shell 运行命令

使用try-except块来处理错误:

try:
    # Prepare the curl command with the Authorization header
    curl_command = f'curl -o {filename} {file_url}'
    # Execute the curl command
    subprocess.run(curl_command, check=True, shell=True)
    print(f"Downloaded '{filename}' successfully.")
except subprocess.CalledProcessError:
    print(f"Failed to download '{filename}'. Check the URL and your internet connection") 

我们现在有一个独立的下载脚本,将在整本书中使用。让我们继续下载本程序所需的资源。

下载 OpenAI 资源

本笔记本需要三个资源:

  • requirements01.py用于安装我们想要的精确的 OpenAI 版本

  • openai_setup.py用于初始化 OpenAI API 密钥

  • openai_api_py包含一个可重用的函数来调用 GPT-4o 模型,因此你不需要在多个单元格或笔记本中重写相同的代码

我们将在整本书中重复使用相同的函数来执行标准的 OpenAI API 调用。如果你想重新访问安装过程,可以随时回到这一节。当需要时,其他场景将被添加到commons目录中。

我们可以使用download()函数下载这些文件:

from grequests import download
download("commons","requirements01.py")
download("commons","openai_setup.py")
download("commons","openai_api.py") 

第一资源是requirements01.py

安装 OpenAI

requirements01.py确保安装了特定的 OpenAI 库版本,以避免与其他已安装库冲突。因此,代码会卸载现有版本,强制安装请求的指定版本,并验证结果。该函数执行安装并带有错误处理:

def run_command(command):
    try:
        subprocess.check_call(command)
    except subprocess.CalledProcessError as e:
        print(f"Command failed: {' '.join(command)}\nError: {e}")
        sys.exit(1) 

函数的第一步是卸载当前存在的 OpenAI 库(如果有的话):

print("Installing 'openai' version 1.57.1...")
run_command([sys.executable, "-m", "pip", "install", "--force-reinstall", "openai==1.57.1"]) 

函数随后安装 OpenAI 的特定版本:

run_command(
    [
        sys.executable, "-m", "pip", "install", 
        **"--force-reinstall"****,** **"openai==1.57.1"**
    ]
) 

最后,函数会验证 OpenAI 是否正确安装:

try:
    import openai
    print(f"'openai' version {openai.__version__} is installed.")
except ImportError:
    print("Failed to import the 'openai' library after installation.")
    sys.exit(1) 

函数末尾的输出应如下所示:

'openai' version 1.57.1 is installed. 

我们现在可以初始化 OpenAI API 密钥。

OpenAI API 密钥初始化

在笔记本中初始化 OpenAI API 密钥有两种方法:

  1. 使用 Google Colab secrets:在 Google Colab 的左侧面板中点击密钥图标,如图 1.8 所示,然后点击添加新密钥,并添加你将在笔记本中使用的密钥变量名称:

图 1.8:添加新的 Google 密钥

图 1.8:添加新的 Google 密钥

然后,我们可以在openai_setup.py中的openai_setup函数中调用它来使用 Google 的函数初始化密钥:

# Import libraries
import openai
import os
from google.colab import userdata
# Function to initialize the OpenAI API key
def initialize_openai_api():
# Function to initialize the OpenAI API key
def initialize_openai_api():
    # Access the secret by its name
    API_KEY = userdata.get('API_KEY')

    if not API_KEY:
        raise ValueError("API_KEY is not set in userdata!")

    # Set the API key in the environment and OpenAI
    os.environ['OPENAI_API_KEY'] = API_KEY
    openai.api_key = os.getenv("OPENAI_API_KEY")
    print("OpenAI API key initialized successfully.") 

如果google_secrets设置为True,则激活此方法:

google_secrets=True
if google_secrets==True:
    import openai_setup
    openai_setup.initialize_openai_api() 
  • 自定义安全方法:你也可以选择自定义方法,或者通过设置google_secretsFalse,取消注释以下代码,并直接输入你的 API 密钥,或者任何你选择的方法:

    if google_secrets==False: # Uncomment the code and choose any method you wish to initialize the API_KEY
        import os
        #API_KEY=[YOUR API_KEY]
        #os.environ['OPENAI_API_KEY'] = API_KEY
        #openai.api_key = os.getenv("OPENAI_API_KEY")
        #print("OpenAI API key initialized successfully.") 
    

在这两种情况下,代码将创建一个环境变量:

os.environ['OPENAI_API_KEY'] = API_KEY
openai.api_key = os.getenv("OPENAI_API_KEY") 

OpenAI API 密钥已初始化。我们现在将导入一个自定义的 OpenAI API 调用。

OpenAI API 调用

接下来的目标是创建一个在openai_api.py中的 OpenAI API 调用函数,我们可以在两行中导入它:

#Import the function from the custom OpenAI API file
import openai_api
from openai_api import make_openai_api_call 

因此,该函数在调用时构建以接收四个变量并无缝显示它们:

# API function call
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role)
print(response) 

此函数中的参数如下:

  • input: 包含输入(用户或系统),例如,夏威夷在哪里?

  • mrole: 定义系统的角色,例如,你是一位地质学专家。 或简单地 系统。

  • mcontent: 是我们期望系统成为的内容,例如,你是一位地质学专家。

  • user_role: 定义用户的角色,例如,用户

函数中的代码的第一部分定义了我们将在此笔记本中使用的模型,并创建了一个带有我们发送的参数的 API 调用消息对象:

def make_openai_api_call(input, mrole,mcontent,user_role):
    # Define parameters
    gmodel = "gpt-4o"
    # Create the messages object
    messages_obj = [
        {
            "role": mrole,
            "content": mcontent
        },
        {
            "role": user_role,
            "content": input
        }
    ] 

然后我们为这个笔记本定义 API 调用参数的字典:

# Define all parameters in a dictionary named params:
    params = {
        **"temperature"**: 0,
        **"max_tokens"**: 256,
        **"top_p"**: 1,
        **"frequency_penalty"**: 0,
        **"presence_penalty"**: 0
    } 

字典参数如下:

  • temperature: 控制响应的随机性。0 将产生确定性响应。更高的值(例如,0.7)将产生更具创造性的响应。

  • max_tokens: 限制响应的最大标记数。

  • top_p: 产生核采样。它通过从累积概率为 1 的顶部标记中进行采样来控制响应的多样性。

  • frequency_penalty: 通过减少标记的重复来避免冗余。0 将不应用任何惩罚,而 2 则应用强烈的惩罚。在这种情况下,由于 OpenAI 模型的高性能,0 已经足够了。

  • presence_penalty: 通过惩罚现有内容来鼓励新内容,以避免冗余。它适用于与频率惩罚相同的值。在这种情况下,由于 OpenAI 模型的高性能,它不需要这种控制。

然后我们初始化 OpenAI 客户端以创建 API 调用的实例:

 client = OpenAI() 

最后,我们通过发送模型、消息对象和展开的参数来执行 API 调用:

 # Make the API call
    response = client.chat.completions.create(
        model=gmodel,
        messages=messages_obj,
        **params  # Unpack the parameters dictionary
    ) 

函数通过返回我们需要的 API 响应内容结束:

 #Return the response
    return response.choices[0].message.content 

这个函数将帮助我们专注于 GenAISys 架构,而无需在笔记本中加载重复的库和函数。

在笔记本中,我们有以下内容:

  • 程序将输入、角色和消息内容提供给函数

  • messages_obj 包含对话历史

  • API 行为的参数定义在 params 字典中

  • 使用 OpenAI 客户端对 OpenAI 模型进行 API 调用

  • 函数仅返回 AI 的响应内容

GenAISys 将包含许多组件——包括一个生成模型。你可以选择适合你项目的模型。在这本书中,模型仅用于教育目的,不作为认可或推荐。

现在我们构建并运行一个无状态和无记忆的会话。

1. 无状态和无记忆会话

如果我们只想进行一次性和临时的交换,且请求之间没有存储信息,那么无状态和无记忆的会话是有用的。本节中的示例既无状态又无记忆:

  • 无状态 表示每个请求都将独立处理

  • 无记忆意味着没有机制来记住过去的交流

让我们从语义查询开始。

语义查询

这个请求期望一个纯粹语义、事实性的响应:

uinput = "Hawai is on a geological volcano system. Explain:"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user" 

现在,我们调用 OpenAI API 函数:

# Function call
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role)
print(response) 

如您所见,响应完全是语义性的:

Hawaii is located on a volcanic hotspot in the central Pacific Ocean, which is responsible for the formation of the Hawaiian Islands. This hotspot is a region where magma from deep within the Earth's mantle rises to the surface, creating volcanic activity… 

下一个查询是情景式的。

情景查询带有语义背景

本例中的查询是情景式的,并借鉴了个人经验。然而,由于对夏威夷的描述,存在语义背景。以下是一条相当诗意的消息:

# API message
uinput = "I vividly remember my family's move to Hawaii in the 1970s, how they embraced the warmth of its gentle breezes, the joy of finding a steady job, and the serene beauty that surrounded them. Sum this up in one nice sentence from a personal perspective:"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user" 

mcontent 从语义查询示例(“你是地质学专家”)中重用,但在这个案例中,它对响应的影响并不大。由于用户输入非常个人化和叙事驱动,系统提示的作用很小。

如果需要,我们可以在函数调用之前插入外部信息。例如,我们可以添加来自另一个来源的信息,比如当天从家庭成员那里收到的短信:

text_message='I agree, we had a wonderful time there.'
uninput=text_message+uinput
text_message="Hi, I agree, we had a wonderful time there." 

现在,我们调用函数:

# Call the function
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role)
print(response) 

我们看到响应主要是情景式的,并包含一些语义信息:

Moving to Hawaii in the 1970s was a transformative experience for my family, as they found joy in the island's gentle breezes, the security of steady employment, and the serene beauty that enveloped their new home. 

无状态和无记忆验证

我们之前没有添加任何记忆保留功能,使得对话无状态。让我们检查一下:

# API message
uinput = "What question did I just ask you?"
mrole = "system"
mcontent = "You already have this information"
user_role = "user" 

当我们调用函数时,我们的对话将被遗忘:

# API function call
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role
)
print(response) 

输出确认会话是无记忆的:

I'm sorry, but I can't recall previous interactions or questions. Could you please repeat your question? 

API 调用是无状态的,因为 OpenAI API 不会在请求之间保留记忆。如果我们直接使用 ChatGPT,交换会被保存在那个会话中。这对实现有重大影响。这意味着我们必须构建自己的记忆机制,以赋予 GenAISys 有状态的行为。让我们从第一层:短期记忆开始。

2. 短期记忆会话

本节的目标是使用两步过程模拟短期记忆会话:

  1. 首先,我们从一个用户输入到一个响应的会话:

用户输入 => 生成模型 API 调用 => 响应

为了实现这一第一步,我们将会话运行到响应:

uinput = "Hawai is on a geological volcano system. Explain:"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user"
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role)
print(response) 

响应的输出存储在 response 中:

"Hawaii is part of a volcanic system known as a hotspot, which is a region of the Earth's mantle where heat rises as a thermal plume from deep within the Earth. This hotspot is responsible for the formation of the Hawaiian Islands. Here's how the process works:…" 
  1. 下一步是将之前的交互输入到下一个提示中,并附带一个后续问题:

    • 解释情况:当前对话会话为:

    • 添加用户的初始输入:夏威夷位于一个地质火山系统。解释:

    • 添加我们在上一个调用中获得的响应

    • 添加用户的新的输入:用最多 20 个字总结你之前的回答。

这里的目标是压缩会话日志。我们并不总是需要压缩对话,但在较长的会话中,大的上下文窗口会迅速堆积。这项技术有助于保持令牌计数低,这对成本和性能都很重要。在这个特定案例中,我们只管理一个响应,如果我们想的话,可以保留整个交互在内存中。不过,这个例子介绍了一个有用的习惯,有助于扩展。

一旦提示被组装:

  • 调用 API 函数

  • 显示响应

场景在代码中得到了说明:

ninput = "Sum up your previous response in a short sentence in a maximum of 20 words."
uinput = (
    "The current dialog session is: " +
    uinput +
    response +
    ninput
)
response = openai_api.make_openai_api_call(
    uinput, mrole, mcontent, user_role
)
print("New response:", "\n\n", uinput, "\n", response) 

输出提供了一个很好的、简短的对话摘要:

New response: Hawaii's islands form from volcanic activity over a stationary hotspot beneath the moving Pacific Plate. 

这个功能在这里并不是严格必要的,但它为我们设置了在书中稍后遇到的更长时间对话的基础。接下来,让我们构建一个多个会话的长期模拟。

请记住:由于会话目前只保存在内存中,如果笔记本断开连接,对话就会丢失。目前还没有任何内容存储在磁盘或数据库中。

3. 多个会话的长期记忆

在本节中,我们通过从早期会话继续对话来模拟长期记忆。这里的区别在于,我们不仅仅是“记住”单个会话中的对话——我们正在“重用”过去会话的内容来扩展对话。在这个时候,“会话”这个词有了更广泛的意义。在传统的副驾驶场景中,一个用户在一个自包含的会话中与一个模型交互。在这里,我们正在混合会话并支持多个子会话。多个用户可以在共享环境中与模型交互,有效地创建一个具有分支记忆线程的单个全局会话。想象一下,模型就像一个正在进行的 Zoom 或 Teams 会议中的客人。你可以要求 AI 客人参与或保持安静——当它加入时,它可能需要回顾。

为了避免重复过去对话的第一步,我们正在重用我们刚刚运行的短期记忆会话的内容。让我们假设之前的会话已经结束,但我们仍然想从我们离开的地方继续:

session01=response
print(session01) 

输出包含了我们短期记忆会话的最终响应:

Hawaii's islands form from volcanic activity over a stationary hotspot beneath the moving Pacific Plate. 

本节中的过程将在之前的会话基础上构建,类似于你离开一段时间后再次与在线副驾驶进行对话的方式:

保存上一个会话 => 加载上一个会话 => 将其添加到新会话的场景中

让我们先测试一下 API 是否能够自己记住一些东西:

uinput="Is it safe to go there on vacation"
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role
)
print(response) 

输出显示它忘记了我们正在进行的对话:

I'm sorry, but I need more information to provide a helpful response. Could you specify the location you're considering for your vacation? … 

API 忘记了之前的调用,因为无状态 API 不会保留过去的对话。这取决于我们决定在提示中包含什么。我们有几个选择:

  • 我们是否希望以大量消耗令牌的方式记住所有内容?

  • 我们是想总结之前的部分对话还是全部对话?

在一个真实的 GenAISys 中,当输入触发请求时,AI 控制器会决定应用任务的最佳策略。现在的代码将之前会话的上下文和记忆与新的请求关联起来:

ninput = "Let's continue our dialog."
uinput=ninput + session01 + "Would it be safe to go there on vacation?"
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role
)
print("Dialog:", uinput,"\n")
print("Response:", response) 

响应显示系统现在记住了过去的会话,并且有足够的信息提供可接受的输出:

Response: Hawaii is generally considered a safe destination for vacation, despite its volcanic activity. The Hawaiian Islands are formed by a hotspot beneath the Pacific Plate, which creates volcanoes as the plate moves over it. While volcanic activity is a natural and ongoing process in Hawaii, it is closely monitored by the United States Geological Survey (USGS) and other agencies… 

现在我们将构建一个跨不同主题的多个会话的长期模拟。

4. 多个跨主题会话的长期记忆

本节说明了如何将两个单独的会话合并为一个。这不是标准 ChatGPT-like 平台提供的东西。通常,当我们开始一个新的主题时,共乘者只记得当前会话中发生的事情。但在企业环境中,我们可能需要更多的灵活性——特别是在多个用户协作时。在这种情况下,AI 控制器可以被配置为允许用户组查看和合并同一组中其他人生成的会话。

假设我们想要总结两个单独的对话——一个关于夏威夷的火山系统,另一个关于组织到亚利桑那州的地质野外考察。我们首先保存先前的长期记忆会话:

session02=uinput + response
print(session02) 

然后,我们可以从另一个位置,即亚利桑那州,开始一个单独的多用户子会话:

ninput ="I would like to organize a geological visit in Arizona."
uinput=ninput+"Where should I start?"
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role
)
#print("Dialog:", uinput,"\n") 

我们现在期望对亚利桑那州有响应,而夏威夷则被排除在外:

Response: Organizing a geological visit in Arizona is a fantastic idea, as the state is rich in diverse geological features. Here's a step-by-step guide to help you plan your trip:… 

响应是可以接受的。现在,让我们通过结合两个会话并提示系统总结它们来模拟跨多个主题的长期记忆:

session02=response
ninput="Sum up this dialog in a short paragraph:"
uinput=ninput+ session01 + session02
response = openai_api.make_openai_api_call(
    uinput,mrole,mcontent,user_role
)
#print("Dialog:", uinput,"\n")#optional
print("Response:", response) 

系统的输出显示,系统的长期记忆是有效的。我们看到第一部分是关于夏威夷的:

Response: The dialog begins by explaining the formation of Hawaii's volcanic islands as the Pacific Plate moves over a stationary hotspot, leading to active volcanoes like Kilauea…. 

然后响应继续到关于亚利桑那州的段落:

It then transitions to planning a geological visit to Arizona, emphasizing the state's diverse geological features. The guide recommends researching key sites such as the Grand Canyon… 

我们现在已经涵盖了 GenAISys 的核心记忆模式——从无状态和短期记忆到多用户、多主题的长期记忆。现在,让我们总结本章的旅程,并进入下一个层次!

摘要

一个商业就绪的 GenAISys 提供了与 ChatGPT-like 平台相当的功能。它汇集了生成式 AI 模型、代理功能、RAG、记忆保持以及一系列 ML 和非 AI 功能——所有这些都由一个 AI 控制器协调。与传统管道不同,控制器不遵循固定的步骤序列。相反,它动态地编排任务,适应上下文。

GenAISys 通常在 GPT-4o 或最适合您用例的任何模型上运行。但正如我们所见,仅仅访问 API 是不够的。上下文意识和记忆保持是必不可少的。虽然 ChatGPT-like 工具默认提供这些功能,但当我们创建定制系统时,我们必须自己构建它们。

我们探索了四种类型的记忆:无记忆、短期记忆、长期记忆和跨主题记忆。我们还区分了语义记忆(事实)和情景记忆(个人、带时间戳的信息)。上下文意识在很大程度上依赖于记忆——但上下文窗口有局限性。即使我们增加窗口大小,模型仍然可能错过复杂任务中的细微差别。这就是高级 RAG 发挥作用的地方——将内容分解成更小的块,嵌入它们,并将它们存储在 Pinecone 等向量存储中。这扩大了系统可以“记住”并用于推理的内容。

我们还看到,无论 GenAISys 如何先进,没有人类专业知识它就无法运行。从设计到部署、维护和迭代,人在整个系统生命周期中始终至关重要。然后,我们根据可用资源和目标概述了三种现实世界的实施模型:利用现有 AI 平台的混合系统、针对特定商业需求的小规模系统以及为 ChatGPT 级别性能构建的全规模系统。

最后,我们亲自动手——使用 GPT-4o 在 Python 中构建了一系列内存模拟模块。这些示例为下一步奠定了基础:将管理 GenAISys 中的内存、上下文和编排的 AI 控制器。我们现在准备好构建 GenAISys AI 控制器了!

问题

  1. API 生成式 AI 模型如 GPT 是否是 AI 控制器?(是或否)

  2. 无记忆的会话是否记得最后的交流?(是或否)

  3. RAG 是否用于优化上下文窗口?(是或否)

  4. GenAISys 的整个生命周期中人类角色是否重要?(是或否)

  5. AI 控制器能否动态运行任务?(是或否)

  6. 使用有限数量的关键特性构建的小规模 GenAISys 是否?(是或否)

  7. 全规模的类似 ChatGPT 的系统是否需要大量资源?(是或否)

  8. 在多个会话中是否需要长期记忆?(是或否)

  9. 向量存储如 Pinecone 是否支持知识和 AI 控制器功能?(是或否)

  10. GenAISys 是否可以在没有上下文意识的情况下运行?(是或否)

参考文献

进一步阅读

  • Feuerriegel, S.,Hartmann, J.,Janiesch, C.,& Zschech, P. (2023). 生成式人工智能。商业与信息系统工程doi.org/10.1007/s12599-023-00834-7

  • Eloundou 等人 (2023)。GPTs 是 GPTs:大型语言模型对劳动力市场影响潜力的早期观察arxiv.org/abs/2303.10130

    |

    现在解锁此书的独家优惠

    扫描此二维码或访问 packtpub.com/unlock,然后通过书名搜索此书。 | 白色背景上的二维码 AI 生成的内容可能不正确。 |

    注意:在开始之前,请准备好您的购买发票。

第二章:构建生成式 AI 控制器

一个生成式 AI 系统GenAISys)的控制器需要两个关键组件:一个对话代理和一个编排器。对话代理由生成式 AI 模型驱动,与人类用户和系统进程进行交互。另一方面,编排器是一组生成式 AI 和非 AI 功能,例如管理用户角色、内容生成、激活机器学习算法以及运行经典查询。我们需要这两个组件来构建一个功能性的 GenAISys。

如果我们仔细检查这个架构,我们会看到软件编排器和用户界面可以追溯到第一台计算机。任何具有甚至基本功能的操作系统都有编排器,可以触发磁盘空间警报、内存使用和其他数百个功能。今天的用户界面直观且具有事件驱动功能,但在高层次上,GenAISys 的底层架构仍然反映了数十年的软件设计原则。那么,什么是经典软件控制器与 GenAISys 控制器之间的区别呢?

我们可以用一个词来总结这种差异:适应性。在经典软件控制器中,一系列任务或多或少是硬编码的。但在 GenAISys 中,用户界面是一个灵活的对话 AI 代理,其背后的生成式 AI 模型经过预训练,可以无需额外编码对广泛的请求做出响应。此外,编排器也没有锁定在静态流程中;它可以根据用户(人类或系统)的提示修改它触发的任务。

在本章中,我们将采取动手实践的方法来构建一个基于前一章中定义的 GenAISys 架构的定制 GenAISys。我们首先将定义我们的 AI 控制器结构,在 Python 中将它分为两部分——对话代理和编排器——并探讨这两个部分如何交互。然后,我们将使用 GPT-4o 构建对话代理。我们将自动化从第一章中提到的上下文感知和记忆保持功能。我们的系统将支持短期和长期记忆,以及多用户和跨会话功能——将其推向标准共飞行员通常提供的服务之外。

最后,我们将构建一个 AI 控制器的结构来解释用户输入并触发响应场景。响应将根据 AI 控制器将分析和管理的上下文进行情感分析或语义(硬科学)分析。我们的定制 GenAISys 将为特定领域的 RAG 奠定基础,这是标准 ChatGPT 级系统在处理大量数据时无法提供的,尤其是在每日数据集更新案例中,例如产品或服务的每日销售。到本章结束时,你将了解如何构建 GenAISys AI 控制器的基石,我们将在整本书中对其进行增强。

总结来说,本章涵盖了以下主题:

  • AI 控制器的架构

  • AI 会话代理及其工作流程架构

  • 在代码中实现短期和长期记忆会话的存储

  • AI 协调器和意图功能架构

  • 创建一个包含指令场景的 GenAI 场景库

  • 使用向量搜索处理输入以协调指令

  • 使用 GPT-4o 分析处理输入以协调指令

  • 根据输入使用多功能协调器选择和执行任务

让我们从定义 AI 控制器的架构开始。

AI 控制器的架构

我们将继续按照在 图 1.1 中定义的架构实现 GenAISys 的架构,第一章。另一方面,图 2.1 带我们进一步了解了 GenAISys 的底层功能。

图 2.1:定义要构建的功能

图 2.1:定义要构建的功能

在上一章中,我们确定了人类角色的必要性,前面的图也认可了这一点。无论构建块(模型或框架)多么先进,我们都是 GenAISys 的核心。我们的第一个任务是利用人类的创造力,找到有效的方法来实施 GenAISys 控制器。GenAISys 需要人类的创造力、判断和技术决策。在 ChatGPT、Gemini 和 Microsoft Copilot 等无缝协同驾驶员的底层,隐藏着复杂的 AI 和非 AI 逻辑层。如果我们想构建自己的 ChatGPT 类似系统,我们需要人类付出辛勤的努力!

我们将构建两个独立的程序:

  • 使用 GPT-4o 实现的 会话代理,它支持短期和长期记忆。这将帮助我们加强多个交流中的上下文意识。它与 图 2.1 中的功能 F3 保持一致。

  • 一个 AI 控制器协调器,它也将使用 GPT-4o 分析用户输入,搜索指令库,用适当的指令增强输入,并运行指令中的函数(们)。

在本章中,我们将关注两个场景:情感分析和语义(硬科学)分析,这对应于我们架构中的功能 F1F2。功能 F4F5 将在第三章第三章中添加。

虽然这些示例是为 OpenAI 的 API 构建的,但其逻辑是模型无关的。一旦你了解了它的工作原理,你就可以将代码修改为使用任何大型语言模型(LLM),例如 Meta 的 Llama、xAI 的 Grok、Google 的 Gemini 或 Cohere。

一旦我们分别构建了会话代理和控制器协调器程序,我们将它们合并成一个统一的智能 AI 控制器,如图 2.2 所示。

图 2.2:下一步——通过 Pinecone 向量存储整合 AI 控制器功能

图 2.2:下一步——通过 Pinecone 向量存储整合 AI 控制器功能

现在,我们需要专注于单独构建每个组件,以便我们能够完全理解它们的行为。一旦这个基础建立起来,在 第三章 中,我们将通过 Pinecone 向量存储将它们合并。现在让我们直接进入代码,开始开发对话代理。

对话人工智能代理

本节的主要目标是构建一个具有以下功能的对话人工智能代理:

  • 短期记忆保留完整的 ChatGPT 风格对话循环。用户和代理可以进行他们希望的任何数量的交换;他们之间的交互次数没有限制。

  • 长期记忆保留跨越多个用户和会话。我们将存储内存中的会话并将它们持久化到内存存储(在这种情况下,是一个文本文件)。这将使用户如 John、Myriam 和 Bob 等能够实现多用户上下文感知。我们的对话代理将超越经典的点对点 ChatGPT 风格对话,转向能够处理多会话、多用户交互的定制 GenAISys。

要开始,请在此章节的 GitHub 目录中打开 Conversational_AI_Agent.ipynbgithub.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。这个笔记本将引导您完成环境设置。

设置环境

我们将重用前一章中的设置过程。如果您需要复习,请随时查阅该部分。首先安装 OpenAI 并下载所需的文件:

!curl -L https://raw.githubusercontent.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/master/commons/grequests.py --output grequests.py
from grequests import download
download("commons","requirements01.py")
download("commons","openai_setup.py")
download("commons","openai_api.py") 

我们还需要下载两个额外的函数来构建我们的对话代理:

  • download("commons","conversational_agent.py"):此文件包含管理完整回合对话循环和记忆对话的功能。

  • download("commons", "processing_conversations.py"):此文件包含用于加载、显示和净化过去对话的工具,以增加对话代理在多个会话和用户之间的记忆跨度。这个定制的多会话、多用户功能超出了标准 ChatGPT 风格合作者的范畴。

现在让我们继续在 conversational_agent.py 中实现函数,这是我们将在与对话人工智能代理的整个会话中使用的。

对话人工智能代理工作流程

对话人工智能代理包含两个主要部分:

  • 开始初始对话以与人工智能代理开始对话

  • 运行完整回合对话循环,以继续用户希望与人工智能代理进行的内存交换。在每个会话结束时,对话将被保存,以便稍后可以继续——无论是同一用户还是其他用户。

开始初始对话

初始对话是新会话的入口点。它由 AI 控制器处理,并在 图 2.3 中展示。

图 2.3:初始对话控制器

图 2.3:初始对话控制器

我们将逐步了解与生成式 AI 模型的初始对话的每个步骤,以详细了解一个小型 ChatGPT-like 对话代理是如何工作的。10 步流程从开始开始。

1. 开始对话

程序通过 openai_api.py 中的 run_conversational_agent 函数从这个入口点开始,该函数将在笔记本中通过 conversational_agent 及其参数被调用:

# Start the conversational agent
def run_conversational_agent(
    uinput, mrole, mcontent, user_role, user_name
):
    conversational_agent(uinput, mrole, mcontent, user_role, user_name) 

在这种情况下,对话代理将处理的参数如下:

  • uinput:包含输入(用户或系统),例如,夏威夷在哪里?

  • mrole:定义消息的角色。它可以是 用户系统。您还可以分配 API 将解释的其他角色,例如定义 AI 的个性,例如,您是一位地质学专家

  • mcontent:这是我们期望系统呈现的内容,例如,您是一位地质学专家

  • user_role:定义用户的角色,例如,用户

  • user_name:用户的姓名,例如,约翰

2–3. 初始化 API 变量和消息对象

messages_obj 使用上一步中描述的对话参数初始化,开始对话

messages_obj = [{"role": mrole, "content": mcontent}] 

messages_obj 关注系统的记忆。此对象将在会话期间与 GPT-4o 模型的交流中附加。它将被用于记录会话之间的对话。第一条消息包含设置代理上下文的角色和内容。

4. 打印欢迎信息

系统现在已准备好与用户互动。代理首先显示欢迎信息,并解释如何在对话结束后退出系统:

print("Welcome to the conversational agent! Type 'q' or 'quit' to end the conversation.") 

5. 处理初始用户输入

用户的初始输入被添加到 messages_obj 中,以向代理提供记忆并提供代理预期遵循的方向。初始用户输入将由对话代理发送:

if initial_user_input:
    print(f"{user_name}: {initial_user_input}")
    messages_obj.append(
        {"role": user_role, "content": initial_user_input}
    ) 

6. 清理初始对话日志

messages_obj 以结构化格式保存对话的历史。在我们的应用程序中,对于某些操作,例如生成简化的显示、创建综合日志条目或为基于文本的函数准备输入,我们需要将这个结构化日志转换为单个、连续的字符串。这确保了数据以正确的格式适用于这些特定任务,并有助于解决在组合不同的消息部分时可能出现的任何潜在的标点或格式问题:

conversation_string = cleanse_conversation_log(messages_obj) 

清理函数清理对话并返回一个字符串:

def cleanse_conversation_log(messages_obj):
  conversation_str = " ".join(
        [f"{entry['role']}: {entry['content']}" for entry in messages_obj]
    )
    # Remove problematic punctuations
    return re.sub(r"[^\w\s,.?!:]", "", conversation_str) 

7. 进行初始 API 调用

清理后的对话字符串被发送到 API 进行处理。API 根据最后输入和对话历史提供响应。现在系统有了记忆:

agent_response = make_openai_api_call(
    input=conversation_string,
    mrole=mrole,
    mcontent=mcontent,
    user_role=user_role
) 

8. 添加初始 API 响应

API 的助手响应被处理并附加到 messages_obj。我们正在继续增加系统的记忆和,因此,其上下文意识:

messages_obj.append({"role": "assistant", "content": agent_response}) 

9. 显示初始助手响应

系统的响应显示给用户分析,并决定是否继续或退出会话:

print(f"Agent: {agent_response}") 

10. 开始对话循环

系统现在进入对话循环,其中可以发生多个对话回合,直到用户决定退出会话:

while True:
    user_input = input(f"{user_name}: ")
    if user_input.lower() in ["q", "quit"]:
        print("Exiting the conversation. Goodbye!")
        break 

我们现在准备好开始一个完整对话循环。

完整对话循环

初始对话现在初始化。我们将从步骤 11开始,进入完整对话循环,如图 2.4 所示。

图 2.4:从步骤 11 开始的对话循环

图 2.4:从步骤 11 开始的对话循环

11. 提示用户输入

对话继续初始对话,并通过messages对象进行记忆。用户提示触发完整对话循环。第一步是输入用户的名字。这个自定义功能使我们超越了仅限于每个会话一个用户的标准 ChatGPT-like 对话代理。我们正在初始化一个多用户对话:

user_input = input(f"{user_name}: ") 

12. 检查退出条件

如果输入qquit,会话结束:

if user_input.lower() in ["q", "quit"]:
    print("Exiting the conversation. Goodbye!")
    break 

13. 将用户输入附加到消息对象

系统现在具备了一个完整对话循环的记忆。它使用我们定义的通用 API 格式。用户的输入被附加到messages_obj

messages_obj.append({"role": user_role, "content": user_input}) 

14. 清理对话日志(循环)

更新的messages_obj被清理以确保它符合 API 调用,正如在步骤 6清理初始对话日志中所述:

conversation_string = cleanse_conversation_log(messages_obj) 

15. 在对话循环中调用 API

在这个完整对话循环中,整个对话被发送到 API。因此,API 将根据整个对话的上下文和新输入返回响应:

agent_response = make_openai_api_call(
    input=conversation_string,
    mrole=mrole,
    mcontent=mcontent,
    user_role=user_role
) 

16. 在对话循环中附加 API 响应

在每个对话回合,API 的响应被附加到messages_obj

messages_obj.append({"role": "assistant", "content": agent_response}) 

17. 显示助手响应

在循环的每个对话回合中显示 API 响应:

print(f"Agent: {agent_response}") 

18. 退出并保存对话日志

当用户退出循环时,对话将被保存。这个功能将复制一个 ChatGPT-like 平台,可以保存同一用户在两个会话之间的对话。然而,正如我们将在“运行对话代理”部分中看到,我们的程序将能够在团队成员之间的对话中保存多用户会话:

with open("conversation_log.txt", "w") as log_file:
    log_file.write("\n".join([f"{(user_name if entry['role'] == 'user' else entry['role'])}: {entry['content']}" for entry in messages_obj])) 

19. 结束

对话代理在记忆对话后终止会话:

print("Conversation saved to 'conversation_log.txt'.") 

我们已经探讨了对话代理的功能。

现在,让我们继续讨论代表 AI 控制器的 AI 对话代理程序。

运行对话 AI 代理

主程序Conversational_AI_Agent.ipynbconversational_agent.py调用必要的函数来处理 AI 交互。我们将使用这个场景运行三个用户会话的对话:

  1. 约翰开始与对话式人工智能代理进行短期记忆会话。

  2. 当会话结束时,约翰的对话将保存在日志文件中。

  3. Myriam 使用相同的日志文件继续会话。

  4. 当会话结束时,Myriam 的对话将保存在与约翰相同的日志文件中。

  5. 鲍勃将从约翰和 Myriam 离开的地方继续。

  6. 当会话结束时,鲍勃的对话将保存在与约翰和 Myriam 相同的日志文件中。

所有三位用户在连续的会话中进行互动。在 第三章 中,我们将通过 Pinecone 向量存储将用户分组,以便多个用户可以实时一起参与会话。目前,让我们一步一步地走过这个多用户设置,看看对话式人工智能代理如何处理这些会话。让我们从第一步开始:约翰的短期记忆会话。

短期记忆会话

会话以对话代理的 步骤 1开始对话 中描述的参数开始:

uinput = "Hawai is on a geological volcano system. Explain:"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user" 

我们还在会话中添加了用户名,就像在 ChatGPT 类型的会话中一样:

user_name = "John" 

这个简单的添加——user_name——使我们的 GenAISys 超越了标准 ChatGPT 类型的平台。它允许我们将记忆与特定用户关联,并在单个系统中扩展到多用户对话。

我们现在将导入第一个函数,即 OpenAI API 功能,按照 第一章 中所述向 OpenAI 的 API 发送请求:

from openai_api import make_openai_api_call 

程序现在导入第二个函数,即对话代理,并按本节前面所述运行:

from conversational_agent import run_conversational_agent
run_conversational_agent(uinput, mrole, mcontent, user_role,user_name) 

让我们逐一查看使用我们两个函数实现的对话的每个步骤。代理首先欢迎我们:

Welcome to the conversational agent! Type 'q' or 'quit' to end the conversation. 

约翰,第一个用户,请求关于夏威夷的地质解释:

John: Hawai is on a geological volcano system. Explain: 

代理提供了令人满意的回答:

Agent: Hawaii is part of a geological volcanic system known as a "hotspot"… 

约翰现在询问“那里”冲浪的情况:

John: Can we surf there? 

多亏了代理中内置的记忆,它现在通过记忆保留具有上下文意识。代理正确地回答了关于夏威夷冲浪的问题:

Agent: Yes, you can definitely surf in Hawaii! The Hawaiian Islands are renowned … 

约翰现在询问最佳住宿地点,但没有提到夏威夷:

John: Where are the best places to stay? 

代理利用上下文意识正确回答:

Agent: Hawaii offers a wide range of accommodations … 

约翰然后退出会话:

John: quit 

代理退出对话,并将对话保存在对话日志中:

Agent:Exiting the conversation. Goodbye!
Conversation saved to 'conversation_log.txt'. 

短期会话结束,但多亏了通过 conversation_log.txt 实现的记忆保留,我们可以轻松地从约翰离开的地方继续。因此,我们可以立即或稍后继续对话,利用自动生成的 conversation_log.txt 文件实现记忆保留。

长期记忆会话

短期会话已保存。我们有三个选项:

  • 现在停止程序。在这种情况下,conversation_log.txt 将只包含约翰的会话,可以选择继续或不继续。

  • 决定为下一个用户 Myriam 初始化一个单独的 conversation_log.txt

  • 通过将约翰的对话加载到 Myriam 的初始对话上下文中,继续进行多用户会话。

本章的程序选择继续一个多会话、多用户场景。

继续与 John 对话的第一步是使用我们在设置环境部分下载的processing_conversations.py中的函数加载和显示对话日志。我们现在导入并运行我们需要的加载和显示对话日志的函数:

from processing_conversations import load_and_display_conversation_log
conversation_log = load_and_display_conversation_log() 

该函数是一个标准的IPython过程,使用 HTML 功能读取和显示对话:

from IPython.core.display import display, HTML
import re
# Step 1: Load and Display Conversation Log
def load_and_display_conversation_log():
    try:
        with open("conversation_log.txt", "r") as log_file:
            conversation_log = log_file.readlines()
        # Prepare HTML for display
        html_content = "<h3>Loaded Conversation Log</h3><table border='1'>"
        for line in conversation_log:
            html_content += f"<tr><td>{line.strip()}</td></tr>"
        html_content += "</table>"
        # Display the HTML
        display(HTML(html_content))
        return conversation_log
    except FileNotFoundError:
        print("Error: conversation_log.txt not found. Ensure it exists in the current directory.")
        return [] 

输出显示对话中的每个参与者,首先是系统的信息,然后是 John 的请求,接着是 GPT-4o 助手在每个回合的回应:

system: You are an expert in geology.
John: Hawai is on a geological volcano system. Explain:
assistant: Hawaii is part of a geological volcanic system… 

在将对话添加到下一个输入的上下文之前,我们将对其进行清理和准备。为此,我们依次导入cleanse_conversation_log和从processing_conversations.py导入initialize_uinput

from processing_conversations import cleanse_conversation_log
from processing_conversations import initialize_uinput 

然后,我们将调用我们定义的两个 Python 函数来清理并准备新的输入:

cleansed_log = cleanse_conversation_log(conversation_log)
nuinput = initialize_uinput(cleansed_log) 

cleanse函数移除标点符号和可能有问题的人物:

# Step 2: Clean the conversation log by removing punctuations and special characters
def cleanse_conversation_log(conversation_log):
    cleansed_log = []
    for line in conversation_log:
        # Remove problematic punctuations and special characters
        cleansed_line = re.sub(r"[^\w\s,.?!:]", "", line)
        cleansed_log.append(cleansed_line.strip())
    return " ".join(cleansed_log)  # Combine all lines into a single string 

最后,我们初始化新的输入:

# Step 3: Initialize `uinput` with the cleansed conversation log to continue the conversation
def initialize_uinput(cleansed_log):
    if cleansed_log:
        print("\nCleansed conversation log for continuation:")
        print(cleansed_log)
        return cleansed_log  # Use the cleansed log as the new input
    else:
        print("Error: No data available to initialize `uinput`.")
        return "" 

输出确认对话日志已被清理:

Cleansed conversation log for continuation:
system: You are an expert in geology… 

然后,输出确认nuinput包含用于继续的对话日志:

# `nuinput` now contains the cleansed version of the conversation log and can be used
print("\nInitialized `nuinput` for continuation:", nuinput) 
继续之前的会话

我们现在可以使用nuinput作为记忆保留变量来继续 John 开始的对话。我们将使用消息变量将上下文nuinput添加到 Myriam 的请求中:

ninput = nuinput+ "What about surfing in Long Beach"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user"
user_name = "Myriam" 

消息调用包含两个关键特性:

  • ninput = nuinput+ [user input],这表明 AI 控制器现在拥有超越单个会话的长期记忆

  • user_name = "Myriam",这展示了多用户功能,证明了我们定制的 ChatGPT-like AI 控制器比标准机助有更大的灵活性

整个过程与 John 的情况相同。Myriam 提出一个问题:

Myriam: What about surfing in Long Beach 

代理回应:

Agent:Long Beach, California, offers a different surfing experience compared to Hawai… 

Myriam 退出:

Myriam: quit 

代理确认对话已结束并保存在对话日志中:

Agent:Exiting the conversation. Goodbye!
Conversation saved to 'conversation_log.txt'. 

AI 控制器现在有了 John 的会话和 Myriam 继续会话的日志。控制器可以进一步操作并添加另一个用户到对话中。

继续长期的多用户记忆

让我们加入 Bob 以继续对话。首先,再次显示对话日志:

# Run the process
conversation_log = load_and_display_conversation_log() 

你将看到 John 和 Myriam 的条目:

system: You are an expert in geology.
Myriam: system: You are an expert … 

然后将日志清理并准备为对话的下一个回合。nuinput现在包含 John 和 Myriam 的会话:

uinput =nuinput+ "Read the whole dialog then choose the best for geology research"
mrole = "system"
mcontent = "You are an expert in geology."
user_role = "user"
user_name = "Bob" 

Bob 专注于地质任务,而不是休闲:

Bob:"Read the whole dialog then choose the best for geology research" 

AI 代理提供了一个准确的回应:

Agent: For geology research, the most relevant part of the dialogue is the explanation of Hawaii's geological volcanic system. This section provides detailed insights into the Hawaiian hotspot, mantle plumes, volcanic activity,… 

Bob 随后退出了会话:

Bob: quit 

代理退出对话并将其保存在对话日志中:

Agent:Exiting the conversation. Goodbye!
Conversation saved to 'conversation_log.txt'. 

通过这三个场景,我们已经在多用户全回合对话循环中实现了由 AI 控制器管理的对话代理。让我们检查这个对话代理的下一步:

下一步

在这个阶段,我们已经拥有了对话代理的基本结构。我们需要将其集成到一个 AI 控制器协调器中。在开始构建 AI 控制器协调器之前,让我们总结一下我们为对话代理所做的工作。

图 2.5:对话代理循环的周期

图 2.5:对话代理循环的周期

如前图所示,AI 对话代理执行以下操作:

  1. 代理处理输入(系统或人类用户)。

  2. 代理做出回应。

  3. 激活记忆保留功能。

  4. 对话被添加到以下输入作为上下文。

  5. 用户可以退出。

然而,入口/出口点是不完整的。我们可以进入和退出对话,但不能调用函数来协调任务,如激活情感分析和语义分析。为了完成 AI 控制器的架构,我们需要开始构建 AI 控制器协调器。

AI 控制器协调器

在本节中,我们将构建我们的 AI 控制器协调器的第一个组件:选择正确任务执行的能力。我们将开发这个作为独立组件,从第三章开始集成,在那里我们将通过 Pinecone 向量存储将对话代理与 AI 控制器协调器连接起来。

图 2.6展示了我们将开发的 AI 控制器协调器的工作流程:

  • C1. AI 控制器入口点输入触发流程。

  • C2. 分析输入,这可能是一个系统或人类用户的提示。

  • C3. 通过 GPT-4o 的本地功能嵌入用户输入

  • C4. 通过 GPT-4o 的本地功能嵌入任务场景 存储库

  • C5. 选择一个 场景 来执行与输入最匹配的任务。

  • C6. 执行 AI 控制器协调器选择的场景

图 2.6:AI 控制器协调器的工作流程

图 2.6:AI 控制器协调器的工作流程

我们将使用 OpenAI 的 GPT-4o API 和 Python 开发 AI 控制器协调器的这个第一个组件。此外,由于我们的想法是利用生成式 AI 模型的全功能来执行 AI 控制器协调器请求的多个任务,因此我们将避免在协调器上加载额外的库,以专注于 GenAISys 的架构。

在这个笔记本中,GPT-4o 将在程序中执行三个关键功能,如图图 2.7所示:

  • 嵌入:GPT-4o 系统性地将所有通过提示接收到的数据嵌入。输入在通过模型层之前被嵌入。在第三章中,我们将通过将可重用数据如指令场景嵌入到 Pinecone 向量存储中进一步扩展这一做法。

  • 相似度搜索:GPT-4o 可以执行相似度搜索并得到可靠的结果。GPT-4o 没有确定性的固定余弦相似度函数。它通过其复杂的神经网络学习理解关系,以一种更加细腻、不那么确定性的方式模仿相似度判断。

  • 任务执行:一旦选择了一个场景,GPT-4o 可以执行一系列标准任务,例如情感分析和语义分析。

图 2.7:在指令列表中使用相似度搜索触发任务

图 2.7:在指令列表中使用相似度搜索触发任务

我们已经定义了协调器的工作流程和生成式 AI 模型的使用。然而,我们必须检查模型如何识别它预期执行的任务。

理解意图功能

无论像 GPT-4o 这样的生成式 AI 模型多么强大,如果没有一个明确表达意图的提示,它就无法猜测用户的需求。我们不能只是说,“大峡谷是亚利桑那州一个伟大的旅游胜地”,并期望模型猜测我们想要对这句话进行情感分析。我们必须通过输入以下内容来明确表达我们的意图:“提供以下文本的情感分析:大峡谷是亚利桑那州一个伟大的旅游胜地。”

为了解决 AI 控制器的意图问题,我们必须找到一个框架来协调其任务。一个好的起点是研究 文本到文本迁移变换器T5),这是一个文本到文本模型(Raffel 等人,2020 年)。T5 模型使用 任务标签特定任务的前缀 来向变换器模型提供提示的意图。任务标签包含总结、翻译和分类等指令。模型将检测标签并知道要做什么,如图 图 2.8 所示。

图 2.8:带有任务标签的 T5

图 2.8:带有任务标签的 T5

训练 T5 模型涉及在创建输入时 明确地 添加任务标签,然后提供响应。然而,OpenAI 的 GPT 模型通过分析包含指令和响应的数十亿个语言序列来学习执行哪个任务,而不是显式结构。因此,使用类似 GPT 架构的生成式 AI 模型将通过提示的上下文 隐式地 学习执行哪个任务。例如,一个良好解析的提示,如“提供以下文本的情感分析:大峡谷是亚利桑那州一个伟大的旅游胜地。”,为 GPT-4o 提供了足够多的上下文来推断所需的操作——无需显式标签。

让我们通过运行带有 GPT-4o 隐式分析需要执行哪个任务的 T5 风格示例来展示 GPT 模型的工作原理。

从 T5 到 GPT 模型

在本节中,我们将编写一个程序来展示 GPT-4o 如何解释指令——这是我们将在编排器中利用的能力。目标是证明,尽管 GPT 风格的模型隐式地推断意图,但它们仍然需要清晰的指令。

我们将首先在 GitHub 上的Chapter02目录中打开T52GPT.ipynb。设置环境与设置环境子节中的对话式 AI 代理部分完全一致,仅安装 OpenAI 环境:

download("commons","requirements01.py")
download("commons","openai_setup.py")
download("commons","openai_api.py") 

不需要额外的安装。现在让我们开始一个 CoLA 任务。

语言学可接受性语料库(CoLA)

语言学可接受性语料库CoLA)是一个公共的短英语句子数据集,每个句子都被标记为可接受(语法正确)或不可接受(语法错误)。通过在这些例子上测试 GPT-4o,我们可以展示高级生成模型可以通过理解语言来处理新任务,而无需任何特定任务的微调。这意味着我们可以将高级生成式 AI 模型应用于我们未对其进行训练的广泛任务。

让我们先向 GPT-4o 模型提交以下输入,看看它是否在没有明确任务标签的情况下是可接受的:

input="This aint the right way to talk." 

我们将向系统提供最少的信息:

mrole = "system"
user_role = "user"
mcontent = "Follow the instructions in the input" 

我们还将使用本章中一直使用的函数调用 OpenAI API:

# API function call
task_response = openai_api.make_openai_api_call(
    input,mrole,mcontent,user_role
)
print(task_response) 

输出显示,即使是最强大的生成式 AI 模型在没有任务标签的情况下也没有头绪:

I apologize if my previous response didn't meet your expectations. Please let me know how I can assist you better! 

现在,让我们编写一个带有任务标签和相同信息的指令:

input="Is the following sentence gramatically correct:This aint the right way to talk."
mrole = "system"
user_role = "user"
mcontent = "Follow the instructions in the input"
# API function call
task_response = openai_api.make_openai_api_call(
    input,mrole,mcontent,user_role
)
print(task_response) 

输入现在包含了对生成式 AI 模型期望的指示。输出现在也是准确的:

The sentence "This aint the right way to talk." is not grammatically correct. The response corrects the sentence:
"This isn't the right way to talk."
Alternatively, if you want to maintain the informal tone, you could write:
"This ain't the right way to talk."
Note that "ain't" is considered informal and nonstandard in formal writing. 

现在我们执行一个翻译任务。

翻译任务

任务以自然语言表达的任务标签开始:

input=”Translate this sentence into French: Paris is quite a city to visit.”
mrole = “system”
user_role = “user”
mcontent = “Follow the instructions in the input”
# API function call
task_response = openai_api.make_openai_api_call(
    input,mrole,mcontent,user_role
)
print(task_response) 

我们得到的输出是准确的:

Paris est vraiment une ville à visiter. 

现在我们执行一个语义文本相似度基准STSB)任务。

语义文本相似度基准(STSB)

STSB 风格的评分是 GenAISys AI 控制器的重要功能,它依赖于相似度搜索来选择正确的指令场景、文档和其他资源。编排器将依赖于这一能力。在接下来的测试中,我们向模型提交两个句子并要求它判断它们的语义相似度:

input=”stsb:Sentence 1: This is a big dog. Sentence 2: This dog is very big.”
mrole = “system”
user_role = “user”
mcontent = “Follow the instructions in the input”
# API function call
task_response = openai_api.make_openai_api_call(
    input,mrole,mcontent,user_role)
print(task_response) 

我们得到的输出是准确的:

The sentences "This is a big dog." and "This dog is very big." are semantically similar. Both sentences convey the idea that the dog in question is large in size. The difference in wording does not significantly alter the meaning, as both sentences describe the same characteristic of the dog. 

当我们在数据集中搜索与输入匹配的数据时,这个函数将非常有用。现在让我们运行一个摘要任务。

摘要

在以下输入中,GPT-4o 可以检测到摘要指令标签,并解释所需的响应最大长度:

input="Summarize this text in 10 words maximum: The group walked in the forest on a nice sunny day. The birds were singing and everyone was happy."
mrole = "system"
user_role = "user"
mcontent = "Follow the instructions in the input"
# API function call
task_response = openai_api.make_openai_api_call(
    input,mrole,mcontent,user_role)
print(task_response) 

输出再次是准确的:

Group enjoyed a sunny forest walk with singing birds. 

这次探索的要点是,无论我们实施哪种生成式 AI 模型,它都需要任务标签才能按照我们的预期进行反应。接下来,我们将利用这一洞察力在我们的编排器中实现语义文本相似度处理任务标签。

实现指令选择的编排器

在本节中,我们将开始构建基于任务标签的两个指令的调度器,如图2.9所示:情感分析以确定句子的情感和语义分析以分析句子中的事实。

我们将通过要求生成式 AI 模型根据输入找到最佳任务标签场景(情感或语义分析)来使系统更加复杂。换句话说,任务标签将不会是输入的一部分。我们将使用 GPT-4o 的语义文本相似度功能来选择正确的任务标签本身。

图 2.9:使用隐式任务标签运行任务

图 2.9:使用隐式任务标签运行任务

最终,我们的调度器将支持任何任务(参见图 2.9中的3. 任何所需任务),而不仅仅是情感或语义分析。

环境设置与之前相同:

download("commons","requirements01.py")
download("commons","openai_setup.py")
download("commons","openai_api.py") 

对于调度器不需要额外的安装。我们将首先实施一个指令场景选择。

选择场景

AI 控制器的核心是在接收到输入(系统或人类用户)时决定做什么。任务的选择打开了一个我们将全书探索的可能方法的世界。然而,我们可以将它们分为两类:

  • 使用显式任务标签来触发指令。这个标签可以是一个生成式 AI 模型中的上下文,并在提示中以各种方式自由表达。

  • 提示没有任务指令,而是一个场景存储库,AI 控制器将根据语义文本相似度从中做出决策。

在这里,我们将探讨第二种更主动的方法。我们将测试两个没有任何指示、没有任务标签和没有任何关于对生成式 AI 模型期望的提示的提示。虽然我们稍后会实施带有任务标签的更明确的方法,但 GenAISys AI 控制器调度器必须能够在某些情况下主动行事。

  • 第一个提示是对一部电影的看法,暗示用户可能对情感分析感兴趣:

    if prompt==1:
        input = "Gladiator II is a great movie although I didn't like some of the scenes. I liked the actors though. Overall I really enjoyed the experience." 
    
  • 第二个提示是一个事实,暗示用户可能对语义分析感兴趣:

    if prompt==2:
        input = "Generative AI models such as GPT-4o can be built into Generative AI Systems. Provide more information." 
    

为了提供 AI 控制器决策能力,我们需要一个指令场景存储库。

定义任务/指令场景

场景是一组存在于 GenAISys 内部存储库中的指令。虽然 ChatGPT-like 模型被训练来原生处理许多指令,但特定领域的用例需要定制场景(我们将在第五章中深入探讨这些)。例如,GenAISys 可能收到一条消息,例如“客户订单#9283444 延迟”。这条消息可能是关于生产延迟或交付延迟。通过检查发送者的用户名和组(生产或交付部门),AI 控制器可以确定上下文,并选择一个场景,做出适当的决定。

在这个笔记本中,场景存储在内存中。在第三章中,我们将组织这些指令集在 Pinecone 向量存储中的存储和检索。

在这两种情况下,我们首先创建一个结构化场景的仓库(市场、情感和语义分析):

scenarios = [
    {
**"scenario_number"****:** **1****,**
        "description": "Market Semantic analysis.You will be provided with a market survey on a give range of products.The term market must be in the user or system input. Your task is provide an analysis."
    },
    {
**"scenario_number"****:** **2****,**
        "description": " Sentiment analysis  Read the content and classify the content as an opinion  If it is not opinion, stop there  If it is an opinion then your task is to perform a sentiment analysis on these statements and provide a score with the label: Analysis score: followed by a numerical value between 0 and 1  with no + or - sign.Add an explanation."
    },
    {
**"scenario_number"****:** **3****,**
        "description": "Semantic analysis.This is not an analysis but a semantic search. Provide more information on the topic."
    }
] 

我们还将添加一个包含相同场景的字典,包含场景的简单定义:

# Original list of dictionaries
scenario_instructions = [
    {
        **"Market Semantic analysis.You will be provided with a market survey on a give range of products.The term market must be in the user or system input. Your task is provide an analysis."**
    },
    {
        **"Sentiment analysis  Read the content return a sentiment analysis on this text and provide a score with the label named : Sentiment analysis score followed by a numerical value between 0 and 1  with no + or - sign and  add an explanation to justify the score."**
    },
    {
        **"Semantic analysis.This is not an analysis but a semantic search. Provide more information on the topic."**
    }
] 

我们现在从字典中提取字符串并将它们存储在一个列表中:

# Extract the strings from each dictionary
instructions_as_strings = [
    list(entry)[0] for entry in scenario_instructions
] 

到目前为止,我们的 AI 控制器已经拥有了识别意图所需的一切——将任何传入的提示与最佳匹配的场景相匹配。

执行意图识别和场景选择

我们首先定义对话人工智能代理的参数,就像我们在对话人工智能代理部分所做的那样:

**# Define the parameters for the function call**
mrole = "system"
mcontent = "You are an assistant that matches user inputs to predefined scenarios. Select the scenario that best matches the input. Respond with the scenario_number only."
user_role = "user" 

调度器的任务是找到任何给定输入的最佳任务,使人工智能控制器灵活且适应性较强。在某些情况下,调度器可能决定不应用场景,而只是跟随用户的输入。然而,在以下示例中,调度器将选择一个场景并应用它。

我们现在调整输入以考虑调度器的请求:

# Adjust `input` to combine user input with scenarios
selection_input = f"User input: {input}\nScenarios: {scenarios}"
print(selection_input) 

GPT-4o 现在将执行文本语义相似度搜索,就像我们在语义文本相似度基准(STSB)部分所做的那样。在这种情况下,它不仅执行纯文本比较,而且将一个文本(用户输入)与一系列文本(我们的场景描述)进行匹配:

# Call the function using your standard API call
response = openai_api.make_openai_api_call(
    selection_input, mrole, mcontent, user_role
) 

我们的用户输入如下:

User input: Gladiator II is a great movie 

然后,选择场景:

# Print the response
print("Scenario:",response ) 

然后,选择场景编号,将其与相应的指令一起存储并显示:

scenario_number=int(response)
instructions=scenario_instructions[scenario_number-1]
print(instructions) 

对于我们的Gladiator II示例,调度器正确地选择了情感分析场景:

{'Sentiment analysis  Read the content return a sentiment analysis on this text and provide a score with the label named : Sentiment analysis score followed by a numerical value between 0 and 1  with no + or - sign and  add an explanation to justify the score.'} 

这种自主任务选择能力——让 GenAISys 在没有明确标签的情况下选择正确的分析——将在实际部署中非常有价值(参见第五章)。程序现在使用生成式人工智能代理运行场景。

使用生成式人工智能代理运行场景

现在人工智能控制器已经识别出正确的scenario_number,是时候执行所选任务了。在这个笔记本中,我们将逐步介绍这个过程。我们首先打印输入:

print(input) 

使用scenario_number值,我们从instructions_as_strings列表中访问场景描述:

# Accessing by line number (1-based index)
line_number = scenario_number
instruction = instructions_as_strings[line_number - 1]  # Adjusting for 0-based indexing
print(f"Instruction on line {line_number}:\n{instruction}")
mrole = "system"
user_role = "user"
mcontent = instruction 

现在调度器已经准备好运行情感分析了。

情感分析

我们将场景描述附加到原始用户提示中,并将组合请求发送给 GPT-4o:

Instruction on line 2:
Sentiment analysis  Read the content return a sentiment analysis nalysis on this text and provide a score with the label named : Sentiment analysis score followed by a numerical value between 0 and 1  with no + or - sign and  add an explanation to justify the score. 
# API function call
sc_input=instruction +" "+ input
print(sc_input)
task_response = openai_api.make_openai_api_call(
    sc_input,mrole,mcontent,user_role
)
print(task_response) 

对于我们的Gladiator II示例,响应可能看起来像这样:

Sentiment analysis score 0.75
The text expresses a generally positive sentiment towards the movie "Gladiator II." The use of words like "great movie," "liked the actors," and "really enjoyed the experience" indicates a favorable opinion. However, the mention of not liking some of the scenes introduces a slight negative element. Despite this, the overall enjoyment and positive remarks about the actors and the movie as a whole outweigh the negative aspect, resulting in a sentiment score leaning towards the positive side. 

响应显示调度器找到了与输入匹配的场景并产生了可接受的输出。现在,让我们回到之前,更改提示,看看调度器是否找到了正确的场景。

语义分析

目前的目标是验证,在不更改任何一行代码的情况下,协调器能否访问另一个场景。协调器将依赖于 GPT-4o 的本地能力来执行语义文本相似度搜索。

现在我们将激活提示 2:

prompt=2
…
if prompt==2:
    input = "Generative AI models such as GPT-4o can be built into Generative AI Systems. Provide more information." 

这个输入明显需要语义分析而不是情感分析。然后我们重复使用与我们的情感分析搜索相同的代码:

# Accessing by line number (1-based index)
line_number = scenario_number
instruction = instructions_as_strings[line_number - 1]  # Adjusting for 0-based indexing
print(f"Instruction on line {line_number}:\n{instruction}")
mrole = "system"
user_role = "user"
mcontent = instruction 

输出显示找到了正确的场景:

Instruction on line 3:
Semantic analysis.This is not an analysis but a semantic search. Provide more information on the topic. 

任务响应显示:

print(task_response) 

输出显示协调器产生了连贯的语义分析:

Generative AI models, like GPT-4, are advanced machine learning models designed to generate human-like text based on the input they receive…. 

这表明在某些情况下,协调器将能够在没有任务标签的情况下找到正确的场景。当我们处理更复杂的流程时,例如高级生产和支持,这将非常有用。

摘要

本章的第一个要点是人在 GenAISys 中的核心作用。人类设计推动了我们的对话式代理和协调器的创建。我们只是用 OpenAI API 和 Python 开始开发这两个复杂组件,但我们这些“人类”设计了为我们的定制 GenAISys 提供动力的 AI 控制器的初始级别。基本的 GenAISys 规则始终适用:没有人类角色,就没有 GenAISys。我们设计 AI 系统,实施它们,维护它们,并根据持续的反馈进行进化。

第二个要点是如何我们的对话式 AI 代理超越了小型 ChatGPT-like 结构。我们不仅为完整轮对话构建了短期上下文和记忆保留,还添加了跨多个用户和多个主题的长期记忆。我们的对话包括三个用户(John、Myriam 和 Bob)和两个主题(地质学和冲浪)。随着我们阅读这本书的进展,我们将扩大这些多用户、多主题会话的范围,以应用于团队合作至关重要的用例。

第三个要点涉及我们的 AI 控制器协调器。我们为协调器提供了一个包含自定义指令的小型场景数据集,我们可以根据特定用例进行扩展,然后利用 GPT-4o 来选择合适的场景并执行任务本身。

到目前为止,我们有一个对话式代理和一个新兴的 AI 控制器协调器。当我们组装我们的 AI 控制器时,它们将共同形成一个独特的多用户、多领域定制 GenAISys。为了构建我们的多用户、多领域 GenAISys AI 控制器,我们将在下一章构建 Pinecone 向量存储。

问题

  1. 类似 ChatGPT 的 GenAISys 只需要一个生成式 AI 模型,如 GPT-4o。(对或错)

  2. 类似 ChatGPT 的 GenAISys 不需要 AI 控制器。(对或错)

  3. 在构建和运行 GenAISys 时,人类角色至关重要。(对或错)

  4. 通常情况下,但不总是,一个生成式 AI 模型如 GPT-4o 以一种或另一种形式包含任务标签。(对或错)

  5. 有时,但不总是,一个生成模型可以在没有任务标签的情况下找到最可能执行的任务。(对或错)

  6. 语义文本相似性不能由 GPT-4o 原生执行。(对或错)

  7. 使用 OpenAI API 的 AI 进行全轮生成式人工智能对话需要编码。(对或错)

  8. 长期记忆人工智能对话会话从不必要。(对或错)

  9. 总结文本只能用英语由 GPT-4o 完成。(对或错)

  10. 人工智能控制器协调器是有感知的。(对或错)

参考文献

  • Raffel, C., Shazeer, N., Roberts, A., Lee, K., Narang, S., Matena, M., Zhou, Y., Li, W., & Liu, P. J. (2020). Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer. arxiv.org/abs/1910.10683

  • Ren, J., Sun, Y., Du, H., Yuan, W., Wang, C., Wang, X., Zhou, Y., Zhu, Z., Wang, F., & Cui, S. (2024). Generative Semantic Communication: Architectures, Technologies, and Applications. doi.org/10.48550/arXiv.2412.08642

进一步阅读

订阅免费电子书

新框架、演进的架构、研究发布、生产分解——AI_Distilled将噪音过滤成每周简报,供与 LLMs 和 GenAI 系统实际工作的工程师和研究人员阅读。现在订阅,即可获得免费电子书,以及每周的洞察力,帮助您保持专注并获取信息。

packt.link/TRO5B订阅或扫描下面的二维码。

Newsletter_QR_Code

第三章:将动态 RAG 集成到 GenAISys 中

一个面向商业的生成式 AI 系统GenAISys)需要具备灵活性和随时应对 AI 市场快速变化的能力。AI 控制器充当电子营销、生产、存储、分销和支持的适应性协调者,但要满足如此广泛的任务,我们需要一个检索增强生成RAG)框架。在前一章中,我们构建了一个用于指令场景(AI 协调器)的对话式 AI 代理和相似性搜索功能,用于生成式 AI 模型。在本章中,我们将增强这个基础,并在 Pinecone 索引中构建一个可扩展的 RAG,以整合指令场景和经典数据,这些数据生成式 AI 模型将与之连接。

在本章中,我们明确区分了指令场景——专家精心制作的提示片段(或如前一章所述的任务标签),告诉模型如何推理或行动,以及经典数据——RAG 系统检索以支持其答案的参考材料。

为什么我们需要这样一个动态和自适应的 RAG 框架,其上还有基于经典数据的指令场景向量化?因为全球市场从内部和外部影响实体。例如,一场飓风可能导致电力短缺,使企业的供应链处于危险之中。企业可能不得不重新定位供应路线、生产或分销。通用 AI 云平台可能完成一些工作。但更常见的情况是我们需要提供定制、特定领域的功能。因此,我们需要一个动态的指令集,在向量存储库中,就像我们对 RAG 数据所做的那样。

我们将首先通过 Pinecone 索引定义面向生成式 AI 模型(在本例中为 GPT-4o)的架构驱动任务执行。我们将仔细分析投资于智能场景(通过相似性搜索和检索)的成本效益。我们将介绍一个动态框架,以产生类似 ChatGPT 的能力,这些能力将在接下来的章节中逐步介绍。

一旦定义了架构,我们首先将构建一个 Pinecone 索引来分块、嵌入和更新指令场景。我们将确保 GenAISys 向量存储可以嵌入查询并找到相关的指令场景。这种能力将是我们在设计对话代理的界面和协调器时,在第四章(Chapter 4)中构建 AI 控制器协调接口的关键组件。最后,我们将编写一个程序,将经典数据在 RAG 环境中更新到与指令场景相同的 Pinecone 索引。我们将使用不同的命名空间来维护场景和经典数据之间的区分。到本章结束时,我们将构建将指令链接到生成式 AI 模型的主要组件。我们将为第四章(Chapter 4)中设计用户界面和 AI 控制器协调器做好准备。

本章涵盖了以下主题:

  • 构建用于指令和数据动态检索的 RAG

  • 开发相似性搜索时的收益递减定律

  • 检查混合 GenAISys CoT 的架构

  • 通过分块、嵌入和更新指令场景来创建 Pinecone 索引

  • 通过经典数据增强 Pinecone 索引

  • 查询 Pinecone 索引

我们的第一项任务是构建一个用于动态检索的 RAG 框架。

构建动态检索的 RAG

在本节中,我们将定义一个 Pinecone 索引,该索引存储指令场景和经典数据。这种结构为 GenAISys 提供了动态、成本效益的检索:指令场景引导生成式 AI 模型(以我们为例的 GPT-4o),而经典数据为 RAG 管道使用的实际背景提供信息。

我们将探讨以下组件:

  • 场景驱动任务执行:设计优化的指导提示(“场景”),我们将将其更新到 Pinecone 索引。

  • 成本效益策略:考虑收益递减定律,避免过度投资于自动化。

  • 使用命名空间分区 Pinecone:使用 Pinecone 索引命名空间明确区分指令场景和经典数据。

  • 混合检索框架:实现隐式向量相似性搜索,但同时也触发生成式 AI 模型(更多内容请参阅场景驱动任务执行部分)的显式指令。

  • CoT loops:解释场景选择过程的灵活性将如何导致生成式 AI 函数的循环,最终产生输出。

  • GenAISys 框架:为我们在整本书中构建的高级 GenAISys 框架奠定基础。

让我们先深入了解场景驱动任务执行。

场景驱动任务执行

在上一章中,我们看到了 AI 控制器可以选择下一步做什么的两种互补方式:

  • 隐式选择:控制器嵌入用户的提示,在其场景库中运行语义相似性搜索,并选择最接近的匹配项,而不需要任何任务标签。这为我们提供了灵活的、无需代码的编排(例如,它自动为“角斗士 II”评论选择了情感分析场景)。

  • 显式选择:所需任务明确说明,可以是提示中的任务标签,也可以是用户界面操作,例如“运行网络搜索”。在这里,控制器跳过相似性搜索,直接跳到请求的工具或工作流程。

这种相同的模式在本章中继续,但规模更大。我们不是管理几个精选的提示,而是管理存储在向量数据库中的数百甚至数千个专家撰写的指令场景;我们不是支持单个用户实验,而是支持许多并发用户和工作流程。这种以场景驱动的(隐式)方法有三个优点:

  • 专业专家通常创建这些高级提示/指令场景,通常超过主流用户的专家水平。

  • 这些场景可以由 AI 专家和领域专家共同设计,涵盖公司从销售到交付的广泛活动。

  • 场景的执行顺序是由提示驱动的、灵活的且无序的。这种动态方法避免了硬编码任务顺序,尽可能增加了适应性。

然而,尽管隐式任务规划最大化了灵活性,但当我们朝着构建业务就绪系统迈进时,我们必须在灵活性和成本效益之间取得平衡。因此,在某些情况下,显式指令,例如通过在用户界面中选择选项来触发网络搜索,可以显著降低潜在成本,如图 图 3.1 所示:

图 3.1:成本增加时的收益递减

图 3.1:成本增加时的收益递减

我们在 Pinecone 指数中自动化的隐式场景越多,即生成式 AI 模型通过向量相似性搜索选择的场景越多,成本就越高。为了管理这一点,我们必须仔细考虑收益递减定律:

图 3.1:成本增加时的收益递减

在这个方程中,如图 图 3.1 所示,在理论单位中,我们有以下内容:

  • 整体效益 表示整体效益,当成本达到 50 时,大约为 15。

  • 初始效益 表示将指令场景存储在 Pinecone 指数中,并通过与用户输入的向量相似性选择一个场景的初始效益。在这种情况下,几乎每个成本单位对应 1 个效益单位。

  • 效益增加率 是随着成本增加,效益开始增加的速率。

  • 成本测量 表示以理论单位(货币、人力或计算资源)衡量的成本。

  • 收益递减率 表示随着成本增加,收益递减的速率。

例如,当成本达到 7 个理论单位时,收益也达到 7 个理论单位。每单位成本产生 1 单位收益是合理的。然而,当收益达到 10 个单位时,成本可能翻倍达到 14 个单位,这表明出了问题。

减少的 因素对通过平方成本带来的益处有强烈的负面影响

我们将在本书的使用案例中仔细监控 因素。我们将在通过 Pinecone 索引运行隐式自动场景选择和通过提示中的预定义指令显式触发动作之间做出选择。

现在我们来探讨如何在 Pinecone 索引中识别指令场景。

混合检索和 CoT

我们的第一步是教会 GenAISys 框架明确区分经典数据和指令场景。为了实现这一点,我们将在同一个 Pinecone 索引中用两个命名空间来区分指令场景和数据,命名为 genai-v1

  • genaisys 将包含信息指令向量

  • data01 将包含信息数据向量

    我们将在本章的 创建 Pinecone 索引 部分用代码实现 genai-v1,并在其中提供额外的解释。

一旦 Pinecone 索引被划分为场景和数据,我们就可以通过混合检索将 GenAISys 提升到另一个层次,如图 图 3.2 所示。

图 3.2:AI 控制器编排 GenAISys

图 3.2:AI 控制器编排 GenAISys

前面图中描述的混合检索框架将使 GenAISys 能够执行以下操作:

  • 使用处理过的、分块和嵌入的数据内存(见 图 3.2 中的 13)直接运行生成式 AI 模型,而不通过 Pinecone 索引(见 3B)。这将减少临时数据的成本,例如。

  • 在将分块和嵌入的数据更新到 Pinecone 索引后运行生成式 AI 模型,要么作为场景中的一组指令,要么作为经典数据。

  • 在 Pinecone 索引(见 3B)和生成式 AI 模型控制器之间创建一个 CoT 循环作为编排者。例如,模型的输出可以作为另一个 CoT 循环的输入,该循环将从 Pinecone 索引检索场景或数据。类似于 ChatGPT 的共飞行员通常会展示他们的输出,然后通过询问你是否想进一步探索来结束,有时甚至会建议你可以点击的现成后续提示。

CoT 循环可以通过向量相似度搜索隐式运行,也可以通过直接指令触发或任务标签(例如“运行网络搜索”)显式运行。例如,类似于 ChatGPT 的共飞行员可以直接通过用户界面或 AI 控制器中的规则触发网络搜索。

我们将在本章开始构建我们的 GenAISys,并在接下来的几章中继续对其进行优化。从 第四章 开始,构建 AI 控制器编排接口,我们将使用这里引入的 RAG 基础来开发 图 3.2 中所示的混合检索框架。我们构建的 GenAISys 将包括动态流程管理——这是跟上市场变化趋势的必要条件。具体来说,我们的 GenAISys 将执行以下操作:

  • 利用 Pinecone 的向量数据库或内存中的分块和嵌入信息,通过相似性搜索优化检索(指令或数据)

  • 明确触发直接指令,例如网络搜索,并将其包含在 CoT 循环中进行总结、情感分析或语义分析

  • 将复杂的指令和数据检索组合分解为可管理的步骤

  • 在生成输出之前,以类似人类思维过程的方式迭代优化解决方案

  • 通过提供优化的指令场景,充分发挥生成式 AI 模型(包括 OpenAI 的推理模型如 o3)的潜力

本章的初始步骤是构建 genai-v1 Pinecone 索引,AI 控制器将使用它来管理 genaisys 命名空间内的指令场景。然后,我们将演示如何将经典数据分块、嵌入并更新到 data01 命名空间。让我们开始吧!

构建动态 Pinecone 索引

我们将专注于创建一个 Pinecone 索引,用于管理指令场景和经典数据。在接下来的章节中,我们将开始更新指令场景以及经典数据。工作流程分为三个简单的阶段:

  • 设置 OpenAI 和 Pinecone 的环境

  • 处理数据,将其分块,然后嵌入

  • 初始化 Pinecone 索引

在 GitHub 的 Chapter03 目录中打开 Pinecone_instruction_scenarios.ipynb 笔记本(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。我们的第一个任务是设置环境。

设置环境

随着我们阅读本书,我们将不断重用第 1 章和 2 章中实现的函数和功能,为 Pinecone 添加新的功能,并将安装过程分为两部分:

  • 使用与 第一章 中相同的流程安装 OpenAI。如有需要,请参阅该章节。

  • 为本章和后续章节安装 Pinecone。

首先,通过从 GitHub 仓库检索 grequests.py 文件来下载我们需要的文件:

!curl -L https://raw.githubusercontent.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/master/commons/grequests.py --output grequests.py 

要安装 OpenAI,请遵循 第一章 中的相同步骤。现在我们将继续安装 Pinecone,在本书的后续章节中,我们将多次提及它。

安装 Pinecone

下载包含我们想要在整本书中使用的 Pinecone 版本说明的 Pinecone 需求文件。如果需要其他版本,这将是需要更新的唯一文件:

download("commons","requirements02.py") 

快速提示:使用 AI 代码解释器快速复制 功能来增强您的编码体验。在下一代 Packt 阅读器中打开此书。点击 复制 按钮

1)快速将代码复制到您的编码环境,或点击 解释 按钮

2)让 AI 助手为您解释一段代码。

白色背景上的黑色文字 AI 生成的内容可能不正确。

下一代 Packt 阅读器随本书免费赠送。扫描二维码或访问 packtpub.com/unlock,然后使用搜索栏通过名称查找此书。请仔细检查显示的版本,以确保您获得正确的版本。

白色背景上的二维码 AI 生成的内容可能不正确。

文件包含安装函数,我们将使用以下命令调用它:

# Run the setup script to install and import dependencies
%run requirements02 

脚本与在 第一章 中描述的 OpenAI 脚本相同,但已调整为适用于 Pinecone。我们首先卸载 Pinecone,然后安装所需的版本:

import subprocess
import sys
def run_command(command):
    try:
        subprocess.check_call(command)
    except subprocess.CalledProcessError as e:
        print(f"Command failed: {' '.join(command)}\nError: {e}")
        sys.exit(1)
# Uninstall the 'pinecone-client' package
print("Uninstalling 'pinecone-client'...")
run_command(
    [sys.executable, "-m", "pip", "uninstall", "-y", "pinecone-client"]
)
# Install the specific version of 'pinecone-client'
print("Installing 'pinecone-client' version 5.0.1...")
run_command(
    [
        sys.executable, "-m", "pip", "install",\
        "--force-reinstall", "pinecone-client==5.0.1"
    ]
) 

然后,我们验证安装:

# Verify the installation
try:
    import pinecone
    print(
        f"'pinecone-client' version {pinecone.__version__} is installed."
)
except ImportError:
    print(
        "Failed to import the 'pinecone-client' library after installation."
)
    sys.exit(1) 

输出显示我们已成功安装客户端:

Uninstalling 'pinecone-client'...
Installing 'pinecone-client' version 5.0.1...
'pinecone-client' version 5.0.1 is installed. 

让我们继续初始化 Pinecone API 密钥。

初始化 Pinecone API 密钥

程序现在下载 pinecone_setup.py,我们将使用它来初始化 Pinecone API 密钥:

download("commons","pinecone_setup.py") 

此设置反映了我们在 第一章 中为 OpenAI 使用的基于 Google Colab 秘密的方案,但在此处调整为初始化 Pinecone API:

# Import libraries
import openai
import os
from google.colab import userdata
# Function to initialize the Pinecone API key
def initialize_pinecone_api():
    # Access the secret by its name
    PINECONE_API_KEY = userdata.get('PINECONE_API_KEY')

    if not PINECONE_API_KEY:
        raise ValueError("PINECONE_API_KEY is not set in userdata!")

    # Set the API key in the environment and OpenAI
    os.environ['PINECONE_API_KEY'] = PINECONE_API_KEY
    print("PINECONE_API_KEY initialized successfully.") 

如果在 OpenAI 部分的笔记本中将 Google 秘密设置为 True,则 Pinecone 设置函数将被调用:

if google_secrets==True:
    import pinecone_setup
    pinecone_setup.initialize_pinecone_api() 

如果 Google 秘密设置为 False,则可以通过取消注释代码并使用您希望的方法输入 Pinecone API 密钥来实现自定义函数:

if google_secrets==False: # Uncomment the code and choose any method you wish to initialize the Pinecone API key
    import os
    #PINECONE_API_KEY=[YOUR PINECONE_API_KEY]
    #os.environ['PINECONE_API_KEY'] = PINECONE_API_KEY
    #openai.api_key = os.getenv("PINECONE_API_KEY")
    #print("Pinecone API key initialized successfully.") 

程序现在已准备好处理我们将要上载到 Pinecone 索引中的数据。

处理数据

我们现在的目标是准备存储和检索的场景,以便我们随后可以查询 Pinecone 索引。该过程的主要步骤在 图 3.2 中表示,这是后续章节路线图的一层。我们将按以下步骤处理数据:

  1. 数据加载和准备,其中数据将被分成更小的部分。在这种情况下,每个场景将存储在场景列表的一行中,这将准备分块过程。然而,我们不会总是将文本拆分成行,正如我们将在后面的 将经典数据插入索引 部分中看到的。

  2. 分块功能将场景的每一行存储到块中。

  3. 嵌入获取的文本块。

  4. 验证以确保我们嵌入的块数量正确。

现在我们来介绍前两个步骤:加载数据和准备数据,然后进行块分割。

数据加载和块分割

我们将使用在 第二章 中实现的场景。它们存储在一个文件中,我们现在将其下载:

download("Chapter03","scenario.csv") 

在本书的旅程中,我们将添加更多场景以创建 GenAISys。目前,我们的主要目标是让我们的 Pinecone 索引工作。程序首先初始化 start_time 用于时间测量。然后我们逐行将场景指令的行直接加载到 chunks 中:

import time
start_time = time.time()  # Start timing
# File path
file_path = 'scenario.csv'
# Read the file, skip the header, and clean the lines
chunks = []
with open(file_path, 'r') as file:
    next(file)  # Skip the header line
    chunks = [line.strip() for line in file]  # Read and clean lines as chunks 

然后,代码显示块的数量和创建块所需的时间:

response_time = time.time() - start_time  # Measure response time
print(f"Response Time: {response_time:.2f} seconds")  # Print response time 
Total number of chunks: 3
Response Time: 0.00 seconds 

程序现在验证场景指令的前三个块:

# Optionally, print the first three chunks for verification
for i, chunk in enumerate(chunks[:3], start=1):
    print(chunk) 

输出显示了我们将在本章中处理的三个场景:

['ID,SCENARIO\n',
 '100,Semantic analysis.This is not an analysis but a semantic search. Provide more information on the topic.\n',
 '200,Sentiment analysis  Read the content return a sentiment analysis nalysis on this text and provide a score with the label named : Sentiment analysis score followed by a numerical value between 0 and 1  with no + or - sign and  add an explanation to justify the score.\n',
 '300,Semantic analysis.This is not an analysis but a semantic search. Provide more information on the topic.\n'] 

数据块现在已准备好进行嵌入。让我们继续进行嵌入。

嵌入数据集

为了嵌入数据集,我们首先初始化嵌入模型,然后嵌入块。程序首先初始化嵌入模型。

初始化嵌入模型

我们将使用 OpenAI 嵌入模型来嵌入数据。为了使用 OpenAI 模型嵌入我们的数据,我们可以选择三种主要模型之一:

  • text-embedding-3-small,速度快,资源使用量低。这对于实时使用来说足够了。这是一个较小的模型,因此具有成本效益。然而,随着复杂场景的向量存储库增大,它可能在细微的任务中准确性较低。

  • text-embedding-3-large,提供高精度和细微的嵌入,对于复杂的语义相似性搜索将非常有效。它需要更多的资源,因此成本更高。

  • text-embedding-ada-002,对于高质量的嵌入来说既经济又实惠。然而,它比 text-embedding-3-smalltext-embedding-3-large 等模型略慢。

您可以查阅 OpenAI 文档以获取更多信息:platform.openai.com/docs/guides/embeddings

为了在本章中导入有限数量的场景,我们将使用 text-embedding-3-small 来优化速度和成本。程序初始化模型,而其他模型则被注释以供将来使用(如果需要):

import openai
import time
embedding_model="text-embedding-3-small"
#embedding_model="text-embedding-3-large"
#embedding_model="text-embedding-ada-002" 

我们初始化 OpenAI 客户端:

# Initialize the OpenAI client
client = openai.OpenAI() 

然后创建一个嵌入函数,该函数将发送给它的文本转换为嵌入。该函数旨在使用我们选择的嵌入模型为一批输入文本(texts)生成嵌入,在这种情况下,为 text-embedding-3-small

def get_embedding(texts, model="text-embedding-3-small") 

函数首先通过将每个文本中的换行符替换为空格来清理文本:

texts = [text.replace("\n", " ") for text in texts] 

然后,该函数执行 API 嵌入调用:

response = client.embeddings.create(input=texts, model=model) 

嵌入的向量是从响应中提取的:

embeddings = [res.embedding for res in response.data]  # Extract embeddings 

最后,返回嵌入的向量:

return embeddings 

程序现在已准备好嵌入块。

将块嵌入

程序首先定义一个函数来嵌入块:

def embed_chunks(
    chunks, embedding_model="text-embedding-3-small",
    batch_size=1000, pause_time=3
): 

函数的参数是:

  • chunks: 要嵌入的文本部分

  • embedding_model: 定义要使用的模型,例如text-embedding-3-small

  • batch_size: 函数在单个批次中可以处理的块的数量,例如batch_size=1000

  • pause_time: 以秒为单位的暂停时间,这在速率限制中可能很有用

然后我们初始化计时函数、embeddings变量和计数器:

**start_time** = time.time()  # Start timing the operation
**embeddings** = []  # Initialize an empty list to store the embeddings
**counter** = 1  # Batch counter 

代码现在已准备好批量处理文本块:

# Process chunks in batches
    for i in range(0, len(chunks), batch_size):
        chunk_batch = chunks[i:i + batch_size]  # Select a batch of chunks 

然后将每个批次发送到嵌入函数:

 # Get the embeddings for the current batch
        current_embeddings = get_embedding(
            chunk_batch, model=embedding_model
        ) 

嵌入的批次被追加到嵌入列表中:

# Append the embeddings to the final list
        embeddings.extend(current_embeddings) 

监控批次的数量并显示,然后激活暂停:

 # Print batch progress and pause
        print(f"Batch {counter} embedded.")
        counter += 1
        time.sleep(pause_time)  # Optional: adjust or remove this depending on rate limits 

一旦所有批次都处理完毕,将显示总时间:

 # Print total response time
    response_time = time.time() - start_time
    print(f"Total Response Time: {response_time:.2f} seconds") 

嵌入函数现在可以调用带有块列表:

embeddings = embed_chunks(chunks) 

输出显示场景数据已嵌入:

Batch 1 embedded.
Total Response Time: 4.09 seconds 

首个嵌入用于验证:

print("First embedding:", embeddings[0]) 

输出确认嵌入已生成:

First embedding: 0.017762450501322746, 0.041617266833782196, -0.024105189368128777,… 

最终验证是检查嵌入的数量是否与块的数量匹配:

# Check the lengths of the chunks and embeddings
num_chunks = len(chunks)
print(f"Number of chunks: {num_chunks}")
print(f"Number of embeddings: {len(embeddings)}") 

输出确认分块和嵌入过程很可能成功:

Number of chunks: 3
Number of embeddings: 3 

文本块和嵌入现在已准备好更新到 Pinecone 索引。

创建 Pinecone 索引

我们将要创建的genai-v1 Pinecone 索引将包含两个命名空间,如图图 3.3所示:

  • genaisys: 指令场景的存储库。这些提示驱动生成式 AI 行为,也可以触发传统功能,如网络搜索。

  • Data01: RAG 管道查询的经典嵌入数据。

![图 3.3:将 Pinecone 索引分区为命名空间

图 3.3:将 Pinecone 索引分区为命名空间

我们首先导入两个类:

from pinecone import Pinecone, ServerlessSpec 

Pinecone类是与 Pinecone 索引交互的主要接口。我们将使用这个类来配置 Pinecone 的无服务器服务。

在继续之前,您需要设置一个 Pinecone 账户并获取一个 API 密钥。请确保在www.pinecone.io/上验证这些服务的费用。本章是自包含的,因此您可以在决定创建 Pinecone 账户之前先阅读内容、评论和代码。

一旦我们的账户设置好,我们需要检索并初始化我们的 API 密钥:

# Retrieve the API key from environment variables
api_key = os.environ.get('PINECONE_API_KEY')
if not api_key:
    raise ValueError("PINECONE_API_KEY is not set in the environment!")
# Initialize the Pinecone client
pc = Pinecone(api_key=api_key) 

我们现在导入规范类,定义我们的索引名称(genai-v1),并为我们的场景初始化第一个命名空间(genaisys):

from pinecone import ServerlessSpec
index_name = "genai-v1"
namespace="genaisys" 

我们现在需要做出一个项目管理决策——使用 Pinecone 云托管我们的索引或Amazon Web ServicesAWS)?

cloud = os.environ.get('PINECONE_CLOUD') or 'aws'
region = os.environ.get('PINECONE_REGION') or 'us-east-1'
spec = ServerlessSpec(cloud=cloud, region=region) 

代码首先检查是否设置了环境变量(PINECONE_CLOUD)以使用 Pinecone 云。如果没有预定义的环境变量检查设置,则变量默认为 AWS,默认区域为'aws''us-east-1'

更多信息,请参阅 Pinecone Python SDK 文档docs.pinecone.io/reference/python-sdk

在这种情况下,选择 AWS 的原因如下:

  • 市场领导力和可靠性:AWS 在全球基础设施市场占有超过 30% 的市场份额。因此,它被大量组织认为是可靠的。

  • 合规性和安全标准:AWS 拥有超过 140 项数据安全和隐私安全标准,包括 PCI-DSS 和 HIPAA/HITECH、FedRAMP、GDPR、FIPS 140-2 和 NIST 800-171。

  • 可扩展性:AWS 拥有全球数据中心网络,使可扩展性无缝。

或者,您可以在 Pinecone 控制台中手动创建索引以选择嵌入模型和主机,例如 AWS 或 Google Cloud PlatformGCP)。您还可以选择从 x1 到更多的大小,这将确定您索引的最大大小。每个选择都取决于您的项目和资源优化策略。

在任何情况下,我们需要指标来监控使用情况和成本。Pinecone 通过您的账户提供详细的指标,使您能够有效地管理索引。例如,我们可能想要删除不再需要的信息,添加目标数据,或优化每个用户的使用情况。

Pinecone 提供三个关键指标:

  • 无服务器存储使用量:以 千兆时GB-hours)衡量。成本按每小时 1 GB 存储计算。仔细监控我们存储的数据量是任何 AI 项目的重要因素。

  • 无服务器写入操作单位:衡量写入到包含我们索引的 Pinecone 数据库的操作消耗的资源。

  • 无服务器读取操作 单位:衡量读取操作消耗的资源。

您可以通过访问您的 Pinecone 账户,选择使用情况,然后点击此处所示的下载按钮来下载您的详细消费信息:

图 3.4:下载 Pinecone 使用数据

图 3.4:下载 Pinecone 使用数据

下载的文件是 CSV 格式,包含我们 Pinecone 使用情况的详细记录,例如 BillingAccountId(账户标识符)、BillingAccountName(账户名称)、OrganizationName(组织名称)、OrganizationId(组织 ID)、ProjectId(项目标识符)、ProjectName(项目名称)、ResourceId(资源标识符)、ResourceName(资源名称)、ChargePeriodStart(收费开始日期)、ChargePeriodEnd(收费结束日期)、BillingPeriodStart(账单开始日期)、BillingPeriodEnd(账单结束日期)、SkuId(SKU 标识符)、SkuPriceId(SKU 价格 ID)、ServiceName(服务名称)、ChargeDescription(收费详情)、CloudId(云提供商)、RegionId(区域)、Currency(货币类型)、PricingQuantity(使用量)、PricingUnit(使用单位)、ListCost(列出的成本)、EffectiveCost(计算成本)、BilledCost(最终成本)和 Metadata(附加数据)。

随着人工智能逐渐进入其工业时代,逐渐远离 2020 年代初的初始兴奋,对这些指标的不断监控变得越来越关键。

我们现在将检查我们选择的索引是否存在。程序导入pineconetime类,在检查索引是否存在之前插入一个睡眠时间:

import time
import pinecone
# check if index already exists (it shouldn't if this is first time)
if index_name not in pc.list_indexes().names(): 

如果索引已存在,以下代码将被跳过以避免创建重复索引。如果不存在,则创建索引:

 # if does not exist, create index
    pc.create_index(
        index_name,
        dimension=1536,  # dimension of the embedding model
        metric='cosine',
        spec=spec
    )
    # wait for index to be initialized
    time.sleep(1) 

参数如下:

  • index_name,这是我们的 Pinecone 索引名称,genai-v1

  • dimension=1536,嵌入向量的维度

  • metric='cosine',这设置了相似度搜索的距离度量标准为余弦相似度

  • spec=spec,它定义了我们之前为云服务定义的区域和服务器无规格

  • time.sleep(1),这使得程序等待以确保索引完全创建后再继续

如果索引刚刚创建,输出将显示其详细信息,其中total_vector_count设置为0(如果您看到除0以外的数字,笔记本可能已经运行过):

{'dimension': 1536,
 'index_fullness': 0.0,
 'namespaces': {},
 'total_vector_count': 0} 

如果索引已经存在,将显示统计信息,包括index_fullness以监控索引 pod 中使用的空间从 0 到 1:

Index stats
{'dimension': 1536,
 'index_fullness': 0.0,
 'namespaces': {'genaisys': {'vector_count': 3}},
 'total_vector_count': 3} 

在这种情况下,我们尚未填充索引。我们可以在填充之前连接到我们刚刚创建的索引并显示其统计信息:

# connect to index
index = pc.Index(index_name)
# view index stats
index.describe_index_stats() 

输出显示信息,确认我们已连接:

{'dimension': 1536,
 'index_fullness': 0.0,
 'namespaces': {'genaisys': {'vector_count': 0}},
 'total_vector_count': 0} 

选定的嵌入模型必须与 Pinecone 索引的维度(1536)匹配。当我们开始处理使用案例时,我们将交互式地创建 Pinecone 索引的参数,见第五章。在这里,我们使用embedding_model="text-embedding-3-small及其 1,536 维,这与 Pinecone 索引的维度相匹配。

还要注意,我们初始化的'genaisys'命名空间被考虑在内。这确保了当我们上载我们设计的场景时,它们不会与另一个命名空间中的经典数据混淆。我们现在已准备好将数据上载到我们的 Pinecone 索引。

将指令场景上载到索引

将嵌入块上载到 Pinecone 索引需要成本,如本节开头所述。我们必须仔细决定要上载哪些数据。如果我们上载所有数据,我们可能会做以下操作:

  • 过载索引并使检索变得具有挑战性,无论是指令场景还是经典数据

  • 提高读写操作的成本

  • 添加比可管理的更多的噪声并混淆检索函数

如果我们选择不上载数据,我们有两种选择:

  • 实时内存查询:将分块嵌入的数据加载到内存中,并实时查询信息可以减轻数据存储的负担,并且是一种处理我们不需要存储的临时信息的实用方法,例如每日天气预报。然而,我们也必须权衡这种方法与我们在从第五章开始的工作用例中每一步进行更新时的成本/效益。

  • 微调数据:这伴随着构建训练数据集的成本,这需要人力和计算资源。在快速变化的市场中,我们可能需要定期进行微调,这需要高额投资。成本/效益将由项目管理团队考虑。将在第五章中探讨微调与 RAG 的成本/效益分析。

我们首先初始化库并开始计时器以测量脚本运行所需的时间:

import pinecone
import time
import sys
start_time = time.time()  # Start timing before the request 

程序随后必须计算发送到 Pinecone 的批次的最大大小。为了安全起见,它设置为 400,000 字节,或 4 MB。如果达到限制,则返回批次大小:

# Function to calculate the size of a batch
def get_batch_size(data, limit=4000000):  # limit set to 4MB to be safe
    total_size = 0
    batch_size = 0
    for item in data:
        item_size = sum([sys.getsizeof(v) for v in item.values()])
        if total_size + item_size > limit:
            break
        total_size += item_size
        batch_size += 1
    return batch_size 

我们现在需要一个upsert函数,它在被调用时考虑批次大小:

# Upsert function with namespace
def upsert_to_pinecone(batch, batch_size, namespace="genaisys"):
    """
    Upserts a batch of data to Pinecone under a specified namespace.
    """
    try:
        index.upsert(vectors=batch, namespace=namespace)
        print(
            f"Upserted {batch_size} vectors to namespace '{namespace}'."
        )
    except Exception as e:
        print(f"Error during upsert: {e}") 

在生产环境中,我们通常会因错误而退出,但在这个教育笔记中,打印信息有助于我们观察而不停止执行。

注意,我们将把指令场景更新到 Pinecone 索引中的命名空间genaisys内。我们现在可以定义主要的批次更新函数:

def batch_upsert(data): 

函数首先确定数据的总长度,然后准备与get_batch_size函数计算出的批次大小相匹配的批次。然后,它创建一个批次并将其发送到我们定义的upsert_to_pinecone函数:

# Function to upsert data in batches
def batch_upsert(data):
    total = len(data)
    i = 0
    while i < total:
        batch_size = get_batch_size(data[i:])
        batch = data[i:i + batch_size]
        if batch:
            upsert_to_pinecone(batch, batch_size, namespace="genaisys")
            i += batch_size
            print(f"Upserted {i}/{total} items...")  # Display current progress
        else:
            break
    print("Upsert complete.") 

当更新完成后,输出将显示成功消息,表明我们已准备好准备更新过程。Pinecone 索引需要一个 ID,我们现在将创建它:

# Generate IDs for each data item
ids = [str(i) for i in range(1, len(chunks) + 1)] 

一旦每个嵌入块都有一个 ID,我们需要格式化数据以适应 Pinecone 的索引结构:

# Prepare data for upsert
data_for_upsert = [
    {"id": str(id), "values": emb, "metadata": {"text": chunk}}
    for id, (chunk, emb) in zip(ids, zip(chunks, embeddings))
] 

数据现在已格式化,带有 ID、值(嵌入)和元数据(块)。让我们调用batch_upsert函数,该函数将调用我们创建的相关函数:

# Upsert data in batches
batch_upsert(data_for_upsert) 

当更新过程完成后,将显示已更新到命名空间中的向量的数量以及所需时间:

Upserted 3 vectors to namespace 'genaisys'.
Upserted 3/3 items...
Upsert complete.
Upsertion response time: 0.45 seconds 

我们还可以显示 Pinecone 索引的统计信息:

#You might have to run this cell after a few seconds to give Pinecone
#the time to update the index information
print("Index stats")
print(index.describe_index_stats(include_metadata=True)) 

注意,你可能需要等待几秒钟,以便给 Pinecone 更新索引信息的时间。

输出显示以下信息:

Index stats
{'dimension': 1536,
 'index_fullness': 0.0,
 'namespaces': {'genaisys': {'vector_count': 3}},
 'total_vector_count': 3} 

显示的信息如下:

  • 'dimension': 1536:嵌入的维度。

  • 'index_fullness': 0.0: 一个介于 0 和 1 之间的值,显示 Pinecone 索引的满载程度。我们必须监控此值以优化我们正在 upsert 的数据,以避免需要增加我们使用的存储容量的尺寸。有关更多信息,请参阅 Pinecone 文档docs.pinecone.io/guides/get-started/overview

  • 'namespaces': {'genaisys': {'vector_count': 3}}: 显示命名空间和向量数。

  • 'total_vector_count': 3}: 显示 Pinecone 索引中的总向量数。

现在,我们已经准备好将经典数据上传到其命名空间。

将经典数据 upsert 到索引中

构建 GenAISys 需要团队。为了使每个团队能够并行工作以优化生产时间,我们将在一个单独的程序/笔记本中 upsert 经典数据。一个团队可以处理指令场景,而另一个团队可以收集和处理数据。

打开 Pinecone_RAG.ipynb。我们将重用本章“构建动态 Pinecone 索引”部分中构建的 Pinecone_instruction_scenarios.ipynb 笔记本中的几个组件。设置环境与上一个笔记本相同。Pinecone 索引相同,genai-v1。源数据 upsert 的命名空间为 data01,正如我们在前面的章节中已经建立的,以确保数据与指令场景分开。因此,唯一的真正区别是我们加载的数据和分块方法。让我们开始吧!

数据加载和分块

本节使用与 Pinecone_instruction_scenarios.ipynb 中指令场景相同的流程嵌入块。然而,这次,GPT-4o 进行分块。当我们导入指令场景的行时,我们希望在一个块中保持场景的完整性,以便能够向生成 AI 模型提供一组完整的指令。在这种情况下,我们将利用生成 AI 的力量,并使用 GPT-4o 对原始文本进行分块。

我们首先下载数据,而不是场景,并设置文件路径:

download("Chapter03","data01.txt")
# Load the CSV file
file_path = '/content/data01.txt' 

现在,文本文件已作为一个大块加载到一个变量中并显示:

try:
    with open(file_path, 'r') as file:
        text = file.read()
    text
except FileNotFoundError:
    text = "Error: File not found. Please check the file path."
print(text) 

在生产应用程序中,通常会因关键 FileNotFoundError 而退出,但对于这个教育笔记本,打印错误允许我们观察结果而不中断学习流程。

您可以注释 print(text) 或只打印几行。在这种情况下,让我们验证我们是否正确地导入了文件。输出显示我们已经这样做:

The CTO was explaing that a business-ready generative AI system (GenAISys) offers functionality similar to ChatGPT-like platforms… 

文本包含来自我们上传到自定义 RAG 数据库的公司 CTO 的消息。一家公司可能有数千条这样的内部消息——太多(且太不稳定)以至于无法证明模型微调的合理性。仅在 Pinecone 中存储关键块可以为我们提供可搜索的上下文,而不会使索引充满噪音。

text 变量尚未准备好由 GPT-4o 分块。第一步是创建一个 OpenAI 实例并给出 GPT-4o 模型的指令:

# Import libraries
from openai import OpenAI
# Initialize OpenAI Client
client = OpenAI()
# Function to chunk text using GPT-4o
def chunk_text_with_gpt4o(text):
    # Prepare the messages for GPT-4o
    messages = [
        {"role": "system", "content": "You are an assistant skilled at splitting long texts into meaningful, semantically coherent chunks of 50-100 words each."},
        {"role": "user", "content": f"Split the following text into meaningful chunks:\n\n{text}"}
    ]
Now we send the request to the API:
    # Make the GPT-4o API call
    response = client.chat.completions.create(
        model="gpt-4o",  # GPT-4o model
        messages=messages,
        temperature=0.2,  # Low randomness for consistent chunks
        max_tokens=1024  # Sufficient tokens for the chunked response
    ) 

我们需要关注 max_tokens=1024 设置:GPT-4o 会在达到该限制时停止生成。对于非常大的文档,您可以将文本流式传输为较小的片段——然后让 GPT-4o 精细化每个片段。我们还可以使用现成的分块函数,这些函数将文本分解为优化的 ,以在检索数据时获得更细微和精确的结果。然而,在这种情况下,让我们最大限度地使用 GPT-4o;我们通过一个低温度的调用发送整个文件,这样我们可以观察模型从头到尾分割真实世界的文档。

现在,我们可以从响应中检索块,清理它们,将它们存储在块列表中,并返回 chunks 变量:

 # Extract and clean the response
    chunked_text = response.choices[0].message.content
    chunks = chunked_text.split("\n\n")  # Assume GPT-4o separates chunks with double newlines
    return chunks 

现在,我们可以调用分块函数。我们不需要显示块,并且可以在生产环境中注释代码。然而,在这种情况下,让我们验证一切是否正常工作:

# Chunk the text
chunks = chunk_text_with_gpt4o(text)
# Display the chunks
print("Chunks:")
for i, chunk in enumerate(chunks):
    print(f"\nChunk {i+1}:")
    print(chunk) 

输出显示块已成功创建:

Chunks:
Chunk 1:
The CTO was explaining that …
Chunk 2:
GenAISys relies on a generative AI model…
Chunk 3:
We defined memoryless, short-term, long-term… 

剩余的嵌入和 Upsert 步骤与 Pinecone_instruction_scenarios.ipynb 中的步骤相同——只需记住在写入向量时使用 namespace="data01"。之后,我们就准备好查询索引并验证检索。

查询 Pinecone 索引

如你所知,我们的向量存储现在有两个逻辑区域—genaisys 用于指令场景,data01 用于经典数据。在本节中,我们将在将代码集成到 第四章 中的多用户界面之前,交互式地查询每个区域以证明检索代码是有效的。我们将在 Pinecone 索引中查询这两个命名空间,如图 3.5 所示:

图 3.5:生成式 AI 模型查询指令场景或数据

图 3.5:生成式 AI 模型查询指令场景或数据

打开 Query_Pinecone.ipynb 运行验证查询。接下来的步骤与 设置环境创建 Pinecone 索引 部分的步骤相同,除了两个细微的差异:

  • 连接到 Pinecone 索引时,我们不提供命名空间,只提供其名称:index_name = 'genai-v1'。这是因为查询函数将管理命名空间的选择。

  • 笔记本中的 Upserting 部分已被移除,因为我们不是进行 Upsert 操作,而是在查询 Pinecone 索引。

笔记本中的 Query 部分分为两个子部分。第一个子部分包含查询函数,第二个子部分包含查询请求。让我们从查询函数开始。

查询函数

有四个查询函数,如下所示:

  • QF1: query_vector_store(query_text, namespace),它接收查询,将请求发送到 QF2,并返回响应。它将使用 QF4 来显示结果。

  • QF2: get_query_results(query_text, namespace),它接收来自 QF1 的查询,将其发送到 QF3 进行嵌入,执行实际查询,并将响应返回给 QF1。

  • QF3: get_embedding(text, model=embedding_model),它接收来自 QF2 的要嵌入的文本,并将嵌入的文本发送回 QF2。

  • QF4: display_results(query_results),它接收来自 QF1 的结果,处理它们,并将它们返回给 QF1。

我们可以通过创建两个函数组来简化表示,如 图 3.6 所示:

  • 一个包含 QF1、query_vector_store 和 QF4、display_results 的组,其中 QF1 通过 QF2 查询向量存储,并将结果返回以显示。

  • 一个包含 QF2、get_query_results 的组在将查询通过 QF3、get_embedding 嵌入后查询向量存储,并将结果返回给 QF1。

图 3.6:使用两组函数查询向量存储

图 3.6:使用两组函数查询向量存储

让我们从第一组函数开始。

查询向量存储并返回结果

第一个函数,QF1,接收用户输入:

def query_vector_store(query_text, namespace):
    print("Querying vector store...") 

然后,函数调用 QF2 的 query_results

 # Retrieve query results
    query_results = get_query_results(query_text, namespace) 

QF2 然后返回 query_results 中的结果,该结果随后被发送到 display_results 以获取文本和目标 ID:

 # Process and display the results
    print("Processed query results:")
    text, target_id = display_results(query_results)
    return text, target_id 

display_results 处理它接收到的查询结果,并返回结果以及元数据以找到在 Pinecone 索引的元数据中获得的文本。当找到时,函数检索 ID:

def display_results(query_results):
    for match in query_results['matches']:
        print(f"ID: {match['id']}, Score: {match['score']}")
        if 'metadata' in match and 'text' in match['metadata']:
            text=match['metadata']['text']
            #print(f"Text: {match['metadata']['text']}")
            target_id = query_results['matches'][0]['id']  # Get the ID from the first match
            #print(f"Target ID: {target_id}")
        else:
            print("No metadata available.")
      return text, target_id 

文本和 ID 返回给 QF1、query_vector_store,然后该函数在调用时返回结果。请注意,出于教育目的,此函数假定 query_results 将始终至少包含一个具有 'metadata''text' 字段的匹配项。现在让我们看看查询是如何处理的。

处理查询

程序使用 get_query_results 函数查询 Pinecone 索引,输入文本和命名空间提供。但首先,必须将输入文本嵌入,以便在向量存储中进行向量相似度搜索:

def get_query_results(query_text, namespace):
    # Generate the query vector from the query text
    query_vector = get_embedding(query_text)  # Replace with your method to generate embeddings 

一旦输入被嵌入,就在指定的命名空间内请求使用向量化的输入进行向量搜索:

 # Perform the query
    query_results = index.query(
        vector=query_vector,
        namespace=namespace,
        top_k=1,  # Adjust as needed
        include_metadata=True
    ) 

注意,在这个例子中,k 被设置为 1 以获取单个最精确的结果,同时,元数据被设置为 True 以包含相应的文本。结果返回到 QF2 的 query_results

 # Return the results
    return query_results 

嵌入函数与我们用于在 Pinecone 索引中更新数据时使用的函数相同:

import openai
client = openai.OpenAI()
embedding_model = "text-embedding-3-small"
def get_embedding(text, model=embedding_model):
    text = text.replace("\n", " ")
    response = client.embeddings.create(input=[text], model=model)
    embedding = response.data[0].embedding
    return embedding 

确保使用与嵌入您已更新的数据相同的模型来嵌入查询,以便嵌入的输入与存储的嵌入数据具有相同的向量格式。这对于进行准确的相似度计算至关重要。

我们现在准备运行两个测试:一个指令场景查询(命名空间 genaisys)和一个源数据查询(命名空间 data01)。

检索查询

要检索一个指令场景,我们将输入用户输入和命名空间,让系统找到最接近的指令来执行:

# Define your namespace and query text
namespace = "genaisys"  # Example namespace
query_text = "The customers like the idea of travelling and learning. Provide your sentiment." 

系统应检测到简短提出的任务,并返回一个全面的指令场景。为此,我们将调用函数的入口点query_vector_store,并显示返回的输出:

# Call the query function
text, target_id = query_vector_store(query_text, namespace)
# Display the final output
print("Final output:")
print(f"Text: {text}")
print(f"Target ID: {target_id}") 

输出令人满意,并准备好在第四章的对话循环中使用:

Querying vector store...
Processed query results:
ID: 2, Score: 0.221010014
Querying response time: 0.54 seconds
Final output:
Text: 200,Sentiment analysis  Read the content return a sentiment analysis nalysis on this text and provide a score with the label named : Sentiment analysis score followed by a numerical value between 0 and 1  with no + or - sign and  add an explanation to justify the score.
Target ID: 2 

程序现在从 Pinecone 索引中检索数据。由于命名空间是一个变量,查询函数是相同的。让我们只看看查询和输出。查询是针对数据命名空间的:

# Define your namespace and query text
namespace = "data01"  # Example namespace
query_text = "What did the CTO say about the different types of memory?"
The result is printed:
# Display the final output
print("Final output:")
print(f"Text: {text}")
print(f"Target ID: {target_id}") 

输出令人满意:

Querying vector store...
Processed query results:
ID: 3, Score: 0.571151137
Querying response time: 0.45 seconds
Final output:
Text: We defined memoryless, short-term, long-term memory, and cross-topic memory. For the hybrid travel marketing campaign, we will distinguish semantic memory (facts) from episodic memory (personal events in time, for example). The CTO said that we will need to use episodic memories of past customer trips to make the semantic aspects of our trips more engaging.
Target ID: 3 

因此,我们已经填充了一个 Pinecone 向量存储并对其进行了查询。在我们继续添加更多层到我们的 GenAISys 之前,让我们总结一下 Pinecone 索引的实现。

摘要

在本章中,我们通过超越普通的 RAG,将我们的 GenAISys 项目推进了一步。首先,我们在源数据语料库之上叠加了专家编写的指令场景,将静态的 RAG 管道转变为一个动态框架,不仅可以检索事实,还可以检索模型应遵循的确切推理模式。全球市场正在迅速加速,用户现在在需要时立即期望 ChatGPT 级别的帮助;如果我们希望保持同步,我们的架构必须灵活、成本意识强,并且能够实现近乎实时交付。

我们首先概述了该架构,然后介绍了递减回报定律,以确定何时隐式相似性搜索值得其计算成本,何时直接、显式的调用——例如简单的网络搜索——能以更低成本完成任务。在理论确立之后,我们编写了一个程序,用于下载、分块、嵌入并将指令场景更新到一个 Pinecone 索引中的专用命名空间。接下来,我们部署了 GPT-4o 来对源文档执行相同的分块和嵌入流程,并将这些向量存储在第二个命名空间中。一旦两个分区都到位,我们就验证了检索层:现在单个查询函数会将任何提示路由到正确的命名空间,并返回最佳匹配及其元数据。

在场景和数据清晰分离且可即时搜索的情况下,GenAISys 拥有了所需的检索骨干。在下一章中,我们将将这些组件插入到对话循环中,让系统展示其全面、业务就绪的敏捷性。

问题

  1. 在生成式 AI 系统中自动化所有任务没有限制。(对或错)

  2. 递减回报定律在人工智能中毫无用处。(对或错)

  3. 分块是将数据分解成更小部分以检索更细微信息的过程。(对或错)

  4. 你应该只使用一个嵌入模型。(对或错)

  5. 向 Pinecone 索引中上载数据意味着将数据上传到数据库。(对或错)

  6. 命名空间是数据库的名称。(对或错)。

  7. 命名空间可用于访问不同类型的数据。(正确或错误)

  8. 查询 Pinecone 索引需要用户输入进行嵌入。(正确或错误)

  9. 查询 Pinecone 索引基于诸如余弦相似度之类的度量。(正确或错误)

  10. Pinecone 索引和查询函数是 GenAISys 的唯一组件。(正确或错误)

参考文献

进一步阅读

第四章:构建 AI 控制器编排界面

今天的商业需要以前从未达到的速度来设计、生产和交付商品和服务。响应性几乎在每一个领域都已成为关键,从在线云服务到交付食物、药物、服装等等。这样一个事件驱动的经济产生了一连串的任务,只有同样事件驱动的、以人为本的生成式 AI 系统GenAISys)才能跟上。

即使是最自动化的工作流程,人类的判断仍然是基础:当火灾爆发、风暴摧毁基础设施或供应链出现问题时,团队——而不仅仅是算法——必须采取行动。一个将人类排除在外的先进 GenAISys 只是一个神话。因此,本章首先概述了一个架构,该架构拆除了用户和 AI 之间的墙壁,以创建一个协作的多用户聊天机器人。

首先,我们从高层次概述事件驱动的 GenAISys 界面,展示早期章节中的构建块——短期、情景和长期记忆,多轮对话代理,以及用于指令场景和数据的双 RAG 管道——是如何组合在一起的。为了实现响应式系统,我们必须编码 GenAISys 的过程,然后是管理生成式 AI 代理的对话代理。一旦我们的 GenAISys 界面构建完成,我们将进行多用户、多轮对话,三个用户在一个在线旅行社中工作。他们的在线会议将包括一个作为参与者的对话 AI 代理。

这些用户将能够与或没有 AI 代理进行在线会议。他们可以利用 RAG 来查找指令场景或简单地要求生成式 AI 代理回答问题。到本章结束时,我们将有一个完全工作的 GenAISys 界面,准备进行多模态思维链扩展(第五章)。

简而言之,本章涵盖了以下主题:

  • 事件驱动的 GenAISys 界面架构的高层次视图

  • GenAISys 界面的低级、实战流程图

  • 实现对输入、AI 代理和活跃用户的响应小部件

  • 聊天机器人在多轮对话中的事件驱动流程

  • 以 AI 代理作为参与者的多用户 GenAISys 对话

  • 对话代理的响应 RAG 功能

  • GenAISys 界面和 AI 代理的编排能力

我们的首要任务是定义一个事件驱动的 GenAISys 界面。

事件驱动的 GenAISys 界面架构

我们的事件驱动 GenAISys 界面集成了我们在前几章中构建的功能。该界面将利用 IPython 小部件的灵活性,创建一个反应式的事件驱动环境,其中以下内容适用:

  • 高级任务将是事件驱动的,由用户输入触发

  • 生成式 AI 任务将触发生成式 AI 代理功能

我们将首先从高层次上检查我们正在构建的程序,如图 4.1 所示:

图 4.1:GenAISys 接口的高级架构

图 4.1:GenAISys 接口的高级架构

让我们回顾一下在前几章中已经构建的功能,并列出本章添加的关键功能:

  • I1 – AI 控制器:本章的主要新组件是具有响应式小部件的生成式 AI Python 接口,它将作为 AI 控制器和协调器运行

  • I2 – 多用户聊天机器人:多个用户同时交互的聊天界面

  • F1 – 生成式 AI 模型:继承自所有前面的章节,特别是 第三章,其中我们使用 GPT-4o 运行生成式 AI 调用

  • F2 – 记忆保持:继承自 第一章,其中介绍了不同类型的记忆

  • F3 – 模块化 RAG:继承自 第三章 的指令和数据管道

  • F4 – 多功能能力:从 第二章第三章 中提取语义和情感分析,将在 第五章 中扩展,包括图像、音频、网络搜索和机器学习功能

要构建这个架构,我们将执行以下操作:

  • 构建 GenAISys 接口的事件驱动流程

  • 使用 GPT-4o 和 OpenAI 嵌入式模型实现对话代理

  • 运行一个多用户、多轮会话,探索 GenAISys AI 控制器和协调器的主要功能

决定在没有箭头的情况下展示 GenAISys 架构的主要组件(在本章和下一章),这是一个故意的选择,旨在传达一个核心概念:模块化和架构灵活性。该图不是一个刚性的蓝图,而是一个概念工具包。它展示了您可用的强大组件——I1. AI 控制器I2. 多用户聊天机器人F1. 生成式 AI 模型F2. 记忆保持F3. 模块化 RAGF4. 多功能能力——作为独立的、可互操作的块。这赋予您权力,说明您可以自由设计自己的系统架构。例如,用户可以选择运行一些功能组件,如 F4. 多功能能力,作为独立的、分布式的代理,由控制器调用。或者,他们可以实施一个完全不同的界面,甚至在没有界面的情况下运行系统。

然而,这个架构的重点在于展示以人为中心的 GenAISys。在这个配置中,I1. AI 控制器(生成式 AI IPython 界面)作为中央枢纽和协调者。这种以人为中心的架构保证了完全控制和透明度。这在构建风险规避的企业环境中的信任至关重要。虽然控制流程没有用箭头表示,但它是隐含的:I2. 多用户聊天机器人的用户交互由 AI 控制器管理,然后战略性地将任务委托给各种功能组件(F1F4)以生成响应、访问内存、执行 RAG 或执行特定功能。这种方法提供了一条清晰、稳定且可解释的路径,用于构建商业就绪的生成式 AI 系统。

让我们先探讨以场景驱动的任务执行。

构建事件驱动的 GenAISys 界面流程

让我们从构建图 4.2中显示的 GenAISys 界面开始,使用 IPython 小部件创建一个响应式、事件驱动的环境。结果将是一个动态的多用户聊天界面,带有下拉菜单、文本输入字段和复选框——所有这些对于人们/用户与生成式 AI 代理之间的实时协作都是必需的。

在 GitHub 的 Chapter04 目录中打开Event-driven_GenAISys_framework.ipynb笔记本(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。设置环境与前面章节中描述的相同:

  • 要设置 OpenAI,请参考第一章,包括此处使用的自定义 OpenAI API 调用:openai_api.make_openai_api_call

  • 请参考第三章以设置 Pinecone,连接到索引并查询它

需要额外的包(ipython)用于笔记本环境。Google Colab 中已预装 IPython;如果需要,请使用以下命令安装:

!pip install ipython 

我们将要构建的代码演示了核心概念,例如事件驱动的交互、动态内容更新和模块化函数组织。在本节结束时,你将学会如何弥合人工智能功能与最终用户参与之间的差距。

图 4.2:事件驱动的 GenAISys 界面流程图

图 4.2:事件驱动的 GenAISys 界面流程图

构建此界面所需的主要功能组如下:

  • 初始化小部件

  • 处理用户输入和选择更改

  • 处理聊天消息,包括触发函数和退出命令

  • 生成和处理 AI 响应

  • 动态更新 UI

  • 保存对话历史

在从开发者的角度深入代码之前,让我们牢记用户的视角。我们必须构建一个直观的界面,可以无缝执行图 4.2中概述的流程。

图 4.3:从用户角度看到的 GenAISys

图 4.3:从用户角度看到的 GenAISys

黑色背景上的放大镜  AI 生成的内容可能不正确。提示:需要查看此图像的高分辨率版本?在下一代 Packt Reader 中打开此书或在其 PDF/ePub 副本中查看。

下一代 Packt Reader随本书免费赠送。扫描二维码或访问packtpub.com/unlock,然后使用搜索栏通过书名查找此书。请仔细核对显示的版本,以确保您获得正确的版本。

白色背景上的二维码  AI 生成的内容可能不正确。

UI 中只包含三个小部件:一个用于输入提示的输入框、一个用于选择活动用户的下拉列表和一个用于激活和停用对话 AI 代理的复选框。

让我们逐步了解设置和运行此交互式 GenAISys 环境的过程。

1. 开始

程序从“与代理作为参与者的多用户对话”单元格开始。我们首先导入所需的模块和库,从IPython开始:

from IPython.display import display, HTML, clear_output 

让我们逐一了解在 Google Colab 中将要实现的功能:

  • displayHTML用于显示小部件、图像和丰富的 HTML 输出

  • clear_output用于清除单元格的输出

然后,我们导入由 Jupyter 项目管理的ipywidgets

from ipywidgets import Dropdown, Text, Checkbox, VBox, Layout 

ipywidgets是本笔记本交互界面的核心组件,我们将使用以下小部件:

  • Dropdown:一个下拉小部件,可以从选项列表中选择一个值

  • Text:一个用于用户文本输入的小部件

  • Checkbox:一个用于布尔值选中/未选中输入的小部件

  • Vbox:一个容器小部件,用于以垂直框布局排列子小部件

  • Layout:使用布局属性(如宽度、高度和边距)自定义小部件的样式

最后,我们导入 JSON,用于存储多用户对话历史:

import json 

然后,我们初始化所有用户的对话历史,定义第一个活动用户,并将活动对话设置为True

# Initialize conversation histories for all users and active user
user_histories = {"User01": [], "User02": [], "User03": []}
active_user = "User01"  # Default user
conversation_active = True 

因此,从一开始,我们就在初始化一个多用户协作的 GenAISys,其中用户可以是人类提示和系统提示。例如,“用户”可以是从另一个系统来的消息,并通过读取待处理消息的事件触发此界面。用户列表可以扩展,存储在变量中,或用于满足项目需求的各种用户管理系统,包括访问权限、密码和各种应用程序的角色。接下来,我们初始化小部件本身。

2. 初始化小部件

代码现在设置了所需的DropdownTextCheckbox小部件。这些小部件也链接到事件处理器。用户Dropdown小部件定义了在对话开始时初始化的三个用户:

# Create a dropdown to select the user
user_selector = Dropdown(
    options=["User01", "User02", "User03"],
    value=active_user,
    description='User:',
    layout=Layout(width='50%')
) 

选择器有四个参数:

  • options 列出了可用于扩展并可访问任何用户管理仓库的可用用户。

  • value 确定活动用户。程序以 User01 作为初始用户启动。当授权用户首次连接到 GenAISys 时,这可以自动化。

  • description 为将要显示的下拉列表提供标签。

  • layout 设置将要显示的小部件的宽度。

注意,我们正在创建一个核心 GenAISys,而不是一个平台。目标是掌握 GenAISys 的内部工作原理。一旦它按预期工作,我们就可以添加经典的用户管理层(名称、角色和权限)。在这种情况下,我们保持专注于 GenAISys 的灵活核心概念,而不是它们将如何封装在特定的平台和框架中。我们正在学习如何成为生成式 AI 代理架构师,而不是特定框架的操作员。

下一步是插入事件处理器。在这种情况下,它是一个事件监听器,用于检测 user_selector 的值何时发生变化。当选择其他用户时,on_user_change 函数会自动调用,并且 value 变为新的用户:

user_selector.observe(on_user_change, names='value') 

在 GenAISys 对话中用户动态变化代表了一种从一对一聊天机器人到重大进化。它为与 AI 作为共同参与者的协作团队合作引入了一个全新的维度。

需要激活的第二个小部件是输入小部件:

# Create the input box widget
input_box = Text(placeholder="Type your message here or type 'exit' to end the conversation.", layout=Layout(width='100%')) 

输入可以是任何文本,并将占用 UI 布局的 100%。当用户输入 exitquit 时,对话结束。当文本输入并按下 Enter 按钮时,事件处理器接管:

input_box.on_submit(handle_submit)  # Attach the on_submit event handler 

on_submitinput_box 小部件的方法。handle_submit 是我们可以按自己的意愿编写的回调函数,将在本节后面描述。

第三个小部件是 AI 对话代理的复选框:

# Create a checkbox to toggle agent response
agent_checkbox = Checkbox(
    value=True,
    description='Agent',
    layout=Layout(width='20%')
) 

复选框显示描述标签,在这种情况下是一个代理。布局将占用 UI 的 20%。如果 value 设置为 True,则对话式 AI 代理将被激活。我们将在本章的 对话代理 部分构建 AI 代理。AI 代理也将是事件驱动的。

UI 容器现在已准备好显示。

3. 显示用户界面

UI 容器小部件现在结合了我们定义在 VBoxV 代表垂直;即,在垂直框中)中的三个事件驱动小部件。这三个小部件用括号括起来:

# Display the initial interface
display`(`
    `VBox(`
       `[user_selector, input_box, agent_checkbox]`,
        layout=Layout(
            display='flex', flex_flow='column',
            align_items='flex-start', width='100%'
        )
    )) 

接下来定义布局:

layout=Layout(
    display='flex', flex_flow='column',
    align_items='flex-start', width='100%'
))) 

此响应式 UI 的参数如下:

  • display='flex' 激活 CSS 弹性盒模型以动态布局,而不指定项目的大小。

  • flex_flow='column' 垂直排列子小部件。

  • align_items='flex-start' 将小部件对齐到 UI(左侧)容器的起始位置(左侧)。

  • width='100%' 使容器占据可用空间的全部宽度。

这样,UI 就准备好了。我们可以选择从三个小部件中的任何一个开始。用户选择器可以在输入之前运行,以及 AI 代理复选框。在这种情况下,用户选择器被设置为默认值 User01,AI 代理复选框被设置为默认值 True

三个小部件及其过程可以根据项目需求构建到任何经典网页或软件界面中。由于输入没有默认值,让我们继续使用输入小部件。

4. 输入框事件

输入文本由上一节中描述的 UI 管理,当用户输入文本时触发 input_box.on_submit(handle_submit)。反过来,submit 方法调用 handle_submit 函数:

# Function to handle the submission of the input
def handle_submit(sender):
    user_message = sender.value
    if user_message.strip():
        sender.value = ""  # Clear the input box
        chat(user_message) 

现在,该函数执行以下三个操作:

  • user_message = sender.value 处理从输入小部件接收到的文本

  • if user_message.strip() 检查是否存在消息,并使用 sender.value = "" # 清空输入框 清空输入框以供下一次输入。

  • 如果有消息,则调用 chat(user_message)

chat(user_message) 是下一个处理过程,也是 GenAISys 的关键事件处理中心。让我们来看看它。

5. chat(user_message) 函数

chat(user_message) 函数是我们事件驱动 GenAISys 的 协调器 组件。它应该保持以人为中心,以便进行关键的人机控制。一旦系统赢得了用户的信任,并在经过仔细考虑后,它可以被系统消息触发的动作中的一些动作可以触发。协调器在处理从 handle_submit(sender) 函数接收到的用户消息时包含重要的决策。它封装了几个选择和功能,如 图 4.2 所示:决定是否继续对话,将对话历史记录追加或保存到文件中,确定是否调用 AI 对话代理,以及更新 UI 显示。

它首先继承了对话变量(conversation_active = True)的全局状态,我们在对话开始时(在 图 4.2 中的节点 1)初始化了它:

# Function to handle user input and optional bot response
def chat(user_message):
    global conversation_active 

它会继续通过检查用户是否退出或结束对话来确定多轮对话是否结束(见 图 4.2 中的 6):

 if user_message.lower() in ['exit', 'quit']: 

让我们看看如果用户选择退出对话会发生什么。

6. 如果选择“退出”

假设用户输入 exitquit;那么我们在对话开始时(在 图 4.2 中的节点 1)设置的 conversation_active 变量现在将被设置为 False。系统现在知道不再需要更新显示。然后它告诉 clear_output 函数等待到下一个对话轮次来清除输出,以避免闪烁效果:

clear_output(wait=True) 

退出过程继续,显示一条消息,表示对话结束,并指示正在保存对话历史记录:

display(HTML("<div style='color: red;'>Conversation ended. Saving history...</div>")) 

通过调用对话的 save 函数结束退出过程,该函数将保存所有历史记录到文件中(见 图 4.2 的节点 7):

save_conversation_history() 

因此,对话将在会话结束时保存以供进一步使用(用于新会话或会议摘要),如 图 4.2 的节点 7 所示:

# Function to save conversation history to a file
def save_conversation_history():
    filename = "conversation_history.json"  # Define the filename
    with open(filename, 'w') as file:
        json.dump(user_histories, file, indent=4)  # Write the user histories dictionary to the file in JSON format
    display(HTML(f"<div style='color: green;'>Conversation history saved to {filename}.</div>")) 

现在,让我们通过用户(们)选择继续对话的过程来进行分析。

7. 如果用户继续对话

如果用户输入不包含 exitquit,则多轮、多用户对话将继续。然而,我们在这个功能上需要做出一些重大决策。我们是将其附加到每个用户请求上,还是不附加?如果我们将其附加到每个用户请求上,在某个时刻,上下文窗口将完整,但我们通过 API 发送的标记数量将增加处理时间和成本。

第一步是将我们在开始时初始化的对话历史记录(在 图 4.2 的节点 1)附加上:

# Append user message to the active user’s history 
user_histories[active_user].append(
    {“role”: “user”, “content”: user_message}
) 

因此,在这个笔记本的混合场景中,在这个时候,我们将用户历史记录保存在内存中,直到会话结束,因此我们将使用户的输入历史记录增加每个用户的输入,正如在 图 4.2 的节点 11 所见。如果用户输入不包含 exitquit,则多轮、多用户对话将继续。它将用户消息附加到用户的历史记录(在 图 4.2 的节点 8)中。

然而,如果我们不想将用户请求附加到其中,但仍然想保留整个对话的记录以供上下文参考,我们也可以在对话的中点或结束时总结对话。如果在对话中总结,我们可以添加一个函数,每次都将其附加到用户输入中。如果在会话结束后总结,我们可以继续一个新的、全新的会话,并带有前一个会话的历史记录摘要。

在这个笔记本中,我们将实现一个混合的短期和长期记忆过程。我们可以通过不输入 'quit''exit' 来继续对话。现在,chat(user_message) 函数将检查对话式代理的复选框值:

if agent_checkbox.value: 

这种验证在 图 4.2 的节点 9 中显示。如果复选框被勾选,则我们之前章节中创建的函数将通过调用 chat_with_gpt 被激活:

 response = chat_with_gpt(user_histories[active_user],
        user_message) 

一旦返回响应,它将被附加到之前描述的响应历史记录中:

 user_histories[active_user].append( 
            {“role”: “assistant”, “content”: response} 
        ) 

我们现在有一个入口点记忆框架。然后程序调用 update_display(),这是在 图 4.2 的节点 14 中显示的另一个关键函数。如果代理复选框被勾选,chat_with_gpt 将被调用。

8. 生成机器人响应

chat_with_gpt 函数将我们在前几章中完成的工作组装起来,以创建一个具有基于 Pinecone 的 RAG 功能的对话式人工智能代理。我们将在本章的 对话式代理 部分完全实现这一集成。

chat_with_gpt通过提供信息来编排 AI 会话代理,使其具有动态性和响应性。将此对话的用户历史和用户消息发送到chat_with_gpt会话代理函数:

response = chat_with_gpt(user_histories[active_user], user_message) 

一旦返回响应,update_display函数将从chat(user_message)中调用。

9. 更新显示

update_display函数通过更新会话历史刷新 UI,并显示小部件的状态。它首先通过将wait设置为True告诉 UI 等待新的输出到来:

def update_display():
    clear_output(wait=True) 

函数随后过滤并显示活跃用户的会话历史(参见图 4.2中的节点15):

 for entry in user_histories[active_user]:  # Show only the active user's history
        if entry['role'] == 'user':
            display(HTML(f"<div style='text-align: left; margin-left: 20px; color: blue;'>{active_user}: {entry['content']}</div>"))
        elif entry['role'] == 'assistant':
            display(HTML(f"<div style='text-align: left; margin-left: 20px; color: green;'>Agent: {entry['content']}</div>")) 

如果会话是活跃的,UI VBox将显示,同时显示小部件的状态:

 if conversation_active:
        display(VBox([user_selector, input_box, agent_checkbox]))  # Keep input box, selector, and checkbox visible if active 

输入框被清除,代理复选框已被用户独立检查,系统已验证其状态。活跃用户将根据用户的独立决定显示。在这种情况下,会话开始时(1)初始化的活跃用户active_user保持不变。如果用户改变了,on_user_change下拉事件(13)将由user_selector小部件的observe方法触发:

user_selector.observe(on_user_change, names='value') 

在那种情况下,user_selector.observe将独立调用update active_user函数(14),并首先确保活跃用户是一个全局变量:

def on_user_change(change):
    global active_user 

然后,它将使新用户成为活跃用户:

 active_user = change['new'] 

最后,它将调用我们在本小节中构建的update_display函数:

 update_display() 

现在我们已经实现了动态 UI 和事件驱动的功能,接下来让我们实现被chat_with_gpt调用的会话代理逻辑。

会话代理

我们在第一章第二章中实现了一个 AI 会话代理,并在第三章中构建了查询 Pinecone 功能。前往笔记本中的会话代理部分。如果需要,在继续之前花时间回顾那些章节。在本节中,是我们将这些组件集成到一起的时候,为我们的 GenAISys 会话代理准备多用户会话。

我们首先导入 OpenAI 并初始化客户端:

from openai import OpenAI
# Initialize the OpenAI client
client = OpenAI() 

然后,我们决定是否存储每个调用中所有用户的会话历史,以优化上下文窗口大小,从而优化成本和清晰度:

user_memory = True # True=User messages are memorized False=User messages are not memorized 

在生产环境中,应战略性地监控内存设置。例如,在这里我们将user_memory设置为True,但在 RAG 查询期间避免应用它,因为历史上下文可能会混淆 Pinecone 相似度搜索。然后我们定义chat_with_gpt函数,该函数在图 4.2中的节点10被调用:

def chat_with_gpt(messages, user_message): 

函数首先在输入文本中搜索关键词以触发从 Pinecone 索引中进行的 RAG 检索,如Query_Pinecone.ipynb中实现并在第三章中描述。代码首先确定命名空间:

 try:
      namespace=""
      if "Pinecone" in user_message or "RAG" in user_message:
        # Determine the keyword
        if "Pinecone" in user_message:
            namespace="genaisys"
        elif "RAG" in user_message:
            namespace="data01"
        print(namespace)
… 

如果用户消息包含“Pinecone”,查询将针对包含指令场景的genaisys命名空间。genaisys命名空间实现不同于静态数据检索,它带我们进入代理式的、动态的决策来触发指令或任务。如果用户消息包含“RAG”,查询将针对包含静态数据的data01命名空间。Pinecone 索引的查询和内容是在第三章中实现的:

 #define query text
        query_text=user_message
        # Retrieve query results
        query_results = get_query_results(query_text, namespace)
        # Process and display the results
        print("Processed query results:")
        qtext, target_id = display_results(query_results)
        print(qtext) 

一旦查询结果返回,我们将用户消息附加到其中以增强输入:

 #run task
        sc_input=qtext + " " + user_message
        mrole = "system"
        mcontent = "You are an assistant who executes the tasks you are asked to do."
        user_role = "user" 

消息参数和 OpenAI API 调用在第一章设置环境部分中描述。OpenAI 的响应存储在task response

 task_response = openai_api.make_openai_api_call(
            sc_input,mrole,mcontent,user_role
        )
        print(task_response) 

OpenAI API 调用返回的响应,加上 Pinecone 查询的结果,存储在aug_output

 aug_output=namespace + ":" +task_response 

如果用户消息不包含触发 RAG 功能的关键词,用户请求将直接发送到 OpenAI API 调用,响应将存储在aug_output。然而,系统必须首先检查user_memory是否为True。系统还必须提取user_message的文本内容:

 else:
        if user_memory:
                # Extract ALL user messages from the conversation history
                user_messages_content = [
                    msg["content"] for msg in messages
                    if msg["role"] == "user" and "content" in msg
                ]
                # Combine all extracted user messages into a single string
                combined_user_messages = " ".join(user_messages_content)
                # Add the current user_message to the combined text
                umessage = f"{combined_user_messages} {user_message}" 

在这种情况下,umessage现在包含从combined_user_messages中提取并存储的活跃用户的对话历史和用户消息本身在user_message中的拼接。生成式 AI 模型现在对这个用户的对话有完整的上下文信息。

管理对话历史的策略将严重依赖于每个实际应用场景。例如,我们可能会选择提取会话中所有用户的对话历史,或者只提取特定用户的。或者,一个团队可能会决定在整个对话中使用一个共享的用户名。通常,最佳实践是与最终用户一起组织研讨会,以定义和配置最适合他们工作流程的对话记忆策略。

在某些情况下,我们可能会决定完全忽略对话历史。在这种情况下,我们将user_memory参数设置为False,系统将忽略之前的交流:

 else:
                umessage = user_message 

umessage变量现在可以直接发送到生成式 AI 模型:

 mrole = "system"
        mcontent = "You are an assistant who executes the tasks you are asked to do."
        user_role = "user"
        task_response =openai_api.make_openai_api_call(
            umessage,mrole,mcontent,user_role
        )
        aug_output=task_response 

OpenAI API 调用的响应随后返回到chat_with_gpt函数(在图 4.2的节点10):

 # Return the augmented output
      return aug_output 

如果 OpenAI API 调用失败,将引发异常并返回:

 except Exception as e:
        # Return the error message in case of an exception
        return f"An error occurred: {str(e)}" 

有了这些,我们已经汇集了在前三章中开发的生成式 AI 功能。在这个阶段,我们已经构建了一个响应式的 GenAISys 界面,并集成了一个生成代理,共同形成一个统一的 AI 控制器和协调者。现在让我们将我们的 GenAISys 付诸行动。

多用户、多轮 GenAISys 会话

现在我们有一个响应式的事件驱动型 GenAISys,能够以多种方式执行多个任务,如图 4.4 所示。我们将探讨我们使用 IPython 构建的 GenAISys 接口的灵活性,并组装来自前几章的 OpenAI 和 Pinecone 组件。

图 4.4:总结本章构建和组装的组件

图 4.4:总结本章构建和组装的组件

由于 GenAISys 内的功能是事件驱动的,用户(人类或系统)或一组用户可以利用这个框架来解决多个跨领域任务。该系统以人为中心,在人类和生成式 AI 代理之间创造一个协作、无摩擦的环境。重要的是,在这个框架中人类和 AI 之间没有竞争。团队可以在使用 GenAISys 来提升他们的表现和生产力的同时,与同事保持人类社交关系。这种以人为中心的方法是我几十年来一直倡导的,为全球公司、中型企业和小型组织提供 AI 驱动的自动化解决方案。当团队将 AI 视为协作工具而不是竞争对手时,它营造了一种积极的环境,从而迅速取得胜利——展示了团队合作和技术结合的有效性。

如果我们深入探讨 GenAISys 框架在团队合作场景中的应用,我们可以建立几个在现实世界项目中通常需要的根本事件序列:

  1. 用户选择 => 输入 => 代理检查 => RAG 指令 => GenAI 代理 => 输出

  2. 用户选择 => 输入 => 代理检查 => RAG 数据 => GenAI 代理 => 输出

  3. 用户选择 => 输入 => 代理检查 => 用户历史 => GenAI 代理 => 输出

  4. 用户选择 => 输入 => 代理检查 => 无用户历史 => GenAI 代理 => 输出

  5. 用户选择 => 输入 => 代理未检查 => 输出

这些基本序列构成了一组序列,S

为了实现单个用户或一组用户的目标,序列可以组装如下:

  • {a, b}: 使用 RAG 进行情感分析,随后检索过去会议的情景记忆。

  • {d, e}: 运行 OpenAI API 请求,然后为其他用户发表评论。在这个案例中的新意在于,AI 代理在团队中仍然是一个同事,有时它不会表达自己,让团队思考它提出的想法。

这些序列可以根据具体任务和场景的需要排列成更长的会话流程。因为序列可以重复,所以我们有无限多的可能动态组合。例如,这里是对这种灵活性的一瞥:

  • 三人小组,例如 {a, c, e}, {b, d, e},

  • 四人小组,例如 {a, b, c, d}, {b, c, d, e},

  • 五人小组,例如

我们可以向这些序列添加退出会话和总结,以及重新加载保存的文件并继续会话。还可以有重复的集合、不同用户的集合以及具有更多功能的集合。在接下来的章节中,我们将添加新的功能,包括图像生成、音频、网络搜索和机器学习,这将扩大我们构建的 GenAISys 框架的范围。

然而,在本节中,我们将以简单的顺序运行两个用户的会话。然后,我们将运行具有多个用户和一些基本序列的场景。让我们从简单的事件序列开始。

两个用户的会话

在这个示例会话中,两个用户合作构思他们可以向在线旅游网站客户推荐的吸引人的旅游目的地。我们首先运行一个界面会话,然后显示对话历史,最后总结讨论。要开始会话,打开Event-driven_GenAISys_framework.ipynb并运行这些单元格部分:

  • 设置环境:运行所有单元格

  • 会话代理:运行单个单元格

  • 在 GenAISys IPython 接口运行界面:这将初始化对话

由于生成式 AI 模型的随机性,输出可能会在每次执行时略有不同。同样,在质量控制期间多次运行,因此本笔记本与打印章节之间可能存在细微差异。

对话初始化后,现在让我们运行交互式会话。

交互式对话

对话默认从User01开始,显示输入框和激活的代理复选框。在此场景中触发的事件和函数序列如图 4.5所示。

图 4.5:GenAI 代理使用用户的历史记录执行任务

图 4.5:GenAI 代理使用用户的历史记录执行任务

流程遵循以下顺序:

用户选择 => 输入 => 代理检查 => 用户历史记录 => GenAI 代理 => 输出

对于用户来说,这个过程无缝衔接,如图 4.6所示。然而,为了产生这种平滑的效果,需要仔细设计和开发底层功能。

图 4.6:带有 GenAI 代理复选框的 UI

图 4.6:带有 GenAI 代理复选框的 UI

从用户的角度来看,这个过程很简单。User01 在输入框中输入提示:法国的首都是什么?

图 4.7:用户输入简单提示

图 4.7:用户输入简单提示

输出将显示在输入小部件上方,如下所示:

图 4.8:输出显示在输入框上方

图 4.8:输出显示在输入框上方

到目前为止,即使是没有经过训练的用户也可以直观地使用一页文档中提供的基本信息运行 GenAISys。User01 继续提出后续问题:

`User01:` What is there to visit? 

由于在对话代理中用户历史选项设置为 True,代理知道问题关于巴黎,并提供了一些值得参观的标志性地点的信息:

**Agent:** The capital of France is Paris. There are numerous attractions to visit in Paris, including: 1\. **Eiffel Tower** - An iconic symbol of Paris, offering stunning views of the city. 2\. **Louvre Museum** - The world's largest art museum, home to the Mona Lisa… 

User02 现在通过在下拉菜单中选择 User02,如 图 4.9 所示,进入对话。User02 然后询问西班牙的首都是哪里,代理进行了回答,输出显示在输入框上方。

图 4.9:输入:另一个用户可以进入对话

图 4.9:输入:另一个用户可以进入对话

到目前为止,GenAISys 核心框架已经设置好,我们将在后续章节中通过解决诸如安全性、用户访问控制和数据隐私等特性来逐步增强它。User02 进一步询问值得参观的地方。代理正确响应,因为用户历史选项已被激活:

**User02:** What is there to visit? 
**Agent:** The capital of Spain is Madrid. There are many attractions to visit in Madrid, including: 1\. **The Royal Palace of Madrid** - The official residence of the Spanish royal family, although it is now used only for state ceremonies. 2\. **Prado Museum** … 

现在,一个关键特性开始发挥作用。User02图 4.10 所示,停用了 AI 代理,并直接对 User01 进行了交流,类似于社交媒体或远程协作平台上的互动。

图 4.10:没有 AI 代理的团队直接沟通

图 4.10:没有 AI 代理的团队直接沟通

User01 非正式地回应:“是的,这是个好主意,但让我们再考虑一下。”随后,User01 通过输入 exit 来结束会话。正如 图 4.11 所示,这种能力使我们的 GenAISys 在本书将要探讨的使用案例中达到了一个新的水平,例如以下配置:

  • 用户可以单独与 GenAISys 进行一对一的对话

  • 团队可以一起工作,通过 AI 代理作为合作者来提高他们的表现

  • 当人类管理者不可用时,用户可以是来自不同地点的 AI 代理,扮演管理者的角色

  • 用户可以是向人类用户提供实时信息的系统

图 4.11:团队直接沟通然后结束会话

图 4.11:团队直接沟通然后结束会话

退出时,会话结束,对话历史保存到 conversation_history.json 文件中:

图 4.12:保存并结束对话

图 4.12:保存并结束对话

就像这个框架中的所有其他功能一样,退出行为可以根据个别项目进行定制。以下是一些例子:

  • 对话历史可以保存也可以不保存

  • 只能保存对话历史的一部分

  • 保存的对话历史文件名可以包含时间戳

  • 选择“…转到下一个单元格”是可选的

这些是为每个用例做出的决策。它们不会修改 GenAISys 的整体框架,但允许高度定制。

在这种情况下,团队希望显示他们刚刚进行的对话。

加载和显示对话

这个函数的代码是一个标准的 IPython 显示函数,用于将 JSON 文件conversation_history.json转换为 Markdown 格式。我们首先检查会话历史参数和/或摘要参数是否已激活:

`display_conversation_history=True`
`summary=True` 

在这种情况下,会话历史和摘要函数都已激活。现在,我们将检查是否存在会话历史文件:

import json
from IPython.display import display, Markdown
import os
if display_conversation_history == True or summary==True:
    # File path
    file_path = 'conversation_history.json'
    # Check if the file exists
    if os.path.exists(file_path):
        display_conversation_history=True
        summary=True
        print(f"The file '{file_path}' exists.")
    else:
        display_conversation_history=False
        summary=False
        print(f"The file '{file_path}' does not exist.")
        print("The conversation history will not be processed.") 

如果存在文件,display_conversation_history将被设置为Truesummary=True(即使之前设置为False)。将显示一条消息,表明文件存在:

The file 'conversation_history.json' exists. 

如果display_conversation_history==True,则将显示会话:

# Display option
if display_conversation_history==True:
  # File path
  file_path = 'conversation_history.json'
  # Open the file and read its content into the 'dialog' variable
  with open(file_path, 'r', encoding='utf-8') as file:
      dialog = json.load(file)  # Parse JSON content
…
# Function to format JSON content as markdown
def format_json_as_markdown(data, level=0):
    html_output = ""
    indent = "  " * level
…
return html_output
# Format the JSON into markdown
formatted_markdown = format_json_as_markdown(dialog)
# Display formatted JSON as Markdown
display(Markdown(formatted_markdown)) 

输出格式良好:

…
**User01**:
**role**:
user
**content**:
What is the capital of France?
**role**:
assistant
**content**:
The capital of France is Paris.
…
**Content**:
The capital of Spain is Madrid.
**role**:
user
**content**:
What is there to visit?
**role**:
assistant
**content**:
The capital of Spain is Madrid. There are many attractions to visit in Madrid, including:
**The Royal Palace of Madrid** – … 

团队已经显示了会话,但希望将过程进一步深入,并总结包括 AI 代理作为参与者的在线会议。

加载和总结会话

我们正在总结的会话展示了如何将 AI 代理融入现有的人类团队以提升生产力。在某些情况下,GenAISys 将独立完成自动化任务。在其他情况下,GenAISys 将成为一个或多个用户的副驾驶。在其他情况下,在组织的许多关键时刻,人类和 AI 代理的团队将能够一起工作来做出决策。

在本节中,我们将要求 AI 代理总结会话。我们将在接下来的章节中将此功能集成到 GenAISys 中作为一个函数。目前,我们将在显示会话后单独运行它,如图4.13所示。

图 4.13:显示和总结会话

图 4.13:显示和总结会话

代码首先以显示函数中的方式加载conversation_history.json文件。然后,我们定义一个函数,将会话历史内容转换为 OpenAI API 的最佳格式:

# Function to construct dialog string from the JSON conversation history
def construct_dialog_for_summary(conversation_history_json):
    dialog = ""
    for user, messages in conversation_history_json.items():
        dialog += f"\n{user}:\n"
        for message in messages:
            role = message["role"]
            content = message["content"]
            dialog += f"- {role}: {content}\n"
    return dialog 

构建完整会话历史的函数被调用:

# Construct the full dialog from the JSON history
formatted_dialog = construct_dialog_for_summary(conversation_history_json) 

现在,我们准备为系统构建的定制 GenAISys API 调用准备完整消息,并在我们笔记本的设置环境部分的OpenAI子部分中导入:

# Task to summarize the conversation
mrole = "system"
mcontent = "Your task is to read this JSON formatted text and summarize it."
user_role = "user"
task = f"Read this JSON formatted text and make a very detailed summary of it with a list of actions:\n{formatted_dialog}" 

最后,我们调用 GenAISys OpenAI 函数:

# The make_openai_api_call function is called
task_response = openai_api.make_openai_api_call(
    task, mrole, mcontent, user_role
) 

将以 Markdown 格式显示 API 响应代码:

from IPython.display import Markdown, display
# Display the task response as Markdown
display(Markdown(task_response)) 

现在,一切准备就绪。如果summary==True,我们可以调用摘要函数:

if summary==True:
    # File path to the JSON file
    file_path = '/content/conversation_history.json'
    # Check if the file exists before calling the function
    if os.path.exists(file_path):
        summarize_conversation(file_path)
    else:
        print(f"File '{file_path}' does not exist. Please provide a valid file path.") 

注意,在 Google Colab 中,/content/是默认目录。因此,以下文件路径指向相同的目录:

 file_path = ‘/content/conversation_history.json’ or
 file_path = ‘conversation_history.json’ 

在另一个环境中,你可能需要绝对路径。

输出是一个包含简介和详细摘要的会话历史摘要。可以修改此摘要的提示以请求更短或更长的长度。我们还可以设计一个提示,要求生成式 AI 模型针对会话的一部分或为特定项目设计任何其他特定提示。在这种情况下,输出是令人满意的:

The JSON formatted text contains interactions between users and an assistant, where users inquire about the capitals of France and Spain and seek recommendations for attractions to visit in these cities. Below is a detailed summary with a list of actions:
**User01 Interaction:**
**1\. Question about the Capital of France:**
    User01 asks for the capital of France.
    The assistant responds that the capital of France is Paris.
**2\. Inquiry about Attractions in Paris:**
    User01 asks what there is to visit in Paris.
    The assistant provides a list of notable attractions in Paris:
 **1\. Eiffel Tower** - Iconic symbol and must-visit landmark.
 **2\. Louvre Museum** - Largest art museum, home to the Mona Lisa…. 

通过运行许多可能的任务和事件序列,我们看到了 GenAISys 给我们的灵活性。让我们运行一个更复杂的多人会话。

多用户会话

在本节中,我们将运行一个技术会话,激活我们在前几章和本章中构建的主要功能:

  • 语义和情感分析

  • 用于情节记忆检索的 RAG

  • 没有 AI 对话代理的对话

  • 加载、显示和总结对话历史

如果你没有中断之前的会话,那么只需在我们的笔记本中再次运行 在 GenAISys IPython 接口运行界面部分 单元格即可,这将启动一个新的对话。

如果你是从零开始,那么要开始会话,请打开 Event-driven_GenAISys_framework.ipynb 并运行以下单元格部分:

  • 设置环境:所有单元格

  • 对话代理:包含一个单元格

  • 在 GenAISys IPython 接口运行界面:将启动对话

我们准备探索 GenAISys 的一些高级功能。我们将突出显示每个提示触发的事件和函数。会话的第一个序列是语义和情感分析。

语义和情感分析

要执行语义和情感分析,我们需要运行 GenAISys 如 图 4.14 所示编排的以下序列:

  • 1. 用户选择 未激活,因为 User01 是会话开始时的默认用户。如果我们愿意,可以根据用例称此用户为“主机”。

  • User012. 输入 触发 3. 代理检查,这是会话开始时的默认值。

  • AI 对话 AI 控制器接管,解析提示,在提示中找到 Pinecone 关键词,在指令场景命名空间中触发 Pinecone 查询,增强提示,并触发 4. GenAI 代理

  • 4. GenAI 代理 触发对 GPT-4o 的 API 调用并返回响应。

  • 5. 输出 触发显示的更新。系统已准备好接受新的输入。

图 4.14:执行语义和语义分析的的事件和函数序列

图 4.14:执行语义和语义分析的的事件和函数序列

触发此序列的函数和事件的提示如下:

A customer said that our travel agency was pretty good but should have more activities. Let's ask Pinecone for ideas. 

生成式 AI 控制器正确地将 Pinecone 识别为查询指令场景命名空间的触发器,GPT-4o 使用它来生成令人满意的响应:

**Agent:** genaisys:To enhance your travel agency's offerings based on the customer's feedback, … 3\. **Gather Data**: Collect data from various sources such as travel blogs, customer reviews, social media, and travel forums. This data can be used to train or query your semantic search model. 4\. **Generate Ideas**: Use the results from the semantic search to generate a list of potential activities. For example, if you're looking to expand adventure activities, the search might suggest zip-lining, rock climbing, or guided hiking tours…. 

注意,AI 代理以 genaisys 开头开始响应,这表明已查询了正确的命名空间。这是一个可选的质量控制功能,在开发 GenAISys 时实施是良好的实践。

图 4.15 所示的提示 2 情感分析序列与语义分析序列相同,但有两个区别:

  • 由于 User02 被选中,1. 用户选择事件被激活。

  • 提示将包含对情感分析的暗示。

图 4.15:情感分析的任务编排

图 4.15:情感分析的任务编排

提示包含 Pinecone 关键字以激活 Pinecone 查询,以及表示相似性搜索的单词sentiment

`A customer said that our travel agency was worse than our competition and should have better service. Let's ask Pinecone what its sentiment is.` 

我们可以为所有请求的任务添加一个明确的下拉列表,我们将在某些情况下这样做。但在这个案例中,我们依赖于隐式关键字搜索。显式(在下拉列表中选择任务等)和隐式(使用关键字或依赖于提示内容)之间的平衡应在与用户的研讨会中决定。

在这种情况下,选择了 Pinecone 关键字 genaisys 命名空间,输出令人满意:

**Agent:** genaisys:Sentiment analysis score: 0.2 Explanation: The text expresses a negative sentiment towards the travel agency. The customer explicitly states that the agency is "worse than our competition" and suggests that it "should have better service." These statements indicate dissatisfaction and a negative comparison to competitors, which justifies a low sentiment score. 

会话继续触发情景记忆检索。

RAG 用于情景记忆检索

情景记忆检索的序列将在 Pinecone 索引中搜索团队成员的个人记忆。该记忆与保存并更新到 data01 命名空间中的 Pinecone 索引的过去会议相关。User03 将触发以下函数和事件序列,如图 4.16 所示:

  • 1. 用户选择独立触发,因为用户已更改。

  • 2. 输入触发3. 代理检查的验证。

  • 3. 代理检查触发对话式 AI 代理控制器,该控制器随后触发基于提示中的 RAG 关键字的 data01 命名空间中的3.2. RAG 数据检索。

  • 最后,生成式 AI 代理 GPT-4o 使用增强输入运行请求并返回输出。

  • 4. 输出将触发显示更新,系统准备进行对话的新一轮。

图 4.16:情景记忆检索

图 4.16:情景记忆检索

提示明确指代与团队个人经历相关的历史事件。此事件的痕迹是存储在 Pinecone 索引中的情景记忆:

The CTO was talking about leveraging different kind of memories the other day. What did he mean by that? Let's search RAG. 

代理的响应令人满意:

**Agent:** data01:RAG, or Retrieval-Augmented Generation, is a framework that combines retrieval-based methods with generative models to enhance the capabilities of AI systems. When your CTO mentioned leveraging different kinds of memories, they were likely referring to the various ways in which information can be stored, accessed, and utilized within such a system. Here are some types of "memories" that might be relevant in this context: 1\. **Short-term Memory**: 

我们可以看到代理正确找到了命名空间,并且使用了短语“你的 CTO 提到”,认识到这是一个与团队个人经历相关的事件,而不是非个人语义数据。

会话继续进行创意活动。

生成式 AI 代理用于创意

会话继续进行创意活动。在这种情况下,我们希望利用生成式 AI 模型 GPT-4o 的力量,以获得想法。因此,序列将不会使用 Pinecone 索引检索指令或数据,如图 4.17 所示:

  • 用户保持不变,2. 输入直接进入3. 代理检查

  • 系统随后忽略 Pinecone 索引,但考虑3.2. 用户历史

  • 最后,4. GenAI 代理触发生成式 AI 调用并返回输出。

  • 5. 输出 触发显示更新,系统准备进行另一轮对话。

图 4.17:GenAISys 作为创意生成器

图 4.17:GenAISys 作为创意生成器

提示要求 AI 代理提供一些想法:

But what do you, the AI Agent, suggest we do to leverage these types of memories in our traveling promotion campaigns? 

由于 AI 代理继承了情景记忆,它引用了对话历史中 CTO 的反思,现在它根据对话的历史给出建议:

When the CTO mentioned leveraging different kinds of memories, they were likely referring to the concept of using various types of memory systems in artificial intelligence and computing to enhance performance and capabilities.…
…consider the following strategies: 1\. **Personalized Recommendations**: Use short-term and long-term memory to analyze customer preferences and past interactions to provide personalized travel recommendations and offers. 2\. **Dynamic Content**: Utilize episodic memory to tailor marketing content based on past customer interactions and experiences, making the promotions more relevant and engaging. … 

GenAISys 为团队提供了想法。现在,团队希望仔细考虑这些想法。

没有 AI 对话代理的对话

团队已经进行了一次简短的对话,他们本可以继续对话直到他们需要停止。User01 接管并直接与团队沟通。现在,GenAISys 被用作协作远程会议工具,如图 图 4.18 所示:

  1. 用户选择被触发,因为 User01 正在介入。

  2. User01 取消了 代理 小部件的勾选。

  3. 输入了一条消息,但提示是针对其他用户,而不是 AI 代理

  4. 然后,User01 结束对话,并将其保存。

图 4.18:没有 AI 代理的对话

图 4.18:没有 AI 代理的对话

User01 为其他人输入了一条消息:

OK. Let's stop here, get a summary, and go see the manager to get some green lights to move ahead. 

图 4.19 显示 User01 取消了 AI 代理的勾选以发送消息,现在准备通过输入 exit 来结束会话。

图 4.19:用户结束对话

图 4.19:用户结束对话

GenAISys 显示了 对话结束 的消息,如图 图 4.20 所示。

图 4.20:对话结束

图 4.20:对话结束

黑色背景上的放大镜  AI 生成的内容可能不正确。快速提示:需要查看此图像的高分辨率版本?在下一代 Packt Reader 中打开此书或在其 PDF/ePub 版本中查看。

下一代 Packt Reader 在购买本书时免费赠送。扫描二维码 OR 前往 packtpub.com/unlock,然后使用搜索栏通过名称查找本书。请仔细检查显示的版本,以确保您获得正确的版本。

白色背景上的二维码  AI 生成的内容可能不正确。

消息指示用户继续到下一个单元格以显示和总结对话。

加载、显示和总结对话

对话的显示和总结将集成到 GenAISys 框架的 第五章 功能中,通过思维链添加多模态、多功能推理

在本笔记本中,我们将按照 与两位用户会话 部分所述继续进行下一单元格。

显示函数的输出提供了对话的 Markdown 文本:

…assistant
**content**:
When the CTO mentioned leveraging different kinds of memories, they were likely referring to the concept of…
**Episodic Memory**: This involves storing information about specific events or experiences. In AI, episodic memory can be used to recall past interactions or events to inform future decisions…
…To leverage these types of memories in your travel promotion campaigns, consider the following strategies:
**Personalized Recommendations**: Use short-term and long-term memory to analyze customer preferences and past interactions to provide personalized travel recommendations and offers.
**Dynamic Content**: Utilize episodic memory to tailor marketing content based on past customer interactions and experiences, making the promotions more relevant and engaging….
The summary is interesting because it provides useful suggestions for this online travel agency:
**AI Suggestion for Travel Promotion**:
**1.Personalized Recommendations**: Use short-term and long-term memory for personalized travel offers.
**2.Dynamic Content**: Utilize episodic memory for tailored marketing content.
**3.Knowledge-Based Insights**: Leverage semantic memory for travel tips and destination information.
**4.Real-Time Engagement**: Use working memory for real-time customer interactions.
**5.Feedback and Improvement**: Implement long-term memory systems to analyze feedback and improve campaigns. 

我们构建了将在下一章中增强的 GenAISys 框架的基本结构。我们还进行了一些基本的对话。让我们总结本章,并提升到下一个层次。

摘要

一个复杂、事件驱动、快速发展的经济体需要强大的自动化来处理即时消费者需求产生的数百个任务。GenAISys 可以通过响应式界面和生成式 AI 能力来满足这些需求。挑战在于提供一个动态、直观的系统。无论生成式 AI 如何自动化任务——它们可以非常自动化——最终的决定将由人类做出。人类需要在会议中沟通,无论这些会议是物理组织还是在线组织。挑战随后转变为向组织提供多用户 GenAISys。

在本章中,我们首先探索了一个高级框架来构建多用户、多轮次、多功能和 RAG 功能。该框架包括实时记忆功能和存储在向量存储中的长期知识。整体上,类似于 ChatGPT 的系统需要一个我们将增强的响应界面和对话代理。

我们随后使用 IPython 构建了一个事件驱动的 GenAISys 响应界面。对于最终用户来说,这个界面是无缝的,他们可以使用三个小部件来使用系统。第一个小部件管理用户的输入,第二个小部件是活跃用户,第三个小部件是一个代理复选框,用于激活或停用使用 GPT-4o 构建的 AI 对话代理。

最后,我们为在线旅行社团队进行了一次多用户、多轮次的 GenAISys 会话,主题是旅行。第一个目标是运行一个无缝的 GenAISys,为用户提供三个小部件。第二个目标是探索短期、长期、语义和情景记忆的范围。第三个目标是运行 RAG 来检索指令和数据。最后,目标是让用户能够与或没有 AI 代理进行交流。我们通过保存和总结会话来结束这次会话。

我们现在有一个框架,我们可以在接下来的章节中进行配置和增强,首先是在第五章中添加多模态功能和外部扩展到 GenAISys,即《通过思维链添加多模态、多功能推理》。

问题

  1. GenAISys 的界面必须对用户无缝。(对或错)

  2. IPython 是构建 GenAISys 界面的唯一工具。(对或错)

  3. 使用 GPT-4o 构建的 AI 对话代理必须通过 RAG 进行增强。(对或错)。

  4. GPT-4o 可以提供足够的信息并很好地完成任务。(对或错)

  5. Pinecone 可以用于检索指令场景。(对或错)

  6. 命名空间仅用于 Pinecone 中的数据。(对或错)

  7. 向量存储如 Pinecone 是存储情景记忆的好方法。(对或错)

  8. 我们不需要代理复选框选项。(对或错)

  9. 在 GenAISys 中,查询 Pinecone 是由用户完成的。(对或错)

  10. GenAISys 是一个对用户来说应该无缝对接的复杂系统。(对或错)

参考文献

进一步阅读

  • 刘,J.,谭,Y. K.,傅,B.,与林,K. H.(n.d.).在生成式对话系统中平衡多轮意图分类的准确性和效率:针对 LLM 的生产系统arxiv.org/abs/2411.12307

免费电子书订阅

新框架、演进的架构、研究更新、生产分析——AI_Distilled 将噪音过滤成每周简报,供实际操作 LLM 和 GenAI 系统的工程师和研究人员阅读。现在订阅,即可获得免费电子书,以及每周的洞察力,帮助您保持专注并获取信息。

packt.link/TRO5B 订阅或扫描下面的二维码。

第五章:添加基于思维链的多模态、多功能推理

在我们旅程的这个阶段,我们已经构建了 GenAISys 的核心框架。我们有一个响应式的、小规模的、类似 ChatGPT 的交互界面。我们超越了典型的点对点协同助手交互,创造了一个多用户协作环境,其中人工智能代理积极参与讨论。我们通过集成 RAG 进一步扩展了以人为中心的设计,使我们的 AI 代理能够访问一个能够管理指令场景和数据的 Pinecone 索引。最后,我们构建了一个灵活的 GenAISys,允许用户在协作会议期间激活或停用 AI 代理。简而言之,我们创造了一个以人为中心的 AI 系统,它增强而不是试图用机器智能取代人类团队。

然而,尽管其以人为中心的特点,全球跨大陆供应链的指数级增长以及大量日常商品、服务和数字内容的流动,需要显著程度的自动化。例如,我们无法合理地期望像 Meta、X 或 LinkedIn 这样的社交媒体平台每天雇佣数百万人来审核数十亿条消息——包括图像、音频和视频文件。同样,像亚马逊这样的公司不能仅通过人力来管理数百万在线交易和实物配送。自动化对于增强人类决策和推理至关重要,尤其是在大规模的关键任务中。因此,在本章中,我们将通过添加多模态能力和推理功能来扩展 GenAISys 框架。为了解决跨领域自动化的挑战,我们将实施图像生成和分析,并开始集成机器学习。我们的目标是构建一个新的代理人工智能层到我们的 GenAISys 中。

我们将首先概述我们将集成到现有 GenAISys 框架中的功能。鉴于 GenAISys 范围的扩大,我们将引入思维链(CoT)推理过程,以有效地编排和管理复杂任务。然后,我们将引入计算机视觉能力。这包括使用 DALL-E 构建图像生成功能和使用 GPT-4o 进行图像分析功能。接下来,我们将为偏好语音交互的用户添加音频功能——使用语音转文本(STT)作为输入提示和文本转语音(TTS)作为响应。最后,我们将在 GenAISys 中引入一个决策树分类器,作为机器学习端点,能够预测活动。到本章结束时,我们将成功将 GenAISys 扩展为一个完全交互的多模态推理平台,准备好应对复杂的跨领域用例。

总的来说,本章涵盖了以下主题:

  • 为我们的 GenAISys 添加附加功能架构

  • 实现小部件图像文件处理

  • 实现小部件以启用语音对话

  • 使用 DALL-E 进行图像生成

  • 使用 GPT-4o 进行图像分析

  • 建立决策树分类器的机器学习端点

  • 实施 CoT 推理

让我们从为我们的 GenAISys 设计一个具有额外 AI 能力的增强界面开始。

增强事件驱动的 GenAISys 界面

到目前为止,我们开发的 GenAISys 框架是事件驱动的,由用户输入(人工或系统生成)触发特定 AI 代理功能激活。在本章中,我们将通过添加几个新功能来扩展 GenAISys:

  • 语音交互,允许用户通过语音管理 GenAISys

  • 使用决策树分类器进行预测任务的新机器学习端点

  • 多模态功能,包括使用 DALL-E 进行图像生成和使用 GPT-4o 进行图像分析

  • 一个用于协调复杂、自我反思指令场景的CoT推理协调器

让我们从检查图 5.1中显示的扩展 GenAISys 架构开始:

图 5.1:增强的 GenAISys 界面架构

图 5.1:增强的 GenAISys 界面架构

此图(是前一章中图 4.1的扩展版本)突出了我们将集成到我们的 GenAISys 中的新功能:

  • I1AI 控制器:通过 CoT 推理增强,能够根据需要自动执行任务序列,并包含一个用于管理基于语音的用户交互的小部件

  • I2多用户聊天机器人:与之前章节中设计保持完全一致

  • F1生成式 AI 模型:扩展以处理多模态任务

  • F2记忆保留:与早期章节保持不变

  • F3模块化 RAG:与早期章节保持不变

  • F4多功能能力:新增涵盖音频和图像处理的功能,包括用于预测的决策树分类器

    提醒

    决定不使用箭头展示 GenAISys 架构的主要组件是一个旨在传达核心概念的故意选择:模块化和架构灵活性。此图不是一个刚性的蓝图,而是一个概念工具包。它展示了您可用的强大组件——I1. AI 控制器I2. 多用户聊天机器人F1. 生成式 AI 模型F2. 记忆保留F3. 模块化 RAGF4. 多功能能力——作为独立、可互操作的块。

我们通过添加新层而不是替换现有组件来扩展 GenAISys 的功能,正如在第四章中构建的那样。我们在这里的重点是增强和无缝集成。以下图提供了一个高级流程图,展示了附加功能将如何集成到我们现有的 GenAISys 架构中:

图 5.2:GenAISys 附加功能的流程图

图 5.2:GenAISys 附加功能的流程图

以下附加功能将集成到我们现有的 GenAISys 接口中:

  • 启动:初始化两个新的小部件——一个用于 TTS 功能,另一个用于处理图像文件

  • 用户输入:现在包括可选的语音输入,如果用户选择则启用

  • 生成机器人生成机器人响应:这些过程直接连接到现有的 VBox 接口,当 AI 代理使用 CoT 逻辑时,会清晰地显示推理步骤。

为了实现这一扩展功能,我们将开发以下关键特性:

  • 语音识别和语音合成:集成使用 Google Text-to-Speech (gTTS)

  • 机器学习端点:实现决策树分类器以提供预测能力

  • 图像生成和分析:由 OpenAI 的 DALL-E 和 GPT-4o 模型提供支持

  • CoT 推理:协调任务、功能和扩展,从而为 GenAISys 提供明确的机器(而非人类)推理能力

虽然我们添加了包括推理功能(CoT)在内的几个新功能,但我们只引入了一个新的包安装,即 gTTS,以最小化本章的复杂性。我们主要关注构建一个可靠的架构,并实现最佳的依赖关系管理。首先,让我们探索 IPython 接口的更新元素和 AI 代理的增强。

IPython 接口和 AI 代理增强

我们开发的 GenAISys 架构现在可以看作由三个相互连接的层组成,如 图 5.3 所示。这些增强模糊了协调、控制和代理功能之间的界限,因为这些角色现在分布在多个层中:

  • 第一层(IPython 接口) 通过事件驱动的小部件管理用户和系统输入,根据用户交互(输入和复选框)协调任务。

  • 第二层(AI 代理) 控制生成式 AI 模型(在我们的案例中是 OpenAI 模型)并可以触发 CoT 推理序列。

  • 第三层(功能和代理) 包含由 AI 代理触发的功能。值得注意的是,CoT 功能本身作为一个代理,能够协调生成式 AI 任务、机器学习以及所需的其他功能。

图 5.3:事件驱动的 GenAISys 的三层结构

图 5.3:事件驱动的 GenAISys 的三层结构

这种高级架构集成了协调器、控制器和代理,每个部分都分解为特定的 Python 功能。让我们从功能角度开始探索 第一层,即 IPython 接口。

第一层:IPython 接口

IPython 接口现在集成了三个新特性(在 图 5.4 中以黄色突出显示):一个语音小部件、一个文件处理小部件以及由用户输入和 AI 代理活动触发的专用推理接口。这些增强使得接口总共有六个交互式小部件和功能。

图 5.4:语音、文件和推理功能添加到 IPython 接口

图 5.4:将语音、文件和推理功能添加到 IPython 界面

让我们逐一查看每个小部件和功能:

  1. 用户选择第四章中按原设计保留。它是 GenAISys 协作设计的关键,且保持不变。

  2. 用户输入未经修改地保留自第四章;此小部件仍然是捕获用户提示的中心。

  3. 第四章所述,AI 代理激活或停用生成式 AI 代理(chat_with_gpt)。

  4. 语音小部件通过 STT 和 TTS 实现基于语音的交互。我们使用的是免费的内置 STT 功能:

    • Windows:按 Windows 键 + H

    • macOS:在键盘设置下启用语音输入并选择一个自定义快捷键

对于语音合成(TTS),使用的是 gTTS 服务,默认通过一个设置为False的复选框进行控制和利用:

# Create a checkbox to toggle text-to-speech
tts_checkbox = Checkbox(
    value=False,
    description='Voice Output',
    layout=Layout(width='20%')
) 

如果 AI 代理的复选框被勾选,则调用 TTS 函数:

if agent_checkbox.value:
…
if tts_checkbox.value:
            text_to_speech(response) 

生成的 MP3 文件(response.mp3)在update_display()函数中自动播放:

def update_display():
…
#Audio display
    if os.path.exists("/content/response.mp3"):
      display(Audio("/content/response.mp3", autoplay=True))
      !rm /content/response.mp3 
  1. 文件小部件是一个新的小部件,用于激活文件管理。它将显示在 AI 代理功能chat_with_gpt中触发的生成式 AI 模型(DALL-E)生成的和保存的图像。它通过另一个复选框进行控制,初始设置为False

    # Create a checkbox to toggle agent response
    files_checkbox = Checkbox(
        value=False,
        description='Files',
        layout=Layout(width='20%')
    ) 
    

如果存在图像,它将在update_display()函数中使用Python 图像库PIL)显示:

 if os.path.exists("/content/c_image.png") and files_checkbox.value==True:
    # Open the image using PIL
    original_image = PILImage.open("/content/c_image.png")
    # Resize the image to 50% of its original size
    new_size = (original_image.width //2, original_image.height//2)
    resized_image = original_image.resize(new_size)
    # Display the resized image
    display(resized_image) 
  1. 推理激活是 GenAISys 的另一个新小部件。用户输入将触发 AI 代理中的事件,进而触发 CoT 推理过程。推理界面将实时显示 CoT 的思考过程。推理输出小部件在会话开始时创建:

    # Create an output widget for reasoning steps
    reasoning_output = Output(
        layout=Layout(border="1px solid black", padding="10px",
            margin="10px", width="100%")
    ) 
    

该小部件将从 CoT 过程中接收输出,并在update_display()函数中独立显示,并持久化:

def update_display():
…
# Display reasoning_output persistently
    display(reasoning_output)… 

VBox界面现在包含所有交互式小部件,包括新添加的 TTS 和文件小部件:

if conversation_active:
        display(
            VBox(
                [user_selector, input_box, agent_checkbox,
                tts_checkbox, files_checkbox],
                layout=Layout(display='flex', flex_flow='column',
                    align_items='flex-start', width='100%')
            )
        ) 

由于 AI 代理(特别是在 CoT 过程中)的响应长度和复杂性,我们引入了使用 Markdown 的增强格式化功能。update_display()函数现在格式化条目清晰,调用专门的格式化函数:

def update_display():
    clear_output(wait=True)
    for entry in user_histories[active_user]:
        formatted_entry = format_entry(entry)
        display(Markdown(formatted_entry)) 

format_entry(entry)函数格式化用户的(蓝色)和助手的(绿色)响应,确保可读性:

def format_entry(entry):
    """Format the content of an entry for Markdown display."""
    if entry['role'] == 'user':
        formatted_content = format_json_as_markdown(entry['content'])
            if isinstance(entry['content'], (dict, list))
            else entry['content']
        formatted_content = formatted_content.replace("\n", "<br>")  # Process newlines outside the f-string
        return f"**<span style='color: blue;'>{active_user}:</span>** {formatted_content}"
…
    elif entry['role'] == 'assistant':
        formatted_content = format_json_as_markdown(entry['content'])
        …
        return f"**<span style='color: green;'>Agent:</span>** {formatted_content}" 

此设计强调 IPython 界面(层 1)纯粹是为了编排用户交互并触发底层函数和代理。这种架构确保了如果您想直接调用函数和代理而不使用用户界面,您将拥有所需的灵活性。

在描述了 IPython 界面后,让我们探索层 2,即 AI 代理的增强功能。

层 2:AI 代理

层 1中由 IPython 接口调用的 AI 代理仍然是chat_with_gpt函数,这加强了 GenAISys 的对话性质。随着推理能力的引入,现在 AI 代理之间可以直接进行对话。

chat_with_gpt函数已添加了几个新功能。如有必要,请回顾第第四章中描述的核心功能。

让我们探索添加到 AI 代理中的新增强功能:

  • 在函数开头引入了continue_functions=True,以确保一次只执行一个请求的任务。

  • 在 Pinecone 查询过程的末尾将continue_functions设置为False,这是由用户消息中出现的Pinecone关键字触发的。这停止了任何额外的未预期任务执行。

  • 在后续的使用 CoT 进行推理部分中描述的新功能reason.chain_of_thought_reasoning在特定条件下被调用:

    if "Use reasoning" in user_message and "customer" in user_message and "activities" in user_message and continue_functions==True: 
    

continue_functions==True条件确保推理函数使用初始用户查询进行调用。作为此过程的一部分,还下载了一个样本客户活动文件:

initial_query = user_message
download("Chapter05","customer_activities.csv")
reasoning_steps = reason.chain_of_thought_reasoning(initial_query) 

在本章的示例用例中,一个团队可以自动访问和查询一个定期更新的客户活动数据源。提供的样本文件包含 10,000 条历史客户活动记录,包括客户 ID、位置、活动类型和活动评分:

图 5.5:历史地点的客户评分

图 5.5:历史地点的客户评分

后续的决策树分类器在 CoT 推理函数中使用此数据集来预测最受欢迎的客户活动。一旦生成响应,它就被添加到输出中,并将continue设置为False

aug_output=reasoning_steps
continue_functions=False 
  • 我们将在图像生成和分析部分中实现的reason.generate_image新功能也已集成。它的调用方式如下:

    prompt = user_message
    image_url = reason.generate_image(prompt, model="dall-e-3", 
        size="1024x1024", quality="standard", n=1) 
    

返回生成的图像 URL,并将图像本身下载并保存在本地以供显示或进一步处理:

# Save the image locally
save_path = "c_image.png"
image_data = requests.get(image_url).content
with open(save_path, "wb") as file:
    file.write(image_data) 

在输出中添加了相应的消息,并将continue标志设置为False

aug_output="Image created"
continue_functions=False 
  • 之前称为openai_api.make_openai_api_call的函数现在重命名为reason.make_openai_api_call。它保持了与第四章中相同的函数性,但现在它是 GenAISys 推理库的一部分。内存管理if user_memory…else条件,该条件考虑了完整用户历史或仅考虑当前用户消息,已更新为具有显式条件,这些条件检查user_memory的状态和continue_functions标志:

    if user_memory==False and continue_functions==True:    
    …
    if user_memory==True and continue_functions==True: … 
    

因此,AI 代理充当中间编排者,调用和管理低层函数的执行,而不是直接执行它们。Pinecone 接口仍然是顶层,它调用 AI 代理,AI 代理随后与第 3 层中的特定函数进行交互。

第 3 层:函数

在这一层,我们的重点是引入的新功能,通过 CoT 认知代理实现高级推理。Pinecone 索引和标准的 OpenAI 调用保持与第四章中实现的方式相同。本章的主要新增内容如下:

  • 使用 DALL-E 和 GPT-4o 进行图像生成和分析

  • CoT 推理,它引入了一个能够编排任务的认知代理

  • 通过 gTTS 启用语音交互功能

  • 利用决策树分类器的机器学习端点

我们将在本章接下来的部分中探索这些功能,如下所示:

  • gTTS 和机器学习的环境设置和初始化在设置环境部分中详细说明

  • 图像功能在图像生成和分析部分进行介绍

  • 推理编排构建在使用 CoT 进行推理部分

到本章结束时,我们的增强型三层 GenAISys 将拥有新的、强大的功能,这些功能旨在在后续章节中进一步扩展。现在让我们深入探讨这些增强,从环境设置开始。

设置环境

在本节中,我们将增强、扩展和重新排列之前构建的环境,以最终确定 GenAISys 框架。这些更改对于后续章节中的用例至关重要。在 GitHub 的 Chapter05 目录中打开Multimodal_reasoning_with_Chain_of_Thought.ipynb笔记本(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。

关于包安装,笔记本中的设置环境部分与上一章(Event-driven_GenAISys_framework.ipynb)基本保持不变,仅增加了一个新项:Google Text-to-Speech (gTTS)

然而,为了支持 CoT 生成式 AI 推理功能,已经进行了几个重大更新。让我们逐一检查这些更新,从OpenAI部分开始。

OpenAI

我们下载的前两个文件与之前章节相同。然而,第三和第四个文件是新的,已被添加以支持高级功能:

from grequests import download
download("commons","requirements01.py")
download("commons","openai_setup.py")
**download(****"commons"****,****"reason.py"****)**
**download(****"commons","machine_learning.py")** 

reason.py现在包含生成式 AI 库,其中包含之前章节中构建的函数以及本章中添加的函数。生成式 AI 库中的这些函数及其状态如下:

  • make_openai_api_call(input, mrole,mcontent,user_role) 是在 第一章设置环境 部分描述的通用 OpenAI API 调用。现在它如下导入:

    from reason import make_openai_api_call 
    
  • image_analysis 是一个图像分析函数,它可以描述图像或使用图像作为起点生成内容,如故事。该函数在本章的 图像生成和分析 部分有描述。

  • generate_image 是一个新函数,它使用 DALL-E 生成图像,在本章的 图像生成和分析 部分有详细说明。

  • chain_of_thought_reasoning 是我们正在构建的 GenAISys 的新 CoT 逻辑函数。我们将在本章的 使用 CoT 进行推理 部分实现它。它可以调用来自其他库的函数,例如 machine_learning

machine_learning.py 现在将包含一个名为 ml_agent 的函数中的决策树分类器。该函数接受两个参数:

ml_agent(ml_agent(feature1_value, feature2_column) 

在我们的示例用例中,feature1_value 将代表客户位置,而 feature2_column 将代表客户活动。基于历史数据,ml_agent 分类器将预测特定位置的最受欢迎的客户活动。

我们如下从 machine_learning.py 导入 ml_agent

# Import the function from a custom machine learning file
import os
import machine_learning
from machine_learning import ml_agent 

剩余的 OpenAI 设置子部分,包括包安装和 API 密钥初始化,与前面的章节相同。现在让我们初始化我们的新功能。

初始化 gTTS、机器学习和 CoT

我们将初始化以下新函数:

  • gTTS 使用 !pip install gTTS==2.5.4 安装,这是一个开源、免费的 TTS 库,适用于原型设计目的:pypi.org/project/gTTS/. `click`, 一个命令行库,是 gTTS 所必需的。第一个单元检查我们是否希望使用 gTTS,通过将 use_gtts 设置为 True

    use_gtts = True #activates Google TTS in Google Colab if True and deactivates if False 
    

笔记本的第二个单元将检查并设置正确的 `click` 版本,如果 use_gtts 设置为 True。如果需要更新,它将在笔记本输出中显示一个清晰的提示信息,提示您手动重新启动运行时。重启后,只需点击 `Run All` 继续即可。如果版本已更新,代码将显示一个 HTML 消息以重启:

import importlib.metadata
from IPython.display import display, HTML # Required for the message
# ... (define required_click_version, current_click_version, and html_message as in your code) ...
if current_click_version != required_click_version: 
    # --- Commands to uninstall and install ‘click’ would go here --- 
    # Example: !pip uninstall -y click 
    # Example: !pip install click==8.1.8
    # Display the styled message prompting for manual restart 
    display(HTML(html_message)) 
    # Stop the Python cell execution gracefully, prompting restart 
    raise SystemExit(“Please restart the Colab runtime to apply changes.”)
else: 
    print(f”--- ‘click’ is already at the correct version ({required_click_version}). No action needed. ---”) 

如果 use_gtts 设置为 True,我们将安装 gTTS 并定义一个 TTS 转换函数:

# use_gtts activates Google TTS in Google Colab if True and deactivates if False
if use_gtts: 
  !pip install gTTS==2.5.4 
  from gtts import gTTS 
  from IPython.display import Audio
def text_to_speech(text): 
    # Convert text to speech and save as an MP3 file 
    if use_gtts: 
      if not isinstance(text, str): 
          text = str(text) # Making sure the text is a string not a list 
      tts = gTTS(text) 
      tts.save(“response.mp3”) 

当 AI 代理返回响应时,该函数将在 IPython 界面中激活,如前文在 层 1:IPython 界面 部分所述。

  • ml_agent 算法端点machine_learning.py 导入:

    # Import the function from the custom OpenAI API file
    import os
    import machine_learning
    from machine_learning import ml_agent 
    

此决策树分类器函数将根据历史数据预测流行的客户活动,增强我们 GenAISys 的预测能力。

  • CoT 推理 框架从 reason.py 导入:

    # Import the function from the custom OpenAI API file
    import os
    import reason
    from reason import chain_of_thought_reasoning 
    

然后如第三章第四章中所述,定义 Pinecone 的安装、初始化和查询。如有需要,请花些时间回顾这些章节,因为我们将会重用之前开发的函数。我们现在已经准备好构建图像生成和分析功能。

图像生成和分析

在本节中,我们将首先创建一个使用 OpenAI 的 DALL-E 模型的可灵活图像生成函数。随后,我们将构建一个图像分析函数。目标是增强 GenAISys 的计算机视觉能力,同时保留其响应式、事件驱动的功能,如图图 5.6所示:

图 5.6:使用灵活的事件驱动触发生成图像

图 5.6:使用灵活的事件驱动触发生成图像

前面的图是我们在第四章中首先开发的架构的演变。它已经增加了新的功能:激活语音(声音)功能、管理图像文件、增强显示功能以及通过 CoT 进行推理。在本节中,我们将特别关注将计算机视觉能力与增强的显示功能相结合。

图像生成和分析过程被设计成灵活的:

  • 对于图像生成或分析,不需要进行强制选择或显式小部件激活。如果用例需要,我们可以轻松添加标记为图像生成图像分析的显式小部件。然而,我们这里采用的方法是有意为之的灵活,为在更复杂的自动化推理工作流程(如 CoT)中集成铺平道路。

  • 文件复选框小部件有两个不同的用途:

    • 如果未勾选,DALL-E 将生成图像,保存到文件中,但不会显示。这允许图像在后台安静地生成,以供以后使用或存储。

    • 如果勾选,生成的或分析后的图像将在用户界面中显示,如图图 5.7所示。

  • 人工智能对话代理会根据用户提示自动激活图像生成或分析。这些视觉能力还可以触发自动化推理过程,使系统能够无缝执行综合 CoT 任务。

注意,只有当文件小部件被勾选时,显示才会显示图像文件。现在让我们深入了解这些视觉功能如何在 GenAISys 界面中集成。具体来说,我们将演示文件复选框被激活(勾选)的情景,如图图 5.7所示:

图 5.7:文件复选框被勾选,以便显示图像

图 5.7:文件复选框被勾选,以便显示图像

当选择文件复选框时,DALL-E 根据用户提示生成的图像将立即显示,如图图 5.8所示:

图 5.8:输入提示并显示生成的图像

图 5.8:输入提示并显示生成的图像

如果未勾选文件选项,图像将被生成并保存,但不会显示。同样,图像显示功能也适用于从外部来源下载的图像分析。当文件复选框未勾选时,分析将运行而不显示图像。我们现在可以检查图像生成函数的实现细节。

图像生成

生成图像的函数位于自定义生成式 AI 库reason.py中的commons目录。用户提示或 CoT 框架可以触发此函数。该函数的名称为generate_image,并接受五个参数:

def generate_image(
    prompt, model="dall-e-3", size="1024x1024", quality="standard", n=1
): 

五个参数如下:

  • prompt: 用户或系统提供的与图像相关的查询。

  • model: 要使用的 OpenAI 模型。在这种情况下,默认值为gpt-4o

  • size: 图像的大小。图像的默认大小为1024x1024

  • quality: 定义图像的质量。默认值是standard,其成本低于更高品质的hd选项。

  • n: 定义要生成的图像数量。默认值为1

函数返回生成图像的 URL。代码首先初始化 OpenAI 客户端:

def generate_image(
    prompt, model="dall-e-3", size="1024x1024", quality="standard", n=1
):
    # Initialize the OpenAI client
    client = OpenAI() 

然后通过 OpenAI API 调用 DALL-E 模型,并使用指定的参数:

 # Generate the image using the OpenAI API
    response = client.images.generate(
        model=model,
        prompt=prompt,
        size=size,
        quality=quality,
        n=n,
    ) 

参数在设置环境部分的第一章中详细描述。

一旦定义了内容、消息和参数,就调用 OpenAI API:

 # Make the API call
    response = client.chat.completions.create(
        model=model,
        messages=messages,
        **params  # Unpack the parameters dictionary
    ) 

response中提取图像的 URL 并返回:

# Extract and return the image URL from the response
    return response. data[0].url 

一旦生成或检索到图像,我们可以根据需要选择显示或分析它。

图像分析

分析图像的函数也位于自定义生成式 AI 库reason.py中的commons目录。该函数名为image_analysis,如下定义,并接受三个参数:

def image_analysis(image_path_or_url, query_text, model="gpt-4o"): 

三个参数如下:

  • image_path_or_url (str): 访问本地图像文件的路径或图像的 URL。

  • query_text (str): 用户或系统提供的与图像相关的查询

  • model (str): 要使用的 OpenAI 模型。在这种情况下,默认值为gpt-4o,它具有视觉能力(生成和分析)。

函数使用提供的查询文本初始化 API 调用的内容结构:

# Initialize the content list with the query text
    content = [{"type": "text", "text": query_text}] 

该函数随后在 URL 或本地文件中搜索图像:

 if image_path_or_url.startswith(("http://", "https://")):
        # It's a URL; add it to the content
        content.append({"type": "image_url", 
            "image_url": {"url": image_path_or_url}})
    else:
        # It's a local file; read and encode the image data
        with open(image_path_or_url, "rb") as image_file:
            image_data = base64.b64encode(
                image_file.read()).decode('utf-8') 

如果图像在 URL 中,则将其附加到内容中。如果图像是本地文件,则将其编码为 Base64 并格式化为 UTF-8 字符串。这种格式使得可以在基于文本的系统(如 JSON 或 HTML)中嵌入图像数据。然后创建一个数据 URL 并将其附加到内容中:

# Create a data URL for the image
    data_url = f"data:image/png;base64,{image_data}"
    content.append({"type": "image_url", "image_url": {"url": data_url}}) 

OpenAI 消息是在包含查询信息和图像的上下文中创建的:

# Create the message object
    messages = [{"role": "user", "content": content}] 

API 调用包括一组标准参数,在第一章(在设置环境部分)中详细说明:

# Define the parameters
    params = {
        "max_tokens": 300,
        "temperature": 0,
        "top_p": 1,
        "frequency_penalty": 0,
        "presence_penalty": 0, 

一旦定义了内容、消息和参数,就调用 OpenAI API:

 # Make the API call
    response = client.chat.completions.create(
        model=model,
        messages=messages,
        **params  # Unpack the parameters dictionary
    ) 

为了进一步集成,特别是与第六章中使用的 Pinecone 结合 RAG,将响应保存为文件中的文本。这使后续使用和检索成为可能:

# Save the result to a file
    with open("image_text.txt", "w") as file:
        file.write(response.choices[0].message.content)
return response.choices[0].message.content 

image_analysis函数也将被本章后面构建的 CoT 推理过程调用,其中query_text将动态创建并传递到该函数中:

 response = image_analysis(image_url, query_text) 

我们现在已经将功能齐全的计算机视觉组件集成到我们的 GenAISys 中。有了这些功能,我们准备构建 CoT 推理过程。

使用 CoT 进行推理

全球市场的指数级加速导致每天在社交媒体、电子商务网站、生产线和 SaaS 平台等平台上产生数十亿个微任务。没有强大的自动化,跟上这些实时需求是不可能的。速度和效率变得至关重要,需要实时或接近实时地执行任务。最近在 AI 方面的进步显著帮助我们适应这些市场范式,在这些范式中,我们必须在越来越短的时间内处理越来越多的任务。然而,随着我们将 AI 功能的数量和范围增加以解决问题,用户运行复杂场景与共飞行员一起变得令人困惑。对于开发团队来说,创建包含他们需要的功能并包含清晰直观的操作序列以解决问题的 GenAISys 也相当具有挑战性。

在本节中,我们通过实现 CoT 推理来解决这些挑战。CoT 推理将复杂任务分解成更小、更易于管理的步骤,其中一步的输出成为下一步的输入。这个过程模仿(而不是取代)类似人类的推理。它减少了用户的认知负荷,使他们能够主要专注于决策。此外,CoT 推理使 AI 代理的内部思维过程变得透明,提供了每个推理步骤的实时可解释性。

本节的目标是使用 Python 构建一个 CoT 推理过程,利用我们开发的灵活和交互式的 GenAISys 框架。具体来说,我们将应用 CoT 来模拟在线旅游平台的客户偏好分析,生成活动创意建议,使用 DALL-E 生成图像,以及基于这些图像使用 GPT-4o 创建叙事叙述。

初看之下,CoT 认知代理可能看起来与传统软件开发中发现的函数序列相似。因此,在我们深入代码之前,让我们首先明确它们之间的重要区别。

GenAISys 中的 CoT 与传统的软件序列

经验丰富的软件开发者习惯于实现复杂的函数序列。为了弥合传统软件序列和认知 CoT 推理(它模仿而不是取代人类认知)之间的概念差距,让我们首先明确它们的用途:

  • 传统序列的非 AI 或 AI 函数由一系列独立执行的步骤组成,遵循一个黑盒模型,其中一个函数的输出作为下一个函数的静态输入。

  • CoT 推理过程中,步骤模仿人类的推理方式。每个步骤都超越了一个简单的函数,并遵循逻辑的进展。每个新的过程都建立在之前步骤的输出之上,正如我们在实现 CoT 时将看到的。我们将通过我们的交互界面实时观察 GenAISys 的“思考过程”。这个过程是透明的且可解释的,因为它在 IPython 界面中实时可视化。我们可以看到系统正在做什么,并在必要时隔离任何功能以调查过程。

CoT 的另一个关键方面是其中间推理

  • CoT 过程中的每一步都建立在之前的基础上,但并非所有步骤都是静态的。例如,当 DALL·E 生成一个图像时,它创造了一些全新的东西——而不是从数据库中检索出来的。这依赖于一个生成式 AI 模型,而不是预先编程的内容。

  • 过程的下一步不是预先生成的,而是一个固定的消息列表。例如,当 DALL-E 生成一个图像时,我们将要求 GPT-4o 执行一个基于它接收到的输入从无到有创造的故事讲述任务。或者,我们也可以要求 GPT-4o 简单地描述图像——无需更改或微调模型。

CoT 推理提供了更接近人类思维模式的认知对齐。我们人类将单一问题分解成更小的部分,处理每个部分,然后将中间结论组装起来以得出全局解决方案。我们在本章中构建的 CoT 过程的类似人类框架使 GenAISys 更加直观和富有创造力,模仿(而不是取代)人类的问题解决方法。在接下来的章节中,特别是在第六章中,我们将进一步扩展和增强 CoT 推理能力。这里的要点是,CoT 涉及一系列任务,但比经典的非 AI 或 AI 序列更加灵活和富有创造力。让我们继续前进,并定义 CoT 推理的认知流程。

CoT 推理的认知流程

我们将使用术语 认知流程 而不是传统的术语流程图来描述我们正在实现的 CoT 过程。这个术语强调了我们的 AI 代理类似人类的推理和动态问题解决能力,与经典的软件流程图有明显的区别。一个经典的流程图提供了函数序列的视觉表示。推理 CoT 认知流程或认知工作流程映射了 AI 代理从一步到另一步的思维过程的逻辑进展。认知流程显示了 AI 代理如何模仿人类推理。

让我们先了解一下我们将在 Python 中实现的认知流程,如图 5.9 所示。我们将使用的 Python 函数位于 commons 目录下的 reason.py 文件中,并在本章的 设置环境 部分的 OpenAI 子节 中详细描述。

图 5.9:CoT 过程的认知流程

图 5.9:CoT 过程的认知流程

我们 CoT 推理过程的认知流程由五个主要阶段组成,由 chain_of_thought_reasoning() 函数编排。这个序列从 开始 开始。

开始

当 CoT 推理过程接收到 AI 代理提供的输入文本时,它开始。AI 代理分析用户输入,然后触发 CoT 函数,如前文在 层 2:AI 代理 部分所述。在 CoT 函数的开始,发生两个关键初始化:推理记忆(steps = [])被初始化,并在 IPython 交互式界面中激活推理显示小部件:

steps = []
    # Display the reasoning_output widget in the interface
    display(reasoning_output) 

display(reasoning_output) 触发 display 小部件,它使交互式 IPython 接口能够实时更新,确保 CoT 过程对用户保持透明且易于理解。

第一步:ML 基准

第一步,ML 基准,激活机器学习端点 (machine_learning.ml_agent())。它使用决策树分类器动态分析客户数据并预测感兴趣的活动。该函数接受一个位置(例如,"Rome")和 "ACTIVITY" 作为预测的目标列:

# Step 1: Analysis of the customer database and prediction
    steps.append("Process: Performing machine learning analysis of the customer database. \n")
    with reasoning_output:
        reasoning_output.clear_output(wait=True)
        print(steps[-1])  # Print the current step
    time.sleep(2)  # Simulate processing time
    result_ml = machine_learning.ml_agent("Rome", "ACTIVITY")
    steps.append(f"Machine learning analysis result: {result_ml}") 

这段代码会为每个推理步骤重复:

  • 思维过程的每一部分都以类似这样的注释开始:# 第一步:分析客户数据库和预测

  • steps.append("Process: Performing machine learning analysis of the customer database. \n") 将步骤描述追加到推理记忆步骤列表中

  • with reasoning_output 为显示小部件启动代码块

  • reasoning_output.clear_output(wait=True) 清除 reasoning_output t

  • print(steps[-1]) # 打印当前步骤 打印最近添加的步骤

  • time.sleep(2) # 处理时间 引入两秒延迟

  • result_ml =machine_learning.ml_agent("Rome", "ACTIVITY") 调用 ml_agent

  • steps.append(f"Machine learning analysis result: {result_ml}") 将机器学习函数返回的结果追加到步骤列表中

来自 machine_learning.ml_agent 的输出,该输出预测了位于 "Rome" 的顶级客户偏好活动,成为后续步骤的输入,暗示了创意活动。

在进行下一步之前,让我们简要探索 machine_learning.py 内部的底层决策树分类器。

决策树分类器

决策树分类器非常适合我们的任务,因为它是一种通过根据特征值将数据分割成树状结构进行预测的机器学习模型。它通过在每次分割时递归地选择最优特征,直到达到定义的停止条件(如最大深度或每个叶子的最小样本大小)来工作。在每一步,可能性会缩小,直到出现单个预测。

要运行它,我们首先导入处理数据和构建决策树所需的库。我们还禁用了警告以避免 cluttering IPython 输出:

import pandas as pd
import random
from sklearn.preprocessing import LabelEncoder  # For encoding categorical variables
from sklearn.tree import DecisionTreeClassifier  # For training the Decision Tree model
import warnings
warnings.simplefilter(action='ignore', category=UserWarning) 

接下来,我们定义我们的分类器函数 ml_agent(),它有两个参数:

def ml_agent(feature1_value, feature2_column): 

两个参数如下:

  • feature1_value:我们想要预测活动位置的价值。

  • feature2_column:我们想要预测的目标列("ACTIVITY")。

函数首先将客户活动数据集加载到 pandas DataFrame 中:

 # Load the dataset from a CSV file into a DataFrame
    df = pd.read_csv("customer_activities.csv") 

然后,我们将分类变量(LOCATIONACTIVITY)进行编码以进行处理:

 # Create LabelEncoder objects for encoding categorical variables
    le_location = LabelEncoder()
    le_activity = LabelEncoder()
# Encode categorical values
    df["LOCATION_ENCODED"] = le_location.fit_transform(df["LOCATION"])
    df["ACTIVITY_ENCODED"] = le_activity.fit_transform(df["ACTIVITY"]) 

如果没有提供特定位置(feature1_value),则函数默认选择最频繁的位置:

# Select default location if feature1_value is empty
    if not feature1_value.strip():  # If empty string or only spaces
        feature1_value = df["LOCATION"].mode()[0]  # Most common location 

然后,我们从编码的数据中准备特征(X)和目标变量(y):

 # Select the encoded 'LOCATION' column as the feature (X)
    X = df[["LOCATION_ENCODED"]]
    # Select the encoded 'ACTIVITY' column as the target variable (y)
    y = df["ACTIVITY_ENCODED"] 

在数据准备就绪后,我们训练决策树模型:

 # Train a Decision Tree Classifier on the dataset
    model = DecisionTreeClassifier(random_state=42)
    model.fit(X, y) 

设置 random_state=42 确保每次运行代码时结果一致。现在,我们将提供的(或默认的)位置输入编码以准备预测:

 # Encode the input location using the same LabelEncoder
   feature1_encoded = le_location.transform([feature1_value])[0] 

Python 的 .transform 方法在 le_location 对象上将分类字符串转换为唯一的整数代码。

函数现在已准备好预测最可能的活动并将其转换回其原始标签。我们将使用训练模型的 Python .predict 方法来查看它对这个新数据点的预测:

 # Predict the encoded activity for the given location
    predicted_activity_encoded = model.predict([[feature1_encoded]])[0]
    # Convert the predicted numerical activity back to its original label
    predicted_activity = le_activity.inverse_transform(
        [predicted_activity_encoded]
    )[0] 

最后,该函数构建一个针对预测活动的客户描述性输出消息:

 # Generate output text
    text = (f"The customers liked the {predicted_activity} because it reminded them of how "
            f"our democracies were born and how it works today. "
            f"They would like more activities during their trips that provide insights into "
            f"the past to understand our lives.") 

此描述性输出返回到 CoT 函数:

 return text 

要从 CoT 函数调用分类器,我们使用以下方法:

result_ml = ml_agent("", "ACTIVITY")
print(result_ml) 

我们让分类器找到位置和活动。在这种情况下,预期的输出将是以下内容:

Machine learning analysis result: The customers liked the Forum of Rome because it reminded them of how our democracies were born and how it works today. They would like more activities during their trips that provide insights into the past to understand our lives. 

现在,我们将使用此步骤的输出建议活动。

第 2 步:建议活动

此步骤遵循与 步骤 1 相同的逻辑和结构。该过程的名称如下:

steps.append("Process: Searching for activities that fit the customer needs. \n") 

步骤 1 的输出 (result_ml) 成为发送给 GPT-4o 以增强输入上下文的指令的一部分。GPT-4o 的组合查询 (umessage) 如下所示:

umessage = (
        "What activities could you suggest to provide more activities and excitement in holiday trips."
        + result_ml
    ) 

在这个阶段,指令专门针对我们的以旅行为重点的领域。在 第六章 中,我们将这些指令演变为动态的事件驱动变量。在这里,我们继续使用我们在早期章节中构建的 GenAISys OpenAI API 调用:

mrole = "system"
    mcontent = (
        "You are an assistant that explains your reasoning step by step before providing the answer. "
        "Use structured steps to break down the query."
    )
    user_role = "user"
    task_response = make_openai_api_call(umessage, mrole, mcontent, user_role) 

从 GPT-4o 收到的输出 (task_response) 将作为下一步 (步骤 3) 的输入。添加和显示推理步骤的方法与 步骤 1 保持一致。

第 3 步:生成图像

此步骤首先从上一步收到的详细建议 (task_response) 中获取,并将其直接作为提示传递给 DALL-E 的图像生成函数。这里的结构和逻辑与之前的步骤一致,现在专注于生成图像:

prompt = task_response
image_url = generate_image(prompt) 

一旦生成,该图像将被下载并保存在本地,文件名为 c_image.png。如果检查了 文件 小部件,该图像文件将通过 IPython 接口显示,如 层 1:IPython 接口 部分所述:

 …
    save_path = "c_image.png"
    image_data = requests.get(image_url).content
    with open(save_path, "wb") as file:
        file.write(image_data)
    steps.append(f"Image saved as {save_path}")
    … 

图像生成并保存后,CoT 流程将推进到分析这个新创建的图像。

第 4 步:分析图像

此分析步骤的输入是 步骤 3 中生成的图像的 URL,存储为 image_url。如前所述,在这个笔记本中,查询文本目前被设置为针对 GPT-4o 的一个通用、但特定于旅行的请求。在随后的章节中,此查询文本将变为事件驱动和更动态。

对于我们的图像分析,我们指示生成式 AI 模型根据生成的图像编写一个引人入胜的故事:

query_text = "Providing an engaging story based on the generated image" 

包含指令的代码与之前的步骤相同。CoT 函数现在激活了在 图像生成和分析 部分之前描述的 image_analysis 函数:

 response = image_analysis(image_url, query_text) 

输出返回到 response 变量,并保存在 image_text.txt 文件中供进一步使用。这标志着 CoT 推理步骤的完成。

结束

完成所有推理任务后,CoT 函数通过清除和更新 IPython 显示来表示过程的结束。

 # Clear output and notify completion
    with reasoning_output:
        reasoning_output.clear_output(wait=True)
        print("All steps completed!")
    return steps 

从这里开始,IPython 接口接管。现在让我们从用户角度运行 CoT。

从用户角度运行 CoT 推理

在本节中,我们将无缝运行自本书开头以来一直在构建的复杂 GenAISys。一个提示将触发整个 CoT 流程。

我们将模拟一个用户激活 GenAISys 的推理能力,以获得在线旅行社的综合构思。具体来说,我们旨在预测客户偏好的活动,生成吸引人的图像,并创建讲述故事性的叙述来唤起客户的情景记忆。这些情景记忆可能是现实世界的经历或访问某个地方并参与特定活动的梦想。

要运行此场景,请确保勾选AI 代理文件复选框,并仔细输入以下提示:

Use reasoning to suggest customer activities. 

使用推理客户活动关键词将被 AI 代理识别并触发本章构建的 CoT 流程。或者,我们可以在 Pinecone 索引中实现下拉菜单或执行相似性搜索以检索特定的指令场景。STT 输入也是可能的。然而,在本章中,我们将使用带有关键词的输入提示来清楚地说明 CoT 流程。

第七章中,我们将构建一个中心关键词注册表和一个协调器,以进一步优化 AI 代理的决策过程。

一旦用户按下 Enter,我们只需坐下来观看,就像我们与在线 ChatGPT 类的共飞行员一样。第一个过程是分析客户基础,根据每日数据找到排名靠前的活动,如图所示。

图 5.10:寻找活动

图 5.10:寻找活动

一旦整个流程完成,决策树分类器将返回结果:

..Machine learning analysis result: The customers liked the Forum of Rome because it reminded them of how… 

下一个阶段涉及搜索适合客户偏好的合适活动:

图 5.11:寻找符合客户需求的活动

图 5.11:寻找符合客户需求的活动

GPT-4o 的创意输出提供了结构化步骤来增强在线产品:

Activity suggestions: To enhance holiday trips with more activities, especially focusing on cultural experiences, we can consider a variety of options. Here's a structured approach to brainstorming and suggesting activities:
…### Step 3: Suggest Activities
1\. **Historical Tours and Sites**:
- **Athens, Greece**: Visit the Acropolis and the Agora, where democracy was born. Include guided tours that explain the significance of these sites.
- **Philadelphia, USA**: Explore Independence Hall and the Liberty Bell, focusing on the birth of modern democracy.
- **Westminster, UK**: Tour the Houses of Parliament and learn about the evolution of the British democratic system… 

接下来,CoT 指示 DALL-E 根据这些建议的活动生成一个吸引人的图像:

图 5.12:基于前一步输出的图像生成

图 5.12:基于前一步输出的图像生成

因为勾选了文件复选框,所以生成的图像会显示出来。这个图像相当有创意,并且每次运行都会有所不同:

图 5.13:一幅文化和历史图像

图 5.13:一幅文化和历史图像

在这种情况下,图像包含诸如…对历史及其对现代生活的影响的理解。之类的文本,这与我们的请求完美契合。

注意,由于上下文变化和生成式 AI 模型(如 GPT-4o)的随机(概率)性质,每次运行可能会产生不同的输出。

下一个过程涉及要求 GPT-4o 为一个利用过去真实生活经历或想象之旅的情景记忆的故事性促销创建叙述:

图 5.14:基于生成的图像创建引人入胜的故事

图 5.14:基于生成的图像创建引人入胜的故事

如前所述,GPT-4o 生成的叙事输出是说明性的,并将有所不同:

…Story response: In the bustling town of New Haven, a place where history and technology intertwined, a young historian named Clara discovered an ancient artifact that would change everything. The artifact, a mysterious tablet, was said to hold the secrets of the past, capable of bringing historical figures to life through augmented reality… 

一旦 CoT 序列结束,GenAISys 将保持其推理状态,等待新的独立提示或进一步的 CoT 运行:

图 5.15:在 GenAISys 中持续激活推理

图 5.15:在 GenAISys 中持续激活推理

笔记本中的加载并显示对话历史加载并总结对话历史部分使用了详细说明的相同功能第四章

我们现在已经成功构建了一个小型 ChatGPT-like GenAISys,它配备了自定义功能,包括多用户支持、特定领域的 RAG 和定制的 CoT 能力。在接下来的章节中,我们将把这个 GenAISys 框架应用于几个实际的商业领域。

摘要

在本章中,我们已经完成了 GenAISys 的基本框架,由三层组成。第一层是一个 IPython 交互式界面,充当协调器。现在它包括语音功能、文件显示和 CoT 功能,以及用户输入、用户选择和 AI 代理小部件。

第二层是 AI 代理协调器,由用户提示触发。这表明在 GenAISys 中,由于这些组件的交互性质,协调和控制功能之间的界限有些模糊。AI 代理在 Pinecone 索引查询和 OpenAI API 代理生成任务(如内容生成和图像生成)之间分配任务。AI 代理还可以触发 CoT 过程,我们将在下一章进一步增强其功能。

第三层和最后一层包含 GenAISys 的核心功能,涉及由 GPT-4o 和 DALL-E 驱动的 AI 工作者。在本章中,我们介绍了 DALL-E 用于图像生成,并利用 GPT-4o 对这些图像提供有洞察力的评论。此外,我们还实现了一个决策树分类器来预测客户活动,将机器学习能力纳入我们的 GenAISys。

引入 CoT 功能标志着我们从用户角度创建无缝推理能力的初步步骤。复杂任务需要能够模拟人类推理的复杂人工智能系统。因此,在下一章中,我们将扩展 GenAISys 的推理能力,以及其他功能。

问题

  1. 在线生成式 AI 系统的无缝界面表明,构建该系统是容易的。(对或错)

  2. 选择一个大型语言模型LLM)就足以构建一个 GenAISys。(对或错)

  3. 生成式 AI 应用程序需要一个事件驱动的交互式界面。(对或错)

  4. 一个 AI 系统可以模仿人类推理。(对或错)

  5. CoT 过程只是一个经典函数的序列。(对或错)

  6. CoT 可以处理自然语言,但不能处理计算机视觉。(对或错)

  7. CoT 是一个认知代理,可以包括非 AI 或 AI 功能。(对或错)

  8. 推理 GenAISys 可以为最终用户分组一系列任务。(对或错)

  9. 经济的持续加速需要更多的自动化,包括 AI。(对或错)

  10. 以人为中心的推理 GenAISys 可以提升团队的效率。(对或错)

参考文献

  • 查恩,安迪,凯西迪·埃泽尔,迈克尔·考夫曼,凯文·韦,劳拉尔·哈蒙德,亨特·布拉德利,埃利奥特·布卢姆克,南迪尼·拉贾库马尔,大卫·克鲁格,尼基塔·科尔特,卢卡斯·海姆,以及马克斯·安德尔容。 “AI 代理的可见性。” 在 2024 年 ACM 公平、问责和透明度会议(FAccT ‘24)论文集中,里约热内卢,巴西,2024 年 6 月 3 日至 6 日。纽约:ACM,2024 年。arxiv.org/pdf/2401.13138.

  • 普塔,普拉文,埃里克·米尔斯,纳曼·加尔,索汉·莫特万尼,切尔西·芬恩,迪维亚恩什·加尔,以及罗汉·拉菲洛夫。 “Agent Q:为自主 AI 代理的高级推理和学习。” 最后修改于 2024 年。arxiv.org/abs/2408.07199.

  • 魏辛格,贾尼斯,彼得·马尔洛,以及弗拉基米尔·弗斯克维奇。 “代理。” Kaggle 白皮书。2025 年 7 月 8 日访问。www.kaggle.com/whitepaper-agents.

  • OpenAI. OpenAI API 文档。2025 年 7 月 8 日访问。platform.openai.com/docs/api-reference/introduction.

|

现在解锁这本书的独家优惠

扫描此二维码或访问packtpub.com/unlock,然后通过书名搜索此书。 | 白色背景上的二维码 AI 生成的内容可能不正确。 |

注意:在开始之前准备好您的购买发票。

第六章:推理电子营销 AI 代理

成功广告活动的基础概念是记忆。想想昨天你看到的广告。那一年前甚至几年前的广告呢?你记得最清晰的是那些对你最有效的广告,但可能对其他人来说并非如此。任何广告公司的主要挑战是设计能够触发不同个体积极反应的促销内容。更重要的是,成功的营销活动努力让消费者记住品牌、产品和服务。

尼尔森神经科学团队(Brandt & Nieuwenhuis,2017)解释了为什么记忆在广告中如此重要。他们证明,记忆在仅仅 24 小时后就显著衰退,这使得广告难以产生持久的效果。包括重复和内容情感或智力影响在内的几个因素可以增强记忆的保持。代理系统如 GenAISys 的出现重塑了营销格局,因为这些系统能够复制类似人类专家的营销推理。

在本章中,我们将增强我们在前几章中构建的 GenAISys。首先,我们将设计一个针对特定市场段的消费者记忆代理。这个代理的目标是分析消费者如何编码促销信息。我们将从探讨记忆为什么重要以及它是如何结构化的开始,检查关键的记忆类别,如短期、长期、显性和隐性记忆,以及重要的维度,如智力编码和情感编码。接下来,我们将通过将消费者记忆的更深入理解整合到其知识库中,扩展 GenAISys 的架构。然后,我们将开发一个利用前几章中引入的多模态能力的战略消费者记忆代理。这个代理将采用神经科学启发的策略来制作定制化的营销信息。通过引入 OpenAI 的高级o3 推理模型中的元认知,我们将使代理能够在其多步骤 CoT 推理过程中执行复杂的、近似人类的自我反思。

此外,我们将把我们的生成式 AI 模型转变为一个类似神经科学的代理,它能够进行推理分析,而不仅仅是内容生成。复杂系统——如人脑——不仅仅是其各部分的简单总和,机器智能也是如此。使用 OpenAI 的 o3 推理模型的战略消费者记忆代理将应用复杂的神经科学提示来分析酒店评论中的消费者记忆编码模式。这些洞察将输入到一个多模态的推理线程管道,建立在第五章中引入的 CoT 框架之上,即“通过思维链增加多模态、多功能推理”。最终,GenAISys 将利用这种详细的记忆分析,通过 GPT-4o 生成定制营销内容,并辅以 DALL-E 生成的图像。

最后,我们将通过添加新功能进一步增强 IPython 交互式界面,包括一个能够触发记忆分析和客户服务任务的代理元认知小部件。用户可以选择分析各种类型的内容以获得与记忆相关的洞察,或启动以客户服务为导向的 CoT 交互。

到本章结束时,你将学会如何构建一个基于我们消费者记忆代理架构的定制、推理驱动的 GenAISys,适用于任何领域。我们将一步步构建它。

本章涵盖以下主题:

  • 消费者记忆在营销中的重要性

  • 人类记忆的高级结构

  • 构建战略 CoT 消费者记忆代理

  • 使用 CoT 分析酒店评论

  • 设计类似神经科学的复杂提示

  • 使用 o3,OpenAI 的能够深入分析内容的推理模型

  • 使用 OpenAI 的 GPT-4o 生成内容,使用 DALL-E 生成图像

  • 在推理线程函数中将推理和生成组装在一起

  • 将消费者记忆代理 CoT 推广到任何内容

  • 增强 IPython 交互式界面

让我们从设计增强的 GenAISys 界面及其 AI 驱动的功能开始。

设计消费者 GenAISys 记忆代理

消费者神经科学可以通过情感共鸣、个性化的信息显著提升品牌记忆度。在本章中,我们首先分析消费者如何编码记忆。Nicks 和 Carriou(2016)展示了有效的消费者神经科学通过叙事迁移来利用讲故事,使消费者情感投入并生动地记住促销信息。

在我们的实现中,我们将深入分析消费者如何编码记忆,保持一种真实的方法。如果消费者对一项服务表示不满,我们的系统将定制信息以强调改进的提供。我们的目标是通过对记忆深刻、情感共鸣的信息建立真正的联系。

在本节中,我们将描述如何增强我们在前几章中构建的 GenAISys:

  • 消费者记忆代理用例:展示了如何将来自短期和长期记忆(LTM)框架的记忆原则应用于解释消费者反馈。

  • 定义记忆结构:这超出了我们之前考察的基本类别,如短期记忆(STM)、LTM、情景记忆和语义记忆,并引入了新的类别和维度,为输入提供了更深入的分析。

  • 增强 GenAISys 的架构:这为触发 AI 代理添加了新功能,并集成了一个新的 CoT 场景。

让我们先探索消费者记忆代理用例。

消费者记忆代理用例

本章中的用例展示了如何通过一个 CoT 消费者记忆代理来增强 GenAISys。我们的目标是通过对酒店评论的详细分析来理解特定消费者在选择酒店时的需求。我们开发的系统执行全面的内容分析,评估情感,并生成个性化的营销内容。CoT 代理通过酒店评论的详细记忆和情感分析启动此过程。它识别心理特征、情感标记和特定的记忆标签,为每个分析段分配情感分数。这些分数被组合起来产生一个整体情感分数和评分(0-5)。通过这种方法,代理有效地捕捉了特定酒店体验是如何被感知、情感处理并在消费者记忆中保留的。

基于这些提取的见解和由此产生的认知档案,代理使用评分来确定适当的营销策略。最终,消费者记忆代理生成定制的促销内容,包括一个带有相关图像的定制信息。例如,如果分析揭示了一个通常不喜欢酒店的客户,旅行社可以强调客户之前提到过的替代住宿或改进的服务。在这种情况下,代理生成一个带有吸引人图像的个性化信息,如图图 6.1所示。

图 6.1:由 DALL-E 生成的基于自定义内容的图像

图 6.1:由 DALL-E 生成的基于自定义内容的图像

代理通过分析从客户酒店评论中确定的认知档案来制作一个温暖、个性化的信息:

Customer message: Dear Customer,
We invite you to consider a unique vacation experience that goes beyond the typical hotel stay. Imagine the warmth and comfort of staying with family or friends, where every moment is filled with genuine connections and cherished memories. From waking up to the aroma of freshly brewed coffee made just the way you like it to sharing home-cooked meals and laughter around a family table, this experience offers a heartfelt alternative to the impersonal nature of hotels. Embrace the spontaneity and freedom of living in the moment, surrounded by those who matter most. Whether it's a cozy evening of board games or a relaxed afternoon in the backyard, staying with loved ones provides a true home away from home. This vacation, choose the warmth of a family home and create memories that will last a lifetime. Book your stay with loved ones today and rediscover the true meaning of home.
Warm regards,
[Your Company Name] 

生成式 AI 是随机的,因此相同的输入不一定产生相同的输出。因此,响应可能从一个运行到另一个运行而变化。

现在我们来定义消费者记忆代理将使用的记忆结构。

定义记忆结构

让我们现在通过概述构建我们的消费者记忆代理所必需的人类记忆结构来扩展在第一章中引入的记忆类别。人类记忆是多方面的:STM暂时捕捉执行即时任务或情绪处理所需的信息,如果没有强化会迅速消失;LTM在长时间内存储重要事件、知识和经验;语义记忆存储一般知识和事实,独立于个人经验;情景记忆捕捉带有背景和细节的个人经历;程序记忆使无意识的任务检索成为可能,例如走路或驾驶;情绪记忆根据情绪强度对经历进行分类——积极或消极;显性记忆涉及有意识的回忆,而隐性记忆在无意识中运作。

我们的消费者记忆代理将使用这些记忆类别的灵活组合来分析消费者内容,如图图 6.2所示。这种分类为 o3 OpenAI 推理模型提供了足够的自由度,以有效地解释消费者数据。

图 6.2:记忆代理的记忆类别

图 6.2:记忆代理的记忆类别

上层的主要类别如下:

  • 无记忆指系统或人类无法记住过去事件的信息。这些是我们最易忘记的事件,例如我们昨天眨眼的次数。

  • 短期记忆用于暂时存储信息以执行任务或情绪过程。如果没有事件再次刺激,这种记忆会迅速衰退。这可能是阅读长文本的工作记忆。

  • 长期记忆指我们在长时间内存储的信息,从几天到几年。这是一种至关重要的记忆,例如知道我们身处哪个国家,我们的年龄,以及我们的家庭成员是谁。

  • 现实记忆是我们确信与实际事件或事实相关的内容,以及外部世界。

  • 虚构记忆包括想象或假设的内部事件或叙述。

  • 时间记忆对于区分过去、现在和未来事件至关重要。否则,我们会认为我们已经吃掉了我们打算明天午餐要吃的东西。

注意到无记忆、短期和长期记忆形成一个子集(浅绿色),而现实、虚构和时间记忆(浅橙色)都是相互连接的。这些类别并不是孤立的;它们在现实生活中动态地相互连接。换句话说,我们的记忆不是在子集中运作,而是在我们称之为标签的 AI 中运作。一个记忆可以是多个标签的组合:

  • 一种无记忆的虚构,例如梦境

  • 短期现实,例如阅读新闻

  • 长期虚构,例如我们很久以前读过的小说

当检查这些记忆子类别时,我们很快就会意识到与主要记忆类别(如语义 STM 或情景 LTM)可能的标签组合数量众多。此外,记忆可以无缝地融合子类别;例如,短语“我去年访问了罗马”同时结合了情景、语义和时间记忆标签。此外,我们的记忆范围从隐性的(潜意识地整天眨眼)到显性的(由于不适而有意眨眼)。

在我们的消费者记忆代理中,我们将要求对内容进行彻底分析,为每个文本段分配适当的记忆标签。然而,即使这种详细的标签本身也不够。为了有效地捕捉消费者体验,我们将通过三个分析维度丰富每个记忆标签:

  • 智力维度:识别文本中的思想、逻辑和推理。

  • 情感维度:确定情感、感受和整体情绪——对于有效的消费者参与至关重要——并提供一个从 0 到 1 的可量化的情感评分,可扩展到熟悉的 1-5 评分,用于客户满意度表格。

  • 物理维度:突出感官体验和身体感觉,例如“游泳太冷了”或“睡在那家酒店的床上后背疼。”

考虑到这些增强,让我们现在探索如何将它们整合到我们不断发展的 GenAISys 架构中。

增强 GenAISys 的架构

在本章中,我们将基于之前在图 5.3中展示的 GenAISys 现有三层架构,如下所示:

图 6.3:事件驱动的 GenAISys 的三个层次

图 6.3:事件驱动的 GenAISys 的三个层次

我们的方法将是自下而上的,从基础功能开始,然后通过 AI 代理向上到 GenAISys 界面:

  • 第 3 层(功能和代理):在这里,我们将向我们的自定义 OpenAI 库(reason.py)中引入额外的功能,这些功能专门针对消费者记忆代理和 CoT 推理。我们还将开发一个独立的记忆分析功能,该功能提供类似于神经科学的分析,适用于任何内容。

  • 第 2 层(AI 代理):这一层管理我们 GenAISys 的行为和决策。我们将建立明确的输入触发器和命名规范,以有效地激活和控制 AI 代理。

  • 第 1 层(IPython 界面):交互式界面将扩展以方便用户交互。我们将添加一个新的小部件,使用户能够方便地选择如何调用消费者记忆代理。最初,我们将专注于酒店评论,然后推广到任何形式的输入。

让我们现在开始构建消费者记忆代理。

构建消费者记忆代理

在本节中,我们将我们的 GenAISys 提升到下一个层次,通过为其配备分析酒店评论的神经科学能力。消费者记忆代理将捕捉用户的认知、情感和身体心态,通过六个步骤的 CoT 过程解码每个评论段,如图图 6.4所示:

图 6.4:记忆代理的思维链过程

图 6.4:记忆代理的思维链过程

消费者记忆代理的 CoT 将使用 OpenAI 的 o3、GPT-4o 和 DALL-E 来运行其六个步骤:

  • 步骤 1:记忆和情感分析:代理将使用复杂的记忆结构系统信息分析酒店评论的内容。它将逐段分析和标记内容。

  • 步骤 2:提取评分:代理处理步骤 1 的输出,以提取每个内容段的情感评分。

  • 步骤 3:统计分析:代理使用所有标记段的评分来生成内容的整体认知评分。

  • 步骤 4:创建内容:代理现在必须根据评分做出决定。如果评分超过积极阈值,它将生成一条鼓励消费者选择酒店的短信。然而,如果评分是负面的,将创建一个客栈信息。一旦做出决定,代理将使用消费者的记忆标签创建一个定制的促销信息。

  • 步骤 5:图像创建:代理现在使用步骤 4 的输出创建一个符合消费者心态的图像。

  • 步骤 6:信息创建:代理现在拥有生成针对消费者定制信息的所有必要信息。

在单独开发这些步骤之后,我们将在接下来的部分中完全集成它们,即GenAISys 界面:从复杂到简单,旨在将 CoT 功能推广到酒店评论之外。

要开始我们的旅程,请打开1_Building_the_Consumer_Memory_Agent.ipynb笔记本,该笔记本在 GitHub 的 Chapter06 目录中重用了之前构建的功能(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。我们首先将下载一组酒店评论数据集,以提供 AI 代理的输入。

数据集:酒店评论

我们将使用合成的酒店评论来构建记忆代理。在本章中,我们将处理酒店评论,并将代理的记忆结构推广到我们希望分析的其他内容。由于版权原因,我们使用的数据集是由人工创建并使用生成式 AI 辅助创建的合成评论数据集。

如果你想探索更多数据集,可以使用包含 Kaggle 上 TripAdvisor 酒店评论的类似数据集,用于非商业私人实施,网址为www.kaggle.com/datasets/andrewmvd/trip-advisor-hotel-reviews

在 GitHub 上运行设置环境部分,与第五章相同,并直接从 GitHub 仓库下载数据集:

download("Chapter06","hotel_reviews.csv") 

提示:使用AI 代码解释器快速复制功能增强您的编码体验。在下一代 Packt Reader 中打开此书。点击复制按钮

1)快速将代码复制到您的编码环境,或点击解释按钮

2)让 AI 助手为您解释一段代码。

白色背景,黑色文字  AI 生成的内容可能不正确。

下一代 Packt Reader随本书免费赠送。扫描二维码或访问packtpub.com/unlock,然后使用搜索栏通过书名查找此书。请仔细核对显示的版本,以确保您获得正确的版本。

白色背景上的二维码  AI 生成的内容可能不正确。

我们将使用 pandas DataFrame 处理数据集。程序现在加载 CSV 文件并显示数据:

import pandas as pd
# Load the CSV file into a Pandas DataFrame
dfta = pd.read_csv('/content/hotel_reviews.csv',sep=',')
# display the DataFrame
dfta 

此数据集包含两个主要列:ReviewRating。例如,记录 0 有一个相对建设性的评分 3,而记录 1 显示一个明显的正面评分 5:

图 6.5:酒店评论数据集摘录

图 6.5:酒店评论数据集摘录

然而,仅凭评分不足以提供足够的深度——我们需要细微的情感分析来完全理解客户为何满意或不满意。我们将选择一篇具有挑战性的评论开始我们的分析:

index_number = 0  # Specify the index number 

程序现在提取评论及其评分:

 # Extract the desired fields
    review = row['Review']
    rating = row['Rating']
    # Display the results
    print(f"Review: {review}")
    print(f"Rating: {rating}")
except IndexError:
    print(f"Error: Index {index_number} is out of bounds for the DataFrame.")
except KeyError as e:
    print(f"Error: Column '{e}' not found in the DataFrame.") 

输出显示评论及其评分:

Review: We got a nice hotel. The parking was rather expensive. However, we got a good deal for my birthday. We arrived in during the night because of a late flight but the parking was open 24hours The check in was rapid. The room was a large size. Cool. But we didn't get the view expected. The bed was super comfortable and got a nice sleep for a few hours but then there was a raucous of a noisy crowd going to bed late. Anyway the price was acceptable and we made it to the shopping mall next to the hotel which reminded me of the one we had at home.
Rating: 3 

我们选择了一篇难度较大的评论,因为它包含负面和正面情感。评论的负面方面将挑战代理生成建设性的解决方案。在继续之前,请自己分析每个评论段的记忆标签、情感分数和维度。这项练习明确了记忆类别使用情况,并为将您的见解与代理的分析进行比较提供了基准。将提取的评论作为初始输入:

input1=review 

我们现在将为input1第 1 步设计一个复杂系统消息。

第 1 步:记忆和情感分析

此步骤通过结合 OpenAI o3 推理模型中的元认知和元推理,将高级推理引入我们的消费者记忆代理。换句话说,代理不会仅仅处理文本——它将积极反思其内部推理,进行逐段分析以分类记忆类型并分配情感分数。

具体来说,o3 模型将在我们精心设计的系统消息中运行,我们将详细设计这个系统消息。这个系统消息明确地引导模型,促进深入推理,并确保它根据类似人类的认知过程准确分配记忆标签。我们确实处于推理和自我反思 AI 的时代!

在本节中,我们将执行以下操作:

  • 设计一个复杂的系统消息,其中包含之前定义的详细记忆结构。这个消息被称为system_message_s1,将单独存储在 Python 文件中以实现模块化。

  • 依靠 OpenAI 的 o3 的推理能力来完成繁重的工作并执行详细的段落级分析,从而减轻我们手动解释的负担。

注意,我们使用 o1 作为一个总称,向 LLM(大型语言模型)表明其作为推理模型的角色。此外,尽管我们在 API 中尽可能多地使用 o3,但 LLM 在回复中可能会直接提到 o1。

现在,让我们一步一步地构建这个详细的系统消息。

设计步骤 1 的复杂系统消息

我们必须设计一个足够全面的系统消息,以便模型能够深入理解和执行受神经科学启发的记忆分析。为此,我们仔细地将消息结构化成明确标记的各个部分,每个部分引导代理通过分析的各个方面。

0. 模型介绍和代理的角色

第一行在两个层面上为代理设定了基调。第一个层面为代理提供了理解此任务高级记忆分析所必需的概念。第二个层面详细描述了代理的角色:

You are a generative AI model, an advanced memory-analysis model. Your role is to examine **each segment** of an incoming text and generate a set of "memory encoding tags," similar to how the human brain encodes memories in neuroscience. For every segment in the input, you will identify which categories apply, discuss the rationale, and assign additional metadata (dimension, sentiment, etc.). 

现在,让我们通过这些说明来了解代理通过消息的这一部分所学习的内容:

  • 生成式 AI 模型,一个高级记忆分析模型:我们以一种特殊的方式设定了系统的角色。我们要求模型思考,而不仅仅是生成文本。对于这个任务,我们不希望模型被创建,而是要分析和推理。

  • 检查**每个段落**:我们正在教模型复制神经科学方法。我们的大脑以离散的包编码信息。在这种情况下,我们要求模型模仿人类的记忆过程。文本的每个部分可以是一个句子、一个句子片段或一个段落。这样,模型将以类似于人类大脑在独立包中编码信息的方式分析文本。

  • 生成一组“记忆编码标签”,类似于人类大脑编码记忆的方式:人类大脑使用标签来编码记忆,这是一个我们可以在高层次上使用而无需深入了解生物过程的术语。我们的大脑将标签应用于它们编码的每一信息位,以区分过去的事件和未来的事件,例如,从语义数据或个人情感体验中。这些标签代表了我们在人类生成的文本中寻找的记忆类别。

  • discuss the rationale, and assign additional metadata: 模型必须解释它标记的记忆类别的理由。每个类别,如 STM 或 LTM,都必须解释。我们需要知道为什么将记忆标签分配给该段。模型被要求在其描述中添加维度,包括理性和情感原因。

你可能会在代码中注意到一个 Markdown 分隔符(---)。它向模型显示我们现在正在转向另一个主题。这可能看起来并不重要,但我们需要强调主题的变化,就像我们向人类给出指令时那样。现在,我们将给模型一个目的。

1. 目的

第 3 行是一个标题,向模型显示我们正在进入消息的第一个重要部分:

### 1\. Purpose 

第 4 行定义了 o3,OpenAI 推理模型的目标:

The goal is for you, O1, to perform an **in-depth memory analysis** of each segment of the text. In other words, you will classify and label each segment you find using specific memory categories (also called "memory encoding tags"). This process provides insight into how different parts of the text might be encoded in human memory. 

注意消息中包含的“o1”,在这里用作 OpenAI 推理模型的通用术语。主要思想是让 API 理解我们期望推理。无论选择哪个推理模型,这条指令都将激活推理。目的部分的要点坚持我们期望的内容:

  • in-depth memory analysis: 我们不希望进行经典分析,而是一种深入到每个段落的细节的反思。

  • Classify and label each segment you find using specific memory categories: 这是一个强烈的指示,表明模型预期要标记的记忆类别。再次提醒智能体,我们不希望生成文本,而是对段落进行分类和标记。

  • provides insight into how different parts of the text might be encoded in human memory: 这是一个明确的指示,我们期望类似人类的思考,并复制大脑编码记忆的方式。

我们现在需要给智能体提供它需要学习的标题。前几行提供了清晰的指令。现在,我们已经到达了消息的第二节。

2. 记忆编码标签

我们现在教智能体如何识别不同的人类编码标签类别。我们正在触及人类记忆编码的核心。记忆类别是本章 定义记忆结构 部分中讨论的那些:

### 2\. Memory Encoding Tags (Categories) 

这个标题至关重要,因为智能体将通过这个标题的提示来学习我们期望的标签。现在,智能体已经吸收了这个标题。然后,我们给模型一个清晰的解释,说明我们期望它采取哪些行动:

Below is a list of memory categories you must use. Consider them your "tagging schema." A single segment may exhibit one or more categories. If no category seems relevant, you may provide the special tag "memoryless" to indicate no significant memory encoding. 

让我们关注这条消息的关键部分:

  • tagging schema: 将模型与人类大脑编码不同记忆类别的方式对齐,使用 标签 来区分过去和现在

  • A single segment may exhibit one or more categories: 解释给模型知道一个记忆可以编码在多个类别中,就像在人类大脑中一样

  • If no category seems relevant … memoryless: 告诉模型,如果它无法确定一个记忆的类别,应该分配一个无记忆标签

我们随后明确定义了类别(例如,STM、LTM、情景记忆、语义记忆、时间记忆、现实记忆、虚构记忆、无记忆),如前所述:

1\. **Short Term Memory (STM)**
   - Used for information that seems fleeting, recently introduced, or relevant only in the immediate context.
…
8\. **Memoryless**
  - If a segment does not appear to connect to any memory encoding or is purely functional text (e.g., disclaimers, random filler), label it "memoryless." 

记忆标签已经描述,但不足以捕捉人类记忆,人类记忆依赖于其他维度来编码事件。

3. 维度

维度部分为智能体调查增添了智力、情感和身体特征。以下信息中这些维度的描述在之前的定义记忆结构部分已有描述:

`Dimension Descriptions`
  1\. `Intellectual`
  2\. Logical, analytical, or factual thought processes.
      - `Explanation`: If the text focuses on reasoned arguments, data, 
        or factual details, it should be labeled "Intellectual."
  3\. `Emotional`
  4\. Feelings, mood, or affective elements.
      - `Explanation`: If the text displays happiness, sadness, or other 
        strong emotional content, "Emotional" is assigned.
  5\. `Physical (with Sensations` 

有了这些,我们已经定义了记忆类别和额外的维度。然而,我们还需要对情感进行更精细的分析。

4. 情感得分

如在定义记忆结构部分所定义,情感得分衡量一个段落的情感价值。它提供一个介于 0(负面)和 1(正面)之间的数值得分,如果无法检测到情感,则为 0.5(中性):

### 4\. Sentiment Score
Assign each segment a **sentiment score** between **0.0** and **1.0**, where:
  - **0.0** = very negative
  - **0.5** = neutral
  - **1.0** = very positive
If a segment is purely factual with no emotional valence, use 0.5 (neutral). 

注意,信息中的每个部分都以清晰的 Markdown 指示符开始和结束,表明主题的变化。

接下来,我们将要求一个特定的响应格式。

5. 响应格式

我们需要响应清晰地显示原始文本的每个部分,为每个部分提供记忆标签,确定每个部分的维度(智力、情感或身体),提供情感得分,并提供简短的解释以证明分析:

### 5\. Format of the Response
For **each segment** in the incoming text:
  1\. Show the segment excerpt or a short summary.
  2\. **Memory Tags**: list any relevant categories.
  3\. **Dimension**: choose intellectual, emotional, or physical.
  4\. **Sentiment Score**: 0.0 → 1.0.
  5\. **Brief Explanation**: why these tags/dimensions. 

为了确保模型理解我们要求的内容,我们提供了一个示例格式:

Example format:
Segment 1: "Excerpt..."
  - Memory Tags: [Time Memory Past, Reality Memory]
  - Dimension: Emotional
  - Sentiment Score: 0.7
  - Explanation: The speaker refers to a past real event with positive affect. 

如果我们正在编写一个传统的生成式 AI 模型信息,我们就可以在这里停止。然而,这是一个复杂的信息,因此我们需要添加指令来坚持我们期望的内容。

6. 额外指令

我们避免了在信息的前几部分过度加载指令。如果我们试图塞入太多指令,模型可能会感到困惑。让我们提醒系统,我们始终希望进行分段分析。我们坚持认为,如果模型找不到类别,我们希望得到一个“无记忆”标签,而不是幻觉。此外,我们只希望有简短且清晰的解释:

### 6\. Additional Instructions
  - Always analyze segment-by-segment.
  - If no memory category applies, use "memoryless."
  - Use a short but clear explanation. 

现在是棘手的部分。我们告诉模型,如果它完全找不到类别,则使用“无记忆”标签。然而,如果模型有一个想法但不是 100%确定,那么它被允许选择最可能的记忆标签,并附带一个强制性的情感得分:

 - If uncertain about the correct memory category, pick the most likely.
  - Always include a sentiment score. 

到目前为止,我们已经向模型提供了许多指令。让我们确保它记得其主要任务。

7. 主要任务回忆

在我们向模型提供的所有指令之后,我们将提醒模型其主要任务是文本段落的记忆标签分析。我们还期望输出格式按照定义的结构化:

### 7\. Primary Task
When I provide multisegment text, you must do a thorough memory-tag analysis for each segment. Return the results in the structured format above.
[End of System Prompt] 

注意,我们添加了 [系统提示结束] 以确保模型理解全局提示的信息部分现在已完全定义。我们使用术语 prompt 来确保它理解它是一组指令,而不仅仅是一般信息。

我们现在已准备好运行记忆分析。

运行记忆分析

我们设计的复杂系统消息存储在名为system_message_s1的变量中,位于 GitHub 仓库的commons目录下的cot_message_c6.py中。目标是使这条消息以及其他步骤的消息与函数调用分开,以便 GenAISys 的 AI 代理可以在本步骤或其他步骤中重新使用此函数用于不同的任务。

我们首先下载包含消息的文件:

download("commons","cot_messages_c6.py") 

然后我们导入system_message_s1消息以及我们将在第 4 步中需要的消息,我们稍后会讨论:

from cot_messages_c6 import (
    system_message_s1, generation,imcontent4,imcontent4b)
print(system_message_s1) # Print to verify 

print函数取消注释后,将显示我们刚刚创建的消息。它可以在任何时间取消注释并使用,以验证消息是否正确导入。我们现在为 o3 准备消息:

# Step 1 : Memory and sentiment analysis
mrole= system_message_s1
user_text=review 
  • mrolesystem_message_s1,我们设计的系统消息

  • user_textreview,从酒店评论数据集中选择的评论

我们现在调用 o3 并将结果存储在一个变量中:

retres=reason.make_openai_reasoning_call(user_text, mrole) 

make_openai_reasoning_call位于reason,GenAISys 的 AI 库。它接受我们刚刚定义的两个参数,创建 OpenAI 客户端,发出请求,并返回响应:

# Implemented in Chapter06
def make_openai_reasoning_call(user_text, mrole):
    system_prompt=mrole
    client = OpenAI()
    rmodel = "o3-mini" # o1 or other models. model defined in this file in /commons to make a global change to all the notebooks in the repo when there is an OpenAI update
    response = client.chat.completions.create(
        model=rmodel,
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_text}
        ],
    )
    return response.choices[0].message.content 

对于这次调用,我们选择了o3-mini版本的o3推理模型系列。可以选择其他版本和推理模型。程序显示了在retres中接收到的输出:

# Print the generated output (memory analysis)
print(retres) 

输出显示了系统消息和 o3 推理模型的深度。AI 模型已将内容分解为段,并潜意识地解码了人类审阅者使用的记忆标签,如第一段所示。

模型首先提供段落数和该段的内容。让我们关注第 7 段,它需要我们的注意:

Segment 7: "But we didn't get the view expected." 

它还提供了编码此段落的记忆标签:

- Memory Tags: [Episodic Memory, Reality Memory] 

它继续提供维度,如下所示:

• Dimension: Emotional 

接着给出一个情感分数,如下所示:

• Sentiment Score: 0.4 

最后,它产生一个总结其分析的说明:

 - Explanation: The disappointment regarding the view introduces a negative emotional element to this real-life account, impacting the overall perception of the stay. 

模型接着对其评论的所有段进行分析。我们现在已经完成了一个复杂的记忆分析,为后续步骤奠定了基础。让我们继续提取情感分数。

第 2 步:提取情感分数

从这一点开始,存储在review中的原始输入不再使用。CoT 过程依赖于前一步的输出,这将根据上下文不断变化。下一步涉及从第 1 步:记忆和情感分析产生的所有段提取情感分数。我们需要这些信息来为第 4 步:内容创作做出决策。

为了提取分数,我们首先创建一个extraction函数并提供详细的说明:

def extract(tasks_response):
    umessage = """
    1) Read the following text analysis that returns detailed memory tags for each part of the text
    2) Then return the list of memory tags with absolutely no other text
    3) Use no formatting, no hashtags, no markdown. Just answer in plain text
    4) Also provide the sentiment analysis score for each tag in this format(no brackets) : memory tag sentiment Score
    """ 

我们已明确指示我们的 GenAISys 只以干净的格式提供情感分数。现在我们将使用之前定义的reason.make_openai_api_call调用 GPT-4o,并添加reason.py,这是我们之前章节开始构建的 AI 库。API 调用的输入是最后一步的输出retres,附加到指令消息umessage

 umessage+=retres 

system角色提醒代理其心理营销功能:

 mrole = "system"
    mcontent = "You are a marketing expert specialized in the psychological analysis of content" 

user角色引入用户消息umessage,并执行 API 调用:

 user_role = "user"
    task_response = reason.make_openai_api_call(
        umessage,mrole,mcontent,user_role
    )
    return task_response 

代理返回task_response,我们将从中提取记忆情感分数,处理并验证:

# Step 2: Extract scores
task_response=extract(retres)
print(task_response) 

每个记忆标签预期的输出分数列表如下:

Reality Memory sentiment 0.8
Episodic Memory sentiment 0.8
Reality Memory sentiment 0.4
Episodic Memory sentiment 0.4
Episodic Memory sentiment 0.8
Reality Memory sentiment 0.8
Time Memory Past sentiment 0.8
Episodic Memory sentiment 0.5… 

我们现在需要整合这些分数,以便用于决策。

第 3 步:统计

我们将使用一个简单的非 AI 正则表达式re)模块来执行此函数的匹配和提取。这表明 GenAISys CoT 可以包含非 AI 函数,从而扩展其范围,超越生成式 AI 模型。

要分析的文字是前一步的输出:

# Input text
text=task_response 

我们正在寻找小数:

# Regular expression to extract sentiment scores
pattern = r"(\d+\.\d+)"
scores = [float(match) for match in re.findall(pattern, text)] 

我们然后显示分数:

# Output the extracted scores
print("Extracted sentiment scores:", scores) 

输出包含分数:

Extracted sentiment scores: [0.8, 0.8, 0.4, 0.4, 0.8, 0.8, 0.8, 0.5, 0.5, 0.5, 0.7,… 

如果函数返回分数,我们首先计算一个总体分数:

# Optional: calculate the overall score and scaled rating
if scores:
    overall_score = sum(scores) / len(scores) 

然后我们将分数从 1 到 5 进行缩放:

scaled_rating = overall_score * 5 

最后,我们显示总体分数和缩放分数:

print("Overall score (0–1):", round(overall_score, 2))
print("Scaled rating (0–5):", round(scaled_rating, 2)) 

输出是我们预期的:

Overall score (0–1): 0.63
Scaled rating (0–5): 3.14 

输出需要一些人工分析:

  • 在实际项目中,这个过程可能不会如此顺利!也许 AI 代理根本不会产生我们期望的结果;也许它会在某一步产生,但不会在分数上。当这种情况发生时,我们必须处理替代步骤。构建 GenAISys,就像任何 AI 系统一样,是一个迭代的过程。

  • 在酒店数据集中,此评论的原始评分为 3,我们获得了 3.14,这更加精细。在线评分是主观的,可能无法准确反映评论的内容。AI 代理将通过类似本节中所述的高级分析过程提供更细致的评分。我们可以平均酒店评论和我们的评论。然而,我们的目标是生成针对消费者的定制信息。在实际项目中,我们会联系营销小组中的消费者,利用消费者记忆代理,并获取实时反馈。

然而,目前我们有了确定要创建的内容所需的信息。

第 4 步:内容创建

在决定要创建的内容之前,代理读取信息消息。第一条消息是umessage4

from cot_messages_c6 import umessage4 

消息包含有关如何创建促销活动的说明。我们将消息保存在一个变量中,以便函数可以根据任务使用不同的提示进行调用。

代理必须首先使用分析的内存标签生成文本,而不是分析:

umessage4 = """
1) Your task is to generate an engaging text  for a customer based on a memory analysis of a text
2) The analysis of the text is provided in the following format: text segment, memory tags, dimension, sentiment score, and explanation
The text also contains the overall sentiment score and the list of memory tags in the text
3) Use no other memory tags than those provided to generate your engaging text 

然后,代理接收有关情感分析的说明:

4) Use the overall sentiment score to give the tone of your response
If the overall sentiment score is positive write an engaging text addressing each segment with its memory tag and sentiment score
If the overall sentiment score is negative analyze why and find ideas and solutions to find a way to satisfy the customer
If the overall sentiment score is negative analyze make sure to show empathy for this negative feeling and then make the transition from negative to positive
4) Focus on the topic provided that begins with the term the topic which focuses on the core topic of the text to make the customer happy 

然后,代理接收有关要生成内容的最终说明:

5) Use your training to suggest named entities for that topic to make sure that the customer receives a message tailored to the memory tags and sentiment score 

我们现在通过添加我们获得的评分和代理找到的记忆标签来创建输入:

ugeneration=generation + "The advanced memory analysis of each segment of a text with a sentiment score:" + retres + " the scaled overall rating: "+ str(scaled_rating)+ " and the list of memory tags of the text "+ task_response 

代理现在对预期的任务有一个完整的表示。我们用imcontent4解释代理的角色:

imcontent4 = "You are a marketing expert specialized in the psychological analysis of content" 

代理现在准备好使用make_openai_api_call调用进行生成:

ugeneration=generation + …
mrole4 = "system"
mcontent4 = imcontent4
user_role = "user"
pre_creation_response = make_openai_api_call(
    ugeneration,mrole4,mcontent4,user_role
)
print(pre_creation_response) 

如果情绪是消极的,则响应是一个富有同情心的pre_creation_response,否则它会适应评论的语气:

**Segment 7: "But we didn't get the view expected."**
Memory Tags: [Episodic Memory, Reality Memory]
Sentiment Score: 0.4
It's understandable to feel a bit let down when expectations aren't met. For future stays, … 

输出是一种认知格式。我们将运行相同的调用,但带有清理和准备内容以生成图片的消息:

umessage4b="Clean and simplify the following text for use as a DALL-E prompt. Focus on converting the detailed analysis into a concise visual description suitable for generating an engaging promotional image" + pre_creation_response
mrole4b = "system"
mcontent4b = imcontent4b
user_role4b = "user"
creation_response = make_openai_api_call(
    umessage4b,mrole4b,mcontent4b,user_role4b
)
print(creation_response) 

输出是一个清晰的指令,要求创建一个包含令人兴奋的豪华优惠的图片,这种优惠总是受到欢迎的:

"Luxurious hotel stay with spacious rooms and swift check-in; enjoy a comfortable bed and convenient 24-hour parking. Celebrate with special deals and nearby shopping reminiscent of home. Despite minor noise and view issues, the overall experience is positive and memorable." 

每次运行请求时,信息的输出可能会有所不同,但语气应保持一致。此外,我们可以调整指令以生成其他内容。在这种情况下,代理已经准备好使用此指令来创建图片。

第 5 步:创建图片

在这个阶段,消费者记忆代理使用在第 4 步:内容创建期间生成的指令(creation_response)来使用 OpenAI 的 DALL-E 创建定制的促销图片:

# Step 5: Creating an image
import requests
prompt=creation_response
image_url = reason.generate_image(prompt) 

generate_image(prompt)函数是从上一章复用的。通过一致地复用函数,我们减少了开发开销并确保了代码的可维护性。正如第五章中所述,图片被生成并存储在文件c_image.png中:

save_path = "c_image.png"
image_data = requests.get(image_url).content
with open(save_path, "wb") as file:
    file.write(image_data) 

图片现在准备好与我们的最终个性化信息一起使用。我们将在流程结束时显示该图片:

第 6 步:创建自定义信息

准备好促销图片后,我们现在生成一个简洁而吸引人的客户信息。首先,我们确认第 5 步:创建图片中的creation_response是可用的:

if creation_response != "":
    umessage = """
    1) Read the following text carefully
    2) Then sum it up in a paragraphs without numbering the lines
    3) They output should be a text to send to a customer
    """ 

代理的输出提供了一个经过打磨的信息,适合客户沟通:

Dear Customer,
Experience a luxurious hotel stay with spacious rooms and a swift check-in process. Enjoy a comfortable bed and the convenience of 24-hour parking. Take advantage of special deals and nearby shopping that feels like home. While there may be minor noise and view issues, the overall experience remains positive and memorable.
Best regards, 

如果我们愿意,现在可以用 Python 的textwrap显示输出格式:

import os
from IPython.display import Image, display
import textwrap
# Set the desired width for each line
line_width = 70
# Wrap the text to the specified width
wrapped_message = textwrap.fill(process_response, width=line_width)
print(wrapped_message) 

显示的信息清晰、专业,适合直接与客户接触:

Dear Customer,  Experience a luxurious hotel stay with spacious rooms
and a swift check-in process. … 

为了增强这条信息,你可能需要调整提示语,以省略对 AI 或任何内部系统细节的提及,专注于以客户为导向的语言。

最后,系统将生成的图片与信息一起显示,以创建一个吸引人的个性化促销套餐:

# Define the image path
image_path = "/content/c_image.png"
# Check if the image file exists
if os.path.exists(image_path):
    # Display the image
    display(Image(filename=image_path))
else:
    print(f"Image file {image_path} not found.") 

最终的视觉效果强调了酒店的升级豪华产品,与客户根据他们的评论分析得出的期望完美匹配:

图 6.6:为顾客在酒店住宿的升级

图 6.6:为顾客在酒店住宿的升级

你现在可以尝试使用额外的评论进行实验,测试代理的深度和灵活性。我们已经成功开发了一个复杂的、受神经科学启发的 CoT 消费者记忆代理。在下一节中,我们将把这个完整的过程集成到reason.pyAI 库中,并进一步增强我们的 GenAISys 框架。

GenAISys 界面:从复杂到简单

在本章中,我们的旅程带我们深入到自我反思、推理和元认知智能代理的时代。在本节的最后,我们将从复杂的消费者记忆 CoT 内部工作转移到清晰直观的用户体验。我们将添加一个 CoT 小部件,允许任何用户在任意文本上触发内存分析或完整内容生成。然后我们将扩展 AI 代理,使其对那个小部件的选项做出反应。最后,我们将通过一个航班评论演示通用工作流程,以展示相同的记忆逻辑如何应用于新的领域。

在 GitHub 上打开2_Running_the_Reasoning_GenAISys.ipynb笔记本。然后运行设置环境部分,这部分与第五章中的笔记本相同。我们将首先向 IPython 界面添加一个 CoT 小部件。

添加 CoT 小部件

为了使记忆代理简单直观,我们引入了一个简单的下拉菜单(图 6.6)。用户可以轻松选择他们希望 GenAISys 代理执行的任务:

  • (默认):不激活任何推理任务

  • 分析:激活独立的内存分析功能

  • 生成:执行完整的消费者记忆代理工作流程(步骤 1–6),包括情感分析、内容生成和定制消息创建

这种简化的用户交互显著降低了最终用户的复杂性,将复杂的内部操作移至后台。

图 6.7:选择推理任务

图 6.7:选择推理任务

小部件的实现分为三个步骤——添加小部件、添加观察者以及将选项发送到 AI 代理:

  1. 添加小部件只需几行代码。我们在 IPython 界面中定义了下拉菜单(instruct_selector):

    # Ensure 'Instructions' exists in the memory_selector options
    instruct_selector = Dropdown(
        options=["None","Analysis", "Generation"],
        value="None",  # Ensure default active_memory is in the options
        description='Reasoning:',
        layout=Layout(width='50%')
    ) 
    

下拉菜单提供了清晰的选择,确保用户容易理解他们的选择:分析生成。接下来,我们将instruct_selector集成到现有的界面布局(VBox)中:

VBox:
Box(
                [user_selector, input_box, agent_checkbox,
                    tts_checkbox, files_checkbox,instruct_selector],
                layout=Layout(display='flex', flex_flow='column',
                    align_items='flex-start', width='100%') 

当用户提交他们的选择时,处理器会更新输出消息,让用户看到他们的选择已被考虑,使用标准的提交代码:

def handle_submit(sender):
    user_message = sender.value
    if user_message.strip():
        sender.value = ""  # Clear the input box
        # Check if instruct_selector is "Analysis" or "Generation"
        if instruct_selector.value in ["Analysis", "Generation"]:
            with reasoning_output:
                reasoning_output.clear_output(wait=True)
                print("Thinking...")  # Display "Thinking..." only when
            print("Reasoning activated")  # Restore default message… 

我们希望显示“正在思考…”,以向用户发出系统正在工作的信号。

  1. 第二步是插入一个观察者,它会检测用户所做的更改并更新显示。instruct_selector通过instruct_selector.observe被调用:

    # Ensure 'Instructions' exists in the memory_selector options
    instruct_selector = Dropdown(
        options=["None","Analysis", "Generation"],
        value="None",  # Ensure default active_memory is in the options
        description='Reasoning:',
        layout=Layout(width='50%')
    instruct_selector.observe(on_instruct_change, names='value') 
    
  2. 最后,我们将用户的选择无缝地传递到 AI 代理调用中。选定的推理模式(active_instruct)集成到代理的执行路径中:

    if agent_checkbox.value:
            pfiles = 1 if files_checkbox.value else 0
            active_instruct = instruct_selector.value  # Retrieve the selected instruction
            response = chat_with_gpt(user_histories[active_user],
                user_message, pfiles, active_instruct) 
    

通过明确集成这几行代码,AI 代理动态激活适当的推理模式,而无需额外的用户复杂性。我们现在可以增强 AI 代理。

增强 AI 代理

AI 代理现在将在名为active_instruct的新参数中接收到用户的部件选择,这将触发其决策:

def chat_with_gpt(messages, user_message,files_status,active_instruct): 

当用户选择分析时,AI 代理将触发之前构建的推理函数make_openai_reasoning_call以执行记忆分析:

if active_instruct=="Analysis" and continue_functions==True:
        from cot_messages_c6 import (
            system_message_s1, generation,imcontent4,imcontent4b)
        mrole= system_message_s1
        reasoning_steps=reason.make_openai_reasoning_call(
            user_message, mrole
        )
        aug_output=reasoning_steps
        continue_functions=False 

类似地,当选择生成时,代理使用自定义的memory_reasoning_thread函数运行完整的记忆代理工作流程:

if active_instruct=="Generation" and continue_functions==True:
        from cot_messages_c6 import (
            system_message_s1, generation,imcontent4,imcontent4b)
        reasoning_steps = reason.memory_reasoning_thread(
            user_message,system_message_s1,
            generation,imcontent4,imcontent4b
        )
        aug_output=reasoning_steps
        continue_functions=False 

通过这些简单的集成,GenAISys 界面现在透明地提供了强大的推理能力。

泛化 GenAISys 的能力

通过增强的界面,用户可以轻松地将记忆代理推理应用于酒店评论以外的各种内容。让我们用一个关于航班的普通用户评论来说明这种灵活性。用户只需选择分析,然后提交航班评论,无需额外指令:

`User01`: The flight from Tokyo to Honolulu was nice in general but the food was awful! 

GenAISys 立即返回详细的、逐段的记忆分析:

**Agent:** Segment 1: "The flight from Tokyo to Honolulu was nice in general"
- Memory Tags: [Reality Memory, Time Memory Past]
- Dimension: Emotional
- Sentiment Score: 0.7
- Explanation: This segment recounts a real past experience (a flight) and expresses a positive emotional evaluation ("nice"). The reference to a completed event classifies it under reality and past time memory… 

用户随后重新输入句子,但这次选择了生成选项和文件选项,以便显示使用文本生成的图像。用户只需选择选项,输入文本,然后提交即可。再次强调,体验无缝,用户无需额外指令,响应完整:完全分析、处理和最终客户信息,正如我们在上一节中设计的那样——从记忆分析开始,接着是情感评分,内容生成,最后是定制的客户信息和吸引人的图像(见图 6.8),如果界面中勾选了文件

Process: Performing memory and sentiment analysis.
Memory analysis result: Segment 1: "The flight from Tokyo to Honolulu was nice in general but the food was awful!"
- Memory Tags: [Reality Memory, Episodic Memory, Time Memory Past]
- Dimension: Emotional
- Sentiment Score: 0.4
- Explanation: This segment recounts a specific past travel event (a flight between two cities), embedding personal experience and subjective evaluation (positive about the flight overall and strongly negative about the food). The use of experiential details and judgment indicates that the experience is encoded as a real, episodic, past memory with an emotional emphasis, resulting in an overall slightly negative sentiment.
…
Dear Customer,
Experience a serene flight from Tokyo to Honolulu while enjoying a gourmet meal inspired by the renowned Chef Nobu Matsuhisa. Indulge in diverse and vibrant dishes crafted to enhance your journey.
Best regards, 

图 6.8:与个性化信息相匹配的吸引人的客户图像

图 6.8:与个性化信息相匹配的吸引人的客户图像

从用户的角度来看,我们的 GenAISys 运行得非常顺畅。我们给用户一种错觉,即生成式 AI 中的所有事情都很简单。当然,在实际项目中,我们可能需要投入资源尝试所有类型的文本,找到局限性,并解决问题,以覆盖边缘情况并完善输出。现在让我们总结本章的旅程,并将 GenAISys 提升到另一个层次。

摘要

本章将我们的 GenAISys 推进到超越经典 AI 的领域,进入了元认知、自我反思推理的领域。我们定义了一个实用记忆模型,将主要类别(短期、长期、现实、虚构和时间)与语义和情景标签相结合,然后在上面叠加了智力、情感和物理维度。使用这个框架,我们构建了一个六步推理代理,解码每个评论段,标记记忆类别,量化情感,并生成一个整体认知评分。基于认知配置文件和情感评分,代理生成了个性化的促销文本,并创建了一个匹配的 DALL-E 图像——然后将一切包装成精致的客户信息。

现在有一个新的下拉小部件,允许用户选择分析生成,使复杂的推理任务成为单次点击体验。幕后,AI 代理将请求路由到独立的记忆分析或完整的消费者记忆工作流程。我们最终在航班评论中展示了代理,展示了它能够分析、评分并对任何文本做出响应——将 GenAISys 从酒店业扩展到更广泛的客户服务场景。

随着这些进步,GenAISys 已准备好进行实时、生产级决策。下一章将重点介绍扩展我们的 GenAISys 架构的功能,以实现即时、高吞吐量的 AI 操作。

问题

  1. 情感记忆是电子商务的关键因素。(对或错)

  2. OpenAI 的 o3 是一个可以执行复杂任务的推理模型。(对或错)

  3. 长期记忆不包括情感因素。(对或错)

  4. 一个生成式 AI 模型不能分析复杂的记忆结构。(对或错)

  5. 生成式 AI 模型不仅可以分析情感,还可以提供介于 0 和 1 之间的数值评分。(对或错)

  6. Pinecone 指数可以根据系统查询生成复杂的指令。(对或错)

  7. 一个推理线程代理可以思考复杂的提示并执行多个协调任务。(对或错)

  8. 一个推理线程场景可以通过用户输入触发。(对或错)

  9. 一个推理代理可以处理来自 TripAdvisor 等网站的评论并生成定制信息。(对或错)

  10. 生成式 AI 系统不能处理推理线程代理。(对或错)

参考文献

进一步阅读

免费订阅电子书

新框架、演进的架构、研究更新、生产故障——AI Distilled 将噪音过滤成每周简报,供与 LLM 和 GenAI 系统实际操作的研究人员和工程师使用。现在订阅,即可获得免费电子书,以及每周的洞察力,帮助您保持专注并获取信息。

packt.link/TRO5B 订阅或扫描下面的二维码。

第七章:使用 DeepSeek 增强 GenAISys

DeepSeek-V3 技术报告于 2024 年 12 月发布,一个月后,DeepSeek-R1论文和一套完整的开源资源紧随其后。这一发布在 AI 社区中引起了轩然大波:Hugging Face 上的下载量激增,DeepSeek 应用在商店排行榜上名列前茅,新的 API 提供商一夜之间涌现。政府在辩论暂停令的同时,主要的生成式 AI 玩家——OpenAI、X(带有 Grok 3)和其他人——加快了步伐。在几周内,我们看到了 o3 版本改进了 OpenAI 模型,这是一个明确的信号,表明 AI 竞赛已经进入了一个新的阶段。与此同时,现实世界的 AI 生产团队目睹了这些令人眼花缭乱的创新堆积起来,破坏了现有的 AI 系统。那些花费数月时间调整其系统以适应一个生成式 AI 模型的团队发现自己陷入了系统工作但仍有改进空间的灰色地带。

那么,我们应该怎么做?我们应该以成本和风险为代价,将稳定的 GenAISys 升级以跟随加速的 AI 市场的最新趋势吗?或者,如果我们的系统稳定,我们应该忽略最新的模型吗?如果我们忽略进化,我们的系统可能会过时。如果我们继续跟随趋势,我们的系统可能会变得不稳定!

本章展示了如何找到一个可行的平衡点。我们不是为每个模型升级或新功能重写整个环境,而是引入了一个处理器选择机制,该机制将用户请求路由到正确的时间的正确工具。一个处理器注册表存储了我们开发的每个 AI 功能;选择层检查每个传入的消息并触发适当的处理器。这种设计使得 GenAISys 可以无限期地进化而不会破坏堆栈。我们将从定义如何在模型演化和实际使用之间找到一个平衡方法开始本章,通过产品设计和生产用例进行说明。接下来,我们将简要介绍 DeepSeek-V3、DeepSeek-R1 以及我们将要实施的精炼 Llama 模型。然后,我们将使用 Hugging Face 本地安装DeepSeek-R1-Distill-Llama-8B,将其封装在一个可重用的函数中,并将其插入到我们的 GenAISys 中。到那时,我们将开发灵活、可扩展的处理器选择机制环境,以便我们可以激活每个项目所需的模型和任务。到本章结束时,你将能够完全控制 GenAISys,并准备好应对 AI 市场带来的任何挑战。

本章涵盖了以下主题:

  • 人工智能加速与使用的平衡

  • DeepSeek-V3、R1 和蒸馏模型的概述

  • 本地安装 DeepSeek-R1-Distill-Llama-8B

  • 创建一个运行 DeepSeek-R1-Distill-Llama-8B 的函数

  • 在 GenAISys 中部署 DeepSeek-R1-Distill-Llama-8B

  • 为所有 AI 功能构建处理器注册表

  • 构建处理器选择机制以选择处理器

  • 升级 AI 功能以兼容处理器

  • 运行产品设计和生产示例

让我们从定义不懈的 AI 进化与日常业务使用之间的平衡开始。

平衡模型进化与项目需求

在急于采用每个新模型之前,我们必须根据项目需求来做出决策。到目前为止,我们的 GenAISys 主要服务于在线旅行社的营销功能。现在,想象一下,这家旅行社已经发展壮大,足以资助一系列品牌商品——定制旅行包、手册和其他好东西。为了管理这项新业务,公司雇佣了一位产品设计师和生产经理PDPM)。PDPM 研究客户反馈并设计个性化套装,但很快发现 AI 可以提升创造力和效率。

本章中的示例因此专注于产品设计和生产工作流程。我们的目标不是将 DeepSeek(或任何其他模型)强加到每个任务上,而是选择最适合需求的模型。为此,我们将通过一个处理程序选择机制扩展 GenAISys,该机制响应 IPython 界面中的用户选择和每条消息中的关键词。根据具体情况,操作团队可以配置系统将请求路由到 GPT-4o、DeepSeek 或任何未来的模型。

在将 DeepSeek 集成到我们的 GenAISys 之前,让我们回顾一下 DeepSeek 模型家族。

DeepSeek-V3, DeepSeek-V1, 和 R1-Distill-Llama:概述

DeepSeek 的旅程始于 DeepSeek-V3,发展到 DeepSeek-R1——一个以推理为重点的升级,然后分支到基于 Qwen 和 Llama 架构的蒸馏变体,如图图 7.1所示。V3 负责将模型推向市场,而 R1 则带来了强大的推理能力。

图 7.1:DeepSeek 开发周期

图 7.1:DeepSeek 开发周期

根据 DeepSeek-AI 等人(2024)的研究,V3 实现了显著的效率提升。其完整训练预算仅为 2.788 百万 H800 GPU 小时(≈每 GPU 小时 2 美元的 5.6 百万美元)——对于一个现代前沿模型来说,这个成本非常低。即使是按每个 token 计算,成本也很低,只需 180 K GPU 小时就能处理万亿个 tokens。因此,与通常报道的大规模模型相比,成本非常经济。

当我们查看 arXiv 上 DeepSeek-V3 技术报告(2024)的作者名单arxiv.org/abs/2412.19437时,我们首先注意到超过 150 位专家撰写了这篇论文!仅此一点,就证明了开源方法的有效性,这些方法涉及集体努力,通过向愿意贡献的每个人开放思想来产生效率驱动的架构。《附录 A》中的贡献和致谢名单是对开源发展的致敬。

图 7.2:DeepSeek-R1 源自 DeepSeek-V3

图 7.2:DeepSeek-R1 源自 DeepSeek-V3

DeepSeek-R1 直接从 DeepSeek-V3 发展而来。团队希望拥有 V3 的冲击力,但又要实现轻量级的推理,因此他们在推理时仅激活了专家的最小子集,如图 图 7.2 所示。此外,训练过程也保持了简洁。R1 直接进入强化学习,没有进行监督微调。推理能力很高,但面对经典 NLP 任务的限制。引入基于规则的奖励以避免神经网络训练周期。训练提示以整洁的 <think> … <answer> 标签结构化,避免将偏见带入模型的最终答案。此外,强化学习过程从包含 思维链CoT)示例的 冷启动 数据开始,这些示例专注于推理。这种方法减少了训练时间和成本。

DeepSeek 通过优化 MoE 策略和集成多令牌预测,演变为 R1,显著提高了准确性和效率。最终,DeepSeek-R1 被用于增强 DeepSeek-V3 的推理功能。DeepSeek-R1 还被蒸馏成更小的模型,如 Llama 和 Qwen。所使用的技术是知识蒸馏,其中较小的“学生”模型(在本章中为 Llama)从“教师”模型(在本章中为 DeepSeek-R1)学习。这种方法有效,因为它教会学生模型达到与教师模型相似的性能,同时更高效且适合部署在资源受限的设备上,正如您在本章中将会看到的。

让我们安装并运行 DeepSeek-R1-Distill-Llama-8B 并将其连接到我们的 GenAISys。

开始使用 DeepSeek-R1-Distill-Llama-8B

在本节中,我们将实现 DeepSeek-RAI-Distill-Llama-8B,这是 DeepSeek-R1 的精简版本,如图 图 7.3 所示。我们将安装 Hugging Face 的开源 Transformers 库,这是一个用于使用和微调预训练 Transformer 模型的开放框架。

图 7.3:安装 DeepSeek-RAI-Distill-Llama-8B,DeepSeek-R1 的精简版本

图 7.3:安装 DeepSeek-RAI-Distill-Llama-8B,DeepSeek-R1 的精简版本

我们将使用 Hugging Face 记录的 DeepSeek-RAI-Distill-Llama-8B:huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Llama-8B。Hugging Face 还为此模型提供了推荐:huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Llama-8B#usage-recommendations

我们将下载的版本是由 LLM 加速器 Unsloth 提供的 DeepSeek-R1 的开源蒸馏版本,在 Hugging Face 上:unsloth.ai/。因此,我们将不使用 DeepSeek API,而只使用本地安装的开源版本,该版本不与网络交互,利用 Hugging Face 的 SOC 2 Type 2 认证,符合隐私和安全约束:huggingface.co/docs/inference-endpoints/en/security

在本地机器上安装 deepseek-ai/DeepSeek-R1-Distill-Llama-8B,建议拥有大约 20 GB 的 RAM。稍微少一点也是可能的,但最好避免风险。也建议大约 20 GB 的磁盘空间。

在 Google Colab 上安装 DeepSeek-R1-Distill-Llama-8B,建议使用 Google Colab Pro 以获得 GPU 内存和动力。在本节中,Hugging Face 模型是在 Google Drive 上下载的,并通过 Google Colab 挂载。所需的磁盘空间将超过 Google Drive 的免费版本,可能需要 Google Drive 的最小订阅。在 Google Colab 上安装之前请检查费用。

在 GitHub 的 Chapter07 目录中打开 Getting_started_with_DeepSeek_R1_Distill_Llama_8B.ipynb (github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。我们将遵循 Hugging Face 框架的标准程序:

  • 运行一次笔记本以在本地安装 DeepSeek-R1-Distill-Llama-8B:

    install_deepseek=True 
    
  • 无需安装即可运行笔记本并与模型交互:

    install_deepseek=False 
    

模型就位后,我们可以在下一节中将它包装在处理器中,并将其插入我们的 GenAISys。

设置 DeepSeek Hugging Face 环境

我们将首先安装 DeepSeek-R1-Distill-Llama-8B(本地或 Colab),然后运行快速推理以确认一切正常工作。

我们将在第一个会话中首先安装 DeepSeek:

# Set install_deepseek to True to download and install R1-Distill-Llama-8B locally
# Set install_deepseek to False to run an R1 session
install_deepseek=True 

需要激活 GPU,让我们检查一下:

Checking GPU activation
!nvidia-smi 

如果我们在安装 Google Colab,我们可以挂载 Google Drive:

from google.colab import drive
drive.mount('/content/drive') 

我们现在设置 Google Drive 中的缓存目录并设置相应的环境变量:

import os
# Define the cache directory in your Google Drive
cache_dir = '/content/drive/MyDrive/genaisys/HuggingFaceCache'
# Set environment variables to direct Hugging Face to use this cache directory
os.environ['TRANSFORMERS_CACHE'] = cache_dir
#os.environ['HF_DATASETS_CACHE'] = os.path.join(cache_dir, 'datasets') 

我们现在可以安装 Hugging Face 的 Transformers 库:

!pip install transformers==4.48.3 

这样,我们就准备好下载模型了。

下载 DeepSeek

现在,让我们在 Hugging Face 框架内从 unsloth/DeepSeek-R1-Distill-Llama-8B 下载模型,包括分词器和模型:

from transformers import AutoTokenizer, AutoModelForCausalLM
import time
if install_deepseek==True:
    # Record the start time
    start_time = time.time()
    model_name = 'unsloth/DeepSeek-R1-Distill-Llama-8B'
    # Load the tokenizer and model
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForCausalLM.from_pretrained(
        model_name, device_map='auto', torch_dtype='auto'
    )
    # Record the end time
    end_time = time.time()
    # Calculate the elapsed time
    elapsed_time = end_time - start_time
    print(f"Time taken to load the model: {elapsed_time:.2f} seconds") 

下载时间将显示,并取决于您的互联网连接和 Hugging Face 的下载速度。安装完成后,请验证本地目录中是否已安装所有内容。在这种情况下,如下所示:

if install_deepseek==True:
    !ls -R /content/drive/MyDrive/genaisys/HuggingFaceCache 

输出应显示下载的文件:

/content/drive/MyDrive/genaisys/HuggingFaceCache:
models--unsloth--DeepSeek-R1-Distill-Llama-8B  version.txt
/content/drive/MyDrive/genaisys/HuggingFaceCache/models--unsloth--DeepSeek-R1-Distill-Llama-8B:
blobs  refs  snapshots
/content/drive/MyDrive/genaisys/HuggingFaceCache/models--unsloth--DeepSeek-R1-Distill-Llama-8B/blobs:
03910325923893259d090bfa92baa4088cd46573… 

现在,让我们运行一个 DeepSeek 会话。

运行 DeepSeek-R1-Distill-Llama-8B 会话

为了确保模型正确安装,并避免在启动新会话时覆盖安装,请回到笔记本的顶部并设置以下内容:

install_deepseek=False 

现在,我们将本地加载 DeepSeek-R1-Distill-Llama-8B 分词器和模型:

import time
from transformers import AutoTokenizer, AutoModelForCausalLM
if install_deepseek==False:
    # Define the path to the model directory
    model_path = '/content/drive/MyDrive/genaisys/HuggingFaceCache/models--unsloth--DeepSeek-R1-Distill-Llama-8B/snapshots/71f34f954141d22ccdad72a2e3927dddf702c9de'
    # Record the start time
    start_time = time.time()
    # Load the tokenizer and model from the specified path
    tokenizer = AutoTokenizer.from_pretrained(
        model_path, local_files_only=True
    )
    model = AutoModelForCausalLM.from_pretrained(
        model_path, device_map='auto', torch_dtype='auto', 
        local_files_only=True
    )
    # Record the end time
    end_time = time.time()
    # Calculate the elapsed time
    elapsed_time = end_time - start_time
    print(f"Time taken to load the model: {elapsed_time:.2f} seconds") 

加载模型所需的时间将显示,并取决于你的机器配置:

Time taken to load the model: 14.71 seconds 

我们可以查看 Llama 模型的配置:

if install_deepseek==False:
    print(model.config) 

输出显示了有趣的信息。LlamaConfig 的读取确认我们正在运行一个紧凑、范围明确的模型:

LlamaConfig {
  "_attn_implementation_autoset": true,
  "_name_or_path": "/content/drive/MyDrive/genaisys/HuggingFaceCache/models--unsloth--DeepSeek-R1-Distill-Llama-8B/snapshots/71f34f954141d22ccdad72a2e3927dddf702c9de",
  "architectures": [
    "LlamaForCausalLM"
  ],
 … 

精炼的 Llama 模型有 32 个 transformer 层和每层 32 个注意力头,总共 1,024 个注意力头。此外,它包含 80 亿个参数。相比之下,其教师模型 DeepSeek-R1 是一个 MoE 巨型,有 61 层 和庞大的 6710 亿参数,其中大约 370 亿 在每次前向传递时是活跃的。现在让我们用一个针对生产问题的提示来运行一个示例:

if install_deepseek==False:
    prompt="""
    Explain how a product designer could transform customer requirements for a traveling bag into a production plan.
    """ 

我们首先插入时间测量,并使用 GPU 对输入进行分词:

import time
if install_deepseek==False:
    # Record the start time
    start_time = time.time()
    # Tokenize the input
    inputs = tokenizer(prompt, return_tensors='pt').to('cuda') 

然后,我们运行生成:

 # Generate output with enhanced anti-repetition settings
    outputs = model.generate(
      **inputs,
        max_new_tokens=1200,
        repetition_penalty=1.5,     # Increase penalty to 1.5 or higher
        no_repeat_ngram_size=3,     # Prevent repeating n-grams of size 3
        temperature=0.6,            # Reduce randomness slightly
        top_p=0.9,                  # Nucleus sampling for diversity
        top_k=50       # Limits token selection to top-k probable tokens
  ) 

我们参数的目标是限制重复并保持专注:

  • max_new_tokens=1200: 限制输出标记的数量

  • repetition_penalty=1.5: 限制重复(可以更高)

  • no_repeat_ngram_size=3: 防止重复特定大小的 n-gram

  • temperature=0.6: 减少随机性并保持专注

  • top_p=0.9: 允许核采样以增加多样性

  • top_k=50: 将标记选择限制为 top_k 以进行下一个标记选择

这组标记倾向于限制重复,同时允许多样性。现在我们可以使用分词器解码生成的文本:

 # Decode and display the output
    generated_text = tokenizer.decode(
        outputs[0], skip_special_tokens=True
    )
    # Record the end time
    end_time = time.time()
    # Calculate the elapsed time
    elapsed_time = end_time - start_time
    print(f"Time taken to load the model: {elapsed_time:.2f} seconds") 

输出显示了模型思考和响应所花费的总时间:

Time taken to load the model: 20.61 seconds 

让我们将 generated_text 包装并显示:

import textwrap
if install_deepseek==False:
    wrapped_text = textwrap.fill(generated_text, width=80)   
print(wrapped_text) 

输出提供了所需的想法。它显示了 DeepSeek-R1 的思考能力:

…Once goals & priorities become clearer, developing
prototypes becomes more focused since each iteration would aim at testing one main feature rather than multiple changes simultaneously—which makes refining individual elements easier before moving towards finalizing designs, When prototyping starts: 1) Start with basic functional mockups using simple tools –… 

集成 DeepSeek-R1-Distill-Llama-8B

在本节中,我们将通过几个步骤将 DeepSeek-R1-Distill-Llama-8B 添加到我们的 GenAISys 中。打开 GenAISys_DeepSeek.ipynb。你可以决定在第一个单元中运行笔记本,这将需要 GPU:

# DeepSeek activation deepseek=True to activate. 20 Go (estimate) GPU memory and 30-40 Go Disk Space
deepseek=True 

你也可以选择不在本笔记本中运行 DeepSeek,在这种情况下,你不需要 GPU,可以将运行时更改为 CPU。如果你选择此选项,OpenAI 的 API 将接管,确认不需要 GPU:

deepseek=False 

现在,转到笔记本的 设置 DeepSeek Hugging Face 环境 子节。我们将简单地从 Getting_started_with_DeepSeek_R1_Distill_Llama_8B.ipynb 将以下单元格转移到这个子节。以下代码仅在 deepseek=True 时激活:

  • GPU 激活检查:!nvidia-smi

  • 设置模型的本地缓存:…os.environ['TRANSFORMERS_CACHE'] =cache_dir…

  • 安装 Hugging Face 库:!pip install transformers==4.48.3

  • 加载分词器和模型:

     from transformers import AutoTokenizer, AutoModelForCausalLM
      # Define the path to the model directory
      model_path = … 
    

安装现在已完成。如果DeepSeek==True,则 DeepSeek 模型的调用将在AI 函数部分进行,参数在运行 DeepSeek-R1-Distill-Llama-8B 会话部分中描述:

 if models == "DeepSeek":
      # Tokenize the input
      inputs = tokenizer(sc_input, return_tensors='pt').to('cuda')
….
      task_response =tokenizer.decode(outputs[0],skip_special_tokens=True) 

在 DeepSeek 运行的情况下,我们已准备好构建处理器选择机制,该机制将把每个用户请求路由到 GPT-4o、DeepSeek 或任何未来的模型——而不触及堆栈的其余部分。

将处理器选择机制作为 GenAISys 的编排器实现

在在线旅行社中,PDPM 正面临日益增长的需求,要求旅行社设计和生产大量商品套装,包括旅行包、手册和笔。PDPM 希望直接参与 GenAISys 的开发,以探索它如何显著提高生产力。

由于系统中 AI 任务的复杂性和多样性不断增加,GenAISys 开发团队已决定使用处理器来组织这些任务,如图7.4所示:

图 7.4:GenAISys 数据流和组件交互

图 7.4:GenAISys 数据流和组件交互

因此,我们将定义、实现该处理器选择机制,然后邀请 PDPM 运行增强版的 GenAISys,以评估旨在提高商品设计和生产效率的函数。

图 7.4描述了我们将要实施的处理器管道的行为:

  1. IPython 界面作为用户交互的入口和出口点,捕获用户输入,对其进行格式化,并显示处理器机制返回的响应。

  2. 处理器机制解释用户输入,在 IPython 界面、处理器注册表和 AI 函数之间引导数据。它确保由用户消息触发的任务能够顺利执行。

  3. 处理器注册表维护所有可用处理器及其对应函数的列表。它通过明确处理器注册和检索来支持系统模块化和可扩展性。

  4. AI 函数执行核心任务,如自然语言理解和数据分析,执行从处理器机制接收的指令,并将输出返回到 IPython 界面。

在此设置中,用户通过 IPython 界面提供输入。此输入被路由到处理器选择机制,该机制随后评估注册的可用处理器以及特定条件。注册表中的每个条目都是一个(条件,处理器)对,负责不同的操作,如推理、图像生成或数据分析。一旦找到匹配的条件,相应的 AI 函数就会被激活。处理完毕后,它将结果返回到界面。这个结构化的管道——从用户输入到 AI 生成的响应——被优雅地处理,每个处理器都明确定义以提高可读性和效率。

在编码之前,让我们明确定义在 GenAISys 中我们所说的“处理器”是什么。

什么是处理器?

处理器本质上是一个专门的功能,用于处理特定的任务或请求类型。每个处理器都与一个条件注册在一起,通常是一个小的函数或 lambda 表达式。当评估为True时,这个条件表明应该调用相关的处理器。这种设计巧妙地将决定“哪个”处理器应该运行的逻辑与处理器执行其任务的逻辑分离。

在我们的上下文中,处理器是协调器的构建块——设计用于处理特定输入类型的条件函数。当用户提供输入时,处理器选择机制将其与处理器注册表进行比较,该注册表由条件和处理器成对组成。一旦找到匹配项,相应的处理器就会被触发,调用专门的函数,如handle_generationhandle_analysishandle_pinecone_rag。这些处理器执行复杂的推理、数据检索或内容生成任务,提供精确和有针对性的输出。

但为什么处理器(handler)比传统的if…then条件列表更适合我们的 GenAISys 呢?

为什么处理器比传统的 if...then 列表更好?

使用处理器可以提高可维护性和可读性。而不是在代码中分散多个if...then检查,每个处理器都是自包含的:它有自己的条件和执行所需操作的单独函数。这种结构使得在不冒险在长条件链中产生意外交互的情况下添加、删除或修改处理器变得更容易。此外,由于它将“我们需要哪个处理器?”的逻辑与“该处理器实际上是如何工作的?”的逻辑分开,我们得到了一个更模块化的设计,这使得扩展变得无缝。

我们将首先介绍我们对 IPython 界面的修改。

1. IPython 界面

我们首先回顾一下我们对 IPython 界面的主要更新,它仍然是主要的交互点,如图 7.5所示。从用户的角度来看,引入处理器并没有显著改变界面,但需要对一些底层代码进行调整。

图 7.5:IPython 界面处理用户输入并显示输出

图 7.5:IPython 界面处理用户输入并显示输出

IPython 界面像以前一样调用chat_with_gpt

response = chat_with_gpt(
    user_histories[active_user], user_message, pfiles, 
    active_instruct, models=selected_model
) 

现在,然而,我们可以明确选择 OpenAI 或 DeepSeek 模型,如下所示:

models=selected_model 

要将模型添加到chat_with_gpt调用中,我们首先在界面中添加一个下拉模型选择器:

# Dropdown for model selection
model_selector = Dropdown(
    options=["OpenAI", "DeepSeek"],
    value="OpenAI",
    description="Model:",
    layout=Layout(width="50%")
) 

模型选择器被添加到界面中的VBox实例中:

# Display interactive widgets
display(
    VBox(
        [user_selector, input_box, submit_button, agent_checkbox, 
            tts_checkbox, files_checkbox, instruct_selector, 
            model_selector],
        layout=Layout(display='flex', flex_flow='column', 
            align_items='flex-start', width='100%')
    )
) 

用户现在可以直接从界面中选择他们偏好的模型,如图所示:

图 7.6:选择模型

图 7.6:选择模型

黑色背景上的放大镜  AI 生成的内容可能不正确。快速提示:需要查看此图像的高分辨率版本?在下一代 Packt Reader 中打开此书或在其 PDF/ePub 副本中查看。

新一代 Packt Reader随本书免费赠送。扫描二维码或访问packtpub.com/unlock,然后使用搜索栏通过名称查找本书。请仔细核对显示的版本,以确保您获得正确的版本。

白色背景上的二维码  AI 生成的内容可能不正确。

已添加一个额外的功能来管理文件显示。

文件管理

设计文件管理的方式有很多。在这里,我们将介绍一个可以在项目实施阶段根据需要扩展的功能。我们的文件管理代码有三个函数:

  • 管理用户触发的文件删除

  • 当复选框取消选中时删除c_image.png

  • 使用存在性检查来防止删除时的错误

我们将在 Jupyter Notebook 环境中直接通过观察界面复选框小部件的变化来构建处理用户交互的代码。当用户取消选中名为files_checkbox的复选框时,该代码将删除特定的图像文件(c_image.png)。这确保了当文件不再需要时,文件会被干净地移除,防止杂乱并节省存储空间。

我们首先定义函数:

def on_files_checkbox_change(change): 

事件处理函数定义了一个名为on_files_checkbox_change的回调函数,当files_checkbox的状态发生变化时将执行。change由观察者提供,其中包含有关更改事件的信息,包括以下内容:

  • old: 复选框的先前状态

  • new: 复选框的新状态

 # Only remove images if the checkbox changed from True to False.
    if change['old'] == True and change['new'] == False: 

代码验证复选框之前是否被选中(True)并且现在已被取消选中(False)。这保证了文件删除仅在用户明确取消选中复选框时发生,防止意外删除文件。我们现在删除文件:

 if os.path.exists("c_image.png"):
            os.remove("c_image.png") 

我们还需要添加一个观察者,以便在文件状态发生变化时通知on_files_checkbox_change函数:

# Attach the observer to files_checkbox
files_checkbox.observe(on_files_checkbox_change, names='value') 

files_checkbox.observe()函数将on_files_checkbox_change函数链接到files_checkbox小部件。names='value'指定当复选框的值发生变化时(即,当它被选中或取消选中时)应触发该函数。

我们现在将进入管道的下一部分,并实现处理程序选择机制。

2. 处理程序选择机制

处理器选择机制根据预定义的条件动态选择并执行适当的处理程序。它遍历可用的处理程序,评估条件直到找到匹配项,确保对用户输入进行高效和结构化的处理。处理器选择机制在我们在前几章中构建的chat_with_gpt函数中。然而,现在它包含了一个协调任务,如图 7.7所示:

  • chat_with_gpt在 GenAISys 中仍然是一个关键功能,并且现在包含处理器机制

  • 它按顺序检查条件以决定调用哪个处理器

  • 如果没有条件匹配,它将回退到基于内存的处理程序

  • 它确保了通过错误处理来保证用户体验的连续性

图 7.7:处理器机制的协调角色

图 7.7:处理器机制的协调角色

在更广泛的 GenAISys 工作流程中,处理器机制充当协调者。它处理用户输入并识别要激活的 AI 功能。当 IPython 界面捕获用户消息时,处理器机制评估这些输入以确定从处理器注册表中适当的处理器。如果没有特定的处理器匹配,它默认使用基于内存的响应,然后将其返回到 IPython 界面。

chat_with_gpt函数封装了这个逻辑。它遍历一个预定义的处理程序列表,每个处理程序都与相应的条件函数配对。当条件评估为真时,将执行相关的处理程序。如果没有匹配项,回退的基于内存的处理程序确保了无缝的响应:

def chat_with_gpt(
    messages, user_message, files_status, active_instruct, models
):
     global memory_enabled  # Ensure memory is used if set globally 

让我们来看看函数的参数:

  • messages: 用户和 AI 之间的对话历史

  • user_message: 用户最新的消息

  • files_status: 跟踪涉及对话的任何文件的状态

  • active_instruct: 可能影响响应生成的任何指令或模式

  • models: 指定正在使用的活动 AI 模型

该函数使用global memory_enabled来访问一个全局变量,该变量确定是否应该应用内存来存储/记住用户的完整对话。在本章中,global memory_enabled=True

函数尝试根据提供的条件执行适当的处理程序:

 try:
        # Iterate over handlers and execute the first matching one
        for condition, handler in handlers:
            if condition(messages, active_instruct, memory_enabled, 
                models, user_message):
                return handler(messages, active_instruct, memory_enabled, 
                    models, user_message, files_status=files_status) 

如您所见,for condition, handler in handlers遍历一个名为handlers的列表,其中每个项目都是一个包含以下内容的元组:

  • 一个条件函数,用于检查是否应该使用处理程序

  • 一个处理器函数,无论条件是否满足都要执行

  • 一个通用的if条件(...), 用于使用提供的参数评估条件函数

  • 如果条件满足,代码将返回相应处理程序的输出,并立即退出函数

现在我们添加一个回退,如果没有任何处理器匹配输入条件:

 # If no handler matched, default to memory handling with full conversation history
        return handle_with_memory(
            messages,  # Now passing full message history
            user_message,
            files_status=files_status,
            instruct=active_instruct,
            mem=memory_enabled,  # Ensuring memory usage
            models=models
        ) 

handle_with_memory作为默认处理器被调用,执行以下操作:

  • 使用完整的对话历史(messages

  • 如果 memory_enabled 为 true,则考虑内存,在本章中就是这种情况

  • 如果执行,则直接返回响应

最后,让我们添加一个异常来捕获返回错误:

 except Exception as e:
        return f"An error occurred in the handler selection mechanism: {str(e)}" 

在定义了处理器选择机制之后,我们现在可以继续构建存储这些处理器的处理器注册表。

3. 处理器注册表

处理器注册表是一个结构化的条件-处理器对集合,其中每个条件都是一个 lambda 函数,它评估用户消息和指令以确定是否满足特定标准。当条件满足时,相应的处理器立即被触发并执行,如图所示:

图 7.8:创建处理器注册表

图 7.8:创建处理器注册表

所有 lambda 函数都有四个参数(msginstructmemmodels)。这确保了当 chat_with_gpt() 调用一个处理器时,参数的数量匹配。

处理器注册表有三个主要功能:

  • 由处理器机制编排,可以无限扩展

  • 根据关键词、指令或模型选择路由输入

  • 如果没有条件匹配,则保证有回退响应

我们将按照以下四个关键属性的结构设计我们的处理器注册表:

  • 处理器注册:创建一个处理器列表,每个处理器都有一个条件函数和一个相应的处理器函数

  • 特定处理器条件:依次检查输入是否满足任何特定条件

  • 回退处理器:如果没有条件匹配,则添加一个默认的基于内存的处理器

  • 执行:当条件满足时,相应的处理器立即执行

代码中 **kwargs 的作用提供了一个灵活的方式与 AI 函数交互。**kwargs关键字参数 的缩写,用于 Python 函数中,允许向函数传递可变数量的参数。在我们的处理器注册表代码中,**kwargs 通过允许处理器接受额外的、可选的参数,而不需要在函数中显式定义它们,发挥着至关重要的作用。这使得处理器易于扩展,以便于未来的更新或添加新参数,而无需修改现有的函数签名。

我们现在将开始构建带有 Pinecone/RAG 处理器的处理器注册表。

Pinecone/RAG 处理器

Pinecone/RAG 处理器管理之前定义的 检索增强生成RAG)功能。它在检测到用户消息中包含 PineconeRAG 关键词时激活:

 # Pinecone / RAG handler: check only the current user message
    (
        lambda msg, instruct, mem, models, user_message,
        **kwargs: “Pinecone” in user_message or “RAG” in user_message,
        lambda msg, instruct, mem, models, user_message,
        **kwargs: handle_pinecone_rag(user_message, models=models)
    ), 

此处理器检查用户消息是否包含“Pinecone”或“RAG”,如果是,则 lambda: 返回 True;否则,返回 False。我们现在将创建推理处理器。

推理处理器

我们已经构建了推理函数,但现在我们需要一个处理程序。触发处理程序的关键字是 Use reasoningcustomeractivities。消息中的任何附加文本都为推理过程提供上下文。处理程序使用 all() 确保所有关键字都包含在消息中:

 # Reasoning handler: check only the current user message
    (
        lambda msg, instruct, mem, models, user_message, **kwargs: all(
            keyword in user_message for keyword in [
                “Use reasoning”, “customer”, “activities”
            ]
        ),
        lambda msg, instruct, mem, models, user_message, **kwargs:
            handle_reasoning_customer(user_message, models=models)
    ), 

让我们继续创建分析处理程序。

分析处理程序

分析处理程序到目前为止已被用于内存分析,并由 Analysis 指令触发:

 # Analysis handler: determined by the instruct flag
    (
        lambda msg, instruct, mem, models, user_message,
            **kwargs: instruct == “Analysis”,
        lambda msg, instruct, mem, models, user_message,
            **kwargs: handle_analysis(
                user_message, models=models)
    ), 

是时候创建生成处理程序了。

生成处理程序

生成处理程序通过要求生成式 AI 模型根据文本的内存分析为顾客生成吸引人的文本,将内存分析提升到了另一个层次。Generation 指令触发生成处理程序:

 # Generation handler: determined by the instruct flag
    (
        lambda msg, instruct, mem, models, user_message,
               **kwargs: instruct == “Generation”,
        lambda msg, instruct, mem, models, user_message,
                **kwargs: handle_generation(
                    user_message, models=models)
    ), 

现在我们来构建图像创建处理程序。

图像处理程序

图像创建处理程序由用户消息中的 Createimage 关键字触发:

 # Create image handler: check only the current user message
    (
        lambda msg, instruct, mem, models, user_message,
        **kwargs: “Create” in user_message and “image” in user_message,
        lambda msg, instruct, mem, models, user_message,
            **kwargs: handle_image_creation(user_message, models=models)
    )
] 

我们现在将创建用于没有关键字或指令的情况的自由处理程序。

回退内存处理程序

当没有指令或关键字触发特定功能时,此处理程序是一个通用处理程序。让我们相应地附加回退内存处理程序:

# Append the fallback memory handler for when instruct is “None”
handlers.append(
    (
        lambda msg, instruct, mem, models, user_message,
               **kwargs: instruct == “None”,
        lambda msg, instruct, mem, models, user_message,
               **kwargs: handle_with_memory(
            msg,
            user_message,
            files_status=kwargs.get(‘files_status’),
            instruct=instruct,
            mem=memory_enabled,  # Replace user_memory with memory_enabled
            models=models
        )
    )
) 

注意,我们已经将 user_memory 替换为 memory_enabled 以实现内存管理的通用化。

您可以将任意数量的处理程序和 AI 函数添加到处理程序注册表中。您可以根据需要扩展 GenAISys。您还可以通过替换显式指令来修改关键字,就像我们对 Analysisgeneration 函数所做的那样。然后,处理程序将调用您需要的所有 AI 函数。

让我们现在来了解 AI 函数的新组织结构。

4. AI 函数

我们现在将运行由处理程序注册表激活的 AI 函数。这些函数基于早期章节中的函数,但现在由本章中引入的处理程序选择机制管理。此外,本节中使用的示例基于与产品设计和生产场景相关的典型提示。请记住,由于生成式 AI 模型的随机(概率)性质,每次运行这些任务时输出都可能有所不同。

图 7.9:处理程序选择机制和注册表调用的 AI 函数

图 7.9:处理程序选择机制和注册表调用的 AI 函数

我们现在将执行 GenAISys 中目前所有可用的 AI 函数,并在适用的情况下调用 DeepSeek 模型。让我们从 RAG 函数开始。

诸如语音合成、文件管理、对话历史和摘要生成等功能与上一章保持不变。

RAG

此 RAG 函数可以在用户消息中使用 Pinecone 关键字与 OpenAI 或 DeepSeek 运行。RAG 函数的名称已更改,但其查询过程保持不变:

# Define Handler Functions
def handle_pinecone_rag(user_message, **kwargs):
    if "Pinecone" in user_message:
      namespace = "genaisys"
    if "RAG" in user_message:
      namespace = "data01"
    print(namespace)
    query_text = user_message
    query_results = get_query_results(query_text, namespace)
    print("Processed query results:")
    qtext, target_id = display_results(query_results)
    print(qtext)
    # Run task
    sc_input = qtext + " " + user_message 

然而,该函数现在包含了一个 DeepSeek 蒸馏 R1 调用。如果没有提供模型或 DeepSeek 被禁用时,该函数默认使用 OpenAI:

 models = kwargs.get("models", "OpenAI")  # Default to OpenAI if not provided
    if models == "DeepSeek" and deepseek==False:
       models="OpenAI"
    if models == "OpenAI":
      task_response = reason.make_openai_api_call(
      sc_input, "system","You are an assistant who executes the tasks you are asked to do.", "user") 

如果激活了 DeepSeek,它将在 IPython 界面中为此任务选择时被调用:

 if models == "DeepSeek":
      …
    return f"{namespace}:{models}: {task_response}" 

我们将首先进行情感分析。

情感分析(genaisys)

PDPM 的以下示例用户输入:

Let's see what Pinecone thinks about this sentence: The customer did not like the design of the traveling bag we gave out because it was not the right color requested. 

选择 OpenAI(默认)和勾选Agent的输出将如下所示:

Agent: genaisys:OpenAI: Sentiment analysis score: 0.3
Explanation: The sentiment of the text is predominantly negative. The customer expresses dissatisfaction with the traveling bag due to it not being the right color as requested. The use of phrases like "did not like" and "not the right color" indicates a negative sentiment, as the customer's expectations were not met. The score of 0.3 reflects this negative sentiment, though it is not extremely low because the issue is specific to the color and not the overall quality or functionality of the bag. 

另一方面,选择 DeepSeek(默认)和勾选Agent的输出将如下所示:

**Agent:** genaisys:DeepSeek:
…The numerical value should be between 0 and 1, so let's say 0.2….
Wait, but the user didn't specify a particular method or model for sentiment analysis. Maybe they want a simple rule-based approach? Let's consider the presence of negative words like "did not like" and "not the right color requested." These words indicate dissatisfaction. However, the sentiment isn't extremely negative since it's just one aspect (color) that's the issue, not the entire product or experience. So, a score of 0.2 seems appropriate because it reflects a moderate negative sentiment based on the specific criticism given. 

在两种情况下,情感分数和解释分数都是可以接受的。想象一下接收数千条这样的客户反馈消息——GenAISys 会过滤掉低分,并自动提供这些输出,并将它们存储在客户数据库中。

现在,PDPM 检查语义分析。

语义分析(genaisys)

考虑 PDPM 的另一个示例输入:

Let's see what meaning analysis Pinecone on this comment: The customer did not accept the traveling bag we gave out for free because the size and colors did not match the order processed. 

此 RAG 函数可以与 OpenAI 或 DeepSeek 一起运行,只要用户消息中包含“Pinecone”关键字。

OpenAI 的输出是可以接受的,并且清楚地概述了消息中的语义关系:

**Agent:** genaisys:OpenAI: Semantic analysis involves understanding the meaning and interpretation of words, phrases, and sentences in context. It is a crucial aspect of natural language processing (NLP) that helps in extracting meaningful information from text. In the context of your comment, semantic analysis would involve breaking down the sentence to understand the underlying meaning and the relationships between different components of the sentence.
Here's a breakdown of the semantic elements in the comment:
1\. **Subject**: "The customer" - This refers to the individual who is the focus of the action.
2\. **Action**: "did not accept" - This indicates the customer's refusal or rejection of something.
3\. **Object**: "the traveling bag we gave out for free" - This is the item that was offered to the customer without charge.
4\. **Reason**: "because the size and colors did not match the order processed" - This provides the explanation for the customer's refusal, indicating a mismatch between what was expected (the order) and what was received (the traveling bag).
… 

DeepSeek 的输出同样相关:

**Agent:** genaisys:DeepSeek: 300,Semantic analysis…This is not an analysis but a semantic search. Provide more information on the topic. …
The original problem was that the customer didn't accept the travel bag due to mismatched size and color from the ordered one. So, my goal here should be to understand why this happened and perhaps suggest solutions.
I think the first step would be to look into whether there was a miscommunication in the ordering process. Maybe the website had incorrect images or descriptions leading to wrong expectations. Or perhaps during manufacturing, sizes got altered without notice. Another angle could be customer feedback—have others reported similar issues? It might also help to check if there were any system errors in processing orders which caused discrepancies between what was ordered and what was delivered.
…
# Final Answer
After conducting thorough research and identifying potential contributing factors, effective solutions have been implemented to address the discrepancy issues, resulting in improved satisfaction among customers receiving accurate products aligned with their expectations. 

DeepSeek 的回答更长且更复杂。然而,团队会偏好哪种?像 OpenAI 那样简短的回答,还是带有更多解释的长回答?这个决定可以通过研讨会和会议达成。

数据检索(data01)

OpenAI 和 DeepSeek 都可以用于数据检索。产品设计师的用户输入可能如下所示:

I'm a product designer and am trying to analyze human memory types. Use RAG to tell us what the CTO said about different memory types 

输出令人满意:

**Agent:** data01:OpenAI: To analyze the CTO's statement about different memory types using Retrieval-Augmented Generation (RAG), we can break down the information into the relevant memory types and their application in the hybrid travel marketing campaign:
1\. **Memoryless**: This refers to systems or processes that do not retain any information from past interactions. In the context of your campaign, this might relate to interactions that do not require historical data, such as one-time queries or transactions… 

因此,在我们的 GenAISys 中,我们有一个灵活的 RAG 系统,可以使用我们想要的模型运行。然而,我们仍然必须评估我们想要执行的每一组任务的模型。

思维链

CoT 函数在勾选Files并默认使用OpenAI作为模型提供者时运行。其实现保持一致,因为它是在上一章中构建和运行的。主要区别在于它现在集成到处理程序选择机制中,该机制基于输入中的特定关键字激活:

def handle_reasoning_customer(user_message, **kwargs):
    initial_query = user_message
    download("Chapter05", "customer_activities.csv")
    reasoning_steps = reason.chain_of_thought_reasoning(initial_query)
    return reasoning_steps 

考虑 PDPM 的另一个示例用户输入:

Use reasoning to analyze customer activities so I can design custom travel merchandise kits. 

输出看起来是可以接受的:

**Agent:** data01:OpenAI: To analyze the CTO's statement about different memory types using Retrieval-Augmented Generation (RAG), we can break down the memory types mentioned and their relevance to the hybrid travel marketing campaign:
1\. **Memoryless**: This refers to systems or processes that do not retain any information from past interactions. In the context of a marketing campaign, this would mean treating each customer interaction as a standalone event without any historical context…. 

现在让我们看看内存分析如何使用这两种模型源(OpenAI 和 DeepSeek)运行。

分析(记忆)

OpenAI 和 DeepSeek 模型都使用神经科学风格的分类处理基于记忆的客户档案。该函数已适应处理程序选择过程,并包含一个 DeepSeek 调用:

def handle_analysis(user_message, **kwargs):
    from cot_messages_c6 import system_message_s1
    models = kwargs.get("models", "OpenAI")  # Default to OpenAI if not provided
    if models == "DeepSeek" and deepseek==False:
      models="OpenAI"
    if models == "OpenAI":
      reasoning_steps = reason.make_openai_reasoning_call(
        user_message, system_message_s1)
    if models == "DeepSeek":
   …
    return reasoning_steps 

使用Reasoning列表中的Analysis选项的示例用户输入可以是:

The hotel was great because the view reminded me of when I came here to Denver with my parents. I sure would have like to have received a custom T-shirt as a souvenir. Anyway, it was warm and sunny so we had an amazing time. 

OpenAI 的输出包含一个有用的段落,突出了与客户对个性化纪念品愿望相关的情感维度,这可能有助于产品设计师在商品套装生产方面的努力:

…
Segment 2: "I sure would have like to have received a custom T-shirt as a souvenir."
- Memory Tags: [Episodic Memory]
- Dimension: Emotional
- Sentiment Score: 0.4
- Explanation: Here the speaker expresses a personal wish or regret about a missing souvenir from the event. Although it doesn't recount an actual episode in detail, it still connects to the personal event and reflects a feeling of slight disappointment, thereby engaging episodic memory and an emotional dimension with a modestly negative sentiment. 

然而,DeepSeek 的输出却偏离了轨道。它首先找到正确的任务去做:

Okay let's see this through step by step now...
Alright, I need to tackle analyzing segments from the given user response according to their detailed tagging system based on cognitive psychology principles regarding STM vs LTM, semantic versus episodic memory, reality vs fiction, among others plus dimensions such as Intellectual, Emotional, Physical, along with assigning sentiments scores ranging from 0-1 reflecting positivity.
Let me start reading carefully paragraph-wise.
First sentence:"The hotel wasgreatbecauseviewremindedmeofwhencyamehere todallas." 

但随后它似乎迷失了方向,在格式和连贯性上遇到了困难,引入了不规则的间距甚至外文字符:

…Butwait,theuser later talks about souvenirs wantingcustomTshirtswhichmaybe indicatespositiveintent。…
但此处更多的是体验性的(Eating 和 Enjoying)=所以可能既有知识元素也有身体维度的食物味道。但主要在这里是描述经历,因此属于 Episode 或语义吗?… 

DeepSeek 当然可以做得更好,但改善这个结果需要额外的提示改进迭代,或者选择更健壮的 DeepSeek 变体或 API。在提示改进上投入时间存在一些风险,因为即使如此,结果可能也不会达到你的期望。是否改进提示、切换到 DeepSeek API、探索另一个 DeepSeek 变体,还是默认使用 OpenAI,最终应在团队内部协作决定,并基于你的项目需求。

现在让我们继续运行生成函数。

生成

生成函数(在推理列表中选择生成),默认激活,OpenAIAgent文件被勾选,支持创建引人入胜、基于记忆的客户消息:

def handle_generation(user_message, **kwargs):
    from cot_messages_c6 import (
    system_message_s1, generation, imcontent4, imcontent4b
)
    reasoning_steps = reason.memory_reasoning_thread(
        user_message, system_message_s1, generation, 
        imcontent4, imcontent4b
    )
    return reasoning_steps 

让我们以一个通用用户输入为例:

The hotel was great because the view reminded me of when I came here to Denver with my parents. I sure would have like to have received a custom T-shirt as a souvenir. Anyway, it was warm and sunny so we had an amazing time. 

OpenAI 的输出是一个吸引顾客的消息,融合了怀旧和商品建议,并附有合适的定制 T 恤图像:

Customer message: Dear Customer,
Experience the charm of Denver with a nostalgic hotel view and enjoy the sunny weather. Explore the beautiful Denver Botanic Gardens and the iconic Red Rocks Amphitheatre. Don't miss out on exclusive souvenirs from local artists and a personalized T-shirt to remember your trip.
Best regards, 

图 7.10:客户的个人图像

图 7.10:客户的个人图像

现在让我们创建一个图像。

创建图像

此功能利用 DALL-E 生成图像,并勾选了文件框。该函数在适配处理程序选择机制之外没有变化,该机制通过用户输入中的Createimage关键字激活此功能:

def handle_image_creation(user_message, **kwargs):
    prompt = user_message
    image_url = reason.generate_image(
        prompt, model="dall-e-3", size="1024x1024", 
        quality="standard", n=1
    )
    # Save the image locally
    save_path = "c_image.png"
    image_data = requests.get(image_url).content
    with open(save_path, "wb") as file:
        file.write(image_data)
    return "Image created" 

产品设计师可以利用它来构思商品套装:

Create an image:  Create an image of a custom T-shirt with surfing in Hawaii on big waves on it to look cool. 

输出是一个酷炫的 T 恤,生产团队可以使用并适应生产:

图 7.11:定制 T 恤设计

图 7.11:定制 T 恤设计

我们现在将创建一些自由风格的提示,这些提示不会被任何关键字或指令触发。

回退处理程序(基于内存)

当没有特定指令或关键字与输入匹配时,此通用处理程序会被激活。handle_with_memory根据所选模型,与 OpenAI 和 DeepSeek 一起运行。用户对话的内存通过全局变量memory_enabled设置,该变量在开始时初始化:

# Global variable to ensure memory is always used
memory_enabled = True  # Set to True to retain conversation memory
def handle_with_memory(messages, user_message, **kwargs):
    global memory_enabled  # Ensure global memory setting is used 

如果memory_enabled设置为False,则函数将返回消息并停止:

 # If memory is disabled, respond with a message
    if not memory_enabled:
        return "Memory is disabled." 

它将处理用户从对话历史中的过去消息:

 # Extract all past messages (user + assistant) from the conversation history
    conversation_history = [
        f"{msg['role'].capitalize()}: {msg['content']}"
        for msg in messages if "content" in msg
    ]
    # Combine all conversation history
    combined_history = "\n".join(conversation_history)
    # Append the latest user message to the history
    full_context = f"{combined_history}\nUser: {user_message}" 

然后,在 IPython 界面中没有选择其他模型的情况下,默认模型提供者是 OpenAI:

 models = kwargs.get("models", "OpenAI")  # Default to OpenAI if not provided
    if models == "OpenAI":
        task_response = reason.make_openai_api_call(
            full_context, "system",
            "You are an assistant who executes the tasks you are asked to do.", "user"
        )
    elif models == "DeepSeek":
        # Tokenize the full conversation history for DeepSeek
        …
        # Decode the output
        task_response = tokenizer.decode(outputs[0], skip_special_tokens=True) 

响应消息将被存储并返回:

 # Store bot response in memory
    messages.append({"role": "assistant", "content": task_response})
    return task_response 

PDPM 的一个示例输入可能是以下内容:

We are new to production processes and experience issues with the production of a customized travel bag by Supplier S100 for a trip to Hawaii that should have an image of Hawaii on it with the name of the customer. The production process contained operations 10,20,30,40,50 and 60\. Operation 40 is the operation that prints the image and the name of the customer on the bag. Supplier S100 lacks the special ink to perform the operation. SupplierS200 has the ink but the production of operations 10 to 30 have already been performed. Instructions: think this problem through and provide real-world production ideas to solve this issue. 

OpenAI 的回答既可接受又富有成效。花点时间阅读提示和响应,这显示了生成式 AI 从 NLP 通用任务到零样本特定领域任务的转变:

**Agent:** To address the issue of Supplier S100 lacking the special ink needed for operation 40, while Supplier S200 has the ink, consider the following real-world production solutions:
1\. **Outsource Operation 40 to Supplier S200**:
- Coordinate with Supplier S200 to perform operation 40\. This involves transporting the semi-finished bags (after operations 10 to 30) to Supplier S200 for printing.
- Ensure that Supplier S200 is capable of handling the volume and has the necessary equipment to perform the operation to your quality standards.
2\. **Ink Transfer**:
- If feasible, arrange for Supplier S200 to supply the special ink to Supplier S100\. This would allow Supplier S100 to continue with operation 40 without needing to transport the bags.
- Ensure that Supplier S100 has the necessary equipment and expertise to use the ink provided by Supplier S200.
3\. **Collaborative Production**:
- Establish a partnership between Supplier S100 and Supplier S200 where both suppliers work together to complete the production process. This could involve sharing resources, expertise, and logistics.
4\. **Logistics and Scheduling**:
- Plan the logistics for transporting the bags between suppliers efficiently to minimize delays.
- Adjust the production schedule to accommodate the additional time required for transportation and coordination between suppliers.
5\. **Quality Control**:
- Implement a quality control process to ensure that the printing meets the required standards, regardless of which supplier performs the operation.
- Conduct inspections before and after operation 40 to maintain quality consistency.
6\. **Communication and Coordination**:
- Maintain clear communication with both suppliers to ensure that all parties are aligned on timelines, quality expectations, and responsibilities.
- Use project management tools to track progress and address any issues promptly.
7\. **Contingency Planning**:
- Develop a contingency plan in case of further supply chain disruptions, such as identifying alternative suppliers or inks that could be used in the future. 

尽管 DeepSeek 的回答包含一些有趣的观点,但它的质量并不相同:

C.), Utilize Alternate Suppliers With Intermediaries Who Could Possibly Acquire Required Inks From Other Sources Perhaps Via Importing Directly Under Different Terms Agreements,
D ). Leverage Existing Inventory Wherever Feasible Reallocating Stockpiles Smartly Across Production Lines Maybe Even Repurposing Materials When Not Used For Primary Function Into Secondary Applications Which May Free Up Costs And Resources While Mitigating Penalties Imposed By Delays, 

要获得更好的结果,需要进一步的提示设计和输出分析循环,评估未蒸馏的 DeepSeek 模型,如 DeepSeek-V3 或 DeepSeek-R1。DeepSeek 确实可以做得更好,正如使用 DeepSeek-R1 在chat.deepseek.com/上所展示的,它产生了以下输出:

To resolve the production issue with the customized travel bags, consider the following structured solutions:
### 1\. **Outsource Operation 40 to Supplier S200** 
   - **Process**: 
     - S100 ships semi-finished bags (post-operation 30) to S200\. 
     - S200 performs operation 40 (printing) using their special ink. 
     - Bags are returned to S100 to complete operations 50 and 60\. 
   - **Key Considerations**: 
     - Use expedited shipping (e.g., air freight) to minimize delays. 
     - Ensure packaging protects semi-finished goods during transit. 
     - Negotiate cost-sharing for logistics between S100 and S200\. 
### 2\. **Expedite Ink Procurement for S100** 
   - **Action**: 
     - Source the ink directly from S200 or an alternative supplier. 
     - Prioritize urgent delivery (e.g., same-day courier). 
   - **Feasibility Check**: 
     - Verify if the ink is proprietary or available on the open market. 
     - Address contractual barriers if S200 is a competitor. 
### 3\. **Supplier Collaboration for End-to-End Production** 
   - **Option**: 
     - S200 takes over all remaining steps (40, 50, 60) after S100 completes operations 10–30\. 
   - **Requirements**: 
     - Confirm S200's capability to perform operations 50 and 60\. 
     - Align quality standards between suppliers to avoid inconsistencies. 
### 4\. **Process Re-engineering** 
   - **Temporary Workaround**: 
     - Explore alternative printing methods (e.g., heat transfer, patches) if customer specs allow. 
     - Assess feasibility of resequencing operations (e.g., printing later), though this is unlikely. 
### 5\. **Proactive Communication and Risk Mitigation** 
   - **Customer Transparency**: 
     - Inform the customer of potential delays and offer solutions (e.g., partial deliveries, discounts). 
   - **Prevent Future Issues**: 
     - Implement dual sourcing for critical materials (e.g., ink). 
     - Use inventory management tools to track material availability in real-time. 
### **Cost vs. Speed Tradeoff Analysis** 
- **Outsourcing to S200**: Higher logistics costs but faster resolution if suppliers are geographically close. 
- **Expedited Ink**: Higher material costs but avoids production handoffs. 
### **Recommended Approach** 
1\. **Prioritize Outsourcing Operation 40**: 
   - This balances speed and feasibility if S200 can print without disrupting the workflow. 
2\. **Backup Plan**: 
   - If logistics are too slow, expedite ink procurement while negotiating with S200 for a bulk discount. 
By combining supplier collaboration, agile logistics, and proactive planning, the production delay can be minimized while maintaining quality and customer trust. 

仔细阅读本节中的提示和输出。出于安全和隐私原因,我们仅使用本地安装的、蒸馏的 Hugging Face 开源版本的 DeepSeek-R1。然而,如果您有必要的权限,您可以使用 DeepSeek 的在线版本执行某些任务,例如本节中的生产示例,就像您使用 ChatGPT 或任何其他在线平台一样。根据您项目的具体要求,您还可以探索基于美国的 DeepSeek API 或替代部署方法。

无论如何,OpenAI 和 DeepSeek 都能够在正确提示和选择最合适的模型版本时提供有效的生产解决方案。生成式 AI 显然已经进入了一个新的阶段!

摘要

在本章中,我们进一步深入到生成式 AI 系统的探索之旅。首先,我们花时间消化了 DeepSeek-R1 的问世,这是一个以训练中创新效率提升而闻名的强大开源推理模型。这一发展立即为项目经理们提出了一个关键问题:我们应该不断追随实时趋势,还是优先考虑维护一个稳定的系统?

为了应对这一挑战,我们通过构建一个处理程序选择机制来开发了一个平衡的解决方案。该机制处理用户消息,在处理程序注册表中触发处理程序,然后激活适当的 AI 功能。为了确保灵活性和适应性,我们更新了我们的 IPython 接口,使用户在启动任务之前能够轻松地在 OpenAI 和 DeepSeek 模型之间进行选择。

这种设计允许 GenAISys 管理员在保持对已验证结果访问的同时,引入新的实验模型或任何其他功能(非 AI、ML 或 DL)。例如,在分析用户评论时,管理员可以使用可靠的 OpenAI 模型同时评估 DeepSeek 模型。管理员还可以在必要时禁用特定模型,在稳定性和创新之间提供实际平衡,这在当今快速发展的 AI 环境中至关重要。

为了在实际上实现这种平衡,我们首先在一个独立的笔记本中安装并运行了 DeepSeek-R1-Distill-Llama-8B,通过生产相关示例展示了其能力。然后,我们将这个蒸馏模型集成到我们的 GenAISys 中,这需要增强灵活性和可扩展性。

引入处理器选择机制和结构化处理器注册表确保我们的系统可以有效地无限扩展。每个处理器都遵循统一的、模块化的格式,使得管理员可以轻松地进行管理、激活或停用。我们通过一系列与产品设计和生产相关的实际提示展示了这些处理器。

我们现在处于扩展和扩展 GenAISys 的位置,在这个可适应的框架内添加新功能。在下一章中,我们将继续这一旅程,通过将 GenAISys 连接到更广泛的外部世界。

问题

  1. DeepSeek-V3 使用零样本示例进行训练。(对或错)

  2. DeepSeek-R1 是一个推理模型。(对或错)

  3. DeepSeek-R1 首次仅使用强化学习进行训练。(对或错)

  4. DeepSeek-R1-Distill-Llama-8B 是 DeepSeek-R1 的教师。(对或错)

  5. DeepSeek-V3 通过 DeepSeek 衍生的 DeepSeek-R1 进行增强。(对或错)

  6. 包含所有 AI 功能处理器的处理器注册表是可扩展的。(对或错)

  7. 一个处理用户消息的处理器选择机制使 GenAISys 非常灵活。(对或错)

  8. 如 OpenAI 和 DeepSeek 推理模型之类的生成式 AI 模型无需额外训练即可解决广泛的问题。(对或错)

  9. 一个具有坚实架构的 GenAISys 在模型和执行任务方面足够灵活,可以扩展。(对或错)

参考文献

进一步阅读

|

现在解锁这本书的独家优惠

扫描此二维码或访问packtpub.com/unlock,然后通过书名搜索这本书。 | 白色背景上的二维码 AI 生成的内容可能不正确。 |

注意:开始之前请准备好您的购买发票。

第八章:GenAISys 轨迹模拟和预测

随着人工智能角色的不断扩展,轨迹分析已经渗透到人类活动的各个方面,从披萨配送到基因组测序。本章介绍了城市规模的移动性预测,强调了缺失或噪声坐标如何破坏配送、灾害管理、城市规划和流行病预测等现实世界应用。我们移动性系统的架构受到了 Tang 等人(2024)的创新工作的启发。

我们首先将使用 1_Trajectory_simulation_and_prediction.ipynb 笔记本在我们的 GenAISys 中构建和集成一个高级轨迹模拟和预测管道。主要目标是利用合成数据生成和大型语言模型LLMs)来应对模拟人类短期和长期移动性的挑战。然后,我们将展示如何使用基于 Python 的解决方案来扩展这一想法,包括一个定制的合成网格生成器,该生成器通过二维城市地图模拟随机轨迹,故意插入缺失数据以进行测试。这些随机轨迹可能代表配送或其他序列,例如在线旅行社的旅行套餐(定制袋子或手册)。

接下来,我们将构建一个多步骤编排函数,将用户指令、合成数据集和特定领域的消息合并在一起,然后再将它们传递给由 LLM 驱动的推理线程。该模型将检测并预测由占位符值(如 999, 999)标记的未知位置,通过上下文插值来填补这些空白。这种方法展示了基于文本预测的可解释性,同时保持系统性的思维链,包括在生成最终 JSON 输出之前记录缺失点的调试步骤。

为了支持稳健的用户交互,我们将把轨迹管道集成到我们构建的 GenAISys 多处理器环境中,允许对“移动”指令的请求触发轨迹的创建和分析。我们将实现轨迹模拟和预测接口。可视化组件被整合,自动生成并显示结果路径(包括方向箭头、缺失数据标记和坐标修正)作为静态图像。数据生成、LLM 推理和用户界面之间的协同展示了我们方法端到端的有效性,使用户能够根据需要在不同领域应用轨迹模拟和预测。

本章提供了一个蓝图,将合成轨迹数据集与 GenAISys 中的提示驱动 LLM 方法相结合。通过遵循 Tang 等人描述的设计模式,我们将探讨纯文本导向的模型如何通过最小的结构修改在空间时间推理方面表现出色。连接流动性模拟和用户友好的界面可以为各种流动性分析场景提供高度可解释、细致的预测。

本章涵盖了以下主题:

  • 轨迹模拟和预测

  • 构建轨迹模拟和预测功能

  • 将流动性智能添加到 GenAISys 中

  • 运行增强的 GenAISys

让我们首先定义轨迹模拟和预测框架的范围。

轨迹模拟和预测

本节灵感来源于 Tang 等人(2024)的Instruction-Tuning Llama-3-8B Excels in City-Scale Mobility Prediction。我们将探讨人类流动性预测的挑战、论文的关键贡献以及这些想法如何转化为实用的 Python 实现。

人类流动性预测专注于预测个人(或群体)将在何时何地旅行,它在包括以下在内的不断扩大的领域中发挥着关键作用:

  • 灾害响应,用于预测野火路径、危机期间的人口流动或地震的影响

  • 城市规划,用于模拟短期和长期流动性模式,以帮助城市规划者优化公共交通和基础设施

  • 流行病预测,用于模拟和预测一个地区传染病的传播

在我们的案例中,我们首先将流动性预测应用于在线旅行社客户的定制产品(例如,包、T 恤和手册)的交付。

传统上,这些预测依赖于专门的机器学习模型,例如具有注意力机制的循环神经网络RNNs)或图神经网络GNNs)。虽然这些技术可能有效,但它们通常需要劳动密集型的特征工程,并且不易于在不同地点或时间范围内(例如,短期与长期预测)进行泛化。

让我们现在来审视推动使用 LLMs 解决这些问题的关键挑战。

大规模流动性预测的挑战

最先进的 LLMs 为解决传统流动性分析和预测系统历史上一直困扰的几个挑战提供了有希望的解决方案:

  • 长期与短期预测:预测接下来的几步(短期)通常依赖于时间重复和即时上下文信息。然而,将其扩展到多日、城市规模的范围会引入额外的复杂性,例如用户行为的变化、日常生活的变化、节假日或意外事件。

  • 跨城市的泛化:在 City A 的数据上训练的模型在接触到 City B 独特的地理、人口密度或文化旅行习惯时可能会失败。真正的城市规模移动解决方案必须足够鲁棒,能够处理这些差异。

  • 计算限制:现实世界的移动数据集,尤其是代表整个大都市区的数据集,可能非常庞大。训练复杂的深度学习模型或 LLMs 可能会变得计算成本高昂。

  • 数据质量和缺失数据:大规模移动数据集通常存在噪声或缺失坐标。处理用户轨迹中的“缺口”(例如,来自 GPS 掉电或匿名化过程)是一个重大挑战。

虽然 LLMs 并不完美,但它们通过最小化手动特征工程来解决这些关键障碍,为传统模型提供了一种有效的替代方案。让我们看看它是如何做到的。

从传统模型到 LLMs

从传统方法到 LLMs 的转变可以通过几个突破性的转变来追踪。传统方法消耗了大量的人力资源来设计启发式方法、工程特征和实施复杂的特定领域解决方案。相比之下,最近在生成式 AI 方面的突破——如 Llama 3、GPT-4o、Grok 3、DeepSeek-V3 和 DeepSeek-R1——在推理和多模态机器智能方面开辟了令人兴奋的新途径。而且,不要误解——这仅仅是开始!最近的研究强调了这些模型如何能够很好地泛化到文本以外的任务,并在以下方面表现出色:

  • 时间序列预测

  • 零样本或少量样本适应新任务

  • 数据预处理

最近的研究表明,当由精心设计的提示或轻量级微调引导时,LLMs 甚至可以在城市规模、长期轨迹预测方面超越专用模型。在本章中,我们将使用 GPT-4o 展示零样本提示的有效结果——无需任何额外的微调。

然而,为了清楚地理解这个有希望的方向,我们首先应该检查作为本章基础的论文的关键贡献。

论文的关键贡献

要将 LLMs 提升到下一个水平,需要由 Tang, P.,Yang, C.,Xing, T.,Xu, X.,Jiang, R.和 Sezaki, K.(2024)组成的团队通过三个关键创新来实现。

将轨迹预测重新表述为问答

与将原始坐标序列传递给标准回归或分类模型不同,作者将输入转换为一个包含以下内容的问题:

  • 一个指令块明确说明领域上下文(城市网格、坐标定义、日/时索引)

  • 一个问题块,提供历史移动数据,并包含缺失位置的占位符

  • 生成预定义、结构化的 JSON 格式的预测结果请求

这种问答风格利用了 LLM 读取指令并产生结构化输出的内在能力。

然后,他们对 LLM 进行了微调。

指令微调以实现领域适应性

指令微调是一种技术,其中 LLM 通过精心设计的提示和答案进行微调,教会它产生特定领域的输出,同时仍然保留其通用的语言推理能力。作者展示了即使你只使用移动性数据集的一小部分进行微调,模型仍然可以推广到新的用户或新的城市。在我们的情况下,我们没有数据集也达到了可接受的结果。

令人惊讶的是,正如我们在 构建轨迹模拟和预测功能 部分构建 Python 程序时将看到的,即使采用零样本、无微调的方法,我们也能取得强大的结果,利用 GPT-4o 的卓越推理能力,而无需任何特定领域的微调数据。

移动性研究团队随后解决了缺失数据的问题。

处理缺失数据

在移动性数据集中,一个常见的挑战是存在缺失的坐标,通常用占位符值,如 999 标记。基于 LLM 的系统被明确地要求填补这些空白,有效地执行时空插补。自然地,这种方法并非没有局限性,我们将在运行移动性模拟时通过实际示例清楚地说明这些局限性。但在探索这些边界之前,让我们首先深入到构建我们的解决方案中。

在下一节中,我们将使用 OpenAI 模型开发一个轨迹(移动性)模拟和分析组件。然后,我们将把这个移动性功能集成到我们 GenAISys 的 第 3 层,如图 8.1 所示的 F4.1 功能所示。我们还将更新 第 2 层,以注册处理程序并确保它可以在 第 1 层 的 IPython 接口级别激活。

图 8.1:集成轨迹模拟和预测

图 8.1:集成轨迹模拟和预测

一旦轨迹模拟和预测组件集成到我们的 GenAISys 中,它就可以应用于配送和广泛的移动性相关任务。我们将首先为在线旅行社的客户建模定制商品的配送——如品牌包、T 恤和手册——然后探索其他潜在的应用。现在,让我们构建我们的轨迹模拟!

构建轨迹模拟和预测功能

本节的目标是创建一个健壮的轨迹模拟,准备预测函数,并运行 OpenAI LLM 来分析合成轨迹数据并预测缺失坐标。稍后,在 将移动性智能添加到 GenAISys 部分,我们将将其集成到我们全面的 GenAISys 框架中。

在 GitHub 的 Chapter08 目录下打开1_Trajectory_simulation_and_prediction.ipynb笔记本(github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。初始设置与Chapter07/GenAISys_DeepSeek.ipynb中的环境配置相匹配,并包括以下内容:

  • 文件下载脚本

  • OpenAI 设置

  • 思维链环境设置

我们将按照图 8.2中所示的三步主要步骤来构建程序:

  • 创建网格和轨迹模拟以生成实时合成数据

  • 创建一个移动编排器,该编排器将调用轨迹模拟,导入 OpenAI 模型的消息,并调用 OpenAI 模型的分析和预测消息

  • 通过移动编排器利用 OpenAI 的轨迹分析和预测模型

添加移动智能到 GenAISys部分中,移动编排器将被添加到我们的 GenAISys 处理程序注册表中,并在通过 IPython 界面激活时由处理程序选择机制管理。在本节中,我们将直接调用移动编排器。

图 8.2阐述了移动编排器、轨迹模拟器和生成式 AI 预测器之间的关系。这种代理的混合与轨迹分析和预测框架保持紧密一致。

图 8.2:移动编排器的功能

图 8.2:移动编排器的功能

我们将首先开始创建轨迹模拟。

创建轨迹模拟

Tang 等人撰写的参考论文展示了如何将 LLM 指令调整以填充缺失的轨迹坐标并预测网格城市地图中的未来位置。请注意,在我们的情况下,我们将利用 OpenAI API 消息对象的力量,在论文框架内实现零样本提示的实时有效结果。

他们的方法中的一个重要步骤是拥有(day, timeslot, x, y)记录,其中一些坐标可能缺失(例如,999, 999)以表示未知位置。

我们将要编写的函数create_grid_with_trajectory()本质上通过以下方式模拟了这个场景的小规模版本:

  1. 生成一个代表城市的二维网格(默认:200×200)。

  2. 在网格内创建一定数量的随机代理轨迹。

  3. 故意插入缺失的坐标(标记为(999, 999))以模拟现实世界的数据缺口。

  4. 绘制并保存轨迹可视化,用箭头和标签突出显示方向和缺失数据。

这种类型的合成生成对于测试或概念验证演示很有用,与论文的精神相呼应:

  • 您有基于网格的数据,例如文章中使用的 200×200 城市模型

  • 您注入缺失的值(999, 999),这些值 LLM 或另一个模型可以稍后尝试填充

让我们现在逐步通过轨迹模拟函数:

  1. 让我们首先用参数初始化函数:

    def create_grid_with_trajectory(
        grid_size=200, num_points=50, missing_count=5
    ):
        grid = np.zeros((grid_size, grid_size), dtype=int)
        trajectory = [] 
    

参数如下:

  • grid_size=200:网格沿一个轴的大小(因此网格是 200×200)

  • num_points=50:要生成的轨迹点(或步骤)数量

  • missing_count=5:这些点中有多少将被故意转换为缺失坐标(999, 999

  1. 我们现在创建网格:

    • grid = np.zeros((grid_size, grid_size), dtype=int) 创建了一个二维的零数组(int类型)。将 grid[x][y] 视为该单元格的状态,初始为 0。

    • trajectory = []: 将存储形如 (day, timeslot, x, y) 的元组。

这反映了论文中离散城市概念,其中每个 (x, y) 单元可能代表城市内的一个区域。

  1. 我们现在可以设置代理的初始状态:

     x = random.randint(0, grid_size - 1)
        y = random.randint(0, grid_size - 1)
        day = random.randint(1, 365)
        timeslot = random.randint(0, 47) 
    
    • 随机起始点:代理的初始位置 (x, y) 在网格的任何位置随机选择。

    • 时间设置:选择 1 到 365 之间的随机天数和 0 到 47 之间的随机时间槽,与论文中的时间切片方法相一致,其中每一天被划分为多个离散的时间槽。

  2. 我们现在确定移动方向和转向概率:

     directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        current_dir_index = random.randint(0, 3)
        turn_weights = {-1: 0.15, 0: 0.70, 1: 0.15} 
    

这种结构是经典的移动代理框架:

  • directions:表示四个可能的方向——上、右、下、左。

  • current_dir_index:选择代理最初面对的四个方向中的哪一个。

  • turn_weights: 指定代理在每个步骤中转向左(-1)、直行(0)或转向右(1)的概率分布。在我们的例子中,转向左的概率为 15%,继续直行的概率为 70%,转向右的概率为 15%。这引入了代理移动的随机性,是对人类或类似代理移动模式的简单近似。

  1. 我们现在准备好生成轨迹:

     for _ in range(num_points):
            turn = random.choices(list(turn_weights.keys()),
                weights=list(turn_weights.values()))[0]
            current_dir_index = (current_dir_index + turn) % \
                len(directions)
            dx, dy = directions[current_dir_index]
            new_x = x + dx
            new_y = y + dy
            ...
            trajectory.append((day, timeslot, x, y))
            grid[x, y] = 1
            timeslot = (timeslot + random.randint(1, 3)) % 48 
    

让我们现在逐步通过虚拟代理的动作:

  • 选择转向:根据 turn_weights,代理随机决定是否继续同一方向、转向左或转向右。

  • 更新坐标

    1. dxdy 是所选方向沿 xy 的增量。

    2. 新位置 (new_x, new_y) 被计算。

      • 检查边界条件:如果 (new_x, new_y) 超出 [0, grid_size-1] 范围,代码将寻找一个有效的方向或恢复到旧位置,以保持代理在网格内。

      • 记录轨迹

    3. (day, timeslot, x, y) 被添加到 trajectory

    4. grid[x, y] 标记为 1,表示已访问的单元格。

  • 更新时间timeslot = (timeslot + random.randint(1, 3)) % 48:时间槽从 1 步跳到 3 步,保持在 [0, 47] 范围内。

  1. 我们现在需要引入缺失的数据,这将成为生成式 AI 预测的基础:

     missing_indices = random.sample(range(len(trajectory)),
                                        min(missing_count, 
                                        len(trajectory)))
        for idx in missing_indices:
            d, t, _, _ = trajectory[idx]
            trajectory[idx] = (d, t, 999, 999) 
    

缺失的点分两步确定:

  1. 选择缺失的点:从轨迹的总num_points中随机选择missing_count个点。

  2. 999, 999替换缺失的点:对于每个选定的索引,将有效的(x, y)替换为999, 999

在论文中,作者将999, 999定义为 LLM 必须后来填补的未知或缺失坐标的信号。这段代码模拟了这种情况——一些坐标丢失,需要填补或预测步骤。

我们希望添加一个可视化函数,以帮助用户看到轨迹及其缺失的点。

可视化轨迹模拟器

我们将使用 Matplotlib 绘制网格和轨迹:

 x_coords = [x if x != 999 else np.nan for _, _, x, y in trajectory]
    y_coords = [y if y != 999 else np.nan for _, _, x, y in trajectory]
    plt.figure(figsize=(8, 8))
    plt.plot(x_coords, y_coords, marker='o', linestyle='-',
             color='blue', label="Agent Trajectory")
    ...
    plt.quiver(...)
    ...
    plt.title("Agent Trajectory with Direction Arrows and Missing Data")
    plt.xlabel("X coordinate")
    plt.ylabel("Y coordinate")
    plt.grid(True)
    plt.legend()
    plt.savefig("mobility.png")
    plt.close() 

让我们通过可视化过程:

  • 绘图坐标:将缺失的999, 999值转换为np.nan,这样 Matplotlib 就会断开线条,在视觉上不连接它们。

  • 用颜色、箭头和文本绘图

    1. 轨迹线用蓝色绘制。

    2. Quiver 箭头(plt.quiver)显示了从每个点到下一个点的方向。

    3. 缺失数据点用紫色的'X'标记突出显示。

  • 标题和坐标轴:清晰标注和图例

  • 保存并关闭:将图形保存为mobility.png

这种绘图反映了论文中案例研究部分(第 4.4 节)的风格,其中作者比较了实际轨迹与预测轨迹。在这里,你只是展示了合成路径以及缺失数据的视觉指示。

模拟函数的输出

我们将处理的函数输出包含网格和轨迹:

 return grid, trajectory 

这两个变量将包含我们的生成式 AI 模型需要做出预测的内容:

  • grid:一个标记已访问路径的二维数组

  • trajectory:一个包含(day, timeslot, x, y)元组的列表,其中一些被替换为999, 999

这个最终结果将被输入到一个基于 LLM 的方法(如论文中描述的方法)中,使用 OpenAI 生成式 AI 模型,在零样本过程中产生可接受的输出。我们现在将开始处理轨迹模拟。

创建移动性协调器

轨迹模拟已生成网格、轨迹和轨迹中的缺失坐标。我们现在将开发一个协调器函数,该函数整合了轨迹模拟和 OpenAI 模型的预测能力。我们将把这个协调器称为handle_mobility_orchestrator()

这个协调器与 Tang 等人(2024)在他们的论文《Instruction-Tuning Llama-3-8B 在城规模度移动性预测中表现卓越》中概述的方法相一致。其目的是简单而强大,执行三个关键功能:

  • 生成合成移动性数据:调用create_grid_with_trajectory()函数来模拟带有可能缺失点的轨迹。

  • 准备 LLM 调用数据:它将新的轨迹数据格式化为 JSON 字符串,将其附加到用户消息中,然后调用推理函数——可能是基于 LLM 的解决方案或编排逻辑(reason.mobility_agent_reasoning_thread())。

  • 返回结构化响应:它清楚地返回最终结果(reasoning_steps),包括新生成的轨迹数据和 LLM 推理步骤。

这种方法与《Instruction-Tuning Llama-3-8B 在城市场规模移动预测中表现卓越》论文中的方法一致,该论文的作者强调创建结构化输入数据——例如带有缺失点的轨迹——然后将其传递给 LLM 进行完成或预测。

现在我们一步一步地通过编排器:

  1. 首先,编排器函数使用必要的参数初始化:

    def handle_mobility_orchestrator(
        muser_message1, msystem_message_s1, mgeneration, 
        mimcontent4, mimcontent4b
    ): 
    

立即调用我们之前构建的轨迹模拟函数:

grid, trajectory = create_grid_with_trajectory(
    grid_size=200, num_points=50, missing_count=5
) 
  1. 我们现在将轨迹转换为 JSON 并进行处理:

    trajectory_json = json.dumps({"trajectory": trajectory}, indent=2)
        #print("Trajectory Data (JSON):\n", trajectory_json)
        muser_message = f"{muser_message1}\n\nHere is the trajectory data:\n{trajectory_json}" 
    

此代码负责将轨迹转换为 JSON 格式并增强用户消息:

  • 将轨迹转换为 JSON:

    1. trajectory_json成为数据的序列化版本,以便它可以嵌入到文本消息或 API 调用中。

    2. 在底层,它只是{"trajectory": [...list of (day, timeslot, x, y)...]}

  • 增强用户消息:

    1. 该函数接收原始用户消息(muser_message1),并将新生成的轨迹数据附加到其中。

    2. 这确保了模型(或推理线程)在生成预测或完成时看到完整的上下文——即用户的原始查询和合成数据。

此步骤与 Tang 等人(2024 年)提出的问答式交互非常相似,其中轨迹数据——通过占位符(999, 999)清晰标记——直接传递给模型。

  1. 在上下文明确定义后,编排器调用移动推理函数(我们将在下一步构建):

     reasoning_steps = reason.mobility_agent_reasoning_thread(
            muser_message, msystem_message_s1, mgeneration, 
            mimcontent4, mimcontent4b
        ) 
    

这是幕后发生的事情:

  • reason.mobility_agent_reasoning_thread(...)通过所选的 LLM(如 GPT-4o)处理移动预测逻辑。

  • 提供的参数(msystem_message_s1mgenerationmimcontent4mimcontent4b)代表了清晰的操作指令和特定上下文,为生成式 AI 模型提供指导,引导其推理和预测。

这与 Tang 等人论文中描述的方法相似,其中模型接收结构化输入数据,并被提示推断缺失的轨迹或预测下一步动作。

  1. 最后,将轨迹添加到推理步骤中,以提供完整的响应:

     reasoning_steps.insert(
            0, ("Generated Trajectory Data:", trajectory)
        )
        return reasoning_steps 
    

接下来,让我们开发处理程序注册表将调用的 AI 推理函数。

准备预测指令和 OpenAI 函数

在本节中,我们将开发一个函数,允许我们的 GenAISys 处理与移动相关的用户消息。具体来说,我们将实现一个名为handle_mobility(user_message)的函数,该函数可以无缝集成到我们的 GenAISys 的 AI 功能中。

我们将把这个任务分为两个主要部分:

  1. 消息准备: 明确结构化引导生成式 AI 模型的指令

  2. 在 OpenAI API 调用中实现这些消息: 利用 AI 推理线程中的结构化消息

这与在Instruction-Tuning Llama-3-8B Excels in City-Scale Mobility Prediction中描述的轨迹完成方法紧密一致,其中结构化提示显著提高了预测准确性。

消息准备

我们有四个主要的消息变量要发送到 OpenAI 函数:

  • msystem_message_s1: 系统消息

  • mgeneration: 生成消息

  • mimcontent4: 补充背景信息

  • muser_message1: 用户消息

它们在最终发送到 LLM(GPT-4o 或类似)进行预测任务的提示中各自发挥着不同的作用。系统消息将为任务设定场景。

系统消息

系统消息设置了 LLM 的整体上下文和约束,确保模型清楚地理解其主要目标。系统消息存储在msystem_message_s1中。我们首先指定模型的角色:

msystem_message_s1 = """
You are GPT-4o, an expert in grid-based mobility analysis. Your task is to analyze the provided trajectory dataset and **identify missing coordinates** flagged as `999,999`, then predict their correct values. 

现在,我们明确详细地描述预期的任务,使用明确的自然语言:

**Task:**
1\. **Process only the dataset provided in the user input. Do not generate or use your own sample data.**
2\. Identify **every single** instance where `x` or `y` is `999`, including consecutive and scattered occurrences.
3\. Predict the missing coordinate values based on the trajectory pattern.
4\. **Do not modify, reorder, or filter the data in any way**—your response must reflect the dataset exactly as given except for replacing missing values.
5\. Before responding, **validate your output** against the original dataset to confirm completeness and accuracy.
6\. Maintain the exact order of missing values as they appear in the dataset.
7\. Include a debugging step: **first print the list of detected missing values before structuring the final JSON output**. 

指定输出格式:

**Output Format:**
```json

{"predicted_coordinates": [[day, timeslot, x, y], ...]}

```py 

这些指令反映了我们在实施的论文中的方法——系统消息澄清了模型的角色任务指令,有效地减少了混淆或幻觉。论文展示了如何一个结构良好的指令块显著提高准确性。现在,我们可以构建生成消息。

生成消息

这个二级提示提供了生成指令,这将加强模型处理数据的处理方式:

mgeneration = """
Scan the user-provided trajectory data and extract **every** point where either `x` or `y` equals `999`.
You must process only the given dataset and not generate new data.
Ensure that all missing values are explicitly listed in the output without skipping consecutive values, isolated values, or any part of the dataset. **Before responding, verify that all occurrences match the input data exactly.**
Then, predict the missing values based on detected trajectory movement patterns. **Provide a corrected trajectory with inferred missing values.**
To assist debugging, **first print the detected missing values list as a pre-response validation step**, then return the structured JSON output.
""" 

这个提示专注于扫描缺失值,确保没有遗漏。然后,它解决下一步:提供带有推断缺失值的修正轨迹。

补充背景信息

为了确保我们得到我们想要的,我们现在将添加额外的背景信息。这个额外背景信息的角色是补充系统/生成消息以提供特定领域的上下文:

mimcontent4 = """
This dataset contains spatial-temporal trajectories where some coordinate values are missing and represented as `999,999`. Your goal is to **identify these missing coordinates from the user-provided dataset only**, then predict their correct values based on movement patterns. Ensure that consecutive, isolated, and scattered missing values are not omitted. **Before generating the final response, validate your results and confirm that every missing value is properly predicted.**
""" 

这额外的背景信息进一步引导生成式 AI 模型进行精确预测。我们将现在构建一个用户消息以进一步指导模型。

用户消息

是时候进一步强调指令,以确保我们提供更多的上下文给输入。用户消息表达了用户的明确请求。它引用了实际数据集(带有缺失点的数据集)。在实际代码中,你将在将其传递给生成式 AI 模型之前,将实际的轨迹数据(带有999, 999占位符)附加或嵌入:

muser_message1 = """
Here is a dataset of trajectory points. Some entries have missing coordinates represented by `999,999`.
You must process only this dataset and **strictly avoid generating your own sample data**.
Please identify **all occurrences** of missing coordinates and return their positions in JSON format, ensuring that no values are skipped, omitted, or restructured. Then, **predict and replace** the missing values using trajectory movement patterns.
Before returning the response, **first output the raw missing coordinates detected** as a validation step, then structure them into the final JSON output with predicted values.
""" 

让我们把这些消息组合起来。

将消息组合在一起

四个消息汇聚在一起,以指导生成式 AI 模型:

  • 系统消息(msystem_message_s1)设定场景并强制执行顶级策略

  • 生成消息(mgeneration)明确了扫描、验证和预测的方法

  • 附加内容(mimcontent4)确保领域清晰

  • 最后,用户的消息(muser_message1)包括需要处理的数据(部分或缺失的轨迹)

它们共同构成了零样本高级生成模型预测的结构。

现在,让我们将消息适配到 OpenAI API 函数中。这些消息存储在 commons/cot_messages_c6.py 中,以便由 OpenAI API 函数导入。

将消息实现到 OpenAI API 函数中

当我们将它集成到我们的 GenAISys 时,我们将在 AI 函数 部分创建一个 AI 移动性函数:

def handle_mobility(user_message): 

我们现在将存储在 cot_messages_c6.py 中的消息导入:

 from cot_messages_c6 import (
        msystem_message_s1, mgeneration, mimcontent4,muser_message1
    ) 

我们现在完成函数,以便我们可以通过在生成式 AI 调用中插入消息来进一步调用此程序,并返回推理步骤:

 #call Generic Synthetic Trajectory Simulation and Predictive System
    reasoning_steps = handle_mobility_orchestrator(
        muser_message1, msystem_message_s1, mgeneration, 
        mimcontent4, mimcontent4b
    )
    return reasoning_steps
    mimcontent4b=mimcontent4 

现在,我们可以调用移动性协调器并返回其推理步骤:

 #call Generic Synthetic Trajectory Simulation and Predictive System
    reasoning_steps = handle_mobility_orchestrator(
        muser_message1, msystem_message_s1, mgeneration, 
        mimcontent4, mimcontent4b)
    return reasoning_steps 

然后,我们在本书前几章中实现的 reason.py 库中创建 handle_mobility_orchestrator 函数。我们首先创建函数:

# Implemented in Chapter08
def mobility_agent_reasoning_thread(
    input1,msystem_message_s1,mumessage4,mimcontent4,mimcontent4b
): 

然后,我们将推理步骤初始化以在 VBox 中显示:

 steps = []

    # Display the VBox in the interface
    display(reasoning_output)
    #Step 1: Mobility agent
    steps.append("Process: the mobility agent is thinking\n")
    with reasoning_output:
        reasoning_output.clear_output(wait=True)
        print(steps[-1])  # Print the current step 

然后,我们将接收到的消息插入到我们在前几章中使用的标准 make_openai_call 中,并返回步骤:

 mugeneration=msystem_message_s1 + input1
    mrole4 = "system"
    mcontent4 = mimcontent4
    user_role = "user"
    create_response = make_openai_api_call(
        mugeneration,mrole4,mcontent4,user_role
    )
    steps.append(f"Customer message: {create_response}")
    return steps 

现在,我们已经准备好运行轨迹模拟和预测。

轨迹模拟、分析和预测

在我们的移动性函数构建和明确定义后,我们现在可以运行完整的轨迹管道——生成合成轨迹数据、识别缺失坐标,并使用零样本 LLM 进行预测。本节将演示端到端执行和结果解释。

我们将使用一个简单、通用的提示来启动移动性分析:

user_message="Check the delivery path"
output=handle_mobility(user_message) 

这触发了我们之前设置的整个管道,从合成数据生成到坐标预测。

为了清楚地说明轨迹和缺失点,系统生成一个视觉图表(mobility.png)。我们可以直接显示此图像:

# Display mobility.png if it exists and the "Mobility" instruction is selected
if os.path.exists("mobility.png"):
    original_image = PILImage.open("mobility.png")
    display(original_image) 

输出包含网格、轨迹和缺失数据,如图 图 8.3 所示:

图 8.3:轨迹和缺失数据

图 8.3:轨迹和缺失数据

输出以颜色、箭头和文本作为设计进行绘制:

  • 绿色是起点

  • 轨迹线用蓝色绘制

  • 红色箭头(plt.quiver)显示从每个点到下一个点的方向

  • 缺失数据点用x标记突出显示,颜色为洋红色

然后,我们打印原始输出:

print(output) 

显示的输出是包含轨迹数据和预测的单行、非结构化内容:

[('Generated Trajectory Data:', [(50, 28, 999, 999), (50, …. 

显然,我们需要更直观地展示这些数据。让我们创建一个函数来显示一个漂亮、格式化的响应:

def transform_openai_output(output):
    """
    Takes the 'output' (a list/tuple returned by OpenAI) and transforms
    it into a nicely formatted multiline string.
    """ 

代码将输出分解为展示良好的行:

 …
    lines = []
    …
    # Join all lines into one neatly formatted string
    return "\n".join(lines) 

然后,我们调用函数以获取格式化输出:

pretty_response = transform_openai_output(output)
print(pretty_response) 

输出包含我们构建的三个步骤过程:

  1. 显示轨迹。

  2. 将缺失数据隔离。

  3. 对缺失数据进行预测。

输出首先包含轨迹:

Generated Trajectory Data:
  (228, 6, 999, 999)
  (228, 7, 69, 79)
  (228, 9, 70, 79)
  (228, 11, 71, 79)
  (228, 13, 71, 78)
  (228, 16, 71, 77)
  (228, 18, 71, 76)
  (228, 21, 71, 75)
  (228, 24, 71, 74)
  (228, 26, 70, 74)
  (228, 27, 70, 73)
  (228, 29, 70, 72)
  (228, 32, 999, 999)
  … 

注意包含999作为x,y坐标的缺失数据的记录。以下是一个示例:

(228, 6, 999, 999) 

第二步是 OpenAI GPT-4o 通过思考问题来隔离缺失数据并显示它:

Process: the mobility agent is thinking
Customer message: **Detected Missing Coordinates:**
1\. [228, 6, 999, 999]
2\. [228, 32, 999, 999]
3\. [228, 9, 999, 999]
4\. [228, 45, 999, 999]
5\. [228, 47, 999, 999] 

第三步是让 OpenAI 的生成式 AI 预测缺失的数据:

**Predicted Missing Coordinates:** 

输出显示并带有解释的预测:

1\. [228, 6, 69, 79] - Based on the trajectory pattern, the missing values at timeslot 6 are likely to be the same as the next known values at timeslot 7.
2\. [228, 32, 69, 72] - Interpolating between timeslot 29 (70, 72) and timeslot 33 (68, 72), the missing values at timeslot 32 are predicted to be (69, 72).
3\. [228, 9, 64, 72] - The missing values at timeslot 9 are interpolated between timeslot 7 (64, 71) and timeslot 10 (64, 73), resulting in (64, 72).
4\. [228, 45, 58, 81] - Interpolating between timeslot 43 (58, 82) and timeslot 46 (58, 80), the missing values at timeslot 45 are predicted to be (58, 81).
5\. [228, 47, 58, 79] - The missing values at timeslot 47 are interpolated between timeslot 46 (58, 80) and timeslot 1 (58, 78), resulting in (58, 79). 

输出还包含 JSON 格式的预测:

```json

{

"predicted_coordinates": [

    [228, 6, 69, 79],

    [228, 32, 69, 72],

    [228, 9, 64, 72],

    [228, 45, 58, 81],

    [228, 47, 58, 79]

]

}

```py 

结果是可以接受的,并显示出最近的生成式 AI 模型具有零样本能力,可以对序列中的缺失数据进行预测。

然而,真正的力量在于将这些预测扩展到广泛的现实世界应用。下一步合乎逻辑的步骤是将此功能集成到我们的 GenAISys 界面中,使用户能够轻松自定义提示以适应各种与轨迹相关的用例。

让我们继续前进,实现这一用户友好的集成。

将移动性智能添加到 GenAISys

现在我们将把轨迹模拟和预测组件集成到我们的 GenAISys 中,使用户能够设计特定领域的提示。在用户界面层面,我们将把“轨迹模拟和预测”这一术语简化为用户友好的“移动性”。这个更短的标签对用户来说更直观,尽管技术文档可以根据需要保持详细的术语。然后,用户将决定他们希望在界面中看到哪些特定领域的术语。

我们将把在1_Trajectory_simulation_and_prediction.ipynb中构建的移动性函数以三个级别添加到 GenAISys 中,如图 8.4 所示:

  1. IPython 界面:将移动性功能添加到用户界面

  2. 处理程序选择机制:将移动性处理程序添加到处理程序注册表中

  3. AI 功能:在 AI 功能库中实现移动性功能

图 8.4:将轨迹模拟和预测管道集成到 GenAISys 中

图 8.4:将轨迹模拟和预测管道集成到 GenAISys 中

打开2_GenAISys_Mobility.ipynb笔记本。如果需要,在继续此处之前,回顾一下第七章中描述的处理程序选择机制。该笔记本不是为坐标列表的语音输出而设计的。因此,默认情况下最好通过在笔记本顶部设置use_gtts = False来禁用 gTTS。

让我们先增强 IPython 界面。

IPython 界面

移动性选项主要添加到 IPython 界面的以下部分:

  • instruct_selector下拉菜单,其中移动性是其可能的值之一

  • update_display()内部的显示逻辑,该逻辑检查用户是否选择了移动性,如果是,则显示mobility.png文件

  • handle_submission()的处理逻辑中,如果instruct_selector.value"Analysis""Generation""Mobility",则代码会打印"Thinking..."

  • 移动性图像(即mobility.png)仅在文件小部件被选中时显示

我们将首先将此选项添加到界面中。我们将创建并添加一个选项到instruct_selector,然后处理轨迹图像显示和提交代码。让我们从界面中的选项开始。

instruct_selector中创建选项

我们首先将移动性选项添加到推理下拉列表中,如图 8.5 所示:

instruct_selector = Dropdown(
    options=["None", "Analysis", "Generation","Mobility"],
    value="None",
    description='Reasoning:',
    layout=Layout(width='50%')
)
instruct_selector.observe(on_instruct_change, names='value') 

计算机屏幕截图 AI 生成的内容可能不正确。

图 8.5:将移动性添加到下拉列表

我们可以像图 8.6 所示那样选择移动性

图 8.6:选择移动性以激活管道

图 8.6:选择移动性以激活管道

移动性现在被选中。注意默认模型设置为OpenAI;然而,根据项目需求,在后续阶段,您可能将其扩展到其他模型,如 DeepSeek。

现在我们来处理更新显示时的“移动性”值。

update_display()中处理“移动性”值

我们必须确保在移动性选项被选中且文件复选框被启用时,生成的轨迹可视化(mobility.png)会自动显示:

def update_display():
    clear_output(wait=True)
    ...
    # Display c_image.png if it exists
    if files_checkbox.value == True:
    …
        # Display mobility.png if "Mobility" is selected
        if (
            os.path.exists("mobility.png")
            and instruct_selector.value == "Mobility"
        ):
            original_image = PILImage.open("mobility.png")
            display(original_image) 

轨迹模拟创建的图像将被显示。我们现在需要增强提交逻辑输出以运行 AI 函数。

handle_submission()逻辑

chat_with_gpt函数像之前一样被调用,但它直接与处理程序选择机制(在下一节中描述)交互*:

The response = chat_with_gpt(
    user_histories[active_user], user_message, pfiles, 
    active_instruct, models=selected_model
) 

然而,我们将移动性功能添加到提交处理函数中:

def handle_submission():
    user_message = input_box.value.strip()
…
        if instruct_selector.value in [
            "Analysis", "Generation","Mobility"
        ]:
            with reasoning_output:
                reasoning_output.clear_output(wait=True)
                … 

我们现在将移动性函数添加到处理程序选择机制中。

处理程序选择机制

处理程序选择机制包含两个主要部分。第一个组件chat_with_gpt与之前章节保持不变,并由 IPython 界面直接调用:

def chat_with_gpt(
    messages, user_message, files_status, active_instruct, models
): 

第二个组件是处理程序注册表,我们将现在添加新开发的移动性处理程序:

handlers = 
…
# Mobility handler: determined by the instruct flag
    (
        lambda msg, instruct, mem, models, user_message, **kwargs: 
            instruct == "Mobility",
        lambda msg, instruct, mem, models, user_message, **kwargs: 
            handle_mobility(user_message, models=models)
    ),
… 

这确保了当用户从界面中的推理下拉列表中选择移动性时,相应的处理程序会自动激活。我们可以看到处理程序选择机制可以无缝扩展。现在让我们将我们为这个移动性函数开发的函数添加到 AI 函数库中。

AI 函数

接下来,我们将集成轨迹模拟和预测函数——之前在构建轨迹模拟和预测部分中开发的——到笔记本中的 AI 函数库中:

def create_grid_with_trajectory(
    grid_size=200, num_points=50, missing_count=5
):
… 

此函数添加在处理程序选择机制调用的函数之前。

def handle_mobility_orchestrator(
    muser_message1, msystem_message_s1, mgeneration, 
    mimcontent4, mimcontent4b
):
… 

此功能也添加在处理选择机制调用的函数的开始部分之上。

我们现在还添加了我们开发的 handle_mobility 函数,并为处理处理机制选择函数发送的参数添加了 **kwargs**

def handle_mobility(user_message, **kwargs):
    from cot_messages_c6 import (
        msystem_message_s1, mgeneration, mimcontent4,muser_message1
    )
    mimcontent4b=mimcontent4
    #call Generic Synthetic Trajectory Simulation and Predictive System
    reasoning_steps = handle_mobility_orchestrator(
        muser_message1, msystem_message_s1, mgeneration, 
        mimcontent4, mimcontent4b
    )
    return reasoning_steps 

代码将像在 构建轨迹模拟和预测函数 部分中一样运行。使用此设置,移动功能已完全集成到 GenAISys 生态系统中,准备好通过直观的 IPython 界面触发。现在让我们让用户参与进来。

运行增强移动性的 GenAISys

在本节中,我们将通过运行两个不同的场景——一个交付用例和一个火灾灾害场景——来展示增强移动性的 GenAISys,以说明轨迹模拟和预测的通用性,这受到了 Tang 等人(2024)工作的启发。

打开 2_GenAISys_Mobility.ipynb 笔记本。首先,在初始设置单元中禁用 DeepSeek(你将只需要 CPU):

deepseek=False
HF=False
Togetheragents=False 

然后运行整个笔记本。完成后,转到笔记本中的 运行界面 部分。我们需要激活 AgentFilesMobility,并将默认模型保留为 OpenAI

![图 8.7:使用移动功能运行交付检查图 8.7:使用移动功能运行交付检查合成轨迹模拟真实世界输入数据,每次运行时都会生成新的数据。本节中的说明仅反映其中的一次运行。当你执行程序时,你将每次获得新的输出,模拟实时数据。限制:目前,每当生成新的轨迹时,轨迹文件就会被覆盖。如果需要,此功能可以在项目期间扩展,以保存多个文件。让我们先通过一个交付示例来探索移动功能。## 生产交付验证场景要运行生产交付验证,我们只需激活 AgentFilesMobility 作为推理功能,以及 OpenAI 作为模型。然后,点击 SEND 并让 AI 做工作。在这种情况下,我们可以想象一个在线旅行社想在旅行前向其客户发送定制的礼物,例如印有他们名字的个性化旅行包、旅游指南和博物馆折扣券。GenAISys 将开始思考,如界面底部所示,如图 图 8.8图 8.8:GenAISys 已开始思考

图 8.8:GenAISys 已开始思考

输出首先显示合成轨迹,它可以来自任何来源,例如实时数据、数据库和传感器。在这种情况下,合成轨迹显示在用户消息下方,该消息指示讨论的标题,因为移动功能本身是自主的:

**User01**: Check deliveries
Agent: ('Generated Trajectory Data:', [(145, 20, 999, 999), (145, 22, 189, 125), (145, 25, 190, 125), (145, 28, 190, 124), (145, 29, 190, 123), (145, 31, 999, 999), 

然后,生成式 AI 函数接管并指示它正在处理轨迹中的缺失数据:

Process: The mobility agent is thinking 

当它完成思考后,它提供了缺失数据的列表:

Customer message: **Detected Missing Coordinates:**
1\. [145, 20, 999, 999]
2\. [145, 31, 999, 999]
3\. [145, 34, 999, 999]
4\. [145, 42, 999, 999]
5\. [145, 3, 999, 999] 

GenAISys 然后提供其预测:

**Predicted Missing Coordinates:** To predict the missing coordinates, we will analyze the trajectory pattern before and after each missing value:
**Predicted Coordinates:**
1\. [145, 20, 189, 125] - Based on the pattern before and after the missing value.
2\. [145, 31, 189, 122] - Interpolated from the surrounding points.
3\. [145, 34, 189, 121] - Interpolated from the surrounding points.
4\. [145, 42, 191, 128] - Based on the pattern before and after the missing value.
5\. [145, 3, 190, 124] - Interpolated from the surrounding points. 

提供了结构化的 JSON 输出,以便与其他系统集成或进一步处理:

json<br>{<br> "predicted_coordinates": [<br> [145, 20, 189, 125],<br> [145, 31, 189, 122],<br> [145, 34, 189, 121],<br> [145, 42, 191, 128],<br> [145, 3, 190, 124]<br> ]<br>}<br> 

用户可以看到原始轨迹,以便做出决策,如图 图 8.9 所示:

图 8.9:带有缺失数据的原始轨迹

图 8.9:带有缺失数据的原始轨迹

现在,三个 主题专家SME)代理可以介入:

  • 人类用户:一个人评估数据,验证预测或提供反馈

  • AI 代理:可以添加一个附加功能。轨迹网格可以进行标注,并且可以向 AI 函数提供指令。这些指令将依赖于网格的坐标区域来生成进一步的功能或消息。

  • 混合(人类用户 + AI 代理):一旦人类用户成功创建了多个提示,如果项目范围内接受,自动化其中一些可能有助于减轻人类用户的负担。

现在,让我们停用 移动性 功能和 文件 显示,以便将前沿的生成式 AI 投入工作,如图 图 8.10 所示:

图 8.10:生成式 AI 取代并生成消息

图 8.10:生成式 AI 取代并生成消息

在这个阶段,人类用户可以解释 AI 的输出并制定一个定制的提示。例如,考虑以下场景:

The missing x,y coordinates with 999,999 respectively in this dialog are deliveries that were not made! The predicted x,y coordinates are inference from the coordinates before and after. 

这里是一个特定领域的提示示例,以解决该问题:

Write an email to SUPPLIER COMPANY specifying that the missing coordinates from x values 20 to 40 are located in the Midtown mall area. Provide the missing coordinates and their predictions to inform the SUPPLIER COMPANY. Be as precise and explicit as possible. 

如所示,这样的提示可以很容易地适应各种领域。只需调整坐标的标注和预期的接收者,就可以生成各种消息。确切的范围和应用完全取决于您特定项目的需求。

生成式 AI 对先前提示的响应是可以接受的且详细的:

Dear [Supplier Company Contact Name],
I hope this message finds you well. I am writing to inform you about certain discrepancies identified in the delivery data for the Midtown Mall area. Specifically, there are missing coordinates in the trajectory data, which indicate deliveries that were not completed. These missing coordinates are represented by the values 999,999.
Below, I have detailed the missing coordinates along with their predicted values, which have been inferred based on the surrounding data points:
1\. Missing Coordinate: [145, 20, 999, 999]
- Predicted Coordinate: [145, 20, 189, 125]
2\. Missing Coordinate: [145, 31, 999, 999]
- Predicted Coordinate: [145, 31, 189, 122]
3\. Missing Coordinate: [145, 34, 999, 999]
- Predicted Coordinate: [145, 34, 189, 121]
4\. Missing Coordinate: [145, 42, 999, 999]
- Predicted Coordinate: [145, 42, 191, 128]
5\. Missing Coordinate: [145, 3, 999, 999]
- Predicted Coordinate: [145, 3, 190, 124]
These missing deliveries occurred within the x-value range of 20 to 40, specifically in the Midtown Mall area. The predicted coordinates have been calculated by analyzing the trajectory data pattern before and after the missing points.
We kindly request that you review this information and take the necessary actions to address these unfulfilled deliveries. Your prompt attention to this matter will help ensure that our delivery operations continue to run smoothly and efficiently.
Please feel free to reach out if you require further details or clarification regarding this issue.
Thank you for your cooperation.
Best regards,
[Your Full Name]
[Your Position]
[Your Company Name]
[Your Contact Information] 

接下来,不重新启动会话,让我们询问我们的 GenAISys 这种方法如何应用于火灾场景。

火灾场景

现在,让我们探讨如何在灾难预测场景中利用轨迹分析、缺失坐标和预测坐标的概念,特别是在森林火灾等情况下。我们将提交此场景给 GenAISys 并分析其见解:

**User01:** How could the trajectory, missing coordinates, and predicted coordinates be used for disaster prediction such as fires? Explain and create an output for this use case.
**Agent:** Trajectory data, missing coordinates, and predicted coordinates can be valuable tools in disaster prediction and management, such as for fires, in the following ways:
1\. **Trajectory Analysis**: By analyzing the movement patterns of vehicles, drones, or other mobile units, authorities can identify areas that are frequently visited or monitored. This can help in understanding the normal patterns of activity and detecting anomalies that might indicate a disaster, such as a sudden deviation from a typical route due to a fire.
2\. **Missing Coordinates**: Missing data points can indicate areas where monitoring or data collection was interrupted, possibly due to a disaster like a fire. Identifying these gaps can help in pinpointing locations that need immediate attention or further investigation.
3\. **Predicted Coordinates**: By predicting the missing coordinates, authorities can fill in the gaps in the data to maintain a continuous monitoring system. This can help in reconstructing the events leading up to a disaster and in planning the response by understanding the spread and impact of the fire.
### Use Case Output for Disaster Prediction (Fires)
**Scenario**: A fire has been reported in a forest area, and trajectory data from drones monitoring the region is being analyzed to assess the situation.
**Output**:
json<br>{<br> "fire_prediction_analysis": {<br> "trajectory_analysis": "Drones deviated from their usual path at coordinates [145, 20] to [145, 40], indicating potential fire activity.",<br> "missing_coordinates": [<br> {"missing_coordinate": [145, 25, 999, 999], "predicted_coordinate": [145, 25, 190, 130]},<br> {"missing_coordinate": [145, 30, 999, 999], "predicted_coordinate": [145, 30, 191, 128]}<br> ],<br> "predicted_fire_area": [<br> {"coordinate": [145, 25, 190, 130]},<br> {"coordinate": [145, 30, 191, 128]}<br> ],<br> "actionable_insights": "Immediate investigation and firefighting efforts are recommended in the predicted fire area to prevent further spread."<br> }<br>}<br>
This output provides a structured analysis of the situation, helping disaster management teams to quickly identify and respond to potential fire threats based on trajectory data and inferred information. 

这种结构化输出提供了宝贵的见解,使灾害响应团队能够根据轨迹分析、确定的数据差距和预测坐标迅速识别和应对潜在的威胁。

这种方法表明,我们可以在各个领域创建许多专业化的提示。尽管存在不可避免的限制,但 GenAISys 时代才刚刚开始,不断扩展到新的、未知的领域。

摘要

在本章中,我们首先认识到,稳健的轨迹分析对于从配送和流行病预测到城市规模规划的各种应用至关重要。在 Tang, P.,Yang, C.,Xing, T.,Xu, X.,Jiang, R.和 Sezaki, K.(2024)概述的创新方法指导下,我们强调了基于文本的 LLM 在移动预测中的变革潜力。他们的框架指导我们设计了一种方法,能够通过精心构建的提示,在实时合成数据集中智能地填补间隔。

我们随后构建了一个基于 Python 的轨迹模拟器,该模拟器在网格上随机化移动,反映了典型的用户路径。它分配了日和时间段索引,这使得我们能够捕捉到移动的时间方面。关键的是,我们插入了标记为999, 999的合成间隔,这近似了现实世界中的数据缺失或日志缺失。接下来,我们集成了一个编排器功能,在将数据发送到 LLM(在这种情况下是 OpenAI GPT-4o 模型)之前,使用这些合成数据添加指令。编排器编写了准确反映轨迹数据集的提示,将模型的注意力集中在标记的间隔上。它采用了一种思维链流程,在生成最终 JSON 输出之前,记录缺失的点以进行调试。

我们随后通过在多处理系统中添加一个专门的移动处理程序,将此管道合并到 GenAISys 环境中。此处理程序简化了整个流程:轨迹生成、模型推理和可视化都在一个地方完成。用户可以提示系统评估缺失的坐标,并立即看到叠加在静态城市网格上的更新路径。最终,我们证明了当基于有目的的提示设计时,稳健的 GenAISys 预测不必保持抽象。

在下一章中,我们将通过一个外部服务将 GenAISys 推向世界,这将使我们能够通过增强安全性和监管功能来改进我们的系统。

问题

  1. 轨迹只能是一个城市中的物理路径。(对或错)

  2. 合成数据可以加速 GenAISys 模拟设计。(对或错)

  3. 生成式 AI 不能超越自然语言序列。(对或错)

  4. 只有 AI 专家才能运行 GenAISys。(对或错)

  5. 生成式 AI 现在可以帮助我们进行提示设计。(对或错)

  6. 轨迹模拟和预测不能帮助火灾灾害。(对或错)

  7. GenAISys 的潜力正在全速扩张,可以应用于越来越多的领域和任务。(对或错)

参考文献

  • P. Tang, C. Yang, T. Xing, X. Xu, R. Jiang, and K. Sezaki. 2024. “Instruction-Tuning Llama-3-8B Excels in City-Scale Mobility Prediction.” arXiv, October 2024. arxiv.org/abs/2410.23692.

  • 任河江,宋璇,范子培,夏天奇,陈全君,宫崎胜,以及柴崎亮祐。2018。“DeepUrbanMomentum:一种用于短期城市出行预测的在线深度学习系统。”《AAAI 会议人工智能论文集》 32,第 1 期:784–791。ojs.aaai.org/index.php/AAAI/article/view/11338

  • 风杰,李勇,张超,孙凤宁,孟凡超,郭昂,以及金德鹏。2018。“DeepMove:使用注意力循环网络预测人类出行。”《2018 年全球网页会议论文集》,法国里昂,2018 年 4 月 23 日至 27 日,1459–1468。doi.org/10.1145/3178876.3186058

进一步阅读

  • 岛田晴人,玉村直树,塩崎和幸,片山真,浦野健太,米良隆,以及川口信夫。2023。“人类出行预测挑战:使用时空 BERT 进行下一位置预测。”《第 1 届国际人类出行预测挑战研讨会论文集》,日本东京,2023 年 9 月 18 日至 21 日,第 1–6 页。dl.acm.org/doi/10.1145/3615894.3628498

免费电子书订阅

新框架、演进的架构、研究论文、生产故障——AI_Distilled 将噪音过滤成每周简报,供与 LLM 和 GenAI 系统实际操作的工程师和研究人员阅读。现在订阅,即可获得免费电子书,以及每周的洞察力,帮助您保持专注并获取信息。

packt.link/TRO5B 或扫描下面的二维码进行订阅。

Newsletter_QR_Code1

第九章:为客户服务升级 GenAISys 的数据安全和适度

在本章中,我们将通过将其与真实世界的在线服务集成来开放我们的 GenAISys——具体来说,通过将其连接到在线天气 API。这将使我们在整本书中一直支持的虚构在线旅行社能够访问实时天气数据。特定位置的天气预报是旅行社运营中各种必要任务的切入点,例如营销活动、旅游活动推荐和产品交付协调。

将我们的 GenAISys 连接到外部在线资源,使我们的系统从受控的内部环境过渡到不可预测的实时数据交互领域。然而,这种过渡引入了关键的安全问题。在没有足够保护的情况下打开系统可能会无意中暴露敏感数据或导致安全漏洞,对用户和整个组织都构成真正的风险。因此,在完全集成外部服务之前,强大的安全措施是必不可少的。因此,本章提出了三项挑战:使用 OpenWeather API 实现天气服务、利用 OpenAI 的适度能力构建适度系统,以及开发一个基于 RAG 的数据安全功能,使用 Pinecone 来检测和预防敏感主题的违规行为。我们将严重依赖现有 GenAISys 架构中灵活且强大的处理选择机制,以无缝集成这些新功能。我们的目标依然明确——最小化代码增强,最大化功能影响。

本章首先详细介绍了这些额外组件——适度、数据安全和实时天气——如何融入 GenAISys 的整体架构。然后,我们将深入探讨,利用 OpenAI 的适度端点构建适度功能。接着,我们将构建一个由 RAG 驱动的数据安全模块,使用 Pinecone 来主动检测和过滤掉敏感或不适当的内容。通过将这些两层安全措施直接集成到 GenAISys 的处理选择机制中,我们确保了对不受欢迎的交互的全面保护。

在安全措施得到巩固后,我们将实施 OpenWeather API。这种集成使我们能够检索实时天气信息,以支持一系列引人入胜、以用户为中心的任务。最后,我们将通过实际的多模式、多用户场景——例如基于天气的活动推荐、为旅游商品制作定制化的促销图片以及为旅行者动态创建个性化的天气感知信息——来展示增强型 GenAISys 的功能。到本章结束时,你将完全准备好将我们在 GenAISys 中探索的核心架构和概念应用于现实世界应用,自信地交付一个全面、安全且高度功能性的 概念验证

本章涵盖以下主题:

  • 增强 GenAISys

  • 将安全功能添加到处理程序选择机制

  • 构建天气预报组件

  • 在 GenAISys 中运行用例

让我们先明确地绘制出新审查、数据安全和天气功能如何集成到我们的 GenAISys 中。

增强 GenAISys

将审查、数据安全和实时天气功能集成到我们的 GenAISys 中将影响所有三个架构层,如图 9.1 所示。我们将依靠围绕我们的处理程序选择机制构建的框架来实现这一三级、三功能的无缝实施。

图 9.1:审查、数据安全和天气预报集成

图 9.1:审查、数据安全和天气预报集成

实施将对所有三个层次产生以下影响:

  • 层 1 (IPython 接口): 我们将在 IPython 接口的 推理 下拉菜单中引入一个新的 天气 选项。为什么放在这里?因为在现实世界的项目设置中,天气预报功能可以很容易地扩展成一个更复杂的多步骤 思维链 (CoT) 流程,从而根据天气条件生成复杂、上下文感知的输出。

  • 层 2 (AI 代理): 我们 GenAISys 的核心协调器,即处理程序选择机制,现在将管理一个额外的组件——实时天气预报能力。更重要的是,我们将为处理程序集成一个综合的审查和数据安全机制,该机制将作为一个立即的 关闭开关,一旦检测到不适当或敏感内容,将立即终止进程并向用户返回安全警告。

  • 第 3 层(功能和代理):将在这一层实现三个新的关键功能——审核、数据安全和天气预报检索。由于这些功能是必需的,因此审核和数据安全检查将位于处理程序注册表之外。如图 9.2所示,这两个功能将形成一个强制性的全局安全屏障,直接由处理程序选择机制控制,在启动任何进一步任务之前保护用户和公司数据。

图 9.2:安全和审核检查直接在处理程序选择机制中管理

图 9.2:安全和审核检查直接在处理程序选择机制中管理

此安全系统将主动拦截和评估每个用户输入,如果检测到不适当或敏感内容,将通过 IPython 接口阻止进一步处理并立即向用户发出警报。

在构建和展示 GenAISys 作为灵活的证明概念时,请务必清楚地展示其可扩展性。突出其与附加 AI 功能、进一步的安全功能或替代生成模型的集成潜力。然而,要谨慎行事:避免在没有具体项目要求的情况下提前添加功能,因为这可能导致不必要的复杂性或过度开发项目。目标是清楚地展示项目的潜力,而不在未经请求的开发上投入资源。

带着这种战略清晰度,我们将首先构建安全功能。

将安全功能添加到处理程序选择机制中

在本节中,我们将构建安全功能审核功能数据安全功能,如图 9.3所示:

图 9.3:处理程序选择机制直接调用安全功能

图 9.3:处理程序选择机制直接调用安全功能

我们将按以下方式实现这些功能:

  • 安全功能将调用审核功能

  • 安全功能还将调用数据安全功能

  • 审核功能将包含子功能

  • 数据安全功能将确保符合安全标准

让我们首先构建安全功能及其调用。

实现安全功能

安全功能直接集成到处理程序选择机制中,如图 9.4所示。它直接接收用户消息,在处理程序注册表中的任何处理程序选择之前。如果用户消息违反 GenAISys 内容策略,安全功能将向 IPython 接口返回一个 False 标志(表示内容违规)。

图 9.4:安全功能直接连接到处理程序选择机制

图 9.4:安全功能直接连接到处理程序选择机制

打开 GenAISys_Customer_Service.ipynb 并转到 GitHub 上 Chapter09 目录中的安全部分 (github.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。我们首先创建一个函数,将 securitym 标志设置为 True,表示内容不违反内容策略。在此函数中,securityd=True 表示未检测到敏感主题,消息符合数据安全标准:

def security(user_message):
  securitym=True # default value
  securityd=True # default value 

快速提示:使用AI 代码解释器快速复制功能增强您的编码体验。在下一代 Packt Reader 中打开此书。点击复制按钮

1)快速将代码复制到您的编码环境,或点击解释按钮

2)让 AI 助手为您解释代码块。

白色背景,黑色文字  AI 生成的内容可能不正确。

下一代 Packt Reader 在购买本书时免费提供。扫描二维码或访问 packtpub.com/unlock,然后使用搜索栏通过名称查找本书。请仔细核对显示的版本,以确保您获得正确的版本。

白色背景上的二维码  AI 生成的内容可能不正确。

函数开始时调用审核和内容可接受性函数:

 response=moderation(user_message)
  # Moderation
  security = is_acceptable(user_message,response)
  #print(security)  # Outputs: True if acceptable, False otherwise 
  • moderation(user_message) 调用 OpenAI 审核 API

  • is_acceptable(user_message, response) 处理审核响应

  • 在测试或故障排除期间可以取消注释调试行 (print(securitym))

接下来,安全函数调用数据安全函数,检查用户消息中的敏感主题:

 # Data security
  securityd = data_security(user_message)
  #print securityd 

securityd 变量将存储 TrueFalse,具体取决于消息是否符合数据安全标准。

函数的最后部分评估两个标志(securitymsecurityd),并根据结果返回安全状态:

 if securitym==False or securityd==False:
    return False
  else:
    return True 

如果您不想激活审核或数据安全检查,可以在安全函数中取消注释相关行——特别是 securitym=Truesecurityd=True 赋值之间的代码,以及 if securitym==Falsesecurityd==False 条件语句。这样,函数默认始终返回 True

让我们来看看处理器选择机制如何与 IPython 界面交互。

处理器选择机制交互

处理器选择机制和 IPython 界面紧密交互,如图 9.5所示。当 IPython 界面将用户消息发送到处理器选择机制时,它确定消息是否符合安全策略。

图 9.5:处理器选择机制与 IPython 交互

图 9.5:处理器选择机制与 IPython 交互

处理程序选择机制函数的主要结构在之前的章节中保持不变:

def chat_with_gpt(
    messages, user_message, files_status, active_instruct, models
):
    global memory_enabled  # Ensure memory is used if set globally 

然而,在这个函数的开始,我们现在调用安全函数。它返回一个安全状态(对于合规的返回True,对于不合规的返回False):

 try:
        if not security(user_message):
            return "Your message could not be processed as it may violate our security guidelines."d 

如果消息被标记为不合规,将立即向用户界面返回一个清晰的消息。我们将在运行安全检查部分中彻底测试安全函数示例。在那之前,让我们通过实现审查功能来继续前进。

实现审查功能

我们将使用 OpenAI Omni,它具有全面的分类选项,作为审查模型:platform.openai.com/docs/guides/moderation

打开GenAISys_Customer_Service.ipynb笔记本,并导航到安全部分内的审查子部分。审查功能将由处理程序选择机制直接调用,如图 9.6 所示。它将分类用户消息,并在处理过程中提供任何被标记为不适当内容的详细信息。

图 9.6:调用审查函数

图 9.6:调用审查函数

我们将按照以下方式使用 OpenAI Omni 实现审查功能:

from openai import OpenAI
client = OpenAI()
def moderation(user_message):
  response = client.moderations.create(
      model="omni-moderation-latest",
      input=user_message,
  )
  return response 

此函数处理用户消息并返回一个审查响应。一旦被安全函数接收,响应将被发送到另一个函数is_acceptable以评估消息是否可接受:

def is_acceptable(user_message, response):
    # Extract the 'flagged' status from the first result
    flagged = response.results[0].flagged 

响应包含response.results[0].flagged,如果内容被标记,则提供True值,如果响应可接受,则提供False状态。如果内容被标记,响应的详细信息将被保存在一个带时间戳的 JSON 文件中:

 if flagged:
        # Generate filename based on current date and time
        timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        sanitized_message = ''.join(
            e for e in user_message if e.isalnum() 
            or e in (' ', '_')
        ).strip()
        filename = \
            f"{sanitized_message[:50].replace(' ', '_')}_{timestamp}.json"

        # Ensure the 'logs' directory exists
        os.makedirs('logs', exist_ok=True)
        # Convert the response to a dictionary
        response_dict = response.model_dump()

        # Write the response to a JSON file in the 'logs' directory
        with open(os.path.join('logs', filename), 'w') as file:
            json.dump(response_dict, file, indent=4) 

最后,函数返回标记状态为not_flagged

 # Return True if content is acceptable, False otherwise
    return **not_flagged** 

如果消息被标记,详细信息将被保存在位于/logs子目录中的带时间戳的 JSON 文件中。生成的 JSON 文件包含一个唯一 ID、使用的模型以及一系列类别的状态:

{
    "id": "modr-bb021ae067c296c1985fca7ccfd9ccf9",
    "model": "omni-moderation-latest",
    "results": [
        {
            "categories": {
                "harassment": true,
                "harassment_threatening": false,
                "hate": false,
                "hate_threatening": false,
                "illicit": false,
                "illicit_violent": false,
                "self_harm": false,
                "self_harm_instructions": false,
                "self_harm_intent": false,
                "sexual": false,
                "sexual_minors": false,
                "violence": false,
                "violence_graphic": false,
                "harassment/threatening": false,
                "hate/threatening": false,
                "illicit/violent": false,
                "self-harm/intent": false,
                "self-harm/instructions": false,
                "self-harm": false,
                "sexual/minors": false,
                "violence/graphic": false
            },
            "category_applied_input_types": {
                "harassment": [
                    "text"
                ],
                "harassment_threatening": [
                    "text"
                ],… 

在这种情况下,骚扰类别已被标记,例如。文件还包含每个类别的分数,如下面文件摘录所示:

 "category_scores": {
                **"harassment"****:** **0.8075929522141405**,
                …
            },
            "flagged": true
           … 

要执行快速质量控制检查或手动评估特定用户消息,请在您的笔记本中取消以下行的注释:

# Uncomment to use as security user message evaluation
user_message="Your ideas are always foolish and contribute nothing to our discussions."
security(user_message) 

包含这些信息的文件可以根据您项目的需要使用其他功能进一步处理。我们可以将用户添加到文件中。我们还可以在笔记本的加载和显示对话历史记录部分查看对话的详细信息,以找出哪个用户输入了被标记的消息。我们将在运行安全检查部分中详细介绍这些功能。

现在让我们构建数据安全函数。

构建数据安全函数

现在我们将构建一个数据安全功能,用于检测用户消息是否包含敏感主题。此功能涵盖了广泛的与安全相关的问题,从保护机密信息到通过 GenAISys 界面防止不适当或敏感的讨论。数据安全功能包含两个组件,如图 9.7 所示:第一个组件将敏感主题填充到 Pinecone 索引中,第二个组件查询此索引以检测用户消息中的敏感主题。

图 9.7:数据安全功能的两个组件

图 9.7:数据安全功能的两个组件

填充 Pinecone 索引

我们首先将敏感主题填充到 Pinecone 索引中。打开Pinecone_Security.ipynb。这个笔记本反映了早期笔记本的结构第三章Chapter03/Pinecone_instruction_scenarios.ipynb)。我们只需将其适应此处以容纳敏感主题。如有需要,请随时回顾Pinecone_instruction_scenarios.ipynb以进行详细的复习。

我们将简要介绍针对此领域特别适配的代码部分。第一步是下载我们的sensitive_topics数据集:

download("Chapter09","sensitive_topics.csv") 

文件sensitive_topics.csv包含 100 个敏感主题,结构如下:

  • id:一个范围从10001099的唯一标识符

  • values:敏感主题的文本描述

例如,第一个主题如下:

Discussing the mismanagement of client funds that has resulted in significant financial discrepancies which have raised concerns among regulatory bodies and could lead to potential legal actions being taken against the travel agency if corrective measures are not implemented promptly and with strict accountability this issue demands immediate thorough review. 

如果用户消息包含与该主题类似的内容,例如,它将被标记。基于向量的相似性搜索比传统方法提供更细致的检测。

下一步是从sensitive_topics.csv文件中分块数据:

import time
start_time = time.time()  # Start timing
# File path
file_path = 'sensitive_topics.csv'
# Read the file, skip the header, and clean the lines
chunks = []
… 

我们然后在 Pinecone 中创建一个命名空间来存储这些敏感数据。我们将称此命名空间为security

from pinecone import ServerlessSpec
index_name = 'genai-v1'
namespace="security"
cloud = os.environ.get('PINECONE_CLOUD') or 'aws'
region = os.environ.get('PINECONE_REGION') or 'us-east-1'
spec = ServerlessSpec(cloud=cloud, region=region) 

插入更新函数保持不变,保留与.csv文件相同的列名:

def upsert_to_pinecone(batch, batch_size, namespace="security"):
    … 

现在数据已填充到 Pinecone 中,我们将继续实现查询组件。

查询 Pinecone 索引

打开GenAISys_Customer_Service.ipynb并导航到“安全”部分的“数据安全”子部分。此处的目标是确定用户消息是否与存储在 Pinecone 安全索引中的任何敏感主题匹配。如果找到匹配项,则消息将被标记。

初始时,我们设置了默认的安全指标:

# Define data security function
import datetime
def data_security(user_message):
    sec = True # Initialize to True (safe by default)
    target_id = 0
    score = None     # Initialize score
    security_level = 0.30 # Set your desired security threshold here (as a float, e.g., 0.0 to 1.0) 

默认值 sec 被设置为 True,这意味着用户消息在未发现其他情况之前是安全的。此外,target_id 被设置为 0,表示尚未在 Pinecone 索引中找到记录。此外,我们有一个安全级别阈值 security_level,在生产中可以将其设置为认为必要的值。您可以在代码中修改它,或者一旦与团队决定策略,创建一个安全接口。在这种情况下,security_level 被设置为 0.30 以避免在此教育示例中过滤低级别安全项。

我们随后定义我们的命名空间以进行查询:

 namespace = **"security"**
    print(namespace) 

我们随后查询 Pinecone 索引以检测敏感话题:

 query_text = user_message
    query_results = get_query_results(query_text, namespace) 

我们现在提取分数,我们将将其用作安全级别阈值:

# Extract score directly from query_results BEFORE calling display_results
    if (
        query_results
        and "matches" in query_results
        and query_results["matches"]
    ):
        score = query_results['matches'][0]['score']
        print(f"Extracted Score: {score}") # Optional: print to verify 

现在,我们可以显示结果:

 print("Processed query results:")
    qtext, target_id = display_results(query_results)
    print(qtext) 

如果发现类似敏感话题(通过得分超过阈值来指示),我们将启动安全逻辑流程:

# --- LOGIC FOR SECURITY CHECK ---
    # Determine 'sec' based on score first, if a score is available.
    if score is not None:
        if score > security_level:
            sec = False # Breach detected: Score is above threshold
            print(f"Security flag triggered: Score ({score}) exceeds threshold ({security_level}).")
        else:
            sec = True # No breach: Score is below or equal to threshold
            print(f"Score ({score}) is below or equal to threshold ({security_level}). Not a score-based breach.")
    else:
        # If no score is available (e.g., no match found), then use target_id as a fallback.
        if target_id is not None and int(target_id) > 0:
            sec = False # Breach detected: Target ID is positive (fallback)
            print(f"Security flag triggered: Target ID ({target_id}) is greater than 0 (fallback check).")
        else:
            sec = True # No breach detected by target_id fallback
    # --- END SECURITY CHECK  LOGIC - 

查询结果将被跟踪并记录详细信息:

 # Create a filename with the prefix "security_breach" and current datetime (format: YYYYMMDD_HHMMSS)
    if not sec: # Only log if a security breach is detected
        now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"security_breach_{now}.txt"
        # Include score and threshold in the log for context
        log_content = f"Security Breach Detected!\nUser Message: {user_message}\nMatched Text: {qtext}\nTarget ID: {target_id}\nScore: {score}\nThreshold: {security_level}"
        with open(filename, "w") as file:
            file.write(log_content)
        print(f"Security breach logged to {filename}")
    else:
        print("No security breach detected.") 

结果,True(非敏感)或 False(敏感),被返回到安全功能:

return sec 

要手动评估消息,您可以取消注释以下代码片段:

#Uncomment for security message evaluations
'''
user_message="Some client funds were mismanaged"
response=data_security(user_message)
print(response)
''' 

现在让我们运行审查和敏感数据分类的安全检查。

正在运行安全检查

我们将执行两个安全评估:一个用于审查(骚扰)和一个用于敏感数据分类。让我们首先从审查用户消息开始。

考虑一个包含骚扰内容的用户消息,如下所示:

图 9.8:骚扰信息

图 9.8:骚扰信息

审查功能检测到不适当的内容:

**User01**: Your ideas are always foolish and contribute nothing to our discussions
**Agent**: Your message could not be processed as it may violate our security guidelines. 

/logs 目录中创建包含标记消息的 JSON 文件:

/content/logs/Your_ideas_are_always_foolish_and_contribute_nothi_20250306213022.json 

该文件包含审查类别,并将用户消息标记为 骚扰

{
    "id": "modr-5ef1eeaaa3256a7c45feaa17396f11fd",
    "model": "omni-moderation-latest",
    "results": [
        {
            "categories": {
                "harassment": true, 

概率也被记录:

…
            "category_scores": {
                "harassment": 0.8054343118110135, 

现在我们有一个数据安全功能。当我们对敏感话题进行安全检查,例如提及管理不善的客户资金时,输出确认检测到敏感话题:

**User01:** Some client funds were mismanaged and used in a case of intellectual property violations.
**Agent:** Your message could not be processed as it may violate our security guidelines. 

创建包含标记消息的文件:

/content/security_breach_20250306_213240.txt 

此文件包含在 Pinecone 索引中标记消息的记录:

1063, Discussing disputes over intellectual property in travel brochure designs which have led to accusations of copyright infringement potential lawsuits and significant reputational damage to the travel agency thereby necessitating an immediate review of all creative materials and strict adherence to intellectual property laws with immediate legal consultation and review now. 

审查和敏感数据检查都创建了详细的记录。这些日志可以根据项目需求的发展进一步扩展,包括用户配置文件或附加数据。此外,GenAISys 存储完整的对话历史记录 (conversation_history.json) 和摘要,以供未来参考和审计。当我们输入 exit 时,会话历史记录被激活:

Conversation ended. Saving history...
Conversation history saved to conversation_history.json.
History saved. Proceed to the next cell. 

加载并显示会话历史记录 输出包含带有用户名和安全标志的会话日志:

**User01**:..
Your ideas are always foolish and contribute nothing to our discussions…
assistant…
Your message could not be processed as it may violate our security guidelines.
…
Some client funds were mismanaged and used in a case of intellectual property violations.
assistant…
Your message could not be processed as it may violate our security guidelines…. 

会话的原始日志被保存在 /content/conversation_history.json 中,以供进一步使用。加载并总结会话历史记录 部分包含对话的摘要,包括用户名、用户消息和助手的回复:

**List of Actions:**
1\. User01's First Message:
- Action: User01 criticized the quality of ideas in discussions.
- Assistant's Response: The message was blocked due to potential security guideline violations.
2\. User01's Second Message:
- Action: User01 reported an issue regarding the mismanagement of client funds.
- Assistant's Response: The message was again blocked for potential security guideline violations. 

在这些核心功能到位后,我们系统的审核和安全措施可以轻松调整或扩展以满足您项目的特定要求。我们现在可以继续前进,通过集成外部天气预报组件来整合。

构建天气预报组件

在本节中,我们将通过集成天气预报库和构建使用外部 API 的专用天气预报功能来谨慎地打开 GenAISys。这种集成允许我们的 GenAISys 直接与实时天气信息交互,为与外部网络服务的更受控交互提供途径。在成功实现此功能后,GenAISys 可以根据需要授权与其他网站交互。

我们将为特定位置(例如城市)实现实时天气预报,以支持市场营销、生产计划、配送和客户服务,如即将到来的 运行 GenAISys 部分所示。

打开 GenAISys_Customer_Service.ipynb 笔记本。该笔记本使用 OpenWeather API,可在 home.openweathermap.org/ 找到。OpenWeather 提供了广泛的天气预报服务,但我们将专注于适合我们用例的实时预报。

要使用 OpenWeather API,请注册账户,获取您的 API 密钥,并仔细查看他们的定价计划 openweathermap.org/price。在撰写本文时,我们示例中所需的 API 调用可在其免费层中获取,但受请求限制。请在继续之前确认费用和限制。

我们将使用处理选择机制,如图 图 9.9 所示,无缝地将我们的天气预报功能集成到 GenAISys 框架中:

图 9.9:在 GenAISys 框架中集成天气预报 API

图 9.9:在 GenAISys 框架中集成天气预报 API

一旦我们设置了 OpenWeather 环境,我们将无缝地将天气预报功能与处理选择机制框架集成:

  1. IPython 接口:在界面中添加 天气预报 选项。

  2. 处理选择机制:无变化。

  3. 处理注册表:包含一个专门的天气预报处理程序。

  4. AI 功能:开发特定的天气预报功能。

让我们先设置 OpenWeather 环境。

设置 OpenWeather 环境

GenAISys_Customer_Service.ipynb 中,转到 设置环境 部分的 天气 子部分。

首先,从 Google Secrets 下载获取您的 OpenWeather API 密钥的脚本:

download("commons","weather_setup.py") 

笔记本随后运行 API 密钥初始化函数:

google_secrets=True
if google_secrets==True:
  import weather_setup
  weather_setup.initialize_weather_api() 

然后,使用此函数初始化 API 密钥:

import requests
import os  # Make sure to import os to access environment variables
# Fetch the API key from environment variables
api_key = os.environ.get('Weather_Key')
if not api_key:
    raise ValueError("API Key is not set. Please check your initialization.") 

您也可以使用另一种方法设置 API 密钥,具体取决于您在哪个环境中运行笔记本。我们首先确保 api_key 已设置:

def weather_location(city_name):
    # Fetch the API key from environment variables
    api_key = os.environ.get('Weather_Key') 

这种双重检查不是强制性的;它只是确保如果会话因微网页中断而中断,代码仍然是健壮的。如果您的环境稳定,请随意删除冗余检查。

OpenWeather 的调用非常简单。它只需要您的 API 密钥和城市名称:

# OpenWeatherMap API URL for city name
url = f"https://api.openweathermap.org/data/2.5/weather?q={city_name}&units=metric&appid={api_key}" 

注意,metric是 OpenWeatherMap API 定义的特定关键字,表示摄氏度C,同时也提供风速为米/秒m/s)。如果您想使用美国习惯单位,将metric改为imperial&units=imperial,您将获得华氏度F和风速为英里/小时mph)。

我们现在只需发出请求并检索响应:

 # Fetch real-time weather data
    response = requests.get(url)
    weather_data = response.json() 

我们现在将提取并返回我们用例所需的实时天气信息。我们将使用当前温度、简短的天气描述和风速:

# Extract relevant data
    current_temp = weather_data['main']['temp']
    current_weather_desc = weather_data['weather'][0]['description']
    wind_speed = weather_data['wind']['speed']
    return current_temp, current_weather_desc, wind_speed 

注意,我们只提供了城市名称,没有提供国家。OpenWeatherMap API 有一个智能系统来处理不同位置具有相同名称的城市的请求。当它搜索“巴黎”时,默认选择最突出和最知名的位置,即法国巴黎。

当 API 收到仅包含城市名称的请求(q={city_name})时,它使用一个内部算法来确定最可能意图的位置。此算法优先考虑几个因素:

  • 人口:更大、人口更多的城市通常排名更高

  • 重要性:首都和主要文化或经济中心被优先考虑

  • 内部排名:OpenWeatherMap 维护自己的数据库和位置排名系统

由于法国巴黎是一个具有比德克萨斯州巴黎更大的人口和国际知名度的全球首都,API 默认选择法国首都。

由于我们正在使用主要旅游地点构建一个教育示例,例如巴黎,算法很容易默认选择法国巴黎。如果在生产中需要,您可以修改函数以包括国家和国家代码,如下例所示:

def weather_location(city_name, state_code="", country_code=""):
…
query = city_name if state_code: query += f",{state_code}" 
    if country_code: query += f",{country_code}" 

我们返回的信息足以让生成式 AI 模型解释实时天气预报并据此做出决策。有了这个,我们现在准备向 IPython 界面添加天气预报选项。

在界面中添加天气小部件

现在我们将在指令下拉列表中添加一个天气选项,如图 9.10 所示。为什么要在推理列表中添加天气预报选项?这种动机源于我们正在构建一个 GenAISys 原型。我们可以基于我们将在 GenAISys 中运行的用例想象几个 CoT 场景。然而,如果我们在与最终用户进行研讨会之前编写这些管道,他们可能会觉得系统过于僵化。

图 9.10:向 IPython 界面添加天气预报选项

图 9.10:向 IPython 界面添加天气预报选项

最佳做法是提供一些 CoT 和管道场景来展示 GenAISys 的能力,但留出灵活性,直到用户建议我们自动化他们在运行 GenAISys 时执行的某些 CoT 场景。

因此,我们将此选项添加到 IPython 界面中的instruct_selector,使其使用方式保持开放,供讨论:

# Dropdown for reasoning type
instruct_selector = Dropdown(
    options=["None", "Analysis", "Generation","Mobility","Weather"],
    value="None",
    description='Reasoning:',
    layout=Layout(width='50%')
) 

当运行预报时,用户选择天气并简单地输入一个城市名称。尽管添加城市选择器或位置自动完成可以提高用户体验,但对于这种实时用例来说,简单的文本输入更为实用,尤其是对于游客来说,通常知道他们确切的目的地名称。

这就是我们在 IPython 界面中层 1所需的所有内容。处理程序选择机制保持不变,所以我们直接进入处理程序注册表。

将处理程序添加到处理程序注册表

我们注册表中的天气处理程序只需要用户消息中的一个单词位置和在这个 OpenWeather 实现中使用的"Weather"指令:

# Weather handler: determined by the instruct flag
    (
        lambda msg, instruct, mem, models, user_message, 
            **kwargs: instruct == "Weather",
        lambda msg, instruct, mem, models, user_message, 
            **kwargs: handle_weather(
                user_message, models=models)
    ), 

为什么不使用关键词呢?使用"weather"作为关键词而不是指令,可能会在以下语境中被误认为是后续问题,如下所示:

  • 用户 1 可能会问:“巴黎的天气怎么样?”助手会回答:“20°C,晴朗,风速 5m/s”。

  • 用户 2 可能会问:“在这种天气下我能参观什么?”在这种情况下,weather可能会触发一个 API 天气调用,但由于没有提供位置,这个调用会失败。

在撰写本章时,即使 ChatGPT Plus 在提交请求之前也有选项,如下所示:

  • 在通用任务、图像的 DALL-E、推理的 o1-mini、高推理的 o3-mini、GPT-4.5 等多个模型之间进行选择

  • 一个用于激活网络搜索的按钮,另一个用于深度研究

  • 手动文件上传

这些多个交互式选择使界面灵活。然而,当我们致力于用户界面时,我们将看到许多这些选项的逐步自动化,以及包含多个旧模型功能的新生成 AI 模型。这是一场持续加速的生成 AI 进化!

我们现在将天气预报功能添加到 AI 功能库中。

将天气预报功能添加到 AI 功能

实时天气预报功能首先检查在会话期间api_key是否仍然有效。这个额外的检查确保了在我们在使用的虚拟机中会话出现微中断时,API 调用仍然稳定,不会断开连接:

def handle_weather(user_message, **kwargs):
 # Fetch the API key from environment variables
  api_key = os.environ.get('Weather_Key')
  if not api_key:
      raise ValueError("API Key is not set. Please check your initialization.") 

城市名称是用户消息;将请求天气预报;并返回温度、描述和风速:

 city_name = user_message
    current_temp, current_weather_desc, wind_speed = \
        weather_location(city_name)
    return f"Current Temperature in {city_name}: {current_temp}°C\nWeather: {current_weather_desc}\nWind Speed: {wind_speed} m/s" 

我们可以在较长的用户消息中添加关键词搜索。

在这个阶段,约束是用户消息必须只包含城市的名称。然而,根据在项目研讨会期间收集到的用户反馈,功能可以以各种方式扩展,如下所示:

  • 如果启用了天气选项,扫描用户消息以获取位置。

局限性:只需要城市的名称。

  • 有一个包含所有可能城市位置的下拉列表。

局限性:列表可能包含数百个城市。

  • 有一个国家选择列表,然后选择一个地区(或地区的行政名称),然后选择城市。

局限性:客户可能不知道地区的名称或州名。此外,这比只输入城市名称要花更长的时间。

  • 自动检测客户的位置。

局限性:查询可能是另一个城市,而不是客户所在的城市。

  • 只输入城市名称,不要输入其他内容,就像我们现在这样做的一样。

局限性:我们可能需要增强功能,以城市关键词搜索来应对用户输入的不仅仅是城市名称的情况。此外,客户可能拼错了位置名称。

如您所见,在用户层面实现实时天气预报请求有几种方法。最佳做法是首先清楚地展示系统的基本功能,然后根据从客户小组讨论中获得的反馈来调整和扩展界面。

现在我们已经将天气预报功能集成到处理选择机制框架中,我们准备在 GenAISys 中展示实际应用案例。

运行 GenAISys

在本节中,我们将使用 GenAISys 进行多用户、跨领域、多模态交互,以提供实时旅游相关服务。通常,当游客访问一个城市时,他们会在一个应用程序中查看天气预报,并在另一个应用程序中决定他们的活动。在这里,我们将这些领域合并为一个无缝体验。用户将请求实时天气预报,GenAISys 将根据当前天气条件建议合适的活动——室内、室外或两者兼有。这种集成、跨领域的做法可以扩展到建筑规划、配送调度以及几乎任何需要多个应用程序来支持用户决策的场景。

本节的主要目标是灵活地展示 GenAISys 的跨领域能力,说明系统如何适应各种特定领域的场景。具体来说,我们将关注以下方面:

  • 激活和停用天气预报功能

  • 激活和停用文件显示选项

我们的目标是展示一个清晰且实用的概念验证,在用户工作坊中自动化决策最终确定之前突出潜在的工作流程。通过不提前自动化太多场景,GenAISys 保持了灵活性,允许实际用户首先自由实验,并确定哪些功能应该自动化。记住,你引入的自动化越多,你在用户交互中保留的灵活性就越少——尽管通过仔细规划,可以在自动化和交互性之间取得平衡。

如前所述,一个有效的策略始于支持交互式、手动工作流程,然后随着用户熟悉程度和反馈的提供,逐步自动化某些或所有任务。时间不是目标;用户的成熟度是。交互式场景可以按照用户的步伐过渡到完全自动化的管道或 CoT 流程。通过让用户反馈塑造开发,采用率自然会提高。

生成式 AI 系统依赖于概率性响应,这意味着输出可能会随着每次运行而略有变化。这种随机行为确保响应保持动态,而不是僵化或重复。

在笔记本的起始部分(GenAISys_Customer_Service.ipynb),您可以选择激活或停用 DeepSeek 模型:

# DeepSeek activation deepseek=True to activate. 20 Go (estimate) GPU memory and 30-40 Go Disk Space
deepseek=False 

对于本章,deepseek设置为False,我们将依赖 OpenAI 来运行我们的用例。

在所有必要的基于天气的决策功能准备就绪后,现在让我们探索 GenAISys 中的交互式用例。

多用户、跨领域和跨模态的对话

我们将运行一个与 GenAISys 的交互式场景,模拟一个寻求特定城市实时、基于天气的建议的游客——无论天气是多云并有雨的可能还是晴朗。因此,GenAISys 必须调整其建议以适应该特定位置的实时天气预报。

以下用户之间的对话将是多用户的:

  • User01:一个期望根据天气提供建议的游客

  • User02:一个提供支持的客户服务代理

  • User03:一个协调营销、产品设计、生产、交付和客户服务的决策者

此对话中的每次交互都明确标记,表明是用户发起的请求。如果启动新的会话,它将以New Session为前缀。

界面操作将如下所示:

  • 编写和提交提示

  • 激活或停用天气预报功能

  • 激活或停用文件显示

我们可以向 GenAISys 添加许多增强功能、改进、附加功能、CoT 流程和管道,以扩展我们的系统。然而,这应该与客户/用户小组合作完成。

让我们在巴黎开始对话。

**User01**: Paris 

客户激活了天气功能并输入了巴黎,知道在这个概念验证中,这些是必须遵循的指令,如下所示:

图 9.11:请求实时天气预报

图 9.11:请求实时天气预报

GenAISys 代理提供所需的信息:

**Agent:** Current Temperature in Paris: 10.68°C
Weather: clear sky
Wind Speed: 3.09 m/s 

注意,天气响应将不断变化,因此,接下来的整个对话将采取不同的方向。不同的地点、不同的天气条件和客户的不同兴趣点将使此对话走向独特的方向。客户现在请求建议:

**User01**: What should I first visit with this weather 

推理选项设置为时,GenAI 提供个性化建议:

图 9.12:询问在这种天气下做什么活动

图 9.12:询问在这种天气下做什么活动

GenAI 根据天气建议一些吸引人的活动:

**Agent:** With clear skies and cool temperatures in Paris, it's a great opportunity to explore outdoor attractions. Here are a few suggestions:
1\. **Eiffel Tower**: Start your day with a visit to the iconic Eiffel Tower. You can enjoy the view from the ground or take an elevator ride to the top for a panoramic view of the city.
2\. **Champs-Élysées and Arc de Triomphe**: Take a stroll down the famous Champs-Élysées and visit the Arc de Triomphe. The clear weather will make for great photos and a pleasant walk.
…
4\. **Seine River Cruise**: Consider taking a Seine River cruise to see many of Paris's landmarks from the water. The clear sky will provide beautiful views of the city.
5\. **Luxembourg Gardens**: Enjoy a leisurely walk in the Luxembourg Gardens. It's a perfect spot to relax and take in the beauty of the well-maintained gardens.
Make sure to dress warmly, as the temperature is quite cool. Enjoy your visit! 

用户觉得这个回应很有用,但也想参观博物馆:

**User01**:But what if I want to only visit one outdoor site and then go to a museum? 

在不改变界面配置的情况下,代理提供定制行程:

1\. **Outdoor Site: Eiffel Tower**: Start your day with a visit to the Eiffel Tower. It's an iconic symbol of Paris and offers stunning views of the city. You can choose to admire it from the ground or take a trip to the top.
2\. **Museum: Musée d'Orsay**: After visiting the Eiffel Tower, head to the Musée d'Orsay. It's located along the Seine River and is housed in a beautiful Beaux-Arts railway station. The museum features an extensive collection of Impressionist and Post-Impressionist masterpieces by artists like Monet, Van Gogh, and Degas.
This combination allows you to enjoy both the outdoor beauty of Paris and its rich cultural heritage. Make sure to check the museum's opening hours and any ticket requirements in advance. Enjoy your day! 

现在,客户服务代理介入以增强客户的个性化体验:

**User02**: Create an engaging image of the Eiffel tower and the Musée d'Orsay museum in Paris for a tourist 

这种多用户界面可以轻松地集成到一个具有文本和图像生成、客户资料和对话历史等功能的网站中——你的想象力是唯一的限制。

在这种情况下,确保文件被勾选以显示图像,如图所示:

图 9.13:为参观创建自定义图像

图 9.13:为参观创建自定义图像

GenAISys 生成一个代表推荐定制参观的吸引人图像,如图所示:

图 9.14:为定制参观创建的自定义图像

图 9.14:为定制参观创建的自定义图像

我们的 GenAISys 可以扩展到将图像发送到游客的手机上,或者更好的是,GenAISys 可以开发成一个与 GenAISys 服务器连接的手机应用程序。

图像很棒,天气很好。满意的User02要求促销优惠:

**User02**: Create an offer with a 10% discount for a Paris Seine River Cruise 

文件未被勾选,以便 GenAI 可以制作基于文本的促销信息,如图所示:

图 9.15:为定制参观创建的自定义图像

图 9.15:为定制参观创建的自定义图像

模型生成一个吸引人的信息:

**Agent:****Exclusive Offer: 10% Discount on Paris Seine River Cruise!** 
Experience the magic of Paris from the water with our exclusive Seine River Cruise. Glide past iconic landmarks like the Eiffel Tower, Notre-Dame Cathedral, and the Louvre, all while enjoying the stunning views of the City of Light.
**Offer Details:**
- **Discount:** 10% off your Seine River Cruise ticket
- **Promo Code:** SEINE10
- **Validity:** Book by [insert date] for travel until [insert date]
**Highlights:**
- Breathtaking views of Paris's most famous attractions
- Relaxing and scenic cruise experience
- Perfect for couples, families, and solo travelers 

河流游轮优惠很棒,但现在User03提出一个前沿的想法来增强客户参与度:

**User03**: Create an image of a cool travel bag with all the outdoor locations a tourist can visit in Paris on a sunny day. Add the Eiffel Tower and the Musée du Louvre to make it complete. 

文件再次被勾选,以便代理可以生成所需图像,如图所示:

图 9.16:检查文件以显示图像

图 9.16:检查文件以显示图像

结果是这里显示的引人注目的设计:

图 9.17:定制的旅行包图像

图 9.17:定制的旅行包图像

经理立即将这个定制设计转发给一个维护旅行包库存和专用印刷设备的本地印刷合作伙伴。旅行包将在半小时内打印并送到客户的酒店——这就像订购披萨一样方便和及时!这代表了实时客户服务的未来。

为了最后的润色,经理要求发送一封吸引人的电子邮件给客户:

**User03**: Write an engaging email for the tourist that will receive this custom-printed travel bag at the hotel desk within 30 minutes! 

消息可以是应用中的通知、短信,以及/或在一个前沿的、多用户、跨领域、多模态网站上的在线对话的一部分!

在这种情况下,文件未被勾选,为 GenAI 生成文本腾出空间,如图所示:

图 9.18:取消勾选文件以发送消息

图 9.18:取消勾选文件以发送消息

如果经理希望的话,文件可以保持勾选,图像可以被处理并附加到信息中。

信息吸引人并突出了旅行社提供的卓越客户服务级别:

Dear [Tourist's Name],
Bonjour and welcome to the enchanting city of Paris!
We are thrilled to inform you that your custom-printed travel bag, designed exclusively for your Parisian adventure, is ready and waiting for you at the hotel desk. This isn't just any travel bag; it's your personal guide to the most iconic outdoor locations in the City of Light, all beautifully illustrated to inspire your journey.
….
We hope this bag not only serves as a practical companion but also as a cherished keepsake of your time in Paris. Whether you're strolling along the Seine or enjoying a café au lait at a local bistro, let this bag be your guide to unforgettable memories.
Please visit the hotel desk within the next 30 minutes to collect your bag and start your Parisian adventure in style.
…
P.S. Don't forget to share your adventures with us on social media using #ParisWith[HotelName]! We can't wait to see where your travels take you. 

在实时交付的背景下,“P.S.”信息很重要,因为它鼓励客户在社交媒体上分享他们的积极体验。这种用户生成的内容有助于品牌扩大其影响力并加强市场差异化,尤其是在几乎所有行业竞争加剧的情况下。

现在,让我们转到另一个地点,采用不同的方法。通过输入退出并重新运行笔记本的单元格来重启会话。客户服务代表将现在探索为访问东京的客户提供的选项:

New Session. **User02**: Tokyo 

在这次会话中,User02(客户服务代表),User03(经理)正在试图弄清楚向到达东京的客户建议什么。他们希望定制体验以确保他们保持竞争优势。他们首先想知道当天的天气,因此选择天气(如图 9.19 所示)并输入东京

图 9.19:文件未勾选,天气被选中

图 9.19:文件未勾选,天气被选中

GenAISys 实时返回天气信息:

**Agent:** Current Temperature in Tokyo: 9.51°C
Weather: moderate rain
Wind Speed: 10.8 m/s 

现在,User02想知道针对这种天气应该建议什么:

**User02**: What places would you suggest a tourist visit in this weather? 

天气功能已禁用(见图 9.11)。GenAI 必须分析天气然后建议活动。

图 9.20:文件未勾选,推理设置为无

图 9.20:文件未勾选,推理设置为无

代理考虑了天气因素并提出了有趣的建议:

**Agent:** In moderate rain and cooler temperatures, it's a good idea to suggest indoor activities or places where tourists can enjoy themselves without being too affected by the weather. Here are some suggestions for a tourist visiting Tokyo in such conditions:
1\. **Museums and Art Galleries**:
- **Tokyo National Museum**: Located in Ueno Park…
- **Mori Art Museum**: Situated in Roppongi Hills…
2\. **Shopping and Entertainment Complexes**:
- **Odaiba**: This man-made island has shopping malls…
- **Shibuya Scramble Square**: Offers shopping, dining, …
3\. **Aquariums and Zoos**:
- **Sumida Aquarium**: Located in…
- **Ueno Zoo**: While some parts…
… 

我们可以看到 GenAISys 以可接受的方式适应不同的场景。

现在,User02正在从响应中获得一些想法。由于天气下雨,为什么不建议巴士之旅呢?

**User02**: Ok. Write an engaging email to offer a bus tour for some of these locations to visit in one day. Don't make it too dense. Make the bus tour nice and cool. 

配置(文件未勾选,推理设置为)不会改变。GenAISys 提供了一个吸引人的巴士之旅报价:

**Agent:** Subject: Discover Tokyo's Hidden Gems with Our Exclusive Bus Tour!
Hi [Name],
Are you ready to explore Tokyo like never before? Join us for a one-of-a-kind bus tour that takes you to some of the city's most fascinating indoor attractions, perfect for a day of adventure, rain or shine!
**Tour Highlights:**
…
Our comfortable, climate-controlled bus ensures a relaxing journey between stops, with a friendly guide sharing insider tips and stories about each location. Plus, enjoy complimentary snacks and refreshments on board!
**Tour Details:**
- **Date**: [Insert Date]
- **Time**: [Insert Time]
- **Pick-up Location**: [Insert Location] 

User03介入并要求 GenAISys 为食品和饮料撰写一条吸引人的信息:

User03: Write an engaging email for the food and beverages for tourists taking a bus tour of Tokyo with some stops. Do not mention the stops at all or the locations. Just focus on the super discount prices for food and beverages. Make sure to have food with and without meat. No alcohol on the bus is allowed. Also, think of some gluten-free food. 

配置(文件未勾选,推理设置为)没有改变。GenAISys 在巴士之旅期间为食品和饮料提供了一个吸引人的报价。目的是向客户展示旅行社在细节上非常关心他们。

GenAISys 理解情况并提供了一条吸引人的信息:

**Agent:** Subject: Delicious Deals Await on Your Tokyo Bus Tour!
Dear Traveler,
Get ready to embark on a delightful culinary journey as you explore Tokyo with us! We're thrilled to offer you an array of mouth-watering food and beverage options at unbeatable prices, ensuring your taste buds are as entertained as your eyes.
**Savor the Flavors:**
- **Meaty Marvels:** …
- **Veggie Delights:** …
- **Gluten-Free Goodies:**…
**Thirst-Quenching Beverages:** Stay refreshed with our selection of non-alcoholic beverages…
**Exclusive Offer:…**
**…**
P.S. Remember, no alcohol is allowed on the bus so that you can enjoy a safe and family-friendly environment throughout your adventure! 

我们可以看到 GenAISys 具有灵活性并有效地利用生成式 AI 模型。

让我们在纽约结束我们的旅行体验。退出会话并重新运行 IPython 单元格。

User02想要预测纽约的活动:

New session. **User02**: New York 

在这个环节中,User02(客户服务代表)和User03(经理)正在为即将抵达东京的游客头脑风暴个性化的推荐。他们希望定制体验以领先竞争对手。首先,他们通过选择天气选项(图 9.21)并输入东京来查看当前天气:

图 9.21:未勾选文件且选择天气

图 9.21:未勾选文件且选择天气

代理实时提供天气信息:

**Agent:** Current Temperature in New York: 10.06°C
Weather: mist
Wind Speed: 4.12 m/s 

User02认为雾蒙蒙的天气不是带客户游览中央公园的最佳日子。GenAISys 能想出什么?

**User02**: I'm a tourist customer service agent. Considering the weather, I was thinking of suggesting an exciting activity to my tourist group. Find one activity for the morning that could be exciting. 

User02在未勾选文件且没有推理指令的情况下运行 GenAISys(图 9.22)。情况并不那么简单,因为我们希望顾客参观新地方,并可能给他们一点惊喜:

图 9.22:未勾选文件且未选择天气

图 9.22:未勾选文件且未选择天气

GenAISys 找到一个有趣的程序,可以为旅行增添文化气息:

**Agent:** Considering the misty weather in New York, a great morning activity for your tourist group could be visiting the American Museum of Natural History. It's an exciting indoor experience where they can explore fascinating exhibits, including dinosaur fossils, the Hall of Ocean Life, and the Rose Center for Earth and Space. This activity will keep them engaged and comfortable regardless of the weather outside. 

在纽约之行的最后,经理User03介入,向顾客提供纪念品 T 恤:

**User03**: The hotel was great for a tourist group in New York because the view reminded some of them of when they first came to  New York with their parents. I'm sure they would have like to receive a custom T-shirt as a souvenir to remind them of that experience. Make sure that the image you produce shows a T-shirt. 

User03决定激活全面的 GenAISys CoT 生成来分析客户反馈并制作一件漂亮的 T 恤。文件被勾选,生成被激活,如图所示:

图 9.23:勾选文件且选择生成

图 9.23:勾选文件且选择生成

我们的 GenAISys 开始逐步进行生成过程:

"The hotel was great for a tourist group in New York because the view reminded some of them of when they first came to New York with their parents.I'm sure they would have like to receive a custom T-shirt as a souvenir to remind them of that experience.Make sure that the image you produce shows a T-shirt." 

它首先对导游检测到的反馈进行记忆和情感分析:

**Agent: Process: Performing memory and sentiment analysis.**
**Memory analysis result**: Segment 1: "The hotel was great for a tourist group in New York because the view reminded some of them of when they first came to New York with their parents."
- Memory Tags: [Episodic Memory, Time Memory Past, Reality Memory]
- Dimension: Emotional
- Sentiment Score: 0.8
- Explanation: This segment references a real past event (their first visit to New York with their parents) that triggers personal, nostalgic recollections, placing it in episodic and time (past) memory while affirming its reality and positive emotional tone. 

然后它从分析的内容中提取分数:

**Process: Extracting scores from response.**
Memory analysis result: Episodic Memory sentiment 0.8
Time Memory Past sentiment 0.8
Reality Memory sentiment 0.8
Episodic Memory sentiment 0.75
Time Memory Past sentiment 0.75
Memoryless sentiment 0.5 

然后它进行统计分析,提供整体评分:

**Process: Statistical analysis**
Extracted sentiment scores: [0.8, 0.8, 0.8, 0.75, 0.75, 0.5]
Extracted sentiment scores: 0.73
Scaled rating (0–5): 3.65
Process: Creating content 

分数不是 4 或 5,因为他们想要一个纪念品,一件 T 恤,但他们还没有得到!所以,GenAISys 现在创建了一个用于图像生成的提示:

**Prompt created for image generation:** "Design a custom T-shirt featuring the iconic New York skyline or a memorable landmark like Times Square or Central Park, capturing the essence of a nostalgic and cherished tourist experience." 

GenAISys 现在为提示创建了一个图像(图 9.24):

Process: Creating an image
Image created 

图 9.24:定制 T 恤

图 9.24:定制 T 恤

GenAISys 现在为顾客创建了一条信息:

**Process: Creating a message.**
Customer message: Dear Customer,
We invite you to design a custom T-shirt that beautifully showcases the iconic New York skyline or a memorable landmark such as Times Square or Central Park. This design aims to capture the essence of a nostalgic and cherished tourist experience.
Best regards, 

对于纽约之行,经理将指示当地印刷商将定制图像打印到印刷商现场已备好的 T 恤批量上。T 恤将在一小时内生产和交付到游客的酒店。

旅行社对 GenAISys 的概念验证非常满意,现在正在准备与所有团队成员一起组织研讨会,将系统提升到下一个水平。

让我们现在总结我们的旅程——并准备好探索接下来是什么!

摘要

现代市场的加速导致了等待时间的灭绝。实时响应现在是默认的。本章探讨的使用案例表明,一个商业就绪的 GenAISys 概念验证必须能够提供即时、现实世界的服务。我们实施了一个实时旅行社场景——一旦进入项目模式,它就可以轻松地适应其他领域。

为了使我们的概念验证适合向团队、客户或投资者进行现场演示,我们首先将审查组件集成到 GenAISys 中。我们实施了 OpenAI 的 Omni 模型来检测和标记多个类别的内容政策违规。此审查功能嵌入在处理程序选择机制级别,确保在进一步处理之前标记并拒绝不适当的用户消息。为了进一步让利益相关者放心,我们添加了一个数据安全层。使用向量相似性搜索,我们构建了一个检测用户消息是否与敏感话题一致的功能。我们创建了一个专门的 Pinecone 命名空间来存储这些话题,并针对每个传入的用户消息进行查询。如果找到匹配项,系统将标记内容,显示警告,并拒绝请求。

所有标记的审查和安全违规都记录在单独的文件中,完整的对话历史可以追溯到单个用户。有了这些基本的安全保障,我们继续实施实时天气预报功能,使用 OpenWeather—紧密集成到 GenAISys 中以进行天气感知决策。最后,我们走过了完整的 GenAISys 对话,展示了系统支持实时、多用户、跨领域、多模态交互的能力——这是生成式 AI 在生产环境中所能实现的有力证明。

下一步是什么?展示你的 GenAISys 概念验证以获得扩展和扩展系统所需的资源。但这样的展示必须精心制作——这正是我们将在下一章中关注的。

问题

  1. 可以通过向量相似性搜索检测敏感话题。(对或错)

  2. 包含 GenAISys 中敏感话题的标记用户消息不会停止对话。(对或错)

  3. OpenAI 的审查工具只为粗俗语言提供了一个类别。(对或错)

  4. 包含违反 GenAISys 内容政策内容的标记用户消息不会停止对话。(对或错)

  5. 实时天气预报以自动建议活动可以给公司带来竞争优势。(对或错)

  6. 多用户、跨领域、多模态的 GenAISys 是应用的未来。(对或错)

  7. 多用户、跨领域、多模态的应用程序还不存在。(对或错)

  8. 将 GenAISys 添加到应用中将显著提高生产力和吸引用户。(对或错)

  9. GenAISys 应该与客户小组一起开发。(对或错)

参考文献

进一步阅读

|

现在解锁这本书的独家优惠

扫描此二维码或访问 packtpub.com/unlock,然后通过书名搜索这本书。 | 白色背景上的二维码 AI 生成的内容可能不正确 |

注意:在开始之前,请准备好您的购买发票。

第十章:展示你的商业就绪生成式 AI 系统

仅创建一个创新的 GenAISys 并不能为我们带来客户、资金,甚至可能连认可都不会有。在今天这个竞争激烈的环境中,成百上千的 AI 解决方案、智能体系统和类似产品同时争夺市场的关注。企业、投资者和最终用户面临着来自行业巨头(如谷歌云、微软 Azure、亚马逊网络服务AWS)和 IBM)以及不断扩大的初创公司和中等规模公司的压倒性选择。这让我们处于何种境地,我们应该怎么做?

要穿透市场日益厚重的壁垒,我们需要两样东西:实施盈利性。到目前为止,在这本书中,我们已经证明了我们能够交付一个有效的 GenAISys,它能够支持供应链中的核心业务功能——从营销和生产到交付和客户服务。但现在,我们必须将我们的技术成就转化为一个引人入胜的故事,以便有效地向利益相关者传达和销售我们的想法——无论是内部团队、雇主、潜在客户还是投资者。为了成功展示我们的 GenAISys,我们需要一个精心设计的演示场景,突出我们的现有能力,并清楚地传达我们进一步创新和扩展的能力。决定何时暂停开发并过渡到展示概念验证至关重要。

在本章中,描述的方法只是众多成功展示 GenAISys 的方法之一,尤其是在激烈的 AI 竞争中。我们将专注于直截了当。鉴于当今 AI 知情受众的注意力有限,吸引观众的注意力将是一项挑战。因此,本章将专注于我们 GenAISys 展示的前七分钟。我们将从本书中开发的基于 IPython 的界面顺利过渡到一个灵活、易于适应的前端网页。这种策略使我们能够快速定制我们的演示,以满足特定的项目需求,并得到我们工作原型 GenAISys 的信誉支持。我们将系统地介绍关键组件:核心功能、向量存储集成、关键性能指标KPIs)、外部数据库连接以及安全和隐私的关键方面。此外,我们将强调系统如何通过利益相关者研讨会进行协作定制。

最后,为了展示我们框架的终极灵活性和未来潜力,我们将介绍我们 GenAISys 的预期进化:一个基于群体的多智能体系统MAS),展示了人机协作的强大新范式。到本章结束时,你将了解如何将实际的 GenAISys 功能与可以添加到系统中的潜在进化相结合。

本章涵盖了以下主题:

  • 设计 GenAISys 的展示

  • 构建灵活的前端网页界面

  • 展示基本 GenAISys 功能

  • 展示在集成、安全和定制方面的可能演变

  • 介绍一个多智能体系统(MAS)

让我们从精心设计 GenAISys 的展示开始。

设计 GenAISys 的展示

设计本书中构建的教育 GenAISys 展示不仅超越了技术维度。无论您的受众是内部团队、投资者还是客户,您的 GenAISys 的成功在很大程度上将取决于清楚地传达其 商业价值

一个强大的 GenAISys 展示必须从一个引人入胜的介绍开始,尤其是在最初的几分钟内,如图 图 10.1 所示:

图 10.1:快速通道展示

图 10.1:快速通道展示

指示的时间(以分钟计)是灵活的,可以根据您的需求进行调整。然而,现代观众期望简洁、有影响力和有效的展示。通过清楚地展示专业性和效率来保持观众的参与度。为了简单起见,我们将把任何受众——您的内部团队、投资者或客户——称为 客户

客户期望以下时间表:

  • 第 1 分钟 - 展示您的团队和您自己:简要介绍您的团队和您自己。突出您的优势,然后在他们感到无聊之前开始展示。这个介绍的时间长度由您决定,但不要做得太过分。

  • 第 2 分钟 - 使用有说服力的 KPI 解释用例:确保您展示的用例是盈利的,无论是市场营销增长、生产资源优化、减少交付时间、更好的客户服务以增加销售额,还是任何其他活动助推器。简要介绍项目的生成式 AI 基础。然后,快速解释如果需要,KPI 可以添加到界面并实时显示,如下所示:

图 10.2:实时 KPI

图 10.2:实时 KPI

  • 第 3 分钟 - 开始展示前端 GenAISys 界面:无论您多么努力工作,总会有所遗漏。此外,我们构建的 GenAISys 需要使用 PowerPoint 展示和前端网页进行更高层次的解释,这些内容我们将从本章的 构建灵活的 HTML 界面 部分开始准备。HTML 页面包含了我们在 GenAISys 中构建的功能,并在此基础上加入了我们需要用于展示的想法以及客户想要的想法。展示您能够快速适应灵活的 HTML 页面以满足客户需求,并在研讨会中进行互动,正如我们将在 6. 定制化 部分中看到的。

  • 第 5 分钟 – 在展示灵活界面时开始展示 AI 功能:继续合作完成 GenAISys 界面和集成的概念,采用以人为中心的协作式 AI 方法。强调 GenAISys 中集成的下一代技术的独特融合,如 OpenAI、DeepSeek 和 Pinecone。尽可能使演示以人为中心,展示目标是利用你构建的多用户 GenAISys 的力量,以 AI 作为副驾驶而非替代品来提高性能。尽可能多地记住这一点,传达一种协作精神,这将有助于建立对你系统的信任。你可以开始展示这本书中构建的教育型 GenAISys 的一些功能。如果你进一步适应了用例,你也可以展示更多。

  • 第 7 分钟 – 在网页界面和 GenAISys 功能之间交替操作:现在,是时候展示你的 GenAISys 如何通过结合实施和盈利能力来提供高效服务了。在网页界面和你构建的 GenAISys 之间进行导航。用 GenAISys 组件展示你的专业知识。通过一个可以快速适应客户需求的网页界面,展示你的灵活性和创造力。

通过这样精心构建你的演示,你展示了明确的专家知识和实际灵活性。你已经为有说服力地展示你商业就绪的 GenAISys 做好了准备。

接下来,让我们构建灵活的网页界面,为无缝引导你的观众通过完全集成且用户友好的 GenAISys 打下基础。

构建灵活的 HTML 界面

演示网页界面需要灵活且可适应。在某些情况下,我们甚至可能需要在咖啡休息时现场调整代码!客户可能会坚持添加标志、更改字体或更改颜色。如果我们拒绝,这可能会成为绊脚石,给整个演示投下阴影!在这个生成式 AI 意识客户的新时代,我们需要在适应性和稳定性之间走一条细线。因此,在本节中,我们将首先构建一个具有 GenAISys 核心功能的界面,同时考虑到灵活性。如果客户坚持立即看到修改,你可以将网页页面在 HTML 编辑器中打开并实时刷新。记住,每个人都可以访问 AI 副驾驶,并且可以实时超越我们。我们需要比竞争更快,这也可能是最终用户。

目标是表明 IPython 原型界面与底层 AI 编排函数无关。因此,它可以适应任何必要于项目的环境。在这种情况下,我们选择展示一个在专用服务器上的网页看起来会是什么样子。让我们开始,通过在 GitHub 的 Chapter10 目录中打开GenAISys_Presentation.ipynbgithub.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/tree/main)。

首先,我们下载演示所需的辅助脚本和网页:

!curl -L https://raw.githubusercontent.com/Denis2054/Building-Business-Ready-Generative-AI-Systems/master/commons/grequests.py --output grequests.py
from grequests import download
download("Chapter10","01.html")
download("Chapter10","02.html")
download("Chapter10","03.html")
download("Chapter10","04.html")
download("Chapter10","05.html")
download("Chapter10","06.html") 

然后,我们定义一个可重用的 Python 函数,以便在笔记本中方便地加载和显示 HTML 界面:

from IPython.display import HTML, display
def display_interface(filename):
    with open(filename, "r", encoding="utf-8") as file:
        html_content = file.read()
    display(HTML(html_content)) 

在本节中,我们将仔细分析01.html的代码。目标是确保您清楚地理解界面的结构和逻辑。这种清晰度对于在演示过程中迅速响应潜在客户请求至关重要。

代码从标准的<head>部分开始,其中包含元数据(如<meta charset="UTF-8"><title>)。CSS,视觉样式,嵌入在``标签中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Generative AI Chat Interface</title>
  
    body {
      font-family: Arial, sans-serif;
      margin: 20px;
      background: #f4f4f4;
    }
….
  
</head> 

<head><body>部分可以根据项目的特定品牌和设计指南进行完全定制。在这种情况下,<body>容器将包裹所有内容并应用我们刚刚定义的 CSS 布局样式:

<body>
  <div class="container"> 

标题栏不包含“生成式 AI 系统”这一术语。在这种情况下,选择提供一个更广泛的受众可以相关联的术语:

<h1>Generative AI Chat Interface</h1> 

用户选择块包含我们在整本书中一直在使用的三个通用用户名。它提供了灵活性,可以根据项目的具体规格适应任何关于他们是谁的问题。您可以选择根据演示的上下文提供特定领域的名称。您也可以添加更多用户。目前,让我们保持简单:

<div class="form-group">
  <label for="userSelector">User:</label>
  <select id="userSelector">
    <option>User01</option>
    <option>User02</option>
    <option>User03</option>
  </select>
</div> 

用户输入信息区域包含标准信息。我们可以根据行业或任务对其进行修改。它甚至可能因用户而异,具有特定领域,例如“在此处输入客户的评价。”在这种情况下,我们将显示我们一直在使用的消息来构建我们的 GenAISys:

<div class="form-group">
  <label for="messageInput">Your Message:</label>
  <textarea id="messageInput" placeholder="Type your message here or type 'exit' or 'quit' to end the conversation." rows="4"></textarea>
</div> 

然后实现了一个标准的发送按钮,但请记住,在您的演示过程中,它可以根据特定的品牌要求进行视觉定制:

<div class="form-group">
  <button id="sendButton">Send</button>
</div> 

现在让我们添加复选框选项/小部件,以便 AI 代理启用语音或激活文件管理:

<div class="checkbox-group">
  <label>
    <input type="checkbox" id="agentCheckbox" checked>
    Agent
  </label>
  <label>
    <input type="checkbox" id="voiceCheckbox">
    Voice Output
  </label>
  <label>
    <input type="checkbox" id="filesCheckbox">
    Files
  </label>
</div> 

研究代码,无论其设计如何,以便在显示某物时情况变得紧张时能够实时修改。这将表明您具有灵活性,可以轻松适应客户需求。这可能很棘手,但可能是必要的。只需确保仅在客户坚持修改时才进行修改,以避免承担不必要的风险。

推理下拉菜单突显了我们 GenAISys 中强大的推理能力,正如前几章所实现的那样。你可以轻松调整或添加推理选项以匹配你的项目规格:

<div class="form-group">
  <label for="reasoningSelector">Reasoning:</label>
  <select id="reasoningSelector">
    <option value="None" selected>None</option>
    <option value="Analysis">Analysis</option>
    <option value="Generation">Generation</option>
    <option value="Mobility">Mobility</option>
  </select>
</div> 

模型选择块包含战略信息。客户想知道模型是否安全且开源,或者它来自哪个国家。我们可以添加其他模型或解释我们如何通过下拉列表的灵活性添加更多模型:

<div class="form-group">
  <label for="modelSelector">Model:</label>
  <select id="modelSelector">
    <option value="OpenAI" selected>OpenAI</option>
    <option value="DeepSeek">DeepSeek</option>
  </select>
</div> 

最后,输出区域是一个标准化的部分,用于清晰地显示对话响应:

<div class="output-area">
  <p><em>Conversation output will appear here...</em></p>
</div> 

现在,我们已经准备好编写结束标签并打开文件:

 </div>
</body>
</html> 

01.html文件是用基本文本编辑器创建的,上传到我们的 GitHub 仓库,然后由我们的笔记本自动下载。你可以在浏览器或演示环境中直接打开该文件。在这种情况下,我们现在将在笔记本中打开它。

是否使用 HTML 进行演示的选择权在你。对于这个特定的策略,PowerPoint 演示可能过于静态,而直接运行 Python 代码可能会让高层管理人员分心,无法理解核心概念。HTML 页面提供了一个有效的平衡点——比静态幻灯片更动态,但比实时代码更清晰、更灵活。

然而,我建议你将注意力集中在信息本身,而不是媒介上。清晰地阐述以人为本和自动化的收益,这将把你的观众带到下一个层次。

现在,让我们概述我们将遵循的七个步骤路线图,以在接下来的章节中更深入地探讨每个组件之前,有效地展示我们的 GenAISys:

  1. 展示核心 GenAISys,专注于 GenAISys 的实用功能。不要陷入 Python、CSS、HTML 或其他低级技术术语中。只有一个目标:向观众展示这个界面如何帮助他们构建以人为本、下一代 GenAISys。

  2. 展示向量存储以展示一个组织的数据可以以创新的方式安全存储。要传达的概念是数据不是静态的,存储在单一位置,而是动态的。我们可以直接访问数据,就像我们汽车中的 GPS 一样。

  3. 以人为中心的 KPI 方法以展示尽管我们可以自动化许多任务,但以人为中心系统可以成为一个利润中心。如果人类有实时的 KPI 来证明生产力的实时增长,那么一个强大的人机协作团队将把公司带到下一个层次。

  4. 整合平台和框架可以是一个选择。这将由公司来决定。我们展示了我们从头开始构建 GenAISys 的专业技能。因此,我们对于部署任何 GenAISys 所需的复杂功能,无论是通过平台还是其他方式,都是宝贵的资产。我们还将展示我们能够整合强大的 MASs 来提高公司的生产力。

  5. 安全和隐私是项目的关键组成部分。我们将展示我们能够根据市场上现有的最佳实践和法规在这个领域实施标准做法。

  6. 定制是我们的品牌形象!我们已经展示了从零开始构建尖端 GenAISys 的能力。因此,我们能够定制所需的任何 AI 功能。

  7. GenAISys 资源(RACI)是我们的实际接触点。我们知道构建 GenAISys 有多困难。我们认识到从模型到系统的过渡是一个复杂的过程。我们认识到一对一、用户到副驾驶的体验本身是不够的。我们有一个一对多的愿景,一个可以扩展到用户组的架构,这需要仔细的资源规划。

在这个路线图确定之后,让我们首先介绍核心的 GenAISys。

1. 展示核心 GenAISys

导航到笔记本中的1. 生成式 AI 聊天界面部分,并运行以下单元格以显示01.html页面:

display_interface("/content/01.html") 

这个输出与我们在本书中精心开发的 IPython 界面完全一致。然而,通过将其显示为网页,我们强调我们的 GenAISys 界面是平台无关的——它可以在任何地方托管,嵌入到演示中,或通过网页浏览器访问,如图图 10.3所示:

图 10.3:生成式 AI 聊天界面

图 10.3:生成式 AI 聊天界面

您在演示中提供的描述需要用户友好且直观。您必须根据观众调整您的技术术语水平。从清晰的术语开始,然后在必要时扩展,以提供更多技术或更直接的解释。我们解释的灵活性必须与我们所构建的 GenAISys 的灵活性相匹配。

以下是一些应对观众可能提出的大量问题和我们必须解决的问题的方法。技术细节已在本书中描述。这里的想法是让您准备好回答棘手的问题。让我们逐一分析每个组件:

  • 生成式 AI 聊天界面:这个术语很直观。客户可以选择任何适合项目需求的术语。

  • 用户:解释说您的 GenAISys 具有多用户功能。我们可以限制用户数量到一个人或扩展到n个用户。每个用户都可以有一个特定的名字,例如“John Doe”,一个角色,例如“营销”,或任何其他用户名,具体取决于项目。在这种情况下,用户是从列表中选择的:

图 10.4:手动或自动用户选择

图 10.4:手动或自动用户选择

  • 您的信息:我们需要解释用户信息可以包含客户决定的关键词。因此,这些信息将触发 AI 行为,如文本生成、图像生成、推理(思维链,或CoT)和高级文本分析。在此阶段,我们可以参考我们希望展示的用例。根据演示的范围,您可以决定是否深入探讨(切换到 Google Colab 笔记本或您的本地安装)并展示您的用例。别忘了解释完整对话可以被保存和总结。

  • 代理、语音输出和文件复选框:我们可以解释这些选项,并决定是否深入探讨,这取决于客户兴趣。如果它们在客户寻找的项目范围内,您还可以提出创新的想法。

  • 推理:推理代理将展示您的 GenAISys 有多有效。确保描述图 10.5中的选项,以展示 GenAISys 在神经科学文本分析、CoT 生成或通用移动功能方面的强大能力。简要解释本书中讨论的 CoT 方法。如果被要求,可以使用 Google Pro 或您的本地安装(个人电脑或服务器)进行详细说明。

图 10.5:选择推理函数

图 10.5:选择推理函数

  • 模型:如图图 10.6所示,模型的选择完美地说明了系统的灵活性。客户可以选择使用 API 或本地安装的开源模型。解释说,如果需要,GenAISys 可以支持其他模型。

图 10.6:选择生成式 AI 模型

图 10.6:选择生成式 AI 模型

  • 输出区域:我们可以解释输出生成文本和图像。如果需要,我们可以决定是否展示一个示例。

我们可以通过解释 GenAISys 界面只是前端来得出结论。GenAISys 的概念验证是一个复杂、可扩展和安全的结构。该界面提供了一个无缝、多用户、高性能的系统,允许全球范围内的交互。还解释说,这个概念验证可以无缝部署到云服务,如 AWS、Microsoft Azure、IBM Cloud 或 Google Cloud。在此阶段,我们可以深入了解本书中开发的功能及其针对特定用例的适配。

2. 展示向量存储

向量存储是您构建的 GenAISys 的一个重要组成部分。首先,解释 Pinecone 已被实现,但如果需要,您可以实现另一个向量存储。然后,演示如何通过前端界面上的视觉元素通知用户 Pinecone 索引的状态。

首先,将 01.html 复制到一个名为 02.html 的新文件中,以保持界面初始展示的状态。为什么?一个完全填充的 Web 界面可能会使您的听众感到困惑,但逐步的方法可以确保您不会在过程中失去任何人。此外,也许客户可能不想看到 Pinecone 连接。或者,客户可能不想进一步操作并使用 01.html 开始项目。我们必须保持灵活和适应,以应对所有这些情况。

02.html 中,首先添加一个清晰的 Pinecone 连接指示器:

<div class="container">
  <h1>Generative AI Chat Interface</h1>
  <!-- Pinecone Connection Status -->
  <div id="pineconeStatus" style="text-align: center; margin-bottom: 10px;">
    <span style="color: green;">&#9679;</span> Connected to Pinecone Index
  </div>
  <!-- Existing form elements -->
  ...
</div> 

客户也可能希望在增强生成式 AI 模型的输入之前审查 Pinecone 检索。在这种情况下,我们可以添加一个新部分:

<div class="output-area">
  <p><em>Conversation output will appear here...</em></p>
</div>
<div id="pineconeResults" style="background: #fff; padding: 10px; border: 1px solid #ccc; margin-top: 10px;">
  <h3>Context Retrieved from Pinecone</h3>
  <p><em>No results yet.</em></p>
</div> 

然后,我们可以运行单元格以显示界面:

display_interface("/content/02.html") 

界面现在包含我们可以应用的可能的增强,如下所示:

图 10.7:使用 Pinecone 功能增强界面

图 10.7:使用 Pinecone 功能增强界面

要介绍 Pinecone,我们可以进一步深入,通过访问我们的 Pinecone 控制台来展示向量存储的结构,控制台地址为 www.pinecone.io/。您可以在展示笔记本的 Chapter03/Pinecone_RAG.ipynb 版本的同时,总结 第三章 中涵盖的内容,并使用以下清单之类的检查清单:

  • Pinecone 安装

  • OpenAI 安装

  • 分块

  • 嵌入

  • Upserting

  • 查询

然而,在深入到笔记本之前,确保您的听众理解向量和向量存储的含义。否则,只需简单地解释向量存储提供了一种高效的数据检索方式,并增强生成式 AI 输入以获得更好的结果。

您还可以运行任何其他查询 Pinecone 索引或您构建的笔记本。请注意,本书中的笔记本是教育性的,因此您可能希望在此基础上构建自己的笔记本以用于演示。现在让我们在以人为中心的环境中介绍 KPIs。

3. 以人为中心的方法对待关键绩效指标(KPIs)

将 GenAISys 的实现以人为中心仍然是部署 AI 的最佳方式。一开始,以人为中心的方法似乎有些反直觉。为什么不直接替换员工?为什么不裁员所有可以被替换的人?为什么不通过解雇员工获得大量现金?毕竟,为什么不大幅减少劳动力,因为 GenAISys 可以节省大量时间和金钱?为什么不简单地投资并快速获得投资回报率?通过裁员或“替换”的简单、反直觉的 ROI 情景 1 将如下所示:

事实上,某些公司已经采取了大规模裁员,选择依赖 AI。他们甚至可能看起来很成功。然而,在跟随这条道路之前,考虑一下我的个人经验和观点,然后选择您希望如何继续前进。让我们通过我的增长投资回报率(ROI)愿景来探讨。

通过增长实现投资回报率(ROI)

图 10.8展示了基于过去几十年真实人工智能项目的 AI 实施和政策愿景。它通过 GenAISys 神经科学营销增加销售额来表示投资回报率,通过生成式 AI(包括 CoT)缩短从生产到交付的时间,以及通过 GenAISys 提升销售额。

图 10.8:通过增长进化

图 10.8:通过增长进化

这怎么可能呢?我是一个理想主义者吗?让我用一个我为一个超过 100,000+平方米的巨型仓库中的配送中心实施的真实人工智能项目来解释这个问题,这个仓库大约有 1.076+百万平方英尺。该项目是一个从头开始的混合人工智能和高级数学项目:

  • 人工智能位置优化器通过计算从生产地点(A)到配送中心(B)再到当地客户(C),例如超市和大型商店的数千次配送的质心,确定了仓库应该建在哪个位置,如图图 10.9所示:

图 10.9:大型仓库人工智能驱动优化

图 10.9:大型仓库人工智能驱动优化

  • 内部仓库人工智能代理优化了仓库的设计,包括码头和区域数量。

  • 然后,人工智能仓库代理优化了从码头到存储位置(从 A)以及从存储到码头用于交付(C)的流程。

  • 关键问题是大量未计划事件的消息数量,例如晚到的卡车(由于交通或天气)和有缺陷的产品。一个 GenAISys,例如我们在本书中构建并适应此用例的 GenAISys,可以在一定程度上自动化这些消息。

那为什么不替换那些 24/7 工作以自动解决这些问题的许多规划者呢?每个人都首先认为这是可能的。我发现这在一定程度上是可行的。然而,我很快发现规划者考虑的许多参数是不可预测的。生成式 AI,甚至基于规则的系统,在检测模式方面表现出色,但在没有模式时却不知所措!它们在遇到前所未有的、非重复的场景时会遇到很大的困难。

考虑这个实际的仓库场景:货柜#100234 上缺少标签,而另一个货柜包含有缺陷的产品(#343445)。同时,一个自动导引车AGV)无法解释地比平时运行得慢。位于 94 号码头的卡车必须立即出发,因为周六晚上快到 11 点了,而卡车在周日不能使用高速公路。任何延误现在都可能导致严重的罚款和客户不满。

我发现许多类似的问题每天都在发生。所以,是的,一个具有强大数学功能的混合型 GenAISys 可以自动化许多决策过程。而且,是的,这在大仓库中一年内代表了许多毛利润。但是,关于 AI 无法解决的未解决问题怎么办?记住,在分销供应链中,延迟交货会带来严厉的罚款,甚至可能失去客户信任,导致许多合同的损失。

在那个时刻,我全天候工作在另一种方法上。让我们保留人员,特别是规划人员,即使整体上提高生产力需要更少的仓库人员。为什么和怎么做?我设计了一个包含一个 KPI(就像我们将在本节中添加的那样)的界面,以及一个 AI 代理和一名人类专家。图 10.10展示了专家如何实时可视化 KPI。每次专家运行 AI 系统并完成决策,考虑到复杂的不计划事件,系统都会显示节省了多少资金,例如不需要使用第二辆卡车,调整订单以优化人员,以及有额外的时间来修复错误。

图 10.10:以人为中心的 GenAISys 协作

图 10.10:以人为中心的 GenAISys 协作

因此,专家规划人员提高了进出存储事件的效率。仓库可以处理更多的单位,而无需建造额外的码头,购买新的 AGV 或雇佣更多人力。生产力的提升为超级仓库带来了 3%的毛利润增长。在仓库管理中,毛利润的显著增长产生了可观的利润。

您可以使用您希望的参数设计 ROI 比率,但核心概念是协作的人机增长非常高效。通过增长产生的 ROI,在以人为中心的系统中比裁员产生了更多的利润:

图片

这个成功的项目对我的声誉和销售产生了巨大影响:

  • 传言说 Rothman 是道德的,他的 AI 系统是可以信赖的。

  • 以人为中心的成功建立了一个 AI 项目形象,这将团结团队,而不是摧毁它们。

  • 人工智能专业知识可以 24/7 工作,帮助团队提升绩效,从而产生增长并获得奖金!

最终,在激进裁员和战略增长之间的选择权在你手中。这个例子只是简单地反映了我个人的方法和经验。无论如何,如果客户需要实时 KPI,让我们将其添加到界面中。

将实时 KPI 添加到 GenAISys 网络界面

如果您的客户感兴趣,以下是我们将如何将实时 KPI 实现到现有网络界面中的方法,强调以人为中心的做法:

  1. 将上一个界面文件(02.html)复制到一个新版本(03.html)中,以保留之前的界面状态。然后,添加 KPI 面板:

     <!-- Gross Margin KPI Panel -->
       <div class="kpi-panel" id="grossMarginKPI">
         <h2>Gross Margin</h2>
         <div class="kpi-value" id="grossMarginValue">Loading...</div>
       </div> 
    
  2. 然后,我们将添加 CSS 样式:

     .kpi-panel {
         background: #fff;
         padding: 15px;
         margin: 20px auto;
         border: 1px solid #ccc;
         border-radius: 5px;
         text-align: center;
         box-shadow: 0 2px 4px rgba(0,0,0,0.1);
         max-width: 300px;
       }
       .kpi-panel h2 {
         margin-bottom: 10px;
         font-size: 20px;
       }
       .kpi-value {
         font-size: 36px;
         font-weight: bold;
         color: #007bff;
       } 
    
  3. 最后,我们将添加 JavaScript 的实时更新模拟,以展示如果在实际情况下实施,KPI 将会是什么样子:

     // Example function to update the KPI
       function updateGrossMargin() {
         // Replace this with your real-time data-fetching logic
         const grossMargin = fetchGrossMarginFromBackend(); // your API call here
         document.getElementById('grossMarginValue').textContent = `$${grossMargin.toFixed(2)}`;
       }
       // Simulate real-time update every 5 seconds
       setInterval(updateGrossMargin, 5000); 
    

现在运行显示笔记本中第 3KPI 部分的 03.html 单元格:

display_interface("/content/03.html") 

这个模拟显示了毛利润关键绩效指标(KPI)的实时更新,从视觉上强化了人类规划师为 GenAISys 实施带来的价值:

图 10.11:人类与 KPI 的关系

图 10.11:人类与 KPI 的关系

客户可能希望删除此功能或增强它以适应他们的项目。我们的角色是适应项目需求,无论所需的自动化程度如何。我们现在将展示我们的 GenAISys 在客户环境中的集成。

4. 集成:平台和框架

集成通常是部署 GenAISys 最具挑战性的阶段之一,尤其是在选择平台、操作系统和框架时。虽然初创公司或内部项目最初可能享有自由选择平台的奢侈,但现实场景往往涉及来自投资者、客户或内部政策的严格限制。以下例子是从现实情况中抽取的,用以说明您可能面临的潜在挑战:

  • “我们公司只与带有 ISO 和原生安全性的 Windows Server 合作。我们不会接受您的 Ubuntu 服务。这不容讨论。这是我们的政策。” (www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2025)

  • “我们公司只使用 Ubuntu Server。我们不会接受任何 Windows 应用程序。这不容讨论。这是我们的政策。” (ubuntu.com/download/server)

  • “作为投资者,我们需要确保您的 GenAISys 符合 AWS 安全和隐私标准,这些标准通过数据隐私框架DPF)遵守美国-欧洲法规。我们不在乎您安装的第三方组件。要么您使用 AWS 的框架,要么我们不会投资。” (aws.amazon.com/compliance/eu-us-data-privacy-framework/)

  • “你在开玩笑吗?你真的认为我们会让你们的 GenAISys 进入我们的网络吗?不可能。所以,别再考虑你展示的安全和隐私组件了,包括 AWS 的框架。你在一个高度安全的空间站。我们将在一个完全无法访问网络的隔离虚拟机上安装你们的 GenAISys,而不是你们。只有认证用户才能访问它。我们的安全部门 24/7 实时监控这些连接。任何试图写入未经授权的提示都将被过滤,并在到达你们的系统之前伴随一个高安全警报。我们不会告诉你更多。我们只会给你一个提示。我们的策略之一是 IBM 的入侵检测和预防系统IDPSs)。” (www.ibm.com/docs/en/snips/4.6.0?topic=introducing-security-network-intrusion-prevention-system-ips-productn)

  • “我们与谷歌云合作已有多年,并且只接受符合我们托管、安全和隐私框架的系统。” (cloud.google.com/)

  • “我们的一切都只使用 Microsoft Azure:托管、AI、安全和隐私。假设你们有一个创新的 GenAISys。它将如何适应我们的框架?” (azure.microsoft.com/en-us/)

可能的托管平台、安全和隐私框架清单是无限的!你们的 GenAISys 概念验证必须保持灵活。正是这种灵活性使得我们构建的前端 HTML 页面能够快速适应特定的客户需求——而不需要在后端进行深度修改。然后,你们可以使用这本书中构建的教育组件以及你们添加的专业特定演示准备来满足客户的要求。

但集成并不止于此!可能会出现一些创造性和意外的请求。潜在客户可能会问你以下两个问题:

  • “我们真的很喜欢你们的 GenAISys!多用户功能太棒了,尤其是它支持激活或停用 AI 代理!太好了!如果你们能让它与 Zoom API 兼容,我们会立即购买你们的系统。那将太棒了!你们需要多长时间才能将 GenAISys 与 Zoom 集成?” (developers.zoom.us/docs/api/)

  • “我们超级喜欢你们的 Zoom 集成!太棒了!但我们的公司政策是只使用 Microsoft Teams。你们需要多长时间才能将 GenAISys 与 Teams 集成?” (learn.microsoft.com/en-us/graph/api/resources/teams-api-overview?view=graph-rest-1.0)

一旦你解决了这些挑战,可能会出现围绕企业级 ERP(如 SAP 或 Oracle)、特定数据库解决方案或甚至认证以验证你的 GenAISys 的合规性和安全措施的需求。为此,我说,欢迎来到现实世界!你必须坚持一个基本原则:无论你如何发展你的 GenAISys,潜在的客户通常会要求更多或以不同的方式实施你的系统。你的 GenAISys 提供了合法性。除此之外,保持灵活的专业性!

让我们现在展示我们适应任何情况的意愿。复制03.html并将其命名为04.html以保持界面之前的步骤不变。将此部分添加到 HTML 前端页面:

 <!-- ERP Integration Dropdown -->
    <div class="form-group">
      <label for="erpIntegrationSelector">ERP, database, platform and meeting Integration:</label>
      <select id="erpIntegrationSelector">
        <option value="none" selected>Select ERP or Meeting API</option>
        <option value="SAP">SAP</option>
        <option value="Oracle">Oracle</option>
        <option value="Microsoft Dynamics">Microsoft Dynamics</option>
        <option value="NetSuite">NetSuite</option>
        <option value="AWS">AWS</option>
        <option value="Google Cloud">Google Cloud</option>
        <option value="Azure">Azure</option>
        <option value="Zoom API">Zoom</option>
        <option value="Teams API">Teams</option>
        <option value="Other">Other</option>
      </select>
    </div> 

现在,运行页面以显示更新后的界面:

display_interface("/content/04.html") 

这个新增加的集成选择显示在推理下拉菜单下方(如图图 10.12所示)。它是讨论多模态 CoT、ERP 集成或特定平台兼容性的优秀视觉辅助工具。

图 10.12:ERP、数据库、平台和会议集成列表

图 10.12:ERP、数据库、平台和会议集成列表

在添加此下拉菜单之前,确保你已经彻底准备就绪。熟悉每个列表中的集成(如图图 10.13所示),因为你的受众可能会对每个项目提出具体、详细的问题:

图 10.13:一些可能集成的列表

图 10.13:一些可能集成的列表

记住,GenAISys 提供的集成灵活性不仅限于这些示例。甚至可能包括 MAS 实施——这是我们接下来要探索的另一种复杂方法。

展示高级框架:一个 MAS

在这次演示的这个阶段,你可以从展示你的 GenAISys 目前能做什么转变为突出它所启用的未来。引入 MAS 不仅仅是新增一个功能——它是对生成式 AI 变革潜力的预览,展示了你的系统核心设计如何处理复杂任务。它捕捉了这本书的哲学:以人为本、可扩展和协作的 AI。

在决定是否展示它时,考虑以下参数:

  • 这可能是一个“哇”的时刻,因为你在打开通往未来的大门。

  • 这也可能是一个对风险规避的受众来说令人恐惧的时刻,他们可能害怕无论你说什么:工作替代、取代或破坏。

  • 即使这是一个“哇”的时刻,内容可能过于复杂,也许应该等到 GenAISys 进入实施阶段。如果发生这种情况,你可以将这个 MAS 添加到 GenAISys 的处理程序注册表中,让用户决定是否激活它。

  • 即使这是一个“哇”的时刻,观众想要进一步了解,在让它自行运行之前,提醒他们以人为中心的 GenAISys 具有人机界面,确保专家控制输出,即使在高级 MAS 实现中也是如此。

如果你选择展示 MAS,请明确将其定位为一个创新性的颠覆性产品。它可以自主运行或部分自主运行——无论是独立运行还是通过现有 GenAISys 中的简化界面。

要查看这个 MAS 的完整实现,请打开GenAISYS_&_MAS.ipynb笔记本。程序流程和代码设计得非常直观,每个部分都有对其目的的明确解释。我们,即人类作者和 Gemini 2.5 Pro/ChatGPT,这个项目的合作伙伴,已经仔细地在代码中添加了详细的注释,不仅解释了函数的功能,还解释了背后的设计决策——从引导代理的提示工程到使群体高效运行的异步模式。

这个笔记本有三个关键特性:

  • MAS:这个笔记本演示了一个教育性的 MAS,如图 10.14 所示。这个 MAS 协调一组 AI 代理进行并发任务处理。程序首先设置异步环境,定义核心组件:独立的工作代理创建和解决任务,一个摘要代理进行综合,以及一个中央协调器来管理两阶段工作流程。最后的单元格执行完整的模拟,展示了高效、并行解决复杂问题的方法。

  • 人机协作悖论:尽管这个程序展示了 AI 代理自动化任务,一个常与人类替代相关的概念,但这个笔记本本身是对人机协作的证明。它由人类作者撰写,随后经过 ChatGPT 的优化,并与 Gemini 合作演变成这个 MAS。这个过程反映了书籍的核心、以人为本的主题:未来不是 AI 与人类的对抗,而是 AI 作为合作伙伴,增强我们的创造力和生产力。

  • “从头开始”的方法:我们故意选择从基础库如asyncioaiohttp构建这个系统,而不是使用现有的代理框架。这种从头开始的方法有两个目的。首先,它揭示了多代理协调工作的核心机制,这是这个项目的教育目标之一。其次,它确保生成的框架尽可能灵活和模块化,不受任何单一平台的限制,并准备好适应任何现实世界的商业需求。

图 10.14:MAS 工作流程概述

图 10.14:MAS 工作流程概述

前面的图显示了 MAS 的主要组件:

  • 中央编排器通过在章节笔记本中每个任务少于 1 秒显示代理的输出,指导工作流程。

  • 工作代理并行处理任务,与 OpenAI 交互

  • 摘要代理综合响应,使代理能够通过输出进行交互,形成 MAS 工作的摘要

让我们现在来看看战略集成选项。

MAS 的战略集成选项

既然我们已经确定了 MAS 的是什么为什么,那么关键的商业问题是如何与我们所展示的 GenAISys 相匹配。

图 10.15:MAS 的战略集成模型

图 10.15:MAS 的战略集成模型

图 10.15所示,我们可以为其部署提供三种战略愿景:

  • 将模型 A 作为集成处理程序:对于许多用例,整个蜂群过程可以封装为一个新函数,并添加到核心 GenAISys 的处理程序注册表中。用户只需从推理下拉菜单中选择蜂群处理选项,就可以触发这个大规模并行任务。这展示了主系统的模块化和可扩展性。

  • 模型 B 作为独立、专业的服务:对于大规模、专用需求(例如,分析数百万份文档或实时数据流),MAS 可以作为单独的、高度优化的服务部署。主要对话 GenAISys 可以在需要时调用此服务。这展示了构建用于企业级问题的强大、微服务式架构的能力。

  • 将模型 C 作为更大 AI 平台的支柱:我们可以将整个 GenAISys 构建为一个有两个主要支柱的平台。第一个是面向人类协作的对话和推理代理。第二个是用于大规模自动化的蜂群智能引擎(MAS)。这展示了这项工作的最宏伟、最强大的愿景,不仅是一个工具,而且是一个全面、商业就绪的 AI 平台。

这种集成愿景将你的 GenAISys 提升到仅仅功能性之上,成为一个完全实现、企业就绪的 AI 生态系统。

在从零开始构建你的 GenAISys 之后,你现在拥有一个强大、灵活的 AI 控制器,能够进行动态编排和高级推理。这个坚实的基础使你能够拥抱新兴标准,如模型上下文协议(MCP)代理通信协议(ACP)

  • 模型上下文协议:MCP 为你的 GenAISys 提供了一个标准化的方式,以便无缝访问和集成各种外部工具和数据源。如果客户想要实施这一功能,你现在拥有完成这项工作的技能。你可以在这里了解更多关于 MCP 及其规范的信息:modelcontextprotocol.io/

  • 代理通信协议:ACP 为您的复杂 AI 代理与其他专业代理无缝协作提供蓝图。您在本书中构建了许多代理,为这一协议做准备。您可以在 DeepLearning.AI 平台上找到更多关于 ACP 及其课程的信息,通常与 IBM Research 的 BeeAI 合作:www.deeplearning.ai/short-courses/agent-communication-protocol/

您在设计智能 AI 管道和代理工作流程方面的专业知识意味着您已经准备好利用甚至贡献这些强大的互操作性框架,将您的商业就绪 AI 解决方案提升到下一个层次。现在是一个更具挑战性的方面:安全约束和隐私法规。

5. 安全和隐私

安全和隐私通常从所选的托管平台或框架继承约束,这些平台或框架是在初始集成阶段决定的。然而,即使您的系统符合既定标准,您也必须在 GenAISys 中明确展示您的监管和数据安全组件。始终准备好面对这些主题的严格问题。强烈建议在演示过程中有认证的安全专家陪同。如果不可能,确保您表现出根据客户建立的协议和框架调整 GenAISys 的意愿。

这里是 GenAISys 可能需要集成或与之一致的基本安全层——仔细审查它们,以便准备好应对挑战性问题,即使这些安全层由另一个团队或外部服务管理:

你不必是专家,但至少应该能够舒适地使用准确术语讨论这些领域。仔细审查提供的链接,以确保你了解当代的安全实践。

让我们展示你的系统如何有效地处理实时安全警报。像往常一样,为了避免让你的观众感到不知所措,将04.html复制为05.html,确保如果你决定不继续演示,之前的演示状态保持不变。

我们将在灵活的 HTML 界面中添加一个简单、直观的红色警报横幅:

<!-- Place this alert banner near the top of your container -->
<div id="securityAlert" style="display:none; background-color: #ffdddd; color: #a94442; padding: 15px; border: 1px solid #ebccd1; border-radius: 4px; margin-bottom: 20px;">
  Security Alert: Suspicious activity detected.
</div> 

然后,在你的 JavaScript 中,你可以根据某些条件轻松切换其可见性:

// Example function to display the alert
function showSecurityAlert() {
  document.getElementById('securityAlert').style.display = 'block';
}
// Example function to hide the alert
function hideSecurityAlert() {
  document.getElementById('securityAlert').style.display = 'none';
}
// Simulate a security event after 5 seconds (for demonstration purposes)
setTimeout(showSecurityAlert, 5000);
red alert banner / 5 seconds 

在这个例子中,警报横幅在五秒后自动出现,直观地展示了实时安全通知可能的样子。阅读代码以便能够实时修改它,或者至少在会议中如果需要的话快速修改。一些客户可能不喜欢它的显示方式或颜色。

有时,修改前端页面表明你愿意快速适应客户的需求,正如我们现在已经反复强调的那样。另一方面,谨慎和经过深思熟虑的修改则表明谨慎和可靠性。根据你对受众需求和期望的理解做出战略选择。

警报可能来自你的系统或托管环境。现在,让我们运行代码以显示更新的界面:

display_interface("/content/05.html") 

如下所示,安全警报将在五秒后显示:

图 10.16:实时安全警报横幅

图 10.16:实时安全警报横幅

在项目的实施阶段,必须精确定义安全警报条件,以确保与客户的确切安全策略保持一致。在解决了安全和隐私考虑因素后,我们现在可以继续到定制这个微妙且经常具有挑战性的领域。

6. 定制

与大多数软件一样,GenAISys 的成功之路依赖于我们定制应用程序的能力。无论我们多么努力,最终用户都会要求界面和流程进化。我们可以忽略它们或接受它们。中间地带是接受那些可行且在项目范围内的请求,并为需要根本性修改的进化找到尽可能多的现实解决方案。

有许多可能的定制方法;在这里,我们关注一种实用的、以人为本的三阶段定制方法:

  • 第一阶段:通过头脑风暴研讨会定制前端 HTML 页面,所需组数越多越好

  • 第二阶段:创建一个隔离的沙盒,逐步向构建的 GenAISys 添加功能

  • 第三阶段:逐步将沙盒进化集成到 HTML 页面中(文档化和稳定化)

图 10.17:一个以人为本的三阶段定制过程

图 10.17:一个以人为中心的三阶段自定义过程

所有三个阶段将在研讨会周期中持续进展。强化你参与者的角色,作为积极的共同创造者,而不是仅仅表达他们愿望的技术被动消费者。

再次,复制05.html并将其命名为06.html。添加一些图标以触发观众的反应,使他们能够表达他们的创造力、想法和需求。如果你能成功地让观众参与进来,你已经在成功的路上了一半。

这段代码中的图标来自 Font Awesome。它们通过在<head>中包含一个链接来提供Font Awesome CSS 库。然后,使用带有适当 Font Awesome 类的<i>标签在 HTML 中插入图标。以下是你可以在研讨会期间实时或接近实时定制的关键片段:

  1. 导入Font Awesome库:

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> 
    
  2. 在 HTML 中整合图标:

    • 毛利率 KPI 面板标题:

      <h2><i class="fas fa-chart-line"></i> Gross Margin</h2> 
      
    • 用户选择器标签:

      <label for="userSelector"><i class="fas fa-user"></i> User:</label> 
      
    • 消息输入标签:

      <label for="messageInput"><i class="fas fa-comment"></i> Your Message:</label> 
      
    • 发送按钮:

      <button id="sendButton" title="Send your message"><i class="fas fa-paper-plane"></i> Send</button> 
      
    • 理由选择器标签:

      <label for="reasoningSelector"><i class="fas fa-brain"></i> Reasoning:</label> 
      
    • 模型选择器标签:

      <label for="modelSelector"><i class="fas fa-robot"></i> Model:</label> 
      
fas fa-chart-line, fas fa-user, etc.), ensuring clear visual communication of each component’s purpose. Here, too, you’ll have to be prepared to swiftly modify these icons in real time during workshops to demonstrate your agility in adapting to user feedback.

现在,运行网页以可视化你的图标丰富的界面:

display_interface("/content/06.html") 

页面现在包含图标,如下面的 HTML 页面摘录所示:

图 10.18:使用图标自定义网页

图 10.18:使用图标自定义网页

不要轻视这个话题!最终用户只看到前端网页及其输出(文本、图像和弹出窗口)。花所有必要的时间倾听客户(你的同事或外部客户)。最终用户在这个领域与你合作得越多,它就越成为他们的 GenAISys。

困难的部分是将第 2 阶段(GenAISys)开发和第 3 阶段(GenAISys 和网页集成)结合起来。你可以通过并行实施所有三个阶段来加速项目,如图图 10.19所示。

图 10.19:在本地或远程并行处理所有三个阶段的工作团队

图 10.19:在本地或远程并行处理所有三个阶段的工作团队

选择取决于项目和你的愿景。你的部署方法将创造一个快速、事件丰富、优化上市时间的项目所需的持续动力。然而,每个项目都以自己的速度前进,最佳的速度是用户选择的速度,给他们时间适应你的尖端 GenAISys。

在某个时候,你不可避免地需要解释项目所需的资源和其相关成本。那么,让我们继续讨论这一点。

7. GenAISys 资源(RACI)

每个成功的软件项目都明确指定了所需的人类和机器资源。机器资源通常与早期集成讨论中确定的平台紧密一致(参考本章的集成:平台和框架部分)。然而,人力资源需要更仔细的考虑和明确的详细说明,可以使用如RACI 矩阵这样的结构化方法,如第一章中概述的。回想一下,RACI 矩阵将项目责任分为四个类别:

  • R (Responsible): 积极从事任务的人(们)

  • A (Accountable): 对任务的成功或失败负责的人(们)

  • C (Consulted): 在复杂项目中,这是提供输入、建议和反馈以帮助团队中其他人的人(们),但他们不负责执行工作

  • I (Informed): 这些是那些需要了解任务进度或结果的人

笔记本中的第七部分(RACI)提供了一个针对本书中开发的 GenAISys 设计的 RACI 矩阵的实际示例。图 10.20展示了这个 RACI 构思的摘录,为构建你项目特定的 RACI 提供了一个具体的起点:

图 10.20:本书中构建的 GenAISys 的 RACI 构思摘录

图 10.20:本书中构建的 GenAISys 的 RACI 构思摘录

在演示时,你需要解释GenAISys 实施 RACI 矩阵的构思清晰地概述了部署高级 AI 系统的协调、跨职能方法:

  • 项目经理提供整体战略监督并领导规划和文档工作

  • 同时,AI/ML 工程师推动技术方面的工作——从 DeepSeek 激活和模型集成到 API 设置、机器学习功能以及全面测试

  • DevOps 工程师的职责是搭建环境、配置硬件资源,以及管理部署和可扩展性

  • 相比之下,软件开发者专注于编写交互式界面和处理注册表以及支持文本到语音等特性

  • 同时,业务/CTO 角色提供战略指导,确保关键决策与组织目标一致,并维护合规性和安全措施,确保每个阶段——从初始设置到持续维护——都得到有效管理

使用 RACI 矩阵作为你的参考点将直接带你到你必须估算和谈判的成本(在你的公司、投资者或客户那里)。明确定义的角色将帮助你量化人力小时数,有效分配预算,并确定需要专业知识的领域。这允许你透明地估算项目成本,内部或外部谈判资源分配,并将你的项目划分为可管理的里程碑或交付成果。

有了这些,你现在就为 GenAISys 做好了商业准备。市场是你的征服之地!

摘要

在本章中,我们设计了一个战略框架,在激烈的市场竞争中展示一个商业就绪的 GenAISys。我们看到,技术创新本身不足以确保客户或资金。一个引人入胜的商业叙事必须伴随着技术概念验证,以展示现实世界的价值。一种快速通道的方法是从对团队的简洁介绍开始,迅速建立我们的信誉和专业知识。然后,将演示转向对我们构建的 GenAISys 的明确解释,以实时 KPI 为基础。

我们设计了一个灵活的前端网页来展示系统的功能。想法是拥有一个可适应的 HTML 页面,可以根据情况实时或快速修改。前端网页将我们构建的 IPython 界面转换为一个可访问、可定制的 HTML 显示。实时数据更新和实时模拟加强了系统的实际影响。我们设计了一个强调 GenAISys 的适应性和随着客户需求发展能力的叙事。始终,你看到了如何深入挖掘本书中教授的主要概念,并用你的发展来增强它们。你还可以从头开始构建你自己的 GenAISys,并准备好展示,它可以适应你正在工作的项目的规格。

本章青睐以人为中心的方法,确保人工智能增强而非取代专家决策。系统定位为一个旨在提升运营效率的协作工具。实时关键绩效指标可以加强 GenAISys 的盈利能力和加强 GenAISys 与使用它的团队之间的联系。如向量存储等创新功能增强了数据检索,以改善输出。我们展示了如何通过展示系统向基于群体的 MAS 的预期演变来呈现一个前瞻性的愿景,证明了框架的可扩展性,并引入了强大的人机协作合作叙事。我们展示了与主要云平台和 ERP 系统的集成。我们展示了集成服务如 AWS、Google Cloud 和 Microsoft Azure 的可能性,突出了其多功能性。通过可能的实时警报和自适应措施,严格处理了安全和隐私问题。

灵活性仍然是关键,使系统能够满足多样化的企业需求。这种方法平衡了尖端技术与可衡量的商业成果。迭代过程鼓励根据持续的客户反馈进行定制。我们通过提供交互式研讨会作为即时定制系统的方式。引入了 RACI 矩阵来明确界定角色并简化项目管理。最终,本章提供了一个全面蓝图,用于部署动态、市场就绪的 GenAISys 演示。我们平衡了技术深度与清晰的商业效益。

您现在可以设计、构建和交付一个 GenAISys 了!

问题

  1. 展示一个商业就绪的生成式 AI 系统GenAISys)不需要准备。(对或错)

  2. 在演示目的上不需要前端 GenAISys。(对或错)

  3. 在演示过程中不需要解释什么是向量存储。(对或错)

  4. Pinecone 是市场上最好的向量存储。(对或错)

  5. 只有 OpenAI 和 DeepSeek 可以提供生成式 AI 模型。(对或错)

  6. 开源生成式 AI 模型优于那些不共享其代码的模型。(对或错)

  7. 我们需要为 GenAISys 开发自己的安全和隐私软件。(对或错)

  8. 如果我们认为它很好,我们不需要定制我们的 GenAISys。(对或错)

  9. 所有定制会议都应该面对面和现场举行。(对或错)

  10. 在实施我们的 GenAISys 时不需要展示必要的资源。(对或错)

参考文献

进一步阅读

订阅免费电子书

新框架、演进的架构、研究新发现、生产故障分析——AI_Distilled 将噪音过滤成每周简报,供实际操作 LLM 和 GenAI 系统的工程师和研究人员阅读。现在订阅,即可获得免费电子书,以及每周的洞察力,帮助您保持专注并获取信息。

订阅请访问 packt.link/TRO5B 或扫描下方的二维码。

第十一章:答案

第一章

  1. 不,GPT 模型只执行任务。需要 AI 控制器来动态编排和管理任务。

  2. 不,无记忆会话独立处理每个请求并记住什么都不。

  3. 是的,RAG 可以从文档中检索特定数据。

  4. 是的,从设计到生产和维护,都需要人类的专业知识。

  5. 是的,AI 控制器根据输入上下文动态调整任务顺序。

  6. 是的,目标是优化开发和时间成本。

  7. 是的,这些系统需要计算能力、熟练的团队和大量的预算。

  8. 是的,长期记忆可以保留单次会话之外的交流。

  9. 是的,向量存储可以存储知识和指令场景。

  10. 不,上下文感知对于检测 LLM 请求的关键点至关重要。

第二章

  1. 错误。类似于 ChatGPT 的 AI 代理是一个高度集成的生成式 AI 系统,具有多个组件。

  2. 错误。尽管在线平台有无缝的框架,但系统是使用智能控制器构建的。

  3. 真的。在 GenAISys 中的基本规则是:“没有人类,就没有 GenAISys。”

  4. 真的。一般来说,GenAISys 的提示将包含一个精确的任务标签,例如“总结此文本。”

  5. 真的。在某些情况下,AI 控制器协调者可以根据用户输入确定最可能执行的任务。

  6. 错误。GPT-4o 可以原生地执行语义文本相似性任务。

  7. 真的。每个项目都不同,需要我们设计和编写的不同类型的对话。

  8. 错误。有时,我们需要访问与副驾驶的完整对话历史来做出决定。

  9. 错误。GPT-4o 可以在多种语言中运行。

  10. 错误。有感知的 AI 代理或自我意识的错觉来自于用户对话的流畅性。

第三章

  1. 错误。生成式 AI 系统需要 AI 专家团队、ML 专家以及更多专家。此外,计算和因此自动化任务是有成本的。

  2. 错误。我们必须持续监控我们构建到 GenAISys 中的功能的成本效益。

  3. 真的。当执行向量搜索时,检索系统可以针对数据的具体区域进行定位。

  4. 错误。复杂数据可能需要更多维度,但对于简单数据,较小的维度就足够了。

  5. 真的。上载向量化数据到 Pinecone 数据库的过程称为 Upserting。

  6. 错误。命名空间只是 Pinecone 数据库中记录的一个子集。

  7. 真的。命名空间可以用来查询数据集的特定部分。

  8. 真的。要执行向量相似度搜索,我们必须将输入嵌入到向量中。

  9. 真的。例如,余弦相似度这样的度量标准将使系统能够找到与用户输入数据相似度的向量。然而,根据需要,其他度量标准也是可能的,例如欧几里得距离。

  10. 真的。一个全面的 GenAISys 需要一个 AI 控制器、一个 AI 对话代理以及更多。

第四章

  1. 真。生成式 AI 的复杂性不应成为用户的限制。目标是帮助他们在工作场所。

  2. 错误。每个项目都需要特定的接口,这些接口可以用 Web 框架或经典软件接口构建,或者无缝集成到现有软件中。

  3. 真假。GenAISys 需要提供 GPT-4o 等生成式 AI 模型无法知道的知识,例如特定公司的数据。然而,在其他情况下,GPT-4o 等模型可以提供足够的信息并很好地完成任务。

  4. 错误。你的想象力是无限的!每个项目可能需要标准 ChatGPT 类协作者中不可用的自定义功能。

  5. 真。我们可以在 Pinecone 中存储嵌入式指令场景,检索它们,并用这些指令增强生成式 AI 模型的输入。

  6. 错误。命名空间可以用来区分指令场景和数据。

  7. 真。生成式 AI 模型如 GPT-4o 可以学习一般信息,但不能学习组织内的特定记忆。在模型中微调个人记忆可能成本高昂且耗时。将它们存储在 Pinecone 中并在那里管理可能更有效。

  8. 真假。如果用户只想使用具有向量存储的 AI 对话代理,则为真。在多用户对话中,AI 对话代理只是像团队其他成员一样的一个参与者,则为假。

  9. 真假。真是因为我们可以向 GenAISys 界面添加查询功能。假是因为我们可以实现响应 RAG 触发器,这些触发器将由对话代理管理。

  10. 真。帮助用户最好的方式是提供直观的界面。

第五章

  1. 错误。无缝的 GenAISys 表明界面是无缝的,但这并不证明完成这项工作没有花费很多努力。

  2. 错误。构建 GenAISys 需要大量的工作。

  3. 真假。可以构建一个非事件驱动的 AI 应用程序界面,但它可能缺乏灵活性。

  4. 真。AI 系统可以模仿人类推理,就像思维链过程一样。

  5. 错误。经典的功能序列无法匹配生成式 AI 任务链的创造力,其中每个任务都会对前一个任务的输出做出反应。

  6. 错误。CoT 可以是多模态的。

  7. 真。CoT 流程可以包括具有中间调用非 AI 函数的 AI 函数。

  8. 真。这是推理式 GenAISys 的一个生产性功能。

  9. 真。一个不断增长和加速的经济体的挑战需要自动化。AI 是自动化问题解决的有效方式。

  10. 真。使用 AI 提高团队的生产力可以减轻困难任务,并为更多决策时间和创造力留出空间。

第六章

  1. 真。情感记忆在人与促销信息之间建立联系。

  2. 真。OpenAI 的 o3 可以进行推理并执行思维链任务。

  3. 错误。人类可以在事件发生后多年甚至童年时期记住情感。

  4. 错误。例如,像 o3 这样的生成式 AI 模型可以理解复杂的提示和记忆结构。

  5. 正确。生成式 AI 模型现在可以在一定程度上处理数值,以及自然语言。

  6. 正确。Pinecone 索引可以包含可以用于相似性查询的向量化指令。

  7. 正确。早期的生成式 AI 模型只能处理相对简单的提示。现在,它们可以理解任务的复杂步骤并很好地执行。

  8. 正确。简单的用户输入可以触发复杂的推理场景。

  9. 正确。一个推理模型分析提示并具有通过几个步骤执行复杂任务以处理评论的能力。

  10. 错误。生成式 AI 系统可以解释复杂的提示并执行请求的任务集。

第七章

  1. 错误。DeepSeek 与其他 LLMs 一样进行训练,但采用了高效的技术。

  2. 正确。

  3. 正确。

  4. 错误。DeepSeek-R1 是教师,Llama 模型是学生。

  5. 正确。这是一个复杂的循环。R1 是从 V3 中衍生出来的,以学习推理,而 V3 则是从 R1 中学习推理。

  6. 正确。处理器注册表可以包含指向 AI 函数的处理器,数量多达我们所需。所有处理器都采用相同的格式使得 GenAISys 高度可扩展和可扩展。

  7. 正确。如果我们以独特格式设计处理器,处理器选择机制可以保持不变。如果需要,我们可以增强该机制,但核心过程保持不变。

  8. 正确和错误。正确,因为这些模型是在大量数据和上下文中训练的。错误,因为在某些情况下,RAG 将是必要的,例如。在某个时刻,微调也可能有必要,尽管生成式 AI 模型的应用范围持续增长。

  9. 正确。一个符合项目规格的良好设计的 GenAISys 将能够根据用户请求和 AI 市场的发展进行扩展。

第八章

  1. 错误。轨迹可以是任何事件序列。

  2. 正确。设计良好的合成数据可以节省许多资源并加速 GenAISys 的发展。

  3. 错误。生成式 AI 现在可以解决数学问题和时间序列,并且许多任务已经超越了 LLMs。

  4. 错误。扩大 GenAISys 的整个目的就是让每个人都能使用这项技术。

  5. 正确。我们可以使用生成式 AI 来设计有效、复杂的提示。

  6. 错误。缺失数据的轨迹预测可以应用于广泛的领域,包括火灾灾害。

  7. 正确。我们看到 GenAISys 和代理创新不断发布。

第九章

  1. 正确。向量搜索可以找到其他情况下难以找到的特定单词和表达。

  2. 错误。如果检测到不适当的内容,GenAISys 将不会处理。

  3. 错误。OpenAI 的 API 提供了广泛的类别。

  4. 错误。GenAISys 将标记内容并拒绝请求。

  5. 正确。能够适应不断变化的条件的实时服务将给公司带来竞争优势。

  6. 正确。生成式 AI 系统正在全速发展,趋势将是多用户、跨领域、多模态,以及更多,因为 AI 正在越来越多地整合传感器。

  7. 错误。例如,WhatsApp、Zoom 和 Teams 是经过验证的例子。

  8. 正确。通过自动化许多任务并提供交互式 AI 功能,使用 GenAISys 的团队将超越没有这项技术的公司。

  9. 正确。客户面板是获取实时反馈的最佳方式。当然,决策权在于开发 GenAISys 的团队。但建议是:如果可能,倾听客户面板所代表的市场的意见。

第十章

  1. 错误。展示 GenAISys 需要仔细的准备,否则我们将无法应对棘手的问题。

  2. 正确和错误。一个可以快速修改的前端界面对于复杂项目的展示可能很有用。然而,如果 GenAISys 已经完全完成,这一步可能就不必要了。这是一个战略性的展示选择。

  3. 错误。对于专家来说,一个简单的提醒就足够了。然而,非 AI 专家可能需要一个教育性的解释。

  4. 错误。尽管 Pinecone 是一个优秀的向量存储,但最好的向量存储是那个最适合特定项目需求的。

  5. 错误。可以在 Hugging Face 和各种平台上找到许多其他模型。最好的模型是那个符合您项目需求的一个。

  6. 错误。是否选择开源的生成式 AI 模型取决于我们正在工作的项目的目标。

  7. 正确和错误。如果项目需要,我们可能必须实施自己的安全和隐私组件。我们可能开发一切或向现有解决方案添加功能。然而,许多客户可能会要求我们依赖现有的平台框架,如 AWS、Microsoft Azure 和 Google Cloud。

  8. 正确和错误。您可能希望通过开发计划控制产品的版本,而不是为每个请求进行定制。然而,某些项目可能需要定制,或者 GenAISys 可能无法覆盖范围。

  9. 正确和错误。面对面的会议可以促进更多的人际互动。然而,如果团队分布在不同的地点,远程会议也能完成任务。

  10. 错误。在几乎每个项目中,人类和机器资源是我们必须从一开始就解决的约束,以建立我们的信誉。

新 Packt 标志

packtpub.com

订阅我们的在线数字图书馆,全面访问超过 7,000 本书和视频,以及行业领先的工具,帮助您规划个人发展并推进您的职业生涯。更多信息,请访问我们的网站。

为什么订阅?

  • 使用来自 4,000 多位行业专业人士的实用电子书和视频,花更少的时间学习,更多的时间编码。

  • 通过为您量身定制的技能计划提高您的学习效果

  • 每月免费获得一本电子书或视频

  • 完全可搜索,便于轻松访问关键信息

  • 复制和粘贴、打印和收藏内容

www.packt.com,您还可以阅读一系列免费技术文章,订阅各种免费通讯,并享受 Packt 书籍和电子书的独家折扣和优惠。

其他您可能喜欢的书籍

如果您喜欢这本书,您可能对 Packt 的以下其他书籍感兴趣:

使用 LLMs、RAG 和知识图谱构建 AI 代理

Salvatore Raieli, Gabriele Iuculano

ISBN: 978-1-83508-038-2

  • 学习 LLMs 的工作原理、结构、用途和限制,并设计 RAG 管道将它们与外部数据链接

  • 构建和查询知识图谱以实现结构化上下文和事实基础

  • 开发能够规划、推理和使用工具完成任务的人工智能代理

  • 将 LLMs 与外部 API 和数据库集成以纳入实时数据

  • 应用技术以最小化幻觉并确保输出准确

  • 协调多个代理解决复杂的多步骤问题

  • 优化提示、内存和上下文处理以适应长期任务

  • 在生产环境中部署和监控 AI 代理

实践中的 AI 代理

Valentina Alto

ISBN: 978-1-80580-134-4

  • 掌握核心代理组件,如 LLMs、内存系统、工具集成和上下文管理

  • 使用 LangChain 等框架用代码构建生产就绪的 AI 代理

  • 使用问题解决编排模式创建有效的多代理系统

  • 实施针对电子商务、客户支持等行业的特定代理

  • 为具有短期和长期回忆能力的代理设计健壮的内存架构

  • 通过监控、护栏和人工监督应用负责任的 AI 实践

  • 优化 AI 代理在 production environments 中的性能和成本

Packt 正在寻找像您这样的作者

如果您有兴趣成为 Packt 的作者,请访问authors.packtpub.com并今天申请。我们已与数千名开发人员和科技专业人士合作,就像您一样,帮助他们将见解分享给全球科技社区。您可以提交一般申请,申请我们正在招募作者的特定热门话题,或提交您自己的想法。

分享您的想法

您已完成《构建业务就绪的生成式 AI 系统》,我们非常乐意听到您的想法!如果您从亚马逊购买了这本书,请点击此处直接转到该书的亚马逊评论页面并分享您的反馈或在该购买网站上留下评论。

您的评论对我们和科技社区非常重要,并将帮助我们确保我们提供高质量的内容。

posted @ 2025-10-27 08:52  绝不原创的飞龙  阅读(10)  评论(0)    收藏  举报