1.Tool:在构建Agent 时,您需要为其提供一个它可以使用的工具列表。

        除了实际调用的函数之外,工具还包括几个组件:

        ps:如果工具具有好的,名称/描述/args_schema,模型将会有更好的表现

        2.智能体调用的时候有4条消息:

        1.Human Message,用户输入的消息

        2.AI Message,调用工具的指令

        3.Tool Message,工具执行之后的结果

        4.AI Message,对第三步结果的总结,如果return_direct定义为True,此步骤就省略了,执行到第三步就结果。

        3.LangChain 支持从以下对象创建工具:

        1.函数;

        2.Langchain Runables;

        3.通过BaseTool的子类化-这是最灵活的方法,它提供了最大的控制程度,但代价是需要付出更多的努力和编写更多的代码。

        ps:还有MCP,这里暂时不讲

        3.1--函数的定义方式

        这个 @tool 装饰器是定义自定义工具的最简单方法。默认情况下,装饰器使用函数名称作为工具名称,但可以通过将字符串作为第一个参数传递来覆盖。此外,装饰器将使用函数的文档字符串作为工具的描述 - 因此必须提供文档字符串。请注意,@tool 支持解析注释、嵌套模式和其他特性,有几种常见的方法,此次列举几种常见的方法

          3.1.1--第一种
@tool()
def calculate1(a:float,b:float,opeartion:str) -> float:
    """工具函数:计算两个数字的运算结果"""
    print(f"调用calculate工具,第一个数字:{a},第二个数字:{b},运算类型:{opeartion}")
    result=0.0
    match opeartion:
        case "add":
            result=a+b
        case "subtract":
            result=a-b
        case "multiply":
            result=a*b
        case "divide":
            if b!=0:
                result=a/b
            else:
                raise ValueError("除数不能为0")
    return result

print(calculate1.name)
print(calculate1.description)
print(calculate1.args)
print(calculate1.args_schema.model_json_schema())
print(calculate1.return_direct)

        这种方式比较简单,但是缺乏对参数的描述,可能会造成模型的了解错误,不推荐使用,此模块单独运行的结果如下:

--calculate1
--工具函数:计算两个数字的运算结果
--{'a': {'title': 'A', 'type': 'number'}, 'b': {'title': 'B', 'type': 'number'}, 'opeartion': {'title': 'Opeartion', 'type': 'string'}}
--{'description': '工具函数:计算两个数字的运算结果', 'properties': {'a': {'title': 'A', 'type': 'number'}, 'b': {'title': 'B', 'type': 'number'}, 'opeartion': {'title': 'Opeartion', 'type': 'string'}}, 'required': ['a', 'b', 'opeartion'], 'title': 'calculate1', 'type': 'object'}
--False

      3.1.2--第二种
from langchain_core.tools import tool
from pydantic import BaseModel,Field


class CalculateArgs(BaseModel):
    a:float=Field(description='第一个需要输入的数字')
    b:float=Field(description='第二个需要输入的数字')
    operation:str=Field(description='运算类型,add,subtract,multiply,divide')

@tool('calculate',args_schema=CalculateArgs)
def calculate2(a:float,b:float,opeartion:str) -> float:
    """工具函数:计算两个数字的运算结果"""
    print(f"调用calculate工具,第一个数字:{a},第二个数字:{b},运算类型:{opeartion}")
    result=0.0
    match opeartion:
        case "add":
            result=a+b
        case "subtract":
            result=a-b
        case "multiply":
            result=a*b
        case "divide":
            if b!=0:
                result=a/b
            else:
                raise ValueError("除数不能为0")
    return result

print(calculate2.name)
print(calculate2.description)
print(calculate2.args)
print(calculate2.args_schema.model_json_schema())
print(calculate2.return_direct)

        上图是tool模块的代码,单独运行此模块的结果如下:

--calculate
--工具函数:计算两个数字的运算结果
--{'a': {'description': '第一个需要输入的数字', 'title': 'A', 'type': 'number'}, 'b': {'description': '第二个需要输入的数字', 'title': 'B', 'type': 'number'}, 'operation': {'description': '运算类型,add,subtract,multiply,divide', 'title': 'Operation', 'type': 'string'}}
--{'properties': {'a': {'description': '第一个需要输入的数字', 'title': 'A', 'type': 'number'}, 'b': {'description': '第二个需要输入的数字', 'title': 'B', 'type': 'number'}, 'operation': {'description': '运算类型,add,subtract,multiply,divide', 'title': 'Operation', 'type': 'string'}}, 'required': ['a', 'b', 'operation'], 'title': 'CalculateArgs', 'type': 'object'}
--False

       3.1.3--第三种
from typing import Annotated

from langchain_core.tools import tool
from pydantic import BaseModel,Field

@tool('calculate')
def calculate3(
    a:Annotated[float,'第一个需要输入的数字'],
    b:Annotated[float,'第二个需要输入的数字'],
    operation:Annotated[str,'运算类型,add,subtract,multiply,divide'],) -> float:
    """工具函数:计算两个数字的运算结果"""
    print(f"调用calculate工具,第一个数字:{a},第二个数字:{b},运算类型:{operation}")
    result=0.0
    match operation:
        case "add":
            result=a+b
        case "subtract":
            result=a-b
        case "multiply":
            result=a*b
        case "divide":
            if b!=0:
                result=a/b
            else:
                raise ValueError("除数不能为0")
    return result

print(calculate3.name)
print(calculate3.description)
print(calculate3.args)
print(calculate3.args_schema.model_json_schema())
print(calculate3.return_direct)

print(calculate3.invoke({'a': 2, 'b': 3, 'operation': 'multiply'}))

        上图是tool模块的代码,单独运行此模块的结果如下:

