导语:欢迎开启课程第三周的挑战!在经历了第一周的“单兵作战”和第二周的“团队协同”之后,我们将在本周完成一次“集团军”级别的综合项目实战。我们的目标是构建一个名为 “旅小智”(TripGenius) 的 AI 旅行规划智能体。这不仅仅是一个后台运行的脚本,而是一个完整的、拥有前端用户界面、后端 API 服务、以及复杂多智能体内核的全栈应用。本章作为本周的开篇,我们将扮演“首席架构师”的角色,从零开始,设计“旅小智”的宏观系统架构。我们将定义它的愿景、角色、技术栈,并绘制出系统各组件之间交互的蓝图。一份清晰、健壮的架构设计,是项目成功的一半。
目录
- 项目愿景:人人都能拥有的“私人旅行定制师”
- 痛点分析:传统旅行规划的繁琐与信息过载
- “旅小智”的核心价值:提供个性化、端到端的旅行规划与预订服务
- 技术栈选型:构建一个现代化的 AI 应用
- 前端(Frontend):
Streamlit- 快速构建数据驱动的 Web UI - 后端(Backend):
FastAPI- 高性能的 Python API 框架 - 智能体内核(Agent Core):
LangGraph- 编排我们的多智能体团队 - 容器化(Containerization):
Docker- 实现标准化的打包与部署
- 前端(Frontend):
- 系统宏观架构:前后端分离与智能内核
- 三层架构:用户界面层、业务逻辑层、智能体核心层
- Mermaid 图:可视化“旅小智”的系统架构
- 数据流:一次完整的用户请求是如何在三层之间流动的?
- 智能体团队设计:定义“旅小智”的多角色 Agent
- 团队角色:
TravelPlanner(旅行规划师 - 主管): 团队的核心大脑,负责与用户沟通、分解任务、调度其他专家。CityExpert(城市攻略专家): 负责搜索和推荐目的地城市的景点、美食、文化活动。HotelExpert(酒店预订专家): 负责根据预算和偏好搜索和筛选酒店。FlightExpert(机票预订专家): 负责搜索和比较机票信息。ItineraryGenerator(行程生成器): 负责将所有信息整合成一份详细的、每日的行程单。
- 协作模式:一个以
TravelPlanner为中心的、动态的、层级化的协作网络。
- 团队角色:
- LangGraph 图设计:为 AI 团队绘制“组织架构图”
- 状态定义(
TripState): 我们需要追踪用户的需求、目的地、预算、规划草案、预订信息等。 - 核心节点:
planner,city_expert_node,hotel_expert_node,flight_expert_node,itinerary_generator_node。 - 路由逻辑:
planner将扮演一个极其智能的中央路由器,根据对话的进展和当前任务,动态地将工作流分发给不同的专家节点。
- 状态定义(
- API 接口设计(API Contract)
- 定义前后端之间的通信契约。
POST /trip/invoke: 发起一个新的对话回合,流式返回 Agent 的思考过程和最终结果。GET /trip/state: 获取指定会话的当前状态,用于前端恢复和展示。
- 用户交互流程(User Flow)
- 描绘用户从打开网页到获得最终行程单的完整交互路径。
- 总结:蓝图在手,天下我有
1. 项目愿景:人人都能拥有的“私人旅行定制师”
痛点分析
规划一次完美的旅行是一件既令人兴奋又极其耗时费力的事:
- 信息过载:面对网络上无穷无尽的攻略、点评、榜单,我们常常无所适从。
- 需求繁杂:需要同时考虑机票、酒店、景点、餐饮、交通、预算等多个维度,并在它们之间做出权衡。
- 个性化缺失:大多数在线旅游平台(OTA)提供的是标准化的产品,难以满足“我想在一个安静的海边小镇住三天,其中一天下午想去学冲浪”这类高度个性化的需求。
- 流程割裂:搜索攻略、预订机票、预订酒店通常需要在不同的平台上来回切换。
“旅小智”的核心价值
“旅小智”旨在解决这些痛点。它不仅仅是一个聊天机器人,而是一个对话式的、端到端的私人旅行定制师。
- 个性化理解:通过自然语言对话,深入理解用户的模糊需求、预算和个人偏好。
- 专家级建议:利用背后由多个专家 Agent 组成的团队,提供专业、可靠的目的地、住宿和交通建议。
- 动态规划:能够与用户进行多轮“讨价还价”,实时调整和优化行程计划。
- 一站式服务:在未来,可以集成真实的预订 API,实现从规划到预订的无缝体验(本次项目将使用模拟工具)。
2. 技术栈选型:构建一个现代化的 AI 应用
- 前端:
Streamlit- 为什么选它? Streamlit 是一个纯 Python 的前端框架,能让我们以惊人的速度将数据脚本转换为可交互的 Web 应用。对于以 Python 为主的 AI 开发者来说,无需学习复杂的前端技术(如 React, Vue),就能快速构建出漂亮、实用的用户界面。非常适合原型验证和内部工具。
- 后端:
FastAPI- 为什么选它? FastAPI 以其高性能、易用性、以及与 Pydantic 的无缝集成而闻名。它能自动生成交互式的 API 文档(基于 OpenAPI 和 JSON Schema),非常适合作为 AI 应用的后端,为前端提供稳定、标准的 API 服务。
- 智能体内核:
LangGraph- 为什么选它? 旅行规划是一个典型的、需要多专家协作的复杂任务。
LangGraph提供了构建这种复杂、有状态、有循环的多智能体系统的完美工具,其灵活性和可控性远超传统的AgentExecutor。
- 为什么选它? 旅行规划是一个典型的、需要多专家协作的复杂任务。
- 容器化:
Docker- 为什么选它? Docker 是实现开发、测试、生产环境一致性的行业标准。它能将我们的全栈应用(包括 Python 环境、前后端代码、Agent 模型)打包成一个标准化的容器,实现“一次构建,到处运行”。
3. 系统宏观架构:前后端分离与智能内核
我们将采用经典的前后端分离架构。
- 用户界面层 (UI Layer):由
Streamlit构建。它是一个独立运行的服务,负责渲染用户界面、接收用户输入、并通过 HTTP 请求与后端通信。 - 业务逻辑层 (Business Logic Layer):由
FastAPI构建。它也是一个独立的服务,负责处理前端的请求、管理用户会话、并作为“翻译官”与智能体内核进行交互。 - 智能体核心层 (Agent Core Layer):由
LangGraph构建的 AI 团队。它被业务逻辑层调用,负责执行真正的“智能”任务。
Mermaid 图:可视化“旅小智”的系统架构
graph TD
subgraph User's Browser
U[用户]
end
subgraph Frontend Server (Streamlit)
S[Streamlit UI]
end
subgraph Backend Server (FastAPI + LangGraph)
F[FastAPI Endpoints]
L[LangGraph Core]
end
subgraph External Services
DB[(Memory DB\nSqlite)]
T[Tool APIs\n(Search, Weather, etc.)]
end
U -- "1. 交互" --> S;
S -- "2. 发起 HTTP API 调用 (e.g., /invoke)" --> F;
F -- "3. 调用 LangGraph App" --> L;
L -- "4. 读/写状态" --> DB;
L -- "5. 调用外部工具" --> T;
T -- "6. 返回工具结果" --> L;
L -- "7. 返回执行结果" --> F;
F -- "8. 流式返回 HTTP 响应" --> S;
S -- "9. 更新 UI 展示" --> U;
数据流解读:
- 用户在 Streamlit 界面上输入“我想去云南玩一周,预算 5000”。
- Streamlit 将这个请求打包,通过 HTTP POST 发送给 FastAPI 的
/invoke端点。 - FastAPI 接收到请求,为该用户会话找到或创建一个
thread_id,然后调用 LangGraphapp的stream或invoke方法,并将thread_id和用户输入传入。 - LangGraph 内核开始运转。
TravelPlanner主管 Agent 介入,它从Sqlite数据库中加载该thread_id的历史状态。 TravelPlanner决定需要了解云南的景点,于是将任务分配给CityExpert。CityExpertAgent 节点被执行,它调用外部的Tavily SearchAPI。- 搜索结果返回给
CityExpert,它进行整理后更新TripState。 TravelPlanner看到CityExpert的结果后,决定下一步需要咨询HotelExpert... 这个过程不断循环。- 在整个过程中,FastAPI 可以通过 LangGraph 的
stream方法,将每一步的中间结果(如“正在为您搜索景点...”、“正在为您筛选酒店...”)流式地返回给 Streamlit 前端。 - Streamlit 接收到这些流式数据,实时地更新 UI,向用户展示 Agent 的“思考过程”,极大地提升了用户体验。
4. 智能体团队设计:定义“旅小智”的多角色 Agent
我们的 AI 团队将由以下核心角色组成:
| 角色 | 职责 | 使用工具 (示例) |
|---|---|---|
| TravelPlanner (主管) | 核心协调者。与用户直接对话,理解需求,分解任务,调用其他专家,并最终确认计划。 | (不直接使用外部工具,而是“调用”其他 Agent 节点) |
| CityExpert (专家) | 提供关于特定城市或地区的详细信息,如必游景点、特色美食、当地文化、最佳旅行时间等。 | TavilySearch, Wikipedia |
| HotelExpert (专家) | 根据用户的预算、位置偏好、住宿类型(酒店、民宿)等,搜索和筛选酒店。 | AmadeusHotelSearch (模拟), Booking.com (模拟) |
| FlightExpert (专家) | 根据用户的出发地、目的地和日期,搜索和比较机票。 | SkyscannerAPI (模拟), GoogleFlights (模拟) |
| ItineraryGenerator (专家) | 一个特殊的、非交互式的 Agent。它接收所有已确认的信息(城市、酒店、航班、活动),并生成一份格式化的、每日的行程单。 | (无外部工具,纯粹的 LLM 生成能力) |
5. LangGraph 图设计
状态定义(TripState)
class TripState(TypedDict):
# 用户的原始需求
user_request: str
# 由 Planner 生成的旅行计划草案
draft_plan: Dict[str, Any]
# 专家 Agent 的研究结果
expert_outputs: Dict[str, Any]
# 最终确认的行程单
final_itinerary: Optional[str]
# 对话历史
messages: Annotated[List[BaseMessage], operator.add]
# 下一个要执行的节点
next_node: str
路由逻辑
TravelPlanner 将是这个图的核心路由器。在每个循环的开始,它都会被调用。它会审视整个 TripState,特别是最新的用户消息和 expert_outputs,然后做出决策,更新 next_node 字段。
- 初始状态 -> 用户输入 ->
TravelPlanner决策 ->next_node=city_expert city_expert完成 ->TravelPlanner决策 ->next_node=hotel_expert- ...
- 所有信息收集完毕 ->
TravelPlanner决策 ->next_node=itinerary_generator - 行程单生成 ->
TravelPlanner决策 ->next_node=END
6. API 接口设计(API Contract)
FastAPI 将提供以下核心接口:
POST /trip/invoke:- Request Body:
{"input": "用户输入", "thread_id": "可选的会话ID"} - Response Body (流式): Server-Sent Events (SSE) stream. 每个事件都是一个 JSON 对象,可能包含:
{"event": "on_agent_start", "agent": "CityExpert"}{"event": "on_tool_end", "output": "搜索结果..."}{"event": "on_llm_end", "output": "AI 思考的中间文本..."}{"event": "final_result", "itinerary": "{...}"}
- 作用: 驱动 Agent 进行一轮或多轮工作,并实时反馈进度。
- Request Body:
GET /trip/state/{thread_id}:- Response Body:
{"state": TripState} - 作用: 获取某个会话的完整历史状态,用于调试或在用户刷新页面后恢复前端 UI。
- Response Body:
7. 用户交互流程(User Flow)
- 用户打开 Streamlit 应用,看到一个欢迎界面和聊天输入框。
- 用户输入第一个请求:“下个月我想带家人去海边玩,有什么推荐吗?”
- Streamlit 将请求发送到 FastAPI 后端。
- 后端
TravelPlannerAgent 开始工作,它可能会反问:“很棒的想法!为了更好地为您推荐,能告诉我您的预算、出行人数和偏好的旅行风格(比如悠闲度假还是紧凑观光)吗?” - 这个反问通过流式响应实时显示在前端 UI 上。
- 用户回复:“我们两个人,预算 8000,喜欢悠闲一点的。”
TravelPlanner接收到新信息,决定调用CityExpert。前端显示:“正在为您寻找合适的海滨城市...”CityExpert返回了几个城市选项(如三亚、厦门、青岛)及各自的优缺点。TravelPlanner将这些选项呈现给用户。- 用户选择了“厦门”。
TravelPlanner接着调用HotelExpert和FlightExpert...- 经过几轮这样的交互,所有信息确认完毕。
TravelPlanner调用ItineraryGenerator,生成最终的 PDF 或 Markdown 行程单。- 前端显示“您的专属行程已生成!”,并提供下载链接。
8. 总结:蓝图在手,天下我有
通过本章的设计,我们为“旅小智”项目绘制了一份清晰、完整、可执行的架构蓝图。我们明确了项目的目标、技术栈、系统分层、数据流、AI 团队的角色与协作方式,以及前后端的交互契约。
这份蓝图将是我们接下来几章编码工作的“北极星”,指引我们高效、有序地将一个宏大的构想,一步步变为现实。