在使用大模型时,你是否遇到过这样的困境:

  • 大模型的训练数据截止到某一时间点,无法回答实时问题(如 “今天北京的天气怎么样?”);
  • 大模型擅长文本生成,但不擅长精确计算(如 “123456*789012 等于多少?”);
  • 大模型无法直接访问你的私有数据(如公司数据库、本地文件)。

这些问题的根源在于大模型本身的局限性—— 它是一个 “文本生成器”,没有直接与外部世界交互的能力。而 LangChain 的Tools 系统正是为解决这一痛点而生,它能让大模型调用外部工具,实现与外部世界的交互,拥有 “超能力”。

本文将从工具的基本概念实战案例,带你全面掌握 LangChain Tool 的创建与使用,重点使用@tool装饰器(LangChain 推荐的方式)。


一、什么是 LangChain Tool?

1. 定义:大模型的 “外部接口”

LangChain Tool 是大模型与外部工具交互的桥梁,它允许大模型调用外部工具(如搜索引擎、计算器、数据库、API 等),获取实时信息或执行特定任务。

简单来说,Tools 系统让大模型从 “文本生成器” 升级为 “任务解决者”—— 不仅能生成文本,还能调用工具解决实际问题。

2. 核心价值

  • 扩展能力边界:让大模型能处理实时信息、精确计算、私有数据访问等原本无法处理的任务;
  • 提升输出准确性:通过调用工具获取真实数据,减少大模型的 “幻觉”;
  • 实现复杂任务:将多个工具串联,实现多步任务(如 “生成旅行计划→查询机票价格→推荐酒店”)。

二、LangChain Tool 的核心结构

一个 LangChain Tool 通常包含以下三个部分:

  • 名称(name):工具的唯一标识,大模型通过名称选择工具;
  • 描述(description):工具的功能说明,大模型通过描述判断是否需要调用该工具;
  • 函数(func):工具的执行逻辑,实际调用外部工具的代码。

在 LangChain 中,推荐使用@tool装饰器来定义工具,它能自动处理工具的名称、描述和函数的绑定,让代码更简洁。


三、使用@tool装饰器创建工具

1. 基本用法:创建简单工具

from langchain.tools import tool

@tool("weather_tool")
def get_weather(city: str) -> str:
    """获取指定城市的实时天气信息"""
    # 这里模拟调用天气API,实际开发中替换为真实API调用
    weather_data = {
        "北京": "晴,20-28℃",
        "上海": "多云,22-30℃",
        "广州": "小雨,24-26℃"
    }
    return f"{city}的天气:{weather_data.get(city, '暂无数据')}"

# 测试工具
result = get_weather.run("北京")
print(result)  # 输出:北京的天气:晴,20-28℃
关键说明:
  • @tool("weather_tool"):装饰器参数为工具的名称(weather_tool);
  • 函数的文档字符串("""获取指定城市的实时天气信息""")作为工具的描述;
  • 函数的参数和返回值作为工具的输入和输出。

2. 带参数验证的工具

为了确保工具接收的参数符合要求,可以在工具函数中添加参数验证:

from langchain.tools import tool

@tool("flight_price_tool")
def get_flight_price(route: str) -> str:
    """获取指定航线的机票价格,输入格式为“出发地-目的地 日期”(如“北京-上海 2024-06-01”)"""
    # 参数验证
    if "-" not in route or " " not in route:
        return "输入格式错误,请使用“出发地-目的地 日期”格式(如“北京-上海 2024-06-01”)"
    
    # 模拟调用机票API
    flight_data = {
        "北京-上海 2024-06-01": "经济舱:500-800元,商务舱:1200-1800元",
        "上海-北京 2024-06-01": "经济舱:450-750元,商务舱:1100-1700元"
    }
    return f"{route}的机票价格:{flight_data.get(route, '暂无数据')}"

# 测试工具
result = get_flight_price.run("北京-上海 2024-06-01")
print(result)  # 输出:北京-上海 2024-06-01的机票价格:经济舱:500-800元,商务舱:1200-1800元

