本地化一个技能
产出结果
一个独立运行的工件,以及其创建过程的完整记录。
<skill-name>/ 一个普通技能。可直接运行。
SKILL.md 所有值均已写入,无{{slots}},无TODO
references/… scripts/… 同上,所有文件均已完成
<org>.context.yml 已填充的上下文。保留以备将来重新本地化。
<org>.profile.yml 组织级答案,每个未来技能均可复用
LOCALIZE-NOTES.md 记录推导、询问、默认值、未确认的内容
本地化后的技能 在运行时不会读取上下文文件。所有值已直接写入技能本体。一个必须在运行时加载上下文才能知道自身字段名的技能,每次调用都会付出高昂代价,并在文件移动时引发令人困惑的错误——上下文是决策的记录,而非运行时的依赖。
请先阅读 references/contract.md 了解文件格式,在向任何人提问前阅读 references/asking.md,在交付任何内容前阅读 references/verify.md。
关键的失败模式
不是问题数量。而是采纳者无法回答的问题。
一个向镇书记员询问数据集标识符和模式字段名的技能,不会被缓慢填写——而是会被直接放弃。这种放弃看起来像缺乏兴趣,而非设计缺陷。这正是阻止技能交换在规模上发挥作用的原因,它是问题本身的特性,而非采纳者的特性。
因此:推导可推导的内容,询问关于组织而非技能的问题,让组织已给出的答案为之后采纳的每个技能服务。
第二种失败更隐蔽。一个被填入看似合理但错误值的插槽,会产生一个能运行、能返回数字但结果是错误的技能。绝不要将未确认的值写入 exact: true 的插槽。 一个空白但能被阻止的值是可恢复的;一个误导性的填充则不可。
步骤
1. 在阅读任何其他内容前,先检查 contract_version。 它是上下文文件中的第一个键。将其与 references/contract.md 中的版本进行比较。
匹配是常见情况——继续执行,无需额外说明。如果文件是旧版本,请根据变更日志迁移并记录哪些条目发生了变化。如果文件本技能无法理解的新版本,请停止。 不要填充任何插槽。未知的破坏性变更意味着文件中的任何值都可能被误读,而误读的值会在一个能运行并返回数字的技能中变成看似合理的错误值。请指出差异并要求获取更新的 localize-skill。
如果没有 contract_version,不要假定为 1。引入版本控制之前编写的文件具有未知的结构,而非旧结构。询问其来源。
2. 读取 scope,并大声说出来。 在任何问题之前,告诉采纳者本技能在哪个层级运行以及它被推广到何种程度,用一句话说明:此技能为城市编写,已推广至其他美国城市和城镇。
他们是否处于该范围之内是一个判断,而非查找,因此请交由他们判断,而非进行测试。超出范围的采纳者应重新推广而非填充:插槽是唯一可移植的部分,而遗留的部分从当前角度不可见。填充这些插槽会产生一个看起来已完成但默认假设了他们不存在的国家、法律体系或政府形式的技能。
如果保留的值看起来对他们来说是本地的——例如在选区级别的技能中出现了城市名称——那是 reach 在起作用,而非疏忽。请在他们尝试修复之前说明这一点。
3. 加载已知信息。 在提问之前,先收集手头的答案:
<org>.profile.yml,如果该组织之前采纳过技能。司法管辖区、批准官员、开放数据门户、财政年度等在他们将来采纳的所有技能中都是相同的。重复询问是导致交换在第二个技能上失去用户的原因。- 其他插槽隐含的值。门户基础URL和数据集标识符不是两个独立的问题。
- 由
scope确定的默认值——国家、货币、邮政编码格式、法定制度——这些已由层级和范围固定。
4. 推导可推导的内容,然后确认。 对于有公开来源的值——数据集标识符、模式字段名、门户端点、部门名称——请查找并提出建议。您的311开放日期列似乎是 case_opened_dt。正确吗? 是任何人都能回答的问题。您的311开放日期列是什么? 是几乎没人能回答的问题。
确认推导出的值也是一个问题,但属于不同类型:它要求识别而非回忆,而识别正是让那些并非数据创建者也能使用此方法的原因。推导永远不会免除对 exact: true 值的确认。它只是转移了负担,而非检查。
5. 一次性询问剩余内容。 一次批处理,而非逐步询问。按采纳者最熟悉的内容排序:先问组织,最后问数据。跳过步骤2中已解答的内容,以及该采纳者不会使用的技能分支对应的可选插槽——一个急切询问的可选插槽与一个必填插槽无法区分。
根据 exact 来匹配问题类型。对于 exact: false 的情况,提供一个默认值并说明粗略回答即可;我们采用非正式方式,谁有空谁做 是真实答案。对于 exact: true 的情况,说明该值必须精确匹配及其原因,以便用户明确猜测不是选项。references/asking.md 中提供了有效的提问模式。
6. 写入所有值。 在技能本体、参考文献、脚本、文件名、注释中全部替换。然后恢复前置元数据:description、civic.use-when 和 civic.avoid-when 应使用上下文中的组织特定版本,因为智能体在任何上下文加载前就会读取这些内容,而中性的版本不会因本地请求触发。
将 civic.localization 设置为 localized,civic.jurisdiction 设置为组织名称。从技能目录中移除 context.template.yml。最终交付的技能应看起来像是有人为这个组织专门编写的,因为这正是它现在的定位。
7. 编写记录。 创建 <org>.context.yml,记录每个值及其来源——配置文件、推导值、询问值、默认值。更新 <org>.profile.yml,添加任何组织级的答案,以便下一个技能在大部分内容已填充的状态下启动。创建 LOCALIZE-NOTES.md,记录所有未确认即使用默认值的内容、作为未使用项跳过的内容,以及任何采纳者不确定的内容。来源(provenance)是日后有人审核错误数字时无需重做整个访谈的关键。
8. 在交付前进行验证。 按照 references/verify.md 执行。一个仍包含 {{slot}} 或 TODO 的技能尚未完成,而一个值从未被确认的技能比一个明显未完成的技能更糟糕。
完成前检查
- 上下文文件的
contract_version已检查,且没有从本技能无法理解的新版本文件中填充任何插槽。 - 任何地方(包括脚本、参考文献、文件名和注释)都不存在
{{placeholder}}或TODO。 - 每个
exact: true的值都经过人员确认或来自组织自己的系统。没有任何值是通过推断后静默写入的。 description、civic.use-when和civic.avoid-when中提及组织名称,并且会在本地请求时触发。- 技能无需读取任何上下文文件即可运行。
LOCALIZE-NOTES.md列出了所有未确认或使用默认值的值,并且采纳者已看到该列表。<org>.profile.yml包含所有组织级信息,以便下一个技能提出的问题更少。