Day16:LangChain Tool与Toolkit完全指南:从零开始打造你的第一个多工具智能体
Day16:LangChain Tool与Toolkit完全指南:从零开始打造你的第一个多工具智能体
🌟 前言
在Day15的教程中,我们学习了LangChain的基础概念,并搭建了第一个问答Chain。很多同学在后台问我:“我已经会调用模型了,但如何让AI真正动手做事?比如帮我查天气、算数学题、操作文件?”
今天,我们就来深入探讨LangChain最强大的特性之一:Tool(工具)与Toolkit(工具包) 。学完本文,你将能够:
-
✅ 理解Tool和Toolkit的核心概念
-
✅ 掌握三种创建自定义Tool的方法
-
✅ 将上周封装的天气和计算器函数转换为LangChain Tool
-
✅ 构建Toolkit实现多工具协同调用
-
✅ 使用ReAct代理让AI自主选择工具
让我们开始吧!🚀
🧐 一、什么是LangChain Tool?
1.1 为什么需要Tool?
大语言模型(LLM)本身存在两个天然缺陷:
-
知识截止日期:不知道最新信息
-
无法执行操作:只能生成文字,不能调用外部系统
Tool 就是为了解决这些问题而生的。在LangChain中,Tool是AI模型可以用来与世界交互的函数 。每个Tool都代表一个特定的能力:搜索、计算、查天气、发邮件等。
1.2 Tool的核心组件
一个完整的LangChain Tool由以下五个核心组件构成 :
| 组件 | 作用 | 示例 |
|---|---|---|
| name | 工具的唯一标识 | "weather_search" |
| description | 告诉AI什么时候用这个工具 | "当用户需要查询天气时使用" |
| func | 实际执行的函数 | get_weather(city) |
| args_schema | 输入参数的定义和验证 | Pydantic模型 |
| return_direct | 是否直接返回结果 | False(通常不直接返回) |
通俗理解:Tool就像是给AI配的"瑞士军刀",每一把刀(工具)都有明确的用途和使用说明,AI会根据任务需要选择合适的工具。
🧩 二、什么是Toolkit?
Toolkit 是一组相关Tool的集合,用于完成特定领域的复杂任务 。
Tool vs Toolkit:一张图看懂

