daphne-chen 1 mēnesi atpakaļ
vecāks
revīzija
b1ff0257fb
82 mainītis faili ar 212 papildinājumiem un 0 dzēšanām
  1. 0 0
      04_work/.env.example
  2. 0 0
      04_work/.gitignore
  3. 212 0
      04_work/README.md
  4. 0 0
      04_work/app/__init__.py
  5. 0 0
      04_work/app/agents/__init__.py
  6. 0 0
      04_work/app/agents/itinerary_agent.py
  7. 0 0
      04_work/app/agents/map_agent.py
  8. 0 0
      04_work/app/agents/requirement_agent.py
  9. 0 0
      04_work/app/agents/resource_agent.py
  10. 0 0
      04_work/app/agents/reviewer_agent.py
  11. 0 0
      04_work/app/clients/__init__.py
  12. 0 0
      04_work/app/clients/serpapi_client.py
  13. 0 0
      04_work/app/config.py
  14. 0 0
      04_work/app/graph/__init__.py
  15. 0 0
      04_work/app/graph/builder.py
  16. 0 0
      04_work/app/graph/final_nodes.py
  17. 0 0
      04_work/app/graph/map_nodes.py
  18. 0 0
      04_work/app/graph/nodes.py
  19. 0 0
      04_work/app/graph/planner_builder.py
  20. 0 0
      04_work/app/graph/planner_nodes.py
  21. 0 0
      04_work/app/graph/research_builder.py
  22. 0 0
      04_work/app/graph/resource_nodes.py
  23. 0 0
      04_work/app/graph/review_nodes.py
  24. 0 0
      04_work/app/graph/route_builder.py
  25. 0 0
      04_work/app/graph/route_nodes.py
  26. 0 0
      04_work/app/graph/selection_builder.py
  27. 0 0
      04_work/app/graph/selection_nodes.py
  28. 0 0
      04_work/app/graph/state.py
  29. 0 0
      04_work/app/graph/supervisor_nodes.py
  30. 0 0
      04_work/app/graph/travel_builder.py
  31. 0 0
      04_work/app/graph/validation_nodes.py
  32. 0 0
      04_work/app/llm.py
  33. 0 0
      04_work/app/logging_config.py
  34. 0 0
      04_work/app/mcp_client.py
  35. 0 0
      04_work/app/schemas/__init__.py
  36. 0 0
      04_work/app/schemas/common.py
  37. 0 0
      04_work/app/schemas/flight.py
  38. 0 0
      04_work/app/schemas/hotel.py
  39. 0 0
      04_work/app/schemas/itinerary.py
  40. 0 0
      04_work/app/schemas/place.py
  41. 0 0
      04_work/app/schemas/review.py
  42. 0 0
      04_work/app/schemas/route.py
  43. 0 0
      04_work/app/schemas/selection.py
  44. 0 0
      04_work/app/schemas/travel_request.py
  45. 0 0
      04_work/app/schemas/validation.py
  46. 0 0
      04_work/app/services/__init__.py
  47. 0 0
      04_work/app/services/candidate_selection_service.py
  48. 0 0
      04_work/app/services/finalization_service.py
  49. 0 0
      04_work/app/services/plan_validation_service.py
  50. 0 0
      04_work/app/services/route_evaluation_service.py
  51. 0 0
      04_work/app/services/travel_search_service.py
  52. 0 0
      04_work/main.py
  53. 0 0
      04_work/mcp_servers/__init__.py
  54. 0 0
      04_work/mcp_servers/travel_search_server.py
  55. 0 0
      04_work/pyproject.toml
  56. 0 0
      04_work/scripts/__init__.py
  57. 0 0
      04_work/scripts/run_regression.py
  58. 0 0
      04_work/scripts/test_amap_mcp.py
  59. 0 0
      04_work/scripts/test_connections.py
  60. 0 0
      04_work/scripts/test_final_graph.py
  61. 0 0
      04_work/scripts/test_mcp_registry.py
  62. 0 0
      04_work/scripts/test_planner_graph.py
  63. 0 0
      04_work/scripts/test_requirement_graph.py
  64. 0 0
      04_work/scripts/test_research_graph.py
  65. 0 0
      04_work/scripts/test_resource_graph.py
  66. 0 0
      04_work/scripts/test_reviewer_graph.py
  67. 0 0
      04_work/scripts/test_route_graph.py
  68. 0 0
      04_work/scripts/test_selection_graph.py
  69. 0 0
      04_work/scripts/test_serpapi.py
  70. 0 0
      04_work/scripts/test_serpapi_client.py
  71. 0 0
      04_work/scripts/test_travel_mcp.py
  72. 0 0
      04_work/scripts/test_travel_service.py
  73. 0 0
      04_work/scripts/test_validation_graph.py
  74. 0 0
      04_work/tests/test_candidate_selection_service.py
  75. 0 0
      04_work/tests/test_itinerary_schema.py
  76. 0 0
      04_work/tests/test_plan_validation_service.py
  77. 0 0
      04_work/tests/test_requirement_validation.py
  78. 0 0
      04_work/tests/test_review_schema.py
  79. 0 0
      04_work/tests/test_route_evaluation_service.py
  80. 0 0
      04_work/tests/test_supervisor_nodes.py
  81. 0 0
      04_work/uv.lock
  82. 0 0
      README.md

