ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【openclaw实用Skill】goplaces 技能:把 Google Places API 的 JSON 结果接进 CLI 工作流

【openclaw实用Skill】goplaces 技能:把 Google Places API 的 JSON 结果接进 CLI 工作流 1. goplaces 技能到底解决什么问题CLI 调用 Google Places API 并解析 JSON 返回如果你写过跟地点相关的脚本大概率经历过这种别扭想查一家咖啡店的营业状态、评分、地址得先打开浏览器搜一遍再把信息手动抄进代码或表格里。Google Places API 本身能力很强但它的返回是一大坨嵌套 JSON字段名长、层级深直接丢给 shell 脚本处理非常难受。goplaces 这个 openclaw 技能本质就是给 Google Places API新版套了一层命令行外壳让你在终端里一条命令完成文本搜索、地点详情、地址解析和评论拉取并且默认给人看的排版加--json就切成机器可读的结构化输出。它适合谁三类人最明显。第一类是经常在终端里干活的开发者想用curl或脚本批量查地点不想为每个查询写一遍 HTTP 请求和 JSON 解析。第二类是做 Agent 或自动化流程的人需要把「找附近评分 4 以上的餐厅」这种自然语言意图变成可复现的命令行调用。第三类是数据整理场景比如把一批地址解析成标准地点信息再喂给下游程序。goplaces 的定位不是替代地图 App而是把地点查询变成一条可管道、可组合、可脚本化的命令。我试过把它接进一个简单的 shell 流程先用goplaces search拿到候选地点列表再用jq抽出 place id最后用goplaces details补全营业时间和评论。整个过程没有打开任何网页输出直接进文件。这就是它相对「手动查」的核心价值——把非结构化的查询动作变成结构化数据流。需要先明确一点goplaces 依赖 Google Places API 的密钥它自己不提供地点数据。所以本文的重点有两块一是技能本身的配置和命令用法二是怎么把 API Key 和 Base URL 填对让请求真正跑通。很多人卡住不是因为命令不会写而是环境变量没配对或者 Base URL 指向了错误的端点导致返回 401 或空结果。下面按「先配好、再跑通、再排错」的顺序展开。2. TaoToken 前置准备API Key 与 Base URL 的填写位置在 openclaw 里用 goplaces第一步不是敲命令而是把凭据配好。goplaces 读取两个环境变量GOOGLE_PLACES_API_KEY是必需的GOOGLE_PLACES_BASE_URL是可选的用于指向自定义端点或测试环境。如果你只是本地跑通流程最省事的方式是写进 shell 的配置文件比如~/.zshrc或~/.bashrc这样每个新终端都能读到。这里要区分两个概念。Google Places API 官方端点需要你自己的 Google Cloud 项目密钥申请和配额管理都在 Google 侧。而如果你希望通过统一的网关来管理调用、观察请求日志、或者把多个模型的调用收敛到一个入口可以用 TaoToken 提供的 API 入口作为 Base URL。它的 API 地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为基础路径使用。密钥则在控制台里生成对应填到GOOGLE_PLACES_API_KEY的位置。具体操作上你可以先到 TaoToken 控制台创建一个 API Key。入口在https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content登录后进入 API Keys 页面生成。生成后复制那串 key不要截图外传。然后编辑你的 shell 配置# 写入 ~/.zshrc 或 ~/.bashrc export GOOGLE_PLACES_API_KEY你的_API_Key export GOOGLE_PLACES_BASE_URLhttps://taotoken.net/api保存后执行source ~/.zshrc让配置生效。验证是否读到echo $GOOGLE_PLACES_API_KEY echo $GOOGLE_PLACES_BASE_URL如果第一行输出你的 key、第二行输出 Base URL说明环境变量没问题。这里有个容易忽略的点Base URL 结尾不要多加斜杠也不要拼上/v1之类的路径goplaces 会自己在后面拼接具体端点。多写一段路径往往就是后面 404 的根源。如果你不想污染全局环境也可以在每个项目目录下放一个.env文件用direnv或手动source加载。对于临时测试直接在命令前加变量也行GOOGLE_PLACES_API_KEY你的_API_Key \ GOOGLE_PLACES_BASE_URLhttps://taotoken.net/api \ goplaces search coffee --json这种方式适合一次性验证不适合长期使用因为每次都要重复输入。配好之后建议先别急着搜复杂条件用最简单的goplaces search coffee确认链路通。如果这一步就报错问题一定在凭据或网络层而不是命令参数。另外提醒一句API Key 属于敏感信息不要写进会提交到 Git 的脚本里。如果团队协作用环境变量注入或密钥管理服务别硬编码。goplaces 本身不会把 key 打印到输出里但你的 shell 历史可能会记录带 key 的命令临时测试后记得清理历史或改用环境变量方式。3. 可复制配置openclaw 技能片段与 settings 写法openclaw 的技能通常通过配置文件声明goplaces 也不例外。你需要在一个技能配置里告诉 openclaw这个技能叫什么、用哪个命令、需要哪些环境变量、参数怎么传。下面给一份可直接复制的 JSON 配置片段路径按 openclaw 的约定放在 skills 目录下比如~/.openclaw/skills/goplaces.json。如果你的 openclaw 版本用 TOML我也在下面附了等价写法。先看 JSON 版本{ name: goplaces, description: Google Places API CLI for text search, details, resolve and reviews, command: goplaces, env: { GOOGLE_PLACES_API_KEY: ${GOOGLE_PLACES_API_KEY}, GOOGLE_PLACES_BASE_URL: ${GOOGLE_PLACES_BASE_URL} }, args: { search: { description: Search places by keyword, options: [--json, --open-now, --min-rating, --max-price, --limit, --lat, --lng, --radius-m, --type, --page-token] }, details: { description: Get place details by place id, options: [--reviews, --json] }, resolve: { description: Resolve an address text to places, options: [--limit, --json] } } }这份配置的关键点有三个。第一env里用${VAR}引用外部环境变量而不是把 key 写死这样配置可以安全地提交或分享。第二command指向goplaces可执行文件前提是它已经在 PATH 里如果不在写绝对路径。第三args把子命令和常用选项列出来方便 openclaw 在生成调用时知道有哪些参数可用。注意--type只接受一个值API 侧只认第一个所以别指望传多个类型做并集。如果你用 TOML等价写法是这样name goplaces description Google Places API CLI for text search, details, resolve and reviews command goplaces [env] GOOGLE_PLACES_API_KEY ${GOOGLE_PLACES_API_KEY} GOOGLE_PLACES_BASE_URL ${GOOGLE_PLACES_BASE_URL} [args.search] description Search places by keyword options [--json, --open-now, --min-rating, --max-price, --limit, --lat, --lng, --radius-m, --type, --page-token] [args.details] description Get place details by place id options [--reviews, --json] [args.resolve] description Resolve an address text to places options [--limit, --json]配置写好后openclaw 在加载技能时会读取它并把环境变量注入到子进程。这里有个细节${GOOGLE_PLACES_API_KEY}这种写法依赖 openclaw 的变量展开能力如果你的版本不支持就改成在启动 openclaw 前先export配置里只写变量名。两种方式效果一样选你环境能跑通的。再补一个 settings 层面的片段用于把 goplaces 注册到 openclaw 的技能列表里。假设主配置是~/.openclaw/settings.json{ skills: { goplaces: { enabled: true, path: ~/.openclaw/skills/goplaces.json } } }这样 openclaw 启动时会自动加载 goplaces。如果你同时用 Cline MCP 或 Codex 的auth.json管理凭据注意别把同一份 key 在多处重复配置容易改了一处忘了另一处。统一在环境变量里维护配置只引用变量名是最省心的做法。三件套始终是 Base URL、Key、Model ID——goplaces 场景里 Model ID 不涉及但 Base URL 和 Key 必须成对出现缺一个都会在请求阶段失败。4. 验证请求一条 curl 命令确认地点搜索返回结构化 JSON配置写完别急着在 openclaw 里跑复杂流程先用一条curl命令确认端点、密钥、返回格式都对。这一步能把「配置问题」和「技能问题」分开排错效率高很多。下面这条命令直接打 Google Places 新版文本搜索端点通过 TaoToken 的 Base URL 转发curl -s -X POST https://taotoken.net/api/v1/places:searchText \ -H Content-Type: application/json \ -H X-Goog-Api-Key: $GOOGLE_PLACES_API_KEY \ -H X-Goog-FieldMask: places.displayName,places.formattedAddress,places.rating,places.currentOpeningHours.openNow \ -d { textQuery: coffee, maxResultCount: 3 } | jq .这条命令做了几件事。-X POST指定方法Places 新版搜索是 POST。X-Goog-Api-Key头带上你的 key注意这里用的是$GOOGLE_PLACES_API_KEY所以前面环境变量必须已经生效。X-Goog-FieldMask是 Places 新版的重要机制它决定返回哪些字段不写会报错或返回默认字段。上面这个 mask 只要了名称、地址、评分和是否营业返回体小、看得清。-d里的textQuery是搜索词maxResultCount限制条数。如果一切正常你会看到类似这样的 JSON{ places: [ { displayName: { text: Blue Bottle Coffee }, formattedAddress: 315 Linden St, San Francisco, CA 94102, USA, rating: 4.5, currentOpeningHours: { openNow: true } } ] }看到places数组里有对象说明链路通了。接下来换成 goplaces 命令验证技能层goplaces search coffee --json | jq .[] | .name如果这条能输出一串店名说明 goplaces 已经正确读取环境变量、拼接端点、解析返回。注意--json的输出结构可能和原始 API 略有不同goplaces 会做一层整理字段名更友好。你可以先用goplaces search coffee --json | jq keys看看顶层结构再决定怎么取字段。再验证一下详情和地址解析# 先拿一个 place id PLACE_ID$(goplaces search coffee --json | jq -r .[0].id) # 用 place id 查详情带评论 goplaces details $PLACE_ID --reviews --json | jq .reviews[0].text # 地址解析 goplaces resolve Soho, London --limit 3 --json | jq .[].formattedAddress这几条跑通说明搜索、详情、解析三条主路径都正常。如果curl通但goplaces不通问题在技能配置或可执行文件路径如果curl也不通问题在 key、Base URL 或网络。分清楚这一点后面排错就不会瞎猜。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth实际跑的时候报错集中在几类。下面按真实错误信息对照排查每条都给判断依据和修法。401 Unauthorized / API key not valid。这是最常见的一类。先确认echo $GOOGLE_PLACES_API_KEY有输出且没有多余空格或换行。然后确认 key 本身有效、没有过期、没有在控制台被禁用。如果你用的是 TaoToken 的 Base URL确认 key 是在对应控制台生成的而不是 Google 官方项目的 key 混用。混用会导致端点认不出这个 key。修法重新生成一个 key只配一处source后重试curl。local proxy failed / connection refused。这类通常出现在 Base URL 写错或本地网络策略拦截时。检查GOOGLE_PLACES_BASE_URL是不是https://taotoken.net/api结尾没有多余斜杠也没有拼/v1。如果之前配过其他代理变量比如HTTP_PROXY、HTTPS_PROXY先临时unset掉再试排除干扰。注意不要使用任何非正规的网络中转方式保持直连官方入口即可。reading choices / unexpected end of JSON input。这个报错说明返回体不是合法 JSON常见原因是端点返回了 HTML 错误页或者jq拿到空输入。先用不带jq的curl看原始返回curl -s -X POST https://taotoken.net/api/v1/places:searchText \ -H Content-Type: application/json \ -H X-Goog-Api-Key: $GOOGLE_PLACES_API_KEY \ -H X-Goog-FieldMask: places.displayName \ -d {textQuery:coffee,maxResultCount:1}如果返回 HTML 或一段错误文本按文本提示修。如果返回空检查FieldMask是否拼错Places 新版对字段名大小写敏感。OAuth / permission denied。如果你在 Google Cloud 侧用的是 OAuth 而非 API Key或者项目没启用 Places API新版会报权限类错误。确认项目里已启用 Places API (New)并且 key 的 API 限制里允许该 API。用 TaoToken 入口时权限校验在网关侧完成但仍需保证 key 有对应额度。返回结果为空但没报错。检查textQuery是否太窄maxResultCount是否被设成 0--type是否传了 API 不支持的值。另外--open-now和--min-rating组合过严也会导致空结果先去掉过滤条件看有没有数据再逐步加回。goplaces: command not found。说明可执行文件不在 PATH。用which goplaces确认没有的话把安装目录加进 PATH或在技能配置里写绝对路径。排错时建议固定顺序先curl验证端点再goplaces验证技能最后加过滤条件。每步只改一个变量改完立刻重试这样能快速定位是哪一层出的问题。6. 把 goplaces 接进你的工作流从单次查询到可复用脚本跑通之后goplaces 真正的价值在于组合。举一个我常用的场景给定一个城市和关键词批量拉取评分 4 以上、当前营业的地点输出成 CSV 给下游用。命令可以这样写goplaces search ramen \ --lat 35.68 --lng 139.76 --radius-m 2000 \ --open-now --min-rating 4 --limit 20 --json \ | jq -r .[] | [.name, .rating, .formattedAddress] | csv \ ramen_tokyo.csv这条命令把地理偏置、营业过滤、评分过滤、条数限制和 JSON 输出串在一起最后用jq转 CSV。注意--lat、--lng、--radius-m三个要一起用单独给经纬度不生效。--limit控制返回条数避免一次拉太多。分页场景用--page-token。第一次搜索返回里会带一个 token把它传给下一次调用TOKEN$(goplaces search sushi --json | jq -r .nextPageToken) goplaces search sushi --page-token $TOKEN --json | jq .[].name注意 token 有时效别存太久。另外--no-color或NO_COLOR1在写脚本时建议加上避免 ANSI 颜色码污染输出。如果你在 openclaw 里做 Agent 流程可以把 goplaces 当成一个工具节点用户说「找附近评分高的咖啡店」Agent 解析出关键词和过滤条件生成goplaces search调用拿到 JSON 后再决定下一步。这里的关键是让 Agent 知道有哪些参数可用也就是第 3 节配置里args的作用。参数声明清楚Agent 生成的命令才不容易出错。长期做编码或 Agent 编排的话可以考虑用 Coding Plan 来统一管理调用入口和额度入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。如果你只是想先验证模型或接口的返回用模型对话页面更直接https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。需要生成或管理 key 时API Keys 页面在https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。Claude Code 相关的接入说明在https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。最后给一个实用技巧把常用查询封装成 shell 函数放在~/.zshrc里比如coffee() { goplaces search coffee --open-now --min-rating 4 --limit 5 $; }以后直接敲coffee就能查。参数用$透传灵活又不重复。这样 goplaces 就从一条命令变成了你终端里的一个固定动作用起来才顺手。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进