、agent、langserve初探)
文章目录一. 架构二. 快速入门1. LLM ChainLLM问答步骤串联成链2. Retrieval Chain: 检索链检索文档来提供专业材料2.1. 检索链利用向量查询提供context2.2. 少样本学习增强LLM能力2.3. 深入了解3. 对话检索链可以连续问答的链3.1. 聊天机器人只支持两轮对话3.2. 代理人4. 使用LangServe进行服务4.1. 服务器4.2. 创建客户端LangChain本质上就是对各种大模型提供的API的套壳是为了方便我们使用这些API搭建起来的一些框架、模块和接口。一. 架构LangChain 简化了LLM应用程序生命周期的每个阶段二. 快速入门快速入门中我们将学到如下技能将从一个简单的LLM链开始它只依赖于提示模板中的信息来回复。我们将添加聊天记录以创建一个对话检索链。这使您可以以聊天方式与此LLM进行交互因此它会记住以前的问题。我们将构建一个代理该代理利用LLM来确定是否需要获取数据来回答问题。使用LangServe为您的应用程序提供服务1. LLM ChainLLM问答步骤串联成链实现了langchain调用openai使用OpenApi进行模型对话通过提示模版设置system来指导chat回答将上面的步骤组成调用链以便调用输出解析器使用字符提取器提取回答fromlangchain_openaiimportChatOpenAI# 1. 调用大模型# 通过langchain设置chatapillmChatOpenAI()llm.invoke(how can langsmith help with testing?)# 2. 使用提示模版更加专业的回答# 使用提示模板来指导其回答。 # 提示模板将原始用户输入转换为更好的输入以供LLM使用。fromlangchain_core.promptsimportChatPromptTemplate promptChatPromptTemplate.from_messages([(system,You are world class technical documentation writer.),(user,{input})])# 3. 引入字符解析器提取ChatMessage中的回答fromlangchain_core.output_parsersimportStrOutputParser output_parserStrOutputParser()#4. 将前面三步组成调用链chainprompt|llm|output_parser#5. 链调用Outputchain.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表、互联网等。在本例中我们将填充一个向量存储并将其用作检索器。有关向量存储的更多信息请参阅此文档。加载数据 加载数据使用BeautifulSoup(opens in a new tab)加载网页数据shell pip install beautifulsoup4数据加载到向量存储中生成索引需要嵌入模型和向量存储。文档分片使用嵌入模型将文档导入向量存储这里使用一个简单的本地向量存储FAISS。创建文档链用来创建问答链基于文本链与检索器创建检索链这样就能基于文档来回答具体问题。# 1. 加载要索引的数据。# 使用WebBaseLoader加载网页数据fromlangchain_community.document_loadersimportWebBaseLoader loaderWebBaseLoader(https://docs.smith.langchain.com/user_guide)docsloader.load()# 2. 文档分片并通过向量存储构建文档索引fromlangchain_openaiimportOpenAIEmbeddings embeddingsOpenAIEmbeddings()# FAISS轻量化的本地存储fromlangchain_community.vectorstoresimportFAISSfromlangchain_text_splittersimportRecursiveCharacterTextSplitter#文档分片text_splitterRecursiveCharacterTextSplitter()documentstext_splitter.split_documents(docs)# 分片数据添加索引vectorFAISS.from_documents(documents,embeddings)# 3. 创建文本检索链promptllm来接收文档和问题# 现在我们在向量存储中索引了这些数据我们将创建一个检索链。该链将接收一个输入问题查找相关文档然后将这些文档连同原始问题一起传递给LLM并要求它回答原始问题。fromlangchain_openaiimportChatOpenAI llmChatOpenAI()fromlangchain_core.promptsimportChatPromptTemplatefromlangchain.chains.combine_documentsimportcreate_stuff_documents_chain# 使用提示样本promptChatPromptTemplate.from_template(Answer the following question based only on the provided context: context {context} /context Question: {input})# 构建文本链document_chaincreate_stuff_documents_chain(llm,prompt)# 基于检索器来动态匹配最相关的文档并传递给指定问题fromlangchain.chainsimportcreate_retrieval_chain retrievervector.as_retriever()retrieval_chaincreate_retrieval_chain(retriever,document_chain)responseretrieval_chain.invoke({input:how can langsmith help with testing?})print(response[answer])2.2. 少样本学习增强LLM能力# 通过langchain设置chatapifromlangchain_openaiimportChatOpenAI llmChatOpenAI()fromlangchain_core.promptsimportChatPromptTemplatefromlangchain.chains.combine_documentsimportcreate_stuff_documents_chain# 使用提示样本promptChatPromptTemplate.from_template(Answer the following question based only on the provided context: context {context} /context Question: {input})# 构建文本链document_chaincreate_stuff_documents_chain(llm,prompt)# 少样本学习# 5.1. 直接基于写好的文档进行回答context# 如果我们想的话可以直接传递文档来运行它fromlangchain_core.documentsimportDocument document_chain.invoke({input:how can langsmith help with testing?,context:[Document(page_contentlangsmith can let you visualize test results)]})2.3. 深入了解我们现在已经成功设置了一个基本的检索链。我们只触及了检索的基础知识-要更深入地了解这里提到的所有内容请参阅文档的此部分。3. 对话检索链可以连续问答的链本节的目标是构建能多轮对话的聊天机器人我们仍然可以使用create_retrieval_chain函数但我们需要更改两件事情检索方法现在不仅适用于最近的输入而且还应考虑整个历史记录。最终的LLM链也应考虑整个历史记录3.1. 聊天机器人只支持两轮对话文档检索器构建# 1. 加载要索引的数据。 # 使用WebBaseLoader加载网页数据fromlangchain_community.document_loadersimportWebBaseLoader loaderWebBaseLoader(https://docs.smith.langchain.com/user_guide)docsloader.load()# 2. 文档分片并通过向量存储构建文档索引fromlangchain_openaiimportOpenAIEmbeddings embeddingsOpenAIEmbeddings()# FAISS轻量化的本地存储fromlangchain_community.vectorstoresimportFAISSfromlangchain_text_splittersimportRecursiveCharacterTextSplitter#文档分片text_splitterRecursiveCharacterTextSplitter()documentstext_splitter.split_documents(docs)# 分片数据添加索引vectorFAISS.from_documents(documents,embeddings)# 索引转为检索器fromlangchain.chainsimportcreate_retrieval_chain retrievervector.as_retriever()构建多轮对话fromlangchain.chains.combine_documentsimportcreate_stuff_documents_chainfromlangchain_core.messagesimportHumanMessage,AIMessagefromlangchain_openaiimportChatOpenAI llmChatOpenAI()fromlangchain.chainsimportcreate_history_aware_retrieverfromlangchain_core.promptsimportMessagesPlaceholder,ChatPromptTemplate# 1. 更新检索器promptChatPromptTemplate.from_messages([MessagesPlaceholder(variable_namechat_history),(user,{input}),(user,根据上面的对话生成一个搜索查询来获取与对话相关的信息)])# 接收对话历史并返回文档的chain# retriever上面创建的数据索引retriever_chaincreate_history_aware_retriever(llm,# 大模型retriever,# 文档检索器prompt)# 有历史对话并能基于历史对话来生成搜索查询能够补全下面的问题# 2. 基于新的检索器创建新的链有文档检索能力# 由聊天记录生成的promptpromptChatPromptTemplate.from_messages([(system,根据下面的上下文回答用户的问题\n\n{context}),MessagesPlaceholder(variable_namechat_history),(user,{input}),])# 对话链document_chaincreate_stuff_documents_chain(llm,prompt)retrieval_chaincreate_retrieval_chain(retriever_chain,# 有历史对话的检索链document_chain)# 对话链# 3. 新链测试# 封装的历史对话之后通过Memory来实现chat_history[HumanMessage(contentCan LangSmith help test my LLM applications?),AIMessage(contentYes!)]retrieval_chain.invoke({chat_history:chat_history,# todo存储历史文件input:Tell me how})由聊天记录生成的prompt将历史对话都添加到message中只支持两轮我们可以看到这给出了一个连贯的答案-我们已成功将我们的检索链转变为一个聊天机器人3.2. 代理人本文我们将创建一个代理人 - 在这种情况下LLM决定要采取的步骤。创建工具fromlangchain.tools.retrieverimportcreate_retriever_tool retriever_toolcreate_retriever_tool(retriever,langsmith_search,搜索与LangSmith相关的信息。有关LangSmith的任何问题您必须使用此工具,)创建代理人有了工具我们可以创建一个代理人来使用它们。深入了解请查看代理人入门文档。首先安装langchain hubpip install langchainhub pip install langchain-openaifromlangchain.tools.retrieverimportcreate_retriever_tool# 1. 封装成工具retriever_toolcreate_retriever_tool(retriever,langsmith_search,搜索与LangSmith相关的信息。有关LangSmith的任何问题您必须使用此工具,)# tools [retriever_tool]fromlangchain_openaiimportChatOpenAIfromlangchainimporthubfromlangchain.agentsimportcreate_openai_functions_agentfromlangchain.agentsimportAgentExecutor# 加载官方提示prompthub.pull(hwchase17/openai-functions-agent)# 2. 创建agentor# 您需要设置OPENAI_API_KEY环境变量或者将其作为参数api_key传递。llmChatOpenAI(modelgpt-3.5-turbo,temperature0)agentcreate_openai_functions_agent(llm,tools,prompt)agent_executorAgentExecutor(agentagent,toolstools,verboseTrue)我们现在成功地设置了一个基本的agentor。我们只触及了代理人的基础知识 - 如果您想更深入地了解这里提到的所有内容请参阅文档的这一部分。4. 使用LangServe进行服务LangServe帮助开发人员将LangChain链部署为REST API。使用以下命令安装LangServepipinstalllangserve[all]4.1. 服务器我们用serve.py文件来创建一个服务器。其中包含用于提供我们的应用程序的逻辑。它由以下三个部分组成我们刚刚构建的链的定义我们的FastAPI应用程序定义一个路径以提供链的那部分代码可以使用langserve.add_routes来实现#!/usr/bin/env pythonfromtypingimportListfromfastapiimportFastAPIfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain_community.document_loadersimportWebBaseLoaderfromlangchain_openaiimportOpenAIEmbeddingsfromlangchain_community.vectorstoresimportFAISSfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain.tools.retrieverimportcreate_retriever_toolfromlangchain_community.tools.tavily_searchimportTavilySearchResultsfromlangchainimporthubfromlangchain.agentsimportcreate_openai_functions_agentfromlangchain.agentsimportAgentExecutorfromlangchain.pydantic_v1importBaseModel,Fieldfromlangchain_core.messagesimportBaseMessagefromlangserveimportadd_routes# 1. 加载检索器loaderWebBaseLoader(https://docs.smith.langchain.com/user_guide)docsloader.load()text_splitterRecursiveCharacterTextSplitter()documentstext_splitter.split_documents(docs)embeddingsOpenAIEmbeddings()vectorFAISS.from_documents(documents,embeddings)retrievervector.as_retriever()# 2. 创建工具retriever_toolcreate_retriever_tool(retriever,langsmith_search,搜索与LangSmith相关的信息。有关LangSmith的任何问题您必须使用此工具,)# search TavilySearchResults() 暂不使用此工具tools[retriever_tool]# 3. 创建代理人prompthub.pull(hwchase17/openai-functions-agent)llmChatOpenAI(modelgpt-3.5-turbo,temperature0)agentcreate_openai_functions_agent(llm,tools,prompt)agent_executorAgentExecutor(agentagent,toolstools,verboseTrue)# 4. 应用程序定义appFastAPI(titleLangChain服务器,version1.0,description使用LangChain的可运行接口的简单API服务器,)# 5. 添加链路由# 我们需要添加这些输入/输出模式因为当前的AgentExecutor缺乏模式。classInput(BaseModel):input:strchat_history:List[BaseMessage]Field(...,extra{widget:{type:chat,input:location}},)classOutput(BaseModel):output:stradd_routes(app,agent_executor.with_types(input_typeInput,output_typeOutput),path/agent,)if__name____main__:importuvicorn uvicorn.run(app,hostlocalhost,port8000)执行python serve.py页面访问每个LangServe服务都自带一个简单的内置UI用于配置和调用具有流式输出和对中间步骤的可见性的应用程序。请访问http://localhost:8000/agent/playground/(opens in a new tab) 传入与之前相同的问题 - “how can langsmith help with testing?” 它应该与之前的响应一样。4.2. 创建客户端使用langserve创建客户端fromlangserveimportRemoteRunnable remote_chainRemoteRunnable(http://localhost:8000/agent/)remote_chain.invoke({input:how can langsmith help with testing?,chat_history:[]# 提供空列表作为这是第一个调用})要了解有关LangServe的许多其他功能的更多信息请在此处查看。