《使用 LangChain 进行大模型应用开发》学习笔记(二)

news2024/11/24 11:37:11

前言

本文是 Harrison Chase (LangChain 创建者)和吴恩达(Andrew Ng)的视频课程《LangChain for LLM Application Development》(使用 LangChain 进行大模型应用开发)的学习笔记。由于原课程为全英文视频课程,国内访问较慢,同时我整理和替换了部分内容以便于国内学习。阅读本文可快速学习课程内容。

课程介绍

本课程介绍了强大且易于扩展的 LangChain 框架,LangChain 框架是一款用于开发大语言模型(LLM)应用的开源框架,其使用提示词、记忆、链、代理等简化了大语言模型应用的开发工作。由于 LangChain 仍处于快速发展期,部分 API 还不稳定,课程中的部分代码已过时,我使用了目前最新的 v0.2 版本进行讲解,所有代码均可在 v0.2 版本下执行。另外,课程使用的 OpenAI 在国内难以访问,我替换为国内的 Kimi 模型,对于学习没有影响。参考这篇文章来获取 Kimi 的 API 令牌。

  • 第一部分
  • 第二部分

在这里插入图片描述

课程链接

第二部分

链(Chain)

链可以将 LLM 模型及多种类型的组件连起来,以完成更加复杂的任务。

LLMChain

LLMChain 是最简单且强大的链,请看下面的例子。

from langchain.chains import LLMChain

# 还是一样创建 LLM
llm = ChatOpenAI(temperature=0.3, model=llm_model, base_url=base_url, api_key=api_key)
# 创建提示模版
prompt = ChatPromptTemplate.from_template(
    "请说出一个中国公司名称,这家公司生产产品 {product} ?"
)
# 构建链
chain = LLMChain(llm=llm, prompt=prompt)
# 输入参数
product = "智能手机"
# 执行链
out = chain.run(product)
print(out)

执行后可获得类似如下的输出。

华为(Huawei)是一家中国公司,生产智能手机。

LLM 每次的输出可能并不相同。

这个例子非常简单,只是把 LLM 和提示词组合起来。我们可以通过提供不同的参数,来获得不同的结果。

SimpleSequentialChain

接下来我们使用 SimpleSequentialChain,它可以按序列顺序执行一系列的链。上一个链的输出是下一个链的输入。SimpleSequentialChain 支持的子链只能有一个输入参数和一个输出参数。

from langchain.chains import SimpleSequentialChain

# 创建 LLM
llm = ChatOpenAI(temperature=0.3, model=llm_model, base_url=base_url, api_key=api_key)
# 提示词模板 1
first_prompt = ChatPromptTemplate.from_template(
    "请说出一个中国公司名称,这家公司生产产品 {product} ?"
)

# 链 1
chain_one = LLMChain(llm=llm, prompt=first_prompt)

# 提示词模板 2
second_prompt = ChatPromptTemplate.from_template(
    "请写一段 20 字以内的文字介绍公司:{company_name}"
)
# 链 2
chain_two = LLMChain(llm=llm, prompt=second_prompt)

# 构建简单序列链
overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],
                                             verbose=True
                                             )
# 输入参数
product = "智能手机"
# 执行链
out = overall_simple_chain.run(product)
print(out)

执行后我们会获得类似下面的结果。

在这里插入图片描述

上面的序列链包含了两个子链,第一个子链输入参数是产品,输出结果是公司名称,这个输出结果作为了第二个子链的输入。第二个子链输入参数是公司名称,输出公司的介绍。通过 SimpleSequentialChain 就可以将两次执行串联起来了。

在这里插入图片描述

SequentialChain

上面的 SimpleSequentialChain 只支持一个输入和一个输出的情况,但实际情况可能需要有多个输入和多个输出,这时候我们就可以使用 SequentialChain。

看下面的例子。

from langchain.chains import SequentialChain

# 创建 LLM
llm = ChatOpenAI(temperature=0.3, model=llm_model, base_url=base_url, api_key=api_key)

# 提示词模板 1
first_prompt = ChatPromptTemplate.from_template(
    "请生成一条关于产品 {product} 的评价,30 字以内"
)
# 链 1: input= product output= review
chain_one = LLMChain(llm=llm, prompt=first_prompt,
                     output_key="review"
                     )
second_prompt = ChatPromptTemplate.from_template(
    "请根据下面产品的评价写一段 30 字以内的回复:"
    "\n\n产品:{product}\n\n评价: {review}"
)
# 链 2: input= product, review output= response
chain_two = LLMChain(llm=llm, prompt=second_prompt,
                      output_key="response"
                      )
