001:LangChain 简介 🚀
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_0.png
在本节课中,我们将学习什么是LangChain,它为何被创建,以及它的核心价值与主要组件。LangChain是一个用于构建大语言模型应用的开源框架,旨在简化开发流程。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_2.png
通过提示大语言模型来开发应用,如今变得更快。然而,应用通常需要多次提示模型并解析其输出,这导致开发者需要编写大量“胶水代码”。Harrison Chase创建的LangChain正是为了简化这一过程。
我们很高兴Harrison能参与本课程。DeepLearning.AI与他合作开发了这门课程,旨在教授如何使用这个强大的工具。
感谢邀请,我非常高兴来到这里。LangChain最初是一个开源框架。当我与领域内的一些人交流时,发现他们正在构建更复杂的应用程序,并看到了开发过程中的一些共同抽象模式。
我们一直对LangChain社区的广泛采纳感到兴奋,因此期待与大家分享,并期待看到人们用它构建出什么。实际上,作为LangChain核心动力的标志,还有数百名开源贡献者,这对快速开发至关重要。团队以惊人的速度发布代码和功能。
因此,希望在这门短期课程后,你能快速使用LangChain开发出很酷的应用。也许你甚至会决定回馈开源LangChain社区。
LangChain是用于构建大语言模型应用的开源框架,它有两个不同的包:一个是Python包,另一个是JavaScript包。其设计专注于组合性和模块化。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_4.png
它们包含许多可以单独使用或相互结合的独立组件,这是其关键价值之一。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_6.png
另一个关键价值是它支持一系列不同的用例。这些模块化组件可以组合成更多端到端的应用程序,并且使得开始使用这些用例变得非常容易。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_8.png
在接下来的课程中,我们将涵盖LangChain的常见组件。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_10.png
我们将讨论模型,这是应用的核心。
我们将讨论提示,这是如何让模型执行有用和有趣任务的关键。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_12.png
我们将讨论索引,即数据摄入的方式,以便你能将其与模型结合使用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_14.png
然后,我们将讨论用于端到端用例的链,以及代理。这些都是令人兴奋的端到端用例类型,它们将模型用作推理引擎。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_16.png
我们也感谢Anish Gola,他与Harrison Chase共同创办了公司,深入思考了这些材料,并协助制作了这门短期课程。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_18.png
在DeepLearning.AI方面,Jeff、Ludwig、Eddie Shu和Dilara作为院长也为这些材料做出了贡献。
那么,让我们继续观看下一个视频,在那里我们将学习模型的基础知识。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_20.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3f1bd41233bf49e869486f95b83a9507_22.png
本节课总结:本节课我们一起学习了LangChain的起源、核心价值(模块化与组合性)以及其主要组件(模型、提示、索引、链和代理)。它为简化大语言模型应用开发提供了强大的框架支持。
002:模型、提示与输出解析
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_0.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_2.png
在本节课中,我们将学习LangChain的核心概念:模型、提示和输出解析。我们将了解如何使用LangChain的抽象来更高效地调用语言模型、构建可重用的提示模板,并将模型输出解析为结构化的格式,以便于下游应用使用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_4.png
🚀 开始之前:环境设置
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_6.png
要开始使用,我们需要导入必要的库并设置环境。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_8.png
import os
import openai
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_10.png>
openai.api_key = os.getenv("OPENAI_API_KEY")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_12.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_14.png
如果你在本地运行且尚未安装openai库,你需要先运行以下命令:
pip install openai
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_16.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_18.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_20.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_22.png
🤖 直接调用模型
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_24.png
首先,我们回顾一下直接调用OpenAI API的方式。以下是一个辅助函数,用于调用GPT-3.5 Turbo模型。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_26.png
def get_completion(prompt, model="gpt-3.5-turbo"):
messages = [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message["content"]
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_28.png>
prompt = "1加1是什么?"
response = get_completion(prompt)
print(response)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_30.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_32.png
运行上述代码,模型会返回答案“2”。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_34.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_36.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_38.png
📝 构建应用:翻译客户邮件
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_40.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_42.png
假设我们收到一封非英语(例如“海盗英语”)的客户投诉邮件,我们需要将其翻译成礼貌、尊重的美式英语,以便客服人员处理。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_44.png
客户邮件内容如下:
“Arrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse, the warranty don’t cover the cost of cleaning up me kitchen! I need yer help right now, matey!”
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_46.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_48.png
我们的目标是将其翻译为:“美式英语,语气冷静且尊重”。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_50.png
我们可以构建一个提示来完成这个任务:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_52.png
style = "美式英语,语气冷静且尊重"
text = "Arrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse, the warranty don't cover the cost of cleaning up me kitchen! I need yer help right now, matey!"
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_54.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_56.png>
prompt = f"""将以下文本翻译成 {style}:
{text}
"""
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_58.png>
response = get_completion(prompt)
print(response)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_60.png
模型返回的翻译结果类似于:
“我非常沮丧,我的搅拌机盖子飞了出去,把厨房墙壁弄得一团糟!更糟糕的是,保修不包括清理厨房的费用!我现在真的需要你的帮助,朋友。”
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_62.png
这种方法有效,但如果我们有大量不同语言的邮件需要处理,手动构建每个提示会很繁琐。接下来,我们将看到如何使用LangChain来优化这个过程。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_64.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_66.png
🔄 使用LangChain:模型与提示模板
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_68.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_69.png
LangChain提供了ChatOpenAI类来抽象化对ChatGPT API的调用,以及ChatPromptTemplate类来创建可重用的提示模板。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_71.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_73.png
首先,我们导入LangChain的相关模块并设置模型。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_75.png
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_77.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_78.png>
chat = ChatOpenAI(temperature=0)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_80.png
接着,我们定义一个提示模板。这个模板包含两个变量:style(目标风格)和text(待翻译文本)。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_82.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_84.png
template_string = """将以下文本翻译成 {style}:
{text}
"""
prompt_template = ChatPromptTemplate.from_template(template_string)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_86.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_88.png
现在,我们可以使用这个模板为不同的场景生成具体的提示。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_90.png
customer_style = "美式英语,语气冷静且尊重"
customer_email = "Arrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse, the warranty don't cover the cost of cleaning up me kitchen! I need yer help right now, matey!"
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_92.png>
customer_messages = prompt_template.format_messages(
style=customer_style,
text=customer_email
)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_94.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_96.png>
customer_response = chat(customer_messages)
print(customer_response.content)
提示模板的优势在于可重用性。例如,当客服用英语回复后,我们可以使用同一个模板将回复翻译成“海盗英语”风格返回给客户。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_98.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_100.png
service_reply = """您好,根据保修条款,因您使用叉子戳搅拌机盖导致损坏,清理费用不在保修范围内。很抱歉带来不便。"""
service_style_pirate = "英语海盗风格,语气礼貌"
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_102.png>
service_messages = prompt_template.format_messages(
style=service_style_pirate,
text=service_reply
)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_104.png>
service_response = chat(service_messages)
print(service_response.content)
使用提示模板,我们无需重复编写复杂的提示字符串,只需更改变量即可。这对于构建复杂、提示较长的应用程序尤其有用。LangChain还内置了许多常见任务(如摘要、问答、连接数据库)的提示模板,可以进一步加速开发。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_106.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_108.png
🧩 输出解析:从文本到结构化数据
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_110.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_112.png
很多时候,我们希望语言模型的输出是结构化的(例如JSON),而不是纯文本,以便程序能够直接处理。这就是输出解析器的用武之地。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_114.png
假设我们有一个产品评论,我们希望从中提取特定信息(例如:是否为礼物、送达天数、价格),并以JSON格式输出。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_116.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_118.png
原始评论如下:
“这款睡眠风扇效果惊人,有4档风力设置,从轻柔的微风到龙卷风般强劲。两天后就送到了,正好赶上我给妻子的周年纪念礼物。我想我妻子很喜欢它,因为她至今没说话…不过我一直是唯一在使用它的人…”
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_120.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_122.png
我们期望的输出格式是一个Python字典:
{
"gift": true,
"delivery_days": 2,
"price_value": "相当实惠"
}
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_124.png
不使用解析器的尝试
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_126.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_128.png
我们可以先尝试用提示让模型直接输出JSON字符串。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_130.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_132.png
review_template = """\
针对由三个反引号分隔的文本,请提取以下信息:
是否为礼物:如果购买是为了送给别人,则为真;如果是购买者自用,则为假;如果无法确定,则为未知。
送达天数:产品下单后多少天送达。如果未提及送达信息,输出-1。
价格价值:提取评论中关于产品价值的任何描述,例如“物超所值”、“价格合理”、“太贵了”等。
文本: ```{text}```
"""
prompt_template = ChatPromptTemplate.from_template(review_template)
messages = prompt_template.format_messages(text=product_review)
response = chat(messages)
print(response.content)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_134.png
模型可能会输出类似这样的字符串:
是否为礼物:真
送达天数:2
价格价值:未明确提及
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_136.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_138.png
虽然内容正确,但response.content的类型是字符串,不是Python字典。我们无法直接通过键(如response[“gift”])来访问值。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_140.png
使用LangChain的输出解析器
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_142.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_144.png
LangChain的StructuredOutputParser可以帮我们解决这个问题。它允许我们定义期望的输出模式(schema),并自动将模型输出解析为结构化的Python对象。
首先,我们定义输出模式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_146.png
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_148.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_150.png>
gift_schema = ResponseSchema(
name="gift",
description="购买的商品是送给别人的礼物吗?如果是,则为真;如果是自用,则为假;如果不确定,则为未知。"
)
delivery_days_schema = ResponseSchema(
name="delivery_days",
description="产品下单后多少天送达?如果未提及,则为-1。"
)
price_value_schema = ResponseSchema(
name="price_value",
description="评论中关于产品价值的描述,例如'物超所值'、'价格合理'、'太贵了'等。"
)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_152.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_154.png>
response_schemas = [gift_schema, delivery_days_schema, price_value_schema]
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_156.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_157.png
然后,我们创建输出解析器,并将其与提示模板结合。解析器会自动生成格式指令,并添加到提示中。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_159.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_161.png
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_163.png>
format_instructions = output_parser.get_format_instructions()
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_165.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_167.png>
review_template_with_format = """\
针对由三个反引号分隔的文本,请提取以下信息:
{format_instructions}
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_169.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_171.png>
文本: ```{text}```
"""
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_173.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_175.png>
prompt = ChatPromptTemplate.from_template(template=review_template_with_format)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_177.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_179.png>
messages = prompt.format_messages(
text=product_review,
format_instructions=format_instructions
)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_181.png>
response = chat(messages)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_183.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_185.png
最后,我们使用解析器来解析模型的输出字符串。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_186.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_188.png
output_dict = output_parser.parse(response.content)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_190.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_192.png>
print(type(output_dict))
print(output_dict)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_194.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_196.png>
print(f"是否为礼物: {output_dict['gift']}")
print(f"送达天数: {output_dict['delivery_days']}")
print(f"价格评价: {output_dict['price_value']}")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_198.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_199.png
通过结合提示模板和输出解析器,我们构建了一个强大的流程:用定义好的模式提示模型,并自动将返回的文本解析为结构化的数据,极大地方便了后续的程序化处理。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_201.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_203.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_205.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_207.png
📚 本节总结
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_209.png
在本节课中,我们一起学习了LangChain的三个核心组件:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_211.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_213.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_215.png
-
模型:使用ChatOpenAI等类来抽象化对大语言模型的调用,简化参数设置。
-
提示:使用ChatPromptTemplate创建可重用的提示模板,提高代码的复用性和可维护性,并能方便地使用LangChain内置的各类提示。
-
输出解析:使用StructuredOutputParser定义输出模式,将语言模型返回的非结构化文本自动解析为结构化的Python对象(如字典),便于下游应用程序直接使用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/f5b781dc791e91ed41bc97e6c7e7e36f_217.png
通过将这些组件组合使用,你可以更高效、更可靠地构建基于大语言模型的应用程序。在下一节课中,我们将探索如何使用LangChain构建更复杂的聊天机器人或让模型进行更有效的多轮对话。
003:记忆 🧠
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_0.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_1.png
在本节课中,我们将要学习LangChain中的“记忆”功能。大型语言模型本身是无状态的,不会记住之前的对话。为了构建能够进行连贯对话的聊天机器人等应用,我们需要一种机制来存储和利用对话历史。本节课将介绍LangChain提供的多种记忆管理方式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_3.png
概述
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_5.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_7.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_9.png
与大型语言模型互动时,它们默认不会记住之前的对话内容。这是一个问题,因为当你构建如聊天机器人等应用时,你希望对话能够连贯进行。因此,在这一节中我们将涵盖记忆功能,即如何记住对话的前一部分并将其输入语言模型。这样,当你与模型互动时,它们可以有这种对话流程。LangChain提供了多种高级选项来管理这些记忆。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_11.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_13.png
环境设置与基础记忆
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_15.png
首先,我们需要导入必要的API密钥和工具。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_17.png
import os
os.environ['OPENAI_API_KEY'] = 'your-api-key-here'
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_19.png>
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_21.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_23.png
上一节我们介绍了环境设置,本节中我们来看看如何使用基础记忆功能。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_25.png
我们将使用LangChain来管理聊天对话。为此,需要设置语言模型和记忆组件。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_27.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_29.png
llm = ChatOpenAI(temperature=0)
memory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=memory, verbose=False)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_31.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_33.png
在这门短课中,我们不会深入探讨链的本质和LangChain的所有细节,现在不必太担心语法的细节。但这构建了一个可以对话的LLM应用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_35.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_37.png
现在,让我们开始一段对话。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_39.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_41.png
response = conversation.predict(input="Hi, my name is Andrew.")
print(response)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_43.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_45.png>
response = conversation.predict(input="What is 1+1?")
print(response)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_47.png>
response = conversation.predict(input="What is my name?")
print(response)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_49.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_51.png
通过设置 verbose=True,你可以查看LangChain生成的实际提示,了解记忆是如何被整合到每次对话中的。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_53.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_55.png
记忆的工作原理
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_57.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_59.png
上一节我们介绍了基础对话,本节中我们来看看记忆内部是如何存储的。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_61.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_63.png
LangChain存储对话的方式是使用“对话缓冲内存”。我们可以打印出当前记忆的内容。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_65.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_67.png
print(memory.buffer)
print(memory.load_memory_variables({}))
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_69.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_71.png
记忆缓冲区存储了到目前为止的所有对话。它只是AI或人类所说的一切内容的记录。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_73.png
如果你想明确地向记忆中添加内容,可以手动保存上下文。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_75.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_77.png
memory.save_context({"input": "Hello"}, {"output": "What's up?"})
memory.save_context({"input": "Not much, just hanging"}, {"output": "Cool"})
print(memory.load_memory_variables({}))
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_79.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_81.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_83.png
当你使用大型语言模型进行聊天对话时,语言模型本身实际上是无状态的。每次API调用都是独立的。聊天机器人之所以能记住对话,是因为有代码提供了迄今为止的完整对话作为上下文。因此,记忆功能可以明确存储对话历史,并将其作为输入或附加上下文提供给模型,以便它们可以生成知道之前说了什么的回复。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_85.png
不同类型的记忆
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_87.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_89.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_91.png
随着对话变长,所需内存量会变得非常大,发送大量令牌到语言模型的成本也会增加。因此,LangChain提供了几种方便的内存类型来存储和累积对话。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_93.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_95.png
我们一直在看“对话缓冲内存”。让我们看看另一种类型的内存。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_97.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_99.png
对话缓冲窗口内存
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_101.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_103.png
这种内存只保留最近的一段对话。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_105.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_107.png
from langchain.memory import ConversationBufferWindowMemory
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_109.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_111.png>
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(llm=llm, memory=memory, verbose=False)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_113.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_115.png>
conversation.predict(input="Hi, my name is Andrew.")
conversation.predict(input="What is 1+1?")
response = conversation.predict(input="What is my name?")
print(response)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_117.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_118.png
因为 k=1,它只记得最近一次交流(“1+1=2”),而忘记了更早的交流(“我的名字是Andrew”)。这是一个很好的功能,因为它让你可以跟踪最近的几次对话,防止内存无限制增长。在实践中,你可能会将 k 设置为一个较大的数字。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_120.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_122.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_124.png
对话令牌缓冲记忆
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_126.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_128.png
这种记忆将限制保存的令牌数,这更直接地映射到语言模型调用的成本。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_130.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_132.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_134.png
from langchain.memory import ConversationTokenBufferMemory
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_136.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_138.png>
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=50)
conversation = ConversationChain(llm=llm, memory=memory, verbose=False)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_140.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_142.png>
inputs = ["AI is amazing.", "Backpropagation is beautiful.", "Chatbots are cool."]
for inp in inputs:
_ = conversation.predict(input=inp)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_144.png>
print(memory.load_memory_variables({}))
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_146.png
如果你减少令牌限制,那么它会切掉对话的早期部分,以保留对应最近交流的令牌数,但受限于不超过令牌限制。需要指定 llm 参数是因为不同的语言模型使用不同的计数令牌方式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_148.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_150.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_152.png
对话摘要缓冲记忆
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_154.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_156.png
这种记忆的想法不是限制记忆到固定数量的令牌或基于最近的陈述,而是使用语言模型为对话生成摘要,让摘要成为记忆。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_158.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_160.png
from langchain.memory import ConversationSummaryBufferMemory
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_162.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_164.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_166.png>
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
conversation = ConversationChain(llm=llm, memory=memory, verbose=True)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_168.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_170.png>
schedule = "早上9点与产品团队会议,需要准备PPT。中午12点在意大利餐厅与客户共进午餐,记得带上笔记本电脑展示最新的产品演示。下午3点进行代码审查。"
conversation.predict(input=f"Today's schedule is: {schedule}")
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_172.png>
response = conversation.predict(input="What should I present to the client?")
print(response)
它试图做的是保持消息的显式存储,直到达到我们指定的标记数为止。任何超出部分它将使用语言模型生成摘要来保存。
其他记忆类型与总结
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_174.png
尽管我们已用聊天示例说明了这些不同记忆,但这些记忆对其他应用也有用。例如,若系统反复在线搜索事实,但你想保持总记忆量,不让列表任意增长。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_176.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_178.png
实际上,LangChain还支持其他类型的内存。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_180.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_182.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_184.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_186.png
在用LangChain实现应用时,也可以组合使用多种类型记忆。例如,使用一种对话记忆来记住对话流程,同时使用实体记忆来回忆对话中重要人物的具体信息。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_188.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_190.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_192.png
当然,除了使用这些记忆类型,开发人员将整个对话存储在传统数据库(如键值存储或SQL数据库)中也很常见。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_194.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_196.png
总结
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_197.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_198.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/6611f57afa341027c62f44f8188df02e_199.png
本节课中我们一起学习了LangChain中的记忆功能。我们了解到大型语言模型本身是无状态的,需要外部机制来管理对话历史。我们介绍了对话缓冲内存、对话缓冲窗口内存、对话令牌缓冲内存和对话摘要缓冲内存这几种核心记忆类型,并了解了它们各自的适用场景和配置方法。最后,我们还简要提到了更高级的向量数据库记忆和实体记忆。合理利用记忆功能,是构建流畅、智能对话应用的关键。
004:链 🔗
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_0.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_2.png
在本节课中,我们将学习LangChain中最重要的基础构建块——链。链通常结合一个大语言模型和一个提示,你也可以将这些构建块组合在一起,执行文本或其他数据的序列操作。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_4.png
环境与数据准备
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_6.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_8.png
我们将像以前一样加载环境变量。我们还将加载一些稍后要使用的数据。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_10.png
这些链的强大之处在于你可以同时运行它们。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_12.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_14.png
我们将加载一个Pandas数据框。Pandas数据框是一种数据结构,包含大量不同元素的数据。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_16.png
如果你不熟悉Pandas,不用担心。主要观点是我们正在加载一些稍后可以使用的数据。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_18.png
所以如果我们查看这个Pandas数据框,我们可以看到有一个产品列,然后有一个评论列。每行都是我们可以开始通过链条的不同数据点。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_20.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_22.png
LLM链:基础构建块
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_24.png
我们要覆盖的第一个链条是LLM链。这是一个简单但非常强大的链条,它支撑着未来将讨论的许多链条。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_26.png
我们将导入三个不同的东西。我们将导入OpenAI模型,所以我们将导入LLM聊天提示模板,这就是提示,然后我们将导入LLM链条。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_28.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_30.png
所以首先我们要做的是,我们将初始化要使用的语言模型。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_32.png
我们将初始化聊天OpenAI,带有高温度。这样我们可以得到一些有趣的描述。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_34.png
现在我们将初始化一个提示。这个提示将接受一个名为product的变量,它将要求LLM生成描述生产该产品的公司的最佳名称。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_36.png
最后,我们将把这两个东西组合成一个链条,这就是我们所说的LLM链条。它非常简单,它只是LLM和提示的组合。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_38.png
但现在这个链条将允许我们按顺序通过提示和LLM运行。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_40.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_42.png
以序列方式,所以如果我们有一个名为“queen size sheet set”的产品,我们可以通过使用chain.run运行它。这将内部格式化提示,然后将整个提示传递给LLM。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_44.png
因此,我们可以看到我们得到了这个假设公司的名称,称为“皇家床品”。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_46.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_48.png
现在暂停是个好时机,可输入任何产品描述,可查看链输出结果。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_50.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_52.png
LLM链是最基本类型,未来将广泛使用。可看到如何用于下一种链,即顺序链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_54.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_56.png
顺序链:串联执行
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_58.png
顺序链依次运行一系列链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_60.png
首先导入简单顺序链。这效果很好,当子链只期望一个输入和一个输出时。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_62.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_64.png
因此,我们首先将创建一个链。它将使用一个LLM和一个提示,这个提示将接受产品,并将返回描述该公司的最佳名称。所以这将是第一个链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_66.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_68.png
然后,我们将在第二个链中创建第二个链,我们将输入公司名称,然后输出该公司的20字描述。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_70.png
因此,你可以想象这些链可能希望一个接一个地运行。第一链输出所在,公司名传入第二链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_72.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_74.png
创建简单序列链可轻易实现。描述的两个链在此,整体称为简单链,现可运行此链于任何产品描述。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_76.png
若与上述皇后尺寸床单一起使用,可运行并查看首先输出“皇家寝具”,然后传入第二链,得出该公司描述。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_78.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_80.png
简单序列链在单输入单输出时效果好。但多输入或多输出时如何?仅用常规序列链即可做到。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_82.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_84.png
导入它,然后创建将使用的多个链,一个接一个。将使用上面的评论数据,含评论。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_86.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_88.png
以下是我们要创建的链:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_90.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_92.png
-
翻译链:首先将评论翻译成英语。
-
总结链:用第二条链,将(英文)评论总结为一句话。
-
语言检测链:第三条链将检测评论的原始语言。
-
响应链:最后,第四条链将接受多个输入。这将接受我们使用第二条链计算的summary变量,以及我们使用第三条链计算的language变量,并将以指定语言请求对摘要的后续响应。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_94.png
关于所有这些子链的一个重要事项,输入和输出键需要精确。我们正在回顾,这是开始时传入的变量。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_96.png
我们可以看到明确设置了输出键为english_review。这在下面的下一个提示中被使用,我们使用相同的变量名输入english_review。并将该链的输出键设置为summary。我们可以在最终链中看到它被使用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_98.png
第三个提示输入原始变量和输出language,这再次在最终提示中被使用。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_100.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_102.png
变量名对齐很重要。因输入输出很多,若有键错误,应检查对齐。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_104.png
简单序列链接受多链,每链一输入一输出。看图,一链入另一链。这里序列链视觉描述。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_106.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_108.png
与上链比较,可见链中任一步可多输入。这很有用,当你有更复杂的下游链需要组合多个先前链时。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_110.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_112.png
现在我们有所有这些链,我们可以轻松地在顺序链中组合它们。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_114.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_116.png
所以你会注意到,我们将创建的四个链传递给链,变量将创建包含一个人类输入的输入变量,即评论。然后我们想要返回所有中间输出,所以英语评论,摘要,然后是后续消息。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_118.png
现在我们可以运行数据。让我们选个评论,通过总链传递。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_120.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_122.png
可见原始评论似乎是法语,可见英文评论为翻译,可见该评论的摘要,然后可见原始语言的法语后续消息。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_124.png
你应该在这里暂停视频,尝试不同的输入。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_126.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_128.png
我们涵盖了LLM链和顺序链,但如果你想做更复杂的事,一个常见但基本操作是将输入路由到链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_130.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_132.png
路由器链:智能分发
根据输入内容,想象一下,如果你有多个子链,每个都针对特定类型输入,你可以有一个路由器链,它首先决定将输入传递给哪个子链,然后传递给该链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_134.png
具体例子,让我们看看我们在不同类型链之间路由,根据进来的主题。我们有不同的提示,一个好问题解答物理,第二个解答数学,第三个历史,第四个计算机科学,定义所有提示模板。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_136.png
有了这些提示模板,然后提供更多信息,可以给每个命名。然后描述,物理的描述,一个适合回答物理问题。此信息将传递给路由器链。因此路由器链可决定何时使用此子链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_138.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_140.png
现在导入我们需要的其他类型链。我们需要一个多提示链,这是一种特定类型的链,用于在多个不同的提示模板之间路由。如你所见,我们所有的选项都是提示模板本身。但这只是你可以路由之间的类型之一,你可以在任意类型的链之间路由。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_142.png
我们还将实现的其他类是LLM路由器链,使用语言模型路由子链。将使用上述描述和名称。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_144.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_146.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_148.png
导入路由器输出解析器,解析输出为字典,用于下游确定使用哪个链,以及该链的输入。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_150.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_152.png
现在可以开始使用它,导入并定义将使用的语言模型。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_154.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_156.png
创建目标链,由路由器链调用的链。如你所见,每个目标链本身是语言模型链,一个LLM链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_158.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_160.png
除了目标链外,我们还需要一个默认链,这是一个被称为,当路由器无法决定使用哪个子链时。上面的例子可能在输入问题与物理无关时被调用,数学历史,或计算机科学。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_162.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_164.png
现在定义LLM用于在不同链间路由的模板。这是任务说明,输出格式需符合特定要求。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_166.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_168.png
让我们把这些部件组合起来构建路由器链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_170.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_172.png
首先,我们以上述目的地格式化完整路由器模板。此模板适用于多种目的地,这里你可以做的是暂停,添加不同类型的目的地。所以在这里,与其只是物理学,数学史和计算机科学,可添加不同主题,如英语或拉丁语。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_174.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_176.png
接下来创建基于此模板的提示模板,然后通过传入LLM创建路由器链。注意,总路由器提示包含路由器输出解析器,这很重要,因为它将帮助此链决定路由到哪些子链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_178.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_180.png
最后,整合所有内容,可以创建总链,它有一个在此定义的路由器链,它包含在此传递的目的地链,然后还传递默认链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_182.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_184.png
现在可以使用此链。所以让我们问你一些问题,如果我们问它一个关于物理的问题,希望看到它路由到物理链并带有输入。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_186.png
什么是黑体辐射,然后传递到下面的链。我们可以看到响应非常详细,包含许多物理细节。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_188.png
在这里暂停视频并尝试输入不同内容,可以尝试使用上面定义的所有其他特殊链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_190.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_192.png
例如,如果我们问它一个数学问题,应该看到它路由到数学链,然后传递到那里。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_194.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_196.png
我们还可以看到当我们传递一个问题时,它与任何子链无关,所以这里我们问它一个关于生物的问题。我们可以看到它选择的链是空,这意味着它将传递到默认链。它本身只是一个对语言模型的通用调用,幸运的是,语言模型对生物学了解很多。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_198.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_200.png
总结
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_202.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_204.png
本节课中我们一起学习了LangChain中的核心构建块——链。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_206.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_208.png
我们首先介绍了最基本的LLM链,它结合了语言模型和提示模板。接着,我们学习了如何将多个链串联起来,构建顺序链,以实现更复杂的多步处理流程。最后,我们探讨了路由器链,它能够根据输入内容智能地将任务分发给不同的专业子链进行处理。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/33ec68ac66317c48322d0ad86cdb256f_210.png
这些链是构建强大LangChain应用的基础,通过组合它们,你可以创建出能够执行序列化、条件化处理的智能应用程序。在接下来的课程中,我们将利用这些基础构建更高级的应用。
005:基于文档的问答 📚
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_0.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_2.png
在本节课中,我们将要学习如何构建一个基于文档的问答系统。这是利用大语言模型(LLM)构建的最常见、最强大的复杂应用之一。我们将学习如何将语言模型与您自己的文档(如PDF、网页或公司内部资料)结合起来,让模型能够回答关于这些文档内容的问题,从而帮助用户深入理解并获取所需信息。
环境准备与导入 🛠️
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_4.png
上一节我们介绍了课程目标,本节中我们来看看如何准备开发环境。首先,我们需要导入必要的库和设置环境变量。
import os
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_6.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_8.png>
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
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_10.png
以下是关键导入项的说明:
-
RetrievalQA: 用于构建检索式问答链的核心类。
-
ChatOpenAI: 我们将使用的聊天语言模型。
-
CSVLoader: 用于加载CSV格式的专有数据文档。
-
DocArrayInMemorySearch: 一个易于入门的内存向量存储,无需连接外部数据库。
-
display 和 Markdown: 在Jupyter Notebook中显示格式化结果的工具。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_12.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_14.png
快速开始:一行代码构建问答链 ⚡
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_16.png
现在,让我们使用LangChain提供的高级接口快速构建一个可运行的问答系统。我们将加载一个关于户外服装的CSV文件作为我们的知识库。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_18.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_20.png
file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_22.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_24.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_26.png>
from langchain.indexes import VectorstoreIndexCreator
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_28.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_30.png>
index = VectorstoreIndexCreator(
vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_31.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_33.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_35.png
代码解释:
-
使用 CSVLoader 加载指定路径的CSV文件。
-
使用 VectorstoreIndexCreator 并指定向量存储类为 DocArrayInMemorySearch。
-
调用 .from_loaders([loader]) 方法,传入文档加载器列表,自动完成文档加载、分块、创建嵌入和构建向量存储索引的过程。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_37.png
索引创建完成后,我们就可以直接进行提问了。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_39.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_41.png
query = "Please list all your shirts with sun protection in a table. Summarize each one."
response = index.query(query)
display(Markdown(response))
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_43.png
执行以上代码,语言模型会基于CSV文档中的信息,返回一个包含防晒衬衫名称和描述的Markdown表格,并附上总结。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_45.png
核心原理:嵌入与向量存储 🧠
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_47.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_49.png
上一节我们快速体验了文档问答的效果,本节中我们来深入了解一下其背后的核心原理。直接让语言模型处理长文档存在一个关键问题:语言模型的上下文窗口有限,一次只能处理几千个单词。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_51.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_53.png
那么,如何让语言模型回答超长文档中的所有问题呢?这时,嵌入(Embeddings) 和 向量存储(Vector Stores) 就开始发挥作用了。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_55.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_57.png
理解嵌入
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_59.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_61.png
嵌入是为文本片段创建数值表示(即向量)的过程。这种表示能够捕获文本的语义含义。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_63.png
embedding_vector = embed("I love programming.")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_65.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_67.png
具有相似含义的文本,其向量在向量空间中的位置也会相近。例如,关于“宠物”的句子向量会彼此靠近,而与关于“汽车”的句子向量则相距较远。这使我们能够通过计算向量相似度来找出语义相近的文本。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_69.png
理解向量数据库
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_71.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_73.png
向量数据库是专门用于存储和检索这些向量表示的数据系统。构建向量数据库的典型流程如下:
-
文档分块:将长文档拆分成较小的文本块,以适应语言模型的上下文限制。
-
创建嵌入:为每个文本块生成对应的向量。
-
存储向量:将文本块及其向量存入向量数据库。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_75.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_77.png
当用户提出查询时,系统会:
-
为查询文本生成嵌入向量。
-
在向量数据库中搜索与查询向量最相似的K个文本块(即相似性搜索)。
-
将这些最相关的文本块作为上下文,与原始问题一起构造提示(Prompt),发送给语言模型以生成最终答案。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_79.png
逐步实现:拆解问答链的构建 🛠️
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_81.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_83.png
上一节我们了解了核心概念,本节我们将手动逐步实现一个问答链,以彻底理解每个环节。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_85.png
第一步:加载文档
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_87.png
这与快速开始的第一步类似。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_89.png
loader = CSVLoader(file_path=file)
docs = loader.load()
print(docs[0].page_content)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_91.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_93.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_95.png
第二步:创建嵌入并构建向量存储
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_97.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_99.png
由于我们的文档(每个产品描述)本身已经很小,可以跳过显式的分块步骤,直接创建嵌入。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_101.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_103.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_105.png
from langchain.embeddings import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_107.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_108.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_110.png>
sample_embedding = embedding.embed_query("Hi, my name is Harrison")
print(f"嵌入向量维度: {len(sample_embedding)}")
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_112.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_114.png>
db = DocArrayInMemorySearch.from_documents(docs, embedding)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_116.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_118.png
第三步:执行相似性搜索
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_120.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_122.png
现在我们可以使用向量存储来查找与用户查询最相关的文档。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_124.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_126.png
query = "Please recommend a shirt with sunblocking."
docs_result = db.similarity_search(query)
print(docs_result[0].page_content)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_128.png
第四步:创建检索器并组装问答链
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_130.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_132.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_134.png
检索器(Retriever)是一个通用接口,db.as_retriever() 会返回一个基于我们向量存储的检索器对象。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_136.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_137.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_139.png
retriever = db.as_retriever()
llm = ChatOpenAI(temperature=0.0)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_141.png>
relevant_docs = retriever.get_relevant_documents(query)
combined_context = "\n\n".join([doc.page_content for doc in relevant_docs])
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_143.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_145.png
LangChain 的 RetrievalQA 链封装了以上所有步骤。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_147.png
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
verbose=True
)
response = qa_chain.run(query)
display(Markdown(response))
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_149.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_151.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_153.png
chain_type="stuff" 表示将所有检索到的文档内容“堆叠”到一个提示中,然后调用一次语言模型。这种方法简单高效,适用于检索到的文档总长度不超过模型上下文限制的场景。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_155.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_157.png
进阶讨论:不同的链类型与总结 🚀
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_159.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_161.png
我们使用了 stuff 方法,但它并非唯一选择。LangChain 提供了多种处理多文档的链类型,适用于不同场景:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_163.png
以下是几种主要的链类型:
-
Stuff: 将所有文档内容放入一个提示中。优点是简单、成本低、只调用一次LLM。缺点是受限于模型的上下文长度。
-
MapReduce: 首先为每个文档单独调用LLM生成答案(Map),然后调用另一个LLM来汇总所有独立答案(Reduce)。优点是可处理任意数量的文档,且Map步骤可并行。缺点是LLM调用次数多,成本较高,且文档间信息不交互。
-
Refine: 迭代处理文档,基于前一个文档的答案和当前文档来逐步完善最终答案。优点适合需要整合跨文档信息的复杂答案。缺点是速度慢,调用不独立,且答案可能冗长。
-
MapRerank: 为每个文档调用LLM,要求其返回一个答案及相关性分数,最后选择分数最高的答案。优点是速度快,可批量处理。缺点是严重依赖LLM评分能力,需要精心设计提示,且调用次数多。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_165.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_167.png
对于文档摘要等需要处理超长文本的任务,MapReduce 是一种非常常用的模式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_169.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_171.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_173.png
课程总结 📝
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_175.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_177.png
本节课中我们一起学习了基于文档的问答系统的构建。
-
目标:我们学会了如何将大语言模型与外部文档结合,构建能够回答特定领域问题的智能应用。
-
核心组件:我们深入理解了嵌入和向量存储这两个关键技术,它们通过语义搜索解决了模型上下文有限的瓶颈。
-
实践方法:我们掌握了两种构建方式:使用 VectorstoreIndexCreator 快速原型开发,以及手动分步实现以获得更精细的控制。
-
链类型:我们了解了 stuff、map_reduce、refine 和 map_rerank 等不同的文档处理策略及其适用场景。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/89a5977cf51ecc58c6386d1d630341b1_179.png
通过本课,你已经掌握了构建强大文档问答应用的基础。在接下来的课程中,我们将探索LangChain中更多的链和组件。
006:评估 📊
在本节课中,我们将学习如何评估基于大语言模型(LLM)构建的应用。评估是开发流程中至关重要但有时又很棘手的一步,它能帮助我们判断应用是否满足准确性标准,并在我们更改实现(如替换模型、调整检索策略或修改参数)时,确认改进是否有效。
1. 理解评估的挑战
上一节我们介绍了如何构建一个问答链。本节中,我们来看看如何评估它的表现。LLM应用通常由多个步骤串联而成,因此理解每个步骤的输入和输出是评估的基础。虽然一些工具可以像调试器一样可视化这些步骤,但要全面评估模型表现,查看大量数据点会更有帮助。
手动检查是一种方法,但使用语言模型本身来评估其他模型和应用则更为高效和强大。随着开发范式转向基于提示的工程,评估流程也在被重新思考,这带来了许多激动人心的新概念。
2. 设置待评估的应用
首先,我们需要一个待评估的链或应用。我们将使用上一节课构建的文档问答链作为示例。
以下是设置步骤:
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
documents = load_documents()
vectorstore = Chroma.from_documents(documents, OpenAIEmbeddings())
qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(),
chain_type="stuff",
retriever=vectorstore.as_retriever(),
verbose=False
)
3. 创建评估数据集
有了应用后,我们需要确定用于评估的数据点。我们将介绍几种方法。
方法一:手动创建示例
最简单的方法是手动构思一些好的查询-答案对。例如,浏览文档后,我们可以提出:
-
查询:舒适套头衫套装是否有侧口袋?
-
真实答案:是。
但这种方法扩展性差,需要为每个示例花费时间。
方法二:使用语言模型自动生成
我们可以利用语言模型本身来自动化生成评估数据集。LangChain提供了QAGenerationChain工具。
以下是生成问答对的步骤:
from langchain.evaluation.qa import QAGenerationChain
example_gen_chain = QAGenerationChain.from_llm(ChatOpenAI())
examples = example_gen_chain.apply_and_parse([{"doc": t} for t in documents[:5]])
这个链会分析每个文档的内容,并自动生成相关的查询和对应的真实答案,极大地节省了时间。
现在,我们可以将手动和自动生成的示例合并,形成一个评估数据集。
4. 调试与检查链的内部状态
在评估所有示例之前,了解单个查询在链中是如何处理的很有帮助。仅仅查看最终答案是不够的,我们需要知道中间步骤、检索到的文档以及传递给LLM的完整提示。
LangChain提供了一个实用工具 langchain.debug。
设置并运行调试:
import langchain
langchain.debug = True
result = qa_chain.run("舒适套头衫套装是否有侧口袋?")
langchain.debug = False
启用调试模式后,运行链会输出详细信息,例如:
-
进入RetrievalQA链。
-
进入StuffDocuments链(使用stuff方法合并文档)。
-
进入LLMChain,显示输入(原始问题、检索到的上下文)。
-
进入ChatOpenAI模型,显示完整的提示模板和系统消息。
-
最终输出答案及Token使用量等元数据。
这有助于定位问题:如果答案错误,可能是检索步骤没找到相关文档,而不是语言模型本身的问题。
5. 使用语言模型进行自动化评估
为所有示例手动检查预测结果非常乏味。我们可以再次借助语言模型来自动化评估过程。
首先,为数据集中的所有示例生成预测:
predictions = []
for example in evaluation_dataset:
pred = qa_chain.run(example["query"])
predictions.append(pred)
然后,使用LangChain的QAEvalChain进行评估:
from langchain.evaluation.qa import QAEvalChain
eval_chain = QAEvalChain.from_llm(ChatOpenAI())
graded_outputs = eval_chain.evaluate(
evaluation_dataset,
predictions,
question_key="query",
answer_key="answer",
prediction_key="result"
)
for i, (example, prediction, grade) in enumerate(zip(evaluation_dataset, predictions, graded_outputs)):
print(f"示例 {i+1}:")
print(f"问题: {example['query']}")
print(f"真实答案: {example['answer']}")
print(f"预测答案: {prediction}")
print(f"评分: {grade['text']}")
print("-" * 50)
使用语言模型评估的核心优势在于它能理解语义。两个字符串在字面上可能完全不同(例如“是”和“舒适保暖套头衫条纹确实有侧口袋”),但只要含义正确,语言模型就能给出“正确”的评分。这是传统的字符串匹配或正则表达式方法无法做到的。
6. 利用LangSmith平台进行持久化评估
最后,我们介绍LangChain的官方平台——LangSmith。它可以将我们在笔记本中进行的运行、调试和评估工作持久化,并在一个统一的UI界面中展示。
在LangSmith平台中,你可以:
-
追踪运行:查看所有历史查询的输入和输出。
-
可视化链:以更清晰的方式查看链的每一步,包括中间状态和传递给模型的提示。
-
构建数据集:直接将从应用运行中得到的好的查询-答案对添加到数据集中,方便后续评估。
-
实现评估飞轮:持续运行应用,收集数据,进行评估,并用结果指导应用优化,形成一个闭环。
这为管理和规模化评估流程提供了一个强大的工具。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/9b61fa15ca6b87a2a2754f8ebb0f6832_1.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/9b61fa15ca6b87a2a2754f8ebb0f6832_2.png
本节课总结:
在本节课中,我们一起学习了评估LLM应用的完整流程。我们从理解评估挑战开始,然后设置了一个待评估的问答链。接着,我们探讨了两种创建评估数据集的方法:手动创建和使用LLM自动生成。为了深入理解应用行为,我们使用了langchain.debug工具来调试和检查链的内部状态。最重要的是,我们学会了如何利用语言模型本身作为评估器,对预测结果进行自动化、基于语义的评分。最后,我们介绍了LangSmith平台,它能为评估工作流提供持久化、可视化和规模化的支持。掌握这些评估方法,是构建可靠、高效大模型应用的关键。
007:代理 🧠
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_0.png
在本节课中,我们将要学习LangChain中的代理框架。代理允许我们将大语言模型视为一个推理引擎,而非仅仅是知识库。通过代理,模型可以调用外部工具(如计算器、搜索引擎或自定义API)来获取信息、进行计算并决定下一步行动,从而完成更复杂的任务。
环境与模型初始化 ⚙️
上一节我们介绍了代理的基本概念,本节中我们来看看如何设置环境并初始化模型。
首先,我们需要设置环境变量并导入必要的库。然后,我们将初始化语言模型。这里我们使用ChatOpenAI,并将温度设置为0,以确保模型作为推理引擎时输出稳定且精确。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_2.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_4.png
from langchain.chat_models import ChatOpenAI
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_6.png>
llm = ChatOpenAI(temperature=0)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_8.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_10.png
加载与使用内置工具 🛠️
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_12.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_14.png
初始化模型后,我们需要为代理配备工具。LangChain提供了一些内置工具,例如用于数学计算的LLMMathTool和用于查询的Wikipedia工具。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_16.png
以下是加载这两个工具的代码:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_18.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_20.png
from langchain.agents import load_tools
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_22.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_24.png>
tools = load_tools(["llm-math", "wikipedia"], llm=llm)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_26.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_28.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_30.png
创建并运行代理 🤖
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_32.png
现在,我们可以使用加载的工具和语言模型来初始化一个代理。我们将使用initialize_agent函数,并指定代理类型为"chat-zero-shot-react-description"。这个类型专为与聊天模型配合使用而优化,并采用了“ReAct”提示技术以获得更好的推理性能。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_34.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_36.png
from langchain.agents import initialize_agent
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_38.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_40.png>
agent = initialize_agent(
tools,
llm,
agent="chat-zero-shot-react-description",
handle_parsing_errors=True,
verbose=True
)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_42.png
代理创建完成后,我们就可以向它提问了。让我们先问一个简单的数学问题。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_44.png
agent.run("三百的百分之二十五是多少?")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_46.png
执行时,verbose=True会让我们看到代理的思考过程:
-
思考:模型分析问题,决定需要做什么。
-
动作:模型输出一个JSON结构,指定要使用的工具(如Calculator)和输入(如"300*0.25")。
-
观察:工具执行并返回结果(如75.0)。
-
最终答案:模型根据观察结果,生成最终答案返回给用户。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_48.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_50.png
探索更复杂的查询:维基百科示例 🔍
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_52.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_54.png
接下来,我们看看代理如何处理需要外部知识的问题。我们将询问关于“汤姆·米切尔”的信息。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_56.png
agent.run("汤姆·米切尔写了哪本书?")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_58.png
代理会识别出需要使用Wikipedia工具,并执行搜索。它可能得到多个结果(例如,同名的计算机科学家和足球运动员)。通过阅读返回的摘要,代理能够推理出正确的答案(《机器学习》),并最终给出回应。这个过程展示了代理如何串联使用工具和推理能力。
创建代码执行代理 💻
代理的一个强大功能是能够编写并执行代码。这类似于ChatGPT的代码解释器插件。我们将创建一个使用PythonREPLTool的代理,它可以在一个安全的沙箱环境中运行Python代码。
以下是创建Python代理的步骤:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_60.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_62.png
from langchain.agents import load_tools
python_tools = load_tools(["python_repl"])
python_agent = initialize_agent(
python_tools,
llm,
agent="chat-zero-shot-react-description",
verbose=True
)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_64.png
现在,我们可以让这个代理解决一个编程问题,例如对一个名字列表进行排序。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_66.png
question = """
请按姓氏对以下名字列表进行排序,然后按名字排序,并打印结果:
[‘哈里森·蔡斯’, ‘LangChain LLM’, ‘杰夫·融合’, ‘变压器·生成AI’]
"""
python_agent.run(question)
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_68.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_70.png
代理会思考如何用代码解决这个问题,然后生成并执行相应的Python代码(如使用sorted函数和lambda表达式),最后将代码的输出作为观察结果返回,并整理出最终答案。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_72.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_74.png
深入调试与理解内部机制 🔬
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_76.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_78.png
为了更深入地理解代理的工作流程,我们可以开启LangChain的调试模式。这将打印出链中所有层级的详细输入和输出,帮助我们看清模型接收的完整提示、工具调用的细节以及中间状态的变化。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_80.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_82.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_84.png
import langchain
langchain.debug = True
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_85.png>
agent.run("一个简单的问题")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_87.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_89.png
通过调试输出,你可以看到:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_91.png
这对于诊断代理出错的原因或优化提示工程非常有帮助。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_93.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_95.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_97.png
构建自定义工具 🔗
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_99.png
目前我们使用了LangChain的内置工具,但代理的真正优势在于能够连接到任何自定义的数据源或API。接下来,我们将介绍如何创建自定义工具。
我们将创建一个简单的工具,用于返回当前日期。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_101.png
首先,导入工具装饰器并定义函数:
from langchain.tools import tool
from datetime import datetime
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_103.png>
@tool
def time(text: str) -> str:
"""
当需要知道当前日期时使用此工具。
输入应始终为空字符串。
"""
return datetime.now().strftime("%Y-%m-%d")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_105.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_107.png
关键点:函数的文档字符串至关重要。代理通过阅读它来决定何时以及如何调用这个工具。我们需要清晰说明工具的用途和输入格式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_109.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_111.png
然后,将这个新工具加入到工具列表中,并创建一个新的代理:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_113.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_115.png
custom_tools = [time] + tools
custom_agent = initialize_agent(
custom_tools,
llm,
agent="chat-zero-shot-react-description",
verbose=True
)
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_117.png>
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_119.png>
custom_agent.run("今天的日期是什么?")
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_121.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_123.png
代理会识别出需要使用time工具,调用它获取当前日期,并最终给出回答。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_125.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_127.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_129.png
总结 📝
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_131.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_133.png
本节课中我们一起学习了LangChain代理框架的核心内容。我们了解到代理如何将大语言模型转变为推理引擎,通过调用外部工具来扩展其能力。我们实践了:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_135.png
-
如何初始化代理并为其加载内置工具(如数学计算和维基百科查询)。
-
如何观察代理的思考-行动-观察循环,理解其问题解决流程。
-
如何创建代码执行代理,让模型能够编写和运行Python代码。
-
如何利用调试模式深入探查代理的内部工作机制。
-
如何构建自定义工具,将代理连接到任意的数据源或API。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/3ff7beb031a24989fc152622b2092ecc_137.png
代理是LangChain中强大且前沿的部分,它为实现复杂、动态的AI应用打开了大门。希望本教程能帮助你开始构建自己的智能代理应用。
008:【LangChain大模型应用开发】课程总结 🎯
在本节课中,我们将对这门短课的核心内容进行回顾与总结。我们将梳理已学习的应用类型,理解LangChain如何简化开发流程,并展望语言模型的更多可能性。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_1.png
在这门短课中,我们学习了一系列基于大语言模型的应用开发实例。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_1.png
这些应用包括处理客户评论、构建文档问答系统,以及使用语言模型决策何时调用外部工具(如网络搜索)来回答复杂问题。
如果在一两周前,有人问及构建所有这些应用程序需要多少工作量,许多人可能会认为这需要数周甚至更长时间。
然而,在这门短课中,我们仅用了几行简洁的代码就实现了这些功能。这证明了你可以使用LangChain高效地构建各类应用程序。
因此,我希望你能吸收这些想法,并尝试将在Jupyter笔记本中看到的代码片段应用到自己的项目中。
这些应用只是一个起点。由于大语言模型功能强大且适用于广泛的任务,你还可以利用它们开发许多其他类型的应用。
无论是回答关于CSV文件的问题、查询SQL数据库,还是与API进行交互,LangChain都提供了丰富的示例。
这些功能主要通过组合使用链(Chains)、提示(Prompts) 和输出解析器(Output Parsers) 来实现。LangChain中更多的链式组件使得完成所有这些任务成为可能。
这一切在很大程度上要归功于LangChain社区的贡献。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_3.png
在此,我想向社区中的每一位成员表示衷心的感谢。无论是通过改进文档帮助他人更容易上手,还是通过创建新的链式组件开启了全新的可能性世界。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_3.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_5.png
课程到此结束。如果你还没有开始实践,我希望你现在就打开你的笔记本电脑或台式机,运行 pip install langchain 命令来安装LangChain,并开始你的探索之旅。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/0a21b91eeccc922bc28c1f59f3288010_5.png
本节课总结
在本节课中,我们一起回顾了本课程涵盖的核心应用类型,理解了LangChain框架如何通过简洁的代码大幅降低大模型应用开发的门槛。我们认识到,借助强大的语言模型和活跃的社区生态,开发者可以高效构建从文本处理到复杂决策的多样化应用。最后,我们鼓励你立即动手安装LangChain,将所学知识付诸实践。
009:📚 构建与数据对话的聊天机器人(一)—— 介绍
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/e8d0be9d5f1da6d4ce9efdc3b4bb66c4_0.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/e8d0be9d5f1da6d4ce9efdc3b4bb66c4_0.png
概述
在本节课中,我们将要学习如何使用 LangChain 框架来构建一个能与你的专属数据进行对话的聊天机器人。大型语言模型(LLMs)虽然强大,但其知识通常局限于训练数据。本课程将指导你如何让 LLM 访问并利用你的私有文档来回答问题。
课程内容
大型语言模型(LLMs),例如 ChatGPT,能够回答许多主题的问题。但一个孤立的 LLM 只知道它被训练过的内容,不包括你的个人资料。例如,如果你在一家公司,拥有不在网络上的专有文件,或者 LLM 训练后编写的数据或文章,那么 LLM 就无法直接利用这些信息。
因此,如果你或其他人,比如你的客户,希望与自己的文件进行对话并获得基于这些文档信息的回答,就需要特殊的方法。在本短期课程中,我们将介绍如何使用 LangChain 与你的数据聊天。
LangChain 是一个用于构建 LLM 应用程序的开源开发者框架。LangChain 由几个模块化组件以及更多的端到端模板组成。LangChain 中的模块化组件包括:提示、模型、索引、链和代理。要更详细地了解这些组件,你可以参考我和 Andrew 教授的第一门课。
在本课程中,我们将聚焦于 LangChain 一个更受欢迎的用例:如何使用 LangChain 与你的数据聊天。
学习路径
以下是本课程将涵盖的核心步骤:
首先,我们将介绍如何使用 LangChain 的文档加载器,从各种来源加载数据。
上一节我们介绍了课程目标,本节中我们来看看数据处理的第一步。以下是加载数据后的关键预处理步骤:
- 我们将讨论如何将这些文档拆分为语义上有意义的块。这个预处理步骤可能看起来很简单,但其中有很多细微差别。
接下来,我们将概述语义搜索,这是一种根据用户问题获取相关信息的基本方法。这是最简单的入门方法,但也有几种情况会失败,我们会仔细检查这些案例。
然后,我们将讨论如何修复这些失败案例。之后,我们将展示如何使用这些检索到的文档,使 LLM 能够回答有关文档的问题。
但此时,你仍然缺少一个关键的部分来完全重现聊天机器人的体验。最后,我们将讨论这个缺失的部分——记忆,并展示如何构建一个功能齐全的、可以与你的数据聊天的聊天机器人。
这将是一个激动人心的短期课程。我们感谢 Ankura、Lance Martin,感谢 LangChain 团队为 Harrison 提供的所有材料,以及 DeepLearning.AI 的方杰夫。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/e8d0be9d5f1da6d4ce9efdc3b4bb66c4_2.png
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/e8d0be9d5f1da6d4ce9efdc3b4bb66c4_2.png
Ludwig 和 Diala Eine,万一你要上这门课,并决定想复习一下 LangChain 的基础知识,我鼓励你也参加之前的 LangChain 短期培训班,关于 LLM 应用开发,Harrison 也提到过。那么现在让我们进入下一个视频,Harrison 将向你展示如何使用。
总结
本节课中,我们一起学习了构建与数据对话的聊天机器人的核心动机和整体路线图。我们了解到,为了让 LLM 利用私有数据,需要借助 LangChain 框架,并依次完成数据加载、分块、检索、增强生成以及添加记忆功能等关键步骤。接下来,我们将深入每个环节的具体实现。
010:文档加载
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_0.png
在本节课中,我们将学习LangChain中一个核心且基础的概念:文档加载。为了创建一个能与您的数据对话的应用程序,首先必须将数据加载到可用的格式中。LangChain提供了80多种不同类型的文档加载器来处理这一任务。本节课将介绍其中最重要的一些加载器,帮助您理解其基本概念和工作原理。
概述:什么是文档加载器?
文档加载器负责处理访问和转换数据的细节,将各种不同格式和来源的数据转换为标准化的格式。这些数据来源广泛,包括网站、数据库、YouTube视频等。数据格式也多种多样,例如PDF、HTML、JSON等。
文档加载器的核心目的是获取各种数据源,并将它们加载到标准的文档对象中。每个文档对象由内容和相关的元数据组成。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_2.png
文档加载器的分类
LangChain中有许多不同类型的文档加载器。虽然没有时间全部介绍,但我们可以将其大致分为几类。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_4.png
以下是主要的分类:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_6.png
-
处理非结构化公共数据:用于加载来自公共数据源的文本文件,例如YouTube、Twitter、Hacker News等。
-
处理非结构化专有数据:用于加载您或您的公司拥有的专有数据源,例如Figma、Notion等。
-
处理结构化数据:用于加载表格格式的数据,这些数据可能在单元格或行中包含文本信息,适用于问答或语义搜索任务。相关来源包括Airbyte、Stripe、Airtable等。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_8.png
实践:使用文档加载器
上一节我们介绍了文档加载器的概念和分类,本节中我们来看看如何实际使用它们。首先,我们需要加载一些环境变量,例如OpenAI API密钥。
1. 加载PDF文档
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_10.png
我们要处理的第一类文档是PDF。让我们从LangChain导入相关的文档加载器。
from langchain.document_loaders import PyPDFLoader
我们已将一些PDF文件放入工作区的documents文件夹中。现在,让我们选择一个PDF文件,并使用加载器加载它。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_12.png
loader = PyPDFLoader("documents/example.pdf")
接下来,我们通过调用load方法来加载文档,并查看加载的内容。
docs = loader.load()
print(len(docs))
默认情况下,这将加载一个文档列表。对于PDF,每个页面通常是一个独立的文档。让我们查看第一个文档的组成。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_14.png
first_doc = docs[0]
print(first_doc.page_content[:500])
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_16.png
另一个重要的信息是与每个文档关联的元数据,可以通过.metadata属性访问。
print(first_doc.metadata)
您会看到元数据中包含source(来源文件)和page(对应的PDF页码)等信息。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_18.png
2. 从YouTube加载音频并转录
我们将要看到的下一种文档加载器可以从YouTube加载内容。YouTube上有大量有趣的内容,许多人使用这个加载器来向他们喜欢的视频或讲座提问。
以下是实现步骤:
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_20.png
from langchain.document_loaders.generic import GenericLoader
from langchain.document_loaders.parsers import OpenAIWhisperParser
from langchain.document_loaders.blob_loaders.youtube_audio import YoutubeAudioLoader
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_22.png
关键部分是YoutubeAudioLoader(用于从YouTube视频加载音频文件)和OpenAIWhisperParser(使用OpenAI的Whisper语音转文本模型,将音频转换为文本)。
现在,我们可以指定一个YouTube视频的URL,并创建加载器。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_24.png
url = "https://www.youtube.com/watch?v=example_video_id"
save_dir = "tmp/youtube_audio"
<https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_26.png>
loader = GenericLoader(
YoutubeAudioLoader([url], save_dir),
OpenAIWhisperParser()
)
docs = loader.load()
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_28.png
加载完成后,我们可以查看转录的文本内容。
print(docs[0].page_content[:1000])
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_30.png
3. 从网页URL加载内容
互联网上有很多优秀的教育内容。如果能与这些内容“对话”,将会非常酷。接下来,我们学习如何从网页URL加载数据。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_32.png
我们将通过从LangChain导入基于Web的加载器来实现。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_34.png
from langchain.document_loaders import WebBaseLoader
然后,我们可以选择任何URL(例如一个GitHub页面的Markdown文件),并为它创建一个加载器。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_36.png
url = "https://raw.githubusercontent.com/langchain-ai/langchain/master/README.md"
loader = WebBaseLoader(url)
docs = loader.load()
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_38.png
现在,我们可以查看加载的页面内容。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_40.png
print(docs[0].page_content[:1500])
您可能会注意到内容中包含很多空白和原始文本。这是一个很好的例子,说明了为什么通常需要对加载的信息进行后处理,以使其成为更易于处理的格式。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_42.png
4. 从Notion加载数据
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_44.png
Notion是一个非常流行的个人和公司数据存储工具。许多人希望创建能与自己的Notion数据库对话的聊天机器人。
您需要先将数据从Notion数据库导出为特定的格式(如Markdown),然后才能将其加载到LangChain中。
一旦有了导出文件,就可以使用NotionDirectoryLoader来加载数据。
https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-lngchn-llm-appdev/img/45fbcc5f08d4b53978152b089a1da51e_46.png
所有评论(0)