Langchain(一) -使用langchain快速开始搭建聊天机器人

快速开始

在本快速入门中,我们将向您展示如何:

  • 使用 LangChain、LangSmith 和 LangServe 进行设置
  • 使用LangChain最基本、最常用的组件:提示模板、模型和输出解析器
  • 使用 LangChain 表达式语言,这是 LangChain 构建的协议,有助于组件链接
  • 使用LangChain构建一个简单的应用程序
  • 使用 LangSmith 追踪您的应用程序
  • 使用 LangServe 为您的应用程序提供服务

这是一个相当大的金额!让我们深入了解一下。

设置

Jupyter笔记本

本指南(以及文档中的大多数其他指南)使用Jupyter 笔记本,并假设读者也使用 Jupyter 笔记本。Jupyter 笔记本非常适合学习如何使用 LLM 系统,因为事情经常可能会出错(意外输出、API 关闭等),而在交互式环境中阅读指南是更好地理解它们的好方法。

您不需要在 Jupyter Notebook 中阅读该指南,但建议您这样做。有关如何安装的说明,请参阅此处。

安装

要安装 LangChain 运行:

pip install langchain

有关更多详细信息,请参阅我们的安装指南

LangSmith

您使用 LangChain 构建的许多应用程序将包含多个步骤以及多次调用 LLM 调用。随着这些应用程序变得越来越复杂,能够检查链或代理内部到底发生了什么变得至关重要。最好的方法是使用LangSmith

请注意,LangSmith 不是必需的,但它很有帮助。如果您确实想使用 LangSmith,请在上面的链接注册后,确保设置环境变量以开始记录跟踪:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."

与LangChain一起

LangChain 能够构建将外部数据源和计算连接到LLM的应用程序。在本快速入门中,我们将介绍几种不同的方法。我们将从一个简单的LLM链开始,它仅依赖于提示模板中的信息来响应。接下来,我们将构建一个检索链,它从单独的数据库中获取数据并将其传递到提示模板中。然后,我们将添加聊天历史记录,以创建对话检索链。这允许您以聊天方式与该法学硕士进行交互,因此它会记住以前的问题。最后,我们将构建一个代理 - 它利用 LLM 来确定是否需要获取数据来回答问题。我们将在高层次上介绍这些内容,但所有这些都有很多细节!我们将链接到相关文档。

LLM Chain

我们将展示如何使用通过 API 提供的模型(例如 OpenAI)和本地开源模型,以及使用 Ollama 等集成。

 

首先我们需要导入LangChain x OpenAI集成包。
pip install langchain-openai


访问 API 需要 API 密钥,您可以通过创建帐户并前往此处获取该密钥。一旦我们有了密钥,我们就需要通过运行以下命令将其设置为环境变量:
export OPENAI_API_KEY="..."


然后我们可以初始化模型:
from langchain_openai import ChatOpenAI

llm = ChatOpenAI()


如果您不想设置环境变量,可以openai_api_key在启动 OpenAI LLM 类时直接通过命名参数传递密钥:
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(openai_api_key="...")

一旦您安装并初始化了您选择的 LLM,我们就可以尝试使用它!让我们问它 LangSmith 是什么 - 这是训练数据中不存在的东西,因此它不应该有很好的响应。

llm.invoke("how can langsmith help with testing?")

我们还可以通过提示模板来指导其响应。提示模板将原始用户输入转换为更好的 LLM 输入。

from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are world class technical documentation writer."),
("user", "{input}")
])

我们现在可以将它们组合成一个简单的 LLM 链:

chain = prompt | llm

我们现在可以调用它并提出同样的问题。它仍然不知道答案,但对于技术作家来说,它应该以更合适的语气做出响应!

chain.invoke({"input": "how can langsmith help with testing?"})

ChatModel(这个chain)的输出是一条消息。然而,使用字符串通常要方便得多。让我们添加一个简单的输出解析器来将聊天消息转换为字符串。

from langchain_core.output_parsers import StrOutputParser

output_parser = StrOutputParser()

我们现在可以将其添加到之前的链中:

chain = prompt | llm | output_parser

我们现在可以调用它并提出同样的问题。现在答案将是一个字符串(而不是 ChatMessage)。

