跳转到主要内容
Chinese, Simplified

LangChain聊天

今天,我们很高兴地宣布并展示一个开源聊天机器人,专门用于回答有关LangChain文档的问题。

关键链接

  • 已部署聊天机器人:chat.langchain.dev
  • 在HuggingFace空间部署聊天机器人:HuggingFace.co/spaces/hwchase17/chat-langchain
  • Open source repo:github.com/hwchase17/chat-langchain
  • Next.js前端:github.com/zahidkhawaja/langchain-chat-nextjs

对扎希德·卡瓦贾在这件事上与我们合作大加赞赏。如果你想为网页提供这种类型的功能,你应该看看他的浏览器扩展名:Lucid。

如果你喜欢这个,并且想为你的代码库提供一个更高级的版本,你应该看看ClerkieAI。他们的问答机器人在我们的Discord上直播。

概述

在过去的几周里,还有一些其他项目与此类似(更多内容见下文)。然而,我们希望分享我们认为独特的见解,包括:

  • 文档摄取(什么是一般性的,什么不是一般性的)
  • 如何在聊天机器人设置中实现这一点(重要的用户体验)
  • (Prompt Engineering)速度与性能之间的权衡
  • (提示工程)如何让它引用来源
  • (提示工程)输出格式

在粗体部分展开,我们认为聊天机器人界面是一个重要的用户体验(看看ChatGPT的成功吧!),我们认为其他实现中缺少这一点。

动机

将LLM与外部数据相结合一直是LangChain的核心价值支柱之一。我们制作的第一个演示之一是Notion QA Bot,Lucid很快就通过互联网实现了这一点。

我们希望能够回答问题的外部数据之一是我们的文档。我们有一个不断壮大的Discord社区,希望为他们的所有问题提供快速准确的支持。因此,这似乎是一个在内部利用我们自己技术的绝佳机会!我们联系了一位ML创作者和LangChain爱好者Zahid,看看他是否愿意为此合作,让我们松了一口气的是,他答应了!于是我们开始建造。

类似工作

不管出于什么原因,就在过去的一周里,这里也做了很多类似的工作!几乎所有这些都遵循相同的管道,可以浓缩如下:

Diagram of typical ingestion process

摄入:

  • 拿一套专有文件
  • 把它们分成小块
  • 为每个文档创建嵌入

Diagram of typical query process

查询:

  • 为查询创建嵌入
  • 在嵌入空间中查找最相似的文档
  • 将这些文档与原始查询一起传递到语言模型中以生成答案

其他一些很好的例子包括:

  • GitHub支持机器人(由Dagster提供)-就其试图解决的问题而言,可能与此最相似
  • Dr.Doc Search-与书籍对话(PDF)
  • Simon Willison关于“语义搜索答案”的文章——对这里的一些主题进行了很好的解释
  • Sahil Lavingia的《问我的书》,也许是掀起当前热潮的例子

文件摄入

我们立即面临一个问题:究竟从哪里获取数据。有两种选择:GitHub中的文件,或者从互联网上抓取。虽然GitHub中的一些文件的格式很好(markdown和rst),但我们也有一些不太好的文件(.ipynb文件,自动生成的文档)。出于这个原因,我们决定从互联网上删除它。

在那之后,我们面临着如何预处理html文件的问题。为此,我们最初以一种通用的方式(只需使用Beautiful Soup来获取页面上的所有文本)。然而,在使用这些结果后,我们发现一些侧边栏内容产生了糟糕的结果。作为一个视觉示例,在下面的图片中,红色的两个区域并没有真正提供太多新信息。

当我们检查我们得到的一些糟糕的结果时,我们发现往往是这些信息被提取并填充到上下文中。我们通过更改解析器以显式忽略这些区域来解决这个问题。

尽管这是针对这种布局的,但我们确实认为,这突出了非常有意地将你所做(或不做)的数据作为潜在上下文的重要性。虽然使用通用的摄取工具并将其作为快速入门的一种方式可能很容易,但为了获得更好的性能,进行更深入的检查和修改管道可能是必要的。

如何在聊天机器人设置中实现此功能

如前所述,我们认为聊天机器人设置是一个重要的用户体验决策,它:

  • 人们觉得熟悉(参见ChatGPT的成功)
  • 启用其他关键功能(下面将详细介绍)

