欢迎光临
我们一直在努力

零基础学AI大模型之LangChain Tool异常处理

大家好,我是工藤学编程 🦉一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉 C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷 【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案
分库分表 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
消息队列 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK)
AI大模型 零基础学AI大模型之LLM绑定Tool工具实战

前情摘要

1、零基础学AI大模型之读懂AI大模型 2、零基础学AI大模型之从0到1调用大模型API 3、零基础学AI大模型之SpringAI 4、零基础学AI大模型之AI大模型常见概念 5、零基础学AI大模型之大模型私有化部署全指南 6、零基础学AI大模型之AI大模型可视化界面 7、零基础学AI大模型之LangChain 8、零基础学AI大模型之LangChain六大核心模块与大模型IO交互链路 9、零基础学AI大模型之Prompt提示词工程 10、零基础学AI大模型之LangChain-PromptTemplate 11、零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战 12、零基础学AI大模型之LangChain链 13、零基础学AI大模型之Stream流式输出实战 14、零基础学AI大模型之LangChain Output Parser 15、零基础学AI大模型之解析器PydanticOutputParser 16、零基础学AI大模型之大模型的“幻觉” 17、零基础学AI大模型之RAG技术 18、零基础学AI大模型之RAG系统链路解析与Document Loaders多案例实战 19、零基础学AI大模型之LangChain PyPDFLoader实战与PDF图片提取全解析 20、零基础学AI大模型之LangChain WebBaseLoader与Docx2txtLoader实战 21、零基础学AI大模型之RAG系统链路构建:文档切割转换全解析 22、零基础学AI大模型之LangChain 文本分割器实战:CharacterTextSplitter 与 RecursiveCharacterTextSplitter 全解析 23、零基础学AI大模型之Embedding与LLM大模型对比全解析 24、零基础学AI大模型之LangChain Embedding框架全解析 25、零基础学AI大模型之嵌入模型性能优化 26、零基础学AI大模型之向量数据库介绍与技术选型思考 27、零基础学AI大模型之Milvus向量数据库全解析 28、零基础学AI大模型之Milvus核心:分区-分片-段结构全解+最佳实践 29、零基础学AI大模型之Milvus部署架构选型+Linux实战:Docker一键部署+WebUI使用 30、零基础学AI大模型之Milvus实战:Attu可视化安装+Python整合全案例 31、零基础学AI大模型之Milvus索引实战 32、零基础学AI大模型之Milvus DML实战 33、零基础学AI大模型之Milvus向量Search查询综合案例实战 33、零基础学AI大模型之新版LangChain向量数据库VectorStore设计全解析 34、零基础学AI大模型之相似度Search与MMR最大边界相关搜索实战 35、零基础学AI大模型之LangChain整合Milvus:新增与删除数据实战 36、零基础学AI大模型之LangChain+Milvus实战:相似性搜索与MMR多样化检索全解析 37、零基础学AI大模型之LangChain Retriever 38、零基础学AI大模型之MultiQueryRetriever多查询检索全解析 39、零基础学AI大模型之LangChain核心:Runnable接口底层实现 40、零基础学AI大模型之RunnablePassthrough 41、零基础学AI大模型之RunnableParallel 42、零基础学AI大模型之RunnableLambda 43、零基础学AI大模型之RunnableBranch 44、零基础学AI大模型之Agent智能体 45、零基础学AI大模型之LangChain Tool工具 46、零基础学AI大模型之LLM绑定Tool工具实战


本文章目录

    • 前情摘要
  • 零基础学AI大模型之LangChain Tool异常处理
    • 一、 工具调用也会“掉链子”:不处理异常,智能体就“罢工”
    • 二、 ToolException:给工具错误“定规矩”的关键
    • 三、 三种异常处理方式:从“简单兜底”到“自定义降级”
      • 方式一:自动处理(handle_tool_error=True)——最简单的“兜底”
        • 代码示例:
        • 输出结果:
        • 适用场景:
      • 方式二:固定错误信息(handle_tool_error="提示文本")——给用户“说人话”
        • 代码示例:
        • 输出结果:
        • 适用场景:
      • 方式三:自定义处理函数——灵活“降级”,智能应对
        • 代码示例:
        • 输出结果:
        • 适用场景:
    • 四、 实战:给天气查询工具加“全链路异常防护”
      • 4.1 完整代码(带详细注释)
      • 4.2 运行结果(模拟三种异常)
      • 4.3 关键亮点:
    • 五、 生产环境最佳实践:异常处理的“三要素”
    • 六、 小结:异常处理是智能体“成熟度”的试金石

