LangChain大型语言模型(LLM)应用开发(三):Chains

news2024/11/16 0:12:59

LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,以便在不同的应用程序中使用。

今天我们来学习DeepLearning.AI的在线课程:LangChain for LLM Application Development的第三门课:Chains,该门课程主要讲解LangChain的核心组件:链,即Chain,  chain可以将大型语言模型(LLM)和提示语(prompt)结合在一起, 你还可以创建多种不同功能的Chain,然后将这些chain组合在一起,对文本或其他数据执行一系列操作。

目录

  • LLMChain

  • Sequential Chains

  •       SimpleSequentialChain

  •        SequentialChain

  • Router Chain

下面我们导入本地环境配置文件.env, 在.env文件中我们存放了opai的api key 。

import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

 下面我们导入一个csv文件,该文件存放了用户对产品的评论信息。

import pandas as pd
df = pd.read_csv('Data.csv')
df

LLMChain

LLMChain是最基本的chain,他将LLM和prompt组合在一起,下面我们要实现一个让LLM给生产不同产品的公司取名字的功能:

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

#定义大型语言模型
llm = ChatOpenAI(temperature=0.9)

prompt = ChatPromptTemplate.from_template(
    "描述生产{product}的公司的一个最佳名称是什么?"
)

#将llm和prompt组合在一起创建一个LLMChain的实例
chain = LLMChain(llm=llm, prompt=prompt)

#执行chain
product = "床上用品"
chain.run(product)

 这里我们定义llm时使用的温度参数temperature为0.9,该参数的取值范围为0-1,之所以这里要设置为0.9,因为temperature的值越大,那么llm返回结果的随机性就越大,这里我们要实现的功能是给公司取名字的功能,因此我们需要LLM具有较大的灵活性和多样性,所以llm每次返回的结果可能都会不一样,这也就是我们希望llm实现的功能。

Sequential Chains

Sequential chain 是另一种类型的chain。它可以将多个chain组合在一起,其中一个chain的输出是下一个chain的输入。

SimpleSequentialChain

SimpleSequentialChain是最基本的一种Sequential Chains,因为它只有一个输入和一个输出,其中前一个chain的输出为后一个chain的输入,如下图所示:

下面我们看个例子,在这个例子中我们除了要执行之前LLMChain的给公司取名的功能外,我们还要需要llm生成20个字左右的公司名称的描述信息,所以,在这里需要创建两个chain, 一个chain负责给公司取名字,另一个chain负责就公司的名字生成20个字左右的描述信息,最后我们需要将这两个chain组合在一起,创建一个新的chain,对于这个新的chain它只有一个输入和一个输出,输入就是公司生产的产品,输出则是对公司名称的20字左右的描述信息。

from langchain.chains import SimpleSequentialChain

llm = ChatOpenAI(temperature=0.9)

# prompt template 1
first_prompt = ChatPromptTemplate.from_template(
    "描述生产{product}的公司的一个最佳名称是什么?"
)

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


# prompt template 2
second_prompt = ChatPromptTemplate.from_template(
    "为以下公司编写 20 个字的描述:{company_name}”"
)
# chain 2
chain_two = LLMChain(llm=llm, prompt=second_prompt)

# 将chain1和chain2组合在一起生成一个新的chain.
overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],
                                             verbose=True
                                            )
#执行新的chain
overall_simple_chain.run(product)

 SequentialChain

SequentialChain与SimpleSequentialChain的区别在于它可以有多个输入和输出,而SimpleSequentialChain只有一个输入和输出,如下图所示:

在下面的例子中我对官方课件的代码做了修改,原来官方的代码只有4个chain, 而我在此基础上增加了一个chain,这样的修改主要是让大家更好的理解该案例中涉及的prompt的含义,原先的prompt使用的都是英语,我都将其翻译成了中文,这样大家就比较能看懂这些prompt了,该案例主要功能是要让llm对前面导入的用户评语进行分析,并给出回复,因为用户的评语可能使用的是多种不同的语言,为此我们需要让chain能够识别用户评语使用的是那种语言,并将其翻译成中文,最后给出回复,具体来说包含以下功能和步骤:

  1. 将用户评论翻译成中文
  2. 用一句话概括用户评论
  3. 识别出用户评论使用的语言
  4. 按原始评论语言生成回复
  5. 将回复翻译成中文
from langchain.chains import SequentialChain

#定义llm
llm = ChatOpenAI(temperature=0.9)

