💡 核心观点:地图不应该是"你输入坐标、它输出路线"的被动工具,而应该是听得懂自然语言、看得见真实道路、会主动规划行程的出行大脑。本文完整呈现从原型到进阶的升级全过程。

在这里插入图片描述


腾讯位置服务官网https://lbs.qq.com

一、痛点:地图交互的最后一个短板

1.1 我们和地图之间,还差一个"翻译层"

你有没有过这种经历:

  • 周末想带孩子和老人出去转转,打开地图 App,输入目的地……然后不知道去哪
  • 想规划一个"不太累、有好吃、适合拍照"的半日游,结果在搜索框里只能一个关键词一个关键词地搜
  • 出差到陌生城市,想找酒店附近步行可达的餐馆,还要自己判断距离、方向、评价

问题出在哪?

传统地图的交互逻辑是 “坐标驱动”——你给坐标,它画线。但用户真正的需求是**“意图驱动”**的自然语言:「帮我规划一个适合周末亲子的路线,不要太累,有室内外结合,午餐人均 80 以内。」

这就是 AI + 地图 要解决的核心问题:让地图从"工具"进化为"大脑"

1.2 本文升级版 Demo 解决的核心问题

初版 Demo 存在几个明显短板(自我剖析):
在这里插入图片描述

问题 影响 升级方案
AI 意图解析用简单 includes 匹配,融合度约 40% 用户说"带娃出去玩"无法准确识别为亲子游 接入 LLM API + 扩展本地语义映射表
路线用直线连接,未贴合真实道路 可视化效果差,用户不信任 解码 polyline + 逐段调用 direction API
景点排序按 popularity,未考虑距离 推荐路线绕远、不紧凑 调用距离矩阵 API + 贪心最近邻算法
IP 定位函数定义了但未调用 每次都要手动选城市 初始化时自动 IP 定位
搜索框无自动补全 用户输入体验差 接入 suggestion API + 300ms 防抖下拉

二、技术架构:三层 + 双引擎

2.1 三层架构

在这里插入图片描述

层级 核心能力说明
用户交互层 (UI Layer) 自然语言输入、意图解析、搜索补全、结果可视化
AI 决策层 (AI Layer) LLM意图理解、参数抽取、距离矩阵编排
(支持OpenAI兼容接口/本地降级双引擎)
腾讯位置服务层 (Map Layer) WebService API/JSAPI GL/小程序
地理编码、POI搜索、路线规划、距离矩阵
IP定位、输入提示、坐标转换、热力图

核心升级:AI 决策层现在支持"双引擎"——有 LLM API 走云端,没有则自动降级到本地智能规则引擎,保证 Demo 在任何环境下都可运行。

与 workbuddy 对话过程如下图。
在这里插入图片描述

2.2 涉及的腾讯位置服务能力

能力 API 用途 对应 Skill
地理编码 /ws/geocoder/v1 地址 → 坐标 tencentmap-webservice-skill
逆地理编码 /ws/geocoder/v1 坐标 → 地址描述 tencentmap-webservice-skill
关键词搜索 /ws/place/v1/search 搜索景点/餐厅/酒店 tencentmap-webservice-skill
输入提示 /ws/place/v1/suggestion 搜索框自动补全 tencentmap-webservice-skill
驾车路线 /ws/direction/v1/driving 驾车导航 tencentmap-webservice-skill
步行路线 /ws/direction/v1/walking 步行导航 tencentmap-webservice-skill
公交路线 /ws/direction/v1/transit 公交出行 tencentmap-webservice-skill
骑行路线 /ws/direction/v1/bicycling 骑行规划 tencentmap-webservice-skill
距离矩阵 /ws/distance/v1/matrix 批量距离/时间计算 tencentmap-webservice-skill
IP 定位 /ws/location/v1/ip 用户位置自动获取 tencentmap-webservice-skill
坐标转换 /ws/coord/v1/translate GPS→GCJ-02 坐标转换 tencentmap-webservice-skill
JSAPI GL 初始化 TMap.Map 地图初始化 + 体验 Key 获取 tencentmap-jsapi-gl-skill
MultiMarker TMap.MultiMarker 多点标记渲染 tencentmap-jsapi-gl-skill
MultiPolyline TMap.MultiPolyline 真实道路折线渲染 tencentmap-jsapi-gl-skill
热力图 TMap.visualization.Heat POI 密集度可视化 tencentmap-jsapi-gl-skill
InfoWindow TMap.InfoWindow 点击标记弹出详情 tencentmap-jsapi-gl-skill
小程序地图组件 <map> + MapContext 移动端地图交互 tencentmap-miniprogram-skill

