介绍

LangChain 的核心优势之一是支持灵活扩展外部工具(Tools),让大语言模型(LLM)突破纯文本交互的限制,具备调用 API、操作文件、执行计算等实际业务能力。本文将以「天气查询 + 本地文件写入」为例,详解如何自定义 Tools、绑定到 Agent 并实现智能调用,完整覆盖工具开发、参数定义、异常处理和 Agent 集成的全流程。

案例一,自定义天气工具使用


from dotenv import load_dotenv
load_dotenv()
import os
from pydantic import SecretStr
from langchain.tools import tool
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    model="qwen-plus",
    api_key=SecretStr(os.environ["DASHSCOPE_API_KEY"]),
)
from langchain.agents import create_agent
# 1. 定义工具 (Tools)
#编写问题"北京天气怎么样"来测试智能体,并使用 agent.stream 方法实现流式输出,通过 pretty_print() 方法格式化显示每次的输出结果
@tool
def get_weather(city: str) -> str:
    """获取给定城市的当前天气信息。"""
    return f"总是晴天,温度为 25 度 in {city}!"
SYSTEM_PROMPT = "你是一个天气助手,具备调用get_weather天气函数获取指定地点天气的能力"
# 3. 创建代理
agent = create_agent(
    model=llm,
    tools=[get_weather],
    system_prompt=SYSTEM_PROMPT,
)

question="北京的天气怎么样?"
for step in agent.stream(
{'messages': question},
    stream_mode="values"
):
    step["messages"][-1].pretty_print()

    #运行上述代码后,我们可以清晰地观察到
    #LangChain1.0
    #智能体的完整执行流程:

    #用户提问:接收到问题
    #"北京天气怎么样"
    #模型分析:大语言模型识别出自身无法直接回答,决定调用工具函数
    #get_weather,并自动生成调用参数
    #{loc: 北京}
    #工具执行:执行工具函数并获取返回结果
    #结果整合:大语言模型根据工具函数的执行结果,生成格式化的最终回答

案例二,网络搜索工具使用

Tavily API Platform 注册获取api key


from dotenv import load_dotenv
load_dotenv()
import os
from pydantic import SecretStr
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    model="qwen-plus",
    api_key=SecretStr(os.environ["DASHSCOPE_API_KEY"]),
)
from langchain.agents import create_agent

from langchain_tavily import TavilySearch


# 3. 初始化Tavily搜索工具(配置API密钥)
web_search = TavilySearch(
    api_key=os.environ["TAVILY_API_KEY"],  # 配置Tavily密钥
    max_results=2,  # 限制搜索结果数量
    search_depth="basic"  # 基础搜索,速度更快
)

# 3.创建Agent
agent = create_agent(
    model=llm,
    tools=[web_search],
    system_prompt="你是一名多才多艺的智能助手,可以调用工具帮助用户解决问题。"
)

from langchain_core.tools import tool


# 4.运行Agent获得结果
result = agent.invoke(
    {"messages": [{"role": "user", "content": "请帮我查询2023年诺贝尔物理学奖得主是谁?"}]}
)

finalAnswer  = result['messages'][-1].content
print(finalAnswer)

案例三

一、案例背景与核心目标

本案例将实现一个具备两大核心能力的智能 Agent:

  1. 调用 OpenWeather API 查询指定城市的实时天气;
  2. 将查询到的天气信息自动写入本地文本文件;
  3. Agent 能根据用户指令(如 “查询天津、石家庄、上海天气并写入文件”),自动判断并依次调用上述两个工具完成任务。

二、环境准备

1. 安装依赖

pip install langchain langchain-openai langchain-tavily python-dotenv pydantic requests

2. 配置环境变量(.env 文件)

在项目根目录创建.env文件,填入所需 API 密钥(需提前申请):

# 阿里云通义千问API密钥(灵积平台获取)
DASHSCOPE_API_KEY=your_dashscope_api_key
# OpenWeather天气API密钥(官网免费申请)
OPENWEATHER_API_KEY=your_openweather_api_key

3.openweather官网获取API-KEY

这里需要先登录openweather官网获取API-KEY:https://home.openweathermap.org/ ,然后将其写入.env中的OPENWEATHER_API_KEY变量中。

三、完整实战代码(含详细注释)

from datetime import datetime
from dotenv import load_dotenv
load_dotenv()  # 加载.env环境变量
import os
import requests
import json
from pydantic import SecretStr
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from langchain.tools import tool  # 自定义工具装饰器

# ====================== 1. 初始化大语言模型 ======================
llm = ChatOpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    model="qwen-plus",  # 通义千问增强版
    api_key=SecretStr(os.environ["DASHSCOPE_API_KEY"]),
)

