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

在这一篇文章中,我们将继续深入探讨 LangChain 的其他关键组件——「嵌入」、「向量存储」、「评估」和「代理」,它们同样撑起了开发LLM应用的各个重要环节。

LangChain 是一个强大的LLM应用开发框架,它能帮我们轻松地构建出高效、智能、可扩展的LLM应用。LangChain 的核心是对开发LLM应用过程所需的组件提供了模块化抽象,并且可以用特定方式组装这些组件,以轻松地开发特定的用例。

在上一篇文章中,我们已经介绍了「记忆」和「链」的这两个关键组件,如果你还没有阅读,请点击这里查看。在这一篇文章中,我们将继续深入探讨 LangChain 的其他关键组件——「嵌入」、「向量存储」、「评估」和「代理」,它们同样撑起了开发LLM应用的各个重要环节。

如果你对 LangChain 感兴趣,并想了解如何利用它开发出属于你自己的LLM应用,请继续阅读下去,我们将为你揭示 LangChain 的强大魅力和无限可能。

如果你觉得《精华笔记》系列对你有所启发,还请不吝分享给你的朋友,让更多人了解 ChatGPT 这类大型语言模型背后的原理及应用,谢谢~

基于文档的问答

LLM可以根据从PDF文件、网页或公司内部文档中提取的文本来回答问题,这使得LLM能够与未经训练的数据结合起来,从而更灵活地适配不同应用场景。

要构建一个基于文档的问答系统,需要引入 LangChain 的更多关键组件,例如嵌入(Embedding)模型和向量存储(Vector Stores)。

简单实现,以轻松完成文档问答功能

首先,需要导入一些辅助构建链的工具:

javascript
复制代码
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文件的路径

ini
复制代码
file = 'OutdoorClothingCatalog_1000.csv' loader = CSVLoader(file_path=file)

步骤2:创建一个内存方式的向量存储,传入上一步创建的️️加载器。

ini
复制代码
from langchain.indexes import VectorstoreIndexCreator index = VectorstoreIndexCreator( vectorstore_cls=DocArrayInMemorySearch ).from_loaders([loader])

步骤3:定义查询内容,并使用index.query生成响应

ini
复制代码
query ="Please list all your shirts with sun protection in a table in markdown and summarize each one." response = index.query(query)

步骤4:展示查询结果的表格以及摘要

scss
复制代码
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文件的路径

ini
复制代码
loader = CSVLoader(file_path=file) docs = loader.load()

步骤2:为加载的所有文本片段生成嵌入,并存储在一个向量存储器中

ini
复制代码
from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() db = DocArrayInMemorySearch.from_documents( docs, embeddings )

我们可以用一段特定文本来查看生成的嵌入内容形式:

ini
复制代码
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维的向量,以及向量中的数字是如何表示的。

我们也可以直接输入一段查询内容,查看通过向量存储器检索到的与查询内容相似的文本片段:

ini
复制代码
query = "Please suggest a shirt with sunblocking" docs = db.similarity_search(query) # 打印检索到的文本片段数 len(docs) # 4 # 打印第一个文本片段内容 docs[0] # Document(page_content=': 255nname: Sun Shield Shirt byndescription: "Block the sun, not the fun – our high-performance sun shirt is guaranteed to protect from harmful UV rays. nnSize & Fit: Slightly Fitted: Softly shapes the body. Falls at hip.nnFabric & Care: 78% nylon, 22% Lycra Xtra Life fiber. UPF 50+ rated – the highest rated sun protection possible. Handwash, line dry.nnAdditional Features: Wicks moisture for quick-drying comfort. Fits comfortably over your favorite swimsuit. Abrasion resistant for season after season of wear. Imported.nnSun Protection That Won't Wear OffnOur 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链对查询进行检索,然后在检索的文档上进行问答

ini
复制代码
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.将检索出来的文本片段合并成一段文本

go
复制代码
qdocs = "".join([docs[i].page_content for i in range(len(docs))])

2.将合并后的文本和问题一起传给LLM

ini
复制代码
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:创建一个查询,并把查询的内容传入链并运行

ini
复制代码
response = qa_stuff.run(query)

步骤5:展示查询结果的表格以及摘要

scss
复制代码
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应用性能的影响

基本的思路就是利用语言模型本身和链本身,来辅助评估其他的语言模型、链和应用程序。

我们还是以上一节课的文档问答应用为例。

评估过程需要用到评估数据集,我们可以直接硬编码一些示例数据集,比如:

ini
复制代码
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链用于接收文档,并借助语言模型为每个文档生成一个问答对。

ini
复制代码
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]] )

我们可以打印看下其返回的内容:

