本地化一個技能
產出內容
一個可獨立運作的成品,加上其製作過程的記錄。
<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 匹配。當其為 false 時,提供一個預設值並說明粗略的回答即可;我們非正式地處理,誰在就誰做 是一個真實的答案。當其為 true 時,說明該值必須完全匹配及其原因,這樣猜測就不會被視為一個選項。references/asking.md 中有可行的範例。
6. 填入數值。 在整個文件中進行替換——本文、參考文件、腳本、檔案名稱、註解。然後恢復 frontmatter: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 記錄哪些是在未經確認的情況下以預設值填入的、哪些因未使用而跳過,以及任何採用者不確定的內容。來源記錄是日後讓某人能在不重新進行訪談的情況下審計錯誤數值的依據。
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包含了所有組織層級的資訊,這樣下一個技能就會問得更少。