生产级AI智能体开发实践【旅行规划】

在我最近的博客文章《使用 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901873.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——15.C++11(1)

1. 自动类型推导 (auto) C11 引入了 auto 关键字&#xff0c;可以根据初始值的类型自动推导变量的类型&#xff0c;从而减少了手动声明类型的繁琐。例如&#xff1a; std::vector<int> vec {1, 2, 3, 4}; auto it vec.begin(); // 自动推导类型为 std::vector<in…

C语言程序设计:现代设计方法习题笔记《chapter5》下篇

第七题 题目分析&#xff1a;求最大最小值转换为条件判断问题&#xff0c;最大值有四种可能&#xff0c;最小值相应有三种情况&#xff0c;给出下列代码。 示例代码&#xff1a; #include <stdio.h>int main() {int num1, num2, num3, num4; // 定义四个变量来存储输入…

【项目实战】HuggingFace教程,初步实战,使用HF做一些小型任务

Huggingface教程 一、前期准备工作二、学习pipline2.1.试运行代码&#xff0c;使用HuggingFace下载模型2.2. 例子1&#xff0c;情感检测分析(只有积极和消极两个状态)2.3. 例子2&#xff0c;文本生成 三、学会使用Tokenizer & Model3.1.tokenizer&#xff08;分词器&#x…

Lampiao靶机入侵实战

07-Lampiao靶机入侵实战 一、扫描采集信息 1、获取IP地址 nmap -sn 192.168.81.0/24获得IP地址为&#xff1a;192.168.81.1282、获取端口信息 由于nmap默认情况下只扫描常用的1000个端口&#xff0c;覆盖面并不全&#xff0c;所以建议全端口扫描 nmap -p 1-65535 192.168.…

JSON格式及jackson.jar包的安装与配置

目录 为什么会出现JSON? JSON格式 jackson的jar文件下载与配置 jackson的简单使用 读取json格式 将现有对象转换成json序列 为什么会出现JSON? 在JSON出现前&#xff0c;由于多种编程语言的语法细节都不是完全相同&#xff0c;在网络传输信息时无法使用同一的格式&…

高效集成:YS采购订单与帆软MongoDB的对接实践

高效集成&#xff1a;YS采购订单与帆软MongoDB的对接实践 YS采购订单对接帆软MongoDB&#xff1a;用友BIP数据集成案例分享 在企业信息化系统中&#xff0c;数据的高效流动和处理是实现业务智能化的关键。本文将聚焦于一个具体的系统对接集成案例——YS采购订单对接帆软MongoD…

sqli-labs靶场安装以及刷题记录-docker

sqli-labs靶场安装以及刷题记录-docker sqli-labs靶场安装-dockersqli-labs靶场刷题less-1 单引号less-2 数字型less-3 单引号括号less-4 双引号括号less-5 单引号布尔盲注less-6 双引号布尔盲注less-7 单引号加括号、输出到文件less-8 单引号布尔盲注less-9 单引号时间盲注les…

Ollama+Open WebUI,windows部署一个本地AI

在Ollama官网下载&#xff0c;点击DownLoad 下载完之后进行安装&#xff0c;配置环境变量&#xff0c;完成后打开CMD命令行工具测试 运行并下载模型 之后选择Open WebUI作为图形化界面 &#x1f680; Getting Started | Open WebUI 运行Docker命令 docker run -d -p 3000:80…

ArcGIS002:软件自定义设置

摘要&#xff1a;本文详细介绍安装arcgis10.2后软件自定义设置内容&#xff0c;包括工具条的启用、扩展模块的启用、如何加载项管理器、快捷键设置、样式管理器的使用以及软件常规设置。 一、工具条的启用 依次点击菜单栏【自定义】->【工具条】&#xff0c;根据工作需求勾…

07 设计模式-结构型模式-桥接模式

桥接&#xff08;Bridge&#xff09;是用于把抽象化与实现化解耦&#xff0c;使得二者可以独立变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 这种模式涉及到一个作为桥接的接口&#xff0c;使得…

背包九讲——二维费用背包问题

目录 二维费用背包问题 问题描述&#xff1a; 解决方法&#xff1a; 方法一&#xff1a; 代码实现&#xff1a; 方法二&#xff1a; 代码实现&#xff1a; 背包问题第五讲——二维费用背包问题 背包问题是一类经典的组合优化问题&#xff0c;通常涉及在限定容量的背包中…

gateway 整合 spring security oauth2

微服务分布式认证授权方案 在分布式授权系统中&#xff0c;授权服务要独立成一个模块做统一授权&#xff0c;无论客户端是浏览器&#xff0c;app或者第三方&#xff0c;都会在授权服务中获取权限&#xff0c;并通过网关访问资源 OAuth2的四种授权模式 授权码模式 授权服务器将授…

CentOS 7镜像下载

新版本系统镜像下载&#xff08;当前最新是CentOS 7.4版本&#xff09; CentOS官网 官网地址 http://isoredirect.centos.org/centos/7.4.1708/isos/x86_64/ http://mirror.centos.org/centos/7/isos/ 国内的华为云&#xff0c;超级快&#xff1a;https://mirrors.huaweiclou…

Linux TCP CC状态机

万字详文&#xff1a;TCP 拥塞控制详解 - 知乎bcc/tools/tcpcong.py at master iovisor/bccbcc/tools/tcpcong_example.txt at master iovisor/bcc 1.状态机 2.tcp map

认识类与对象(上)

目录 何为类&#xff0c;何为对象? 一.对于类 1.idea修改文件类名 二.对于对象 三.this关键字 1.区分成员变量和局部变量 2.引用当前对象 3.调用当前对象的其他构造方法 4.总结 四.构造方法 1.利用idea特性快速写出构造方法 五.封装 1.利用idea特性快速写出set和…

鸿蒙网络编程系列32-基于拦截器的性能监控示例

1. 拦截器简介 在Web开发中拦截器是一种非常有用的模式&#xff0c;它允许开发者在请求发送到服务器之前或响应返回给客户端之前执行一些预处理或后处理操作。这种机制特别适用于需要对所有网络请求或响应进行统一处理的情况&#xff0c;比如添加全局错误处理、请求头的修改、…

【深度学习】【OpenVINO】【C++】模型转化、环境搭建以及模型部署的详细教程

【深度学习】【OpenVINO】【C】模型转化、环境搭建以及模型部署的详细教程 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【OpenVINO】【C】模型转化、环境搭建以及模型部署的详细教程前言模型转换--pytorch转onnxWindows平台搭建…

我们可以用微服务创建状态机吗?

大家好&#xff0c;我是锋哥。今天分享关于【我们可以用微服务创建状态机吗&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 我们可以用微服务创建状态机吗&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 是的&#xff0c;微服务架构可…

为什么选择 Spring data hadoop

&#x1f449; 请点赞支持这款 全新设计的脚手架 &#xff0c;让 Java 再次伟大&#xff01; spring-data-hadoop hbase 常见的操作方式有以下三种&#xff1a; Native Api 原生 api 操作繁琐&#xff0c;就像用 JDBC 操作关系型数据库一样&#xff0c;类似 flush、submit、…

Windows系统启动MongoDB报错无法连接服务器

文章目录 发现问题解决办法 发现问题 1&#xff09;、先是发现执行 mongo 命令&#xff0c;启动报错&#xff1a; error: MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017&#xff1b; 2&#xff09;、再检查 MongoDB 进程 tasklist | findstr mongo 发现没有进程&a…