2026-08-07
AI
0

目录

1. 工具的调用方式
2. 工具的定义方式
2.1 不使用@tool的方式
2.1.1 工具描述的各部分详解
2.1.2 了解:converttoopenai_tool
2.1.3 description说明
2.1.4 参数说明
2.2 使用@tool的方式
2.2.1 自定义工具描述:description
2.2.2 更改工具名称:nameorcallable
2.2.3 自定义args_schema
2.2.3.1 使用Pydantic模型定义
2.2.3.1.1 pydantic类型的定义
2.2.3.2 使用Json Schema定义

上一篇我们讲述了消息与提示词模版,本篇我们看一下如何使用工具。工具是赋予大语言模型 与外部世界交互能力 的关键组件,从而能让智能体执行搜索、计算、数据库查询、邮件发送或调用第三方API等,进而构建功能强大的AI应用。借助工具,大模型才能从“ 认识世界 ” 走向“ 改变世界 ”。

在LangChain中,工具(Tools)实际上是指明确定义了输入和输出的 可调用函数 。因此, 工具调用 (Tool Calling) 也被称为 函数调用(Function Calling) 。

1. 工具的调用方式

python
import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model load_dotenv() model = init_chat_model( model="qwen3.7-plus", model_provider="openai", # 关键:指定使用openai兼容协议 api_key=os.getenv("DASHSCOPE_API_KEY"), base_url=os.getenv("DASHSCOPE_API_BASE_URL") ) # 定义工具 @tool def get_weather(city: str) -> str: """获取指定城市的天气""" # 你的实现 return "晴天,温度 15°C" # 绑定工具 model_with_tools = model.bind_tools([get_weather]) # AI 可以决定是否调用工具 response = model_with_tools.invoke("北京天气如何?") # 检查 AI 是否要调用工具 if response.tool_calls: print("AI 想调用工具:", response.tool_calls) else: prAint("AI 直接回答:", response.content) # AI 想调用工具: [{'name': 'get_weather', 'args': {'city': '北京'}, 'id': 'call_2b913327adab4fcebffdaa13', 'type': 'tool_call'}]

大模型只能分析出是否调用工具,以及传递的参数,具体怎么调用还是得交给ai应用。让我们补充上工具调用的部分

python
from langchain.messages import HumanMessage @tool def get_weather(city: str): """获取天气的工具""" return f"{city}天气晴朗~" # 将模型和工具绑定 model_with_tools = model.bind_tools([get_weather]) messages = [ HumanMessage("今天北京天气如何") ] # 模型生成调用工具请求 response = model_with_tools.invoke(messages) # 添加AIMessage messages.append(response) tool_calls = response.tool_calls for tool_call in tool_calls: if tool_call["name"] == "get_weather": # 返回的是ToolMessage类型消息 tool_response = get_weather.invoke(tool_call) print(type(tool_response)) messages.append(tool_response) print("=====================> messages <=====================") for msg in messages: msg.pretty_print() print("=====================> messages <=====================") final_response = model_with_tools.invoke(messages) print(f"final_response: \n{final_response}")

输出如下:

plaintext
<class 'langchain_core.messages.tool.ToolMessage'> =====================> messages <===================== ================================ Human Message ================================= 今天北京天气如何 ================================== Ai Message ================================== Tool Calls: get_weather (call_24ae81aeea504a42a0dbd842) Call ID: call_24ae81aeea504a42a0dbd842 Args: city: 北京 ================================= Tool Message ================================= Name: get_weather 北京天气晴朗~ final_response: content='今天北京天气晴朗~ ☀️' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 52, 'prompt_tokens': 316, 'total_tokens': 368, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 39, 'rejected_prediction_tokens': None, 'text_tokens': 52}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0, 'text_tokens': 316}}, 'model_provider': 'openai', 'model_name': 'qwen3.7-plus', 'system_fingerprint': None, 'id': 'chatcmpl-64a3ce5b-0209-949e-8e64-57490fda1146', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019fd794-e4d0-7d62-953d-17fd215cc6cf-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 316, 'output_tokens': 52, 'total_tokens': 368, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 39}}

2. 工具的定义方式

2.1 不使用@tool的方式

python
def get_weather(city: str): """获取天气的工具""" return f"{city}天气晴朗~"

2.1.1 工具描述的各部分详解

def get_weather(city: str): """获取天气的工具""" return f"{city}天气晴朗~"

response = model_with_tools.invoke(messages)

response的类型是AiMessage,其中关于工具调用的部分如下:

tool_calls=[ { 'name': 'get_weather', 'args': {'city': '北京'}, 'id': 'call_ECvZNV7RLTWpKQSjhvdGzKBd', 'type': 'tool_call' } ]

