继《面向开发者的ChatGPT提示工程》一课爆火之后,时隔一个月,吴恩达教授再次推出了别的三门免费的AI课程,今日要讲的就是其间联合了 LangChain 一起授课的——《依据LangChain的大言语模型运用开发》。

这门课程将体系地介绍 LangChain 的常见组件及其运用,包括:

  • 模型,提示和输出解析(第1章节)
  • 回忆(第2章节)
  • 链(第3章节)
  • 依据文档的问答(第4章节)
  • 评价(第5章节)
  • 代理(第6章节)

本篇为上篇,首要涵盖第1~3章节。

作为一篇图文笔记,本文编撰的首要意图是对该课程内容的精华部分进行提炼和组织,便利读者进行回顾与总结

——究竟,图文阅读的功率总是要比观看视频高得多的。

(本课程的在线观看链接以及可运转代码地址均在文末,可自取。)

介绍

LangChain是什么?

一个开源的、用于构建LLM运用的开发框架

LangChain做了什么作业?

虽然经过提示(Prompt),能够加快开发LLM运用的进程,但过程中可能会发生许多胶水代码。

LangChain所做的,就是把其间一些公共的部分笼统出来

LangChain有什么特色?

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

LangChain重视组合和模块化

LangChain拥有许多独立组件,能够单独运用,也能够与其他组件组合运用。

经过将模块化的组件链式组合,能够构建一个更完好的运用程序。

模型、提示与输出解析

先理清几个概念:

概念 解释
模型 言语模型,用于生成文本。
提示 用于向模型传递信息。
解析器 接纳模型的输出,并将其解析成更结构化的格局。

LangChain供给了一套简略的笼统,用于简化原先需要对模型重复提示与解析的操作。

直接调用API vs 运用LangChain

运用LangChain访问ChatGPT,与直接运用OpenAI API有什么区别?让咱们用一个比方来对比一下。

任务是将文本按指定风格翻译成方针言语。

直接调用API

过程1:定义辅佐函数,用于调用OpenAI API

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"]

过程2:定义待翻译文本与翻译风格

# 文本
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!
"""
# 风格
style = """American English \
in a calm and respectful tone
"""

过程3:定义提示,用于指定方针言语,并以字符串插值的办法刺进文本与风格

prompt = f"""Translate the text \
that is delimited by triple backticks 
into a style that is {style}.
text: ```{customer_email}```
"""

过程4:调用函数并打印成果

response = get_completion(prompt)
print(response)

运用LangChain

过程1:创立ChatOpenAI实例

# 导入ChatOpenAI,这是LangChain对ChatGPT API访问的笼统
from langchain.chat_models import ChatOpenAI
# 要控制 LLM 生成文本的随机性和创造性,请运用 temperature = 0.0
chat = ChatOpenAI(temperature=0.0)

过程2:创立提示模板实例

# 模板字符串,用于指定方针言语,拥有两个输入变量,"style"和"text"
template_string = """Translate the text \
that is delimited by triple backticks \
into a style that is {style}. \
text: ```{text}```
"""
# 构建一个ChatPromptTemplate实例,用于模板的重用
from langchain.prompts import ChatPromptTemplate
prompt_template = ChatPromptTemplate.from_template(template_string)

过程3:定义翻译风格与待翻译文本,作为输入变量传入提示模板

# 风格
customer_style = """American English \
in a calm and respectful tone
"""
# 文本
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!
"""
# 将风格和文本作为输入变量传入提示模板
customer_messages = prompt_template.format_messages(
                    style=customer_style,
                    text=customer_email)

过程4:调用LLM翻译成指定风格,并打印成果

customer_response = chat(customer_messages)
print(customer_response.content)

能够看出,运用LangChain访问ChatGPT,与直接运用OpenAI API相比,首要区别是:

  • 对ChatGPT API的访问做了笼统,简化调用
  • 改用提示模板,而不是”f”字符串,便利重用

为什么要运用提示模板?

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

构建杂乱的运用程序时,提示可能会适当冗长且具体。

提示模板作为一种笼统,能够让咱们当令重用提示

此外,LangChain还为一些常见操作供给了提示,如摘要、答复问题、连接到SQL数据库或连接到不同的API。

经过运用LangChain的内置提示,能够快速地使运用程序运转,而无需设计自己的提示。

LangChain输出解析器的作用

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

输出解析器能够提取模型输出中的特定字段,解析为更易于处理的格局