# 合成链: input= product output= product, review, response
overall_chain = SequentialChain(
    chains=[chain_one, chain_two],
    input_variables=["product"],
    output_variables=["product", "review", "response"],
    verbose=True
)

# 输入参数
product = "智能手机"
# 执行链
out = overall_chain(product)
print(out)

注意不要搞混输入和输出的变量名。

执行上述代码可得到类似下面的输出。

> Entering new SequentialChain chain...

> Finished chain.
{'product': '智能手机', 'review': '设计时尚,性能卓越,拍照清晰,续航给力,用户体验极佳。', 'response': '感谢您的好评!我们很高兴您喜欢我们的设计、性能和用户体验。'}

上面构建了一个包含两个子链的序列链,其中第二个子链有多个输入参数和输出结果,最终的输出结果也是合并后的综合结果。

在这里插入图片描述

我们可以通过链来构建更复杂的应用场景,但目前都是一个接一个执行的顺序场景,接下来我们可以看看实际中更复杂的分支场景。

Router Chain

路由分支好比是一个岔路口,我们有好几条链可以选择。根据不同的条件或场景,我们可以选择不同的分支链继续执行。这样我们就可以构建非常复杂的应用场景了。

在这里插入图片描述

看下面的例子。

# 首先定义不同的提示词模板
physics_template = """你是一位著名的物理学教授。 \
你非常擅长以简洁且易于理解的方式解答物理学问题。\
如果你不知道问题的答案你就回答不知道。\

下面是问题:
{input}"""

math_template = """你是一位著名的数学家。 \
你非常擅长解答数学问题。 \
你擅长将复杂的数学问题分解为多个小问题,最后合并解决。 \

下面是问题:
{input}"""

history_template = """你是一位著名的历史学家。\
你对于人类的历史事件有非常丰富的知识和理解。\
你非常擅长思考、总结、讨论过去的事件,并善于使用历史事件作为依据。\

下面是问题:
{input}"""

computerscience_template = """ 你是一位成功的计算机专家。\
你对创造力、协作、前瞻性思维、自信、解决问题的能力充满热情。\
你擅长回答编码问题,你还知道如何\
选择在时间复杂性和空间复杂性之间取得良好平衡的解决方案。\

下面是问题:
{input}"""

prompt_infos = [
    {
        "name": "物理",
        "description": "擅长回答物理学问题",
        "prompt_template": physics_template
    },
    {
        "name": "数学",
        "description": "擅长回答数学问题",
        "prompt_template": math_template
    },
    {
        "name": "历史",
        "description": "擅长回答历史问题",
        "prompt_template": history_template
    },
    {
        "name": "计算机科学",
        "description": "擅长回答计算机科学问题",
        "prompt_template": computerscience_template
    }
]

# 引入依赖
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.prompts import PromptTemplate

# 构建 LLM
llm = ChatOpenAI(temperature=0.3, model=llm_model, base_url=base_url, api_key=api_key)
# 构建链
destination_chains = {}
for p_info in prompt_infos:
    name = p_info["name"]
    prompt_template = p_info["prompt_template"]
    prompt = ChatPromptTemplate.from_template(template=prompt_template)
    chain = LLMChain(llm=llm, prompt=prompt)
    destination_chains[name] = chain

# 构建候选提示词
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)
# 默认提示词
default_prompt = ChatPromptTemplate.from_template("{input}")
default_chain = LLMChain(llm=llm, prompt=default_prompt)

# 构建路由提示词模板
MULTI_PROMPT_ROUTER_TEMPLATE = """请为下面的原始输入选择最适合的候选提示词。 \
你将获得候选提示词的提示名称和适合领域的描述。\
你可以对原始输入进行修改来匹配适合的领域。

<< 格式 >>
请返回包含下面 JSON 对象的 Markdown 格式:
```json
{{{{
    "destination": string
    "next_inputs": string
}}}}
```其中:"destination" 必须是下面候选提示词的名称中的一个或者是 "DEFAULT" 如果没有匹配任何一个候选提示词。
其中:"next_inputs" 可以是原始输入或者是修改后的版本。

<< 候选提示词 >>
{destinations}

<< 原始输入 >>
{{input}}

<< 输出 (记得包含 ```json)>>"""

# 路由提示词
router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(
    destinations=destinations_str
)
router_prompt = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),
)

# 构建路由链
router_chain = LLMRouterChain.from_llm(llm, router_prompt)
# 构建链
chain = MultiPromptChain(router_chain=router_chain,
                         destination_chains=destination_chains,
                         default_chain=default_chain, verbose=True
                         )