2.1.2 了解:convert_to_openai_tool

执行 model.bind_tools([get_weather]) ,底层最终会调用 convert_to_openai_tool 生成工具描述。所以我们可以直接调用后者查看解析后的工具描述。

python
from langchain_core.utils.function_calling import convert_to_openai_tool from rich import print as rprint def get_weather(city: str): """查询天气的工具""" return f"{city}天气晴朗" rprint(convert_to_openai_tool(get_weather))

输出如下:

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '查询天气的工具', 'parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'} } }

结果字段说明:

  • (1) type:定义当前数据节点必须是什么数据类型。常见类型有 string, number, integer, boolean, object, array, null。object即是json对象。
  • (2) properties:用于定义JSON 对象(Object)中可以包含哪些属性(键),以及每个属性对应的 值类型和说明。
  • (3) required:当 type为 "object"时使用,是一个数组,列出了对象中必须存在的属性名。

2.1.3 description说明

convert_to_openai_tool 会从 docstring(文档字符串) 加载工具的描述信息

2.1.4 参数说明

convert_to_openai_tool 会从 docstring 加载参数说明,这里的 docstring 必须遵循 Google 风格 。

  • Google 风格 docstring 说明:https://google.github.io/styleguide/pyguide.html
  • Google 风格 docstring 示例:https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html
  • Python docstring 通用约定:https://peps.python.org/pep-0257/

使用 Args: 、 Returns: 、 Raises: 等关键字,这种方式可读性强。Agent通过工具的这些注释来理解工具的用途和调用时机,因此清晰、准确的文档字符串是工具能被正确调用的前提。

python
def get_weather(city: str) -> str: """ 天气查询工具 Args: city: 城市名称 Returns: 该地区的天气情况 """ return f"{city}天气晴朗" rprint(convert_to_openai_tool(get_weather))

参数类型来源于函数的类型注解,如果参数没有默认值,则会包含 在required对应的列表 中

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '天气查询工具', 'parameters': { 'properties': {'city': {'description': '城市名称', 'type': 'string'}}, 'required': ['city'], 'type': 'object' } } }

2.2 使用@tool的方式

使用 @tool 装饰器修饰,可以自动将普通 Python 函数转化为智能体可调用的工具。此方式 最直接 ,代码量极少,非常适合快速验证想法或创建参数简单的工具。

python
from langchain_core.tools import tool from langchain_core.utils.function_calling import convert_to_openai_tool from rich import print as rprint @tool def get_weather(city: str): """获取天气的工具""" return f"{city}天气晴朗" rprint(convert_to_openai_tool(get_weather))

2.2.1 自定义工具描述:description

@tool 会从 docstring 生成描述信息,同样要求遵循 Google docstring 规范 。如果没有 docstring则报错

@tool 的参数 description 可以更改工具描述,优先级高于 docstring 的函数说明.

python
from langchain.tools import tool @tool(description="根据城市名称查询当日天气的工具") def get_weather(city: str): """ 天气查询工具 """ return f"{city}天气晴朗" rprint(convert_to_openai_tool(get_weather))

输出如下:

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '根据城市名称查询当日天气的工具', 'parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'} } }

当我们没有向 @tool 传递 description 参数时,默认情况下, tool 会将 docstring 整体视为description

python
@tool def get_weather(city: str, units: str = "celsius", include_forecast: bool = False) -> str: """ 获取当日天气,可选择是否同时查询未来五日天气预报 Args: city: 城市 units: 气温单位,可选:celsius-摄氏度,fahrenheit-华氏度 include_forecast: 是否包含未来五日的天气预报 """ temp = 22 if units == "celsius" else 72 result = f'{city}当天气温: {temp} {"摄氏度" if units == "celsius" else "华氏度"}' if include_forecast: result += "\n未来五天都是晴天" return result rprint(convert_to_openai_tool(get_weather))

输出如下:

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '获取当日天气,可选择是否同时查询未来五日天气预报\n\nArgs:\n city: 城市\n units: 气温单位,可选:celsius-摄氏度,fahrenheit-华氏度\n include_forecast: 是否包含未来五日的天气预报', 'parameters': { 'properties': { 'city': {'type': 'string'}, 'units': {'default': 'celsius', 'type': 'string'}, 'include_forecast': {'default': False, 'type': 'boolean'} }, 'required': ['city'], 'type': 'object' } } }

