AI大模型学习笔记:LangChain核心组件-工具(Tools)

文章目录

      • [为什么需要 Tool](#为什么需要 Tool)
      • [Tool 工作原理](#Tool 工作原理)
      • [Tool 常用属性](#Tool 常用属性)
      • 基本用法
      • 自定义工具

LangChain 的 ‌工具(Tools)‌ 是其核心组件之一,用于扩展大语言模型(LLM)的能力,使其能够与外部系统、API 或自定义函数交互,从而完成仅靠文本生成无法实现的任务,如查询天气、执行计算、搜索数据库等。

为什么需要 Tool

虽然大模型具备强大的语言理解和生成能力,但它本质上是静态的、不可交互的。比如:

  • 不具备访问数据库、调用 API 的能力

  • 不能执行代码或文件操作

  • 无法实时访问互联网或动态数据等

    通过 Tool(工具)机制,可以让模型具备"调用外部函数"的能力,使其能够与外部系统、API 或自定义函数交互,从而完成仅靠文本生成无法实现的任务。例如:

  • 实时访问外部世界(如天气、股票、网页等)

  • 调用计算函数(数学、单位换算)

  • 查询数据库或搜索文档

  • 实现"多轮决策"流程(如规划任务、搜索后总结)

一个完整的Agent至少要包含两个关键的部分:

  • 模型:是Agent的大脑,负责推理、分析,规划任务步骤
  • 工具:是Agent的手脚,负责执行任务,与外界交互

Tool 工作原理

工具的工作流程如下:

  • 定义工具:指定工具的名称、描述和执行逻辑(函数或类)。
  • 注册工具:将工具提供给代理或链,代理根据任务描述选择工具。
  • 调用工具:代理生成工具调用的指令(包括输入参数),工具执行并返回结果。
  • 处理结果:代理或链将工具输出整合到工作流中,生成最终响应。

工具的核心依赖:

  • 工具描述:帮助代理理解工具的功能和适用场景。
  • 输入解析:确保工具能正确处理代理提供的输入。
  • 输出格式:工具返回的结果应与代理或链的期望兼容。

Tool 常用属性

属性 类型 描述
name str 必选,在提供给LLM或Agent的工具集中必须是唯一的。
description str 可选但建议,描述工具的功能。LLM或Agent将使用此描述作为上下文,使用它确定工具的使用
args_schema Pydantic BaseModel 可选但建议,可用于提供更多信息(例如,few-shot示例)或验证预期参数。
return_direct boolean 仅对Agent相关。当为True时,在调用给定工具后,Agent将停止并将结果直接返回给用户。

基本用法

我们先通过一个案例快速回顾Agent定义的步骤,以及Agent的工作原理。

定义一个带有工具的Agent分为两步:

  • 定义工具
  • 定义Agent,绑定工具

首先,使用tool装饰器定义工具:

python 复制代码
# 1.使用tool装饰器定义工具
from langchain.tools import tool

@tool
def get_weather(location: str) -> str:
    """
    Get the weather in a given location.
    Args:
        location: city name or coordinates
    """
    return f"Current weather in {location} is sunny"

接着,定义Agent,绑定工具:

python 复制代码
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage

# 2.创建智能体,并绑定工具
agent = create_agent(
    model="deepseek-chat",
    tools=[get_weather]
)

# 3.调用Agent
response = agent.invoke(
    {"messages": [HumanMessage(content="杭州今天天气如何?")]},
)

for message in response['messages']:
    message.pretty_print()

执行结果如下:

python 复制代码
================================ Human Message =================================

杭州今天天气如何?
================================== Ai Message ==================================

我来帮您查询杭州今天的天气情况。
Tool Calls:
  get_weather (call_00_FETE4MIR9p1Gr6uszgjcko6m)
 Call ID: call_00_FETE4MIR9p1Gr6uszgjcko6m
  Args:
    location: 杭州
================================= Tool Message =================================
Name: get_weather

Current weather in 杭州 is sunny
================================== Ai Message ==================================

根据查询结果,杭州今天的天气是晴朗的。天气很好,适合外出活动!

流程图:

由此可见,所谓的工具,本质就是一个可调用的函数,要想让Agent知道有哪些工具可调用,该如何调用这些工具,就必须把这个函数的详细信息发送给模型。包括:

  • 函数名
  • 函数的作用
  • 函数的参数和返回值信息

所以,定义工具的时候,关键就是把这些信息描述清楚即可。

大模型会自动分析用户需求,判断是否需要调用指定工具。

如果模型认为需要调用工具(如 MoveFileTool ),返回的 message 会包含

  • content : 通常为空(因为模型选择调用工具,而非生成自然语言回复)。
  • additional_kwargs : 包含工具调用的详细信息:
    如果模型认为无需调用工具(例如用户输入与工具无关),返回的 message 会是普通文本回复

自定义工具

在LangChain中,定义工具的过程被大大简化,与定义普通函数几乎没什么差别,只是在一些细节上需要注意。

首先,定义工具需要在函数上添加@tool装饰器。

例如,我们定义一个计算平方根的数学工具:

python 复制代码
# 定义工具
from langchain.tools import tool

@tool
def square_root(x: float) -> float:
    """计算指定数字的平方根"""
    return x ** 0.5

智能体在工作时,需要将函数的名称、输入、作用传递给大模型,默认情况下这些信息的来源是:

  • 工具名称:函数名
  • 工具输入:函数入参
  • 工具作用:函数的注释

当然,我们可以通过tool装饰器来覆盖上述信息:

  • 通过装饰器定义工具名称
python 复制代码
@tool("square_root")
def tool1(x: float) -> float:
    """Calculate the square root of a number"""
    return x ** 0.5
  • 通过装饰器定义工具作用描述
python 复制代码
@tool("square_root", description="Calculate the square root of a number")
def tool1(x: float) -> float:
    return x ** 0.5
  • 通过装饰器定义工具入参约束
    如果要覆盖工具的入参信息则会复杂很多,我们要借助于Pydantic或JSON约束。

例如,我们需要定义个查询天气的tool,借助于Pydantic来约束入参。

我们定义一个入参的模型,在模型中添加入参描述信息:

python 复制代码
# 例如一个查询天气的tool
class WeatherInput(BaseModel):
    """查询天气的输入参数."""
    location: str = Field(description="City name or coordinates")
    units: Literal["celsius", "fahrenheit"] = Field(
        default="celsius",
        description="Temperature unit preference"
    )
    include_forecast: bool = Field(
        default=False,
        description="Include 5-day forecast"
    )

定义工具,使用定义的模型来约束入参:

python 复制代码
# 定义一个查询天气的tool
@tool(args_schema=WeatherInput)
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
    """Get current weather and optional forecast."""
    temp = 22 if units == "celsius" else 72
    result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
    if include_forecast:
        result += "\nNext 5 days: Sunny"
    return result

工具定义好之后,调用方式与普通函数类似:

python 复制代码
# 调用数学工具
tool1.invoke({"x": 467})

# 调用查询天气工具
get_weather.invoke({"location": "杭州", "include_forecast": True})

注意: 在LangChain中,作为工具的函数有两个保留的参数名,你的自定义参数不能与之重复!他们是:

  • config:用来传递运行时配置
  • runtime:用来传递运行时上下文

当我们创建智能体时,可以把定义好的工具传递给智能体,将来模型就能得到工具信息,并根据情况判断是否需要调用工具,需要调用哪个工具了。

python 复制代码
from langchain.agents import create_agent

# 创建智能体,并添加工具
agent = create_agent(
    model="deepseek-chat",
    tools=[tool1, get_weather],
    system_prompt="你是一个智能助手,你使用工具来解决用户问题。"
)

接下来,调用智能体,向其提问,模型会自动根据用户问题判断:

  • 是否需要调用工具?
  • 该调用哪个工具?
  • 该传递那些参数?
    并且在调用工具之后,根据工具执行结果给用户生成响应。
python 复制代码
# 调用智能体
for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="467的平方根是多少?")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)
    

for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="北京和杭州接下来几天天气如何?")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)

