LangChain
对超长文本进行总结
假如我们想要用 open ai api 对一个段文本进行总结,我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。这时,我们一般会进行对文章进行分段,比如通过 tiktoken 计算并分割,然后将各段发送给 api 进行总结,最后将各段的总结再进行一个全部的总结。
LangChain 很好的帮我们处理了这个过程,使得我们编写代码变的非常简单。
# 导入os,设置环境变量。导入文本加载器、总结链、文本分割器及OpenAI模型
import os
os.environ["OPENAI_API_KEY"] = '你的api key'
from langchain.document_loaders import TextLoader
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain import OpenAI
# 获取当前脚本所在的目录
base_dir = os.path.dirname(os.path.abspath(__file__))
# 构建doc.txt文件的路径
doc_path = os.path.join(base_dir, 'static', 'open.txt')
# 通过文本加载器加载文本
loader = TextLoader(doc_path)
# 将文本转成 Document 对象
document = loader.load()
# 初始化文本分割器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 800,
chunk_overlap = 0
)
# 切分文本
split_documents = text_splitter.split_documents(document)
# 加载 llm 模型
llm = OpenAI(model_name="text-davinci-003", max_tokens=1500)
# 创建总结链
chain = load_summarize_chain(llm, chain_type="refine", verbose=True)
# 执行总结链
chain.run(split_documents)
这里解释下文本分割器的 chunk_overlap 参数和 chain 的 chain_type 参数。
- chunk_overlap 是指切割后的每个 document 里包含几个上一个 document 结尾的内容,主要作用是为了增加每个 document 的上下文关联。比如,chunk_overlap=0 时, 第一个 document 为 aaaaaa,第二个为 bbbbbb;当 chunk_overlap=2 时,第一个 document 为
aaaaaa,第二个为 aabbbbbb。
chain_type 主要控制了将 document 传递给 llm 模型的方式,一共有 4 种方式: - stuff: 这种最简单粗暴,会把所有的 document 一次全部传给 llm 模型进行总结。如果 document 很多的话,势必会报超出最大 token 限制的错,所以总结文本的时候一般不会选中这个。
- map_reduce: 这个方式会先将每个 document 进行总结,最后将所有 document 总结出的结果再进行一次总结。
### 使用 Hugging Face 模型
使用 Hugging Face 模型之前,需要先设置环境变量
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = ''
使用在线的 Hugging Face 模型
from langchain import PromptTemplate, HuggingFaceHub, LLMChain
template = """Question: {question}
Answer: Let's think step by step."""
prompt = PromptTemplate(template=template, input_variables=["question"])
llm = HuggingFaceHub(repo_id="google/flan-t5-xl", model_kwargs={"temperature":0, "max_length":64})
llm_chain = LLMChain(prompt=prompt, llm=llm)
question = "What NFL team won the Super Bowl in the year Justin Beiber was born?"
print(llm_chain.run(question))
将 Hugging Face 模型直接拉到本地使用
from langchain import PromptTemplate, LLMChain
from langchain.llms import HuggingFacePipeline
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForSeq2SeqLM
model_id = 'google/flan-t5-large'
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(model_id)
pipe = pipeline(
"text2text-generation",
model=model,
tokenizer=tokenizer,
max_length=100
)
local_llm = HuggingFacePipeline(pipeline=pipe)
print(local_llm('What is the capital of France? '))
template = """Question: {question} Answer: Let's think step by step."""
prompt = PromptTemplate(template=template, input_variables=["question"])
llm_chain = LLMChain(prompt=prompt, llm=local_llm)
question = "What is the capital of England?"
print(llm_chain.run(question))
将模型拉到本地使用的好处:
- 训练模型
- 可以使用本地的 GPU
- 有些模型无法在 Hugging Face 运行
langchain的文档阅读允许我们将大模型与外部文档结合起来,对文档内容进行回答。我们在网上寻找有关于2022年的诺贝尔文学奖获得者的信息,比如网址,保存为Annie Ernaux.txt,作为ChatGPT的外部输入文档。
langchain使用文档加载器将数据加载为Document. 一个Document是一系列文本片段和相关的元数据。加载文件后有三个主要步骤:
- 将文档分割成块
- 为每个文档创建嵌入向量
- 在向量库中存储文档和嵌入向量
默认情况下,LangChain 使用 Chroma 作为向量存储来索引和搜索嵌入。因此我们需要先安装chromadb,命令为:pip install chromadb
.
基于此,我们可以对外部文档进行问答,Python示例代码:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain.document_loaders import TextLoader
from langchain.indexes import VectorstoreIndexCreator
# set api key
import os
os.environ["OPENAI_API_KEY"] = 'sk-xxx'
# install openai and choose model
llm = OpenAI(model_name='gpt-3.5-turbo')
# prompt with no answer
prompt = "Who is the winner of 2022 Noble Prize in literature?"
completion = llm(prompt)
print(completion)
# load other source data
loader = TextLoader('Annie Ernaux.txt')
index = VectorstoreIndexCreator().from_loaders([loader])
print('index the document.')
# prompt with answer
query = "Who is the winner of 2022 Noble Prize in literature?"
print(index.query_with_sources(query))
使用LangChain对多个LLM模型进行对比
这个部分他是利用了LangChain有个ModelLaboratory的功能
可以一次性对多个llm跑同样的询问。
你先要把每个模型整理成这样的BaseModel的类
from langchain.llms import OpenAI, OpenAIChat
chatGPT_turbo = OpenAIChat(model_name='gpt-3.5-turbo',
temperature=overal_temperature,
max_tokens = 256,
)
# 准备好prompt
from langchain.prompts import PromptTemplate
template = """Question: {question}
Answer: Let's think step by step."""
prompt = PromptTemplate(template=template, input_variables=["question"])
# 然后你就可以批量询问了
from langchain.model_laboratory import ModelLaboratory
lab = ModelLaboratory.from_llms([
chatGPT_turbo,
gpt3_davinici_003,
gpt_j6B,
flan_20B,
flan_t5xxl,
cohere_command_xl,
cohere_command_xl_nightly
], prompt=prompt)
lab.compare("What is the opposite of up?")
构建本地知识库问答机器人
在这个例子会介绍如何从本地读取多个文档构建知识库,并且使用 Openai API 在知识库中进行搜索并给出答案。
这个是个很有用的教程,比如可以很方便的做一个可以介绍公司业务的机器人,或是介绍一个产品的机器人。
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain import OpenAI,VectorDBQA
from langchain.document_loaders import DirectoryLoader
from langchain.chains import RetrievalQA
# 加载文件夹中的所有txt类型的文件
loader = DirectoryLoader('/content/langchain_data/xunfei/', glob='**/*.txt')
# 将数据转成 document 对象,每个文件会作为一个 document
documents = loader.load()
# 初始化加载器
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
# 切割加载的 document
split_docs = text_splitter.split_documents(documents)
# 初始化 openai 的 embeddings 对象
embeddings = OpenAIEmbeddings()
# 将 document 通过 openai 的 embeddings 对象计算 embedding 向量信息并临时存入 Chroma 向量数据库,用于后续匹配查询
docsearch = Chroma.from_documents(split_docs, embeddings)
# 创建问答对象
qa = VectorDBQA.from_chain_type(llm=OpenAI(), chain_type="stuff", vectorstore=docsearch,return_source_documents=True)
# 进行问答
result = qa({"query": "科大讯飞今年第一季度收入是多少?"})
print(result)