result = get_flight_price.run("北京上海2024-06-01")
print(result)  # 输出:输入格式错误,请使用“出发地-目的地 日期”格式(如“北京-上海 2024-06-01”)

3. 带 Pydantic 参数验证的工具

对于更复杂的参数验证,可以使用 Pydantic 模型来定义工具的输入参数:

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

# 定义参数模型
class FlightPriceInput(BaseModel):
    departure: str = Field(description="出发城市")
    destination: str = Field(description="目的地城市")
    date: str = Field(description="出行日期,格式为YYYY-MM-DD")

@tool("flight_price_tool", args_schema=FlightPriceInput)
def get_flight_price(departure: str, destination: str, date: str) -> str:
    """获取指定航线的机票价格"""
    # 模拟调用机票API
    route = f"{departure}-{destination} {date}"
    flight_data = {
        "北京-上海 2024-06-01": "经济舱:500-800元,商务舱:1200-1800元"
    }
    return f"{route}的机票价格:{flight_data.get(route, '暂无数据')}"

# 测试工具
result = get_flight_price.run({"departure": "北京", "destination": "上海", "date": "2024-06-01"})
print(result)  # 输出:北京-上海 2024-06-01的机票价格:经济舱:500-800元,商务舱:1200-1800元
关键说明:
  • args_schema=FlightPriceInput:指定参数验证的 Pydantic 模型;
  • 工具函数的参数需要与 Pydantic 模型的字段一一对应;
  • 调用工具时,需要传递字典格式的参数。

四、工具的调用方式

1. 直接调用工具

最直接的方式是直接调用工具的run方法:

result = get_weather.run("北京")
print(result)  # 输出:北京的天气:晴,20-28℃

2. 通过 Agent 调用工具

Agent 是能自主决策并调用工具的大模型,它能根据用户需求判断是否需要调用工具、调用哪个工具、如何使用工具结果生成最终回答。

代码示例:使用 ZeroShotAgent 调用工具
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
from langchain.tools import tool

# 1. 创建工具
@tool("weather_tool")
def get_weather(city: str) -> str:
    """获取指定城市的实时天气信息"""
    weather_data = {
        "北京": "晴,20-28℃",
        "上海": "多云,22-30℃"
    }
    return f"{city}的天气:{weather_data.get(city, '暂无数据')}"

@tool("calculator_tool")
def calculate(expression: str) -> str:
    """执行数学计算,输入参数为数学表达式(如123+456)"""
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except Exception as e:
        return f"计算错误:{str(e)}"

# 2. 初始化大模型
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# 3. 初始化Agent
tools = [get_weather, calculate]
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True  # 开启调试模式,查看Agent的思考过程
)

# 4. 测试Agent
# 测试天气查询
result = agent.invoke("今天北京的天气怎么样?")
print(result["output"])

# 测试数学计算
result = agent.invoke("123456*789012等于多少?")
print(result["output"])

# 测试复杂问题
result = agent.invoke("我明天要去北京出差,需要穿什么衣服?")
print(result["output"])
输出结果(调试模式):
> Entering new AgentExecutor chain...
我需要获取北京今天的天气信息,然后根据天气建议穿什么衣服。首先调用weather_tool获取北京的天气。
Action: weather_tool
Action Input: 北京
Observation: 北京的天气:晴,20-28℃
Thought: 北京今天晴,20-28℃,天气比较舒适,建议穿长袖衬衫或薄外套,搭配长裤。
Final Answer: 北京今天晴,20-28℃,天气比较舒适,建议穿长袖衬衫或薄外套,搭配长裤。
> Finished chain.
关键说明:
  • verbose=True可以查看 Agent 的思考过程,包括为什么调用工具、调用哪个工具、工具返回结果等;
  • Agent 会根据工具的描述自动判断是否需要调用工具,无需手动指定;
  • 复杂问题中,Agent 会自动串联多个工具,实现多步任务。

五、实战案例:构建智能旅行助手

需求分析

开发一个智能旅行助手,具备以下功能:

  1. 能根据用户的出发地、目的地、出行日期生成旅行计划;
  2. 能查询机票价格、酒店推荐、当地天气等信息;
  3. 能根据用户的预算和偏好调整旅行计划;
  4. 支持多轮对话,记住用户的上下文信息。