# prompt template 1: 将评论翻译成中文
first_prompt = ChatPromptTemplate.from_template(
    "将下面的评论翻译成中文:"
    "\n\n{Review}"
)
# chain 1: input= Review and output= Chinese_Review
chain_one = LLMChain(llm=llm, prompt=first_prompt, 
                     output_key="Chinese_Review"
                    )
#概括评论
second_prompt = ChatPromptTemplate.from_template(
    "你能用 1 句话概括以下评论吗:"
    "\n\n{Chinese_Review}"
)
# chain 2: input= Chinese_Review and output= summary
chain_two = LLMChain(llm=llm, prompt=second_prompt, 
                     output_key="summary"
                    )


# prompt template 3: 识别评论使用的语言
third_prompt = ChatPromptTemplate.from_template(
    "下面的评论使用的是什么语言?:\n\n{Review}"
)
# chain 3: input= Review and output= language
chain_three = LLMChain(llm=llm, prompt=third_prompt,
                       output_key="language"
                      )


# prompt template 4: 生成回复信息
fourth_prompt = ChatPromptTemplate.from_template(
    "使用指定语言编写对以下摘要的后续回复:"
    "\n\n摘要:{summary}\n\n语言:{language}"

)
# chain 4: input= summary, language and output= followup_message
chain_four = LLMChain(llm=llm, prompt=fourth_prompt,
                      output_key="followup_message"
                     )

# prompt template 5: 将回复信息翻译成中文
five_prompt = ChatPromptTemplate.from_template(
    "将下面的评论翻译成中文:"
    "\n\n{followup_message}"
)
# chain 5: input= followup_message and output= Chinese_followup_message
chain_five = LLMChain(llm=llm, prompt=five_prompt, 
                     output_key="Chinese_followup_message"
                    )


# overall_chain: input= Review 
# output= language,Chinese_Review,summary, followup_message,
          #Chinese_followup_message
overall_chain = SequentialChain(
    chains=[chain_one, chain_two, chain_three, chain_four,chain_five],
    input_variables=["Review"],
    output_variables=["language","Chinese_Review", "summary",
                      "followup_message","Chinese_followup_message"],
    verbose=True
)

这里我们看到我们在定义最后的overall_chain 时设置了输入变量和输出变量,因此这些输入和输出变量最后会作为中间结果被输出。

下面我们看一下用户的评语:

review = df.Review[5]
print(review)

 接下来我们执行SequentialChain:

overall_chain(review)

 Router Chain

有一种应用场景就是我们有时候希望根据信息的内容将其传送到不同的chain,而每个chain的职能是只擅长回答自己所属领域的问题,那么在这种场景下我们就需要一种具有"路由器"功能的chain来将信息传输到不同职能的chain.

在下面的例子中,我们有多个不同职能的chain,它们负责回复关于不同学科领域的用户问题,比如数学chain,历史chain,物理chain,计算机chain,每个chain都只擅长回复自己专业领域的问题,这里我们还有一个路由chain, 它的作用是识别用户问题属于哪个领域,然后将问题传输给那个领域的chain,让其来完成回答用户问题的功能。下面我们首先定义4个专业领域的prompt模板,在这些模板中我们将告知llm它的职责与定位:

physics_template="""你是一位非常聪明的物理学教授。\
你擅长以简洁易懂的方式回答有关物理的问题。 \
当你不知道某个问题的答案时,你就承认你不知道。

这里有一个问题:
{input}"""


math_template="""你是一位非常优秀的数学家。\
你很擅长回答数学问题。 \
你之所以如此出色,是因为你能够将难题分解为各个组成部分,\
回答各个组成部分,然后将它们组合起来回答更广泛的问题。

这里有一个问题:
{input}"""

history_template = """你是一位非常优秀的历史学家。\
你对各个历史时期的人物、事件和背景有深入的了解和理解。 \
你有能力思考、反思、辩论、讨论和评价过去。 \
你尊重历史证据,并有能力利用它来支持你的解释和判断。

这里有一个问题:
{input}"""


computerscience_template="""你是一位成功的计算机科学家。\
你有创造力,协作精神,前瞻性思维,自信,有很强的解决问题的能力,\
对理论和算法的理解,以及出色的沟通能力。\
你很擅长回答编程问题。
你是如此优秀,因为你知道如何通过描述一个机器可以很容易理解的命令步骤来解决问题,\
你知道如何选择一个解决方案,在时间复杂度和空间复杂度之间取得良好的平衡。

这里有一个问题:
{input}"""

