Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛫 携程 AI 旅行助手(Ctrip AI Travel Assistant)

Python

LangGraph

LangChain

FastAPI

MySQL

License

基于 LangGraph 多 Agent 协同架构 的智能旅行预订系统,支持航班查改退、酒店预订、租车服务、旅行推荐,集成 四合一 RAG 检索管线 实现公司政策精准问答,内置 人机确认安全机制 保障敏感操作可控。


系统架构

                         ┌──────────────────────────┐
                         │       👤 用户对话         │
                         └────────────┬─────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                     🤖 Primary Assistant(主助理)                │
│                   意图识别 → 任务分派 → 对话管理                    │
│                                                                 │
│  工具:  Tavily 联网搜索  │  search_flights  │  lookup_policy     │
│                                                                 │
│  路由:  ToFlightBooking  │  ToHotel  │  ToCarRental  │  ToExcursion │
└──────┬──────────┬──────────┬──────────┬──────────────────────┘
       │          │          │          │
       ▼          ▼          ▼          ▼
┌──────────┐┌──────────┐┌──────────┐┌──────────┐
│ ✈️ 航班   ││ 🏨 酒店   ││ 🚗 租车   ││ 🏝️ 旅行   │
│   助理    ││   助理    ││   助理    ││   助理    │
├──────────┤├──────────┤├──────────┤├──────────┤
│ 搜索航班  ││ 搜索酒店  ││ 搜索租车  ││ 搜索旅行  │
│ 改签     ││ 预订     ││ 预订     ││ 预订     │
│ 退票     ││ 修改     ││ 修改     ││ 修改     │
│          ││ 取消     ││ 取消     ││ 取消     │
└──────────┘└──────────┘└──────────┘└──────────┘
       │          │          │          │
       └──────────┴──────────┴──────────┘
                       │
                  ┌────▼────┐
                  │  主助理  │ ← 子助理完成/升级后自动返回
                  └─────────┘

