langchain 的 agent + tool 使用

目录

工具自定义

接受单个输入

接受多个输入

agent 调用工具

直接调用

initialize_agent 调用

ReAct 调用单个输入的工具

structured_chat 调用多输入工具

链式调用参考

关于只调用了第一个工具解决

initialize_agent  异步顺序调用

ReAct

Plan-and-Execute


工具自定义

langchain 中提供了内置工具的,但是基本不能用,除了一个计算器和一个执行 python 代码的,其他的都要 api

Tool 模块相当于是使用外部工具,或者自定义工具

官方文档:Defining Custom Tools | 🦜️🔗 LangChain

接受单个输入

这种定义方式,只能接受一个参数,且不能封装成类,要不然会报少参数

定义一个搜索的工具

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool

class SearchInput(BaseModel):
    query: str = Field(description="search query")

@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "我是一个搜索的工具"

接受多个输入

这种既可以接受多个,也可以接受单个 

定义一个计算 a * b 的计算器

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool

class CalculatorInput(BaseModel):
    s: str = Field(description="输入字符串")

def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

calculator = StructuredTool.from_function(
    func=multiply,  # 工具具体逻辑
    name="Calculator",  # 工具名
    description="multiply numbers",  # 工具信息
    args_schema=CalculatorInput,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)

定义一个排序列表的工具

class SortList(BaseModel):
    num: str = Field(description="待排序列表")

def dort_fun(num):
    """Multiply two numbers."""
    return sorted(eval(num))

sorter = StructuredTool.from_function(
    func=dort_fun,  # 工具具体逻辑
    name="sort_num",  # 工具名
    description="排序列表中的数字",  # 工具信息
    args_schema=SortList,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)

不管是单个输入,还是多个输入,传进去的参数一定是 str 类型,如果要使用其他类型需要转换

agent 调用工具

直接调用

定义工具,直接调用

from langchain_core.tools import tool

@tool
def multiply(first: int, second: int) -> int:
    """实现两个整数的乘法运算。"""
    return first * second

result = multiply.invoke({"first": 4, "second": 5})
print(result)  # 输出结果:20

initialize_agent 调用

这是中文文档给的代码:入门指南 | LangChain中文网:500页中文文档教程,助力大模型LLM应用开发从入门到精通

这种调用方式,自定义工具只能接受单个输入

