[智能体设计模式] 第12章:异常处理与恢复

智能体在真实环境中需应对突发错误(如工具调用失败、服务不可用),异常处理与恢复模式的核心是:通过错误检测、分层处理、恢复机制,确保智能体在故障时不崩溃,保持功能连续性或优雅降级,提升系统可靠性。

核心逻辑

1. 核心组成

  • 错误检测:识别工具调用失败、API 错误(404/500)、数据格式异常等问题。
  • 错误处理:日志记录、重试、备用方案、优雅降级、通知告警。
  • 恢复机制:状态回滚、自我修正、人工升级,将系统恢复至稳定状态。

2. 典型应用场景

  • 客服机器人:数据库不可用时,告知用户并转人工。
  • 交易机器人:处理“资金不足”“市场关闭”等错误,避免重复无效操作。
  • 数据处理智能体:跳过损坏文件,继续批量任务并记录异常。
  • 爬虫智能体:应对验证码、服务器错误,优雅暂停或报告失败。

实战代码示例(LangChain)

以下基于 LangChain 实现健壮的位置查询系统,核心能力:主工具调用失败时自动触发备用方案,最终统一输出结果,全程记录错误日志。

依赖安装

pip install langchain langchain-google-genai python-dotenv requests

创建 .env 文件配置密钥:

GOOGLE_API_KEY=你的 Gemini API 密钥(从 Google AI Studio 获取)

核心代码

"""
LangChain 异常处理与恢复示例:健壮位置查询系统
核心特性:
1. 主工具(精确位置查询)优先执行,失败自动触发备用工具(城市级查询)
2. 全程错误日志记录,支持问题追溯
3. 统一结果输出,失败时给出友好提示
4. 状态管理确保流程衔接顺畅
"""

import logging
from typing import Dict, Any
from dotenv import load_dotenv
from langchain.agents import AgentType, initialize_agent, Tool
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.callbacks.base import BaseCallbackHandler

# --------------------------
# 1. 日志配置:记录错误与流程(便于调试和追溯)
# --------------------------
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("agent_error.log"),  # 错误日志写入文件
        logging.StreamHandler()  # 同时输出到控制台
    ]
)
logger = logging.getLogger("location_agent")

# 加载环境变量
load_dotenv()

# --------------------------
# 2. 自定义异常类:统一管理位置查询相关错误
# --------------------------
class LocationToolError(Exception):
    """位置查询工具专用异常类,区分不同故障场景"""
    pass

# --------------------------
# 3. 位置查询工具实现(模拟真实场景中的工具/API)
# --------------------------
def get_precise_location_info(address: str) -> str:
    """
    主工具:获取精确位置信息(需完整地址)
    功能:返回包含经纬度、详细地址的精确结果
    失败条件:地址缺少街道、门牌号等关键信息
    """
    try:
        # 模拟业务校验:仅接受包含街道关键词的完整地址
        street_keywords = ["街", "路", "巷", "弄", "号"]
        if not any(keyword in address for keyword in street_keywords):
            raise LocationToolError(f"地址 '{address}' 不完整,缺少街道或门牌号信息")
        
        # 模拟成功响应(实际场景中对接地图API)
        return (
            f"精确位置结果:\n"
            f"- 地址:{address}\n"
            f"- 经度:120.123456\n"
            f"- 纬度:30.654321\n"
            f"- 行政区域:XX省XX市XX区"
        )
    except LocationToolError as e:
        # 记录业务错误日志
        logger.error(f"精确位置查询失败:{str(e)}")
        raise  # 抛出异常,让智能体检测
    except Exception as e:
        # 捕获未知错误,统一包装为自定义异常
        logger.error(f"精确位置查询意外错误:{str(e)}")
        raise LocationToolError(f"系统异常:{str(e)}") from e

def get_general_area_info(city: str) -> str:
    """
    备用工具:获取城市级模糊位置信息(容错性更高)
    功能:仅需城市名称,返回大致区域信息
    适用场景:主工具失败时的降级方案
    """
    try:
        # 模拟基础校验:城市名称不为空
        if not city.strip():
            raise LocationToolError("城市名称不能为空")
        
        # 模拟成功响应(实际场景中对接简化版地图API)
        return (
            f"城市级位置结果:\n"
            f"- 城市:{city}\n"
            f"- 经度:120.123\n"
            f"- 纬度:30.654\n"
            f"- 行政区域:XX省{city}市"
        )
    except Exception as e:
        logger.error(f"城市位置查询错误:{str(e)}")
        raise LocationToolError(f"获取城市信息失败:{str(e)}") from e

# --------------------------
# 4. 回调处理器:检测工具错误并管理状态
# --------------------------
class ErrorDetectionCallback(BaseCallbackHandler):
    """
    自定义回调处理器,核心作用:
    1. 监听工具调用失败事件
    2. 维护流程状态(主工具是否失败、查询结果等)
    3. 为后续智能体提供状态数据
    """
    def __init__(self):
        # 初始化状态字典,存储流程关键信息
        self.state: Dict[str, Any] = {
            "primary_failed": False,  # 主工具是否失败
            "location_result": None,  # 最终位置结果
            "original_query": "",     # 用户原始查询
            "extracted_city": ""      # 提取的城市名称
        }
    
    def on_tool_error(self, error: Exception, **kwargs):
        """工具调用失败时触发的回调方法"""
        if isinstance(error, LocationToolError):
            self.state["primary_failed"] = True
            logger.info("主工具调用失败,将触发备用方案")
    
    def reset(self):
        """重置状态(每次处理新查询前调用)"""
        self.state = {
            "primary_failed": False,
            "location_result": None,
            "original_query": "",
            "extracted_city": ""
        }