三、实现详解:从原型到进阶的完整升级

3.1 AI 意图解析:双引擎设计(升级核心)

与 workbuddy 对话过程如下图。
在这里插入图片描述
在这里插入图片描述

升级前:简单字符串匹配,query.includes('亲子') 这种方式,覆盖面窄,无法处理语义变体。

升级后:支持 LLM + 本地双引擎,融合度从 40% 提升到 90%+。

3.1.1 LLM 引擎(云端)
// AI_ENGINE.config - 支持任何 OpenAI 兼容接口
config: {
    mode: 'llm',  // 切换为 llm 模式
    apiUrl: 'https://api.deepseek.com/v1/chat/completions',
    apiKey: 'YOUR_KEY',
    model: 'deepseek-chat'
    // 也支持腾讯混元、OpenAI、Qwen 等所有兼容接口
}

Prompt 设计要点(保证结构化输出):

你是一个出行意图解析器。根据用户输入,输出结构化 JSON。
可用城市:北京、上海、广州、杭州、深圳
出行类型:general(通用)、family(亲子)、food(美食)、culture(文化)、tour(旅游)、leisure(休闲)

输出格式:
{
  "city": "城市名",
  "type": "出行类型",
  "preferences": ["偏好1", "偏好2"],
  "keywords": ["搜索关键词1", "关键词2"],
  "from": "起点名(如无则为null)",
  "to": "终点名(如无则为null)",
  "transport": "driving/walking/bicycling/transit",
  "confidence": 0.95
}
3.1.2 本地规则引擎(降级,智能版)

当用户没有配置 LLM API 时,自动降级到扩展后的本地语义映射表:

// 扩展后的语义映射(覆盖 7 种类型 × 3-6 个同义词)
const typeMap = [
    { patterns: ['亲子', '孩子', '小孩', '宝宝', '儿童', '带娃'], type: 'family', prefs: ['亲子友好', '步行距离短', '有室内备选'] },
    { patterns: ['美食', '吃', '餐厅', '小吃', '好吃', '餐饮', '馆子'], type: 'food', prefs: ['特色餐饮', '口碑好'] },
    { patterns: ['一日游', '游玩', '旅游', '旅行', '行程', '打卡'], type: 'tour', prefs: ['景点丰富', '路线合理'] },
    { patterns: ['轻松', '不太累', '休闲', '休闲游', '放松', '佛系', '不赶'], type: 'leisure', prefs: ['轻松休闲', '避免爬山'] },
    { patterns: ['文化', '博物馆', '艺术', '历史', '古迹', '展览'], type: 'culture', prefs: ['文化体验'] },
    { patterns: ['购物', '逛街', '商场', '买东西'], type: 'shopping', prefs: ['购物便利'] },
    { patterns: ['老人', '爸妈', '长辈', '老年', '父母'], type: 'general', prefs: ['轻松休闲', '步行距离短', '避免爬山'] },
];

关键升级:还支持「从 X 到 Y」的起点终点识别正则,以及城市模糊匹配(「魔都」→ 上海,「帝都」→ 北京)。


3.2 真实道路渲染:Polyline 解码 + 逐段规划

与 workbuddy 对话过程如下图。
在这里插入图片描述

升级前:用直线连接各景点,视觉效果差,用户不信任。

升级后:调用 direction API 获取每段路线的真实道路 polyline,解码后渲染。

3.2.1 前向差分解码(腾讯地图独有格式)

WebService API 返回的 polyline前向差分压缩数组

  • 前两个元素为绝对坐标(纬度、经度,需 ÷10⁶)
  • 后续每两个元素为整数差值(同样需 ÷10⁶)
