拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

腾讯位置服务开发者征文大赛:用 WorkBuddy 与 MCP 打造 AI 地图智能应用实战

腾讯位置服务开发者征文大赛:用 WorkBuddy 与 MCP 打造 AI 地图智能应用实战

1. 从「约饭选址」到 AI 地图应用:WorkBuddy + 腾讯位置服务 MCP 到底能做什么

先说我自己的真实起点。去年冬天组织一次四人聚会,张三在回龙观、李四在东直门、王五在南四环、我在中关村,群里刷了三十多条「在哪见」,最后选了个离谁都远的地方。传统导航只回答「怎么去」,不回答「去哪最公平」。这个缺口,就是 AI 地图应用的机会:让用户用一句自然语言描述需求,由 AI 完成意图识别、调用地理编码与路线规划工具、再把结果画到地图上。

腾讯位置服务开发者征文大赛这次的主题,正好卡在这个点上。腾讯位置服务提供 geocoder(地理编码)、placeSearchNearby(周边 POI 检索)、directionDriving(驾车路线)、matrix(多点距离矩阵)等 WebService 能力,以及 JavaScript API GL 的 3D 渲染与 MultiMarker、MultiPolyline 图层;WorkBuddy 负责把模糊想法翻译成架构、生成可运行代码、整理文档。两者之间用 MCP(Model Context Protocol)串起来,AI Agent 就能像人一样「先想再调工具」。

这篇写给谁:会一点 HTML/JS、想做一个能跑起来的 AI 地图 Demo 的开发者;正在准备征文大赛、需要可复制配置和联调步骤的参赛者;以及想把 MCP 真正用进业务、而不是停在概念演示的人。全文按「问题场景 → 前置准备 → 可复制配置 → 验证请求 → 报错排查 → 下一步」推进,每一步都给命令、参数和预期结果,你可以边看边敲。

我试过把 MCP 当噱头堆 API,结果页面很花但没人用;后来把「汇合点计算」这一个场景做透,反而被朋友追着要链接。所以下面的路线是:先跑通一条最小链路,再往上加功能。

2. 前置准备:TaoToken 接入与腾讯位置服务 Key 申请全流程

2.1 为什么中间要有一层模型网关

MCP 的调用方是 AI Agent,Agent 需要一个能稳定输出结构化 tool_calls 的模型。直接在前端硬编码模型厂商的 Key,一是暴露风险,二是换模型要改代码。用 TaoToken 这类兼容 OpenAI 协议的中转层,好处是 Base URL 统一、模型 ID 可切换、额度集中管理,前端只认一个地址。

官网入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 根地址是 https://taotoken.net/api (注意这个地址不加 UTM 参数,配置里写干净版本)。

2.2 拿到三件套:Base URL、Key、Model ID

登录后进控制台,在 API Keys 页面创建一个新 Key。建议按项目命名,比如map-agent-demo,方便后面按项目看用量。创建后立刻复制,页面刷新就不再完整显示。

模型 ID 的选择上,做 MCP Tool Calling 要挑支持 function calling 的模型。行程规划这种多步推理场景,建议用推理能力强的型号;如果只是做地址解析和简单问答,轻量型号就够,成本差好几倍。具体可用列表在模型对话页面能看到,也可以直接在控制台里试跑一条请求验证。

2.3 腾讯位置服务侧的 Key 与安全设置

去腾讯位置服务控制台创建应用,分别申请两类 Key:一类给 JavaScript API GL(前端渲染用),一类给 WebService(geocoder、direction 等后端接口用)。前端 Key 必须配 Referer 白名单,把本地调试域名和部署域名都加进去,否则浏览器控制台会直接报INVALID_USER_DOMAIN。

配额管理别偷懒。WebService 的每日调用上限设一个合理值,比如 5000 次,防止 Demo 被爬。纯前端架构下 Key 一定会出现在网络请求里,这是参赛 Demo 可以接受的取舍;正式上线时用云函数做一层代理,把 WebService Key 藏到服务端。

2.4 本地环境与目录结构

Node 18 以上,一个静态服务器(npx serve或 VSCode Live Server 都行)。目录建议这样分:

map-agent-demo/ ├── index.html # 地图容器 + 对话面板 ├── js/ │ ├── mcp-client.js # MCP 调用封装 │ ├── agent.js # 意图识别 + tool_calls 编排 │ └── map-render.js # GL 图层渲染 ├── config/ │ └── settings.json # 模型与 Key 配置(勿提交仓库) └── prompts/ └── system.md # WorkBuddy 提示词模板

把配置单独放一个文件,后面换模型、换 Key 只改一处。.gitignore里加上config/settings.json。

3. 可复制配置:MCP Server、settings.json 与 WorkBuddy 提示词模板

3.1 MCP Server 配置片段

MCP 的配置格式各客户端略有差异,核心是三件套:命令、参数、环境变量。下面这份是通用形态,路径按你本地实际位置改:

{ "mcpServers": { "tencent-map": { "command": "npx", "args": ["-y", "@tencentmap/mcp-server"], "env": { "TENCENT_MAP_KEY": "你的WebService-Key", "TENCENT_MAP_BASE_URL": "https://apis.map.qq.com" } } } }

