一、Tools 核心概述

1. 工具的核心价值

LangChain的Tools是为大语言模型(LLM) 打造的外部能力扩展接口,解决了LLM仅能生成文本、无法与外部系统交互的问题,让AI从“文本生成”走向“实际操作”。

  • 核心作用:让LLM能调用搜索引擎、计算器、数据库、文件操作、API等外部功能,完成纯文本生成做不到的任务。
  • 应用场景:实时信息搜索、数据计算、文件操作、SQL查询、天气查询、代码运行等。
    在这里插入图片描述

2. Tools 与LangChain其他组件的关系

Tools是LangChain中Agent(智能体) 的核心依赖,Agent负责决策何时/调用哪个工具,Tools负责执行具体操作,二者结合实现AI的“思考+行动”能力。
同时Tools可搭配Memory(记忆)、Chain(链)使用,形成完整的AI工程应用流程:
用户输入 → Agent决策 → 调用Tools → 工具执行 → 结果返回(给Agent/直接给用户)

3. Tools 三大核心特点

  1. 增强LLM功能:突破纯文本限制,实现实际操作;
  2. 支持智能决策:Agent可根据用户输入动态选择合适工具
  3. 模块化设计:每个工具只做一个功能,可自由组合(如搜索+计算+天气)。

4. LangChain 官方工具生态

LangChain内置了大量第三方集成工具,可直接调用,官网地址:https://docs.langchain.com/oss/python/langchain/tools#tools

常见官方工具:Bing Search(必应搜索)、Calculator(计算器)、CodeInterpreter(代码解释器)、MoveFileTool(文件移动)、SQLTool(数据库查询)等。

二、Tool 的核心要素(定义工具的关键)

Tools本质是封装特定功能的可调用模块,定义一个工具必须明确以下要素,要素的规范性直接影响LLM/Agent能否正确调用工具。

要素 类型 是否必选 核心作用
name str 工具的唯一标识,LLM通过名称识别工具,工具集中不能重名
description str 建议选 工具的功能描述,LLM/Agent靠这段文字判断是否调用该工具,描述越精准,调用越准确
args_schema Pydantic BaseModel 建议选 工具的入参规范,定义入参的类型、描述、约束,用于参数校验和给LLM提示入参信息
return_direct bool 可选 仅对Agent生效,True=工具执行结果直接返回给用户(中断Agent流程),False=结果返回给Agent(由Agent决定下一步)

注意点

  • description工具调用的核心,比如描述写“用于两个整数相加的计算工具”,LLM遇到“10+20等于多少”时会自动选择该工具;如果描述模糊,LLM可能无法识别。
  • args_schema 用于规范入参,比如限定入参为int类型,可避免传入字符串导致工具执行报错。

三、自定义工具的两种核心方式

文档中讲解了LangChain自定义工具的两种主流方式,其中@tool装饰器新手首选(最简单),StructuredTool.from_function进阶选择(可配置性更高)。

方式1:@tool 装饰器

基于Python装饰器快速定义工具,默认复用函数名作为工具名、函数文档字符串作为工具描述,可通过参数覆盖默认配置,支持自定义入参规范。

基础用法(直接装饰函数)
from langchain.tools import tool

# 装饰器直接修饰函数,函数文档字符串=工具描述,函数名=工具名
@tool
def add_number(a:int,b:int)->int:
    """两个整数相加的计算工具"""
    return a + b

# 调用工具:传入字典格式的入参
res = add_number.invoke({"a":10,"b":20})
print(res) # 输出30
进阶用法(覆盖默认配置+自定义入参描述)

通过装饰器参数修改工具名、描述、return_direct,结合Pydantic的BaseModel定义入参的详细描述:

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

# 定义入参规范:给每个参数加描述,LLM能识别
class AddNumberSchema(BaseModel):
    a :int = Field(description="需要相加的第一个整数")
    b :int = Field(description="需要相加的第二个整数")

# 覆盖默认配置:自定义工具名、描述、return_direct,指定入参规范
@tool(
    name_or_callable="add_two_integer", # 自定义工具名
    description="实现两个整数的加法运算,输入两个整数返回求和结果", # 自定义描述
    args_schema=AddNumberSchema, # 绑定入参规范
    return_direct=True # 结果直接返回给用户
)
def add_number(a:int,b:int)->int:
    """两个整数相加"""
    return a + b

# 调用
res = add_number.invoke({"a":20,"b":30})
print(res) # 输出50

方式2:StructuredTool.from_function(进阶,高可配置)

与@tool装饰器功能一致,但支持更精细的配置,适合需要自定义更多细节的场景,写法上更显式,便于团队协作和代码维护。

基础用法
from langchain_core.tools import StructuredTool