接下来我们还还需要对这些模板功能进行结构化的解释说明这样便于后面的路由chain能找到它们,为此我们要定义一个模板的索引结构:

prompt_infos = [
    {
        "name": "physics", 
        "description": "擅长回答有关物理方面的问题", 
        "prompt_template": physics_template
    },
    {
        "name": "math", 
        "description": "擅长回答有关数学方面的问题", 
        "prompt_template": math_template
    },
    {
        "name": "history", 
        "description": "擅长回答有关历史方面的问题", 
        "prompt_template": history_template
    },
    {
        "name": "computer science", 
        "description": "擅长回答有关计算机科学方面的问题", 
        "prompt_template": computerscience_template
    }
]

接下来我们还需要定义一个目标chain的集合,所谓的目标chain就是指回答单一领域问题的chai成,它们都是基本的LLMChain:

from langchain.chains import LLMChain
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.prompts import PromptTemplate
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI

#定义llm
llm = ChatOpenAI(temperature=0)

#创建目标chain
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)
print(destinations_str)

 这里我们还生成了一个目标字符串destinations_str,它会在后面别嵌入到路由chain的prompt模板中来为定位目标chain提供索引。

接下来我们还需要定义default_chain,这个chain的作用是当用户的问题与现有的所有目标chain都无法匹配时,那么就由default_chain来回答用户的问题:

default_prompt = ChatPromptTemplate.from_template("{input}")
default_chain = LLMChain(llm=llm, prompt=default_prompt)

这里我们看到default_prompt 中只包含了一个变量{input},没有包含任何的前缀信息,这是因为default_chain回答的是哪些无法被识别的属于领域的问题,所以这里就让LLM自由发挥了。

下面我们要创建一个路由prompt模板,这是给后续的路由chain使用的:

MULTI_PROMPT_ROUTER_TEMPLATE = """给定一个原始文本输入到\
一个语言模型并且选择最适合输入的模型提示语。\
你将获得可用的提示语的名称以及该提示语最合适的描述。\
如果你认为修改原始输入最终会导致语言模型得到更好的响应,你也可以修改原始输入。

<< FORMATTING >>
返回一个 Markdown 代码片段,其中 JSON 对象的格式如下:
```json
{{{{
"destination": string \ 要使用的提示语的名称或"DEFAULT"
"next_inputs": string \ 原始输入的可能修改版本
}}}}
```

记住:"destination"必须是下面指定的候选提示语中的一种,\
如果输入语句不适合任何候选提示语,则它就是"DEFAULT"。

记住:"next_inputs"可以只是原始输入,如果你认为不需要做任何修改的话。

<< CANDIDATE PROMPTS >>
{destinations}

<< INPUT >>
{{input}}

<< OUTPUT (remember to include the ```json)>>"""

这上面的模板里,我们允许LLM修改用户的原始输入,如果修改后的输入能产生更好的输出效果的话,也就是说LLM会先判断是否需要修改用户的prompt,如果觉得有必要修改用户的prompt,那么就会把修改过的prompt传送给后续处理特定领域问题的chain,如果没必要修改,那么就直接把用户的prompt传送给后续的chain。下面还需要在路由prompt模板中嵌入destinations_str,它是为识别领域chain提供索引: 

router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(
    destinations=destinations_str
)

print(router_template)

接下来我们要定义最核心的MultiPromptChain,它的三个主要参数为路由chain, 领域chain(集合),默认chain。由这3个主要的参数,我们也能猜测出MultiPromptChain的主要处理逻辑:首先让路由chain来识别用户prompt,并将其传送给特定领域chain,如果没找到合适的领域chain,则由默认chain来处理用户prompt,这里我们给MultiPromptChain的verbose设置为True,这样MultiPromptChain在处理用户prompt的时候会输出一些中间结果,这些中间结果有助于我们观察llm的思维过程是否和我们给它的设定的业务逻辑是一致的。如果不想显示中间结果可以把verbose参数设置为False:

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是怎么来回答用户问题的:

response = chain.run("2+2等于几?")
print(response)

 这里我们可以看到LLM能按照我们的router_template模板内的要求识别出该问题属于"math"领域,然后由该领域的chain来回答这个问题,并最后返回了正确的答案。

response = chain.run("成吉思汗是谁?")
print(response)

 

 对于“成吉思汗是谁?”这个问题,我们发现LLM对问题进行了修改,它把用户的问题改成了:“成吉思汗是哪个历史时期的重要人物?”,可能是LLM觉得修改后的prompt更有助于后续的领域chain来回答这个问题吧。

