【腾讯位置服务开发者征文大赛】AI驱动的智能旅途规划助手
技术栈:腾讯地图 GLJS SDK + SiliconFlow AI API + 原生 JavaScript
项目类型:单文件Web应用(index.html,约3900行)
目录
- [项目背景与痛点分析](#1-项目背景与痛点分析)
- [产品核心理念](#2-产品核心理念)
- [技术架构与腾讯位置服务集成](#3-技术架构与腾讯位置服务集成)
- [创新功能详解](#4-创新功能详解)
- [AI能力集成与工程实践](#5-ai能力集成与工程实践)
- [关键技术难点与解决方案](#6-关键技术难点与解决方案)
- [项目展示与Demo](#7-项目展示与demo)
- [总结与展望](#8-总结与展望)
1. 项目背景与痛点分析
1.1 旅行规划的现状痛点
在现代快节奏生活中,规划一次出行往往需要耗费大量时间:打开地图查路线、打开点评找景点、打开备忘录记行程……信息分散在多个App之间,最终得到的往往是一张截图或一条微信消息,到了现场依然一片混乱。
核心痛点有三:
- 信息割裂:路线、景点、时间、天气各自为政,没有一个工具能把它们串起来。
- 静态规划:传统规划是"死"的——临时改路线?重新查地图;时间不够?手动删节点;错过了景点?行程全乱。
- 缺乏智能:大多数工具只会"导航",不会"规划"——它们告诉你怎么走,但不会告诉你"应该去哪、待多久、怎么安排最合理"。
1.2 为什么选择腾讯位置服务
腾讯位置服务(Tencent Location Services)提供了完整的地图能力栈:
|
能力 |
腾讯位置服务产品 |
本项目用途 |
|
地图渲染 |
GLJS SDK |
高性能WebGL地图展示 |
|
路线规划 |
驾车/公交/步行/骑行路线规划API |
多模式路线计算 |
|
POI搜索 |
地点搜索API |
沿途推荐地点候选池 |
|
坐标解析 |
地点搜索(Suggestion) |
地名→坐标解析 |
|
地铁数据 |
地图底图+线路数据 |
地铁模式紫色路线展示 |
2. 产品核心理念
"策略必须是可执行的,而不仅仅是可读的。"
这是本项目设计的出发点。传统旅行攻略是"文章"——你读完了,然后呢?还是要自己打开地图、逐个搜索、手动规划。
本项目的核心理念是:让AI生成的行程,直接变成可交互的地图操作。
2.1 三大核心原则
① 结构化,而非文本化
AI输出不再是"建议早上8点从天安门出发,先去故宫……"这样的大段文字,而是严格的结构化JSON:
{
"summary": "经典皇城一日游,兼顾历史与自然风光",
"tips": "今日紫外线较强,建议携带防晒用品",
"nodes": [
{"type": "start", "place": "天安门广场", "stayMinutes": 0, "tips": "", "transport": "地铁1号线约15分钟"},
{"type": "waypoint", "place": "故宫博物院", "stayMinutes": 120, "tips": "建议提前网上预约门票", "transport": "步行约10分钟"},
{"type": "waypoint", "place": "景山公园", "stayMinutes": 60, "tips": "登顶可俯瞰故宫全景", "transport": "驾车约25分钟"},
{"type": "end", "place": "颐和园", "stayMinutes": 0, "tips": ""}
]
}
② 可交互,而非静态展示
每个行程节点都是可操作的卡片:
- 点击 → 地图飞到对应位置,弹出InfoWindow
- 修改停留时长 → 实时重算后续时间轴
- 删除节点 → 路线自动重规划
- 上下移动 → 调整游玩顺序
③ 双向联动,而非单向展示
地图上点击POI标记,可以直接"插入行程";行程面板里的节点,点击后地图同步定位。地图和行程是双向联动的,而不是两个互不相干的功能。
3. 技术架构与腾讯位置服务集成
3.1 整体架构
┌─────────────────────────────────────────────┐
│ 浏览器前端(单文件应用) │
│ index.html(~3900行,无构建工具依赖) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 地图视图 │ │ 行程面板 │ │ AI聊天 │ │
│ │(GLJS SDK)│ │(时间轴) │ │(侧边栏)│ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴─────────────┴─────────────┴────┐ │
│ │ 核心状态管理(appState) │ │
│ │ waypoints[] / itineraryData / map │ │
│ └──────────────────┬──────────────────────┘ │
└─────────────────────┼──────────────────────────┘
│
┌────────────┴────────────┐
│ │
┌──────┴──────┐ ┌─────┴──────┐
│ 腾讯位置服务 │ │ SiliconFlow │
│ GLJS SDK │ │ AI API │
│ 路线规划API │ │ (Qwen2.5-32B)│
│ POI搜索API │ └────────────┘
└─────────────┘
3.2 腾讯地图GLJS SDK集成
项目使用腾讯地图GLJS SDK(WebGL渲染),核心集成代码如下:
// 初始化地图
const map = new TMap.Map('map-container', {
center: new TMap.LatLng(39.9087, 116.3975), // 北京天安门
zoom: 12,
viewMode: '2D',
});
// 驾车路线规划(核心功能)
function planRoute() {
const driving = new TMap.service.DrivingService({
map: map,
});
driving.search({
from: startLocation,
to: endLocation,
waypoints: waypoints, // 支持途经点
policy: 'REAL_TRAFFIC', // 实时路况
}).then(response => {
// 渲染路线 + 沿路线搜索POI
renderRoute(response.result.routes[0]);
searchPOIAlongRoute(start, end, keyword, routePath);
});
}
3.3 地铁模式的特殊处理
腾讯位置服务的Transit API(公交路线规划)对地铁的展示不够直观,因此本项目不用Transit SDK,而是:
- 用驾车路线规划模拟地铁线路(起点→终点,途经地铁站)
- 用紫色加粗Polyline渲染,与普通驾车路线区分
- 在地图上标注地铁站出入口POI
4. 创新功能详解
4.1 功能一:AI推荐途径点(先推荐,后规划)
这是本项目最具创新性的功能。传统路线规划是"填起终点→直接出路线",但用户往往不知道沿途有什么值得停的地方。
新流程(方案C):
用户输入起终点
↓
系统规划基础路线
↓
沿路线搜索POI(候选池)
↓
AI筛选推荐(5~8个精选地点)
↓
用户勾选想要去的途径点
↓
AI生成完整行程(含时间推算)
核心代码——AI推荐函数:
async function aiRecommendPOIs(pois, start, end, durationSec, distanceM) {
// 构建候选列表(最多20个,避免token超限)
const candidates = pois.slice(0, 20).map((p, i) =>
`${i+1}. ${p.title}(类别:${p.category},距路线约${p._routeDist}m)`
).join('\n');
const prompt = `用户从"${start.name}"到"${end.name}",${durationMin}分钟${distKm}公里。
从候选中挑5个最值得停留的:
${candidates}
只返回JSON数组:[{"index":1,"reason":"理由","stayMinutes":60}]`;
const response = await fetch(SILICONFLOW_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${SILICONFLOW_API_KEY}`,
},
body: JSON.stringify({
model: 'Qwen/Qwen2.5-32B-Instruct',
messages: [
{ role: 'system', content: '只返回纯JSON数组,不要包含markdown标记或任何其他文字。' },
{ role: 'user', content: prompt }
],
stream: false,
temperature: 0.2,
max_tokens: 500,
}),
});
// ...解析推荐结果,渲染可勾选面板
}
用户侧体验:
推荐面板展示每个推荐地点的:
- 地点名称 + 类别标签
- AI生成的推荐理由(15字以内)
- 建议停留时间
- 勾选框——用户按需选择,不强制全选
4.2 功能二:可设定出发时间的动态时间轴
行程面板顶部有出发时间输入框,用户可以:
- 使用当前时间(默认)
- 设置为明天早上8点(规划未来行程)
- 时间轴根据出发时间动态重算
时间轴效果:
08:00 天安门广场(起点)
↓ 地铁1号线 约15分钟
08:15 故宫博物院
停留 120 分钟
↓ 步行 约10分钟
10:15 景山公园
停留 60 分钟
↓ 驾车 约25分钟
11:40 颐和园(终点)
4.3 功能三:AI推荐玩法(生成式行程建议)
除了结构化行程,AI还会生成文字版的游玩建议,融入天气、时间、景点特色:
// generateTravelStrategy 函数中的prompt核心部分
const prompt = `请为以下行程生成JSON行程规划。
今天:${todayStr} ${timeStr},天气:${weatherText}
起点:${start.name}
终点:${end.name}
交通:${modeLabel},约${durationMin}分钟
严格按此JSON格式返回:
{"summary":"一句话建议","tips":"天气提示","nodes":[...]}
规则:
1. 必须以{开头}结尾,纯JSON,无markdown
2. nodes首尾必须是start和end
3. 最多5个waypoint节点
4. stayMinutes:景区60-120,餐饮45,普通30
5. 最后一节点无transport
6. 所有字符串值必须用双引号`;
5. AI能力集成与工程实践
5.1 为什么选择SiliconFlow + Qwen2.5-32B
|
方案 |
优点 |
缺点 |
最终选择 |
|
直调腾讯位置服务API |
无额外成本 |
无AI能力 |
❌ |
|
调用OpenAI GPT-4o |
能力强 |
需科学上网、收费高 |
❌ |
|
调用文心一言 |
国内访问 |
需百度账号、配额有限 |
❌ |
|
SiliconFlow Qwen2.5-32B |
国内直连、JSON输出稳定、性价比高 |
需API Key |
✅ |
5.2 JSON输出稳定性保障(工程重点)
AI生成JSON的最大问题是输出不稳定——可能带markdown代码块、可能截断、可能有语法错误。本项目实现了四层容错解析:
function parseItineraryJSON(raw) {
if (!raw || typeof raw !== 'string') return null;
// 策略1:直接解析(理想情况)
try {
const obj = JSON.parse(raw.trim());
if (obj.nodes && Array.isArray(obj.nodes)) return obj;
} catch (e) {}
// 策略2:提取 ```json ... ``` 代码块
const codeBlockMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
if (codeBlockMatch) {
try {
const obj = JSON.parse(codeBlockMatch[1].trim());
if (obj.nodes && Array.isArray(obj.nodes)) return obj;
} catch (e) {}
}
// 策略3:找第一个 { 到最后一个 },并尝试修复
const firstBrace = raw.indexOf('{');
const lastBrace = raw.lastIndexOf('}');
if (firstBrace !== -1 && lastBrace > firstBrace) {
let jsonStr = raw.substring(firstBrace, lastBrace + 1);
const repaired = repairJSON(jsonStr); // 关键:自动修复
if (repaired) {
try {
const obj = JSON.parse(repaired);
if (obj.nodes && Array.isArray(obj.nodes)) return obj;
} catch (e2) {}
}
}
// 策略4:暴力提取nodes数组
const nodesMatch = raw.match(/"nodes"\s*:\s*\[/);
if (nodesMatch) {
// ...尝试从nodes字段重建完整JSON
}
return null;
}
// 自动修复常见的AI输出JSON错误
function repairJSON(str) {
let s = str;
s = s.replace(/,\s*([}\]])/g, '$1'); // 去掉尾部逗号
s = s.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":'); // 补键名引号
s = s.replace(/:\s*'([^']*)'/g, ':"$1"'); // 单引号→双引号
// 补全缺失的闭合符号
const openBraces = (s.match(/{/g) || []).length;
const closeBraces = (s.match(/}/g) || []).length;
for (let i = 0; i < openBraces - closeBraces; i++) s += '}';
return s;
}
5.3 天气信息的融合
行程建议结合实时天气,提升实用性
async function getWeather(cityName) {
const weatherUrl = `https://wttr.in/${encodeURIComponent(cityName)}?format=j1`;
const response = await fetch(weatherUrl, { signal: AbortSignal.timeout(5000) });
if (response.ok) {
const data = await response.json();
const cur = data.current_condition?.[0];
return `当前:${cur.weatherDesc?.[0]?.value},${cur.temp_C}℃,体感${cur.FeelsLikeC}℃`;
}
return '(未获取到天气信息)';
}
6. 关键技术难点与解决方案
6.1 难点一:途径点与行程的双向同步
问题:用户可以在地图上手动添加途径点(waypoints[]),也可以让AI生成行程(itineraryData.nodes)。这两套数据之前互不感知——用户在地图上加了点,AI生成的行程里没有;AI生成的行程里的点,地图上的标记不对应。
解决方案——融合联动:
// 在 addWaypointFromPOI 中(地图上点标记→添加途径点)
function addWaypointFromPOI(lat, lng, name) {
waypoints.push({ name, lat, lng, stayDuration: 30 });
renderWaypointPanel();
// 【融合】同步到行程数据
if (itineraryData && itineraryData.nodes) {
itineraryData.nodes.splice(endIdx, 0, {
type: 'waypoint', place: name, stayMinutes: 30, lat, lng
});
renderItineraryCards(itineraryData);
}
}
// 在 removeItineraryNode 中(行程面板删除节点→同步途径点)
function removeItineraryNode(idx) {
const node = itineraryData.nodes[idx];
if (node.type === 'waypoint') {
// 【融合】从 waypoints[] 中同步删除
const wpIdx = waypoints.findIndex(w =>
Math.abs(w.lat - node.lat) < 0.01 && Math.abs(w.lng - node.lng) < 0.01
);
if (wpIdx >= 0) waypoints.splice(wpIdx, 1);
renderWaypointPanel();
}
itineraryData.nodes.splice(idx, 1);
renderItineraryCards(itineraryData);
}
6.2 难点二:沿路线搜索POI的性能优化
问题:路线有几百个坐标点,对每个点做POI搜索是不可能的(API配额不够,也太慢)。
解决方案——抽样+距离过滤:
async function searchPOIAlongRoute(from, to, keyword, routePath) {
// 1. 对路线坐标抽样(每10个点取1个)
const sampledPoints = routePath.filter((_, i) => i % 10 === 0);
// 2. 并行搜索多个代表点(限制并发数)
const results = [];
for (const point of sampledPoints.slice(0, 5)) {
const pois = await searchNearby(point, keyword, 2000);
results.push(...pois);
}
// 3. 去重(同名POI只保留距离路线最近的)
const unique = deduplicatePOIs(results);
// 4. 计算每个POI到路线的距离(判断是否在沿途)
for (const poi of unique) {
poi._routeDist = minDistanceToRoute(poi.location, routePath);
}
return unique.filter(p => p._routeDist < 3000); // 3公里以内
}
6.3 难点三:单文件架构的代码组织
问题:index.html是单文件应用(~3900行),HTML/CSS/JS全在一起,维护困难。
解决方案——逻辑分区+函数命名规范:
/* ============ 分区1:地图与路线 ============ */
function initMap() { ... }
function planRoute() { ... }
function renderRoute() { ... }
/* ============ 分区2:途经点管理 ============ */
function addWaypoint() { ... }
function removeWaypoint() { ... }
function renderWaypointPanel() { ... }
/* ============ 分区3:AI行程规划 ============ */
function generateTravelStrategy() { ... }
function parseItineraryJSON() { ... }
function renderItineraryCards() { ... }
/* ============ 分区4:推荐系统 ============ */
function aiRecommendPOIs() { ... }
function renderRecommendPanel() { ... }
function confirmRecommendation() { ... }
7. 项目展示与Demo
ai旅途规划demo
7.1 功能演示流程
场景例:北京西站到故宫
第一步:输入起终点
在左侧边栏输入或与ai助手直接沟通

第二步:AI推荐途径点

第三步:查看AI生成的行程


【复制行程单】(示例):
📅 2026年5月8日 行程规划
🚦 出行方式:🚗 驾车
📝 建议合理安排行程,避免疲劳
☀️ 今天天气阴,气温适中,适合出行
────────────────────────────
08:00 🟢 出发 北京西站
💡 从北京西站出发,天气阴,温度26℃
→ 驾车约34分钟
08:34 📍 途经 首都博物馆
停留 60 分钟
💡 首都博物馆是了解北京历史的好地方
→ 驾车约10分钟
09:44 📍 途经 什刹海公园
停留 90 分钟
💡 什刹海公园环境优美,适合散步
→ 驾车约15分钟
11:29 📍 途经 景山公园
停留 90 分钟
💡 景山公园可以俯瞰故宫全貌
→ 驾车约10分钟
13:09 📍 途经 前门大街景区
停留 90 分钟
💡 前门大街是体验北京传统文化的好去处
→ 驾车约15分钟
14:54 🔴 终点 故宫
停留 120 分钟
💡 故宫是北京的标志性景点,建议提前购票
────────────────────────────
🏁 预计 16:54 到达终点
由旅途规划 AI 助手生成
第四步:动态调整
- 用户把故宫的停留时间改为90分钟 → 时间轴自动重算,后续节点时间整体偏移
- 用户删除景山公园 → 路线自动重新规划(故宫直连颐和园)
- 用户点"颐和园"卡片 → 地图飞到颐和园位置,弹出InfoWindow
8. 总结与展望
8.1 项目创新点总结
|
创新点 |
传统工具 |
本项目 |
|
行程生成 |
大段文字,不可交互 |
结构化JSON,可点击/修改/删除 |
|
途径点规划 |
用户自己想 |
AI沿路线推荐,可勾选 |
|
时间管理 |
静态,不改了 |
动态时间轴,改停留时长自动重算 |
|
地图联动 |
无 |
双向联动,点击即跳转 |
|
AI能力 |
无或仅聊天 |
深度集成,生成+推荐+对话三位一体 |
8.2 腾讯位置服务的价值体现
本项目中,腾讯位置服务提供了完整的位置能力栈:
- GLJS SDK:高性能WebGL地图,路线渲染流畅
- 路线规划API:多模式(驾车/公交/步行/骑行)全覆盖
- POI搜索API:丰富的地方数据库,沿途推荐有数据支撑
- 坐标解析:地名→坐标,让AI生成的文字变成地图上的实实在在的标记
8.3 未来展望
阶段二:一句话生成完整攻略
当前版本需要用户手动输入起终点、选择途径点。未来的目标是真正的自然语言意图理解:
用户说:"去西湖玩一天,偏小众一点,下午要留时间喝茶。"
系统直接输出完整的可交互行程。
实现路径是在现有结构化行程 JSON 的基础上,引入对话式修改上下文——用户说"把第三个景点换成更冷门的",AI 识别意图、定位节点、就地修改,而不是推倒重来。整个行程对象始终保持结构化,支持用户自由拖拽调序、修改停留时长,最终一键"锁定方案"。
多日行程也是这一阶段的重要目标:AI 自动将景点按地理分区,合理规划每天的游玩范围,避免同一天在城市两端来回奔波。
阶段三:AI 预学习 + 随身导游(最终展望)
这是整个产品最令人期待的一跃。
行程确认之后、出发之前,存在一个宝贵的时间窗口。AI 利用这段时间主动学习目的地相关知识:景点历史典故、开放时间与门票规则、近期游客评价、节假日排队规律……用户出发时,AI 已经是一个"提前备课的本地通",而不是到了现场再临时现查。
真正到了旅途中,产品切换为随身导游模式:
- 位置感知触发讲解:用户走进故宫午门区域,AI 主动开口介绍历史背景,无需用户手动询问。
- 随问随答:游览途中任何疑问,直接语音提问,AI 基于预学习的知识即时回答。
- 行程动态调整:遇到排队过长或临时关闭,AI 实时感知并重排后续行程,推荐替代方案。
- MCP 协议集成:将腾讯位置服务封装为 MCP Server,让 AI Agent 能够自主调用地图、搜索、路线等全部能力,真正实现"AI 自主驾驶"式的旅行辅助。
这三个阶段的演进逻辑是一脉相承的:结构化行程是地基,一句话规划是效率革命,AI 导游是体验升华。每一步都建立在上一步积累的数据结构和 AI 能力之上,而腾讯位置服务的 POI 数据、路线规划、实时位置 API 则是贯穿始终的核心基础设施。
作者注:本项目为原创作品,所有代码均由作者独立编写。腾讯位置服务API的使用符合其开放平台规范。AI生成内容已做工程化处理,不代表腾讯位置服务的官方建议。
如果觉得这篇文章对你有帮助,欢迎点赞、评论、转发!你们的支持是我继续优化的动力 。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)