快速入门
在快速入门中,我们将介绍如何:
- 使用LangChain、LangSmith 和 LangServe 进行设置
- 使用LangChain最基本和常见的组件:提示词模板、模型和输出解析器
- 使用LangChain表达式语言,是LangChain所基于的协议,以促进组件的链接
- 使用LangChain构建简单的应用
- 使用LangSmith追踪您的应用
- 使用LangServer为您的应用提供服务
这是一个相当可观的旅程!让我们开始吧。
设置
Jupyter Notebook
要安装LangChain,请运行:
# Pip
pip install langchain
# Conda
conda install langchain -c conda-forge
LangSmith
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=""
使用LangChain进行构建
LangChain支持构建将外部数据源和计算连接到LLM的应用程序。在本快速入门中,我们将逐步介绍几种不同的方法。我们将从一个简单的LLM链开始,仅依赖提示模板中的信息进行应答。
LLM Chain
我们将展示如何使用通过 API 提供的模型,像OpenAI,或集成本地开源的模型,如Ollama。
确保Ollama服务处在运行中,然后可以编写如下代码:
from langchain_community.llms import Ollama
llm = Ollama(model="llama3")
一旦您已经安装和初始化了您选择的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 的输出是一个消息。然而,使用字符串通常要方便得多,让我们添加一个简单的输出解析器来将聊天信息转换成字符串。
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链。我们只触及了提示、模型和输出解析器的基础知识 - 为了更深入地了解这里提到的所有内容:Model I/O
Retrieval Chain
为恰当的回答之前的问题(“how can langsmith help with testing?”),我们需要为 LLM 提供额外的上下文,我们可以通过检索来做到这一点。当您有太多数据无法直接传递给 LLM 时,检索非常有用。然后,您可以使用检索器仅获取最相关的部分并将其传递。
在此过程中,我们将从 Retriever 中查找相关文档,然后将它们传递到提示符中。Retriever可以支持任意的如SQL 表、互联网等—但在本实例下,我们将填充一个向量存储并将其用作Retriever。关于矢量存储的更多信息可以查看:矢量存储
首先,我们要加载我们想要索引的数据。为此,我们将使用 WebBaseLoader。这需要安装BeautifulSoup:
pip install beautifulsoup4
之后,我们就可以导入和使用WebBaseLoader:
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.smith.langchain.com/user_guide")
docs = loader.load()
接下来,我们需要将其索引到向量存储中。这需要一些组件,即嵌入模型(embedding model)和矢量存储(vectorstore)。
使用本地模型(Ollama)
确保Ollama服务处于运行中(与LLM的设置相同)。
from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings(model="llama3")
现在我们可以使用这个嵌入模型来提取文档到向量存储。我们将使用一个简单的本地向量存储,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"])
深入了解
我们现在已经成功地建立了一个基本的检索链。我们只触及了检索的基础知识 - 为了更深入地了解这里提到的所有内容,详见:https://python.langchain.com/docs/modules/data_connection/
Conversation Retrieval Chain
到目前为止,我们创建的链只能回答单个问题。人们正在构建的 LLM 应用程序的主要类型之一是聊天机器人。那么,我们如何把这个链条变成一个可以回答后续问题的链条呢?
我们仍然可以使用create_retrieval_chain
,但是需要做两处的调整:
- 检索方法现在不仅应该处理最新的输入,还应该考虑整个历史记录。
- 最终的 LLM 链同样应该考虑整个历史
为了更新检索,我们创建一个新的链;这条链将接受最新的输入、对话历史记录和使用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"
})