上面的代码构建了一个路由链,根据提问的类型,选择最适合的目标链来回答。我们首先通过路由链获得要使用的目标链,每个目标链都是普通的 LLM 链。另外我们也需要一个默认的链,用于处理覆盖不到的情况。

接下来我们问一个物理问题。

# 提问
out = chain.run("什么是丁达尔效应?")
print(out)

可能得到如下回答。

> Entering new MultiPromptChain chain...
物理: {'input': '什么是丁达尔效应?'}
> Finished chain.
丁达尔效应(Tyndall effect)是一种物理现象,它描述了当光线通过一个含有悬浮微粒的透明介质(如胶体溶液)时,这些微粒会散射光线,使得光线的路径变得可见。这种现象通常在胶体中观察到,因为胶体粒子的尺寸(通常在1纳米到1微米之间)与可见光的波长(大约400纳米到700纳米)相当,因此能够有效地散射光线。

当光线通过这样的介质时,如果观察角度合适,可以看到一条明亮的光路,这是因为光线被介质中的微粒散射到了观察者的眼睛。这种现象最早由英国物理学家约翰·丁达尔(John Tyndall)在1869年描述,因此得名。

丁达尔效应在日常生活中也很常见,例如在雾中或在空气中悬浮的灰尘中,当阳光或其他光源照射时,可以看到光线的路径。在实验室中,丁达尔效应可以用来区分溶液和胶体,因为溶液中的粒子太小,无法有效散射光线,而胶体中的粒子则可以。

总结来说,丁达尔效应是一种光线散射现象,它在含有适当尺寸悬浮粒子的透明介质中观察到,使得光线的路径变得可见。

如果我们提问一个历史问题。

out = chain.run("什么是九一八事变?")
print(out)

则可能得到这样的回答。

> Entering new MultiPromptChain chain...
历史: {'input': '什么是九一八事变?'}
> Finished chain.
九一八事变,又称柳条湖事件,是1931年9月18日在中国东北地区发生的一起重大历史事件。这一事件标志着日本帝国主义对中国的全面侵略的开始,也是中国抗日战争的起点。

1. 背景:在20世纪初,日本帝国主义对中国的侵略野心日益膨胀。日本在1905年日俄战争后,通过《朴茨茅斯条约》获得了在中国东北的特权,包括铁路、矿山等资源的控制权。此后,日本在东北的势力不断扩张,与当地民众的矛盾日益加剧。

2. 事件经过:1931年9月18日晚,日本关东军在沈阳附近的柳条湖铁路附近制造了一起爆炸事件,然后以此为借口,声称中国军队破坏了铁路,随即发动了对沈阳的进攻。由于当时的中国政府采取了不抵抗政策,日本军队迅速占领了沈阳,并在随后的几个月内占领了整个东北三省。

3. 影响:九一八事变对中国和世界历史产生了深远的影响。首先,它标志着日本对中国的全面侵略的开始,导致了中国东北三省的沦陷,数百万中国人民遭受了巨大的苦难。其次,这一事件也激发了中国人民的民族意识和抗日情绪,为后来的全面抗日战争奠定了基础。最后,九一八事变也是第二次世界大战亚洲战场的序幕,对世界历史产生了重要影响。

4. 历史评价:九一八事变是日本帝国主义侵略中国的重要标志,也是中国人民反抗外来侵略、争取民族独立和解放的重要历史事件。这一事件提醒我们,要警惕外来侵略,维护国家主权和领土完整,同时也要珍惜和平,反对战争。

接着我们再问一个生物问题,会找不到合适的目标链,就会使用默认链来处理。

out = chain.run("为什么细胞中包含 DNA?")
print(out)
> Entering new MultiPromptChain chain...
None: {'input': '为什么细胞中包含 DNA?'}
> Finished chain.
细胞中包含DNA的原因是因为DNA是生物体内遗传信息的主要载体。DNA(脱氧核糖核酸)是一种长链状的生物大分子,由四种核苷酸(腺苷、鸟苷、胞嘧啶和胸腺嘧啶)组成。这些核苷酸按照特定的顺序排列,形成了遗传密码。以下是详细解释为什么细胞中包含DNA的几个步骤:

1. 遗传信息的传递:DNA的主要功能是存储和传递遗传信息。生物体的遗传特征,如形态、生理功能和行为等,都是由DNA中的遗传信息决定的。通过DNA的复制和传递,生物体可以将遗传信息从一代传递到下一代。

