旅游助手 (travel-buddy):先定去哪儿,再给一份能照着订的行程

前言

给开发者或 agent 做旅行规划时,一个常见的坑是:用户说「7 天、1500 欧」,助手直接吐出一份逐日行程,而那座城市用户从没选过。目的地还没验证过可达、没查过硬性限制,行程里的营业时间、价格、入境规则却已经写得信心十足。

travel-buddy 把「去哪儿」和「玩什么」拆成两个阶段。先生成候选目的地、做硬过滤、并留下淘汰记录;只有目的地真正成立,才开始建行程,产出的页面里每一行预算都带来源和查询时间。它不做预订、不碰支付,所有链接只负责打开搜索页,由用户自己完成下单。

这是什么

travel-buddy(旅游助手)是一个开源的旅行决策 agent skill,由 user_f486c577 发布在 SkillHub(分类 life-service),仓库在 https://github.com/dong845/travel-buddy,MIT 协议。它面向 Claude Code 与 Codex 两类 CLI agent,运行在用户本机,全程不需要账号,脚本只用 Python 标准库(要求 Python 3.10+,开发环境为 3.13),页面产物里不含第三方脚本。

它解决的是:从不完整的出行需求出发,先做目的地发现与比较,再生成结构化、可预订的逐日行程;当约束发生变化(日期挪动、条件收紧)时,只重算受影响的部分并给出变更记录。

核心功能

下面介绍的能力来自 SKILL.md 的 description 与官方 README。

四阶段决策流程

用户不用手动选模式,说出手上已有的信息,模式随之确定:

  1. 还没有目的地、或只有大洲 → Discovery:3–5 个排序候选,附取舍理由和淘汰记录
  2. 有国家/地区但没定城市 → Constrained discovery:先比较子区域和城市
  3. 目的地已定 → Construction:完整逐日方案 + 两份产物
  4. 已有方案但条件变了 → Incremental replanning:只重算受影响部分,给出变更日志

Discovery 不会悄悄滑进 Construction。如果范围写死却没有点名任何具体地点,任务会被拦下而不是靠猜。

硬过滤与打分

候选先过硬约束(入境可行性、可达性、预算上限、时间窗),不通过的直接淘汰,不能因为「有吸引力」而胜出。只有过了硬门的候选才进入打分,推荐的起始权重为:体验契合 25、全包性价比 20、季节契合 15、出发可达性与本地物流 15、舒适/人群/美食/语言/安全 15、灵活性与证据置信度 10,并且只在用户真正表达过的偏好之间分配。分数只是摘要,解释本身写在淘汰记录里。

易变事实必须实时查证

价格、营业时间、天气、入境规则、汇率、安全通告、当地交通这类易变事实,一律通过工具或联网检索获取,不允许把记忆中的信息当成当前事实。每条重要推荐都要标注为 estimate(估算)、researched current information(已检索,附来源与日期)或 user-confirmed(用户确认)。查不到的字段如实写「本次运行未获取」,而不是编一个值。

官方文档里特别强调:不要过早放弃检索。列出页不等于核实过,200 响应也只是候选。一个来源的 detail 页没有某个字段,才算该类证据不可用,并在计划里写明是哪个字段、哪个页面。

只浏览,不交易

每个链接打开的都是用户自己完成搜索的页面。skill 不登录、不输入支付信息、不接受价格变更,也不会因为网页显示了库存就把某选项称作「已订」。「已订」只留给用户亲口告知。

四道闸门

方案保存前要跑四个程序做校验。跳过事实核验的方案,会在生成页面最上方用用户自己的语言印一条「未经事实核验」横幅。

交付产物

Construction 任务不交齐以下文件不算完成,全部是普通文件,存在用户自己的文件夹里:

产物 内容
plans/<日期>-<标题>.json 结构化完整方案:每个选项、价格口径、来源 URL 与假设
html/<日期>-<标题>.html 单文件自包含页面:分时行程、逐段地图、预订卡片、预算表、来源登记
plans/<日期>-<标题>.ics 日历文件:已选或已订的交通、住宿、用餐与有时刻的安排,按当地时区写入

HTML 页面上包含:每天的真实时刻与步行分钟数时间线;每段路程按当地实际可用服务商路由的导航链接;人均预算(每行写明口径与查询日期);步行负荷、预算构成、每日行程分散度的内嵌图表;真实地点的自由许可照片(字节内嵌,断网可看);一块「落地第一小时」面板(能否刷卡、如何上网、紧急联系方式、保险是否覆盖);以及一份来源登记,列出查了什么、何时查的、下单前还需复核什么。

用户订完后告知 skill,页面会标出已订选项、折叠备选、合计已付金额。

安装与启用

仓库根目录本身就是这个 skill。四条安装路径任选其一。

方式一,用 npx skills 一行装完:

npx skills add dong845/travel-buddy

会询问 agent 与安装范围。加 -g 全局安装,加 -a claude-code 或 -a codex 跳过 agent 选择,加 -y 全程非交互,加 -l 只列出发现的 skill 而不安装。

方式二,作为 Claude Code 插件安装(可管理更新,也是唯一能覆盖云端会话的方式):

/plugin marketplace add dong845/travel-buddy
/plugin install travel-buddy@travel-buddy
/reload-plugins

