【2026飞猪AI旅行创新大赛】童行 · 带娃旅游规划器
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 1/100
- Issue 类型
- 功能
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- java, react, spring-boot, tailwindcss, typescript, vite
- 领域
- content
调研方向
This issue is a complete hackathon project submission for kidtrip-planner, with its own repository and deployed demo; it does not describe a change to this repository. Start by reviewing the linked project and demo to understand the submission. The described work is already implemented and tested, so there is no scoped change or completion criterion for a first contribution here.
由索引模型根据 Issue 内容生成。
描述
参赛项目名称
童行 · 带娃旅游规划器(仓库:kidtrip-planner)
和 AI 聊几句,它去飞猪查真实的景点、酒店和城际车次,然后排出一份带娃真能跑得完的行程。
👉 在线试用:http://114.132.233.6/(一次生成 30~60 秒,因为它真的在查)
团队 / 作者与奖品领取人
- 团队名称:童行
- 主要提交人 GitHub ID(仅 1 位,必填):heyan0805
- 其他成员(可选,仅用于署名):无(个人参赛)
旅行场景与目标用户
场景:带娃出行的行前行程规划。不是"帮我推荐去哪儿玩",而是用户已经把目的地和日期定了,需要有人把"每天几点去哪、两个点之间怎么走、住哪、回程车几点"排出来。
目标用户:带 1-2 个孩子的家庭,孩子集中在 3-10 岁,一趟 2-7天,以周边游和国内中短途为主;出行时通常推着婴儿车、背着一天的口粮,对"临时改主意"的容错很低。](url)
用户真正的痛点不是订票,是"排"。 带娃出门贵的不是机票,是时间:每天去哪儿、几点去、两个点之间多远、孩子会不会走到崩溃、酒店要不要换、回程车几点——这些排起来比订票费神得多。而市面上的 AI 旅行助手大多在编:编一个不存在的营业时间,编一句"步行可达"其实隔着 40 公里。
带娃场景对这类错误的容忍度极低:一个排错的下午,就是孩子在陌生城市的街头哭。所以这个场景有三条硬约束,直接决定了产品必须长成什么样:
- 每天能跑的景点有限 —— 3 个是带娃的现实上限,而同行有 3 岁以下幼儿时压到 2 个;
- 必须考虑到达时刻 —— 去程 14:16 才到,上午 09:30 就不该排景点;
- 距离和换乘是硬门槛,不是"建议" —— 推着车走两公里和空手走两公里不是一件事。
我做了什么
一句话:对话攒需求 → 真实数据检索 → 规则层校验 → 模型排程 → 事实回填,最后交出一份每个数字都能核对的行程。
核心功能
- 对话式需求采集:不填表。用自然语言聊出出发地、目的地、天数、日期、孩子年龄、是否带推车等必填项,缺什么追问什么,已确认的不会被覆盖。
- 支持多个孩子:收的是每个孩子的年龄(不是"几个孩子"),排程按最小的那个算体力上限——"5 岁 + 10 岁"不是"7.5 岁",两个孩子也不会变成"能多排两个景点"。
- 画像(推论层):从用户的表达里推出"怕走路 / 怕人多 / 需要午休 / 预算敏感"这类偏好,每一条都必须附上用户自己的原话作为证据,在界面上与推论并列显示。
- 真实数据检索:经飞猪 FlyAI CLI 查景点(35 个类别)、酒店(按星级档)、城际班次(火车 / 机票),带真实的名称、价格、经纬度、图片和购票链接。
- 行程组装:每天输出主题、景点、城际交通、备选、酒店、酒店备选、以及一句"为什么这么排"。呈现上做成一天一个节点的时间轴,景点可"换一个(还剩 N 个)"。
- 可溯源:页面底部"展开溯源"能看到这一趟真实发出的查询命令,以及被规则层筛掉的候选。成本是可见的。
创新点(全部有自动化测试钉住,不是设计口号)
① 模型不做事实,只做选择与表达。
名称、价格、坐标、图片、购票链接全部由后端从飞猪返回值回填;模型拿到的是一份带 poiId 的候选清单,它只能从里面挑,不能凭空造。模型只出现在三个位置:画像抽取、检索计划、行程组装。这一条把"幻觉"从"可能发生"变成结构上不可能——它没有可编的字段。
② 事实与推论分两份数据,合并规则故意相反。
TravelParams(用户说过的,事实)与 Persona(模型推的,推论)永不混存。前者"没答就保留旧值",后者"同 key 覆盖、没提保留"。推论入档要过两道闸门:维度闭集(只允许 4 个 key)+ evidence 逐字回查(证据必须在用户真实消息里出现过,防止模型自说自话补证据)。为什么"孩子的兴趣"不进这个闭集:兴趣是多值的,而闭集是单值结构——设计新维度前先问"它一次会不会取多个值",会就不该进来。
③ 节奏由"生理事实"决定,不由"偏好"决定。
每天排几个点看两个变量:pace(用户选的快/慢,属偏好)与最小孩子年龄(属生理事实)。同行有 3 岁及以下时,即使选了"快",每天也压到 2 个点——偏好可以让行程放松,但不能让孩子走不动。同理,人再多也不加景点:多一个大人在交通上省的是钱,不是时间。
④ 兜底三级,且"不知道"≠"没有"。
本地重算(免费)> 再问模型 > 报错。查询失败与查询为空严格区分:某天航班这次没查成,界面会明说"这次没查成,不代表这条线没有合适的航班";而上游明确说没有,就原样转述、不加这句。把不确定性如实交还用户,而不是沉默或假装没这回事。
⑤ 每天那句"为什么这么排"是模板拼的,不是模型写的。
里面的数字(当天跨度、空档时长、车次时刻)必须来自本地已算出的事实。凡是能被用户核对的句子,就不交给模型自由发挥——与"价格由后端回填"是同一条原则。这一条还挡住了最隐蔽一种错:用户说过"体力很好",这句话绝不能被引用成"今天排得轻松"的理由。
⑥ 犯错时人一定看得见。
模型偶尔仍会排出 24 公里的跨度。兜底校验不假装没发生,而是在界面上写一句人话告诉用户。不指望它不犯错,但犯错时必须可见。
⑦ 限流是设计约束,不是事后补丁。
飞猪 CLI 是外部限流接口(并发 3~6 个即 429,密集串行会 451 风控),因此查询做了串行锁 + 间隔 + 缓存 TTL + 退避,并优先用"宽查"一次覆盖多个类别。产品允许慢,但不允许"时好时坏"。
工程质量
- 后端 378 个单元测试 / 26 个测试类全绿;前端 mock 全链路验收 49 项、端到端(真实模型 + 真实上游)30 项通过。
- 关键断言做过注入验证:把被测代码故意改错,确认测试真的会失败,再恢复——避免"测试写了但从来没红过"的假绿。这一轮多孩子功能就做了 2 组(把
≤3 岁改成≤0、把"整体替换"改成"永不替换",都如期变红)。 - 已部署上线并端到端实测:一次真实生成 34~45 秒返回完整行程(真实景点、图片、坐标、购票链接)。架构为 nginx 反代 + systemd 守护,后端只监听
127.0.0.1,不直接暴露公网;配置与密钥全部走环境变量。
百炼使用说明(必填)
-
百炼能力 / 模型:通义千问
qwen3.8-flash(百炼工作区专属网关,北京地域)。只使用 Chat Completions(文本对话 + JSON 结构化输出)这一项能力,未使用向量检索、微调、Agent 编排等其它能力。 -
调用方式:百炼 API(OpenAI 兼容模式)。
基址https://ws-<workspace-id>.cn-beijing.maas.aliyuncs.com/compatible-mode/v1,请求路径/chat/completions;客户端为 LangChain4j 1.18 的OpenAiChatModel(换 baseUrl + apiKey 即可对接,不绑定厂商 SDK)。
未使用 DashScope SDK、百炼 CLI(bl)、OpenWork。 -
使用环节与输入输出:完全位于运行时链路(不在开发链路;代码与 prompt 都是自己写的,模型只在服务运行时被调用)。一次"生成行程"共 3 个环节:
环节 输入 输出 调用次数 对话攒需求( ChatComposer)对话消息 + 已确认参数 + 已有画像 一句回复 + 更新后的参数(含 childAges数组)+ 新增/修正的画像条目每轮对话 1 次 检索计划( RetrievalPlanner)已齐参数 + 今天的日期 + 35 个 POI 类别清单 + 城市名白名单 结构化 JSON 检索骨架(城市、日期区间、各类别查询词、酒店星级档) 1 次(JSON 解析失败带提示重试 1 次) 行程组装( PlanComposer)参数 + 画像 + 真实候选清单(景点/酒店/车次,含 poiId、价格、坐标、发到时刻)+ 规则约束(点数上限由节奏与最小孩子年龄共同决定) 每天的主题、所选 poiId 及顺序、时段、注意事项 1~2 次(校验不过则回退重排) 即:总调用次数 = 对话轮数 + 2~3 次。全部调用走同一条 OpenAI 兼容通道,模型只负责"选哪个、怎么说",不产出任何事实字段。模型输出还会经过一层结构强校验:字段名逐字对齐、编号对不上直接丢弃并记入"被筛掉的候选"、非法 JSON 带提示重试。
-
Skill 名称:无。未使用百炼 Skill / 插件,全部为后端自建 prompt + 输出结构强校验。
-
其他工具 / 技术栈:
- 飞猪 FlyAI CLI(
@fly-ai/flyai-cli):唯一的真实数据源,取 POI、酒店、城际班次;串行调用 + 缓存 + 退避以规避限流。 - 后端:Spring Boot 4.1 + Java 21 + LangChain4j 1.18(Jackson 3)。
- 前端:React 19 + TypeScript + Vite 8 + Tailwind 3。
- 部署:腾讯云轻量服务器(4C4G),nginx 反代静态页与
/api,systemd 守护后端(开机自启、崩溃自动拉起),配置与密钥全部走环境变量,与代码分离。
- 飞猪 FlyAI CLI(
效果展示
https://github.com/user-attachments/assets/c60e9010-f964-4941-b927-5fcfff53ff6a
项目链接与复现方式
| 入口 | 地址 | 说明 |
|---|---|---|
| GitHub 仓库 | https://github.com/heyan0805/kidtrip-planner | public,MIT。仓库里没有任何真实密钥,所有密钥位置都是 ${...} 占位符 |
| 在线 Demo | http://114.132.233.6/ | 打开就能用,不用注册、不用装环境。同一台 4C4G 轻量服务器上跑 nginx + 后端 |
| 演示视频 | 暂无 | 在效果展示里,有加快速度的gif |
最快体验(不用装任何东西,约 1 分钟)
打开 http://114.132.233.6/ → 输入「想带孩子去珠海玩 3 天,孩子 6 岁」→ 补答它追问的出发城市和日期 → 点生成。
一次 30~60 秒(它不是装慢,是真在查飞猪的景点、酒店和车次)。
几个值得留意的地方:每天的时间轴(点位、耗时、距离);景点卡右上角「换一个(还剩 N 个)」;点了缩略图能看大图,一天有多个场景时可左右翻;页面底部「展开溯源」能看到这一趟真实发出的查询命令和被规则筛掉的候选。
只跑前端(不装 Java、不配密钥,约 2 分钟)
git clone https://github.com/heyan0805/kidtrip-planner.git
cd kidtrip-planner/frontend
npm install
VITE_USE_MOCK=true npm run dev # → http://localhost:5173
Windows PowerShell 里第一句换成:$env:VITE_USE_MOCK="true"; npm run dev
假数据能跑通全流程。降级刻意做得很显眼:界面上有黄色横幅、行程里的名字都带「(假数据)」——静默降级会让人拿着一份编出来的行程去订酒店。
完整复现(前后端 + 真实数据)
前置:Node ≥ 20.19 或 ≥ 22.12(Vite 8 硬要求)· JDK 21 · Maven 3.9+ · npm i -g @fly-ai/flyai-cli · 一份 OpenAI 兼容的模型 Key(本项目实测百炼 · 通义千问)· 黑客松发放的飞猪 FlyAI 凭据(~/.flyai/config.json 与 device-id,按 FlyAI CLI 的说明放置)。
# 1) 环境变量(都不是可选项:仓库里故意不留默认值)
export KIDTRIP_LLM_API_KEY=sk-xxxx
export KIDTRIP_LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
export KIDTRIP_LLM_MODEL_NAME=qwen-plus
export KIDTRIP_LLM_ENABLE_THINKING=false # 用千问 3.x 必填,否则非流式请求会被网关掐断
export FLYAI_CLI_PATH="$(npm root -g)/@fly-ai/flyai-cli/dist/flyai-bundle.cjs"
# 2) 后端 → http://localhost:8003(首次启动会联网拉 Maven 依赖)
cd backend && mvn spring-boot:run
# 3) 前端 → http://localhost:5173(另开一个终端)
cd frontend && npm install && npm run dev
启动自检:curl http://localhost:8003/api/health 应返回 {"code":0,"message":"ok",...}。
缺密钥时后端会在启动阶段直接报「缺少配置 kidtrip.llm.api-key」,不会等到你点生成才失败——失败趁早,且带着"该怎么修"一起失败。
跑测试:cd backend && mvn test → 378 个用例全绿,不需要任何密钥(模型用 FakeChatModel 替身,测试不碰网络)。
没有飞猪凭据怎么办:后端能起来,但检索层查不到数据,生成会如实报"这次没查成"(不做假数据冒充)。这种情况下建议直接用上面的 mock 模式体验界面与交互。
关于密钥(模板要求,明确回应)
- 仓库里 没有 提交任何 API Key、密码、token、私钥;模型密钥、飞猪凭据全部走环境变量注入。
- 唯一需要说明的是飞猪凭据不能共享:它绑设备标识,且上游对访问来源有风控(机房 IP 实测可用,但会波动)。所以在线 Demo 才是最省事的体验入口。
踩坑记录(可选)
千问 3.x 默认开启 thinking。思考期间链路上零字节流动,而百炼专属网关会把长时间无字节的非流式请求当空闲连接掐掉(客户端只看到 EOF reached while reading,看起来像网络故障)。因此请求体显式带 enable_thinking: false。
**奖品说明:**每个团队最多发放 1 份奖品。同一团队即使提交多个参赛作品,也只登记 1 位奖品领取人;其他团队成员可以共同署名,但不重复发放奖品。
- 主要语言
- HTML
- 星标
- 11
- 派生
- 3
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
modelstudioai/modelstudioai.github.io 的其他 Issue
-
2026飞猪AI旅行创新大赛 showcase
难度 2/5 1-3 小时 新手友好度 72/100
-
2026飞猪AI旅行创新大赛 showcase
难度 5/5 一周以上 新手友好度 1/100
-
难度 5/5 一周以上 新手友好度 25/100
-
2026飞猪AI旅行创新大赛 showcase
难度 5/5 一周以上 新手友好度 25/100
modelstudioai/modelstudioai.github.io#201 · 1 条评论 ·
-
难度 1/5 1 小时以内 新手友好度 35/100
modelstudioai/modelstudioai.github.io#199 · 1 条评论 ·
查看 modelstudioai/modelstudioai.github.io 的全部 Issue
相似的 Issue
-
难度 1/5 1 小时以内 新手友好度 68/100
-
难度 1/5 1 小时以内 新手友好度 85/100
521xueweihan/HelloGitHub#4074 ·
-
难度 1/5 1 小时以内 新手友好度 83/100
awesome-dsh-plugin/awesome-dsh-plugin#8715 ·
维护者通常 1 天内回复
-
Add: Pbs Kids未关闭check:passed streams:add
难度 2/5 1-3 小时 新手友好度 67/100
维护者通常 2 天内回复
-
难度 1/5 1 小时以内 新手友好度 66/100
维护者通常 2 天内回复