LangChain中工具(Tool)的使用 | 豆包MarsCode AI刷题

270 阅读6分钟

前言

这两天学习了LangChain中load_tools检索增强生成 的进一步介绍,我认为这两部分是非常实用的,也做了一点自己的思考,所以也想做一下总结。

工具Tool

在前面的课程中,讲到了各种各样的代理(Agent),多样的代理给予大模型多样的推理方式,大模型具有一定的思考能力,而功能丰富的工具给予了大模型进行推理的能力。用课程里面的话来说,工具就是代理的武器,代理通过工具与世界进行交互,控制并改造世界。

那什么是工具呢?在LangChain中,工具就是被封装好的,具有自己输入和输出的,能够实现一定功能的框架。工具可以实现一些细分领域的专业功能,如使用搜索引擎进行搜索,访问学术文献,查看图片,搜索视频,处理自然语言等,可谓功能非常丰富。除了LangChain中已经存在的工具,我们也可以自己定义工具来实现我们需要的功能。

先来看一下一个简单的使用工具的框架,如调用serpapi, llm-math计算玫瑰花的平均价格,并加价15%卖出。

serpapi这个工具就是可以让大模型进行联网搜索信息,llm-math则是让大模型进行数学计算。使用serpapi的前提是获得SERPAPI的API密钥,这需要去官网进行注册,可能会遇到一些问题。

注册的时候可以使用谷歌账号进行授权登录,但是还需要进行验证,如下图所示,需要进行邮箱验证和手机号验证。

img_v3_02gk_69fbe338-6482-4360-a31c-e8550612e7bg.jpg

邮箱验证使用谷歌邮箱即可,这一步挺简单,把发送的验证码直接输入。进行手机号验证的时候,我遇到了一些麻烦,最开始我用的是移动的手机号,但是验证码怎么也发不过来,挂了梯子也不行,所以我换成了联通的手机号,就能收到验证码,成功注册。之后就能获得SERPAPI的API密钥了,它有一定额度的免费token。

下面看一下代码,在导入需要的工具库,代理库和大模型库之后,先初始化大模型,然后使用load_tools函数设置serpapillm-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("十二点的非吸烟区有几个人吸烟")

运行上述代码,可以得到以下结果:

image.png

即使我问的问题带有一定的迷惑性质,比如十二点的非吸烟区有几个人打架,既包含吸烟 关键词,又包含 打架 关键词,大模型仍然可以准确识别用使用工具,结果如下:

image.png

总结

通过本次的学习,了解了集成工具的使用,也探索了一下自己定义工具的使用,为以后开发相关应用拓展了思维。