// Polyline 前向差分解码(腾讯地图 WebService API 特有格式)
function decodePolyline(encoded) {
    if (!encoded || encoded.length < 2) return [];
    const points = [];
    let lat = encoded[0] / 1e6;   // 第一个点:绝对纬度
    let lng = encoded[1] / 1e6;   // 第一个点:绝对经度
    points.push({ lat, lng });
    // 后续点:整数差值累加
    for (let i = 2; i < encoded.length; i += 2) {
        lat += encoded[i] / 1e6;
        lng += encoded[i + 1] / 1e6;
        points.push({ lat, lng });
    }
    return points;
}
3.2.2 逐段调用 direction API 渲染真实道路
// 逐段规划,获取每段真实道路
async function fetchAndRenderRoute(stops) {
    const allPaths = [];
    for (let i = 0; i < stops.length - 1; i++) {
        const from = stops[i];
        const to = stops[i + 1];
        const route = await TMAP_WS.direction(from, to, currentMode);
        
        if (route && route.decodedPath && route.decodedPath.length > 0) {
            allPaths.push(...route.decodedPath);  // 真实道路坐标
        } else {
            // 降级:直线连接
            allPaths.push({ lat: from.lat, lng: from.lng });
            allPaths.push({ lat: to.lat, lng: to.lng });
        }
    }
    
    // 用 MultiPolyline 渲染真实道路
    polylineLayer = new TMap.MultiPolyline({
        map,
        styles: {
            route: new TMap.PolylineStyle({
                color: '#3777FF', width: 6,
                borderWidth: 2, borderColor: '#1A3A80',
                lineCap: 'round'
            })
        },
        geometries: [{
            id: 'route_real',
            styleId: 'route',
            paths: allPaths.map(p => new TMap.LatLng(p.lat, p.lng))
        }]
    });
}

3.3 距离矩阵编排:从 popularity 排序到 AI 贪心排序

升级前:按 popularity 字段排序,忽略景点间实际距离,导致路线绕远。

升级后:先调用距离矩阵 API 批量计算所有景点间的距离/时间,再用贪心最近邻算法排序。
在这里插入图片描述

// 调用距离矩阵 API(一次请求,N×N 矩阵)
const distResult = await TMAP_WS.distanceMatrix(selected, selected, currentMode);
if (distResult) {
    distances = distResult.map(row =>
        row.elements.map(el => ({
            distance: el.distance,  // 米
            duration: el.duration   // 秒
        }))
    );
}

// 贪心最近邻排序(AI 决策层)
const visited = [0];
const unvisited = new Set(Array.from({ length: n }, (_, i) => i).slice(1));
while (unvisited.size > 0) {
    const last = visited[visited.length - 1];
    let nearest = -1, nearestDur = Infinity;
    for (const idx of unvisited) {
        const row = distances[last]?.[idx];
        if (row && row.duration < nearestDur) {
            nearestDur = row.duration;
            nearest = idx;
        }
    }
    if (nearest >= 0) {
        visited.push(nearest);
        unvisited.delete(nearest);
    } else break;
}
itinerary.stops = visited.map(i => itinerary.stops[i]);

在这里插入图片描述

效果:用户说「帮我规划北京亲子游」,系统会自动把距离近的景点排在相邻位置,减少绕路。


3.4 IP 自动定位

与 workbuddy 对话过程如下图。
在这里插入图片描述

升级前TMAP_WS.locateByIP() 函数已定义但未调用,每次都要手动选城市。

升级后:地图初始化时自动调用 IP 定位,识别用户所在城市并居中显示。