response = chain.run("什么是黑体辐射?")
print(response)

response = chain.run("为什么学习机器学习都要使用python语言?")
print(response)

response = chain.run("天上一共有多少颗星星?")
print(response)

对于“天上一共有多少颗星星?”这个问题,我们看到LLM并没有识别出来它属于哪个领域,因此它返回的领域值为None, 然后该问题交由默认chain来回答。

总结

今天我们学习了Langchain的核心组件chain。主要分为LLMChain,Sequential Chains,Router Chain,其中LLMChain是最基本的chain它简单的组合了LLM和promt, Sequential Chains主要包含SimpleSequentialChain和SequentialChain,对于SimpleSequentialChain来说它只是简单的将多个LLMChain串联在一起,前一个chain的输出是后一个chain的输入,所以总体上来说SimpleSequentialChain只有一个输入和一个输出,而SequentialChain则具体多个输入或输出。而Router Chain则是具有路由功能的chain ,它可以将用户的问题进行分类,从而将问题传递给特定的chain。

参考资料

https://learn.deeplearning.ai/langchain/lesson/4/chains

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

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

相关文章

系列一、RocketMQ入门

一、MQ概述 1.1、MQ简介 MQ&#xff0c;Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件&#xff0c;是一套提供了消息生产、存储、消费全过程的API软件系统。消息&#xff1a;消息即数据&#xff0c;一般消息的体量不会很大。 1.2、M…

redis主从同步对象模型学习笔记

目录 1 淘汰策略1.1 配置1.2 哪些数据将会被淘汰呢&#xff1f;1.2.1 过期key中的1.2.2 所有的key1.2.3 禁止淘汰 2 持久化2.1 背景2.1.1 概念2.1.2 fork进程写时复制机制2.1.3 大key 2.2 redis持久化的方式2.2.1 aof2.2.2 aof-rewrite2.2.3 rdb 2.3 redis持久方案的优缺点2.4 …

Redis跳表

简介 Redis 中的有序集合(Sorted Set)是用跳表&#xff08;Skip list&#xff09;来实现的。这里就需要了解一下跳表的概念。 链表&#xff1a;链表插入&#xff0c;删除某一个节点的时间复杂度是O(1)&#xff0c;但是查询的时间复杂度是O(n)。 跳表就是解决链表在有序节点场…

Jmeter:使用代理录制脚本

目录 前言&#xff1a; 介绍下各设置项&#xff1a; 前言&#xff1a; JMeter 是一个功能强大的性能测试工具&#xff0c;可以用于模拟多种场景下的负载测试和性能测试。其中一个常用的功能是使用代理服务器录制脚本&#xff0c;以便在后续的测试中模拟真实的用户行为。 下…

数据库优化---索引

这里写目录标题 索引简介结构&#xff08;Btree&#xff09;操作总结 索引 简介 优缺点 利远远大于弊 结构&#xff08;Btree&#xff09; 所有的数据都存在叶子节点 操作 具体代码 注意&#xff0c;主键以及唯一约束&#xff0c;都会自动创建一个索引&#xff0c;主键索…

git常用命令之Pull

7. Pull 命令作用延展阅读git pull 1. git fetch2. git merge FETCH_HEAD1. fetch origin的所有分支2. merge 当前分支参考git pull origin master1. git fetch origin master2. git merge FETCH_HEAD 拓展&#xff1a;Git常用命令汇总

时间触发嵌入式系统:各种系统的概念

1.1 引言 一说到软件系统&#xff0c;脑子里面就会闪现很多名词&#xff1a; 信息系统 桌面应用系统 实时系统 嵌入式系统 事件触发系统 时间触发系统 这些名字搞得脑子很乱&#xff0c;感觉都熟悉&#xff0c;又有些陌生&#xff0c;还是需要简单的介绍一下。 1.2 信息系统…

MySQL高可用 MMM

MySQL高可用 MMM 一、MMM1.1 MMM介绍1.2 关于 MMM 高可用架构的说明 二、搭建 MySQL MMM2.1 环境准备2.2 搭建 MySQL 多主多从模式2.3 安装配置 MySQL-MMM 一、MMM 1.1 MMM介绍 Master-Master replication manager for MvSQL&#xff0c;MySQL 主主复制管理器。 1、是一套支持…