实现步骤

from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.tools import tool
from langchain_community.tools import SerpAPIWrapper

# 1. 初始化内置工具
search = SerpAPIWrapper()

# 2. 自定义工具
@tool("flight_price_tool")
def get_flight_price(route: str) -> str:
    """获取指定航线的机票价格,输入格式为“出发地-目的地 日期”(如“北京-上海 2024-06-01”)"""
    # 参数验证
    if "-" not in route or " " not in route:
        return "输入格式错误,请使用“出发地-目的地 日期”格式(如“北京-上海 2024-06-01”)"
    
    # 模拟调用机票API
    flight_data = {
        "北京-上海 2024-06-01": "经济舱:500-800元,商务舱:1200-1800元",
        "上海-北京 2024-06-01": "经济舱:450-750元,商务舱:1100-1700元"
    }
    return f"{route}的机票价格:{flight_data.get(route, '暂无数据')}"

@tool("hotel_recommendation_tool")
def recommend_hotel(city: str, budget: str) -> str:
    """根据城市和预算推荐酒店,输入格式为“城市 预算”(如“北京 500元/晚”)"""
    # 模拟调用酒店API
    hotel_data = {
        "北京 500元/晚": "推荐:如家快捷酒店、7天连锁酒店,价格400-600元/晚",
        "上海 1000元/晚": "推荐:希尔顿酒店、万豪酒店,价格800-1200元/晚"
    }
    return f"{city}预算{budget}的酒店推荐:{hotel_data.get(f'{city} {budget}', '暂无数据')}"

@tool("weather_tool")
def get_weather(city: str) -> str:
    """获取指定城市的实时天气信息"""
    weather_data = {
        "北京": "晴,20-28℃",
        "上海": "多云,22-30℃"
    }
    return f"{city}的天气:{weather_data.get(city, '暂无数据')}"

# 3. 初始化Memory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

# 4. 初始化大模型和Agent
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.7)
tools = [search, get_flight_price, recommend_hotel, get_weather]
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,
    memory=memory,
    verbose=True
)

# 5. 测试旅行助手
print("智能旅行助手:您好,我是您的智能旅行助手,请问有什么可以帮您的?")
while True:
    user_input = input("您:")
    if user_input.lower() in ["再见", "退出"]:
        print("智能旅行助手:再见,祝您旅途愉快!")
        break
    result = agent.invoke({"input": user_input})
    print(f"智能旅行助手:{result['output']}")

测试对话示例

智能旅行助手:您好,我是您的智能旅行助手,请问有什么可以帮您的?
您:我明天要从北京去上海出差,预算1000元/晚,帮我安排一下行程。
> Entering new AgentExecutor chain...
用户需要从北京去上海出差,日期是明天,预算1000元/晚。我需要先获取明天北京到上海的机票价格,然后推荐上海预算1000元/晚的酒店,最后生成行程计划。
Action: flight_price_tool
Action Input: 北京-上海 2024-06-01
Observation: 北京-上海 2024-06-01的机票价格:经济舱:500-800元,商务舱:1200-1800元
Thought: 接下来推荐上海预算1000元/晚的酒店。
Action: hotel_recommendation_tool
Action Input: 上海 1000元/晚
Observation: 上海预算1000元/晚的酒店推荐:推荐:希尔顿酒店、万豪酒店,价格800-1200元/晚
Thought: 现在生成行程计划。
Final Answer: 您的上海出差行程安排如下:
1. 交通:明天(2024-06-01)北京到上海的机票价格为经济舱500-800元,商务舱1200-1800元,建议提前预订。
2. 住宿:推荐上海的希尔顿酒店或万豪酒店,价格800-1200元/晚,符合您1000元/晚的预算。
3. 行程建议:到达上海后可以先办理入住,然后根据工作安排进行商务活动,晚上可以在酒店附近的餐厅用餐。
> Finished chain.
智能旅行助手:您的上海出差行程安排如下:
1. 交通:明天(2024-06-01)北京到上海的机票价格为经济舱500-800元,商务舱1200-1800元,建议提前预订。
2. 住宿:推荐上海的希尔顿酒店或万豪酒店,价格800-1200元/晚,符合您1000元/晚的预算。
3. 行程建议:到达上海后可以先办理入住,然后根据工作安排进行商务活动,晚上可以在酒店附近的餐厅用餐。
您:帮我查询一下明天上海的天气。
> Entering new AgentExecutor chain...
用户需要查询明天上海的天气,调用weather_tool工具。
Action: weather_tool
Action Input: 上海
Observation: 上海的天气:多云,22-30℃
Thought: 明天上海的天气是多云,22-30℃。
Final Answer: 明天上海的天气是多云,22-30℃。
> Finished chain.
智能旅行助手:明天上海的天气是多云,22-30℃。

