地图选址与出行规划(trae-map-planner)
用高德开放平台 REST 接口做真实的 POI 检索与路线计算,回答「去哪家店最方便」「哪两家店可以顺路一起逛」。
何时使用
| 用户说法 | 用哪个脚本 | 模式 |
|---|---|---|
| 附近哪家 XX 分店最近 / 哪家店最方便 | find-place.mjs |
--mode single |
| 同时想吃 A 和 B,去哪最划算 / 两家店离得近的 | find-place.mjs |
--mode multi |
| 从某地到某地要多久 / 怎么走 / 地铁还是步行 | route-planner.mjs |
单程/闭环 |
不适用:需要实时公交到站、室内导航、订座、外卖下单等场景。
前置条件
- Node.js ≥ 18(脚本用内置
fetch与 ESM)。优先使用 PATH 中的node,不要假设安装在某个固定路径。
- 验证:node --version - 自备高德 Key(每个使用者都要自己申请,不能共用他人的)
- 入口:<https://lbs.amap.com/> → 控制台 → 应用管理 → 创建应用 → 添加 Key
- 服务平台必须选「Web服务」(不是「Web端(JS API)」,也不是「Android/iOS」)
- 拿到形如 32 位十六进制的 Key 后,写入环境变量AMAP_KEY:- Windows PowerShell(当前会话):
$env:AMAP_KEY="你的Key" - Windows 永久(新终端生效):
setx AMAP_KEY "你的Key" - macOS / Linux:
export AMAP_KEY="你的Key"(可写入~/.zshrc或~/.bashrc) - 未设置时脚本会直接报错退出,并提示
provider=amap 需要密钥:请先设置环境变量 AMAP_KEY。
- Windows PowerShell(当前会话):
> 安全:Key 只从环境变量读取,不会写入包内任何文件,也不会出现在输出里(报错信息会脱敏为 ***KEY***)。
硬性规则(不可违反)
- 出发地必须每次由用户显式提供,
--origin无任何默认值;缺失时脚本直接报错退出(退出码 1)。禁止擅自替用户填一个「常用出发地」,也不要拿上一次的缓存值当出发地。 - 默认出行方式为地铁/公交(transit)。不得擅自改成骑行或驾车;只有用户明确要求时才用
--mode walking|riding|driving。 - 直线距离 ≤ 1 公里一律优先步行(
--walk-first-m,默认 1000)。该段只算步行,不与骑行/公交/地铁比较,也不会因为骑行耗时显示更短而改选骑行。 - 候选排序一律用真实路线耗时,不得用直线距离代替耗时排序。直线距离只用于「粗筛/决定先算谁」,最终名次必须由接口返回的 duration 决定。未计算耗时的候选必须单独标注,禁止与已计算候选混排。
城市范围:默认就近本市,跨城要显式开启
默认行为(不加 --cross-city):就近在本市搜索。
- 先解析出发地/起点地址,取接口返回的
city字段识别所在城市(全国通用,不绑定任何城市)。 - POI 检索
city=<该城市>且citylimit=true,所有候选门店都在出发地城市内;公交规划city、cityd一律用出发地城市。 - 若
--city指定的城市与出发地城市不同,工具直接报错并提示加--cross-city,不会静默跨城。 - 输出会打印
识别城市: 上海市(按出发地自动识别) | 起点城市: 上海市 | 跨城: 关闭(就近本市),方便核对。
跨城(显式开启 --cross-city):
- 起点、终点城市各自识别,transit 的
city(起点城市)与cityd(终点城市)分别传,上海 → 苏州这类场景可以正常算。 - 典型用法:从上海出发、但想检索苏州的门店 →
--city "苏州市" --cross-city。 find-place的 single / multi 模式本身是「就近找店」,跨城只在--city指向异地城市时才有意义;开了但城市相同会提示"按同城就近处理"。
其他约定:
- 想强制指定城市传
--city "杭州市"(城市名或 adcode),显式值优先于自动识别。 - 识别失败或地址模糊时不会静默猜一个,会列出候选城市并提示用
--city指定。 - 百度通道(
--provider baidu)的地理编码不返回城市字段,只能按地址文本推断,跨城建议显式传--city。
用法
以下命令在 skill 目录下执行(scripts/ 与 SKILL.md 同级)。
模式一:单品牌选店
node scripts/find-place.mjs --mode single \
--origin "上海市徐汇区云锦路277号" \
--brand "成都你六姐"
输出:该品牌全量门店中直线最近的 N 家,逐一评估方案,再按真实总耗时升序给出 Top 3。1 公里内的门店会标注「(1公里内步行优先)」。
换个城市只需换 --origin,城市会自动识别(同城就近检索;跨城需加 --cross-city):
node scripts/find-place.mjs --mode single \
--origin "浙江省杭州市西湖区文三路100号" --city "杭州市" \
--brand "成都你六姐" --top-n 2
需要跨城(例如从上海出发但检索苏州的门店)时,显式开启并指定城市:
node scripts/find-place.mjs --mode single \
--origin "上海市徐汇区云锦路277号" --city "苏州市" --cross-city \
--brand "成都你六姐" --top-n 2
模式二:多品牌同址
node scripts/find-place.mjs --mode multi \
--origin "上海市徐汇区云锦路277号" \
--brands "小满手工粉,成都你六姐"
输出:跨品牌门店间距 ≤ --pair-max-m(默认 300 米)的组合,先按 --scan-km(默认 15 公里)做宽松初筛,再逐组计算真实耗时,按耗时升序输出;超出 --candidates 预算未算的组合会明确标注「未计算」,不与已算组合混排。
品牌组合闭环行程(起点 → A → B → 起点)
node scripts/route-planner.mjs --origin "上海市徐汇区云锦路277号" \
--brand-a "小满手工粉" --brand-b "成都你六姐" \
--max-walk-min 20 --top-n 5
先 --dry-run 估算本次要发多少请求,再正式跑。
常用参数
find-place.mjs:
| 参数 | 含义 | 默认值 |
|---|---|---|
--mode |
single / multi |
必填 |
--origin |
出发地(地址或「经度,纬度」) | 必填,无默认 |
--brand |
单品牌关键词(single) | - |
--brands |
多品牌关键词,逗号分隔(multi,≥2 个) | - |
--city |
检索城市(城市名/adcode) | 按出发地自动识别(显式指定优先) |
--cross-city |
允许跨城(检索城市≠出发地城市时) | 关闭(就近本市) |
--walk-first-m |
1 公里内步行优先阈值(米) | 1000 |
--metro-max-walk |
地铁方案累计步行上限(米) | 1200 |
--bike-max-km |
骑行评估的直线距离上限(公里) | 3 |
--top-n |
single:评估家数 | 8 |
--top-show |
输出方案数 | 3 |
--pair-max-m |
multi:同址判定阈值(米) | 300 |
--near-fallback-m |
无同址组合时的放宽阈值(米) | 1000 |
--scan-km |
multi:初筛半径(公里) | 15 |
--candidates |
multi:评估组数(all 为全量) |
10 |
--max-requests |
单次运行请求上限 | 15(multi 为 45) |
--interval |
请求最小间隔(毫秒) | 1000 |
--json |
以 JSON 输出 | 关闭 |
route-planner.mjs:
| 参数 | 含义 | 默认值 |
|---|---|---|
--origin |
起点 | 必填 |
--brand-a / --brand-b |
两个品牌 | 必填 |
--provider |
数据源 amap / baidu |
amap |
--city |
检索城市(城市名/adcode) | 按起点地址自动识别(显式指定优先) |
--cross-city |
允许跨城(起点/终点城市独立识别) | 关闭(就近本市) |
--modes |
允许的交通方式(逗号分隔) | transit,walking |
--mode |
指定单一方式,覆盖 --modes |
- |
--top-n |
每个品牌取最近 N 家 | 5 |
--top-trips |
输出方案数 | 3 |
--max-walk-min |
单段步行上限(分钟) | 20 |
--max-requests |
单次运行请求上限 | 15 |
--interval |
请求最小间隔(毫秒) | 1000 |
--dry-run |
只检索并估算请求数 | 关闭 |
--json |
以 JSON 输出 | 关闭 |
配额与缓存
- 所有请求严格串行,最小间隔 1 秒,单次运行有上限(
--max-requests);超限会停止并明确提示,不会静默失败。 - 响应缓存在
scripts/cache.json(首次运行自动创建,纯响应体、不含 Key)。重复查询同一出发地/目的地/方式时直接命中缓存,0 请求。 - 建议日常工作值:
--candidates 10 --max-requests 45;想一次拿全量结论用--candidates all --max-requests 120。
常见问题
| 现象 | 处理 |
|---|---|
未找到高德 Key |
设置环境变量 AMAP_KEY 后重开终端(IDE 需重启才能继承新变量) |
INVALID_USER_KEY / USER_KEY_RESTRICT |
Key 类型不是「Web服务」,或 Key 有 IP/域名白名单限制 |
已达单次运行请求上限 |
调大 --max-requests,或调小 --top-n / --candidates |
| 门店数量明显偏少 | 换更贴近的 --brand 关键词,或确认 --city 是否正确 |
起点无法唯一确定城市(候选: A / B) |
地址太模糊命中多城市,按提示用 --city "城市名" 指定 |
检测到检索城市「A」与起点城市「B」不同 |
默认就近本市;确实要跨城请加 --cross-city |
| 地址解析失败 / 返回 0 条 | 地址缺省市前缀或写法有误,补全省市区或改用「经度,纬度」 |