vue3如何使用vant中IndexBar索引栏?

目录 1、为什么要使用IndexBar索引栏&#xff1f;2、引入3、基础使用4、处理后端返回的数据5、渲染页面 1、为什么要使用IndexBar索引栏&#xff1f; 在我们开发移动端的时候&#xff0c;有时候会遇到制作通讯录或者城市索引栏&#xff0c;这种时候我们就可以使用vant中快捷方…

warp框架教程2-log模块,addr模块和header模块

log , addr 和 header 从本文开始&#xff0c;我们将介绍 warp 中 Filter 的核心模块。在文档中有 filter 相关模块的介绍&#xff0c; 本文来介绍其中的 addr&#xff0c;header 和 log addr 模块 addr 模块非常简单&#xff0c;它是用来获取远程客户端的地址的。使用起来…

高性能计算学习教程,从入门到精通

学习高性能计算需要一定的计算机科学和数学基础。以下是一个详细的学习路线&#xff0c;从入门到精通高性能计算的步骤&#xff1a; 阶段一&#xff1a;基础知识学习 计算机科学基础&#xff1a;了解计算机体系结构、操作系统、数据结构和算法。学习编程语言如C/C、Python等。 …

苹果手机没法访问Fildder代理服务怎么办

浏览器输入http://ip:port进入可下载证书页面 异常情况&#xff1a; 浏览器访问http://ip:port后无响应&#xff0c;白屏&#xff0c;或有“无法使用跳转网络”的提示 解决方法&#xff1a; 1. PC重新下载fiddle证书并重启 Fildder4--Tools--Options--HTTPS--Actions--"…

【2022吴恩达机器学习课程视频翻译笔记】2.5无监督学习-part-2

2.5无监督学习-part-2 In the last video, you saw what is unsupervised learning, and one type of unsupervised learning called clustering. Let’s give a slightly more formal definition of unsupervised learning and take a quick look at some other types of uns…

ruoyi-vue版本(三十)Spring Security 安全框架中token的生成与解析

目录 1 使用2 写工具类3 使用工具类 1 使用 1 项目里面添加依赖 <!-- Token生成与解析--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency>2 写工具类 package com.ruoyi.framework.we…

【MQ】消息队列的简介以及常见问题的解决方案

MQ MQ的基本概念 MQ全称Message Queue&#xff08;消息队列&#xff09;&#xff0c;实在消息的传输过程中保存消息的容器。多用于分布式系统之间的通信。 分布式系统的两种通信方式&#xff1a;直接调用、借助第三方间接完成 发送者成为生产者&#xff0c;接受者称为消费者…

想要用独立站打造跨境电商品牌吗?这些方法学起来吧!

随着互联网的发展&#xff0c;越来越多的跨境电商卖家开始考虑在独立站上打造自己的品牌。相比于在第三方平台上经营&#xff0c;拥有独立站不仅能够提高品牌认知度和形象&#xff0c;还能够更好地控制产品质量、维护顾客关系&#xff0c;以及获取更多的利润。而要打造一个成功…

CSS盒模型

目录 盒子区域包含块/containing block包含块的确定包含块的影响 行盒/line-boxes行盒的特性vertical-align BFCFCBFC的创建BFC的作用 关于BFC解决margin折叠问题关于设置overflow:auto解决浮动塌陷问题BFC解决塌陷问题的两个条件BFC计算高度规则 盒子区域 浏览器在展示每一个…

N-121基于微信小程序网上书城系统

开发工具&#xff1a;IDEA、微信小程序 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;vue、uniapp 服务端技术&#xff1a;springbootmybatisredis 本系统分微信小程序和管理后台两部分&a…

(23)目标检测算法之YOLOv6 (1)全流程指南:环境安装、模型配置、训练及推理

目标检测算法之YOLOv6 (1)全流程指南&#xff1a;环境安装、模型配置、训练及推理 本文向将介绍 YOLOv6 的整体框架&#xff0c;并提供详细的教程链接。官方论文 ☞ YOLOv6: A Single-Stage Object Detection Framework for Industrial Applicationsv3.0版本论文更新 ☞ YOLOv…

综合评价算法 | Matlab实现基于AHP层次分析法的综合评价算法

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 综合评价算法 | Matlab实现基于AHP层次分析法的综合评价算法 研究内容 AHP的主要特点是通过建立递阶层次结构,把人类的判断转化到若干因 素两两之间重要度的比较上,从而把难于量化的定性判断转化为可操作…