# 一.基本介绍
# 1.什么是 LangChain?
LangChain 是一个用于开发由语言模型驱动的应用程序的框架。它使得应用程序能够:
- 具有上下文感知能力:将语言模型连接到上下文来源(提示指令,少量的示例,需要回应的内容等)
- 具有推理能力:依赖语言模型进行推理(根据提供的上下文如何回答,采取什么行动等)
# 2.架构
这个框架由几个部分组成。
- LangChain 库:Python 和 JavaScript 库。包含了各种组件的接口和集成,一个基本的运行时,用于将这些组件组合成链和代理,以及现成的链和代理的实现。
- LangChain 模板:一系列易于部署的参考架构,用于各种任务。
- LangServe:一个用于将 LangChain 链部署为 REST API 的库。
- LangSmith:一个开发者平台,让你可以调试、测试、评估和监控基于任何 LLM 框架构建的链,并且与 LangChain 无缝集成。
这些产品一起简化了整个应用程序的生命周期:
- 开发:在 LangChain/LangChain.js 中编写你的应用程序。使用模板作为参考,快速开始。
- 生产化:使用 LangSmith 来检查、测试和监控你的链,这样你可以不断改进并有信心地部署。
- 部署:使用 LangServe 将任何链转换为 API。
# 3.LangChain 库
LangChain 包的主要价值主张是:
- 组件:用于处理语言模型的可组合工具和集成。无论你是否使用 LangChain 框架的其余部分,组件都是模块化的,易于使用
- 现成的链:用于完成高级任务的组件的内置组合
现成的链使得开始变得容易。组件使得定制现有链和构建新链变得容易。
LangChain 库本身由几个不同的包组成。
langchain-core
:基础抽象和 LangChain 表达式语言。langchain-community
:第三方集成。langchain
:构成应用程序认知架构的链、代理和检索策略。
# 4.安装 langchain
pip install langchain
# 5.环境设置
安装openai
使用 LangChain 通常需要与一个或多个模型提供者、数据存储、API 等进行集成。在本示例中,我们将使用 OpenAI 的模型 API。
首先,我们需要安装他们的 Python 包:
pip install openai
访问API需要一个API密钥
export OPENAI_API_KEY="..."
如果你不想设置环境变量,你可以在初始化 OpenAI LLM 类时直接通过openai_api_key
命名参数传递密钥:
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="...")
2
# 6.三大组件
LangChain 应用程序的核心构建模块是 LLMChain。它结合了三个方面:
- LLM: 语言模型是核心推理引擎。要使用 LangChain,您需要了解不同类型的语言模型以及如何使用它们。
- Prompt Templates: 提供语言模型的指令。这控制了语言模型的输出,因此了解如何构建提示和不同的提示策略至关重要。
- Output Parsers: 将 LLM 的原始响应转换为更易处理的格式,使得在下游使用输出变得容易。
# 7.语言模型
LangChain 中有两种类型的语言模型,称为:
- LLMs: 这是一个以字符串作为输入并返回字符串的语言模型
- ChatModels: 这是一个以消息列表作为输入并返回消息的语言模型
LLMs 的输入/输出简单易懂 - 字符串。但是 ChatModels 呢?那里的输入是一个ChatMessage
列表,输出是一个单独的ChatMessage
。 一个ChatMessage
具有两个必需的组件:
content
: 这是消息的内容。role
: 这是ChatMessage
来自的实体的角色。
LangChain 为两者提供了一个标准接口,但了解这种差异以便为给定的语言模型构建提示非常有用。LangChain 提供的标准接口有两种方法:
predict
: 接受一个字符串,返回一个字符串predict_messages
: 接受一个消息列表,返回一个消息。
# 8.角色
LangChain 提供了几个对象,用于方便地区分不同的角色:
HumanMessage
: 来自人类/用户的ChatMessage
。AIMessage
: 来自 AI/助手的ChatMessage
。SystemMessage
: 来自系统的ChatMessage
。FunctionMessage
: 来自函数调用的ChatMessage
。
# 9.代码示例
示例1:
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
llm = OpenAI()
chat_model = ChatOpenAI()
llm.predict("hi!")
>>> "Hi"
chat_model.predict("hi!")
>>> "Hi"
2
3
4
5
6
7
8
9
10
11
示例2:
使用predict
方法对字符串输入进行处理
text = "What would be a good company name for a company that makes colorful socks?"
llm.predict(text)
# >> Feetful of Fun
chat_model.predict(text)
# >> Socks O'Color
2
3
4
5
6
7
示例3:
使用predict_messages
方法对消息列表进行处理。
from langchain.schema import HumanMessage
text = "制造多彩袜子的公司的好名字是什么?"
messages = [HumanMessage(content=text)]
llm.predict_messages(messages)
# >> Feetful of Fun
chat_model.predict_messages(messages)
# >> Socks O'Color
2
3
4
5
6
7
8
9
10
# 10.提示模版
大多数 LLM 应用程序不会直接将用户输入传递到 LLM 中。通常,它们会将用户输入添加到一个更大的文本片段中,称为提示模板,该模板提供了有关特定任务的附加上下文。
在前面的示例中,我们传递给模型的文本包含了生成公司名称的指令。对于我们的应用程序,如果用户只需提供公司/产品的描述而无需担心给出模型指令,那将非常好。
PromptTemplates正是为此而设计的!它们将用户输入转化为完全格式化的提示的所有逻辑绑定在一起。这可以从非常简单的开始 - 例如,产生上述字符串的提示只需是
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
prompt.format(product="colorful socks")
What is a good name for a company that makes colorful socks?
2
3
4
5
6
多参数模板:
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")
2
3
4
5
6
7
8
9
10
11
12
13
14
[
SystemMessage(content="You are a helpful assistant that translates English to French.", additional_kwargs={}),
HumanMessage(content="I love programming.")
]
2
3
4
# 11.输出解析器
OutputParsers 将 LLM 的原始输出转换为可以在下游使用的格式。输出解析器有几种主要类型,包括:
- 将 LLM 的文本转换为结构化信息(例如 JSON)
- 将 ChatMessage 转换为字符串
- 将除消息之外的其他信息(如 OpenAI 函数调用)转换为字符串。
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
CommaSeparatedListOutputParser().parse("hi, bye")
# >> ['hi', 'bye']
2
3
4
5
6
7
8
9
10
11
# 12.LLMChain 示例
现在,我们可以将所有这些组合成一个链组件。这个链组件将接收输入变量,将其传递给提示模板以创建提示,将提示传递给 LLM,然后通过一个(可选的)输出解析器将输出传递出去。这是一种方便地将模块化逻辑捆绑在一起的方式。让我们看看它的作用!
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chain = LLMChain(
llm=ChatOpenAI(),
prompt=chat_prompt,
output_parser=CommaSeparatedListOutputParser()
)
chain.run("colors")
# >> ['red', 'blue', 'green', 'yellow', 'orange']
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 二.LangChain 表达式语言
# 1.
LCEL 是一种声明性的组合链的方式。LCEL 从第一天开始就被设计为支持将原型投入生产,无需更改代码,从最简单的“提示 + LLM”链到最复杂的链。
- 概述 (opens new window):LCEL 及其优点
- 接口 (opens new window):LCEL 对象的标准接口
- 如何 (opens new window):LCEL 的关键特性
- 烹饪书 (opens new window):完成常见任务的示例代码
# 2.OutputParser
JsonOutputParser 和 StrOutputParser 区别
- 对于数组类型的 json 字符串,使用 JsonOutputParser
- 对于单个的 json 字符串,使用 StrOutputParser
- 对于单个字符串,使用 StrOutputParser
使用JsonOutputParser接收:
# 三.学习调试
# 1.初体验
fastagi代理
# export OPENAI_API_KEY="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"
# export OPENAI_API_KEY="sk-YZYSy3yOGuWzVGwi4555E869E22247Be93D5E7199d33A60c"
# llm = OpenAI(openai_api_key="sk-YZYSy3yOGuWzVGwi4555E869E22247Be93D5E7199d33A60c")
from langchain.chat_models import ChatOpenAI
model = ChatOpenAI(
openai_api_key="sk-YZYSy3yOGuWzVGwi4555E869E22247Be93D5E7199d33A60c",
openai_api_base="https://fastagi.deepexi.com/v1",
model_name="gpt-35-turbo-16k", # 16K
temperature=0.0,
request_timeout=20,
max_retries=5,
)
text = "What would be a good company name for a company that makes colorful socks?"
model.predict(text)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
chatanywhere代理
from langchain.chat_models import ChatOpenAI
model = ChatOpenAI(
openai_api_key="sk-xxxx",
openai_api_base="https://api.chatanywhere.com.cn/v1",
# model_name="GPT-3.5-turbo-0613", # 16K
temperature=0.0,
request_timeout=20,
max_retries=5,
)
model.predict("hi!")
2
3
4
5
6
7
8
9
10
# 2.提示模版
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
prompt.format(product="colorful socks")
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 四.高阶使用
# 1.鹦鹉笑话
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("告诉我一个关于 {topic} 的笑话")
parser = StrOutputParser()
chain = prompt | model | parser
async for chunk in chain.astream({"topic": "鹦鹉"}):
print(chunk, end="|", flush=True)
2
3
4
5
6
7
8
9
# 2.单个调用
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model
chain.invoke({"topic": "bears"})
2
3
4
5
6
# 3.批量调用
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model
# 批量调用
chain.batch([{"topic": "bears"}, {"topic": "cats"}])
2
3
4
5
6
7
8
# 4.LCEL 表达式
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("写一首诗关于 {topic}")
output_parser = StrOutputParser()
chain = prompt | model | output_parser
chain.invoke({"topic": "冰淇淋"})
2
3
4
5
6
7
8
9
# 5.逗号分割
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chain = LLMChain(
llm=model,
prompt=chat_prompt,
output_parser=CommaSeparatedListOutputParser()
)
# chain.run("colors")
chain.run("fruits")
# >> ['red', 'blue', 'green', 'yellow', 'orange']
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 五.问答对生成
# 1.生成字符串问答对
# 成功的问答对 但是是str输出的
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
prompt = ChatPromptTemplate.from_template("请根据如下内容 {text} \n 生成问答对")
chain = prompt | model | output_parser
model_output = chain.invoke({"text": "2.1.1 高层建筑 high-rise building \n 建筑高度大于27m 的住宅建筑和建筑高度大于24m 的非 单层厂房、仓库和其他民用建筑。\n 注:建筑高度的计算应符合本规范附录 A 的规定"})
print(model_output)
2
3
4
5
6
7
8
9
10
# 2.生成 json 问答对
# 成功的问答对 json输出
import json
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
prompt = ChatPromptTemplate.from_template("小王喜欢打篮球")
chain = prompt | model | output_parser
model_output = chain.invoke({"text": "小王今年30岁"})
print(model_output)
json_data = json.loads(model_output)
print(json_data)
# 打印 data 的数据
print(json_data['data'])
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.批量问题
# 成功的问答对 json输出
import json
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
output_parser = JsonOutputParser()
prompt = ChatPromptTemplate.from_template("请根据如下内容 {text} \n 生成问答对,并以json的格式输出,一个数据里面包含多个key-value的对象")
chain = prompt | model | output_parser
model_output = chain.batch([
{"text": "2.1.1 高层建筑 high-rise building \n 建筑高度大于27m 的住宅建筑和建筑高度大于24m 的非 单层厂房、仓库和其他民用建筑。\n 注:建筑高度的计算应符合本规范附录 A 的规定"},
{"text": "2.1.5 高架仓库 high rack storage \n 货架高度大于 7m 且采用机械化操作或自动化控制的货架仓库。"}
])
print(model_output)
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4.参考例子
# 成功的问答对 json输出
import json
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
output_parser = JsonOutputParser()
prompt = ChatPromptTemplate.from_template("请根据如下内容 {text} \n 生成问答对. \n\n 参考例子如下\n {example} \n 请根据例子生成json格式的问答对,参考例子中的问答对不要出现在结果中,结果里面包含多个key-value的对象")
chain = prompt | model | output_parser
slice_str = ['2.1.1 高层建筑 high-rise building \n 建筑高度大于27m 的住宅建筑和建筑高度大于24m 的非 单层厂房、仓库和其他民用建筑。\n 注:建筑高度的计算应符合本规范附录 A 的规定。'
, '2.1.1 明确了高层建筑的含义,确定了高层民用建筑和高层 工业建筑的划分标准。建筑的高度、体积和占地面积等直接影 响到建筑内的人员疏散、灭火救援的难易程度和火灾的后果。 本规范在确定高层及单、多层建筑的高度划分标准时,既考虑 到上述因素和实际工程情况,也与现行国家标准保持一致。本规范以建筑高度为27m 作为划分单、多层住宅建筑与 高层住宅建筑的标准,便于对不同建筑高度的住宅建筑区别对 待,有利于处理好消防安全和消防投入的关系。对于除住宅外的其他民用建筑(包括宿舍、公寓、公共建 筑)以及厂房、仓库等工业建筑,高层与单、多层建筑的划分标 准是24m。但对于有些单层建筑,如体育馆、高大的单层厂房 等,由于具有相对方便的疏散和扑救条件,虽建筑高度大于 24m, 仍不划分为高层建筑。有关建筑高度的确定方法,本规范附录 A 作了详细规定, 涉及本规范有关建筑高度的计算,应按照该附录的规定进行。'
]
example="""
2.1.11 防火隔墙 fire partition wall 建筑内防止火灾蔓延至相邻区域且耐火极限不低于规定要求的不燃性墙体。
2.1.12 防火墙 fire wall 防止火灾蔓延至相邻建筑或相邻水平防火分区且耐火极限不低于 3.00h 的不燃性墙体。
{'question': '有一堵墙的耐火极限为4小时那么这堵墙是否可能是防火墙?是否可能是防火隔墙?', 'answer': '防火墙的耐火极限要求是不低于3.00小时,所以这堵墙是防火墙,可能是防火墙,因为未给出防火隔墙具体的耐火极限'}
"""
joined_string = ' '.join(slice_str)
model_output = chain.invoke({"text": joined_string,"example": example})
print(model_output)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 5.不参考例子
# 成功的问答对 json输出
import json
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
output_parser = JsonOutputParser()
prompt = ChatPromptTemplate.from_template("请根据如下内容生成问答对。 {text} \n 结果以json的格式输出,结果里面包含多个key-value的对象")
chain = prompt | model | output_parser
slice_str = ['2.1.1 高层建筑 high-rise building \n 建筑高度大于27m的住宅建筑和建筑高度大于24m的非单层厂房、仓库和其他民用建筑。\n 注:建筑高度的计算应符合本规范附录 A 的规定。'
, '2.1.1 明确了高层建筑的含义,确定了高层民用建筑和高层工业建筑的划分标准。建筑的高度、体积和占地面积等直接影响到建筑内的人员疏散、灭火救援的难易程度和火灾的后果。 本规范在确定高层及单、多层建筑的高度划分标准时,既考虑到上述因素和实际工程情况,也与现行国家标准保持一致。本规范以建筑高度为27m作为划分单、多层住宅建筑与高层住宅建筑的标准,便于对不同建筑高度的住宅建筑区别对待,有利于处理好消防安全和消防投入的关系。对于除住宅外的其他民用建筑(包括宿舍、公寓、公共建 筑)以及厂房、仓库等工业建筑,高层与单、多层建筑的划分标 准是24m。但对于有些单层建筑,如体育馆、高大的单层厂房等,由于具有相对方便的疏散和扑救条件,虽建筑高度大于24m, 仍不划分为高层建筑。有关建筑高度的确定方法,本规范附录 A 作了详细规定, 涉及本规范有关建筑高度的计算,应按照该附录的规定进行。'
]
joined_string = '\n'.join(slice_str)
print(joined_string)
model_output = chain.invoke({"text": joined_string})
print(model_output)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 语料
小王今年21岁
小王是大学生
2
3
# 6.markdown 如何展示
print(result)
# 7.复制到粘贴板
import pyperclip
text = "要复制到剪贴板的文本"
pyperclip.copy(text)
print("复制完成")
2
3
4
5
# 二.LCEL 表达式
# 1.非流式
import asyncio
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
async def main():
# 配置API密钥和模型
model = ChatOpenAI(
openai_api_key="sk-xxxx",
openai_api_base="https://api.chatanywhere.tech/v1",
model_name="gpt-3.5-turbo-0613",
temperature=0.0,
request_timeout=20,
max_retries=5,
)
# 创建prompt和parser
prompt = ChatPromptTemplate.from_template(
"你是一个语言情感助手,请直接告诉我{topic}这句话是消极还是积极?只允许回答两个字")
parser = StrOutputParser()
chain = prompt | model | parser
res = chain.invoke({"topic": "鹦鹉说话真好听"})
print(res)
# 运行异步主函数
asyncio.run(main())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 2.流式
import asyncio
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
async def main():
# 配置API密钥和模型
model = ChatOpenAI(
openai_api_key="sk-xxxx",
openai_api_base="https://api.chatanywhere.tech/v1",
model_name="gpt-3.5-turbo-0613",
temperature=0.0,
request_timeout=20,
max_retries=5,
)
# 创建prompt和parser
prompt = ChatPromptTemplate.from_template(
"你是一个语言情感助手,请直接告诉我{topic}这句话是消极还是积极?只允许回答两个字")
parser = StrOutputParser()
chain = prompt | model | parser
# 使用async for迭代输出
async for chunk in chain.astream({"topic": "鹦鹉"}):
print(chunk, flush=True)
print(chunk, end="|", flush=True)
# 运行异步主函数
asyncio.run(main())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32