将LLM 接入 LangChain
LangChain 为基于 LLM 开发自定义应用提供了高效的开发框架,便于开发者迅速地激发 LLM 的强大能力,搭建 LLM 应用。LangChain 也同样支持多种大模型,内置了 OpenAI、LLAMA 等大模型的调用接口。但是,LangChain 并没有内置所有大模型,它通过允许用户自定义 LLM 类型,来提供强大的可扩展性。
在我们开发大模型应用时,大多数情况下不会直接将用户的输入直接传递给 LLM。通常,他们会将用户输入添加到一个较大的文本中,称为提示模板
,该文本提供有关当前特定任务的附加上下文。 PromptTemplates 正是帮助解决这个问题!它们捆绑了从用户输入到完全格式化的提示的所有逻辑。
我们现在可以将所有这些组合成一条链。该链将获取输入变量,将这些变量传递给提示模板以创建提示,将提示传递给语言模型,然后通过(可选)输出解析器传递输出。接下来我们使用LCEL这种语法去快速实现一条链(chain)。
什么是 LCEL ? LCEL(LangChain Expression Language,Langchain的表达式语言),LCEL是一种新的语法,是LangChain工具包的重要补充,他有许多优点,使得我们处理LangChain和代理更加简单方便。
- LCEL提供了异步、批处理和流处理支持,使代码可以快速在不同服务器中移植。
- LCEL拥有后备措施,解决LLM格式输出的问题。
- LCEL增加了LLM的并行性,提高了效率。
- LCEL内置了日志记录,即使代理变得复杂,有助于理解复杂链条和代理的运行情况。
用法示例:
chain = prompt | model | output_parser
上面代码中我们使用 LCEL 将不同的组件拼凑成一个链,在此链中,用户输入传递到提示模板,然后提示模板输出传递到模型,然后模型输出传递到输出解析器。| 的符号类似于 Unix 管道运算符,它将不同的组件链接在一起,将一个组件的输出作为下一个组件的输入。
构建检索问答链
搭建数据库
,我们已经介绍了如何根据自己的本地知识文档,搭建一个向量知识库。 在接下来的内容里,我们将使用搭建好的向量数据库,对 query 查询问题进行召回,并将召回结果和 query 结合起来构建 prompt,输入到大模型中进行问答。
加载向量数据库
首先,我们加载已经构建的向量数据库。注意,此处你需要使用和构建时相同的 Emedding。
创建检索链
我们可以使用LangChain的LCEL(LangChain Expression Language, LangChain表达式语言)来构建workflow,LCEL可以支持异步(ainvoke)、流式(stream)、批次处理(batch)等多种运行方式,同时还可以使用LangSmith无缝跟踪。
LCEL中要求所有的组成元素都是Runnable
类型,前面我们见过的ChatModel
、PromptTemplate
等都是继承自Runnable
类。上方的retrieval_chain
是由检索器retriever
及组合器combiner
组成的,由|
符号串连,数据从左向右传递,即问题先被retriever
检索得到检索结果,再被combiner
进一步处理并输出。
创建LLM
构建检索问答链
向检索链添加聊天记录
现在我们已经实现了通过上传本地知识文档,然后将他们保存到向量知识库,通过将查询问题与向量知识库的召回结果进行结合输入到 LLM 中,我们就得到了一个相比于直接让 LLM 回答要好得多的结果。在与语言模型交互时,你可能已经注意到一个关键问题 -它们并不记得你之前的交流内容。这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。这个问题该如何解决呢?
传递聊天记录
我们将使用 LangChain 中的ChatPromptTemplate
,即将先前的对话嵌入到语言模型中,使其具有连续对话的能力。ChatPromptTemplate
可以接收聊天消息历史记录,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。
带有信息压缩的检索链
因为我们正在搭建的问答链带有支持多轮对话功能,所以与单轮对话的问答链相比会多面临像上方输出结果的问题,即用户最新的对话语义不全,在使用用户问题查询向量数据库时很难检索到相关信息。