向 state 字典中的 “messages“ 键添加一条新的用户消息,提示模型返回实际的输出。

完整代码:

from datetime import datetime
from langchain_core.runnables import Runnable, RunnableConfig
from langchain_core.prompts import ChatPromptTemplate

primary_assistant_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful customer support assistant for Swiss Airlines. "
            " Use the provided tools to search for flights, company policies, and other information to assist the user's queries. "
            " When searching, be persistent. Expand your query bounds if the first search returns no results. "
            " If a search comes up empty, expand your search before giving up."
            "\n\nCurrent user:\n\n{user_info}\n"
            "\nCurrent time: {time}.",
        ),
        ("placeholder", "{messages}"),
    ]
).partial(time=datetime.now())

tools = [fetch_user_flight_information,search_flights]

assistant_runnable = primary_assistant_prompt | llm.bind_tools(tools)

class Assistant:
    def __init__(self, runnable: Runnable):
        self.runnable = runnable

    def __call__(self, state: State, config: RunnableConfig):
        while True:
            configuration = config.get("configurable", {})
            passenger_id = configuration.get("passenger_id", None)
            state = {**state, "user_info": passenger_id}
            result = self.runnable.invoke(state)
            # If the LLM happens to return an empty response, we will re-prompt it
            # for an actual response.
            if not result.tool_calls and (
                not result.content
                or isinstance(result.content, list)
                and not result.content[0].get("text")
            ):
                messages = state["messages"] + [("user", "Respond with a real output.")]
                state = {**state, "messages": messages}
            else:
                break
        print('\n result======\n',result)
        return {"messages": result}
       

# Define nodes: these do the work
builder.add_node("assistant", Assistant(assistant_runnable))

这段代码是在创建一个用于航空公司客户支持的智能助手。它定义了助手的行为,包括如何处理用户输入、与语言模型(LLM)的交互,以下是对代码的详细解释:

  1. 导入必要的模块和类:

    from datetime import datetime
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.runnables import Runnable, RunnableConfig
    
    • datetime:用于获取当前日期和时间。
    • ChatPromptTemplate:用于创建聊天提示模板,帮助格式化和组织传递给语言模型的提示信息。
    • RunnableRunnableConfig:用于定义可运行的对象和其配置,控制助手的执行行为。
  2. 创建聊天提示模板:

    primary_assistant_prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                "You are a helpful customer support assistant for Swiss Airlines. "
                "Use the provided tools to search for flights, company policies, and other information to assist the user's queries. "
                "When searching, be persistent. Expand your query bounds if the first search returns no results. "
                "If a search comes up empty, expand your search before giving up."
                "\n\nCurrent user:\n\n{user_info}\n"
                "\nCurrent time: {time}.",
            ),
            ("placeholder", "{messages}"),
        ]
    ).partial(time=datetime.now())
    
    • 使用 ChatPromptTemplate.from_messages 方法创建一个聊天提示模板。
    • 第一个元组定义了系统消息,指示助手的角色和行为,包括使用工具搜索航班信息、公司政策等,并在搜索无结果时扩大搜索范围。
    • "{user_info}""{time}" 是占位符,将在实际使用时被替换为用户信息和当前时间。
    • 第二个元组使用占位符 {messages},表示将在此处插入实际的用户和助手之间的对话消息。
    • 使用 .partial(time=datetime.now()) 方法将当前时间部分应用于模板。
  3. 定义助手类:

    class Assistant:
        def __init__(self, runnable: Runnable):
            self.runnable = runnable
    
        def __call__(self, state: State, config: RunnableConfig):
            while True:
                configuration = config.get("configurable", {})
                passenger_id = configuration.get("passenger_id", None)
                state = {**state, "user_info": passenger_id}
                result = self.runnable.invoke(state)
                # If the LLM happens to return an empty response, we will re-prompt it
                # for an actual response.
                if not result.tool_calls and (
                    not result.content
                    or isinstance(result.content, list)
                    and not result.content[0].get("text")
                ):
                    messages = state["messages"] + [("user", "Respond with a real output.")]
                    state = {**state, "messages": messages}
                else:
                    break
            print('\n result======\n', result)
            return {"messages": result}
    
    • 定义一个 Assistant 类,初始化时接受一个 Runnable 对象。
    • __call__ 方法用于处理助手的执行逻辑:
      • 从配置中获取 passenger_id,并将其添加到状态的 user_info 中。
      • 调用 self.runnable.invoke(state) 执行可运行对象,并传入当前状态。
      • 如果语言模型返回空响应,助手会重新提示模型,直到获得有效响应。
      • 打印结果并返回包含消息的字典。
  4. 定义工具和可运行对象:

    tools = [fetch_user_flight_information, search_flights]
    
    assistant_runnable = primary_assistant_prompt | llm.bind_tools(tools)
    
    • tools 列表包含两个工具函数:fetch_user_flight_informationsearch_flights,用于检索用户的航班信息和搜索航班。
    • 使用管道操作符 |primary_assistant_prompt 和绑定了工具的语言模型(llm.bind_tools(tools))组合成一个可运行对象 assistant_runnable
  5. 添加助手节点:

    builder.add_node("assistant", Assistant(assistant_runnable))
    
    • 使用 builder.add_node 方法将助手节点添加到构建器中,节点名称为 "assistant",对应的可运行对象为 Assistant(assistant_runnable)

示例说明:

假设用户请求查询从苏黎世到纽约的航班信息,助手的处理流程如下:

  1. 初始化助手:

    assistant = Assistant(assistant_runnable)
    
  2. 设置状态和配置:

    state = {"messages": [("user", "请帮我查询从苏黎世到纽约的航班信息。")]}
    config = {"configurable": {"passenger_id": "12345"}}
    
  3. 调用助手:

    response = assistant(state, config)
    
  4. 助手执行流程:

    • 获取用户信息: 从配置中获取 passenger_id,并将其添加到状态的 user_info 中。
    • 生成提示: 使用 primary_assistant_prompt 生成包含用户信息和当前时间的提示。
    • 调用语言模型: 使用绑定了工具的语言模型处理提示,检索航班信息。
    • 处理响应: 如果语言模型返回空响应,助手会重新提示模型,直到获得有效响应。
    • 返回结果: 返回包含助手回复的消息。

通过上述步骤,助手能够根据用户的请求,使用提供的工具检索相关的航班信息,并在必要时调整搜索范围,以确保为用户提供准确且有用的支持。

messages = state["messages"] + [("user", "Respond with a real output.")]
state = {**state, "messages": messages}

这段代码的作用是向 state 字典中的 "messages" 键添加一条新的用户消息,提示模型返回实际的输出。具体操作如下:

  1. 添加新消息:

    messages = state["messages"] + [("user", "Respond with a real output.")]
    
    • state["messages"]:获取当前状态中 "messages" 键对应的列表。
    • [("user", "Respond with a real output.")]:创建一个包含新消息的列表,表示用户发送了一条内容为 “Respond with a real output.” 的消息。
    • state["messages"] + [...]:将现有的消息列表与新消息列表连接,生成一个新的列表,包含所有消息。
  2. 更新 state 字典:

    state = {**state, "messages": messages}
    
    • {**state, "messages": messages}:使用字典解包的方式创建一个新的字典,其中包含原有的 state 键值对,但 "messages" 键的值被更新为新的 messages 列表。

数值举例说明:

假设初始的 state 字典如下:

state = {
    "messages": [
        ("user", "请帮我查询从苏黎世到纽约的航班信息。"),
        ("assistant", "好的,请稍等,我正在为您查询。")
    ],
    "user_info": "12345"
}

执行上述代码后,state 字典将更新为:

state = {
    "messages": [
        ("user", "请帮我查询从苏黎世到纽约的航班信息。"),
        ("assistant", "好的,请稍等,我正在为您查询。"),
        ("user", "Respond with a real output.")
    ],
    "user_info": "12345"
}

在这个示例中,"messages" 列表中新增了一条用户消息,内容为 “Respond with a real output.”。这通常用于在模型未能返回有效响应时,提示模型生成实际的输出。


两个函数:handle_tool_errorcreate_tool_node_with_fallback
以下是对每个函数的详细解释:

1. handle_tool_error 函数

功能:

该函数用于处理工具执行过程中的错误,将错误信息格式化为消息,并将其添加到聊天记录中。

参数:

  • state:一个包含当前工具状态的字典,其中包括错误信息和工具调用记录。

返回值:

  • 返回一个字典,包含一个 ToolMessage 对象的列表,其中包含错误信息。

详细解释:

  • 首先,从 state 字典中获取键为 "error" 的值,即当前的错误信息。

  • 然后,获取 state 字典中 "messages" 列表的最后一个元素的 tool_calls 属性,即最近的工具调用记录。

  • 接下来,返回一个字典,其中包含一个 "messages" 键,其值是一个 ToolMessage 对象的列表。每个 ToolMessage 对象的 content 属性包含格式化的错误信息,并附加提示让用户修正错误;tool_call_id 属性对应工具调用的 ID。

示例:

假设 state 如下:

state = {
    "error": "FileNotFoundError: 'data.csv' not found",
    "messages": [
        {
            "tool_calls": [{"id": "12345"}]
        }
    ]
}

调用 handle_tool_error(state) 将返回:

{
    "messages": [
        ToolMessage(
            content="Error: FileNotFoundError: 'data.csv' not found\n please fix your mistakes.",
            tool_call_id="12345"
        )
    ]
}

2. create_tool_node_with_fallback 函数

功能:

该函数创建一个具有回退错误处理功能的 ToolNode 对象。

参数:

  • tools:一个工具列表,将包含在 ToolNode 中。

返回值:

  • 返回一个配置了回退错误处理的 ToolNode 对象。

详细解释:

  • 首先,创建一个包含指定工具的 ToolNode 对象。

  • 然后,使用 with_fallbacks 方法为该 ToolNode 配置回退函数,以处理在工具执行过程中可能发生的错误。这里,回退函数是通过 RunnableLambda 包装的 handle_tool_error 函数。

  • exception_key="error" 参数指定在发生异常时,将错误信息存储在状态字典的 "error" 键中。

示例:

假设有一个工具列表:

tools = ["tool_a", "tool_b"]

调用 create_tool_node_with_fallback(tools) 将返回一个配置了回退错误处理的 ToolNode 对象。当工具执行过程中发生错误时,handle_tool_error 函数将被调用,以处理并记录错误信息。

这两个函数的组合使用确保了在工具执行过程中发生错误时,系统能够捕获并处理这些错误,将其记录为消息,并添加到聊天记录中,以便用户了解并进行相应的修正。

你可能感兴趣的:(langgraph,langgraph,tools,Agent)