chain.invoke({"input": "how can langsmith help with testing?"})

深入探索

我们现在已经成功建立了一个基本的LLM Chain。我们只涉及了提示、模型和输出解析器的基础知识 - 要更深入地了解这里提到的所有内容,请参阅文档的这一部分

检索

为了正确回答最初的问题(“langsmith 如何帮助测试?”),我们需要为LLM提供额外的背景信息。我们可以通过检索来做到这一点。当您有太多数据无法直接传递给LLM时,检索非常有用。然后,您可以使用检索器仅获取最相关的部分并将其传递进去。

在此过程中,我们将从检索器中查找相关文档,然后将它们传递到提示符中。检索器可以由任何东西支持 - SQL 表、互联网等 - 但在本例中,我们将填充向量存储并将其用作检索器。有关矢量存储的更多信息,请参阅此文档

首先,我们需要加载要索引的数据。为此,我们将使用 WebBaseLoader。这需要安装BeautifulSoup

pip install beautifulsoup4

之后我们就可以导入并使用WebBaseLoader了。

from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("")

docs = loader.load()

接下来,我们需要将其索引到向量存储中。这需要一些组件,即嵌入模型向量存储

对于嵌入模型,我们再次提供通过 API 或运行本地模型访问的示例。

 

Make sure you have the `langchain_openai` package installed an the appropriate environment variables set (these are the same as needed for the LLM).

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()

现在,我们可以使用此嵌入模型将文档提取到向量存储中。为了简单起见,我们将使用一个简单的本地向量库FAISS 。

首先我们需要安装所需的软件包:

pip install faiss-cpu

然后我们可以建立我们的索引:

from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter


text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)
vector = FAISS.from_documents(documents, embeddings)

现在我们已经在矢量存储中索引了这些数据,我们将创建一个检索链。该链将接受传入的问题,查找相关文档,然后将这些文档与原始问题一起传递给 LLM 并要求其回答原始问题。

首先,让我们建立一个链,该链接受问题和检索到的文档并生成答案。

from langchain.chains.combine_documents import create_stuff_documents_chain

prompt = ChatPromptTemplate.from_template("""Answer the following question based only on the provided context:

<context>
{context}
</context>

Question: {input}""")

document_chain = create_stuff_documents_chain(llm, prompt)

如果我们愿意,我们可以通过直接传入文档来运行它:

from langchain_core.documents import Document

document_chain.invoke({
"input": "how can langsmith help with testing?",
"context": [Document(page_content="langsmith can let you visualize test results")]
})

但是,我们希望文档首先来自我们刚刚设置的检索器。这样,我们可以使用检索器动态选择最相关的文档并将其传递给给定的问题。

from langchain.chains import create_retrieval_chain

retriever = vector.as_retriever()
retrieval_chain = create_retrieval_chain(retriever, document_chain)

我们现在可以调用这个链。这将返回一个字典 - 来自 LLM 的响应位于answer键中

response = retrieval_chain.invoke({"input": "how can langsmith help with testing?"})
print(response["answer"])

# LangSmith offers several features that can help with testing:...

这个答案应该更准确!

深入探索

现在我们已经成功建立了一个基本的检索链。我们只涉及了检索的基础知识 - 要深入了解此处提到的所有内容,请参阅文档的这一部分

对话检索

到目前为止,我们创建的链只能回答单个问题。人们构建的 LLM 应用程序的主要类型之一是聊天机器人。那么我们如何将这个链条变成一个可以回答后续问题的链条呢?

我们仍然可以使用该create_retrieval_chain函数,但我们需要更改两件事:

  1. 检索方法现在不应仅适用于最近的输入,而应考虑整个历史记录。
  2. 最终的 LLM 链同样应该考虑整个历史

更新检索

为了更新检索,我们将创建一个新链。该链将接受最近的输入 ( input) 和对话历史记录 ( chat_history) 并使用 LLM 生成搜索查询。

from langchain.chains import create_history_aware_retriever
from langchain_core.prompts import MessagesPlaceholder

# First we need a prompt that we can pass into an LLM to generate this search query