五、高级技巧:工具的进阶使用

1. 工具的批量调用

在 Agent 中,可以通过batch方法批量调用工具,提高效率:

results = agent.batch([
    {"input": "今天北京的天气怎么样?"},
    {"input": "123+456等于多少?"},
    {"input": "北京到上海的机票价格是多少?"}
])
for result in results:
    print(result["output"])

2. 工具的权限控制

在生产环境中,需要对工具的调用进行权限控制,避免滥用:

from langchain.tools import tool

def check_permission(user_id: str, tool_name: str) -> bool:
    """检查用户是否有权限调用该工具"""
    # 模拟权限验证逻辑
    allowed_users = {
        "user1": ["weather_tool", "calculator_tool"],
        "user2": ["flight_price_tool"]
    }
    return tool_name in allowed_users.get(user_id, [])

@tool("weather_tool")
def get_weather(city: str, user_id: str) -> str:
    """获取指定城市的实时天气信息"""
    if not check_permission(user_id, "weather_tool"):
        return "您没有权限调用该工具"
    # 实际逻辑
    weather_data = {
        "北京": "晴,20-28℃"
    }
    return f"{city}的天气:{weather_data.get(city, '暂无数据')}"

3. 工具的异步调用

对于 IO 密集型的工具(如调用外部 API),可以使用异步函数来提高效率:

from langchain.tools import tool
import httpx

@tool("async_weather_tool")
async def get_async_weather(city: str) -> str:
    """异步获取指定城市的实时天气信息"""
    # 模拟调用异步天气API
    async with httpx.AsyncClient() as client:
        # 实际开发中替换为真实API
        response = await client.get(f"https://api.weather.com/weather?city={city}")
        weather_data = response.json()
        return f"{city}的天气:{weather_data.get('weather', '暂无数据')}"

六、最佳实践与注意事项

  1. 工具描述要清晰:工具的描述越清晰,Agent 越容易判断是否需要调用该工具,避免错误调用;
  2. 参数格式要明确:在工具描述中明确参数格式,帮助 Agent 正确传递参数;
  3. 错误处理要完善:在工具函数中添加错误处理,避免工具调用失败导致整个 Agent 崩溃;
  4. 权限控制要严格:生产环境中,对工具的调用进行权限控制,避免滥用;
  5. 性能优化要重视:工具调用是 Agent 的性能瓶颈,需要优化工具的执行速度,避免长时间等待;
  6. 监控日志要完整:记录工具的调用日志,包括调用时间、用户、参数、结果等,便于排查问题和优化。

七、总结

LangChain Tool 系统是大模型应用的 “超能力扩展器”,它让大模型从 “文本生成器” 升级为 “任务解决者”,能处理实时信息、精确计算、私有数据访问等原本无法处理的任务。

在实际开发中,推荐使用@tool装饰器来创建工具,它能自动处理工具的名称、描述和函数的绑定,让代码更简洁。同时,结合 Agent 使用工具,能实现自主决策和多步任务处理,打造真正的智能 AI 应用。

掌握 LangChain Tool 的创建与使用,是从 “简单对话机器人” 到 “智能 AI 助手” 的关键一步,让你的 AI 应用真正具备解决实际问题的能力!

Logo

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

更多推荐