如果你用的是支持 TOML 的客户端,等价写法:

[mcp_servers.tencent-map] command = "npx" args = ["-y", "@tencentmap/mcp-server"] [mcp_servers.tencent-map.env] TENCENT_MAP_KEY = "你的WebService-Key" TENCENT_MAP_BASE_URL = "https://apis.map.qq.com"

注意TENCENT_MAP_KEY用的是 WebService 类型 Key,不是前端 GL 的 Key,两者权限不同,混用会报INVALID_KEY。

3.2 settings.json:模型侧配置

{ "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的TaoToken-Key", "model": "你的模型ID", "temperature": 0.3, "tools": [ "geocoder", "placeSearchNearby", "directionDriving", "directionWalking", "matrix" ] }

temperature压到 0.3 是因为工具调用需要稳定输出 JSON,太高会偶发格式错乱。tools数组显式声明允许调用的工具,避免模型幻觉出不存在的函数名。

3.3 WorkBuddy 提示词模板

把下面这段存进prompts/system.md,作为 Agent 的系统提示:

你是「聚点智行」地图助手,负责把用户的自然语言需求转成地图工具调用。 工作流程: 1. 解析意图,归类为:汇合点计算 / 周边搜索 / 路线规划 / 行程编排 2. 从文本中抽取地点、时间、人数、预算等约束 3. 选择工具:地名转坐标用 geocoder;找周边用 placeSearchNearby; 算路线用 directionDriving 或 directionWalking;多点距离用 matrix 4. 每次调用前用一句话说明理由,调用后解读返回结果 5. 最终输出结构化行程单,含时间、地点、费用、交通方式 约束: - 坐标统一用「纬度,经度」格式,保留 6 位小数 - 不确定的地点先调 geocoder 确认,不要猜坐标 - 费用估算标注「预估」,不要编造精确价格

这份模板的关键是第 4 条:要求 AI 输出调用理由。这既是给用户看的「思维链」,也是你调试时的日志。

3.4 前端调用封装

// js/mcp-client.js const settings = await fetch('/config/settings.json').then(r => r.json()); export async function callModel(messages, tools) { const res = await fetch(`${settings.baseUrl}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${settings.apiKey}` }, body: JSON.stringify({ model: settings.model, messages, tools, temperature: settings.temperature }) }); if (!res.ok) throw new Error(`模型请求失败: ${res.status}`); return res.json(); }

这段是整条链路的入口,后面所有工具调用都由它返回的tool_calls字段驱动。

4. 验证请求:从地理编码到行程单的完整联调

4.1 第一步:验证模型连通性

先用一条最简单的请求确认 Base URL 和 Key 没问题:

curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "你的模型ID", "messages": [{"role": "user", "content": "回复 OK 两个字母"}] }'

返回体里choices[0].message.content是OK,说明模型侧通了。如果这里就失败,先别往下走,去第 5 节排查。

4.2 第二步:验证 geocoder 工具调用

给模型发一条带地名的请求,看它是否主动发起 tool_call:

const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: '西直门在哪?给我坐标' } ]; const result = await callModel(messages, toolDefinitions); console.log(result.choices[0].message.tool_calls);

预期输出里能看到function.name为geocoder,arguments是{"address":"西直门"}。拿到这个 tool_call 后,你把它转发给腾讯位置服务的 geocoder 接口,返回的坐标大约是39.9434,116.3497。把结果作为role: "tool"的消息塞回对话,模型会生成一句自然语言解读。

4.3 第三步:跑通「四人汇合点」场景

这是最能体现 MCP 价值的场景。用户输入「帮 4 个人找汇合点,分别在回龙观、东直门、南四环、中关村」,Agent 的执行序列是:

先对四个地名各调一次 geocoder,拿到四组坐标;再用 matrix 接口一次性计算四点两两之间的距离矩阵;然后按「距离总和最小」选出候选点,用 placeSearchNearby 在候选点周边 500 米内找餐厅或咖啡厅作为具体汇合地;最后用 MultiMarker 把四个起点和一个汇合点画到地图上,用 MultiPolyline 连出四条路线。

matrix 接口的调用参数长这样:

const matrixResult = await fetch( `https://apis.map.qq.com/ws/distance/v1/matrix?mode=driving` + `&from=${origins.join(';')}&to=${destinations.join(';')}` + `&key=${webServiceKey}` ).then(r => r.json());

返回的result.rows是二维数组,rows[i].elements[j].distance就是第 i 个起点到第 j 个终点的距离。遍历所有候选点求总和,取最小值即可。

4.4 第四步:地图渲染与结果确认

拿到汇合点坐标后,初始化 GL 地图:

const map = new TMap.Map(document.getElementById('map'), { center: new TMap.LatLng(39.9434, 116.3497), zoom: 12, pitch: 45, viewMode: '3D' }); const markerLayer = new TMap.MultiMarker({ map, styles: { start: new TMap.MarkerStyle({ width: 24, height: 32, src: 'pin-blue.png' }), meet: new TMap.MarkerStyle({ width: 28, height: 36, src: 'pin-red.png' }) }, geometries: [ { id: 'p1', styleId: 'start', position: new TMap.LatLng(40.0755, 116.3390) }, { id: 'meet', styleId: 'meet', position: new TMap.LatLng(39.9434, 116.3497) } ] });

验证清单:地图能加载并显示 3D 视角;四个起点标记和一个汇合点标记都出现;点击标记弹出 InfoWindow 显示地名和距离;路线连线颜色区分不同出行方式;控制台无INVALID_USER_DOMAIN报错。

4.5 第五步:行程编排场景

把「西直门一日行程」这类复杂需求丢进去,观察 Agent 是否按「解析约束 → 搜住宿 → 排三餐 → 选景点 → 算总距离 → 输出行程单」的顺序执行。一个健康的执行链路会产生 8 到 12 次工具调用,每次调用之间模型会输出一句推理说明。如果模型跳过 geocoder 直接猜坐标,说明提示词里的约束没生效,回去检查prompts/system.md是否被正确加载。

5. 常见报错排查:401、local proxy failed 与 tool_calls 解析失败

5.1 401 Unauthorized

最常见的原因是 Key 复制时带了空格或换行。用echo -n "sk-xxx" | wc -c确认长度,或者直接在代码里console.log(apiKey.length)。另一个原因是把腾讯位置服务的 Key 填到了模型配置里,两者前缀不同,别搞混。

如果确认 Key 正确仍报 401,检查请求头是不是Authorization: Bearer sk-xxx,少个空格也会失败。

5.2 local proxy failed

这个报错通常出现在 MCP Server 启动阶段,含义是客户端连不上本地起的 MCP 进程。排查顺序:先确认npx -y @tencentmap/mcp-server能在终端单独跑起来;再检查env里的TENCENT_MAP_KEY是否传进去了,很多客户端不会自动继承 shell 环境变量;最后看端口是否被占用,换个端口重试。

如果是 Windows 环境,command字段可能要写npx.cmd而不是npx,这是路径解析差异导致的。

5.3 reading 'choices' of undefined

这个报错说明你在解析响应时,result.choices是 undefined。三种可能:请求根本没成功,返回的是错误对象;返回体结构和你预期的不一样,先console.log(JSON.stringify(result))看原始结构;流式响应没处理完就取值了,加个await或改用非流式模式调试。

调试期建议先关掉 streaming,拿到完整响应再开。

5.4 OAuth 相关报错

部分 MCP 客户端在首次连接时会走 OAuth 授权流程。如果报OAuth callback failed,检查回调地址是否和客户端注册的一致,本地调试常用http://localhost:端口/callback。有些客户端把 token 缓存在用户目录下,缓存损坏时删掉重新授权即可。

5.5 tool_calls 格式错乱

模型返回的arguments不是合法 JSON,通常是 temperature 太高或提示词里没强调格式。把 temperature 降到 0.2 以下,并在系统提示里加一句「工具参数必须是合法 JSON,不要包含注释」。如果模型持续输出带 markdown 代码块的 JSON,在解析前先剥掉```json和```。

5.6 地图不显示或白屏

先看浏览器控制台有没有INVALID_USER_DOMAIN,有就是 Referer 白名单没配。没有报错但地图空白,检查容器 div 有没有设高度,GL 地图需要一个非零高度的父容器。3D 视角下如果显卡驱动老旧,viewMode: '3D'可能渲染失败,临时改成'2D'验证是不是渲染层问题。

6. 下一步:把 Demo 变成能用的智能出行助手

跑通上面这条链路后,你手里已经有一个能对话、能调工具、能画地图的最小闭环。接下来可以往三个方向加厚。

第一是补全工具集。目前只用了 geocoder、placeSearchNearby、direction、matrix 四类,腾讯位置服务还有逆地理编码、IP 定位、行政区划等能力,接进来能让 Agent 处理「我在哪」「这个坐标属于哪个区」这类问题。

第二是做结果缓存。同一批地名反复调 geocoder 是浪费配额,用 localStorage 或内存 Map 缓存「地名 → 坐标」的映射,命中就直接返回。行程规划场景里,用户改一个约束条件往往只需要重算部分节点,缓存能显著降低延迟。

第三是把 Key 挪到服务端。参赛 Demo 用纯前端可以接受,但如果想给别人长期用,用云函数包一层代理,前端只调自己的接口,WebService Key 不出现在浏览器里。这一步做完,项目就从「演示」变成了「能上线」。

如果你在编码 Agent 或长期跑自动化任务,可以看看 Coding Plan 的额度方案;只是验证模型和工具调用是否通,模型对话页面直接试最快;Key 管理和用量查看都在 API Keys 页面。接入过程中卡在某个报错,接入文档里有各接口的完整参数说明,对照着改通常能解决。

地图应用的下半场,拼的不是谁画的点更多,而是谁能让 AI 真正理解「用户想去哪、和谁去、什么时候去」。把这条 MCP 链路跑顺,你就已经站在起跑线前面了。

返回列表