对话式-AI-和聊天机器人的-ChatGPT

对话式 AI 和聊天机器人的 ChatGPT

原文:ChatGPT for Conversational AI and Chatbots

译者:飞龙

协议:CC BY-NC-SA 4.0

Cover.png

学习如何使用最新的大型语言模型技术自动化对话

贡献者

关于作者

Adrian Thompson对话式人工智能(CAI)领域的领先专家,自 2018 年以来一直处于构建聊天机器人和语音助手的最前沿。作为 The Bot Forge 的创始人,他建立了一家以 CAI 的尖端创新而闻名的先驱咨询服务。Adrian 的专长涵盖了最新的大型语言模型(LLMs),如 ChatGPT 和 Google Gemini。作为一名多才多艺的程序员和提示工程师,他在 LLM 领域和相关技术方面非常熟练。在 loveholidays,Adrian 通过开发先进的 CAI 系统来提升客户体验。他对 CAI 的最新进展充满热情,以其在对话设计、AI 开发和跨行业战略咨询方面的专业能力而闻名。

我首先要感谢我的爱人和耐心、孩子们、朋友们和家人,感谢他们在撰写这本书的漫长过程中给予的支持、耐心和鼓励。还要感谢 loveholidays 的对话式人工智能团队倾听我的想法,以及在我建立 The Bot Forge 的日子里与我交谈的许多有趣的人,他们提供了灵感和鼓励。

关于审稿人

Krishnan Raghavan是一位拥有超过 20 年经验的 IT 专业人士,在软件开发和交付卓越的多个领域和技术方面拥有经验,从 C++到 Java、Python、Angular、Golang 以及数据仓库。

当 Krishnan 不工作的时候,他喜欢和妻子以及女儿共度时光,同时阅读小说、非小说以及技术书籍,并参与黑客马拉松。Krishnan 通过成为 GDG – Pune 志愿者小组的一员,试图回馈社区。

您可以通过 mailtokrishnan@gmail.com 或 LinkedIn:www.linkedin.com/in/krishnan-Raghavan与 Krishnan 取得联系。

我要感谢我的妻子 Anita 和女儿 Ananya,感谢她们给予我时间与空间来审阅这本书。

Manoj Palaniswamy是 Kyndryl 的高级技术员工,在应用、数据和 AI 实践中扮演着技术领导角色。他已在 IT 行业工作超过 17 年,其专业领域包括企业 AI 战略、数据管理、AIOps、MLOps、AI 平台工程以及混合云 IT 基础设施和分析。他领导了全球多个跨文化技术团队在复杂技术项目中的工作,并与客户紧密合作,将他们的业务需求转化为技术解决方案。Manoj 在机器学习和虚拟机工作负载优化领域拥有两项专利。

前言

你好!

自 2022 年发布以来,ChatGPT 席卷全球,迎来了大型语言模型LLM)的时代,并彻底改变了对话 AI 领域。

这本书,《ChatGPT for Chatbots and Conversational AI: 利用高级语言模型革新对话体验》是您了解和掌握对话 AI 最新进展的全面指南,特别关注 OpenAI 的 ChatGPT。

ChatGPT 的出现标志着聊天机器人和虚拟助手能力的重大飞跃。与传统的基于规则的系统不同,LLMs 根据提供的上下文生成类似人类的文本。这允许更流畅、自然和上下文适当的交互,从而在各种应用中改变用户体验,从客户服务到个人助理。

在这本书中,我们将探讨 ChatGPT 和 LLMs 如何重塑对话 AI 的格局。

内容结构旨在提供理论见解和实践应用。我们首先从基础知识开始,涵盖聊天机器人和 LLMs 的演变及其在对话设计中的应用,以及 ChatGPT 和 OpenAI 模型的坚实基础介绍。然后,我们转向更高级的主题,包括提示工程的最先进技术、LangChain 的深入研究、检索增强生成(RAG)系统的使用,以及创建您自己的复杂聊天机器人应用程序。

目前仍有成千上万的基于传统自然语言理解(NLU)的系统在生产中,我知道关于何时、如何或是否应该过渡到由 LLM 驱动的系统仍然有很多疑问,我将通过强调你可能遇到的挑战和克服它们的策略来尝试解答这些问题。

将您的 LLM 应用程序投入生产不仅仅是技术实现。它需要强大的评估策略,以确保模型在现实世界场景中按预期表现。本书强调持续监控、严格测试和迭代改进的重要性,以保持高质量互动和用户满意度。

在整本书中,我们强调现实世界的应用和案例研究,确保你学到的概念可以直接应用于你的项目。到这本书的结尾,你不仅将了解如何在各种场景中实施 ChatGPT,而且还将为该领域的未来趋势做好准备。

这本书通过提供 ChatGPT 景观的全面概述脱颖而出,结合了最新的研究和实用见解。我们深入研究基础概念、高级技术、创新工具和行业最佳实践,为任何希望使用 ChatGPT 开发复杂对话应用的人提供清晰的路线图。

有很多内容需要涵盖,而且这是一个快速变化的领域。加入我,一起发掘 ChatGPT 在对话式 AI 应用中的全部潜力。

享受阅读!

这本书面向的对象

这本书是为那些渴望利用 ChatGPT 和其他高级语言模型在他们的对话式 AI 项目中的人设计的。主要受众包括以下几类:

  • 对话式 AI 专业人士:从对话设计师到客户体验经理和对话式 AI 负责人,任何参与与聊天机器人、语音助手、智能 IVR 系统和多模型客户支持工作的人,都将发现利用 ChatGPT 创造更吸引人和自然互动的实用见解。

  • 开发人员和对话式 AI 工程师:那些有技术背景,希望从传统的 NLU 系统过渡到由 LLM 驱动的应用程序的人,将从详细的指导中受益,包括集成、部署和克服常见挑战。

  • 产品负责人:负责监督 AI 驱动产品开发的领导者将全面了解将创新对话解决方案推向市场所需的最新技术、工具和最佳实践。

  • AI 爱好者和研究人员:对 AI 进步充满热情的个人将欣赏对 ChatGPT、提示工程、LangChain 以及其他塑造对话式 AI 未来的创新技术的深入探讨。

无论你是想改进现有的聊天机器人应用、启动新的 AI 项目,还是保持对行业趋势的领先,这本书都提供了帮助你成功的知识和工具。

本书涵盖的内容

第一章聊天机器人、对话式 AI 和 ChatGPT 简介,介绍了聊天机器人和对话式 AI 的基础知识。它探讨了它们的演变、各种类型以及它们在电子商务、客户服务、医疗保健等行业中的影响。本章深入探讨了 OpenAI 的 ChatGPT,详细介绍了其开发、功能和局限性,并考察了它在更广泛的对话式 AI 领域的位置。

第二章使用对话设计进行 ChatGPT 应用,深入探讨了对话设计师的角色以及 LLM 如 ChatGPT 对对话设计的影响。它涵盖了实际应用,包括模拟对话和创建角色,并强调在开发引人入胜的对话式 AI 系统中测试和迭代的重要性。到那时,你将了解如何有效地在对话设计中使用 ChatGPT。

第三章ChatGPT 精通 – 解锁其全部潜力,探讨了与 ChatGPT 交互的技术方面,包括网页聊天界面、OpenAI 游乐场、API 使用和官方库。你将了解免费版和 Plus 版之间的区别、自定义指令以及如何使用游乐场。到那时,你将能够根据你的需求选择最佳的交互方法。

第四章使用 ChatGPT 进行提示工程,专注于掌握提示工程。你将了解成功提示的核心组件、语气和复杂性的策略,以及提高可读性的技术。本章将帮助你创建能够最大化 ChatGPT 能力的提示,确保精确和相关的交互。

第五章LangChain 入门,介绍了 LangChain,这是一个用于构建复杂 LLM 应用的开源框架。你将了解其核心组件、LangChain 表达式语言LCEL)以及你可以创建的各种链。到那时,你将拥有构建 LangChain 应用和解决下一章中更高级功能的坚实基础。

第六章使用 LangChain、代理和工具进行高级调试、监控和检索,深入探讨了 LangChain 的高级主题,重点关注调试技术、利用代理和工具以及理解 LLM 驱动的对话体验的内存。您将探索 LangSmith 平台、即插即用的工具以及为代理创建自定义工具。本章建立在先前概念的基础上,使您能够开发更复杂的 LangChain 应用程序。

第七章将向量存储作为检索增强生成(RAG)的知识库,介绍了 RAG,这是 LLM 的一个流行用例。您将了解创建 RAG 系统的基本步骤以及如何使用 LangChain 实现这些流程。通过一个真实世界的例子,您将获得掌握 RAG 概念和技术的基础。

第八章创建您的 LangChain 聊天机器人示例,将前几章的关键概念整合到一个实际项目中。您将构建一个由 ChatGPT 驱动的聊天机器人,能够回答有关您数据的问题并处理复杂任务。我们将探讨项目的范围、为 RAG 准备您的数据、创建代理工具、在 LangChain 中使用它们,以及最后,使用 Streamlit 框架将所有内容整合在一起以创建您的聊天机器人 UI。到结束时,您将拥有一个功能性的聊天机器人和对如何使用 ChatGPT 构建复杂对话代理的深刻理解。

第九章使用 LLM 的对话 AI 的未来,深入探讨了将 ChatGPT 应用程序投入生产,检查行业中学到的经验教训,并探索成功策略。它探讨了 ChatGPT 的替代方案,特别是较小的语言模型,并讨论了 LLM 的未来趋势。到结束时,您将能够导航不断发展的对话 AI 领域并为您组织的未来做出规划。

要充分利用本书

虽然熟悉聊天机器人和对话 AI 的基本概念将有益,但并非必需。建议具备一些编码专业知识,尤其是 Python,以有效地跟随示例和练习。需要一个运行 Python 3.10 的工作 Python 环境。我们建议使用 Anaconda 来设置此环境,并安装 Jupyter Notebook,因为所有章节示例都使用 Jupyter Notebook。

本书涵盖的软件/硬件 操作系统要求
Python 3.10 跨平台
LangChain 跨平台

需要一个免费的 OpenAI 账户,以便您可以获得 OpenAI API 密钥以访问 ChatGPT 和其他相关服务:openai.com/

需要一个 LangSmith 账户,以便您可以为监控和测试您的 LangChain 应用程序创建 API 密钥:smith.langchain.com

通过确保你满足这些先决条件,你将准备好深入本书涵盖的实际应用。

如果你使用的是本书的电子版,我们建议你亲自输入代码或从本书的 GitHub 仓库(下一节中有一个链接)获取代码。这样做将帮助你避免与代码的复制和粘贴相关的任何潜在错误

下载示例代码文件

你可以从 GitHub 下载本书的示例代码文件github.com/PacktPublishing/ChatGPT-for-Conversational-AI-and-Chatbots。如果代码有更新,它将在 GitHub 仓库中更新。

我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/找到。查看它们吧!

使用的约定

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

文本中的代码: 表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“确保你已经通过运行 pip install -U langsmith 安装了 LangSmith。”

代码块按照以下方式设置:

def format_evaluator_inputs(run: Run, example: Example):
    return {
        "input": example.inputs["question"],
        "prediction": next(iter(run.outputs.values())),
        "reference": example.outputs["answer"],
    }

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

splitter = RecursiveCharacterTextSplitter(chunk_size=250, 
    chunk_overlap=20)

粗体: 表示新术语、重要单词或你在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“点击 SUCCESS 或 FAILURE 按钮将显示数据集中每个输入和输出的测试详情。”

小贴士或重要注意事项

看起来像这样。

联系我们

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

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

勘误: 尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果你在这本书中发现了错误,我们非常感谢你向我们报告。请访问www.packtpub.com/support/errata并填写表格。

盗版: 如果你在网上遇到我们作品的任何非法副本,我们将非常感谢你提供位置地址或网站名称。请通过电子邮件发送至 copyright@packt.com 并提供材料的链接。

如果你有兴趣成为作者: 如果你精通某个主题,并且有兴趣撰写或为本书做出贡献,请访问authors.packtpub.com

分享你的想法

一旦您阅读了《ChatGPT for Conversational AI and Chatbots》,我们非常乐意听听您的想法!请点击此处直接访问此书的亚马逊评论页面并分享您的反馈。

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

下载此书的免费 PDF 副本

感谢您购买此书!

您喜欢在路上阅读,但无法携带您的印刷书籍到处走吗?

您的电子书购买是否与您选择的设备不兼容?

别担心,现在每购买一本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。

在任何地方、任何时间、任何设备上阅读。从您最喜欢的技术书籍中搜索、复制和粘贴代码直接到您的应用程序中。

优惠远不止于此,您将获得独家折扣、时事通讯和丰富的免费内容,每天直接发送到您的邮箱。

按照以下简单步骤获取这些好处:

  1. 扫描下面的二维码或访问以下链接

packt.link/free-ebook/978-1-80512-953-0

  1. 提交您的购买证明

  2. 就这样!我们将直接将您的免费 PDF 和其他好处发送到您的邮箱。

第一部分:对话人工智能的基础

在这部分,您将全面了解对话人工智能的基础。我们将从探讨聊天机器人的基础知识、它们的演变以及它们在各个行业中的影响开始。您还将了解 OpenAI 的 ChatGPT 的革命性功能、其应用和局限性。此外,我们还将深入探讨如何将 ChatGPT 用于对话设计,增强用户互动并创造更自然的对话体验。

本部分包含以下章节:

  • 第一章聊天机器人、对话人工智能和 ChatGPT 简介

  • 第二章使用 ChatGPT 进行对话设计

1

聊天机器人、对话人工智能和 ChatGPT 简介

欢迎来到聊天机器人、对话人工智能对话 AI)和 ChatGPT 的激动人心世界!

在本章中,我们向您介绍聊天机器人和对话人工智能。

我们的旅程将从探讨聊天机器人的基础知识及其不同类型开始,追溯这些数字对话者的演变,并评估它们在多个行业(如电子商务、客户服务、医疗保健)中的影响。

我们将接着探讨对话人工智能领域随着时间的推移而发生的改变以及大型语言模型LLM)技术的近期快速崛起,特别是 OpenAI 的 ChatGPT、生成式预训练变换器 3GPT-3)和 GPT-4 模型的崛起。

在阅读本章的过程中,你将全面了解 OpenAI 的 ChatGPT。我们将揭开这个技术奇迹的面纱,来考察其发展、性能和局限性。你将亲眼看到 ChatGPT 如何融入更广泛的对话式人工智能领域,以及它是如何通过其多样化的应用革命性地改变了各个行业。

为什么本章有价值?我们的目标是观察对话式人工智能的更广泛图景,并深入理解 ChatGPT,这实际上为你在本书后面学习实用技能奠定了基础。到本章结束时,你将深入理解聊天机器人和对话式人工智能,特别是 ChatGPT 的现实应用和潜力,以及与早期对话式人工智能技术相比,ChatGPT 提供的机遇。这种洞察力将使你能够看到 ChatGPT 的对话式人工智能应用如何为你的组织带来实际利益,提升用户体验和业务流程,并为你的行业带来新的优势。让我们共同踏上这段启发性的旅程吧!

在本章中,我们将探讨以下主要主题:

  • 聊天机器人和对话式人工智能是什么?

  • 聊天机器人和对话式人工智能的演变

  • 理解对话式人工智能应用

  • OpenAI 的 ChatGPT 是什么?

  • ChatGPT 的能力和应用

  • ChatGPT 的局限性

聊天机器人和对话式人工智能是什么?

当我们想到对话式人工智能时,我们指的是一个不断发展的 AI 领域,它使计算机系统能够以交互式的方式使用自然语言(NL)与人类进行交流。

在过去的十年中,由对话式人工智能驱动的基于语音和文本的助手已经融入我们的日常生活,在各种平台上提升了用户体验,并应对了广泛的使用案例。它们革命性地改变了企业与客户互动的方式,已成为现代数字战略的关键组成部分。

本节旨在提供一个关于对话式人工智能领域的全面概述。它将深入探讨聊天机器人和对话式人工智能的历史,突出塑造从基础规则系统到复杂人工智能驱动的聊天机器人的关键里程碑。我们将考察技术进步,例如自然语言理解(NLU)以及从基于规则的聊天机器人到人工智能驱动的聊天机器人的发展,强调它们的性能和局限性。总体而言,本节旨在为读者提供一个关于对话式人工智能在革命性改变人类与计算机之间互动中的重要性及其潜力的清晰理解。

对话式人工智能的简要历史

第一个聊天机器人是在 20 世纪中叶被创建的,第一个记录的例子 ELIZA 是在 1966 年从麻省理工学院MIT)的神圣殿堂中诞生的,这得益于约瑟夫·魏岑鲍姆的开创性工作。ELIZA 被设计成模仿心理治疗师的语言模式,能够与人类用户进行直接的互动。这一开创性的创造为后来更复杂的对话式 AI 系统的发展奠定了基础。

最初,这些基本的聊天机器人只能执行有限的预编程响应或决策树。然而,它们已经经历了显著的演变,扩大了它们对各种输入的响应能力。

革命性技术的出现,如机器学习ML)、自然语言处理NLP)和 NLU,推动了从原始聊天机器人向复杂对话式 AI 系统的转变。这些先进系统不仅能够以更自然、更本能的方式理解和回应人类语言,还能进行更动态的对话。这些现代系统的一个关键特性是它们能够利用机器学习在时间上学习和适应,从而逐步提高其效率和用户接受度,因此需求也在增加。

对话式 AI 的发展和演变被一系列重大里程碑所标记,这些里程碑突出了它从原始聊天机器人到能够模拟类似人类对话的先进 AI 系统的稳步进步。

这些里程碑中的每一个都代表了对话式 AI 发展中的一个重大进步,为今天我们所看到的复杂基于意图的系统铺平了道路。然而,说直到 2022 年 11 月对话式 AI 才真正起飞并不夸张。

为了强调 ChatGPT 的惊人增长,考虑这样一个事实:它在 2022 年 11 月发布后的短短 5 天内就积累了超过一百万用户。这一增长轨迹甚至超过了 Netflix、Facebook、Instagram 和 Zoom 等科技巨头。

聊天机器人和自动化助手的概述

当我们谈论聊天机器人或数字助手时,我们究竟指的是什么?聊天机器人这个术语一直存在争议,有些人认为它在技术仍处于萌芽阶段时承担了过去的失望。为了本书的目的,无论我们称它们为聊天机器人、数字助手还是其他任何术语,我们本质上都是在讨论一个与人类通过文本或语音进行交流的计算机程序。这种交互式通信可以在各种媒介上进行,例如网站、移动应用、消息平台、协作工具、智能音箱、数字人类头像或交互式语音响应IVR)系统。

为了进一步明确,我们可以将这些实体分为两种主要类型的对话式代理,它们具有不同的能力:

图 1.1 – 基于规则和人工智能驱动的聊天机器人的比较

图 1.1 – 基于规则和人工智能驱动的聊天机器人的比较

基于规则的聊天机器人/数字助手

简单的基于规则的聊天机器人基于一组预定义的规则或常见问题解答(FAQ)。它们被设计用来回答常见问题、提供信息或引导用户完成特定任务。然而,它们处理交互的能力局限于预编程的知识,并且在与预定义脚本不符的请求面前可能会遇到困难:

图 1.2 – 与基于规则的聊天机器人的交互

图 1.2 – 与基于规则的聊天机器人的交互

简而言之,这些聊天机器人无法理解它们编程之外的语言。这类聊天机器人不利用任何机器学习技术,在用例和功能上有限且脆弱。如果用户提出超出其对话能力或决策树范围的要求,它们往往会崩溃,导致用户体验不佳。

由对话式人工智能驱动的聊天机器人/数字助手

对话式人工智能是指使计算机或机器能够与用户进行自然、类似人类的对话的技术。它结合了多个领域,如自然语言处理(NLP)、自然语言理解(NLU)、机器学习(ML)和对话管理,以对话方式理解和响应用户输入。如今,对话式人工智能是涵盖聊天机器人和语音助手以及创建它们的系统和技术的领域的通用术语。

随着技术的进步,对话式人工智能已经发展得更加复杂,能够理解复杂的查询,提供有意义的、与上下文相关的响应,并采用更加稳健、更加动态和适应性强的方法。

对话式人工智能聊天机器人的核心特性包括以下内容:

  • 对上下文的理解:自然语言理解(NLU)最显著的特征之一是其理解对话上下文的能力。这意味着它不仅处理孤立的语言,还考虑这些词语使用的上下文。这允许人工智能正确地解释用户输入背后的含义,即使它是不明确的或复杂的。

  • 语义理解:自然语言理解(NLU)系统具有高度的语义理解能力。它们可以通过实体识别来理解用户话语背后的含义,包括同义词、俚语、地方方言和行业特定术语。

  • 处理歧义:在人类交流中,歧义很常见。我们经常使用模糊或不清晰的表述,这些表述可以有不同的解释。NLU 系统可以通过使用上下文线索来推断意图的含义来处理这种歧义。例如,考虑以下句子,“我看见她 duck。” 这个句子可以有多种解释:它可能意味着说话者看见一位女性躲避某物,或者它可能意味着说话者看见了一只属于女性的鸭子。如果之前的对话是关于避免飞行物体,系统就会推断第一种含义。如果对话是关于宠物或动物,它就会推断第二种含义。

  • 意图识别:NLU 系统可以识别用户话语背后的意图。这意味着它们不仅处理用户所说的话,还理解用户想要实现的目标。这对于提供有帮助和相关的回应至关重要。

  • 实体识别:实体识别是自然语言处理(NLP)中的关键技术。它是识别和分类提供的输入文本中的命名实体(如人物、组织、地点、产品类型、日期和其他变量)的任务。

  • 槽填充:槽填充是根据实体类型从输入中提取信息的功能。它高度依赖于实体识别,它涉及识别和从输入中提取特定的信息片段,并将它们放入内存中预定义的槽位中,以供以后使用。例如,在酒店预订对话系统中,槽位可能包括房间类型、预订时间和人数。

  • 情感分析:许多自然语言理解(NLU)系统可以分析用户话语背后的情感。这使得它们能够识别用户是快乐、沮丧、愤怒还是悲伤,并以对用户情绪状态敏感的方式做出回应。

  • 对话管理:NLU 系统可以管理复杂的对话。它们可以跟踪对话的历史,并使用这些信息来指导它们的回应。它们可以处理中断、后续问题和对话主题的变化,提供更类似人类的交互。

  • 多语言能力:高级 NLU 系统可以理解和用多种语言进行交流。这使得企业能够为全球客户提供客户服务和支持。

  • 与外部系统集成:NLU 系统通常可以与其他系统集成,例如客户关系管理(CRM)系统、数据库或其他 API。这使得人工智能在与用户交互时能够检索和利用实时数据,提供更个性化和相关的回应。

以下图表显示了与现代对话式人工智能聊天机器人交互的步骤:

图 1.3 – 与人工智能聊天机器人的交互

图 1.3 – 与人工智能聊天机器人的交互

在过去的 5 年里,对话式人工智能平台经历了巨大的增长,大小技术供应商都在努力构建最好的低代码、无代码、专业代码解决方案。多年来在对话式人工智能领域工作的人都有自己对于最佳或最喜欢的平台来构建对话体验的看法。

所有这些系统的关键组成部分是它们都是基于意图的。人工智能技术根据一组训练好的意图处理用户意图,并根据其对对话上下文的理解提供答案。

对话式人工智能平台

现代对话式人工智能系统采用几个功能来管理对话。这些功能通常包括以下内容:

  • 能够通过文本或语音理解用户的自然语言输入

  • 生成相关、连贯和吸引人的自然语言输出的能力

  • 能够理解对话中的多个意图、实体和上下文

  • 能够从用户反馈和数据中学习,以随着时间的推移提高其准确性和理解能力

  • 在多个平台和渠道上提供一致和个性化的体验

图 1.4 – 现代对话式人工智能系统的元素

图 1.4 – 现代对话式人工智能系统的元素

市场上有很多优秀的对话式人工智能系统,供应商从最大的技术提供商到专注于对话式人工智能解决方案的技术初创公司都有。

实际上,并不是这些系统之一创造的最终对话体验决定了成功的实施,而是系统中存在的功能和这些功能的可用性,使得用户能够创建对话体验。

要欣赏今天先进的人工智能对话,让我们回顾一下聊天机器人从其不起眼的起点的发展历程。

聊天机器人和对话式人工智能的演变

当聊天机器人首次进入场景时,它们被誉为技术领域的突破性进化,有望彻底改变企业与其客户沟通的方式。

然而,早期的版本并没有像许多人所希望的那样令人印象深刻。与聊天机器人平台的增长以及任何人都能轻松创建聊天机器人的便利性相结合,这导致了糟糕的用户体验和整体表现不佳,这损害了它们的声誉。

早期聊天机器人的一个主要缺陷是它们在理解和回应人类语言方面的缺乏复杂性和细微差别。这些基本的版本通常是基于规则的,严重依赖于预先编写的脚本。这意味着它们只能处理非常具体的输入,并且很容易因为任何偏离脚本的内容而受到影响。结果,用户经常发现自己陷入令人沮丧的循环对话中,聊天机器人无法理解他们的查询,并持续提供不相关或不合逻辑的回应。

语音助手的发展历程也充满了起伏。虽然它们最初很受欢迎,尤其是在亚马逊的 Alexa、苹果的 Siri 和谷歌助手的推出后,但随着时间的推移,它们已经见证了下降趋势。这些语音助手的准确性和理解力导致了用户的某些挫败感。此外,关于隐私和数据安全的担忧在这次下降中发挥了重要作用。设备“始终在监听”的想法让许多用户感到不舒服,不愿意使用这些助手。

围绕聊天机器人和语音助手的早期炒作与它们的局限性现实形成了对比,导致这些技术出现了一种“人工智能冬天”。媒体迅速抓住这些失败,引发了一波负面报道。宣称聊天机器人和语音助手“死亡”的标题变得司空见惯,导致对这些技术潜力的普遍怀疑。

自然语言处理(NLP)和机器学习(ML)等更高级人工智能技术的出现,使得更先进和能干的聊天机器人和语音助手得以开发。这些新一代产品在理解和回应人类语言方面表现得更好,并且能够随着时间的推移学习和适应。与基于意图的对话式人工智能超越了基于规则的代理一样,大型语言模型(LLMs)也寻求做到这一点。

LLMs 已经开发了好几年。然而,直到最近几年,随着 OpenAI 推出的 GPT-3 技术的出现,这项技术才开始获得一些曝光并进入主流。但在 2022 年 11 月,所有这些都发生了变化,ChatGPT 的爆炸式增长引发了技术竞赛,数百个组织都在努力创造最先进的 LLM。ChatGPT 和现在的 GPT-4 处于领先地位,它们可能是最具挑战性的。事实上,不仅仅是 LLM 技术正在进步,还有构成生态系统的其他相关技术也在进步。

对话式人工智能专业人士可以看到,随着人工智能驱动通信的巨大飞跃,存在着机会。为聊天训练的 GPT 模型可以使聊天机器人和自动化助手进行极其类似人类的对话。在下一节中,我们将更详细地探讨这些应用。

理解对话式人工智能应用

在查看 ChatGPT 之前,考虑对话式人工智能应用的使用案例,并首先在传统对话式人工智能系统和技术的可能性背景下考虑它们,是很重要的。

对话式人工智能已成为众多行业中的一个强大工具,从客户服务到医疗保健、银行、保险、零售和人力资源。通过自动化常规任务和增强用户交互,对话式人工智能应用已经改变了许多领域的格局。让我们看看一些现有的对话式人工智能的例子。

客户服务

对话式人工智能在客户支持用例中取得了巨大成功,以多种方式简化流程并改善用户体验。通过采用人工智能驱动的聊天机器人和虚拟助手,企业可以无缝且高效地处理大量客户互动。

在这个用例中,对话式人工智能提供了多种功能和改进。首先,代理可以同时与多个客户互动,即时解决查询。这消除了长时间的等待,这是传统支持系统中常见的客户不满来源。

其次,人工智能全天候的可用性极大地提升了客户体验。对话式人工智能可以随时响应客户咨询,包括节假日,确保持续的支持。

第三,人工智能与 CRM 系统和其他数据库的集成提供了个性化的体验。对话式人工智能可以使用客户数据来了解他们的偏好和购买历史,并提供定制化的解决方案或产品推荐,从而提高客户满意度并可能推动销售。

最后,对话式人工智能可以帮助企业节省资源。人工智能可以处理日常的、重复性的任务,从而释放人力资源去处理更复杂和敏感的问题。这不仅提高了效率,还降低了运营成本。

loveholidays,一家位于英国的在线旅行社,实施了一个名为 Sandy 的聊天机器人。Sandy 被设计成实时响应客户查询,减少等待时间并提升客户体验。这个机器人全天候处理大量互动,比人类代表更有效地解决简单问题。这是一个典型的例子,说明了对话式人工智能如何革命性地改变客户服务,从回答常规问题到主动的客户参与。

语言翻译

语言翻译系统,如谷歌翻译和 DeepL,使用对话式人工智能来促进实时翻译口头或书面交流。考虑一个用例,一个说法语的用户需要与一个中文同事沟通。使用谷歌翻译,他们可以无缝沟通,每个人都在自己的母语中,从而打破语言障碍,实现顺畅的沟通。

教育

像卡内基学习这样的基于人工智能的教育平台利用人工智能提供个性化的学习体验。这些平台适应个别学生的需求,提供定制化的指导和反馈。通过研究学生习惯,这些算法个性化他们的学习体验,提供更有效、个性化的学习方法。

医疗保健

在医疗保健领域,对话人工智能被用于患者分诊和初步诊断。例如,Babylon Health 开发了一个聊天机器人,可以进行初步症状检查,根据发现结果推荐进一步医疗关注或家庭护理。此机器人还可以安排预约和续方,显著提高患者护理和满意度。

其他用例示例包括为心理健康应用创建的;例如,Woebot 是一个由人工智能驱动的个人心理健康伴侣,旨在帮助用户维持他们的情绪健康。利用具有自然语言处理能力的对话人工智能,它逐渐了解用户的心理状态,提供基于认知行为疗法CBT)、人际心理治疗IPT)和辩证行为疗法DBT)的定制、经临床验证的策略。这种复杂的人工智能和经过验证的治疗策略的独特组合创造了一个独特的易于访问的心理健康聊天机器人,它使用智能对话能力和流畅的聊天用户界面UI)。

银行和保险业

银行和保险行业使用对话人工智能处理常规查询、账户管理、账单支付、索赔处理和政策管理。一些机构,如摩根大通,使用对话人工智能提供个性化的财务建议和推荐,创造更具吸引力的客户体验。

零售

在零售业中,聊天机器人通过推荐产品、跟踪订单和回答常规查询来提升客户服务。例如,一个由人工智能驱动的机器人可以根据客户的浏览历史推荐产品,创造个性化的购物体验。它们还帮助定制营销活动,有助于增加销售额和客户保留率。

人力资源

在人力资源领域,人工智能驱动的聊天机器人使招聘任务变得更加高效。例如,Mya 可以回答常见问题、筛选候选人、安排面试和管理简历。Mya 报告称,在最初的 10,000 次对话中,与 92%的候选人进行了有效互动,显著减少了招聘人员的工作量。

总之,对话人工智能的应用范围广泛且不断演变。无论是使客户服务更加高效、个性化教育、简化医疗保健、革命化银行、保险和零售,还是提升人力资源流程,对话人工智能都注定将在各个行业中继续发挥其变革性作用。

尽管旅程崎岖,但聊天机器人和语音助手的传奇故事远未结束。随着这些技术的持续发展,它们有潜力真正改变我们与机器以及彼此沟通的方式。与任何技术创新一样,关键是从过去的错误中学习并继续前进。

对话人工智能作为培训工具——数字人类的兴起

随着对话式 AI 能力的不断发展,我们正在见证“数字人”的兴起,这些数字人是高度逼真的、由 AI 驱动的虚拟存在,以类似人类的方式与用户互动。这些数字人,结合对话式 AI 的力量,为许多组织在健康、教育、培训和客户服务领域开辟了新的前沿;例如,德国电信、沃达丰、契尔氏和瑞士信贷。

如 UneeQ 和 Soul Machines 等公司处于开发能够表达情感、根据上下文调整其响应并从每次互动中学习的数字人的最前沿。这些类型的创新界面可以直接集成到现代对话式 AI 系统中,处理语音转文本STT)和文本转语音TTS)功能,并支持语音合成标记语言SSML)以及它们自己的动作编程语言,以展示人类情感和手势。

在教育和培训领域,由对话式人工智能驱动的数字人可以用来创建个性化的沉浸式学习体验,以满足每个学习者的需求。例如,一个数字人可以扮演辅导老师的角色,在各个科目提供一对一辅导,或者在企业环境中作为培训助理,指导员工通过复杂的过程或系统。

数字人供应商是早期采用 LLM 和生成式人工智能GenAI)的先驱。这些可能性真正令人着迷,并为 AI 领域的进一步探索和发展开辟了广泛的机会。许多公司已经意识到,将高级数字人和由 LLM 驱动的对话式服务相结合,可以创造独特的品牌体验。

创建数字人形式的代理有助于创建更个人化、富有同理心的互动,并使应用范围更广泛。以下是一些值得注意的例子:

  • 心理健康应用:南加州大学创意技术研究所开发的数字人 Ellie 已被用于对人们进行访谈,以筛查抑郁和创伤后应激障碍的迹象。

  • 医学教育:可以使用数字病人来训练医学生的病人互动和诊断技能。

  • 数字训练师,创建个性化的沉浸式学习体验,以满足每个学习者的需求。想想你自己的个人导师或企业环境中的培训助理,他们指导员工通过复杂的过程或系统。

在过去,即使是基于意图的最先进对话式 AI 系统也难以提供支持这些类型代理所需的广泛对话体验,尤其是在涉及多个回合和复杂上下文的情况下。LLM 技术能够提供更逼真的对话。

结论

我们已经全面审视了对话 AI 领域,探讨了其应用并承认了其局限性。现在,让我们将我们的重点转向 ChatGPT 的增强能力。这个强大的工具有可能在对话 AI 领域带来根本性的转变,为更复杂的虚拟助手、聊天机器人以及各种其他通信系统和设备铺平道路。

什么是 OpenAI 的 ChatGPT?

ChatGPT 是 OpenAI 专门用于聊天的 LLM,它使用机器学习来生成对您的文本输入类似人类的响应。

在 2022 年 11 月推出后不到一个月的时间里,ChatGPT 的用户数量就超过了 1 亿。到 2023 年 2 月,其总网站访问量飙升至 10 亿次。这种爆炸性的增长使 ChatGPT 成为历史上增长最快的消费软件应用。

ChatGPT 可以用期望的风格或编程语言解释科学和技术概念,基本上可以头脑风暴任何你能想到的问题...当然,当然可以举行复杂的对话!

理解 ChatGPT 背后的大型语言技术

ChatGPT 建立在一种称为 LLM 的 AI 类型之上。在 LLM 的领域内,有两种主要类型:基本 LLM 和指令优化 LLM。在检查 OpenAI 的 ChatGPT 时,理解这两种类型之间的区别非常重要。

探索基本 LLM

基本 LLM 被编程为预测一串单词中的下一个单词,使用从各种在线来源获得的大量文本数据集。它们的主要功能是预测给定序列的单词之后最可能出现的单词。

到目前为止,实际上预测的不是单词,而是标记;关于这一点,稍后在本节中会进一步讨论。

为了说明预测的上下文,让我们看看一些例子,从叙事生成开始。如果我们向基本 LLM 提供短语“Hey diddle diddle,the cat and the fiddle”,它可能会继续说“the cow jumped over the moon”。它使用从其庞大的语料库中学到的模式,根据其文本训练数据预测一个有趣且与上下文相关的下一个标记。

这里有一个特定查询没有得到完美回答的例子:如果您问“1988 年美国总统是谁?”基本 LLM,而不是提供直接答案(罗纳德·里根),可能会返回一个这样的声明:“美国总统在总统选举中每 4 年选举一次。”这个回答,虽然与美国总统的主题相关,但并没有直接回答原始问题,这是基本 LLM 概率预测方法的一个潜在缺点。

理解指令优化 LLM 和从人类反馈中强化学习

与基本 LLM 不同,指令优化 LLM 是专门开发来更准确地遵循指令的。因此,它们是当前 LLM 研究和应用的主要兴趣领域。

让我们看看这个过程,可以分为三个步骤:

  1. 预训练一个语言模型LM

  2. 收集数据和训练奖励模型

  3. 使用强化学习RL)微调 LM

要开始这个过程,一个指令优化的 LLM 最初是在与基本 LLM 相同的大型文本数据集上训练的。OpenAI 为其第一个流行的从人类反馈中进行强化学习RLHF)模型 InstructGPT 使用了 GPT-3 的一个较小版本。该模型通过特定的指令遵循数据进行更多微调,从而产生更精确的响应。

因此,当被问及“2020 年谁赢得了普利策小说奖?”时,一个指令优化的 LLM 可能会直接回答:“2020 年的普利策小说奖授予了科尔森·怀特黑德的《镍男孩》。”

为了提高 LLM 输出的质量,一个常见的做法是获取人类对许多不同 LLM 在某些标准上的输出质量的评分;例如,如果输出是有帮助的、真实的和无害的。

这种指令学习通过一种称为 RLHF 的方法进一步精炼,这种方法本质上优化了 LM 以使其更有用。RLHF 是一种关键的方法,用于微调 LLM,尤其是指令优化的模型。RLHF 方法基于强化学习(RL)的原则,这是机器学习的一个子领域,其中代理通过与环境的交互获得决策技能,并作为反馈接收奖励或惩罚。然而,在对话中定义明确的奖励或惩罚以区分好或坏的响应是复杂的,并且在大规模上可能不切实际。为了改进这些模型的响应,我们寻求人类的帮助。AI 训练师与模型进行对话。当模型给出不同的响应时,训练师决定哪些是最好的。他们将答案从最好到最差进行排名。这种排名给模型一种评分:好的答案得到高分。然后,模型使用这些评分来学习给出更好的答案,这个过程类似于通过分析你获得的分数来磨练你在游戏中技能的过程。

下面的图表概述了 RLHF 的过程:

图 1.5 – RLHF 的过程

图 1.5 – RLHF 的过程

这个过程通常是迭代的,包括多轮交互、反馈收集和微调,以改进模型的响应。重要的是,RLHF 比传统的监督学习SL)提供了更细致和上下文相关的反馈,从而更好地与人类价值观保持一致,并减少有害或不适当的内容。

RLHF 的挑战

尽管 RLHF 有其好处,但它也带来了挑战,并可能产生有害或事实错误的内容。

收集人类偏好数据的过程,这是 RLHF 的一个基本组成部分,可能因为需要包含人类工作者而变得成本高昂。RLHF 的有效性取决于其人类标注的质量,这包括人类生成的文本和模型输出之间的人类偏好标签。这种数据收集通常需要雇佣额外的工作人员,使得对于学术实验室来说既昂贵又具有挑战性。此外,人类标注者可能会意见不一致,这可能会给训练数据带来潜在的变异性。

RLHF 是创建有效、安全和用户友好的指令优化语言模型(LLMs)的重要工具,但它需要谨慎的实施和持续的改进。

进一步研究以提升强化学习与人类反馈(RLHF)性能的空间仍然很大。在开源或众包人类协助训练这些模型方面也存在潜力。在撰写本文时,一个成功的开源 RLHF 示例是 LAION 创建的 Open Assistant 模型,其中贡献者可以协助排名、标注和生成回复:open-assistant.io/.

标记在语言模型(LMs)中的作用

例如 OpenAI 的 GPT-3 这样的语言模型在技术上并不预测单词;相反,它们预测标记。为了理解这个概念,重要的是要认识到标记是什么以及标记化是如何工作的。

标记化是自然语言处理(NLP)中的一种常见过程,涉及将文本分解成更小的单元,称为标记。根据标记化策略,这些标记可以代表整个单词、单词的一部分,甚至标点符号。

在英语中,一个标记通常等同于一个单词,但这并不总是如此。一些标记化方法,如 WordPiece、字节对编码(BPE)或一元语言模型(Unigram LMs),被 GPT-3 等模型使用,将单词分解成更小的子词单元。例如,单词“conversational ai”可能被分成五个标记:[“con”, “versa”, “**ational”,” a”,”i”].

当我们说 LLMs 预测标记时,这意味着模型的任务是根据一系列先前标记预测最可能的下一个标记。这种标记级预测使模型能够处理广泛的词汇,包括罕见单词、人名甚至新词。它还有助于模型更有效地处理除英语以外的语言,因为许多语言具有复杂的形态学,这些形态学在简单的单词级别上无法得到充分表示。

这对于 LLMs 生成连贯且上下文适当的文本的能力至关重要。通过预测序列中的下一个标记,模型可以构建句子并完成思想,给人一种理解并生成自然语言(NL)的印象。然而,重要的是要理解这些模型并不真正理解它们生成的文本;它们是基于在训练期间学习到的模式进行序列生成的概率模型。

标记成本是确定 OpenAI 的 LLMs(包括 ChatGPT)成本的基础,这些 LLMs 具有多种能力和价格选项,我们将在后面的章节中介绍。

理解 OpenAI 的 LMs

OpenAI 凭借其开创性的 LMs,GPT,已成为对话 AI 领域的先驱。

OpenAI 的 LMs 的演变

OpenAI 的 GPT-3 是 ChatGPT 的基础架构,自 2020 年发布以来已经经历了多次改进。

GPT-3

GPT-3 于 2020 年 6 月发布,其不同的基础模型:Ada、Babbage、Curie 和 Davinci,设定了语言生成能力的新标准。每个变体都有其独特的特点。

GPT-3.5

GPT-3.5 被推出作为文本补全任务的优化版本,其中一个模型专门设计用于代码补全任务。这一系列中的最新版本gpt-3.5-turbo于 2023 年 3 月推出。gpt-3.5-turbo是 GPT-3.5 中最先进的模型,专门针对聊天应用进行了优化。最重要的是,它的成本仅为text-davinci-003模型的十分之一。该模型可以处理高达 4,096 个标记,其知识更新至 2021 年 9 月。同时,还创建了gpt-3.5-turbo-16k模型。这个模型与标准gpt-3.5-turbo模型具有相同的性能,但提供了四倍的上下文,允许进行更长和更复杂的对话。

GPT-4

2023 年 3 月 14 日推出的 GPT-4 被誉为 OpenAI LMs 中最先进的。它拥有更高的事实准确性、多模态(包括图像处理能力)和创意输出。它提供两种模型变体:gpt-4-8kgpt-4-32k,它们的不同之处在于上下文窗口的大小。

GPT-3、GPT-3.5 和 GPT-4 之间的关键差异

可用的模型在能力、上下文容量和输入类型方面存在一些关键差异:

  • 能力:GPT-4 在可靠性、创造力、协作和细微指令处理方面显著优于其前辈。OpenAI 在不同基准上进行的测试比较证明了 GPT-4 在各个领域的优越性。

  • 上下文长度:GPT 版本之间最突出的区别之一是上下文长度。虽然 GPT-3 模型可以处理最多 2,049 个标记,GPT-3.5 将这一数字提高到了 4,096 个标记。GPT-4 实现了巨大的飞跃,其两个模型分别可以处理 8,192 和 32,768 个标记。

  • 输入类型:GPT-4 不仅能够处理文本输入,还具有处理图像的能力。这种独特的能力可以彻底改变其在各个领域的应用。

  • 成本影响:更高的能力伴随着更高的价格。GPT-4 的高级功能使得每 1K 个标记的提示和补全成本更高。由于输入和输出标记的不同成本,使用成本不仅更高,而且更具不可预测性。

虽然 GPT-4 无疑在对话式 AI 领域设定了新的基准,但重要的是要记住,它并没有使 GPT-3 和 GPT-3.5 过时。每个模型都提供了独特的功能和潜在的应用。

结论

总之,ChatGPT 模型基于强化学习与人类反馈(RLHF)以及 OpenAI 的 GPT 系列模型,这些模型本身是在大量数据上训练的。

要创建 ChatGPT,最新的 GPT-3.5 Instruct 模型通过对话示例进行了微调,而不是整个互联网,以集中提高模型的专业对话能力。然后使用强化学习(RL)让模型练习其对话技能并改进其响应。

在接下来的章节中,我们将更详细地探讨其能力、用例和对对话式 AI 领域的影响。

ChatGPT 的能力和应用

大型语言模型(LLMs)提供了大量的实际用途,ChatGPT 通过其先进的 NLP 能力脱颖而出。在本节中,我们将详细探讨这项技术带来的应用范围,以及 ChatGPT 在最具潜力的行业领域中的突出表现。虽然许多这些用例对于对话式 AI 应用来说并不一定是新的,但 ChatGPT 确实有可能承担更高级的任务。

ChatGPT 的能力

在以下章节中,我们将探讨 ChatGPT 的多种应用,从自然语言理解(NLU)和自然语言生成(NLG)用于聊天机器人和虚拟助手开始。然后,我们将继续探讨其在机器翻译、摘要、情感分析和内容创作方面的能力。其他主题包括其在垃圾邮件过滤、语言教学和软件开发中的应用。最后,我们将讨论通过 ChatGPT 插件可用的扩展功能。

用于聊天机器人和虚拟助手的 NLU 和 NLG

对话式能力是本书的核心焦点,我们将更详细地探讨这些内容。

ChatGPT 的革命性能力,尤其是其维持复杂的多轮对话、涵盖不同主题和风格的能力,在对话式 AI 领域标志着重大里程碑。ChatGPT 可以完成大多数对话式 AI 系统和体验经常难以实现的任务。对于一直在使用基于意图的系统并了解挑战的资深从业者来说,ChatGPT 的出现确实具有变革性。

必须指出,看到对话式 AI 现在在各种媒体平台上获得的关注也令人兴奋,包括电视、广播和印刷媒体。

除了支持对话之外,一个不那么明显的用例是 ChatGPT 还可以作为一个工具来创建和管理基于意图系统的对话式 AI 应用。我们将在第二章中更详细地探讨这些应用。

语言之间的机器翻译

ChatGPT 支持 95 种语言。模型如 ChatGPT 中的语言翻译技术,在教育、旅行等领域的语言障碍中架起桥梁。通过学习过去的交互,这些系统提供准确的实时翻译,增强跨文化交流。

文章、报告或其他文本文档的摘要

ChatGPT 模型擅长将复杂主题压缩成简洁、易于理解的摘要。它们可以快速处理大量文本,为用户提供精确、易于消化的信息,从而消除手动研究的需求。

市场研究或社交媒体监控的情感分析

通过理解和生成类似人类的响应,工具如 ChatGPT 为企业提供了对客户情绪的更深入洞察。它们可以集成到分析并标记可能存在欺诈活动的系统中,尤其是在银行等领域的系统中。

营销、社交媒体或创意写作的内容生成

内容创作者可以利用 ChatGPT 高效地生成引人入胜的内容。从博客文章和营销材料到社交媒体帖子,该模型生成独特、用户定制的内容。它甚至可以提供主题建议、校对和编辑服务。

垃圾邮件过滤、主题分类或文档组织

在任何行业中,ChatGPT 都可以用于分类客户查询、检测可疑交易和分析内容。

个性化语言学习和辅导工具

模型如 ChatGPT 提供的语言支持,理解超过 40 种语言,扩展到个性化语言学习工具。它们可以处理多语言查询并提供帮助,从而增强语言学习中的可访问性和用户体验。

代码生成和软件开发辅助

ChatGPT 可以理解和生成多种语言的代码,包括以下语言:

  • Python

  • JavaScript

  • C++

  • C#

  • Java

  • Ruby

  • PHP

  • Go

  • Swift

  • TypeScript

  • SQL

  • Shell

    ChatGPT 简化了调试和代码重构任务,为复杂的编码问题提供高效的解决方案。它可以快速定位潜在问题,自动化手动任务,并提供高度准确的结果,使其成为软件开发人员的宝贵工具。

    ChatGPT 插件通过创建自己的代码解释器插件来扩展这些功能,旨在处理一些特定任务:

  • 解决数学问题

  • 执行数据分析和可视化

  • 在格式之间转换文件

与图像一起工作

ChatGPT 无法生成图像。然而,当与 GPT-4 结合使用时,它可以分析信息图表和图像,并根据输入回答问题。例如,您可以输入食品成分的图片,它将提供食谱,或者它可以描述信息图表。

通过使用新插件功能与其他技术结合使用,还可以通过将这些服务传递图像描述来创建图形。

ChatGPT 插件

ChatGPT 插件于 3 月份发布,是 OpenAI 的一项创新发展,旨在扩展 GPT-4 和 ChatGPT 的现实世界应用、影响和安全。

ChatGPT 插件作为专门的扩展,旨在增强 LLMs 的功能。它们使 ChatGPT 能够访问实时信息,执行计算任务,并与第三方服务交互。

开发者可以为 ChatGPT 设计插件,并且模型通过全面的文档提供了利用每个插件的具体说明。从概念上讲,插件作为 LLMs 的感觉输入,使它们能够获取太新、太个人化或太具体于上下文的、无法成为原始训练数据一部分的信息。它们还允许模型在用户的明确请求下执行安全、有限的操作。

插件提供了丰富的优势。它们解决了与 LLMs 相关的内在挑战,例如幻觉(我们将在本章后面讨论)、跟上最新发展,以及根据必要权限访问专有信息源。通过促进对外部数据的明确访问,LLMs 可以用基于证据的参考来丰富其响应,增强模型的效用,并使用户能够交叉验证输出的准确性。

插件不仅解决了当前的局限性,还为几乎任何使用场景铺平了道路。OpenAI 与来自不同行业的公司之间的合作正在改变我们与技术互动的方式,从浏览产品目录和预订航班到直接从组织订购产品。

随着 ChatGPT 插件生态系统的持续发展,我们可以期待看到更多利用 ChatGPT 强大功能的新颖应用和解决方案。

OpenAI 发布了自己的插件,包括网页浏览器和代码解释器,以及来自受信任提供商的几个第三方插件。

ChatGPT 有多聪明?

AI,尤其是像 ChatGPT 这样的语言模型,在传统的人类意义上并不一定是“聪明”的。所以,基本上,它没有意识或自我意识。相反,它在理解和生成类似人类的文本方面表现出高水平的能力,从而显得聪明。

最近的研究试图通过进行智商测试和现实世界应用来量化 ChatGPT、GPT-3 和 GPT-4 等 AI 模型的智能程度。

OpenAI 对 GPT-3.5 和 GPT-4 进行了多次专业和学术基准测试,以及为机器学习模型设计的基准测试。

结果在此有详细记录:openai.com/research/gpt-4

研究结果表明,这些 GPT 模型在各种领域的专业水平已经证明与平均水平相当,甚至在某些情况下超过了普通人类的表现。例如,ChatGPT 在语言智力测试和雷文测试(衡量抽象推理和解决问题的能力)中取得了高分,使其位于 99.9 百分位。

ChatGPT 的令人印象深刻的成就不止于此。它成功通过了西班牙医学考试和美国医学执照考试(USMLE),在雷文渐进矩阵能力测试中优于大学生,甚至通过了沃顿商学院的 MBA 学位考试。此外,GPT-3.5,GPT-3 的一个后续版本,成功通过了美国律师资格考试和美国注册会计师(CPA)考试。

ChatGPT 还被用于实际应用。它协助哥伦比亚的一名法官作出裁决,在美国撰写了几个法案,甚至登上了《时代》杂志的封面。这些 AI 模型的成就为该技术的潜力提供了非凡的证明。

ChatGPT 及其变体的成就展示了这些 AI 模型的强大能力。然而,尽管这些分数和成功凸显了它们在理解和生成文本方面的熟练程度,但我们必须记住,它们并不等同于人类的智能或意识。AI 的“智能”在于其编程以及根据该编程处理和生成文本的能力。ChatGPT 的“智能”,正如其高智商分数和实际应用所证明的那样,是对对话 AI 领域取得的令人印象深刻的进步的证明。

ChatGPT 的应用

从传统对话 AI 方法的应用,特别是更基于意图的方法,让我们来看看 ChatGPT 的一些实际应用。

商业和金融

在最近几年,商业和金融领域对 AI 的采用显著增加。从自动化财务报告生成到识别潜在的财务风险,ChatGPT 已被证明是简化运营和促进数据驱动决策的有价值工具:

  • 客户服务聊天机器人:ChatGPT 的一个关键应用,对话 AI 可以用于任何需要智能和大规模处理客户支持的职位。ChatGPT 提供了一个前线交互平台,为处理客户咨询、处理交易甚至提供个性化产品推荐的能力的代理人员提供支持。

  • 市场分析和预测:ChatGPT 的能力扩展到市场分析和预测领域,它可以分析大量财务数据,以识别模式和趋势,并对市场状况提供见解。它可以生成分析摘要,全面了解财务状况。

  • 投资管理:ChatGPT 的数据分析能力也使其成为投资管理的宝贵工具。它可以通过提供个性化的投资建议,考虑个人风险特征和财务目标,帮助企业和投资者做出明智的决策。

  • 欺诈检测:在金融安全领域,ChatGPT 可以用来检测欺诈活动。通过分析交易数据并识别欺诈活动的指示性模式,ChatGPT 可以提供强大的欺诈检测机制。

  • 风险管理:ChatGPT 在风险管理中也至关重要。通过分析财务数据并识别潜在风险,它可以帮助企业和金融机构制定减轻这些风险的策略。

  • 财务报告:通过分析数据和提供对财务表现的洞察,ChatGPT 可以用于自动化生成财务报告。

总结来说,ChatGPT 在商业和金融领域的应用广泛且具有变革性。从通过聊天机器人增强客户服务到识别风险和欺诈,这个 AI 模型提供了众多功能,颠覆了传统的商业运营,并为由智能、数据驱动策略主导的未来铺平了道路。

医疗和医学应用

可能是充满最多伦理和监管挑战的领域。在医疗保健领域,ChatGPT 强大的对话体验可以应用于医疗和医学应用。从帮助诊断和治疗规划到推动患者参与,这个领域有许多用例:

  • 患者分诊聊天机器人:ChatGPT 可以成为开发用于患者分诊的聊天机器人的重要工具。这样的系统帮助医疗保健提供者评估患者状况的紧迫性,并找到最合适的行动方案。

  • 医学诊断和治疗建议:ChatGPT 的一个引人注目的应用在于协助医学诊断和治疗建议,以帮助提高治疗计划的准确性和有效性。通过分析患者数据、症状和医疗史,ChatGPT 可以为医疗专业人员提供有价值的见解和建议,用于诊断和治疗。

  • 医学教育:ChatGPT 提供准确和全面信息的能力使其成为医学教育的宝贵工具。它可以作为医疗保健提供者和患者的信息资源,提供关于广泛医疗状况和治疗选择的资料。

在扮演培训师或面试官的角色中运用 ChatGPT 也是该技术能够大放异彩的领域:

  • 心理健康咨询:ChatGPT 可以作为提供心理健康咨询的聊天机器人的基础。通过分析患者数据和提供个性化建议,这些聊天机器人可以帮助患者管理他们的心理健康状况。尽管不能替代专业咨询,但这些 AI 赋能的平台可以提供初步的支持和指导。

    我们已经看到,会话式 AI 技术在多个聊天机器人产品中成功应用在这个用例中,例如 Woebot (woebothealth.com) 和 Wysa (www.wysa.com)。

  • 患者参与和治疗依从性:ChatGPT 还可以用于增强患者参与度和对治疗计划的依从性。它可以生成个性化的提醒和建议,帮助患者遵守他们的处方方案。这种由 AI 驱动的患者参与形式对于慢性病管理尤其有益,因为药物依从性至关重要。

ChatGPT 在医疗和医药领域的应用是多方面的,并且具有重大影响。通过在诊断、患者参与和研究方面提供可靠和基于数据的解决方案,ChatGPT 正在为 AI 辅助医疗的新时代铺平道路。

法律和法律服务

AI 正在越来越多地渗透到所有行业,法律领域也不例外。ChatGPT 的应用范围从总结法律文件和协助起草法律简报到为法律研究提供见解,以及促进法律专业人士之间的有效沟通:

  • 合同审查:ChatGPT 在审查合同时可以发挥关键作用,以确定需要进一步审查或修改的法律问题,如不一致或含糊不清的条款。

  • 法律咨询聊天机器人:这又是一个特定于会话式 AI 的应用场景。ChatGPT 可以成为提供法律咨询的聊天机器人的基础,帮助客户处理法律咨询。由 ChatGPT 驱动的代理可以分析法律数据并提供个性化建议,帮助客户了解他们的选择。

  • 文件起草:ChatGPT 可以通过分析相关法律数据并提出有见地的内容和建议,用于简化复杂法律文件(如合同和简报)的起草过程。

  • 尽职调查和电子发现:ChatGPT 可以成为进行尽职调查和电子发现的有力工具,能够评估法律文件,执行背景调查,识别可能的法律挑战,以及通过审查文本数据和识别主导趋势和模式,帮助在法律纠纷中确定相关的文件和数据。

总结来说,ChatGPT 对法律和法律服务的影响是深远的。它提供了变革性的解决方案,增强了法律专业人士的能力,使他们能够更高效、更有效地履行职责。从促进法律研究和合同审查到简化法律文件的起草和加快电子发现,ChatGPT 确实正在改变法律服务领域,塑造一个 AI 和法律实践内在交织的未来。

教育与培训

教育和培训是关于 ChatGPT 以及一般性大型语言模型的热门话题。随着 LLMs 变得越来越智能,它们在教育领域的应用也变得更加广泛,从提供实时反馈、生成吸引人的教育内容、协助教育工作者到创建适应性学习环境:

  • 个性化学习:ChatGPT 在个性化学习体验中可以发挥关键作用。通过使用关于学习者偏好的数据、优势、劣势或能力水平,ChatGPT 可以生成学习材料和活动的推荐,遵循任何特定领域的个性化课程。

  • 教师支持:同样,ChatGPT 可以通过根据特定的年龄、课程或水平提出针对性的课程计划建议,以及提供不同的课堂管理和教学方法,显著地协助教育工作者。

  • 考试准备:ChatGPT 可以成为考试准备的重要工具。它可以提供学习材料的建议,以及创建练习考试和试卷。

这些能力也可以与新的媒介,如数字人相结合,实现丰富的学习体验。

总结来说,人工智能与教育的交叉融合开辟了众多可能性。在教育领域使用如 ChatGPT 这样的 AI 语言模型,对教学和学习实践产生了深远的影响。从个性化学习、教师支持到语言学习、考试准备和在线辅导,ChatGPT 的应用正在帮助重塑教育格局,使其更加个性化、吸引人且有效。随着我们继续前进,我们可以期待在教育领域看到更多创新的 AI 应用,迎来一个由技术赋能的新学习时代。

这里列出的许多应用类似于本章早期部分涵盖的使用案例,即理解对话式人工智能应用。对话式人工智能解决方案在过去已经为其中许多应用开发过,并且成功程度各异,这并不令人惊讶。

ChatGPT 的局限性

就像其他 LLMs 一样,ChatGPT 并非完美无缺,它存在一些重要的风险、局限性和安全考虑,如果你打算在生产对话式人工智能用例中使用 ChatGPT,这些是需要注意的。

局限性

毫无疑问,ChatGPT 具有一些令人难以置信的能力,但让我们看看事情可能出错的地方。

准确性和深度

可能最著名的限制,也是人们投入最多努力克服的限制是 ChatGPT 的“信息截止日期”。早期的 GPT-4 模型是在公开可用的互联网数据上训练的,截止日期远至 2021 年。最新的 GPT 模型已经显示出改进。根据 OpenAI 的说法,最新的 GPT-4 Turbo(gpt-4-turbo)的知识截止日期为 2023 年 12 月。然而,在此之后,它并没有更新最新的信息或事件。这种限制意味着使用 ChatGPT 实现的对话式 AI 应用无法原生支持 2023 年 12 月之后发生的数据或事件,至少直到发布新的模型。

ChatGPT 回答关于私人数据或更近期信息的问题的能力,当然是许多对话式 AI 应用的核心需求,我们将在稍后更详细地探讨如何实现这一点。

幻觉与准确性

在 LLM 的背景下,“幻觉”指的是模型生成的不连贯、不相关或不准确文本的情况。ChatGPT 等 AI 系统中的幻觉问题是一个复杂的问题。这可能会发生,因为 ChatGPT 在数据中学习了某些模式,这些模式并不适用于任务的特定上下文。在其他情况下,LLM 可能会生成与输入或任务完全不相关的文本,这可以描述为“幻觉”文本。对于 ChatGPT 来说,幻觉是其中最令人担忧的问题之一。

不仅仅是 AI 编造事实;它还涉及到 AI 生成可能有害或具有误导性的信息。在 AI 的输出被用于做出重要决策或向人们通报关键问题时,这种情况尤其成问题。

主要担忧之一是 ChatGPT 生成输出的准确性。OpenAI 承认,输出有时可能是不准确的、不真实的或具有误导性的。这对那些希望依赖由 ChatGPT 驱动的生产应用的公司来说是一个复杂的问题。

准确性不仅仅是 ChatGPT 对话式 AI 应用中的一个考虑因素。任何生成内容需要经过审查并确保其真实性的地方都可能存在问题。2023 年 6 月,两名美国律师因提交来自 ChatGPT 的虚假法庭引证而被罚款。律师所在的律师事务所被处罚,因为后来发现虚假引证是由 ChatGPT 创建并作为航空伤害索赔的一部分提交的。

虽然 ChatGPT 擅长生成看似连贯和逻辑的文本,但其回答可能并不总是正确或足够详细。输出通常需要手动审查和强大的验证机制。解决幻觉问题并始终保持 ChatGPT 无法辨别事实准确性的认识,对于确保 ChatGPT 应用的可靠性和安全性至关重要。

上下文限制

ChatGPT 通过使用每次对话的新转折点之前的对话信息来管理对话上下文。这样,它知道之前说过什么,并可以利用这些信息作为其决定接下来说什么的过程的一部分。

尽管上下文理解能力有所提高,但 GPT-3.5 和 GPT-4 都有上下文限制,GPT-4 的限制显著更大。这种限制可能导致 ChatGPT 只考虑其最新的输出,而忽略了互动早期上下文的情况。OpenAI 最近还发布了一个新的聊天特定模型:gpt-3.5-turbo-16k,其上下文大小是早期模型的四倍。上下文限制可以通过总结策略和书中稍后讨论的方法进行改进。

风险和安全

ChatGPT 的快速采用和广泛使用引发了重大的安全和知识产权IP)担忧,担心技术可能被犯罪企业滥用。

财产权

另一个复杂的问题是公司的知识产权,特别是在声称对 ChatGPT 生成的内容或部分由 AI 生成的内容拥有权利时。

根据 OpenAI 的使用条款,用户拥有输入内容的所有权,而 OpenAI 则将所有权利、标题和利益转让给输出内容。然而,OpenAI 无法转让其最初不拥有的内容的权利。这导致了关于 AI 生成知识产权及其所有权的未解决问题。

安全

并非必然与 AI 和 ChatGPT 功能本身相关的安全问题,但考虑到 OpenAI 的用户数量,这确实是一个非常现实的问题。2023 年,当 OpenAI 确认由于代码开源库中的漏洞导致的数据泄露时,ChatGPT 自身的安全性受到了考验。这次泄露使得用户能够看到其他活跃用户的聊天历史,引发了关于用户数据安全性的担忧。漏洞很快得到了修复,但它凸显了使用 AI 技术可能带来的潜在风险。

在另一起事件中,更深入的调查发现,同样的漏洞可能暴露了支付信息几个小时,直到 ChatGPT 被关闭。这一事件进一步引发了关于敏感用户数据安全性的担忧。

ChatGPT 插件的日益流行也可能通过无意中启用有害或未预期的行为来放大安全风险,尽管 OpenAI 做出了最大努力。

教育担忧

如前所述,ChatGPT 可以通过教育测试并执行现实世界的应用。这导致了教育专家和学术界的担忧,因为存在伦理问题、作弊和学校中的滥用。

许多学术机构已经在其网络上禁止了这项技术,这是一个徒劳的措施,但也表明人们确实担心学生可能会利用 ChatGPT 来写论文、作弊并规避学习过程。这引发了关于学术机构诚信以及学习和教育本质的问题。随着 LLM 能力的增长,这些问题只会随着其他 LLM 技术在识别 AI 生成内容方面的增长而增加。

隐私担忧

使用 AI LMs(如 ChatGPT)也引发了隐私担忧。这些模型存储了大量的数据,并使用这些信息来生成回应。

已用于训练模型的内容是一个主要问题,但一个更紧迫的问题是 ChatGPT 对话数据会发生什么。

如果将敏感数据,如组织的知识产权或敏感客户信息,输入到聊天机器人中,这些数据就会进入聊天机器人库,并超出用户的控制。

作为对这些担忧的回应,一些企业和国家已经加强了对 AI 使用的限制。例如,摩根大通和苹果公司出于对安全的担忧,限制了员工使用 ChatGPT。

由于通用数据保护条例GDPR)合规问题的担忧,意大利暂时在全国范围内封锁了该应用程序。

值得注意的是,ChatGPT 允许用户停止记录聊天历史,但如果用户将内部数据(如病历)作为其提示工程的一部分,这是一个重要的考虑因素。

恶意使用

ChatGPT 的许多优势,如逼真的对话能力和文本生成,很可能会被用于犯罪目的,从工业规模的增强钓鱼到有针对性的虚假信息传播。

犯罪分子也将被赋予使用更不传统的媒介,如消息平台,来进行针对性攻击的能力。

在过去,钓鱼邮件通常具有语法差和句子结构不寻常的特点,这使得它们很容易被识别。犯罪分子将利用 ChatGPT 来开发令人信服的钓鱼邮件。这些邮件现在可以模仿母语人士并传递定制信息。ChatGPT 无缝翻译语言的能力预计将大大提高外国犯罪分子进行全球攻击的能力。

偏见

与许多其他 LLM 一样,ChatGPT 是在互联网上的人类生成内容上训练的。因此,ChatGPT 容易受到各种偏见的影响,包括性别、种族、文化、语言、意识形态和商业偏见,以及其他一些偏见。

偏见问题范围广泛;以下是一些例子:

  • 生成内容未能融入对多样化个人经验和语言细微差别的全面视角

  • 制定基于性别或种族分配角色或工作的回应,从而加强现有的刻板印象

  • 创建描绘对某些社会哲学或政治意识形态有微妙偏见的文本

  • 产生反映训练数据中存在的占主导地位叙事的内容,导致产生耸人听闻或寻求注意的标题和声明

即使有安全措施,这些模型有时也会说出性别歧视/种族主义/恐同的话。在使用面向消费者的应用程序中的 LLM 时要小心,使用 ChatGPT 进行研究时也需要谨慎。

摘要

总结来说,在本章中,我们看到了对话式人工智能如何从基于规则的系统稳步发展到以人工智能驱动的意图为基础的系统。通过观察 ChatGPT 的应用,我们了解到随着现代对话式人工智能系统能力的增长,对话式体验的使用范围和深度也在增加。有成千上万的这些系统,在多个行业中执行复杂的任务。

从我们对 ChatGPT 的最初关注来看,我们发现它是一个强大的工具,具有通过承担更多复杂任务和用例来革命化对话式人工智能领域的潜力,这些任务和用例直到最近都难以用现代对话式人工智能平台实现。它在许多行业中提供了广泛的应用,包括客户服务、医疗保健、金融、法律、教育等。

然而,本章也强调了了解其局限性和风险的重要性,包括准确性和深度限制、幻觉、上下文限制、安全问题、隐私问题以及偏见。这些挑战在开发和部署 ChatGPT 应用时需要仔细考虑和缓解策略。随着我们继续前进,解决这些限制并确保 ChatGPT 负责任、道德地使用,并采取适当的保护措施至关重要。

在我们开始探讨使用 ChatGPT 创建对话式应用之前,让我们先看看这项技术如何在传统的对话设计中得到应用。

在下一章中,我们将更深入地探讨 ChatGPT 的对话设计应用。我们将探讨如何使用 ChatGPT 设计有效和吸引人的对话,涵盖对话流程、用户提示、系统响应、上下文管理等多个主题。加入我们,一起揭示创建强大和有意义的对话式人工智能体验所需的实用技能。

进一步阅读

要了解更多与本章节相关的话题,您可以访问以下链接:

2

使用 ChatGPT 进行对话设计

在本章中,我们将深入探讨 ChatGPT 与对话设计的交集。我们将探讨对话设计师的角色,并探讨大型语言模型LLMs)如 ChatGPT 如何影响对话设计。我们还将检查 ChatGPT 在对话设计中的实际应用,包括其在模拟对话和创建角色中的应用。最后,我们将讨论测试和迭代设计在创建有效和引人入胜的对话人工智能系统中的重要性。到本章结束时,您将全面了解如何利用 ChatGPT 进行对话设计。

列出了一些提示结果,而为了节省空间,其他结果已被省略。我们鼓励您亲自尝试这些提示。

在本章中,我们将介绍以下主要内容:

  • 理解对话设计

  • 在对话设计中应用 ChatGPT 的实用案例

  • 模拟对话

  • 使用 ChatGPT 创建角色

  • 使用 ChatGPT 进行对话设计的测试和迭代

技术要求

在本章中,我们将使用 ChatGPT。我们建议您在 OpenAI 上注册账号。

理解对话设计

对话设计是一个复杂且重要的角色,对于创建一个既有帮助又自然、因此成功的聊天机器人或语音助手至关重要。对话设计领域还有其他角色,尤其是 AI 训练师及其变体。为了本书的目的,在讨论对话设计时,我们将考虑这些其他角色,因为许多任务的执行在这些角色之间有很大的重叠。

对话设计利用用户体验设计、语言学、认知心理学和人工智能的原则,通过声音或文本媒介在人类和机器之间创造引人入胜的互动体验。在核心上,对话设计师理解沟通、对话人工智能的技术环境、部署给用户的媒介以及如何满足用户需求。

对话设计的目的是创建一个平滑、直观且自然的用户界面,使用户在使用过程中感觉像是在进行真实的对话,这是通过利用现有技术来模拟类似人类的对话实现的。

探索对话设计师的角色

对话设计师执行几个重要的任务。这些任务很重要,因为我们可以看到 LLMs 和 ChatGPT 如何用于简化并改进这个过程。让我们看看创建对话设计所涉及的过程。这些设计将在项目所选的对话人工智能平台上实施。

理解用户需求

对话设计的第一步是理解用户的需求和行为,以及对话发生的背景。

对话设计师的角色是理解组织的运营、流程、挑战和目标。一个好的设计师可以将业务需求转化为客户旅程、用例和自然流程。设计师需要了解目标用户的角色,包括他们的年龄、人口统计、需求、期望和语言。他们还需要了解组织或应用中的当前交互。对现有查询和现有非结构化或结构化数据的深入了解在这里尤为重要,对对话体验将部署到的渠道的深入了解也同样重要。

设计角色

代理角色的设定不仅决定了其语音的语气,还指导了其对话方式。这需要仔细考虑,以匹配用户需求。

还需要考虑现有的品牌和内容指南。

例如,部署在企业软件平台上处理客户支持查询的聊天机器人,其语气和角色将与设计用于在新生周期间帮助学生在 WhatsApp 上查询的代理不同。

设计对话

对话流程是用户与对话代理之间交互的序列。

对话设计师需要优先考虑现有用例,以了解代理需要执行哪些任务,以及如何构建对话来实现这一目标。

意图澄清、话语创建和实体澄清

意图代表了用户的意图。例如,意图可能是查询订单状态或预订航班。每个意图都与一组话语相关联,这些话语是用户可能用来表达该意图的短语。例如,对于检查航班状态的意图,话语可能是“我的航班什么时候起飞?”或“我的航班 准时吗?”。

实体是聊天机器人需要用来实现意图的具体信息片段。例如,对于预订航班的意图,实体可能包括出发城市、目的地城市和旅行日期。理解每种实体及其不同条目是对话设计师的工作。常见的实体通常比较直接,因为它们得到了对话人工智能模型的支撑。然而,如果需要自定义实体,每个都需要单独获取。例如,一个狗训练聊天机器人可能需要理解所有不同的狗品种。

对话设计

用户旅程图

设计师会仔细编写对话和响应的不同路径。这些路径基于潜在的用户输入,其中需要收集信息以使用户能够表达他们的需求,并使代理收集回答查询所需的值。设计师从通常所说的“快乐路径”开始,这是通过对话实现目标的最简单途径,然后扩展以处理对话周围的边缘情况。

设计需要支持其他情境边缘情况,例如未处理的意图、不匹配的意图、输入时,以及用户尝试引导对话的任何其他方式。这里有很多东西需要记录。随着对话的多次转折,这些设计可能会变得复杂,因为对话通常不是线性的,用户可能会改变话题或提出意外的问题。这是对话设计师在设计中包含这些内容的职责。

对话设计可以通过多种不同的方法在项目利益相关者之间共享,如下所示:

  • 最后一步是编写聊天机器人的实际回复文本。这涉及到使用有说服力和引人入胜的语言引导用户通过对话。文案应反映聊天机器人的个性,并与品牌的语气和风格保持一致。对于拥有数百甚至数千个回复的大型代理,挑战通常在于确保一致性,尤其是如果有几个对话设计师同时或随着时间的推移在一个项目上工作。随着对话式 AI 项目的成熟,这种情况发生的可能性更大。由于每个参与者都会为项目带来自己的风格,语气可能会偏离代理的原始个性和品牌指南。

  • 电子表格

  • 模拟代码

  • 对话管理软件,例如 Voiceflow

根据项目规模、团队和预算,以及个人偏好,没有一种适合所有对话设计工具的方法。只要它们易于迭代和协作,这些设计通常会在签署前被多个不同的团队触及。然而,一些更受欢迎的对话管理工具提供了比设计和协作更多的功能,并包括一些利用 LLMs 的非常有用的功能。这将在下一节中介绍。

写作

对话设计师的职责是创建交互的细节。这包括设计用户与对话代理之间的对话流程。它包括定义聊天机器人将用于引导对话的提示、用户响应和代理的回复。对话应该设计得自然且引人入胜,并引导用户实现他们的目标。

现在我们已经涵盖了对话设计师的角色以及对话设计实施对话式人工智能解决方案之前构成该过程的具体任务,现在是时候看看 ChatGPT 可以在这些特定的工作流程中如何被利用了。

在对话设计中与 ChatGPT 的实际应用合作

从我们对对话设计所需执行的任务的理解来看,很容易看出在某些领域,我们可以利用 ChatGPT 来帮助完成这些任务。一些最受欢迎的对话设计工具也提供了作为其功能一部分执行这些任务的能力。

小贴士

记住,ChatGPT 是一个对话设计工具,而不是对话设计最佳实践的替代品。

使用 ChatGPT 进行意图聚类

意图是大多数传统对话式人工智能代理的核心概念。意图的存在是为了定义用户的意图,并且每个意图都需要一组语句来触发这个意图。许多对话式人工智能实现都是从大量的实时聊天数据、语音转录或其他非结构化文本数据开始的,这些数据将形成聊天机器人或语音界面需要支持的任务或意图的基础。

意图聚类有什么用?

一个对话式人工智能项目可能还处于起步阶段。它也可能是一个在重压下使用或主题内容经常变化的成熟项目。通常,对话设计师或 AI 训练员的任务是使用这些数据通过聚类非结构化训练数据或语句来理解和优先排序意图。

例如,如果你正打算从实时聊天转向聊天机器人自动化,你可能有一大堆历史聊天记录。你需要查看这些记录并决定哪些常见问题或意图被问得最多。同样,处理特定流动主题(如假日)的聊天机器人或语音助手可能需要定期更新以回答由外部因素引起的新问题。这些新问题可以通过聚类来突出显示。

什么是意图聚类?

意图聚类本质上意味着查看大量数据并寻找语义相似句子的分组。因此,对于我们的用例,我们将查看我们的非结构化聊天数据,并根据语义相似的意义进行分组,这样我们就可以开始浮现意图。

在过去,通过聚类进行意图浮现的过程涉及使用嵌入的复杂过程,或者使用如 HumanFirst 之类的专有解决方案。这个过程将遵循以下步骤:

  1. 数据收集:组装你想要分析的文本数据集合。这可能包括科学文章的集合到用户生成内容的数据库。

  2. 嵌入生成:使用 TensorFlow 等机器学习库、Word2Vec 等服务或双向编码器表示的 Transformer(BERT)来生成文本数据的相似性嵌入。这些嵌入是高维向量表示,能够捕捉文本的语义内容。因此,如果一个文本与另一个文本具有相似的意义,那么这些嵌入将更接近。

  3. 聚类算法:将无监督机器学习算法(如 K-means)应用于生成的嵌入。这些算法根据点之间的密度和距离将高维嵌入空间分离成聚类。

  4. 聚类分析:一旦完成,应该有一组包含语义相似文本的话语聚类。分析这些聚类可以揭示意图或问题,然后可以用来训练基于意图的机器学习模型。

在本质上,在这个上下文中,聚类是一种无监督技术,它使用语义嵌入将相似文本分组在一起,有助于发现非结构化文本数据大型文本数据集中的潜在意图。

学习如何使用 ChatGPT 创建意图聚类

当你遵循提示工程的基本规则时,使用 ChatGPT 实现这一点很简单:指令、上下文、输入数据和输出指示器。我们将在第四章中更详细地介绍更多提示工程的示例。

对于我们的意图,提示可能看起来像以下这样。重要的是要注意,设计提示是一个迭代过程,有时需要实验才能得到你想要的结果。

对于我们的第一个示例,我们正在考虑为我们的大学网站创建一个聊天机器人,该机器人将回答有关大学的问题。我们有一组从实时聊天实现中收集的非结构化话语。

对于这个示例,我们在提示中使用了指令、输入数据和输出指示器。指令和输入数据处理告诉 ChatGPT 我们想要什么以及使用哪些话语。输出指示器还显示了我们想要的输出格式。在这种情况下,JSON 将最有用,因为我们正在考虑将意图或话语作为自动化过程的一部分使用。该模型还会处理其他输出格式,如 CSV。它看起来像这样:

Look at the following utterances from livechat transcripts and cluster them into intents
Utterances:   "can you tell me where is the college located", "where's the college", "where is college located", "how can I reach college","whats is the college address", "whats the Syllabus for IT", "what is the Information Technology syllabus"," "Whats my next lecture"
Output: Return as JSON in the following format-{"intent": {name},"utterance":{utterances}}

结果应该看起来像以下这样:

[
  {
    "intent": "Get_College_Location",
    "utterances": ["can you tell me where is the college located", "where's the college", "where is college located", "how can I reach college"]
  },{
    "intent": "Get_College_Address",
    "utterances": ["whats is the college address"]
  }
]

除了通过 ChatGPT 界面手动创建意图外,还可以通过直接使用 ChatGPT API 进一步自动化此过程。

扩展示例以创建意图

考虑到我们的聊天机器人用例,我们可能希望通过创建更多的意图来构建我们的意图集。例如,如果你的实时聊天数据有限,并且你希望扩展到其他意图,你可以使用 ChatGPT 执行一个任务,利用你现有的某些意图和话语来创建更多的意图和话语。

让我们通过使用我们之前示例的输出来创建我们的提示,提示意图聚类,您可以在提示中看到{input_data}占位符:

Look at the following intents and utterances for a chatbot which will answer questions about a college, these JSON objects consist of an array of intent objects, each of which includes a name and a list of corresponding utterances.
Create another 5 examples of intents and ensure that each intent has 10 utterances:
Intents:
{input_data}
Output: Return as JSON in the following format-{"intent": {name},"utterance":{utterances}}

如果我们运行这个提示,我们可以看到这效果很好。这是输出:

[
  {
    "intent": "Get_College_Events",
    "utterances": ["Whats happening on Tuesday","What are the upcoming events?", "Can you tell me about any college events?", "What's happening on campus?", "What events are scheduled this month?", "Is there a college event this week?", "Are there any sports events coming up?", "When is the next cultural fest?", "Are there any seminars or workshops?", "What's the college event calendar?", "Are there any academic events happening soon?"]
  },
  {
    "intent": "Inquire_About_College_Facilities",
    "utterances": ["What facilities are available in the college?", "Does the college have a library?", "Can you tell me about the sports facilities?", "What are the lab facilities in the college?", "Are there any on-campus cafeterias?", "Does the college have a gym?", "Are there any hostel facilities?", "Does the college have a swimming pool?", "Tell me about the medical facilities", "Are there any recreational facilities in the college?"]
  },
...
 ]

理解话语和实体生成

在现代对话式 AI 系统中,意图和实体是至关重要的组件,它们使系统能够理解和处理人类语言,从而实现更自然和有效的对话。创建这些元素的任务是对话设计师最常见的任务之一。这些元素可以用来训练我们用于对话式 AI 平台的机器学习模型。

创建话语

在之前的如何使用 ChatGPT 创建意图聚类部分,我们探讨了如何从非结构化训练数据中聚类话语以提取意图。ChatGPT 也可以用来创建话语。

如果我们没有足够的话语来满足特定的意图,我们可以提示 ChatGPT 为特定意图创建一组话语,如下所示:

Consider a "Get_College_Events" intent for a chatbot which will answer questions about college events.
Create another 10 examples of utterances for each intent:
Output: Return as JSON in the following format-{"intent": {name},"utterance":{utterances}}

结果令人惊讶地好:

[
  {
    "intent": "Get_College_Events",
    "utterances": ["What's happening in college this week?", "Tell me about the upcoming college events.", "Are there any events in college next month?", "Is there a sports meet this year?", "What are the details of the cultural fest?", "When is the next science fair?", "Is there any guest lecture scheduled soon?", "When is the annual college fest?", "Are there any workshops I can attend?", "Can you give me a list of events for this semester?"]
  }
]

我们还可以更具体地说明话语的类型。例如,如果我们想要更广泛的话语范围,我们可以提示 ChatGPT 提供更长的尾例。让我们以“获取大学位置”意图用例为例,并将长尾话语添加到现有话语中:

Look at the following intent for a chatbot that will answer questions about a college, these JSON objects consist of an array of intent objects, each of which includes a name and a list of corresponding utterances.
Create another 5 examples of long tail utterances for each intent and add to the array of utterances
Utterances:
[
  {
    "intent": "Get_College_Location",
    "utterances": ["can you tell me where is the college located", "where's the college", "where is college located", "how can I reach college"]
  }
]
Output: Return as JSON in the following format-{"intent": {name},"utterance":{utterances}}

这使得我们的 NLU 训练数据集拥有更广泛的话语范围:

[
  {
    "intent": "Get_College_Location",
    "utterances": ["can you tell me where is the college located", "where's the college", "where is college located", "how can I reach college", "I am new to this city, can you guide me to the college?", "Can you provide the exact location of the college?", "I am not familiar with the area, could you help me find the college?", "I would like to visit the college, can you tell me its location?", "I need directions to the college, can you help?", "Could you give me the location details of the college?"]
  }
]

每个创建的话语都符合我们的标准,具有更对话式和复杂的(长尾)格式。

小贴士

记住,人工训练数据,即使是 LLM 创建的,也不能替代真实的使用数据。当我们为语音创建话语时,这一点尤其正确,因为 ChatGPT 是在文本数据上训练的。

创建实体

ChatGPT 非常擅长的一项生成任务是创建实体。

实体是与意图相关的特定信息片段。它们是提供用户请求细节的变量。

例如,考虑我们的Get_College_Events意图。为了正确回答问题,我们需要了解一些事情:事件的日期和类型。虽然系统日期通常由对话式 AI 平台支持,但为了训练 NLU,通常需要创建自定义实体。对于这个特定用例,事件类型就是我们需要填充的自定义实体。我们可以请 ChatGPT 帮助我们。记住,提示要尽可能具体。在这种情况下,我们要求输出格式正确,以便导入我们的对话式 AI 平台:

Consider a "Event_Type" entity which needs to be extracted from utterances for the Get_College_Events for a chatbot which will answer questions about college events.
Create 5 examples of entity_val and 5 synonyms  for each entity type:
Output: Return as JSON in the following format-{"entity_val": 
{entity_val},"synonyms  ": [synonyms]  }

结果是一套全面的实体类型及其对应同义词:

[
  {
    "entity_val": "seminar",
    "synonyms": ["workshop", "conference", "symposium", "meeting", "forum"]
  },
  {
    "entity_val": "sports meet",
    "synonyms": ["athletic meet", "sports event", "sports day", "athletic event", "games"]
  },…
]

通过正确地找到和处理实体,ChatGPT 可以快速创建精确而有用的响应。

在没有任何客户对话数据的情况下,ChatGPT 的话语可以作为启动聊天机器人进行进一步迭代的好方法。

使用 ChatGPT 帮助你编写对话

写出引人入胜的聊天和语音对话是对话设计师角色的重要部分。那么,ChatGPT 如何帮助,你甚至应该考虑使用它吗?

理解编写对话的挑战

作为对话设计师,我们工作中最吸引人但最具挑战性的方面之一是制定我们的聊天机器人或语音助手的回复。毕竟,这是你展示自己的机会。好的对话是平淡的对话体验和真正吸引用户的对话体验之间的区别。

创建示例对话,确保对话流程中各部分对话之间的流畅过渡,并为高度特定的情境制定精确的回复都需要时间和仔细的考虑。这一切都是在应对满足截止日期的压力、保持利益相关者知情并采取反馈行动的同时完成的。以下是一些需要考虑的事项:

  • 保持与你的 AI 助手角色相呼应的语气和语调

  • 遵守公司内容指南

  • 使用与您可能需要提供给用户的内容相一致的语言

  • 能够并一致地处理错误情况

  • 在说得太多和过于冗长之间找到平衡

  • 确保制定的回复在各种模态下都有效,而不仅仅是理论上

  • 解决可能影响我们使用语言并影响最终用户的固有偏见

  • 仔细遵守法律和合规指南,以确保我们使用的语言是正确的,不会让你陷入法律麻烦

从本质上讲,编辑对话对话是一系列复杂的任务,需要创造力和精确性的微妙平衡。

使用 ChatGPT 编辑你的对话

ChatGPT 可以执行多项任务来增强你的对话。让我们深入探讨几个例子,例如为了提高可读性而重写、检查内容指南或创建不同版本的副本以获得更好的对话体验。

为了提高可读性而重写

如果你有的副本不是为你自己的用例编写的,但你仍然需要传达包含的信息,你可以要求 ChatGPT 为你重写。以下是一个执行此操作的提示示例。这是一个临床试验患者信息表的副本:

I'm writing a chatbot response for my "what is the purpose of this drug trial" intent. Revise this dialogue to make it more understandable for clinical trial patients and ensure it's under 100 words:
Chronic kidney disease (CKD), affecting 1 in 10 UK adults, is a progressive loss of kidney function that can lead to complete kidney failure, requiring dialysis or transplantation. High blood pressure treatment, especially with drugs like Angiotensin Converting Enzyme inhibitors (ACEi) or Angiotensin Receptor Blockers (ARBs), can slow CKD progression. However, recent research suggests that stopping these drugs in advanced CKD (stage 4 or 5) can stabilize kidney function and delay dialysis, indicating these drugs might contribute to kidney function decline. To confirm this, the ACEi trial will recruit 500 CKD stage 4 or 5 patients on ACEi/ARBs treatment, randomly allocating half to continue and half to stop their treatment. The trial will also examine other effects of stopping these drugs, such as heart effects and participant quality of life.

从结果中,你可以看到 ChatGPT 在总结内容方面做得非常出色:

The STOP-ACEi trial is for CKD patients, a kidney condition affecting 1 in 10 UK adults. We're studying if stopping certain blood pressure drugs (ACEi/ARBs) can help stabilize kidney function and delay the need for dialysis. We'll have two groups: one continues the medication, the other stops. We aim to understand the best approach for CKD treatment

尝试使用你自己的示例文本。持续迭代你的提示,直到你满意为止。

另一个良好的对话创建示例是为特定目的重写内容。例如,如果我们想从描述性副本中创建一组简洁的指令,我们可能会使用以下内容:

I'm writing copy for my dog training chatbot intent "how do i teach my dog to sit". Rewrite these instructions into a set of steps in the style of Barbara Woodhouse. Each step can only be 150 characters. Also write an introductory sentence:
Training a puppy to sit is one of the most basic commands and is useful in various situations. Start by holding a treat close to your puppy's nose and then move your hand up, allowing their head to follow the treat and causing their bottom to lower. Once they're in sitting position, say "sit", give them the treat and share affection. Remember, repetition is key. Practice this command a few times each day and be sure to reward your puppy for sitting even without command, to reinforce this behavior.

提供具有上下文、输入和输出指令的简洁指令会产生良好的结果,并且是我们可以工作的内容。尝试使用你自己的示例。

认为我们可以自动化响应创建是很诱人的。然而,这样做并不明智。ChatGPT 创建的内容只是一个起点。确保 ChatGPT 提供正确的信息,同时不改变意义,并遵守您的对话设计要求是至关重要的。

使用 ChatGPT 创建用户画像

用户画像在以用户为中心的设计中是关键组成部分,因为它们使组织能够了解其目标受众,并构建满足他们需求的具体解决方案。本节将深入探讨如何使用 ChatGPT 生成复杂和智能的用户画像。

真实世界案例

来认识 LuxeLocks,我们虚构的一家专注于销售高端护发产品的公司。LuxeLocks 热衷于为其客户提供高端、高质量的产品,将他们的头发变成令人瞩目的荣耀。为了将客户服务提升到新的水平,并实现全天候解答疑问,LuxeLocks 决定实施聊天机器人。

这个聊天机器人将被设计成以多种方式协助客户,从根据他们的发质和需求帮助他们选择完美的产品,到回答关于产品使用和成分的常见问题,甚至协助订单跟踪和退货。

通过提出问题和呈现场景,您可以深入了解用户偏好、行为和痛点。

用户画像的创建基于硬事实和特定用户数据。使用 ChatGPT 不是逃避真实研究的捷径,但它可以帮助。

使用 ChatGPT 进行用户研究

在本书的范围之外,概述通过调查、访谈和市场研究收集关于目标受众信息的过程。这也无法替代。以下是一些外部资源,您可以了解更多关于此过程的信息:

然而,使用 ChatGPT 帮助您提出一些进行研究的想法是可行的。您可以使用以下提示:

Create an outline for market research, including surveys, interviews, and additional market research methods for a luxury haircare brand:

至少,输出可以成为开始您研究的基础。这可能看起来像这样:

A. Customer Interviews:
Purpose: Gain deeper insights into the customer experience.
Sample Questions:
Describe your haircare routine.
What led you to try our brand?
Are there any challenges you have faced with our products?
B. Expert Interviews:
Purpose: Gather insights from industry experts, such as hairstylists or dermatologists.
Sample Questions:
What trends are you currently noticing in the luxury haircare market?
How do you think our brand is perceived in the market?
IV. Additional Market Research:
A. Competitor Analysis:
Purpose: Understand the competitive landscape.
Identify key competitors in the luxury haircare market.
Analyze their product range, pricing strategy, marketing efforts, and customer reviews. Identify their strengths and weaknesses.
B. Focus Groups:
Purpose: Gather qualitative data on potential new products or marketing strategies.
Assemble a diverse group of individuals who are part of the target market. Present them
with new product concepts, packaging designs, or marketing materials.
Facilitate a discussion to gather their feedback and impressions.
C. Market Trend Analysis:
Purpose: Identify current trends in the luxury haircare market.
Review industry reports and publications for data on emerging trends.
Analyze social media and influencer content to identify popular products and ingredients.
…..

一旦您有了详细信息,您也可以使用 ChatGPT 来分析数据,并揭示一些关于用户群体的细节:

Based on the following data {data}, please describe the main demographic characteristics and preferences of our target audience.
Preferences:
Characteristics:

LuxeLocks 用户的偏好和特征可以帮助我们构建我们的用户画像,并为我们的聊天机器人画像提供指导。

创建我们的用户和聊天机器人画像

您可以使用从早期提示中创建的人口统计特征来帮助您创建用户和聊天机器人的角色。

创建我们的用户角色

让我们提示 ChatGPT 创建一个角色,并使用我们早期提示中的偏好和特征的结果。将提示中以下内容中的characteristicspreferences替换为这些值:

Create a user persona description for a luxury haircare brand. Users tend to have these Characteristics: *characteristics*
Preferences: *preferences*
The persona is to be the user of our luxury haircare brand over multiple channels. The brand sells high end haircare products which are targeted at specific hair types:
Use the following template:
Name: {first_name}
Age: {age}
Relationship status: {relationship_status}
Occupation: {occupation}
Location: {location}
Interests: {interests}
Bio: {bio}
{first_name}'s motivations:
1\. {motivation 1}
2\. {motivation 2}
3\. {motivation 3}
{first_name}'s goals:
1\. {goal 1}
2\. {goal 2}
3\. {goal 3}
{first_name}'s frustrations:
1\. {frustration 1}
2\. {frustration 2}
3\. {frustration 3}
{first_name}'s Key concern/barrier to purchase:
1\. {barrier 1}
2\. {barrier 2}
3\. {barrier 3}
A quote from {first_name}'s: {quote}

我们可以使用由此产生的角色描述在后续问题中向 ChatGPT 提问。

创建我们的聊天机器人角色

您还可以使用 ChatGPT 来创建聊天机器人或虚拟助手的角色。与任何提示一样,您可以调整包含的信息量,但我发现更详细的提示会产生更好的结果。尝试使用以下内容:

Create our luxury haircare chatbot persona:
Name and Title:
What is the chatbot's name?
Does the chatbot have a title or role (e.g., Customer Care Assistant, Haircare Expert)?
Background and Purpose:
Why was this chatbot created?
What is its primary role in interacting with customers?

我们现在可以使用用户和聊天机器人的角色来引导 ChatGPT 在创建对话和交互相关的进一步任务中。

模拟对话

ChatGPT 可以用来创建具有特定角色的潜在用户的样本对话,这可以帮助您创建对话流程。再次强调,这不应取代对话流程设计过程,而是一种查看特定用例的有效方法。

什么是样本对话?

样本对话包括用户和代理之间特定多轮对话的例子。

对于参与对话体验设计和开发的人来说,这些对话片段是必不可少的工具。它们使我们能够探索对话可能遵循的潜在路径,并评估哪些分支需要考虑并整合到最终的对话设计中。

User: What's the luggage limit for my flight to Paris?
Chatbot: May I know the airline you are flying with?
User: It's AirExcellence.
Chatbot: For AirExcellence, you're allowed one carry-on up to 10 kg and one checked bag up to 23 kg. Carry-on size: 55 cm x 40 cm x 23 cm.
User: Thanks!
Chatbot: You're welcome! Have a great flight.

现在让我们看看在下一节中创建我们自己的聊天机器人对话。

创建样本对话

在以下提示中,我们提供有关语气、语言、澄清和对话元素的信息。我们希望在这种情况下提供这些信息,以确保我们已解决问题:

Generate a conversation between a user and a customer support chatbot. The user is trying to troubleshoot a problem with their internet connection. The chatbot should follow these content guidelines:
1\. Maintain a polite and professional tone throughout the conversation.
2\. Use simple, clear language that is easy for the user to understand.
3\. Ask clarifying questions to accurately diagnose the problem.
4\. Provide step-by-step instructions to resolve the issue.
5\. Confirm that the user's problem has been resolved before ending the conversation.
6\. If the chatbot cannot resolve the issue, it should suggest the user to contact a human support representative.
User: "Hello, I'm having trouble with my internet connection. It's really slow."

这产生了一个好的对话示例。尝试不同的变体是值得的,这样您可以建立起对对话可能走向的理解。

在这个阶段,我们正在设计流程,但稍后我们也会看到,我们可以将这种类似的技术作为测试过程的一部分使用。

使用角色创建样本对话

我们可以通过将更多关于用户和代理角色的信息传递到提示中,来构建迄今为止主要集中在特定用例上的样本对话的创建:

We are going to create some sample dialogues between our luxury haircare chatbot and a user:
User persona:
Name: Sophia
Age: 42
Relationship status: Single
Occupation: Corporate Wellness Coach
Location: London, UK
Interests: Pilates, Culinary Arts, Wine Tasting, Sustainable Fashion, Volunteering
...

这里的技巧是向 ChatGPT 提供您的用户和聊天机器人角色的详细信息。一旦您向 ChatGPT 提供了这些信息,您就可以给出后续提示,请求更多对话示例或用例。

这种技术在查看示例用例时也会有效。在下一个提示中,我们将在此基础上构建,并要求另一个对话示例:

Using the persona descriptions of Sophia and Lila, create a conversation between them in which Sophia is asking about the best shampoo for her hair type.. Lila asks whether Sophie would like to do her quiz so she can learn about her hair.

ChatGPT 的回应在这里很令人印象深刻,因为它更进一步,创建了一些测验问题,尽管最好的选择是包括您的测验细节。

详细提示以创建对话示例的技术也可以用于测试和进一步的迭代,我们将在下一节中介绍。

使用 ChatGPT 进行对话设计和迭代测试

对话设计是一个迭代的过程。自动化代理总是在变化和改进。在本节中,我们将探讨如何使用 ChatGPT 测试和改进我们的代理。

使用 ChatGPT 进行测试

在前面的章节中,我们了解到 ChatGPT 可以通过创建对话来帮助我们设计,从而成为简化设计流程的有价值工具。在我们部署代理之前测试代理时,我们也可以采取类似的方法。

我们通常根据我们认为他们会被问到的哪些问题来创建我们的代理。如果我们是从零开始,几乎没有训练数据的话,这种情况就更加可能。如果是这种情况,在将代理发布到野外之前测试你的代理就更加重要。

即使对话人工智能项目有内部测试人员,或者你可以在 alpha 或 beta 发布前将你的代理展示给朋友或家人,但在将其交给人类用户之前尽可能彻底地进行测试仍然很有价值。这就是 ChatGPT 可以发挥作用的地方。

用于测试的对话模拟

这个过程与设计过程类似。我们可以创建模拟,其中 ChatGPT 扮演用户角色。然后,你可以构建一系列测试用户交互脚本,以便在无需真实用户参与的情况下与聊天机器人进行交互。

我们将以我们的豪华护发聊天机器人示例为背景来考虑这一点。与 ChatGPT 用于创建实体和话语的方式相同,我们也可以用它来生成反映现实对话的额外训练数据。

小贴士

如果你继续使用之前的 ChatGPT 会话,我们已经有提示了我们的角色。如果你开始一个新的会话,请记住将它们添加到你的提示中,以设置上下文。

因此,我们将简单地要求 ChatGPT 创建以问题形式呈现的训练数据结果,这些问题涵盖了与护发、产品推荐、可持续性和个性化流程相关的多个主题,反映了 Sophia 的个性和兴趣:

Create 10 questions which Sophia could ask Lila

我们还可以要求更多的长尾示例,以便我们可以用我们的代理进行测试:

Create 10 long tail questions which Sophia could ask Lila

一旦我们有一组训练问题,你可以手动测试我们的代理,或者如果你的聊天机器人提供了 API,可以创建自动化测试。

创建更具体的测试脚本

对于更复杂的对话交互,ChatGPT 也可以用来创建相同的流程示例,以便用于测试你的代理。

考虑一个用户对他们的订单状态感兴趣的示例查询。这可以用作提示 ChatGPT 创建其他具有不同对话转折的示例:

Consider the following enquiry from Sophie about her order:
####
Sophia: Hi, placed an order for the Curl Harmony Shampoo yesterday. Can you tell me when it will be shipped?
Lila: Welcome back, Sophia! I'm glad to assist you. Your order for the Curl Harmony Shampoo is scheduled to be shipped tomorrow. You'll receive an email confirmation with the tracking details once it's on its way. Is there anything else I can help you with?
Sophia:
#####
Create 3 examples of this conversation when Sophie asks follow up questions

然后,你可以运行这些脚本示例,看看你的聊天机器人表现如何。

测试失败和边缘情况

对于同一用例,也可以考虑并利用 ChatGPT 来处理其他对话结果。例如,您可以使用 ChatGPT 来覆盖设计中需要考虑的边缘情况。

一些例子可能涉及用户偏离了快乐路径,或者以下例子,其中存在 Lila 依赖以提供答案的服务问题:

Give 1 example where Lila has technical issues so she can't access any order details.

您也可以提示 ChatGPT 在此处提供自己的建议:

Provide 3 examples of what else could go wrong with the conversation

这些结果可用于检查您在设计实现中是否遗漏了任何内容。

使用 ChatGPT 迭代您的聊天机器人

一旦您的代理有真实用户进行测试,您就可以使用转录和交互日志来查看如何通过向 ChatGPT 提供示例来改进您的对话设计:

Look at the following chat transcript:
{transcript}
Provide an example of how to improve this conversation

如果您想查看失败的对话、以不满意结果结束的对话或以不满意的用户结束的对话,这尤其有用。它让您能够查看如何改进您的对话流程。

摘要

在本章中,我们专注于如何使用 ChatGPT 进行对话设计。我们探讨了对话设计师的多重角色,并更详细地研究了构成对话设计过程的许多任务。我们了解到,一些任务可以在 ChatGPT 的帮助下完成。

我们深入研究了涉及的实际任务,例如理解用户需求、设计角色、创建对话流程和编写对话。

我们还了解到,理解 ChatGPT 不是替代良好对话设计实践的,而是一个功能极其强大的工具。

我们使用 ChatGPT 作为对话设计助理的核心是有效实施提示工程。我们开始研究提示工程所涉及的原则。在第四章中,我们将更详细地探讨提示工程,以深入了解这个新兴领域。在下一章中,我们将探讨使用 ChatGPT 的不同方式。

进一步阅读

以下链接是帮助您理解本章内容的资源:

第二部分:使用 ChatGPT、提示工程和探索 LangChain

本部分侧重于 ChatGPT 的实用使用、提示工程的复杂性以及 LangChain 的深入研究。您将探索与 ChatGPT 交互的不同方式,无论是通过网页界面、API 还是官方库。您还将深入了解提示工程,学习如何制作有效的提示。最后,本节介绍了 LangChain,引导您了解其基本和高级用法,包括调试技术、内存管理和利用代理以增强功能。

本部分包含以下章节:

  • 第三章ChatGPT 精通——释放其全部潜力

  • 第四章使用 ChatGPT 进行提示工程

  • 第五章LangChain 入门

  • 第六章使用 LangChain 进行高级调试、监控和检索

3

ChatGPT 精通——释放其全部潜力

在本章中,我们将深入探讨使用 ChatGPT 的技术细节,以便您能够充分利用这项技术,并使用多种不同的技术有效地与 OpenAI 模型进行交互。我们将详细介绍与 ChatGPT 交互的四种不同方式——即通过网页聊天界面、OpenAI Playground、直接使用应用程序编程接口API)或使用官方 OpenAI 的一个库,所有这些我们都会更详细地探讨。

您将深入了解 ChatGPT 界面以及免费版和 Plus 版本之间的差异,以及自定义指令的力量。接下来,您将了解如何使用 AI Playground。最后,我们将介绍如何直接与 API 交互,并探讨 OpenAI 的 Python 和 Node.js 库。

到本章结束时,您将深入了解与 ChatGPT 交互的不同方式,并能够就使用哪些技术做出明智的决定。

在本章中,我们将涵盖以下主要主题:

  • 掌握 ChatGPT 界面

  • 探索 OpenAI Playground

  • 学习使用 ChatGPT API

技术要求

在本章中,我们将广泛使用 ChatGPT,因此您需要注册一个免费账户。如果您还没有创建账户,请访问 openai.com/ 并点击页面右上角的开始使用,或访问 chat.openai.com

对于入门示例,根据您的编程语言,您需要一个已安装 Python 的环境。

掌握 ChatGPT 界面

使用 ChatGPT 界面是大多数用户开始使用 ChatGPT 的地方,也是与这项技术交互的最简单方式。在撰写本文时,您可以在 iOS 和 Android 上以及通过网页使用 ChatGPT。

ChatGPT 的免费版和 Plus 版本

在撰写本文时,ChatGPT 有免费版和 Plus 版本。免费版允许您在有限制的情况下使用 ChatGPT,而 Plus 版本包括一些更强大的功能和访问最新的 GPT-4 模型。

让我们来看看两个版本之间的差异以及它们在设备上的可用性。

  • 免费版 - 基本功能

    • 模型:GPT-3.5

    • 功能:无插件支持

    • 费用:免费

    • 支持:无客户支持

    • 响应时间:与 Plus 版本相比,响应时间较低

  • ChatGPT Plus - 增强功能,提供 高级访问

    • 模型:GPT-3.5 和 GPT-4

    • 功能:访问包括浏览插件高级 数据分析在内的测试版功能

    • 费用:每月 $24.00

    • 支持:客户支持

    • 响应时间:响应时间比免费版快,尽管 GPT-4 目前每 3 小时限制为 50 条消息。

你应该选择免费版还是 Plus 版本?

你是否选择 Plus 版本取决于你的预算以及你是否需要额外的功能。Plus 版本确实提供了更快的响应时间和访问最新 GPT-4 模型的权限,这使得它物有所值。如果你想要完成更复杂的任务,那么 GPT-4 提供的输出更好,并且可以处理更复杂的任务。

此外,由于 Plus 版本提供测试版功能,你可以使用插件,这极大地扩展了 ChatGPT 的功能。

ChatGPT 界面

在本节中,我们将提供使用主 ChatGPT 界面时看到的特性的详细分解,并使用图像作为参考。尽管大部分内容是自我解释的,但某些区域需要进一步说明。以下截图显示了当前的 ChatGPT 界面:

图 3.1 – ChatGPT 界面

图 3.1 – ChatGPT 界面

登录到你的 OpenAI 账户后,你就可以开始使用 ChatGPT (chat.openai.com/) 界面了。让我们熟悉这个 AI 工具的界面。

侧边栏

在屏幕的左侧部分是侧边栏,它包含以下功能来管理对话和你的账户:

  • 新聊天:这允许你开始一个新的对话。如果你想在不涉及之前讨论的上下文中开始一个新的对话,请使用此按钮。记住,ChatGPT 模型保留了过去对话的记忆,以提供上下文相关的回复。所以,如果你想改变对话的主题,明智的做法是开始一个新的对话。

  • 聊天历史:左侧边栏存储了所有你的过去对话,允许你在需要时随时回顾。你还可以在设置 | 数据控制中关闭此功能。

  • 账户选项:点击侧边栏底部的电子邮件地址或姓名会显示一个弹出窗口,提供以下选项的访问权限:

    • 我的计划

    • 自定义指令

    • 设置 和测试版

如果你没有 ChatGPT Plus,你也可以升级。

聊天视图

聊天屏幕是你与 ChatGPT 互动的地方。它设计成模仿一个消息平台,提供了一个用户友好的环境,你可以输入你的查询并从 AI 那里获得响应:

  • 从下拉菜单中选择一个模型:对于 Plus 用户,你可以选择你想要与之交互的 GPT 模型:GPT 3.5GPT 4插件

  • 提示示例:还有四个按钮可供选择,以及尝试的提示示例

  • 文本输入区域:在这里,你可以输入你的问题和回复

  • 回复:当 ChatGPT 对您的查询进行回复时,您可以通过选择点赞按钮,并将回复复制到剪贴板来提供反馈。

  • 底部栏:这告诉您您正在使用 ChatGPT 的哪个发布版本,并包含一个指向发布说明的链接。这对于检查最新功能以及它们是否在您的地区可用非常有用。

自定义指令

直到最近,ChatGPT 的一个问题是需要在每个会话的提示中重复上下文和指令。您不得不将提示存储在某个地方,并记住您之前使用过哪些提示。

自定义指令功能解决了这个问题,因为它允许用户通过提供特定的指令来个性化与 AI 的互动,这些指令将在所有未来的对话中记住。

自定义指令是 ChatGPT 的指南,帮助它理解您的偏好和需求,而无需在您的提示中包含所有这些信息。您可以提供指令,涵盖您希望 ChatGPT 了解的有关您的信息,以便它能提供更好的回复。

让我们看看这个主题的一个具体例子:一个面向对话 AI 专业人士的指令。

对话设计师指令的示例

我是一名对话设计师,正在为虚拟助手创建引人入胜且自然的对话。我经常需要帮助构思对话流程、生成自然回复和理解对话设计的最佳实践。

使用这个指令,ChatGPT 将协助以多种方式:

  • 设计流程:每当设计师请求帮助创建对话流程时,ChatGPT 可以提供符合行业标准的结构化和详细的对话序列。

  • 自然回复:ChatGPT 可以帮助生成自然且引人入胜的回复,这些回复可用于虚拟助手的脚本中,节省设计师的时间和精力,并在他们想要提供不同变体时提供变化。

  • 最佳实践:设计师可以询问对话设计的最佳实践,ChatGPT 将基于最新的行业标准和趋势提供见解。

  • 反馈和审查:设计师可以要求 ChatGPT 审查他们创建的对话,并接收建设性的反馈以提升他们的工作。

  • 资源推荐:ChatGPT 可以建议书籍、课程和其他资源,帮助设计师在对话设计方面进一步扩展知识和技能。

通过设置自定义指令,对话设计师可以拥有一个了解其专业需求并高效协助其工作的个性化助手。它本质上成为一个理解对话设计细微差别并提供定制化协助的工具,而无需在后续会话中输入这些信息。

如何设置自定义指令

设置 自定义指令 是一个简单的过程,并且对免费和 ChatGPT Plus 用户都可用,他们可以在网页上或通过 Android 和 iPhone 应用程序使用它。

简单点击肉丸菜单()并选择 自定义指令 选项。您将看到两个文本框:一个用于添加关于您自己的详细信息(例如年龄、位置、爱好、行业和职业类型),另一个用于指定 ChatGPT 应遵循的指令(例如回复的语气和长度)。

小贴士

重要的是要注意,在使用 API 时不支持自定义指令。相反,这可以通过将自定义指令放入系统提示消息中来实现。

GPTs

GPTs 是 ChatGPT 的定制版本,专为特定任务或目的而构建。您可以通过给出指令、添加额外知识和创建动作来创建自己的 GPTs,而无需编写代码。动作允许您从 ChatGPT 外部获取信息,使您能够调用外部 API 并将返回的数据用于 GPT 的知识库。创建 GPT 界面将引导您完成这个过程,使构建自己的 GPT 变得容易。

将 GPTs 视为针对您需求定制的 ChatGPT 专用版本。例如,您可以创建一个 GPT 来帮助您学习棋盘游戏规则、教您的孩子数学或设计贴纸。您甚至可以将这些 GPTs 与他人分享到 GPT 市场中,如果它们受到欢迎,您可能还能从中赚钱。

ChatGPT 社区正在积极构建和分享用于各种目的的 GPTs。"GPT 商店"使查找和使用这些创作变得容易。GPTs 代表了一种新的定制 ChatGPT 和解锁其特定应用潜力的方式。

到目前为止,您已经很好地理解了如何使用 ChatGPT 界面。在下一节中,我们将探讨我们使用 ChatGPT 和其他 GPT 模型的三种方法中的第二种:OpenAI Playground。

探索 OpenAI Playground

OpenAI Playground 提供了一个免费使用的基于网页的沙盒环境,使用户能够轻松测试和实验 ChatGPT 和 GPT 系列语言模型。该平台还提供了使用这些模型可以执行的有用指南和示例任务。用户可以与各种模型进行交互,并保存他们的 playground 会话,以便他们可以返回或与其他用户分享。

入门

到目前为止,我假设您已经创建了一个免费的 OpenAI 账户。一旦登录,您可以通过点击页面顶部的 Playground 链接来访问 OpenAI Playground。

以下截图显示了 OpenAI Playground 的登录页面:

图 3.2 – OpenAI Playground

图 3.2 – OpenAI Playground

主要文本区域是您可以与模型交互的地方。尝试使用本书前面提到的提示之一输入一个问题。您还可以加载预设。OpenAI 内置了数十个预制的提示。点击您的预设 | 浏览示例,从列表中选择一个。查看这些示例很有价值,这样您可以了解可以执行的任务类型以及实现它们所需的条件。

UI 功能

OpenAI 游戏场容易理解,但让我们快速了解一下核心功能,所有这些功能都提供了几个有用的功能。

保存您的预设

您可以通过点击保存按钮保存游戏场的状态。在此阶段,您可以切换是否希望将预设设置为可通过链接访问。这些预设也将显示在预设下拉菜单中,以便以后使用。

模式

模式设置允许您决定系统如何响应您的提示。最好将其设置为聊天,因为其他两个选项现在已弃用。

AI 模型

您可以通过使用模型下拉菜单来选择您希望与之交互的模型。列表包含所有最新的 GPT-3 和 GPT-4 模型,以及一些旧版本。

参数

在这里,您可以配置以下新参数以获取不同结果的提示。当我们在提示工程部分进行详细讲解时,我会涵盖这些内容:

  • 温度:这可以在 0 和 1 之间设置,并决定了 AI 的创造力水平。默认设置为0.7,这通常对我的创造性任务提供了更好的性能。

  • 最大长度:这控制了输入提示和结果输出的范围,以“标记”而不是单词或字符来衡量。一个标记约等于四个英语字符。

  • 停止序列:这指示 AI 在指定点停止生成。在对话式 AI 应用场景中,通常在生成一条回复后停止模型很有用。

  • Top P:此参数通过根据现有提示的相关性对标记进行排名,提供了一种引导输出随机性和创造性的另一种方法。

内容过滤器偏好

在菜单上点击三个点显示选择游戏场会话内容过滤器偏好的选项。开启此选项,如果发现涉及性主题、仇恨言论、暴力或自残的内容,将显示警告。

历史

点击历史按钮将加载您过去 30 天的使用记录。选择您的任何一次会话都可以查看会话,并为您提供恢复此版本的选择,这将覆盖您当前会话。

查看代码

对于我来说,游乐场的一个关键特性是能够看到驱动操作和生成输出的底层代码。点击菜单顶部的 查看代码 选项,检查您与所选模型交互时执行的代码。

在顶部选择 下拉菜单时,您可以选择以下选项来查看如何与 OpenAI 模型交互的示例:

  • API 使用 curl 和 JSON 有效载荷

  • SDKs 使用 Python 和 Node.js

在下一节中,我们将更详细地介绍使用 ChatGPT 技术的这些方法。

API 和游乐场的定价

OpenAI 的定价基于按使用付费的模式。在初始注册时,用户将获得一个包含有效期为前 3 个月的增值试用版信用额;在此期间之后,信用额将过期。

信用消费因每个模型而异,这些费用已在 OpenAI 网站上记录。计费指标基于使用的令牌数量,每 1K 令牌相当于大约 750 个单词,将产生费用。

小贴士

当您使用游乐场时,您仍然调用的是您直接调用 OpenAI 端点时使用的相同 API 端点。因此,游乐场和 API 调用的费用相同。

如何跟踪和控制令牌使用

您可以通过以下仪表板查看您的 LLM 使用跟踪:

图 3.3 – OpenAI 使用仪表板

图 3.3 – OpenAI 使用仪表板

点击页面右上角的用户名以显示主菜单,然后转到 管理账户 | 使用

您可以查看当前和过去计费周期中使用的令牌数量,以及每个请求的令牌细分。您还可以查看其他统计数据,例如您还剩下多少信用额可以消费。

为了让您放心,设置使用限制也是一个好主意,这样您可以管理您的支出。您可以通过访问 组织计费 | 使用限制 来这样做。在这里,您可以设置硬限制和软限制。

如果您有多个团队成员使用 API,这一点尤为重要。建议您定期检查使用跟踪仪表板。

学习使用 ChatGPT API

对于我们在 第二章 中讨论的许多用途,使用 ChatGPT 网络界面或交互式游乐场是有意义的。

然而,OpenAI 提供了一个广泛的 API,允许您使用他们的模型执行多个任务,包括使用代码与 ChatGPT 及其其他模型交互。因此,如果您想创建复杂的 ChatGPT 应用程序,并且我希望您是这样的,那么使用 API 是正确的选择。

在本节中,我们将更详细地探讨您可以使用来与 ChatGPT API 交互的不同技术。这些技术将在剩余的章节中使用。

入门

您可以通过任何语言的常规 HTTP 请求轻松与 API 交互,通过官方的 Python 或 Node.js 库,或社区维护的库。查看代码示例以了解如何与 API 交互很有用,可以通过查看游乐场并点击代码选项来查看每个库或 curl 请求的示例。或者,您可以查看 API 文档,其中包含各种示例。在执行与 API 和库的交互时,您必须理解身份验证、模型名称、消息和超参数等元素。

身份验证

在使用任何可用方式与 OpenAI API 交互之前,您需要使用 API 密钥进行身份验证,该密钥可以在控制台中创建。登录到 OpenAI 控制台后,点击右上角的用户名。从下拉菜单中选择查看 API 密钥。然后,点击创建新的密钥并为其命名。确保您记下您的 API 密钥,因为您将无法再次看到它。

可用模型

可用模型下,您可以指定要使用哪个模型。在这种情况下,是 GPT-3.5 Turbo,这是 ChatGPT 接口所使用的模型,除非您选择了 GPT4。在撰写本文时,以下模型可用于聊天完成:

  • gpt-4

  • gpt-4-0613

  • gpt-4-32k

  • gpt-4-32k-0613

  • gpt-3.5-turbo

  • gpt-3.5-turbo-0613

  • gpt-3.5-turbo-16k

  • gpt-3.5-turbo-16k-0613

游乐场提供了您可以使用的其他 GPT 模型的名称,尽管您可以参考模型页面以获取更多详细信息:platform.openai.com/docs/models

消息

消息数组是由角色和内容形成的消息对象的数组。角色可以是以下类型之一:

  • 系统消息:系统消息描述了在整个会话期间 AI 助手的行为了例,“*您是一位像电影《好家伙》中的角色一样的 Python 专家程序员。””

  • 用户消息:用户消息本质上是你将发送到 API 的提示。在本教程中,我们将涵盖用户消息的示例。

  • 助手消息:助手消息是会话中的先前响应。

发送的第一条消息应该是系统消息。随后的消息应在用户和助手之间交替,并包含内容。

提示

消息数组是您将持久化对话中过去消息以用于您的 API 集成的地方。API 不会神奇地记住对话的上下文。此机制是 ChatGPT 内部使用的。

超参数

通过微调这些值,您可以显著影响模型的输出:

  • 温度:这是模型输出的随机程度。

  • max_tokens:要生成的最大标记数

  • top_p:这控制了生成文本的多样性

  • frequency_penalty:这会影响基于训练数据中频率的令牌出现的概率

  • presence_penalty:这会影响在生成的文本中指示“存在”的某些实体或概念的概率

通过调整这些参数,你可以影响模型的输出,使其更加确定、有创意或具有上下文意识。

直接调用 API

API 端点提供其他功能,例如嵌入和微调模型,以及生成任务。然而,对于这本书,我们只关注与我们的模型进行聊天的相关功能,即聊天/完成端点。

要直接与 ChatGPT API 交互,你可以向api.openai.com/v1/completions发送一个POST请求。

包含一个带有 API 密钥和任何其他你想要发送到 API 的参数的认证头:

curl --location 'https://api.openai.com/v1/chat/completions' \--header 'Content-Type: application/json' \--header 'Accept: application/json' \--header 'Authorization: Bearer OPEN_AI_KEY' \
--data '{
  "model": "gpt-3.5-turbo",
  "messages": [{
    "role": "user",
    "content": "Provide 3 names for dog training chatbot"}],
  "temperature": 1,
  "top_p": 1,
  "n": 1,
  "stream": false,
  "max_tokens": 250,
  "presence_penalty": 0,
  "frequency_penalty": 0
}'

API 的响应包括生成的文本以及其他元数据,如下所示:

{
  "id": "chatcmpl-84DaAYWLg69y4XUD86YbXgD4iuI5j",
  "object": "chat.completion",
  "created": 1696016214,
  "model": "gpt-3.5-turbo-0613",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "1\. \"Pawsitive PupBot\"\n2\. \"Canine Companion Coach\"\n3\. \"Smart Bark Assistant\""},
   "finish_reason": "stop"}],
  "usage": {
  "prompt_tokens": 17,
  "completion_tokens": 25,
  "total_tokens": 42
  }
}

返回的有效负载包括聊天的完成详情,包括响应本身和使用数据。

这种简单的方法提供了对与 OpenAI 模型交互的细粒度控制,这对于理解 API 端点的请求和响应是理想的。

使用类似curl的工具直接调用 OpenAI API 非常简单,但可能会有些麻烦。使用 Postman 这样的 API 工作流程工具来简化调用端点是一个好主意。有一个非官方的 Postman 收藏夹,你可以将其分支并使用它来简化流程。

现在我们已经介绍了直接调用 API,在下一节中,我们将探讨如何开始使用 Python 和 Node.js 库。

使用 OpenAI Python 库进行设置

设置你的环境以使用 OpenAI Python 库是一个简单的过程。以下是一些启动步骤:

  1. 首先,使用以下命令安装库:

    $ pip install openai
    
  2. 创建一个 Python 文件,并将以下代码添加到其中。导入 OS 和 OpenAI Python 包。然后,从环境变量中加载你的密钥,这样你就可以使用它与包一起使用:

    import os
    import openai
    openai.api_key = os.getenv("OPENAI_API_KEY")
    
  3. 要调用 ChatGPT API,你需要调用openai.ChatCompletion.create()。这是你必须调用来与聊天完成端点交互的方法。以下是如何调用此方法的示例。为了使你的代码更具可重用性,将其包装在辅助函数中。它将接受你想要发送的消息和其他传递给create()函数的参数,并返回 API 的响应:

    import os
    import openai
    openai.api_key = os.getenv("OPENAI_API_KEY")
    print(openai.api_key)
    def chat_with_gpt( model, user_message,
        top_p=1,frequency_penalty=0,presence_penalty=0,
        temperature=0
    ):
        try:
            response = openai.ChatCompletion.create(
                model=model,
                messages=[
                    {
                        "role": "system",
                        "content": "You are a helpful conversational 
                            AI expert."
                    },
                    {"role": "user",
                        "content": user_message},
                ],
            top_p=top_p,
            frequency_penalty=frequency_penalty,
            presence_penalty=presence_penalty,
            temperature=temperature)
            return response
        except Exception as e:
            return str(e)
    

以下辅助函数允许你轻松自定义与 ChatGPT API 的交互。你可以按照以下方式调用该函数并打印响应:

response = chat_with_gpt(
    "gpt-3.5-turbo",
    "Suggest a good name for a customer support chatbot working for a holiday company",
    top_p=0.9,
    frequency_penalty=-0.5,
    presence_penalty=0.6,
    temperature=0.5)
print(response)

这使我们能够发送我们想要的任何超参数并更改模型。

运行程序

让我们看看如何运行程序:

  1. 设置你的环境变量:确保你在环境变量中设置了 OpenAI API 密钥。你可以在终端中运行以下命令来完成此操作(将 YOUR_API_KEY 替换为你的实际 API 密钥):

    export OPENAI_API_KEY='YOUR_API_KEY'
    
  2. 执行 Python 脚本:将代码保存到文件中,例如 chatgpt_interaction.py,然后从终端运行脚本:

    python chatgpt_interaction.py
    

此设置允许你发送任何你想要的消息,并调整参数以微调 GPT 模型的行为,并比较不同模型之间的响应。

使用 OpenAI Node.js 库进行设置

OpenAI 提供了一个用 TypeScript 编写的 Node.js 库,这使得它成为 TypeScript 项目的绝佳选择,因为库中包含了 TypeScript 定义。让我们开始使用这个库:

  1. 首先,使用以下命令安装库:

    $ npm install openai
    
  2. 应该使用环境变量或秘密管理工具来公开你的密钥。例如,你可以创建一个 .env 文件来存储你的环境变量(确保将此文件添加到 .gitignore 中,以避免将其提交到版本控制)。你可以使用如 dotenv 这样的包来在你的应用程序中加载这些环境变量:

    import * as dotenv from 'dotenv';
    dotenv.config();
    const mySecret = process.env['OPENAI_API_KEY']
    

    引用存储在环境变量中的 OpenAI API 密钥。

  3. 为了提高灵活性,创建一个辅助函数也是合理的:

    import OpenAI from 'openai';
    const openai = new OpenAI({
        apiKey: mySecret, // defaults to process.env["
            OPENAI_API_KEY"]
    });
    async function chatWithGPT(
        model,
        userMessage,
        topP = 1,
        frequencyPenalty = 0,
        presencePenalty = 0,
        temperature = 0
    ) {
        try {
            const prompt = userMessage;
            const maxTokens = 100;
            const chatResponse = \
                await openai.chat.completions.create({
                model: model,
                messages: [{
                    role: "user",
                    content: prompt
                }],
                temperature: temperature,
                top_p: topP,
                frequency_penalty: frequencyPenalty,
                presence_penalty: presencePenalty,
                max_tokens: maxTokens
            });
            return chatResponse;
        } catch (error) {
            return error.toString();
        }
    }
    
  4. 辅助函数允许你轻松自定义与 ChatGPT API 的交互。你可以这样调用它:

    async function main() {
        try {
            const response = await chatWithGPT("gpt-3.5-turbo",
                "Hello world", 0.9, -0.5, 0.6);
            console.log("ChatGPT Response:", response.data);
        } catch (error) {
            console.error("Error:", error);
        }
    }
    

模型、消息和超参数与 Python 库中使用的相同。

处理错误

如果库无法与 API 建立连接或收到非成功状态码,例如 4xx 或 5xx 响应,它将抛出一个从 APIError 类派生的异常。

在此情况下,处理来自服务的错误很容易,你可以根据需要处理这些错误。在我们的辅助函数中,我们正在寻找 APIError

if (error instanceof OpenAI.APIError) {
    // Do something with the APIError
    console.log(error.status); // 400
    console.log(error.name); // BadRequestError
    throw error;
} else {
    throw error;
}

返回的错误代码如下:

  • 400: BadRequestError

  • 401: AuthenticationError

  • 403: PermissionDeniedError

  • 404: NotFoundError

  • 422: UnprocessableEntityError

  • 429: RateLimitError

  • >= 500: InternalServerError

  • N/A: APIConnectionError

通过理解这些错误代码及其处理方式,你可以使用 OpenAI Python 库创建更健壮且具有错误恢复能力的应用程序。

请求和响应结构

此库包含了所有请求参数和响应字段的 TypeScript 定义。它们可以按如下方式导入和使用:

const parameters: OpenAI.Chat.ChatCompletionCreateParams = {
    model: model,
    messages: [{
        role: "user",
        content: prompt
    }],
    temperature: temperature,
    top_p: topP,
    frequency_penalty: frequencyPenalty,
    presence_penalty: presencePenalty,
    max_tokens: maxTokens
};
const chatResponse: OpenAI.Chat.ChatCompletion = \ 
    await openai.chat.completions.create(parameters);

通过在 OpenAI 库中使用请求参数和响应字段的 TypeScript 定义,你可以确保你的代码是类型安全的,并与 API 的预期结构保持一致。这种方法简化了请求构建和响应解释的过程,并在与 OpenAI API 交互时确保更高效和具有错误抵抗力的开发体验。

重试和超时

默认情况下,API 抛出的以下错误会自动重试两次,并带有短暂的指数退避:

  • 连接错误408409429

  • 内部错误>=500

您可以使用maxRetries选项来配置或禁用所有 API 调用,如下所示:

const openai = new OpenAI({
    maxRetries: 0, // default is 2
});

或者,您可以在每次调用的基础上设置以下参数:

await openai.chat.completions.create({
    messages: [{
        role: 'user',
        content: 'How can I...?'
    }], model: 'gpt-3.5-turbo' }, {
        maxRetries: 5
});

类似地,可以使用timeout选项配置 API 超时。默认超时时间为 10 分钟。您可以设置所有请求的默认值:

const openai = new OpenAI({
    timeout: 20 * 1000, // 20 seconds (default is 10 minutes)
});

您也可以为每个请求设置超时:

await openai.chat.completions.create({
    messages: [{
        role: 'user',
        content: 'How can I......?' }],
    model: 'gpt-3.5-turbo' },
    {timeout: 5 * 1000,}
);

使用哪种语言是个人喜好。也有几个开源库可供选择。

其他 ChatGPT 库

如果您想使用其他语言与 OpenAI API 交互,有很多选择。开源社区已经为各种编程语言开发了与 OpenAI 服务交互的库。这些库涵盖了多种编程语言,并为使用 OpenAI 的 API 提供了绑定和方便的方法。

如果您在使用 Microsoft 的 Azure,有一些特定的库可以用来与 Azure 上的 OpenAI 服务交互,例如 Java 和.NET 的 Azure OpenAI 客户端库,这些库是 OpenAI REST API 的适配版本。

这些库共同构成了一个丰富的生态系统,开发者可以利用它来直接或通过云平台(如 Azure)与 OpenAI 服务和模型交互。

摘要

在本章中,重点是各种与 ChatGPT 交互的方法,每种方法都有其独特的优势,满足不同的用户需求和技能水平。最初,我们探讨了 ChatGPT 界面,区分了免费版和增强版,并突出了后者增强的功能,包括更快的响应时间和访问 GPT-4 模型,这对于更复杂的任务至关重要。我们还介绍了自定义指令的新特性,该特性通过在会话间保留指定指令,显著优化了用户交互。

接下来,我们探讨了 OpenAI Playground,这是一个用于实验 OpenAI 模型的绝佳平台。它拥有用户友好的界面,允许用户亲手探索模型,保存和共享会话,并查看底层代码,充当点击和代码驱动方法之间的桥梁。

在最后一节中,我们介绍了与 OpenAI API 交互的不同方式。

API 是开发者使用 ChatGPT 的主要手段。您通过直接通过 HTTP 使用 API 或使用 OpenAI 的 Python 和 Node.js 库来了解如何这样做。我们解释了进行 API 调用、处理错误以及配置重试和超时的过程,使其成为开发者的全面指南。

在这个阶段,你可能想知道何时使用 API 而不是网络界面或 Playground。对于日常交互和到目前为止我们查看的大多数对话设计任务,使用广受欢迎的聊天界面是有意义的,它能很好地处理你的对话上下文、自定义指令和插件交互。

如果你想要开始查看其他模型,并接触一些 API 交互背后的代码,那么 OpenAI Playground 是一个很好的下一步。

然而,如果你想在你的对话式 AI 应用、内部服务或数据管道中包含 ChatGPT,或者你只是想要对你的模型交互有更多的控制,那么 API 会更加合适。通过 OpenAI 的库或你团队选择的社区驱动的库来利用 API 是最佳选择。无论你的选择如何,在这个阶段,你应该对所有的这些方法感到舒适。

到目前为止,你在第二章中广泛使用了提示,学习如何使用 ChatGPT 进行对话设计任务。在下一章中,我们将更深入地探讨提示工程的新领域。

进一步阅读

以下链接是一份精选的资源列表,帮助你使用 ChatGPT:

4

ChatGPT 的提示工程

在这一章中,我们将把重点转向 ChatGPT 的提示工程的艺术和科学,这是任何希望充分利用对话式 AI 潜力的人的关键技能集。我们将剖析提示的结构,探讨其结构、语气和复杂性如何影响模型的响应。

你将学习如何制作出适合专业对话的提示,我们将分享一些技巧,以在不使模型感到不知所措的情况下引入复杂性。我们还将深入研究段落和项目符号的战略使用,以增强可读性和理解力。

此外,我们将讨论如何在提示中在提供充分上下文和保持简洁之间找到完美的平衡。对于那些想要采用角色扮演的人,我们将通过提示提供模仿对话式 AI 工程师专业知识的见解。

到本章结束时,您将准备好构建能够引发准确和上下文相关的响应,并提升 ChatGPT 能力到新高度的提示。

在本章中,我们将涵盖以下关键领域:

  • 通过提示工程的概念

  • 理解成功提示的核心组件

  • 使用提示工程策略进行工作

  • 了解提示工程技巧

本章旨在成为您掌握提示工程的不二指南,使您能够更有效、更细致地与 ChatGPT 互动。

技术要求

本章我们将广泛使用 ChatGPT,因此您需要注册一个免费账户。如果您还没有创建账户,请访问openai.com/,点击页面右上角的开始使用,或者访问chat.openai.com

要执行本章中展示的示例,除非另有说明,我建议您通过网页或移动应用使用 ChatGPT。

最后一个示例技术需要安装 Python 3.9 和 Jupyter Notebook,请使用以下链接:jupyter.org/try-jupyter/notebooks/?path=notebooks/Intro.ipynb

通过提示工程的概念

随着 LLMs 及其能力的兴起,提示工程已成为一门新学科,每个人都似乎在谈论它。我们可以利用提示工程来帮助我们使用 LLMS 处理各种任务,从常见的问答到与其他系统的更复杂集成。对于任何使用 LLMs 的人来说,掌握这项技能是非常重要的。

那么,提示工程到底是什么呢?简单来说,提示工程是创建最优化输入以从与 LLMs 的交互中获得最大收益。因此,您的提示结构越好,输出就会越好。

如果您发送模糊的提示,那么现实是您将得到模糊或不正确的结果。确实,提供一个简单的在线提示通常会得到一些有趣的结果。然而,它们不太可能是您所希望的结果,尤其是如果您希望完成更复杂的任务。

这里是一个简单的提示示例。尝试用 ChatGPT 来试试:

Tips on conversation design

好吧,这确实返回了一些有用的信息。然而,如果我们想要返回更针对性的结果,我们可以改进这一点:

"Suggest methods to enhance a conversation design to better capture and retain user engagement, with a particular focus on utilizing empathetic language and providing meaningful responses."

在这个经过改进的提示中,我们提供了更多的清晰度和具体性,以确保 AI 的帮助被引导到我们感兴趣的对话设计领域。

创建一个成功的提示不仅关乎提出正确的问题,还关乎向 LLM 提供足够的信息以创建正确的答案,并确保一切都在 LLM 理解的理想格式中。提示工程就是根据你试图完成的任务了解使用哪些技术。

在下一节中,让我们首先看看提示的不同组成部分,并考虑其他具体细节,例如最佳格式。

理解成功提示的核心组件

成功的提示词没有一劳永逸的方法。你想要完成的每个任务都是不同的,因此实现这些任务所需的提示词也是不同的。然而,由于模型训练的方式和用于训练它们的数据,有一些规则需要遵循以获得最佳结果。在第二章中,我们探讨了 ChatGPT 如何帮助进行对话设计任务。这包括提供详细的提示,包括成功提示的一些关键组成部分。是的,你已经进行了一些广泛的提示工程,并使用了以下列表中概述的一些核心提示组件:

  • 指令:指定要采取的行动,通常通过输入动词(如设计或编写)来启动

  • 上下文:提供指导模型的其他信息,例如环境或目的

  • 范围:缩小任务的重点,指定要涵盖的查询或主题类型

  • 角色:定义 AI 应操作的能力,例如专家或客户服务代表

  • 受众:表明预期输出接收者的知识水平和兴趣

  • 输入数据:指定任务中要使用的数据,通常由分隔符分隔

  • 输出数据:详细说明预期的输出格式和结构,指导 AI 的响应

下图说明了有助于构建成功提示的核心组件:

图 4.1 – 成功提示的核心组件

图 4.1 – 成功提示的核心组件

让我们更详细地看看成功提示的关键组件。

指令

给出明确的提示指令。良好的做法是以动词开始提示,例如设计、起草、创建、生成、编写或制作。这样,ChatGPT 应该能确切地了解你希望它如何回应,并且没有误解的空间。同时,告诉 ChatGPT 你期望在回应中看到什么,例如对话流程、网站文案、博客文章、聊天记录或描述。

让我们看看一个示例提示,要求 ChatGPT 提供一个聊天机器人对话示例:

"Design a conversation flow for a customer service chatbot that handles product returns and exchanges, focusing on a friendly and efficient user experience"

在这个提示中,我们给出了一个精确的指令:设计一个对话流程。因此,指令越清晰、越精确,留给 ChatGPT 猜测你想要完成的事情就越少。

上下文

为了改进提示语,我们可以提供超出第一指令之外的信息。让我们通过提供一些上下文来继续这个例子,以引导模型理解我们的对话设计请求的需求和目的:

"Design a conversation flow for a customer service chatbot"

我们在我们的提示语中添加了用于客户服务聊天机器人的内容。这应该有助于 ChatGPT 调整聊天机器人的对话和动作。因此,通过提供更多上下文,我们可以引导模型理解对话流程将被使用的环境。

范围

就像任何项目概要或工作说明书一样,向 ChatGPT 提供更多关于任务范围的具体信息是有意义的。在我们的案例中,我们的对话设计是为客户服务聊天机器人,这可能涉及任何类型的请求,从常见问题解答到投诉或退货。因此,让我们提供一个范围,以便我们可以专注于我们正在设计的问题类型:

"Design a conversation flow for a customer service chatbot that handles product returns and exchanges"

希望通过向 ChatGPT 提供处理产品退货和换货的指令,我们可以确保模型专注于生成与产品退货和换货相关的对话流程,避免离题的偏离。

角色

成功提示语最重要的组成部分之一是角色组件。为 ChatGPT 指定一个角色,以确定 AI 在生成响应时应工作的能力。例如,您可能要求它扮演专家或具有特定的观点或能力:

Act as a first line customer service representative and provide assistance on how to troubleshoot technical problems with the SAAS. Please ensure a professional tone and intermediate level of complexity in your response.

将此角色作为您提示语的一部分,将引导由 ChatGPT 驱动的客户支持聊天机器人的语言和行为。在提供角色时,重要的是要具体、清晰且相关。记住,我们在第二章创建我们的用户和聊天机器人角色部分讨论了提供更复杂的角色细节。

根据您的任务,提示语中未定义的角色可能导致缺乏焦点或专业性的泛泛或模糊的响应。

受众

在您的提示语中指定受众细节可以显著定制输出。例如,考虑以下提示语:

"Explain the principles of machine learning to a technical audience."

这可能结果是一个深入的解释,使用技术术语并讨论算法、数据训练、验证和背后的数学原理。

如果您想为更广泛的受众创建内容,您可以尝试以下方法:

Explain the principles of machine learning to a general audience.

预期的输出将是一个使用通俗语言并避免技术术语的简化解释。

通过在提示语中包含受众的具体信息,您可以使 ChatGPT 的响应与预期收件人的知识水平和兴趣保持一致。

输入数据

输入数据通常是您提示语的重点。这可以是文本或其他格式的数据。

将指令放在提示语的开头。如果您正在为 ChatGPT 提供作为提示语一部分的特定数据,使用某种分隔符是一种良好的实践。我发现使用###"""来分隔指令和输入数据效果很好:

Summarize the conversation delimited with triple hashes
Conversation: ###{conversation}###

这里是一个示例,这个提示将我们的输入对话数据作为纯文本提供:

Summarize the conversation below as a bullet point list of the most important points. The conversation is delimited with triple hashes
Conversation: ###
User: Hi, I'd like to return a product I purchased last week.
Chatbot: Of course, I can aid with that. May I have your order number, please?
User: Sure, it's 12345.
Chatbot: Thank you. I found your order. May I ask the reason for the return?
User: The product has a defect and doesn't work properly.
Chatbot: I apologize for the inconvenience. I can process the return for you. Would you like a refund or an exchange?
User: I'd prefer an exchange.
Chatbot: Great! I've started the exchange process. You'll receive an email with further instructions shortly.
User: Thank you!
###

ChatGPT 擅长分析各种输入类型,如JavaScript 对象表示法JSON)、超文本标记语言HTML)、可扩展标记语言XML)、图像、标记和纯文本等。例如,如果你的对话数据存储为 JSON,你可以简单地将其传递到你的提示中:

Summarize the conversation below as a bullet point list of the most important points. The conversation is delimited with triple hashes
Conversation: ###
{
"conversation": [
  {
    "speaker": "User",
    "message": "Hi, I'd like to return a product I purchased last week."
  },{
    "speaker": "Chatbot",
    "message": "Of course, I can assist with that. May I have your order number, please?"
  },{
    "speaker": "User",
    "message": "Sure, it's 12345."
  }]
}
###

确保输入数据的格式和结构的一致性对于获得可靠的响应至关重要。

一旦你提供了正确的输入,告诉 ChatGPT 它应该提供什么输出是很重要的。让我们看看下一个例子。

输出数据

指定预期的输出数据和详细程度可以引导 AI 生成符合你要求的响应。我们可以提供详细的说明,说明我们想要的输出是什么,无论是文本、格式化数据还是代码。

为了获得最佳结果,明智的做法是明确定义所需输出的结构和格式。这可能包括指定使用数组、对象或其他数据结构来组织信息。也可能涉及定义属性或键的命名约定,确保输出标准化和可预测,从而简化数据提取和后续处理,如果你计划在软件或管道中使用你的响应。你已经在许多例子中广泛应用了这种做法,当我们要求 ChatGPT 返回 JSON 数据时。

简单文本

让我们看看更多示例。在这个简单的例子中,我们要求以项目符号列表的形式输出文本:

Summarize the conversation delimited with ### as a bullet point list of the most important points which should be no more than 150 characters each.
Conversation: ###{conversation}###

输出特定的格式或代码

另一个技巧是指定一个编号的表格,例如,可以通过以下方式:

Please can you create a numbered table of the components of a successful chatbot for a technical audience.

你可以随后通过编号的项目提出后续问题:

can you provide more detail on number 3

我们也可以要求 ChatGPT 返回更复杂的特定格式,例如 HTML 中的表格数据:

Create a table summarizing the chatbot's performance across four metrics (User Engagement, Response Accuracy, Processing Time, and User Satisfaction) over a span of three months. Output the table as HTML. The metrics are as follows:
- User Engagement: Jan: 1200 interactions, Feb: 1300 interactions, Mar: 1400 interactions
- Response Accuracy: Jan: 85%, Feb: 87%, Mar: 90%
- Processing Time: Jan: 1.2 seconds, Feb: 1.1 seconds, Mar: 1.0 second
- User Satisfaction: Jan: 80%, Feb: 82%, Mar: 85%
Include a column for the average across the three months for each metric.

你还可以更进一步,要求特定的格式,并指导基于我们选择的格式,最佳的输出是什么。在下一个例子中,我们将要求 ChatGPT 提供 Vega-Lite(视觉分析的语法):

The following is data delimited in ### summarizing a chatbot's performance across four metrics (User Engagement, Response Accuracy, Processing Time, and User Satisfaction) over a span of three months.
Please can you create this for vega lite representation for this data?
Include a column for the average across the three months for each metric.
###
- User Engagement: Jan: 1200 interactions, Feb: 1300 interactions, Mar: 1400 interactions
- Response Accuracy: Jan: 85%, Feb: 87%, Mar: 90%
- Processing Time: Jan: 1.2 seconds, Feb: 1.1 seconds, Mar: 1.0 second
- User Satisfaction: Jan: 80%, Feb: 82%, Mar: 85%
###

另一个指定输出的好例子是指导 ChatGPT 查看非结构化数据并将其转换为我们可以用于进一步管道或软件应用的输出。在以下示例中,我们将要求 JSON,并指定我们想要创建的属性,以及添加一个用于填充情感的属性:

Please look at these live chat transcripts and create JSON for this conversation as a list of message objects, add one extra property which will include sentiment for each message:
[2023-10-09 08:00:00] User: What's the weather like today?
[2023-10-09 08:00:05] Virtual Assistant: Today's forecast is cloudy with a high of 68°F and a low of 52°F. There's a 60% chance of rain in the afternoon.
[2023-10-09 08:01:00] User: Do you have any suggestions for indoor activities?
[2023-10-09 08:01:05] Virtual Assistant: Certainly! You might consider reading a good book or visiting a local museum. Both activities are excellent ways to spend a rainy day indoors.

LLM 的输出可能不一致,例如列表这样的结果可能脆弱,所以如果你想在软件或管道中使用输出,通常建议返回 JSON。

正如你所见,输出可以是任何东西,因此仔细指定我们希望 ChatGPT 提供的确切内容是有意义的。

结论

一个提示不需要所有这些元素,其格式根据你想要实现的具体任务而变化。还值得注意的是,相同的提示组件可以与任何 LLM 一起使用。

虽然这些组件并不全面,但它们应该能够帮助你获得持续改进的结果。

现在,既然你已经知道了提示的关键部分,让我们通过考虑你的提示策略来更详细地探讨提示工程。

使用提示工程策略进行工作

提示工程是一个迭代的过程。你不太可能通过第一次、第二次或第三次提示就成功完成你的任务。这就是为什么我倾向于避免互联网上提供的 100 个最佳提示指南。提示工程没有固定的规则,但有一些策略可以遵循,同时使用一些或所有我们有效的提示组件。让我们更详细地审视一些这些策略。

明确定义目标

在你开始使用提示之前,最好考虑你试图完成的任务。明确的设计和目标将意味着整体迭代次数更少。因此,考虑你的任务,看看你是否能清楚地对自己解释它,或者用几句话描述它,包括一些适当的关键词,以确保你已经深思熟虑,并且有足够的细节提供给 ChatGPT。如果没有提供足够的细节,LLMs 往往会走偏,因为它们有太多的可能性走错方向。

采用迭代式提示开发

提示开发是一个迭代的过程。你不太可能用第一个用来向 LLM 解释你的任务的提示在生产中使用。关键的是,你开始时要简单,然后,根据每次输出的结果,根据结果缺乏或需要改进的地方对提示进行迭代。在下一个例子中,我们将展示对特定任务的提示进行迭代的过程。

迭代开发示例

在这个例子中,你被要求为即将部署在大学网站上的新聊天机器人设计一个对话流程,该机器人将用于回答有关招生、项目和校园设施的问题。对话流程应该直观、信息丰富且引人入胜,以帮助潜在学生找到他们所需的信息。

你有一些关于大学招生数据的信息,这些信息可以作为你的提示的一部分提供:

Data:
Admissions:
Application Period: 6 September to 15 January
Requirements:
A-Level qualifications or equivalent (specific grade requirements may vary by program)
Personal Statement (4000 characters max)
Academic References (1 required, 2 recommended)
Transcripts from previous institutions

我们的第一尝试相当简单:

Create a chatbot conversation flow for university inquiries
Data: {data}

这相当模糊,缺乏上下文和指导,导致 ChatGPT 没有生成有意义对话流程所必需的信息。ChatGPT 的输出相当令人印象深刻,包括一个示例对话,但它相当基础。

让我们尝试用更多细节来改进我们的提示:

You are tasked with designing a conversational flow for a chatbot deployed on a university's website. The chatbot should be able to answer queries regarding admissions, programs, and campus facilities based on the provided data. Draft a conversational script for the following user inquiry: "Tell me about the admission process and deadlines."
Data: {data}

这是一个更好的提示;我们提供了更广泛的范围和更清晰的指示,以及一个场景,并要求为特定用户查询编写脚本。然而,它并没有提供任何关于聊天机器人角色的指导或对聊天机器人语气的强调。

Envision yourself as a chatbot developer crafting a conversational flow for a university chatbot called Unipal. Utilizing the given data, ensure the chatbot provides informative, clear, and engaging responses regarding admissions. Here's a scenario: A prospective student inquires, "I am interested in the Engineering program. Can you guide me through the admission requirements and process?" Create a conversational script that demonstrates how the chatbot would guide the user through this inquiry, providing all necessary details in a friendly and supportive manner.
Data: {data}

这个提示为 ChatGPT 创建了一个角色,将其置于一个现实场景中,并提供了一个特定的用户查询来回应。它强调了友好、支持和吸引人的语气的重要性,并为 ChatGPT 提供了构建有意义、信息丰富的回应所需的环境和数据,以满足我们的对话流程任务。

正如您从这个示例中可以看到的,提示工程是一个迭代的过程。我们开始得很简单,通过一系列提示改进,根据每个提示的结果逐步构建了我们的提示细节。

从简单开始

同时,也要记住,根据你想要完成的任务,使用几个简单的提示可能比一个长而复杂的提示效果更好。如果你使用的是 ChatGPT 的网页或移动聊天界面,你可以从一个简单的明确提示开始,然后通过进一步的后续提示来构建。记住,ChatGPT 应用在幕后管理上下文和对话历史,如果你使用的是 API,你必须自己实现这一点。

小贴士

如果你试图在一个提示中完成太多事情,LLMs 可能会变得困惑,可能不会提供最佳结果。如果你试图一次做四到五件事情以上,可能到了将这些任务拆分成一系列后续提示的时候了。

如果你试图完成一个非常复杂的任务,可能更容易不是试图创建一个完美的提示,而是考虑在多个提示中实现你的任务。从一个清晰简洁的提示开始,然后通过进一步的问题或澄清来跟进。

让我们考虑一个更复杂的任务:为医疗提供者设计一个多功能对话 AI 系统,该系统能够处理预约安排、开具处方续方,并提供有关医疗状况的一般信息。与其要求 ChatGPT 一次性提供所有信息,你不妨从一个清晰简洁的提示开始,为系统的基本框架奠定基础:

Design a conversational interface for a healthcare provider that can greet users and ask for their primary concern.

一旦你有了基本结构,你可以通过后续问题深入了解每个功能,例如询问预约安排的更多细节:

Elaborate on how the conversational AI should handle appointment scheduling including checking doctor availability and confirming appointment details with the user.

你在这里做的是从简单开始,这样 ChatGPT 就能理解整体任务,然后将复杂任务分解成更小、更易于管理的子任务。这种方法对于更大、更复杂的任务,如编码和文本用例,效果很好。

使用后续提示来测试多个示例

有时您将有多组数据示例来评估您的提示符。测试提示符跨越一系列输入以查看您的提示符是否在多个示例中正确执行是有意义的。如果您使用 ChatGPT 处理大量数据,这一点尤为重要。您可以使用 ChatGPT 来帮助完成这项工作。以下是一个例子。假设您有一个基于一组酒店数据的 LLM 自动化系统,用于创建酒店描述。这个提示符可能看起来像这样:

Act as a travel agent and provide a comprehensive hotel description of 200 words maximum for the following hotel data: {
  "hotel_name": "Mountain Lodge",
  "location": "Swiss Alps",
  "rating": 4.5,
  "no_of_rooms": 80,
  "facilities": [
    "Ski-in/Ski-out",
    "Fireplace",
    "Restaurant"
    ],
  "price_range": "£200-600",
  "description": "A lodge nestled among the snow-capped Swiss Alps."
  }
Output the description as a description property on the same JSON

可能的情况是,您并不完全确定设施数据将适用于每家酒店,您不希望有任何虚构的设施细节或提及没有设施的情况,因此您可以检查描述中不提及设施的其他提示符:

Look at the following hotel_description and return are_facilities_mentioned = true if facilities are mentioned or are_facilities_mentioned = false if not.
You don't need to explain your reasoning
hotel description: "situated in the..."

您可以在测试您的提示符跨越一系列输入并使用后续提示符对 ChatGPT 的输出进行清理时看到其价值。

当需要时使用温度。

我们在第三章中介绍了如何更改温度。温度允许您改变模型响应的随机性。温度越高,响应将越多样化、越随机。通常,当构建需要可预测响应的应用程序时,使用零温度是一个好习惯。因此,如果您正在尝试构建一个可靠且可预测的系统,我建议使用零。对于您希望有更多创造性的应用程序,提高温度是个好主意。

处理 ChatGPT 中的内存限制

ChatGPT 或任何 LLM 中的内存限制在尝试维持长时间或复杂的对话或理解更广泛的上下文时可能成为瓶颈。所有 GPT 模型都有一个令牌限制,包括输入和输出令牌。一旦达到令牌限制,您就必须截断、省略或以其他方式管理对话历史,为新输入和输出腾出空间。

管理内存问题的策略

在解决对话式 AI 的内存限制时,可以采用几种策略来优化交互流程。以下是一些有效的方法:

  • 选择性截断:仅保留对话的必要部分。例如,删除问候语或不太相关的交流以节省后续消息的空间。

  • 总结:定期总结到目前为止讨论的内容,并在后续提示中使用这些内容。

  • 分页:将对话或上下文内容分解成页面或部分,并独立处理每个部分。您可以使用如www.chatsplitter.com/这样的提示符分割器将较长的输入文档分成更小的、可管理的段。如果您处理的是较大的文档,这很有用。此工具允许您轻松上传多个文件,并将它们自动分割成多个块,然后您可以将其加载到 ChatGPT 中。

  • 提示最小化:有一些空间可以最小化提示的长度,但正如你在本章中学习到的,创建最佳提示,因此限制它们并没有太多意义。结果可能微不足道。话虽如此,根据你的使用情况,可能值得删除你在提示中添加的输入数据。

重置机制

当你达到内存限制时,重置模型非常重要。未能这样做可能会导致输入或输出不可预测地截断,造成上下文丢失或给出错误答案。重置应该是一个受控的操作,在丢弃可消耗部分的同时保持对话的精髓。最有效的方法是总结对话,并将其用于你下一个提示。

小心复制早期迭代中的错误转向。如果回答偏离了轨道,确保你在重置模型时不要包括那部分内容。

以下是一些重置对话的不同方法:

  • 硬重置:完全清除对话,并从新的初始化上下文开始

  • 软重置:将先前对话的关键点或摘要作为初始化上下文保留

  • 上下文缓存:将关键信息存储在外部数据库或上下文管理器中,并在需要时重新引入

使用具有更大内存的 GPT-4 模型

这是一个简单的修复,并且在缓解内存问题方面取得了重大进展。最新的 GPT-4 模型具有更大的内存。GPT-35-Turbo 的令牌限制为 4,096 个令牌,而 GPT-4 和 GPT-4-32k 的令牌限制分别为 8,192 和 32,768 个,因此通常明智的做法是使用这些。但请记住 API 成本。

结论

正如你所学的,拥有一个坚实的提示工程策略非常重要,这样你才能克服提示工程的挑战。遵循迭代策略,并确保你提供具体、清晰的提示,包含丰富的背景信息和上下文,并避免歧义。在下一节中,我们将探讨一些具体的提示工程技术。

了解提示工程技巧

让我们利用我们所学到的 ChatGPT 提示技巧和特定于对话式 AI 的用例。

在本节中,我们将深入研究高级提示工程技巧,旨在发挥 ChatGPT 在对话式 AI 中特定用例的潜力。我们将探讨如针对特定响应的少样本学习、数据解释的摘要以及为旅行聊天机器人进行提示的迭代优化等方法。每种技术都是为了提高 AI 的理解和输出,确保最终交互尽可能有效和与任务相关。无论是塑造客户支持聊天机器人还是集成 LLMs 进行数据摘要,本节应帮助你学习使用最有用的提示技巧。

客户支持聊天机器人的少样本学习

使用少样本学习方法来提示 ChatGPT 并给出更紧的输出边界是一种常见方式。在少样本学习中,一组训练示例作为您提示的一部分提供。这种方法的优点是您提供了额外的上下文,每个响应都为 ChatGPT 提供了您所期望的输出示例,因此您可以对响应有相当程度的信心。

为了观察这一过程,让我们考虑让 ChatGPT 扮演一家智能手机公司的客户支持聊天机器人的角色。

单轮提示可能如下所示:

Act as a dog training chatbot designed to answer questions about dog training.
- Only answer questions related to dog training
- If you're unsure of an answer, you can say "I don't know" or "I'm not sure" and recommend  a source on the internet

ChatGPT 的输出效果良好,但对我们这个用例来说有点过于详细。您可以提供更多的输出指南,或者,通过少样本学习方法,您可以指导 ChatGPT 以更结构化和一致的方式回答:

Act as a dog training chatbot called Fido designed to answer questions about dog training.
- Only answer questions related to dog training
- If you're unsure of an answer, you can say "I don't know" or "I'm not sure" and recommend  a source on the internet
Example conversations:
Example 1:
User: How do I stop my dog from barking at strangers?
Assistant: To curb your dog's barking at strangers, work on socialization and desensitization techniques. Reward calm behavior and consider using a 'quiet' command.
Example 2:
User: What's the best way to potty train my puppy?
Assistant: Consistency is key for potty training. Take your puppy outside frequently, especially after meals or playtime, and reward them for doing their business outside.
Example 3:
User: My dog pulls on the leash. What should I do?
Assistant: To correct leash-pulling, use a short leash and stop walking when your dog pulls. Only resume walking when the leash is slack. This teaches them that pulling gets them nowhere.

对于相同的例子,如果您正在与 ChatGPT 补全 API 交互,您的示例将是您发送给 API 的消息数组的一部分:

{"role": "system", "content": "You are a dog training chatbot called Fido designed to answer questions about dog training.  Only answer questions related to dog training - If you're unsure of an answer, you can say "I don't know" or "I'm not sure"},
{"role": "user", "content": " How do I stop my dog from barking at strangers "},
{"role": "assistant", "content": " To curb your dog's barking at strangers, work on socialization and desensitization techniques. Reward calm behavior and consider using a 'quiet' command."},
{"role": "user", "content": " What's the best way to potty train my puppy?"},
{"role": "assistant", "content": " Consistency is key for potty training. Take your puppy outside frequently, especially after meals or playtime, and reward them for doing their business outside "}

通过向 ChatGPT 提供示例,您正在为模型提供特定领域的知识,同时设置任务的交互角色、响应格式和任务理解。您也希望有助于保持响应的一致性。

对于这个用例,少样本学习使 ChatGPT 能够充当专业助手,将其从通用聊天机器人转变为能够提供特定领域指导的机器人,例如在这次案例中是针对狗狗训练。在下一节中,我们将探讨使用 ChatGPT 执行另一个带有一些额外复杂性的常见用例。

提示对话式代理总结数据

大型语言模型(LLM)的一个显著用途是利用它们进行总结任务。我们的提示总结示例与标准文本总结任务不同。相反,我们将创建一个提示来回答关于 JSON 格式数据的疑问。

如果您希望您的聊天机器人或自动化助手能够回答关于特定数据的查询,这种技术非常有价值。

对于这个例子,假设您有一个在线旅行社的客户支持聊天机器人。您的聊天机器人正在处理一位客户关于其航班行李详情的查询。聊天机器人与旅行社的后台网络服务有直接集成。它还拥有当前用户的详细信息,因此查找客户的预订数据非常直接。复杂性在于解释和呈现数据以回答用户的问题。

对于我们的例子,系统返回的航班数据看起来如下:

"flights": [{
  "status": "CONFIRMED",
  "supplierName": "Easyjet Flight",
  "segments": [{
    "direction": "OUTBOUND",
    "legs": [{
    "flightNumber": "EZY8703",
    "airline": {
      "bagsConfiguration": {
      "cabinBagWeight": "NO_LIMIT",
      "holdWeight": "20kg",
      "baggageIncluded": false,        "cabinBagDimensions": "36x45x20 cm",                                      "cabinBagAllowance": 1}
    },"carrier": {"carrierCode": "EZY","name":"easyJet"}
  }
]},{
  "legs": [{
    "airline": {
    "bagsConfiguration": {
      "holdWeight": "20kg",
      "cabinBagDimensions": "36x45x20cm",
      "cabinBagAllowance": 1,
      lugageIncluded": false,
      "cabinBagWeight": "NO_LIMIT"
      }
},"carrier": {"name": "easyJet","carrierCode": "EZY"},
  "flightNumber": "EZY8706"
    }
  ],
  direction": "INBOUND"}
  ]
}]

在基于意图的对话式人工智能系统中,我们会根据数据构建对用户的响应,通过解析这些数据并手动构建或使用模板系统来构建。这可能会变得脆弱且难以维护。相反,我们可以使用 ChatGPT 来处理对航班数据的总结性回答问题。

让我们看看实现这一目标的提示:

You are a customer support chatbot for an online travel agency. look at the following flights information represented in JSON format delimited with ###, use this to create a summary of inbound and outbound flight baggage details
Summarize outbound then inbound and include all flights even if they have no baggage
If a flight has no baggage state "My records show no confirmed hold luggage for this part of your trip.
Include the following statement as the last part of the summary:
"Hold luggage is not per person, but for the entire booking."
flights: ###{flights}###

在收到 ChatGPT 的连贯输出后,我们可以迭代地改进我们的提示以适应我们的特定用例。例如,我们可以通过改变输出以生成针对 IVR 系统的定制摘要:

create a summary of inbound and outbound flight baggage details for an IVR system

如您所见,当输入是结构化数据或非结构化文本时,使用 ChatGPT 进行总结的技术效果良好。如果您正在使用基于意图的系统,但希望谨慎地引入 LLM 技术,并且仅在意图级别或针对某些意图,这也是一个很好的技术。

ChatGPT 还能做更多。让我们在下一节中基于我们的例子来创建一个完整的聊天机器人。

提示创建由 ChatGPT 驱动的自己的聊天机器人

我们可以通过使用 ChatGPT 创建自己的工作旅行助手聊天机器人来构建我们之前旅行助手代理的例子。

此代码示例演示了使用 Python、ChatGPT 和 IPython widgets 在 Jupyter Notebook 环境中创建的简单交互式聊天机器人。聊天机器人包含一些以 JSON 格式表示的假日信息,这些信息包含在您的提示上下文中。

导入必要的库

首先,我们需要导入所有必要的库:

import os
import json
import openai
import ipywidgets as widgets
from IPython.display import display, clear_output, Markdown
openai.api_key = os.getenv("OPENAI_API_KEY")

导入必要的库和模块以支持聊天机器人的功能。例如,openai用于与 GPT-3.5-Turbo 模型交互,ipywidgetsIPython.display用于在 Jupyter Notebook 中创建交互式 UI。我们还传递了包含我们的 OpenAI 密钥的环境变量。

加载聊天机器人的预订数据

接下来,我们需要从 JSON 文件中加载聊天机器人的预订数据:

with open('booking.json', 'r') as f:
    booking = json.load(f)

代码读取booking.json文件以获取一个虚构客户的预订详情,这样当您询问假日信息时,聊天机器人将有一些信息。这模拟了与后台系统的集成。

定义调用 completions 端点的辅助函数

以下代码概述了用于调用带有我们的消息和其他参数的 completions 端点的辅助函数:

def chat_with_gpt(messages, model="gpt-3.5-turbo",
    top_p=1, frequency_penalty=0,
    presence_penalty=0,temperature=0
):
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            top_p=top_p,
            frequency_penalty=frequency_penalty,
            presence_penalty=presence_penalty,
            temperature=temperature
        )
        return response.choices[0].message["content"]
    except Exception as e:
        return str(e)

此函数将对话历史(messages)发送到 GPT-3.5-Turbo 模型,并返回模型的响应。

创建 UI 元素

以下元素是构成我们聊天界面的简单 UI 组件:

inp = widgets.Text(value="Hi",
    placeholder='Enter text here…')
chat_button = widgets.Button(description="Chat!")
output = widgets.Output()
panels = []

UI 组件使用ipywidgets创建。这包括一个文本输入字段(inp)、一个按钮(chat_button)和一个输出区域(output)来显示对话,以及一个面板列表,该列表初始化为保存将要显示的对话面板。

初始化上下文

接下来,我们将使用系统提示和预订信息创建我们的对话上下文:

system_content = f"You are Shelley an automated travel assistant to answer questions about a customers holiday, \
start by greeting them by their first name and asking them how you can help with their holiday \
mention where they are going \
This customers holiday details are here: \
{booking}"
context = [{'role':'system', 'content':system_content}]

上下文数组初始化时包含一个系统消息,该消息指示助手使用提示细节和客户数据输入。这很重要,因为它为对话设置了场景。

定义 collect_messages 函数和 UI 元素

我们还将创建一个函数来格式化消息并创建我们的 UI 元素:

def collect_messages(change):
    # ...
    context.append({'role':'user', 'content': f"{prompt}"})
    # ...
    context.append({'role':'assistant', 'content': f"{response}"})
    # ...

当用户点击 Chat! 按钮时,此函数被触发。

它读取用户的输入,清除输入字段,将用户的消息更新到上下文数组中,并通过调用 chat_with_gpt 获取助手的响应。

上下文数组再次更新,以包含助手的响应,从而形成对话历史。

用户和助手的消息将被格式化并添加到包含对话的列表中。

collect_messages 函数也被绑定到 chat_button 的点击事件:

chat_button.on_click(collect_messages)
dashboard = widgets.VBox([inp, chat_button, output])
display(dashboard)

创建了一个垂直框(VBox)小部件来包含文本输入、按钮和输出区域,形成聊天机器人仪表板。

调用 display 函数以在 Jupyter Notebook 中渲染仪表板。

聊天机器人上下文

上下文数组在管理对话历史和确保 ChatGPT 提供连贯且上下文相关的响应中起着至关重要的作用。它在用户和助手之间的每次交流后都会更新,为根据当前对话和初始系统指令生成有意义的响应提供必要的上下文。本质上,这就是当你与 ChatGPT UI 交互时幕后发生的事情。

一旦运行了代码,你应该能够看到一个简单的聊天机器人界面:

图 4.2 – 聊天机器人界面

图 4.2 – 聊天机器人界面

你现在可以通过说“你好”开始对话。你应该被 ChatGPT 欢迎并能够就你的假期提出后续问题。

尝试更改 JSON 中的信息,并自己提出其他问题。

你也可以尝试更改提示和数据输入,创建不同类型的聊天机器人和用例。

摘要

在本章中,我们探讨了提示工程的兴起领域。你了解了成功提示的核心组件。我们介绍了在提示中明确定义角色、受众、输入和输出数据的重要性,以使模型的响应适应特定的任务或用户群体。

在提示工程的迭代性质上给予了高度重视,我们看到了拥有一个坚实的提示工程策略的重要性。我们希望已经涵盖了在提示工程期间应寻找或考虑的一些具体细节。

我们还探讨了某些提示工程技巧,以及如何在特定于对话人工智能世界的实际例子中使用这些技巧。

通过在多个数据示例上的迭代开发和测试,你被鼓励完善提示以从 ChatGPT 获得更好、更一致的结果,从而增强模型在各种应用中的实用性。

因此,你现在应该能够舒适地过渡到更复杂的 ChatGPT 用例。在下一章中,我们将深入研究 LangChain,这是一个开源框架,有助于将 ChatGPT 与其他外部组件集成,从而创建更高级的应用。

进一步阅读

以下链接是本章的资源:

5

LangChain 入门

在本章中,我们将探讨 LangChain 以及这个框架如何使用户能够构建复杂的 LLM 应用。你将了解 LangChain 及其解决的问题,以及 LangChain 的核心组件、LangChain 表达式语言和你可以创建的不同类型的链的介绍。

在其核心,LangChain 是一个为构建 LLM 应用而设计的开源开发框架。在本章结束时,你将准备好构建 LangChain 应用,并使用下一章中涵盖的更高级的功能和能力。

在本章中,我们将涵盖以下关键领域:

  • LangChain 简介

  • LangChain 的核心组件

  • 理解 LangChain 表达式语言

  • 创建不同的 LangChain 链

本章旨在介绍核心概念,为你掌握 LangChain 打下坚实的基础,使你能够过渡到更复杂的 LangChain 应用。

技术要求

在本章中,我们将广泛使用 ChatGPT,因此你需要注册一个免费账户。如果你还没有创建账户,请访问 https://openai.com/,然后在页面右上角点击开始使用,或者访问 https://chat.openai.com

为了执行示例,除非另有说明,否则我建议通过网页或移动应用使用 ChatGPT。

最后一个示例技术需要安装 Python 3.9 和 Jupyter Notebook(https://jupyter.org/try-jupyter/lab/index.html)。

LangChain 简介

随着我们进一步深入到 LLM 应用开发的领域,你将开始注意到这类应用很快就会变得复杂,并需要越来越复杂的提示。一个提示可以包括基本的系统指令、用户输入、主题元数据、针对用户的个性化、之前的交互数据以及来自其他系统的其他信息。因此,一个典型的应用可能需要多次对 LLM 进行提示,并解析其输出,从而需要大量的辅助代码。这就是 Harrison Chase 创建的 LangChain 发挥作用,为你的 LLM 应用添加结构并简化开发过程的地方。

LangChain 源于在开发蓝图中使用常见抽象的同时,制造复杂 LLM 应用的需求。它是一个拥有强大社区和许多活跃贡献者的开源框架。

LangChain 的诞生源于简化开发流程的愿望,使开发者与 LLMs(大型语言模型)合作时感到不那么令人畏惧。事实上,这正是我开始使用 LangChain 的主要原因——作为一个简单的方法来部署一个潜在客户的原型,展示一个能够就客户自己的数据进行聊天的聊天机器人。

LangChain 是一个针对构建由语言模型驱动的应用程序的框架。它通过接口与语言模型和应用特定数据交互,强调上下文感知和推理。它提供模块化组件和现成的链,以方便使用和定制,促进组件的有序组装,以完成更高级别的任务。该框架还封装了各种模块,如模型 I/O、检索、链、代理、内存和回调,以满足 LLM 应用程序中交互和数据处理的各个方面。

LangChain 库

LangChain 框架支持两种不同的脚本语言:Python 和 JavaScript(TypeScript)。LangChain 的本质在于其对组合和模块化的强调,包含众多单个组件。这些组件可以合并使用,也可以独立使用,展示了框架的灵活性质。

两个库都易于使用。虽然 Python LangChain 库更加成熟且功能丰富,但TypeScript库较新,但正在开发中,以紧密模仿 Python 版本的功能。两者都旨在易于使用,重点是简化 LLMs 在各种应用程序中的集成和使用。

由于强大的社区支持,两个库都有大量的贡献者,从文档加载器到代理蓝图、内存提供者以及来自大小技术提供商的集成,应有尽有。

但为了最好地使用 LangChain,从其基础知识开始是很好的。在下一节中,我们将查看 LangChain 的核心组件。

LangChain 的核心组件

LangChain 提供各种模块,可用于创建语言模型应用程序。这些模块可以单独用于简单应用程序,也可以组合起来创建更复杂的应用程序。灵活性是这里的关键!

任何 LangChain 链最常见的组件如下:

  • LLM 模型:LangChain 的核心推理引擎是您的语言模型。LangChain 使使用多种不同类型的 LLMs 变得容易。

  • 提示模板:这些为 LLM 提供指令,控制其输出。理解如何构建提示和不同的提示策略至关重要,所以很高兴我们在上一章中已经覆盖了这一点。

  • 输出解析器:这些将 LLM 的原始响应转换为更可用的格式,简化了下游处理。

让我们更详细地看看这些核心组件。

在 LangChain 中与 LLMs 合作

LangChain 中有两种不同的 LLM 模型,称为 LLMs 和 ChatModels。这些模型用于与不同的 LLM 模型进行接口。LangChain 支持许多不同类型的 LLMs,因此是尝试不同类型 LLMs 和比较结果的强大工具。

  • LLMs:这是一个以字符串为输入并返回字符串的语言模型

  • ChatModel:这是一个以消息列表为输入并返回消息的语言模型

LLMs

LangChain 中的 LLMs 指的是它们与之接口的纯文本完成模型——例如,GPT-4。这些模型接受简单的字符串输入并输出字符串。

Chat models

相比之下,Chat 模型是为对话而调优的。LLM API 使用与纯文本完成模型不同的接口。它们不是接受单个字符串,而是接受一个标记有特定角色的聊天消息列表:系统、助手和用户。您已经在第三章学习使用 ChatGPT API部分中介绍了与聊天消息列表一起工作的概念。ChatGPT 的完成端点期望这种输入。

由于我们专注于使用 ChatGPT 和通过 LangChain 创建对话体验,我们将在本章的剩余部分更多地关注 Chat 模型。如果您对执行生成任务感兴趣,那么使用 LLM 模型可能更适合。

在 LangChain 中,聊天模型支持一系列 ChatMessages,它们有两个属性:

  • content:消息的内容

  • role: ChatMessage来源实体的角色

支持的角色如下:

  • AIMessage

  • HumanMessage

  • SystemMessage

  • FunctionMessage

您也可以在ChatMessage类中手动创建一个角色。

ChatModel 提供了一个predict_messages()方法,通过消息列表与模式进行交互。这看起来如下所示:

from langchain.schema import HumanMessage
text = " Im looking to book a direct flight from New York to London departing on December 10th and returning on January 5th. Can you provide me with the available options, including airlines, flight times, and prices?"
messages = [HumanMessage(content=text)]
chat_model.predict_messages(messages)

这应该输出类似以下的内容:

AIMessage(content='Certainly! Here are some available options for direct flights....')

现在我们来看看如何使用 LLM 的提示模板。

Prompt templates

正如我们所见,提示可以很快变得详细和长。我们也经常想要重用我们的提示。这就是 LangChain 提示模板能大量帮助的地方。它们作为结构化蓝图,用于为我们要执行的所有不同任务创建提示。

提示模板可以组合,LangChain 还提供了常见任务(如问答和摘要)的提示。

从本质上讲,我们不需要直接用指令操作提示字符串,只需传入特定提示的变量,让 LangChain 处理其余部分。我们还可以使用 LangChain 提示与我们的 Chat Model 提示进行交互,让我们看看。

LangChain 中的PromptTemplate类作为字符串提示的模具,可以填充用户定义的参数。

让我们看看一个例子。您正在尝试构建一个应用程序,该应用程序可以分析您的聊天记录,以便您了解不同部门之间对话的情感。

我们导入PromptTemplate,然后使用from_template函数创建模板和相应的变量占位符:

from langchain.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template(
    "Look at the following conversation {conversation} from the following service area {service_area} on {event_date_time} and returna sentiment"
)
conversation = """Customer: My new bike is missing a wheel!\
Chatbot: I'm sorry to hear that. Could I have your order number, please? ….
"""
conversation_analysis = prompt_template.format(
    conversation=conversation,
    service_area="complaints",
    event_date_time="2023-10-19 14:30:00"
)

如果您在模板上调用format方法并输出conversation_analysis,您应该得到如下所示的内容:

"Look at the following conversation Customer: My new bike is missing a wheel!Chatbot: I'm sorry to hear that. Could I have your order number, please?... from the following service area complaints on 2023-10-19 14:30:00 and return a sentiment"

注意,您有一个由模板和传递的变量组成的完整提示。

聊天提示模板

ChatPromptTemplate与聊天模型一起工作,并允许创建对话提示,封装一系列带有指定角色(如'system''human''AI')的聊天消息。

让我们看看一个例子。我们正在创建一个健康诊所聊天机器人,以协助处理一般健康相关咨询。我们导入ChatPromptTemplate,然后通过调用from_messages函数创建模板:

from langchain.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages(
    [
    ("system", "You are a health advisory bot for HealthHub Clinic. You can answer questions from the patient called {name}"),
    ("ai", "Hi, {name} please ask me your question."),
    ("human", "{user_input}"),
    ]
)

您可以使用此模板如下;这将创建我们的消息列表,其中包含我们分配的变量:

messages = chat_template.format_messages(name="Lucy",
    user_input="What are the symptoms of the flu?")

这些信息现在格式化如下:

[SystemMessage(content='You are a health advisory bot for HealthHub Clinic. You can answer questions from the patient called Lucy'),
AIMessage(content='Hi, Lucy please ask me your question.'),
HumanMessage(content='What are the symptoms of the flu?')]

您现在可以通过传递格式化的提示列表来在调用您的聊天模型时使用这些提示:

chat_model= ChatOpenAI()
Chat_model(messages)

此外,还有一些现成的提示,例如使用少量示例的提示模板。少量示例模板的主要组成部分是示例,这是一个要传递到提示中的示例列表以及示例提示本身。提示模板为您提供了许多提示类型的选择;然而,有时您可能想创建自己的提示模板。LangChain 也通过自定义提示模板使这变得简单。让我们在下一节中看看这些内容。

自定义模板

LangChain 中的自定义提示模板通过使用户能够为超出标准模板范围的任务创建定制提示,提供了灵活性。当任务需要特定的提示格式或特定细节来引导语言模型朝预期方向时,这些自定义模板变得非常有用。让我们看看一个例子:

Consider a scenario where you want to generate responses for a learning productivity assistant in a chat interface. This assistant might need to consider the specific task the user is asking about, the time available, and any particular user preferences or constraints.
Here's an example of what the custom prompt template for this productivity assistant could look like:
from langchain.prompts import StringPromptTemplate
from pydantic import BaseModel, validator
class ProductivityAdvicePromptTemplate(
    StringPromptTemplate, BaseModel
):
    @validator("input_variables")
    def validate_input_variables(cls, v):
        required_vars = {"task", "time_available",
            "user_preferences"}
        if not required_vars.issubset(v):
            raise ValueError(
                f"Input variables must include: {required_vars}")
        return v
    def format(self, **kwargs) -> str:
        prompt = f"""
        As a virtual productivity assistant, provide advice on:
        Task: {kwargs['task']}
        Time Available: {kwargs['time_available']}
        User Preferences: {kwargs['user_preferences']}
        Advice:
        """
        return prompt

此模板的示例用法可能如下所示,通过在定义提示时传递输入变量,并使用您所需的变量调用format函数:

productivity_advisor = ProductivityAdvicePromptTemplate(
    input_variables=[
        "task", "time_available", "user_preferences"])
# Generate a prompt for the virtual assistant
prompt = productivity_advisor.format(
task="write a research paper",
time_available="2 hours",
user_preferences="focus on quality over quantity")

您现在有一个可以重复使用和分享的生产力建议提示模板。

使用输出解析器

现在我们已经了解了 LLM 和我们的提示,LangChain 应用的核心最后一个组件是输出解析器。

通常情况下,一旦我们从我们的语言模型(LLM)中提取出响应,我们会对特定格式有具体要求。我们的示例用例基于我们在 第二章 中执行的一些任务,在名为 创建话语 的部分。我们可以使用我们的 LLM 来创建意图和话语。在这些例子中,尽管看起来它以 JSON 格式响应,但实际上它是一个字符串。更有用的事情是将 LLM 输出字符串解析为 Python 字典。

首先,我们导入所有必需的库,然后通过提供名称和描述来创建我们的 ResponseSchema。我们可以有任意多个这些,以匹配我们的输出变量,然后我们通过调用 StructuredOutputParser.from_response_schemas 函数来创建输出解析器。

我们可以通过在输出解析器上调用 get_format_instructions() 来创建包含在我们的提示模板中的指令。然后,这些指令用于我们的提示模板。请记住将我们的意图格式指令传递到我们的提示中。让我们看看以下代码示例中我们将如何做到这一点:

intent_schema = ResponseSchema(name="intents",
    description="Format the output as JSON object consisting of a key: intents, the intents key will be a list of objects with the following keys: intent, utterance, category")
response_schemas = [intent_schema]
intent_output_parser = StructuredOutputParser.from_response_schemas(
    response_schemas)
intent_format_instructions = \
    intent_output_parser.get_format_instructions()
print(intent_format_instructions)
intent_template = """ 
Create intents and utterances for a chatbot which will answer questions about a college, \
Create 10 examples of intents for the following categories: facilities and course_information \
ensure that each intent has 10 utterances, create 5 long tail and 5 more common utterances \
{intent_format_instructions}
""" 
prompt_template = ChatPromptTemplate.from_template(intent_template)
messages = prompt_template.format_messages(
    intent_format_instructions=intent_format_instructions)
#messages = prompt_template.format_messages(intent_examples=intents)
chat = ChatOpenAI(temperature=0.0, model="gpt-4")
response = chat(messages)
output_dict = intent_output_parser.parse(response.content)
output_dict.get('intents')

一旦我们从 LLM 获取响应,我们只需将我们的响应传递到我们的解析函数中,以格式化我们的结果——output_dict = intent_output_parser.parse(response.content)——现在它将是一个我们可以像平常一样交互的字典。

在这里使用输出解析器有很多好处,因为它可以管理任何数量的特定指令,用于提示中,并且结果响应可以根据需要进行解析,而无需手动格式化每一个。输出解析器是 LangChain 应用程序的核心组件之一。

在下一节中,我们将探讨链的概念以及用于操作它们的语言。

理解 LangChain 表达式语言

我们已经介绍了 LangChain 的核心组件。现在,我们将关注一个关键概念,这个概念可以用于创建和执行这些组件:LangChain 表达式语言LCEL)。让我们深入了解 LCEL 是什么,以及它在 LangChain 框架中的重要性。

什么是 LCEL?

链的概念是它们是 LangChain 的关键构建块。一个链是一系列功能块集合,在其最简单的形式中,一个链将包括一个提示、对 LLM 的调用以及结果的处理。我们在上一节中看到了这些功能块。在最复杂的情况下,链可以由数百个步骤组成。

LCEL 提供了一种声明性语法和编排框架,它被创建出来,以便用户能够以标准化的方式轻松创建功能链,定义和调用方式,使其尽可能容易运行以及创建自定义链。

LCEL 的关键组件

LCEL 提供许多开箱即用的功能,并基于管道化和模块化,以及每个组件的特定功能和可运行的协议,每个对象都提供了一个通用接口,因此您可以以相同的方式与每个对象交互。

以下列出了 LCEL 的关键特性:

  • 流支持:LCEL 通过减少第一个输出产生前的延迟来提高流效率。它从 LLM 流式传输令牌到输出解析器,以实现实时快速、逐步解析。

  • 异步和同步支持:使用 LCEL 构建的链可以使用同步(例如,在 Jupyter 笔记本中进行原型设计)和异步(例如,在 LangServe 服务器上)API 进行调用。

  • 优化并行执行:LCEL 通过按顺序执行并行步骤来有效地处理任务,例如从各种来源同时检索文档,以最小化延迟。

  • 重试和回退:为了确保您的应用程序可靠,您可以在 LCEL 链的任何部分配置重试和回退。

  • 输入和输出模式:为了帮助进行输入和输出验证、文档和错误处理,LCEL 链包括 Pydantic 和 JSON Schema,可用于验证。

  • 可观察性:LCEL 默认记录每个步骤的输入和输出以及链中步骤序列的详细信息,然后可以使用 LangSmith 服务器查看,我们将在后面的章节中介绍。

  • 集成:对于复杂的链,访问每个步骤的结果对于反馈或调试通常至关重要。LCEL 提供了与 LangSmith 的简单集成,用于监控和调试。

Runnable 协议

LCEL 的 Runnable 协议对于自定义链创建非常重要。LCEL 采用“Runnable”协议来简化自定义链的开发。

LCEL 中的 Runnable 协议旨在使构建和使用自定义处理链更加容易。简单来说,它就像一套规则或指南,有助于组织这些链的创建和运行。此协议包括用于流式传输数据和批量处理等任务的特定方法,以及它们的高级版本,用于更复杂的操作。此协议的主要目的如下:

  • 标准化:它创建了一种统一的方式来定义和使用系统的不同部分。这意味着无论您处理的是哪种组件(例如模型或工具),您都使用相同的一套规则来与之交互。

  • 灵活性:通过采用标准方法,混合和匹配不同的组件变得更加容易。您可以将不同的部分插入到您的链中,它们将顺利协同工作。

  • 清晰性:它提供了关于每种数据进入和离开每个组件的明确指南。这有助于理解和检查系统的每个部分是如何工作的。

  • 效率:它简化了构建和修改链的过程,节省了时间,并减少了出错的可能性。

因此,本质上,Runnable 协议就像是一种通用语言或蓝图,有助于有效地和高效地构建、修改和理解 LCEL 中的自定义链。

LCEL 语法

在 LCEL 中,我们使用管道操作符|)而不是Chain来创建我们的链,以不同的方式创建链。

Chain = x | y

当 LangChain 在两个对象之间遇到管道操作符时,它会尝试将x输入到y中。

LCEL 的一个简单示例

为了帮助您看到使用 LCEL 和传统方法之间的区别,让我们比较创建简单链的两种方法。

这两个示例实现了相同的结果:设置一个包含语言模型和默认提示的链。让我们探索每一个:

  1. 按如下方式使用LLMChain类。在此方法中,你明确地创建了一个LLMChain类的实例:

    llm = ChatOpenAI(()
    second_prompt = ChatPromptTemplate.from_template("tell me a joke"))
    chain = LLMChain(llm=llm, prompt=default_prompt)
    

    这涉及到将语言模型(llm)和默认提示(default_prompt)作为参数传递。

  2. 使用 LCEL 通过管道操作符(|)连接每个步骤来创建链:

    chain = llm | default_prompt
    

    此方法使用管道操作符(|)将语言模型(llm)和默认提示(default_prompt)连接起来。管道操作符有效地将一个组件(LLM)的输出“管道”到下一个组件(默认提示处理器)。

LCEL 的关键区别和优势

这里有一些关键的区别和优势需要指出:

  • 语法、风格和可读性:最明显的区别在于语法。第一种方法更为冗长和明确,而第二种方法则更为简洁,对于那些熟悉函数式编程或常见管道操作的命令行操作者来说可能更为直观。对于 LangChain 的新手来说,显式的LLMChain实例化可能更易于阅读和理解。虽然管道操作符简洁,但可能需要一些时间来习惯。

  • 可扩展性:两种方法都是可扩展的,但扩展它们的方式不同。使用LLMChain类,您可以通过子类化或修改类来扩展功能。使用管道操作符,您通过向管道添加更多组件来扩展。

  • 底层机制:虽然两者都实现了类似的结果,但底层机制可能略有不同。

  • 高级功能:LCEL 在 Python 和 Typescript 中都提供了优化并行执行和通过重试和回退处理错误的支持等优势。LCEL 还提供了在最终链完成之前输出链的各个部分结果的能力,这对于调试和向最终客户端发送更新非常有用——例如,如果您想在长时间执行期间发送聊天界面更新。

小贴士

初始时,LLMChain 接口是标准方法。然而,更现代的方法是 LCEL。LLMChain 仍然有效,但为了新的应用程序开发,建议使用 LCEL 来组合链。

在本章和本书剩余部分的下述示例中,我们将尽可能使用 LCEL。在下一节中,我们将深入探讨创建不同类型的 LangChain 链。

创建不同的 LangChain 链

在本节中,我们将探讨如何在 LangChain 中创建一些可以创建的各种链。我们的目标是引导你从基本链到更高级的链。

我们将从介绍简单链的基本知识开始。这将为你理解 LangChain 中链的工作方式提供基础。接下来,我们将学习如何创建顺序链、并行链,最后是路由链。

到本节结束时,你将清楚地了解如何创建和利用不同的 LangChain 链,并具备将这些技能应用于你未来 LangChain 项目的技能。让我们深入探讨。

基本链示例

在这个基本示例中,我们将展示一个带有提示和 LLM 组件的最简单的链,这是许多更复杂实现的基础。在这个例子中,我们使用我们的模型将文本翻译成任何语言:

prompt = ChatPromptTemplate.from_template("""
    Translate this text: {text} to {language}
""")
language = "Spanish"
text = "what is the capital of england"
runnable = prompt | ChatOpenAI() | StrOutputParser()
runnable.invoke({"text":text,"language":language})

在代码中漫步,你可以看到这是一个简单的链。我们从一个模板字符串创建一个ChatPromptTemplate实例。模板字符串定义了将呈现给语言模型的提示。提示要求模型将文本翻译成指定的语言:

prompt = ChatPromptTemplate.from_template("""
    Translate this text: {text} to {language}
""")

提示模板是一个包含以下占位符的字符串:

  • {text}: 这个占位符将被要翻译的文本替换

  • {language}: 这个占位符将被目标语言替换

然后,我们可以创建runnable,我们的组件链,所有这些组件都实现了 runnable 接口,并设计成可以串联在一起,这是 LCEL 的核心概念。这一行代码使用|运算符创建runnable链:

runnable = prompt | ChatOpenAI() | StrOutputParser()

runnable是一个由三个组件组成的链:

  • prompt: 这个组件将聊天提示模板应用于输入数据

  • ChatOpenAI: 这是将提示文本发送到ChatOpenAI聊天模型的模型

  • StrOutputParser: 这个模型将ChatOpenAI聊天模型的输出解析为字符串,便于轻松集成到各种应用中。

你可能会遇到LLMChain类实例化的链。这是本例中我们runnable的等效物:

llm_chain =LLMChain(llm=llm,
    prompt=PromptTemplate.from_template(prompt_template))

LLMChain现在是一个遗留类,因此最佳实践是使用 LCEL。

在下一节中,我们将探讨为特定于对话 AI 的更复杂用例创建一个简单的顺序链。

创建一个顺序链来调查对话数据

让我们先看看一个简单的顺序链。顺序链依次运行一系列链,当您有预期的输入和输出以执行下游处理时,效果很好。

对于这个例子,假设我们有一个名为 GreenRide 的电动汽车订阅公司,它使用实时聊天来处理其网站上的客户查询。它有兴趣创建一个聊天机器人来自动化一些客户对话。它有很多未分类的聊天转录本。它希望将这些聊天转录本分类为常见问题FAQs)和交易查询,以便它可以了解哪些查询是复杂的,哪些是简单的。它对使用基于意图的自然语言理解NLU)平台来处理交易查询和一个 LLM 来处理 FAQs 感兴趣。对于交易查询,它希望按意图聚类对话,以便它可以更详细地查看每个用例,并查看哪些团队需要参与。

您的任务是查看这些转录本数据并执行这些任务。因此,让我们将其分解:

  1. 对每个对话进行分类并将其拆分为两个列表:FAQ 和交易对话。

  2. 查看交易对话列表并按意图进行聚类。

为了实现这一点,我们将使用 LangChain 通过一系列操作处理聊天转录本。以下图表中突出了这些过程:

图 5.1 – 调查对话数据的顺序链过程

图 5.1 – 调查对话数据的顺序链过程

您需要两个链来完成分类和聚类。第一个链使用一个 LLM 和一个提示,将接收转录本列表并返回两个对话列表。第二个链也将由一个 LLM 和一个提示组成,并将接收交易对话列表并按意图类型对这些对话进行聚类。

在本例中,我们将使用 LCEL 并将一个链的结果传递给另一个链以进行进一步处理:

  1. 首先从langchain导入必要的模块,并使用温度0初始化我们的ChatOpenAI模型,因为这不是一个创意任务:

    import json
    from langchain.output_parsers import (
        ResponseSchema, StructuredOutputParser)
    from langchain.prompts import (
        SystemMessagePromptTemplate,
        HumanMessagePromptTemplate, ChatPromptTemplate)
    from langchain.chat_models import ChatOpenAI
    chat_model = ChatOpenAI(
        temperature=0, model="gpt-3.5-turbo-1106")
    
  2. 聊天转录本从 JSON 文件中加载,这将是处理的数据源:

    with open('transcripts.json', 'r') as file:
        transcripts = json.load(file)
    
  3. 设置我们的输出模式以将两个对话分类为transactional_transcriptsfaq

    response_schemas = [
        ResponseSchema(name="transactional_transcripts", description="Format the output as JSON list of conversations with the same JSON format as the input,add a category key to each conversation", type="list"),
        ResponseSchema(name="faq", description="Format the output as JSON list of conversations with the same JSON format as the input, add a category key to each conversation ", type="list"),
    ]
    

    您会注意到,尽管您为您的两个分类列表的转录本有响应模式,但您将只使用一个,即transactional_transcripts,来完成这个处理任务。

  4. 设置用于分类转录本的提示模板,包括动态内容的占位符:

    transcript_template = "Look at the following chat transcripts {transcripts} and categorize them into FAQ and transactional in the following format {format_instructions}"
    
  5. 配置输出解析器以结构化语言模型的输出,并为分类任务设置一个ChatPromptTemplate

    output_parser = StructuredOutputParser.from_response_schemas(
        response_schemas)
    format_instructions = output_parser.get_format_instructions()
    prompt = ChatPromptTemplate(
        messages=[transactional_categorization_prompt_template],
        input_variables=["transcripts"],
        partial_variables={"format_instructions": 
            format_instructions},
    )
    
  6. 创建你的交易分类处理链,结合提示、ChatGPT 模型和输出解析器来对转录本进行分类。这是使用 LangChain 的链机制组成的,其中每个组件都通过管道运算符(|)连接:

    chain_one = prompt | chat_model | output_parser
    

    这是第一个完成的链,所以现在你可以继续创建下一个链。

  7. 对于第二个意图聚类阶段,你创建新的响应模式和意图聚类提示模板:

    intent_response_schemas = [
        ResponseSchema(name="transactional_intents", description="Format the output as JSON list of conversations, add an intent key to each conversation", type="list"),
    ]
    intent_transcript_template = "Look at the following chat transcripts {transactional_transcripts} Cluster these conversations by intent {intent_format_instructions}"
    
  8. 首先设置第二个处理链进行意图聚类,通过创建新的提示和意图输出解析器。我们可以使用与第一个链相同的聊天模型,尽管根据你的任务,这些可能不同。LangChain 的美丽之处在于所有组件都是可互换的。

    intent_clustering_prompt_template = \
        HumanMessagePromptTemplate.from_template(
            intent_transcript_template)
    intent_output_parser = \
        StructuredOutputParser.from_response_schemas(
            intent_response_schemas)
    intent_format_instructions = \
        intent_output_parser.get_format_instructions()
    prompt_two = ChatPromptTemplate(
        messages=[intent_clustering_prompt_template],
        input_variables=["transactional_transcripts"],
        partial_variables={
            "intent_format_instructions": 
                intent_format_instructions},
    )
    
  9. 代码的最后部分帮助你创建第二个链,使用你创建的元素。chain_one的转录本输出被传递进来:

    chain2 = (
        {"transactional_transcripts": chain_one}
        | prompt_two
        | chat_model
        | intent_output_parser
    )
    chain_two_result = chain2.invoke({"transcripts": transcripts})
    

    输出应该是一个包含转录本列表和意图及类别属性的字典。你可以如下访问第一个:

print(chain_two_result.get('transactional_intents')[0])

这里还有其他你可以尝试的改进。如果你将要处理大量的转录本,循环处理数据块可能是个好主意,这样你就不太可能遇到标记问题。

你也可以通过添加另一个链元素来进一步处理,例如,为意图创建话语或为特定部门对意图进行分类。

使用 LangChain,我们也可以并行运行链。在下一节中,让我们看看一个例子。

利用 LangChain 中的并行链进行高效的多源信息收集

可能会有一些情况,你希望作为序列的一部分并行运行链。例如,想象一个场景,我们想要同时查询多个信息源。这种能力在用户提出需要从不同类型的内容中提取数据(如新闻文章、科学论文和一般网络信息)的复杂问题时特别有用。以下图表概述了并行链中涉及的过程:

图 5.2 – 在序列中使用并行链

图 5.2 – 在序列中使用并行链

以下代码示例说明了如何实现这种方法:

  1. 创建我们的模型,然后创建三个我们将要在链中使用单独的提示(news_chainacademic_chainweb_info_chain),每个都使用模板来查询特定类型的内容(新闻、学术论文和一般网络信息)关于给定主题:

    model = ChatOpenAI(model="gpt-4-1106-preview")
    news_prompt = ChatPromptTemplate.from_template(
        "summarize recent news articles about {topic}")
    academic_prompt = ChatPromptTemplate.from_template(
        "summarize recent scientific papers about {topic}")
    web_info_prompt = ChatPromptTemplate.from_template(
        "provide a general overview of {topic} from web sources")
    
  2. 使用RunnableParallel类创建我们的可运行并行链,因为它用于并行运行这些链:

    parallel = RunnableParallel(
        news = news_prompt | model,
        academic = academic_prompt | model,
        web_info = web_info_prompt | model
    )
    
  3. 使用主题(例如,"人工智能")调用并行链,每个链将根据其配置检索相关信息:

    results = parallel.invoke({"topic": "artificial intelligence"})
    

    这将实现你所期望的结果。所有链并行运行,并返回一个字典,你可以按以下方式访问:results['web_info'])

    创建所有三个结果的总结可能更有用,以回答用户的问题。为了实现这一点,你需要运行并行链,然后将其作为顺序链的一部分使用。

  4. 创建总结提示:

    summarise_prompt = ChatPromptTemplate.from_template("""
    summarize the following information from these different sources:
    News source: {news}
    Academic: {academic}
    Web: {web_info}
    Summary:
    """)
    
  5. 创建我们的RunnableSequence并使用invoke()调用我们的链:

    summarise_chain = parallel | summarise_prompt | model
    summarise_output = summarise_chain.invoke(
        {"topic": "artificial intelligence"})
    

总结来说,RunnableParallel输出一个包含每个并行链结果的字典。

我们可以使用我们为并行链提供的键(例如,新闻、学术和网页信息)来访问这些结果。

我们将整个输出字典传递给RunnableSequence

我们的summarise_prompt提示可以通过键访问那些结果来填充其模板。因此,这允许将并行过程的输出平滑地管道化到顺序链中。

让我们继续到一个稍微复杂一点的例子,我们将智能地路由我们的请求到不同的链。

路由链以有效回答问题

当创建一个由 LLM(大型语言模型)驱动的应用程序时,你可能需要根据需要提供的问题或信息类型调用不同的链。RunnableBranch允许你这样做。

以此类例,让我们回到我们的汽车订阅公司:GreenRide。我们有一个需要处理的不同类型查询的想法,这些查询可以分为三类:维护、车辆信息和账户。然而,我们需要用不同的链来回答这些问题。让我们看看这是如何实现的:

  1. 首先,我们从langchain库导入必要的类,然后初始化我们的模型:

    from langchain.chat_models import ChatOpenAI...
    llm = ChatOpenAI(temperature=0, model="gpt-4-1106-preview")
    
  2. 接下来,我们需要为每个部门创建提示。我们为不同类型的查询(维护、车辆信息和账户)创建模板。每个模板都旨在引导语言模型在特定上下文中回答。

    maintenance_template = "You are an expert in car maintenance     {input}"
    maintenance_prompt = PromptTemplate.from_template(
        maintenance_template)
    car_info_template = "You are knowledgeable about various car models    {input}"
    car_info_prompt = PromptTemplate.from_template(
        car_info_template)
    accounts_template = "You are well-versed in account management    {input}"
    accounts_prompt = PromptTemplate.from_template(
        accounts_template)
    
  3. 我们还需要一个通用模板:

    general_prompt = PromptTemplate.from_template(
        "You are a helpful assistant. Answer the question... {input}"
    )
    

    这是一个适用于不符合特定部门查询的回退模板。

  4. 接下来,我们使用RunnableBranch创建分支逻辑:

    prompt_branch = RunnableBranch(
        (lambda x: x["topic"] == "maintenance", maintenance_prompt),
        general_prompt,
    )
    

    这一部分定义了基于主题来决定使用哪个模板的逻辑。它会检查输入的主题,并将其与相应的模板进行匹配。

  5. 然后,我们需要创建主题分类器和分类链:

    class TopicClassifier(BaseModel):
        topic: Literal["maintenance", "car_info", "accounts", 
            "general"]
    

    TopicClassifier类定义了一个 Pydantic 数据模型,它代表了主题分类过程的输出。它有一个单独的字段,topic,这是一个枚举值,表示用户问题的分类主题。

  6. 接下来,我们使用convert_pydantic_to_openai_function函数将TopicClassifier Pydantic 模型转换为 OpenAI 函数,该函数可以与ChatOpenAI API 一起使用:

    classifier_function = \
        convert_pydantic_to_openai_function(TopicClassifier)
    parser = PydanticAttrOutputFunctionsParser(
        pydantic_schema=TopicClassifier, attr_name="topic"
    )
    
  7. 然后,我们使用 bind 方法将转换后的 TopicClassifier 函数添加到 ChatOpenAI 对象中。这实际上使得主题分类函数在 ChatOpenAI 上下文中作为一个可调用的函数可用。PydanticAttrOutputFunctionsParser 类用于解析主题分类函数的输出,它是一个 JSON 对象。pydantic_schema 参数指定用于解析 JSON 对象的 Pydantic 模型,在这种情况下是 TopicClassifier 模型。attr_name 参数指定从 Pydantic 模型中提取分类主题的属性,即主题属性。

OpenAI 函数

我们在这里使用 OpenAI 函数调用以确保我们接收正确的 JSON 格式和模式。值得注意的是,使用 OpenAI 模型的最新版本(gpt-4-1106-previewgpt-3.5-turbo-1106),你可以将 response_format 设置为 { "type": "json_object" } 以启用 JSON 模式。当启用 JSON 模式时,模型将仅生成可以解析为有效 JSON 对象的字符串。然而,这并不保证正确的模式。

  1. 然后,我们在链中将这些整合在一起:

     classifier_chain = llm | parser
    

    classifier_chain 被一个用户问题调用时,问题首先被传递到 ChatOpenAI 函数进行主题分类。然后,主题分类函数的输出被 Pydantic 属性输出函数解析器解析,提取出的分类主题被返回,使我们能够定义要调用的模板。

  2. 最后,我们创建我们的主链管道,将所有这些整合在一起:

    final_chain = (
        RunnablePassthrough.assign(topic=itemgetter("input") 
        | classifier_chain)
        | prompt_branch
        | ChatOpenAI()
        | StrOutputParser()
    )
    

    最终的链首先对输入进行分类,然后选择适当的模板,使用语言模型处理输入,并解析输出。最后,调用我们的链变得非常简单:

    final_chain.invoke( {"input": "How do I update my payment method for my car subscription?"})
    

你现在应该有一个可以工作的示例,设置了一个能够智能地将客户支持查询路由到特定部门(如维护、车辆信息和账户)的聊天机器人。

目前,我们正在考虑不同的提示。我们可以扩展 RunnableBranch 以将输入路由到不同的提示,甚至完全不同的链。这允许根据输入的主题或其他标准进行更复杂和专业的处理。

假设除了处理维护、车辆信息和账户查询外,你还想将一些查询路由到不同的链进行特殊处理。例如,你可能有一个处理信用控制查询(如支付)的链,这需要访问支付服务和用户历史记录,因此链更加复杂。这是一个只需创建链并将其添加到 RunnableBranch 配置中的分支逻辑中的简单案例:

credit_control_template = PromptTemplate.from_template(
    "You are a credit control assistant. Provide immediate and useful credit control advice for GreenRide customers and allow them to pay their bills .\n\n{input}"
)
credit_control_chain = llm | access_stripe_details credit_control_template
prompt_branch = RunnableBranch(
    (lambda x: x["topic"] == "credit_control", credit_control_chain),
    general_prompt,
)

这是一个相当简单的链和理论示例,它使用文档加载组件来查找用户支付账户详情。这介绍了 LangChain 中可用的许多不同模块之一,我们将在下一章中探讨。

摘要

在本章中,我们首次了解了 LangChain,您应该对它是什么、解决的问题以及它在简化复杂 LLM 应用开发中的作用有了良好的理解。

我们已经探讨了 LangChain 的核心组件,如 LLM 模型、提示模板和输出解析器。您应该对 LCEL、其关键特性和它在 LangChain 框架中创建和执行链的作用有良好的理解。最后,本章涵盖了从基本到复杂的 LangChain 链的各种示例,以说明所讨论概念的实际应用。

在本章中,我们只是对 Langchain 进行了初步的探索,但希望我们已经为您构建了一个坚实的基础,以便您设计和实现 LangChain 应用,并使您能够继续学习 LangChain 库的更复杂的概念和应用。在下一章中,我们将探讨其他概念,如内存、代理、模块和其他工具,特别是 LangSmith。

进一步阅读

以下链接是经过精心挑选的资源列表,旨在帮助您了解本章讨论的主题:

6

使用 LangChain 进行高级调试、监控和检索

本章我们将探讨一些更高级的 LangChain 主题及其应用。您将了解一些重要过程,例如调试 LangChain 和使用新的 LangSmith 平台。您将了解代理和工具的力量,并了解它们如何赋予代理超级能力。您将研究现成的工具,并为代理创建一个自定义工具。然后,您将在创建由大型语言模型LLM)驱动的对话体验的背景下了解内存,并了解如何使用 LangChain 实现这一点。

本章旨在在前一章的基础上,探讨更高级的概念,使您能够创建更复杂的 LangChain 应用。

本章将涵盖以下主题:

  • 调试和监控 LangChain

  • 利用 LangChain 代理

  • 探索 LangChain 内存

技术要求

在本章中,我们将广泛使用 ChatGPT,因此您需要注册一个免费账户。如果您还没有创建账户,请访问 openai.com/ 并点击页面右上角的 Get Started,或者访问 chat.openai.com

这些示例需要安装 Python 3.9 和 Jupyter Notebook,您可以从 jupyter.org/install 下载。Jupyter Notebook 也包含在 Anaconda 中。您可以在本书的 GitHub 仓库中找到这一章的代码:github.com/PacktPublishing/ChatGPT-for-Conversational-AI-and-Chatbots/chapter6

调试和监控 LangChain

到现在为止,您可能已经意识到,即使是在更简单的链中,LangChain 内部仍然有很多事情在进行。通常,当您从不同的来源构建提示时,您需要查看您语言模型的输入和输出,以便理解和迭代它们。

因此,了解您应用程序内部发生的情况非常重要,这样您就可以构建、监控和调试您的应用程序。LangChain 提供了多种不同的方法来实现这一点。

让我们探索这些选项,以更清楚地了解它们如何增强您应用程序的功能。我们将从最简单的选项开始,逐步过渡到最全面的选项:LangSmith。

理解跟踪技术

LangChain 提供了一些简单的方法来输出链的不同步骤。

如果您正在使用 Jupyter Notebook 或仅通过运行 Python 脚本来使用本书中提供的示例,您有一些提供跟踪输出的选项:

  • 详细输出:将 verbose 设置为 True 会创建一个全局设置,并将链的步骤以最高级别输出,以便我们可以看到正在发生的不同 LLM 调用。您可以按照以下方式设置:

    from langchain.globals import set_verbose
    set_verbose(True)
    
  • 调试:将 debug 设置为 True 会创建一个全局设置,输出具有回调支持(链、代理、模型、工具和检索器)的组件生成的一切输入和输出,并提供最全面的信息:

    from langchain.globals import set_debug
    set_debug()
    
  • 详细日志:您可能还希望在特定的链上激活详细日志,因为如果您正在处理多个链,全局输出可能会太多。如果您使用链对象,则可以按照以下方式实现:

    conversation_with_summary = ConversationChain(
        llm=llm,
        verbose=True,
    )
    
  • 回调函数:如果您使用 LCEL 创建链并且想将 verbose 设置为 True,那么您将需要使用回调函数。在下面的代码示例中,我们在对 chain 调用 invoke 时,传递了带有 ConsoleCallbackHandler 的配置:

    from langchain.callbacks.tracers import ConsoleCallbackHandler
    from langchain.schema.runnable import RunnableLambda
    def fun_1(x: int) -> int:
        return x + 1
    def fun_2(x: int) -> int:
        return x * 2
    runnable = RunnableLambda(fun_1) | RunnableLambda(fun_2)
    runnable.invoke(1, config={'callbacks': 
        [ConsoleCallbackHandler()]})
    

    之前的代码创建了一个可运行对象的链,然后调用它。我们使用|运算符来链接两个可运行对象。这意味着fun_1的输出将被传递为fun_2的输入。在这里,runnable.invoke(1, config={'callbacks': [ConsoleCallbackHandler()]})调用以 1 为输入的链。配置指定应使用ConsoleCallbackHandler

    输出将显示链的每个步骤。部分输出如下所示:

    [chain/start] [1:chain:RunnableSequence] Entering Chain run with input:
    {
      "input": 1
    }
    [chain/start] [1:chain:RunnableSequence > 2:chain:fun_1] Entering Chain run with input:
    {
      "input": 1
    }
    

如果您仍在使用笔记本或 Python 脚本进行开发,这些技术是可行的。然而,如果您想持久化日志,需要更细粒度的信息和直观的界面,或者您打算将应用程序投入生产,那么可能是时候考虑使用 LangSmith 了。我们将在下一节中介绍这一点。

介绍 LangSmith

LangSmith 目前是一个处于 beta 阶段的早期产品。除了是早期发布之外,它还是用于处理 LangChain 的新工具,你可能会经常使用它。它简化了调试、测试、监控和评估您的 LangChain 项目。本节将仅简要介绍 LangSmith,因此鼓励您查看文档,因为它们正在不断更新。

设置 LangSmith

开始使用 LangSmith 涉及几个简单的步骤:

  1. 首先,您需要创建一个 LangSmith 账户并生成一个 API 密钥。

    1. 访问 LangChain 网站smith.langchain.com。遵循网站上的说明进行注册并创建一个新账户。

    2. 创建账户后,使用您的新凭据登录 LangSmith 控制台。

    3. 登录后,在 LangSmith 控制台内导航到设置页面。在此,找到创建 API 密钥并生成一个的选项。

  2. 接下来,您需要配置您的开发环境,以便它们可以与 LangSmith 集成。这只是一个设置以下变量的简单案例:

    os.environ['LANGCHAIN_TRACING_V2'] = "true"
    os.environ['LANGCHAIN_ENDPOINT'] = "https://api.smith.langchain.com"
    os.environ['LANGCHAIN_API_KEY'] = "Your Langchain API key"
    

一旦设置了这些,每次运行将意味着相应的跟踪将被记录到您的默认项目中。运行代表您应用程序中的单个工作单元。

通过设置以下命令可以轻松地针对特定项目:

os.environ[' LANGCHAIN_PROJECT'] = "Your project name"

然后,您可以查看每次运行,并深入了解每个步骤的详细信息,以确切了解每个步骤中发生了什么。

利用 LangChain 代理

LLMs 非常强大,但它们也有一些基本缺陷。我们已经广泛讨论了它们的限制;请记住,它们的知识只到 ChatGPT 的训练数据截止时,ChatGPT 的训练数据截止于 2021 年晚些时候。令人惊讶的是,这项先进的技术在其他计算任务上也不太擅长,例如基本的数学、逻辑,甚至查找它们不知道的其他信息的能力。

为了弥补这些缺点,我们需要另一种技术或方法来帮助我们的 LLM 在需要帮助的地方。这些解决方案被称为 代理,在本节中,我们将探讨它们是什么,如何工作,以及如何使用 LangChain。

代理是什么?

代理为 LLM 提供了执行它们无法有效执行的任务的工具。有几种不同类型的代理被设计用来与不同的模型一起工作,例如 OpenAI LLM,并提供对不同的任务和用例的支持,例如 XML 或 JSON 处理。

每种类型都有特定的用例,因此查看 LangChain 关于每个代理的信息是值得的,这样你可以决定哪个最适合你的用例。

要创建一个代理,我们需要考虑三个不同的组件:

  • LLM

  • 执行任务的工具

  • 一个代理来控制任务

LLM 将处理理解和生成响应,专门的工具将执行特定任务,而代理将协调这些任务。

LangChain 工具是什么?

LangChain 工具允许代理通过与其他系统交互来执行其定义的任务。一个工具由一个工具模式组成,其中包含有关工具期望哪些输入的信息,以及一个用于执行任务的函数。LangChain 提供了许多内置工具,并允许你创建自定义工具,你可能会在某个时候想要这样做。除了单个工具之外,LangChain 还提供了工具包的概念,这是你可以用来执行特定任务的工具组。

让我们看看构成工具的因素:

  • 一个名称和描述,以记录其预期用途

  • 用于定义输入参数的 JSON 模式

  • 一个带有输入的运行函数

  • 一个 return_direct 标志,指示输出是否应直接发送给用户

重要的是尽可能包含这些信息,并保持工具简单,以便 LLM 能够轻松使用。名称、描述和模式都将用于向 LLM 的提示中,以便它知道要采取什么行动。这些需要清晰简洁。

OpenAI 工具调用的介绍

在我们深入研究下一个示例之前,了解 OpenAI 函数/工具非常重要,这样我们才能理解它们为什么存在以及如何使用它们。只是为了混淆,这些曾经被称为 函数,但现在它们被称为 工具,这更有意义。

在函数调用发布之前,你会问 ChatGPT 一个问题,比如“伦敦的最新新闻是什么?”,你不会得到一个有用的回答。正如我们所知,它不擅长返回最新信息,因为它没有连接到互联网,无法拉取或抓取数据。

我们可以编写一些代码去调用新闻服务,但我们需要传递位置和其他任何参数,然后回到我们的对话中。这并不容易做到,尤其是如果我们想使用对话中的参数来调用我们的服务。

函数调用是由 ChatGPT Turbo 和 GPT4 模型创建并支持的,以克服这些问题,并通过轻松调用外部 API 和提取结构化数据来提供轻松回答问题的方法。这些模型被训练来查看函数,并智能地决定何时调用它们。实现函数的基本过程如下:

  1. 使用用户查询和预定义的函数触发模型。模型可能会调用函数,生成包含可能假设参数的 JSON 对象。

  2. 在你的代码中解码 JSON 并使用任何给定的参数执行函数。

  3. 将函数的响应输入回模型,以便为用户进行总结。

让我们来看一个简单的例子。

查看一个简单的 OpenAI 工具示例

我们通过聊天完成调用中的tools参数将我们的函数定义传递给聊天完成,该参数接受一个表示为标准JSON格式的工具数组。以下是一个定义,ChatGPT 可能会考虑并调用以获取特定主题的最新新闻文章:

  tools = [{
      "type": "function",
      "function": {
        "name": "get_news_articles",
        "description": "Retrieve news articles based on a specific topic and date range",
        "parameters": {
          "type": "object",
          "properties": {
            "topic": {
              "type": "string",
              "description": "The topic or subject of interest for the news articles"
            },
          "required": ["topic"]
        }
      }
    }
  ]

我们提供工具的名称,这将迫使模型调用我们的函数,并尽可能提供详细的描述。记住,这个描述将在提示的上下文中使用,所以越准确、越详细越好。当涉及到工具时,尽量描述你的函数将要做什么,因为这是模型被训练的方式。然后,我们添加将要发送到函数的参数的描述。在我们的例子中,我们传递一个topic字符串。

现在,当我们尝试通过询问我们的 ChatGPT 模型关于伦敦的最新新闻来进行聊天完成时,模型将知道使用我们在工具定义中定义的特定参数调用我们的函数。如果我们定义了更多的参数,ChatGPT 会询问澄清问题,直到它获得所需的所有信息。

工具如下传递到我们的完成调用中:

response = client.chat.completions.create(
        model="gpt-3.5-turbo-0125",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )

注意,我们已经将tool_choice设置为auto,这告诉 ChatGPT 决定是否使用工具。

这应该输出类似以下内容,显示没有指定内容的ChatCompletionMessage。然而,在我们的函数调用中,我们应该有ChatCompletionMessageToolCall。我们还有topic参数和我们的函数名称:

ChatCompletionMessage(content=None, role='assistant', 
    function_call=None, 
    tool_calls=[
        ChatCompletionMessageToolCall(
            id='call_ewHp8R8GUAHY6Dy4UXdEej3B',
            function=Function(
                arguments='{"topic":"London"}', 
                name='get_news_articles'), 
            type='function')])

在这里,我们可以看到 ChatGPT 已经决定调用我们的函数;如果它决定不这样做,我们可以进行一些测试。如果我们把问题改为“解释量子物理”这样的内容,那么我们应该得到包含回答问题的内容的ChatCompletionMessage

ChatCompletionMessage(content="Chess is a classic strategy board game played ....

正如我们所见,ChatGPT 决定使用哪些工具来满足这个问题,并将这些工具列在我们的tool_calls列表中。我们可以遍历这个列表,如果 ChatGPT 从我们的问题中提取了这些参数,我们可以用参数调用每个函数。之后,我们可以将结果添加到我们的消息列表中,并让 ChatGPT 为用户总结结果。

不要忘记,你还可以在我们的聊天完成调用中设置tool_choice={"type": "function", "function": {"name": "another_response_function"}},以强制 ChatGPT 使用特定的函数,而不是让它自己决定。

函数/工具的另一个强大应用是使 ChatGPT 能够轻松创建确定性、完美格式化的数据。在第二章中,我们是在提示用户话语或 JSON 数据集。现在,我们可以通过创建一个函数定义来创建完美的输出,从而使用工具来实现这一点。我建议你查看第二章中的一些训练数据创建任务,并创建一个工具来实现相同的结果。

OpenAI 函数有很多功能,但这至少应该能让你对它们的优点和使用步骤有足够的了解。现在,让我们看看 LangChain 工具,看看 LangChain 如何简化 OpenAI 函数的使用。

插即用的 LangChain 工具,立即集成

LangChain 提供了许多现成的工具,这使得为你的代理提供工具变得容易。你可以在文档中找到这些工具的列表,网址为python.langchain.com/docs/integrations/tools/,这些工具由供应商和社区成员创建和维护。它们涵盖了从搜索引擎到与文件系统交互以及与像 Google Drive 这样的大型云服务供应商交互的广泛功能。

一个现成的工具示例

让我们看看我最喜欢的工具之一:Tavily 搜索 API。Tavily 搜索是一个针对 LLM(大型语言模型)优化的搜索引擎,以提供最佳搜索结果。因此,它是一个很好的 LLM 工具示例,你可能会用到。在查看如何创建这个工具的同时,了解其细节也非常有用,这样我们可以理解构成有效工具的组件。首先,我们需要安装所需的库:

pip install -U langchain-community tavily-python

接下来,导入库并创建我们需要的 API 密钥:

os.environ['OPENAI_API_KEY'] = OPENAI_KEY
os.environ["LANGCHAIN_API_KEY"] = "TAVILY_API_KEY "

现在,我们可以通过创建TavilySearchAPIWrapper类的实例来创建工具,该类作为 Tavily 搜索 API 的包装器。我们可以将这个实例传递给我们的TavilySearchResults类:

tavily_search = TavilySearchAPIWrapper()
tavily_tool = TavilySearchResults(api_wrapper=tavily_search)

你可以通过打印print(tavily_tool.name), print(tavily_tool.description), print(tavily_tool.args)来检查工具的不同属性,最重要的是通过调用invoke()来执行搜索:

tavily_tool.invoke({"query": "how many named storms have there been this year in the UK"})

当你运行这个程序时,你应该得到一个包含搜索最新信息的响应。你应该看到以下类似的输出:

图 6.1 – Tavily 搜索输出

图 6.1 – Tavily 搜索输出

在下一节中,我们将探讨如何使用工具与代理一起使用。

使用我们的工具与代理一起使用

到目前为止,我们已经创建了一个工具,但还没有使用它。为此,我们需要创建一个代理。在我们的例子中,我们使用的是 OpenAI Functions 代理。在上一节中,我们介绍了 OpenAI 函数;在本节中,我们将看到使用 LangChain 实现这一点是多么简单。代理可以使用create_openai_functions_agent()函数创建,该函数接受三个参数:

  • llm:支持 OpenAI 函数调用 API 的语言模型

  • tools:代理可以使用的工具列表

  • 提示:代理将使用的提示

我们将这些三个参数传递给创建我们的代理:

open_ai_agent = create_openai_functions_agent(llm, tools,prompt)

现在我们有了这个代理,我们需要创建一个AgentExecuter类来运行它:

open_ai_agent_executor = AgentExecutor(agent=agent, tools=tools)

我们应该能够调用invoke()函数并返回包含最新信息的某些结果:

result = open_ai_agent_executor.invoke({"input": "how many named storms have there been in 2024 in the UK"})

如果您打印出结果,您应该得到一个包含最新信息的答案,显示我们的代理和工具正在正确工作。请记住查看 Langsmith 中的日志,以便您可以跟踪那里发生的事情。

您可以通过使用 LangChain 生态系统提供的工具包,进一步利用 LangChain 的即插即用工具。这些工具包提供了专为特定任务设计的工具集合。

现在我们已经查看了一个预构建的工具箱并介绍了代理,您可以看到 LangChain 代理是多么强大。我们鼓励您查看其他工具和代理类型,请参阅python.langchain.com/docs/integrations/tools/

您可能需要一种不同类型的工具来满足需求。好消息是创建自定义工具也很容易。让我们深入一个具体的例子,以便您了解涉及的步骤。

创建自定义天气工具

对于我们的例子,我们将创建一个自定义工具,使用 Open-Meteo,这个免费的天气 API Meto 来获取位置的当前天气。

我们的工具将接受两个参数,latitudelongitude,这样我们就可以查找特定位置的天气。这两个参数都是必需的。

首先要考虑的是,我们需要一个支持多个输入的代理类型。因此,让我们选择StructuredChatAgent。让我们直接进入代码:

  1. 首先,导入必要的模块。该脚本导入了各种 Python 模块,包括用于制作 HTTP 请求、处理数据和用于工具和代理创建的特定 LangChain 组件:

    import os
    from langchain.tools import BaseTool
    from typing import Union
    from langchain.agents import (AgentExecutor, 
        create_structured_chat_agent)
    from langchain import hub
    from langchain_openai import ChatOpenAI
    
  2. 设置 OpenAI 和 LangChain API 所需的环境变量,您的 LangSmith 密钥用于日志记录,以及其他配置细节。

  3. LangChain 工具是我们从代理中调用的函数。为了创建一个,我们必须遵循相同的基本模式。这涉及到继承BaseTool,实现run(),并在创建代理时传递我们工具的实例。自定义工具类GetWeatherByLocationTool扩展了BaseTool类,提供了基于纬度和经度获取天气信息的具体功能。我们还必须提供一个名称和描述,以便我们的 LLM 知道如何以及何时使用该工具:

    class GetWeatherByLocationTool(BaseTool):
        name = "Weather service"
        description = " A weather tool optimized for comprehensive up to date weather information. Useful for when you need to answer questions about the weather.  Use this tool to answer questions about the weather for a specific location. To use the tool, you must provide at the following parameters"
     "['latitude', 'longitude']. "
    def _run(self, latitude: Union[int, float], longitude: Union[int, float]) -> str:
            ...
                return result_string
            else:
                return "Failed to retrieve weather data."
    

    该工具的_run()方法执行实际的逻辑,使用 Open-Meteo API 获取天气信息,并将结果作为字符串返回。

  4. 现在我们已经创建了我们的工具,我们可以初始化语言模型和自定义工具,然后使用create_structured_chat_agent()函数创建代理,该函数将语言模型与工具结合以处理特定查询:

    llm = ChatOpenAI(model="gpt-3.5-turbo-1106")
    tools = [GetWeatherByLocationTool()]
    prompt = hub.pull("hwchase17/structured-chat-agent")
    agent = create_structured_chat_agent(llm, tools, prompt)
    
  5. 创建一个AgentExecutor类,该类负责使用提供的工具执行代理。然后,使用特定的查询调用代理,如下所示:

    executor = AgentExecutor(agent=agent,
        tools=tools,,handle_parsing_errors=True)
    output = executor.invoke({"input": "What's the weather like in waddesdon"})
    print(output)
    

    希望当你运行这个程序时,你会得到以下类似的结果:

    {'input': 'whats the weather like in waddesdon', 'output': 'The current weather in Waddesdon is 5.6°C with no rain.'}
    

好玩的是,我们传递了一个位置,LLM 知道该位置使用的纬度和经度坐标,并在调用自定义工具时使用这些坐标。

通过这个,你已经看到了当创建自定义工具以及依赖一些现成的强大工具时,LangChain 代理是多么强大。可能性是无限的!

在下一节中,我们将探讨为你的 ChatGPT 代理提供的一个更高级的要求,即给他们赋予记忆能力。我们将学习如何使用 LangChain 来实现这一点。

探索 LangChain 的记忆功能

当我们与 LLMs 一起工作时,一个关键挑战出现了,因为它们无法天生地回忆过去的交互。因此,本质上,它们是无状态的。无状态的操作不会将信息从一个请求持久化到下一个请求,如果你想要创建一个聊天机器人,这是一个问题。解决这个问题的方法是将整个对话添加到上下文中。随着 ChatGPT 客户端的进展,它将把整个对话传递到每个提示中。

我们希望我们的 ChatGPT 应用能够提供具有状态交互的功能,其中信息可以在请求和会话之间被记住。为了实现这一点,我们需要使用一个记忆机制。然后,不同的记忆表示将被包含在 LLM 提示中。本节专门探讨在 LLMs 背景下记忆的概念。我们将深入研究不同类型的记忆以及在使用 LLMs 时面临的挑战,然后再深入探讨如何使用 LangChain 为 ChatGPT 应用提供记忆能力。

小贴士

ChatGPT UI 在底层使用记忆,通过在每次提供提示时传递消息历史来引入状态。这也允许你选择并重新启动之前的对话。

探索不同类型的记忆应用

如果你考虑进行一次对话——无论是只是就某个主题聊天,还是更私人的对话,或者是为了实现交易结果而进行的对话——很快就会变得明显,可能会有不同类型的记忆在发挥作用。对记忆的明显需求是存储在活跃对话中说过的话。然而,可能还需要其他类型的记忆,例如历史对话的记忆、与特定用户相关的特定信息的记忆,或者与用户或应用程序相关的特定主题知识的记忆。让我们在有效对话的背景下看看不同的记忆类型。

活跃对话中的记忆

在活跃对话中,以下形式的记忆之一会发挥作用:

  • 对话缓冲记忆:这种记忆类型记录了正在进行中的对话的完整文本,包括所有输入和响应。它保留了对话的全部上下文,以便可以将每个提示传递给大型语言模型(LLM)。

  • 对话缓冲窗口记忆:这是缓冲记忆的更复杂版本,它只维护最近指定数量的交互,丢弃较旧的交互或将它们合并为摘要。它作为短期记忆,随着对话在多个回合中进展,优化令牌的使用。

历史记忆

历史记忆可以分为两种类型:

  • 过去对话:这包括长期记忆,可能是针对此特定用户的先前对话和会话。此用户可能会通过身份验证被您的代理所知。历史对话可能只是一个先前交互的列表,或者可能是一个更复杂的实现,其中在使用之前会查询交互。

  • 过去对话摘要:这种方法建立在历史记忆之上,并在将其整合到模型的历史中之前压缩之前的交互。它旨在减少令牌使用并简化内存管理,同时保留对话的必要元素。

个性化记忆

个性化记忆可能包括更广泛的信息,例如用户偏好和历史数据,这些数据可以是结构化格式(如知识图谱)或非结构化格式(如文档集合)组织。这种类型的记忆还可能提供记忆库机制,以微调记忆,为大型语言模型(LLM)提供最佳支持。

理解记忆挑战

对于所有这些不同类型的记忆,我们必须考虑的关键资源是我们正在使用的大型语言模型(LLM)的上下文窗口大小。这将决定工作对话的大小,包括提示和结果,因此你选择实现的所有这些类型的记忆都需要考虑在上下文窗口的整体大小中。作为一个 ChatGPT 开发者,你需要将这个上下文窗口大小视为有限资源,因此决定什么信息应该包含在这个窗口内可能成为创建复杂大型语言模型(LLM)应用的一个具有挑战性的方面。

对于你 ChatGPT 应用的发展来说,好消息是 OpenAI 已经为他们的模型发布了越来越大的上下文窗口。例如,最新的 GPT-4 模型支持超过 32k 个 token,这大约是 24k 个单词。

坏消息是,拥有更大、越来越大的上下文可能并不能保证性能的改善。以下是一些可能影响响应准确性或产生其他影响的其他因素:

  • 位置:信息的相对位置可能影响结果,因此战略性地将最重要的信息放置在上下文窗口的开始或结束处可能会提高模型的输出。

  • 清晰度:更大的上下文可能意味着准确性下降。明智的做法不是认为上下文越大,你就能添加的信息就越多。尽可能多地加载信息可能会导致响应不够准确或不相关。

  • 知识优先级:许多 LLM 实现将涉及特定领域的知识。作为 LLM 开发者,你可能需要决定当上下文记忆资源紧张时,这种知识是否应该优先于对话记忆。

  • 成本:尽管 OpenAI 试图通过每次发布的 GPT 模型来降低成本,但这些更大的上下文允许你使用更多的 token,如果不小心,成本可能会飙升。

小贴士

在使用记忆时,不仅要考虑选择适当的信息,还要以增强模型性能的方式组织信息。

介绍记忆使用技巧

有几种不同复杂度和实施难度的记忆管理技巧,一些旨在简化活跃对话记忆,而另一些则旨在帮助历史和知识。让我们看看我们可以使用的不同记忆使用技巧:

  • 滚动活跃对话记忆:滚动窗口技术保持一个动态的窗口,显示最近的交互或消息,确保模型始终关注最新的上下文。以下图显示了这种类型记忆实现的过程:

图 6.2 – 滚动对话记忆过程

图 6.2 – 滚动对话记忆过程

随着新消息的到来,旧数据将从窗口中移除,有效地限制了模型对过去消息的暴露。这种方法既简单又高效。然而,这是一个基本的方法,它存在在不知道刚刚移除了什么以及这会如何影响对话的情况下丢弃有价值的信息历史的风险。

  • 增量总结活跃对话记忆:这种方法将对话中的关键要点作为总结并传递给上下文,而不是整个对话,同时包括最新的消息。这种方法降低了数据丢失的风险,并允许进行简洁的总结,同时仍然保持对话的主题。以下图展示了增量记忆实现过程:

图 6.3 – 增量总结技术

图 6.3 – 增量总结技术

然而,如果你在多个对话调用中总结内容,这可能会导致对话细微差别的持续稀释。此外,创建这些总结还需要进一步的 LLM 调用,从而增加计算成本

  • 使用记忆库增强上下文:有一种新兴的技术称为记忆库,这是一种为大型语言模型(LLM)量身定制的记忆机制。这种类型的实现将能够从其记忆存储机制中召回多轮对话、个人信息和总结事件。以下图展示了使用记忆库的过程:

图 6.4 – 记忆库技术

图 6.4 – 记忆库技术

应用程序将通过使用受艾宾浩斯遗忘曲线理论启发的记忆更新器来管理存储和遗忘的内容,同时使用其 LLM 调用来决定当前对话中要使用的内容,从而不断演变其上下文。将这些内容整合在一起,有望提供更加个性化的体验。实现具有记忆库的应用程序将是一项复杂的任务。

理解记忆挑战部分,我们概述了可能存在一些与较大上下文相关的问题。可能的情况是,具有 4k 令牌限制的模型根本不足以支持你需要放入上下文中的所有内容,因此查看具有更大上下文的 GPT 模型可能是一个好主意。

克服记忆约束的最简单方法之一是将更复杂的任务分解成更小的提示。这种技术有助于简化复杂的提示,并且通常能获得更好的结果。

希望你现在能够从创建会话体验的角度理解记忆,并了解一些可用的技术,同时也能够欣赏到添加记忆的一些挑战和复杂性。在下一节中,我们将看到 LangChain 如何被用来向 LLM 应用程序添加记忆。

理解在 LangChain 中使用记忆的示例

在其最简单形式中,会话系统必须能够直接访问一系列过去的交互,以便它们可以在聊天界面中显示会话历史,或者在我们的情况下传递给 LLM。在这个例子中,我们将探讨使用 LangChain 记忆来为现场音乐助手创建一个简单的会话界面。主要目的是展示我们如何在简单的会话应用程序中使用记忆。

LangChain 提供了多种支持记忆的集成方式,从内存到持久数据库。在下面的示例中,我们将使用ConversationBufferMemory类,这是 langChain 中最基本的记忆形式。

基本上,我们的记忆系统应该促进两个主要功能:读取和写入记忆。

在接收用户初始输入并在启动其核心逻辑之前,链从其记忆系统中读取,以便可以使用以前的交互在提示中使用。

一旦核心逻辑执行完毕但在发送响应之前,链会将输出和输入写入记忆。这一动作确保了这些信息可以在未来的交互中供参考。本质上,这与传统对话式人工智能平台管理对话的方式相似。

这些过程在以下示例中得到了说明:

  1. 首先,我们必须从langchain库中导入必要的类,然后初始化我们的模型:

    llm = ChatOpenAI(temperature=0.0,
        openai_api_key=os.getenv("OPENAI_API_KEY"),
        model="gpt-4-1106-preview")
    
  2. 接下来,必须初始化一个ConversationBufferMemory对象来管理对话历史。return_messages=True参数确保在查询时记忆返回一个消息列表。默认情况下,这些是单个字符串:

    memory = ConversationBufferMemory(return_messages=True)
    
  3. 现在,我们必须设置一个ChatPromptTemplate模板来结构化对话。它包括一个定义机器人角色(音乐粉丝活动聊天机器人)的系统消息,一个用于历史消息的占位符,以及接收人类输入的结构。

    prompt = ChatPromptTemplate.from_messages([...])
    
  4. 到目前为止,我们可以使用 LCEL 创建链。链由一系列操作组成。链结合了记忆加载、提示处理和语言模型响应生成:

    chain_with_memory = (
        RunnablePassthrough.assign(
            conversation_history=RunnableLambda(
                memory.load_memory_variables) | 
                itemgetter("conversation_history")
        )
        | prompt
        | llm
    )
    

小贴士

使用RunnablePassthrough允许你在通过链的步骤顺序移动时继续添加数据字典。在这个例子中,我们将其加载到历史键中,以便在提示中使用。

在这里,RunnablePassthrough.assign(...)用于创建一个额外的键,然后对话历史被分配到这个键。然后,RunnableLambda(memory.load_memory_variables) | itemgetter("history")检索对话历史。

链随后应用提示模板,并将处理后的输入发送到 LLM 以生成响应。

我们可以通过输入hi并等待响应来启动第一次交互。然后,我们可以将输入和输出保存在记忆中,以便在未来的交互中提供上下文:

inputs = {"input": "hi"}
response = chain_with_memory.invoke(inputs)
 memory.save_context(inputs, {"output": response.content})

随后的交互继续。对于每个新的用户输入都会重复这个过程,从而保持对话的上下文:

inputs = {"input": "My name is Adrian and I like the high flying birds"}
response = chain_with_memory.invoke(inputs)
memory.save_context(inputs, {"output": response.content})
inputs = {"input": "I'm looking for gigs in London this summer"}
response = chain_with_memory.invoke(inputs)
memory.save_context(inputs, {"output": response.content})

记得检索对话历史,以便我们可以加载存储的对话变量以供审查或进一步处理:

memory.load_memory_variables({})

这个例子很简单,因为ConversationBufferMemory是一个内存存储,它存储了所有的交互。LangChain 提供了几种不同的记忆集成。在下一节中,我们将探讨这些如何提供更好的记忆支持。

探索更高级的内存类型

让我们看看 LangChain 中可用的更多高级内存类型。

内存存储

由于我们正在学习使用 ChatGPT 创建对话体验以支持更多复杂性,我们可能会需要支持多轮对话。随着对话的延长,你可以想象缓冲区大小可能会成为一个问题。明智的做法可能是考虑使用 ConversationBufferWindowMemory,它允许你通过在创建时传递 k 值来存储特定数量的交互:

memory_with_5_interactions = ConversationBufferWindowMemory( k=5)

这样,你就可以保留一个包含 5 个最新交互的滑动窗口,以防止缓冲区过大。

将你的对话交互固定在内存中的特定数量可能会限制性,因此你可以考虑使用 ConversationSummaryMemory 来帮助总结对话。这种类型的内存可以按以下方式实例化:

memory = ConversationSummaryMemory(llm=llm, return_messages=True)
memory.save_context({"input": "hi I'm adrian"}, 
    {"output": "whats up"})
memory.load_memory_variables({})

在这里,ConversationSummaryMemory 收集并更新当前对话的概述。这个存储在内存中的摘要可以随后在提示或链中使用,以提供对话到目前为止的快速回顾。

你可以通过结合对话缓冲区和对话摘要的两个概念,使用 ConversationSummaryBufferMemory 来更进一步。

这种类型的内存存储了在实例化内存时设置的令牌长度所基于的最新交互。而不是仅仅在交互超出令牌限制时删除它们,内存将它们存储为摘要并在后续交互中使用。内存可以在以下方式中使用在 ConversationChain 中:

conversation_with_summary = ConversationChain(
    llm=llm,
    # Notice the max_token_limit is very low so you can see the output of the summary
    memory=ConversationSummaryBufferMemory(
        llm=llm, max_token_limit=150),
    verbose=True,
)
response = conversation_with_summary.predict(input = "My name is Adrian and I like 1990s music, can you remember my 3 favourite bands, Nirvana, Offspring and Underworld")
response = conversation_with_summary.predict(input = "What's my second favourite band")

注意,我们设置了 verbose=Truemax_token_limit=150,这样我们就可以在内存中看到摘要和消息历史。如果我们输出内存

memory.load_memory_variables({}),我们应该得到以下类似的结果:

{'history': [SystemMessage(content='Adrian, who likes 1990s ...'),
  HumanMessage(content="What's my second favourite band"),
  AIMessage(content="Your second favorite band is Offspring, Adrian...")]}

注意,摘要被加载到系统内存中,并且有一个包含存储在内存中的 HumanMessageAIMessage 对象交互的列表。

使用持久化内存

我们之前查看的 LangChain 内存实现类型非常适合处理实时对话。然而,这种内存不会在会话之间持久化。我们在 介绍内存使用技术 部分提到了这种类型的方法,其中你可以将历史对话作为你上下文的一部分使用。因此,让我们看看如何使用 LangChain 来实现这一点。

在这个例子中,我们将使用向量存储和嵌入。不要担心这些概念的具体细节,我们将在下一章中探讨 检索增强生成RAG)时详细介绍。在这里,我们使用嵌入和向量存储来跟踪过去的对话轮次,以便我们可以搜索它们。

当向 LLM 发送提示以提供上下文中的对话历史时,我们可以引用早期交互中的相关信息。让我们开始吧:

  1. 首先,我们必须安装所需的包,最值得注意的是 ChromaDB,这是我们用于存储嵌入的数据库:

    pip install -U chromadb langchain-openai tiktoken
    

    我们还必须添加我们的导入并创建用于 API 密钥和 LangChain 配置的环境变量:

    from langchain_openai import OpenAI, (ChatOpenAI, 
        OpenAIEmbeddings)
    ...
    # Environment variables for API keys and LangChain configurations
    os.environ['OPENAI_API_KEY'] = 'your-openai-api-key'
    ...
    os.environ['LANGCHAIN_API_KEY'] = 'your-langchain-api-key'
    
  2. 接下来,我们必须初始化ChatOpenAIOpenAIEmbeddings,这样我们就可以生成响应和嵌入:

    llm = ChatOpenAI(temperature=0.0, model="gpt-4-1106-preview")
    embeddings = OpenAIEmbeddings()
    
  3. 现在,我们可以设置 ChromaDB 和我们的向量存储。ChromaDB 是一个开源数据库,用于管理嵌入,使我们能够存储和搜索我们的嵌入。向量存储允许我们根据这些嵌入高效地检索过去的对话轮次。注意,我们已经创建了PersistentClient,Chroma 数据库已被存储在当前 Jupyter Notebook 文件夹下的embeddings文件夹中:

    chroma_client = chromadb.PersistentClient(path="./embeddings")
    history_vectorstore = Chroma(
        persist_directory="embeddings/",
        collection_name="conversation_history",
        client=chroma_client,
        embedding_function=embeddings)
    
  4. 现在,我们必须创建记忆和检索对象。记忆对象存储对话轮次,检索器通过向量存储的默认相似度搜索帮助我们获取相关的过去轮次:

    retriever = history_vectorstore.as_retriever(
        search_kwargs=dict(k=2))
    memory = VectorStoreRetrieverMemory(
        retriever=retriever,
        memory_key="conversation_history",
        input_key="input")
    
  5. 接下来,我们必须保存一些示例对话到记忆中,以便我们可以在稍后检查它们是否包含在对话的上下文中:

    memory.save_context({"input": "Hi, my name is Adrian, how are you?"}, {"output": "nice to meet you Adrian"})
    memory.save_context({"input": "My favourite sport is running"}, {"output": "that's a good thing to be doing"})
    
  6. 现在,我们必须定义我们的对话模板,它包括过去的对话作为上下文和当前输入:

    _DEFAULT_TEMPLATE = """
    

    以下是人机 AI 体育助手之间的一次友好对话。AI 很有帮助,并从其上下文中提供具体细节以支持聊天。如果 AI 不知道问题的答案,它会诚实地表示不知道:

    Relevant pieces of previous conversation:
    {conversation_history}
    (Don't use these pieces of information if not relevant)
    Current conversation:
    Human: {input}
    AI:"""
    PROMPT = PromptTemplate(
        input_variables=["conversation_history", "input"],
        template=_DEFAULT_TEMPLATE
    )
    
  7. 最后,我们必须创建ConversationChain,它结合所有这些组件并发送聊天输入:

     conversation_with_history = ConversationChain(
        llm=llm,
        prompt=PROMPT,
        memory=memory,
        verbose=True)
    response = conversation_with_history.invoke({
        "input":"what gear do i need to buy to get started in my sport"})
    print(response)
    

    在这里,verbose设置为True,这样我们就可以看到 LLM 的输出。我们会看到对话历史被包含在提示中。如果我们重启 Jupyter Notebook 内核并再次运行代码,对话应该会被持久化。

小贴士

如果你想要查看存储在你的 Chroma 向量存储中的文档及其嵌入,你可以通过运行print(vector_store._collection.get(include=['embeddings']))来输出整个集合。

你也可以尝试运行自己的相似度搜索:similar_documents = vector_store.similarity_search(query="your question", k=1)

摘要

在本章中,我们更深入地探讨了 LangChain,查看了一些更高级的主题。我们首先探讨了调试技术,并介绍了 LangSmith,这是 LangChain 应用的先进日志记录和监控的首选工具。我们还研究了 LangChain 代理,了解了如何使用它们为我们的大型语言模型项目提供不同的功能,以及它们如何与 OpenAI 函数调用相结合。我们关注 LangChain 提供的现成工具,并通过查看实际示例来创建自定义工具,帮助我们的 ChatGPT 应用回答有关实时新闻和天气的问题。最后,我们讨论了为我们的代理提供记忆的概念,同时探讨了不同类型的记忆、挑战以及提供 LangChain 中记忆的技术。

在下一章中,我们将探讨 RAG。您将了解它是什么,涉及的概念和过程,以及如何在 LangChain 中实现检索。

进一步阅读

以下链接是精心挑选的资源列表,旨在帮助您理解本章内容:

第三部分:构建和增强 ChatGPT 应用

在本部分,我们将探讨检索增强生成RAG)系统,展示如何使用向量存储作为知识库。然后,我们将结合到目前为止所涵盖的所有概念,构建和增强 ChatGPT 应用。您将进行自己的实际项目,创建一个能够处理复杂任务并提供个性化交互的聊天机器人。最后,我们将探讨对话式 AI 和大型语言模型LLMs)的未来,讨论将 ChatGPT 应用推向生产的挑战,并考察该领域的替代技术和新兴趋势。

本部分包含以下章节:

  • 第七章作为检索增强生成的知识库的向量存储

  • 第八章创建您自己的 LangChain 聊天机器人示例

  • 第九章使用 LLM 的对话 AI 的未来

7

向量存储作为检索增强生成中的知识库

检索增强生成RAG)无疑是自 ChatGPT 爆发以来 LLM 最常见的用例。在本章中,我们将探讨创建 RAG 系统涉及的关键步骤和概念。一旦您理解了每个步骤所涉及的内容,我们将探讨如何使用 LangChain 执行这些过程和技术。进一步来说,我们将通过一个真实世界的示例来构建我们自己的 RAG 系统。

本章旨在介绍 RAG 的核心概念,以便您有一个坚实的基础来掌握它。

在本章中,我们将涵盖以下主题:

  • 为什么我们需要 RAG?

  • 理解创建 RAG 系统所需的步骤

  • 使用 LangChain 通过 RAG 示例进行工作

技术要求

在本章中,我们将广泛使用 ChatGPT,因此您需要注册一个免费账户。如果您还没有创建账户,请访问 openai.com/ 并在页面右上角点击 Get Started,或者访问 chat.openai.com

这些示例需要安装 Python 3.9 和 Jupyter Notebook,这两个都可以在 jupyter.org/try-jupyter/notebooks/?path=notebooks/Intro.ipynb 找到。

我们将使用 ChromaDB 作为我们的开源向量数据库,因此建议您查看它并熟悉 Chroma (www.trychroma.com)。然而,对于向量存储提供商有很多其他不同的选择。

您可以在此书的 GitHub 仓库中找到本章的代码:github.com/PacktPublishing/ChatGPT-for-Conversational-AI-and-Chatbots/chapter7

为什么我们需要 RAG?

LLM 受限于其训练数据中的世界知识,因此 ChatGPT 不了解最近的事件或您自己的数据,这严重限制了其提供相关答案的能力。由于幻觉,LLM 没有任何知识来支持一个问题,因此它编造了事情,LLM 的性能也可能变得更差。

因此,当我们谈论一个 LLM 的知识时,有两种类型:

  • 来自 LLM 在训练期间使用的知识的知识。

  • 来自在对话上下文中通过提示传递给 LLM 的信息的知识。我们可以称之为上下文特定知识。

因此,对于 LLM 应用的一个突出用例,也是我最常被问到的一个,那就是我们如何允许 LLM 解释和讨论其训练数据集之外的数据。这包括访问实时信息或其他外部数据源,例如公司文档存储库或数据库中包含的专有信息。实际上,我们需要提高 LLM 的上下文特定知识,而 RAG 正是我们实现这一点的手段。

任何可能没有所需广度和深度的知识基础语言模型的要求,意味着我们需要从某处获取上下文信息,以便将其传递给我们的 LLM。我们还要注意 ChatGPT 的上下文窗口限制以及更大上下文窗口的成本。如果你有大量数据,那么向 ChatGPT 发送大量数据块会增加你的令牌使用量和成本。因此,我们的上下文特定知识越小、越相关,就越好。

尽管在本章中我们将专注于 ChatGPT 应用中其他特定主题的上下文特定知识,但请记住,上下文特定知识可以指与对话相关的任何相关内容。当我们在前一章中查看持久化记忆时,你已经了解了 RAG 系统的机制。让我们更详细地看看 RAG 的不同元素。

理解创建 RAG 系统所需的步骤

要实现 RAG,需要执行一系列步骤。首先,我们需要定义数据来源。这可能包括在线数据库、特定网站,甚至定制的数据存储库。然后,我们需要优化和存储这些信息以供检索。一旦完成这些,我们就可以使用检索系统根据查询上下文检索相关信息。然后,在提示过程中将这些信息传递给语言模型。以下图示概述了不同的步骤:

图 7.1 – 创建 RAG 系统的步骤

图 7.1 – 创建 RAG 系统的步骤

我很欣赏这里有很多事情在进行,所以让我们更详细地看看每一步。

定义你的 RAG 数据源

对于我们的第一步,我们必须识别和选择知识数据来源。这可能包括在线数据库、特定网站或针对系统需求定制的数据存储库。我们的来源可能以不同类型的文件格式存在,例如原始 HTML、PDF、PowerPoint、Word 文档或整个网站——这完全取决于你的用例。

为了获得最佳结果,你需要在开始分块过程和其他下游任务之前预处理你的数据,以确保最佳质量。

在创建嵌入之前,你可以做很多事情来提高你的内容。这个过程可能会产生一些成本,但这是值得投资的。一旦完成,你就可以在多个下游任务中使用处理过的内容。

理想情况下,您不需要关心内容来自哪种文件类型;您希望能够处理它们,无论来源格式如何,以便您可以以相同的方式对待它们。为此,您需要将它们分解成常见的元素,如标题和可读的叙事文本。最常见的形式是 JSON,因为它是一个常见且易于理解的格式。这样,您可以序列化内容并提取和存储元数据,如页码、文档名称和关键词。

每种文档类型都不同,并使用不同的元素来区分不同类型的信息。例如,HTML 有标签,或者我们可以使用 NLP 来理解文本;较短的句子可能是标题。对于 PDF 和图像,我们可以使用更高级的技术,如文档布局检测或视觉转换器。

内容处理可能涉及复杂任务,因此考虑使用像 Unstructured 这样的库或服务是值得的。它们提供了一些非常强大的核心开源工具和优秀的文档,以及执行更复杂任务的 API,例如内容提取。它们还计划推出企业级服务。查看他们的文档并遵循他们的快速入门指南以获取更多信息。

预处理我们的内容和生成嵌入

一旦我们确定了将要使用的数据集,我们需要通过将其分割成可管理的块并从这些块中创建嵌入来清理和准备我们的数据。

为有效 LLM 交互进行分块

您的数据集可能包含许多文档和字符,因此索引数据的第一步是通过文本分割将其缩小到合理的尺寸。我们这样做有几个原因:

  • 为了通过提高嵌入的准确性来增强后续处理的成果相关性。

  • 为了支持较小的上下文窗口,这是嵌入模型通常支持的。

  • 因此,我们可以通过将较大的文本来源缩小到更小、更集中的片段来提供更准确和具体的信息。

  • 为了减少我们将要传递给 LLM 的上下文知识量。这有助于保持相关性,影响响应质量,并降低成本。它还允许我们使用更大的文档。

当您对文本数据进行分块时,文本的较大部分会被分割成更小的块,例如章节、句子、短语、分隔符,甚至单词。通过有效的分块策略,我们的目标是把大量内容分解成有意义的片段,这样我们就可以用它来准确回答用户的查询。以下图展示了分块策略的不同元素:

图 7.2 – 分块策略

图 7.2 – 分块策略

然而,分块并不是一个一刀切解决方案。设计一个有效的策略需要仔细考虑您要分块的内容以及您应用程序的使用场景。让我们更仔细地看看这些元素:

  • 块大小:将其视为您 LLM 的“一口大小”。较小的块(句子、短语)提供了细粒度控制,但可能导致信息丢失和上下文碎片化。相反,较大的块(段落、章节)保持了上下文,但可能会超出 LLM 的容量。找到最佳平衡点取决于以下因素:

    • LLM 能力:不同的嵌入模型有不同的处理能力。请参考文档以获取推荐的上下文大小。别忘了,当块被检索时,我们还需要将这些添加到我们的上下文中,因此我们还需要考虑 LLM 上下文限制。请注意,如果您使用的是带有 32k 内容窗口的 GPT-4,这就不成问题了。

    • 任务复杂度:您打算使用什么类型的内容?是较长的文档,如文章,还是较短的,如聊天记录?简单的任务,如情感分析,可能可以处理较大的块,而细微的任务,如摘要,则从较小的块中受益。

    • 期望的细节程度:您需要广泛的概述还是深入的研究?您希望支持哪些类型的问题?相应地调整块的大小。

  • 块分割方法:您如何切割文本很重要。流行的方法有不同的优点和缺点,所以我鼓励您尝试不同的方法,看看您能实现什么样的结果。LangChain 支持所有这些方法的不同库。以下是一些流行的方法:

    • 固定大小的块分割:简单且高效,但存在破坏句子和丢失上下文的风险。我们在本书的例子中最常使用固定大小的块分割。

    • 基于句子的块分割:内容感知的块分割允许您将文本分割成单独的句子。

    • 递归块分割:这个块分割过程通过使用不同的标准迭代地将文本分割成更小的部分,直到达到相似但并非完全相同的块大小,从而允许结构灵活性。

记住,最佳的块分割策略是针对您的 LLM、任务和期望结果独特的。尝试不同的方法,监控性能,并调整您的策略以充分发挥 LLM 交互的潜力。

关键要点是 LangChain 提供了一些强大的现成块分割工具。现在我们有了分割好的数据,我们就可以创建我们的嵌入体了。

理解嵌入体——将文本转换为有意义的向量

在机器学习和自然语言处理领域,向量嵌入这两个术语密切相关,但它们指的是不同的概念。首先,让我们看看什么是向量:

  • 什么是向量?:向量是在由维度定义的空间中数据的数学表示。它本质上是一个浮点数数组。类似于将物品打包进手提箱,我们将数据的各种属性,如高度、重量、颜色或词频,存储在这个列表中。这使得我们可以将复杂的信息输入仅理解数字的机器学习算法。这使计算变得高效,允许算法有效地处理大量现实世界的数据。

  • 不同类型的向量:有不同类型,例如特征向量和嵌入(我们感兴趣的 RAG 中的向量类型)。

  • 它们代表不同的事物:向量可以表示各种数据类型,从简单的数值特征(如图像像素值)到复杂的概念,如词语含义或文档主题。

  • 赋予意义编码:向量值并非随机;它们承载着意义!例如,在词嵌入中,向量空间中词语之间的距离反映了它们的语义相似度。

  • 从输入到输出:向量可以表示算法输入的数据和其输出预测。例如,一个向量(稍后会更详细地介绍)可能输入一些文本作为向量,并输出一个表示最接近问题的答案的向量。

词语嵌入解释 – 从文本到有意义的数字

我们可以创建各种词语或句子嵌入。然而,在 RAG 的上下文中,我们感兴趣的是分块句子,并希望理解它们之间的关系。为此,我们可以使用句子嵌入。

句子嵌入将整个句子转换成固定大小的密集向量,捕捉整体语义意义。与仅表示单个词语的词嵌入不同,句子嵌入考虑了句子中词语的上下文和关系。我们可以通过测量向量之间的距离来展示它们的相关性。

让我们想象我们正在为句子“我喜欢吃蛋糕”和“我对烘焙感兴趣”创建嵌入,每个句子使用一个五维向量。请注意,现实世界的嵌入要大得多:

  • 句子:“我喜欢 吃蛋糕:”

    • 嵌入[0.45, -0.2, 0.33, 0.1, -0.4]
  • 句子:“我对 烘焙 感兴趣:”

    • 嵌入[0.4, -0.15, 0.35, 0.05, -0.3]

在这个假设的例子中,每个向量在五维空间中代表整个句子的意义。维度是抽象的,不能直接解释,但它们以这样的方式组织,使得具有相似意义的句子在这个多维空间中更接近。

想象每个句子都是一个有五个无形墙壁(维度)的大房间中的点。具有相似意义的句子在这个房间里会靠得更近,尽管你无法直接看到那些意义。

将“我喜欢吃蛋糕”和“我对烘焙感兴趣”想象成房间里的两个人。当然,他们正在做不同的事情(吃与烘焙),但他们都对食物有着共同的热爱,就像在房间里的同一个“食物区域”里一样。这反映在他们点之间的接近程度,尽管房间本身是看不见的。

在实际应用中,这个“房间”会有更多的墙壁(维度)来捕捉意义的更细微细节。维度的数量可以从 50 到 1,024 不等,其中 300 是一个常见的选择。

创建嵌入最简单的方法是使用预训练模型。我们将在下一节中探讨这些模型以及如何创建嵌入。

OpenAI 的文本嵌入模型

OpenAI 的文本嵌入模型一直是最受欢迎的之一,其中text-embedding-ada-002是最广泛使用的。然而,这些模型已经被更好的嵌入模型所取代。text-embedding-3-smalltext-embedding-3-large是最新且性能最强大的嵌入模型。

使用向量存储存储和搜索我们的嵌入

除了 OpenAI 之外,还有许多其他嵌入模型,例如 Google 的 BERT 和 T5,Facebook 的 RoBERTa,以及多语言的 XLM-R。使用不同模型的过程通常通过 LangChain 简化。对于本章,我们将专注于使用 OpenAI 嵌入模型。在下一节中,我们将看到这是如何实现的。

使用 OpenAI 模型创建嵌入

使用 OpenAI 嵌入模型有几种不同的方法。一种选择是直接调用embeddings API 端点:

curl https://api.openai.com/v1/embeddings \
  -H "C OpenAI content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "input": ["I like eating cake"," I'm interested in baking"],
    "model": "text-embedding-3-small"
  }'

或者,LangChain 提供了一个简单的OpenAIEmbeddings包装类,用于使用 OpenAI API 创建嵌入。以下是一个简单的示例:

import ...
os.environ['OPENAI_API_KEY'] = 'KEY'
embeddingsService = OpenAIEmbeddings()
embeddings = embeddingsService.embed_documents(["I like eating cake",
    " I'm interested in baking"])

通常,没有必要直接使用嵌入创建服务。许多向量存储提供了同时嵌入和存储文档的简化方法。我们将通过检查 ChromaDB 中的过程来展示这一点。现在我们已经涵盖了向量和嵌入,我们可以继续进行 RAG 过程的下一步:使用向量存储存储和搜索我们的嵌入。

OpenAI 的最新进展,文本嵌入 v3,代表了人工智能能力的重大飞跃。这个模型,其“小型”和“大型”的变体,展示了性能的显著提升,尤其是在多语言嵌入和英语语言处理方面。它引入了一种更有效的方法来处理数据维度性,同时不牺牲准确性,这得益于创新的套娃表示学习。通过将数据分层结构化,就像俄罗斯套娃一样,这优化了嵌入过程,提高了语言模型的效率和准确性。

现在我们有了我们高维数据向量的嵌入,我们需要能够存储它们,更重要的是,有效地搜索它们。我们的向量数据库将在存储和搜索我们的数据中扮演重要的角色。以下图表说明了这个过程:

图 7.3 – 索引我们的数据

图 7.3 – 索引我们的数据

我们的向量数据库是一种特定的数据库,它已被优化以与多维向量一起工作。让我们看看使用这种存储类型的优势。

向量数据库的主要优势

向量数据库是专门为管理向量嵌入而构建的,因此它们提供了几个优势:

  • 简单数据管理:向量数据库提供了我们期望的数据库的所有创建、读取、更新、删除CRUD)操作。向量数据库还提供了简单的方法来执行元数据存储和过滤,这样我们就可以使用额外的元数据过滤器进行更细粒度的查询。

  • 相似度搜索:使用向量数据库的主要优势是它允许我们根据向量中表示的意义的相似性来搜索嵌入。因此,虽然传统数据库是基于精确匹配或标准进行查询的,但我们可以使用向量数据库根据语义或上下文意义找到最相似或相关的数据。

  • 可扩展性:在大多数用例中,我们可能会处理大量向量。随着数据量的增长,向量数据库可以通过在多台机器上分配数据来实现水平扩展,确保即使在大数据集上也能保持高效性能。

向量数据库是如何工作的?

虽然传统数据库以行和列的形式存储数据,以适应字符串和数字等标量数据类型,但向量数据库的设计是为了管理向量。这种基本差异扩展到它们的优化和查询机制。

在传统的数据库设置中,查询通常基于指定的标准在行之间寻找精确匹配。然而,向量数据库采用相似度度量来识别与查询密切相似的向量,这与精确匹配的方法不同。

向量数据库的核心是近似最近邻ANN)搜索,它利用一系列算法来优化和加速搜索过程。这些算法包括哈希、量化以及基于图的搜索等方法,它们被编排成一个流水线,以返回针对查询的快速、准确的结果。

由于向量数据库产生近似结果,一个关键考虑因素是在准确性和查询速度之间取得平衡。较高的准确度级别通常会导致搜索速度变慢。然而,一个优化良好的向量数据库可以实现非常快的搜索,而不会显著降低准确性,为许多应用提供了最佳平衡。向量数据库采用几种不同的技术或相似度度量来比较数据库内的向量,以便它们可以识别最相关的结果。

相似度度量是用于量化向量空间中两个向量之间相似度的数学技术。这使得数据库能够评估存储的向量与查询向量的相似度。有几种相似度度量,以下是一些突出的例子:

  • 余弦相似度:这个度量计算两个向量之间角度的余弦值,其值范围从-1 到 1。在这里,1 表示向量完全相同,0 表示正交(独立)向量,-1 表示完全相反的向量。

  • 欧几里得距离:这衡量两个向量之间的直接直线距离,从 0 延伸到无穷大。0 的值表示向量完全相同,随着值的增加,表示差异越来越大。

  • 点积:这表示两个向量大小的乘积以及它们之间角度的余弦值。正值表示向量指向同一方向,0 表示正交向量,负值表示相反方向。

现在你已经了解了向量数据库的基本工作原理,下一步就是为你的项目选择正确的数据库。

决定使用哪个向量数据库

许多向量数据库和供应商提供开源、托管、可扩展的解决方案,满足各种价格点和需求

就像选择任何持久化层一样,为 RAG 系统和 LangChain 应用选择正确的向量数据库需要仔细考虑几个关键因素,这些因素针对这些高级 AI 框架进行了定制。

对于 RAG 系统,向量数据库必须在快速和准确的检索能力上表现出色,并且必须易于使用。向量数据库通常提供特定编程语言的 SDK,它封装了 API,这将使你在应用程序中与数据库交互变得更加容易。

在 LangChain 的背景下,大多数主要的向量提供者已经在 LangChain 库中创建了集成,并成为langchain-community包的一部分。只需查看集成页面,就可以找到哪些供应商创建了现成的集成和详细的文档。

预算考虑也起着至关重要的作用;对于愿意投资于设置和维护的团队,开源向量数据库可能提供成本节约和可定制性。然而,对于需要无缝可扩展性和最小操作开销的项目,尽管可能成本更高,但基于云的托管向量数据库可能更为合适。项目的范围和规模在这里很重要;可能你有选择提供商的奢侈,也可能你必须查看你选择的云提供商提供的技术。

杰出的向量数据库提供商

当涉及到向量数据库时,既有开源选项,也有托管选项。让我们看看一些例子:

  • ChromaDB 是可靠的开源向量数据库之一。我们已经在本书中使用过它,并且我们将将其作为本书剩余部分的首选向量数据库。Chroma 是一个开源嵌入数据库,允许您轻松管理文本文档,将文本转换为嵌入,并进行相似度搜索。是的,有 ChromaDB LangChain 包装器和检索类用于查询。其他值得提及的杰出开源向量存储包括 Qdrant 和 Weaviate。

  • Pinecone是一个专门为解决与向量相关独特挑战而构建的托管向量数据库平台,它提供了进入生产所需的一切。

  • 由 Meta 提供的Facebook AI 相似度搜索FAISS)是一个开源库,用于快速搜索相似性和聚类密集向量。它并不完全是一个向量数据库;它是一个向量索引,也称为向量库。它包含能够搜索不同大小和复杂度向量集的算法。FAISS 在 LangChain 中得到了良好的支持。

这些只是可用的向量数据库选项中的一部分。我强烈建议进行彻底的研究,以确定最适合你项目的选择。此外,考虑探索 LangChain 集成中特色展示的向量提供商,以获得更全面的理解。

在这个阶段,我们已经理解了我们的 RAG(Retrieval-Augmented Generation)的步骤序列。我们学习了如何定义我们的数据源,将数据预处理为块,并使用专业模型创建我们的嵌入,以及如何利用向量数据库进行存储和搜索。在下一节中,我们将通过 LangChain 框架查看一个端到端示例,这些技术将全部整合在一起。

使用 LangChain 处理 RAG 示例

LangChain 提供了执行我们概述的所有步骤的功能。因此,让我们在更详细地查看 LangChain 如何实现这些步骤的同时,看看一个 RAG 示例。

对于我们的用例,我们将探讨使用非结构化网站数据作为我们 RAG 系统的基础。这是 RAG 应用的一个常见例子,因为大多数组织都有他们希望使用的网站和未结构化数据。想象一下,如果你的组织要求你创建一个由 LLM 驱动的聊天机器人,能够回答有关你组织网站内容的问题。

在我们的场景中,我们将探索利用非结构化网站数据作为我们 RAG 系统的基石。利用网站中的非结构化数据是 RAG 应用的一种常见方法,因为大多数组织都拥有他们希望使用的网站和数据。想象一下,如果你的组织要求你开发一个能够回答与公司网站内容相关的查询的聊天机器人。

在我们的例子中,我们将创建一个能够提供纽约经济最新信息的聊天机器人。对于我们的数据源,我们将使用维基百科。你可以选择自己的主题进行这项工作,甚至可以使用你自己的网站页面。

第一步是使用文档加载器加载我们的数据集。那么,让我们开始吧。

集成数据 – 选择你的文档加载器

LangChain 文档加载器旨在轻松地从不同来源获取文档,作为数据检索过程的初始步骤。LangChain 提供了超过 100 种不同的文档加载器,可以满足各种数据源的需求,例如私有云存储、公共网站,甚至是特定的文档格式,如HTMLCSVPDFJSON和代码文件。

你需要的文档加载器将取决于你的用例和需求。在可用的选项中,你可以将来自几乎任何来源的数据集成到你的 ChatGPT 应用中,无论是来自网站或云存储(如 Google Drive)的非结构化公共或私有数据,还是来自许多不同数据库类型或数据存储提供商的更结构化信息。

除了它们的通用性之外,LangChain 中的文档加载器还设计得易于使用。它们提供直观的接口,允许开发者快速设置并开始使用最小配置检索文档。这种简单性加速了开发过程,尤其是在你创建概念验证以尝试不同的数据源时。希望这能给你更多时间专注于应用程序更复杂的功能。

让我们来看一个文档加载器的简单例子。记住,我们想要回答关于纽约的问题,因此我们的数据集需要满足这些要求。维基百科是一个提供最新信息的优秀来源,所以这个例子中它就足够了。让我们看看如何使用WebBaseLoader,一个HTML文档加载器,从维基百科中提取一些信息作为我们数据集的基础:

from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader(
    ["https://en.wikipedia.org/wiki/New_York_City#Economy"])
docs = loader.load()
print(len(docs))
print(docs)

打印出docs变量应该会得到类似以下的结果,其中page_content是我们将要使用的数据文本:

[Document(page_content='\n\n\n\nNew York City – Wikipedia
...
 metadata={'source': 'https://en.wikipedia.org/wiki/New_York_City#Economy', 'title': 'New York City - Wikipedia', 'language': 'en'})]

考虑到我们所拥有的非结构化 HTML 数据,也可能值得考虑使用documentTransformer来清理我们的 HTML 到纯文本,例如使用AsyncHtmlLoader

许多其他 LangChain 文档加载选项是为特定用例专门构建的,因此始终值得检查 Python 或 TypeScript 中可用的选项。

对于我们的示例,我们将使用WikipediaLoader,这是我们在这章中之前使用过的。请注意,我将load_max_docs保持得较低,以适应这个示例:

docs = WikipediaLoader(query="New York economy",
    load_max_docs=5).load()

使用这个方法的优点是,我们现在有了来自多个维基百科页面的数据。WikipediaLoader的结果应该看起来相当不错,列出的文档结构与WebBaseLoader的结果相似。

现在我们有了我们的数据集,下一步是对其进行索引。

通过文本拆分创建可管理的块

正如我们在关于有效 LLM 交互的块分割部分所讨论的,文本拆分的过程可能相当复杂,需要关于块大小和适当方法的谨慎决策。幸运的是,LangChain 提供了易于使用的接口和集成,用于几个模块,可以用来“块化”或拆分我们的文档数据集,以便进行进一步处理。

LangChain 的文本拆分算法旨在灵活高效,确保在优化检索的同时保持原始文档的完整性和上下文。这涉及到考虑文本的性质和格式、文档内的逻辑划分以及当前检索任务的具体要求。

在 LangChain 中实现文本拆分可以通过使用预置的拆分器之一来完成,这些拆分器根据数据集本身提供不同的拆分方式。

小贴士

一个理解不同块分割策略并评估文本块分割结果的绝佳工具是chunkviz.up.railway.app。这是一个查看基于 LangChain 工具和不同参数(如块大小和重叠)如何分割文本的绝妙方式。

对于这个用例,我们将使用RecursiveCharacterTextSplitter来分割我们的文本。RecursiveCharacterTextSplitter工具旨在高效地将文本分割成可管理的片段。它寻找预定义的分隔符字符,如换行符、空格和空字符串。结果应该是分割成段落、句子和单词的文本块,其中文本片段保留了相关文本片段的意义。该工具动态地将文本分割成块,以字符计数为目标大小。一旦一个块达到这个预定的尺寸,它就被标记为输出段。为了确保这些段之间的连续性和上下文保持一致,相邻的块具有可配置的重叠程度。

它的参数完全可定制,提供灵活性以适应各种文本类型和应用需求。

这是一个将大量文本分解成更小、语义上有意义的单元的好方法。

这里是我们的示例代码,它使用了RecursiveCharacterTextSplitter。这适用于通用文本:

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=100)
split_documents = text_splitter.split_documents(docs)
print(len(split_documents))

我们可以创建我们的RecursiveCharacterTextSplitter类,并包含我们希望控制的属性,包括chunk_size,这确保了处理的可管理大小,以及chunk_overlap,它允许块之间有字符重叠,保持上下文连续性。如果你更改块大小,你将能够创建一个包含更多条目的文档列表。你可以通过运行以下命令查看其中一个分割文档:

print(documents[5])

使用RecursiveCharacterTextSplitter,我们将大量的文本内容分解成更小、更有意义的单元。这为我们的数据进一步处理和分析做好了准备。现在我们已经探讨了文本分割,让我们深入了解如何使用我们的块来创建嵌入:

创建和存储文本嵌入

现在我们有了可管理的数据块,是时候从这些块中创建嵌入并将它们存储在我们的向量数据库中了。在这个例子中,我们将使用 ChromaDB 作为我们的向量存储。

这里,我们将从langchain_openailangchain.vectorstores库中创建嵌入,这些库允许我们调用 OpenAI 嵌入服务并将它们存储在 ChromaDB 中。按照以下步骤操作:

  1. 首先,我们必须使用我们的特定模型text-embedding-3-small初始化OpenAIEmbeddings类的一个实例:

    from langchain_openai import OpenAIEmbeddings
    from langchain.vectorstores.chroma import Chroma
    embeddings_model = OpenAIEmbeddings(
        model=" text-embedding-3-small")
    
  2. docs_vectorstore = Chroma(...)这一行创建了一个 Chroma 类的实例,用于存储文档向量。以下参数被提供给 Chroma:

    • collection_name="chapter7db_documents_store":这指定了 Chroma 中存储文档向量的集合名称。把它想象成在数据库中命名一个表,你的数据将保存在那里。

    • embedding_function=embeddings_model:在这里,之前创建的embeddings_model作为嵌入函数被传递。这告诉 Chroma 在存储文档之前使用OpenAIEmbeddings实例来生成嵌入。本质上,每当文档被添加到 Chroma 时,它将通过这个嵌入模型转换为向量。

    • persist_directory="chapter7db":此参数指定 Chroma 将持久化存储其数据的目录。这允许向量存储在程序运行之间保持其状态。在我们的情况下,它将是运行我们的 Jupyter Notebook 的文件夹:

      documents_vectorstore = Chroma(
          collection_name="docs_store",
          embedding_function=embeddings_model,
          persist_directory="chapter7db",
      )
      
  3. 然后,我们可以通过调用add_documents()将之前分割的文档传递进来。之后,我们可以通过在 Chroma 实例上调用persist()来持久化所有内容:

    chroma_document_store.add_documents(split_documents)
    chroma_document_store.persist()
    
  4. 现在,我们可以进行搜索以查看是否得到任何结果。我们将通过在 Chroma 实例上执行相似性搜索,调用 similarity_search 并使用我们的文本查询来完成此操作。尝试一个与纽约经济相关的问题:

    similar_documents = chroma_document_store.similarity_search(
        query="what was the gross state product in 2022")
    print(similar_documents)
    

你应该能够打印出你查询的搜索结果。现在,让我们看看如何将我们的 RAG 系统与 LangChain 结合起来。

使用 LangChain 整合一切

现在我们有了我们的 Chroma 文档存储返回的结果,让我们学习如何使用 LangChain 将所有我们的 RAG 元素整合在一起,以便我们可以创建一个能够根据我们文档中的信息回答问题的系统:

  1. 我们首先从 langchain_openailangchain_core 库中导入必要的类,以及我们需要登录 LangSmith 的变量。然后,我们需要创建一个 ChatOpenAI 类的实例,以便我们可以利用 GPT-4 生成我们的答案:

    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.runnables import (
        RunnableParallel, RunnablePassthrough)
    os.environ['LANGCHAIN_API_KEY'] = ''
    os.environ['LANGCHAIN_PROJECT'] = "book-chapter-7"
    os.environ['LANGCHAIN_TRACING_V2'] = "true"
    os.environ['LANGCHAIN_ENDPOINT'] = "https://api.smith.langchain.com"
    from langchain_core.output_parsers import StrOutputParser
    llm = ChatOpenAI(model="gpt-4", temperature=0.0)
    

    将温度设置为 0.0 使模型的响应确定性,这对于一致的 QA 性能通常是所希望的。

  2. 现在我们已经设置了 Chroma 文档存储,我们可以初始化一个检索器来根据我们的查询检索相关文档:

    retriever = chroma_document_store.as_retriever(
        search_kwargs={"k": 5})
    

    检索器被配置为返回与查询匹配的前 5 个文档。

  3. 接下来,我们需要创建一个提示模板,告诉语言模型如何利用检索到的文档来回答问题:

    template = """
    You are an assistant specializing in question-answering tasks based on provided document excerpts.
    Your task is to analyze the given excerpts and formulate a final answer, citing the excerpts as "SOURCES" for reference. If the answer is not available in the excerpts, clearly state "I don't know."
    Ensure every response includes a "SOURCES" section, even if no direct answer can be provided.
    QUESTION: {question}
    ==========================
    EXCERPTS:
    {chroma_documents}
    ==========================
    FINAL ANSWER(with SOURCES if available):
    """
    prompt = ChatPromptTemplate.from_template(template)
    

    此模板帮助模型从我们的数据中提供有来源的答案,或指示我们在信息不可用时进行标记:

图 7.4 – 传递给 LLM

图 7.4 – 传递给 LLM 的提示

  1. 接下来,实现一个函数来格式化检索到的文档,以便它们可以包含在提示中:

    def format_chroma_docs(chroma_docs) -> str:
        return "\n".join(
            f"Content: {doc.page_content}\nSource: {doc.metadata['source']}" for doc in chroma_docs
        )
    

    当这些文档包含在我们的提示中时,我们将使用此函数将文档内容来源组织成可读的格式。

  2. 现在,我们必须使用 LCEL 创建我们的问答管道。这种设置允许我们直接对检索到的文档应用格式,并简化了进入提示生成和答案生成阶段的流程:

    rag_chain_from_docs = (
        {"chroma_documents": retriever | format_docs,
            "question": RunnablePassthrough()}
        | prompt
        | llm
        | StrOutputParser()
    )
    

    下面是这个管道的每个部分所做的工作:

    1. 使用 RunnablePassthrough 和文档检索进行处理:{"chroma_documents": retriever | format_docs, "question": RunnablePassthrough()}:这个字典设置了两个并行流。对于 chroma_documents,文档通过 retriever 检索,然后立即使用 format_docs 格式化。对于 question,使用 RunnablePassthrough() 简单地传递问题而不进行任何修改。这种方法有效地为下一步准备了格式化文档和问题。

    2. 提示应用:| prompt:处理过的信息(问题和格式化文档)随后被导入提示。这一步利用 ChatPromptTemplate 将问题与格式化文档根据预定义的模板结合起来,为 LLM 生成答案做好准备。

    3. 语言模型生成:llm:在这里,将前一步的合并输入喂入之前初始化的语言模型(GPT-4)。模型根据提示生成响应,有效地通过从检索到的文档中提取的信息来回答问题。

    4. 输出解析:| StrOutputParser():最后,语言模型的输出通过StrOutputParser()解析为字符串格式。这一步确保了最终的答案易于阅读且格式正确。

  3. 最后,我们可以用一个问题和打印答案来调用管道:

    question = "what stock exchanges are located in the big apple"
    rag_chain_from_docs.invoke(question)
    

    这个搜索应该返回以下类似的内容,包括答案和来源:

    The stock exchanges located in New York City, often referred to as the "Big Apple", are the New York Stock Exchange and Nasdaq. These are the world\'s two largest stock exchanges by market capitalization of their listed companies. \n\nSOURCES: \n- https://en.wikipedia.org/wiki/New_York_City\n- https://en.wikipedia.org/wiki/Economy_of_New_York_City'
    

通过遵循这些步骤,你已经构建了一个能够用来自维基百科的最新信息回答关于纽约经济问题的 RAG 系统。尝试一些其他问题,看看 FAQ 的表现如何。

记住,查看 LangSmith 中的调试输出是有用的,这样你可以看到 LangChain 的每个步骤中发生了什么。在下面的屏幕截图中,我们深入到了 LangSmith 提示模板输出,以便我们可以看到我们检索并传递给 LLM 提示的文档:

图 7.5 – 使用 LangSmith 查看内部运作情况

图 7.5 – 使用 LangSmith 查看内部运作情况

首先,我们根据我们的主题标准从维基百科加载了我们的文档,对这些数据进行分块,并创建了存储在我们的向量存储中的嵌入。然后,我们定义了一个检索器来查询我们的存储库,将文档搜索结果传递给 LLM 提示,并将其交给我们的 LLM 以获取对问题的准确响应,同时列出来源并防止幻觉。这是通过在 LCEL 中定义的 LangChain 实现的。

摘要

在本章中,我们探讨了 RAG 系统是什么以及为什么我们需要它们。然后,我们详细介绍了创建 RAG 系统必须遵循的步骤。到这一点,你应该知道如何使用分块选择和预处理数据,以及什么是向量和嵌入以及如何使用专用模型创建它们,以便你可以将它们存储在用于存储向量的特定类型的数据库中。最后,我们创建了一个 RAG 系统,通过一个真实世界的例子逐步完成每个步骤,最后使用 LangChain 将它们全部整合在一起。

在下一章中,我们将更详细地探讨一个更复杂的由 ChatGPT 驱动的、真实世界的 LangChain 应用。我们将利用前几章中的一些核心概念,以及本章中我们关于如何实现 RAG(Retrieval-Augmented Generation)所学到的东西。我们的目标是创建一个更复杂的聊天机器人,它支持记忆、RAG 以及由 LangChain 工具驱动的更多特定功能。

进一步阅读

以下是一份精选的资源列表,可以帮助你理解本章提供的内容:

8

创建您的 LangChain 聊天机器人示例

在本章中,我们将结合前几章的关键概念,将其应用于一个实际项目。到目前为止,我们已经涵盖了大量的内容,从对话人工智能基础和提示工程到利用 LangChain 创建 RAG 系统。现在,我们准备通过构建一个 ChatGPT 驱动的聊天机器人来应用这些知识。

此项目将展示如何在实际、现实世界的对话人工智能场景中应用 ChatGPT 技术。我们的目标是创建一个自动助手,它不仅能回答关于我们自己的数据的问题,还能处理更复杂的任务并提供个性化。

到本章结束时,您不仅将拥有一个功能性的 ChatGPT 聊天机器人,还将对如何构建更复杂的对话代理有一个扎实的理解。您还将获得洞察力,以更好地评估将 LLM 驱动的代理集成到您的业务运营中的可行性,并确定是否是过渡到现有 NLU 系统的正确时机。

在本章中,我们将涵盖以下关键领域:

  • 确定我们的 ChatGPT 项目范围

  • 准备我们的数据以供聊天机器人使用

  • 创建我们用于复杂交互的代理

  • 将一切整合在一起——使用 Streamlit 构建您自己的 LangChain 聊天机器人

让我们开始构建我们的聊天机器人,但首先,我们需要考虑我们的对话代理的使用场景和范围。

技术要求

在本章中,我们将广泛使用 ChatGPT,因此您需要注册一个免费账户。如果您还没有创建账户,请访问openai.com/,然后在页面右上角点击开始使用,或者访问 https://chat.openai.com

这些示例需要 Python 3.9 和一个已安装的 Jupyter 笔记本:jupyter.org/try-jupyter/notebooks/?path=notebooks/Intro.ipynb

我们将使用 Chroma DB 作为我们的开源向量数据库,因此建议您查看并熟悉 Chroma (www.trychroma.com),尽管还有许多其他不同的向量存储提供商选项。

确定我们的 ChatGPT 项目范围

每个人都喜欢假期,帮助旅行者通过智能对话自动化是我不太热衷的领域,因此对于我们的用例,我们将创建自己的 ChatGPT 驱动的旅行助手。

到目前为止,我们必须对范围保持现实态度;一家在线旅行社可能能够执行数千种不同任务,复杂程度各异,但让我们选择一些既有趣又能够结合我们在本书中介绍的技术的方法特定的用例。

假日助手用例

你为一家在线旅行社工作,并被委以创建一个由大型语言模型(LLM)驱动的假日助手,旨在彻底改变旅行者选择住宿的方式。在线旅行社在住宿搜索方面往往受限,因此你的挑战是提供更个性化的细致搜索。利用包含描述、评论和其他可能的信息来源(如天气和位置)的酒店数据集,你的目标是构建一个由 ChatGPT 驱动的聊天机器人,能够引导用户找到他们理想中的酒店选择。让我们称我们的代理为艾莉探险家,并深入探讨她的角色。

艾莉探险家的角色概述

首先,让我们考虑艾莉的个性和她将提供给用户的技能。

艾莉的个性

艾莉热情、友好且知识渊博。她以积极的态度和真诚的愿望去帮助他人进行每一次互动。她的回复深思熟虑且个性化,反映了她对每个用户独特偏好和需求的了解。艾莉不仅仅是一个聊天机器人;她是一位旅行伴侣,乐于帮助用户规划旅行,像朋友一样提供建议。

艾莉的互动以其热情和积极性为特点。她以对话的语气进行沟通,让复杂的旅行规划感觉像与一位知识渊博的朋友聊天。她的回复迅速、信息丰富,并且始终考虑到用户的需求和偏好。

艾莉的技能

让我们概述一下当处理用户查询时,艾莉的技能将包括哪些:

  • 学习用户偏好:艾莉警觉且观察力敏锐,能够迅速捕捉到关于用户旅行偏好、家庭动态和最喜欢的假日活动的微妙暗示。她会在互动中记住这些细节,不断改进对每个用户喜好的理解。

  • 个性化推荐:利用她对酒店数据集的全面了解,艾莉超越了简单的关键词搜索。她理解自由文本问题,并深入数据库提供与每个用户愿望完美匹配的推荐,无论他们是在寻找家庭友好的度假村、浪漫的度假地,还是充满冒险的旅舍。

  • 目的地信息:艾莉拥有无数目的地的宝贵信息。她可以告诉你何时是访问某个地方的最佳时间,分享对当地景点的见解,提供安全建议,甚至教你一些文化小贴士,帮助你更好地融入当地。她的建议总是最新的,确保旅行者拥有最佳体验。

  • 天气状况:埃莉密切关注全球的天气状况。她可以提供任何目的地的当前和预报条件,建议天气可能如何影响旅行计划。无论是建议海滩游玩的最佳日子还是警告由于恶劣天气可能导致的旅行中断,埃莉的指导是无价的。

现在我们已经了解了埃莉的能力,让我们看看她的对话能力以及我们想要支持的互动类型。

埃莉的对话范围

让我们概述埃莉能够进行的对话。她有望能够进行以下类型的互动:

  • 个性化推荐:根据酒店的数据库,基于用户偏好和以往互动,聊天机器人可以提供个性化的酒店推荐,以满足每个用户的特定需求。我们不仅想要提供关于设施等参数的关键词搜索,还希望支持基于酒店描述和度假者评论的文本问题,以便我们向用户提供更细致的建议。

  • 目的地信息:关于目的地的查询,包括最佳访问时间、当地景点、安全建议和文化提示。

  • 天气状况:关于特定目的地的当前和预报天气条件或天气可能如何影响旅行计划的问题。

希望我们的概念验证POC)一旦运行正常,我们就能做出是否要制作一个具有更全面功能、包含更大酒店数据集的代理的明智决定。

技术特性

为了创建埃莉这个探索者并满足我们概述的对话范围,我们将实施以下特性:

  • 一个 RAG 系统来存储我们酒店描述的信息,我们可以用它来提供我们的建议

  • LangChain 代理提供与外部数据源交互的工具,以获取最新信息

  • 使用 LangSmith 进行性能监控,以便我们可以看到我们的助手的表现

  • 一个可工作的基于网络的聊天机器人界面,我们可以查看我们的对话并与代理互动,同时跟踪正在进行的对话

为聊天机器人准备我们的数据

为了使我们的数据准备就绪,我们首先需要获取并处理它,使其处于最干净的状态,以便使用。

选择我们的数据源

对于这个项目,我们需要向我们的 LLM 代理提供多种不同类型的特定上下文知识,以便我们可以服务预期的问答类型:

  • 酒店信息:这将来自我们的在线旅行社酒店数据集,因此我们需要一些酒店数据来代表我们想要向用户推荐的酒店。我们将使用的数据集是www.kaggle.com/datasets/raj713335/tbo-hotels-dataset数据集的一个小子集,以提供酒店推荐。此数据集包含来自不同国家和地区的超过 1,000,000 家酒店的信息,例如它们的费用、评论、设施、位置和星级评定。数据是从各种来源收集的,如酒店网站、在线旅行社和评论平台。我们将使用此数据的一个较小版本,以降低我们的模型交互成本。

  • 位置天气:用户可能会询问特定位置的天气,因此我们将使用免费的天气 API Open-Meteo。

  • 详细位置信息:为了提供最新的位置信息,我们将使用维基百科,这样我们就可以按位置搜索。

准备酒店数据

我们将要使用的酒店数据集,hotel-info-chapter8-001.csv,是一个包含来自世界各地约 900 家酒店记录的CSV文件,以增加一些多样性。此数据包含以下列:

countryCodecountryNamecityCodecityNameHotelCodeHotelNameHotelRatingAddressAttractionsDescriptionHotelFacilitiesMapPhoneNumberPinCodeHotelWebsiteUrlReviews

这些内容都比较直观;我们最感兴趣的列是描述评论列,因为我们打算使用这些数据作为我们 RAG 系统的依据,以帮助 Ellie 提供酒店推荐。所以,为了总结,我们需要做什么来使这些数据可供 RAG 使用?我们需要*清理数据、分块并创建嵌入,然后将数据作为嵌入存储,以便以后检索。?

清洗和规范化数据

在创建嵌入之前,我们需要确保描述评论列中的数据是干净和规范的。这涉及到移除任何 HTML。如果你查看描述字段,你会注意到它包含带有 HTML 标签的文本,所以我们应该做的第一件事就是清理这些内容。为此,我们可以使用 Python 的bs4包中的BeautifulSoup库。在下面的代码中,我们将使用remove_html_tags函数移除描述景点中的任何 HTML:

def remove_html_tags(text):
    if pd.isna(text):
        return ""  # Return an empty string for NaN values
    elif isinstance(text, str):
        return BeautifulSoup(text, "html.parser").get_text()
    else:
        # Convert non-string, non-NaN values to string
        return str(text)
df['Description'] = df['Description'].apply(remove_html_tags)
df['Attractions'] = df['Attractions'].apply(remove_html_tags)

我们清洁流程的其他改进可能包括标准化缩写(例如,将Rest.改为Restaurant)和纠正拼写错误。规范化数据有助于减少你的嵌入方差,从而提高推荐准确性。

创建我们的数据块

让我们看看如何从描述评论列创建我们的块。你可以用很多不同的方式来做这件事;我们使用 LangChain 文档加载器,但在一个生产环境中,你可能会有一个更大的数据集,你可能会发现使用我们在上一节中用来清理数据的pandas库更有效率。在我们的方法中,我们从 CSV 文件中读取数据,从每一行创建一个字典,以便我们可以访问列值,查看每个文档,然后从描述评论列创建块:

  1. 加载 CSV 文件:首先,我们需要从 CSV 文件中加载我们的酒店信息。我们将为此目的使用一个自定义的CSVLoader类。指定文件路径、包含酒店名称的列以及任何其他元数据列。我们使用HotelName作为源列:

    loader = CSVLoader(
        file_path="hotel-info-chapter8-001_cleaned.csv",
        source_column="HotelName",
        metadata_columns=["countyCode", "countyName",
            "cityCode", "cityName", "HotelCode", "HotelName",
            "HotelRating", "Address", "Attractions",
            "HotelFacilities", "Map", "PhoneNumber",
            "PinCode", "HotelWebsiteUrl"]
    )
    docs = loader.load()
    
  2. 创建文本分割器:为了处理可能很长的酒店描述和评论,我们将它们分割成更小的部分。我们使用RecursiveCharacterTextSplitter来完成这项工作,设置块大小和重叠以确保文本分析的连续性。描述实际上并不大,但为了我们的示例,目标是将它们分解成足够小的块,以便提供有关每个酒店的某些粒度信息:

    splitter = RecursiveCharacterTextSplitter(
        chunk_size=250, chunk_overlap=20)
    
  3. 处理和分割文本:遍历每个文档,提取指定列的内容,并将每个列的内容分割成可管理的块。然后我们遍历每个块,为每个块创建一个文档,包括元数据page_content的键/值对,以便进行下游处理:

    chunked_docs = []
    for doc in docs:
        content_dict = {}
        pairs = doc.page_content.split('\n')
        for pair in pairs:
            if ': ' in pair:
                key, value = pair.split(': ', 1)
                content_dict[key.strip()] = value.strip()
        for column in content_columns:
            if column in content_dict and content_dict[column]:
                chunks = splitter.split_text(content_dict[column])
                chunked_docs.extend(
                    [
                        Document(page_content=doc_part,
                            metadata=doc.metadata)
                        for doc_part in chunked_doc_parts
                    ]
                )
    

我们想要遍历每个 CSV 记录,并选择描述评论,然后分别分割,因此每个包含原始 CSV 元数据的块随后被添加到我们的chunked_docs列表中,以便创建嵌入:

创建我们的嵌入

一旦我们得到了分割后的文本,我们想要创建我们的嵌入。对于我们的向量数据库,我们将使用 Chroma DB 和 OpenAI 模型来创建我们的嵌入。我们将数据库存储在本地,并使用最新的 OpenAI 嵌入模型text-embedding-3-small来创建我们的嵌入。为了降低我的 OpenAI 嵌入成本,我只会从前 100 个块中创建嵌入;至于你想要为你的项目创建多少,那就取决于你了:

embeddings_model = OpenAIEmbeddings(
    model="text-embedding-3-small")
chroma_document_store = Chroma(
    collection_name="chapter8db_hotel_store",
    embedding_function=embeddings_model,
    persist_directory="chapter8db",
)
chroma_document_store.add_documents(chunked_docs[:100])

我们可以通过查看count()的记录数或进行相似度搜索来测试我们是否在存储中有了记录:

print("There are",
    chroma_document_store._collection.count(),
    "in the collection")
similar_documents = chroma_document_store.similarity_search(
    query="I'm interested in going trail running",k=1)
similar_documents

现在我们已经将酒店嵌入及其元数据存储好了,我们可以开始创建代理将利用的工具,以与这些数据和其他来源进行交互:

创建用于复杂交互的代理

我们的代理将由提供满足我们要求的函数的工具提供支持。主要概念是代理将能够接收我们的问题,并使用 LLM 调用进行推理,将这个任务分解成更小的任务,同时决定使用哪些工具来满足我们的请求并给出问题的答案。代理使用的推理过程在以下图中展示:

图 8.1 – 代理的推理过程

图 8.1 – 代理的推理过程

首先,创建一个专门的文件夹,用于存放我们代理的所有代码。这将有助于组织我们的项目文件,并使代码库更容易导航。我将把这个文件夹命名为streamlit,因为我们将在那里创建我们的 Streamlit 应用程序。

将我们创建的 Chroma 数据库复制到这个文件夹中存储向量:**你的项目路径\streamlit\chapter8db**。

接下来,创建一个名为tools的文件夹,以便我们可以开始创建代理的工具。

创建代理工具

在我们创建 LangChain 代理之前,我们需要创建 LangChain 工具来满足我们的要求。我们将尝试使用代理工具实现所有我们的功能,包括 RAG 功能:

  • 酒店信息

  • 天气信息

  • 位置信息

每个工具都将具备执行其自身任务的能力。让我们逐一分析;目前,创建一个名为tools的文件夹,我们将在这里保存用于最终项目的工具。

定制酒店推荐

第一件工具可能是我们应用程序中最重要的,因为这个工具将与我们构成 RAG 系统检索部分的向量存储进行交互。我们将创建一个自定义工具来完成这项任务。当我们开始思考我们的代理如何执行这些搜索时,有几个挑战需要克服。

我们目前将嵌入存储在我们的向量存储中,因此我们需要创建一个检索器,它将接受查询以搜索这些嵌入,例如“你能推荐一些有 美食 的酒店吗?”

记住,我们已经将我们的文本嵌入与其自己的元数据一起存储。更有用的情况是,如果我们能够像使用关系数据库一样通过元数据过滤我们的嵌入。例如,hotel countryNameHotelRating都在我们的元数据中有所表示。所以,如果我们想寻找特定国家特定评级的酒店的相关文档,我们的问题可能类似于“你能推荐一家在英国有 美食 的四星级酒店吗?”

幸运的是,Chroma DB 提供了在元数据上过滤查询的能力,因此我们知道我们可以通过我们的向量存储来实现这一点。

接下来,我们需要考虑如何在 LangChain 工具中实现这一点。第一个挑战是我们希望从问题中提取参数,以便我们可以将这些参数用于下游,特别是用于我们的 chroma 查询。

一种方法是与 LLM 交互以从用户交互中提取相关的搜索参数,然后将这些参数输入到您的检索器中以执行对 Chroma DB 的搜索。然而,在深入之前,始终最好先查看 LangChain 生态系统中的现有内容。碰巧的是,我们已经有了一些可以利用的东西,SelfQueryRetriever,这是一个专门构建来执行此任务的检索器。让我们将其分解为详细的步骤,解释每个组件的作用以及它们是如何集成的。

  1. 创建搜索服务:首先,创建一个新的文件,hotel_search.py

  2. 初始化 OpenAI Embeddings:接下来,我们使用 OpenAI Embeddings 初始化一个嵌入模型。该模型负责将文本转换为向量表示,这些表示用于语义搜索,并且它与创建我们的嵌入所使用的模型相同:

    from langchain_openai import OpenAIEmbeddings
    embeddings_model = OpenAIEmbeddings(
        model="text-embedding-3-small")
    
  3. 创建 Chroma 文档存储库:接下来,我们设置一个使用来自 embeddings_model 的嵌入进行语义搜索的 Chroma 文档存储库。存储在 Chroma 中的文档可以根据其与查询字符串的语义相关性进行检索:

    from langchain.vectorstores.chroma import Chroma
    chroma_document_store = Chroma(
        collection_name="chapter8db_hotel_store",
        embedding_function=embeddings_model,
        persist_directory="chapter8db",
    )
    
  4. 定义文档的元数据:我们为存储在 Chroma 中的文档定义元数据属性。这些元数据字段信息将被传递给检索器。在我们的示例中,我们只对通过 HotelRatingcityNameCountryName 进行搜索感兴趣。您可以自由添加任何其他您想要搜索的参数:

    from langchain.chains.query_constructor.base import AttributeInfo
    metadata_field_info = [
        AttributeInfo(name="HotelRating",
            description="Hotel rating", type="string"),
        AttributeInfo(name="cityName",
            description="Name of the city", type="string"),
        AttributeInfo(name="countryName",
            description="Name of the country", type="string"),
    ]
    
  5. 初始化自查询检索器SelfQueryRetriever 使用我们在上一步中定义的语言模型、文档存储和元数据信息进行初始化。它被配置为在其自己的索引内容内执行基于相似度的搜索,找到与用户查询语义相关的文档:

    from langchain_openai import OpenAI
    from langchain.retrievers.self_query.base import SelfQueryRetriever
    # Initialize the language model with a specific temperature
    llm = OpenAI(temperature=0.0)
    retriever = SelfQueryRetriever.from_llm(
        llm=llm,
        document_store=chroma_document_store,
        document_content_description="Reviews and Descriptions of hotels",
        metadata_field_info=metadata_field_info,
        verbose=True,
        search_type='similarity',
        search_kwargs={'k': 10}
    )
    

    我们还将返回的文档数量限制为 10,并设置 verbose=True 以便我们可以查看输出。让我们继续创建我们的提示。

  6. 配置提示模板:接下来,定义 PromptTemplate 以确保从文档中检索到的信息在回答用户查询时向 LLM 清晰展示:

    from langchain_core.prompts import PromptTemplate
    template = """you can use the info below to answer questions. Helpful Answer: HotelName: {HotelName} CountryName: {countryName} CityName: {cityName} Address: {Address} HotelRating: {HotelRating} HotelWebsite: {HotelWebsiteUrl}\n\n{page_content}"""
    prompt = PromptTemplate(
        input_variables=["HotelName", "HotelRating",
            "countryName","cityName","Address", "HotelWebsiteUrl"],
        template=template,
    )
    

    现在我们已经创建了我们的提示,我们可以将所有内容整合在一起来创建我们的工具:

  7. 创建检索工具:首先,我们使用 create_retriever_tool 将检索器包装在检索工具中,传入工具的标题、传递给检索器的描述以及我们创建的文档提示:

    retriever_description = """
    "Searches and provides hotel suggestions by searching by question, return the Hotel name, Hotel Rating, Hotel City, Description, Website and a short summary from the metadata. If there are no hotels matching, state that it can't find any hotels with this criteria
    """
    hotel_search = create_retriever_tool(
        retriever,
        "search_hotel_suggestions",
        retriever_description,
        document_prompt=prompt
    )
    

create_retriever_tool 返回我们的类型为 Tool 的工具。最后一步是将 hotel_search 集成到我们的 LangChain 对话代理中,我们将在创建代理时通过将其传递给我们的 AgentExecutor 来完成。回顾一下,这个代理将处理关于酒店推荐的用户查询,利用 SelfQueryRetriever 的语义搜索能力,它现在理解在酒店问题中寻找和处理的元数据,为用户提供有用的酒店推荐。

天气信息

我们可以创建一个自定义工具来提供我们的天气信息。创建自定义工具最简单的方法是使用 @tool 注解一个函数。

因此,对于我们的天气工具,构建起来非常直接。我们创建了一个名为 search_weather 的函数,装饰器使用该函数作为工具名,描述信息是从文档字符串中提取的。对于天气数据,我们将使用 OpenWeatherMap,为了使调用这个 API 的过程既简单又方便,我们将使用 Langchain 工具,OpenWeatherMapAPIWrapper。再次强调,如果你找到了想要在 ChatGPT 应用中使用的服务,在构建任何定制化内容之前,总是值得在 LangChain 生态系统中先进行一番探索。创建一个名为 search_weather.py 的文件,并添加以下内容:

from langchain.tools import BaseTool, StructuredTool, tool
from langchain_community.utilities import OpenWeatherMapAPIWrapper
os.environ["OPENWEATHERMAP_API_KEY"] = st.secrets.OPENAI_API_KEY
@tool
def search_weather(query: str) -> str:
    """A weather tool optimized for comprehensive up to date weather information.
    Useful for when you need to answer questions about the weather, use this tool to answer questions about the weather for a specific location.
    Look in context for the location to provide weather for"""
    weather = OpenWeatherMapAPIWrapper()
    weather_data = weather.run(query)
    return weather_data

访问 openweathermap.org/api/ 并注册一个账户以获取你的 API 密钥。这需要作为一个环境变量来提供。我们将在创建聊天机器人应用时讨论如何设置环境变量。

位置信息

我们希望创建一个工具,使用最新的数据来回答有关酒店位置的问题,以便我们可以将这些结果添加到我们的上下文中。有几种选择。我们可以使用 Tavily 搜索引擎,这是为 LLM 定制的搜索引擎,LangChain 中也有一个现成的工具,TavilySearchResults

然而,找到信息的一个好地方是维基百科,所以让我们将其作为我们工具的信息来源。

我们将使用一个现成的 LangChain 工具来与维基百科交互,WikipediaQueryRun。你需要通过运行 pip install --upgrade --quiet Wikipedia 来安装 Wikipedia Python 包。

创建这个工具非常简单——创建一个名为 wikipedia.py 的文件,并添加以下内容以创建 Wikipedia API 包装器:

from langchain.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
api_wrapper = WikipediaAPIWrapper(top_k_results=5,
    doc_content_chars_max=500)

包装器提供了一些微调维基百科搜索结果的有用方法,因此我们已将返回的结果数量限制为 5,并将每个返回文档的内容限制为 500 个字符。

接下来,通过传递我们的包装器并给出工具描述来创建工具:

wikipedia_search = WikipediaQueryRun(
    api_wrapper=api_wrapper,
    description="look up tourist information for locations")

现在,我们可以在我们的代理中使用这个工具了。在下一节中,我们将探讨如何使用我们创建的工具来创建 LangChain 代理。在下一节中,我们将通过创建一个能够利用我们创建的工具的代理来将这些元素整合在一起。

将所有内容整合在一起——使用 Streamlit 构建自己的 LangChain 聊天机器人

让我们开始构建我们的基于 Web 的聊天机器人,这样我们就可以使用 LangChain 与 ChatGPT 进行交互。为了实现这一点,我们将使用 Streamlit Python 库来构建界面。Streamlit 丰富的现成组件和实用工具,以及出色的文档,使我们能够快速开发一个功能性的基于 Web 的聊天机器人。它简单而强大的功能支持快速原型设计和迭代改进,非常适合我们的聊天机器人项目。Streamlit 简化了交互元素的集成,并提供了很多开箱即用的功能,这将缩短我们的开发时间,使我们能够专注于 LangChain 项目。

确保你已经使用 pip install streamlit 或其他许多方法之一安装了 Streamlit。我使用 Anaconda,所以我使用这个发行版。你可以通过运行 streamlit hello 来测试你是否正确安装了 Streamlit。

在我们的项目文件夹中,创建一个名为 app 的文件夹,我们将在这里存储我们的应用程序代码。将你之前创建的工具复制到 app/tools 下的 tools 文件夹中。接下来,让我们看看如何管理我们的 API 密钥。

创建密钥和配置管理

Streamlit 的第一个魔法技巧将是使用开箱即用的密钥管理器。Streamlit 提供了基于文件的密钥管理功能,这样我们可以轻松存储和安全管理我们的 API 密钥以及管理项目。创建一个名为 .streamlit 的文件夹和一个名为 secrets.toml 的文件,然后添加我们在这个项目中需要的 API 密钥:

  • OPENAI_API_KEY="YOUR KEY"

  • LANGCHAIN_API_KEY="YOUR KEY"

  • OPENWEATHERMAP_API_KEY="YOUR KEY"

Streamlit 在开发过程中会自动将密钥从 secrets.toml 文件加载到你的项目目录中,并提供选项,如果你想要通过 Streamlit Cloud 接口部署或者使你的应用程序公开可用。接下来,让我们继续创建我们的代理代码。

创建我们的代理服务

让我们把 LangChain 服务的代码组织到一个专门的 LangChain 服务文件中。

  1. 创建 LangChain 服务:首先创建一个专门用于 LangChain 服务的 Python 文件,并将其存储在 app 文件夹中。这个文件可以命名为 langchain_service.py。这个文件将包含设置和运行代理所需的所有代码。

  2. 导入必要的库和模块:导入 os 模块用于环境变量管理,从 LangChain 导入组件以访问 hub 功能和代理执行,我们的 ChatOpenAI 模型,AgentExecutor 用于管理提示和对话记忆,以及我们在早期步骤中创建的工具(weather_searchwikipedia_searchhotel_search),这些工具是为特定的聊天机器人功能设计的。

  3. 定义 setup_agent 函数:这个函数旨在配置并返回一个配备特定工具和设置的 AgentExecutor 实例,用于聊天机器人:

    def setup_agent(msgs: list, openai_api_key: str, 
        langchain_api_key: str, openweathermap_api_key: str
    ) -> AgentExecutor:
    os.environ["OPENAI_API_KEY"] = openai_api_key
    os.environ['LANGCHAIN_TRACING_V2'] = "true"
    os.environ['LANGCHAIN_ENDPOINT'] = "https://api.smith.langchain.com"
    os.environ['LANGCHAIN_PROJECT'] = "ellie_chatbot"
    

    前面的参数包括来自 Streamlit 应用程序的对话历史消息列表以及 OpenAI、LangChain 和 OpenWeatherMap 服务的 API 密钥。然后我们设置环境变量,以便 LangChain 可以访问它们。我还设置了环境变量,以便我们可以在 LangSmith 中跟踪一切,以及一个项目名称,这样我们就可以轻松跟踪我们与 Ellie 的所有交互。

  4. 初始化语言模型、工具和提示:创建一个具有特定温度和模型参数的 ChatOpenAI 实例。我们还创建了我们的工具列表:

    llm = ChatOpenAI(temperature=0.0, model='
        gpt-4-1106-preview',verbose=True)
    tools = [hotel_search,weather_search,wikipedia]
    hub_prompt = hub.pull("hwchase17/openai-tools-agent")
    

    预定义的工具(hotel_searchweather_searchwikipedia)将添加我们的专用功能,代理将根据提出的问题决定使用哪些功能。hub_prompt 使用 hub.pull 获取,它从 LangChain hub 获取一个预定义的提示模板。如果您想有更多的控制权,可以手动创建,但对我们这个例子来说,这完全适用。

  5. 配置对话记忆:我们将使用 ConversationBufferWindowMemory,这将赋予我们的聊天机器人对话记忆,并允许它提供上下文感知的响应。请注意,我们通过设置 k=20 来保留最后 20 个交互在记忆中,并且我们还从我们的 Streamlit 代理中传递一个消息列表(msgs)到 chat_memory,这使得我们可以将代理记忆与 Streamlit 会话状态联系起来。

  6. 使用工具、记忆和 AgentExecutor 创建代理:接下来,我们使用导入的 create_openai_tools_agent 函数创建我们的代理。这个 LangChain 函数创建了一个能够使用 OpenAI 的 tools 功能的代理:

    agent = create_openai_tools_agent(llm, tools, hub_prompt)
    

    create_openai_tools_agent 函数使用语言模型(llm)、工具列表和 hub_prompt 来创建一个配置好的代理。

  7. 创建我们的 Agent Executor:最后,我们可以创建我们的 AgentExecutor,它使用创建的代理、工具、记忆配置和详细设置进行实例化。这个执行器管理聊天机器人的执行流程,处理输入,并根据集成的工具和对话记忆生成响应。setup_agent() 函数返回一个 AgentExecutor 实例,现在它已准备好在 Streamlit 聊天机器人应用程序中使用。我们将在下一节中查看如何创建这个应用程序以及如何使用我们的 LangChain 服务:

构建我们的 Streamlit 聊天应用

现在我们所有的组件都已准备就绪,是时候构建我们的聊天机器人了。首先创建一个名为 main.py 的文件;这个文件将作为主要的 Streamlit 脚本。在这个脚本中,我们将开发 Ellie 的聊天机器人界面。让我们通过以下步骤来创建这段代码:

  1. 导入库:我们需要导入必要的库,包括我们的 LangChain 历史组件和 streamlit (as st) 用于我们的聊天机器人元素。我们还导入 setup_agent()。这个函数来自我们创建的 langchain_service.py,它使用必要的配置和 API 密钥初始化聊天机器人的代理。

  2. 初始化 Streamlit 网络应用程序:定义 init_streamlit() 函数;这使用 st.set_page_config 设置 Streamlit 页面配置,指定页面标题和图标。我们还使用 st.title( ✈️ Ellie the explorer) 给我们的页面一个标题。

  3. 接下来,我们初始化我们的聊天消息历史:这很重要,因为 Streamlit 应用程序在单线程模式下运行,任何触发重新运行的用户交互都会从顶部到底部重新运行整个脚本。因此,为了保存我们的消息,我们需要创建一个机制来管理这些在 Streamlit 的 Session State 中。我们还需要考虑将这些传递给我们的 LangChain 应用程序。为了实现这一点,我们使用 LangChain 社区库中的一个组件。StreamlitChatMessageHistory 是一个类,允许您在 Streamlit 应用程序中存储和使用聊天消息历史,

    msgs = StreamlitChatMessageHistory()

    它与 LangChain 无缝协作,允许您将聊天消息历史集成到 LangChain 链中。它通过在指定的键(默认为 langchain_messages)中存储消息来实现。然后我们将这个内存的引用传递给我们的代理。

  4. 定义 prepare_agent 函数:这是一个辅助函数,它使用聊天消息历史和存储在 st.secrets 中的 API 密钥调用 setup_agent,返回一个配置好的 AgentExecutor

  5. 创建我们的 AgentExecutor Langchain 代理:我们调用 prepare_agent(). 来创建我们的 agent_executor

    agent_executor: AgentExecutor = prepare_agent(msgs),将聊天消息历史和 API 密钥从 st.secrets 传递到从我们的 LangChain 服务代码 langchain_service.py 中导入的 setup_agent() 函数,该函数返回配置好的聊天机器人 AgentExecutor 实例。

  6. 显示欢迎信息:在对话开始时向用户添加欢迎信息,指导他们如何与聊天机器人互动:

    if len(msgs.messages) == 0:
        msgs.add_ai_message(welcome)
    

    如果是初始加载(即历史中没有消息),则定义并添加消息到聊天历史中。

  7. 用户交互和响应处理:接下来,我们想要处理用户输入。如果用户输入一个新的提示,我们将生成并绘制一个新的响应:

    if prompt := st.chat_input():
        st.chat_message("human").write(prompt)
        try:
            response = agent_executor.invoke({"input": prompt})
            if 'output' in response:
                st.chat_message("ai").write(response['output'])
            else:
                st.error("Received an unexpected response format from the agent.")
        except Exception as e:
            st.error(f"An error occurred: {str(e)}. Please try again later.")
    

    可以添加一个可选组件,以便您可以轻松查看存储在 st.session_state.langchain_messages 中的内容。这是一个展开小部件(st.expander),用于以 JSON 格式显示消息历史。

    应用程序通过 st.chat_input() 监听用户输入。当接收到输入时,它会使用 st.chat_message() 显示为一个 人类 消息。

    然后将输入传递给 agent_executor.invoke() 以处理响应,如果成功,则将响应作为 ai 消息显示给用户。

    我们还在处理响应格式错误和代理调用返回的错误;如果有错误,则使用 st.error() 显示此消息。

    如果脚本是主程序(即,不是作为模块导入),则调用 init_streamlit() 来启动应用程序:

    if __name__ == "__main__":
        init_streamlit()
    

就这样!现在一切应该都已经就绪,可以创建一个功能性的聊天机器人。在下一节中,让我们来试一试。

运行和测试我们的聊天机器人应用程序 Ellie

要运行此 Streamlit 应用程序,请确保您在 Python 环境中安装了 Streamlit 和所有必要的包。然后,导航到包含 main.py 文件的目录,并在您的终端中运行以下命令:

streamlit run app/main.py

此命令启动 Streamlit 网络服务器并在您的默认网络浏览器中打开应用程序,允许您与聊天机器人交互。如果有任何问题,请确保您的 API 密钥和任何其他必需的配置已正确设置在 st.secrets 中,并且已适当地传递给 setup_agent() 函数,以便应用程序按预期运行。您还应该能够在开始与聊天机器人交互后看到您的日志出现在 LangChain 中,从而允许您深入了解每个运行。

让我们尝试我们的第一个酒店推荐搜索。如您在以下输出截图中所见,我们得到了一个有用的结果:

图 8.2 – 向我们的代理请求酒店推荐

图 8.2 – 向我们的代理请求酒店推荐

代理查看问题并选择使用哪个工具来满足请求。这个问题是针对酒店的,因此代理调用我们的 hotel_search 工具来回答我们的问题。记得查看 LangSmith 中的调试输出以查看项目的单个运行。这将允许您看到对各个 LLM 的单个调用,从而深入了解您的代理如何与不同的 LLM 交互以决定使用哪个工具,并将我们的响应返回,以及针对各个工具的特定任务——例如,提取用于过滤我们的向量搜索的参数。以下 LangSmith 截图显示了这一点:

图 8.3 – 在 LangSmith 中查看我们的代理对 LLM 的调用

图 8.3 – 在 LangSmith 中查看我们的代理对 LLM 的调用

随意尝试您自己的问题,只要与您自己的数据相关即可。

我们还应该能够提出后续问题,以便代理练习其他工具。在以下截图中,我们还询问了天气,您可以看到 Ellie 使用我们的天气搜索工具响应数据。

图 8.4 – 我们提出一个特定于天气的问题来测试我们的天气工具

图 8.4 – 我们提出一个特定于天气的问题来测试我们的天气工具

通过询问关于该地区的具体信息来尝试wikipedia_search工具。

因此,我们现在有一个由 ChatGPT 驱动的有效代理,这为创建一个更高级的代理奠定了良好的基础。让我们看看你可以进行哪些其他改进。

提高 Ellie 的方法

你可以实施许多不同的增强来提高 Ellie 的旅行助手功能:

  • 改进聊天 UI——例如,实现流式答案

  • 通过增强我们的 LangChain 代理,提供更复杂的交互,以便我们可以执行更复杂的交易任务

  • 学习用户偏好——他们的兴趣、家庭状况以及他们喜欢在假期做什么

  • 通过使用向量存储增强聊天机器人记忆,以持久化对话,以便在会话之间使用

  • 查看分块策略以改进向量嵌入,以实现更好的搜索

到目前为止,你所创建的只是一个起点,是创建一个更复杂的 ChatGPT 驱动的代理的良好基础。这些增强中的任何一个都值得实施,以提高 Ellie 的能力。

摘要

在本章中,我们研究了创建一个由 ChatGPT 驱动的对话代理的真实世界示例,使用了一些我们在早期章节中介绍的技术和工具。我们的示例被精心设计,以涵盖聊天机器人的用例、功能特性和特性,使我们能够有效地应用我们对 LangChain、RAG 系统和相关工具的知识。你还被介绍到 Streamlit 库,以创建丰富的聊天界面,并看到如何与 LangChain 一起使用它。希望我们已经实现了我们的代码库,使我们的代理可扩展,并可用于更复杂的项目。我们已经实现了我们的目标,即创建一个具有我们自己的数据知识并能够使用外部信息和来源的 ChatGPT 对话代理。

我们已经创建了我们的原型并验证了我们的概念。这是一个起点,但在创建更广泛的应用程序并上线之前,还有很多事情要考虑。在我们的最后一章中,我们将考虑使用到目前为止所学的内容进入生产,以及我们需要创建哪些其他核心功能来实现这一目标。我们还将考虑 ChatGPT 的其他替代方案以及小型语言模型的兴起和重要性。最后,我们将得出一些结论,并探讨在当前技术状态下我们将如何继续前进。

进一步阅读

以下链接是本章中使用的一些资源的精选列表:

9

使用 LLM 的对话式 AI 的未来

在本章中,我们将更深入地探讨与将我们的 ChatGPT 应用投入生产相关的话题。我们在本书的其它部分已经触及了一些这些领域,但现在让我们更详细地考虑这些方面,同时也要看看行业中学到的经验教训。基于到目前为止我们从创建 ChatGPT 应用中学到的知识,我们可以做出明智的决定,并为我们的对话式 AI 项目制定成功的策略。

我们还将探讨在撰写本书时 ChatGPT 的其它替代技术,特别关注较小语言模型的可能性。最后,我们将展望 LLM 的未来,以及你的组织可能的发展方向,为你准备对话式 AI 演变中的下一个阶段。

在本章中,我们将涵盖以下主题:

  • 进入生产阶段

  • 评估生产系统

  • 学习如何使用 LangSmith 评估你的项目

  • LangSmith 的高级监控功能

  • ChatGPT 和 LangChain 的替代方案

  • 小型语言模型(SLM)的增长

  • 接下来该做什么

技术要求

在本章中,我们将广泛使用 ChatGPT,因此你需要注册一个免费账户。如果你还没有创建账户,请访问openai.com/,然后在页面右上角点击开始使用

示例需要安装 Python 3.10 和 Jupyter 笔记本jupyter.org/try-jupyter/notebooks/?path=notebooks/Intro.ipynb。示例需要安装 Python 3.10 和 Jupyter Notebook,你可以通过访问jupyter.org/try-jupyter/lab/index.html来完成。

你可以在这里找到本章的代码:github.com/PacktPublishing/ChatGPT-for-Conversational-AI-and-Chatbots/chapter9

进入生产阶段

随着你通过本书的学习,你在如何创建由 ChatGPT 驱动的对话代理方面的知识得到了很大的提升。希望你也了解了一些由 LLM 驱动的系统的局限性、挑战和陷阱,最重要的是,如何使它们准备好投入生产。这些挑战不容小觑,过去一年多来,尽管 LLM 得到了广泛的应用,但完全由 LLM 驱动的对话式 AI 代理的例子却很少,而且其中一些在某些情况下表现不佳。让我们在下一节中看看一个例子。

理解进入生产的危险

最近的一个例子是,一家知名快递公司部署的聊天机器人出现的问题,如何 LLM 在生产中迅速让你陷入困境。我这里不点名批评这家公司;还有其他一些表现不佳的聊天机器人例子。另一个例子是花一美元买了一辆雪佛兰塔霍——我建议你谷歌一下这个话题!

对于快递聊天机器人,一位不满的客户决定通过提出一系列尴尬的问题来在他们的对话中增加一些幽默感,结果聊天机器人开始咒骂,并发表了一首诗,指责快递公司无用。这对客户支持聊天机器人来说不是最好的对话,但却是任何 LLM 驱动的对话代理在没有适当护栏的情况下可能出错的一个很好的例子。

那么,这里发生了什么?我无法对这家公司在聊天机器人项目中使用的技术栈或 LLM 技术发表评论。然而,如果一个代理开始用脏话回应,看起来他们没有采用任何输出验证器或内容审查。这允许公众成员直接提示 LLM。这看起来不太可能是模型训练的问题,而更可能是由于缺少阻止恶意(好吧,有点夸张)提示的护栏而引起的问题。这允许用户参与 LLM 的非品牌话题或超出范围的请求。因此,对 LLM 问题的内容过滤将阻止这种情况,结合对输出的检查,以确保在发送给客户之前内容适当。

这里实际上有两个问题:输入和输出,你希望它们由更稳固的提示策略来处理。例如,如果代理是一个由 ChatGPT 驱动的 LangChain 代理,那么我们会考虑创建一个强大的系统提示,并在我们进入主管道之前使用 LLM 调用检查初始问题。这需要有一个广泛评估过程的支持,不仅包括标准问题,还包括系统如何处理试图操纵和/或破坏系统的用户,以便他们在社交媒体上发布关于它。

记住——能力越大,责任越大,在创建 LLM 项目时,与传统自然语言理解NLU)系统相比,这完全是另一回事。我们实际上已经从制作一个系统并关注正确、错误和缺失的答案转变为一个系统,在这个系统中,所有这些都可以发生,如果你没有足够强大的努力来阻止它,几乎任何事情都可能发生。

到现在为止,我相信你已经意识到,最受欢迎的 LLM 应用之一是 RAG 系统,我们已经在之前的章节中对此进行了详细讨论。然而,这些系统也并非没有挑战;让我们更详细地探讨一些这些问题。

RAG 系统的挑战

正如我们所学的,RAG 系统是 LLM 对话式 AI 中流行的实现方式之一,可能出现在你目前正在尝试使用 LLM 技术或正在开发的绿色项目中重新创建的系统。你也了解到,你可以在不花费大量努力的情况下从这些系统中获得相当不错的性能。然而,尽管 RAG 系统是 LLM 驱动对话式 AI 的典范,但它确实提出了挑战,这些挑战在你向生产阶段迈进时变得更加重要,我们将在下一节中探讨这些挑战。因此,让我们考虑我们正在将一个带有 RAG 系统的项目投入生产——例如,第八章中的项目:我们旅行助手概念验证POC)。到目前为止,Ellie Explorer 已经给关键利益相关者留下了深刻印象,他们希望将其作为一个基于网络的聊天机器人发布,并扩大其范围,提供更多针对性的个性化酒店建议,并回答常见问题以及更多交易性用例。为了回顾,我们使用了 RAG 系统,以便从我们的 LLM 准备好的酒店信息数据存储库中注入上下文参考数据,以提供简洁、可信的酒店推荐。

尽管它们采用了创新的方法,但原始的 RAG 系统存在一些挑战,可能会阻碍其有效性和可靠性。

从原型到生产的转变是一个巨大的步骤,在将 Ellie 投入实际使用之前,我们需要考虑 RAG 系统面临的挑战。

传统 RAG 的不足

让我们详细看看 RAG 系统的不足之处以及这些不足如何在我们的系统中体现:

  • 缺失内容:当尝试处理无法从现有底层文档数据中找到答案的问题时,可能会发生故障,可能是因为信息根本不存在,或者存在一些分块或嵌入过程的问题。这可能会很难调试,并且需要正确处理。理想情况下,RAG 系统将简单地回复一条消息,例如“抱歉,我没有这个信息。”然而,在问题与内容相关但缺乏具体答案的情况下,系统可能会被误导而提供回应。或者,一个更难发现的故障可以从我们之前的例子中看出:如果 RAG 系统搜索没有返回结果——例如,对于不在我们提供的酒店数据库中的国家的酒店推荐。LLM 正在根据自己对酒店的自身知识进行回应,而不是 RAG 结果中的知识,因此建议的酒店超出了公司酒店列表。这种行为可以通过提示来纠正,但你可以看到这里的问题:很难发现。现实情况下,我们需要定期检查我们的酒店结果建议,以确保这种情况不会发生。

  • 检索不足和精确度问题:对于 RAG 系统来说,检索相关信息是一个关键挑战。底层检索模型可能会获取相关数据,这可能导致生成误导性或不相关的文本。这种情况通常是由于在质量不足的数据或无法准确代表目标领域的数据上训练所导致的。提高数据质量和确保其与目标领域的一致性是解决这一挑战的关键步骤。然而,这也可能表明我们需要更复杂的检索算法,这些算法能够准确理解查询的上下文和细微差别。

    也可能存在结果排序问题,其中包含答案的文档排名不够高,无法展示给用户。也存在结果排序问题,其中包含答案的文档排名不够高,无法展示给用户。在 Ellie 的情况下,如果我们返回n个酒店结果,从理论上讲,所有文档都会被排序,但这可能意味着一些文档可能无法达到标准,无法发送到上下文中。

    基本上,如果我们注入的提示包含不正确或不良的上下文参考,那么结果可能不会提供良好的结果也就不足为奇了。基本上,如果我们注入的提示包含不正确或不良的上下文参考,那么结果可能不会提供良好的结果。

  • 过时信息:如果知识源没有定期更新或模型缺乏识别和整合时间信息的机制,RAG 生成的内容可能基于过时的事实。保持知识库的时效性和设计检索系统以考虑信息的时间敏感性是很重要的。

  • RAG 成本增加:存在担忧,即随着许多带有 RAG 组件的 ChatGPT 系统的增加,将出现越来越多的不必要的令牌成本开销,这主要是由于未优化的检索和额外的文本结果被传递到上下文所导致的。

  • RAG 系统是否过于简单?:坦白说,到目前为止,我们所涵盖的是一种相对简单的 RAG 实现。很明显,RAG 系统需要考虑很多因素,最新的 RAG 系统提出了更高的要求,有三个核心主题对于这些系统至关重要,如果要将系统投入生产,这些主题需要表现良好:

    • 在满足问题需求时知道何时何地检索数据。可能存在多个向量存储库来提取数据。

    • 通过质量检查或结果排序来评估您检索的数据。使用大型语言模型(LLM)进行审查可能是一个解决方案,但可能会导致错误。

    • 您可能需要进行多次检索调用,然后选择最佳结果。实际评估结果很困难,独立验证多个事实可能会耗时且影响系统效率。

    在我们的 Ellie 示例中,我们的 AgentExecutor 将会处理 a,但 bc 是你需要构建到你的系统中的内容。

  • 常见 LLM 问题:幻觉、毒性、无关性

    幻觉和无关性可能源于系统设计的缺陷或知识库中的不准确,以及来自底层 RAG 数据的毒性和偏见,或者通过 ChatGPT 调用的响应生成而显现出来。幻觉和无关性可能源于系统设计的缺陷或知识库中的不准确,以及来自底层 RAG 数据的毒性和偏见,或者通过 ChatGPT 调用的响应生成而显现出来。所有这些都是需要在生产系统中注意的问题。

因此,现在我们已经讨论了你将要面对的挑战和解决方案,在下一节中,让我们考虑如何评估你的 LLM 应用程序。

评估生产系统

开发一个带有 RAG 组件的原型 ChatGPT 应用相对简单,但为生产做准备并有效维护它则需要持续的评估,这具有挑战性。使用大型语言模型(LLMs)来协助评估是一种明显的方法;然而,请注意,由于 LLMs 表现出的位置偏差、答案风格偏好以及每次运行结果的不确定性,这导致需要更结构化的方法。还值得记住的是,用例和代理的性质将影响你的评估方法。例如,与更会话式的代理相比,简单的 RAG 问答需要不同的评估方法。

重要的是要理解,就像在任何机器学习ML)项目中一样,你应该使用验证数据集和评估指标来评估 RAG 管道的性能。这涉及到对组件进行个别和整体评估:知识检索、响应生成以及它们的集成。你可以考虑多种不同的评估指标,例如上下文相关性、扎根性和答案相关性。

目前,确定合适的评估指标和收集良好的验证数据是一个快速发展的主题。为了解决 LLM 辅助评估的缺点,有各种方法和指标用于评估 RAG 系统,包括检索增强生成评估RAGAs)或 RAG 三联指标等工具,以及一系列的工具选项和库。每一个都值得在这里详细讨论,并且值得阅读其中的一些,以了解不同的方法并查看这些方法如何实现。这些主要是旨在通过关注知识检索的精确性和响应生成的质量,以结构化和全面的方式评估 RAG 应用有效性的方法论。在下一节中,我们将考虑使用 LangSmith 对 LangChain 应用进行评估的过程。

评估系统的组成部分

LangSmith 提供了一个强大的评估框架,旨在通过以下图中概述的精心设计的组件来监控和改进 LLM 应用:

图 9.1 – 评估过程

图 9.1 – 评估过程

LangSmith 提供了用于构建数据集、编辑和版本控制的 UI 和 SDK:一个用于定义自己的评估器或创建和使用自定义评估器的 SDK,以及一个用于执行检查和跟踪分析的 UI。

让我们更详细地探讨一个有效评估系统的组成部分:

  • 数据集和示例

    LangSmith 中任何评估系统的基本单元是数据集,它由多个示例组成。数据集中的每个示例代表一个包含输入和预期输出的测试用例:

    • 输入:这些是 LLM 将处理的数据点。

    • 输出结果:这些是当给出输入时,LLM 应该产生的预期结果。

    数据集通常来自各种来源,包括手动创建、用户反馈或进行顺利或生成 LLM 输出的对话示例。如果您正在考虑从现有系统迁移到 ChatGPT 驱动的代理,那么您的历史对话数据对于评估将至关重要。

  • 数据集类型:LangSmith 支持不同类型的数据集:

    • 键值对:可以容纳多个输入和输出的键值对。

    • LLM:直接字符串输入和输出,通常用于简单的提示-响应模型。

    • 聊天:结构类似于聊天对话,适合训练在对话上的模型。

    在 LangSmith 中创建数据集非常简单,您可以在那里创建和编辑数据集以及示例行,还可以从 CSV 文件导入。

  • 任务:任务是实际的操作或正在评估的模型。它处理数据集中的示例输入并生成输出,然后由评估器进行评估。

  • 评估器:评估器是评估任务生成的输出的函数或机制。它们将这些输出与预期结果进行比较或应用特定标准以确定输出的质量。评估器返回分数,并为每个示例提供反馈。存在多种不同类型的评估器:

    • 启发式评估器:这些是执行检查的简单函数,例如验证输出格式(例如,JSON 验证)或与预期输出进行字符串匹配。

    • LLM-as-judge: 高级评估器,使用另一个 LLM 根据内容标准(如冒犯性或相关性)来评估输出质量。

    • 人工:手动审查输出,通常用于最终验证或在需要细微判断的情况下使用。

  • 评估结果:评估的输出通常是EvaluationResult,它包含以下内容:

    • 关键:正在评估的指标名称(例如,准确性,完整性)。

    • 评分:衡量输出与预期结果匹配程度或满足评估标准的定量指标。

    • 注释:可选的见解或评分背后的推理。

现在你已经了解了评估系统的组成部分,在下一节中,我们将通过一个示例来探讨如何将其付诸实践。

学习如何使用 LangSmith 评估你的项目

记住,不同类型的 AI 代理将需要不同类型的评估方法。没有一种适合所有情况的解决方案,你需要根据你的用例来决定采用的方法和途径。如果你希望支持特定领域的知识(例如,来自 RAG 系统的公司特定信息),那么问答代理将更容易评估;而需要支持交易性对话的代理则需要更复杂的评估实现,因为你需要确保你的对话代理能够始终如一地完成任务。

在基于意图的系统下,你可以精确控制对话的每一步,而在 LLM 驱动的对话代理中,你通过提示来控制代理的动作和能力,这在我的看法中是一种更微妙且易变的方法。

Langsmith 使得这种深入的特定评估成为可能,让我们通过一个简单的代码示例来运行,以便你可以看到 LangChain 的基本工作原理:LangSmith 使得这种深入的特定评估成为可能。让我们通过一个简单的代码示例来运行,以便你可以看到与 LangChain 一起工作的基本原理。

我们的示例由一个 RAG 系统组成,该系统从简单的知识库中回答关于超级马拉松的问题:

  1. 处理源文档并索引:对于我们的知识库,我们将使用带有一些运行信息的 source.text 文本文档源.text。请随意使用您自己的主题领域 - 我只是喜欢跑步!我们遵循前面章节中概述的标准工作流程来创建一个简单的基于简单文本语料库的 LangChain RAG 以进行评估 - 文档分块、嵌入创建以及使用 OpenAI 嵌入和内存中的 Chroma DB 作为向量存储的检索器创建:

    loader = TextLoader('source.txt')
    documents = loader.load()
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=20,
        length_function=len,
        is_separator_regex=False,)
    split_documents = text_splitter.split_documents(documents)
    embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
    chroma_document_store = Chroma.from_documents(
        split_documents, embeddings)
    retriever = chroma_document_store.as_retriever(
        search_kwargs={"k": 4})
    
  2. 创建一个简单的 LangChain RAG 以进行评估:在以下代码中,我们创建了一个标准的 RAG 管道来与我们的 Chroma 检索器交互。现在,您应该已经熟悉我们的管道设置。初始化 ChatOpenAI 类的一个实例,并从模板字符串创建一个 ChatPromptTemplate 实例,其中包含问题和上下文的占位符,这些将在 RAG 管道执行期间填充。接下来,使用 LangChain 表达式语言LCEL)将所有内容组合在一起来创建我们的链,您可以调用它来检查一切是否正常工作:

    model = ChatOpenAI(model="gpt-3.5-turbo-0125")
    template = """You are a helpful documentation Q&A assistant, trained to answer questions about ultra marathon running.
    Use the following pieces of retrieved context to answer the question.
    If you don't know the answer, just say that you don't know.
    Use two sentences maximum and keep the answer concise.
    Question: {question}
    Context: {context}
    Answer:
    """
    prompt = ChatPromptTemplate.from_template(template)
    # Setup RAG pipeline
    rag_chain = (
        {"context": retriever,  "question": RunnablePassthrough()}
        | prompt
        | model
        | StrOutputParser()
    )
    chain.invoke("do i need to do any long runs in my training")
    
  3. 安装 LangSmith 并初始化 您的客户端

    确保您已通过运行 pip install -U langsmith 安装了 LangSmith。然后,设置您的环境以使用 LangSmith,然后创建您的 LangSmith 客户端:

    from langsmith import Client, evaluate
    from langsmith.schemas import Run, Example
    # Initialize the LangSmith client
    client = Client()
    
  4. 创建并填充 数据集

    对于 QA 正确性评估,创建一个特别包含关于您特定知识库问题的数据集。每个示例应包括一个问题及其正确答案。我们可以通过从 CSV 导入或编程方式完成此操作:我们创建一个名称和描述,然后调用 client.create_dataset() 来创建数据集,然后使用 create_examples() 添加我们的示例。我们也可以通过从 CSV 导入或编程方式直接添加这些示例:我们创建一个名称和描述,然后调用 client.create_dataset() 来创建数据集,然后使用 create_examples() 添加我们的示例。我们还可以直接使用 LangSmith UI 添加这些示例:

    dataset_name = "Ultra Marathon QA Dataset"
    description = "Dataset for evaluating QA correctness of an ultra marathon chatbot."
    dataset = client.create_dataset(dataset_name, 
        description=description)
    client.create_examples(
        inputs=[
            {"question": "How do...", "context": "..."},
            {"question": "will i...", "context": "..."}
        ],
        outputs=[
            {"answer": "Training..."},
            {"answer": "Consider buying..."}
        ],
        dataset_id=dataset.id,
    )
    

    添加示例到数据集的另一个简单选项是从 LangChain 的现有运行中。只需转到 运行详情 页面,然后点击 添加到 数据集 按钮。

  5. 定义 评估方法

    创建一个函数来调用我们要评估的东西,在我们的例子中是 RAG 链,但这可以是您管道中的任何可运行元素。创建一个函数来调用我们要评估的东西。在我们的例子中,它是我们的 RAG 链,但这可以是您管道中的任何可运行元素:

    def predict(inputs: dict):
        return rag_chain.invoke({"question": inputs["question"]})
    
  6. 为评估器定义输入格式化器

    定义一个函数来格式化评估器的输入。此步骤确保评估器函数以一致格式接收必要的数据:

    def format_evaluator_inputs(run: Run, example: Example):
        return {
            "input": example.inputs["question"],
            "prediction": next(iter(run.outputs.values())),
            "reference": example.outputs["answer"],
        }
    
  7. 配置评估器

    在这一步,我们将设置 LangChainStringEvaluator。在这一步,我们将设置LangChainStringEvaluator评估者。这涉及到配置它以根据预定义的标准和归一化因素评估聊天机器人的响应的正确性。这个评估者将处理字符串比较,允许对答案准确性进行精确测量:

    from langsmith.evaluation import LangChainStringEvaluator
    correctness_evaluator = LangChainStringEvaluator(
        "labeled_score_string",
        config={"criteria": "correctness", "normalize_by": 10},
        prepare_data=format_evaluator_inputs)
    

    让我们来看看创建评估者的详细情况:

    • 标签:‘labeled_score_string’指定了在评估结果中输出的评分标签。标签"labeled_score_string"指定了在评估结果中输出的评分标签。

    • 配置:配置包括以下内容:

      • “标准”:“正确性”,它定义了评估应该衡量什么——在这里,是响应的准确性。"标准": "正确性",它定义了评估应该衡量什么——在这里,是响应的准确性。

      • "normalize_by"10,这调整分数到 0 到 10 的刻度,使其更容易解释结果。

    • 准备数据:format_evaluator_inputs是一个函数,它以评估者可以有效地处理的方式格式化输入、预测和参考。准备数据format_evaluator_inputs是一个函数,它以评估者可以有效地处理的方式格式化输入、预测和参考。

  8. 使用配置的评估者运行评估:

    评估者配置完成后,下一步是执行评估。这涉及到在数据集上运行预测函数,并使用评估者评估每个响应。

    注意我们使用的是evaluate()而不是run_on_dataset(),后者正在被弃用但仍然会返回评估结果:

    results = evaluate(
        predict,
        data=dataset_name,
        experiment_prefix="Chat Single Turn",
        evaluators=[correctness_evaluator],
        metadata={"model": "gpt-3.5-turbo"},
    )
    

    让我们来看看evaluate()调用中的不同元素:

    • 预测:预测函数(predict)是聊天机器人用来从输入生成答案的。

    • 数据:指定用于评估的哪个数据集。这个数据集包含问题和正确答案。

    • 实验前缀:这个字符串有助于对系统内的评估结果进行分类和识别。

    • 评估者:列表包括在之前步骤中设置的LangChainStringEvaluator评估者。您也可以创建自己的自定义评估者并将其包含在这里;您可以使用多个评估者。

    • 元数据:包含有关所使用模型版本的信息,便于进一步分析和追溯。

请记住,LangSmith 还会创建在您从 UI 中选择创建实验时运行的评估代码。这也提供了不同预构建评估链的示例,允许您评估以下内容:

  • 正确性

  • 简洁性

  • 相关性

  • 一致性

  • 损害性

  • 恶意

  • 有用性

  • 争议性

  • 仇视女性

  • 犯罪性

  • 无感觉

在撰写本文时,代码示例使用run_on_dataset(),但将其迁移到evaluate()应该是相当直接的。当您运行evaluate()时,这应该在 LangSmith 中创建一个实验,您应该看到以下输出:

在以下位置查看实验“Chat Single Turn-46c45783”的评估结果:

https://smith.langchain.com/...

该链接应带您进入 LangSmith 中的实验链接,您可以在以下屏幕截图中看到每个实验的详细信息:

图 9.2 – 在 LangSmith 实验视图中显示的评估输出

图 9.2 – 在 LangSmith 实验视图中显示的评估输出

点击成功失败按钮将显示数据集中每个输入和输出的测试详情。从此视图,您还可以深入了解每次运行,查看发生了什么,以及通过其他信息,如每次运行的令牌成本。评估的令牌成本可能会根据您的数据集大小迅速上升。

让我们尝试测试我们用来阻止 LLM 使用其他数据并反馈给用户(如果它无法回答)的提示。在 LangSmith 中向您的数据集中添加另一个问题-答案对,但这次,让我们添加一个它不应该能够回答的问题。在我的例子中,这是关于训练师的一些具体信息,我知道我的知识库中没有提到:

Input: {"question": "Do I have to use carbon inserts in my trainers"}

输出:{"answer": "提供的文档中不包含关于在超长跑训练师中使用碳插片的信息。"}

当我重新运行评估时,我们可以看到测试通过,我们的代理正在按预期响应。您可以在以下屏幕截图中看到输出:

图 9.3 – 在 LangSmith 中显示的评估输出,测试了幻觉

图 9.3 – 在 LangSmith 中显示的评估输出,测试了幻觉

尝试查看其他类型的现成评估器,看看您是否可以评估其他标准。

评估不同由 LLM 驱动的系统没有一种通用的方法。不同类型的对话式 AI 代理将需要不同类型的评估方法和不同的数据集。在 LangSmith 网站上查找不同类型代理测试的示例。

任何评估系统的目标都是提供一个健壮的框架来评估您的代理。LangSmith 使运行评估和提供关于单个和集成组件性能的详细洞察变得容易。使用 LangSmith,您可以更好地为 ChatGPT 应用的生产环境需求做好准备,确保它提供高质量、可靠的响应。

记住 – 成功开发 AI 的关键是持续测试和改进。评估不是一次性的任务,而是开发周期中的常规部分。在下一节中,我们将考虑应用监控。

使用 LangSmith 在生产中的应用监控

监控任何基于 LLM 的应用程序都很困难,直到 LangSmith 的发布,很难全面了解 LangChain 应用程序底层的运行情况。对应用程序的详细监控对于保持运行顺畅至关重要,LangSmith 提供了许多功能来实现这一点。

LangSmith 的高级监控功能

LangSmith 的监控系统通过允许开发者配置和管理跟踪,使生产应用程序的监督变得有效。该系统的关键特性是针对优化生产过程中数据的收集和使用而定制。

跟踪和数据管理

LangSmith 的跟踪和管理能力通过采样提供选择性数据点记录,通过元数据改进数据组织,并通过反馈集成提供关键见解:

  • 采样:在生产中至关重要,此功能允许仅记录数据点的子集,以有效地管理数量和相关性

  • 元数据:将元数据附加到运行中增强了过滤和分组数据的能力,从而促进了更有针对性的分析

  • 反馈:整合用户反馈有助于突出显示重要的数据点,将注意力集中在最需要的地方

监控工具

LangSmith 提供了一套全面的监控工具,旨在帮助您监控应用程序。以下是关键功能:

  • 过滤功能:用户可以使用高级过滤选项深入了解特定的运行,这些选项包括按名称、元数据、反馈和全文搜索进行过滤。

  • 监控图表项目仪表板上的监控选项卡提供了各种指标的视觉表示,例如跟踪延迟每秒令牌数成本。这些图表支持时间序列分析,并可以深入到特定数据点以进行详细的跟踪表,有助于调试。

  • 元数据分组:这允许在同一图表中并排比较不同的应用程序版本,这对于 A/B 测试变化特别有用。

高级监控功能

LangSmith 提供其他高级功能,帮助您理解复杂的对话并自动化一些任务。

  • 线程:对于跟踪是同一对话一部分的应用程序,LangSmith 通过元数据键提供线程化,以便方便地分组相关跟踪。

  • 自动化:为了减少人工监督,LangSmith 的自动化可以配置为处理重复性任务。设置过滤器后,开发者可以自动化将数据发送到数据集、注释队列或进行在线评估等操作。

在 LangChain 领域,缺乏一个功能齐全的监控工具,LangSmith 填补了这一空白。

它作为确保你的 LLM 应用程序稳健性能的必备工具而脱颖而出。通过提供详细的指标和实时数据可视化,LangSmith 应该允许你保持高性能、可靠性和用户满意度的标准,在你的对话式 AI 解决方案中。

ChatGPT 和 LangChain 的替代方案

自 ChatGPT 早期以来,不仅 LLM 技术取得了巨大进步,服务提供的选择和可用性也得到了提升。在本节中,我们将探讨出现的各种服务提供,探索 ChatGPT 和 LangChain 之外的可行替代方案。

ChatGPT 和 OpenAI LLMs 的替代方案

去年年初,你可能会争辩说 OpenAI 的 生成预训练变换器GPT)LLM 是一场独角戏,很可能是你构建一个由 LLM 驱动的项目的首选。如今,许多公司都在争夺发布最佳模型,导致可供选择的 LLM 数量不断增加,无论是开源的还是封闭的,都可以用来创建一个对话式 AI 系统。LLM 的军备竞赛仍在继续;让我们看看一些例子,值得注意的是这并不是一个详尽的列表:

  • Meta: Meta 提供了流行的 LLM 模型系列 Llama。最新的模型,具有 8B 和 70B 参数的 Llama 3 模型,在与其他 LLM 的测试中表现出色,并且以几种方式提供。

  • Anthropic: Anthropic 以其专注于构建可靠和可解释的 AI 模型而闻名。他们的主要模型,Claude,旨在增强安全性和可控性,旨在减少有害或误导性的输出。Anthropic 强调道德 AI 发展,利用如 人类反馈强化学习RLHF)等技术来微调模型响应,确保它们与人类价值观和安全期望紧密一致。

  • AI21: AI21 提供了访问 Jurassic-2 和 Jamba 变换器模型。Jurassic-1 是 AI21 Labs 的旗舰模型系列。Jurassic-1 有多种尺寸,从小型模型适合成本效益应用到大型模型可以生成更复杂和细微的文本。这些模型旨在执行广泛的任务,从回答问题和总结文本到生成内容和代码。

  • Google: Google 从不放过提醒我们他们发明了变换器架构,并创建了强大的模型,如 PaLM 2 和最近推出的 Gemini 系列。特别是最新的 Gemini 1.5,以其 100 万个标记的巨大上下文窗口和据说更好的性能而推动了边界。1.5 系列也有三种尺寸:Ultra、Pro 和 Nano。Google 还将 Bard 重命名为 Gemini。到目前为止,我所看到的 Gemini 性能与 GPT-4 模型相当。

  • Cohere:Cohere 专注于自然语言理解和生成。Cohere:Cohere 专注于 NLU 和 自然语言生成(NLG)。他们的模型旨在各种应用中,如内容生成、摘要和语义搜索。Cohere 的模型以其用户友好的 API 和强大的安全功能而闻名,适用于数据隐私和应用程序完整性至关重要的企业环境。

  • MistralAI:MistralAI 将自己定位为专注于企业的 LLM,具有保护隐私的基础设施。他们提供开源模型:Mistral 7B、Mixtral 8x7B 和 Mixtral 8x22B,这些模型是可定制的。它们可以在 Mistral 平台上下载或按需使用。该公司还提供大型和小型优化的商业模型。

  • Cerebras:Cerebras 发布了一系列 7 个 GPT 模型,参数量从 11 亿到 130 亿不等。他们声称这是训练速度最快、成本最低的一些模型。Cerebras 还提供云基础设施用于模型训练和 Cerebras AI Model Studio,这是一个专门用于训练和微调 LLMs 的平台。

测试这些模型的一种很好的方法是使用 Hugging Face Chat,在这里你可以从流行的 LLMs 中选择来回答你的问题。你会发现,除非被提示做其他事情,否则所有 LLMs 的回答都有一种细微的风格。这个观察是从我与 VUX World 的杰出人物凯恩·西蒙斯(Kane Simms)的对话中得出的。

有证据表明,LLMs 之间的差距正在缩小。最近的表现比较表明,不同 LLMs 之间的差距正在缩小。像 Claude 3、GPT-4 和 Gemini Ultra 这样的模型在多项选择题和推理等任务中取得了相似的成绩。有趣的是,一些较小的模型,如 Mixtral 和 Llama2,在某些领域(例如推理)的表现优于较大的模型,这表明并非总是最大的模型才是最好的。

我们在这本书中大量使用了 LangChain。让我们在下一节看看 LangChain 的替代方案。

LangChain 的替代方案

我非常喜欢 LangChain,现在它已经完全由 LangSmith 支持,用于在生产环境中监控和运行你的应用程序,它是一个稳固的平台。然而,LangChain 并不是适合每个人,在做出决定之前有很多定义因素。还有很多其他选择。你可以用代码构建自己的应用程序,并直接与 LLM API 交互,同时仍然使用 LangSmith 进行监控。你也可以使用像 企业级生成式 AI 大型语言模型(GALE)这样的东西:Kore.ai 的新生产力套件,这是一个无代码解决方案,用于使用最新的 LLM 模型。

或者,还有像 LlamaIndex 这样的选择。LlamaIndex 是一个针对在 LLMs 上构建的应用程序进行优化的综合数据框架。

它支持大量数据格式,如 API、PDF、文档和 SQL 数据库,允许你摄取、组织和结构化你的数据。该平台提供高级检索界面和创建提示链的能力,以创建 LLM 应用程序和评估能力,允许你创建高级 RAG 系统。

LlamaIndex,凭借其支持的 Python 和 TypeScript SDKs 以及一个充满活力的社区提供的丰富资源,如连接器、工具和数据集,是 LLM 领域中新兴创新解决方案的例证。这种针对 LLM 特定服务的增长标志着人工智能领域的一个重大趋势,我们将在下一节中进一步探讨。

观察不断发展的 LLM 领域

自从去年 ChatGPT 发布以来,LLMs 的世界发生了巨大的变化,了解这一点对于你为 ChatGPT 或 LLM 项目做出的任何技术决策都至关重要。

访问 LLMs 的方式越来越多,这可以主要分为以下图表中展示的四种方法:

图 9.4 – 与 LLMs 交互的不同方式

图 9.4 – 与 LLMs 交互的不同方式

让我们来看看访问和利用 LLMs 的四种不同方式的优缺点:

  • 开源原始 LLMs:对于那些具有技术专长的人来说,在自己的基础设施上使用开源模型提供了一种可定制的解决方案,以及微调自己专业模型的手段,尽管这可能带来更高的前期技术挑战和巨大的基础设施成本。此外,还有越来越多的开源工具来运行这些模型;例如,llama.cpp库。尽管这些工具免费使用,但托管和运营这些模型的相关成本可能相当高,需要专业知识。随着使用量的增加,这些费用和持续维护的需求往往会增加。

  • LLM 编排:提供专业云基础设施以托管和训练模型,同时提供一种简单的方式来编排和公开这些模型以供使用,以及针对特定领域专业知识和用例微调这些模型的方法。大多数云服务提供商CSP),如 Google Cloud、Amazon Web ServicesAWS)和 Microsoft Azure,提供基础设施即服务IaaS)以托管你的模型。这可能很昂贵,但提供了在不承担基础设施成本的情况下利用开源 LLMs 的能力。还有一些有前景的平台,例如 Quiq,允许你创建由 LLM 驱动的端到端对话助手。

  • 通过 API 的 LLM:这是组织将 LLM 功能集成到其应用程序中最常用的方法。API 为使用 LLM 开发应用程序提供了一条直接的路径。然而,使用这些 API 也带来了一些挑战,例如成本影响、对数据隐私的担忧、推理延迟问题、速率限制、灾难性遗忘的风险以及模型漂移。

  • LLM 用户界面:无需过多介绍,ChatGPT、HuggingChat、Cohere Coral 和 Gemini 等界面直接为用户提供对话体验,并已成为许多人日常生活的一部分。这些界面旨在提供与 LLM 互动的最高效和用户友好的方式。它们通常还使包括其他来源的上下文信息和通过管理历史对话和利用外部工具进行聊天个性化变得容易。

与 LLM 互动的这些方法提供了不同的优势,并带来了不同的挑战,这使得选择取决于您的用例、定制要求、技术专长、资源可用性和预算限制。最后,在下一节中,我们将简要考虑一种越来越受欢迎的新型模型:SLM。

小型语言模型(SLM)的增长

当考虑围绕 LLM 技术的复杂性以及最新和最伟大的 LLM 的巨大收益放缓时,介绍 SLM(小型语言模型)是值得的。SLM 正在挑战“越大越好”和“大小不一定是一切”的观念(请原谅这个双关语)。模型大小可能不是性能的唯一决定因素,而架构、训练数据和微调技术等因素也起着重要作用。

LLM 是否已经达到了它们的极限?

当性能水平趋于稳定时,这不禁让人质疑:LLM 是否已经达到了它们的极限?当 ChatGPT 首次发布时,我们都对它广博的知识感到震惊,但随后的迭代并没有带来革命性的变化。在训练数据方面,随着新版本的 GPT 使用更新的训练数据,已经取得了一些改进,但现实中,除非模型定期训练,否则 LLM 数据始终会存在局限性,这似乎不太可能。

尽管 LLM 具有令人印象深刻的性能,但它们也伴随着显著的缺点,我在本书中已经进行了概述。这里简要回顾一下。它们需要大量的数据和参数进行训练,导致高计算能力和能源消耗。这导致了高昂的成本,使得小型组织和个人的核心 LLM 开发难以触及。此外,LLM 由于涉及的工具和技术复杂,以及从训练到部署的漫长周期,可能会减缓实验和创新工作。

其他挑战包括训练数据中的偏差以及幻觉问题、缓慢的推理性能、高令牌成本,以及如果您打算消费和从敏感数据中推断,严重的安全影响。将 LLMs 比喻为砸坚果的锤子,突显了广泛的互联网知识对于许多对话式 AI 用例可能并非必要。这引发了以下问题:对于有效的对话式 AI 项目,哪些品质真正重要,SLM 是否能够满足这些要求,甚至提供比 LLMs 更多的优势?

输入 SLMs

从本质上讲,SLM 是更大 AI 模型的紧凑版本,旨在理解、解释和生成人类语言。SLMs 提供了 LLMs 的简化替代方案。由于参数较少和设计更简单,它们需要更少的数据、训练时间和计算能力——通常只需几分钟或几个小时。这使得 SLMs 更有效率,并且更容易在现场或小型设备上实施,以及针对特定用例进行微调的小型数据集。

SLMs 与 LLMs 的比较——关键差异

要更清楚地了解 SLMs,直接将它们与 LLMs 进行比较很有帮助:

  • 规模和范围:SLMs 被设计成紧凑和高效,使其适合特定领域和任务。它们在较小的数据集上进行训练,允许更快的训练和推理时间以及针对性的知识。另一方面,LLMs 更大、更全面,在广泛和多样化的数据源上进行训练。LLMs 捕获广泛的语言模式,擅长生成关于几乎所有主题的高度连贯和上下文相关的文本。

  • 训练时间和计算资源:由于规模较大,LLMs 需要更多的计算资源和更长的训练时间。SLMs 由于其较小的尺寸和更简单的架构,在资源有限或需要快速部署的情况下更为实用。

  • 领域专业知识:虽然这两个模型都可以针对特定领域进行微调,但由于 SLMs 尺寸较小且推理时间更快,它们通常在需要特定领域专业知识的情况下效率更高。SLMs 还可以在更小的数据集上进行训练。一个训练良好的特定领域 SLM 与在上下文级别提供领域知识的 LLM 相比,可能表现足够好。

  • 多功能性和成本:这取决于具体的应用场景,但 LLMs 由于其更广泛的知识库,在内容生成、翻译和理解复杂查询方面表现出色。然而,经过适当微调的 SLMs 可以在计算成本的一小部分内实现特定对话任务的相当性能。SLM 不需要理解每个主题。SLMs 可以被训练在与特定领域的特定知识的基础上与客户互动,提供定制解决方案并改善用户体验。这可以通过使用专业训练数据微调 SLMs 来实现,并且可能更加直接。此外,微调 SLMs 需要很少的资源。具体的硬件要求以及相关的成本取决于模型大小、复杂性和数据集需求,但这些可能要少得多。

SLMs 的优点

SLMs 的一个关键好处是它们适合特定应用。它们的专注范围和减少的数据需求使它们非常适合微调特定领域或任务。这种定制化使公司能够创建满足其特定需求的 SLMs,例如情感分析、命名实体识别(NER)或特定领域的问答。

SLMs 还提供了增强的隐私和安全。它们较小的代码库和简单的架构使它们更容易审计,不太可能包含漏洞。这对于医疗保健和金融等行业处理敏感数据来说特别有吸引力。SLMs 降低的计算需求还使本地处理成为可能,从而进一步提高了数据安全性。

SLMs 在其特定领域内不太容易出现幻觉。它们在目标数据集上的训练有助于它们学习相关的模式、词汇和信息,从而降低产生不相关或不一致输出的可能性。由于参数较少,SLMs 也不太可能捕捉和放大训练数据中的噪声或错误。

SLMs 的缺点

尽管 SLMs 具有许多优点,但它们也面临一些缺点,并且在某些情况下观察到性能下降。一个关键限制是它们对上下文理解的减少以及与较大模型相比的知识库整体上不够全面。这使得 SLMs 在需要深入理解或广泛上下文意识复杂任务时不太有效。此外,由于 SLMs 规模较小且训练数据集专注,它们可能在生成连贯流畅的文本方面遇到困难。例如,参数较少的模型通常在保持较长文本的连贯性或更复杂交互中表现出局限性。这可能会限制它们在需要高质量响应并就技术或复杂领域进行对话的应用中的效用。

SLMs 的一些例子

Phi-3 是微软最新推出的轻量级 Mini 3B 和 14B 中型最先进开放模型系列,在基准测试中取得了令人印象深刻的性能结果。谷歌的 Gemma 是一系列为效率和用户友好性设计的 SLMs。与其他 SLMs 一样,Gemma 模型可以在日常设备上运行,无需专用硬件。Cerule 是一款强大的图像和语言模型,它将 Gemma 2B 与谷歌的Sigmoid 损失函数用于语言-图像预训练SigLIP)相结合,利用高效的数据选择技术。这使得 Cerule 非常适合边缘计算用例。另一个例子是 Llama 2 7B 和现在的 Llama 3 8B,它们不需要大量的硬件要求,还有 Stable Beluga 和 Hugging Face 的 Zephyr。许多这些模型可在 Hugging Face 和 LLM API 提供商的平台以及谷歌 Vertex AI 等云服务上找到。这些模型都是针对对话用例进行训练的。尝试这些模型的一个好方法是使用 Ollama,这是一个在本地机器上运行模型的轻量级框架。

SLMs 的变革潜力

SLMs 有潜力使 AI 访问民主化并推动创新。它们更快的开发周期和改进的效率使得成本效益高、目标明确的解决方案成为可能。在边缘部署 SLMs 为金融、娱乐、汽车、教育、电子商务和医疗保健等领域的实时、个性化、安全应用打开了可能性。

使用 SLMs 进行边缘计算通过本地处理数据,提高了响应时间、数据隐私和用户体验,这是一个吸引人的解决方案,并且可以纠正企业希望在更敏感领域采用 LLMs 时的许多缺点。这种去中心化的 AI 方法有可能改变企业和消费者与 LLM 技术互动的方式。

通过将 SLMs(小型语言模型)暴露于专门的训练数据并对它们的能力进行微调,它们可以在训练一个 LLM(大型语言模型)成本的一小部分内,为对话用例生成准确和相关的输出。它们通常能够提供与 LLM 相似的对话能力并取得很好的结果。如果你在考虑使用 LLM 技术但担心其缺点,考虑一个 SLM 模型可能是一个明智的选择。

然而,也存在局限性:尽管 SLMs 提供了显著的好处,尤其是在效率和成本方面,但它们的适用性有时会根据计划的使用案例而受到限制。

尽管存在任何缺点,它们都提出了一个有力的论点。随着特定模型平台即服务PaaSs)和模型训练平台的日益可用,探索和测试 SLMs 的能力变得越来越方便,因此投入时间和精力去研究它们是非常值得的。

接下来该怎么做

在这本书中,我们一直专注于利用 ChatGPT 和 LLM 作为工具和技术来创造引人入胜的对话体验。自从我们开始这段旅程以来,LLM 的领域经历了巨大的变革,这得益于 LLM 技术的持续进步。尽管 ChatGPT 在发布时是一项突破性的创新,但现在它只是更大、更灵活的 LLM 生态系统中的一个组成部分。

我在对话式人工智能领域工作了多年,早在 ChatGPT 之前,就有幸参与并投入生产了许多基于 NLU 的应用。这让我对对话式人工智能的挑战有了深刻的理解,包括 LLM 需要做什么来克服这些挑战,以及它们是否能够做到。目前有数千个由 NLU 驱动的对话式人工智能应用正在运行,其中许多你可以认为可以被 ChatGPT 应用所取代。或者至少它们的一些元素可以被取代,这通常取决于现有平台的底层技术和供应商构建利用 LLM 技术以及传统基于意图的系统能力的速度和效率。

和所有人一样,我对 ChatGPT 的发布和这项技术的无限可能性感到惊讶。然而,我一直试图对技术的采用、其局限性和风险保持现实态度。当然,这都取决于用例。如果你想深入讨论自己的数据,那么 RAG 系统在对话式人工智能领域是一个巨大的进步,但在交易性角色中,适度的克制是明智的。

我个人认为,未来的最大转变在于为更复杂的使用案例构建交易性 LLM 驱动应用的可行性。使用如 LangChain 等框架创建这些应用已经成为一个更加现实的目标,但仍然不是一件简单的事情。随着专门用于测试和监控 LLM 行为的支持工具(如 LangSmith)的出现,部署交易型机器人的风险得到了缓解。这为考虑用 LLM 的灵活性和适应性来取代传统的基于意图的系统打开了大门。

LLM 的未来在于多模型方法。我们可以在 LLM 管道内利用适合特定任务的模型。想象一下,一个特定的 LLM 在 LangChain 应用中充当代理执行者,利用其他专业模型的优势来完成特定任务。此外,LLM 推理能力的进步也提供了令人兴奋的潜力。

然而,在规划 LLM 应用时,模型选择仍然是一个复杂的决策。使用案例、底层数据、领域类型、成本、安全考虑和可维护性等因素在规划生产时都起着至关重要的作用。这些因素突出了探索 ChatGPT 之外替代方案的重要性。SLMs 为特定场景提供了一个引人入胜的选择,尤其是在拥有大量对话日志和历史使用数据的长期对话 AI 系统中,这些数据可以用于微调。

LangChain 生态系统仍然是构建 LLM 驱动应用的强大平台。随着针对几乎任何需求的集成和工具,我们只是触及了其潜力的表面。你可以利用不断增长的向量存储和服务,以及像 Tavily Search 这样的专用工具,来增强我们 LLM 应用的能力。有许多 LangChain 模板的例子,我建议这些是查看更复杂对话用例的好地方。

在将大型语言模型(LLM)投入生产时,承认其中涉及的风险同样重要。它们具有随机性,即输出中的内在随机性,可能导致不可靠的结果。这需要谨慎规划和稳健的测试方法,尤其是在关键应用中。

OpenAI 继续以其 GPT 模型推动边界。我们已经见证了从 GPT-3.5 到 GPT-4 及其 Turbo 迭代的演变,后者针对基于聊天应用进行了优化。最新的 GPT-4o 于 2024 年 5 月发布,通过将特定模态的模型整合到一个新模型中,集成了多模态能力。结果是,它能够以类似人类的响应速度处理文本、音频、图像和视频输入,实现完全的多模态对话交互。以前,GPTs 在语音交互中平均存在 3-6 秒的延迟问题。

当 OpenAI 继续增强其模型,赋予其令人叹为观止的能力——多模态、多语言、扩展的上下文窗口、提高的准确性和改进的 LLM 推理能力时,他们也明智地保持了 API GPT-4o 的成本,并将其包含在 ChatGPT 的免费版本中,使这项技术对更广泛的受众变得可访问。尽管 OpenAI 继续通过多模态、多语言、扩展的上下文窗口、提高的准确性和改进的 LLM 推理能力等令人叹为观止的能力来增强其模型,但他们也明智地保持了 API GPT-4o 的成本,并将其包含在 ChatGPT 的免费版本中,使这项技术对更广泛的受众变得可访问。

我们最初所了解的景象已经发生了巨大的变化,这反映了 LLM 技术的快速演变。LLM 生态系统持续繁荣,为开发者提供了越来越多的模型以及简化了构建和利用这些能力的工具。随着技术的持续发展,构建变革性的对话体验的可能性也将随之增加。拥抱实验,探索不断扩大的 LLM 生态系统,并保持在这次激动人心的革命的前沿。

摘要

在本章中,我们探讨了将 ChatGPT 驱动的系统从 POC 过渡到完全运营的生产环境所关联的关键考虑因素和挑战,突出了部署 LLM 驱动的应用,尤其是 RAG 系统所涉及的显著责任和风险。到现在,你应该已经理解了稳健的安全措施对于防止不适当回应和确保可靠性的重要性。我们回顾了一个由于内容监管不力和系统控制不足而导致聊天机器人故障的事件,强调了适当的安全措施的需求。

本章的大部分内容都致力于讨论 RAG 系统在生产过程中面临的具体挑战。我们还探讨了评估 LLM 应用的全面策略,强调了对广泛标准的持续验证的必要性,以确保系统的有效性和可靠性。我希望能通过介绍一个评估示例,你现在对 LangSmith 这类工具的重要性有了坚实的理解,并具备了构建稳健评估的良好知识基础。评估和监控工具为管理、测试和改进 LLM 应用提供了一种结构化的方法,它们需要在你的 ChatGPT 项目中扮演重要的角色。

为了提供一个平衡的视角,在本章中,我们获得了一些关于替代 LLM 服务提供和模型的见解,包括 LangChain 和 ChatGPT 的替代方案,反思了对话 AI 技术快速演变的格局。这个格局已经发生了相当大的变化,你可能会希望掌握根据特定用例和运营需求选择正确模型的重要性。我们还探讨了 SLMs 作为传统大型 LLM 的更易于管理和专业化的替代方案的可能性。

最后,我们探讨了下一步该怎么做,这取决于你和你所在的组织在 LLM 旅程中的位置,无论是继续实施 LLM 功能,将你的对话 AI 项目过渡到生产环境,还是开始绿色领域的 LLM 应用。

我们在这里涵盖了大量的内容,但希望这能帮助你克服挑战,提出关键问题,以便你能够成功利用 LLM 技术向前发展。

进一步阅读

以下链接是本章中精选的资源列表,以帮助读者:

索引

由于本电子书版本没有固定的页码,以下页码仅为参考,基于本书的印刷版。

A

活跃对话

对话式缓冲内存 133

对话式缓冲窗口内存 133

高级监控功能,LangChain

自动化 204

线程 203

代理 125

工具,使用 129,130

AI21 204

亚马逊网络服务(AWS) 207

Anthropic 204

应用程序,ChatGPT 23

商业和金融 23,24

教育和培训 25

医疗保健和医疗 24

法律和法律服务 25

应用程序,对话式人工智能 11

银行和保险 12

客户服务 11

教育 12

医疗保健 12

人力资源 13

语言翻译 12

零售 12

近似最近邻(ANN) 156

自动助手 5

B

基础大型语言模型 15

双向编码器表示(BERT) 35

商业和金融应用程序,ChatGPT

客户服务聊天机器人 23

财务报告 23

欺诈检测 23

投资管理 23

市场分析和预测 23

风险管理 23

字节对编码(BPE) 17

C

回调 123

功能,ChatGPT 19

代码生成和软件开发辅助 20, 21

内容生成 20

文档组织 20

机器翻译,跨语言 20

NLU 和 NLG,用于聊天机器人和虚拟助手 19

个性化语言学习 20

插件 21, 22

情感分析 20

垃圾邮件过滤 20

文档摘要 20

主题分类 20

教学工具 20

Cerebras 205

聊天机器人 5

进化 10

ChatGPT 3, 14

应用 23-26

认证 63

可用模型 64

功能 19-22

免费版 54

超参数 65

局限性 26, 27

消息 64

其他库 72

Plus 版 54

风险和安全 28, 29

智能的 22

ChatGPT API 63

电话 65, 66

ChatGPT 社区 58

ChatGPT 界面 54, 55

聊天视图 56

定制指令 56, 57

侧边栏 55, 56

ChatGPT 实际应用,在对话设计 34

对话,与 ChatGPT 写作 40

实体生成 39, 40

意图聚类 34, 35

话语,创建 38, 39

ChatGPT 项目

范围 168

ChatModel 99, 100

聊天提示模板 102

Chroma 157

分块

固定大小分块 151

有效 LLM 交互 150, 151

递归分块 152

基于句子的分块 152

云服务提供商 (CSPs) 207

认知行为疗法 (CBT) 12

Cohere 205

组件,评估系统 194

数据集 194

数据集和示例 194

评估者 195

输入 194

输出 194

任务 195

组件,LangChain

LLM 模型 99

输出解析器 99, 104, 105

提示模板 99, 101

内容

预处理 150

对话式 AI 3, 4, 7

应用 11-14

作为训练工具 13

发展 10

特征 9

历史 4, 5

对话式 AI 聊天机器人 7

特征 7, 8

交互示例 8, 9

对话缓冲内存 133

对话缓冲窗口内存 133

对话设计 31

ChatGPT 实用应用 34

对话,设计 32

写作 34

对话设计 33

实体澄清 33

意图澄清 33

角色设计 32

用户需求 32

话语创建 33

对话设计师 32

对话设计,使用 ChatGPT 进行测试 48

聊天机器人,迭代 50

对话模拟 48

失败和边缘情况,测试 49

特定测试脚本,创建 49

对话模拟 46

样本对话 46

样本对话,创建 46, 47

样本对话,使用角色创建 47

余弦相似度 156

创建、读取、更新、删除 (CRUD) 155

客户关系管理 (CRM) 系统 8

定制指令 56, 57

设置 57

定制提示模板 103

定制天气工具

创建 130, 131

D

数据集 194

调试 122

辩证行为疗法 (DBT) 12

对话写作,使用 ChatGPT 40

挑战 40, 41

对话,编辑 41

重写,以提高可读性 41, 42

字典 115

文档加载器

选择 158, 159

点积 156

E

教育和培训,ChatGPT

个性化学习 25

教师支持 25

考试准备 26

高效的 LLM 交互

为 150-152 进行分块

嵌入模型 153

嵌入 152

创建,使用 OpenAI 模型 154

生成 150

句子嵌入 153

存储和搜索,使用向量存储 155

词嵌入 152, 153

欧几里得距离 156

评估系统

组件 194

评估者 195

启发式评估者 195

人 195

LLM-as-judge 195

可扩展标记语言 (XML) 80

F

Facebook AI 相似性搜索 (FAISS) 157

功能,对话式人工智能聊天机器人

模糊处理 7

环境理解 7

对话管理 8

实体识别 7

与外部系统的集成 8

意图识别 7

多语言能力 8

语义理解 7

情感分析 8

插槽填充 7

功能,对话式人工智能系统 9

固定大小分块 151

常见问题解答 (FAQs) 110

功能 126

G

一般数据保护条例 (GDPR) 29

生成式人工智能 (GenAI) 13

企业生成式人工智能大型语言模型 (GALE) 205

生成式预训练变换器 (GPT) 58, 204

Google 204

GPT-3 3, 18

GPT-3.5 18

GPT-4 3, 18, 88

GPT 商店 58

H

医疗和医疗应用,ChatGPT

患者分诊聊天机器人 24

医疗诊断和治疗建议 24

医学教育 24

心理健康咨询 24

患者参与度和依从性 24

历史记忆 133

过去对话 133

过去对话摘要 133

假日助手用例 168

代理,用于创建复杂交互 174

代理工具,创建 175

块,创建 171, 172

数据源,选择 170

Ellie,功能 169

Ellie,对话范围 169, 170

Ellie,个性 168

嵌入,创建 173

酒店数据,清理 171

酒店数据,标准化 171

酒店数据,准备 171

位置信息 179

定制酒店推荐 175-178

天气信息 178

超文本标记语言 (HTML) 80

I

基础设施即服务 (IaaS) 207

内存存储 140, 141

指令优化的 LLM 15

知识产权 (IP) 28

意图聚类 35

聚类分析 35

聚类算法 35

数据收集 35

嵌入生成 35

流程 35

使用 35

与 ChatGPT 34

意图簇

创建,与 ChatGPT 35, 36

示例 36

交互式语音响应 (IVR) 系统 5

人际心理治疗 (IPT) 12

J

JavaScript 对象表示法 (JSON) 80

L

LangChain 98, 160, 165

高级监控功能 203

代理 124

替代方案 205, 206

ChatModel 99, 100

组件 99

调试 122

库 98, 99

LLMs 99

监控 122

监控工具 203

独出心裁的工具示例 128

即插即用工具 128

RAG 元素,汇集 162-165

工具 125

跟踪和管理功能 203

LangChain 链 108

基本链示例 108, 109

链,路由以有效回答问题 116-119

并行链,用于高效的多源信息收集 113-115

顺序链,用于调查对话数据 109-113

LangChain 聊天机器人,与 Streamlit 179

代理服务,创建 180, 181

配置管理 180

Ellie,改进方法 186

Ellie,运行和测试 184-186

机密信息,创建 180

Streamlit 聊天应用,构建 182, 183

LangChain 表达式语言 (LCEL) 105, 196

示例 107

功能 106

关键差异和优势 107, 108

可运行协议 106, 107

语法 107

LangChain 内存 132

应用 133

挑战 134

示例 138, 139

历史记忆 133

在活跃对话中 133

内存存储 140, 141

持久化内存 141-143

个性化内存 133

使用技巧 134-137

LangSmith 124, 165, 194

应用监控,在生产环境中 202

设置 124

使用,用于评估项目 195-202

语言模型 (LM) 15, 17

比较 18

大型语言模型 (LLMs) 3, 10, 14, 17, 31, 76, 148, 206, 207

与小型语言模型 (SLMs) 相比 208, 209

法律和法律服务,ChatGPT

合同审查 25

文档起草 25

尽职调查和电子发现 25

法律建议聊天机器人 25

局限性,ChatGPT 26

准确性和深度 26

上下文限制 27

幻觉和准确性 27

LlamaIndex 206

Llama 模型家族 204

LLM 模型 99

LLM 编排 207

LLMs,在生产中

问题 190

通过 API 使用 LLMs 207

LLM 用户界面 207

M

机器学习 (ML) 5

可管理的块

创建,使用文本拆分 160, 161

麻省理工学院 (MIT) 4

处理内存限制,ChatGPT 87

GPT-4 模型,使用 88

重置机制 88

策略,用于管理内存问题 87, 88

Meta 204

MistralAI 205

监控工具,LangChain

过滤功能 203

元数据分组 203

监控图表 203

N

命名实体识别 (NER) 209

自然语言生成 (NLG) 19, 205

自然语言 (NL) 4

自然语言处理 (NLP) 5

自然语言理解 (NLU) 4, 110, 191

O

OpenAI

定价 61

OpenAI 模型

嵌入,创建 154

OpenAI Node.js 库 68, 70

OpenAI Playground 58

令牌使用,跟踪 62, 63

UI 功能 59

OpenAI Python 库 66-68

错误,处理 70, 71

请求和响应结构 71

重试 71

超时 72

OpenAI 工具 126

示例 126-128

开源原始 LLMs 206

输出解析器 99

使用 104, 105

P

过去对话 133

过去对话摘要 133

持久化内存 141-143

角色创建,使用 ChatGPT 42

聊天机器人角色,创建 45

用户角色,创建 44, 45

用户研究,执行 43, 44

个性化记忆 133

Pinecone 157

平台即服务 (PaaSs) 210

生产系统

评估 193

提示,核心组件

受众 77, 79

上下文 77, 78

输入数据 77, 80, 81

指令 77, 78

输出数据 77, 81, 82

角色 77, 79

范围 77, 78

提示工程 76

清晰的设计和目标,定义 83

后续提示,用于测试多个示例 86,87

迭代开发示例 84,85

迭代提示开发,采用 84

从简单开始 85,86

温度,使用 87

与之合作 83

提示工程技巧 88

少样本学习,用于客户支持聊天机器人 89,90

创建聊天机器人提示,由 ChatGPT 92 提供支持

提示总结数据,用于对话代理 90-92

提示模板 99,101

聊天提示模板 102

自定义模板 103

概念验证(POC) 170,191

R

RAG 数据源

定义 149

RAG 示例,使用 LangChain 158

文档加载器,选择 158,159

可管理的块,通过文本拆分创建 160,161

文本嵌入,创建和存储 161,162

RAG 系统

挑战 191

短处 191-193

步骤,用于创建 148

递归分块 152

从人类反馈中进行强化学习(RLHF) 204

强化学习(RL) 15

重置机制 88

上下文缓存 88

硬重置 88

软重置 88

检索增强生成评估(RAGAs) 193

检索增强生成(RAG) 141,147,148

风险和安全,ChatGPT 28

偏差 29

教育担忧 28

恶意使用 29

隐私问题 28, 29

财产权 28

安全性 28

从人类反馈中学习(RLHF)15, 16

挑战 16, 17

基于规则的聊天机器人 6

运行 124

可运行协议 106, 107

S

样例对话 46

创建 46, 47

创建,使用角色 47

基于句子的分块 152

句子嵌入 153

语言-图像预训练的 Sigmoid 损失(SigLIP)210

光滑的聊天用户界面 (UI) 12

插槽 7

小型语言模型 (SLMs) 208

优点 209

缺点 209

例子 210

成长 207

变革潜力 210

与大型语言模型 (LLMs) 对比 208, 209

语音合成标记语言 (SSML) 13

语音转文本 (STT) 13

策略,用于管理内存问题

分页 87

提示最小化 88

选择性截断 87

摘要 87

监督学习(SL)16

T

任务 195

Tavily 搜索 128

温度 87

text-embedding-3-large 153

text-embedding-3-small 153

text-embedding-ada-00 153

文本分割

可管理的块,使用 160, 161 创建

文本到语音 (TTS) 13

分词 17

令牌 17

工具 126

使用,与代理 129, 130 一起

跟踪和管理能力,LangChain

反馈 203

元数据 203

抽样 203

跟踪技术

回调 123

调试 122

长篇日志 122

长篇日志 123

U

UI 功能,OpenAI 游乐场

AI 模型 60

内容过滤器首选项 60

历史按钮 60

模式设置 60

参数 60

预设,保存 59

查看代码选项 61

美国医学执照考试(USMLE) 22

美国注册会计师(CPA)考试 22

用户角色 42

V

向量 152

向量数据库

优点 155

示例 157

选择 157

工作 156

向量存储

嵌入式搜索 155

嵌入式存储 155

长篇日志 122

长篇日志 123

W

Woebot

URL 24

词嵌入 152,153

Wysa

URL 24

图片

packtpub.com

订阅我们的在线数字图书馆,全面访问超过 7,000 本书和视频,以及行业领先的工具,帮助您规划个人发展并推进职业生涯。欲了解更多信息,请访问我们的网站。

为什么订阅?

  • 使用来自 4,000 多位行业专业人士的实用电子书和视频,节省学习时间,增加编码时间

  • 通过为您量身定制的技能计划提高您的学习效果

  • 每月免费获得一本电子书或视频

  • 完全可搜索,方便快速获取关键信息

  • 复制粘贴,打印和收藏内容

您知道 Packt 为每本书都提供电子书版本,包括 PDF 和 ePub 文件吗?您可以在 packtpub.com 升级到电子书版本,并且作为印刷书客户,您有权获得电子书副本的折扣。如需了解更多详情,请联系我们 customercare@packtpub.com。

www.packtpub.com,您还可以阅读一系列免费的技术文章,订阅各种免费通讯,并享受 Packt 书籍和电子书的独家折扣和优惠。

您可能还会喜欢以下书籍

如果您喜欢这本书,您可能会对 Packt 的以下其他书籍感兴趣:

使用 ChatGPT API 构建人工智能应用

马丁·亚内夫

ISBN: 978-1-80512-756-7

  • 在自然语言处理任务中使用 ChatGPT API 建立坚实的基础

  • 构建、部署并利用各种桌面和 SaaS 人工智能应用

  • 无缝集成 ChatGPT 到现有的框架,如 Flask、Django 和 Microsoft Office API

  • 通过集成 DALL-E API 来激发您的创造力,在桌面应用程序中产生令人惊叹的 AI 生成艺术

  • 体验 Whisper API 的语音识别和文本到语音功能

  • 发现通过微调过程优化 ChatGPT 模型的技术

ChatGPT 和 Power BI 的金融未来

詹姆斯·布莱恩特,阿洛克·穆克赫杰

ISBN: 978-1-80512-334-7

  • 利用 ChatGPT 的颠覆性见解,在投资、交易和报告中称霸

  • 掌握 Power BI 动态财务可视化、自定义仪表板和有影响力的图表

  • 将人工智能和 ChatGPT 应用于高级财务分析和新闻分析中的自然语言处理(NLP)

  • 利用 ChatGPT 进行强大的市场情绪分析,抓住投资机会

  • 通过数据建模、源连接和 Power BI 集成释放您的财务分析潜力

  • 理解数据安全的重要性,并采用最佳实践来使用 ChatGPT 和 Power BI

Packt 正在寻找像您这样的作者

如果您有兴趣成为 Packt 的作者,请访问 authors.packtpub.com 并今天申请。我们已与成千上万的开发人员和科技专业人士合作,就像您一样,帮助他们将见解分享给全球科技社区。您可以提交一般申请,申请我们正在招募作者的特定热门话题,或提交您自己的想法。

分享您的想法

现在您已经完成了《ChatGPT for Conversational AI and Chatbots》,我们非常乐意听到您的想法!如果您从亚马逊购买了本书,请点击此处直接转到该书的亚马逊评论页面,分享您的反馈或在该购买网站上留下评论。

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

下载本书的免费 PDF 副本

感谢您购买本书!

你喜欢在路上阅读,但无法随身携带你的印刷书籍吗?

您的电子书购买是否与您选择的设备不兼容?

别担心,现在每购买一本 Packt 书籍,您都可以免费获得该书的无 DRM PDF 版本。

在任何地方、任何设备上阅读。直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。

好处不止于此,您还可以获得独家折扣、时事通讯和每日免费内容的每日电子邮件

按照以下简单步骤获取福利:

  1. 扫描下面的二维码或访问以下链接

packt.link/free-ebook/978-1-80512-953-0

  1. 提交您的购买证明

  2. 就这样!我们将直接将您的免费 PDF 和其他福利发送到您的邮箱

posted @ 2026-04-03 22:09  布客飞龙II  阅读(1)  评论(0)    收藏  举报