🌐 点击查看完整系统架构图(建议自行生成最新版本:运行 graph_chat/draw_png.py

此处可放置系统架构全景图片,使用 graph_chat/draw_png.py 生成后替换下方面链接

系统架构图

核心设计理念

设计点 说明
1 主 + 4 子 Agent 主助理负责意图识别与任务路由,4 个子助理各自掌握领域工具完成具体业务
安全/敏感工具分离 只读操作(搜索)直接执行;涉及修改的操作(改签、退票、取消)触发 interrupt_before,需用户确认 y/n
对话状态栈 子助理完成任务或无法处理时通过 CompleteOrEscalate 自动回退到主助理,支持多轮上下文切换
四合一 RAG 公司政策查询采用混合检索 + 父文档映射 + DeepSeek 重排序 + 长上下文重排
联网搜索增强 主助理配备 Tavily 联网搜索,可查询实时信息辅助回答

API 接口设计

所有接口挂载在 /api 前缀下,分为两组:用户管理工作流调用

用户管理

方法 路径 功能 认证
GET /api/users/getUsers/ 获取所有用户列表 需要 Token
GET /api/users/{pk}/ 根据主键 ID 查询单个用户 需要 Token
POST /api/register/ 用户注册(内置用户名重复检查) 白名单通行
POST /api/login/ 用户登录,返回 JWT Token 和用户信息 白名单通行
POST /api/auth/ Swagger 文档中的 OAuth2 认证表单提交 白名单通行
PATCH /api/users/{pk}/ 修改指定用户的信息 需要 Token
POST /api/users/delete/ 根据主键列表批量删除用户 需要 Token

工作流调用

方法 路径 功能 认证
POST /api/graph/ 调用多 Agent 工作流,传入 {user_input, config},返回 AI 回复 需要 Token

请求示例:

POST /api/graph/
{
  "user_input": "帮我查一下从北京飞上海的航班",
  "config": {
    "configurable": {
      "passenger_id": "3442 587242",
      "thread_id": "session-xxx"
    }
  }
}

调用流程:

  1. config 中的 passenger_id 用于查询用户已有机票
  2. graph.stream() 执行 LangGraph 工作流
  3. 返回流式输出的最后一条 AI 消息
  4. 若触发 interrupt_before(敏感操作),返回确认提示,前端/客户端再发 "y" 继续

后端结构详解

ctrip_assistant_backend/
├── api/                   # API 路由层:接口定义 + 参数校验
├── config/                # 配置层:YAML 配置 + 日志配置
├── db/                    # 数据库层:ORM 模型 + 通用 DAO
├── graph_chat/            # 核心引擎:多 Agent 图编排
├── tools/                 # 工具层:Agent 可调用的函数
├── utils/                 # 工具类:JWT / CORS / 中间件 / 密码哈希
├── main.py                # FastAPI 启动入口
├── travel2.sqlite         # 种子数据库(航班/酒店/租车/旅行)
├── travel_new.sqlite      # 运行时数据库(自动生成)
└── order_faq.md           # 公司政策 FAQ(RAG 知识库来源)

1. api/ — API 路由层

负责定义所有的 HTTP 接口和请求/响应数据校验(Pydantic Schema)。

api/
├── __init__.py
├── routers.py              # 路由注册入口,组装所有分路由,挂载到 /api 前缀
├── schemas.py              # 通用 Schema(泛型 CRUD 基类)
│
├── graph_api/              # 工作流接口
│   ├── __init__.py
│   ├── graph_schemas.py    # 请求体 Schema:{user_input, config}
│   └── graph_views.py      # POST /api/graph/ — 调用 graph.stream() 执行工作流
│
└── system_mgt/             # 用户管理接口
    ├── __init__.py
    ├── user_schemas.py     # 用户相关 Schema:注册、登录、查询、修改
    └── user_views.py       # 7 个用户接口(注册/登录/认证/CRUD)

关键文件说明:

  • routers.pyrouter_v1() 创建主路由,通过 include_router 加载用户管理和工作流两个分路由
  • graph_views.py:核心接口,直接 from graph_chat.finally_graph import graph,调用 graph.stream() 执行多 Agent 工作流
  • user_views.py:注册时有用户名查重(409 冲突)、登录返回 JWT、/auth/ 是 Swagger 文档登录入口

2. config/ — 配置层

config/
├── __init__.py             # Dynaconf 配置加载器
├── development.yml         # 开发环境配置
├── production.yml          # 生产环境配置(备选)
└── log_config.py           # 日志配置

关键配置项:

配置项 说明
HOST 127.0.0.1 服务监听地址
PORT 8000 服务端口
DATABASE.DRIVER mysql+pymysql 用户数据用 MySQL
DATABASE.NAME test_db4 数据库名
JWT_SECRET_KEY SHA256 密钥 Token 加密密钥
ACCESS_TOKEN_EXPIRE_MINUTES 30 Token 有效期
WHITE_LIST 登录/注册/docs 等 无需 Token 即可访问的路径
DEFAULT_PASSWORD 123123 新用户默认密码

注意:.env 文件(与 ctrip_assistant_backend 同级)存放 LLM API Key 等敏感信息,由 llm_tavily.pyretriever_advanced.py 通过 load_dotenv 加载。


3. db/ — 数据库层

db/
├── __init__.py             # SQLAlchemy 引擎 + 会话管理 + 公共模型基类
├── dao.py                  # 通用 BaseDAO(增删改查基类)
│
└── system_mgt/             # 用户模块
    ├── __init__.py
    ├── models.py           # t_user 表的 ORM 模型
    └── user_dao.py         # UserDao(继承 BaseDAO,扩展按用户名查询)

说明:

  • 两套数据库:用户认证数据存 MySQL(test_db4),航班/酒店/租车等业务数据存 SQLite(travel_new.sqlite
  • db/init.py
    • 创建 SQLAlchemy enginesessionmaker
    • 定义 DBModelBase 公共基类:自动生成表名(t_+类名)、统一 id/create_time/update_time 字段
  • db/dao.py:泛型 BaseDAO[Model, CreateSchema, UpdateSchema],提供 get / get_by_id / create / update / delete / deletes 通用方法

4. graph_chat/ — 多 Agent 图编排 (核心)

graph_chat/
├── finally_graph.py        # 完整流程图组装与编译(项目入口图)
├── assistant.py            # 主助理定义:提示词 + 工具 + 委派路由
├── agent_assistant.py      # 4 个子助理定义:各自提示词 + 安全/敏感工具
├── build_child_graph.py    # 4 个子工作流图构建
├── entry_node.py           # 子助理入口节点的工厂函数
├── state.py                # 对话状态 State 定义
├── base_data_model.py      # 委派工具定义(ToFlight/ToHotel/ToCar/ToExcursion)
├── llm_tavily.py           # LLM(DeepSeek)+ Tavily 搜索工具初始化
├── log_utils.py            # 日志工具
├── draw_png.py             # 流程图可视化导出
└── graph_gradio.py         # Gradio 演示界面(备选)

4.1 finally_graph.py — 完整流程组装

finally_graph.py 是整个多 Agent 系统的组装入口,主要做以下几件事:

  1. 数据库自检:启动时检查 travel2.sqlite → 自动解压 travel2.zip → 生成 travel_new.sqlite
  2. 节点注册
    • fetch_user_info:启动时先查用户已有航班
    • primary_assistant:主助理节点
    • 4 个子助理节点:update_flight / book_hotel / book_car_rental / book_excursion
    • 各子助理的安全工具节点和敏感工具节点
  3. 路由逻辑:主助理根据工具调用结果,路由到对应子助理入口或工具节点
  4. 编译图builder.compile(checkpointer=memory, interrupt_before=[敏感工具节点]),在敏感操作前暂停等用户确认

4.2 assistant.py — 主助理

assistant.py 定义:

  • CtripAssistant:封装 runnable.invoke() 调用的节点类,带空输出重试机制
  • 主助理提示词:角色是"携程瑞士航空公司客服助理",负责搜索航班信息、查询公司政策、将预订等操作委派给子助理
  • 主助理工具tavily_tool(联网搜索)+ search_flights(航班查询)+ lookup_policy(四合一 RAG 政策检索)
  • 委派路由:通过 Pydantic 工具 ToFlightBookingAssistant / ToHotelBookingAssistant / ToBookCarRental / ToBookExcursion 将任务路由到对应子助理

4.3 agent_assistant.py — 4 个子助理

agent_assistant.py 定义每个子助理的:

子助理 提示词角色 安全工具(只读) 敏感工具(需确认)
航班助理 航班查询、改签和预定 search_flights update_ticket_to_new_flight, cancel_ticket
酒店助理 酒店预订 search_hotels book_hotel, update_hotel, cancel_hotel
租车助理 租车预订 search_car_rentals book_car_rental, update_car_rental, cancel_car_rental
旅行助理 旅行推荐和预订 search_trip_recommendations book_excursion, update_excursion, cancel_excursion

每个助理的 runnableChatPromptTemplate | llm.bind_tools(tools + [CompleteOrEscalate]) 构建。

4.4 build_child_graph.py — 子工作流图

build_child_graph.py 为每个子助理构建独立的 StateGraph:

enter_xxx → xxx_assistant → [路由判断]
                 ├── 纯安全工具 → xxx_safe_tools → 回到 assistant
                 ├── 含敏感工具 → xxx_sensitive_tools → 回到 assistant
                 ├── CompleteOrEscalate → leave_skill → 回到主助理
                 └── END

每个子图的 leave_skill 节点通过 pop_dialog_state 弹出对话栈,自动回到主助理继续对话。

4.5 entry_node.py — 入口节点工厂

entry_node.pycreate_entry_node(assistant_name, new_dialog_state) 是一个工厂函数,生成子助理的入口节点。它创建一条 ToolMessage 告知子助理当前上下文,并设置 dialog_state 标记当前激活的子助理。


5. tools/ — 工具层

tools/
├── __init__.py             # 数据库路径定义
├── tools_handler.py        # 工具节点构建 + 错误回退 + 事件打印
├── flights_tools.py        # 航班工具:查询用户航班 / 搜索 / 改签 / 退票
├── hotels_tools.py         # 酒店工具:搜索 / 预订 / 修改 / 取消
├── car_tools.py            # 租车工具:搜索 / 预订 / 修改 / 取消
├── trip_tools.py           # 旅行推荐工具:搜索 / 预订 / 修改 / 取消
├── retriever_advanced.py   # 四合一 RAG 检索:lookup_policy
├── retriever_vector.py     # 旧版纯向量检索(已被 advanced 替代)
├── location_trans.py       # 地理位置转换
├── init_db.py              # 数据库初始化:从种子库生成运行库
└── llm_tavily.py           # LLM 和 Tavily 初始化(graph_chat 中也有同名文件)

关键工具说明:

  • flights_tools.py:所有航班相关工具,通过 @tool 装饰器注册为 LangChain Tool,直接操作 SQLite
  • tools_handler.py
    • create_tool_node_with_fallback(tools):创建带错误回退的 ToolNode
    • 工具调用失败时自动捕获异常并生成友好的 ToolMessage 反馈给 LLM
  • retriever_advanced.py:四合一 RAG 管线:
    1. 混合检索:BM25 关键词 + BGE 向量 → RRF 融合
    2. 父文档映射:子段落检索 → 映射回完整章节
    3. DeepSeek 重排序:LLM 对候选文档逐条打分(1-10 分)
    4. 长上下文重排序:解决 "Lost in the Middle" 问题

6. utils/ — 工具类

utils/
├── __init__.py
├── cors.py                 # CORS 跨域中间件
├── dependencies.py         # 数据库会话依赖注入 get_db()
├── docs_oauth2.py          # Swagger 文档 OAuth2 认证适配
├── handler_error.py        # 全局异常处理
├── jwt_utils.py            # JWT Token 生成
├── middlewares.py          # Token 验证中间件(核心)
└── password_hash.py        # bcrypt 密码哈希

关键文件说明:

  • middlewares.py
    • 全局 HTTP 中间件:每个请求到达时先执行 verify_token
    • 白名单路径(登录/注册/docs)直接放行
    • 其他路径从 Authorization: Bearer {token} 头提取 Token,用 jose.jwt.decode() 校验
    • 校验成功后把 username 绑定到 request.state.username
  • jwt_utils.pycreate_token(subject) 生成 JWT,payload 包含 {exp, sub},默认 30 分钟过期
  • docs_oauth2.py:重写 OAuth2PasswordBearer,让 Swagger 文档右上角的 "Authorize" 按钮可用,白名单路径不要求认证(避免死循环)
  • password_hash.pyget_hashed_password()verify_password(),使用 bcrypt 算法
  • cors.py:允许前端 localhost:8080 等来源的跨域请求
  • dependencies.pyget_db() 为每个请求创建独立的数据库会话,请求结束自动关闭

快速开始

环境要求

  • Python >= 3.10
  • Conda 虚拟环境 test_env
  • MySQL 数据库 test_db4

1. 激活虚拟环境

conda activate test_env

2. 配置环境变量

ctrip_assistant_backend 的上级目录创建 .env

LLM_MODEL=deepseek-chat
LLM_API_KEY=your_deepseek_api_key
LLM_BASE_URL=https://api.deepseek.com/v1
TAVILY_API_KEY=your_tavily_api_key

3. 配置本地 development.yml

项目提供了脱敏模板 config/development.example.yml,复制后填入真实值:

cd config
copy development.example.yml development.yml

编辑 development.yml,修改以下关键配置:

配置项 说明
DATABASE.PASSWORD MySQL 数据库密码
JWT_SECRET_KEY JWT 签名密钥(自行生成随机字符串)

4. 准备 MySQL 数据库

项目使用 MySQL 存储用户认证数据(需提前安装 MySQL 并启动):

-- 连接 MySQL 后执行
CREATE DATABASE IF NOT EXISTS test_db4 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

首次启动时,程序会自动创建 t_user 表(由 SQLAlchemy ORM 建表)。

5. 启动后端

cd ctrip_assistant_backend
python main.py

后端运行在 http://127.0.0.1:8000,Swagger 文档在 http://127.0.0.1:8000/docs

启动时自动完成数据库初始化(解压 travel2.zip → 生成 travel_new.sqlite)。

6. 启动前端(可选)

⚠️ 注意:前端仅为一个简易 Demo,主要方便参观者快速体验。以下文件可根据需要自行修改:

  • src/views/assistant/AssistantView.vue — 对话界面
  • src/services/graph.ts — API 调用逻辑
  • src/stores/chat.ts — 聊天状态管理
cd ctrip_assistant_fronted
npm install
npm run dev

前端默认运行在 http://localhost:5173(由 Vite 启动)。

7. 通过 Swagger 直接使用

如果不启动前端,也可以直接用 Swagger 文档调试:

  1. 打开 Swagger 文档 http://127.0.0.1:8000/docs
  2. 右上角 "Authorize" 用已注册账号登录
  3. 调用 POST /api/graph/ 与智能助手对话

技术栈

层级 技术
多 Agent 编排 LangGraph(StateGraph + MemorySaver + interrupt_before)
LLM DeepSeek(deepseek-chat
后端框架 FastAPI + JWT 认证 + Swagger / OAuth2
RAG 检索 混合检索(BM25 + BGE 向量)→ RRF 融合 → DeepSeek 重排序 → 长上下文重排
用户数据库 MySQL + SQLAlchemy ORM
业务数据库 SQLite(航班/酒店/租车/旅行)
联网搜索 Tavily Search API
密码加密 bcrypt(passlib)

对话示例

用户: 帮我查一下从北京飞上海的航班
主助理: [调用 search_flights] → 找到 3 个航班,展示给用户

用户: 我要退掉第三张票
主助理: [识别意图 → 委派给航班子助理]
航班子助理: [查询退票政策: lookup_policy] → ⚠ 中断,等待用户确认
系统: "AI助手马上根据你要求,执行相关操作。您是否批准上述操作?输入'y'继续"

用户: y
航班子助理: [执行 cancel_ticket] → "机票已成功取消。"
          → [CompleteOrEscalate] → 回到主助理

用户: 附近有什么推荐的酒店?
主助理: [识别意图 → 委派给酒店子助理]
酒店子助理: [调用 search_hotels] → 展示酒店列表...

About

基于 LangGraph 多智能体架构的携程旅行助手,支持航班查询、酒店预订、租车服务和旅行推荐

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages