跳转到主要内容

上周,OpenAI发布了一个ChatGPT端点。它在上市时有几个大的改进,最显著的是便宜了10倍,速度也快了很多。但它也附带了一个全新的API端点。我们能够快速为这个端点编写一个包装器,让用户像使用LangChain中的任何普通LLM一样使用它,但这并没有充分利用新的基于消息的API。在这篇博客文章中,我们介绍了新的API模式,以及我们如何调整LangChain以适应ChatGPT以及所有未来基于聊天的模型。

关键环节:

为什么是新的抽象概念?

所以OpenAI发布了一个新的API——有什么大不了的?为什么甚至需要新的抽象?

虽然ChatGPT端点在后台使用了一个语言模型,但API与现有的GPT-3端点有很大不同。这有点简化,但现有的GPT-3端点具有以下接口:

  • 输入:文本
  • 输出:文本

新的ChatGPT终结点具有以下接口:

  • 输入:聊天信息列表
  • 输出:聊天消息

这个新接口意味着我们对语言模型的输入/输出的一些抽象不再正确。例如,我们之前构建的提示策略都假设PromptTemplate的输出是字符串。然而,现在对于聊天模型,输入需要是一个消息列表。由于提示是许多LangChain实用程序和功能的核心,因此这是一个非常深入的变化。

为什么是聊天模型?

好吧,有一种新型的模型。我们为什么急于支持它?它真的与现有的API如此不同,以至于它值得新的抽象吗?

为了回答这个问题,值得思考的是,OpenAI为什么选择以这种格式发布模型。这部分都是猜测。这个API和以前的GPT-3 API之间的主要区别是,现在用户输入有更多的结构,以不同类型的消息的形式出现。具体来说,ChatGPT API允许区分“用户”、“助理”和“系统”消息。这种差异可以允许模型以不同的方式处理不同类型的消息,这在理论上可以提高基于这些模型构建的应用程序的安全性。例如,一种常见的针对LLM应用程序的攻击类型是提示注入攻击,即最终用户指示应用程序做一些它不打算做的事情。通过现在将这种结构添加到提示中,理论上,最终应用程序可以将其所有应用指令放在“系统”消息中,所有最终用户输入放在“用户”消息中,然后,可以训练模型始终“服从”系统消息,无论用户消息可能告诉它什么。在实践中,针对聊天模型的即时注入攻击似乎仍然是一件事,因此这可能无法完全解决这些问题。只有时间才能证明。

上面的“用户”与“助理”与“系统”消息的例子也说明了为什么这种格式与现有的API有足够的不同,值得拥有自己的抽象。

还有更实际的原因。OpenAI尚未发布与ChatGPT模型相对应的“普通”LLM端点,因此,如果人们想充分利用这些模型的速度/成本,他们需要使用ChatGPT-API。也有传言称其他聊天模式即将上市(来自Anthropic的Claude、来自谷歌的Bard、来自Cohere的对话模式的早期传言)。虽然还不知道这些模型将以何种格式提供,但假设它们也将具有基于聊天的API选项并不疯狂。

我们对新抽象的目标是什么?

在设计这些新的抽象概念时,我们有三个主要目标:

#1:允许用户充分利用新的聊天模式界面

如上所述,聊天模型的API与现有的LLM API有很大不同。我们希望让用户利用这一点。

#2:允许“正常”LLM API和基于聊天的API之间的提示互操作性

尽管“普通”LLM与基于聊天的API在提示方面肯定存在差异,但我们希望(在合理的范围内)尽可能无缝地对任何一种类型的模型使用相同的提示。实际上,我们优先考虑了这一点,因为代码库中的大多数提示都是针对LLM优化的,并且我们不希望它们在基于聊天的模型中严重中断。

#3:使抽象变得通用,而不仅仅是OpenAI

我们不希望我们建立的任何抽象都是特定于OpenAI的。如上所述,有传言称其他聊天风格的机型即将上市,我们希望确保能够无缝支持它们。

这些新的抽象概念是什么?

虽然我们似乎在代码库中引入了过多的抽象,但它们都是为了让添加到代码库中的任何东西在这些新模型中尽可能好地工作。LangChain的目标之一一直是允许语言模型提供者之间的互操作性,我们希望这有助于实现这一点。

聊天信息

我们正在为不同类型的聊天消息添加抽象。

  • HumanMessage:从人类的角度发送的信息
  • AIMessage:从人类正在交互的人工智能的角度发送的信息
  • 系统消息:设定人工智能应遵循的目标的消息
  • ChatMessage:允许任意设置角色的消息

聊天模型

我们还为聊天模型添加了抽象。这些类型的模型期望的界面与底层的ChatGPT API非常相似——它接受聊天消息列表并返回聊天消息。

聊天信息模板

由于大多数应用程序不硬编码要发送的消息,而是利用“提示模板”的思想(接受用户输入并返回提示),我们正在添加相应的聊天消息提示模板。

  • HumanMessagePromptTemplate:一个公开方法以接受用户输入并返回HumanMessage的类
  • AIMessagePromptTemplate:一个公开方法以接受用户输入并返回AIMessage的类
  • SystemMessagePromptTemplate:一个公开方法以接受用户输入并返回SystemMessage的类
  • ChatMessagePromptTemplate:一个公开方法以接受用户输入并返回ChatMessage的类

提示值

为了实现“普通”LLM API和基于聊天的API之间的提示互操作性,我们添加了PromptValue的概念。这是一个具有以下方法的类:

  • to_string:将PromptValue转换为字符串,用于“普通”LLM API
  • to_messages:将PromptValue转换为消息列表,用于基于聊天的API

为了实现这一点,我们还向BaseLLM和BaseChatModel类添加了接受PromptValues的方法,将它们分别转换为字符串或ChatMessages,然后将它们传递给模型。

这些如何与我们的目标保持一致?

让我们确保这些抽象与我们制定的目标一致

#1:允许用户充分利用新的聊天模式界面

我们涵盖了ChatGPT接口中的所有功能。有些东西我们没有明确的抽象(比如name参数),但这些东西仍然可用,如果它们变得更相关,我们可能会在未来添加更好的支持。

#2:允许“正常”LLM API和基于聊天的API之间的提示互操作性

PromptValue抽象应该考虑到这一点。我们有非常简单的方法将字符串转换为消息(使其成为单个HumanMessage),将消息转换为字符串(只需将整个列表转换为字符串)。这些(尤其是messages-to-string方法)肯定可以改进。

#3:使抽象变得通用,而不仅仅是OpenAI

我们相信,通过添加人类/人工智能/系统消息的明确概念,而不是依赖带有“角色”键的字典,我们已经为自己建立了模型API不可知论者的基础。这样,如果另一个模型提供商有不同的命名约定(例如,他们称AI为“AI”,而不是OpenAI的“助手”),我们可以很容易地在模型包装中映射到这些命名约定。

接下来的步骤

希望这有助于澄清我们对引入的抽象概念的一些想法。我们会喜欢对这些抽象概念的反馈。在不到一周的时间里,必须对一个全新的概念进行抽象,这总是很可怕的,所以我们非常感谢任何建议和评论。

我们还将继续围绕聊天模型添加更多功能。例如,更好的消息到字符串支持,更好的少镜头示例支持,以及更好的聊天内存支持。

由于这次意外发布,我们也积累了大量积压的项目,所以感谢您在我们尝试筛选时的耐心。

最后,非常感谢Anthropic团队(特别是Mike Lambert)对其中一些抽象进行了思考,并确保它们在ChatGPT API之外具有通用性。当只有一个实例可以查看时,总是很难尝试概括抽象,所以我们非常欣赏他们的智慧。