# ====================== 2. 自定义工具开发 ======================
# 工具1:查询即时天气(调用OpenWeather API)
@tool  # 核心装饰器:将普通函数转为LangChain可调用的Tool
def get_weather(loc: str) -> str:
    """
    查询指定城市的即时天气(核心文档字符串,Agent依赖此理解工具功能)
    :param loc: 必要参数,字符串类型,城市英文名称(如北京=Beijing);
    :return: JSON格式的天气信息字符串(包含温度、湿度、天气状况等)。
    """
    # 1. 构建API请求参数
    url = "https://api.openweathermap.org/data/2.5/weather"
    params = {
        "q": loc,
        "appid": os.getenv("OPENWEATHER_API_KEY"),
        "units": "metric",  # 摄氏度(默认华氏度)
        "lang": "zh_cn"     # 中文返回结果
    }
    
    # 2. 发送请求并处理响应
    try:
        response = requests.get(url, params=params)
        response.raise_for_status()  # 捕获HTTP错误(如404/500)
        return json.dumps(response.json(), ensure_ascii=False, indent=2)
    except Exception as e:
        return f"天气查询失败:{str(e)}"

# 工具2:将内容写入本地文件(带时间戳命名)
@tool
def write_file(content: str) -> str:
    """
    将指定内容写入本地文件(自动生成带时间戳的文件名)
    :param content: 必要参数,字符串类型,需写入文件的内容;
    :return: 写入成功/失败的提示信息(含文件绝对路径)。
    """
    try:
        # 生成唯一文件名(避免覆盖)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"weather_{timestamp}.txt"
        
        # 写入文件(指定UTF-8编码,避免中文乱码)
        with open(filename, "w", encoding="utf-8") as f:
            f.write(content)
        
        # 返回绝对路径,方便用户查找
        abs_path = os.path.abspath(filename)
        return f"✅ 文件写入成功:{abs_path}"
    except Exception as e:
        return f"❌ 文件写入失败:{str(e)}"

# ====================== 3. 创建Agent并绑定工具 ======================
agent = create_agent(
    model=llm,                # 核心LLM模型
    tools=[get_weather, write_file],  # 绑定自定义工具列表
    system_prompt="""
    你是专业的天气助手,需按以下规则执行任务:
    1. 查询多个城市天气时,需逐个调用get_weather工具(城市名转英文);
    2. 将所有城市天气信息整理为清晰格式后,调用write_file工具写入本地;
    3. 最终返回文件路径和简要的天气总结。
    """
)

# ====================== 4. 执行Agent并输出结果 ======================
result = agent.invoke({
    "messages": [{"role": "user", "content": "请帮我查询天津、石家庄、上海等地天气,并写入本地文件。"}]
})

# 提取最终回答并打印
final_answer = result['messages'][-1].content
print("Agent执行结果:")
print(final_answer)

四、核心知识点深度解析

1. 自定义 Tool 的核心:@tool装饰器

@tool是 LangChain 将普通 Python 函数转为可被 Agent 调用的工具的核心装饰器,其工作原理是:

  • 解析函数的文档字符串(docstring):Agent 通过这段文字理解工具的功能、参数要求,这是工具能被正确调用的关键;
  • 封装函数入参 / 出参:自动适配 Agent 的调用格式,无需手动处理参数转换;
  • 生成工具标识:为每个工具生成唯一名称(默认是函数名),方便 Agent 选择调用。
文档字符串编写规范(关键!)
@tool
def get_weather(loc: str) -> str:
    """
    查询指定城市的即时天气(工具功能描述)
    :param loc: 必要参数,字符串类型,城市英文名称(如北京=Beijing);(参数说明)
    :return: JSON格式的天气信息字符串;(返回值说明)
    """

⚠️ 注意:文档字符串必须清晰说明参数类型、取值要求、返回格式,否则 Agent 可能传错参数(比如用 “天津” 而非 “Tianjin”)。

2. 天气查询工具(get_weather)核心逻辑

关键步骤:
  1. API 参数配置
    • units="metric":将温度单位从华氏度转为摄氏度(符合中文用户习惯);
    • lang="zh_cn":让返回的天气描述(如 “晴”“多云”)为中文;
    • q=loc:接收城市英文名称(OpenWeather API 要求)。
  2. 异常处理
    • response.raise_for_status()捕获 401(密钥错误)、404(城市不存在)等 HTTP 错误;
    • 外层try-except确保工具不会因异常崩溃,而是返回错误提示(Agent 能识别并调整策略)。
  3. 结果格式化
    • json.dumps(..., ensure_ascii=False, indent=2)让返回的 JSON 字符串带缩进、中文正常显示,方便后续写入文件。

3. 文件写入工具(write_file)核心优化

