【动手学大模型开发 18】使用LangChian构建检索问答链(RAG)

🌈 嗨,我是青松,很高兴遇到你!

🌟 希望用我的经验,让每个人的AI学习之路走的更容易些~

🔥 专栏:大模型(LLMs)高频面题全面整理(★2025最新版★)


目录

1. 加载向量数据库

2. 创建一个 LLM

3. 构建检索问答链

4.检索问答链效果测试

4.1 基于召回结果和 query 结合起来构建的 prompt 效果

4.2 大模型自己回答的效果


在之前的章节,我们已经介绍了如何根据自己的本地知识文档,搭建一个向量知识库。 在接下来的内容里,我们将使用搭建好的向量数据库,对 query 查询问题进行召回,并将召回结果和 query 结合起来构建 prompt,输入到大模型中进行问答。

1. 加载向量数据库

首先,我们加载在前一章已经构建的向量数据库。注意,此处你需要使用和构建时相同的 Emedding。

import sys
sys.path.append("../C3 搭建知识库") # 将父目录放入系统路径中

# 使用智谱 Embedding API,注意,需要将上一章实现的封装代码下载到本地
from zhipuai_embedding import ZhipuAIEmbeddings

from langchain.vectorstores.chroma import ChromaCopy to clipboardErrorCopied

从环境变量中加载你的 API_KEY

from dotenv import load_dotenv, find_dotenv
import os

_ = load_dotenv(find_dotenv())    # read local .env file
zhipuai_api_key = os.environ['ZHIPUAI_API_KEY']Copy to clipboardErrorCopied

加载向量数据库,其中包含了 ../../data_base/knowledge_db 下多个文档的 Embedding

# 定义 Embeddings
embedding = ZhipuAIEmbeddings()

# 向量数据库持久化路径
persist_directory = '../C3 搭建知识库/data_base/vector_db/chroma'

# 加载数据库
vectordb = Chroma(
    persist_directory=persist_directory,  # 允许我们将persist_directory目录保存到磁盘上
    embedding_function=embedding
)Copy to clipboardErrorCopied
print(f"向量库中存储的数量:{vectordb._collection.count()}")Copy to clipboardErrorCopied
向量库中存储的数量:20Copy to clipboardErrorCopied

我们可以测试一下加载的向量数据库,使用一个问题 query 进行向量检索。如下代码会在向量数据库中根据相似性进行检索,返回前 k 个最相似的文档。

⚠️使用相似性搜索前,请确保你已安装了 OpenAI 开源的快速分词工具 tiktoken 包:pip install tiktoken

question = "什么是prompt engineering?"
docs = vectordb.similarity_search(question,k=3)
print(f"检索到的内容数:{len(docs)}")Copy to clipboardErrorCopied
检索到的内容数:3Copy to clipboardErrorCopied

打印一下检索到的内容

for i, doc in enumerate(docs):
    print(f"检索到的第{i}个内容: \n {doc.page_content}", end="\n-----------------------------------------------------\n")Copy to clipboardErrorCopied
检索到的第0个内容: 
 相反,我们应通过 Prompt 指引语言模型进行深入思考。可以要求其先列出对问题的各种看法,说明推理依据,然后再得出最终结论。在 Prompt 中添加逐步推理的要求,能让语言模型投入更多时间逻辑思维,输出结果也将更可靠准确。

综上所述,给予语言模型充足的推理时间,是 Prompt Engineering 中一个非常重要的设计原则。这将大大提高语言模型处理复杂问题的效果,也是构建高质量 Prompt 的关键之处。开发者应注意给模型留出思考空间,以发挥语言模型的最大潜力。

2.1 指定完成任务所需的步骤

接下来我们将通过给定一个复杂任务,给出完成该任务的一系列步骤,来展示这一策略的效果。

首先我们描述了杰克和吉尔的故事,并给出提示词执行以下操作:首先,用一句话概括三个反引号限定的文本。第二,将摘要翻译成英语。第三,在英语摘要中列出每个名称。第四,输出包含以下键的 JSON 对象:英语摘要和人名个数。要求输出以换行符分隔。
-----------------------------------------------------
检索到的第1个内容: 
 第二章 提示原则

如何去使用 Prompt,以充分发挥 LLM 的性能?首先我们需要知道设计 Prompt 的原则,它们是每一个开发者设计 Prompt 所必须知道的基础概念。本章讨论了设计高效 Prompt 的两个关键原则:编写清晰、具体的指令和给予模型充足思考时间。掌握这两点,对创建可靠的语言模型交互尤为重要。

首先,Prompt 需要清晰明确地表达需求,提供充足上下文,使语言模型准确理解我们的意图,就像向一个外星人详细解释人类世界一样。过于简略的 Prompt 往往使模型难以把握所要完成的具体任务。

其次,让语言模型有充足时间推理也极为关键。就像人类解题一样,匆忙得出的结论多有失误。因此 Prompt 应加入逐步推理的要求,给模型留出充分思考时间,这样生成的结果才更准确可靠。

如果 Prompt 在这两点上都作了优化,语言模型就能够尽可能发挥潜力,完成复杂的推理和生成任务。掌握这些 Prompt 设计原则,是开发者取得语言模型应用成功的重要一步。

一、原则一 编写清晰、具体的指令
-----------------------------------------------------
检索到的第2个内容: 
 一、原则一 编写清晰、具体的指令