prompt = ChatPromptTemplate.from_messages([
MessagesPlaceholder(variable_name="chat_history"),
("user", "{input}"),
("user", "Given the above conversation, generate a search query to look up to get information relevant to the conversation")
])
retriever_chain = create_history_aware_retriever(llm, retriever, prompt)

我们可以通过传递用户提出后续问题的实例来测试这一点。

from langchain_core.messages import HumanMessage, AIMessage

chat_history = [HumanMessage(content="Can LangSmith help test my LLM applications?"), AIMessage(content="Yes!")]
retriever_chain.invoke({
"chat_history": chat_history,
"input": "Tell me how"
})

您应该看到这会返回有关 LangSmith 中测试的文档。这是因为LLM生成了一个新查询,将聊天历史记录与后续问题相结合。

现在我们有了这个新的检索器,我们可以创建一个新的链来继续与这些检索到的文档进行对话。

prompt = ChatPromptTemplate.from_messages([
("system", "Answer the user's questions based on the below context:\n\n{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("user", "{input}"),
])
document_chain = create_stuff_documents_chain(llm, prompt)

retrieval_chain = create_retrieval_chain(retriever_chain, document_chain)

我们现在可以端到端地测试这个:

chat_history = [HumanMessage(content="Can LangSmith help test my LLM applications?"), AIMessage(content="Yes!")]
retrieval_chain.invoke({
"chat_history": chat_history,
"input": "Tell me how"
})

我们可以看到,这给出了一个连贯的答案 - 我们已经成功地将检索链变成了聊天机器人!

Agent

到目前为止,我们已经创建了链的示例 - 其中每个步骤都是提前知道的。我们要创建的最后一个东西是一个代理——LLM决定采取什么步骤。

注意:在本示例中,我们将仅展示如何使用 OpenAI 模型创建代理,因为本地模型还不够可靠。

构建代理时要做的第一件事就是决定它应该有权访问哪些工具。在此示例中,我们将授予代理访问两个工具的权限:

  1. 我们刚刚创建的检索器。这将让它轻松回答有关 LangSmith 的问题
  2. 一个搜索工具。这将使它能够轻松回答需要最新信息的问题。

首先,让我们为刚刚创建的检索器设置一个工具:

from langchain.tools.retriever import create_retriever_tool

retriever_tool = create_retriever_tool(
retriever,
"langsmith_search",
"Search for information about LangSmith. For any questions about LangSmith, you must use this tool!",
)

我们将使用的搜索工具是Tavily。这将需要一个 API 密钥(他们有慷慨的免费套餐)。在他们的平台上创建后,您需要将其设置为环境变量:

export TAVILY_API_KEY=...

如果您不想设置 API 密钥,则可以跳过创建此工具。

from langchain_community.tools.tavily_search import TavilySearchResults

search = TavilySearchResults()

我们现在可以创建我们想要使用的工具的列表:

tools = [retriever_tool, search]

现在我们有了工具,我们可以创建一个代理来使用它们。我们将很快讨论这一点 - 要更深入地了解到底发生了什么,请查看代理的入门文档

首先安装langchain hub

pip install langchainhub

安装langchain-openai包要与OpenAI交互,我们需要使用与OpenAI SDK连接的langchain-openai [] 。

pip install langchain-openai

现在我们可以使用它来获取预定义的提示

from langchain_openai import ChatOpenAI
from langchain import hub
from langchain.agents import create_openai_functions_agent
from langchain.agents import AgentExecutor

# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/openai-functions-agent")

# You need to set OPENAI_API_KEY environment variable or pass it as argument `openai_api_key`.
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
agent = create_openai_functions_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

我们现在可以调用代理并查看它如何响应!我们可以向它询问有关 LangSmith 的问题:

agent_executor.invoke({"input": "how can langsmith help with testing?"})

我们可以询问天气情况:

agent_executor.invoke({"input": "what is the weather in SF?"})

我们可以和它进行对话:

chat_history = [HumanMessage(content="Can LangSmith help test my LLM applications?"), AIMessage(content="Yes!")]
agent_executor.invoke({
"chat_history": chat_history,
"input": "Tell me how"
})

深入探索

现在我们已经成功建立了一个基本代理。我们只涉及了代理的基础知识 - 要更深入地了解此处提到的所有内容,请参阅文档的这一部分

使用LangServe

现在我们已经构建了一个应用程序,我们需要为它提供服务。这就是 LangServe 的用武之地。LangServe 帮助开发人员将 LangChain 链部署为 REST API。您不需要使用 LangServe 来使用 LangChain,但在本指南中,我们将向您展示如何使用 LangServe 部署您的应用程序。

虽然本指南的第一部分旨在在 Jupyter Notebook 中运行,但我们现在将不再使用它。我们将创建一个 Python 文件,然后从命令行与其交互。

安装:

pip install "langserve[all]"

服务器

要为我们的应用程序创建服务器,我们将创建一个serve.py文件。这将包含我们为应用程序提供服务的逻辑。它由三部分组成:

  1. 我们刚刚在上面构建的链的定义
  2. 我们的 FastAPI 应用程序
  3. 为链提供服务的路由的定义,由以下命令完成langserve.add_routes

#!/usr/bin/env python
from typing import List

from fastapi import FastAPI
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.tools.retriever import create_retriever_tool
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain import hub
from langchain.agents import create_openai_functions_agent
from langchain.agents import AgentExecutor
from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.messages import BaseMessage
from langserve import add_routes

# 1. Load Retriever
loader = WebBaseLoader("")
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)
embeddings = OpenAIEmbeddings()
vector = FAISS.from_documents(documents, embeddings)
retriever = vector.as_retriever()

