【langchain】构建简单检索问答链
文章目录
- 说明
- 1 加载向量数据库(Chroma + textV4Embeddings)
- 2 构建简单检索链
- 2.1 定义向量检索器(RunnableLamdba)
- 2.2 构建简单检索链(管道机制)
- 3 定义LLM(以 qwen-plus 为例)
- 4 定义提示词模板(PromptTemplate)
- 4 组装完整的简单检索问答链(RAG)(使用LCEL语法连接各种组件)
- 测试
本文内容的复现需要一定的基础。在本系列文章中,已单独出过plog的部分,将不再赘述,如有不懂,请移步专栏查找。点击直通车>>>>
说明
LangChain 是一个用于开发基于大模型(LLM)应用的框架,它提供了丰富的工具和组件来简化 LLM 应用的构建过。
核心概念
-
Components 组件。提供各种基础构建块,如:
PromptTemplate
:用于创建和管理提示词的模板
LLM
和ChatModel
:封装各种大模型的接口
OutputParser
:解析模型输出
Retriever
:实现信息检索功能功能 -
Chains(链)
将多个组件组合成可执行的工作流(Runable
类的才行)
支持顺序执行、并行执行(RunnableParallel
)等不同模式
LCEL(全称:LangChain Expression Language)提供了简洁的链式调用语法 -
Data Connection(数据连接)
提供与外部数据源的连接能力
包括文档加载其、文本分割器、向量存储集成等
支持检索增强生成(RAG,retrieval-Augmented Generation)模式
主要优势
- 模块化设计:各个组件可以灵活组合
- 标准化接口:统一的 API 简化了不同模型和服务的集成
- 内置最佳实践:集成了 LLM 应用开发的最佳实践
- 扩展性强:支持自定义组件和第三方集成
1 加载向量数据库(Chroma + textV4Embeddings)
该部分详解见【langchain】构建向量数据库并存入数据,以chroma为例
实例化数据库,并告诉数据库采用的嵌入模型
from demo import textV4Embeddings
from langchain.vectorstores import Chroma
import osos.getenv("DASHSCOPE_API_KEY") # 加载环境变量(前提是已设置环境变量)
persist_directory = "D:\dev_gitee\embedding-example\data_base\\vector_db" # 数据库地址"""所使用的嵌入模型。这个需要与数据库中的向量数据保持一致"""
embeddings = textV4Embeddings()
"""加载本地db"""
vectorstore = Chroma(persist_directory=persist_directory,embedding_function=embeddings)
2 构建简单检索链
2.1 定义向量检索器(RunnableLamdba)
"""核心代码"""
retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 关键语句:as_retriever()转为向量检索器,search_kwargs={"k": 3}指定返回前3相似度的向量数量"""测试代码:问题检索"""
question = "什么是prompt engineering?"
docs = retriever.invoke(question) # 返回类型依旧是 List[document]
2.2 构建简单检索链(管道机制)
从 2.1 的输出知道,检索器的检索结果是List
类型,后续使用需要将每个Document
的page_content
部分进行组装合并。即,拼接docs[i].page_content
。
- 定义一个合并器
from langchain_core.runnables import RunnableLambdadef combine_docs(docs):return "\n\n".join([doc.page_content for doc in docs])
combiner = RunnableLambda(func=combine_docs) # 创建一个可运行的组件,合并器【问答链每个部分都需要属于Runnable大类】
- 组装检索器和合并器
retriever_chain = retriever | combiner # 将检索器和合并器进拼接
retriever_chain.invoke(question)
3 定义LLM(以 qwen-plus 为例)
LLM实例化仅供参考,不同平台以及模型有所差异。
import os
from langchain_openai import ChatOpenAI"""核心代码"""
chatLLM = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-plus",temperature=0,)"""测试代码:问答模拟"""
messages=[{"role": "user", "content": "请你自我介绍一下自己!"}]
chatLLM.invoke(messages) # 如果只要内容部分,就写chatLLM.invoke(messages).content
4 定义提示词模板(PromptTemplate)
from langchain_core.prompts import PromptTemplate"""模板格式"""
template="使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答案。最多使用三句话。尽量使答案简明扼要。请你在回答的最后说“谢谢你的提问!”。{context}问题:{input}"
"""将template 通过PromptTemplate 转换为prompt,使得可以在LCEL中使用"""
prompt = PromptTemplate.from_template(template)
4 组装完整的简单检索问答链(RAG)(使用LCEL语法连接各种组件)
这里就组装前面所有的东西。
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_core.output_parsers import StrOutputParser"""检索问答链:
将之前的检索链retriever_chain作为context,使用RunnablePassthrough存储用户问题作为prompt的input(使用RunnableParallel并行处理)
将prompt给llm
StrOutputParser()将模型的输出解析为纯字符串格式移除任何额外的格式或元数据,只返回干净的回答文本"""
qa_chain = (RunnableParallel({"context": retriever_chain, "input": RunnablePassthrough()})| prompt| chatLLM| StrOutputParser())
RunnablePassthrough
功能:输入什么就输出什么
用途:通常用于在链中传递原始输入或保持某些数据不变
工作方式:接收输入并原样输出,常用于链的分支或保持上下文
RunnableParallel
功能:并行执行多个可运行组件
用途:同时运行多个操作,提高效率
工作方式:接收输入后,将输入分发给多个组件并行处理,然后合并结果
测试
question_1 = "什么是南瓜书?"
print("大模型+知识库后的回答:",qa_chain.invoke(question_1))question_2 = "prompt engineering for Developer是谁写的?"
print("大模型+知识库后的回答:",qa_chain.invoke(question_2))
下篇文章,讲解构建带聊天记录的检索问答链。