探索LangGraph:如何创建一个既智能又可控的航空客服AI

news2024/11/25 4:31:27

这种设计既保持了用户控制权,又确保了对话流程的顺畅。但随着工具数量的增加,单一的图结构可能会变得过于复杂。我们将在下一节中解决这个问题。

第三部分的图将类似于下面的示意图:

第三部分示意图

状态定义

首先,定义图的状态。我们的状态和LLM调用与第二部分相同

python
复制代码
from typing import Annotated

from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import Runnable, RunnableConfig
from typing_extensions import TypedDict

from langgraph.graph.message import AnyMessage, add_messages


class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]
    user_info: str


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

    def __call__(self, state: State, config: RunnableConfig):
        while True:
            result = self.runnable.invoke(state)
            # 如果LLM碰巧返回了一个空响应,我们将重新提示它
            # 以获得一个实际的响应。
            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}
                messages = state["messages"] + [("user", "请给出真实的输出。")]
                state = {**state, "messages": messages}
            else:
                break
        return {"messages": result}


# Haiku更快更便宜,但准确性较低
# llm = ChatAnthropic(model="claude-3-haiku-20240307")
llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=1)
# 你可以更新LLMs,尽管你可能需要更新提示
# from langchain_openai import ChatOpenAI

# llm = ChatOpenAI(model="gpt-4-turbo-preview")

assistant提示 = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "你是一位乐于助人的瑞士航空客户支持助手。"
            " 使用提供的工具搜索航班、公司政策和其他信息以协助用户的查询。"
            " 当搜索时,要坚持不懈。如果第一次搜索没有结果,扩大你的查询范围。"
            " 如果搜索空手而归,请在放弃之前扩大你的搜索。"
            "\n\n当前用户:\n<User>\n{user_info}\n</User>"
            "\n当前时间:{time}。",
        ),
        ("placeholder", "{messages}"),
    ]
).partial(time=datetime.now())


# "阅读"仅工具(例如检索器)不需要用户确认即可使用
part_3_safe_tools = [
    TavilySearchResults(max_results=1),
    fetch_user_flight_information,
    search_flights,
    lookup_policy,
    search_car_rentals,
    search_hotels,
    search_trip_recommendations,
]

# 这些工具都改变了用户的预订。
# 用户有权控制做出什么决定
part_3_sensitive_tools = [
    update_ticket_to_new_flight,
    cancel_ticket,
    book_car_rental,
    update_car_rental,
    cancel_car_rental,
    book_hotel,
    update_hotel,
    cancel_hotel,
    book_excursion,
    update_excursion,
    cancel_excursion,
]
sensitive_tool_names = {t.name for t in part_3_sensitive_tools}
# 我们的LLM不需要知道它必须路由到哪个节点。在它的"思维"中,它只是在调用函数。
part_3_assistant_runnable = assistant_prompt | llm.bind_tools(
    part_3_safe_tools + part_3_sensitive_tools
)

图的定义

现在,创建图。我们的图与第二部分几乎相同,只是我们将工具分为了两个不同的节点。我们只在实际更改用户预订的工具之前进行中断。

python
复制代码
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({})}


# 新增:fetch_user_info节点首先运行,这意味着我们的助手可以在
# 不需要采取行动的情况下看到用户的航班信息
builder.add_node("fetch_user_info", user_info)
builder.set_entry_point("fetch_user_info")
builder.add_node("assistant", Assistant(part_3_assistant_runnable))
builder.add_node("safe_tools", create_tool_node_with_fallback(part_3_safe_tools))
builder.add_node(
    "sensitive_tools", create_tool_node_with_fallback(part_3_sensitive_tools)
)
# 定义逻辑
builder.add_edge("fetch_user_info", "assistant")


def route_tools(state: State) -> Literal["safe_tools", "sensitive_tools", "__end__"]:
    next_node = tools_condition(state)
    # 如果没有调用工具,返回用户
    if next_node == END:
        return END
    ai_message = state["messages"][-1]
    # 这假设是单个工具调用。要处理并行工具调用,你将想要
    # 使用ANY条件
    first_tool_call = ai_message.tool_calls[0]
    if first_tool_call["name"] in sensitive_tool_names:
        return "sensitive_tools"
    return "safe_tools"


builder.add_conditional_edges(
    "assistant",
    route_tools,
)
builder.add_edge("safe_tools", "assistant")
builder.add_edge("sensitive_tools", "assistant")

