赞
踩
微信公众号:淼学派对
CSDN:淼学派对
哔哩哔哩:淼学派对
各大博客社区:淼学派对
百度智能云千帆大模型平台官方SDK正式对外发布:https://pypi.org/project/qianfan/。同步支持langchain接入千帆api。
本文重点介绍基于langchain+千帆sdk的一个基于文档的QA问答Demo。
可以直接下载Demo,只需修改step0的ak和sk,即可顺利跑完整个demo。
https://bce-doc-on.bj.bcebos.com/qianfanshequ/qianfan-langchain-QA-demo.zip
lanchain >= 0.0.292
qianfan >= 0.0.3
python >= 3.7
此处展示了如何使用 Langchian + 千帆 SDK 完成对特定文档完成获取、切分、转为向量并存储,而后根据你的提问来从文中获取答案。
并且借助 Langsmith 将整个过程可视化展现。
把一个非结构化的文档转成问答链涉及以下步骤:
Loading: 首先我们需要加载数据,非结构化的数据可以从多种渠道加载。LangChain integration hub 查看所有 Langchain 支持的 Loader。
每个 Loader 都会返回 Langchian 中的 Document 对象。
Splitting: 文本切分器 把 Documents 切分成特定的大小。
Storage: Storage (例如 vectorstore)会将切分的数据储存起来,通常还附带对文本做 embedding 。
Retrieval: 用于从 Storage 中获取切分的数据,用于后面生成答案。
Generation: 使用提示词和获取到的数据,搭配 LLM 来生成回答。
Conversation (扩展): 添加 Memory 模块来在你的问答链上实现多轮对话。
接下来我们会演示如何一步步构造我们自己的流水线,并且实现我们自己定制化的功能
为了能够运行我们的 Demo,首先我们需要下载依赖并且设置环境变量
- !pip list | grep langchain
- !pip list | grep qianfan
- !pip install langchain !pip install qianfan
实例代码:
- import os
- os.environ['QIANFAN_AK'] = "your_api_key"
- os.environ['QIANFAN_SK'] = "your_secret_key"
- # 此处为 Langsmith 相关功能开关。当且仅当你知道这是做什么用时,可删除注释并设置变量以使用 Langsmith 相关功能
- # os.environ['LANGCHAIN_TRACING_V2'] = "true"
- # os.environ['LANGCHAIN_ENDPOINT'] = "https://api.smith.langchain.com"
- # os.environ['LANGCHAIN_API_KEY'] = "your_langchian_api_key"
- # os.environ['LANGCHAIN_PROJECT'] = "your_project_name"
- is_chinese = True
- if is_chinese:
- WEB_URL = "https://zhuanlan.zhihu.com/p/85289282"
- CUSTOM_PROMPT_TEMPLATE = """
- 使用下面的语料来回答本模板最末尾的问题。如果你不知道问题的答案,直接回答 "我不知道",禁止随意编造答案。
- 为了保证答案尽可能简洁,你的回答必须不超过三句话。
- 请注意!在每次回答结束之后,你都必须接上 "感谢你的提问" 作为结束语
- 以下是一对问题和答案的样例:
- 请问:秦始皇的原名是什么
- 秦始皇原名嬴政。感谢你的提问。
- 以下是语料:
- {context}
- 请问:{question}
- """
- QUESTION1 = "明朝的开国皇帝是谁"
- QUESTION2 = "朱元璋是什么时候建立的明朝"
- else:
- WEB_URL = "https://lilianweng.github.io/posts/2023-06-23-agent/"
- CUSTOM_PROMPT_TEMPLATE = """
- Use the following pieces of context to answer the question at the end.
- If you don't know the answer, just say that you don't know, don't try to make up an answer.
- Use three sentences maximum and keep the answer as concise as possible.
- Always say "thanks for asking!" at the end of the answer.
- {context}
- Question: {question}
- Helpful Answer:
- """
- QUESTION1 = "How do agents use Task decomposition?"
- QUESTION2 = "What are the various ways to implemet memory to support it?"

指定一个 DocumentLoader 来把你指定的非结构化数据加载成 Documents。一个 Document 是文字(即 page_content)和与之相关的元数据的结合体
- from langchain.document_loaders import WebBaseLoader
- loader = WebBaseLoader(WEB_URL)
- data = loader.load()
接下来把 Document 切分成块,为后续的 embedding 和存入向量数据库做准备。
- from langchain.text_splitter import RecursiveCharacterTextSplitter
-
- text_splitter = RecursiveCharacterTextSplitter(chunk_size = 384, chunk_overlap = 0, separators=["\n\n", "\n", " ", "", "。", ","])
- all_splits = text_splitter.split_documents(data)
为了能够查询文档的片段,我们首先需要把它们存储起来,一种比较常见的做法是对文档的内容做 embedding,然后再将 embedding 的向量连同文档一起存入向量数据库中,此处 embedding 用于索引文档。
- from langchain.embeddings import QianfanEmbeddingsEndpoint
- from langchain.vectorstores import Chroma
- vectorstore = Chroma.from_documents(documents=all_splits, embedding=QianfanEmbeddingsEndpoint())
除了非结构化的文档以外,Langchain 还可以从多种数据源获取数据并将它们存储起来。
我们可以使用 相似度搜索 来从切分的文档内获取数据,获取到的数据会作为最终提交给 LLM 的 prompt 的一部分。
- # 基于prompt问题查找相似文档
- print("prompt问题:"+QUESTION1)
- docs = vectorstore.similarity_search_with_relevance_scores(QUESTION1)
- [(document.page_content, score) for document, score in docs]
接下来我们就可以使用我们的大模型(例如文心一言)和 Langchain 的 RetrievalQA 链,来针对这篇文档进行提问并获取我们想要的回答了。
- from langchain.chains import RetrievalQA
- from langchain.chat_models import QianfanChatEndpoint
- from langchain.prompts import PromptTemplate
-
- QA_CHAIN_PROMPT = PromptTemplate.from_template(CUSTOM_PROMPT_TEMPLATE)
-
- llm = QianfanChatEndpoint(streaming=True)
- retriever=vectorstore.as_retriever(search_type="similarity_score_threshold", search_kwargs={'score_threshold': 0.0})
-
- qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={"prompt": QA_CHAIN_PROMPT})
- qa_chain({"query": QUESTION1})
注意,此处不光可以传入 ChatModel ,也可以传入一个 LLM 对象到 RetrievalQA 中。并且通过代码我们可以看到,用户可以通过传入额外的命名参数字典来自定义我们所需使用的 prompt 模板
用于 QA 的知识文档也可以通过指定 return_source_documents=True 被包含在返回的字典里
- from langchain.chains import RetrievalQA
-
- qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}, return_source_documents=True)
- result = qa_chain({"query": QUESTION1})
- len(result['source_documents'])
- result['source_documents']
我们还可以加入 Memory 模块并替换使用 ConversationalRetrievalChain 来实现记忆化的对话式查询。
- from langchain.memory import ConversationSummaryMemory
- from langchain.chains import ConversationalRetrievalChain
-
- memory = ConversationSummaryMemory(llm=llm,memory_key="chat_history",return_messages=True)
- qa = ConversationalRetrievalChain.from_llm(llm, retriever=retriever, memory=memory, combine_docs_chain_kwargs={"prompt": QA_CHAIN_PROMPT})
- qa(QUESTION1)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。