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

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

文档问答功用的底层原理

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

要想让言语模型与许多文档相结合,有一个要害问题有必要处理。

那就是,言语模型每次只能处理几千个单词,怎样才干让它对一个大型文档的全部内容进行问答呢?

这儿就要用到嵌入(Embedding)和向量存储(Vector Stores)这两个技术。

嵌入(Embedding)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

嵌入是一种将文本片段转换为数字标明的方法,这些数字可以反映文本的语义信息

语义邻近的文本会有邻近的向量,这样我们就可以在向量空间中对文本进行比较。

比如,

  • 两个相同描绘宠物的语句的向量,其相似度会非常高。
  • 而与一个描绘轿车的语句的向量相比较,其相似度则会很低。

通过向量相似度,我们可以轻松地找出文本片段之间的语义联络

运用这个特性,我们可以从文档中检索出与问题语义最匹配的文本片段,然后将它们和问题一起交给言语模型来生成答案。

向量数据库(Vector Database)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

向量数据库是用于保存嵌入向量标明的数据库

我们可以将大型文档拆分红较小的块,为每个块生成一个嵌入,并将其和原始块一起存储到数据库中。

这就是我们创建索引的进程。

索引创建好后,我们就可以用它来查询与问题最相关的文本片段:

  1. 当一个问题进来后,为问题生成嵌入;
  2. 将其与向量存储中的全部向量进行比较,选择最相似的n个文本片段;
  3. 将这些文本片段和问题一起传递给言语模型;
  4. 让言语模型根据检索到的文档内容生成最佳答案。

详细完结,以查看每一步的实行进程

进程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))

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

可选的链类型(chain_type)

stuff

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

将全部内容放入一个提示中,发送给言语模型并获取一个答复。这种方法简略、廉价且作用不错。

当文档数量较少且文档长度较短的情况下,这种方法是可行的。

Map_reduce

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

将每个内容和问题一起传递给言语模型,并将全部单独的答复汇总成毕竟答案。

这种方法可以处理任意数量的文档,并且可以并行处理各个问题。

Refine

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

迭代地处理多个文档,它会根据前一个文档的答案来构建答案。

这种方法适宜组合信息和逐步构建答案,但速度较慢。

Map_rerank

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

每个文档进行单独的言语模型调用,并要求回来一个分数,然后选择最高分数的答案。

这种方法需求告知言语模型怎样评分,并且需求针对这部分指令进行优化。

点评

点评有两个意图:

  • 查验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界面的方式展示,并对数据进行耐久化,包括:

查看和跟踪点评进程中的输入和输出

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

可视化链中每个进程输出的信息

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

将示例添加到数据会集,以便耐久化和进一步点评

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

署理

大型言语模型可以作为一个推理引擎,只需给它供应文本或其他信息源,它就会运用互联网上学习到的布景知识或你供应的新信息,来答复问题、推理内容或抉择下一步的操作。

这就是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?")

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

百科问题:

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) 

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

从打印出来的中间进程详细记录中,我们可以看到几个要害词,其标明的含义分别是:

要害词 标明含义
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}""") 

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

运用自界说的东西

署理的一个优势就是你可以将其联接到你自己的信息来源、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")

精华笔记:吴恩达 x LangChain《根据LangChain的大言语模型使用开发》(下)

在线观看链接:www.youtube.com/watch?v=gUc…

可工作代码地址:learn.deeplearning.ai/langchain/l…