Key Words
LangChain提供了方便的组件库可以将LLM模型与各种外部数据源(图片、PDF、视频、邮件...)进行连接。并提供了一个工具链,可以指导LLM执行一系列的任务(简单的对于文件查询、复杂的对于行业知识图谱的搜集)。从而为LLM扩展了更多的能力。
涉及知识点
- 如何实现对不同LLM支持对接。通过Api、自定义LLM Wrapper的方式和闭源、开源模型交互;
- 外部非结构化数据源导入;
- 数据Embedding。尤其是对中文场景下向量相似度区分;
- 利用向量数据库进行数据检索;
- Prompt管理,自定义模板设计。如果通过零样本、小样本、示例等方式设计Prompt;
LangChain是什么?起到什么作用?
LLM模型本身已经掌握了一定的知识。但是如果想让模型对一些“它”不了解的内容进行回复时。我们需要先要告知模型一些“额外”的内容(当然也可以通过预训练和finetunin的方式对LLM进行微调、这个可以再另一篇文章做说明)。这些“额外”的内容可能是一份PDF文档、或者是某个视频。这些就是“外部知识库”。我们期望LLM可以帮我们对这些“外部知识库”进行的问答、总结。这个时候就可以用到LangChain。
简单说LangChain的作用如下:
- 可以将 LLM 模型与外部数据源进行连接
- 提供一些组件可以更高效的和 LLM 模型进行交互。比如对向量数据库的支持。
LangChain 包含的组件
组件说明
本文并不会对LangChain所包含的组件进行详细的说明。本次主要涉及Models、Indexes、Prompts 3个组件(其他组件另开章节再说,也可以参考可以参考 LangChain Doc 文档 - Pyhton)。Models主要负责和本地以及在线LLM的交互。Indexe主要负责和外部数据源以及向量数据库打交道。Prompts是给LLM更精准的输入信息以及输出格式。
简单举例介绍-爬取网页并输出JSON数据
LLMRequestsChain 是 LangChain提供的一个API。可以直接取得访问URL的Html内容并进行解解析。参考链接:LangChain-LLMRequestsChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.chains import LLMRequestsChain, LLMChain
# 和OpenAI的GPT 模型进行交互。
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)
# 构造Prompt 模版
template = """在 >>> 和 <<< 之间是网页的返回的HTML内容。
网页是新浪财经A股上市公司的公司简介。
请抽取参数请求的信息。
>>> {requests_result} <<<
请使用如下的JSON格式返回数据
{{
"company_name":"a",
"company_english_name":"b",
"issue_price":"c",
"date_of_establishment":"d",
"registered_capital":"e",
"office_address":"f",
"Company_profile":"g"
}}
Extracted:"""
prompt = PromptTemplate(
input_variables=["requests_result"],
template=template
)
# 利用LLMRequestsChain 访问Url
chain = LLMRequestsChain(llm_chain=LLMChain(llm=llm, prompt=prompt))
inputs = {
"url": "https://vip.stock.finance.sina.com.cn/corp/go.php/vCI_CorpInfo/stockid/600519.phtml"
}
response = chain(inputs)
print(response['output'])
# 返回结果
{
"company_name":"贵州茅台酒股份有限公司",
"company_english_name":"Kweichow Moutai Co.,Ltd.",
"issue_price":"31.39",
"date_of_establishment":"1999-11-20",
"registered_capital":"125620万元(CNY)",
"office_address":"贵州省仁怀市茅台镇",
"Company_profile":"公司是根据贵州省人民政府黔府函〔1999〕291号文,由中国贵州茅台酒厂有限责任公司作为主发起人,联合贵州茅台酒厂技术开发公司、贵州省轻纺集体工业联社、深圳清华大学研究院、中国食品发酵工业研究院、北京市糖业烟酒公司、江苏省糖烟酒总公司、上海捷强烟草糖酒(集团)有限公司于1999年11月20日共同发起设立的股份有限公司。经中国证监会证监发行字[2001]41号文核准并按照财政部企[2001]56号文件的批复,公司于2001年7月31日在上海证券交易所公开发行7,150万(其中,国有股存量发行650万股)A股股票。主营业务:贵州茅台酒系列产品的生产与销售,饮料、食品、包装材料的生产与销售,防伪技术开发;信息产业相关产品的研制和开发等。"
}
案例-基于本地知识库的问答应用
本案例参考基于本地知识库的 ChatGLM 等大语言模型应用实现。利用 langchain 实现的基于本地知识库的问答应用。通过ChatGLM对一份本地的文档进行解析。并根据解析内容对用户输入的问题进行回答。
项目工程结构
加载ChatGlm模型
由于 LangChain 没有对 ChatGLM 的支持,需要用自定义LLM Wrapper的方式封装ChatGLM模型。官方的实现参考:How to write a custom LLM wrapper。 同时借鉴在huggingface上的实现。加载本地ChatGLM模型。
相关代码
model_name_or_path: str = "/root/autodl-tmp/model/chatglm-6b"
...
self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path,trust_remote_code=True)
model_config = AutoConfig.from_pretrained(model_name_or_path, trust_remote_code=True)
这里可以引申一个知识点,如何将ChatGLM进行本地化部署并通过本地Api对外提供服务。
加载外部数据并进行检索
-
通过Unstructured File Loader将从指定源进行数据的加载并生成Document对象并进行文本分割。具体可以参考LangChain官方文档Unstructured File Document Loader 。
1.1 Document对象说明。Document对象主要包含了page_content,以及meta_content两部分内容。
``` [Document (page_content='LayoutParser : A Unified Toolkit for Deep Learning Based Document Image Analysis', lookup_str='', metadata={'source': '../../layout-parser-paper.pdf'}, lookup_index=0)] ```
1.2 文本分割说明。需要文本分割的原因是每次不管是做把文本当作 prompt 发给LLM,还是还是使用 embedding 功能都是有字符限制的。
-
将外部数据向量化存储,并利用向量数据库进行检索。
2.1 数据向量化并存储
数据向量化可以简单理解为用一组浮点数据来表示一个实体对象。这个实体对象可以是视频、图片、文本。同时向量之间的距离衡量实体对象的相关性。小距离表示高相关性,大距离表示低相关性。在本例中是把一段文本内容转化成向量。选取的Embeding Model是text2vec-large-chinese。但是LangChain本身并不支持这个Model。可以通HuggingFace提供的API下载和加载Model,并通过模型计算输入文本的Embedding。
LangChain已经集成了很多向量数据库 Chroma / ElasticSearch / FAISS / Milvus / Pinecone 。我们可以直接使用这些向量数据库进行数据的存储和查询。在本案例中我们使用的是FAISS向量数据库。更多了解可参考LangChain - Vectorstores
相关代码
``` # 通过HuggingFace来生成中文Sentence Embedding embedding = HuggingFaceEmbeddings(model_name='shibing624/text2vec-base-chinese') ... # 加载分割好的文本内容 vector_store = FAISS.load_local(vs_path, self.embeddings) ```
2.2 通过向量数据库进行相似性查找并构造Prompt
我们知道通过向LLM输入更多的上下文信息。LLM可以输出更加精准的内容。所以通过FAISS提供的similarity_search_with_score接口函数。我们可以得到跟query 相关的内容。从而构建更有效的Prompt。
相关代码
-
和LLM交互得到输出结果
相关代码
self.llm._call(prompt=prompt, history=chat_history):
延展内容
- 不同向量数据库的相似度检索方案对比
- 不同向量数据库的常用接口