LangChain核心组件-工具(Tools)
为什么需要 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装饰器定义工具:
# 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,绑定工具:
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()
执行结果如下:
================================ 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装饰器。
例如,我们定义一个计算平方根的数学工具:
# 定义工具
from langchain.tools import tool
@tool
def square_root(x: float) -> float:
"""计算指定数字的平方根"""
return x ** 0.5
智能体在工作时,需要将函数的名称、输入、作用传递给大模型,默认情况下这些信息的来源是:
- 工具名称:函数名
- 工具输入:函数入参
- 工具作用:函数的注释
当然,我们可以通过tool装饰器来覆盖上述信息:
- 通过装饰器定义工具名称
@tool("square_root")
def tool1(x: float) -> float:
"""Calculate the square root of a number"""
return x ** 0.5
- 通过装饰器定义工具作用描述
@tool("square_root", description="Calculate the square root of a number")
def tool1(x: float) -> float:
return x ** 0.5
- 通过装饰器定义工具入参约束
如果要覆盖工具的入参信息则会复杂很多,我们要借助于Pydantic或JSON约束。
例如,我们需要定义个查询天气的tool,借助于Pydantic来约束入参。
我们定义一个入参的模型,在模型中添加入参描述信息:
# 例如一个查询天气的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"
)
定义工具,使用定义的模型来约束入参:
# 定义一个查询天气的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
工具定义好之后,调用方式与普通函数类似:
# 调用数学工具
tool1.invoke({"x": 467})
# 调用查询天气工具
get_weather.invoke({"location": "杭州", "include_forecast": True})
注意: 在LangChain中,作为工具的函数有两个保留的参数名,你的自定义参数不能与之重复!他们是:
- config:用来传递运行时配置
- runtime:用来传递运行时上下文
当我们创建智能体时,可以把定义好的工具传递给智能体,将来模型就能得到工具信息,并根据情况判断是否需要调用工具,需要调用哪个工具了。
from langchain.agents import create_agent
# 创建智能体,并添加工具
agent = create_agent(
model="deepseek-chat",
tools=[tool1, get_weather],
system_prompt="你是一个智能助手,你使用工具来解决用户问题。"
)
接下来,调用智能体,向其提问,模型会自动根据用户问题判断:
- 是否需要调用工具?
- 该调用哪个工具?
- 该传递那些参数?
并且在调用工具之后,根据工具执行结果给用户生成响应。
# 调用智能体
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模式,可以看到工具调用的具体步骤:
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()
输出如下:
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'}]
工作流程如图:
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)