探索LangGraph:构建多专家协作模型
探索LangGraph:构建多专家协作模型
探索LangGraph:构建多专家协作模型 探索LangGraph:构建多专家协作模型 Modified May 28, 2024 Code block SQL description="用户关于旅行建议的任何额外信息或请求。" ) class Config: schema extra = { "example": { "location": "卢塞恩", "request": "用户对户外活动和风景感兴趣。", } } 最高级助手执行一般问答,并将专业任务委派给其他助手。 任务委派是一种简单的语义路由/简单的意图检测 llm = ChatAnthropic(model="claude 3 haiku 20240307") llm = ChatAnthropic(model="claude 3 sonnet 20240229", temperature=1) primary assistant prompt = ChatPromptTemplate.from messages( [ ( "system", "您是瑞士航空的乐于助人的客服助手。" "您的主要角色是搜索航班信息和公司政策,以回答客户查询。" "如果客户请求更新或取消预订、租车、预订酒店或获取旅行建议," "通过调用相应的工具,将任务委派给适当的专业助手。您自己无法进行这些类型的更改。" "只有专业助手才有权为用户执行此操作。" "用户不知道不同的专业助手,所以不要提及他们;只需通过功能调用来静静地委派。" "向客户提供详细信息,并在得出信息不可用的结论之前,始终再次检查数据库。" "当搜索时,要坚持不懈。如果第一次搜索没有结果,就扩大您的查询范围。" "\n\n当前用户航班信息:\n<Flights \n{user info}\n</Flights " "\n当前时间:{time}。", ), ("placeholder", "{messages}"), ] ).partial(time=datetime.now()) primary assistant tools = [ TavilySearchResults(max results=1), search flights, lookup policy, ] assistant runnable = primary assistant prompt | llm.bind tools( primary assistant tools + [ ToFlightBookingAssistant, ToBookCarRental, ToHotelBookingAssistant, ToBookExcursion, ] ) 创建助手 我们即将创建图。在前一节中,我们做出了设计决策,让所有节点之间共享messages状态。这在每个委派助手都可以看到整个用户旅程并拥有共享上下文方面非常强大。然而,这意味着较弱的LLMs很容易对它们特定的范围感到困惑。为了标记主助手和委派工作流程之一之间的“交接”(并完成路由器的工具调用),我们将向状态中添加一个ToolMessage。 实用工具 创建一个函数,为每个工作流程制作一个“入口”节点,声明“当前助手是 assistant name”。 Code block SQL from typing import Callable from langchain core.messages import ToolMessage def create entry node(assistant name: str, new dialog state: str) Callable: def entry node(state: State) dict: tool call id = state["messages"][ 1].tool calls[0]["id"] return { "messages": [ ToolMessage( content=f"现在助手是 {assistant name}。回想一下主机助手和用户之间的上述对话。" f" 用户的意图尚未得到满足。使用提供的工具来帮助用户。记住,你是 {assistant name}," " 预订、更新、其他操作或其他动作只有在您成功调用适当的工具后才完成。" " 如果用户改变主意或需要其他任务的帮助,请调用 CompleteOrEscalate 函数,让主机助手接管控制权。" " 不要提及你是谁 只作为助手的代理行事。", tool call id=tool call id, ) ], "dialog state": new dialog state, } return entry node 定义图 现在是我们开始构建图的时候了。和以前一样,我们将从一个节点开始,用用户的当前信息预填充状态。 Code block SQL from typing import Literal from langgraph.checkpoint.sqlite import SqliteSaver from langgraph.graph import END, StateGraph from langgraph.prebuilt import tools condition builder = StateGraph(State) def user info(state: State): return {"user info": fetch user flight information.invoke({})} builder.add node("fetch user info", user info) builder.set entry point("fetch user info") 现在,让我们开始构建我们定制的工作流程。每个小工作流程的结构都和我们在第3部分中展示的完整工作流程图非常相似,它们都包含5个节点: 1. enter : 使用你之前定义的create entry node工具来创建一个ToolMessage,这个ToolMessage表明新的专业助手已经接管了工作。 2. 助手: 这个由提示和大型语言模型(LLM)组成的模块会根据当前状态来决定是使用一个工具、向用户提问还是结束整个工作流程(返回到主助手)。 3. safe tools: 这些是助手可以在不需要用户确认的情况下使用的“只读”工具。 4. sensitive tools: 这些具有“写入”权限的工具需要用户的确认,并且在我们编译工作流程图时,它们会被设置一个interrupt before。 5. leave skill: 通过弹出 dialog state来表示主助手重新掌握了控制权。 由于这些工作流程的相似性,我们本可以定义一个工厂函数来生成它们。但因为这是一个教程,我们会逐一明确地定义它们。 首先,我们来创建一个航班预订助手,它专门负责管理用户更新和取消预订航班的流程。 Code block SQL 航班预订助手 Flight booking assistant builder.add node( "enter update flight", create entry node("Flight Updates & Booking Assistant", "update flight"), ) builder.add node("update flight", Assistant(update flight runnable)) builder.add edge("enter update flight", "update flight") builder.add node( "update flight sensitive tools", create tool node with fallback(update flight sensitive tools), ) builder.add node( "update flight safe tools", create tool node with fallback(update flight safe tools), ) def route update flight( state: State, ) Literal[ "update flight sensitive tools", "update flight safe tools", "leave skill", " end ", ]: route = tools condition(state) if route == END: return END tool calls = state["messages"][ 1].tool calls did cancel = any(tc["name"] == CompleteOrEscalate. name for tc in tool calls) if did cancel: return "leave skill" safe toolnames = [t.name for t in update flight safe tools] if all(tc["name"] in safe toolnames for tc in tool calls): return "update flight safe tools" return "update flight sensitive tools" builder.add edge("update flight sensitive tools", "update flight") builder.add edge("update flight safe tools", "update flight") builder.add conditional edges("update flight", route update flight) This node will be shared for exiting all specialized assistants def pop dialog state(state: State) dict: """Pop the dialog stack and return to the main assistant. This lets the full graph explicitly track the dialog flow and delegate control to specific sub graphs. """ messages = [] if state["messages"][ 1].tool calls: Note: Doesn't currently handle the edge case where the llm performs parallel tool calls messages.append( ToolMessage( content="Resuming dialog with the host assistant. Please reflect on the past conversation and assist the user as needed.", tool call id=state["messages"][ 1].tool calls[0]["id"], ) ) return { "dialog state": "pop", "messages": messages, } builder.add node("leave skill", pop dialog state) builder.add edge("leave skill", "primary assistant") 接下来,创建一个租车助手的工作流程图,它将负责处理所有的租车需求。 Code block SQL 租车助手 Car rental assistant builder.add node( "enter book car rental", create entry node("Car Rental Assistant", "book car rental"), ) builder.add node("book car rental", Assistant(book car rental runnable)) builder.add edge("enter book car rental", "book car rental") builder.add node( "book car rental safe tools", create tool node with fallback(book car rental safe tools), ) builder.add node( "book car rental sensitive tools", create tool node with fallback(book car rental sensitive tools), ) def route book car rental( state: State, ) Literal[ "book car rental safe tools", "book car rental sensitive tools", "leave skill", " end ", ]: route = tools condition(state) if route == END: return END tool calls = state["messages"][ 1].tool calls did cancel = any(tc["name"] == CompleteOrEscalate. name for tc in tool calls) if did cancel: return "leave skill" safe toolnames = [t.name for t in book car rental safe tools] if all(tc["name"] in safe toolnames for tc in tool calls): return "book car rental safe tools" return "book car rental sensitive tools" builder.add edge("book car rental sensitive tools", "book car rental") builder.add edge("book car rental safe tools", "book car rental") builder.add conditional edges("book car rental", route book car rental) 然后,创建一个酒店预订的工作流程。 Code block SQL 酒店预订助手 Hotel booking assistant builder.add node( "enter book hotel", create entry node("Hotel Booking Assistant", "book hotel") ) builder.add node("book hotel", Assistant(book hotel runnable)) builder.add edge("enter book hotel", "book hotel") builder.add node( "book hotel safe tools", create tool node with fallback(book hotel safe tools), ) builder.add node( "book hotel sensitive tools", create tool node with fallback(book hotel sensitive tools), ) def route book hotel( state: State, ) Literal[ "leave skill", "book hotel safe tools", "book hotel sensitive tools", " end " ]: route = tools condition(state) if route == END: return END tool calls = state["messages"][ 1].tool calls did cancel = any(tc["name"] == CompleteOrEscalate. name for tc in tool calls) if did cancel: return "leave skill" 创建助手 我们即将创建图。在前一节中,我们做出了设计决策,让所有节点之间共享messages状态。这在每个委派助手都可以看到整个用户旅程并拥有共享上下文方面非常强大。然而,这意味着较弱的LLMs很容易对它们特定的范围感到困惑。为了标记主助手和委派工作流程之一之间的“交接”(并完成路由器的工具调用),我们将向状态中添加一个ToolMessage。 实用工具 创建一个函数,为每个工作流程制作一个“入口”节点,声明“当前助手是 assistant name”。 定义图 现在是我们开始构建图的时候了。和以前一样,我们将从一个节点开始,用用户的当前信息预填充状态。 现在,让我们开始构建我们定制的工作流程。每个小工作流程的结构都和我们在第3部分中展示的完整工作流程图非常相似,它们都包含5个节点: 1. enter : 使用你之前定义的create entry node工具来创建一个ToolMessage,这个ToolMessage表明新的专业助手已经接管了工作。 2. 助手: 这个由提示和大型语言模型(LLM)组成的模块会根据当前状态来决定是使用一个工具、向用户提问还是结束整个工作流程(返回到主助手)。 3. safe tools: 这些是助手可以在不需要用户确认的情况下使用的“只读”工具。 4. sensitive tools: 这些具有“写入”权限的工具需要用户的确认,并且在我们编译工作流程图时,它们会被设置一个interrupt before。 5. leave skill: 通过弹出 dialog state来表示主助手重新掌握了控制权。 由于这些工作流程的相似性,我们本可以定义一个工厂函数来生成它们。但因为这是一个教程,我们会逐一明确地定义它们。 首先,我们来创建一个航班预订助手,它专门负责管理用户更新和取消预订航班的流程。 接下来,创建一个租车助手的工作流程图,它将负责处理所有的租车需求。 然后,创建一个酒店预订的工作流程。 最后,创建一个主助手。 这里是一个图片链接 对话 那真是很多内容!让我们在下面的对话轮次列表上运行它。这次,我们将有更少的确认。 结论 您现在开发了一个能够处理多种任务的客户支持机器人,它使用了专注的工作流程。更重要的是,您已经学会了如何使用LangGraph的核心功能来设计和根据产品需求重构应用程序。 上述示例并不是针对您的特定需求进行优化的 大型语言模型(LLMs)可能会出错,每个流程都可以通过更好的提示和实验来提高可靠性。一旦您创建了初始支持机器人,下一步就是开始添加评估,这样您就可以自信地改进您的系统。查看那些文档和我们的其他教程,了解更多! ✏️ AI小智 2024 05 27 09:00 湖北 原文地址:https://mp.weixin.qq.com/s/6PWhOWUpT ySJU7UjgVavg AI小智 2024 05 27 09:00 湖北 原文地址:https://mp.weixin.qq.com/s/6PWhOWUpT ySJU7UjgVavg 在之前的部分,我们探讨了如何利用单一提示和大型语言模型(LLM)来处理多样化的用户需求,没看过的同学可以点击链接探索LangGraph:如何创建一个既智能又可控的航空客服AI查阅。 探索LangGraph:如何创建一个既智能又可控的航空客服AI 在之前的部分,我们探讨了如何利用单一提示和大型语言模型(LLM)来处理多样化的用户需求,没看过的同学可以点击链接探索LangGraph:如何创建一个既智能又可控的航空客服AI查阅。 探索LangGraph:如何创建一个既智能又可控的航空客服AI 探索LangGraph:如何创建一个既智能又可控的航空客服AI利用单一提示的方法确实能覆盖很广的应用场景。但是,如果想要为特定的用户需求提供稳定且出色的体验,仅靠这种方法就显得有些力不从心了。 探索LangGraph:如何创建一个既智能又可控的航空客服AI 取而代之的是,我们可以通过识别用户的意图,并将其引导至相应的定制化流程或“技能”,来满足用户的具体需求。每个流程都可以专注于特定的领域,这样不仅可以实现各自领域的优化提升,还不会影响到整体助手的性能。 在本节中,我们将用户交互体验划分为多个子图,形成一个类似下面的结构: 在上图中,每个方框都代表一个具有特定功能的独立工作流程。主要助手负责接收用户的初步询问,然后根据询问内容将任务分配给相应的专家。 状态管理 我们需要跟踪在任何特定时刻哪个子图正在控制交互过程。虽然我们可以通过消息列表上的一些计算来实现这一点,但更简单的方法是使用一个专门的堆栈来跟踪。 在下面的State中添加一个dialog state列表。每当一个node运行并返回dialog state的值时,就会调用update dialog stack函数来决定如何更新堆栈。 助手 这次我们将为每个工作流程创建一个助手。这意味着: 1. 航班预订助手 2. 酒店预订助手 3. 汽车租赁助手 4. 旅行助手 5. 最后,一个“主要助手”来在这些助手之间进行切换 如果你仔细观察,你会发现这实际上是我们在多代理示例中提到的监督者设计模式的一个实例。 下面,定义每个助手的Runnable对象。每个Runnable都有一个提示、LLM以及针对该助手的工具集。每个专门的助手还可以调用CompleteOrEscalate工具,以指示控制权应该交回给主要助手。这可能发生在助手成功完成任务,或者用户改变主意或需要该特定工作流程范围之外的帮助时。 航班预订助手 创建一个专门的助手来处理航班更新和取消预订的任务。 汽车租赁助手 接下来,创建一个汽车租赁助手,以满足所有租车需求。 酒店预订助手 然后定义酒店预订的工作流程。 旅行助手 之后,定义旅行助手。 主要助手 最后,创建主要助手。 之后,定义一个旅行预订助手。