看到一种说法,initialize_agent 废弃了滑动验证页面

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.agents import load_tools
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('../key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)


"""这种定义方式,只能接受一个参数,且不能封装成类,要不然会报少参数"""
class SearchInput(BaseModel):
    query: str = Field(description="search query")

@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "我是一个搜索的工具"

# print(search.name)
# print(search.description)
# print(search.args)
# print(search.return_direct)


"""这种定义方式,可以接受多个参数"""
class CalculatorInput(BaseModel):
    a: str = Field(description="第一个数字")
    b: str = Field(description="第二个数字")


class SortList(BaseModel):
    num: str = Field(description="待排序列表")

def dort_fun(num):
    """Multiply two numbers."""
    return sorted(eval(num))

sorter = StructuredTool.from_function(
    func=dort_fun,  # 工具具体逻辑
    name="sort_num",  # 工具名
    description="排序列表中的数字",  # 工具信息
    args_schema=SortList,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


"""
zero-shot-react-description
此代理使用ReAct框架,仅基于工具的描述来确定要使用的工具。
可以提供任意数量的工具。
此代理需要为每个工具提供描述
工具只能接受一个参数,不支持多个参数
"""
tools = load_tools(["llm-math"], llm=model)
tools = [search, sorter] + tools
agent = initialize_agent(tools, model, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("计算 2 ** 3 + 4,`[10,4,7]`排一下序,并且")

可以看到能识别要调用两个工具,但只调用了一个,换了换位置,工具没问题

在 github 上看到说是 agent 有点问题

ReAct 调用单个输入的工具

这是官网找到的,ReAct | 🦜️🔗 LangChain

定义一个搜索工具,与计算字符串长度的工具

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool

class CalculatorInput(BaseModel):
    s: str = Field(description="输入字符串")
def multiply(s: str) -> int:
    """Multiply two numbers."""
    return len(s)
calculator = StructuredTool.from_function(
    func=multiply,  # 工具具体逻辑
    name="Calculator",  # 工具名
    description="计算字符长度",  # 工具信息
    args_schema=CalculatorInput,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")
@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "你好啊"


tools = [search, calculator]
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({"input": "langchian是什么东西?`阿萨德防守打法`有多少个字符?"})


 可以看到能识别要两个工具,但是值调用第一个问题就没了,,,

structured_chat 调用多输入工具

Structured chat | 🦜️🔗 LangChain

定义一个搜索工具,一个接受两个字符串,返回它们长度的乘积工具

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('../key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool
from langchain.agents import AgentExecutor, create_structured_chat_agent

class CalculatorInput(BaseModel):
    a: str = Field(description="第一个字符串")
    b: str = Field(description="第二个字符串")
def multiply(a: str, b: str) -> int:
    """Multiply two numbers."""
    return len(a) * len(b)
calculator = StructuredTool.from_function(
    func=multiply,  # 工具具体逻辑
    name="Calculator",  # 工具名
    description="计算字符长度的乘积",  # 工具信息
    args_schema=CalculatorInput,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")
@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "你好啊"


tools = [search, calculator]
prompt = hub.pull("hwchase17/structured-chat-agent")
agent = create_structured_chat_agent(model, tools, prompt)
agent_executor = AgentExecutor(
    agent=agent, tools=tools, verbose=True, handle_parsing_errors=True
)
agent_executor.invoke({"input": "`asd`的字符串长度乘以`as`的字符串长度是多少?langchiani是什么?"})

还是一样弄了个识别要调用两个工具,但是值针对第一个问题响应

链式调用参考

LangChain 中如何使用不支持 Function Calling 的模型实现工具 - 知乎

关于只调用了第一个工具解决

前面看到都有一个问题就是都能识别要调用多个工具,但是,运行后只调用了第一个问题对应的工具,就不继续了,参考改了改,是要异步的才能继续调用:https://juejin.cn/post/7329719726892482595

initialize_agent  异步顺序调用

initialize_agent 这个应该用的 ReAct 框架,看输出结构是的

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.agents import load_tools
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('../key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)

import asyncio
import nest_asyncio
nest_asyncio.apply()

"""这种定义方式,只能接受一个参数,且不能封装成类,要不然会报少参数"""
class SearchInput(BaseModel):
    query: str = Field(description="search query")

@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "我是一个搜索的工具"

# print(search.name)
# print(search.description)
# print(search.args)
# print(search.return_direct)


"""这种定义方式,可以接受多个参数"""
class CalculatorInput(BaseModel):
    a: str = Field(description="第一个数字")
    b: str = Field(description="第二个数字")


class SortList(BaseModel):
    num: str = Field(description="待排序列表")

def dort_fun(num):
    """Multiply two numbers."""
    return sorted(eval(num))

sorter = StructuredTool.from_function(
    func=dort_fun,  # 工具具体逻辑
    name="sort_num",  # 工具名
    description="排序列表中的数字",  # 工具信息
    args_schema=SortList,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


tools = load_tools(["llm-math"], llm=model)
tools = [search, sorter] + tools
agent = initialize_agent(tools, model, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# agent.run("计算 2 ** 3 + 4,`[10,4,7]`排一下序,")


async def run():
    response = await agent.arun(input="算 2 ** 3 + 4,`[10,4,7]`排一下序,")
    print(response)


if __name__ == '__main__':
    asyncio.run(run())

看了官网,没找到说 initialize_agent  可以把中间步骤单独保存;这里是只打印最后一次工具调用的结果,可以理解为按照需要调用的工具顺序,最终调用玩最后一个后,把最终结果进行输出的。

如果想看到每一步工具的输出,或者将中间输出拿出来再使用,参考

https://github.com/langchain-ai/langchain/issues/6956

最后要使用 acall,return_intermediate_steps=True

tools = load_tools(["llm-math"], llm=model)
tools = [search, sorter] + tools
agent = initialize_agent(tools, model, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True,
                        return_intermediate_steps=True)
# agent.run("计算 2 ** 3 + 4,`[10,4,7]`排一下序,")


async def run():
    response = await agent.acall(inputs="算 2 ** 3 + 4,第一步的结果转为字符串长度是多少?")
    print(response)


if __name__ == '__main__':
    asyncio.run(run())

ReAct

观察-思考-行动

ReAct 指定 agent ,试过了改prompt,换异步,都不行,以下是试过代码,还是只能调用第一个问题的工具,就没了,应该是 langchian 内部实现哪里有问题

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool
from langchain.agents import AgentExecutor, create_structured_chat_agent

class CalculatorInput(BaseModel):
    s: str = Field(description="输入字符串")
def multiply(s: str) -> int:
    """Multiply two numbers."""
    return len(s)
calculator = StructuredTool.from_function(
    func=multiply,  # 工具具体逻辑
    name="Calculator",  # 工具名
    description="计算字符长度",  # 工具信息
    args_schema=CalculatorInput,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")
@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "你好啊"


tools = [search, calculator]

# https://smith.langchain.com/hub/hwchase17/react?organizationId=c4887cc4-1275-5361-82f2-b22aee75bad1
prompt = hub.pull("hwchase17/react")

# 修改提示词
from langchain.prompts import PromptTemplate
prompt_template = """
Answer the following questions as best you can. You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer

Thought: you should always think about what to do

Action: the action to take, should be one of [{tool_names}]

Action Input: the input to the action

Observation: the result of the action

... (this Thought/Action/Action Input/Observation can repeat N times)

Thought: I now know the final answer

Final Answer: the final answer to the original input question

Begin!

Question: {input}

Thought:{agent_scratchpad}
"""
prompt = PromptTemplate.from_template(prompt_template)

agent = create_react_agent(model, tools, prompt)

# 查看提示词
prompt_template = agent.get_prompts()[0]
# print(prompt_template.format(input="what's 4.1*7.9=?", agent_scratchpad=""))

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, return_intermediate_steps=True)
# agent_executor.invoke({"input": "langchian是什么东西?`阿萨德防守打法`有多少个字符?"})

import asyncio

async def run():
    response = await agent_executor.ainvoke({"input": "`阿萨德防守打法`有多少个字符?langchian是什么东西?"})
    print(response)


if __name__ == '__main__':
    asyncio.run(run())


Plan-and-Execute

也是一个 agent 框架,这个主要是分解任务,即先计划,再依次去执行,这种方法可以用

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
import os
from dotenv import load_dotenv
from langchain_community.llms import Tongyi
load_dotenv('key.env')  # 指定加载 env 文件
key = os.getenv('DASHSCOPE_API_KEY')  # 获得指定环境变量
DASHSCOPE_API_KEY = os.environ["DASHSCOPE_API_KEY"]  # 获得指定环境变量
model = Tongyi(temperature=1)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool
from langchain.agents import AgentExecutor, create_structured_chat_agent



class CalculatorInput(BaseModel):
    s: str = Field(description="输入字符串")
def multiply(s: str) -> int:
    """Multiply two numbers."""
    return len(s)
calculator = StructuredTool.from_function(
    func=multiply,  # 工具具体逻辑
    name="Calculator",  # 工具名
    description="计算字符长度",  # 工具信息
    args_schema=CalculatorInput,  # 工具接受参数信息
    return_direct=True,  # 直接作为工具的输出返回给调用者
    handle_tool_error=True,  # 报错了继续执行,不会吧那些报错行抛出,也可以自定义函数处理,handle_tool_error=函数名
)


class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")
@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "你好啊"


tools = [search, calculator]

# https://smith.langchain.com/hub/hwchase17/react?organizationId=c4887cc4-1275-5361-82f2-b22aee75bad1
prompt = hub.pull("hwchase17/react")

# 修改提示词
from langchain.prompts import PromptTemplate
prompt_template = """
Answer the following questions as best you can. You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer

Thought: you should always think about what to do

Action: the action to take, should be one of [{tool_names}]

Action Input: the input to the action

Observation: the result of the action

... (this Thought/Action/Action Input/Observation can repeat N times)

Thought: I now know the final answer

Final Answer: the final answer to the original input question

Begin!

Question: {input}

Thought:{agent_scratchpad}
"""
prompt = PromptTemplate.from_template(prompt_template)
agent = create_react_agent(model, tools, prompt)
# 查看提示词
prompt_template = agent.get_prompts()[0]

# 设置计划者和执行者
from langchain_experimental.plan_and_execute import PlanAndExecute, load_agent_executor, load_chat_planner
planner = load_chat_planner(model)
executor = load_agent_executor(model, tools, verbose=True)
# 初始化Plan-and-Execute Agent
agent = PlanAndExecute(planner=planner, executor=executor, verbose=True)
# 运行Agent解决问题
agent.run("`阿萨德防守打法`有多少个字符?langchian是什么东西?前面的问题都使用中文回答,并汇总一起给我答案")

虽然肯有时候还是有点问题,但弄了个调用多个自定义工具了。

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值