零基础学AI大模型之LangChain Tool异常处理

一、 工具调用也会“掉链子”:不处理异常,智能体就“罢工”

在这里插入图片描述

之前我们学了怎么给大模型绑定Tool工具,让它能查天气、做计算、调API——但实际用起来会发现,工具调用就像人干活一样,难免“掉链子”:

  • 查天气时网络突然断了,API没响应;
  • 调用股票接口时,密钥过期导致权限不足;
  • 用户输入的城市名是错的(比如“北上广”),参数不合法;
  • 免费API每天限100次,调用超了就被限流。

这些问题如果不处理,后果很糟:

  • 程序直接崩了:一行错误堆栈甩给用户,谁看得懂?
  • 智能体卡壳了:不知道该重试还是换工具,任务直接卡住;
  • 用户体验崩了:本来想查天气,结果看到“503 Service Unavailable”,直接劝退。

就像开车没装安全气囊,遇到突发情况就容易出大问题。而LangChain的ToolException,就是给工具装“安全气囊”——让智能体遇到错误时,能优雅处理、友好反馈,甚至自动恢复。

二、 ToolException:给工具错误“定规矩”的关键

在这里插入图片描述

ToolException是LangChain专门用来处理工具调用异常的类,核心作用就两个:

  • 统一错误格式:不管是网络错、权限错还是参数错,都转成智能体能看懂的标准格式;
  • 传递关键信息:把“哪个工具错了”“为什么错了”这些上下文传给智能体,让它知道该怎么处理(重试?换工具?还是提示用户?)。
  • 简单说,ToolException就像给各种混乱的错误“统一发了身份证”,智能体拿着这张身份证,就知道该怎么应对了。

    三、 三种异常处理方式:从“简单兜底”到“自定义降级”

    LangChain提供了三种处理工具异常的方式,从简单到灵活,覆盖不同场景,我们一个个实战学:

    方式一:自动处理(handle_tool_error=True)——最简单的“兜底”

    只需在定义工具时加个handle_tool_error=True,工具就会自动捕获异常,并返回标准化的错误信息(包含异常原因),不用自己写额外代码。

    代码示例:

    from langchain_core.tools import StructuredTool, ToolException

    # 1. 定义一个可能出错的工具(模拟搜索失败)
    def search(query: str) > str:
    """执行搜索查询,返回结果"""
    # 模拟异常:比如搜索结果为空、网络超时
    raise ToolException(f"搜索失败:未找到'{query}'的相关结果(可能网络超时)")

    # 2. 创建工具时开启自动异常处理
    search_tool = StructuredTool.from_function(
    func=search,
    name="SearchTool",
    description="用于搜索信息的工具",
    handle_tool_error=True # 关键:自动处理异常
    )

    # 3. 调用工具(故意触发异常)
    try:
    result = search_tool.invoke({"query": "不存在的关键词12345"})
    print("工具返回结果:", result)
    except Exception as e:
    # 注意:开启handle_tool_error后,不会走到这里,异常已被工具内部处理
    print("捕获到异常:", e)

    输出结果:

    工具返回结果: SearchTool tool failed with error: SearchTool: 搜索失败:未找到'不存在的关键词12345'的相关结果(可能网络超时)

    适用场景:

    快速开发、不需要自定义错误信息的场景,让工具自己搞定异常。

    方式二:固定错误信息(handle_tool_error=“提示文本”)——给用户“说人话”

    如果觉得自动生成的错误信息太技术化,可以用handle_tool_error直接指定一句友好的提示(比如“网络有点卡,换个关键词试试?”),让用户更容易理解。

    代码示例:

    from langchain_core.tools import StructuredTool, ToolException

    def weather_query(city: str) > str:
    """查询指定城市的天气"""
    # 模拟异常:城市名不合法(比如“火星市”)
    if city not in ["北京", "上海", "广州"]:
    raise ToolException(f"无效城市:{city}(不在支持的城市列表中)")
    return f"{city}今天晴,25℃"

    # 创建工具时指定固定错误提示
    weather_tool = StructuredTool.from_function(
    func=weather_query,
    name="WeatherTool",
    description="查询天气的工具,参数为城市名",
    handle_tool_error="抱歉,暂时查不到这个城市的天气~ 试试北京、上海或广州吧!" # 自定义友好提示
    )

    # 调用工具(传入无效城市)
    result = weather_tool.invoke({"city": "火星市"})
    print("工具返回结果:", result)

    输出结果:

    工具返回结果: 抱歉,暂时查不到这个城市的天气~ 试试北京、上海或广州吧!

    适用场景:

    需要给用户友好反馈的场景,隐藏技术细节,只说用户能懂的话。

    方式三:自定义处理函数——灵活“降级”,智能应对

    如果想更灵活(比如记录错误日志、自动重试、切换备用工具),可以定义一个异常处理函数,让它根据错误类型做不同操作——这是生产环境最常用的方式。

    代码示例:

    from langchain_core.tools import StructuredTool, ToolException
    import time

    # 1. 定义可能出错的工具(模拟API调用次数超限)
    def stock_query(code: str) > str:
    """查询股票价格,参数为股票代码(如600036)"""
    # 模拟异常:每日调用次数超限
    raise ToolException(f"股票查询失败:{code},今日调用次数已达上限")

    # 2. 定义自定义异常处理函数(核心)
    def handle_stock_error(error: ToolException) > str:
    """
    处理股票查询工具的异常
    1. 记录错误日志(实际项目中可写入文件或日志系统)
    2. 根据错误类型返回降级方案
    """

    # 记录错误(模拟日志)
    error_msg = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 错误:{str(error)}"
    print("【错误日志】", error_msg)

    # 根据错误内容返回不同的降级提示
    if "调用次数已达上限" in str(error):
    return "今日股票查询次数已用完~ 明天再试吧,或查看大盘指数替代"
    else:
    return f"查询失败:{str(error)},请检查股票代码是否正确"

    # 3. 创建工具时绑定自定义处理函数
    stock_tool = StructuredTool.from_function(
    func=stock_query,
    name="StockTool",
    description="查询股票价格的工具",
    handle_tool_error=handle_stock_error # 绑定自定义函数
    )

    # 4. 调用工具(触发次数超限异常)
    result = stock_tool.invoke({"code": "600036"})
    print("工具返回结果:", result)

    输出结果:

    【错误日志】 [2025-11-07 15:30:00] 错误:StockTool: 股票查询失败:600036,今日调用次数已达上限
    工具返回结果: 今日股票查询次数已用完~ 明天再试吧,或查看大盘指数替代

    适用场景:

    复杂业务场景,需要根据错误类型做精细化处理(日志、重试、降级方案等)。

    四、 实战:给天气查询工具加“全链路异常防护”

    在这里插入图片描述

    结合之前学的天气查询工具,我们来做一个实战——给它加上完整的异常处理,应对“网络超时”“城市不存在”“API密钥过期”三种常见错误。

    4.1 完整代码(带详细注释)

    import requests
    from langchain_core.tools import StructuredTool, ToolException
    from pydantic import BaseModel, Field

    # 1. 定义参数模型(校验城市名格式)
    class WeatherInput(BaseModel):
    city: str = Field(description="城市名称,如北京、上海")

    # 2. 定义天气查询工具(可能抛出多种异常)
    def get_weather(city: str) > str:
    """调用天气API查询实时天气"""
    # 模拟API密钥(实际项目中用环境变量存储)
    api_key = "无效的密钥" # 故意用无效密钥模拟权限错误

    # 异常1:城市名格式错误(非中文)
    if not all('\\u4e00' <= c <= '\\u9fff' for c in city):
    raise ToolException(f"参数错误:城市名'{city}'必须是中文(如北京)")

    # 调用天气API(模拟)
    try:
    url = f"https://api.weather.com/{city}?key={api_key}"
    response = requests.get(url, timeout=5) # 超时5秒

    # 异常2:API返回错误(如密钥无效)
    if response.status_code != 200:
    raise ToolException(f"API错误:状态码{response.status_code}(可能密钥过期)")

    # 正常返回天气(模拟)
    return f"{city}实时天气:晴,22℃,微风"

    # 异常3:网络超时
    except requests.exceptions.Timeout:
    raise ToolException(f"网络超时:查询'{city}'天气时连接超时,请检查网络")

    # 3. 定义自定义异常处理函数(全链路防护)
    def handle_weather_error(error: ToolException) > str:
    """根据不同错误类型返回处理方案"""
    error_str = str(error)
    # 处理参数错误
    if "参数错误" in error_str:
    return f"输入有误:{error_str.split(':')[1]},请重新输入中文城市名~"
    # 处理网络超时
    elif "网络超时" in error_str:
    return "网络有点慢呢~ 请稍后再试,或换个城市查询"
    # 处理API错误(如密钥问题)
    elif "API错误" in error_str:
    return "系统暂时无法查询天气,工程师正在抢修中,抱歉啦~"
    # 其他未知错误
    else:
    return "查询遇到小问题,请稍后重试~"

    # 4. 创建带异常处理的工具
    weather_tool = StructuredTool.from_function(
    func=get_weather,
    name="WeatherTool",
    description="查询中文城市的实时天气",
    args_schema=WeatherInput, # 绑定参数模型
    handle_tool_error=handle_weather_error # 绑定异常处理函数
    )

    # 5. 测试三种异常场景
    print("=== 测试1:城市名非中文 ===")
    print(weather_tool.invoke({"city": "beijing"}))

    print("\\n=== 测试2:网络超时(模拟) ===")
    # (代码中已模拟超时,实际可通过断网测试)
    print(weather_tool.invoke({"city": "北京"}))

    print("\\n=== 测试3:API密钥无效 ===")
    print(weather_tool.invoke({"city": "上海"}))

    4.2 运行结果(模拟三种异常)

    === 测试1:城市名非中文 ===
    输入有误:城市名'beijing'必须是中文(如北京),请重新输入中文城市名~

    === 测试2:网络超时(模拟) ===
    网络有点慢呢~ 请稍后再试,或换个城市查询

    === 测试3:API密钥无效 ===
    系统暂时无法查询天气,工程师正在抢修中,抱歉啦~

    4.3 关键亮点:

  • 分层异常捕获:从参数校验、网络请求到API响应,全链路覆盖;
  • 用户友好提示:不同错误返回不同的引导话术,避免技术术语;
  • 可扩展性:后续新增错误类型(如“城市未开通服务”),只需在处理函数里加分支。
  • 五、 生产环境最佳实践:异常处理的“三要素”

    在这里插入图片描述

    在实际项目中,处理工具异常不能只靠ToolException,还要结合这三个要点:

  • 日志要全:异常发生时,记录“哪个工具、什么参数、什么时间、错误详情”,方便排查(比如用logging模块写入日志文件);
  • 降级要柔:不能直接报错,要给用户可操作的替代方案(比如“查不了实时天气,要不要看明天的预报?”);
  • 智能重试:对网络超时等临时错误,可在处理函数里自动重试1-2次(比如用tenacity库实现重试逻辑)。
  • 六、 小结:异常处理是智能体“成熟度”的试金石

    这篇我们学了LangChain Tool工具的异常处理——用ToolException统一捕获错误,通过三种方式(自动处理、固定提示、自定义函数)实现兜底降级,让智能体在工具“掉链子”时也能优雅应对。

    核心就是一句话:好的智能体不仅要“会干活”,更要“会处理麻烦”。就像优秀的员工,不仅能完成任务,遇到问题还能想办法解决,而不是直接摆烂。

    结合之前学的Agent,我们还能让智能体根据错误自动调整策略(比如天气API超时了,自动切换备用数据源),这就是更高级的“容错Agent”。

    如果本文对你有帮助,欢迎点赞+关注+收藏🌟 ,有任何问题或实战需求,欢迎在评论区留言交流~ 我是工藤学编程,陪你从零到一玩转AI大模型!🚀

    赞(0)
    未经允许不得转载:171主机测评 » 零基础学AI大模型之LangChain Tool异常处理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址