javascript
复制代码
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:将生成的问答对添加到已有的评估数据集中

makefile
复制代码
examples += new_examples

步骤3:为所有不同的示例生成实际答案

ini
复制代码
# 这里的qa对应的是上一节课的RetrievalQA链 predictions = qa.apply(examples)

步骤4:对LLM应用的输出进行评估

ini
复制代码
from langchain.evaluation.qa import QAEvalChain llm = ChatOpenAI(temperature=0) eval_chain = QAEvalChain.from_llm(llm) # 传入示例列表和实际答案列表 graded_outputs = eval_chain.evaluate(examples, predictions)

步骤5:打印问题、标准答案、实际答案和评分

python
复制代码
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个评估结果如下:

vbnet
复制代码
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:初始化语言模型

javascript
复制代码
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:加载工具

ini
复制代码
# llm-math:解决数学问题 # wikipedia:查询维基百科 tools = load_tools(["llm-math","wikipedia"], llm=llm)

步骤3:初始化代理

ini
复制代码
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:向代理提问

数学问题:

scss
复制代码
agent("What is the 25% of 300?")

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

百科问题:

ini
复制代码
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的大语言模型应用开发》(下)

从打印出来的中间步骤详细记录中,我们可以看到几个关键词,其表示的含义分别是:

关键词表示含义
ThoughtLLM在思考的内容
Action执行特定的动作
Observation从这个动作中观察到了什么

使用 Python 代理工具

类似于ChatGPT的代码解释器,Python 代理工具可以让语言模型编写并执行Python代码,然后将执行的结果返回给代理,让它决定下一步的操作。

我们的任务目标是对一组客户名单按照姓氏和名字进行排序。

步骤1:创建Python代理

ini
复制代码
agent = create_python_agent( llm, tool=PythonREPLTool(), verbose=True )

步骤2:要求代理编写排序代码,并打印输出结果

less
复制代码
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:定义一个工具,用于获取当前日期

python
复制代码
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:初始化代理,将自定义工具加到现有工具列表里

ini
复制代码
agent= initialize_agent( tools + [time], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, verbose = True)

步骤3:调用代理,获取当前日期

python
复制代码
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…

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
人工智能

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

2024-4-26 1:31:42

人工智能

OpenClip

2024-4-26 5:32:55

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

在这一篇文章中,我们将继续深入探讨 LangChain 的其他关键组件——「嵌入」、「向量存储」、「评估」和「代理」,它们同样撑起了开发LLM应用的各个重要环节。

LangChain 是一个强大的LLM应用开发框架,它能帮我们轻松地构建出高效、智能、可扩展的LLM应用。LangChain 的核心是对开发LLM应用过程所需的组件提供了模块化抽象,并且可以用特定方式组装这些组件,以轻松地开发特定的用例。

在上一篇文章中,我们已经介绍了「记忆」和「链」的这两个关键组件,如果你还没有阅读,请点击这里查看。在这一篇文章中,我们将继续深入探讨 LangChain 的其他关键组件——「嵌入」、「向量存储」、「评估」和「代理」,它们同样撑起了开发LLM应用的各个重要环节。

如果你对 LangChain 感兴趣,并想了解如何利用它开发出属于你自己的LLM应用,请继续阅读下去,我们将为你揭示 LangChain 的强大魅力和无限可能。

如果你觉得《精华笔记》系列对你有所启发,还请不吝分享给你的朋友,让更多人了解 ChatGPT 这类大型语言模型背后的原理及应用,谢谢~

基于文档的问答

LLM可以根据从PDF文件、网页或公司内部文档中提取的文本来回答问题,这使得LLM能够与未经训练的数据结合起来,从而更灵活地适配不同应用场景。

要构建一个基于文档的问答系统,需要引入 LangChain 的更多关键组件,例如嵌入(Embedding)模型和向量存储(Vector Stores)。

简单实现,以轻松完成文档问答功能

首先,需要导入一些辅助构建链的工具:

javascript
复制代码
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文件的路径

ini
复制代码
file = 'OutdoorClothingCatalog_1000.csv' loader = CSVLoader(file_path=file)

步骤2:创建一个内存方式的向量存储,传入上一步创建的️️加载器。

ini
复制代码
from langchain.indexes import VectorstoreIndexCreator index = VectorstoreIndexCreator( vectorstore_cls=DocArrayInMemorySearch ).from_loaders([loader])

步骤3:定义查询内容,并使用index.query生成响应

ini
复制代码
query ="Please list all your shirts with sun protection in a table in markdown and summarize each one." response = index.query(query)

步骤4:展示查询结果的表格以及摘要

scss
复制代码
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文件的路径