插件里的 skill 带命名空间,调用形式为 /travel-buddy:travel-buddy。注意两点:如果在 ~/.claude/skills/ 里还留着手动装的副本,skill 会出现两次,系统不做去重,需手动删掉那份;第三方 marketplace 默认不自动更新,要拿新版本需执行 /plugin marketplace update travel-buddy。

方式三,克隆加软链(打算改代码选这个,改完立即生效):

git clone --depth 1 https://github.com/dong845/travel-buddy.git ~/code_project/travel-buddy
ln -s ~/code_project/travel-buddy ~/.claude/skills/travel-buddy

方式四,从 ClawHub 安装(OpenClaw 智能体的 skill 市场):

openclaw skills install @dong845/travel-buddy

SkillHub 上也有该 skill 的页面,适合浏览和横向比较,安装仍走上面四条路之一。

装完初始化一次工作区:

cd ~/.claude/skills/travel-buddy
python scripts/travel_workspace.py init          # 创建 ~/Travel Buddy/{profiles,plans,html}

启用时在 Claude Code 里敲 /travel-buddy,或直接描述需求,比如「帮我找个三月份暖和的地方待一周」。

典型用法

第一次使用,跑引导表单收集需求:

python scripts/start_intake_workflow.py --assistant auto

它会打印一个 http://127.0.0.1:<随机端口>/?token=… 链接,在浏览器里打开、填写、保存,同一标签页会自动跳到本次行程表单。提交之后,存好的路径交回给正在对话的那个助手,不会在背后另起一个 agent。不需要下载、搬运、上传或粘贴 JSON,也不用打「继续」。

其他常用参数:

# 先复核/修改已保存的稳定偏好,再进入本次行程表单
python scripts/start_intake_workflow.py --edit-profile

# 有多个档案时传 ID(不是路径)
python scripts/start_intake_workflow.py --profile alice --assistant claude

# 完全关掉自动接续
python scripts/start_intake_workflow.py --assistant none

# CLI 无法把命令放到后台时,让脚本自己去后台
python scripts/start_intake_workflow.py --detach

对话触发方式,装好之后直接说:

用 travel-buddy —— 五月有 7 天、预算 1500 欧左右,从阿姆斯特丹出发,我该去哪儿?
用 travel-buddy —— 秋天想去日本玩 8 天,先帮我把城市定下来。
用 travel-buddy —— 帮我们两个人排瑞士六日,湖区和老城,不要长距离步行。
用 travel-buddy —— 这是我存好的方案,日期往后挪了一周,哪些要改?

目的地定了之后,可以跑一次证据源探测,看看这台机器上哪些来源能回答各类问题(官方、运营商、餐饮、住宿、百科、汇率):

python scripts/probe_sources.py --market <name>

工作区与隐私

工作区结构固定为三部分:

~/Travel Buddy/
├── profiles/   # 自愿保存的可复用旅行者档案
├── plans/      # intake、工作流事件、方案 JSON、发现任务日志
└── html/       # 最终的只读浏览型行程页

会存的字段:国籍、居留国家与居留身份类别、语言、常住城市与可接受机场、常用货币、节奏、住宿档次、无障碍与饮食需求、去过的地方、心愿单、明确排除项。

永远不存:护照或证件号码与图像、签证有效期、支付或银行信息、账号密码、精确住址、本地身份证号、私人账号上下文。表单服务端会直接拒绝包含这类字段的提交。

档案只在用户勾选同意后创建,最新一次指令永远压过已保存的值。删除档案是刻意手动的操作,没有 forget 子命令:

rm "~/Travel Buddy/profiles/<你点名的那个>.json"

适用场景与注意

适合的场景:目的地尚未确定时的灵感发现与比较;已有范围但需在候选城市间取舍;需要带来源与预算口径的逐日行程;行程定好后条件变化需要增量重排。

使用时需要注意:

  1. 隐私字段边界要守住。入境可行性只记录居留身份类别(如 eu_eea_ch_citizen、member_state_residence_permit 等),不记证件号、有效期、支付信息、精确住址。
  2. 中国大陆路线要把高德地图/Amap 作为地图链接的首选候选,而不是 Google Maps。按目的地服务市场与旅行者实际可用的服务商路由,不要假设全球某个平台在所有国家都能用。
  3. 不要用 VPN、代理、账号绕道或共享凭据来让某个服务跑起来。
  4. 表单的工作模式必须与目的地状态一致:fixed 对应 construction,anchored 对应 constrained_discovery,其余对应 discovery。服务端会故意拒绝矛盾组合,报「不支持的本次旅行需求格式」时先检查这一点。
  5. --assistant auto 下自动接续没有反应,通常是正确行为而不是故障:只要本 skill 已有当前对话上下文,工作流就不会另起规划器。
  6. 抓不到的数据就标注未获取。宁可留一条 range 或一次复核步骤,也不要用猜测填平。

结尾

travel-buddy 的价值在于它把「能说的」和「查过的」分开处理:先证明目的地成立,再排行程;行程里每一条价格、营业时间和入境规则都带来源与查询时间;查不到就写查不到。产物是标准文件(JSON / HTML / ICS),存在用户自己的目录里,不登录、不支付、不同步云端。

官方地址:https://www.skillhub.cn/skills/user_f486c577/travel-buddy
仓库:https://github.com/dong845/travel-buddy

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