
k-skill 项目实战public-restroom-nearby 技能如何实现「附近公共卫生间查找」【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill导读public-restroom-nearby是 k-skill한국인을 위한 스킬 모음집仓库中面向韩国场景的公共卫生间查找技能它以韩国公共数据门户的官方공중화장실정보公共卫生间信息标准数据集为核心数据源配合 Kakao Local REST API 的关键词/加油站图层做补充合并将用户提供的任意位置描述解析为坐标后在本地用 haversine 公式统一计算距离并排序返回。读完本文你将掌握该技能的完整工作流、官方数据接口清单、Node.js 调用方式、全部配置选项的含义以及背后三源合并与去重的源码级实现原理。该技能的运行时指令快照位于 packages/k-skill-cli/test/snapshots/public-restroom-nearby.dolshoi.md技能完整指令本体为 public-restroom-nearby/instruction.md可运行 npm 包源码位于 packages/public-restroom-nearby。技能定位做什么与不做什么技能的核心行为可以用「三个坚持」概括不自动猜测位置位置不会被自动推断必须先向用户询问当前所在位置以官方数据为默认底座卫生间数据默认使用官方공중화장실정보标准数据公开标准数据集不依赖任何第三方私有数据Kakao 仅作可选增强只有当KAKAO_REST_API_KEY环境变量或kakaoRestApiKey选项存在时才会额外调用 Kakao Local REST API把공중화장실公共卫生间、개방화장실开放卫生间、OL7加油站三类 POI 合并进结果。处理位置字符串时技能通过 Kakao Map anchor 搜索确定坐标如果锚点地址能推断出所属市道如 서울/경기/부산就只下载该市道的区域 CSV 以缩小数据量如果用户直接给了坐标则跳过 anchor 解析直接进入邻近计算。在运行时规则上dolshoi 快照明确该技能属于lookup-oriented查询导向完成标准是「取回数据、注明来源表/端点、周期、单位并总结」不承诺任何会改变外部状态的执行动作。适用场景技能面向的自然语言请求包括但不限于근처 화장실 찾아줘帮我找附近的卫生间서울역 근처 공중화장실 있어?首尔站附近有公共卫生间吗광화문 주변 개방화장실 몇 군데만 보여줘光化门附近开放卫生间给我看几个지금 여기서 가까운 화장실 지도 링크 줘给我现在这里最近的卫生间地图链接所有这些请求的共同前提都是先拿到用户的位置。强制第一步必须先问位置无论请求语气多明确只要没有附带位置信息技能就不得直接开始搜索必须先提问。快照与指令文件给出两条推荐话术首选问题현재 위치를 알려주세요. 동네/역명/랜드마크/위도·경도 중 편한 형식으로 보내주시면 근처 공중화장실을 찾아볼게요.请告诉我你的当前位置用小区/站名/地标/经纬度中方便的形式发给我我就帮你找附近的公共卫生间。位置含糊时追问가까운 역명이나 동 이름으로 한 번만 더 알려주세요.请再用附近站名或洞名补充一次。用户可能给出的位置形式在代码层面也被显式支持parseCoordinateQuery见 packages/public-restroom-nearby/src/parse.js用正则/^(-?\d(?:\.\d)?)\s*[,/ ]\s*(-?\d(?:\.\d)?)$/识别37.573713, 126.978338这类经纬度对测试 packages/public-restroom-nearby/test/index.test.js 同时验证了37.573713, 126.978338被解析为{latitude, longitude}而광화문返回null即走 Kakao anchor 解析路径。官方数据源与接口清单技能依赖的数据与接口全部来自公开官方表面快照完整列出了如下端点用途端点公共数据门户标准数据介绍https://www.data.go.kr/data/15012892/standard.do全国 CSV 下载https://file.localdata.go.kr/file/download/public_restroom_info/info区域 CSV 下载按市道代码https://file.localdata.go.kr/file/download/public_restroom_info/info?orgCode시도코드文件介绍页https://file.localdata.go.kr/file/public_restroom_info/infoKakao Map 移动端搜索https://m.map.kakao.com/actions/searchView?qqueryKakao Map 场所面板 JSONhttps://place-api.map.kakao.com/places/panel3/confirmIdnpm 包 READMEpackages/public-restroom-nearby/README.md在此基础上进一步补充了 Kakao Local 的三个 REST 端点关键词搜索https://dapi.kakao.com/v2/local/search/keyword.json查询词为공중화장실、개방화장실分类搜索https://dapi.kakao.com/v2/local/search/category.jsoncategory_group_codeOL7坐标转地址https://dapi.kakao.com/v2/local/geo/coord2address.json区域 CSV 的市道代码由inferRegion从地址前缀推断。源码 packages/public-restroom-nearby/src/parse.js 内置了 17 个市道条目与别名映射例如서울특별시/서울→6110000_ALL경기도/경기→6410000_ALL제주특별자치도/제주도/제주→6500000_ALL测试 packages/public-restroom-nearby/test/index.test.js 验证了「서울특별시 종로구 세종대로 → 6110000_ALL」与「경기도 성남시 분당구 → 6410000_ALL」。buildDatasetDownloadUrl({orgCode})会把 orgCode 拼成?orgCode6110000_ALL形式的区域下载地址。完整工作流7 步快照给出的标准工作流如下右侧附源码印证必须向用户询问当前位置——对应「强制第一步」规则。用 Kakao Map 确定 anchor 坐标收到位置字符串后先请求m.map.kakao.com/actions/searchView?qquery再从返回 HTML 中解析候选。源码resolveAnchorpackages/public-restroom-nearby/src/index.js依次调用parseSearchResultsHtml、rankAnchorCandidates并逐个请求place-api.map.kakao.com/places/panel3/confirmId面板 JSON取到坐标有效的第一个候选作为 anchor。按市道缩小数据范围从 anchor 地址用inferRegion推断市道推断成功则只下载对应区域 CSV。拉取官方 CSV并按需叠加 Kakao 图层下载공중화장실정보CSV有 Kakao 密钥时再并发请求keyword.json?query공중화장실、keyword.json?query개방화장실、category.json?category_group_codeOL7三个图层。对应实现fetchKakaoLayerItemspackages/public-restroom-nearby/src/index.js用Promise.allSettled并发执行三个请求单个图层失败不影响其他图层。丢弃 Kakao 的distance字段统一用 haversine 重算所有结果无论来自 CSV 还是 Kakao都用 WGS84 经纬度经haversineDistanceMeterspackages/public-restroom-nearby/src/parse.js地球半径取 6371008.8m重新计算直线距离并排序。测试中专门断言「local haversine distance, not Kakao distance, controls sorting」见 packages/public-restroom-nearby/test/index.test.js。50m 内重复视为同一设施CSV 结果优先保留mergeAndDeduplicateSourcespackages/public-restroom-nearby/src/index.js先把所有来源按sourceLayerCSV1、Kakao 关键词2、加油站3优先级排序再按「50m 内为同一设施」规则去重同层内按距离排序。测试 packages/public-restroom-nearby/test/index.test.js 验证了同一「통인시장 고객만족센터」在 CSV 与 Kakao 图层都出现时只保留source: csv的一条。简洁输出 3~5 条必要时附地图链接地图链接用buildMapUrlpackages/public-restroom-nearby/src/parse.js生成形如https://map.kakao.com/link/map/URL编码名称,纬度,经度。测试验证了含空格、括号、韩文名的场所名如양재천 영동2교(남단) 개방화장실会被完整 URL 编码避免坐标解析被破坏见 packages/public-restroom-nearby/test/index.test.js。Anchor 解析还有一层容错逻辑某个候选的面板请求返回 4xx/5xx 时isRecoverablePlacePanelError会判定为「可恢复」并跳过该候选继续尝试下一个见 packages/public-restroom-nearby/src/index.js但网络层错误如socket hang up会直接向上抛出对应测试见 packages/public-restroom-nearby/test/index.test.js。应答规范结果字段技能要求在总结结果时通常包含以下字段且保持简短卫生间名称화장실명分类名구분명공중화장실 / 개방화장실距离거리地址주소开放时间/详情개방시간/상세地图链接지도 링크这些字段与源码中 CSV 行归一化产出的对象一一对应normalizePublicRestroomRowspackages/public-restroom-nearby/src/parse.js从官方 CSV 列화장실명、구분명、소재지도로명주소、개방시간、개방시간상세、비상벨설치여부、기저귀교환대유무等映射出包含name、type、address、openTimeCategory、openTimeDetail、hasEmergencyBell、hasBabyChangingTable、hasAccessibleFacility等字段的对象并自动按距离升序、再按分类与名称韩语localeCompare排序。Node.js 使用示例按位置字符串查询推荐的入口const { searchNearbyPublicRestroomsByLocationQuery } require(public-restroom-nearby); async function main() { const result await searchNearbyPublicRestroomsByLocationQuery(광화문, { limit: 3 }); console.log(result.anchor); console.log(result.items); } main().catch((error) { console.error(error); process.exitCode 1; });result.anchor携带解析后的锚点名称、地址、经纬度result.items是排序后的卫生间列表。README 的等价写法还会逐条打印名称、取整距离与地址for (const item of result.items) { console.log(${item.name}: ${Math.round(item.distanceMeters)}m, ${item.address}); }直接给坐标查询当用户直接提供经纬度时使用searchNearbyPublicRestroomsByCoordinatesconst { searchNearbyPublicRestroomsByCoordinates } require(public-restroom-nearby); async function main() { const result await searchNearbyPublicRestroomsByCoordinates({ latitude: 37.57103, longitude: 126.97679, limit: 3, kakaoRestApiKey: process.env.KAKAO_REST_API_KEY }); console.log(result.items); } main().catch((error) { console.error(error); process.exitCode 1; });searchNearbyPublicRestroomsByLocationQuery内部会先调用parseCoordinateQuery识别为坐标对时直接透传给searchNearbyPublicRestroomsByCoordinates见 packages/public-restroom-nearby/src/index.js所以位置字符串入口本身也兼容坐标输入。距离过滤示例需要限制半径时传入maxDistanceMeters合并后的结果会被裁剪const result await searchNearbyPublicRestroomsByLocationQuery(광화문, { limit: 3, maxDistanceMeters: 100 }); console.log(100m 이내 결과 수: ${result.meta.total});配置选项详解技能的核心可配置项均来自 npm 包 README 与源码实现选项默认值说明limit5最终返回的最大结果数必须是正数normalizeLimit会在非法值时抛错radiusMeters1000有 Kakao 密钥时Kakao 关键词/加油站的搜索半径上限钳制为 20000mkakaoSize15Kakao 每个图层的返回条数上限 15Kakao Local API 单次上限maxDistanceMeters无合并后对全部结果按直线距离裁剪的半径上限kakaoRestApiKey/KAKAO_REST_API_KEY无Kakao REST 密钥resolveKakaoRestApiKey的读取顺序为选项 →KAKAO_REST_API_KEY→KAKAO_REST_APIKEYincludeKakaoSourcestrue设为false时跳过 Kakao 关键词/加油站图层仅保留 CSVcorrectCsvWithKakaofalse为true时用 Kakaocoord2address把 CSV 坐标反查的真实建筑名/地址覆盖到结果上csvCorrectionLimit等于limit地址校正的条数上限仅在需要比默认可见窗口更宽时显式设置deduplicateDistanceMeters50判断「同一设施」的坐标距离阈值orgCode/preferredDistrict自动推断手动指定区域 CSV 或偏好行政区优先级高于自动推断结果几个容易混淆的细节radiusMeters与maxDistanceMeters语义不同前者只作用于 Kakao 图层的请求参数后者在合并后统一过滤 CSV 与 Kakao 的所有结果实现见 packages/public-restroom-nearby/src/index.js。limit的默认值是 5而非快照中「3~5 个」建议里的 3后者只是应答排版建议。Kakao 图层失败不致命Kakao Local API 返回 401/429/5xx 时官方 CSV 结果照常返回失败的图层会以{source, status, message, url}形式记录进result.meta.kakaoErrors错误规范化见 packages/public-restroom-nearby/src/index.js。测试 packages/public-restroom-nearby/test/index.test.js 验证了三个 Kakao 图层全部 429 时仍返回 CSV 结果且kakaoErrors.length 3。返回结构resultanchor : { name, address, latitude, longitude } items : [ { name, type, address, latitude, longitude, distanceMeters, source, sourceLayer, openTimeDetail, mapUrl, ... } ] meta : { total, limit, datasetUrl, region, sources, kakaoEnabled, kakaoErrors }其中meta.sources分别统计csv、kakaoKeyword、kakaoGasStation三类来源的数量summarizeSourcespackages/public-restroom-nearby/src/index.js。源码级细节CSV 编码与容错官方 CSV 的编码并非统一 UTF-8decodeDatasetBufferpackages/public-restroom-nearby/src/parse.js先用 UTF-8 解码并检查是否包含개방자치단체코드、화장실명表头不满足时退回TextDecoder(euc-kr)解码。这是该技能针对韩国官方开放数据的实测兼容处理。CSV 的解析还包含带引号字段与转义引号的处理以及空行过滤归一化时会丢弃坐标缺失的行、剔除maxDistanceMeters之外的行并用「名称地址坐标分类」联合键对 CSV 内部重复行去重packages/public-restroom-nearby/src/parse.js对应测试见 packages/public-restroom-nearby/test/index.test.js。完成标准Done when已先确认用户的当前位置基于官方数据至少找到 1 个附近卫生间若一个都没找到则给出失败原因并抛出后续引导问题将最近的结果整理在 3~5 条以内输出。失败模式与应对快照明确列出了四种典型失败模式这也应成为调用方的预期管理依据没有 Kakao REST API 密钥时退化为 CSV 单源可能漏掉官方标准数据未收录的 POI如加油站、私有建筑开放卫生间。Kakao Map anchor 含糊时基准点会漂移同名地点多时如多个「광화문」候选排名与坐标可能不稳定实现上已通过候选排序与面板失败回退缓解。标准数据不含实时占用/锁定状态公开标准数据集不提供实时「是否有人/是否锁门」信息因此只能围绕开放时间개방시간/개방시간상세来答复不得声称实时可用性。CSV 编码或列结构变化若官方文件的编码或列名变更如WGS84위도、화장실명列缺失需要重新核对decodeDatasetBuffer与normalizePublicRestroomRows的映射逻辑。与 k-skill CLI 的关联该技能以完整 skill 目录发布在仓库根目录 public-restroom-nearby同时被打包进nomadamas/k-skillCLIpackages/k-skill-cli。运行时通过以下命令获取该技能的最新指令与文件清单npx -y nomadamas/k-skill0 instruct public-restroom-nearby npx -y nomadamas/k-skill0 files public-restroom-nearby在正式调用 k-skill CLI 工具前快照要求先执行npx -y nomadamas/k-skill0 update保证 CLI 与各编码 Agent 的技能安装含~/.agents/skills处于最新技能元数据profiles: vault, lookup、locale: ko-KR、category: convenience定义在 public-restroom-nearby/skill.json。对密钥类凭据运行时规则要求一律使用预置的vault-run能力缺失时调用request_vault_credential申请绝不把明文密钥写入对话或文件。小结public-restroom-nearby是一个典型的「官方标准数据 可选商业图层增强」的混合查询技能官方 CSV 保证数据权威与零成本可用Kakao 图层补足开放卫生间与加油站的覆盖缺口本地 haversine 重算保证距离排序的一致与可信50m 去重与 CSV 优先策略则保证多源合并后的结果质量。其指令快照、skill 指令文件、npm 包源码packages/public-restroom-nearby/src/index.js、packages/public-restroom-nearby/src/parse.js与 20 个测试用例packages/public-restroom-nearby/test/index.test.js构成了从产品行为到实现细节的完整闭环可以作为韩语地理位置类 skill 设计与数据合并类查询实现的参考范本。【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考