2. 蛋白质合成:DNA中的遗传信息通过转录和翻译过程,指导细胞合成特定的蛋白质。蛋白质是生物体内各种生物化学反应的主要参与者,对于维持生物体的正常生理功能至关重要。

3. 细胞分裂和生长:在细胞分裂过程中,DNA需要复制自身,以确保新产生的细胞具有与母细胞相同的遗传信息。这样,生物体才能正常生长和发育。

4. 基因表达调控:DNA中的遗传信息不仅决定了蛋白质的合成,还参与调控基因的表达。基因表达调控对于生物体对环境变化的适应和发育过程中的细胞分化至关重要。

5. 遗传变异和进化:DNA中的遗传信息在复制过程中可能出现错误,导致遗传变异。这些变异可能对生物体产生有利或不利的影响。有利的变异有助于生物体适应环境,从而在自然选择过程中被保留下来,推动生物的进化。

综上所述,细胞中包含DNA是因为DNA是生物体内遗传信息的主要载体,对于生物体的生长、发育、适应环境和进化具有重要作用。

大家可以尝试不同领域的问题,看路由链的选择是否正确。

链不仅可以将多个组件组合起来,也能支持复杂的逻辑场景,是 LangChain 最基本和强大的能力。

(未完待续)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2122961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ReLU再进化ReLUMax:自动驾驶的瞬态容错语义分割

ReLU再进化ReLUMax&#xff1a;自动驾驶的瞬态容错语义分割 Abstract 度学习模型在自动驾驶感知中至关重要&#xff0c;但其可靠性面临着算法限制和硬件故障的挑战。我们通过研究语义分割模型的容错性来应对后者。使用已有的硬件故障模型&#xff0c;我们在准确性和不确定性方…

视频号接口列表

目前已有的接口列表&#xff1a; 账号搜索 视频搜索 直播搜索 获取作者信息和作品列表 视频解密并下载 获取视频详情 获取视频评论 获取视频评论的子评论 作品喜欢 作品点赞 作品评论 对作品评论进行评论 关注作者 加入直播间 获取直播间弹幕消息 发送弹幕消息 获取直播间商品…

力扣474-一和零(Java详细题解)

题目链接&#xff1a;474. 一和零 - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完01背包&#xff0c;所以现在的题解都是以01背包问题为基础再来写的。 如果大家不懂01背包的话&#…

运维问题0002:SAP多模块问题-SAP系统程序在执行时,跳出“加急快件”窗口,提示:快件文档“更新已终止”从作者***收到

1、问题描述 近期收到2起业务报障&#xff0c;均反馈在SAP执行程序时&#xff0c;弹出“加急快件”窗口&#xff0c;导致操作的业务实际没有更新完成。 1&#xff09;业务场景一&#xff1a;设备管理部门在操作事务代码&#xff1a;AS02进行资产信息变更时&#xff0c;保存正常…

面试官:为什么 Redis 6.0 之后引入多线程?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 回答 Redis 的性能瓶颈从来都不是 CPU&#xff0c;是网络I/O 和内存。 内存好解决&#xff0c;加机器内存和优化数据结构。 网路 I/O 的优化才是大头&#xff0c;因为读写网络的 read…

最新大厂薪资职级表,我酸了。。

大家好&#xff01;我是鸭鸭&#xff01; 又到周末&#xff0c;让我们轻松一下&#xff0c;来吃吃瓜&#xff01; 大厂往往会提供具有竞争力的薪资和福利待遇&#xff0c;正值秋招&#xff0c;相关热帖也是又被翻了出来。鸭鸭今天就刷到一个帖子&#xff0c;据说是几家互联网…

基于构件开发-系统架构师(六十四)

1&#xff08;&#xff09;常见的功能包括版本控制&#xff0c;变更管理&#xff0c;配置状态管理&#xff0c;访问控制和安全控制等。 A软件测试工具 B版本控制工具 C软件维护工具 D软件配置管理工具 解析&#xff1a; 软件过程工具分为&#xff1a;软件开发工具&#xf…

史上最全-经管类国家社科基金立项名单汇总 1991-2024

数据说明&#xff1a;本次数据包括以下内容&#xff1a; 1.国家自科基金立项名单&#xff08;2022-2024&#xff09; 2.国家社科基金立项名单&#xff08;2008-2018&#xff09; 数据简介&#xff1a;国家自然科学基金是中国支持基础研究的主渠道之一&#xff0c;面向全国&am…

容易中、见刊快的6本医学期刊推荐!

常笑医学整理了6本容易中、见刊快的医学期刊&#xff0c;以及期刊详细参数与投稿经验&#xff0c;供医生、医学生们在论文投稿时参考。投稿经历均来自常笑医学网用户真实分享&#xff0c;欢迎大家到常笑医学网分享自己的投稿经历和实用经验。 1.《中国医药科学》 &#xff08;详…

