|
文章目录前言一、安装LangChain二、获取千帆APIKey、SecretKey三、简单对话案例实现四、构建语言模型应用程序LM1.初始化模型2.LLM初始化和调用五、提示词模板(PromptTemplate):管理LLM的提示1.定义提示模板2.组合LLM和提示词3.组合输出解析器六、信息检索链(RetrievalChain)1.加载索引数据2.存储向量数据3.创建检索链传入问题4.使用检索器动态选择最相关的文档并将其传递5.完整代码及调用七、实现简单的聊天机器人1.聊天模型将使用消息进行响应。2.传入一个消息列表:3.使用ConversationChain记住过去的用户输入和模型输出4.对话5.聊天检索1)加载博客文章。2)将其拆分并存储在向量中3)创建会话记忆4)整体代码示例总结前言LangChain就是一个LLM编程框架,你想开发一个基于LLM应用,需要什么组件它都有,直接使用就行;甚至针对常规的应用流程,它利用链(LangChain中Chain的由来)这个概念已经内置标准化方案了。LangChain是一个用于开发由语言模型提供支持的应用程序的框架。它使应用程序能够:数据感知:将语言模型连接到其他数据源具有代理性质:允许语言模型与其环境交互名称网址LangChain中文网https://www.langchain.com.cn/LangChain官网https://www.langchain.com/LangChainAPI文档地址https://api.python.langchain.com/en/latest/langchain_api_reference.html#环境:名称版本Python3.9LangChain0.1.0一、安装LangChain此次我安装的最新版为:0.1.0pipinstalllangchain#安装qianfanpipinstallqianfan123二、获取千帆APIKey、SecretKey登录百度云搜索进入千帆大模型控制台没有应用则创建应用获取APIKey、SecretKey三、简单对话案例实现调用千帆大模型,实现让大模型讲个故事"""Forbasicinitandcall"""importosfromlangchain_community.chat_modelsimportQianfanChatEndpointfromlangchain_core.messagesimportHumanMessageos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"chat=QianfanChatEndpoint(streaming=True,)res=chat([HumanMessage(content="讲一个故事")])print(res.content)123456789101112131415输出结果如下:到此最简单的案例就已经实现了。四、构建语言模型应用程序LMLangChain最基本的构建块是对某些输入调用LLM。让我们来看一个简单的例子。我们假设我们正在构建一个基于公司产品生成公司名称的服务。1.初始化模型fromlangchain_community.llmsimportQianfanLLMEndpointos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"llm=QianfanLLMEndpoint(temperature=0.9)123452.LLM初始化和调用importosfromlangchain_community.llmsimportQianfanLLMEndpointos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"llm=QianfanLLMEndpoint(temperature=0.9)text="对于一家生产彩色袜子的公司来说,什么是一个好的公司名称?"print(llm.invoke(text))1234567891011五、提示词模板(PromptTemplate):管理LLM的提示调用LLM是很好的第一步,但这仅仅是个开始。通常在应用程序中使用LLM时,不会将用户输入直接发送到LLM。相反,您可能接受用户输入并构造一个提示符,然后将其发送给LLM。例如,在前一个示例中,我们传入的文本被硬编码为询问一家生产彩色袜子的公司的名称。在这个虚构的服务中,我们希望只获取描述公司业务的用户输入,然后用这些信息格式化提示符。1.定义提示模板ChatPromptTemplate:是聊天提示词模板ChatPromptTemplate文档地址fromlangchain_core.promptsimportChatPromptTemplateprompt=ChatPromptTemplate.from_messages([("user","我想去{location}旅游,能帮我简单介绍一下吗?")])123456782.组合LLM和提示词importosfromlangchain_community.llmsimportQianfanLLMEndpointfromlangchain_core.promptsimportChatPromptTemplateos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"llm=QianfanLLMEndpoint(temperature=0.9)prompt=ChatPromptTemplate.from_messages([("user","我想去{location}旅游,能帮我简单介绍一下吗?")])chat=prompt|llmresult=chat.invoke({"location":"海南"})print(result)12345678910111213141516171819203.组合输出解析器ChatModel(因此,此链)的输出是一条消息。但是,使用字符串通常要方便得多。让我们添加一个简单的输出解析器,将聊天消息转换为字符串。fromlangchain_core.output_parsersimportStrOutputParseroutput_parser=StrOutputParser()123我们现在可以将其添加到上一个链中:chain=prompt|llm|output_parser1我们现在可以调用它并提出相同的问题。答案现在将是一个字符串(而不是ChatMessage)。六、信息检索链(RetrievalChain)实现目标:提供一份文档,提出问题,在文档中检索出答案。我这里是提供了一个知乎-中国古代史-明朝的网址。我们将从检索器中查找相关文档,然后将它们传递到提示中。Retriever可以由任何东西支持——SQL表、互联网等——但在本例中,我们将填充一个向量存储并将其用作检索器。1.加载索引数据首先,我们需要加载要索引的数据:fromlangchain_community.document_loadersimportWebBaseLoaderWEB_URL="https://zhuanlan.zhihu.com/p/85289282"#使用WebBaseLoader加载HTMLloader=WebBaseLoader(WEB_URL)docs=loader.load()123452.存储向量数据接下来,我们需要将其索引到向量存储中。下载向量数据库Chromapipinstallchromadb1根据版本问题可能出现的问题:问题:Yoursystemhasanunsupportedversionofsqlite3.Chromarequiressqlite3>=3.35.0.解决方案:根据自己的操作系统在SQLiteDownloadPage下载最新的sqlite包,解压后是"sqlite3.def"和"sqlite3.dll"两个文件。将这两个文件覆盖到"python安装目录/DLLs"下即可。然后我们可以构建我们的索引:fromlangchain_community.vectorstoresimportChromafromlangchain_community.embeddingsimportQianfanEmbeddingsEndpointfromlangchain.text_splitterimportRecursiveCharacterTextSplitter#导入千帆向量模型embeddings=QianfanEmbeddingsEndpoint()#导入递归字符文本分割器text_splitter=RecursiveCharacterTextSplitter(chunk_size=384,chunk_overlap=0,separators=["\n\n","\n","","","。",","])#导入文本documents=text_splitter.split_documents(docs)#存入向量数据库vector=Chroma.from_documents(documents,embeddings)1234567891011123.创建检索链传入问题我们设置一个链,该链接受一个问题和检索到的文档并生成一个答案。fromlangchain.chains.combine_documentsimportcreate_stuff_documents_chain#创建提示词模板prompt=ChatPromptTemplate.from_template("""使用下面的语料来回答本模板最末尾的问题。如果你不知道问题的答案,直接回答"我不知道",禁止随意编造答案。为了保证答案尽可能简洁,你的回答必须不超过三句话,你的回答中不可以带有星号。请注意!在每次回答结束之后,你都必须接上"感谢你的提问"作为结束语以下是一对问题和答案的样例:请问:秦始皇的原名是什么秦始皇原名嬴政。感谢你的提问。以下是语料:{context}Question:{input}""")#创建千帆LLM模型llm=QianfanLLMEndpoint()#创建检索链document_chain=create_stuff_documents_chain(llm,prompt)123456789101112131415161718194.使用检索器动态选择最相关的文档并将其传递fromlangchain.chainsimportcreate_retrieval_chainretriever=vector.as_retriever()retrieval_chain=create_retrieval_chain(retriever,document_chain)12345.完整代码及调用importosfromlangchain.chainsimportcreate_retrieval_chainfromlangchain.chains.combine_documentsimportcreate_stuff_documents_chainfromlangchain_community.document_loadersimportWebBaseLoaderfromlangchain_community.embeddingsimportQianfanEmbeddingsEndpointfromlangchain_community.vectorstoresimportChromafromlangchain.text_splitterimportRecursiveCharacterTextSplitterfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_community.llmsimportQianfanLLMEndpointos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"#定义URLWEB_URL="https://zhuanlan.zhihu.com/p/85289282"#使用WebBaseLoader加载HTMLloader=WebBaseLoader(WEB_URL)docs=loader.load()#导入千帆向量模型embeddings=QianfanEmbeddingsEndpoint()#导入递归字符文本分割器text_splitter=RecursiveCharacterTextSplitter(chunk_size=384,chunk_overlap=0,separators=["\n\n","\n","","","。",","])#导入文本documents=text_splitter.split_documents(docs)#存入向量数据库vector=Chroma.from_documents(documents,embeddings)#创建提示词模板prompt=ChatPromptTemplate.from_template("""使用下面的语料来回答本模板最末尾的问题。如果你不知道问题的答案,直接回答"我不知道",禁止随意编造答案。为了保证答案尽可能简洁,你的回答必须不超过三句话,你的回答中不可以带有星号。请注意!在每次回答结束之后,你都必须接上"感谢你的提问"作为结束语以下是一对问题和答案的样例:请问:秦始皇的原名是什么秦始皇原名嬴政。感谢你的提问。以下是语料:{context}Question:{input}""")#创建千帆LLM模型llm=QianfanLLMEndpoint()#我们设置一个链,该链接受一个问题和检索到的文档并生成一个答案。document_chain=create_stuff_documents_chain(llm,prompt)#使用检索器动态选择最相关的文档并将其传递。retriever=vector.as_retriever()retrieval_chain=create_retrieval_chain(retriever,document_chain)#调用这个链了。这将返回一个字典-来自LLM的响应在键中answerresponse=retrieval_chain.invoke({"input":"朱元璋时期中国多少人口?"})print(response["answer"])123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354结果示例:抱歉,我无法得知朱元璋时期中国具体的人口数量。不过,我可以告诉你,在明朝时期,中国的人口数量在历史上经历了巨大的变化。明朝初年,由于元朝末年的战乱和瘟疫,人口数量相对较少。然而,随着时间的推移,明朝政府实行了一系列轻徭薄赋的政策,促进了社会经济的恢复和发展,人口数量也逐渐增加。在明朝中后期,由于农业、手工业和商业的繁荣,中国的人口数量达到了历史高峰。七、实现简单的聊天机器人使用普通聊天模型,我们可以通过传递一个消息或使用ChatModel发送更多消息。1.聊天模型将使用消息进行响应。importosfromlangchain.schemaimportHumanMessage,SystemMessagefromlangchain_community.chat_modelsimportQianfanChatEndpointos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"chat=QianfanChatEndpoint()res=chat.invoke([HumanMessage(content="把这句话从中文翻译成英语:我喜欢编程。")])print(res.content)123456789101112131415输出结果:Ienjoyprogramming.2.传入一个消息列表:importosfromlangchain.schemaimportHumanMessage,SystemMessagefromlangchain_community.chat_modelsimportQianfanChatEndpointos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"#使用默认的模型回答不正确,所以切换至模型:ERNIE-Bot-4chat=QianfanChatEndpoint(model='ERNIE-Bot-4',temperature=0.8)res=chat.invoke([SystemMessage(content="你是把中文翻译成英文的得力助手。"),HumanMessage(content="我喜欢编程。"),])print(res.content)12345678910111213141516输出结果:Ienjoyprogramming.3.使用ConversationChain记住过去的用户输入和模型输出然后,我们可以将聊天模型包装在ConversationChain中,它有内置内存,用于记住过去的用户输入和模型输出。importosfromlangchain.schemaimportHumanMessage,SystemMessagefromlangchain_community.chat_modelsimportQianfanChatEndpointfromlangchain.chainsimportConversationChainos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"chat=QianfanChatEndpoint(model='ERNIE-Bot-4',temperature=0.8)conversation=ConversationChain(llm=chat)res=conversation.invoke({"input":"你是把中文翻译成英文的得力助手:我喜欢编程"})print(res['response'])#结果为:toEnglish.Yoursentence"我喜欢编程"translatesto"Ienjoyprogramming."res2=conversation.invoke({"input":"把他翻译成德语"})print(res2)#结果为:将其翻译成德语为"IchgenießedasProgrammieren.1234567891011121314151617184.对话我们通过ConversationBufferMemory可以指定我们的对话记录此案例是指定对话记录,继续进行对话。importosfromlangchain_community.chat_modelsimportQianfanChatEndpointfromlangchain.chainsimportLLMChainfromlangchain.memoryimportConversationBufferMemoryfromlangchain_core.promptsimportChatPromptTemplate,SystemMessagePromptTemplate,MessagesPlaceholder,\HumanMessagePromptTemplateos.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"chat=QianfanChatEndpoint(model='ERNIE-Bot-4',temperature=0.8)prompt=ChatPromptTemplate.from_messages([SystemMessagePromptTemplate.from_template("你是一个聊天机器人"),MessagesPlaceholder(variable_name="chat_history"),HumanMessagePromptTemplate.from_template("{question}")])memory=ConversationBufferMemory(memory_key="chat_history",return_messages=True)memory.save_context({"input":"你好"},{"output":"你好,请问有什么我可以帮助你的吗?"})memory.save_context({"input":"把这句话从中文翻译成英语:我喜欢编程。"},{"output":"Ienjoyprogramming."})conversation=LLMChain(llm=chat,prompt=prompt,verbose=True,memory=memory)#注意,我们只是传入了“question”变量——“chat_history”由内存填充res=conversation.invoke({"question":"现在把这个句子译成德语。"})print(res)1234567891011121314151617181920212223242526272829输出结果如下:5.聊天检索现在,假设我们想要与文档或其他知识来源聊天。这是一个流行的用例,结合了聊天和文档检索。它允许我们与模型没有训练过的特定信息进行聊天。1)加载博客文章。fromlangchain_community.document_loadersimportWebBaseLoader#加载博客文章。loader=WebBaseLoader("https://zhuanlan.zhihu.com/p/85289282")data=loader.load()12342)将其拆分并存储在向量中fromlangchain.text_splitterimportRecursiveCharacterTextSplittertext_splitter=RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=0)all_splits=text_splitter.split_documents(data)fromlangchain_community.vectorstoresimportChromafromlangchain_openaiimportOpenAIEmbeddingsvectorstore=Chroma.from_documents(documents=all_splits,embedding=OpenAIEmbeddings())1234567893)创建会话记忆memory=ConversationSummaryMemory(llm=llm,memory_key="chat_history",return_messages=True)123fromlangchain.chainsimportConversationalRetrievalChainfromlangchain_openaiimportChatOpenAIllm=ChatOpenAI()retriever=vectorstore.as_retriever()qa=ConversationalRetrievalChain.from_llm(llm,retriever=retriever,memory=memory)1234564)整体代码示例#聊天检索importosfromlangchain_community.chat_modelsimportQianfanChatEndpointfromlangchain.chainsimportConversationChain,LLMChain,ConversationalRetrievalChainfromlangchain.memoryimportConversationBufferMemory,ConversationSummaryMemoryfromlangchain_community.embeddingsimportQianfanEmbeddingsEndpointfromlangchain_community.vectorstoresimportChromafromlangchain_community.document_loadersimportWebBaseLoaderfromlangchain.text_splitterimportRecursiveCharacterTextSplitteros.environ["QIANFAN_AK"]="API_KEY"os.environ["QIANFAN_SK"]="SECRET_KEY"#加载博客文章。loader=WebBaseLoader("https://zhuanlan.zhihu.com/p/85289282")data=loader.load()#将其拆分并存储在向量中。text_splitter=RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=0)all_splits=text_splitter.split_documents(data)#存储在向量中。vectorstore=Chroma.from_documents(documents=all_splits,embedding=QianfanEmbeddingsEndpoint())#像以前一样创建我们的记忆,但是让我们使用ConversationSummaryMemoryretriever=vectorstore.as_retriever()chat=QianfanChatEndpoint(model='ERNIE-Bot-4',temperature=0.8)memory=ConversationSummaryMemory(llm=chat,memory_key="chat_history",return_messages=True)qa=ConversationalRetrievalChain.from_llm(llm=chat,retriever=retriever,memory=memory)res=qa.invoke({"question":"请帮我出3个明朝的题目并给出答案"})print(res["answer"])1234567891011121314151617181920212223242526272829303132333435结果:总结LangCahin框架功能非常强大,但是要注意版本问题。在LangChain0.1.0版本之后很多写法就变了。英文官网上也是只有部分更新的新的写法,老写法也依然支持但是已经不推荐使用了。后续还会持续学习,会继续更新更多用法。存疑:由于是新手python选手,安装python环境直接使用最新的3.12版本装不上LangChain也换电脑试了还是不行被迫改为3.8或3.9。有懂的大佬可以评论讲解一下。本文很多文案和代码示例都来源于官网(略有修改),有一些文案翻译的不对凑活看吧。
|
|