WorkBuddy + tencentmap skill 打造从“查地图“到“对话地图“—— AI 赋能 + 腾讯地图 API 打造智能出行规划助手

黛琳ghz 黛琳ghz
征文大赛 2026-05-21
WorkBuddy + tencentmap skill 打造从“查地图“到“对话地图“—— AI 赋能 + 腾讯地图 API 打造智能出行规划助手

【腾讯位置服务开发者征文大赛】WorkBuddy + tencentmap skill 打造从“查地图“到“对话地图“—— AI 赋能 + 腾讯地图 API 打造智能出行规划助手

作者: 黛琳ghz 发布时间: 已于 2026-05-08 03:53:15 修改
来源: https://blog.csdn.net/weixin_53231455/article/details/160869271


文章目录

  • 一、痛点:地图交互的最后一个短板1.1 我们和地图之间,还差一个"翻译层"1.2 本文升级版 Demo 解决的核心问题二、技术架构:三层 + 双引擎2.1 三层架构2.2 涉及的腾讯位置服务能力三、实现详解:从原型到进阶的完整升级3.1 AI 意图解析:双引擎设计(升级核心)3.1.1 LLM 引擎(云端)3.1.2 本地规则引擎(降级,智能版)3.2 真实道路渲染:Polyline 解码 + 逐段规划3.2.1 前向差分解码(腾讯地图独有格式)3.2.2 逐段调用 direction API 渲染真实道路3.3 距离矩阵编排:从 popularity 排序到 AI 贪心排序3.4 IP 自动定位3.5 搜索框自动补全四、Demo 实战:升级后的完整功能清单4.1 核心功能4.2 关键技术决策4.3 微信小程序端延伸五、踩坑记录与最佳实践5.1 坐标系陷阱5.2 路线 Polyline 解码5.3 体验模式注意事项5.4 LLM 接口适配技巧六、性能优化建议6.1 结合 AI 分析出的建议6.2 关于 Demo 的一些改动七、AI 融合度评估:升级前后对比八、总结与展望8.1 我们做了什么8.2 地图的未来附录:快速运行 DemoA.1 无需任何配置,直接运行A.2 接入真实 LLM(可选)A.3 切换正式 Key(上线前必做)

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

在这里插入图片描述

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

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

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

你有没有过这种经历:

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

问题出在哪?

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

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

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

初版 Demo 存在几个明显短板(自我剖析):

在这里插入图片描述

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

2.1 三层架构

在这里插入图片描述

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

与 workbuddy 对话过程如下图。

在这里插入图片描述

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

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

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 搜索框自动补全

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

升级后:接入腾讯地图suggestionAPI,输入 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 实现了以下功能:

在这里插入图片描述

4.2 关键技术决策

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 开发时,需注意:

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 融合度评估:升级前后对比

在这里插入图片描述

八、总结与展望

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 打造智能出行规划助手(升级版)

在这里插入图片描述

* AI润色输出,仅供参考

我们为您提供位置服务商业授权许可

合规地图省心之选,微信生态独家支持

办理咨询

相关推荐

腾讯位置服务地图接口API:从功能解析到场景化接入指南

叮小明 叮小明

在智慧出行零售选址物流调度等场景中,精准的地图数据与灵活的接口调用能力是业务落地的关键。腾讯位置服务

地图接口 2026-03-03

腾讯位置服务地图API开放平台:从接口调用到场景化落地

叮小灵 叮小灵

在智慧出行本地生活零售选址等场景中,精准的地图能力如定位POI搜索路径规划已成为企业数字化的刚需。腾

地图API 2026-03-03

地图不再“冷静”:当腾讯位置服务遇上 AI,我打造了一个 AI 智能出行“全能大脑”

作者: 小吉择 发布时间: 已于20260502 17:40:36修改 来源: https:bl

征文大赛 2026-05-21