在人工智能的世界里,检索增强生成(RAG)系统已经成为处理简单查询并生成上下文相关响应的常用工具。然而,随着对更复杂的人工智能应用需求的增长,需要超越这些检索能力的系统。于是,AI代理应运而生——这些自主实体能够执行复杂的多步骤任务,跨交互保持状态,并动态适应新信息。LangGraph 是 LangChain 库的一个强大扩展,旨在帮助开发人员构建这些高级 AI 代理,通过支持具有循环计算能力的状态化多角色应用程序。
在本文中,我们将探讨 LangGraph 如何改变 AI 开发,并提供一个分步指南,介绍如何使用计算太阳能板节能的示例来构建自己的 AI 代理。该示例将展示 LangGraph 的独特功能如何创建智能、适应性强且适用于现实世界的 AI 系统。
LangGraph 是一个基于 LangChain 构建的高级库,旨在通过引入循环计算能力来增强您的大型语言模型(LLM)应用程序。虽然 LangChain 允许创建用于线性工作流的有向无环图(DAGs),LangGraph 进一步通过支持添加循环来扩展这一功能,这对于开发复杂、类似代理的行为至关重要。这些行为使 LLM 能够不断循环执行一个过程,根据不断变化的条件动态决定下一步该采取什么行动。
Langraph:节点、状态和边。
在 LangGraph 的核心是 状态图 的概念:
LangGraph 通过无缝管理图结构、状态和协调,重新定义了 AI 开发,赋能复杂多角色应用的创建。自动状态管理确保了在交互过程中上下文得以保留,使您的 AI 能够智能地响应不断变化的输入。其简化的代理协调保证了精确执行和高效的信息交换,让您能够专注于打造创新的工作流程,而不是技术细节。LangGraph 的灵活性允许开发定制的高性能应用,而其可扩展性和容错性则确保您的系统在企业级也能保持稳健和可靠。
现在我们已经对 LangGraph 是什么以及它如何增强 AI 开发有了深入的了解,让我们通过一个实际的例子来进一步探讨。在这个场景中,我们将构建一个 AI 代理,用于根据用户的输入计算太阳能板的潜在节能效果。这个代理可以作为太阳能板销售网站上的潜在客户生成工具,与潜在客户互动,提供个性化的节能估算。通过收集关键数据,如每月的电费,这个 AI 代理不仅帮助客户了解太阳能的经济效益,还同时为销售团队筛选出需要跟进的潜在客户。这个例子展示了 LangGraph 在创建智能、动态系统方面的强大功能,这些系统可以自动化复杂的任务并创造商业价值。
我们首先导入该项目所需的所有必要Python库和模块。
from langchain_core.tools import tool from langchain_community.tools.tavily_search import TavilySearchResults from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import Runnable from langchain_aws import ChatBedrock import boto3 from typing import Annotated from typing_extensions import TypedDict from langgraph.graph.message import AnyMessage, add_messages from langchain_core.messages import ToolMessage from langchain_core.runnables import RunnableLambda from langgraph.prebuilt import ToolNode from langgraph.prebuilt import tools_condition
这些导入为使用LangChain、LangGraph和AWS服务构建我们的AI助手奠定了基础。
接下来,我们定义一个工具,该工具将根据用户提供的每月电费计算节能节省量。
@tool def compute_savings(monthly_cost: float) -> float: """ 工具用于根据用户的月度电费计算切换到太阳能后的潜在节省金额。 参数: monthly_cost (float): 用户当前的月度电费。 返回: dict: 包含以下内容的字典: - 'number_of_panels': 需要的太阳能电池板数量的估计值。 - 'installation_cost': 安装成本的估计值。 - 'net_savings_10_years': 安装成本后的10年净节省金额。 """ def calculate_solar_savings(monthly_cost): # 计算假设 cost_per_kWh = 0.28 cost_per_watt = 1.50 sunlight_hours_per_day = 3.5 panel_wattage = 350 system_lifetime_years = 10 # 月度用电量(千瓦时) monthly_consumption_kWh = monthly_cost / cost_per_kWh # 所需系统大小(千瓦) daily_energy_production = monthly_consumption_kWh / 30 system_size_kW = daily_energy_production / sunlight_hours_per_day # 需要的电池板数量和安装成本 number_of_panels = system_size_kW * 1000 / panel_wattage installation_cost = system_size_kW * 1000 * cost_per_watt # 年度和净节省金额 annual_savings = monthly_cost * 12 total_savings_10_years = annual_savings * system_lifetime_years net_savings = total_savings_10_years - installation_cost return { "number_of_panels": round(number_of_panels), "installation_cost": round(installation_cost, 2), "net_savings_10_years": round(net_savings, 2) } # 返回计算的太阳能节省金额 return calculate_solar_savings(monthly_cost)
此函数处理用户的月度电费,并返回太阳能系统效益的详细估算,包括所需太阳能板的数量、安装成本以及十年内的净节省额。为了简化计算,我们在计算中做了一些假设,例如每千瓦时的平均成本和平均日照小时数。然而,在这个AI代理的更高级版本中,我们可以直接从用户那里收集这些信息,使估算更加精确地符合他们的具体情况。
有效的状态管理和错误处理对于构建稳健的AI系统至关重要。在这里,我们定义了一些工具来管理错误并保持对话的状态。
def handle_tool_error(state) -> dict: """ 处理工具执行过程中出现的错误的函数。 Args: state (dict): AI代理的当前状态,包括消息和工具调用详情。 Returns: dict: 包含每个遇到问题的工具的错误消息的字典。 """ # 从当前状态中获取错误 error = state.get("error") # 从状态的消息历史中获取最后一个消息的工具调用 tool_calls = state["messages"][-1].tool_calls # 返回一个包含错误详情的ToolMessage列表,每个消息都与相应的工具调用ID关联 return { "messages": [ ToolMessage( content=f"错误: {repr(error)}\n请修正你的错误。", # 为用户格式化错误消息 tool_call_id=tc["id"], # 将错误消息与相应的工具调用ID关联 ) for tc in tool_calls # 遍历每个工具调用以生成单独的错误消息 ] } def create_tool_node_with_fallback(tools: list) -> dict: """ 创建一个带有错误处理回退机制的工具节点的函数。 Args: tools (list): 要包含在节点中的工具列表。 Returns: dict: 一个在出现错误时使用回退行为的工具节点。 """ # 使用提供的工具创建一个ToolNode,并附加一个回退机制 # 如果发生错误,将调用handle_tool_error函数来处理错误 return ToolNode(tools).with_fallbacks( [RunnableLambda(handle_tool_error)], # 使用lambda函数包装错误处理程序 exception_key="error" # 指定此回退用于处理错误 )
这些功能确保在工具执行过程中遇到的任何错误都能被优雅地处理,并向用户提供有用的反馈。
在这一步中,我们将定义AI代理如何管理其状态(对话的持续上下文),并确保它能够适当地响应用户的输入和工具输出。
为了做到这一点,我们使用Python的TypedDict
创建了一个State
类,以定义将在各个节点之间传递的消息的结构。状态将包含消息,包括来自用户的输入和来自代理或工具的输出。
class State(TypedDict): messages: Annotated[list[AnyMessage], add_messages]
接下来,我们创建 Assistant 类,该类负责运行 AI 代理,与工具交互,并管理对话流程。Assistant 调用工具,确保它们返回适当的结果,并处理执行过程中可能出现的任何重新提示或错误。其核心功能包括调用 Runnable,该过程定义了调用 LLM 和如 compute_savings
这样的工具的方式,然后监控结果。如果代理未能返回有效响应或某个工具没有提供有意义的数据,Assistant 会重新提示用户或请求澄清。它会继续循环调用 Runnable,直到获得有效输出,确保执行顺畅且响应有效。
class Assistant: def __init__(self, runnable: Runnable): # 使用定义与工具交互过程的runnable进行初始化 self.runnable = runnable def __call__(self, state: State): while True: # 使用当前状态(消息和上下文)调用runnable result = self.runnable.invoke(state) # 如果工具未能返回有效输出,提示用户澄清或重试 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", "请给出一个有效的输出。")] state = {**state, "messages": messages} else: # 当获得有效输出时退出循环 break # 处理完runnable后返回最终状态 return {"messages": result}
这种设置对于保持对话的流畅性以及确保助手根据上下文适当回应至关重要。
在这一步骤中,我们使用 AWS Bedrock 配置大型语言模型(LLM),这将为AI助手的语言能力提供支持。AWS Bedrock 允许我们访问高级的 LLM,例如 Anthropic 的 Claude。为了与 AWS 服务交互,你需要配置你的 AWS 凭证。这意味着你需要通过 AWS CLI 或环境变量将 AWS 凭证设置在你的环境中,或者使用一个 AWS SDK 可以访问的凭证文件。如果没有正确的 AWS 配置,助手将无法连接到像 Bedrock 这样的 AWS 服务来运行 LLM。
def 获取_bedrock客户端(region): return boto3.client("bedrock-runtime", region_name=region) def 创建_bedrock_llm(client): return ChatBedrock(model_id='anthropic.claude-3-sonnet-20240229-v1:0', client=client, model_kwargs={'temperature': 0}, region_name='us-east-1') llm = 创建_bedrock_llm(获取_bedrock客户端(region='us-east-1'))
此集成确保助手能够有效解释并回应用户输入。
现在我们已经设置了大语言模型(LLM)和工具,下一步是定义AI助手的工作流程。这包括创建对话模板,指定助手将使用的工具,并配置AI代理如何响应用户输入并触发不同的功能(如计算太阳能节省)。工作流程本质上是控制助手如何与用户互动、收集信息并调用工具以提供结果的逻辑。
工作流的第一部分涉及创建一个提示模板,该模板定义了助手如何与用户进行交流。提示帮助引导AI助手确定向用户提问的内容、如何根据输入进行回应,以及何时触发如compute_savings
这样的工具。
在这种情况下,助手需要询问用户每月的电费以计算太阳能板的节省金额。以下是对话的定义:
primary_assistant_prompt = ChatPromptTemplate.from_messages( [ ( "system", '''你是一个为比利时太阳能板公司提供客户服务的助手。 你需要从他们那里获取以下信息: - 每月的电费 如果无法获取这些信息,请让他们澄清!不要随意猜测。 在获取所有信息后,调用相关工具。 ''', ), ("placeholder", "{messages}"), ] )
**system**
消息 : 这条消息作为AI代理的指导,指示它向用户询问每月的电费,并在信息不清楚时不要进行猜测。助手将不断提示用户,直到收集到所需的数据。
**占位符**
: 这个占位符允许助手动态注入对话中的消息,创建一个持续的对话,在这种对话中,用户的输入会影响下一步的操作。接下来,我们定义助手在交互过程中将使用的工具,主要工具为 compute_savings
,它根据用户的月度电费计算潜在的节省金额。在指定工具列表后,我们使用 llm.bind_tools()
方法将这些工具绑定到助手的工作流程中。这一步确保了AI助手在对话过程中可以访问并触发所需的工具,从而在用户和助手之间创建无缝的交互体验。
# 定义助理将使用的工具 part_1_tools = [ compute_savings ] # 将工具绑定到助理的工作流程 part_1_assistant_runnable = primary_assistant_prompt | llm.bind_tools(part_1_tools)
在这一步骤中,我们使用LangGraph构建AI助手的图结构,该结构控制助手如何处理用户输入、触发工具以及在各个阶段之间切换。图定义了用于核心操作(如调用助手和工具)的节点以及规定这些节点之间流动的边。
设计用于计算太阳能板潜在节能效果的AI代理。
每个 节点 在 LangGraph 中代表一个操作步骤,例如与用户交互或执行工具。我们为这个AI助手定义了两个关键节点:
compute_savings
)来计算用户的太阳能板节省的费用。builder = StateGraph(State) builder.add_node("assistant", Assistant(part_1_assistant_runnable)) builder.add_node("tools", create_tool_node_with_fallback(part_1_tools))
边定义了节点之间流程如何移动。在这里,助手开始对话,然后在收集到所需输入后过渡到工具,并在工具执行完成后返回到助手。
builder.add_edge(START, "assistant") # 从助理开始 builder.add_conditional_edges("assistant", tools_condition) # 在输入后移动到工具 builder.add_edge("tools", "assistant") # 在工具执行后返回到助理
我们使用 MemorySaver 来确保图在不同步骤之间保留对话状态。这使得助手能够记住用户的输入,确保多步骤交互的连续性。
memory = MemorySaver() graph = builder.compile(checkpointer=memory)
最后,你可以通过启动图并开始对话来运行助手。
# 导入uuid模块 import uuid # 让我们创建一个用户可能与助手进行的示例对话 tutorial_questions = [ '嘿', '你能帮我计算我的能源节省吗', "我每月的成本是100美元,我能节省多少" ] # 使用备份文件更新,以便我们可以在每个部分从原始位置重新开始 # shutil.copy(backup_file, db) thread_id = str(uuid.uuid4()) config = { "configurable": { # passenger_id 用于我们的飞行工具来 # 获取用户的飞行信息 # "passenger_id": "3442 587242", # 通过thread_id访问检查点 "thread_id": thread_id, } } _printed = set() for question in tutorial_questions: events = graph.stream( {"messages": ("user", question)}, config, stream_mode="values" ) for event in events: _print_event(event, _printed)
通过以上步骤,您已成功使用LangGraph创建了一个AI助手,该助手可以根据用户输入计算太阳能板的节能效果。本教程展示了LangGraph在管理复杂多步骤流程方面的强大功能,并强调了如何利用高级AI工具高效解决实际问题。无论您是为客服、能源管理或其他应用开发AI代理,LangGraph都提供了实现您的想法所需的灵活性、可扩展性和稳健性。
有兴趣使用 LangGraph Studio 来可视化和测试这个代理吗?请参阅我最近的文章:
使用LangGraph Studio可视化、测试和开发使用LangChain的AI代理的指南。包括设置和……medium.com
关注我,了解更多人工智能的深度探讨!
中等, Instagram, YouTube