在我最近的博客文章《使用 LangChain 代理创建多模式聊天机器人的开发人员指南》中,讨论了 AI 代理的作用,并演示了使用 LangChain 框架的实现。虽然它适用于概念验证 (POC),但它不适合生产环境。
在这篇文章中,我将提供一种更适合生产级产品的解决方案。你将学习如何创建一个可扩展、高效的系统,该系统更适合实际应用,为你提供构建更强大的 AI 解决方案的工具。
NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - AI模型在线查看 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 - 3D道路快速建模
1、生产环境中 LangChain 代理面临的挑战
LangChain 代理面临的主要挑战是,它们通过一个大型提示将完全控制权授予单个 LLM,该提示管理整个工作流程。在生产环境中,通常需要更精细的控制,尤其是在任务发展时。
那么,我们如何才能最好地将流程划分为更小、更集中的提示,每个提示负责任务的特定部分?我在本文中讨论的这种方法使调试和微调流程中的每个单独组件变得更加容易。此外,没有一个 LLM 可以完美完成每项任务。通常,将流程划分为较小的任务并为每个任务分配最合适的 LLM 会更好,从而优化性能和成本。
2、LangGraph 如何构建可用于生产的系统
这就是 LangGraph 库的作用所在。它提供对代理流程和状态的细粒度控制,这对于构建强大的可用于生产的系统至关重要。LangGraph 通过使用循环图启用有状态、多参与者应用程序来扩展 LangChain,从而更轻松地构建复杂、可靠的代理运行时。
LangGraph 的主要关键功能包括:
- 循环和分支。在您的应用程序中实现循环和条件。在 LangGraph 中,每个节点代表一个 LLM 代理,边缘是这些代理之间的通信渠道。这种结构允许清晰且易于管理的工作流程,其中每个代理执行特定任务并根据需要将信息传递给其他代理。
- 持久状态管理。在图表中的每个步骤之后自动保存状态。可随时暂停和恢复图形执行,以支持错误恢复、人机交互工作流、时间旅行等。
- 人机交互。中断图形执行,并让用户选择批准或编辑代理计划的以下操作。
流式传输支持。流式传输每个节点生成的输出(包括令牌流式传输)。 - 与 LangChain 和 LangSmith 集成:LangGraph 与 LangChain 和 LangSmith 无缝集成(但不需要它们)。
3、我开发了什么?
我构建了一个应用程序,可帮助您规划下一次假期或商务旅行。输入提示,应用程序会获取实时航班和酒店选项,并将其显示在用户友好的网页上。如果需要,您也可以通过电子邮件发送此信息。
你可以在 Github 存储库中找到完整代码。
AI 旅行社使用两个主要工具:
- 与 Google Flights API 交互的工具。
- 与 Google Hotels API 交互的工具。
此外,该应用程序使用 SendGrid API 发送电子邮件。
4、运行应用程序
例如,如果你输入以下提示:
I want to travel to Amsterdam from Madrid from 1 to 7 of October, find me flights and 4-star hotels.
该应用程序根据实时数据提供相关的航班和酒店选项:
你将收到包含徽标和链接的输出,以便于参考。
注意:结果来自 Google Flights 和 Google Hotels API,无意宣传任何特定品牌。
还有一个选项是通过电子邮件发送所有旅行数据。我将在技术部分解释如何实现此功能(提示:它涉及人机交互功能)。
哦,太好了,我把所有的旅行数据都以 HTML 格式显示在一封电子邮件中:
5、代理如何处理旅行请求?
让我们通过几个简单的步骤来分析 AI 代理如何处理用户的旅行请求。假设用户输入以下提示:
“I want to travel to Amsterdam from Madrid from 1 to 7 of October, find me flights and 4-star hotels.”
接下来会发生什么:
1)用户请求发送到 AI (LLM)
请求被发送到支持工具使用的强大语言模型 (LLM)。LLM 识别请求中的两个任务:查找航班和酒店。
2)任务细分
LLM 将请求分解为两个较小的任务:
- 查找航班:系统使用专门设计用于搜索航班的工具。
- 查找酒店:系统还调用一个可帮助查找阿姆斯特丹四星级酒店的工具。
3)激活工具
代理调用这些工具,提供正确的数据(如日期、位置等)作为参数。每个工具都会运行并以结构化格式输出航班和酒店选项。
4)处理结果
再次调用 LLM 来汇总结果并以易于阅读的格式呈现。
5)电子邮件选项
然后为用户提供通过电子邮件发送此信息的选项。如果用户决定通过电子邮件发送,他们会在表单中输入详细信息(如收件人的电子邮件)。
6)电子邮件发送和流程结束
使用之前收集的数据,代理从中断的地方继续。它调用电子邮件发送功能,将信息发送到提供的电子邮件地址。
发送电子邮件后,代理完成其任务,完成流程。
6、如何实现这种类型的代理
首先将图可视化。
使用以下代码生成 Mermaid 编辑器的输入:
print(self.graph.get_graph().draw_mermaid())
要可视化图,请从此代码中获取输出并将其输入到在线 Mermaid 编辑器中。请注意,确切的可视化效果可能会因您使用的 LangGraph 版本而略有不同。
下面的代码片段定义了一个实现代理的类,该类负责使用语言模型(LLM)管理任务和调用工具。
TOOLS = [flights_finder, hotels_finder]
class AgentState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
class Agent:
def __init__(self):
self._tools = {t.name: t for t in TOOLS}
self._tools_llm = ChatOpenAI(model='gpt-4o').bind_tools(TOOLS)
builder = StateGraph(AgentState)
builder.add_node('call_tools_llm', self.call_tools_llm)
builder.add_node('invoke_tools', self.invoke_tools)
builder.add_node('email_sender', self.email_sender)
builder.set_entry_point('call_tools_llm')
builder.add_conditional_edges('call_tools_llm', Agent.exists_action, {'more_tools': 'invoke_tools', 'email_sender': 'email_sender'})
builder.add_edge('invoke_tools', 'call_tools_llm')
builder.add_edge('email_sender', END)
memory = MemorySaver()
self.graph = builder.compile(checkpointer=memory, interrupt_before=['email_sender'])
print(self.graph.get_graph().draw_mermaid())
@staticmethod
def exists_action(state: AgentState):
result = state['messages'][-1]
if len(result.tool_calls) == 0:
return 'email_sender'
return 'more_tools'
def email_sender(self, state: AgentState):
print('Sending email')
email_llm = ChatOpenAI(model='gpt-4o', temperature=0.1) # Instantiate another LLM
email_message = [SystemMessage(content=EMAILS_SYSTEM_PROMPT), HumanMessage(content=state['messages'][-1].content)]
email_response = email_llm.invoke(email_message)
print('Email content:', email_response.content)
message = Mail(from_email=os.environ['FROM_EMAIL'], to_emails=os.environ['TO_EMAIL'], subject=os.environ['EMAIL_SUBJECT'],
html_content=email_response.content)
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(str(e))
def call_tools_llm(self, state: AgentState):
messages = state['messages']
messages = [SystemMessage(content=TOOLS_SYSTEM_PROMPT)] + messages
message = self._tools_llm.invoke(messages)
return {'messages': [message]}
def invoke_tools(self, state: AgentState):
tool_calls = state['messages'][-1].tool_calls
results = []
for t in tool_calls:
print(f'Calling: {t}')
if not t['name'] in self._tools: # check for bad tool name from LLM
print('\n ....bad tool name....')
result = 'bad tool name, retry' # instruct LLM to retry if bad
else:
result = self._tools[t['name']].invoke(t['args'])
results.append(ToolMessage(tool_call_id=t['id'], name=t['name'], content=str(result)))
print('Back to the model!')
return {'messages': results}
7、实现代码的关键概念
让我们分解一下所提供代码的关键概念:
1)工具设置
变量 TOOLS 包含代理可以使用的工具列表,例如 flights_finder 和 hotels_finder。这些工具代表代理可以执行的操作,以协助用户。我在之前的帖子中详细阐述了如何实现此类工具。
2)AgentState
AgentState 是一种以消息对象形式保存代理当前状态的状态。此列表存储代理与用户或工具之间交换的所有通信(消息)。
使用 operator.add 按顺序添加每条消息,这意味着随着对话的进行,新信息将附加到现有消息中。
3)Agent 类
Agent 类通过调用工具、处理用户输入和管理工作流来控制代理的运行方式。它设置了一个 StateGraph,这本质上是任务(或节点)如何连接和执行的蓝图。
4)初始化( __init__
方法)
绑定工具:
- 工具被组织成一个字典,每个工具都可以通过名称访问。
- 代理还将这些工具绑定到语言模型 (LLM),特别是 ChatOpenAI,以便模型可以根据用户输入决定调用哪个工具。
构建 StateGraph:
代理创建一个 StateGraph,它定义了代理将遵循的操作流程。在 LangGraph 术语中,这是一个图,其中代理流程中的每个步骤都由一个节点表示(例如,调用工具、调用它们或发送电子邮件)。
StateGraph 有三个节点:
- call_tools_llm:代理调用 LLM 来根据任务决定使用哪个工具。
- invoke_tools:代理激活所选工具来执行特定任务,例如查找航班或酒店。
- email_sender:代理通过电子邮件将结果发送给用户。
起始节点是 call_tools_llm。
条件边和转换:
图表具有条件边,这意味着它根据代理的当前状态(即消息)决定下一步要做什么。例如,如果需要更多工具,它会移动到invoke_tools节点。如果不需要更多工具,它会转换到email_sender节点。
内存管理:
代理使用Checkpointer(通过MemorySaver)来保存其进度。这允许代理记住其状态并在中断时恢复操作。
8、决策和操作方法:
exists_action 方法:
此方法检查状态中的最新消息以确定下一个操作。如果不再需要工具调用(即消息中没有剩余的工具调用),代理将转换为发送电子邮件。否则,它将继续调用其他工具。在 LangGraph 术语中,此方法充当决策函数,以决定代理下一步应采取哪条路径(边缘)。
email_sender 方法:
此方法处理最后一步,代理发送包含结果的电子邮件。代理实例化另一个 LLM,以帮助根据状态中的最后一条消息起草电子邮件。它使用提示(模板)指导 LLM 生成电子邮件内容。然后使用 SendGridAPIClient 将电子邮件发送给用户。
call_tools_llm 方法:
在此方法中,代理向 LLM 发送消息列表,其中包括系统消息(预定义的提示,指示 LLM 执行的操作)和以前的消息。然后,LLM 返回一条新消息,其中包含有关下一步调用哪个工具的说明。此新消息将添加到状态中。
invoke_tools 方法:
此方法负责根据 LLM 的指令实际调用工具。代理检查状态中的最后一条消息以查找工具调用。它循环遍历这些工具请求,确保工具有效,然后调用相应的工具。工具的结果将作为工具消息返回并附加到状态中。如果请求的工具无效,代理将提示 LLM 重试。
9、主要功能是如何实现的?
持久状态管理:
memory = MemorySaver()
self.graph = builder.compile(checkpointer=memory, interrupt_before=['email_sender'])
代理设计的一个关键部分是它能够记住其最后的状态。这由 MemorySaver 管理,它确保如果代理需要暂停和恢复(例如,在等待用户决定发送电子邮件时),它会从正确的点开始,而无需重新开始。
在生产中可以使用多种检查点选项,例如 Postgres、MongoDB 和 Redis。
在 app.py(处理 UI 代码)中,会为每个会话生成一个唯一的 thread_id,以维护用户交互的上下文。此 thread_id 会随每次对代理的调用一起传递,确保内存状态在请求之间得到保留。
# Create a new thread ID
thread_id = str(uuid.uuid4())
st.session_state.thread_id = thread_id
# Create a message from the user input
messages = [HumanMessage(content=user_input)]
config = {'configurable': {'thread_id': thread_id}}
# Invoke the agent
result = st.session_state.agent.graph.invoke({'messages': messages}, config=config)
人机交互
代理允许在关键决策点进行人为干预:决定是否发送包含收集的旅行信息(航班、酒店等)的电子邮件。这是使用人机交互功能进行管理的,该功能会在发送电子邮件之前暂停代理的执行,让用户查看结果并提供必要的输入。
通过在 graph.compile() 函数中传递interrupt_before=[‘email_sender’] 来实现。
一旦用户决定发送电子邮件并提交数据,以下代码就会在 UI 中运行以完成该过程:
def send_email(sender_email, receiver_email, subject, thread_id):
try:
populate_envs(sender_email, receiver_email, subject)
config = {'configurable': {'thread_id': thread_id}}
st.session_state.agent.graph.invoke(None, config=config)
st.success('Email sent successfully!')
# Clear session state
for key in ['travel_info', 'thread_id']:
if key in st.session_state:
del st.session_state[key]
根据代理状态使用多个 LLM
LangGraph 的主要优势之一是可以灵活地在工作流的不同阶段使用多个 LLM,而不是依赖于单个 LLM 和一个大提示。这允许代理根据当前任务选择最合适的 LLM。例如,您可以使用一个专门用于工具调用和任务处理的 LLM,另一个更适合生成和格式化 HTML 中的电子邮件内容的 LLM。
与 LangChain 和 LangSmith 集成
将 LangChain 集成到您的应用程序中,可以访问其全面的工具套件,用于使用语言模型构建复杂的模块化工作流。通过利用 LangChain 的功能,您可以轻松地将不同的 LLM、工具和工作流合并到代理的功能中。
要与 LangSmith 集成,只需将这些环境变量添加到您的 .env 文件中:
LANGCHAIN_API_KEY=<langchain_api_key>
LANGCHAIN_TRACING_V2=true
LANGCHAIN_PROJECT=<langchain_project_name>
10、AI 旅行代理用例的关键要点
通过将任务分解为更小、更易于管理的组件,LangGraph 可以更轻松地进行调试、在工具和 LLM 集成方面具有灵活性,并包含人机交互。AI 旅行代理示例可帮助用户找到实时航班和酒店选项,展示了 LangGraph 处理复杂工作流程、利用多种工具和提供电子邮件功能的能力。它还突出了 LangGraph 的主要功能,例如持久状态管理、多步骤工作流程以及与 LangChain 和 LangSmith 的无缝集成,使其成为构建强大的 AI 驱动应用程序的强大框架。
原文链接:旅行规划AI代理开发教程 - BimAnt