跳到主要内容

Tool 工具的定义

什么是 Tool

在构建 Agent 时,需要为 Agent 提供一个它可以使用的工具列表。除了实际调用的函数之外,工具还包括几个组件:

  • name:工具名称
  • description:工具描述,帮助模型理解工具的用途
  • args_schema:工具参数的模式定义

注意:如果工具具有精心选择的名称、描述和 args_schema,模型将表现得更好。

Tool 的三种创建方式

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

方式说明适用场景
@tool 装饰器最简单的定义方式快速原型开发
Runnable.as_tool将 LangChain Runnables 转换为工具已有链需要暴露为工具
BaseTool 子类化最大的控制灵活性复杂工具、需要细粒度控制

从函数创建工具

@tool 装饰器是定义自定义工具的最简单方法。默认情况下:

  • 函数名 → 工具名
  • 文档字符串 → 工具描述

基础用法

from langchain_core.tools import tool

@tool(return_direct=False)
def calculate(a: float, b: float, operation: str) -> float:
"""计算两个数字的运算结果"""
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
return result

Pydantic 定义参数

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

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 calculate(a: float, b: float, operation: str) -> float:
"""计算两个数字的运算结果"""
# ...

Annotated 定义参数

from typing import Annotated
from langchain_core.tools import tool

@tool
def calculate(
a: Annotated[float, '第一个需要输入的数字'],
b: Annotated[float, '第二个需要输入的数字'],
operation: Annotated[str, '运算类型']
) -> float:
"""计算两个数字的运算结果"""
# ...

Google 风格注释解析

@tool(parse_docstring=True)
def calculate(a: float, b: float, operation: str) -> float:
"""
计算两个数字的运算结果

Args:
a: 第一个需要输入的数字
b: 第二个需要输入的数字
operation: 运算类型

Returns:
返回运算结果
"""
# ...

从 Runnable 创建工具

接受字符串或 dict 输入的 LangChain Runnables 可以使用 as_tool 方法转换为工具:

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

llm = ChatOpenAI(model="gpt-4o-mini")

prompt = PromptTemplate.from_template("生成关于{topic}的{language}报幕词")
chain = prompt | llm

class ToolArgs(BaseModel):
topic: str = Field(description='报幕词主题')
language: str = Field(description='语言类型')

# 转换为工具
runnable_tool = chain.as_tool(
name='announcer_tool',
description='生成报幕词的工具',
args_schema=ToolArgs,
)

子类化 BaseTool

通过从 BaseTool 子类化来定义自定义工具,提供最大控制力:

from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from typing import Type, Any

class SearchArgs(BaseModel):
query: str = Field(description='搜索查询内容')

class MySearchTool(BaseTool):
"""网络搜索工具"""
name: str = 'search_tool'
description: str = '搜索互联网上公开的内容'
return_direct: bool = False
args_schema: Type[BaseModel] = SearchArgs

def _run(self, query: str) -> str:
# 同步执行逻辑
return self._search(query)

async def _arun(self, query: str) -> str:
# 异步执行逻辑
return await self._async_search(query)

search_tool = MySearchTool()

使用 StructuredTool

from langchain_core.tools import StructuredTool

def calculate(a: float, b: float, operation: str) -> float:
"""计算两个数字的运算结果"""
# ...

# 同步版本
tool1 = StructuredTool.from_function(calculate)

# 异步版本
async def calculate_async(a: float, b: float, operation: str) -> float:
# ...

tool2 = StructuredTool.from_function(
calculate,
name='calculator',
description='计算器工具',
coroutine=calculate_async # 异步版本
)

Tool 的核心属性

# 查看工具属性
print(tool.name) # 工具名称
print(tool.description) # 工具描述
print(tool.args) # 参数字典
print(tool.args_schema) # Pydantic 模型
print(tool.return_direct) # 是否直接返回结果给用户

return_direct 参数

行为
False(默认)工具返回后,Agent 继续思考,可调用其他工具
True工具返回后,直接将结果给用户,终止对话

适用场景

  • return_direct=True:最终答案工具(如 final_answer)、查询类工具
  • return_direct=False:需要多步推理的工具链
@tool(return_direct=True)
def final_answer(answer: str) -> str:
"""直接返回最终答案给用户"""
return answer

在 Agent 中使用 Tool

from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

# 创建 Agent,同时传入工具列表
graph = create_react_agent(
llm,
tools=[calculate, runnable_tool, search_tool]
)

速记要点

方式装饰器/方法适用场景
函数 → 工具@tool快速开发
Runnable → 工具.as_tool()链暴露为工具
BaseTool 子类继承 + _run / _arun精细控制

核心属性

  • name:工具名
  • description:描述(模型靠它理解用途)
  • args_schema:参数定义(推荐用 Pydantic)

记忆口诀

  • 简单工具@tool 一行搞定
  • 参数定义:Pydantic 最好
  • 复杂工具:继承 BaseTool

一句话总结

Tool = 函数 + 元数据(name/description/args_schema),元数据越好,模型调用越准。