memory = SqliteSaver.from_conn_string(":memory:")
part_3_graph = builder.compile(
    checkpointer=memory,
    # 新增:图将在执行"tools"节点之前始终停止。
    # 用户可以在助手继续之前批准或拒绝(甚至更改请求)
    interrupt_before=["sensitive_tools"],
)

示例对话

接下来,让我们尝试新修订的聊天机器人!我们将在以下对话列表上运行它。这次,我们将减少确认的次数。

python
复制代码
import shutil
import uuid

# 使用备份文件更新,以便我们可以从每个部分的原始位置重新启动
shutil.copy(backup_file, db)
thread_id = str(uuid.uuid4())

config = {
    "configurable": {
        # passenger_id在我们的航班工具中使用
        # 以获取用户的航班信息
        "passenger_id": "3442 587242",
        # 通过thread_id访问检查点
        "thread_id": thread_id,
    }
}

tutorial_questions = [
    "嗨,我的航班是什么时候?",
    "我可以更新我的航班到更早的时间吗?我想今天晚些时候离开。",
    "那就更新到下周的某个时间",
    "下一个可用的选项很好",
    "关于住宿和交通呢?",
    "是的,我想要一个负担得起的酒店,用于我为期一周的住宿(7天)。我还想要租一辆车。",
    "好的,可以为你推荐的酒店预订吗?听起来不错。",
    "是的,继续预订任何中等费用且有可用性的酒店。",
    "现在对于汽车,我的选择是什么?",
    "太棒了,我们只需要最便宜的选项。继续预订7天",
    "好的,现在你对旅行有什么建议?",
    "在我在那里的时候,它们可用吗?",
    "有趣 - 我喜欢博物馆,有什么选择?",
    "好的,选一个并在我到达的第二天为我预订。",
]


_printed = set()
# 我们可以重用第一部分的教程问题,看看它的表现如何。
for question in tutorial_questions:
    events = part_3_graph.stream(
        {"messages": ("user", question)}, config, stream_mode="values"
    )
    for event in events:
        _print_event(event, _printed)
    snapshot = part_3_graph.get_state(config)
    while snapshot.next:
        # 我们有中断!代理试图使用工具,用户可以批准或拒绝它
        # 注意:此代码都在图之外。通常,你会将输出流到UI。
        # 然后,当用户提供输入时,你会通过API调用触发新的运行。
        user_input = input(
            "你是否批准上述操作?输入'y'继续;"
            " 否则,请说明你请求的更改。\n\n"
        )
        if user_input.strip() == "y":
            # 只是继续
            result = part_3_graph.invoke(
                None,
                config,
            )
        else:
            # 通过提供有关请求更改/改变主意的说明
            # 满足工具调用
            result = part_3_graph.invoke(
                {
                    "messages": [
                        ToolMessage(
                            tool_call_id=event["messages"][-1].tool_calls[0]["id"],
                            content=f"API调用被用户拒绝。理由:'{user_input}'。继续协助,考虑用户的输入。",
                        )
                    ]
                },
                config,
            )
        snapshot = part_3_graph.get_state(config)

第三部分回顾

现在,我们的聊天机器人工作得很好,你可以通过LangSmith跟踪来检查它的最新运行情况。这个设计可能已经满足了你的需求。代码是封闭的,并且它的行为符合预期。

然而,这个设计的一个潜在问题是,它对单个提示施加了很大压力。如果我们想要添加更多工具,或者每个工具变得更加复杂,那么机器人使用工具的效率和整体行为可能会受到影响。

如何系统的去学习大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓

在这里插入图片描述

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

  • 目标:了解AI大模型的基本概念、发展历程和核心原理。
  • 内容
    • L1.1 人工智能简述与大模型起源
    • L1.2 大模型与通用人工智能
    • L1.3 GPT模型的发展历程
    • L1.4 模型工程
      - L1.4.1 知识大模型
      - L1.4.2 生产大模型
      - L1.4.3 模型工程方法论
      - L1.4.4 模型工程实践
    • L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

  • 目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
  • 内容
    • L2.1 API接口
      - L2.1.1 OpenAI API接口
      - L2.1.2 Python接口接入
      - L2.1.3 BOT工具类框架
      - L2.1.4 代码示例
    • L2.2 Prompt框架
      - L2.2.1 什么是Prompt
      - L2.2.2 Prompt框架应用现状
      - L2.2.3 基于GPTAS的Prompt框架
      - L2.2.4 Prompt框架与Thought
      - L2.2.5 Prompt框架与提示词
    • L2.3 流水线工程
      - L2.3.1 流水线工程的概念
      - L2.3.2 流水线工程的优点
      - L2.3.3 流水线工程的应用
    • L2.4 总结与展望