// initMap() 中新增:IP 定位自动获取用户城市
async function initMap() {
    // Step1: 获取体验 Key(动态从腾讯地图官网抓取)
    const resp = await fetch('https://lbs.qq.com/webApi/uriV1/uriGuide/uriMobileMarker');
    const html = await resp.text();
    const match = html.match(/referer=([a-zA-Z0-9_-]+)/);
    mapKey = match ? match[1] : 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77';
    
    // Step2: 加载 JSAPI GL SDK(+ visualization 库)
    await loadJSAPI(mapKey);
    
    // Step3: 创建地图实例
    map = new TMap.Map('mapContainer', {
        center: new TMap.LatLng(39.9042, 116.4074),
        zoom: 11
    });
    
    // Step4: ⭐ IP 定位(升级新增)
    try {
        const loc = await TMAP_WS.locateByIP();
        if (loc && loc.ad_info && CITY_DATA[loc.ad_info.city]) {
            map.setCenter(new TMap.LatLng(
                CITY_DATA[loc.ad_info.city].center.lat,
                CITY_DATA[loc.ad_info.city].center.lng
            ));
            showToast(`已定位到:${loc.ad_info.city}`, 'success');
        }
    } catch { /* IP 定位失败不影响使用 */ }
}

在这里插入图片描述


3.5 搜索框自动补全

升级前:搜索框只有纯文本输入,无提示,用户体验差。

升级后:接入腾讯地图 suggestion API,输入 2 个字符即触发自动补全,300ms 防抖,点击即填入。

// 搜索框自动补全(对接 suggestion API)
async function handleSuggestion(keyword) {
    if (!keyword || keyword.length < 2) {
        document.getElementById('suggestionList').classList.remove('show');
        return;
    }
    try {
        const results = await TMAP_WS.suggestion(keyword);
        const list = document.getElementById('suggestionList');
        if (results.length === 0) { list.classList.remove('show'); return; }
        
        // 渲染下拉列表(最多 6 条)
        list.innerHTML = results.slice(0, 6).map(r => `
            <div class="suggestion-item" data-title="${r.title}">
                <div class="sug-title">${r.title}</div>
                <div class="sug-addr">${r.address || ''}</div>
            </div>
        `).join('');
        list.classList.add('show');
        
        // 点击补全项,自动填入输入框
        list.querySelectorAll('.suggestion-item').forEach(item => {
            item.addEventListener('click', () => {
                document.getElementById('userInput').value = item.dataset.title;
                list.classList.remove('show');
            });
        });
    } catch { /* 自动补全失败不影响体验 */ }
}

// 输入框绑定(300ms 防抖)
input.addEventListener('input', () => {
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => handleSuggestion(input.value.trim()), 300);
});

在这里插入图片描述


四、Demo 实战:升级后的完整功能清单

在这里插入图片描述

4.1 核心功能

升级后的 Demo 实现了以下功能:

功能模块 实现方式 升级点
自然语言输入 日常语言描述出行需求 支持更丰富的语义变体
智能意图解析 LLM API + 本地双引擎 🔥 新增 LLM 支持,融合度 90%+
POI 智能推荐 基于偏好搜索景点/餐厅 支持 7 种类型识别
多模式路线规划 驾车/步行/骑行/公交 支持 4 种出行方式切换
真实道路渲染 Polyline 解码 + 逐段 direction 🔥 升级核心,不再画直线
距离矩阵编排 贪心最近邻算法优化顺序 🔥 升级核心,路线更紧凑
IP 自动定位 locateByIP API 🔥 新增,自动识别用户城市
搜索自动补全 suggestion API + 防抖下拉 🔥 新增,输入体验提升
可视化展示 热力图 + 路线图 + 标记点 InfoWindow 点击弹出详情
智能建议输出 AI 综合分析给出最优方案 支持 LLM 生成个性化建议

在这里插入图片描述

4.2 关键技术决策

决策 选择 原因
前端框架 原生 HTML + CSS + JS 征文 Demo 尽量轻量,零依赖,单文件可运行
地图渲染 腾讯地图 JSAPI GL 3D 可视化效果最佳,支持 MultiMarker/Polyline/Heat
数据服务 腾讯地图 WebService API 功能全面,覆盖搜索/路线/编码/矩阵
跨域方案 JSONP 体验模式下 h5gw.map.qq.com 不支持 CORS
AI 集成 双引擎(LLM + 本地降级) Demo 可独立运行,有 Key 时自动升级

4.3 微信小程序端延伸

基于 tencentmap-miniprogram-skill,同样的能力可以快速迁移到微信小程序:

