Travel Planner
让 AI 用真实数据规划旅行,而不是靠搜索来的二手攻略。
行程里的每一个数字——距离、通勤时长、余票、票价——都来自工具调用,并带来源和 时间戳。模型只负责取舍和解释,不生成任何数字。
生成的行程会先过一遍确定性可行性检查(时间窗、换乘余量、营业时间、预算), 排不通的方案不会送到你面前。
这是一个 Agent Skill,可以装进 Claude Code、OpenAI Codex、TRAE 或其他支持 Skill、Shell 和 MCP 的客户端。
它解决什么问题
规划一次旅行,真正花时间的不是决策,是信息采集。
为了不多花冤枉钱,你得自己去搜路线怎么走、机票和高铁多少钱、哪些景点值得去。 小红书翻半天、携程比价再半天,才拼出一个大致框架。然后开始比酒店,结果发现 住宿位置又反过来推翻了前面排的行程,回头再改一遍。
现在的 AI 工具帮不上这个忙。它们大多靠 web search 拼凑答案,看着像那么回事, 但落地时几乎每一条都要重新核对——车程是编的、票价是旧的、营业时间是错的, 最后还是得自己重查一遍,等于白做。
这个 Skill 换了个做法:用真实数据还原一个能直接执行的方案。
- 机票查携程等 OTA 的实际航班与可见价格
- 高铁查 12306 的真实车次、余票和票价
- 酒店按你每天实际会去的地方分区查询,而不是只看目的地大城市一个价
- 路线和车程查高德,不是估算
- 每个数字都带来源和查询时间,模型不生成任何数字
- 排完先过一遍可行性检查,时间对不上的方案不会送到你面前
当你已经确定了目的地和日期,它能把这堆散落的信息整合成一份真正可执行的 方案,并告诉你哪些地方还需要你自己确认。
它不解决什么问题
① 它不擅长「不知道去哪、也没定日期」的场景。
现在的能力是围绕「目的地和时间已定」设计的:数据源要有明确的出发地、目的地 和日期才能查。如果你想问的是"国庆前后从上海出发,哪里比较划算"——这种在 多个目的地、多个日期之间横向比较的需求,它还做不好。
② 境外目的地只剩一条腿。
高德的地点数据以中国大陆为主,12306 同理。查摩尔曼斯克这类地方时,两个数据 源同时失效,只剩 Browser Use。
这里有个必须知道的细节:高德对境外查询不返回空,而是返回名称相近的国内 地点,坐标格式完全正常——查「东京」会得到广西一个真名叫东京的村庄。这个 Skill 会识别并拒绝这类结果,而不是拿它去算车程,但代价是境外目的地拿不到 任何已核实的坐标和路线。
这种情况下它仍会给出结果,但会明确标注哪些检查没能做(INCOMPLETE_EVIDENCE),
而不是假装完整。
③ 它是只读的。 装上之后它不能:
- 购买、预订、支付、候补、改签、退票——它没有下单能力
- 输入你的密码、短信验证码、身份证件或支付信息——登录和验证码永远交还给你
- 导出你的 Cookie、Token 或浏览器会话
- 点赞、收藏、关注、评论、发布,或以任何方式改动你的账号
- 绕过验证码、登录墙或平台风控
- 批量抓取小红书笔记、评论、图片或视频
它只看,不动。需要登录时它会停下来把控制权交给你。
④ 查酒店必须先登录,这一步无法跳过。 携程酒店对匿名访问不显示任何价格—— 不是显示不全,是一个数字都没有。所以每次查酒店,它都会先停下来请你扫码登录, 这不是选做步骤。同一个平台的机票查询不需要登录,两者不能类比。
五分钟上手
Claude Code
git clone https://github.com/tanweiping1012-source/travel-planner.git
ln -s "$(pwd)/travel-planner" ~/.claude/skills/travel-planner-mvp
bash ~/.claude/skills/travel-planner-mvp/scripts/setup_amap_key.sh
bash ~/.claude/skills/travel-planner-mvp/scripts/setup_rail_mcp.sh
用软链接而非拷贝,仓库始终是唯一事实源,git pull 后立即生效。
然后把 12306 加进 ~/.claude.json 的 mcpServers(见配置 12306),
重启客户端,再运行:
python3 ~/.claude/skills/travel-planner-mvp/scripts/travel_planner.py doctor --live
doctor 会自动识别当前客户端,无需手动指定。
OpenAI Codex
使用 $skill-installer 安装 GitHub 仓库
https://github.com/tanweiping1012-source/travel-planner
根目录中的 Skill,名称为 travel-planner-mvp。
记录安装器返回的绝对路径(不同 Codex 版本和 CODEX_HOME 会落在不同目录),
然后:
bash <SKILL_ROOT>/scripts/setup_amap_key.sh
bash <SKILL_ROOT>/scripts/setup_rail_mcp.sh --register-codex
重启 Codex 后运行 doctor --live 检查。
其他客户端
仓库根目录本身就是 Skill 目录。放进客户端的 Skill 发现路径即可:
| 客户端 | 项目级 | 用户级 |
|---|---|---|
| Claude Code | <workspace>/.claude/skills/ |
~/.claude/skills/ |
| OpenAI Codex | <workspace>/.agents/skills/ |
~/.agents/skills/ |
| TRAE | <workspace>/.trae/skills/ |
— |
客户端不支持 Skill 结构时,可以把 SKILL.md 当作项目规则加载,允许 Agent 读取
references/ 并执行 scripts/travel_planner.py,再单独配置 12306 MCP 和 Browser Use。
每位用户配置自己的高德 Key;Key 存入本机钥匙串,不随仓库或 Skill 分发。
能力概览
| 能力 | 数据来源 | 作用 |
|---|---|---|
| 攻略与路线研究 | Browser Use | 从小红书读取景点、玩法、路线走法、包车与门票行情、排队与体感、季节性信息 |
| 笔记配图识别 | Browser Use | 读取轮播图里的行程图与分项费用表——小红书的实质内容常常只在图片里 |
| 机票查询 | Browser Use | 从携程等 OTA 网页读取指定日期的航班、时刻与可见价格 |
| 酒店比价 | Browser Use | 按每日活动区域查询房价与取消政策;查询前必须登录,且记录登录态与会员等级,避免不同价格被错误地放在一起比较 |
| 地点与市内路线 | 高德 Web API | 校验 POI、坐标,计算步行、公交和驾车真实耗时;匹配可疑时拒绝返回坐标 |
| 高铁查询 | 社区 12306 MCP | 车次、余票、票价、经停站和中转方案;余票词表经归一化后可比较排序 |
| 可行性检查 | 本地 Python | 时间冲突、换乘缓冲、营业时间、预算和体力负荷 |
| 内容完整性检查 | 本地 Python | 拒绝只有交通、缺少景点特色与游玩说明的方案 |
Browser Use 在本文中指任何满足浏览器契约的 浏览器自动化能力——客户端内置浏览器、Playwright MCP 或其他适配器均可, 不绑定特定实现。
怎么用
直接用自然语言说清楚就行。除了出发地、目的地、日期、人数和预算,只有三件事 必须由你回答,因为它们没有安全的默认值:
- 预算是人均还是总共 —— 2000 元人均和 2000 元两人总共,差一倍
- 体力强度 —— 直接决定哪些行程根本排不出来
- 是否允许访问小红书和 OTA —— 这是授权,不能替你决定
其余的都会先假设再继续,并在方案里写明假设了什么:没说必去景点就当作都可 让路,没说步行上限就按体力强度取值,没说海拔耐受就按可接受处理(真出现高 海拔核心景点时会再问你一次)。
不会让你先填一张表才开始。
使用 $travel-planner-mvp。2027 年 4 月 10 日至 13 日,广州出发去桂林和阳朔,
2 人,人均预算 3500 元,节奏均衡。龙脊梯田为 CORE,不可因省钱或松弛被移除;
接受中等强度步行,核心景观受天气影响可以接受。冲突时优先保证核心地点,其次
省钱、节奏、舒适。小红书允许我手动登录,OTA 仅匿名只读。不购买或预订。
(示例为虚构,仅演示输入结构。)
这段输入已经完整,Agent 不会再问人数、预算、体力、龙脊梯田优先级或 Browser Use 授权。
实际使用时不必写得这么全——少说几项它会自己假设,只有上面那三件事会追问。
完整的 JSON 与纯文本需求模板见
references/intake-template.md。
标 CORE 的地点不可被删除,除非安全、法规、闭园、天气、海拔或体力上确实去不了。
你会得到什么
- 需求假设与限制条件
- 省钱、均衡、松弛三类方案——三者没有实质差别时不强行凑数
- 每日时间线、交通方式和换乘缓冲
- 每个主要景点的:景点特色、推荐理由、建议时长、推荐时段、体力负荷、避坑信息
- 参考费用、价格渠道和查询时间——机票、住宿都按这套规则来,住宿总价按晚数 和登录时看到的房价算出,不是卡片上的起价
- 可行性状态、硬冲突、风险和调整建议
- 来源链接,以及出发前必须自己再确认一遍的事项
已核实的事实和规划建议会分开呈现,不会混在一起。
它是怎么工作的
一句话:把「查事实」和「做判断」拆开,让模型只做后者。
普通 AI 攻略的问题在于两件事混在一起——模型一边回忆训练数据里的景点,一边 顺手编出"车程大约 40 分钟""门票 80 元左右"。这些数字听上去合理,但没有任何 东西为它们负责。
这个 Skill 把流程切成三层,每层职责不同:
┌─ 第一层 · 事实层 ─────────────────────────────────────────┐
│ Browser Use → 小红书:玩法、路线走法、行情、排队、体感 │
│ Browser Use → 携程等 OTA:指定日期的航班与可见价格 │
│ Browser Use → 携程酒店:登录后按每日区域查询的房价与政策 │
│ 高德 Web API :坐标、真实车程、公交方案 │
│ 12306 社区 MCP :车次、余票、票价 │
│ 产出:每条数据都带来源、渠道、登录状态、查询时间 │
└───────────────────────────┬───────────────────────────────┘
↓
┌─ 第二层 · 校验层(纯 Python,不含模型)──────────────────┐
│ 归一化 :把各源的杂乱格式统一成可比较的结构 │
│ 可行性 :时间窗、换乘余量、营业时间、预算、体力 │
│ 完整性 :方案是否只有交通而没讲清楚每个景点 │
│ 产出:FEASIBLE / FEASIBLE_WITH_RISK / INFEASIBLE + 冲突清单 │
└───────────────────────────┬───────────────────────────────┘
↓
┌─ 第三层 · 叙事层(模型)──────────────────────────────────┐
│ 取舍:预算不够时砍哪个、时间冲突时挪哪个 │
│ 解释:为什么推荐这条线、这个景点值得在什么时候去 │
│ 约束:只能引用第一层的数字,不能自己生成任何数字 │
└───────────────────────────────────────────────────────────┘
小红书负责线索,高德和 12306 负责核实
小红书上有大量别处拿不到的信息:某条路线怎么串、包车一天什么价、哪个入口 人少、索道排多久、"看着近其实要爬四十分钟"、枫叶几号红。这些直接决定路线 怎么排,规划全程都要用。
但它们进入方案的方式是假设,不是结论:
每条信息按类别决定它能走多远:
| 小红书说 | 归类 | 怎么处理 |
|---|---|---|
| "这三个点一天能串完" | 路线假设 | 当作候选顺序 → 高德算真实车程 → 可行性检查裁定 |
| "打车过去 20 分钟" | 时长线索 | 高德重新计算 → 冲突时以高德为准 |
| "包车 200 一天" | 行情信号 | 标注来源与时间,明确未核实;不会直接变成方案里的费用 |
| "北门进人少" | 体验 | 直接采纳为建议 → 无需核实,但标明出处 |
| "枫叶十一月中旬红" | 季节性 | 用于时段建议;行程贴近临界期时额外提示 |
营业时间、票价、车次、余票这四类硬事实永远不从笔记里取,一律以官方或 高德 / 12306 为准,笔记怎么写都一样。
这套分级不是为了丢弃社区信息,恰恰是为了能全部用上——一条记为「假设」的 信息可以参与排路线,而不会以「事实」的面目出现在你面前。
机票为什么必须走 OTA 网页
四类数据源里,只有机票没有可用的接口:地图有官方 API,铁路有社区 MCP, 唯独机票没有任何能查到指定日期真实价格的公开途径。
所以携程等 OTA 的网页是唯一的路。Browser Use 打开对应日期的航班列表,读取 页面上可见的航班号、时刻和价格,附上渠道与查询时间,再进入校验层。
这条路有两个必须知道的限制:
- 网页可见价不是最终支付价。 App 价、会员价、优惠券价可能都不同,方案里 的机票价格只是决策参考,以你在实际渠道看到的支付页面为准。
- 机票价格变化很快。 铁路票价基本不浮动,机票几小时就可能变。每条机票
记录都带
checked_at,方案呈现前会由validate-flights检查是否超过 2 小时;超时的价格会被标为需要重新查询,而不是默默呈现给你。
同一个检查还会核对起降时刻与标注时长是否自洽——页面读数出错时,"80 分钟" 的航班可能实际跨了 3 小时。落地早于起飞会直接判为硬冲突。
机票和高铁一样映射为活动而非路段:航班本身占据一段时间,去机场是另一段 由高德计算的路程,国内航班预留 120 分钟、国际 180 分钟的值机与安检余量, 一并进入可行性检查。
酒店比价为什么必须先登录
实测发现的:携程酒店对匿名访问不显示任何价格,不是显示不全,是一个数字 都没有——请求会直接跳转到登录页。所以酒店查询和小红书走同一套规则:先停, 请你扫码登录,看到价格再继续。这一步不能跳过,也不能拿"机票不用登录"去类推, 同一个网站的两个功能,登录要求完全不同。
登录之后还有一个陷阱:卡片上的价格是每晚起价,不是整住这几晚的总价。
¥556 起 住六晚不是 ¥556,是 ¥3,336。系统会用入离日期自动算出总价,
而不是把卡片数字直接当成这次住宿要花的钱。
价格还会随登录身份变化——同一间房,普通登录看到 ¥609,钻石会员看到
¥479。所以每条房价记录都带着当时的登录状态和会员等级;不同状态下查到的
价格不会被混在一起比较或排序。
完整流程
需求校验 ─→ 能力预检
↓
Browser Use:小红书研究(单独运行,读完即关)
↓
景点卡片:特色 / 理由 / 时长 / 时段 / 体力 / 避坑
↓
高德:校验地点坐标、聚类每日区域、计算市内真实路线
↓
生成省钱 / 均衡 / 松弛三类路线骨架
↓
12306 查高铁 ──┐
Browser Use 查机票 ──┤
Browser Use 查酒店(先登录,按每日区域查)──┤
├─→ 归一化 ─→ 可行性检查
┘ ↓
有硬冲突?→ 修复后重新评估(至多三轮)
↓
内容完整性检查
↓
出发前刷新入选的车次、航班与房价
↓
输出方案
小红书、OTA 机票、OTA 酒店 严格串行——不会同时开两个 Browser Use 阶段。 并行会在标签页焦点、登录接管、失效的元素句柄和页面计时器上互相干扰;酒店和 机票即使同属一个网站,登录状态也不共享,各自的登录交接必须分开处理。
所以你拿到的方案
每个数字都能追到来源和查询时间;排不通的方案在到你面前之前就被拦下并修过; 已核实的事实和模型的建议分开呈现,你能一眼看出哪些是查到的、哪些是推荐的。
配置高德
- 打开高德开放平台,创建应用
- 添加 Web服务 API 类型的 Key(类型选错是最常见的失败原因)
- macOS 用户执行(任意目录均可):
bash <SKILL_ROOT>/scripts/setup_amap_key.sh
Key 存入本机钥匙串(service: travel-planner-mvp,account: amap-api-key),
不会写入任何项目文件。旧的 trae-travel-planner 条目仍可读取。
检查:
python3 <SKILL_ROOT>/scripts/travel_planner.py credential-status
python3 <SKILL_ROOT>/scripts/travel_planner.py preflight
Linux 和 Windows 用户需自行使用系统密钥管理器,或仅在当前终端设置
AMAP_API_KEY。不要把 Key 写进仓库。
配置 12306 MCP
先装 uv:
brew install uv
安装运行时:
bash <SKILL_ROOT>/scripts/setup_rail_mcp.sh
脚本会下载固定 commit 的 drfccv/mcp-server-12306、应用 TLS 与日志安全补丁、
创建隔离 Python 环境,并打印标准 stdio MCP 配置。运行时装在用户数据目录,
不在 Skill 目录内,Skill 更新不会覆盖它。
默认位置:
macOS: ~/Library/Application Support/travel-planner-mvp/
Linux: ${XDG_DATA_HOME:-~/.local/share}/travel-planner-mvp/
可用 TRAVEL_PLANNER_DATA_DIR 指定其他绝对路径。
注册到 Claude Code
把脚本输出的 command 与 args 填进 ~/.claude.json 的 mcpServers:
{
"mcpServers": {
"12306": {
"type": "stdio",
"command": "/opt/homebrew/bin/uv",
"args": ["--directory", "<CHECKOUT_DIR>", "run", "mcp-server-12306"]
}
}
}
command 要填 which uv 的完整路径,不要只写 uv——客户端启动时的 PATH
可能不含 Homebrew 目录。保存后重启 Claude Code。
注册到 Codex
安装时加 --register-codex 即可,或在
设置 → MCP servers → Add server → STDIO 中手动填入脚本输出的 command
和 args。之后用 codex mcp list 确认并重启。
确认成功
看到 query-tickets、query-ticket-price、search-stations 等工具即为成功。
这个 MCP 直接查询 12306 网站使用的公开接口,不是官方开发者 API,也不登录 你的账户、不执行购票。它可能受接口变更、查询窗口和平台限制影响。
环境检查
python3 <SKILL_ROOT>/scripts/travel_planner.py doctor --live
doctor 检查 Python、高德、12306 运行环境、MCP 注册和 Browser Use 状态,并通过
actions 返回还缺哪几步。客户端默认自动识别,也可用 --client 显式指定
auto、codex、claude-code 或 generic。
缺少可选能力时会安全降级:没有 12306 就不给出实时铁路声明;没有 Browser Use 就需要 你提供标准化 JSON,或标记该数据源不可用;没有高德则不宣称任何已核实的地点。
Browser Use 授权
启动 Browser Use 之前,Agent 会明确说明要访问哪些域名,并请求一次只读授权。
小红书:优先匿名访问;搜索页要求登录时由你亲自扫码或完成验证,Agent 不输入 密码和验证码;只读取少量相关笔记的页面可见内容。
OTA 机票:在小红书研究和路线骨架完成后才启动;默认查询匿名网页公开价;只有你 明确需要会员价时才请求手动登录。
OTA 酒店:与机票不是同一回事——没有匿名模式。携程酒店对未登录访问不展示 任何价格,所以每次查酒店都会先停下请你扫码登录,这一步是必须的,不是可选项。
网页匿名价、App 价、会员价和优惠券价可能都不一样,最终以你在实际渠道看到的 支付页面为准。
命令参考
大多数时候你不需要手敲命令——Agent 会自己调用。你可能用到的只有这几个:
python3 <SKILL_ROOT>/scripts/travel_planner.py <command>
| 命令 | 作用 |
|---|---|
doctor |
汇总检查 Python、高德、12306 MCP 与 Browser Use 能力 |
credential-status |
检查高德 Key 是否已配置 |
preflight |
发送一次真实高德预检请求 |
search-places |
查询并标准化高德 POI |
以下由 Agent 在规划过程中自动调用,一般不需要你手动执行:
validate-request、amap-snapshot、normalize-rail、compile-research、
evaluate、validate-flights、validate-lodging、validate-plan。
所有命令都返回结构化 JSON。完整说明见
references/script-tools.md。
数据与隐私
仓库里不保存也不应提交:
- 高德 API Key
- 小红书或 OTA 的密码、验证码与 Cookie
- 浏览器 Profile 或 Storage State
- 身份证件和支付信息
旅行日期、预算、出发地、无障碍需求和浏览记录同样可能构成个人隐私。真实运行产物 应写入被忽略的临时目录。
故障处理
高德返回鉴权失败 — 确认 Key 类型是 Web服务 API(不是其他类型)、Key 未删除
或过期、IP 白名单与数字签名配置正确。
12306 查不了远期日期 — 12306 只开放有限的预售窗口,远期日期拿不到实时余票, 必须临近出发再刷新。
小红书要求登录 — 由你手动登录。持续出现验证码时应停止该数据源,降级到公开 信息,而不是反复重试。
OTA 价格与 App 不一致 — 属正常现象,见上文「机票为什么必须走 OTA 网页」。
Browser Use 超时 — 确认小红书和 OTA 是串行执行。某个阶段连续两次没有新数据 时应停止并返回部分结果,而不是无限等待。
第三方与许可
- 本 Skill 源码采用 MIT License
- 社区 12306 MCP 由安装脚本在你本地获取,不包含在发布包中
- 高德、12306、小红书、OTA 和各 Agent 客户端分别受其平台条款约束
- MIT License 不覆盖第三方数据权利、账号规则、隐私要求或商业使用限制
详见 SECURITY.md 与
THIRD_PARTY_NOTICES.md。
深入了解:工作流 · 数据契约 · 客户端兼容性 · 12306 MCP · Browser Use 契约
想参与开发或自己发版,见 CONTRIBUTING.md。
No comments yet
Be the first to share your take.