两个月冲刺软考——校验码的三种类型;编译过程;翻译器与解释器的对比;补充CPU的内容

1.校验码 是通过扩大码距从而实现校验的。 那什么是码距呢&#xff1f;任何一种编码都由许多码字组成的&#xff0c;任意两个码字之间最少变化的二进制位数就称为数据校验码的码距。 对于这个概念可以这样理解&#xff1a;想象一个地图上的城市网络&#xff0c;每个城市代表一…

STM32时钟配置图详解

一图概述&#xff1a; 左侧输入时钟源 Input Frequency (LSE/LSI/HSI/HSE) LSE (Low-Speed External)&#xff1a;外部32.768 kHz晶体振荡器&#xff0c;通常用于RTC&#xff08;实时时钟&#xff09;。LSI (Low-Speed Internal)&#xff1a;内部低速时钟&#xff0c;频率为…

C# 混淆加密大师1.2.5更新功能介绍, 附CSDN下载链接

C#混淆加密大师支持 .Net Framework 2.0到.Net Framework 4.x&#xff0c;以及.NET Core 2.0至最新的.NET 8版本的C#程序, 包括Winform、WPF、Unity游戏以及控制台程序的混淆加密, 可有效保护C#程序代码&#xff0c;防止非法复制或篡改, 保护知识产权. 特性 1. 支持多种不同的…

虚拟机苹果系统的QT安装体验

前言 苹果系统MacOS中除了安装XCode&#xff0c;完全可以安装QT。本质上来讲&#xff0c;苹果系统就是Linux改装版本&#xff0c;实际上和Ubuntu非常的接近。 1、Mac对应的QT安装包的下载 安装参考链接&#xff1a;MacOS下Qt 5开发环境安装与配置_macos qt-CSDN博客 苹果系统…

宠物空气净化器测评:霍尼韦尔、希喂、米家、有哈、范罗士哪款吸浮毛效果好

作为一个忙碌、精致的搬砖人&#xff0c;我开始是没想过我会养带毛的动物的。自己就很忙了&#xff0c;哪有时间清理宠物弄脏的房间。无奈&#xff0c;三年前某天下班&#xff0c;刚进到小区就被楼下一只小流浪缠上了。买了两根火腿肠喂了还不够&#xff0c;非得跟着我到单元楼…

Jedis,SpringDataRedis

快速入门 导入依赖 <!--jedis--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency><!--单元测试--><dependency><groupId>org.ju…

SPI子系统

IO特性 SPI接口一般使用四条信号线通信&#xff1a; SDI&#xff08;数据输入&#xff09;&#xff0c;SDO&#xff08;数据输出&#xff09;&#xff0c;SCK&#xff08;时钟&#xff09;&#xff0c;CS&#xff08;片选&#xff09; MISO&#xff1a; 主设备输入/从设备输出…

每日刷题(二分)

E. Klees SUPER DUPER LARGE Array!!! https://codeforces.com/contest/2009/problem/E 思路&#xff1a; 题目让我们求从k开始的n个数的前k个数的和与剩下的数的和的差最小是多少&#xff0c;可以用数学思维O(1)求解&#xff0c;都是我数学比较差&#xff0c;我们这里用二分…

企业财税自动化解决方案的成本效益分析与投资回报预测

随着企业规模的扩大和业务复杂度的增加&#xff0c;企业在财务管理方面也面临着诸多挑战&#xff0c;传统的财务管理方式逐渐无法满足企业经营需求&#xff0c;借助财税自动化解决方案来提高财务效率和准确性、降低人力成本&#xff0c;为企业带来长期的效益提升&#xff0c;已…

基于MATLAB的图像融合设计

摘 要 图像融合能够将不同类型传感器获取的同一对象的图像数据进行空间配准。并且采用一定的算法将不同类型的传感器获取的同一对象的图像数据所含用的信息优势或互补性有机地结合起来产生的新的图像数据。这种新数据含有所研究对象的更多信息表征&#xff0c;与单一图像相对比…

《python语言程序设计》2018版第8章第15题商业:检测ISBN-10一个国际标准书号

这个作者一天净出幺蛾子.我这边还老打错字,我现在都不敢用缩写,都是全拼 str_vis_text "013601267" len_num len(str_vis_text)def run_text(num_t, text_about):text_sum 0for i in range(0, num_t):text_sum if_digit(text_about[i])*(i1)print(text_sum%11)pr…