阶段3:AI大模型应用架构实践

  • 目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
  • 内容
    • L3.1 Agent模型框架
      - L3.1.1 Agent模型框架的设计理念
      - L3.1.2 Agent模型框架的核心组件
      - L3.1.3 Agent模型框架的实现细节
    • L3.2 MetaGPT
      - L3.2.1 MetaGPT的基本概念
      - L3.2.2 MetaGPT的工作原理
      - L3.2.3 MetaGPT的应用场景
    • L3.3 ChatGLM
      - L3.3.1 ChatGLM的特点
      - L3.3.2 ChatGLM的开发环境
      - L3.3.3 ChatGLM的使用示例
    • L3.4 LLAMA
      - L3.4.1 LLAMA的特点
      - L3.4.2 LLAMA的开发环境
      - L3.4.3 LLAMA的使用示例
    • L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

  • 目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
  • 内容
    • L4.1 模型私有化部署概述
    • L4.2 模型私有化部署的关键技术
    • L4.3 模型私有化部署的实施步骤
    • L4.4 模型私有化部署的应用场景

学习计划:

  • 阶段1:1-2个月,建立AI大模型的基础知识体系。
  • 阶段2:2-3个月,专注于API应用开发能力的提升。
  • 阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。
  • 阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HCIA第二天复习上

延长传输距离-------中继器&#xff08;放大器&#xff09;------物理层设备 可以延长5倍传输距离 增加网络节点数量 网络拓扑结构 1直线型拓扑 信息安全性差 网络延迟高传输速度慢 2环形拓扑 3星型拓扑 4网状型拓扑 传输效率高&#xff0c;…

RISC-V压缩指令扩展测试

概述 RISC-V定义了压缩指令扩展&#xff08;compressed instruction-set extension &#xff09;&#xff0c;命名为“C”扩展。压缩指令使用16位宽指令替换32位宽指令&#xff0c;从而减少代码量。这个C扩展可运用在RV32、RV64和RV128指令集上&#xff0c;通常使用“RVC”来表…

继承初级入门复习

注意&#xff1a;保护和私有在类中没有区别&#xff0c;但是在继承中有区别&#xff0c;private在继承的子类不可见&#xff0c;protect在继承的子类可见 记忆方法&#xff1a;先看基类的修饰符是private&#xff0c;那都是不可见的。如果不是&#xff0c;那就用继承的修饰和基…

变量命名的艺术:让你的代码更具可读性

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;为何变量命名如此重要&#xff1f; 二、变量命名的基本规则 1. 避免数…

NL6621 实现获取天气情况

一、主要完成的工作 1、建立TASK INT32 main(VOID) {/* system Init */SystemInit();OSTaskCreate(TestAppMain, NULL, &sAppStartTaskStack[NST_APP_START_TASK_STK_SIZE -1], NST_APP_TASK_START_PRIO); OSStart();return 1; } 2、application test task VOID TestAp…

弱监督语义分割-对CAM的生成过程进行改进3

三、擦除图像高响应部分以获取更多的分割领域 ECS-Net: Improving Weakly Supervised Semantic Segmentation by Using Connections Between Class Activation Maps&#xff08;ICCV,2021&#xff09; 1.引言 我们首先从图像中擦除高响应区域&#xff0c;并生成这些擦除图像…

数据防泄露解决方案分享

在当今高度数字化和互联的商业环境中&#xff0c;数据防泄密已成为企业保护财产、维护客户隐私和遵守合规要求的重要一环。数据防泄密不仅关乎企业的经济利益&#xff0c;更涉及用户个人信息安全、商业机密保护以及国家安全等核心问题。能做好数据防泄露&#xff0c;对于提升企…

【简单介绍下爬山算法】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

AIGC:AI整活!万物皆可建筑设计

在过去的一年里 AI设计爆火 各行业纷纷将之用于工作中 同时不少网友也在借助它整活 万物皆可设计 甲方骂我方案像屎一样 于是我就回馈他屎一样的方案 他有点惊喜&#xff0c;但是没话 不是吧&#xff0c;随便找了个充电头图片 也能生成建筑设计&#xff01;这都能行 鸟…