--calculate
--工具函数:计算两个数字的运算结果
--{'a': {'description': '第一个需要输入的数字', 'title': 'A', 'type': 'number'}, 'b': {'description': '第二个需要输入的数字', 'title': 'B', 'type': 'number'}, 'operation': {'description': '运算类型,add,subtract,multiply,divide', 'title': 'Operation', 'type': 'string'}}
--{'description': '工具函数:计算两个数字的运算结果', 'properties': {'a': {'description': '第一个需要输入的数字', 'title': 'A', 'type': 'number'}, 'b': {'description': '第二个需要输入的数字', 'title': 'B', 'type': 'number'}, 'operation': {'description': '运算类型,add,subtract,multiply,divide', 'title': 'Operation', 'type': 'string'}}, 'required': ['a', 'b', 'operation'], 'title': 'calculate', 'type': 'object'}
--False
--调用calculate工具,第一个数字:2.0,第二个数字:3.0,运算类型:multiply
6.0


from langgraph.prebuilt import create_react_agent
from agent.tools.tool_demo2 import calculate2
from my_llm import llm

graph = create_react_agent(
    llm,
    tools=[calculate2],
    prompt="你是一个智能助手"
)

        上图是graph.py的代码,启动langgraph的本地服务后,运行结果如下图,看右侧的运行结果

        

        3.2--从可运行对象(Runable创建工具)

        接受字符串或 dict 输入的 LangChain Runnables 可以使用 as_tool 方法转换为工具,该方法允许为参数指定名称、描述和其他模式信息。

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel,Field

from my_llm import llm

prompt=(#外层模板
    PromptTemplate.from_template("帮我生成一个简短的关于{topic}报幕词,")
    +",要求:1.内容搞笑点"
    +"2.输出的内容采用{language}"
)

chain=prompt|llm|StrOutputParser

class ToolArgs(BaseModel):
    topic: str = Field(default="", description='报幕词的主题')
    language: str = Field(default="中文", description='报幕词采用的语言')


runnable_tool=chain.as_tool(
    name='chain_tool',
    description='这是一个生成报幕词的工具',
    args_schema=ToolArgs,
)

print(runnable_tool.args_schema.model_json_schema())
print(runnable_tool.name)
print(runnable_tool.description)

        上图是tool模块的代码,单独运行此模块的结果如下:

--{'properties': {'topic': {'default': '', 'description': '报幕词的主题', 'title': 'Topic', 'type': 'string'}, 'language': {'default': '中文', 'description': '报幕词采用的语言', 'title': 'Language', 'type': 'string'}}, 'title': 'ToolArgs', 'type': 'object'}
--chain_tool
--这是一个生成报幕词的工具

from langgraph.prebuilt import create_react_agent
from agent.tools.tool_demo2 import calculate2
from my_llm import llm
from agent.tools.tool_demo6 import runnable_tool

graph = create_react_agent(
    llm,
    tools=[calculate2,runnable_tool],
    prompt="你是一个智能助手"
)

上图是graph.py的代码,启动langgraph的本地服务后,就可以运行

        3.3--从可运行对象(Runable创建工具)

        通过从 BaseTool 子类化来定义自定义工具

from typing import Any, Type

from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from zhipuai import ZhipuAI


zhipuai_client = ZhipuAI(api_key='xxxxx')

class SearchArgs(BaseModel):
    query: str = Field(description="需要进行网络搜索的信息。")


# 网络搜索的工具
class MySearchTool(BaseTool):
    # 工具名字
    name: str = "search_tool"

    description: str = '用于查询实时信息(如天气、新闻、资讯)的工具,当需要获取当前或最新信息时调用,参数为query(查询内容)'

    return_direct: bool = False

    args_schema: Type[BaseModel] = SearchArgs

    def _run(self, query) -> str:
        try:
            # print("执行我的Python中的工具,输入的参数为:", query)
            response = zhipuai_client.web_search.web_search(
                search_engine="search_pro",
                search_query=query
            )
            # print(response)
            if response.search_result:
                return "\n\n".join([d.content for d in response.search_result])
            return '没有搜索到任何内容!'
        except Exception as e:
            print(e)
            return '没有搜索到任何内容!'

search_tool = MySearchTool()
print(search_tool.name)
print(search_tool.description)
print(search_tool.args_schema.model_json_schema())
if __name__ == "__main__":
    # 单独测试工具
    result = search_tool.run({"query": "今天深圳的天气怎么样"})
    print("工具返回结果:", result)

        此模块单独运行的结果如下:

        graph.py中的代码如下:

from langchain_core.messages import AnyMessage
from langchain_core.runnables import RunnableConfig

#from langgraph.prebuilt import create_react_agent

from langgraph.prebuilt.chat_agent_executor import AgentState, create_react_agent
from agent.tools.tool_demo2 import calculate2
from agent.tools.tool_demo6 import runnable_tool
from agent.tools.tool_demo7 import MySearchTool, search_tool
from my_llm import llm

def prompt(state:AgentState,config:RunnableConfig) -> list[AnyMessage]:
    user_name=config['configurable'].get('user_name','zs')
    print(user_name)
    system_message=f"你是一个智能助手,当前的用户名字是:{'user_name'}"
    return [{'role':'system','content':system_message}] + state['messages']

graph = create_react_agent(
    llm,
    tools=[search_tool,calculate2,runnable_tool],
    prompt ="""你是一个助手,遵循以下规则:
    1. 当用户询问实时信息(如天气、新闻、当前数据),必须调用search_tool工具查询,不能直接回答;
    2. 工具返回结果后,整理成自然语言回复用户;
    3. 其他任务可直接处理。""",
)

        上图是graph.py的代码,启动langgraph的本地服务后,运行结果如下图

        

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