前言
这两天学习了LangChain中load_tools 和 检索增强生成 的进一步介绍,我认为这两部分是非常实用的,也做了一点自己的思考,所以也想做一下总结。
工具Tool
在前面的课程中,讲到了各种各样的代理(Agent),多样的代理给予大模型多样的推理方式,大模型具有一定的思考能力,而功能丰富的工具给予了大模型进行推理的能力。用课程里面的话来说,工具就是代理的武器,代理通过工具与世界进行交互,控制并改造世界。
那什么是工具呢?在LangChain中,工具就是被封装好的,具有自己输入和输出的,能够实现一定功能的框架。工具可以实现一些细分领域的专业功能,如使用搜索引擎进行搜索,访问学术文献,查看图片,搜索视频,处理自然语言等,可谓功能非常丰富。除了LangChain中已经存在的工具,我们也可以自己定义工具来实现我们需要的功能。
先来看一下一个简单的使用工具的框架,如调用serpapi, llm-math计算玫瑰花的平均价格,并加价15%卖出。
serpapi这个工具就是可以让大模型进行联网搜索信息,llm-math则是让大模型进行数学计算。使用serpapi的前提是获得SERPAPI的API密钥,这需要去官网进行注册,可能会遇到一些问题。
注册的时候可以使用谷歌账号进行授权登录,但是还需要进行验证,如下图所示,需要进行邮箱验证和手机号验证。
下面看一下代码,在导入需要的工具库,代理库和大模型库之后,先初始化大模型,然后使用load_tools函数设置serpapi和 llm-math工具,并把大模型作为参数传入。再初始化Agent,传入工具、大语言模型和代理,最后输入问题跑起来。
# 设置SERPAPI的API密钥
import os
os.environ["SERPAPI_API_KEY"] = (
"你自己的SERPAPI_API_KEY"
)
# 加载所需的库
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain_openai import ChatOpenAI # ChatOpenAI模型
# 初始化大模型
llm = ChatOpenAI(model=os.environ["LLM_MODELEND"], temperature=0)
# 设置工具
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 初始化Agent
agent = initialize_agent(
tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
# 跑起来
agent.run(
"目前市场上玫瑰花的平均价格是多少?如果我在此基础上加价15%卖出,应该如何定价?"
)
在上面的代码中,大模型不会因为自己不知道玫瑰花的平均价格而胡言乱语,它会先在网上进行检索,综合网络的信息获得平均价格,再使用数学计算工具,计算加价15%后的价格。
课程中还介绍了其他一些工具,如arxiv论文检索工具,可以帮助你直接通过arxiv的论文编号让大模型访问论文,对论文做出总结等。在这里我就不一一介绍这些工具了,在我们有需求的时候可以参考官方文档,选择需要的工具。
自定义工具
我们已经知道了工具是LangChain封装好的函数,那么如果我们想实现的功能在工具包中不存在,那么就需要我们自己来定义工具。
比如我想用大模型的语义理解能力来调用一个个视觉的小模型,在这里这些小模型就可以当做是一个个工具,那么就需要使用工具框架来调用这些模型。
比如我想监控一个园区大门一上午进来多少人,提出问题:8点到12点进入园区大门的人数是多少?,然后让大模型来选择这个工具,大模型也可以从问题中获取时间和地点等参数,以供工具使用。
下面的代码就是一个例子:
我设置了两个小的模型,分别是用来检测吸烟和打架行为的,在这里我并没有做具体的实现,只是返回一个文本来表示被调用了。并且在吸烟检测中,我还指定了时间和地点,以便作为参数传入真正的吸烟检测模型中。这是让LangChain 的 Agent 可以自动选择合适的工具并传递参数。可以通过自定义 prompt 来指导 Agent 提取时间和地点。
并且如果同时要调用LangChain中封装的工具,仍然可以使用load_tools函数,如我代码中写的那样,调用了arxiv工具。
# 导入库
from langchain_openai import ChatOpenAI
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.tools import Tool
# 模型预测函数
def smoking_predict(input_text: str) -> str:
# 在这里调用模型进行预测,返回预测结果
# 例如,假设模型返回一个吸烟检测结果
# 定义提取 prompt
prompt = PromptTemplate(
input_variables=["input_text"],
template="从以下句子中提取时间和地点:\n问题: {input_text}\n返回格式: 时间: <时间>, 地点: <地点>"
)
//获得 时间 地点 参数
response = llm(prompt.format(input_text=input_text)).content.strip()
location = re.search(r"地点: (.+)", response).group(1)
time = re.search(r"时间: (.+)", response).group(1)
print(location, time)
result = "在"+location+time+"有十五个人吸烟"
return result
def fighting_predict(input_text: str) -> str:
# 在这里调用模型进行预测,返回预测结果
# 例如,假设模型返回一个打架检测结果
result = "在这个时间段有3个人打架"
return result
# 定义一个工具来调用吸烟检测模型
smoking_detection_tool = Tool.from_function(
func=smoking_predict,
name="SmokingDetectionTool",
description="Detects smoking behavior in the provided text based on location and time. Use this tool to check if smoking behavior is mentioned."
)
# 定义一个工具来调用打架检测模型
fighting_detection_tool = Tool.from_function(
func=fighting_predict,
name="fightingDetectionTool",
description="Detects fighting behavior in the provided text. Use this tool to check if fighting behavior is mentioned."
)
# 初始化模型和工具
llm = ChatOpenAI(
temperature=0.0,
model=os.environ.get("LLM_MODELEND"),
)
tools = [load_tools(["arxiv"])[0], smoking_detection_tool, fighting_detection_tool]
# 初始化链
agent_chain = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
)
# 运行链
agent_chain.run("十二点的非吸烟区有几个人吸烟")
运行上述代码,可以得到以下结果:
即使我问的问题带有一定的迷惑性质,比如十二点的非吸烟区有几个人打架,既包含吸烟 关键词,又包含 打架 关键词,大模型仍然可以准确识别用使用工具,结果如下:
总结
通过本次的学习,了解了集成工具的使用,也探索了一下自己定义工具的使用,为以后开发相关应用拓展了思维。