langchain

发布时间 2023-10-17 20:21:52作者: 嘎吱嘎吱脆

对超长文本进行总结

假如我们想要用 openai 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 总结出的结果再进行一次总结。

4.6 使用 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))

构建本地知识库问答机器人
在这个例子会介绍如何从本地读取多个文档构建知识库,并且使用 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)

爬取网页并输出JSON数据
有些时候我们需要爬取一些 结构性比较强 的网页,并且需要将网页中的信息以JSON的方式返回回来。
我们就可以使用 LLMRequestsChain 类去实现,具体可以参考下面代码

为了方便理解,在例子中直接使用了Prompt的方法去格式化输出结果,而没用使用上个案例中用到的 StructuredOutputParser去格式化,也算是提供了另外一种格式化的思路
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.chains import LLMRequestsChain, LLMChain

llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)

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
)

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'])

使用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?")