如果采用stream模式的updates模式,可以看到工具调用的具体步骤:

python 复制代码
for chunk in agent.stream(
    {"messages": [HumanMessage(content="467、529的平方根是多少?")]},
    stream_mode="updates"
):
    for step, data in chunk.items():
        print(f"step: {step}")
        print(f"content: {data['messages'][-1].content_blocks}")
        print()

输出如下:

python 复制代码
step: model
content: [{'type': 'text', 'text': '我来帮你计算这两个数的平方根。'}, {'type': 'tool_call', 'id': 'call_00_oWChR8Xgo21mmWKW0SP9uOS9', 'name': 'square_root', 'args': {'x': 467}}, {'type': 'tool_call', 'id': 'call_01_UqzhGeRNcoSoidItA0gScaoY', 'name': 'square_root', 'args': {'x': 529}}]

step: tools
content: [{'type': 'text', 'text': '21.61018278497431'}]

step: tools
content: [{'type': 'text', 'text': '23.0'}]

step: model
content: [{'type': 'text', 'text': '计算结果如下:\n\n- **467的平方根** ≈ 21.6102\n- **529的平方根** = 23.0(因为23 × 23 = 529,所以529是完全平方数)\n\n所以:\n- √467 ≈ 21.6102\n- √529 = 23'}]

工作流程如图:

相关推荐
秦歌6661 小时前
LangChain-9-中间件middleware
langchain
哥本哈士奇2 小时前
LangChain DeepAgents 学习笔记
笔记·学习·langchain
JavaEdge.2 小时前
06-LangChain Tool 加载与使用指南:预制工具、SerpAPI、edge-tts、GraphQL
chrome·langchain·graphql
Restart-AHTCM2 小时前
LangChain学习之环境搭建与基础概念 - 练习(1/8)
学习·langchain
糖果店的幽灵3 小时前
LangChain 基于 Python 的技术- agent模块使用总结
开发语言·python·langchain
花千树-0103 小时前
SubAgent 基础:拥有自主工具的子代理
java·langchain·llm·agent·langgraph·subagent·harness
qcx233 小时前
【AI Daily】每日AI日报
人工智能·llm·agent·daily
JavaEdge.4 小时前
07-LangChain Toolkit 实战:从工具函数到 Python Agent,再到 SQL Agent
python·sql·langchain
Artech4 小时前
[对比学习LangChain和MAF-01]基本编程模式的差异(上篇)
ai·langchain·agent·maf