新手避坑点:
  1. 唯一文件名生成
    • datetime.now().strftime("%Y%m%d_%H%M%S")生成时间戳,避免多次运行覆盖文件;
  2. 编码设置
    • 写入文件时指定encoding="utf-8",解决中文乱码问题(Windows 默认 GBK 编码);
  3. 绝对路径返回
    • os.path.abspath(filename)返回文件绝对路径,用户无需手动找文件位置;
  4. 异常捕获
    • 捕获所有可能的异常(如权限不足、磁盘满),返回友好提示,而非直接抛出错误。

4. Agent 绑定工具与系统提示优化

核心配置:
agent = create_agent(
    model=llm,
    tools=[get_weather, write_file],  # 支持多个工具同时绑定
    system_prompt="""
    你是专业的天气助手,需按以下规则执行任务:
    1. 查询多个城市天气时,需逐个调用get_weather工具(城市名转英文);
    2. 将所有城市天气信息整理为清晰格式后,调用write_file工具写入本地;
    3. 最终返回文件路径和简要的天气总结。
    """
)
系统提示的关键作用:
  • 无约束的系统提示(如 “你是智能助手”)可能导致 Agent 只查询天气但不写入文件,或直接返回原始 JSON 数据;
  • 明确的规则指引(如 “逐个调用工具”“整理格式后写入”)能大幅提升 Agent 的任务完成率。

五、执行效果与结果示例

用户输入:

请帮我查询天津、石家庄、上海等地天气,并写入本地文件。

Agent 执行流程(内部逻辑):

  1. 解析用户需求:需要查询 3 个城市天气 → 写入文件;
  2. 转换城市名称:天津→Tianjin、石家庄→Shijiazhuang、上海→Shanghai;
  3. 逐个调用get_weather工具,获取每个城市的天气数据;
  4. 整理数据为易读格式(如下);
  5. 调用write_file工具写入本地;
  6. 返回最终结果(含文件路径 + 天气总结)。

最终输出示例:

plaintext

Agent执行结果:
✅ 已完成天气查询并写入文件,详情如下:

1. 天津(Tianjin):
{
  "coord": {"lon": 117.2, "lat": 39.13},
  "weather": [{"id": 800, "main": "Clear", "description": "晴", "icon": "01d"}],
  "main": {"temp": 22.5, "feels_like": 22.8, "humidity": 65},
  "name": "Tianjin"
}

2. 石家庄(Shijiazhuang):
{
  "coord": {"lon": 114.48, "lat": 38.03},
  "weather": [{"id": 801, "main": "Clouds", "description": "多云", "icon": "02d"}],
  "main": {"temp": 24.1, "feels_like": 24.5, "humidity": 58},
  "name": "Shijiazhuang"
}

3. 上海(Shanghai):
{
  "coord": {"lon": 121.47, "lat": 31.23},
  "weather": [{"id": 500, "main": "Rain", "description": "小雨", "icon": "10d"}],
  "main": {"temp": 28.3, "feels_like": 30.5, "humidity": 78},
  "name": "Shanghai"
}

📁 天气信息已写入文件:/Users/xxx/weather_20260107_153022.txt

💡 总结:天津晴(22.5℃)、石家庄多云(24.1℃)、上海小雨(28.3℃)。

六、扩展与优化建议

1. 工具增强

  • 参数校验:在get_weather中添加城市名称校验(如判断是否为有效英文名称);
  • 批量查询:优化get_weather支持多城市批量查询,减少 API 调用次数;
  • 结果解析:将原始 JSON 数据解析为自然语言(如 “天津当前温度 22.5℃,晴,湿度 65%”),提升可读性。

2. Agent 能力优化

  • 工具优先级:通过tool_selection参数指定工具调用优先级;
  • 多轮对话:支持用户追问(如 “文件里的上海温度是多少?”);
  • 重试机制:工具调用失败时(如 API 超时),让 Agent 自动重试。

3. 生产环境适配

  • 日志记录:添加日志模块,记录工具调用过程和参数;
  • 权限控制:限制文件写入路径(避免 Agent 写入敏感目录);
  • 性能监控:统计工具调用耗时,优化慢接口(如天气 API)。

总结

  1. LangChain 自定义 Tool 的核心是@tool装饰器 + 清晰的文档字符串,Agent 依赖文档字符串理解工具功能和参数;
  2. 工具开发需注重异常处理用户体验(如唯一文件名、中文编码、绝对路径),避免崩溃或乱码;
  3. 系统提示是 Agent 正确调用工具的关键,需明确任务步骤和规则,而非仅泛化描述。

通过本案例,你不仅能掌握自定义 Tool 的开发方法,还能理解 Agent 如何 “思考” 并调用工具完成复杂任务,为后续开发更复杂的智能体(如数据分析助手、自动化办公机器人)打下基础。

Logo

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

更多推荐