# 2. Create Tools
retriever_tool = create_retriever_tool(
retriever,
"langsmith_search",
"Search for information about LangSmith. For any questions about LangSmith, you must use this tool!",
)
search = TavilySearchResults()
tools = [retriever_tool, search]


# 3. Create Agent
prompt = hub.pull("hwchase17/openai-functions-agent")
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
agent = create_openai_functions_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)


# 4. App definition
app = FastAPI(
title="LangChain Server",
version="1.0",
description="A simple API server using LangChain's Runnable interfaces",
)

# 5. Adding chain route

# We need to add these input/output schemas because the current AgentExecutor
# is lacking in schemas.

class Input(BaseModel):
input: str
chat_history: List[BaseMessage] = Field(
...,
extra={"widget": {"type": "chat", "input": "location"}},
)


class Output(BaseModel):
output: str

add_routes(
app,
agent_executor.with_types(input_type=Input, output_type=Output),
path="/agent",
)

if __name__ == "__main__":
import uvicorn

uvicorn.run(app, host="localhost", port=8000)

就是这样!如果我们执行这个文件:

python serve.py

我们应该看到我们的链在 localhost:8000 上提供服务。

游乐场

每个 LangServe 服务都带有一个简单的内置 UI,用于配置和调用具有流输出和中间步骤可见性的应用程序。前往 http://localhost:8000/agent/playground/ 尝试一下!传递与之前相同的问题 - “langsmith 如何帮助测试?” - 它的响应应该和以前一样。

客户

现在让我们设置一个客户端,以便以编程方式与我们的服务进行交互。我们可以使用 轻松做到这一点[langserve.RemoteRunnable](/docs/langserve#client)。使用它,我们可以与服务链进行交互,就像它在客户端运行一样。

from langserve import RemoteRunnable

remote_chain = RemoteRunnable("http://localhost:8000/agent/")
remote_chain.invoke({
"input": "how can langsmith help with testing?",
"chat_history": [] # Providing an empty list as this is the first call
})

要了解有关 LangServe 的许多其他功能的更多信息,请前往此处

后续步骤

我们已经介绍了如何使用 LangChain 构建应用程序、如何使用 LangSmith 跟踪它以及如何使用 LangServe 提供服务。这三个方面的功能比我们在此介绍的要多得多。要继续您的旅程,我们建议您阅读以下内容(按顺序):

posted on   ExplorerMan  阅读(166)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2021-01-21 pyspark启动与简单使用----本地模式(local)----shell
2021-01-21 spark RDD详解
2021-01-21 本地调试spark程序
2021-01-21 在IDEA中使用Java编写WordCount程序
2021-01-21 启动spark shell详解
2021-01-21 提交一个spark程序及spark执行器
2021-01-21 错误:启动spark后在web页面看不到worker节点的信息

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示