比方,解析为 Python 字典:

过程1:指定回来的JSON的格局标准

from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser
# 礼物标准
gift_schema = ResponseSchema(name="gift",
                             description="Was the item purchased\
                             as a gift for someone else? \
                             Answer True if yes,\
                             False if not or unknown.")
# 送货日期标准
delivery_days_schema = ResponseSchema(name="delivery_days",
                                      description="How many days\
                                      did it take for the product\
                                      to arrive? If this \
                                      information is not found,\
                                      output -1.")
# 价格值标准
price_value_schema = ResponseSchema(name="price_value",
                                    description="Extract any\
                                    sentences about the value or \
                                    price, and output them as a \
                                    comma separated Python list.")

过程2:创立解析器实例,获取格局指令

# 将格局标准放到一个列表里
response_schemas = [gift_schema, 
                    delivery_days_schema,
                    price_value_schema]
# 构建一个StructuredOutputParser实例
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 获取将发送给LLM的格局指令
format_instructions = output_parser.get_format_instructions()
print(format_instructions)

格局指令用于让LLM生成指定的内容格局,以便解析器能够解析,打印得到其内容如下:

The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "\`\`\`json" and "\`\`\`":
```json
{
	"gift": string  // Was the item purchased as a gift for someone else? Answer True if yes, False if not or unknown.
	"delivery_days": string  // How many days did it take for the product to arrive? If this information is not found,                                      output -1.
	"price_value": string  // Extract any sentences about the value or price, and output them as a comma separated Python list.
}
\```

过程3:创立提示模板实例,将文本和格局指令作为输入变量传入

# 提示
review_template_2 = """\
For the following text, extract the following information:
gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.
delivery_days: How many days did it take for the product\
to arrive? If this information is not found, output -1.
price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.
text: {text}
{format_instructions}
"""
# 构建一个ChatPromptTemplate实例,用于模板的重用
prompt = ChatPromptTemplate.from_template(template=review_template_2)
# 将文本和格局指令作为输入变量传入
messages = prompt.format_messages(text=customer_review, 
                                format_instructions=format_instructions)

过程4:调用LLM解析文本,并打印成果

response = chat(messages)
print(response.content)

打印成果如下:

```json
{
	"gift": true,
	"delivery_days": "2",
	"price_value": ["It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features."]
}
\```

过程5:将成果解析为字典类型,并提取与送货天数相关联的值

output_dict = output_parser.parse(response.content)
print(output_dict.get('delivery_days'))

提取到的值如下:

'2'

回忆(Memory)

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

当咱们与模型互动时,由于模型自身是无状况的,因此它一般无法记住之前对话的前史音讯。

每个请求交互,每次调用API都是独立的,这关于构建流畅的对话运用是个问题。

为此,LangChain供给了多种回忆存储办理策略。

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

策略 特色
ConversationBufferMemory 存储完好的对话前史
ConversationBufferWindowMemory 只保存最后几轮对话
ConversationalTokenBufferMemory 约束存储的令牌数量
ConversationSummaryBufferMemory 运用摘要存储对话前史

ConversationBufferMemory

ConversationBufferMemory可用于临时存储完好的对话前史。

比方如下:

过程1:创立对话链实例

from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferMemory()
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=True
)

过程2:运用”conversation.predict”函数进行对话

conversation.predict(input="Hi, my name is Andrew")
conversation.predict(input="What is 1+1?")
conversation.predict(input="What is my name?")

也可运用”memory.save_context”直接往存储里添加新内容

memory.save_context({"input": "Not much, just hanging"},
                    {"output": "Cool"})

由于咱们把”verbose”变量改成”True,因此能够看到LangChain运转时的更多细节:

> Entering new ConversationChain chain…

Prompt after formatting:

The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: Hi, my name is Andrew

AI: Hello Andrew, it’s nice to meet you. My name is AI. How can I assist you today?

Human: What is 1+1?

AI: The answer to 1+1 is 2.

Human: What is my name?

AI:

> Finished chain.

‘Your name is Andrew, as you mentioned earlier.’

能够看到,回忆存储包括了到目前为止的一切对话音讯,并用作LLM的输入或额外上下文。

这样,它在生成输出时,就能够依据之前所说过的会话内容,再生成新的会话,让你感觉它好像“记得”你说过的话。

过程3:打印当前对话存储的一切前史音讯

print(memory.buffer)

Human: Hi, my name is Andrew

AI: Hello Andrew, it’s nice to meet you. My name is AI. How can I assist you today?

Human: What is 1+1?

AI: The answer to 1+1 is 2.

Human: What is my name?

AI: Your name is Andrew, as you mentioned earlier.

或者,

print(memory.load_memory_variables({}))

{‘history’: “Human: Hi, my name is Andrew\nAI: Hello Andrew, it’s nice to meet you. My name is AI. How can I assist you today?\nHuman: What is 1+1?\nAI: The answer to 1+1 is 2.\nHuman: What is my name?\nAI: Your name is Andrew, as you mentioned earlier.”}

但随着对话的进行,回忆存储的大小会添加,发送Token的本钱也会添加,为此,LangChain供给了别的几种策略。

ConversationBufferWindowMemory

ConversationBufferWindowMemory只保存窗口回忆,也即只保存最后几轮对话。它有一个变量k,表示想记住最后几轮对话。

比方,当k等于1时,表示仅记住最后一轮对话。

比方如下:

from langchain.memory import ConversationBufferWindowMemory
llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=False
)

咱们能够在进行几轮对话之后,尝试让其回顾之前的对话内容:

conversation.predict(input="Hi, my name is Andrew")
# "Hello Andrew, it's nice to meet you. My name is AI. How can I assist you today?"
conversation.predict(input="What is 1+1?")
# 'The answer to 1+1 is 2.'
conversation.predict(input="What is my name?")
# "I'm sorry, I don't have access to that information. Could you please tell me your name?"

这时咱们会发现,由于窗口回忆的约束,它会丢掉了前面有关姓名的沟通,从而无法说出我的姓名。

这个功能能够避免回忆存储量随着对话的进行而无限增加。当然在实践运用时,k不会设为1,而是会一般设置为一个较大的数字。

ConversationalTokenBufferMemory

许多LLM定价是依据Token的,Token调用的数量直接反映了LLM调用的本钱。

运用ConversationalTokenBufferMemory,能够约束保存在回忆存储的令牌数量。

比方如下:

from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI
llm = ChatOpenAI(temperature=0.0)
# 指定LLM和Token约束值
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)

在刺进一些音讯之后,咱们能够打印其实践保存的前史音讯。

# 刺进一些音讯
memory.save_context({"input": "AI is what?!"},
                    {"output": "Amazing!"})
memory.save_context({"input": "Backpropagation is what?"},
                    {"output": "Beautiful!"})
memory.save_context({"input": "Chatbots are what?"}, 
                    {"output": "Charming!"})
# 打印前史音讯
memory.load_memory_variables({})

打印内容如下:

{‘history’: ‘AI: Beautiful!\nHuman: Chatbots are what?\nAI: Charming!’}

咱们会发现,当把Token约束值调得比较高时,它几乎能够包括整个对话。

而假如减少值,它会删掉对话最早的那部分音讯,只保存最近对话的音讯,而且保证总的音讯内容长度不超过Token约束值

别的,之所以还要指定一个LLM参数,是由于不同的LLM运用不同的Token核算办法。

这里是告知它,运用ChatOpenAI LLM运用的核算Token的办法。

ConversationSummaryBufferMemory

ConversationSummaryBufferMemory试图将音讯的显性回忆,保持在咱们设定的Token约束值之下,也即

  1. 当Token约束值能覆盖文本长度时,会存储整个对话前史。
  2. 而当Token约束值小于文本长度时,则会为一切前史音讯生成摘要,改在回忆中存储前史音讯的摘要。

以状况2为例:

from langchain.memory import ConversationSummaryBufferMemory
# 创立一个长字符串
schedule = "There is a meeting at 8am with your product team. \
You will need your powerpoint presentation prepared. \
9am-12pm have time to work on your LangChain \
project which will go quickly because Langchain is such a powerful tool. \
At Noon, lunch at the italian resturant with a customer who is driving \
from over an hour away to meet you to understand the latest in AI. \
Be sure to bring your laptop to show the latest LLM demo."
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({"input": "Hello"}, {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
                    {"output": "Cool"})
memory.save_context({"input": "What is on the schedule today?"}, 
                    {"output": f"{schedule}"})
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=True
)
conversation.predict(input="What would be a good demo to show?")

运转的细节如下:

> Entering new ConversationChain chain…

Prompt after formatting:

The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

System: The human and AI engage in small talk before discussing the day’s schedule. The AI informs the human of a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in the latest AI developments.

Human: What would be a good demo to show?

AI:

> Finished chain.

“Based on the customer’s interest in AI developments, I would suggest showcasing our latest natural language processing capabilities. We could demonstrate how our AI can accurately understand and respond to complex language queries, and even provide personalized recommendations based on the user’s preferences. Additionally, we could highlight our AI’s ability to learn and adapt over time, making it a valuable tool for businesses looking to improve their customer experience.”

能够看到,由于超过了设定的Token约束值,它为前史会话的生成了一个摘要,并放在体系音讯的提示词中。

其他回忆存储办理策略

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

策略 特色
向量数据存储(VectorDataMemory) 存储嵌入向量,用于检索相关文本块
实体回忆存储(EntityMemories) 记住特定实体的具体信息,比方对话中某个重要人物的信息

除了这些回忆存储类型,也可将整个对话存储在传统数据库中,如键值存储(key-value store)或SQL数据库。

这样就能够回顾整个对话,进行审计或进一步改善体系。

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

链(Chain)是LangChain中最要害的构建模块

除了将 LLM 与提示结合在一起,还能够经过组合多个链,对文本或其他数据履行一系列的操作。

LangChain供给了多种可用的链类型:

类型 场景
LLM链(LLMChain) 将LLM和提示结合在一起
简略次序链(SimpleSequentialChain) 只需要一个输入而且只回来一个输出
惯例次序链(SequentialChain) 有多个输入或多个输出
路由链(RouterChain) 依据输入的具体内容路由到不同的子链

下面让咱们来逐个了解一下。

首要,用 pandas DataFrame 加载一些稍后要用到的数据。

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

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

LLM链(LLMChain)

LLM链是一个简略但十分强壮的链,它是咱们后边要讨论的其他链类型的基础,用于将LLM和提示结合在一起。

比方如下:

过程1:初始化言语模型和提示

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
# 用一个比较高的temperature值以获得一些更有意思的成果
llm = ChatOpenAI(temperature=0.9)
# 接纳一个名为“product”的变量,要求LLM生成描绘生产该产品的公司的最佳称号
prompt = ChatPromptTemplate.from_template(
    "What is the best name to describe \
    a company that makes {product}?"
)

过程2:将产品传入链中,并运转链

chain = LLMChain(llm=llm, prompt=prompt)
product = "Queen Size Sheet Set"
chain.run(product)

运转链后,它将在后台格局化提示词,然后将格局化后的完好提示词传递给LLM,然后得到成果:

‘Royal Beddings.’

简略次序链(SimpleSequentialChain)

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

当咱们的子链只需要一个输入而且只回来一个输出时,简略次序链很有用。

比方如下:

过程1:初始化言语模型

from langchain.chains import SimpleSequentialChain
llm = ChatOpenAI(temperature=0.9)

过程2:创立第一个链

# 提示模板1:承受产品并回来描绘该公司的最佳称号
first_prompt = ChatPromptTemplate.from_template(
    "What is the best name to describe \
    a company that makes {product}?"
)
# 第一个链
chain_one = LLMChain(llm=llm, prompt=first_prompt)

过程3:创立第二个链

# 提示模板2:获取公司称号,然后输出该公司的 20 字描绘
second_prompt = ChatPromptTemplate.from_template(
    "Write a 20 words description for the following \
    company:{company_name}"
)
# 第二个链
chain_two = LLMChain(llm=llm, prompt=second_prompt)

过程4:创立简略次序链实例,并运转链

# 第一个链的输出将传递到第二个链
overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],
                                             verbose=True
                                            )
overall_simple_chain.run(product)

运转的细节如下:

> Entering new SimpleSequentialChain chain…

“Royal Bedding Co.”

“Royal Bedding Co. offers luxurious and comfortable bedding solutions for a restful and regal sleep experience fit for royalty.”

> Finished chain.

能够看到,它首要输出公司称号,然后将其传递到第二条链,并给出该公司可能的业务描绘。

惯例次序链(SequentialChain)

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

当有多个输入或多个输出时,能够运用惯例次序链。

比方如下:

过程1:初始化言语模型

from langchain.chains import SequentialChain
llm = ChatOpenAI(temperature=0.9)

过程2:创立一堆将顺次运用的链

# 第一条链,将谈论翻译成英语。
first_prompt = ChatPromptTemplate.from_template(
    "Translate the following review to english:"
    "\n\n{Review}"
)
chain_one = LLMChain(llm=llm, prompt=first_prompt, 
                     output_key="English_Review"
                    )
# 第二条链,用一句话总结该谈论       
second_prompt = ChatPromptTemplate.from_template(
    "Can you summarize the following review in 1 sentence:"
    "\n\n{English_Review}"
)
chain_two = LLMChain(llm=llm, prompt=second_prompt, 
                     output_key="summary"
                    )
# 第三条链,检测原始谈论的言语
third_prompt = ChatPromptTemplate.from_template(
    "What language is the following review:\n\n{Review}"
)
chain_three = LLMChain(llm=llm, prompt=third_prompt,
                       output_key="language"
                      )
# 第四条链,接纳第二条链的摘要内容("summary"变量),以及第三条链的言语类别("language"变量),要求后续回复摘要内容时运用指定言语。
fourth_prompt = ChatPromptTemplate.from_template(
    "Write a follow up response to the following "
    "summary in the specified language:"
    "\n\nSummary: {summary}\n\nLanguage: {language}"
)
chain_four = LLMChain(llm=llm, prompt=fourth_prompt,
                      output_key="followup_message"
                     )

惯例次序链中的任何一个过程,都能够接纳来自上游的多个输入变量,特别当你有杂乱的下游链需要和多个上游链组合时,这会十分有用。

过程3:将这些链组合在次序链中,并指定输入与输出变量

overall_chain = SequentialChain(
    chains=[chain_one, chain_two, chain_three, chain_four],
    input_variables=["Review"],
    output_variables=["English_Review", "summary","followup_message"],
    verbose=True
)

让这些变量称号精确摆放十分重要,由于有许多不同的输入和输出。假如你遇到任何问题,请检查它们摆放次序是否正确。

过程4:选择一条谈论并将其传递到整个链中

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

履行的细节如下:

> Entering new SequentialChain chain…

> Finished chain.

{‘Review’: “Je trouve le got mdiocre. La mousse ne tient pas, c’est bizarre. J’achte les mmes dans le commerce et le got est bien meilleur…\nVieux lot ou contrefaon !?”,

‘English_Review’: “I find the taste mediocre. The foam doesn’t hold up, it’s weird. I buy the same ones in stores and the taste is much better… Old batch or counterfeit!?”,

‘summary’: ‘The reviewer expresses dissatisfaction with the taste and foam of the product, suspecting that it might be an old batch or counterfeit.’,

‘followup_message’: “Rponse : Le critique exprime sa dception quant au got et la mousse du produit, souponnant qu’il s’agit peut-tre d’un lot prim ou contrefait. Il est important que les fabricants prennent des mesures pour garantir la qualit de leurs produits afin de maintenir la confiance de leurs clients. Nous esprons que ce problme sera rapidement rsolu pour que les consommateurs puissent profiter du produit tel qu’il est cens tre.”}

能够看到,其终究采用了检测到的原始言语——法语对摘要内容进行了回复。

路由链(RouterChain)

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

假如你有多个子链,且每个子链专门负责处理某种特定类型的输入,这种状况就能够运用路由链。

路由链会依据输入的具体内容路由到不同的子链

它会首要判断该运用哪个子链,然后将输入传递到相应的子链。

比方如下:

过程1:供给多个特定类型的提示模板

# 第一个提示,合适答复物理问题
physics_template = """You are a very smart physics professor. \
You are great at answering questions about physics in a concise\
and easy to understand manner. \
When you don't know the answer to a question you admit\
that you don't know.
Here is a question:
{input}"""
# 第二个提示,合适答复数学问题
math_template = """You are a very good mathematician. \
You are great at answering math questions. \
You are so good because you are able to break down \
hard problems into their component parts, 
answer the component parts, and then put them together\
to answer the broader question.
Here is a question:
{input}"""
# 第三个提示,合适答复前史问题
history_template = """You are a very good historian. \
You have an excellent knowledge of and understanding of people,\
events and contexts from a range of historical periods. \
You have the ability to think, reflect, debate, discuss and \
evaluate the past. You have a respect for historical evidence\
and the ability to make use of it to support your explanations \
and judgements.
Here is a question:
{input}"""
# 第四个提示,合适答复核算机科学问题。
computerscience_template = """ You are a successful computer scientist.\
You have a passion for creativity, collaboration,\
forward-thinking, confidence, strong problem-solving capabilities,\
understanding of theories and algorithms, and excellent communication \
skills. You are great at answering coding questions. \
You are so good because you know how to solve a problem by \
describing the solution in imperative steps \
that a machine can easily interpret and you know how to \
choose a solution that has a good balance between \
time complexity and space complexity. 
Here is a question:
{input}"""

过程2:为每个提示模板供给更多相关信息

这些信息将传递给路由链,以帮助路由链决定何时运用哪条子链。

prompt_infos = [
    {
        "name": "physics", 
        "description": "Good for answering questions about physics", 
        "prompt_template": physics_template
    },
    {
        "name": "math", 
        "description": "Good for answering math questions", 
        "prompt_template": math_template
    },
    {
        "name": "History", 
        "description": "Good for answering history questions", 
        "prompt_template": history_template
    },
    {
        "name": "computer science", 
        "description": "Good for answering computer science questions", 
        "prompt_template": computerscience_template
    }
]

过程3:导入需要的链类型,定义运用的言语模型

MultiPromptChain是一种特定类型的链,用于在多个不同提示模板之间进行路由。

LLMRouterChain会凭借言语模型的帮助,让言语模型依据上面供给的称号和描绘等信息,判断怎么路由。

RouterOutputParser将LLM输出解析成一个字典,依据字典内容确认下游运用哪条链,以及链的输入应该是什么。

from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.prompts import PromptTemplate
llm = ChatOpenAI(temperature=0)

过程4:创立方针链

路由链会依据输入内容调用这些方针链的其间一个。

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)

过程5:创立默许链

默许链是在路由找不到合适的子链调用时,用来备用的一条链路。

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

过程6:定义一个路由提示模板

LLM 会依据提示词的内容在不同链之间路由。

MULTI_PROMPT_ROUTER_TEMPLATE = """Given a raw text input to a \
language model select the model prompt best suited for the input. \
You will be given the names of the available prompts and a \
description of what the prompt is best suited for. \
You may also revise the original input if you think that revising\
it will ultimately lead to a better response from the language model.
<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
\```json
{{{{
    "destination": string \ name of the prompt to use or "DEFAULT"
    "next_inputs": string \ a potentially modified version of the original input
}}}}
\```
REMEMBER: "destination" MUST be one of the candidate prompt \
names specified below OR it can be "DEFAULT" if the input is not\
well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input \
if you don't think any modifications are needed.
<< CANDIDATE PROMPTS >>
{destinations}
<< INPUT >>
{{input}}
<< OUTPUT (remember to include the ```json)>>"""

过程7:组合言语模型、路由提示模板,构成路由链

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)

过程8:组合路由链、方针链和默许链,创立整条链

chain = MultiPromptChain(router_chain=router_chain,
                         destination_chains=destination_chains, 
                         default_chain=default_chain, verbose=True
                        )

过程9:提问不同类型的问题

# 物理问题
chain.run("What is black body radiation?")

输出如下:

> Entering new MultiPromptChain chain…

physics: {‘input’: ‘What is black body radiation?’}

> Finished chain.

“Black body radiation refers to the electromagnetic radiation emitted by a perfect black body, which is an object that absorbs all radiation that falls on it and emits radiation at all wavelengths. The radiation emitted by a black body depends only on its temperature and follows a specific distribution known as Planck’s law. This type of radiation is important in understanding the behavior of stars, as well as in the development of technologies such as incandescent light bulbs and infrared cameras.”

# 数学问题
chain.run("what is 2 + 2")

输出如下:

> Entering new MultiPromptChain chain…

math: {‘input’: ‘what is 2 + 2’}

> Finished chain.

‘As an AI language model, I can answer this question easily. The answer to 2 + 2 is 4.’

# 生物问题,无匹配,走默许链
chain.run("Why does every cell in our body contain DNA?")

> Entering new MultiPromptChain chain…

None: {‘input’: ‘Why does every cell in our body contain DNA?’}

> Finished chain.

‘Every cell in our body contains DNA because DNA carries the genetic information that determines the characteristics and functions of each cell. DNA contains the instructions for the synthesis of proteins, which are essential for the structure and function of cells. Additionally, DNA is responsible for the transmission of genetic information from one generation to the next. Therefore, every cell in our body needs DNA to carry out its specific functions and to maintain the integrity of the organism as a whole.’

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

可运转代码地址:learn.deeplearning.ai/langchain/l…