LangChain简介
背景
由于ChatGPT的发行,大模型(Large Language Model, LLM)已经变得非常流行了。也许你可能没有足够的资金和计算资源从头开始训练大模型,但你仍然可以使用大模型来做一些比较酷的事情,比如:
- 个人助理:能基于你的数据与外部世界进行互动交流
- 对话机器人:适合你个人使用偏好的对话机器人
- 分析总结:对文档或代码进行分析和总结
通过各式各样的API和提示工程(Prompt Engineering),大模型正在改变我们创建基于AI开发的产品的方式。这正是为什么在LLM背景下,现在到处都在出现新的开发者工具,这就有了一个新的专业术语:LLMOps(类似的专业术语为DevOps)。
其中的一个新工具就是LangChain。
LangChain介绍
LangChain是一个基于语言模型的应用开发框架。它在提升应用方面的作用为:
- 数据感知:可以使用其它数据资源来连接一个语言模型
- 代理式的:允许一个语言模型与它的环境进行互动
LangChain的主要道具为:
- 分支(Components):对如何使用语言模型来进行工作的摘要,每个摘要都有一个执行操作的集合。分支是模块化的,容易使用的,不管你是否在使用LangChain框架的剩余部分。
- 现成的链(Chains):用于完成特定更高阶任务的分支的结构化组装
现成的链使得它容易上手。对于更复杂的应用和细致的使用案例,分支使得它容易去适应现有的链或创建新的链。
LangChain能做什么
LangChain 提供了六个主要模块的支持,这些模块按照逐渐增加的复杂性排列如下:
- 模型(models) : LangChain 支持的各种模型类型和模型集成。
- 提示(prompts) : 包括提示管理、提示优化和提示序列化。
- 内存(memory) : 内存是在链/代理调用之间保持状态的概念。LangChain 提供了一个标准的内存接口、一组内存实现及使用内存的链/代理示例。
- 索引(indexes) : 与您自己的文本数据结合使用时,语言模型往往更加强大——此模块涵盖了执行此操作的最佳实践。
- 链(chains) : 链不仅仅是单个 LLM 调用,还包括一系列调用(无论是调用 LLM 还是不同的使用工具)。LangChain 提供了一种标准的链接口、许多与其它工具的集成。LangChain 提供了用于常见应用程序的端到端的链调用。
- 代理(agents) : 代理涉及 LLM 做出行动决策、执行该行动、查看一个观察结果,并重复该过程直到完成。LangChain 提供了一个标准的代理接口,一系列可供选择的代理,以及端到端代理的示例。
LangChain快速入门
LangChain是一个由Harrison Chase开源的项目,Github访问网址为:https://github.com/hwchase17/langchain .
LangChain提供了对应的Python第三方模块,在安装前,需确保你的Python版本大于等于3.8.1,小于4.0,安装方式如下:
pip install langchain
本文使用的langchain的版本为0.0.201。在开始介绍LangChain的使用前,你还需要有相关大模型的API key,比如OpenAI key等。
模型支持
LangChain提供了一系列大模型的支持,但首先你需要这些大模型的API key。LangChain支持的大模型如下图:
- Proprietary models(私有模型):由拥有大型专业团队和大额AI预算的公司研发的闭源模型,它们通常会比开源模型更大,且表现更好,但API调用较为昂贵。私有模型的提供商有OpenAI, co:here, AI21 Labs, Anthropic等。
- Open-source LLMS(开源模型):比私有模型尺寸更小,能力较差,但它们比私有模型更节省花费。开源模型的代表有BLOOM, LLaMA, Flan-T5, GPT-J等。许多开源模型已由Hugging Face提供了良好的支持。
- Model Hub(模型仓库):模型储存的仓库,比如Hugging Face等。
下面为langchain加载不同模型的示例代码:
# Proprietary LLM from e.g. OpenAI
# pip install openai
from langchain.llms import OpenAI
llm = OpenAI(model_name="text-davinci-003")
# Alternatively, open-source LLM hosted on Hugging Face
# pip install huggingface_hub
from langchain import HuggingFaceHub
llm = HuggingFaceHub(repo_id="google/flan-t5-xl")
本文主要基于OpenAI进行演示,因此,如果你有OpenAI key,你将会有更好的使用langchain的体验。
Prompt管理
大模型的表现取决于Prompt(提示),一个好的Prompt可以使大模型的表现良好,反之,大模型的表现可能会不如人意。
langchain提供了PromptTemplates
, 帮助你更好地为不同的分支创建合理的Prompt。比如创建一个普通的Prompt(零样本问题Prompt模板),Python代码如下:
# -*- coding: utf-8 -*-
from langchain import PromptTemplate
template = "What is a good name for a company that makes {product}?"
prompt = PromptTemplate(
input_variables=["product"],
template=template,
)
print(prompt.format(product="colorful socks"))
输出结果如下:
What is a good name for a company that makes colorful socks?
同样地,langchain还提供了few-shot(少样本)文本的Prompt模板,Python示例代码如下:
# -*- coding: utf-8 -*-
from langchain import PromptTemplate, FewShotPromptTemplate
examples = [
{"word": "happy", "antonym": "sad"},
{"word": "tall", "antonym": "short"},
{"word": "fat", "antonym": "thin"},
]
example_template = """
-> Word: {word}
-> Antonym: {antonym}
"""
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_template,
)
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="\n->Word: {input}\n->Antonym:",
input_variables=["input"],
example_separator="\n",
)
print(few_shot_prompt.format(input="big"))
输出结果如下:
Give the antonym of every input
-> Word: happy
-> Antonym: sad
-> Word: tall
-> Antonym: short
-> Word: fat
-> Antonym: thin
->Word: big
->Antonym:
链(Chains)
langchain中的链描述了将大模型与其它分支组合起来创建一个应用的过程。比如,LLMChain允许我们对创建的Prompt使用大模型,Python示例代码(需安装openai模块,使用pip install openai
)如下:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain import PromptTemplate
# set api key
import os
os.environ["OPENAI_API_KEY"] = 'sk-xxx'
# install openai and choose model
llm = OpenAI(model_name='gpt-3.5-turbo')
# make prompt
template = "What is a good name for a company that makes {product}?"
prompt = PromptTemplate(
input_variables=["product"],
template=template,
)
# chain
chain = LLMChain(llm=llm, prompt=prompt)
# Run the chain only specifying the input variable.
print(chain.run("colorful socks"))
输出结果如下:
Rainbow Socks Co.
对少样本提示,Python示例代码如下:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain import PromptTemplate, FewShotPromptTemplate
# set api key
import os
os.environ["OPENAI_API_KEY"] = 'sk-xxx'
# install openai and choose model
llm = OpenAI(model_name='gpt-3.5-turbo')
# make few-shot prompt
examples = [
{"word": "happy", "antonym": "sad"},
{"word": "tall", "antonym": "short"},
{"word": "fat", "antonym": "thin"},
]
example_template = """
-> Word: {word}
-> Antonym: {antonym}
"""
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_template,
)
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="\n->Word: {input}\n->Antonym:",
input_variables=["input"],
example_separator="\n",
)
# chain
chain = LLMChain(llm=llm, prompt=few_shot_prompt)
# Run the chain only specifying the input variable.
print(chain.run("big"))
输出结果如下:
small
如果我们想要使用之前的LLM的输出作为当前LLM的输入,我们可以使用SimpleSequentialChain
,示例Python代码如下:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain import PromptTemplate
from langchain.chains import LLMChain, SimpleSequentialChain
# set api key
import os
os.environ["OPENAI_API_KEY"] = 'sk-xxx'
# install openai and choose model
llm = OpenAI(model_name='gpt-3.5-turbo')
# Define the first chain as in the previous code example
template = "What is a good name for a company that makes {product}?"
prompt = PromptTemplate(
input_variables=["product"],
template=template,
)
chain = LLMChain(llm=llm, prompt=prompt)
# Create a second chain with a prompt template and an LLM
second_prompt = PromptTemplate(
input_variables=["company_name"],
template="Write a catchphrase for the following company: {company_name}",
)
chain_two = LLMChain(llm=llm, prompt=second_prompt)
# Combine the first and the second chain
overall_chain = SimpleSequentialChain(chains=[chain, chain_two], verbose=True)
# Run the chain specifying only the input variable for the first chain.
catchphrase = overall_chain.run("colorful socks")
print(catchphrase)
输出结果如下:
> Entering new chain...
Rainbow Sox Co.
"Step up your sock game with Rainbow Sox Co."
> Finished chain.
"Step up your sock game with Rainbow Sox Co."
LangChain高阶使用
langchain还支持更多有趣的高阶使用(通过插件实现),比如文档问答,天气查询,数学计算,基于WikaPedia的问答等等,详细的应用介绍的访问网址为:https://python.langchain.com/docs/modules/agents/tools。本文将介绍文档问答,天气查询,数学计算这三个插件应用。
文档问答
众所周知,ChatGPT的知识库截至2021年9月,因此,ChatGPT无法回答这以后的问题,比如我们询问ChatGPT“2022年的诺贝尔文学奖获得者是谁?”,结果如下图:
langchain的文档阅读允许我们将大模型与外部文档结合起来,对文档内容进行回答。我们在网上寻找有关于2022年的诺贝尔文学奖获得者的信息,比如网址:https://www.theguardian.com/books/2022/oct/06/annie-ernaux-wins-the-2022-nobel-prize-in-literature , 保存为Annie Ernaux.txt,作为ChatGPT的外部输入文档。
langchain使用文档加载器将数据加载为Document. 一个Document是一系列文本片段和相关的元数据。加载文件后有三个主要步骤:
- 将文档分割成块
- 为每个文档创建嵌入向量
- 在向量库中存储文档和嵌入向量
默认情况下,LangChain 使用 Chroma 作为向量存储来索引和搜索嵌入。因此我们需要先安装chromadb,命令为:`pip install chromadb`.
基于此,我们可以对外部文档进行问答,Python示例代码:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain.document_loaders import TextLoader
from langchain.indexes import VectorstoreIndexCreator
# set api key
import os
os.environ["OPENAI_API_KEY"] = 'sk-xxx'
# install openai and choose model
llm = OpenAI(model_name='gpt-3.5-turbo')
# prompt with no answer
prompt = "Who is the winner of 2022 Noble Prize in literature?"
completion = llm(prompt)
print(completion)
# load other source data
loader = TextLoader('Annie Ernaux.txt')
index = VectorstoreIndexCreator().from_loaders([loader])
print('index the document.')
# prompt with answer
query = "Who is the winner of 2022 Noble Prize in literature?"
print(index.query_with_sources(query))
输出结果如下:
As an AI language model, I do not have the ability to predict future events or outcomes such as the winner of the 2022 Nobel Prize in Literature. Only the Nobel Committee can make such announcements.
index the document.
{'question': 'Who is the winner of 2022 Noble Prize in literature?', 'answer': ' Annie Ernaux is the winner of the 2022 Nobel Prize in Literature.\n', 'sources': 'Annie Ernaux.txt'}
可以看到,原始的ChatGPT对于问题“Who is the winner of 2022 Noble Prize in literature?”无法给出准确答案,而加入了外部数据后,再使用文档问答,可以准确地回答出该问题。
天气查询
ChatGPT无法查询实时信息,比如天气、股票信息等,以下为ChatGPT回答“上海今天天气如何?”的示例,如下图:
因此,我们需要用到代理(Agents)工具OpenWeatherMap API
来获取天气信息。OpenWeatherMap可以获取全世界各地的天气信息,但首先你需要在它的官网上注册并获取OPENWEATHERMAP_API_KEY
。以下为使用代理工具OpenWeatherMap API
来回答天气的Python示例代码:
# -*- coding: utf-8 -*-
from langchain.llms import OpenAI
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.utilities import OpenWeatherMapAPIWrapper
import os
os.environ["OPENWEATHERMAP_API_KEY"] = "xxx"
os.environ["OPENAI_API_KEY"] = "sk-xxx"
# direct get weather info
weather = OpenWeatherMapAPIWrapper()
weather_data = weather.run("shanghai")
print(weather_data)
# use LLM to do NLU
llm = OpenAI(temperature=0)
tools = load_tools(["openweathermap-api"], llm)
agent_chain = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# get weather info by natural language
print(agent_chain.run("今天上海天气如何?"))
输出结果如下:
In shanghai, the current weather is as follows:
Detailed status: light rain
Wind speed: 5 m/s, direction: 300°
Humidity: 77%
Temperature:
- Current: 28.6°C
- High: 29.92°C
- Low: 27.71°C
- Feels like: 33.09°C
Rain: {'1h': 0.69}
Heat index: None
Cloud cover: 75%
> Entering new chain...
我需要查询上海的天气信息。
Action: OpenWeatherMap
Action Input: Shanghai,CN
Observation: In Shanghai,CN, the current weather is as follows:
Detailed status: light rain
Wind speed: 5 m/s, direction: 300°
Humidity: 77%
Temperature:
- Current: 28.6°C
- High: 29.92°C
- Low: 27.71°C
- Feels like: 33.09°C
Rain: {'1h': 0.65}
Heat index: None
Cloud cover: 75%
Thought: 根据上海的天气信息,我可以得出结论。
Final Answer: 今天上海有轻度降雨,风速为5米/秒,湿度为77%,温度为28.6°C,最高温度为29.92°C,最低温度为27.71°C,体感温度为33.09°C,降雨量为0.65毫米,云量为75%。
> Finished chain.
今天上海有轻度降雨,风速为5米/秒,湿度为77%,温度为28.6°C,最高温度为29.92°C,最低温度为27.71°C,体感温度为33.09°C,降雨量为0.65毫米,云量为75%。
数学计算
langchain提供了代理工具Wolfram Alpha
来更好地进行数学计算,首先你需要在Wolfram Alpha官网上注册并获取WOLFRAM_ALPHA_APPID,然后安装wolframalpha模块,命令为:pip install wolframalpha
.示例Python代码如下:
# -*- coding: utf-8 -*-
import os
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
os.environ["WOLFRAM_ALPHA_APPID"] = "xxx"
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
wolfram = WolframAlphaAPIWrapper()
# 一元一次方程
print(wolfram.run("What is 2x+5 = -3x+7?"))
# 一元二次方程
print(wolfram.run("What is x^2-5x+4=0?"))
# 多项式展开
print(wolfram.run("Expand (x+y)^3?"))
输出结果如下:
Assumption: 2 x + 5 = -3 x + 7
Answer: x = 2/5
Assumption: x^2 - 5 x + 4 = 0
Answer: x = 1
Assumption: expand | (x + y)^3
Answer: x^3 + 3 x^2 y + 3 x y^2 + y^3
总结
本文主要介绍了LangChain,以及LangChain的模型支持、Prompt管理、链,并在此基础上介绍了三个有趣的工具使用。
后续笔者将会进一步介绍LangChain的使用,欢迎大家的关注~
参考文献
- Getting Started with LangChain: A Beginner’s Guide to Building LLM-Powered Applications: https://towardsdatascience.com/getting-started-with-langchain-a-beginners-guide-to-building-llm-powered-applications-95fc8898732c
- LangChain Document in Python: https://python.langchain.com/docs/get_started/introduction.html
- LangChain Agents: https://python.langchain.com/docs/modules/agents/