<!-- 小程序地图组件 -->
<map 
  id="travelMap"
  longitude="{{center.lng}}" 
  latitude="{{center.lat}}" 
  scale="12"
  markers="{{markers}}"
  polyline="{{polylines}}"
  show-location
  bindmarkertap="onMarkerTap"
/>
// 小程序端路线规划(使用 QQMapWX SDK)
const qqmapsdk = new QQMapWX({ key: 'YOUR_KEY' });

qqmapsdk.direction({
  mode: 'driving',
  from: { latitude: 39.98, longitude: 116.30 },
  to: { latitude: 40.01, longitude: 116.40 },
  success: (res) => {
    const coords = res.result.routes[0].polyline.map(p => ({
      latitude: p.lat, longitude: p.lng
    }));
    this.setData({ 
      polylines: [{ points: coords, color: '#3777FF', width: 6 }] 
    });
  }
});

五、踩坑记录与最佳实践

5.1 坐标系陷阱

腾讯地图使用 GCJ-02(国测局坐标系),GPS 原始坐标需要通过坐标转换接口处理:

// ⚠️ GPS坐标必须先转换
async function convertGPS(lat, lng) {
  const res = await jsonpRequest(
    'https://h5gw.map.qq.com/ws/coord/v1/translate',
    {
      locations: `${lat},${lng}`,
      type: 1, // GPS坐标
      key: 'none',
      apptag: 'lbscoord_translate'
    }
  );
  return res.result.locations[0]; // 转换后的GCJ-02坐标
}

5.2 路线 Polyline 解码

这是腾讯地图 WebService API 的一个特有格式,官方文档描述不够清晰,这里详细说明:

编码规则(前向差分):
  polyline[0] = 纬度绝对值 × 10⁶(浮点数)
  polyline[1] = 经度绝对值 × 10⁶(浮点数)
  polyline[2] = 纬度差值₁ × 10⁶(整数)
  polyline[3] = 经度差值₁ × 10⁶(整数)
  ...

解码步骤:
  1. 第一个点:lat = polyline[0] / 1e6, lng = polyline[1] / 1e6
  2. 后续每个点:lat += polyline[i] / 1e6, lng += polyline[i+1] / 1e6

常见错误:把 polyline 当成 [lat, lng, lat, lng, ...] 的简单交替数组,导致坐标完全错误。

5.3 体验模式注意事项

使用腾讯位置服务体验 Key 开发时,需注意:

  • 所有后端服务调用走 h5gw.map.qq.com + JSONP(不支持 CORS)
  • 地图前端加载走 map.qq.com/api/gljs(需带 key 参数)
  • 天气查询和电动车路线不可用,需正式 Key
  • 频次受限,开发测试够用,上线前务必切换正式 Key
  • 动态获取体验 Key:可从 https://lbs.qq.com/webApi/uriV1/uriGuide/uriMobileMarker 页面动态抓取,避免硬编码失效

5.4 LLM 接口适配技巧

腾讯混元、DeepSeek、OpenAI 的 API 格式略有差异,统一用 OpenAI 兼容格式封装:

