LangChain 是一个健壮的LLM运用开发结构,它能帮我们轻松地构建出高效、智能、可扩展的LLM运用。LangChain 的中心是对开发LLM运用进程所需的组件供应了模块化笼统,并且可以用特定方法组装这些组件,以轻松地开发特定的用例。
在上一篇文章中,我们已经介绍了「回忆」和「链」的这两个要害组件,假设你还没有阅读,请点击这儿查看。在这一篇文章中,我们将持续深入探讨 LangChain 的其他要害组件——「嵌入」、「向量存储」、「点评」和「署理」,它们相同撑起了开发LLM运用的各个重要环节。
假设你对 LangChain 感兴趣,并想了解怎样运用它开宣告归于你自己的LLM运用,请持续阅读下去,我们将为你揭示 LangChain 的健壮魅力和无限或许。
假设你觉得《精华笔记》系列对你有所启发,还请不惜共享给你的朋友,让更多人了解 ChatGPT 这类大型言语模型背面的原理及运用,谢谢~
根据文档的问答
LLM可以根据从PDF文件、网页或公司内部文档中提取的文原本答复问题,这使得LLM可以与未经练习的数据结合起来,然后更灵活地适配不同运用场景。
要构建一个根据文档的问答系统,需求引进 LangChain 的更多要害组件,例如嵌入(Embedding)模型和向量存储(Vector Stores)。
简略完结,以轻松完结文档问答功用
首要,需求导入一些辅助构建链的东西:
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.vectorstores import DocArrayInMemorySearch
from IPython.display import display, Markdown
东西 | 用途 |
---|---|
RetrievalQA | 检索文档 |
CSVLoader | 加载专用数据(如CSV),用来与模型结合运用 |
DocArrayInMemorySearch | 内存方法的向量存储,不需求联接到任何类型的外部数据库 |
进程1:初始化CSV加载器,为其指定一个CSV文件的途径
file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
进程2:创建一个内存方法的向量存储,传入上一步创建的️️加载器。
from langchain.indexes import VectorstoreIndexCreator
index = VectorstoreIndexCreator(
vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])
进程3:界说查询内容,并运用index.query生成呼应
query ="Please list all your shirts with sun protection \
in a table in markdown and summarize each one."
response = index.query(query)
进程4:展示查询效果的表格以及摘要
display(Markdown(response))
文档问答功用的底层原理
要想让言语模型与许多文档相结合,有一个要害问题有必要处理。
那就是,言语模型每次只能处理几千个单词,怎样才干让它对一个大型文档的全部内容进行问答呢?
这儿就要用到嵌入(Embedding)和向量存储(Vector Stores)这两个技术。
嵌入(Embedding)
嵌入是一种将文本片段转换为数字标明的方法,这些数字可以反映文本的语义信息。
语义邻近的文本会有邻近的向量,这样我们就可以在向量空间中对文本进行比较。
比如,
- 两个相同描绘宠物的语句的向量,其相似度会非常高。
- 而与一个描绘轿车的语句的向量相比较,其相似度则会很低。
通过向量相似度,我们可以轻松地找出文本片段之间的语义联络。
运用这个特性,我们可以从文档中检索出与问题语义最匹配的文本片段,然后将它们和问题一起交给言语模型来生成答案。
向量数据库(Vector Database)
向量数据库是用于保存嵌入向量标明的数据库。
我们可以将大型文档拆分红较小的块,为每个块生成一个嵌入,并将其和原始块一起存储到数据库中。
这就是我们创建索引的进程。
索引创建好后,我们就可以用它来查询与问题最相关的文本片段:
- 当一个问题进来后,为问题生成嵌入;
- 将其与向量存储中的全部向量进行比较,选择最相似的n个文本片段;
- 将这些文本片段和问题一起传递给言语模型;
- 让言语模型根据检索到的文档内容生成最佳答案。
详细完结,以查看每一步的实行进程
进程1:初始化CSV加载器,为其指定一个CSV文件的途径
loader = CSVLoader(file_path=file)
docs = loader.load()
进程2:为加载的全部文本片段生成嵌入,并存储在一个向量存储器中
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
db = DocArrayInMemorySearch.from_documents(
docs,
embeddings
)
我们可以用一段特定文原本查看生成的嵌入内容方式:
embed = embeddings.embed_query("Hi my name is Harrison")
# 打印嵌入的维度
print(len(embed))
# 1536
# 打印前5个数字
print(embed[:5])
# [-0.021930990740656853, 0.006712669972330332, -0.018181458115577698, -0.039156194776296616, -0.014079621061682701]
从打印效果可知,这个嵌入是一个1536维的向量,以及向量中的数字是怎样标明的。
我们也可以直接输入一段查询内容,查看通过向量存储器检索到的与查询内容相似的文本片段:
query = "Please suggest a shirt with sunblocking"
docs = db.similarity_search(query)
# 打印检索到的文本片段数
len(docs)
# 4
# 打印第一个文本片段内容
docs[0]
# Document(page_content=': 255\nname: Sun Shield Shirt by\ndescription: "Block the sun, not the fun – our high-performance sun shirt is guaranteed to protect from harmful UV rays. \n\nSize & Fit: Slightly Fitted: Softly shapes the body. Falls at hip.\n\nFabric & Care: 78% nylon, 22% Lycra Xtra Life fiber. UPF 50+ rated – the highest rated sun protection possible. Handwash, line dry.\n\nAdditional Features: Wicks moisture for quick-drying comfort. Fits comfortably over your favorite swimsuit. Abrasion resistant for season after season of wear. Imported.\n\nSun Protection That Won\'t Wear Off\nOur high-performance fabric provides SPF 50+ sun protection, blocking 98% of the sun\'s harmful rays. This fabric is recommended by The Skin Cancer Foundation as an effective UV protectant.', metadata={'source': 'OutdoorClothingCatalog_1000.csv', 'row': 255})
从打印效果可知,检索到了4个相似的文本片段,而回来的第一个文本片段也的确与查询内容相关。
进程3:运用RetrievalQA链对查询进行检索,然后在检索的文档上进行问答
retriever = db.as_retriever()
llm = ChatOpenAI(temperature = 0.0)
# stuff标明将文本片段吞并成一段文本
qa_stuff = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
verbose=True
)
RetrievalQA链其实就是把吞并文本片段和调用言语模型这两进程封装起来,假设没有RetrievalQA链,我们需求这样子完结:
1.将检索出来的文本片段吞并成一段文本
qdocs = "".join([docs[i].page_content for i in range(len(docs))])
2.将吞并后的文本和问题一起传给LLM
response = llm.call_as_llm(f"{qdocs} Question: Please list all your \
shirts with sun protection in a table in markdown and summarize each one.")
进程4:创建一个查询,并把查询的内容传入链并工作
response = qa_stuff.run(query)
进程5:展示查询效果的表格以及摘要
display(Markdown(response))
可选的链类型(chain_type)
stuff
将全部内容放入一个提示中,发送给言语模型并获取一个答复。这种方法简略、廉价且作用不错。
当文档数量较少且文档长度较短的情况下,这种方法是可行的。
Map_reduce
将每个内容和问题一起传递给言语模型,并将全部单独的答复汇总成毕竟答案。
这种方法可以处理任意数量的文档,并且可以并行处理各个问题。
Refine
迭代地处理多个文档,它会根据前一个文档的答案来构建答案。
这种方法适宜组合信息和逐步构建答案,但速度较慢。
Map_rerank
每个文档进行单独的言语模型调用,并要求回来一个分数,然后选择最高分数的答案。
这种方法需求告知言语模型怎样评分,并且需求针对这部分指令进行优化。
点评
点评有两个意图:
- 查验LLM运用是否达到了验收标准
- 剖析改动关于LLM运用功能的影响
根本的思路就是运用言语模型自身和链自身,来辅助点评其他的言语模型、链和运用程序。
我们仍是以上一节课的文档问答运用为例。
点评进程需求用到点评数据集,我们可以直接硬编码一些示例数据集,比如:
examples = [
{
"query": "Do the Cozy Comfort Pullover Set\
have side pockets?",
"answer": "Yes"
},
{
"query": "What collection is the Ultra-Lofty \
850 Stretch Down Hooded Jacket from?",
"answer": "The DownTek collection"
}
]
但这种方法不太便当扩展,也比较耗时,所以,我们可以——
进程1:运用言语模型主动生成点评数据集
QAGenerateChain链用于接收文档,并凭借言语模型为每个文档生成一个问答对。
from langchain.evaluation.qa import QAGenerateChain
example_gen_chain = QAGenerateChain.from_llm(ChatOpenAI())
new_examples = example_gen_chain.apply_and_parse(
[{"doc": t} for t in data[:5]]
)
我们可以打印看下其回来的内容:
print(new_examples[0])
{'query': "What is the weight of each pair of Women's Campside Oxfords?",
'answer': "The approximate weight of each pair of Women's Campside Oxfords is 1 lb. 1 oz."}
进程2:将生成的问答对添加到已有的点评数据会集
examples += new_examples
进程3:为全部不同的示例生成实践答案
# 这儿的qa对应的是上一节课的RetrievalQA链
predictions = qa.apply(examples)
进程4:对LLM运用的输出进行点评
from langchain.evaluation.qa import QAEvalChain
llm = ChatOpenAI(temperature=0)
eval_chain = QAEvalChain.from_llm(llm)
# 传入示例列表和实践答案列表
graded_outputs = eval_chain.evaluate(examples, predictions)
进程5:打印问题、标准答案、实践答案和评分
for i, eg in enumerate(examples):
print(f"Example {i}:")
print("Question: " + predictions[i]['query'])
print("Real Answer: " + predictions[i]['answer'])
print("Predicted Answer: " + predictions[i]['result'])
print("Predicted Grade: " + graded_outputs[i]['text'])
print()
罗列其间的前3个点评效果如下:
Example 0:
Question: Do the Cozy Comfort Pullover Set have side pockets?
Real Answer: Yes
Predicted Answer: The Cozy Comfort Pullover Set, Stripe does have side pockets.
Predicted Grade: CORRECT
Example 1:
Question: What collection is the Ultra-Lofty 850 Stretch Down Hooded Jacket from?
Real Answer: The DownTek collection
Predicted Answer: The Ultra-Lofty 850 Stretch Down Hooded Jacket is from the DownTek collection.
Predicted Grade: CORRECT
Example 2:
Question: What is the weight of each pair of Women's Campside Oxfords?
Real Answer: The approximate weight of each pair of Women's Campside Oxfords is 1 lb. 1 oz.
Predicted Answer: The weight of each pair of Women's Campside Oxfords is approximately 1 lb. 1 oz.
Predicted Grade: CORRECT
...
对比第一个点评效果的两个答案可以看到,其标准答案较为简练,而实践答案则较为详细,但表达的意思都是正确的,言语模型也能辨认,因而才把它标记为正确的。
虽然这两个字符串完全不同,以致于运用传统的正则表达式等方法是无法对它们进行比较的。
这儿就表现了运用言语模型进行点评的优势——同一个问题的答案或许有许多不同的变体,只需意思相通,就应该被认为是相似的。
运用LangChain点评渠道
以上操作都可以在LangChain点评渠道上以可视化UI界面的方式展示,并对数据进行耐久化,包括:
查看和跟踪点评进程中的输入和输出
可视化链中每个进程输出的信息
将示例添加到数据会集,以便耐久化和进一步点评
署理
大型言语模型可以作为一个推理引擎,只需给它供应文本或其他信息源,它就会运用互联网上学习到的布景知识或你供应的新信息,来答复问题、推理内容或抉择下一步的操作。
这就是LangChain的署理结构可以帮我们完结的作业,而署理也正是LangChain最健壮的功用之一。
运用内置于 LangChain 的东西
进程1:初始化言语模型
from langchain.agents.agent_toolkits import create_python_agent
from langchain.agents import load_tools, initialize_agent
from langchain.agents import AgentType
from langchain.tools.python.tool import PythonREPLTool
from langchain.python import PythonREPL
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(temperature=0)
- temperature参数
言语模型作为署理的推理引擎,会联接到其他数据和核算资源,我们会期望这个推理引擎尽或许地好用且准确,因而需求把temperature参数设为0。
进程2:加载东西
# llm-math:处理数学问题
# wikipedia:查询维基百科
tools = load_tools(["llm-math","wikipedia"], llm=llm)
进程3:初始化署理
agent= initialize_agent(
tools,
llm,
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
handle_parsing_errors=True,
verbose = True)
- agent参数
agent参数 CHAT_ZERO_SHOT_REACT_DESCRIPTION中的CHAT部分,标明这是一个专门为Chat模型优化的署理。REACT部分标明一种安排Prompt的技术,可以最大化言语模型的推理才干。
- handle_parsing_errors
true标明当内容无法被正常解析时,会将过错内容传回言语模型,让它自行纠正。
进程4:向署理提问
数学问题:
agent("What is the 25% of 300?")
百科问题:
question = "Tom M. Mitchell is an American computer scientist \
and the Founders University Professor at Carnegie Mellon University (CMU)\
what book did he write?"
result = agent(question)
从打印出来的中间进程详细记录中,我们可以看到几个要害词,其标明的含义分别是:
要害词 | 标明含义 |
---|---|
Thought | LLM在考虑的内容 |
Action | 实行特定的动作 |
Observation | 从这个动作中观察到了什么 |
运用 Python 署理东西
相似于ChatGPT的代码说明器,Python 署理东西可以让言语模型编写并实行Python代码,然后将实行的效果回来给署理,让它抉择下一步的操作。
我们的任务方针是对一组客户名单按照姓氏和名字进行排序。
进程1:创建Python署理
agent = create_python_agent(
llm,
tool=PythonREPLTool(),
verbose=True
)
进程2:要求署理编写排序代码,并打印输出效果
customer_list = [["Harrison", "Chase"],
["Lang", "Chain"],
["Dolly", "Too"],
["Elle", "Elem"],
["Geoff","Fusion"],
["Trance","Former"],
["Jen","Ayai"]
]
agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {customer_list}""")
运用自界说的东西
署理的一个优势就是你可以将其联接到你自己的信息来源、API、数据。
进程1:界说一个东西,用于获取当时日期
from langchain.agents import tool
from datetime import date
@tool
def time(text: str) -> str:
"""Returns todays date, use this for any \
questions related to knowing todays date. \
The input should always be an empty string, \
and this function will always return todays \
date - any date mathmatics should occur \
outside this function."""
return str(date.today())
除了函数称号,这儿还写了一份详细的注释说明,署理会根据注释中的信息来判别何时应该调用、以及应该怎样调用这个东西。
进程2:初始化署理,将自界说东西加到现有东西列表里
agent= initialize_agent(
tools + [time],
llm,
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
handle_parsing_errors=True,
verbose = True)
进程3:调用署理,获取当时日期
try:
result = agent("whats the date today?")
except:
print("exception on external access")
在线观看链接:www.youtube.com/watch?v=gUc…
可工作代码地址:learn.deeplearning.ai/langchain/l…