Toolkit的主要作用 :
-
组织多个工具:将相关的工具组合在一起
-
简化接口:统一管理和调用
-
提高效率:一次性加载多个工具给代理使用
🛠️ 三、LangChain Tool的三种创建方式
LangChain提供了三种创建自定义Tool的方法 。我们从最简单到最复杂逐一介绍。
方法1:使用 **@tool** 装饰器(最简单)
这是最快速、最简洁的方式,只需在普通函数上添加 @tool 装饰器 。
from langchain.tools import tool
@tool
def multiply(first_int: int, second_int: int) -> int:
"""将两个整数相乘。"""
return first_int * second_int
# 使用
result = multiply.invoke({"first_int": 5, "second_int": 7})
print(result) # 35
优点:代码量最少,自动从函数签名生成schema
缺点:自定义程度有限
方法2:使用 **Tool** 数据类(最常用)
这是最平衡的方式,适合大多数场景 。
from langchain.tools import Tool
def get_weather(city: str) -> str:
"""获取指定城市的天气"""
# 这里是实际逻辑
return f"{city}今天晴朗,25℃"
weather_tool = Tool.from_function(
func=get_weather,
name="weather_checker",
description="当需要查询某个城市的天气情况时使用"
)
# 或直接使用Tool类
weather_tool = Tool(
name="weather_checker",
func=get_weather,
description="当需要查询某个城市的天气情况时使用"
)
优点:灵活、直观、支持参数验证
缺点:需要手动处理多参数(可用StructuredTool解决)
方法3:继承 **BaseTool** 基类(最强大)
当需要复杂初始化、异步操作或状态管理时,使用这种方法 。
from typing import Optional, Type
from langchain_core.tools import BaseTool
from langchain_core.callbacks import CallbackManagerForToolRun
from pydantic import BaseModel, Field
import random
from datetime import datetime
from dotenv import load_dotenv
from langchain_community.chat_models import ChatTongyi
from langchain.agents.react.agent import create_react_agent
from langchain.agents import AgentExecutor
from langchain_core.prompts import PromptTemplate
load_dotenv() # 从 .env 读取 API 密钥
# ========== 定义模拟天气工具 ==========
class WeatherInput(BaseModel):
city: str = Field(description="城市名称,如'北京'")
date: Optional[str] = Field(None, description="日期,格式 YYYY-MM-DD,默认为今天")
class SimulatedWeatherTool(BaseTool):
name: str = "simulated_weather"
description: str = "查询指定城市和日期的模拟天气数据(仅供演示)"
args_schema: Type[BaseModel] = WeatherInput
def _run(
self,
city: str,
date: Optional[str] = None,
run_manager: Optional[CallbackManagerForToolRun] = None
) -> str:
if date is None:
date = datetime.now().strftime("%Y-%m-%d")
conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temperature = random.randint(10, 35)
humidity = random.randint(40, 90)
condition = random.choice(conditions)
return f"{date} {city} 天气:{condition},{temperature}℃,湿度 {humidity}%"
async def _arun(self, city: str, date: Optional[str] = None, run_manager=None) -> str:
return self._run(city, date, run_manager)
weather_tool = SimulatedWeatherTool()
# ========== 初始化模型 ==========
llm = ChatTongyi(model="qwen-plus") # API 密钥从环境变量读取
# ========== 创建代理 ==========
tools = [weather_tool]
# ✅ 正确的提示模板:包含完整的 ReAct 格式说明
prompt = PromptTemplate.from_template(
"你是一个可以使用工具的助手。\n\n"
"你有以下工具可用:\n{tools}\n\n"
"请严格按照以下格式输出:\n"
"Thought: 你需要做什么\n"
"Action: 工具名称,必须是 [{tool_names}] 中的一个\n"
"Action Input: 工具的输入参数(必须是 JSON 格式)\n"
"Observation: 工具返回的结果\n"
"... (可以重复多次 Thought/Action/Action Input/Observation)\n"
"Thought: 我现在可以给出最终答案\n"
"Final Answer: 对用户的最终回答\n\n"
"用户输入:{input}\n"
"{agent_scratchpad}"
)
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True # 允许解析错误时重试
)
# ========== 测试 ==========
response = agent_executor.invoke({"input": "明天上海的天气怎么样?"})
print(response['output'])
优点:完全控制,支持异步,可管理状态
缺点:代码量较大
三种方式对比
| 维度 | @tool装饰器 | Tool类 | BaseTool子类 |
|---|---|---|---|
| 代码量 | ⭐⭐⭐ 最少 | ⭐⭐ 中等 | ⭐ 最多 |
| 灵活性 | ⭐⭐ 中等 | ⭐⭐⭐ 高 | ⭐⭐⭐ 最高 |
| 异步支持 | ⭐ 不支持 | ⭐ 不支持 | ⭐⭐⭐ 支持 |
| 参数验证 | ⭐⭐ 自动 | ⭐⭐ 需配合Pydantic | ⭐⭐⭐ 精细控制 |
| 适用场景 | 简单函数 | 大多数场景 | 复杂工具 |
🌤️ 四、实战:将天气和计算器封装为自定义Tool
现在,让我们将之前封装的天气和计算器函数转换为LangChain自定义Tool。
4.1 准备工作
首先,安装必要的库:版本:0.1.17
pip install langchain langchain-community python-dotenv dashscope
创建 .env 文件(如果还没有):
DASHSCOPE_API_KEY=你的阿里云百炼API密钥
4.2 封装天气查询Tool
我们将创建一个模拟的天气查询工具(实际项目中可替换为真实API)。
import random
from datetime import datetime
from typing import Optional
from langchain.tools import tool, StructuredTool
from langchain.pydantic_v1 import BaseModel, Field
# ---------- 方式1:使用@tool装饰器(最简洁)----------
@tool
def get_weather_simple(city: str) -> str:
"""
查询指定城市的实时天气。
Args:
city: 城市名称,如'北京'、'上海'
Returns:
包含天气信息的字符串
"""
# 模拟天气数据(实际应用中可调用真实API)
weather_conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temperatures = random.randint(15, 35)
condition = random.choice(weather_conditions)
return f"{city}当前天气:{condition},{temperatures}℃,湿度65%"
# ---------- 方式2:使用Tool类(推荐)----------
def get_weather_with_date(city: str, date: Optional[str] = None) -> str:
"""
查询指定城市在特定日期的天气。
"""
if date is None:
date = datetime.now().strftime("%Y-%m-%d")
# 模拟天气数据
weather_conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temperatures = random.randint(10, 38)
condition = random.choice(weather_conditions)
return f"{date} {city}天气:{condition},{temperatures}℃"
# 创建带参数验证的输入模型
class WeatherInput(BaseModel):
city: str = Field(description="城市名称,如'北京'")
date: Optional[str] = Field(None, description="日期,格式YYYY-MM-DD,默认为今天")
# 使用Tool.from_function创建工具
weather_tool = StructuredTool .from_function(
func=get_weather_with_date,
name="weather_query",
description="查询指定城市和日期的天气信息。输入城市名称,可选日期参数。",
args_schema=WeatherInput # 提供参数schema,让AI更好理解
)
print(get_weather_simple.invoke({"city": "北京"}))
print(weather_tool.invoke({"city": "上海", "date": "2026-03-16"}))
注意点:****针对多参数不适用Tool,官网推荐使用StructuredTool
关键点:description 非常重要,它告诉AI何时使用这个工具。描述越清晰,AI选择越准确 。
返回结果:
北京当前天气:多云,31℃,湿度65%
2026-03-16 上海天气:小雨,20℃
4.3 封装计算器Tool
计算器工具支持加减乘除等基本运算 。
import math
import re
from typing import Union
from langchain.tools import tool
from langchain.tools import StructuredTool
from langchain.pydantic_v1 import BaseModel, Field
# ---------- 计算器核心逻辑 ----------
def calculate(expression: str) -> str:
"""
计算数学表达式。
支持的运算:+ - * / ** () sqrt() 等
Args:
expression: 数学表达式字符串,如"2 + 3 * 4"或"sqrt(16)"
Returns:
计算结果
"""
# 安全检查:只允许数字、运算符、括号和数学函数
if not re.match(r'^[0-9\s\+\-\*\/\(\)\.\,\s]+$', expression) and \
not any(func in expression for func in ['sqrt', 'pow', 'abs']):
return "错误:表达式包含非法字符"
try:
# 替换数学函数
expr = expression.replace('sqrt', 'math.sqrt')
expr = expr.replace('pow', 'math.pow')
expr = expr.replace('abs', 'abs')
# 安全计算(注意:eval有风险,生产环境建议使用numexpr或sympy)
result = eval(expr)
return f"{expression} = {result}"
except Exception as e:
return f"计算错误:{str(e)}"
# ---------- 使用StructuredTool(适合多参数)----------
class CalculatorInput(BaseModel):
expression: str = Field(description="数学表达式,例如'2 * 3'、'sqrt(16)'")
calculator_tool = StructuredTool.from_function(
func=calculate,
name="calculator",
description="用于数学计算。输入数学表达式,支持加减乘除、幂运算、平方根等。",
args_schema=CalculatorInput
)
# ---------- 扩展:专门的幂运算工具 ----------
# ---------- 幂运算工具(也使用 StructuredTool)----------
def power(base: float, exponent: float) -> str:
result = base ** exponent
return f"{base} 的 {exponent} 次方 = {result}"
class PowerInput(BaseModel):
base: float = Field(description="底数")
exponent: float = Field(description="指数")
power_tool = StructuredTool.from_function(
func=power,
name="power_tool",
description="计算一个数的幂。例如:2的3次方等于8",
args_schema=PowerInput
)
# 测试计算器工具
result1 = calculator_tool.invoke({"expression": "2 + 3 * 4"})
print(result1) # 输出:2 + 3 * 4 = 14
result2 = calculator_tool.invoke({"expression": "sqrt(16)"})
print(result2) # 输出:sqrt(16) = 4.0
# 测试幂运算工具
result3 = power_tool.invoke({"base": 5, "exponent": 3})
print(result3) # 输出:5 的 3 次方 = 125
返回结果:
2 + 3 * 4 = 14
sqrt(16) = 4.0
5.0 的 3.0 次方 = 125.0
🧰 五、创建Toolkit实现多工具调用
5.1 什么是Toolkit?
Toolkit就是一组相关工具的集合 。LangChain内置了很多Toolkit,如:
-
FileManagementToolkit:文件操作工具包 -
SQLDatabaseToolkit:数据库查询工具包 -
RequestsToolkit:HTTP请求工具包
5.2 将多个Tool组合成Toolkit
我们将刚才创建的天气工具、计算器工具组合成一个Toolkit 。
import random
from datetime import datetime
from typing import Optional
from langchain.tools import tool, StructuredTool
from langchain.pydantic_v1 import BaseModel, Field
import re
# ---------- 方式1:使用@tool装饰器(最简洁)----------
@tool
def get_weather_simple(city: str) -> str:
"""
查询指定城市的实时天气。
Args:
city: 城市名称,如'北京'、'上海'
Returns:
包含天气信息的字符串
"""
# 模拟天气数据(实际应用中可调用真实API)
weather_conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temperatures = random.randint(15, 35)
condition = random.choice(weather_conditions)
return f"{city}当前天气:{condition},{temperatures}℃,湿度65%"
# ---------- 方式2:使用Tool类(推荐)----------
def get_weather_with_date(city: str, date: Optional[str] = None) -> str:
"""
查询指定城市在特定日期的天气。
"""
if date is None:
date = datetime.now().strftime("%Y-%m-%d")
# 模拟天气数据
weather_conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temperatures = random.randint(10, 38)
condition = random.choice(weather_conditions)
return f"{date} {city}天气:{condition},{temperatures}℃"
# 创建带参数验证的输入模型
class WeatherInput(BaseModel):
city: str = Field(description="城市名称,如'北京'")
date: Optional[str] = Field(None, description="日期,格式YYYY-MM-DD,默认为今天")
# 使用Tool.from_function创建工具
weather_tool = StructuredTool .from_function(
func=get_weather_with_date,
name="weather_query",
description="查询指定城市和日期的天气信息。输入城市名称,可选日期参数。",
args_schema=WeatherInput # 提供参数schema,让AI更好理解
)
# ---------- 计算器核心逻辑 ----------
def calculate(expression: str) -> str:
"""
计算数学表达式。
支持的运算:+ - * / ** () sqrt() 等
Args:
expression: 数学表达式字符串,如"2 + 3 * 4"或"sqrt(16)"
Returns:
计算结果
"""
# 安全检查:只允许数字、运算符、括号和数学函数
if not re.match(r'^[0-9\s\+\-\*\/\(\)\.\,\s]+$', expression) and \
not any(func in expression for func in ['sqrt', 'pow', 'abs']):
return "错误:表达式包含非法字符"
try:
# 替换数学函数
expr = expression.replace('sqrt', 'math.sqrt')
expr = expr.replace('pow', 'math.pow')
expr = expr.replace('abs', 'abs')
# 安全计算(注意:eval有风险,生产环境建议使用numexpr或sympy)
result = eval(expr)
return f"{expression} = {result}"
except Exception as e:
return f"计算错误:{str(e)}"
# ---------- 使用StructuredTool(适合多参数)----------
class CalculatorInput(BaseModel):
expression: str = Field(description="数学表达式,例如'2 * 3'、'sqrt(16)'")
calculator_tool = StructuredTool.from_function(
func=calculate,
name="calculator",
description="用于数学计算。输入数学表达式,支持加减乘除、幂运算、平方根等。",
args_schema=CalculatorInput
)
# ---------- 扩展:专门的幂运算工具 ----------
def power(base: float, exponent: float) -> str:
result = base ** exponent
return f"{base} 的 {exponent} 次方 = {result}"
class PowerInput(BaseModel):
base: float = Field(description="底数")
exponent: float = Field(description="指数")
power_tool = StructuredTool.from_function(
func=power,
name="power_tool",
description="计算一个数的幂。例如:2的3次方等于8",
args_schema=PowerInput
)
# 收集所有工具
my_tools = [
weather_tool,
calculator_tool,
power_tool
]
# 方式1:简单列表(推荐,因为Agent直接接受工具列表)
# 在LangChain最新版本中,Agent直接接受tools参数,不需要显式Toolkit类
# 方式2:自定义Toolkit类(便于管理)
class MyToolkit:
"""我的个人工具包"""
@property
def tools(self):
return [
weather_tool,
calculator_tool,
power_tool
]
def get_tools(self):
return self.tools
# 使用
my_toolkit = MyToolkit()
all_tools = my_toolkit.get_tools()
print(f"工具包包含 {len(all_tools)} 个工具:{[t.name for t in all_tools]}")
输出结果:
工具包包含 3 个工具:['weather_query', 'calculator', 'power_tool']
5.3 使用ReAct代理实现智能调用
现在,我们将工具包交给AI代理,让它能够根据用户问题自主选择工具 。
**注:**通过千问文字解析之后的计算规则与之前的计算规则存在冲突,各种校验无法通过,故以下代码校验项完全更改
import random
import math
import json
from datetime import datetime, timedelta
from typing import List
from dotenv import load_dotenv
from langchain_core.tools import StructuredTool, BaseTool
from langchain_community.chat_models import ChatTongyi
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.prompts import PromptTemplate
# ========== 工具函数实现(接收原始输入字符串,内部解析JSON)==========
def weather_query_tool(input_str: str) -> str:
"""天气查询工具,输入应为JSON字符串,例如 {"city":"北京","date":"明天"}"""
try:
params = json.loads(input_str)
city = params.get("city")
date = params.get("date")
if not city:
return "错误:必须提供城市名称"
# 处理日期
if date is None or date == "今天":
target_date = datetime.now()
elif date == "明天":
target_date = datetime.now() + timedelta(days=1)
else:
try:
target_date = datetime.strptime(date, "%Y-%m-%d")
except ValueError:
return f"错误:日期格式不正确,请使用YYYY-MM-DD、'今天'或'明天'"
date_str = target_date.strftime("%Y-%m-%d")
conditions = ["晴朗", "多云", "阴天", "小雨", "大雨", "雷阵雨"]
temp = random.randint(10, 38)
condition = random.choice(conditions)
return f"{date_str} {city}天气:{condition},{temp}℃"
except json.JSONDecodeError:
return f"错误:输入不是有效的JSON格式。输入内容:{input_str}"
except Exception as e:
return f"天气查询错误:{str(e)}"
def calculator_tool(input_str: str) -> str:
"""计算器工具,输入应为JSON字符串,例如 {"expression":"125*16"} 或 {"expression":"28*1.8+32"}"""
try:
params = json.loads(input_str)
expression = params.get("expression")
if not expression:
return "错误:必须提供数学表达式"
# 清理表达式
expr = expression.replace(" ", "").replace("×", "*").replace("÷", "/")
# 安全过滤
if "__" in expr or "[" in expr or "]" in expr or "{" in expr or "}" in expr:
return "错误:表达式包含非法操作"
# 允许的数学函数
allowed_names = {
"sqrt": math.sqrt, "pow": math.pow, "abs": abs,
"sin": math.sin, "cos": math.cos, "tan": math.tan,
"log": math.log, "exp": math.exp,
"pi": math.pi, "e": math.e
}
result = eval(expr, {"__builtins__": {}}, allowed_names)
return f"{expression} = {result}"
except ZeroDivisionError:
return "错误:除数不能为零"
except SyntaxError:
return "错误:表达式语法不正确"
except json.JSONDecodeError:
return f"错误:输入不是有效的JSON格式。输入内容:{input_str}"
except Exception as e:
return f"计算错误:{str(e)}"
def power_tool(input_str: str) -> str:
"""幂运算工具,输入应为JSON字符串,例如 {"base":2,"exponent":10}"""
try:
params = json.loads(input_str)
base = float(params.get("base"))
exponent = float(params.get("exponent"))
result = base ** exponent
return f"{base} 的 {exponent} 次方 = {result}"
except (ValueError, TypeError):
return "错误:底数和指数必须是数字"
except json.JSONDecodeError:
return f"错误:输入不是有效的JSON格式。输入内容:{input_str}"
except Exception as e:
return f"幂运算错误:{str(e)}"
# ========== 使用 StructuredTool 包装(不提供 args_schema) ==========
weather_tool = StructuredTool.from_function(
func=weather_query_tool,
name="weather_query",
description="查询指定城市和日期的天气信息。输入必须是JSON字符串,例如:{\"city\":\"北京\",\"date\":\"明天\"}"
)
calculator_tool = StructuredTool.from_function(
func=calculator_tool,
name="calculator",
description="用于数学计算。输入必须是JSON字符串,例如:{\"expression\":\"125*16\"} 或 {\"expression\":\"28*1.8+32\"}"
)
power_tool = StructuredTool.from_function(
func=power_tool,
name="power",
description="计算一个数的幂。输入必须是JSON字符串,例如:{\"base\":2,\"exponent\":10}"
)
# ========== 自定义 Toolkit 类 ==========
class MyToolkit:
def get_tools(self) -> List[BaseTool]:
return [weather_tool, calculator_tool, power_tool]
toolkit = MyToolkit()
tools = toolkit.get_tools()
print(f"工具包包含 {len(tools)} 个工具:{[t.name for t in tools]}")
# ========== 初始化模型 ==========
load_dotenv() # 确保 .env 文件中有 DASHSCOPE_API_KEY
llm = ChatTongyi(model="qwen-plus", temperature=0.1)
# ========== 创建 ReAct 代理 ==========
prompt = PromptTemplate.from_template(
"""你是一个有用的AI助手,可以使用工具来回答问题。
可用工具:
{tools}
工具名称列表:{tool_names}
严格按照以下格式执行:
Thought: 分析问题,决定使用哪个工具
Action: 工具名称(必须是工具名称列表中的一个)
Action Input: 严格的JSON格式参数,例如:{{"city":"北京","date":"明天"}} 或 {{"expression":"125*16"}} 或 {{"base":2,"exponent":10}}
Observation: 工具返回的结果
...(可重复多次)
Thought: 可以回答用户问题了
Final Answer: 最终答案
注意:
1. Action Input必须是有效的JSON字符串,不要加任何额外字符或换行
2. 计算器支持小数点和四则运算,例如"28*1.8+32"是合法的
3. 日期参数支持"明天"或YYYY-MM-DD格式
开始处理用户问题:
用户输入:{input}
{agent_scratchpad}"""
)
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True,
max_iterations=5
)
def ask_agent(question):
print(f"\n👤 用户: {question}")
print("-" * 50)
response = agent_executor.invoke({"input": question})
print(f"🤖 助手: {response['output']}")
print("=" * 50)
if __name__ == "__main__":
ask_agent("明天北京的天气怎么样?")
ask_agent("计算 125 乘以 16 等于多少?")
ask_agent("如果北京今天温度是28度,那么华氏度是多少?(提示:华氏度=摄氏度×1.8+32)")
ask_agent("计算 2 的 10 次方,然后开平方根")
运行效果(verbose=True会显示完整思考过程):
工具包包含 3 个工具:['weather_query', 'calculator', 'power']
👤 用户: 明天北京的天气怎么样?
--------------------------------------------------
> Entering new AgentExecutor chain...
Thought: 需要查询明天北京的天气信息,使用weather_query工具
Action: weather_query
Action Input: {"city":"北京","date":"明天"}2026-03-18 北京天气:晴朗,38℃Final Answer: 明天北京的天气晴朗,气温为38℃。
> Finished chain.
🤖 助手: 明天北京的天气晴朗,气温为38℃。
==================================================
👤 用户: 计算 125 乘以 16 等于多少?
--------------------------------------------------
> Entering new AgentExecutor chain...
Thought: 这是一个简单的数学乘法计算问题,应该使用calculator工具
Action: calculator
Action Input: {"expression":"125*16"}125*16 = 2000Final Answer: 125 乘以 16 等于 2000。
> Finished chain.
🤖 助手: 125 乘以 16 等于 2000。
==================================================
👤 用户: 如果北京今天温度是28度,那么华氏度是多少?(提示:华氏度=摄氏度×1.8+32)
--------------------------------------------------
> Entering new AgentExecutor chain...
Thought: 需要计算华氏度,使用计算器工具进行数学运算:28×1.8+32
Action: calculator
Action Input: {"expression":"28*1.8+32"}28*1.8+32 = 82.4Final Answer: 北京今天28摄氏度对应的华氏度是82.4°F。
> Finished chain.
🤖 助手: 北京今天28摄氏度对应的华氏度是82.4°F。
==================================================
👤 用户: 计算 2 的 10 次方,然后开平方根
--------------------------------------------------
> Entering new AgentExecutor chain...
Thought: 需要先计算2的10次方,然后对结果开平方根。可以使用power工具计算2的10次方,然后用calculator工具计算平方根。
Action: power
Action Input: {"base":2,"exponent":10}2.0 的 10.0 次方 = 1024.0现在需要对1024开平方根,可以使用calculator工具计算sqrt(1024)
Action: calculator
Action Input: {"expression":"sqrt(1024)"}sqrt(1024) = 32.0Final Answer: 32.0
> Finished chain.
🤖 助手: 32.0
==================================================
Process finished with exit code 0
🎯 六、进阶:使用StructuredTool处理复杂输入
当工具需要多个参数时,StructuredTool是最佳选择。它支持复杂的输入结构 。
from langchain.tools import StructuredTool
from langchain.pydantic_v1 import BaseModel, Field
from typing import List, Optional
# 定义复杂的输入模型
class TravelPlanInput(BaseModel):
destination: str = Field(description="旅行目的地")
days: int = Field(description="旅行天数", ge=1, le=30)
interests: List[str] = Field(description="兴趣点列表,如['美食', '历史', '购物']")
budget: Optional[float] = Field(None, description="预算(元)")
def generate_travel_plan(
destination: str,
days: int,
interests: List[str],
budget: Optional[float] = None
) -> str:
"""生成旅行计划(模拟)"""
plan = f"【{destination} {days}天旅行计划】\n"
plan += f"兴趣点:{', '.join(interests)}\n"
if budget:
plan += f"预算:{budget}元\n"
plan += f"Day 1: 抵达{destination},入住酒店\n"
plan += f"Day 2-{days-1}: 根据兴趣安排景点\n"
plan += f"Day {days}: 返程"
return plan
# 创建StructuredTool
travel_tool = StructuredTool.from_function(
func=generate_travel_plan,
name="travel_planner",
description="生成个性化旅行计划。需要目的地、天数、兴趣点等",
args_schema=TravelPlanInput
)
# 测试
result = travel_tool.invoke({
"destination": "杭州",
"days": 3,
"interests": ["西湖", "美食", "茶文化"],
"budget": 3000
})
print(result)
返回 结果:
【杭州 3天旅行计划】
兴趣点:西湖, 美食, 茶文化
预算:3000.0元
Day 1: 抵达杭州,入住酒店
Day 2-2: 根据兴趣安排景点
Day 3: 返程
📝 七、总结与最佳实践
通过今天的学习,我们掌握了:
-
Tool的概念:AI与外部世界交互的接口
-
Toolkit的概念:相关工具的集合
-
三种创建Tool的方法:
@tool装饰器、Tool类、BaseTool子类 -
实战封装:将天气和计算器转为Tool
-
多工具调用:使用ReAct代理智能选择工具
Tool设计黄金法则
| 原则 | 说明 | 示例 |
|---|---|---|
| 1. 命名清晰 | 使用动词开头的命名 | search_web 优于 web |
| 2. 描述精准 | 说清楚什么时候用 | ❌ “计算东西” → ✅ “执行数学计算,支持加减乘除、幂运算” |
| 3. 参数验证 | 使用Pydantic模型验证 | 防止错误输入导致崩溃 |
| 4. 错误处理 | 返回友好错误信息 | 不要抛出异常中断流程 |
| 5. 保持简单 | 一个工具只做一件事 | 单一职责原则 |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)