我们希望确保包括的一个关键功能是能够提出后续问题,这是我们在许多其他地方没有看到的。我们相信这对于任何基于聊天的界面来说都是非常重要的。大多数(全部?)实现主要忽略了这个问题,并将每个问题视为独立的。当有人想以自然的方式提出后续问题,或者参考先前问题或答案中的上下文片段时,这种情况就会崩溃。

在LangChain中实现这一点的主要方法是在会话链中使用内存。在最简单的实现中,前面的对话行作为上下文添加到提示中。然而,这在我们的用例中有点分解,因为我们不仅关心将会话历史添加到提示中,而且还关心使用它来确定要获取哪些文档。如果提出后续问题,我们需要知道该后续问题是关于什么的,以便获取相关文件。

因此,我们创建了一个新的链,该链具有以下步骤:

  • 给定一个对话历史和一个新问题,创建一个单独的问题
  • 在普通向量数据库问答链中使用该问题。

Diagram of our query process

我们有点担心在矢量数据库问答链中使用这个问题会有损失,并丢失一些上下文,但我们并没有真正观察到任何负面影响。

在获得此解决方案的过程中,我们尝试了其他一些从矢量数据库中获取文档的方法,但效果不佳:

  • 将聊天历史记录+问题嵌入在一起:一旦聊天历史记录变长,如果你试图改变话题,就会对其进行过度索引。
  • 将聊天和问题分别嵌入,然后将结果组合起来:比上面的要好,但仍然将太多关于先前主题的信息纳入上下文

Prompt工程

在构建聊天机器人时,提供良好的用户体验至关重要。在我们的用例中,有几个重要的考虑因素:

  • 每个答案都应包括文件的官方来源。
  • 如果答案中包含代码,则应将其正确格式化为代码块。
  • 聊天机器人应该停留在话题上,坦率地说不知道答案。

我们通过以下提示实现了所有这些:

You are an AI assistant for the open source library LangChain. The documentation is located at https://langchain.readthedocs.io.
You are given the following extracted parts of a long document and a question. Provide a conversational answer with a hyperlink to the documentation.
You should only use hyperlinks that are explicitly listed as a source in the context. Do NOT make up a hyperlink that is not listed.
If the question includes a request for code, provide a code block directly from the documentation.
If you don't know the answer, just say "Hmm, I'm not sure." Don't try to make up an answer.
If the question is not about LangChain, politely inform them that you are tuned to only answer questions about LangChain.
Question: {question}
=========
{context}
=========
Answer in Markdown:

This is prompt we're currently using to return answers in Markdown with sources and code.

在这个提示中,我们请求一个Markdown格式的响应。这使我们能够用适当的标题、列表、链接和代码块以视觉上吸引人的格式呈现答案。

以下是Next.js前端的外观:

In this screenshot, the user requests a follow-up code example. As you can see, we’re able to provide a code example in a sensible format.

每个答案中的超链接都是使用文档的基本URL构建的,我们在提示中提前提供了文档。由于我们在数据接收管道中抓取了文档网站,因此我们能够确定答案的路径,并将其与基本URL相结合,以创建一个有效的链接。

为了使聊天机器人尽可能准确,我们将温度保持在0,并在提示中包含说明,如果有问题回答不清楚,请说“嗯,我不确定”。为了保持对话的主题,我们还提供了拒绝与LangChain无关的问题的说明。

在速度和性能之间取得平衡:

  • 我们以更长的Markdown答案开始测试。尽管答案质量很好,但响应时间比预期的稍长。
  • 我们花了很多时间完善提示,并尝试使用不同的关键字和句子结构来提高性能。
  • 一种方法是在提示的末尾提到Markdown关键字。对于我们的用例,我们能够返回格式化的输出,只需提及一次关键字。
  • 在提示的开头附近提供基本URL提高了整体性能——它为模型提供了一个工作参考,可以创建一个包含在答案中的最终URL。
  • 我们发现,使用单数形式,如“超链接”而不是“超链接“和“代码块”而不是”代码块“,可以提高响应时间。

未来工作

我们才刚刚开始,我们欢迎来自LangChain社区的反馈。我们迫不及待地想在不久的将来推出新功能和改进!在推特上关注我们以获取更新并签出代码。

如果你喜欢这个,并且想为你的代码库提供一个更高级的版本,你应该看看ClerkieAI。他们的问答机器人在我们的Discord上直播。

原文地址
https://blog.langchain.dev/langchain-chat/
本文地址
Article

微信

知识星球

微信公众号

视频号