亲爱的读者,在与语言模型交互时,您需要牢记一点:以清晰、具体的方式表达您的需求。假设您面前坐着一位来自外星球的新朋友,其对人类语言和常识都一无所知。在这种情况下,您需要把想表达的意图讲得非常明确,不要有任何歧义。同样的,在提供 Prompt 的时候,也要以足够详细和容易理解的方式,把您的需求与上下文说清楚。

并不是说 Prompt 就必须非常短小简洁。事实上,在许多情况下,更长、更复杂的 Prompt 反而会让语言模型更容易抓住关键点,给出符合预期的回复。原因在于,复杂的 Prompt 提供了更丰富的上下文和细节,让模型可以更准确地把握所需的操作和响应方式。

所以,记住用清晰、详尽的语言表达 Prompt,就像在给外星人讲解人类世界一样,“Adding more context helps the model understand you better.”。

从该原则出发,我们提供几个设计 Prompt 的技巧。

1.1 使用分隔符清晰地表示输入的不同部分
-----------------------------------------------------Copy to clipboardErrorCopied

2. 创建一个 LLM

在这里,我们调用 OpenAI 的 API 创建一个 LLM,当然你也可以使用其他 LLM 的 API 进行创建

import os 
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]Copy to clipboardErrorCopied
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model_name = "gpt-3.5-turbo", temperature = 0)

llm.invoke("请你自我介绍一下自己!")Copy to clipboardErrorCopied
AIMessage(content='你好,我是一个智能助手,专门为用户提供各种服务和帮助。我可以回答问题、提供信息、解决问题等等。如果您有任何需要,请随时告诉我,我会尽力帮助您的。感谢您的使用!', response_metadata={'token_usage': {'completion_tokens': 81, 'prompt_tokens': 20, 'total_tokens': 101}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3bc1b5746c', 'finish_reason': 'stop', 'logprobs': None})Copy to clipboardErrorCopied

3. 构建检索问答链

from langchain.prompts import PromptTemplate

template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
"""

QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
                                 template=template)
Copy to clipboardErrorCopied

再创建一个基于模板的检索链:

from langchain.chains import RetrievalQA

qa_chain = RetrievalQA.from_chain_type(llm,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
Copy to clipboardErrorCopied

创建检索 QA 链的方法 RetrievalQA.from_chain_type() 有如下参数:

  • llm:指定使用的 LLM
  • 指定 chain type : RetrievalQA.from_chain_type(chain_type="map_reduce"),也可以利用load_qa_chain()方法指定chain type。
  • 自定义 prompt :通过在RetrievalQA.from_chain_type()方法中,指定chain_type_kwargs参数,而该参数:chain_type_kwargs = {"prompt": PROMPT}
  • 返回源文档:通过RetrievalQA.from_chain_type()方法中指定:return_source_documents=True参数;也可以使用RetrievalQAWithSourceChain()方法,返回源文档的引用(坐标或者叫主键、索引)

4.检索问答链效果测试

question_1 = "什么是南瓜书?"
question_2 = "王阳明是谁?"Copy to clipboardErrorCopied

4.1 基于召回结果和 query 结合起来构建的 prompt 效果

result = qa_chain({"query": question_1})
print("大模型+知识库后回答 question_1 的结果:")
print(result["result"])Copy to clipboardErrorCopied
d:\Miniconda\miniconda3\envs\llm2\lib\site-packages\langchain_core\_api\deprecation.py:117: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.
  warn_deprecated(


大模型+知识库后回答 question_1 的结果:
抱歉,我不知道南瓜书是什么。谢谢你的提问!Copy to clipboardErrorCopied
result = qa_chain({"query": question_2})
print("大模型+知识库后回答 question_2 的结果:")
print(result["result"])Copy to clipboardErrorCopied
大模型+知识库后回答 question_2 的结果:
我不知道王阳明是谁。

谢谢你的提问!Copy to clipboardErrorCopied

4.2 大模型自己回答的效果

prompt_template = """请回答下列问题:
                            {}""".format(question_1)

### 基于大模型的问答
llm.predict(prompt_template)Copy to clipboardErrorCopied
d:\Miniconda\miniconda3\envs\llm2\lib\site-packages\langchain_core\_api\deprecation.py:117: LangChainDeprecationWarning: The function `predict` was deprecated in LangChain 0.1.7 and will be removed in 0.2.0. Use invoke instead.
  warn_deprecated(





'南瓜书是指一种关于南瓜的书籍,通常是指介绍南瓜的种植、养护、烹饪等方面知识的书籍。南瓜书也可以指一种以南瓜为主题的文学作品。'Copy to clipboardErrorCopied
prompt_template = """请回答下列问题:
                            {}""".format(question_2)

### 基于大模型的问答
llm.predict(prompt_template)Copy to clipboardErrorCopied
'王阳明(1472年-1529年),字宪,号阳明,浙江绍兴人,明代著名的哲学家、军事家、教育家、政治家。他提出了“致良知”、“格物致知”等重要思想,强调人的内心本具良知,只要发挥良知,就能认识道德真理。他的思想对后世影响深远,被称为“阳明心学”。'Copy to clipboardErrorCopied

⭐ 通过以上两个问题,我们发现 LLM 对于一些近几年的知识以及非常识性的专业问题,回答的并不是很好。而加上我们的本地知识,就可以帮助 LLM 做出更好的回答。另外,也有助于缓解大模型的“幻觉”问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值