【高德开放平台skill】从拍脑袋到看数据,我是如何把一个“选址直觉“做成 AI Skill 的 AI 高德地图做一个商铺选址分析工具创业圈里有句话“选址定生死”。有个做线下连锁品牌的朋友常说选到一个好铺位生意就成了一半选错了再努力也是给房东打工。但每次听他们聊选址聊到最后往往都是玄学——“这条街风水好”“那边人流旺”“感觉那个位置行”。作为一个常年跟数据和自动化打交道的技术人这种感觉驱动的决策一直让我隐隐不安。借着高德开放平台这次的活动我决定把这个玄学变成科学于是有了这个叫商铺选址分析工具Store Site Analysis的 OpenClaw Skill。这篇文章我想聊聊它是怎么从脑子里的一个念头一步步变成一个能直接用的工具的。一、前言朋友准备在一个新一线城市开一家精品咖啡店。他说他跑了三天看了四个铺位A 铺在一条老街的拐角房租便宜但看着人不多。B 铺在商场负一楼人挤人但全是过路的。C 铺写字楼底商中午爆满晚上没人。D 铺大学城旁边年轻人多但消费力存疑。他问我“你觉得哪个好”我的脑子是一片空白。我知道 A 铺竞品少但不知道少多少我知道 B 铺人多但不知道写字楼的人会不会进来买我想查周边有多少小区、多少地铁口但我手里只有大众点评和高德地图切来切去根本拼不出一张完整的图。于是我在高德开放平台翻 API 文档突然意识到选址本质上是一个空间数据分析问题。竞品密度 → POI 搜索人流来源 → 住宅 地铁 写字楼商业氛围 → 商场 配套交通阻力 → 实时路况这些数据高德都有。缺的只是一个能把它们串起来、让不懂技术的人也能用的壳。二、痛点不在有没有数据而在能不能看懂在做这个 Skill 之前我也试过很多现成的选址工具。要么是给大企业用的 SaaS贵得离谱还要培训半天要么是各种大数据报告动辄几十页 PDF看完还是不知道门口那棵树挡不挡招牌。我总结了三个核心痛点1. 数据孤岛竞品在大众点评交通在高德小区在贝壳。没有一个工具能把它们揉在一起给出一个综合分。2. 滞后性很多报告是半年前的。我想知道的是现在这个路口堵不堵而不是平均堵不堵。3. 无法对比人脑很难同时记住 3 个地址的 10 个维度。当你面对 A、B、C 三个铺位犹豫时你需要的是一个清晰的 PK 表而不是三个独立的报告。所以我给这个 Skill 定了三个死规矩一句话触发AI 对话里直接说不用打开新软件。实时数据调用高德实时 API不是离线库。可视化对比必须能一眼看出谁赢。三、技术选型为什么从 Node.js 换成了 Python最开始的原型我是用Node.js Handlebars写的。原因很简单快。JavaScript 写异步逻辑很顺手Handlebars 模板也够用。第一版出来时我挺满意的——能查竞品、能出热力图、能生成 HTML。但问题很快暴露了。有一次我试图在模板里做一个如果交通状态等于 1显示绿色的判断Handlebars 的语法开始变得极其别扭。更糟糕的是当我准备做多地址对比功能时模板里嵌套了三层{{#each}}我自己都看晕了。这时候我意识到这不是逻辑问题是表达能力的问题。我需要一个更强大的模板引擎。于是我做了一个当时看起来有点激进的决定把整个 Skill 从 Node.js 迁移到 Python。迁移后世界清净了aiohttp负责并发请求高德 API速度比串行快一倍。Jinja2处理模板逻辑支持{% if %}、{% for %}、| tojson过滤器写起来像写代码一样自然。Python 的数学运算让我能轻松实现5 维加权评分模型而不用在 JS 里算浮点数。四、制作过程把感觉量化成分数这个 Skill 最核心的部分不是地图也不是 API而是评分模型。我花了很长时间思考一个问题什么样的铺位算好最后我把它拆解成五个维度并强行给了它们权重维度权重逻辑竞品密度25%越少越好保护利润配套丰富度20%越多越好人流基础交通便捷度20%地铁 实时路况商业活跃度20%商场 写字楼居住潜力15%住宅小区数量为了让这个模型不那么死板我在代码里做了一些人性化设计竞品不是越少越好如果一个地方一家竞品都没有我会提示可能是伪需求。交通不是越快越好太拥堵固然不好但完全没车流也不行。配套要活的地铁站比公交站权重大商场比小卖部权重大。这些细节才是这个 Skill 真正区别于普通查 POI工具的地方。下面是评分计算的核心代码片段defcalc_scores(competitors,facilities,traffic_status,radius):metro[fforfinfacilitiesif地铁inf.get(type,)or轨道inf.get(type,)]residence[fforfinfacilitiesifany(kinf.get(type,)forkin[住宅,小区,公寓])]commercial[fforfinfacilitiesifany(kinf.get(type,)forkin[商场,购物,写字楼,商务])]scores{competitor:max(0,100-len(competitors)*5),facility:min(100,len(facilities)*3),traffic:min(100,len(metro)*25(20iftraffic_status1else0)),commercial:min(100,len(commercial)*15),residence:min(100,len(residence)*8)}scores[total]round(scores[competitor]*0.25scores[facility]*0.20scores[traffic]*0.20scores[commercial]*0.20scores[residence]*0.15)returnscores,len(metro),len(residence),len(commercial)这段代码的思路很直观每个维度先算出 0~100 的原始分再按权重加权求和。竞品每多一家扣 5 分地铁站每多一个加 25 分交通畅通额外加 20 分。最终得到一个总分用来排名。五、异步架构并发才是速度的关键选址分析涉及大量网络请求地理编码、竞品搜索、配套搜索、逆地理编码、交通态势……如果串行执行一个地址就要等好几秒。为了极致的响应速度我用了 Python 的asyncio把所有能并行的请求全部并发asyncdefanalyze_single(session,address,business_keyword,radius,business_type):location,formattedawaitgeocode(session,address)lng,latsplit_location(location)competitor_typesbusiness_typeor050000# 四个请求并发执行competitors,facilities,addr_info,trafficawaitasyncio.gather(around_search(session,location,keywordsbusiness_keyword,typescompetitor_types,radiusradius),around_search(session,location,types120000|150500|141200|050000|060100|170000,radiusradius),regeocode(session,location),traffic_status(session,location,radius))# ... 后续处理asyncio.gather是这里的灵魂。它让四个互不依赖的 HTTP 请求同时发出总时间约等于最慢的那个而不是四个相加。实测下来单地址分析从串行版的 6~8 秒压缩到了 2~3 秒。多地址对比更是如此——3 个地址 × 4 个请求 12 个并发请求依然能在 3 秒左右全部返回。这种体验上的快对用户来说是隐形的但少了它AI 对话就会显得卡顿非常影响使用感受。六、模板引擎从 Handlebars 到 Jinja2 的重生前面提到我最初用 Handlebars 写模板到后期简直是灾难。来看一段对比Handlebars 版本旧{{#eachcompetitors}}{{#ifthis.location}}newAMap.Marker({position:[{{this.location.split(,)[0]}},{{this.location.split(,)[1]}}],title:{{this.name}}}).setMap(map);{{/if}}{{/each}}Jinja2 版本新{% for p in competitors %} {% if p.location %} new AMap.Marker({ position: [{{ p.location.split(,)[0] }}, {{ p.location.split(,)[1] }}], title: {{ p.name }} }).setMap(map); {% endif %} {% endfor %}乍一看差不多但 Jinja2 的优势在于表达式能力。比如我需要在模板里把 Python 对象安全地输出为 JSONHandlebars 要写 helperJinja2 一个过滤器搞定const addresses {{ addresses | tojson }}; const radarData {{ radar_json | tojson }};| tojson会自动处理引号转义、特殊字符、None → null 等细节不会因为一个带引号的店铺名就把 JS 打崩。还有条件判断Handlebars 需要注册 helper// Handlebars 要这样Handlebars.registerHelper(eq,(a,b)ab);Jinja2 直接写{% if loop.index0 0 %} {% elif loop.index0 1 %} {% else %}{% endif %}这种不用注册就能用的能力在做复杂模板时是质的差别。七、可视化从数据到决策数据有了分数也有了但用户看到一堆 JSON 是没用的。我必须把它们变成人眼一眼能懂的东西。1. 单地址热力图我用高德 JS API 画了一张图绿色大点目标选址红色小点竞品蓝色小点配套绿色圆圈搜索范围用户打开 HTML拖动地图放大缩小瞬间就能感受到这个位置的气场。2. 多地址PK 擂台当用户说“帮我对比 A、B、C 三个地方。”Skill 会并行分析三个地址然后生成一张包含以下内容的页面 排名榜直接告诉你谁是第一名。 雷达图一眼看出谁偏科。比如 A 铺竞品少但交通差B 铺交通好但竞品炸。 数据表所有维度的硬数字。️ 聚合地图三个圈画在一张图上谁在核心区一目了然。雷达图的实现用了 Chart.js数据从 Python 侧通过 Jinja2 注入constradarData{{radar_json|tojson}};Object.keys(radarData).forEach((key,idx){constctxdocument.getElementById(radar_idx).getContext(2d);newChart(ctx,{type:radar,data:{labels:dims,datasets:Object.keys(radarData[key]).map((name,di)({label:name,data:radarData[key][name],borderColor:colors[di],backgroundColor:colors[di]22,pointBackgroundColor:colors[di]}))},options:{responsive:true,scales:{r:{beginAtZero:true,max:100}}}});});每个地址在雷达图上画出一条能力曲线五维能力一目了然。用户不需要看懂数据看图就知道哦A 铺竞品少但交通差B 铺交通好但竞品炸。八、踩过的坑做这个 Skill 的过程中有几个坑值得记一笔1. API 限流高德的免费 Key 有 QPS 限制。一开始我没做并发控制三个地址一起查Key用的特别快。后来加了asyncio.gather的限流逻辑才稳住。2. 模板语法灾难这就是我前面提到的。一开始用 Handlebars到后期模板里全是{{{ }}}和{{#if (eq ...)}}维护成本极高。换成 Jinja2 是我做过最正确的决定之一。3. 坐标漂移有些地址解析出来的坐标会飘到马路对面。我不得不在代码里加了逆地理编码二次校验确保点落在真实的道路上。asyncdefgeocode(session:aiohttp.ClientSession,address:str):dataawaitfetch_json(session,GEOCODE_URL,{key:AMAP_KEY,address:address,output:json})geodata.get(geocodes,[{}])[0]ifnotgeo:raiseValueError(f地址解析失败:{address})returngeo[location],geo.get(formatted_address,)如果高德返回的geocodes为空说明地址不够精确这时候我会让 AI 提示用户能否提供更详细的地址而不是直接崩掉。4. 文件路径Python 的os.path在不同系统上表现不一样。为了确保在 ClawHub 上跑通我统一用了os.makedirs(os.path.dirname(output_path), exist_okTrue)来做目录兜底创建。九、现在它是个活的工具现在这个 Skill 静静地躺在我的 ClawHub 里。平时不怎么用它但当朋友问我要开个店你帮我看看我就让他对着 AI 说一句话“帮我在厦门中山路、SM城市广场、湖滨南路对比开奶茶店哪个更好。”几秒钟后一份包含雷达图、评分表和推荐结论的报告就出来了。不需要解释 POI 是什么不需要教他看坐标系。他只需要看一眼就知道该去谈哪个铺位的房租。十、写在最后这个 Skill 并没有用什么惊世骇俗的黑科技。它只是把高德地图的能力、Python 的数据处理能力、AI 的自然语言理解能力用一种顺手的方式缝在了一起。对我来说技术的意义从来不是炫技而是让复杂的事情变简单让模糊的事情变清晰。Githubhttps://github.com/wukongmazi/store-site-analysisClawhubhttps://clawhub.ai/wukongmazi/store-site-analysis