// 统一调用入口(支持所有 OpenAI 兼容接口)
async callLLM(messages) {
    const res = await fetch(this.config.apiUrl, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.config.apiKey}`
        },
        body: JSON.stringify({
            model: this.config.model,
            messages,
            temperature: 0.3,
            response_format: { type: 'json_object' } // 强制 JSON 输出
        })
    });
    const data = await res.json();
    return JSON.parse(data.choices?.[0]?.message?.content);
}

关键response_format: { type: 'json_object' } 是 OpenAI/DeriveSeek 都支持的参数,可以保证 LLM 输出合法 JSON,避免解析失败。


六、性能优化建议

6.1 结合 AI 分析出的建议

  1. 合并请求:用距离矩阵替代循环调用路线接口,N×M 次请求降为 1 次
  2. 数据缓存:POI 搜索结果和地理编码结果按城市+关键词缓存到 localStorage
  3. 按需渲染:JSAPI GL 可视化图层在缩放到一定层级时才加载
  4. 节流防抖:搜索输入提示使用 300ms 防抖,避免频繁请求
  5. 点聚合:标记点超过 100 个时启用点聚合(TMap.MarkerCluster),提升渲染性能
  6. Polyline 精简:长距离路线用 Douglas-Peucker 算法简化 polyline,减少渲染节点

6.2 关于 Demo 的一些改动

  1. 地图层级的调整,遮挡了地图上面的按钮交互操作
  2. 调整按钮的位置布局,避免这点地图默认弹窗的显示位置以及地图默认的操作按钮

在这里插入图片描述


七、AI 融合度评估:升级前后对比

维度 升级前 升级后 提升
意图解析准确率 ~40%(简单 includes) ~90%(LLM + 扩展规则) +50%
WebService API 利用率 85%(缺距离矩阵/IP定位/suggestion) 100%(8 个 API 全接入) +15%
JSAPI GL 利用率 75%(缺 InfoWindow/热力图) 95%(全部核心功能) +20%
路线真实性 直线连接(差) 真实道路 polyline(好) 质的提升
用户体验 无搜索补全、无自动定位 有补全、有定位 明显提升

在这里插入图片描述


八、总结与展望

8.1 我们做了什么

  • 自然语言替代了传统的「选起点、选终点、选出行方式」三步操作
  • AI 双引擎(LLM + 本地规则)实现了高融合度的意图理解
  • 腾讯地图 WebService API 全链路(geocoder + search + direction + distance matrix + suggestion + IP 定位)实现数据获取
  • JSAPI GL 可视化让结果不再是一堆文字,而是直观的地图交互
  • 真实道路 polyline 解码让路线规划可信、可用

与 workbuddy 对话过程如下图。
在这里插入图片描述

8.2 地图的未来

当 AI 和地图深度融合,地图就不再是一个「你查我画」的工具,而是一个能理解你需求、主动给出建议的出行伙伴。这只是开始,未来还可以:

  • 实时路况 AI 调整:根据实时路况自动优化行程顺序
  • 多 Agent 协同规划:多个 AI Agent 分工负责不同维度的推荐
  • 个性化记忆:记住你的偏好,下次直接推荐符合口味的方案
  • AR 导航:结合小程序相机能力实现实景导航

地图的未来,是 AI 的大脑 + 地图的眼睛。


附录:快速运行 Demo

A.1 无需任何配置,直接运行

升级后的 Demo 是单文件 HTML,直接双击即可在浏览器中打开运行(使用体验 Key)。

A.2 接入真实 LLM(可选)

取消 AI_ENGINE.config 中的注释,填入你的 API Key:

AI_ENGINE.config = {
    mode: 'llm',
    apiUrl: 'https://api.deepseek.com/v1/chat/completions',  // 或混元接口
    apiKey: 'YOUR_API_KEY',
    model: 'deepseek-chat'
};

A.3 切换正式 Key(上线前必做)

将代码中的 key: 'none'(体验模式)替换为你的正式 Key,并去掉 apptag 参数。


📌 Demo 在线体验智能出行规划助手(仅限本地、局域网预览,未部署)

🎯代码资源已上传置文章顶部,可以直接下载运行
在这里插入图片描述
📌 腾讯位置服务官网https://lbs.qq.com

📌 涉及的 Skill

  • tencentmap-jsapi-gl-skill:JSAPI GL 地图初始化、MultiMarker、MultiPolyline、热力图、InfoWindow
  • tencentmap-webservice-skill:geocoder、search、direction、distance matrix、suggestion、IP 定位、坐标转换
  • tencentmap-miniprogram-skill:微信小程序地图组件迁移方案

与 workbuddy 对话过程如下图。
在这里插入图片描述


💡 一句话总结:让地图「听懂」你说话,不是魔法,是 AI 意图解析 + 腾讯地图 WebService 全链路 API + JSAPI GL 可视化 的组合拳。技术不复杂,效果很惊艳——这就是 AI + 地图该有的样子。升级的核心在于:不再模拟,直接调用;不再直线,贴真实道路;不再写死,让 AI 决策。# 【腾讯位置服务开发者征文大赛】让地图听懂人话:AI + 腾讯地图 API 打造智能出行规划助手(升级版)

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