+ 0 - 0
.env.example → 04_work/.env.example


+ 0 - 0
.gitignore → 04_work/.gitignore


+ 212 - 0
04_work/README.md

@@ -0,0 +1,212 @@
+# TravelMind — 多角色智能旅行规划系统
+
+TravelMind 是一个基于 **LangGraph 多角色 Agent 工作流** 的智能行程规划系统:用户用自然语言描述旅行需求(出发地、目的地、日期、预算、偏好等),系统自动完成需求解析、航班/酒店资源查询、目的地地图研究、行程编排、风险评审与迭代优化,最终输出结构化多日行程。
+
+> 项目名中的 "Mind" 取自 *multi-agent mind*:多个各司其职的 Agent 以 Supervisor 模式协同工作,像一支"思维团队"一样规划行程。
+
+## ✨ 核心特性
+
+- **自然语言直接规划**:输入"帮我规划 6 月下旬从北京去东京玩 5 天,预算 1.5 万以内",即可获得完整行程方案
+- **多角色 Agent 协作**:需求解析、资源查询、地图研究、行程规划、行程评审 5 个 Agent 分工协作
+- **Supervisor 迭代评审**:规划结果经过确定性校验与独立评审,不合格自动重新规划(带重试上限,避免死循环)
+- **真实数据查询**:航班/酒店走 **SerpApi Google Flights/Hotels**,景点/餐饮/天气走 **高德地图官方 MCP**
+- **MCP 标准化接入**:自建航班/酒店搜索 MCP 服务器(FastMCP),与外部高德 MCP 统一接入
+- **防编造设计**:候选筛选、路线评估、计划校验等环节使用**确定性代码**而非 LLM,保证 ID、日期、价格等信息的真实性,防止模型编造航班、酒店、景点和价格
+- **模型无关**:兼容 OpenAI 及其兼容服务(DeepSeek、通义千问等),仅需配置 `MODEL_BASE_URL`
+
+## 🏗️ 架构总览
+
+系统采用 **LangGraph 状态图** 编排完整工作流,Supervisor 在关键节点做路由决策:
+
+```
+用户需求
+   │
+   ▼
+┌──────────────┐   澄清/报错(条件路由)    ┌──────────────────┐
+│ 需求解析Agent │ ─────────────────────► │  补充需求/终止    │
+└──────┬───────┘                        └──────────────────┘
+       │ TravelRequest(结构化)
+       ▼
+┌──────────────┐   高德 MCP 工具           ┌──────────────────┐
+│ 资源查询Agent │ ─────────────────────►  │   地图研究Agent   │
+│ 航班/酒店     │                          │  景点/餐饮/天气    │
+└──────┬───────┘                          └────────┬─────────┘
+       │ 候选资源                                  │ POI 数据
+       ▼                                           ▼
+┌──────────────────────────────────────────────────────────────┐
+│                候选筛选 → 路线评估 → 行程规划Agent              │
+│                  (生成结构化多日行程)                          │
+└──────────────────────┬───────────────────────────────────────┘
+                       │
+                       ▼
+              ┌──────────────────┐  未通过(重新规划循环)   ┌──────────────┐
+              │ 校验 → 评审Agent  │ ◄────────────────────── │  Supervisor  │
+              └──────┬───────────┘                          │   (路由决策)  │
+                     │ 通过                                 └──────────────┘
+                     ▼
+              ┌──────────────────┐
+              │  最终定稿/输出     │
+              └──────────────────┘
+```
+
+工作流环节:**需求解析 → 资源查询 → 候选筛选 → 地图研究 → 路线评估 → 行程规划 → 校验 → 评审 → 最终定稿**,其中规划/评审环节存在带重试上限的迭代循环(`recursion_limit = 80`)。
+
+### 角色分工
+
+| Agent | 职责 |
+|-------|------|
+| **RequirementAgent** 需求解析 | 把自然语言转换为结构化 `TravelRequest`,意图识别与字段提取(仅解析,不规划);缺字段时走澄清流程 |
+| **ResourceSearchAgent** 资源查询 | 调用航班/酒店 MCP 工具搜索外部资源,指导工具调用顺序并汇总为结构化结果 |
+| **MapResearchAgent** 地图研究 | 调用高德地图 MCP 工具,搜索目的地周边景点、餐饮与天气,返回结构化 POI 数据 |
+| **ItineraryPlannerAgent** 行程规划 | 基于候选资源与地图研究结果,生成包含每日活动安排的结构化多日行程 |
+| **TripReviewerAgent** 行程评审 | 从风险控制角度独立评审,识别节奏、地理、预算等维度的问题并给出修改意见 |
+| **Supervisor** 监督协调 | 汇总校验与评审意见,决定 `replan` / `finalize` / `finalize_with_risks` / `terminate` |
+
+### 确定性模块(不使用 LLM)
+
+以下环节刻意使用确定性代码,保证准确性与成本控制:
+
+| 模块 | 原因 |
+|------|------|
+| Candidate Selector | 排序和过滤规则确定 |
+| Route Evaluator | 距离和评分可确定性计算 |
+| Plan Validator | ID、日期、预算必须准确 |
+| Finalizer | 防止最终展示阶段重新编造信息 |
+
+LLM 只负责自然语言理解、复杂取舍、行程编排和体验审查。
+
+### MCP 集成
+
+通过 `langchain-mcp-adapters` 的 `MultiServerMCPClient` 同时接入两个 MCP 服务器:
+
+1. **travel_search(自建)**:stdio 传输,`mcp_servers/travel_search_server.py`(FastMCP)包装 `TravelSearchService`,提供 `search_airports`、`search_flights`、`search_return_flights`、`search_hotels` 工具,底层调用 SerpApi
+2. **amap(高德官方)**:Streamable HTTP 传输,`https://mcp.amap.com/mcp`,提供 `maps_*` 系列工具(POI 搜索、餐饮、天气、距离测量、路线规划等)
+
+## 🛠️ 技术栈
+
+- **Python ≥ 3.10**,[uv](https://docs.astral.sh/uv/) 包管理
+- **LangChain 1.x / LangGraph**:Agent 与状态图编排
+- **langchain-openai**:统一模型接入(OpenAI / DeepSeek / Qwen 等)
+- **langchain-mcp-adapters + mcp**:MCP 客户端与自建 MCP 服务器(FastMCP)
+- **httpx**:SerpApi HTTP 调用(支持 SOCKS 代理)
+- **pydantic / pydantic-settings**:数据模型与配置管理
+- **rich**:终端输出美化
+- **pytest**:单元测试
+
+## 🚀 快速开始
+
+### 1. 环境准备
+
+需要 [uv](https://docs.astral.sh/uv/) 包管理器(或使用任意虚拟环境工具):
+
+```bash
+# 进入项目目录并安装依赖(自动创建 .venv)
+uv sync
+```
+
+### 2. 配置环境变量
+
+```bash
+cp .env.example .env
+```
+
+编辑 `.env`,填写以下必填项(`app/config.py` 会从项目根目录 `.env` 读取,缺配置时会给出明确错误):
+
+| 变量 | 说明 | 必填 |
+|------|------|------|
+| `MODEL_API_KEY` | OpenAI 或兼容服务的 API Key | ✅ |
+| `MODEL_NAME` | 模型名,如 `gpt-4.1-mini`、`qwen-plus`、`deepseek-chat` | ✅ |
+| `MODEL_BASE_URL` | OpenAI 官方接口可留空;兼容接口填对应 Base URL | 视服务 |
+| `SERPAPI_API_KEY` | SerpApi 密钥(Google Flights/Hotels 搜索) | ✅ |
+| `AMAP_API_KEY` | 高德开放平台密钥(MCP 地图服务) | ✅ |
+| `REQUEST_TIMEOUT_SECONDS` | 请求超时(秒),默认 `120` | 否 |
+
+> ⚠️ `.env` 包含敏感密钥,已被 `.gitignore` 排除,**切勿提交到版本库**。密钥缺失时,`Settings.require()` 会抛出带具体变量名的错误。
+
+### 3. 运行
+
+支持两种输入方式:
+
+```bash
+# 方式一:命令行参数直接传入
+uv run python main.py 帮我规划6月下旬从北京去东京玩5天,预算1.5万以内
+
+# 方式二:交互式输入(支持多行,输入空行结束)
+uv run python main.py
+```
+
+运行结束后会输出最终行程方案与执行状态(trace_id、各环节执行次数、Supervisor 决策、总耗时等)。
+
+## 🧪 测试
+
+```bash
+# 运行全部单元测试
+uv run pytest
+
+# 或使用自动化回归入口(只跑本地单元测试)
+uv run python -m scripts.run_regression
+
+# 真实接口集成测试(会调用真实模型、SerpApi 和高德 MCP,可能产生费用)
+uv run python -m scripts.run_regression --integration
+```
+
+## 📁 项目结构
+
+```
+travel-mind/
+├── main.py                        # CLI 入口:读取需求并执行完整工作流
+├── pyproject.toml                 # 项目配置与依赖(uv)
+├── .env.example                   # 环境变量模板(.env 不入库)
+├── app/
+│   ├── config.py                  # pydantic-settings 配置中心(读取 .env)
+│   ├── llm.py                     # 大模型工厂(兼容 OpenAI/DeepSeek/Qwen)
+│   ├── mcp_client.py              # MCP 工具加载器(自建 + 高德双服务器)
+│   ├── agents/                    # 五个角色 Agent
+│   │   ├── requirement_agent.py   # 需求解析
+│   │   ├── resource_agent.py      # 资源查询
+│   │   ├── map_agent.py           # 地图研究
+│   │   ├── itinerary_agent.py     # 行程规划
+│   │   └── reviewer_agent.py      # 行程评审
+│   ├── graph/                     # LangGraph 工作流(builder + nodes + state)
+│   │   ├── planner_builder.py     # 完整主图编排
+│   │   ├── supervisor_nodes.py    # 监督协调与路由
+│   │   └── ...                    # 各环节节点
+│   ├── schemas/                   # Pydantic 数据模型(航班/酒店/行程/路线…)
+│   ├── services/                  # 业务服务(搜索/筛选/评估/校验/定稿)
+│   ├── clients/
+│   │   └── serpapi_client.py      # SerpApi HTTP 客户端
+│   └── logging_config.py          # 日志与 trace_id
+├── mcp_servers/
+│   └── travel_search_server.py    # 自建旅行搜索 MCP 服务器(FastMCP)
+├── scripts/                       # 各环节调试脚本 + 回归测试入口
+└── tests/                         # pytest 单元测试
+```
+
+## 📌 当前限制
+
+该项目是生产架构导向的可运行 MVP,而不是已上线商业系统:
+
+- 航班和酒店数据用于查询与规划,不执行真实预订
+- 航班接口报价的计价范围需以供应商页面为准
+- 部分未来日期无法查询准确天气
+- 未完整覆盖门票、餐饮和市内交通价格
+- 没有数据库和长期会话持久化
+- 没有针对大规模并发进行压力测试
+- MCP 和第三方 API 失效时的降级能力仍可增强
+
+## 🔭 生产化方向
+
+- FastAPI 服务接口
+- Redis 缓存与限流
+- LangGraph Checkpointer 持久化
+- 用户会话管理
+- MCP 超时、熔断和降级
+- OpenTelemetry 链路追踪
+- Agent 调用成本统计
+- Prompt 和工作流评测集
+- Docker 与 CI/CD
+- 多供应商数据源切换
+
+## 📄 许可
+
+个人学习/作业项目,未指定开源许可证。

+ 0 - 0
app/__init__.py → 04_work/app/__init__.py


+ 0 - 0
app/agents/__init__.py → 04_work/app/agents/__init__.py


+ 0 - 0
app/agents/itinerary_agent.py → 04_work/app/agents/itinerary_agent.py


+ 0 - 0
app/agents/map_agent.py → 04_work/app/agents/map_agent.py


+ 0 - 0
app/agents/requirement_agent.py → 04_work/app/agents/requirement_agent.py


+ 0 - 0
app/agents/resource_agent.py → 04_work/app/agents/resource_agent.py


+ 0 - 0
app/agents/reviewer_agent.py → 04_work/app/agents/reviewer_agent.py


+ 0 - 0
app/clients/__init__.py → 04_work/app/clients/__init__.py


+ 0 - 0
app/clients/serpapi_client.py → 04_work/app/clients/serpapi_client.py


+ 0 - 0
app/config.py → 04_work/app/config.py


+ 0 - 0
app/graph/__init__.py → 04_work/app/graph/__init__.py


+ 0 - 0
app/graph/builder.py → 04_work/app/graph/builder.py


+ 0 - 0
app/graph/final_nodes.py → 04_work/app/graph/final_nodes.py


+ 0 - 0
app/graph/map_nodes.py → 04_work/app/graph/map_nodes.py


+ 0 - 0
app/graph/nodes.py → 04_work/app/graph/nodes.py


+ 0 - 0
app/graph/planner_builder.py → 04_work/app/graph/planner_builder.py


+ 0 - 0
app/graph/planner_nodes.py → 04_work/app/graph/planner_nodes.py


+ 0 - 0
app/graph/research_builder.py → 04_work/app/graph/research_builder.py


+ 0 - 0
app/graph/resource_nodes.py → 04_work/app/graph/resource_nodes.py


+ 0 - 0
app/graph/review_nodes.py → 04_work/app/graph/review_nodes.py


+ 0 - 0
app/graph/route_builder.py → 04_work/app/graph/route_builder.py


+ 0 - 0
app/graph/route_nodes.py → 04_work/app/graph/route_nodes.py


+ 0 - 0
app/graph/selection_builder.py → 04_work/app/graph/selection_builder.py


+ 0 - 0
app/graph/selection_nodes.py → 04_work/app/graph/selection_nodes.py


+ 0 - 0
app/graph/state.py → 04_work/app/graph/state.py


+ 0 - 0
app/graph/supervisor_nodes.py → 04_work/app/graph/supervisor_nodes.py


+ 0 - 0
app/graph/travel_builder.py → 04_work/app/graph/travel_builder.py


+ 0 - 0
app/graph/validation_nodes.py → 04_work/app/graph/validation_nodes.py


+ 0 - 0
app/llm.py → 04_work/app/llm.py


+ 0 - 0
app/logging_config.py → 04_work/app/logging_config.py


+ 0 - 0
app/mcp_client.py → 04_work/app/mcp_client.py


+ 0 - 0
app/schemas/__init__.py → 04_work/app/schemas/__init__.py


+ 0 - 0
app/schemas/common.py → 04_work/app/schemas/common.py


+ 0 - 0
app/schemas/flight.py → 04_work/app/schemas/flight.py


+ 0 - 0
app/schemas/hotel.py → 04_work/app/schemas/hotel.py


+ 0 - 0
app/schemas/itinerary.py → 04_work/app/schemas/itinerary.py


+ 0 - 0
app/schemas/place.py → 04_work/app/schemas/place.py


+ 0 - 0
app/schemas/review.py → 04_work/app/schemas/review.py


+ 0 - 0
app/schemas/route.py → 04_work/app/schemas/route.py


+ 0 - 0
app/schemas/selection.py → 04_work/app/schemas/selection.py


+ 0 - 0
app/schemas/travel_request.py → 04_work/app/schemas/travel_request.py


+ 0 - 0
app/schemas/validation.py → 04_work/app/schemas/validation.py


+ 0 - 0
app/services/__init__.py → 04_work/app/services/__init__.py


+ 0 - 0
app/services/candidate_selection_service.py → 04_work/app/services/candidate_selection_service.py


+ 0 - 0
app/services/finalization_service.py → 04_work/app/services/finalization_service.py


+ 0 - 0
app/services/plan_validation_service.py → 04_work/app/services/plan_validation_service.py


+ 0 - 0
app/services/route_evaluation_service.py → 04_work/app/services/route_evaluation_service.py


+ 0 - 0
app/services/travel_search_service.py → 04_work/app/services/travel_search_service.py


+ 0 - 0
main.py → 04_work/main.py


+ 0 - 0
mcp_servers/__init__.py → 04_work/mcp_servers/__init__.py


+ 0 - 0
mcp_servers/travel_search_server.py → 04_work/mcp_servers/travel_search_server.py


+ 0 - 0
pyproject.toml → 04_work/pyproject.toml


+ 0 - 0
scripts/__init__.py → 04_work/scripts/__init__.py


+ 0 - 0
scripts/run_regression.py → 04_work/scripts/run_regression.py


+ 0 - 0
scripts/test_amap_mcp.py → 04_work/scripts/test_amap_mcp.py


+ 0 - 0
scripts/test_connections.py → 04_work/scripts/test_connections.py


+ 0 - 0
scripts/test_final_graph.py → 04_work/scripts/test_final_graph.py


+ 0 - 0
scripts/test_mcp_registry.py → 04_work/scripts/test_mcp_registry.py


+ 0 - 0
scripts/test_planner_graph.py → 04_work/scripts/test_planner_graph.py


+ 0 - 0
scripts/test_requirement_graph.py → 04_work/scripts/test_requirement_graph.py


+ 0 - 0
scripts/test_research_graph.py → 04_work/scripts/test_research_graph.py


+ 0 - 0
scripts/test_resource_graph.py → 04_work/scripts/test_resource_graph.py


+ 0 - 0
scripts/test_reviewer_graph.py → 04_work/scripts/test_reviewer_graph.py


+ 0 - 0
scripts/test_route_graph.py → 04_work/scripts/test_route_graph.py


+ 0 - 0
scripts/test_selection_graph.py → 04_work/scripts/test_selection_graph.py


+ 0 - 0
scripts/test_serpapi.py → 04_work/scripts/test_serpapi.py


+ 0 - 0
scripts/test_serpapi_client.py → 04_work/scripts/test_serpapi_client.py


+ 0 - 0
scripts/test_travel_mcp.py → 04_work/scripts/test_travel_mcp.py


+ 0 - 0
scripts/test_travel_service.py → 04_work/scripts/test_travel_service.py


+ 0 - 0
scripts/test_validation_graph.py → 04_work/scripts/test_validation_graph.py


+ 0 - 0
tests/test_candidate_selection_service.py → 04_work/tests/test_candidate_selection_service.py


+ 0 - 0
tests/test_itinerary_schema.py → 04_work/tests/test_itinerary_schema.py


+ 0 - 0
tests/test_plan_validation_service.py → 04_work/tests/test_plan_validation_service.py


+ 0 - 0
tests/test_requirement_validation.py → 04_work/tests/test_requirement_validation.py


+ 0 - 0
tests/test_review_schema.py → 04_work/tests/test_review_schema.py


+ 0 - 0
tests/test_route_evaluation_service.py → 04_work/tests/test_route_evaluation_service.py


+ 0 - 0
tests/test_supervisor_nodes.py → 04_work/tests/test_supervisor_nodes.py


+ 0 - 0
uv.lock → 04_work/uv.lock


+ 0 - 0
README.md