使用 LangChain 可以方便的创建内部知识库系统,让 AI 可以准确的利用提供的资料作为上下文解决实际问题
大体上,软件加载文档、分析数据的流程大体分为加载、切分、嵌入、检索、查询等过程
这里应当使用各种 AI 中的 Embedding 模型
加载
langchain_community.document_loaders 包下存在对 PyPDF,Docx2txt 等工具库的包装,可直接将多种不同类型文档加载为 Document 对象
片段中 documents 是一个用于存储读取结果的 Document 数组,后面切分时可以直接对整个数组进行切分处理
切分
将文档切为多个片段以符合 AI 提问时的长度限制。
文档切分使用 langchain.text_splitter 包下的工具即可。RecursiveCharacterTextSplitter 可用于按照给定字符切分字段(split),并将长度限定在给定大小(chunk_size)之内,支持对 Document[] 和字符串进行切分
嵌入
Embedding,将切分后的文本转换成词嵌入的形式,存储到向量数据库中,默认使用 Qdrant
[!note] 词嵌入:Word Embedding,将文字转换为一系列数字,通常为向量。向量参考其含义和上下文,语义上相似或相关的词坐标也接近。
通过 Embeddings 对象实现词嵌入过程(embed_query 方法),可直接将其传入 VectorStore 向量数据库客户端实现类即可。
Embeddings用于具体词嵌入过程,langchain提供用于各类 AI 的实现类,也可以自己实现VectorStore用于存储文档片段和生成的向量,langchain提供多种数据库实现,详见langchain_community/vectorstores/__init__.py
异常:has no len()
[!error] TypeError: object of type 'NoneType' has no len()
使用内置的 Embeddings 类,需要有 Embedding 服务(文本向量化)的 Token,否则会产生一个没有相关授权的异常
自定义 Embedding 类
继承自 BaseModel 和 Embeddings,需要实现 embed_query 和 embed_documents 方法,分别用于对于单个文档和文档数组的嵌入。
一般来说,只需要调用对应 AI 的词嵌入接口即可
检索
Retrieval,提问时,根据问题与文档片段的相关性,从数据库中找到与问题相关的嵌入片。
相关性
根据片段的向量特征确定相似或相关性,通常使用欧氏距离或余弦相似度判断
- 欧氏距离相似度:计算两个坐标之间的距离,同时反应两个片段的绝对差异,同时考虑语义和数量上的关联性
- 余弦相似度:以两个向量之间的夹角为标准,仅考虑两个片段意义上的相似性
RetrievalQA 链
表示一种检索性问答模型,用于生成答案,包含 LLM 和 retriever 两部分
- LLM:大模型对象,负责回答问题
- retriever:负责提供嵌入片,通过前面
VectorStore的as_retriever()获取
# 实例化一个大模型工具 - OpenAI的GPT-3.5
llm = ChatOpenAI(model=os.environ["LLM_MODELEND"], temperature=0)
# 实例化一个MultiQueryRetriever
retriever_from_llm = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(), llm=llm
)
# 实例化一个RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever_from_llm)
# RetrievalQA链 - 读入问题,生成答案
result = qa_chain({"query": question})