極點宏觀|Financial Cloud Cloud · 建構文章
使用 Kiro 建置:他加祿語 學習 App 的深入開發流程工作坊
對象: 想要掌握端到端(End-to-End)AI 輔助工程流程的專業開發者
時長: 2 小時
核心 AWS AI 服務: Kiro
專案產出: 一個確定性(Deterministic)的靜態網站產生器,能將句子庫擴展為他加祿語學習卡、渲染 HTML、驗證輸出並打包發行成品(Artifact)。
僅限教育工程研討會。這是一項軟體架構練習,而非流程發佈建議。
工作坊概述
本工作坊將引導開發者建立一個完整的「檔案優先(File-first)」他加祿語學習網站建置管線。參與者將使用 Kiro 來定義引導原則、建立文章資料模型、擴展句子庫、生成輔助內容、渲染靜態 HTML、驗證輸出並打包發行。核心重點在於可重複的工程流程,透過結構化資料與檢查機制,確保生成的學習材料具備可預測性、可追溯性,並方便後續審查人員進行核對。
工作坊目標
本工作坊聚焦於開發流程。開發者將建構一個檔案優先的內容管線:包含文章中介資料(Metadata)、句子庫、情境擴展、語法輔助、發音輔助、HTML 渲染、驗證檢查及發行打包。Kiro 將在流程中負責引導、規格制定、任務規劃、實作支援、測試生成、勾點(Hooks)、文件編寫以及發行審查。
2 小時議程
| 時間 | 模組 | 開發者成果 |
|---|---|---|
| 0–10 分鐘 | Kiro 工作空間 | 準備好引導(Steering)與規格(Spec)資料夾 |
| 10–25 分鐘 | 內容契約 | 設計文章與句子庫的綱要(Schema) |
| 25–45 分鐘 | 確定性擴展 | 將 10 個基礎片語擴展為 40 張卡片 |
| 45–65 分鐘 | 輔助函式 | 加入語法與發音輔助工具 |
| 65–90 分鐘 | 靜態渲染 | 從結構化資料生成 HTML 頁面 |
| 90–105 分鐘 | 驗證機制 | 加入卡片數量、摘要與禁用字詞參照檢查 |
| 105–115 分鐘 | 打包發行 | 建立 Zip 發行成品 |
| 115–120 分鐘 | 成果審查 | 產出 Kiro 輔助的發行檢查清單 |
步驟 1 — 建立檔案優先產生器的 Kiro 引導原則
Kiro 提示詞範例
建立檔案優先靜態網站產生器的引導文件。
此產品是為 AWS 馬尼拉社群日(AWS Manila Community Day)設計的他加祿語學習 App。
使用 Python 進行確定性生成、HTML 輸出、CSS 與 zip 打包。
信任來源為結構化資料,而非人工撰寫的頁面。
每個生成的頁面在發行前都必須經過驗證。
系統設計決策
● 檔案優先架構: 此應用程式在工作坊期間不需要執行期(Runtime)後端。技術目標是展示如何將精簡的原始資料轉化為大型且一致的學習網站。檔案優先的生成方式讓每個建置步驟都清晰可見、易於檢查且便於解說。
● 確定性生成優於隨機輸出: AI 可以協助草稿和程式碼編寫,但發布的建置版本必須是確定性的。給定相同的句子庫與情境,產生器每次都應產出完全相同的卡片與檔案。這能讓審查、測試與除錯變得切實可行。
● 將驗證視為產品功能: 生成的網站可能外表看起來很完整,卻隱藏了遺漏卡片或行動版 CSS 跑版的問題。建置驗證是系統設計的核心,而非事後補救。發行成品中必須包含已通過必要條件檢查的辨識憑證。
程式碼範例 — .kiro/steering/static-generator.md
# 靜態產生器引導原則
本專案負責從結構化的 Python 資料生成他加祿語學習網站。
當渲染器可以自動生成頁面時,切勿手動撰寫最終頁面。
## 規則
- 文章中介資料(Metadata)控制導覽與檔案名稱。
- 句子庫為精簡的原始資料。
- 情境擴展以確定性的方式建立重複的學習卡片。
- HTML 輸出必須對生成的文字進行轉義(Escape)。
- 每篇文章必須恰好包含 40 張卡片。
- 發行檢查必須在生成後、打包前執行。
- 生成的語言內容在正式上線前,需要經過母語人士審查。
程式碼說明
● 商業邏輯: 引導文件定義了產生器的哲學:結構化資料、確定性輸出與發行檢查。
● 程式邏輯: Kiro 在生成 Python 函式、驗證檢查與發行任務時,會遵循這份 Markdown 指引。
● 預期結果: Kiro 的建議會傾向於使用可重複使用的渲染器與檢查機制,而非手動複製 HTML。
步驟 2 — 生成管線的 Kiro 規格書
Kiro 提示詞範例
建立一個名為 tagalog-static-generator 的規格書。
功能:從中介資料與句子庫生成文章頁面。
包含需求、設計、資料流與實作任務。
驗收標準:每篇文章有 40 張卡片、HTML 內容需轉義、具備行動版 CSS,且發行 zip 包需包含生成的頁面。
系統設計決策
● 規格書描繪的是管線,而非只有 UI: 核心的工程價值在於從原始資料到發行成品的轉換流程。規格書應涵蓋資料、擴展、渲染、驗證與打包,好讓開發者理解整個系統。
● 驗收標準轉化為發行檢查: 「恰好 40 張卡片」與「具備行動版 CSS」是客觀的指標。它們可以被計數與測試,這讓發行過程透明且對工作坊友善。
● 可追溯的任務: Kiro 任務將管線拆解為可管理的實作單元。專業開發者可以在實際團隊中獨立指派、審查或自動化每個任務。
程式碼範例 — .kiro/specs/tagalog-static-generator/design.md
# 設計
## 資料流
1. 文章中介資料定義頁面識別、Slug(網址別名)、標題、分類與摘要。
2. 句子庫定義精簡的文句元組(Tuple)。
3. 情境陣列將每個元組確定性地擴展為多張學習卡片。
4. 輔助函式附加語法說明、範例與發音。
5. 渲染器建立轉義後的靜態 HTML。
6. 驗證器檢查卡片數量、行動版 CSS 標記、摘要字數以及禁用的內部參照。
7. 打包器寫入 zip 發行成品。
## 核心模組
- `content.py`: 原始文章中介資料與句子庫
- `expand.py`: 確定性卡片擴展
- `helpers.py`: 語法、範例與發音輔助
- `render.py`: HTML 渲染
- `validate.py`: 發行檢查
- `build.py`: 編排生成與打包流程
程式碼說明
● 商業邏輯: 此設計展示了如何將文化學習目標轉化為可重複的建置系統。
● 程式邏輯: 每個模組各司其職(單一職責原則),使 Kiro 生成的實作程式碼更易於審查。
● 預期結果: 開發者可以分步實作產生器,並在每個階段進行驗證。
步驟 3 — 建立文章中介資料與句子庫模型
Kiro 提示詞範例
建立靜態他加祿語學習網站的 Python 原始資料。
文章中介資料需包含 id、slug、title、category 以及 20 個字左右的英文摘要。
建立一個精簡的句子庫,包含英文、自然他加祿語、禮貌他加祿語、親切菲律賓英語(Taglish)、趣味菲律賓英語以及語氣。
系統設計決策
● 中介資料作為路由契約: 文章中介資料控制了檔案名稱、導覽、頁面標題與摘要。將中介資料視為契約可防止頁面產生偏差,並讓網站易於重新生成。
● 精簡的元組原始資料: 句子庫只儲存經過審查的最小片語單元。產生器圍繞穩定的基礎句子擴展情境,而不是為每張卡片憑空捏造全新的輸出。
● 原始資料中的語氣變體: 每個基礎片語都包含自然、禮貌、親切與趣味版本。這確保了渲染器在顯示側邊對比時,不需靠猜測來呈現語氣差異。
程式碼範例 — content.py
ARTICLES = [
{
"id": 1,
"slug": "community-greetings-introductions",
"title": "Community Day: Greetings and Respectful Introductions",
"category": "Community Day",
"summary": "Practice polite greetings names beginner phrases and warm introductions for meeting speakers volunteers students and builders in Manila with confidence today"
}
]
SENTENCE_BANKS = {
1: [
(
"Hello, I am learning Tagalog.",
"Kumusta, nag-aaral ako ng Tagalog.",
"Kumusta po, nag-aaral po ako ng Tagalog.",
"Hello po, learning Tagalog ako.",
"Kumusta, learning Tagalog na ako, all right.",
"friendly beginner introduction"
),
(
"May I ask a question?",
"Puwede ba akong magtanong?",
"Puwede po ba akong magtanong?",
"Can I ask po?",
"Question time na ako, all right?",
"polite workshop request"
)
]
}
CONTEXTS = [
("at morning registration", "sa morning registration"),
("before a workshop starts", "bago magsimula ang workshop"),
("while meeting a volunteer", "habang may nakikilalang volunteer"),
("after a session", "pagkatapos ng session")
]
程式碼說明
● 商業邏輯: 這些資料定義了網站的教學內容以及頁面的識別方式。
● 程式邏輯: ARTICLES 儲存頁面中介資料。SENTENCE_BANKS 將文章 ID 對應到片語元組。CONTEXTS 提供確定性擴展時所需的場景情境。
● 預期結果: 其他模組可以生成頁面與卡片,而不需要在渲染函式中寫死(Hardcode)內容。
步驟 4 — 將基礎片語擴展為卡片
Kiro 提示詞範例
建立一個 Python 函式,將每個基礎片語擴展為結合情境的卡片。
每張卡片必須包含:編號、背景說明、英文、自然、禮貌、親切、趣味、語氣與情境欄位。
藉由循環情境並裁切溢出欄位,確保每篇文章正好返回 40 張卡片。
系統設計決策
● 受控的擴展: 產生器擴展的是「情境」而非「含意」。保持基礎句子的穩定有助於學習者在看到不同的活動場景時,能牢記核心句型。
● 精確的數量確保頁面可預測: 文章契約規定每個頁面有 40 張卡片。精確的數量讓版面配置、審查工作量以及發行驗證變得完全可預測。
● 建置版本中不包含隨機性: 隨機生成會使審查變得困難。確定性的迴圈確保了任何錯誤回報都能基於相同的輸入資料完全重現。
程式碼範例 — expand.py
from itertools import cycle
from content import CONTEXTS
def expand_cards(base_sentences, article_id, target_count=40):
cards = []
context_cycle = cycle(CONTEXTS)
while len(cards) < target_count:
for sentence in base_sentences:
if len(cards) >= target_count:
break
english, natural, polite, friendly, playful, tone = sentence
context_en, context_tl = next(context_cycle)
cards.append({
"num": len(cards) + 1,
"background": f"Use this sentence {context_en}. It supports respectful event communication.",
"english": english,
"natural": natural,
"polite": polite,
"friendly": friendly,
"playful": playful,
"tone": tone,
"context_en": context_en,
"context_tl": context_tl,
"article_id": article_id
})
return cards
程式碼說明
● 商業邏輯: 將小型的句子庫轉化為完整的文章卡片集,同時完整保留經審查後的句型文字。
● 程式邏輯: 該函式會循環情境與基礎句子,直到達到 target_count。每張卡片都會獲得確定性的編號。
● 預期結果: 呼叫 expand_cards(SENTENCE_BANKS[1], 1) 將準確返回包含 40 個卡片字典的列表。
步驟 5 — 加入語法與發音輔助工具
Kiro 提示詞範例
建立語法拆解與發音指引的輔助函式。
如果英文提到 thank,解釋 Salamat 與 po。
如果英文詢問 where,解釋 Saan 與 ang。
如果英文詢問 permission,解釋 Puwede、ba 與 magtanong。
返回適合初學者的簡短說明。
系統設計決策
● 基於規則的擴充(Augmentation): 語法備註應該保持一致且可審查。簡單的規則比不透明的執行期生成更容易檢查。
● 初學者優先的說明: 開發者應避免塞入過多學術性的語法。輔助工具應返回能融入行動版卡片的短小說明。
● 輔助工具將資料富集(Enrichment)與渲染分離: 渲染器只負責顯示內容,不應決定語法邏輯。輔助函式能讓富集邏輯保持可測試性與可重複使用性。
程式碼範例 — helpers.py
def grammar_breakdown(card):
english = card["english"].lower()
natural = card["natural"].lower()
if "thank" in english or "salamat" in natural:
return [
("Salamat", "thank you"),
("po", "politeness marker"),
("sa", "for, in, at, or to depending on context")
]
if "where" in english or natural.startswith("saan"):
return [
("Saan", "where"),
("po", "polite marker for respectful questions"),
("ang", "focus marker before the place or thing")
]
if "may i" in english or "question" in english:
return [
("Puwede", "may or can"),
("ba", "question marker"),
("magtanong", "to ask")
]
return [
("po", "polite marker used for respect"),
("ako", "I or me"),
("kayo", "polite or plural you")
]
def pronunciation_guide(tagalog):
if tagalog.startswith("Kumusta"):
return "koo-MOOS-tah. Keep the greeting warm and clear."
if tagalog.startswith("Puwede"):
return "PWEH-deh poh bah AH-kong mag-tah-NONG. Make the question gentle."
if tagalog.startswith("Saan"):
return "SAH-ahn poh. Keep the question short and polite."
return "Read vowels clearly: a as ah, e as eh, i as ee, o as oh, u as oo."
程式碼說明
● 商業邏輯: 輔助工具提供了超越單純翻譯的教學價值。
● 程式邏輯: grammar_breakdown 根據英文與他加祿語文本挑選初學者備註。pronunciation_guide 則返回特定片語的指引或預設方案。
● 預期結果: 每個生成的卡片都能顯示語法與發音,而不必為每張卡片手動撰寫這些內容。
步驟 6 — 安全地渲染靜態 HTML
Kiro 提示詞範例
為文章頁面建立一個 Python HTML 渲染器。
對所有生成的文字進行轉義(Escape)。
渲染標題、摘要、分類、40 張句子卡片、語法拆解、發音指引以及行動版 CSS。
系統設計決策
● HTML 轉義是強制性的: 生成的內容可能包含標點符號、單引號或非預期字元。轉義能保護頁面結構並防止意外的標記法注入(Markup Injection)。
● 每篇文章共用同一個渲染器: 單一渲染器可防止版面產生偏差。如果卡片設計需要變更,開發者只需更新一個函式並重新生成網站即可。
● 為了工作坊的簡潔性而內嵌 CSS: 對大型網站來說,外部 CSS 較為乾淨;但內嵌小型樣式區塊能讓工作坊的產出物保持便攜且易於檢查。
程式碼範例 — render.py
import html
from helpers import grammar_breakdown, pronunciation_guide
def render_card(card):
grammar_items = "".join(
f"<li><strong>{html.escape(term)}:</strong> {html.escape(meaning)}</li>"
for term, meaning in grammar_breakdown(card)
)
return f"""
<article class="sentence-card">
<h2>Sentence {card['num']}</h2>
<p><strong>Background:</strong> {html.escape(card['background'])}</p>
<p><strong>English:</strong> {html.escape(card['english'])}</p>
<p><strong>Natural Tagalog:</strong> <span lang="tl">{html.escape(card['natural'])}</span></p>
<p><strong>Polite Tagalog:</strong> <span lang="tl">{html.escape(card['polite'])}</span></p>
<p><strong>Friendly Filipino-English:</strong> {html.escape(card['friendly'])}</p>
<p><strong>Playful Filipino-English:</strong> {html.escape(card['playful'])} <span class="badge">Informal</span></p>
<p><strong>Tone:</strong> {html.escape(card['tone'])}</p>
<h3>Grammar breakdown</h3>
<ul>{grammar_items}</ul>
<h3>Pronunciation</h3>
<p>{html.escape(pronunciation_guide(card['polite']))}</p>
</article>
"""
def render_article(article, cards):
body = "\n".join(render_card(card) for card in cards)
return f"""<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{html.escape(article['title'])}</title>
<style>
body {{ font-family: system-ui, sans-serif; margin: 0; padding: 1rem; line-height: 1.6; }}
main {{ max-width: 960px; margin: auto; }}
.sentence-card {{ border: 1px solid #d0d7de; border-radius: 16px; padding: 1rem; margin: 1rem 0; }}
.badge {{ background: #fff3cd; color: #7a4d00; padding: .15rem .5rem; border-radius: 999px; font-size: .75rem; }}
@media (max-width: 760px) {{ body {{ padding: .75rem; }} .sentence-card {{ padding: .85rem; }} }}
</style>
</head>
<body>
<main>
<p>{html.escape(article['category'])}</p>
<h1>{html.escape(article['title'])}</h1>
<p>{html.escape(article['summary'])}</p>
<p><strong>Review note:</strong> Generated language content requires native-speaker review before production use.</p>
{body}
</main>
</body>
</html>"""
程式碼說明
● 商業邏輯: 渲染器將結構化的學習卡片轉換為可在瀏覽器中閱讀的課程頁面。
● 程式邏輯: html.escape 保護所有動態文字。render_card 處理卡片的標記,而 render_article 則將卡片包裝進完整的 HTML 文件中。
● 預期結果: 生成的文章頁面會包含精確傳入渲染器的卡片,並在行動裝置上保持良好的可讀性。
步驟 7 — 驗證並打包發行成品
Kiro 提示詞範例
建立 Python 建置程式碼,用來生成文章 HTML、驗證每個頁面、列印 JSON 檢查結果並寫入 zip 壓縮包。
檢查項:每個頁面有 40 個 sentence-card 元素、行動版 CSS 存在、摘要剛好 20 個單字,且不含禁用的內部參照。
系統設計決策
● 以程式碼進行建置編排: 專業的工作坊應該以可重複執行的建置流程結束,而非手動複製示範檔。build.py 以可執行程式碼的形式記錄了發行流程。
● 在渲染後進行驗證: 檢查是針對生成的 HTML 進行,因為這才是學習者最終開啟的檔案。僅驗證原始資料可能會漏掉渲染器本身的缺陷。
● 以 Zip 封裝以便分享: Zip 檔案在社群工作坊結束後非常便於發發。打包確切生成的檔案,能避免對於哪些檔案該被部署或審查產生模糊空間。
程式碼範例 — build.py
import json
import re
import zipfile
from pathlib import Path
from content import ARTICLES, SENTENCE_BANKS
from expand import expand_cards
from render import render_article
OUT_DIR = Path("dist")
ZIP_NAME = "tagalog-learning-static-site.zip"
def word_count(text):
return len(re.findall(r"\b\w+\b", text))
def validate_page(path, article):
text = path.read_text(encoding="utf-8")
return {
"file": path.name,
"sentence_cards": text.count('class="sentence-card"'),
"has_mobile_css": "@media (max-width: 760px)" in text,
"summary_words": word_count(article["summary"]),
"has_forbidden_internal_reference": bool(re.search(r"internal prompt|private instruction", text, re.I))
}
def build():
OUT_DIR.mkdir(exist_ok=True)
checks = []
for article in ARTICLES:
cards = expand_cards(SENTENCE_BANKS[article["id"]], article["id"])
html = render_article(article, cards)
output_path = OUT_DIR / f"article-{article['id']}-{article['slug']}.html"
output_path.write_text(html, encoding="utf-8")
checks.append(validate_page(output_path, article))
with zipfile.ZipFile(ZIP_NAME, "w", zipfile.ZIP_DEFLATED) as package:
for html_file in sorted(OUT_DIR.glob("*.html")):
package.write(html_file, arcname=html_file.name)
print(json.dumps(checks, indent=2))
failures = [
check for check in checks
if check["sentence_cards"] != 40
or not check["has_mobile_css"]
or check["summary_words"] != 20
or check["has_forbidden_internal_reference"]
]
if failures:
raise SystemExit("Release validation failed")
if __name__ == "__main__":
build()
程式碼說明
● 商業邏輯: 建置指令碼建立了一個準備好發行的靜態網站,並證明了該網站符合預期的學習架構契約。
● 程式邏輯: 該指令碼擴展卡片、渲染 HTML、驗證生成的頁面、寫入 zip 壓縮包、輸出 JSON 檢查結果,並在違反任何規則時中斷建置。
● 預期結果: 執行 python build.py 會建立 dist/*.html、生成 tagalog-learning-static-site.zip、輸出檢查報告,且只有在完全符合驗證時才會成功退出。
步驟 8 — 加入 Kiro 發行勾點(Hook)與最終審查
Kiro 提示詞範例
建立一個用於發行維護的 Kiro 勾點。
當 build.py 或 content.py 變更時,自動執行 python build.py,摘要驗證輸出,並針對失敗的卡片數量、行動版 CSS、摘要字數或禁用參照提供修復建議。
系統設計決策
● 讓自動化貼近變更發生的核心: 建置驗證應在原始內容或建置邏輯發生變更時立即觸發,而非僅在發行前的最後一刻。Kiro 勾點能讓開發者在第一時間獲得回饋。
● 除了回報失敗,更要解釋原因: 當工具能解釋發行檢查失敗的原因並給出具體的最小修復建議時,開發者能學得更快。這在參與者可能初次接觸 Kiro 或此程式庫的工作坊中尤為實用。
● 發行檢查清單作為活文件: 勾點成為了「定義完成(Definition of Done)」的即時文件,為未來的專案貢獻者留下了團隊期望的標準。
Kiro 勾點範例 — .kiro/hooks/release-validation.md
# 勾點:發行驗證
觸發條件:當 `build.py`、`content.py`、`expand.py`、`helpers.py` 或 `render.py` 變更時。
執行動作:
1. 執行 `python build.py`。
2. 讀取 JSON 驗證輸出。
3. 若某個頁面的卡片數量不等於 40,指出是哪篇文章失敗。
4. 若遺漏行動版 CSS,提示在 `render.py` 中恢復媒體查詢(Media Query)。
5. 若摘要字數不等於 20,提示修正後的 20 字摘要。
6. 若出現禁用的內部參照,指出受影響的生成檔案並提示刪除該字詞。
勾點說明
● 商業邏輯: 該勾點能防止生成的學習網站偏離發行標準。
● 程式邏輯: 它會偵測產生器檔案的變更、執行建置、解析 JSON 檢查結果並給出精確的修復指引。
● 預期結果: 開發者能在分享靜態網站前,獲得即時的發行品質回饋。
完成度檢查清單
● [ ] Kiro 引導原則文件已詳述檔案優先產生器的規則。
● [ ] Kiro 規格書已描述資料流與各項任務。
● [ ] 文章中介資料與句子庫已建立完成。
● [ ] 擴展函式能精確返回 40 張卡片。
● [ ] 語法與發音輔助工具正常運作。
● [ ] 渲染器已對生成文字進行轉義。
● [ ] 建置指令碼能正確驗證生成的 HTML。
● [ ] Zip 發行壓縮包已順利建立。
● [ ] Kiro 發行勾點指引已就緒。
工作坊後的選配 AWS 延伸擴充
● 將 Zip 壓縮包內容上傳至 Amazon S3 靜態網站代管。
● 在靜態網站前方架設 Amazon CloudFront。
● 將原始 JSON 儲存於已啟用版本控制的 S3 儲存桶中。
● 在 CI/CD 管線中使用 Kiro CLI,以便在發出 Pull Request 時自動執行產生器檢查。
額外實作開發者實驗室(Labs)
這些實驗室是 工作坊 3 — 深度開發流程 所獨有的。它們延伸了 Python 靜態網站產生器,加入了確定性建置作業、發行履歷(Provenance)、發行資訊清單(Manifest)、審查者套件包(Reviewer Bundles)以及管線測試。焦點在於產生器工程,而非前端 React 應用的行為。
實作實驗室 A — 加入建置資訊清單以實現發行履歷
開發者行動
● 請求 Kiro 建立發行資訊清單的格式。
● 在每次建置後生成 dist/manifest.json。
● 內容需包含文章總數、生成的檔案、卡片計數、建置時間戳記與驗證摘要。
● 加入一個驗證器檢查,若資訊清單遺漏預期檔案則判定建置失敗。
Kiro 提示詞範例
在 Python 靜態產生器中加入建置資訊清單。
在渲染頁面後,將生成的檔案名稱、文章 ID、卡片數量、驗證檢查結果以及建置時間戳記寫入 dist/manifest.json。
除了時間戳記外,資訊清單的內容必須是確定性的。
加入一項驗證,確保每個生成的 HTML 檔案都列在資訊清單中。
系統設計決策
● 發行履歷至關重要: 當 Zip 成品中包含一份可供機器讀取的生成內容描述時,審查者能更輕鬆地核對。
● 資訊清單與驗證相輔相成: 驗證機制說明建置是否「通過」,而資訊清單則記錄了建置的「內容」。
● 審查者友善的成品: 審查人員不需逐一開啟 HTML 頁面,即可檢查檔案名稱與數量。
程式碼範例 — manifest.py
from datetime import datetime, timezone
import json
from pathlib import Path
def write_manifest(output_dir: Path, articles: list[dict], checks: list[dict]) -> Path:
html_files = sorted(path.name for path in output_dir.glob("*.html"))
manifest = {
"generatedAt": datetime.now(timezone.utc).isoformat(),
"articleCount": len(articles),
"files": html_files,
"checks": checks,
"cardCounts": {
check["file"]: check["sentence_cards"]
for check in checks
}
}
manifest_path = output_dir / "manifest.json"
manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
return manifest_path
程式碼說明
● 商業邏輯: 資訊清單為審查者與未來的維護人員提供了發行版本的完整記錄。
● 程式邏輯: 該函式掃描生成的 HTML 檔案,記錄驗證輸出,並將 JSON 寫入輸出目錄。
● 預期結果: 每次建置都會在生成頁面的旁側同步產出 dist/manifest.json。
實作實驗室 B — 加入確定性卡片 ID 與 Slug 衝突檢查
開發者行動
● 請求 Kiro 將純數值的卡片識別改為「穩定 ID」。
● 結合文章 ID、原始句子索引與情境索引來生成卡片 ID。
● 針對文章中介資料加入 Slug 衝突檢查。
● 當出現重複的卡片 ID 或文章 Slug 時,判定建置失敗。
Kiro 提示詞範例
為生成的卡片建立確定性 ID。
使用文章 id、原始句子索引、情境索引與序列號組合而成。
針對重複的卡片 id 與重複的文章 slug 加入發行驗證。
若發生衝突,返回能明確指出衝突紀錄的錯誤訊息。
系統設計決策
● 穩定的 ID 能支援審查意見: 當母語審查人員對特定卡片提出修改意見時,需要一個固定的參照基準。
● 衝突檢查可防止頁面遭到覆蓋: 重複的 Slug 會導致某些文章在 dist 目錄中被其他文章覆蓋。
● 確定性有助於迴歸測試: 除非原始資料或擴展邏輯發生變更,否則 ID 絕不應改變。
程式碼範例 — identity.py
import re
def safe_slug(value: str) -> str:
text = value.lower().strip()
text = re.sub(r"[^a-z0-9]+", "-", text)
return text.strip("-")
def card_id(article_id: int, sentence_index: int, context_index: int, sequence: int) -> str:
return f"a{article_id:03d}-s{sentence_index:02d}-c{context_index:02d}-n{sequence:03d}"
def assert_unique(values: list[str], label: str) -> None:
seen: set[str] = set()
duplicates: set[str] = set()
for value in values:
if value in seen:
duplicates.add(value)
seen.add(value)
if duplicates:
joined = ", ".join(sorted(duplicates))
raise ValueError(f"Duplicate {label}: {joined}")
程式碼說明
● 商業邏輯: ID 與 Slug 成為了穩定的審查與路由契約。
● 程式邏輯: card_id 產生確定性的 ID;assert_unique 則在發現重複時立即引發錯誤(Fail-fast)。
● 預期結果: 審查者可以明確引用卡片 ID,且產生器會拒絕編譯具歧義的文章輸出。
實作實驗室 C — 建立增量建置快取以加快反覆運算速度
開發者行動
● 請求 Kiro 為每篇文章的原始資料計算內容雜湊值(Hash)。
● 將雜湊值儲存於 .build-cache.json。
● 除非帶有 --force 參數,否則自動跳過未變更文章的渲染工作。
● 列印出哪些文章已建置、跳過或未通過驗證。
Kiro 提示詞範例
在靜態產生器中加入增量建置(Incremental build)功能。
為每篇文章的中介資料、句子庫與情境計算雜湊值。
將雜湊值儲存於 .build-cache.json。
除非使用了 --force,否則跳過未變更的文章。
在打包之前,務必對現有的輸出檔案重新執行驗證。
系統設計決策
● 為內容密集的建置提供快速回饋: 大型生成網站不應僅因為單一文章變更就重新渲染所有頁面。
● 快取原始輸入,而非輸出檔案的時間戳記: 對原始資料進行雜湊運算,能讓重新建置的決策具備確定性與可移植性。
● 驗證機制依然執行: 跳過渲染並不代表能跳過發行檢查,因為先前既存的輸出檔案仍可能無效或遺失。
程式碼範例 — cache.py
import hashlib
import json
from pathlib import Path
from typing import Any
CACHE_FILE = Path(".build-cache.json")
def stable_hash(value: Any) -> str:
payload = json.dumps(value, sort_keys=True, ensure_ascii=False)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
def read_cache() -> dict[str, str]:
if not CACHE_FILE.exists():
return {}
return json.loads(CACHE_FILE.read_text(encoding="utf-8"))
def write_cache(cache: dict[str, str]) -> None:
CACHE_FILE.write_text(json.dumps(cache, indent=2), encoding="utf-8")
def should_build(cache: dict[str, str], article_id: int, source_hash: str, force: bool = False) -> bool:
return force or cache.get(str(article_id)) != source_hash
程式碼說明
● 商業邏輯: 快取機制減少了等待時間,同時保有建置的可重現性。
● 程式邏輯: 透過排序鍵(Sorted keys)進行 JSON 序列化,為原始輸入建立穩定的雜湊值。
● 預期結果: 重新執行建置會跳過未變更的文章,但仍會對整體發行版本進行驗證。
實作實驗室 D — 生成用於母語人士審查的審查者套件包
開發者行動
● 請求 Kiro 將生成的卡片匯出為 CSV 格式以供審查人員使用。
● 欄位包含:卡片 ID、文章標題、英文、自然他加祿語、禮貌他加祿語、趣味版本、語氣與情境。
● 額外加入一欄留白的「審查者備註(reviewerNotes)」。
● 將此 CSV 檔案與生成的 HTML 一同打包進發行的 zip 壓縮包中。
Kiro 提示詞範例
為產生的他加祿語卡片建立審查者 CSV 匯出功能。
每列應包含:穩定的卡片 id、文章標題、情境、英文、自然他加祿語、禮貌他加祿語、親切菲律賓英語、趣味菲律賓英語、語氣以及 reviewerNotes。
將檔案寫入 dist/reviewer-cards.csv 並將其包含在 zip 壓縮包中。
系統設計決策
● 審查者需要表格化的工作流: 相比於逐頁點開 HTML,母語人士在試算表(Spreadsheet)中進行審查往往更有效率。
● 穩定的 ID 連結審查與輸出: CSV 中的卡片 ID 必須與 HTML 頁面中呈現的 ID 完全一致。
● 留白的審查者備註保留了人類權威: 產生器負責準備好審查結構,但不會代為捏造審查批准決策。
程式碼範例 — review_export.py
import csv
from pathlib import Path
def write_reviewer_csv(output_path: Path, article: dict, cards: list[dict]) -> None:
fieldnames = [
"cardId",
"articleTitle",
"context",
"english",
"naturalTagalog",
"politeTagalog",
"friendlyFilipinoEnglish",
"playfulFilipinoEnglish",
"tone",
"reviewerNotes"
]
with output_path.open("w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
for card in cards:
writer.writerow({
"cardId": card["id"],
"articleTitle": article["title"],
"context": card["context_en"],
"english": card["english"],
"naturalTagalog": card["natural"],
"politeTagalog": card["polite"],
"friendlyFilipinoEnglish": card["friendly"],
"playfulFilipinoEnglish": card["playful"],
"tone": card["tone"],
"reviewerNotes": ""
})
程式碼說明
● 商業邏輯: 匯出功能將生成的學習卡片轉換為便於審查的工具包。
● 程式邏輯: csv.DictWriter 確保寫入一致的欄位,並妥善保存 UTF-8 編碼的他加祿語文本。
● 預期結果: 審查人員收到一份能完美對應回 HTML 卡片的 CSV 檔案。
實作實驗室 E — 使用 pytest 加入管線契約測試
開發者行動
● 請求 Kiro 為產生器的核心契約建立測試。
● 測試項目包含:精確的卡片數量、重複 ID 失敗判定、HTML 轉義、資訊清單建立以及審查者 CSV 欄位標頭。
● 在修改生成邏輯後,於本地端執行 pytest。
● 請求 Kiro 解釋失敗的測試並給出最小的修正提案。
Kiro 提示詞範例
為靜態網站產生器管線生成 pytest 測試。
測試擴展數量、確定性卡片 id、HTML 轉義、資訊清單檔案建立以及審查者 CSV 標頭。
儘可能使用小型的記憶體內(In-memory)範例資料。
除非必要,否則避免進行完整的 HTML 快照對比。
系統設計決策
● 管線契約可保護發行行為: 產生器所面臨的風險大於單一函式,因為資料會流經擴展、渲染、驗證、資訊清單紀錄與打包等複數管線。
● 小型測試更容易診斷問題: 測試應驗證核心契約,而非去比對龐大的生成網頁。
● 轉義是不容妥協的: 渲染器測試必須包含不安全字元,以便在早期捕捉到轉義退化(Regressions)的問題。
程式碼範例 — tests/test_pipeline_contracts.py
import json
from pathlib import Path
from identity import assert_unique, card_id
from manifest import write_manifest
from render import render_article
def test_card_id_is_deterministic():
assert card_id(1, 2, 3, 4) == "a001-s02-c03-n004"
def test_duplicate_detection_fails_fast():
try:
assert_unique(["intro", "intro"], "slug")
except ValueError as error:
assert "Duplicate slug" in str(error)
else:
raise AssertionError("Expected duplicate slug failure")
def test_render_article_escapes_title():
article = {"title": "Hello <Tagalog>", "category": "Test", "summary": "one two three"}
html = render_article(article, [])
assert "Hello <Tagalog>" in html
def test_manifest_records_generated_files(tmp_path: Path):
(tmp_path / "article-1-demo.html").write_text("<html></html>", encoding="utf-8")
manifest_path = write_manifest(tmp_path, [{"id": 1}], [{"file": "article-1-demo.html", "sentence_cards": 40}])
manifest = json.loads(manifest_path.write_text(encoding="utf-8"))
assert manifest["articleCount"] == 1
assert "article-1-demo.html" in manifest["files"]
程式碼說明
● 商業邏輯: 這些測試保護了穩定的識別碼、安全渲染與發行文件的正確性。
● 程式邏輯: 每個測試案例都使用最精簡的設具(Fixture)資料來驗證特定契約。
● 預期結果: 管線的任何變更都將更加安全,因為核心的產生器承諾均已涵蓋在單元測試中。
實作實驗室 F — 加入附帶發行成品檢查碼的模擬執行模式
開發者行動
● 請求 Kiro 為建置指令碼加入 --dry-run(模擬執行)選標。
● 在模擬執行模式下,產出驗證輸出,但跳過寫入 zip 壓縮包。
● 在常規模式下,計算 zip 壓縮包與 manifest.json 的 SHA-256 檢查碼(Checksum)。
● 列印出一份提供給維護人員的最終發行摘要。
Kiro 提示詞範例
在 Python 建置流程中加入模擬執行(Dry-run)模式與成品檢查碼。
--dry-run 應執行渲染與驗證,但跳過寫入 zip 包。
常規發行模式應為 zip 檔案與 manifest.json 寫入檢查碼。
列印一份簡潔的發行摘要,包含檔案、檢查項與檢查碼路徑。
系統設計決策
● 模擬執行能降低發行風險: 維護人員可以在不建立或覆蓋任何產出物的情況下,驗證候選的建置版本。
● 檢查碼保障成品完整性: 檢查碼讓審查者能確認他們拿到的 zip 壓縮包,與通過驗證管線的檔案完全一致。
● 發行摘要改善交接流程: 建置輸出應明確告訴維護人員發生了什麼,以及能在哪裡找到驗證憑證。
程式碼範例 — checksums.py
import hashlib
from pathlib import Path
def sha256_file(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as file:
for chunk in iter(lambda: file.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def write_checksum(path: Path) -> Path:
checksum = sha256_file(path)
checksum_path = path.with_suffix(path.suffix + ".sha256")
checksum_path.write_text(f"{checksum} {path.name}\n", encoding="utf-8")
return checksum_path
程式碼說明
● 商業邏輯: 檢查碼讓生成的發行成品更易於驗證與分享。
● 程式邏輯: 該函式以區塊(Chunk)串流方式讀取檔案,並寫入標準的 .sha256 附隨檔案(Sidecar file)。
● 預期結果: 常規發行會產出 zip 與資訊清單的檢查碼,而模擬執行則只驗證、不打包。
參考架構備註
● 本工作坊著重展現之 Kiro 能力:檔案優先管線規劃、確定性 Python 生成、發行驗證、發行成品打包、出處文件化、管線測試以及建置審查自動化。
● 產品範疇:生成的他加祿語學習網頁,用於審查及最終的靜態代管。在經由他加祿語母語人士審查前,語言內容均視為草稿。
● 執行期範疇:優先生成靜態 HTML。當發行成品通過驗證後,後續的選配 AWS 部署可使用 Amazon S3 靜態網站代管、Amazon CloudFront 或 AWS Amplify Hosting。