# --------------------------
# 5. 构建核心智能体(分层设计,各司其职)
# --------------------------
# 初始化 LLM 模型
llm = ChatGoogleGenerativeAI(
    model="gemini-2.0-flash",
    temperature=0.3  # 低温度保证结果稳定性
)

# 初始化状态管理回调
state_callback = ErrorDetectionCallback()

# 5.1 主智能体:尝试精确位置查询
primary_agent = initialize_agent(
    tools=[
        Tool(
            name="get_precise_location_info",
            func=get_precise_location_info,
            description="获取精确位置信息,必须传入包含街道、门牌号的完整地址(示例:上海市浦东新区博云路2号)"
        )
    ],
    llm=llm,
    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    callbacks=[state_callback],  # 绑定状态回调
    agent_kwargs={
        "system_message": """
        你的任务:
        1. 从用户查询中提取完整地址(含街道、门牌号)
        2. 调用 get_precise_location_info 工具查询
        3. 若工具调用成功,将结果存入 state["location_result"]
        4. 若工具调用失败,无需额外操作,直接结束
        """
    }
)

# 5.2 备用智能体:主工具失败时触发
fallback_agent = initialize_agent(
    tools=[
        Tool(
            name="get_general_area_info",
            func=get_general_area_info,
            description="获取城市级模糊位置信息,仅需传入城市名称(示例:杭州市、上海市)"
        )
    ],
    llm=llm,
    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    callbacks=[state_callback],
    agent_kwargs={
        "system_message": """
        你的任务:
        1. 先检查 state["primary_failed"] 是否为 True(主工具是否失败)
        2. 若是:从用户原始查询中提取城市名称,调用 get_general_area_info 工具
        3. 将查询结果存入 state["location_result"]
        4. 若主工具未失败,直接返回空结果,不调用工具
        """
    }
)

# 5.3 结果输出智能体:统一响应格式
response_agent = initialize_agent(
    tools=[],  # 仅处理状态,无需调用工具
    llm=llm,
    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    agent_kwargs={
        "system_message": """
        你的任务:
        1. 检查 state["location_result"] 是否存在且有效
        2. 若有效:用清晰的语言展示位置信息
        3. 若无效:向用户致歉,说明无法获取位置,并建议提供完整地址(含街道、门牌号)
        """
    }
)

# --------------------------
# 6. 主控制流程:串联各智能体,实现异常处理与恢复
# --------------------------
def robust_location_agent(user_query: str) -> str:
    """
    健壮位置查询主函数:
    流程:主工具查询 → 检测失败 → 备用工具查询 → 统一结果输出
    """
    # 重置状态(处理新查询前清空历史数据)
    state_callback.reset()
    state_callback.state["original_query"] = user_query
    logger.info(f"接收用户查询:{user_query}")

    # 第一步:执行主智能体(精确位置查询)
    logger.info("开始执行精确位置查询...")
    try:
        primary_result = primary_agent.run(f"用户查询:{user_query},当前状态:{state_callback.state}")
        if "精确位置结果" in primary_result:
            state_callback.state["location_result"] = primary_result
    except Exception as e:
        # 捕获主智能体执行失败(工具调用失败或其他异常)
        logger.info(f"精确查询执行失败:{str(e)}")
        state_callback.state["primary_failed"] = True

    # 第二步:主工具失败时,执行备用智能体
    if state_callback.state["primary_failed"] and not state_callback.state["location_result"]:
        logger.info("开始执行城市级备用查询...")
        try:
            fallback_result = fallback_agent.run(f"用户查询:{user_query},当前状态:{state_callback.state}")
            if "城市级位置结果" in fallback_result:
                state_callback.state["location_result"] = fallback_result
        except Exception as e:
            logger.error(f"备用查询执行失败:{str(e)}")
            state_callback.state["location_result"] = None

    # 第三步:执行结果输出智能体,返回最终响应
    logger.info("生成最终用户响应...")
    final_response = response_agent.run(f"当前状态:{state_callback.state}")
    return final_response

# --------------------------
# 测试运行:验证不同场景下的异常处理能力
# --------------------------
if __name__ == "__main__":
    print("=== 健壮位置查询智能体测试 ===\n")

    # 测试用例 1:完整地址(主工具成功)
    print("【测试用例 1】输入完整地址")
    query1 = "查询上海市浦东新区张江高科技园区博云路2号的位置"
    print(f"用户输入:{query1}")
    print(f"智能体响应:{robust_location_agent(query1)}\n")

    # 测试用例 2:仅城市名称(主工具失败,触发备用工具)
    print("【测试用例 2】输入仅城市名称")
    query2 = "查询杭州市的位置"
    print(f"用户输入:{query2}")
    print(f"智能体响应:{robust_location_agent(query2)}\n")

    # 测试用例 3:无效地址(主备工具均失败)
    print("【测试用例 3】输入无效地址")
    query3 = "查询火星XXX区域的位置"
    print(f"用户输入:{query3}")
    print(f"智能体响应:{robust_location_agent(query3)}")

核心亮点

  1. 分层容错:主工具优先,失败自动降级至备用工具,避免单点故障。
  2. 状态可控:通过回调处理器统一管理流程状态,确保各智能体衔接顺畅。
  3. 错误可追溯:完整日志记录错误详情,便于后续问题排查。
  4. 用户友好:无论成功失败,均输出统一格式的友好响应,提升体验。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值