当前位置:   article > 正文

4.应用层

4.应用层

应用层

应用层封装了整个项目的全部核心功能。我们基于 LangChain 提供的检索问答链,在 LLM 层、数据库层的基础上,实现了本项目检索问答链的封装。自定义的检索问答链除具备基本的检索问答功能外,也支持通过 model 参数来灵活切换使用的 LLM。我们实现了两个检索问答链,分别是有历史记录的 Chat_QA_Chain 和没有历史记录的 QA_Chain。

1. 加载向量数据库

使用和构建时相同的 Emedding

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

# 使用智谱 Embedding API
from zhipuai_embedding import ZhipuAIEmbeddings

from langchain.vectorstores.chroma import Chroma

从环境变量中加载 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']

加载向量数据库,其中包含了 ../../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
)
print(f"向量库中存储的数量:{vectordb._collection.count()}")
向量库中存储的数量:20

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

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

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

打印检索到的内容

for i, doc in enumerate(docs):
    print(f"检索到的第{i}个内容: \n {doc.page_content}", end="\n-----------------------------------------------------\n")

2. 创建一个 LLM

在这里,我们调用  API 创建一个 LLM

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

llm.invoke("请你自我介绍一下自己!")
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})

3. 构建检索问答链

from langchain.prompts import PromptTemplate

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

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

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

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})

创建检索 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 = "王阳明是谁?"

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

result = qa_chain({"query": question_1})
print("大模型+知识库后回答 question_1 的结果:")
print(result["result"])
  1. 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.
  2. warn_deprecated(
  3. 大模型+知识库后回答 question_1 的结果:
  4. 抱歉,我不知道南瓜书是什么。谢谢你的提问!
result = qa_chain({"query": question_2})
print("大模型+知识库后回答 question_2 的结果:")
print(result["result"])
  1. 大模型+知识库后回答 question_2 的结果:
  2. 我不知道王阳明是谁。
  3. 谢谢你的提问!

4.2 大模型自己回答的效果

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

### 基于大模型的问答
llm.predict(prompt_template)
  1. 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.
  2. warn_deprecated(
  3. '南瓜书是指一种关于南瓜的书籍,通常是指介绍南瓜的种植、养护、烹饪等方面知识的书籍。南瓜书也可以指一种以南瓜为主题的文学作品。'
prompt_template = """请回答下列问题:
                            {}""".format(question_2)

### 基于大模型的问答
llm.predict(prompt_template)

5. 添加历史对话的记忆功能

1. 记忆

使用 LangChain 中的储存模块,将先前的对话嵌入到语言模型中,使其具有连续对话的能力。使用 ConversationBufferMemory ,它保存聊天消息历史记录的列表,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(
    memory_key="chat_history",  # 与 prompt 的输入变量保持一致。
    return_messages=True  # 将以消息列表的形式返回聊天记录,而不是单个字符串
)

关于更多的 Memory 的使用,包括保留指定对话轮数、保存指定 token 数量、保存历史对话的总结摘要等内容,请参考 langchain 的 Memory 部分的相关文档。

2. 对话检索链(ConversationalRetrievalChain)

对话检索链(ConversationalRetrievalChain)在检索 QA 链的基础上,增加了处理对话历史的能力。

它的工作流程是:

  1. 将之前的对话与新问题合并生成一个完整的查询语句。
  2. 在向量数据库中搜索该查询的相关文档。
  3. 获取结果后,存储所有答案到对话记忆区。
  4. 用户可在 UI 中查看完整的对话流程。

这种链式方式将新问题放在之前对话的语境中进行检索,可以处理依赖历史信息的查询。并保留所有信 息在对话记忆中,方便追踪。

测试这个对话检索链的效果:

提出一个无历史对话的问题“这门课会学习 Python 吗?”,并查看回答。

from langchain.chains import ConversationalRetrievalChain

retriever=vectordb.as_retriever()

qa = ConversationalRetrievalChain.from_llm(
    llm,
    retriever=retriever,
    memory=memory
)
question = "我可以学习到关于提示工程的知识吗?"
result = qa({"question": question})
print(result['answer'])
是的,您可以学习到关于提示工程的知识。本模块内容基于吴恩达老师的《Prompt Engineering for Developer》课程编写,旨在分享使用提示词开发大语言模型应用的最佳实践和技巧。课程将介绍设计高效提示的原则,包括编写清晰、具体的指令和给予模型充足思考时间等。通过学习这些内容,您可以更好地利用大语言模型的性能,构建出色的语言模型应用。

然后基于答案进行下一个问题“为什么这门课需要教这方面的知识?”:

question = "为什么这门课需要教这方面的知识?"
result = qa({"question": question})
print(result['answer'])
这门课程需要教授关于Prompt Engineering的知识,主要是为了帮助开发者更好地使用大型语言模型(LLM)来完成各种任务。通过学习Prompt Engineering,开发者可以学会如何设计清晰明确的提示词,以指导语言模型生成符合预期的文本输出。这种技能对于开发基于大型语言模型的应用程序和解决方案非常重要,可以提高模型的效率和准确性。

可以看到,LLM 它准确地判断了这方面的知识,指代内容是强化学习的知识,也就 是我们成功地传递给了它历史信息。这种持续学习和关联前后问题的能力,可大大增强问答系统的连续 性和智能水平。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/687778
推荐阅读
相关标签
  

闽ICP备14008679号