如何优雅地处理LangChain工具调用中的错误
在使用LangChain和聊天模型时,调用工具通常比纯提示更加可靠,但仍然存在一些挑战。本指南将指导您在链中实现错误处理,以减少这些失败模式带来的影响。
引言
LangChain在调用工具时提供了许多优势,但并不完美。有时模型可能会尝试调用不存在的工具,或者无法返回匹配请求模式的参数。通过保持模式简单、减少传递工具的数量以及良好的命名和描述,可以部分缓解这些问题。本文旨在介绍如何在LangChain中处理工具调用错误。
主要内容
1. 环境设置
首先,我们需要安装必要的包:
%pip install --upgrade --quiet langchain-core langchain-openai
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_with_tools = llm.bind_tools([complex_tool])
# 定义链
chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool
3. 错误处理
在调用链时,可能会出现参数缺失等问题。我们可以使用 try/except 来更优雅地处理这些错误:
from typing import Any
from langchain_core.runnables import Runnable, RunnableConfig
def try_except_tool(tool_args: dict, config: RunnableConfig) -> Runnable:
try:
complex_tool.invoke(tool_args, config=config)
except Exception as e:
return f"调用工具时出错:\n\n{tool_args}\n\n错误信息:\n\n{type(e)}: {e}"
# 使用try/except处理的链
chain = llm_with_tools | (lambda msg: msg.tool_calls[0]["args"]) | try_except_tool
print(
chain.invoke(
"使用复杂工具。参数为5, 2.1, 空字典。不要忘记dict_arg"
)
)
4. 备用模型
当工具调用出错时,可以尝试使用备用模型:
better_model = ChatOpenAI(model="gpt-4-1106-preview", temperature=0).bind_tools([complex_tool], tool_choice="complex_tool")
better_chain = better_model | (lambda msg: msg.tool_calls[0]["args"]) | complex_tool
chain_with_fallback = chain.with_fallbacks([better_chain])
chain_with_fallback.invoke(
"使用复杂工具。参数为5, 2.1, 空字典。不要忘记dict_arg"
)
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")
self_correcting_chain.invoke(
{
"input": "使用复杂工具。参数为5, 2.1, 空字典。不要忘记dict_arg"
}
)
常见问题和解决方案
- 工具调用失败:确保传递给工具的参数正确无误。
- 备用模型选择:根据需求选择合适的备用模型以提高工具调用的成功率。
总结和进一步学习资源
本指南展示了如何在LangChain中处理工具调用错误。您可以进一步了解以下概念:
- 使用工具的Few shot提示
- 工具调用的流式处理
- 向工具传递运行时值
- 使用模型获取结构化输出
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---