ini
复制代码
loader = CSVLoader(file_path=file) docs = loader.load()

步骤2:为加载的所有文本片段生成嵌入,并存储在一个向量存储器中

ini
复制代码
from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() db = DocArrayInMemorySearch.from_documents( docs, embeddings )

我们可以用一段特定文本来查看生成的嵌入内容形式:

ini
复制代码
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维的向量,以及向量中的数字是如何表示的。

我们也可以直接输入一段查询内容,查看通过向量存储器检索到的与查询内容相似的文本片段:

ini
复制代码
query = "Please suggest a shirt with sunblocking" docs = db.similarity_search(query) # 打印检索到的文本片段数 len(docs) # 4 # 打印第一个文本片段内容 docs[0] # Document(page_content=': 255nname: Sun Shield Shirt byndescription: "Block the sun, not the fun – our high-performance sun shirt is guaranteed to protect from harmful UV rays. nnSize & Fit: Slightly Fitted: Softly shapes the body. Falls at hip.nnFabric & Care: 78% nylon, 22% Lycra Xtra Life fiber. UPF 50+ rated – the highest rated sun protection possible. Handwash, line dry.nnAdditional Features: Wicks moisture for quick-drying comfort. Fits comfortably over your favorite swimsuit. Abrasion resistant for season after season of wear. Imported.nnSun Protection That Won't Wear OffnOur 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链对查询进行检索,然后在检索的文档上进行问答

ini
复制代码
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.将检索出来的文本片段合并成一段文本

go
复制代码
qdocs = "".join([docs[i].page_content for i in range(len(docs))])

2.将合并后的文本和问题一起传给LLM

ini
复制代码
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:创建一个查询,并把查询的内容传入链并运行

ini
复制代码
response = qa_stuff.run(query)

步骤5:展示查询结果的表格以及摘要

scss
复制代码
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应用性能的影响

基本的思路就是利用语言模型本身和链本身,来辅助评估其他的语言模型、链和应用程序。

我们还是以上一节课的文档问答应用为例。

评估过程需要用到评估数据集,我们可以直接硬编码一些示例数据集,比如:

ini
复制代码
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链用于接收文档,并借助语言模型为每个文档生成一个问答对。

ini
复制代码
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]] )

我们可以打印看下其返回的内容:

javascript
复制代码
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:将生成的问答对添加到已有的评估数据集中

makefile
复制代码
examples += new_examples

步骤3:为所有不同的示例生成实际答案

ini
复制代码
# 这里的qa对应的是上一节课的RetrievalQA链 predictions = qa.apply(examples)

步骤4:对LLM应用的输出进行评估

ini
复制代码
from langchain.evaluation.qa import QAEvalChain llm = ChatOpenAI(temperature=0) eval_chain = QAEvalChain.from_llm(llm) # 传入示例列表和实际答案列表 graded_outputs = eval_chain.evaluate(examples, predictions)

步骤5:打印问题、标准答案、实际答案和评分

python
复制代码
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个评估结果如下:

vbnet
复制代码
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:初始化语言模型

javascript
复制代码
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:加载工具

ini
复制代码
# llm-math:解决数学问题 # wikipedia:查询维基百科 tools = load_tools(["llm-math","wikipedia"], llm=llm)

步骤3:初始化代理

ini
复制代码
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:向代理提问

数学问题:

scss
复制代码
agent("What is the 25% of 300?")

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

百科问题:

ini
复制代码
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的大语言模型应用开发》(下)

从打印出来的中间步骤详细记录中,我们可以看到几个关键词,其表示的含义分别是:

关键词表示含义
ThoughtLLM在思考的内容
Action执行特定的动作
Observation从这个动作中观察到了什么

使用 Python 代理工具

类似于ChatGPT的代码解释器,Python 代理工具可以让语言模型编写并执行Python代码,然后将执行的结果返回给代理,让它决定下一步的操作。

我们的任务目标是对一组客户名单按照姓氏和名字进行排序。

步骤1:创建Python代理

ini
复制代码
agent = create_python_agent( llm, tool=PythonREPLTool(), verbose=True )

步骤2:要求代理编写排序代码,并打印输出结果

less
复制代码
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:定义一个工具,用于获取当前日期

python
复制代码
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:初始化代理,将自定义工具加到现有工具列表里

ini
复制代码
agent= initialize_agent( tools + [time], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, verbose = True)

步骤3:调用代理,获取当前日期

python
复制代码
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…

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
人工智能

耗时一下午,我终于上线了我的 GPT 终端!(内含详细部署方案记录)

2024-4-25 23:31:38

人工智能

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

2024-4-26 3:33:08

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索