# 定义工具的核心执行函数
def search_function(query: str):
    """模拟搜索工具:根据关键词返回搜索结果"""
    return f"关键词【{query}】的搜索结果:LangChain工具使用教程"

# 用from_function创建工具
search_tool = StructuredTool.from_function(
    func=search_function, # 绑定核心执行函数
    name="SearchTool", # 工具名
    description="用于根据关键词检索实时信息、知识内容的搜索工具" # 工具描述
)

# 调用工具:可传字符串/字典
res = search_tool.invoke("LangChain Tools怎么用")
print(res)
进阶用法(自定义入参+return_direct)
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

# 定义入参规范
class SearchSchema(BaseModel):
    query: str = Field(description="需要检索信息的关键词,为字符串类型")

# 核心执行函数
def search_function(query: str):
    return f"关键词【{query}】的搜索结果:LangChain工具使用教程"

# 创建工具
search_tool = StructuredTool.from_function(
    func=search_function,
    name="SearchTool",
    description="用于根据关键词检索实时信息、知识内容的搜索工具",
    args_schema=SearchSchema, # 绑定入参规范
    return_direct=True # 结果直接返回用户
)

# 调用
res = search_tool.invoke({"query": "LangChain自定义工具"})
print(res)

两种方式的对比

方式 优点 缺点 适用场景
@tool 装饰器 代码简洁、开发速度快,一行装饰器搞定 配置项相对少,显式性弱 新手入门、简单工具开发、快速原型验证
StructuredTool.from_function 配置显式、可定制性高,便于维护 代码量稍多 企业级开发、复杂工具、团队协作、需要精细配置的场景

四、Tools 实际调用流程

工具的核心价值是被LLM/Agent调用,文档中以MoveFileTool(文件移动工具)为例,讲解了LLM根据用户输入判断是否调用工具、如何解析调用参数、如何实际执行工具的完整流程,这是落地Tools的关键,分为4个核心步骤

整体调用逻辑

定义LLM模型 → 加载/定义工具 → LLM分析用户输入并决策是否调用工具 → 解析工具调用参数 → 实际执行工具并返回结果

完整实操代码

步骤1:安装依赖
# 核心LangChain依赖
pip install langchain langchain-core langchain-community
# OpenAI依赖(如果用OpenAI模型)
pip install langchain-openai
# 环境变量管理
pip install python-dotenv
步骤2:完整调用代码(以MoveFileTool为例)
# 1. 导入所有依赖
from langchain_community.tools import MoveFileTool
from langchain_core.messages import HumanMessage
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_openai import ChatOpenAI
import os
import dotenv
import json

# 2. 配置环境变量(OpenAI API)
dotenv.load_dotenv() # 加载.env文件中的环境变量
os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY") # 你的OpenAI API Key
os.environ['OPENAI_BASE_URL'] = os.getenv("OPENAI_BASE_URL") # 可选,国内需配置代理

# 3. 定义LLM模型(温度0=结果更确定,适合工具决策)
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 4. 加载官方工具(也可替换为自定义工具)
tools = [MoveFileTool()] # 文件移动工具

# 5. 将LangChain工具转换为LLM可识别的函数格式(关键步骤)
functions = [convert_to_openai_function(t) for t in tools]

# 6. 定义用户输入
user_input = "将本目录下的abc.txt文件移动到C:\\Users\\你的用户名\\Desktop"
messages = [HumanMessage(content=user_input)]

# 7. LLM分析输入,决策是否调用工具
response = llm.invoke(input=messages, functions=functions)
print("LLM返回结果:", response)

# 8. 解析LLM结果,判断是否调用工具并执行
if "function_call" in response.additional_kwargs:
    # 8.1 解析工具名称和入参
    tool_name = response.additional_kwargs["function_call"]["name"]
    tool_args = json.loads(response.additional_kwargs["function_call"]["arguments"])
    print(f"LLM决定调用工具:{tool_name},入参:{tool_args}")
    
    # 8.2 实际执行工具
    if tool_name == "move_file":
        tool = MoveFileTool()
        result = tool.run(tool_args) # 执行工具
        print("工具执行结果:", result)
else:
    # LLM不调用工具,直接返回自然语言结果
    print("LLM直接回复:", response.content)

LLM调用工具的两种结果判断

LLM接收到用户输入后,会根据工具的description判断是否需要调用工具,返回两种结果,需通过代码解析:

  1. 决定调用工具response.additional_kwargs中包含function_call,里面有工具名入参content通常为空;
  2. 不调用工具response.additional_kwargs中无function_callcontent为LLM的自然语言回复(如用户问天气,却只加载了文件工具,LLM会直接说无法回答)。
Logo

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

更多推荐