【EasyX】快速入门——消息处理,音频

1.消息处理 我们先看看什么是消息 1.1.获取消息 想要获取消息,就必须学会getmessage函数 1.1.1.getmessage函数 有两个重载版本,它们的作用是一样的 参数filter可以筛选我们需要的消息类型 我们看看参数filter的取值 当然我们可以使用位运算组合这些值 例如,我们…

React-router 最佳实践

使用的是 BrowserRouter&#xff0c;Routes 和 Route&#xff0c;这是 react-router-dom v5 和 v6 都支持的 API。这种方式的优点是路由配置和应用的其它部分是紧密集成的&#xff0c;这使得路由配置更加直观和易于理解 // router/index.js import { BrowserRouter as Router,…

使用 Docker 部署 Jenkins 并设置初始管理员密码

使用 Docker 部署 Jenkins 并设置初始管理员密码 每一次开始&#xff0c;我都特别的认真与胆怯&#xff0c;是因为我期待结局&#xff0c;也能够不会那么粗糙&#xff0c;不会让我失望&#xff0c;所以&#xff0c;就多了些思考&#xff0c;多了些拘束&#xff0c;所以&#xf…

基于YOLO系列算法(YOLOv5、YOLOv6、YOLOv8以及YOLOv9)和Streamlit框架的行人头盔检测系统

摘要 本文基于最新的基于深度学习的目标检测算法 (YOLOv5、YOLOv6、YOLOv8)以及YOLOv9) 对头盔数据集进行训练与验证&#xff0c;得到了最好的模型权重文件。使用Streamlit框架来搭建交互式Web应用界面&#xff0c;可以在网页端实现模型对图像、视频和实时摄像头的目标检测功能…

Error:(6, 43) java: 程序包org.springframework.data.redis.core不存在

目录 一、在做SpringBoot整合Redis的项目时&#xff0c;报错&#xff1a; 二、尝试 三、解决办法 一、在做SpringBoot整合Redis的项目时&#xff0c;报错&#xff1a; 二、尝试 给依赖加版本号&#xff0c;并且把版本换了个遍&#xff0c;也不行&#xff0c;也去update过ma…

基于springboot+vue的在线考试系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

web自动化之PO模式

PO模式 1、为什么需要PO思想&#xff1f; 首先我们观察和思考一下&#xff0c;目前我们写的作业脚本的问题&#xff1a; 元素定位和操作动 作写到一起了&#xff0c;这就就会用导致一个问题&#xff1a; UI的页面元素比较容易变化的&#xff0c;所以元素定位和脚本操作写到一…

【Sync FIFO介绍及基于Verilog的实现】

Sync FIFO介绍及实现 1 Intro2 Achieve2.1 DFD2.2 Intf2.3 Module 本篇博客介绍无论是编码过程中经常用到的逻辑–FIFO&#xff1b;该FIFO是基于单时钟下的同步FIFO&#xff1b; FiFO分类&#xff1a;同步FiFO VS 异步FiFO&#xff1b; 1 Intro FIFO可以自己实现&#xff0c;但…

如何安全地进行隔离网数据导出,提升文件流转效率?

隔离网&#xff08;也称为隔离区或DMZ&#xff0c;即Demilitarized Zone&#xff09;是一种网络安全措施&#xff0c;用于将内部网络与外部网络&#xff08;如互联网&#xff09;隔离开来&#xff0c;以减少安全风险。隔离网数据导出通常需要采取一些特殊的安全措施来确保数据的…

pod介绍之 容器分类与重启策略

目录 一 pod 基础概念介绍 1&#xff0c;pod 是什么 2&#xff0c;Pod使用方式 3&#xff0c;如何解决一个pod 多容器通信 4&#xff0c;pod 组成 5&#xff0c; k8s 中的 pod 二 pause容器 1&#xff0c;pause容器 是什么 2&#xff0c;pause容器作用 3&#xff…

【嵌入式Linux】Cmake、makefile、Cmakelist

记录嵌入式 linux环境下的编译方式 测试之前确保你的 Ubuntu 机器上安装了Gcc和cmake 1. 编译有以下几种方式 在 Linux系统下&#xff0c;编译一个 .c文件可以有以下几种方式&#xff1a; 直接用 Gcc 编译器编译为可执行文件编写Makefile文件&#xff0c;使用 make 指令&…