【langchain快速入门】langchain初探:chain、检索(利用向量查询、少样本增强LLM能力)、agent、langserve初探

LangChain本质上就是对各种大模型提供的API的套壳,是为了方便我们使用这些API,搭建起来的一些框架、模块和接口。

一. 架构

LangChain 简化了LLM应用程序生命周期的每个阶段:
在这里插入图片描述

 

二. 快速入门

快速入门中我们将学到如下技能

  • 将从一个简单的LLM链开始,它只依赖于提示模板中的信息来回复。
  • 我们将添加聊天记录,以创建一个对话检索链。这使您可以以聊天方式与此LLM进行交互,因此它会记住以前的问题。
  • 我们将构建一个代理,该代理利用LLM来确定是否需要获取数据来回答问题。
  • 使用LangServe为您的应用程序提供服务

 

1. LLM Chain:LLM问答步骤串联成链

实现了:

  1. langchain调用openai
  2. 使用OpenApi进行模型对话
  3. 通过(提示模版)设置system来指导chat回答
  4. 将上面的步骤组成调用链,以便调用
  5. 输出解析器:使用字符提取器提取回答
from langchain_openai import ChatOpenAI  

# 1. 调用大模型  
# 通过langchain设置chatapi  
llm = ChatOpenAI()  
llm.invoke("how can langsmith help with testing?")  

# 2. 使用提示模版:更加专业的回答
# 使用提示模板来指导其回答。 # 提示模板将原始用户输入转换为更好的输入以供LLM使用。  
from langchain_core.prompts import ChatPromptTemplate  
  
prompt = ChatPromptTemplate.from_messages([  
    ("system", "You are world class technical documentation writer."),  
    ("user", "{input}")  
])  
  
# 3. 引入字符解析器:提取ChatMessage中的回答 
from langchain_core.output_parsers import StrOutputParser  
  
output_parser = StrOutputParser()  
  
#4. 将前面三步组成调用链
chain = prompt | llm | output_parser  
  
#5. 链调用
Output = chain.invoke({"input": "how can langsmith help with testing?"})  
# 答案现在将是一个字符串(而不是ChatMessage)。  
print(Output)

 

2. Retrieval Chain: 检索链:检索文档来提供专业材料

2.1. 检索链(利用向量查询提供context)

利用检索器检索文档并给LLM提供上下文

总体思路
为了正确回答原始问题(“langsmith如何帮助测试?”),我们需要为LLM提供附加上下文。我们可以通过检索来实现这一点。

  • 我们可以把数据传递给LLM,检索工具仅搜索(HOW?)相关数据并传递给LLM。
  • 我们从检索器中查找相关文档,然后将它们传递给提示符prompt。检索器可以由任何东西支持一个SQL表、互联网等。在本例中,我们将填充一个向量存储并将其用作检索器。

有关向量存储的更多信息,请参阅此文档

 

  1. 加载数据 加载数据:使用BeautifulSoup(opens in a new tab)加载网页数据
    shell pip install beautifulsoup4

  2. 数据加载到向量存储中生成索引

    • 需要嵌入模型向量存储
    • 文档分片
    • 使用嵌入模型将文档导入向量存储:这里使用一个简单的本地向量存储FAISS
  3. 创建文档链:用来创建问答链

  4. 基于文本链与检索器创建检索链,这样就能基于文档来回答具体问题。


  
# 1. 加载要索引的数据。  
# 使用WebBaseLoader加载网页数据  
from langchain_community.document_loaders import WebBaseLoader  
loader = WebBaseLoader("https://docs.smith.langchain.com/user_guide")  
docs = loader.load()  
  
# 2. 文档分片,并通过向量存储构建文档索引   
from langchain_openai import OpenAIEmbeddings  
embeddings = OpenAIEmbeddings()  
# FAISS:轻量化的本地存储  
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)  
  
# 3. 创建文本检索链(prompt+llm),来接收文档和问题  
# 现在,我们在向量存储中索引了这些数据,我们将创建一个检索链。该链将接收一个输入问题,查找相关文档,然后将这些文档连同原始问题一起传递给LLM,并要求它回答原始问题。  
from langchain_openai import ChatOpenAI  
llm = ChatOpenAI()  
from langchain_core.prompts import ChatPromptTemplate  
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.chains import create_retrieval_chain  
retriever = vector.as_retriever()  
retrieval_chain = create_retrieval_chain(retriever, document_chain)  
response = retrieval_chain.invoke({"input": "how can langsmith help with testing?"})  
print(response["answer"])

 

2.2. 少样本学习,增强LLM能力

# 通过langchain设置chatapi  
from langchain_openai import ChatOpenAI  
llm = ChatOpenAI()  
from langchain_core.prompts import ChatPromptTemplate  
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)  
  

# 少样本学习
# 5.1. 直接基于写好的文档进行回答context:
# 如果我们想的话,可以直接传递文档来运行它:  
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")]  
})  

 

2.3. 深入了解

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

 

3. 对话检索链:可以连续问答的链

本节的目标是:构建能多轮对话的聊天机器人

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

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

3.1. 聊天机器人(只支持两轮对话?)

文档检索器构建