我们发现解析的description是错误的, 解决办法:通过将 parse_docstring 设置为True,docstring会被解析,填充到相应的字段描述中。@tool(parse_docstring=True)

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '获取当日天气,可选择是否同时查询未来五日天气预报', 'parameters': { 'properties': { 'city': {'description': '城市', 'type': 'string'}, 'units': { 'default': 'celsius', 'description': '气温单位,可选:celsius-摄氏度,fahrenheit-华氏度', 'type': 'string' }, 'include_forecast': { 'default': False, 'description': '是否包含未来五日的天气预报', 'type': 'boolean' } }, 'required': ['city'], 'type': 'object' } } }

要注意:使用了@tool(parse_docstring=True) 如果docstring不符合规范,回抛出错误。

2.2.2 更改工具名称:name_or_callable

默认情况,使用函数名作为工具名称,但可以向@tool 传参 name_or_callable ,以更改工具名称。

python
from langchain.tools import tool # @tool("getWeather") 也可以省略name_or_callable参数名称 @tool(name_or_callable="getWeather") def get_weather(city: str): """ 天气查询工具 """ return f"{city}天气晴朗" print(convert_to_openai_tool(get_weather))

2.2.3 自定义args_schema

2.2.3.1 使用Pydantic模型定义

当工具的参数变得复杂,需要 枚举值 、 范围限制 或 更复杂的业务逻辑验证 时,Pydantic 模型是理想的选择,提供强大的类型检查和数据验证。 使用Pydantic 的主要优势在于能够精确控制工具参数的格式和验证规则,让大模型更准确地理解如何调用工具。

利用 Pydantic 的类型系统进行参数验证,当大模型需要调用工具前,Pydantic 会自动验证参数的类型和有效性。

2.2.3.1.1 pydantic类型的定义

① BaseModel基类

通过继承核心基类 BaseModel 定义数据模型,从而声明字段结构、类型约束、默认值以0及校验规则。

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/8/7 08:49 @Author: sql668 @File : pydamic-1.py """ from typing import Literal from langchain_core.tools import tool from langchain_core.utils.function_calling import convert_to_openai_tool from pydantic import BaseModel, Field from rich import print as rprint class WeatherInput(BaseModel): city: str = Field( default="北京", description="城市" ) unit: Literal["celsius", "fahrenheit"] = Field( default="celsius", description="气温单位" ) include_forecast: bool = Field( default=False, description="是否包含未来五日天气预报" ) @tool(args_schema=WeatherInput) def get_weather(city: str, units: str = "celsius", include_forecast: bool = False) -> str: """ 获取当日天气,可选择是否同时查询未来五日天气预报 """ temp = 22 if units == "celsius" else 72 result = f'{city}当天气温: {temp} {"摄氏度" if units == "celsius" else "华氏度"}' if include_forecast: result += "\n未来五天都是晴天" return result rprint(convert_to_openai_tool(get_weather))

输出如下:

json
{ 'type': 'function', 'function': { 'name': 'get_weather', 'description': '获取当日天气,可选择是否同时查询未来五日天气预报', 'parameters': { 'properties': { 'city': { 'default': '北京', 'description': '城市', 'type': 'string' }, 'unit': { 'default': 'celsius', 'description': '气温单位', 'enum': ['celsius', 'fahrenheit'], 'type': 'string' }, 'include_forecast': { 'default': False, 'description': '是否包含未来五日天气预报', 'type': 'boolean' } }, 'type': 'object' } } }

Field() :用来“ 定制字段 ”的函数,可用于设置默认值、描述等。 每个字段的 description 参数至关重要,它直接影响大模型理解参数含义的能力。

Literal :表示字段不能是任意某种类型的值,而只能是几个固定字面量之一。

2.2.3.2 使用Json Schema定义

在 LangChain 中,还可以直接使用 JSON Schema 字典 来定义工具的参数模式。这种方式提供了极大的灵活性。 因为工具参数模式可以基于数据库配置或用户输入在 运行时动态生成 ,所以这种方式特别适合参数结 构需要动态生成的场景。

python
json_schema = { 'properties': { 'city': {'default': '北京', 'description': '城市', 'type': 'string'}, 'unit': { 'default': 'celsius', 'description': '气温单位', 'enum': ['celsius', 'fahrenheit'], 'type': 'string' }, 'include_forecast': { 'default': False, 'description': '是否包含未来五日天气预报', 'type': 'boolean' } }, 'type': 'object' } @tool(args_schema=json_schema) def get_weather(city: str, units: str = "celsius", include_forecast: bool = False) -> str: """ 获取当日天气,可选择是否同时查询未来五日天气预报 """ temp = 22 if units == "celsius" else 72 result = f'{city}当天气温: {temp} {"摄氏度" if units == "celsius" else "华氏度"}' if include_forecast: result += "\n未来五天都是晴天" return result rprint(convert_to_openai_tool(get_weather))
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:繁星

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!