韩国家庭垃圾投放查询技能实战:基于 k-skill 的 household-waste-info 与 k-skill-proxy 密钥注入架构解析
【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill
导读
household-waste-info是 k-skill 技能仓库中面向韩语用户的生活类(utility)技能,它通过调用韩国行政安全部(행정안전부)"生活垃圾分类投放信息"(생활쓰레기배출정보)公共数据 Open API,按**市郡区(시군구)**查询生活垃圾、食物垃圾与可回收物的投放标准、投放星期与时间信息,并以用户友好的摘要形式返回。本篇文章将围绕该技能在仓库中的两个核心文档——SKILL.md 与 instruction.md——完整讲解其使用场景、认证架构、代理路由参数约束、端到端工作流,并结合 k-skill-proxy 源码与测试用例,深入剖析serviceKey服务端注入、分页参数强校验、内存缓存等底层实现,帮助你掌握"官方 Open API + 代理收口密钥 + 技能指令"这套可复用的开发范式。
一、技能概览:它能做什么
1.1 核心能力
根据 instruction.md 的定义,本技能调用行政安全部的生活垃圾投放信息 Open API,向用户提供按地区划分的三类投放信息:
- **生活垃圾(생활쓰레기)**的投放标准与星期/时间;
- **食物垃圾(음식물쓰레기)**的投放标准与星期/时间;
- **可回收物(재활용품)**的投放标准与星期/时间。
几个关键设计决策:
- 基本查询单元是市郡区名(
SGG_NM),即以行政区划名称为入口; - 响应需整理为易于理解的摘要,而不是把 API 原始负载直接抛给用户;
- Base URL 对齐原始 API:
https://apis.data.go.kr/1741000/household_waste_info; serviceKey(DATA_GO_KR_API_KEY)仅由代理服务器注入与管理,用户侧不保存密钥。
1.2 典型使用场景
文档给出了四类典型用户问法,分别覆盖"星期""时间""地点/方法"三个维度的查询:
| 用户提问(示例) | 对应查询意图 |
|---|---|
| "강남구 쓰레기 배출 요일 알려줘"(告诉我江南区垃圾投放星期) | 按市郡区查询投放星期 |
| "우리 동네 음식물쓰레기 언제 버려?"(我们小区的食物垃圾什么时候扔?) | 查询食物垃圾投放时间 |
| "재활용품 배출 시간 확인해줘"(帮我确认可回收物投放时间) | 查询可回收物投放时间 |
| "생활쓰레기 배출 장소/방법 찾아줘"(帮我找生活垃圾投放地点/方法) | 查询投放地点与投放方法 |
这四类问法共同指向一个事实:用户的自然语言中通常只有地区名,没有结构化参数,因此技能的核心职责是"识别地区 → 构造查询 → 摘要结果"。
1.3 前提条件与运行环境
运行该技能需要满足以下环境要求(instruction.md):
- 互联网连接;
- 可执行
curl、python3的运行环境; - 可访问原始 API 的环境;
- 可访问用于密钥注入的代理(proxy)的环境。
值得强调的是:默认路径下用户不需要额外编写客户端 API 层,直接通过代理路由即可完成查询(详见第三节)。
二、认证与密钥架构:为什么用户端不需要 API 密钥
这是本技能最有代表性的架构决策之一,值得单独展开。
2.1 认证需求
instruction.md 明确指出:用户侧默认没有任何必需的认证密钥。可选环境变量只有一个:
KSKILL_PROXY_BASE_URL—— 当使用自托管(self-hosted)代理时才需要设置;未设置时默认走官方托管的k-skill-proxy.nomadamas.org。
2.2 密钥管理的三条原则
文档以编号形式明确了认证密钥的使用原则:
- 端点/参数体系遵循原始 API:代理路由对外暴露的参数名与原始 API 保持一致,客户端无需学习两套协议;
serviceKey由代理服务器管理并注入:密钥只存在于服务器侧;- 用户本地环境无需放置
DATA_GO_KR_API_KEY:这既降低了密钥泄露风险,也让技能对最终用户几乎零配置。
这一设计与 SKILL.md 中的硬性规则("绝不在聊天、文件或 shell 参数中询问、打印或存储明文凭据")互为印证:密钥隔离不是可选项,而是技能的安全底线。
三、官方 API 面与代理路由设计
3.1 官方 API 面
| 项目 | 值 |
|---|---|
| Base URL | https://apis.data.go.kr/1741000/household_waste_info |
| 端点(Endpoint) | GET /info |
| 密钥注入 | 仅由代理k-skill-proxy在服务端注入serviceKey |
也就是说,代理路由实际上对接的上游完整地址是https://apis.data.go.kr/1741000/household_waste_info/info,这在 server.js 中可以直接看到:
const url = new URL("https://apis.data.go.kr/1741000/household_waste_info/info");3.2 代理支持的查询参数(核心约束)
instruction.md 对代理路由的参数约束做了非常明确的定义,这是整个技能最容易踩坑的部分:
| 参数 | 约束 | 说明 |
|---|---|---|
cond[SGG_NM::LIKE] | 必填 | 市郡区名包含式搜索 |
pageNo/numOfRows(或page_no/num_of_rows) | 必填,且值必须是1/100 | 其他值或非整数(不只含数字)的字符串一律返回400,上游不会被调用 |
returnType | 恒为json | 代理强制指定,客户端即使传值也被忽略 |
serviceKey | 禁止客户端传递 | 由代理在服务端注入 |
分页参数之所以被锁死在1/100,是因为生活垃圾分类投放信息按市郡区粒度查询后,单页 100 条足以覆盖绝大多数地区的完整投放规则;同时统一固定分页也简化了缓存键的设计(见第四节源码分析)。
3.3 附加过滤器的说明
原始 API 还支持cond[DAT_CRTR_YMD::*](数据生成日期)、cond[DAT_UPDT_PNT::*](数据更新点)等附加过滤条件,但当前代理路由并不透传(pass-through)这些参数。文档给出了务实的原因:用户常见提问(如"강남구 쓰레기 배출 요일")仅靠市郡区搜索就足够了;如果需要按时间维度排序,可以在客户端依据响应中的DAT_UPDT_PNT自行排序。
四、端到端工作流
instruction.md 将完整流程划分为四个步骤,下面逐一展开并结合源码佐证。
4.1 第一步:先询问地点
在没有拿到用户地区信息之前,绝不直接发起查询。文档推荐的标准提问语是:
"확인할 지역(시/군/구)을 알려주세요. 예: 강남구, 수원시 영통구"(请告诉我要查询的地区(市/郡/区)。例如:江南区、水原市灵通区)
这一步对应了技能的核心查询粒度——市郡区名(SGG_NM),先确认位置才能构造出合法的cond[SGG_NM::LIKE]参数。
4.2 第二步:校验输入并解析查询
- 如果市郡区输入为空,则再次向用户询问;
- 如果输入含糊不清(例如只给了"首尔"这种市域而非市郡区),则应以包含上级行政区划的形式向用户重新确认。
4.3 第三步:通过代理调用(密钥在服务端注入)
代理会在服务端注入serviceKey后再把请求转发给原始 API。文档给出的标准 curl 示例为:
curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/household-waste/info' \ --data-urlencode "cond[SGG_NM::LIKE]=강남구" \ --data-urlencode "pageNo=1" \ --data-urlencode "numOfRows=100"使用要点:
returnType会被代理强制为json,所以客户端无需再单独发送该参数;- 如果设置了
KSKILL_PROXY_BASE_URL环境变量,则以该值替换默认的托管代理地址。
同样的调用方式在 k-skill-proxy/README.md 中也有对应示例(使用${LOCAL_PROXY_BASE_URL}指向自托管实例),证明这是代理的通用调用约定。
4.4 第四步:为用户生成摘要
从响应中抽取必要字段,用简洁、口语化的方式整理给用户。文档指定的摘要字段见下表:
| 类别 | 响应字段 |
|---|---|
| 管理区域 / 目标区域 | MNG_ZONE_NM、MNG_ZONE_TRGT_RGN_NM |
| 投放地点 / 投放方法 | EMSN_PLC、LF_WST_EMSN_MTHD、FOD_WST_EMSN_MTHD、RCYCL_EMSN_MTHD |
| 投放星期 / 时间 | LF_WST_EMSN_DOW、FOD_WST_EMSN_DOW、RCYCL_EMSN_DOW,以及各类别的开始/结束时间 |
| 不收运日 | UNCLLT_DAY |
| 咨询处 | MNG_DEPT_NM、MNG_DEPT_TELNO |
在测试用例 server.test.js 中可以验证这些字段的真实形态,例如LF_WST_EMSN_DOW: "월,수,금"(周一、周三、周五)与LF_WST_EMSN_BGNG_TM: "18:00"、LF_WST_EMSN_END_TM: "23:00"(开始/结束时间)。字段以全大写韩文缩写命名,是行政安全部公共数据 API 的原始风格。
五、源码级实现:路由、密钥注入、缓存与错误处理
本节基于 k-skill-proxy 源码 还原household-waste-info在代理侧的真实实现,帮助你理解指令文档约束背后的代码逻辑。
5.1 路由注册与参数校验
代理在server.js中注册了GET /v1/household-waste/info路由(server.js),处理顺序如下:
- 读取查询参数中的
cond[SGG_NM::LIKE]; - 若缺失或为空 → 返回
400,错误码为bad_request,消息为cond[SGG_NM::LIKE] is required; - 调用
validateHouseholdWastePaginationQuery(query)校验分页参数(server.js),该校验器的规则与指令文档完全一致:- 同时接受
pageNo/numOfRows与page_no/num_of_rows两种命名; - 两者都必填,缺任一即
400; - 值必须通过
^\d+$(纯数字)正则,非数字字符串(如abc)直接400; - 值必须严格等于
pageNo=1、numOfRows=100,否则400。
- 同时接受
从代码结构可以推断:该校验是先于上游请求执行的,因此一旦参数非法,代理会直接拒绝,而不会把非法请求转发给 data.go.kr。
5.2 serviceKey 注入与上游请求构造
校验通过后,代理固定使用pageNo = "1"、numOfRows = "100",并构造上游请求(server.js):
const url = new URL("https://apis.data.go.kr/1741000/household_waste_info/info"); url.searchParams.set("serviceKey", config.molitApiKey); url.searchParams.set("pageNo", pageNo); url.searchParams.set("numOfRows", numOfRows); url.searchParams.set("returnType", "json"); url.searchParams.set("cond[SGG_NM::LIKE]", sggNm.trim());几个值得注意的实现细节:
serviceKey来自config.molitApiKey,而该配置项由环境变量DATA_GO_KR_API_KEY解析而来(server.js),即指令文档所说"密钥由代理服务器管理";returnType被硬编码为json,印证了"客户端传值也会被忽略"的约束;cond[SGG_NM::LIKE]会先trim()再传入,避免首尾空格导致匹配失败。
5.3 密钥未配置时的行为
如果代理服务器没有配置DATA_GO_KR_API_KEY,路由会返回503,错误码为upstream_not_configured,消息为DATA_GO_KR_API_KEY is not configured on the proxy server.(server.js)。这属于指令文档"失败模式"中提到的第一种情况——密钥缺失/失效时的服务端表现。
5.4 内存缓存
路由使用makeCacheKey({ route: "household-waste-info", sggNm: sggNm.trim() })作为缓存键(server.js)。命中缓存时,响应中的proxy.cache.hit为true并附上ttl_ms;未命中时,代理会发起上游请求并把结果连同query、proxy元信息写入缓存。这意味着同一市郡区的重复查询会被代理层去重,从而降低对公共数据 API 的调用压力。
5.5 上游异常映射
- 上游返回非 2xx → 代理返回
502,错误码upstream_error(附带上游状态码); - 上游网络请求抛错 → 代理返回
502,错误码upstream_fetch_failed。
这两类错误对应指令文档"失败模式"中的"公共数据 API 临时故障/流量限制"。此外,k-skill-proxy/README.md 还提醒了一个常见坑:DATA_GO_KR_API_KEY需要在公共数据门户对相应服务单独申请"使用申请(활용신청)"并获批后才能生效,未激活时上游会返回 401/403 或 data.go.kr 的认证错误 XML,代理会将其转换为 upstream error。
六、测试用例验证
k-skill-proxy 的测试套件 为household-waste/info路由覆盖了五类关键场景,是对指令文档约束的直接可执行验证:
- 缺
cond[SGG_NM::LIKE]→400/bad_request(server.test.js); - 未配置
DATA_GO_KR_API_KEY→503/upstream_not_configured(server.test.js); - 缺少分页参数 →
400(server.test.js); - 非法分页值(
pageNo=99&numOfRows=5、pageNo=abc)→400,且不调用上游(server.test.js); - 正常请求 → 注入
serviceKey、强制returnType=json、写入缓存(server.test.js):- 通过 mock
global.fetch捕获上游 URL,断言其 origin + pathname 正是https://apis.data.go.kr/1741000/household_waste_info/info; - 断言响应中的
proxy.cache.hit首次为false,第二次请求命中缓存; - 断言回显的
query.sgg_nm、query.page_no、query.num_of_rows与请求一致; - 还有用例验证客户端即使传
returnType=xml也会被忽略(server.test.js)。
- 通过 mock
这些测试从行为层面确认了:参数的强校验、密钥的服务端注入、返回类型的强制、以及缓存机制,全部是代理路由的硬性实现,而非文档建议。
七、失败模式排查清单
结合 instruction.md 的失败模式与上文源码分析,整理一份排查清单:
| 现象 | 根因 | 排查/处置 |
|---|---|---|
返回503 upstream_not_configured | 代理服务器未配置DATA_GO_KR_API_KEY或密钥已过期,serviceKey注入失败 | 在代理侧配置/更新密钥(server.js) |
| 查询结果为空 | 搜索的地区名与 API 数据不一致(如行政区划变更、名称不匹配) | 改用更接近官方区划名称的输入,或使用上级区划重新确认 |
| 上游报错 / 响应异常 | 公共数据 API 临时故障或流量限制 | 等待后重试;检查DATA_GO_KR_API_KEY是否已在 data.go.kr 对该服务单独申请激活 |
返回400 bad_request | 缺少cond[SGG_NM::LIKE],或未传分页参数 | 补齐参数(server.js) |
返回400(分页规则) | pageNo/numOfRows不是1/100,或为abc等非纯数字字符串 | 严格使用1/100;代理会直接拒绝,上游不会被调用(server.js) |
八、完成条件(Done when)
instruction.md 定义了一次成功技能执行的判定标准,可作为 Agent 自查清单:
- 已确认用户所在地区(市郡区);
- 已成功调用代理的
/v1/household-waste/info路由; - 已把投放星期/时间/地点整理为3~6 个核心要点摘要提供给用户。
九、注意事项与最佳实践
最后是文档反复强调的几条注意事项,也是将该技能投入实际使用的纪律要求:
- 密钥零落地:用户侧不保存
DATA_GO_KR_API_KEY,密钥只在代理服务器端管理; - 摘要而非透传:不要把 API 原始负载直接展示给用户,必须整理成用户友好的摘要;
- 多结果排序:当响应包含多条记录时,优先按最新的
DAT_UPDT_PNT(数据更新点)排序展示,保证信息时效; - 官方数据源:本技能的数据来源为韩国公共数据门户(공공데이터포털)的官方数据集,查询结果具有官方依据。
此外,SKILL.md 还定义了技能运行时的三条硬性规则(即使不通过 CLI 也适用):未经用户明确事先同意,绝不执行支付、消息/邮件发送、最终提交、取消或公开发布等操作;绝不在聊天、文件或 shell 参数中询问、打印或存储明文凭据;绝不绕过法律、到场核验、验证码、身份核验或电子签名等边界。这些规则与本文的密钥代理架构共同构成了该技能安全运行的前提。
如需在运行时获取最新指令,可通过技能 CLI 拉取:
npx -y @nomadamas/k-skill@0 instruct household-waste-info npx -y @nomadamas/k-skill@0 files household-waste-info该技能的类型定义为utility、语言区域为ko-KR、采用 MIT 许可证,相关元数据可在 skill.json 中查看。完整的指令文档与技能说明分别保存在 instruction.md 与 SKILL.md,代理路由实现与测试用例则分别位于 server.js 和 server.test.js。
【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考