# 1. 加载要索引的数据。  # 使用WebBaseLoader加载网页数据  
from langchain_community.document_loaders import WebBaseLoader    
loader = WebBaseLoader("https://docs.smith.langchain.com/user_guide")    
docs = loader.load()    
    
# 2. 文档分片,并通过向量存储构建文档索引   
from langchain_openai import OpenAIEmbeddings    
embeddings = OpenAIEmbeddings()    
# FAISS:轻量化的本地存储  
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)    
    
  
# 索引转为检索器 
from langchain.chains import create_retrieval_chain    
retriever = vector.as_retriever()

构建多轮对话

from langchain.chains.combine_documents import create_stuff_documents_chain  
from langchain_core.messages import HumanMessage, AIMessage  
from langchain_openai import ChatOpenAI    
llm = ChatOpenAI()    
  
from langchain.chains import create_history_aware_retriever  
from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplate  

# 1. 更新检索器
prompt = ChatPromptTemplate.from_messages([  
    MessagesPlaceholder(variable_name="chat_history"),  
    ("user", "{input}"),  
    ("user", "根据上面的对话,生成一个搜索查询来获取与对话相关的信息")  
])  
# 接收对话历史并返回文档的chain  
# retriever:上面创建的数据索引  
retriever_chain = create_history_aware_retriever(  
                                      llm, # 大模型  
                                      retriever, # 文档检索器  
                                      prompt) # 有历史对话并能基于历史对话来生成搜索查询(能够补全下面的问题?)  
  
  
# 2. 基于新的检索器创建新的链:有文档检索能力
# 由聊天记录生成的prompt,  
prompt = ChatPromptTemplate.from_messages([  
    ("system", "根据下面的上下文回答用户的问题:\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)  # 对话链


# 3. 新链测试
# 封装的历史对话:之后通过Memory来实现?  
chat_history = [HumanMessage(content="Can LangSmith help test my LLM applications?"), AIMessage(content="Yes!")]  
retrieval_chain.invoke({  
    "chat_history": chat_history,  # todo:存储历史文件
    "input": "Tell me how"  
})

由聊天记录生成的prompt,将历史对话都添加到message中,只支持两轮?

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

 

3.2. 代理人

本文我们将创建一个代理人 - 在这种情况下,LLM决定要采取的步骤。

创建工具:

from langchain.tools.retriever import create_retriever_tool
 
retriever_tool = create_retriever_tool(
    retriever,
    "langsmith_search",
    "搜索与LangSmith相关的信息。有关LangSmith的任何问题,您必须使用此工具!",
)

创建代理人;

有了工具,我们可以创建一个代理人来使用它们。
深入了解请查看代理人入门文档

首先安装langchain hub

pip install langchainhub
pip install langchain-openai


from langchain.tools.retriever import create_retriever_tool  
  
# 1. 封装成工具  
retriever_tool = create_retriever_tool(  
    retriever,  
    "langsmith_search",  
    "搜索与LangSmith相关的信息。有关LangSmith的任何问题,您必须使用此工具!",  
)  
  
# tools = [retriever_tool]  
  
from langchain_openai import ChatOpenAI  
from langchain import hub  
from langchain.agents import create_openai_functions_agent  
from langchain.agents import AgentExecutor  
  
# 加载官方提示  
prompt = hub.pull("hwchase17/openai-functions-agent")  

# 2. 创建agentor
# 您需要设置OPENAI_API_KEY环境变量,或者将其作为参数`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)

我们现在成功地设置了一个基本的agentor。我们只触及了代理人的基础知识 - 如果您想更深入地了解这里提到的所有内容,请参阅文档的这一部分

 

4. 使用LangServe进行服务

LangServe帮助开发人员将LangChain链部署为REST API。

使用以下命令安装LangServe:

pip install "langserve[all]"

 

4.1. 服务器

我们用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. 加载检索器
loader = WebBaseLoader("https://docs.smith.langchain.com/user_guide")
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. 创建工具
retriever_tool = create_retriever_tool(
    retriever,
    "langsmith_search",
    "搜索与LangSmith相关的信息。有关LangSmith的任何问题,您必须使用此工具!",
)
# search = TavilySearchResults() 暂不使用此工具
tools = [retriever_tool ]
 
 
# 3. 创建代理人
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 = FastAPI(
  title="LangChain服务器",
  version="1.0",
  description="使用LangChain的可运行接口的简单API服务器",
)
 
# 5. 添加链路由
 
# 我们需要添加这些输入/输出模式,因为当前的AgentExecutor缺乏模式。
 
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

页面访问

每个LangServe服务都自带一个简单的内置UI,用于配置和调用具有流式输出和对中间步骤的可见性的应用程序。
请访问http://localhost:8000/agent/playground/(opens in a new tab) 传入与之前相同的问题 - “how can langsmith help with testing?” 它应该与之前的响应一样。
 

4.2. 创建客户端

使用langserve创建客户端

from langserve import RemoteRunnable
 
remote_chain = RemoteRunnable("http://localhost:8000/agent/")
remote_chain.invoke({
    "input": "how can langsmith help with testing?",
    "chat_history": []  # 提供空列表作为这是第一个调用
})

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值