跳至主要內容
技術

一個需求從 Prompt 到 Production 的完整旅程

一個需求從 Prompt 到 Production 的完整旅程
Agentic Engineering 實戰手冊 第 7 / 14 篇 ,前往系列總覽

這是「Agentic Engineering 實戰手冊」系列的第七篇。上一篇:Agent 產出品質保證

先說清楚:這是從 Commit 還原的案例

前幾篇我們聊了 Context EngineeringSpec-Driven Development品質保證。每篇都有它的理論框架。

但理論歸理論,你可能最想看的是實際操作起來到底長什麼樣。

這篇用一個真實需求回答:在 Astro 部落格裡加上「文章閱讀進度條」和「預估閱讀時間」。不過它不是當時逐分鐘寫下的 live log,而是根據 2025 年 12 月 21 日的兩次 commit、現存原始碼與我的工作筆記,事後還原成一條完整流程。

閱讀進度條和閱讀時間其實分成兩個 commit 上線,後者還在 2026 年 7 月修過中文計數。所以下面的時間是當時的粗略紀錄,prompt 也是整理後的版本;我不會把重建內容假裝成終端機原始輸出。

任務背景

需求來源:我自己在分析部落格的 analytics 時發現,長文的跳出率偏高。假設之一是讀者不知道文章有多長、讀到哪裡了,缺乏「進度感」。

功能描述

  1. 頁面頂部顯示閱讀進度條(scroll-based progress bar)
  2. 文章開頭顯示預估閱讀時間(estimated reading time)
  3. 只在 blog post 頁面顯示,其他頁面不要

複雜度評估:中等。涉及一個新 component、一段 client-side JS、一個 build-time 計算。不是 trivial,但也不需要架構重構。

為什麼選這個任務示範:它有代表性——有 UI component、有邏輯計算、有跨 layer 的整合(build-time + client-side)。而且它有明確的決策點和至少一次 iteration。

Step 1: 把當時的需求補成可驗收 Spec

如果用上一篇的 template 回頭整理,spec 會長這樣:

## Task: Blog Reading Progress & Estimated Read Time

### Goal

在 blog 文章頁面加兩個功能:

1. 頁面頂部固定的閱讀進度條(隨滾動更新)
2. 文章 metadata 區塊顯示預估閱讀時間

### Context

- Astro 5 + MDX + Tailwind CSS 4 + TypeScript
- Blog layout: src/layouts/BlogLayout.astro
- 現有 design tokens: --color-primary, --color-bg-primary
- Dark mode 透過 .dark class 切換
- 已有 View Transitions,script 要用 Astro 的頁面生命週期重新初始化,並避免重複綁 listener

### Constraints

- 不引入任何 npm dependency
- 進度條用 CSS custom properties + Tailwind
- 閱讀時間在 build time 計算,不在 client side
- 中文內容以每分鐘 400 字計算(非英文的 200 wpm)
- 進度條只在 blog post 頁面出現
- 進度條不能蓋住 navigation bar

### Files to modify

- src/layouts/BlogLayout.astro(加入 component)
- 可新增 src/components/blog/ReadingProgress.astro
- 閱讀時間邏輯放在 src/lib/utils.ts,由頁面把結果傳給 layout

### Verification Criteria

1. 滾動頁面時,頂部進度條從 0% 填充到 100%
2. 進度條在到達文章底部時是 100%,在頂部是 0%
3. 顯示格式:「約 N 分鐘閱讀」
4. 2000 字文章 → 顯示「約 5 分鐘閱讀」
5. Dark mode 下進度條顏色正確
6. 在非 blog 頁面(如 /about)不顯示進度條
7. npm run build 通過,無 TypeScript 錯誤

### Out of Scope

- 不做 reading analytics(不追蹤用戶實際閱讀行為)
- 不做 bookmark / save progress 功能
- 不做 table of contents(之後另外做)

真正重要的決策

  • 中文 400 字/分鐘而非英文 200 wpm——這個如果不寫,agent 很可能沿用常見的英文閱讀速度算法
  • 「不引入 npm dependency」——防止 agent 引入 reading-time 之類的 library
  • 「進度條不能蓋住 navigation bar」——這是一個很容易被忽略的 UI 細節
  • View Transitions 相關的提醒——持久化 DOM 與頁面導航會改變 script 的初始化時機,應依 Astro 文件使用對應 lifecycle event,並確認舊 listener 有清理

Step 2: 準備必要 Context

CLAUDE.md 已經有了大部分必要的 context(tech stack、project structure、conventions)。額外需要的只有兩件事:

  1. 讓 agent 看一下 BlogLayout.astro 的現有結構,知道 component 要插在哪裡
  2. 確認 design tokens 的變數名

這些不需要我手動貼——agent 會自己 Read 相關檔案。但在 spec 裡提到「design tokens: —color-primary」是有幫助的,讓 agent 知道去找什麼。

Step 3: 讓 Agent 跑一輪,再看完整 Diff

我把 spec 貼給 Claude Code,讓它先完成一輪探索與實作,再回來看完整 diff。

這不是「agent 沒人管就一定做得更好」。如果它碰到高風險檔案、開始擴張 scope,當然要立刻停;對這種隔離、可回滾的小功能,我只是不想因為每個小選擇都插嘴,讓它無法交出可整體 review 的版本。

以下是根據 diff 重建的行動順序,不是逐字 transcript:

Agent 行動記錄

00:00-02:00 — 探索 codebase

Agent: 讀取 BlogLayout.astro... 了解現有結構
Agent: 讀取 global.css... 找到 design tokens
Agent: 讀取 BaseLayout.astro... 了解 nav 的 position
Agent: 讀取已有的 blog component... 理解命名慣例

02:00-08:00 — 建立 ReadingProgress.astro

Agent: 建立 src/components/blog/ReadingProgress.astro
- Fixed position bar at top of page
- Uses --color-primary for fill color
- z-index lower than nav bar
- Client-side script for scroll tracking
- Handles View Transitions with astro:after-swap

第二個 commit — 加入閱讀時間

Agent: 修改 src/lib/utils.ts 與文章頁
- getReadingTime(post.body) 在 build time 計算
- 結果透過 props 傳到 BlogLayout 與文章卡片
- 初版先移除 frontmatter、code block、HTML tag 與部分 Markdown 符號

接著 — 整合到 BlogLayout.astro

Agent: 修改 BlogLayout.astro
- Import ReadingProgress,接收 readingTime prop
- ReadingProgress placed after nav, before main content
- Reading time placed in article header metadata section
- 頁面使用 post.body 計算,不是不存在的 ReadingTime component 或 compiledContent API

20:00-25:00 — 自我驗證

Agent: npm run build... ✅ 通過
Agent: 檢查 TypeScript... ✅ 無錯誤
Agent: 在 dev server 確認 progress bar 行為...

進度條 commit 的 diff 是 2 個檔案、133 行;閱讀時間則和 view count、文章卡片一起進到另一個較大的 commit。把它們說成單一 25 分鐘任務會比 git history 更漂亮,但不準確。

Step 4: Review 真正抓到什麼

Git history 留下最有價值的反例,是閱讀時間的初版用空白切詞。英文勉強可用,中文幾乎沒有空白,一篇長文也可能只算成一兩個「word」。這個問題直到 2026 年 7 月才改成 CJK 字元與拉丁單字分開計算。

如果當時就把「2000 個中文字要顯示約 5 分鐘」寫成測試,這個 bug 不會留半年。修正 prompt 可以很短:

getReadingTime 目前用空白切詞,會嚴重低估中文文章。
請把 CJK 字元與拉丁單字分開計數:中文 400 字/分鐘、英文 200 words/min,
至少 1 分鐘。保留移除 frontmatter、code block 和 HTML tag 的處理,並補中文、英文、混合內容測試。

這個案例也提醒我:npm run build 通過,只能證明程式可建置,不能證明中文閱讀時間算對。Verification criteria 必須真的覆蓋使用者行為。

Step 5: CI/CD & Deploy

程式完成後,才進入自動化流程。以下 commit message 是整理版;實際上兩個功能分開提交:

# Commit
git add src/components/blog/ReadingProgress.astro \
        src/layouts/BlogLayout.astro
git commit -m "feat(blog): add reading progress bar and estimated reading time

- Fixed progress bar at page top, scroll-synced 0-100%
- Handles Astro View Transitions correctly"

Push 之後由 GitHub Actions 驗證,再部署到 Cloudflare Workers。CI 現在包含 format、ESLint、Astro check、內容檢查、build 與測試;當時的 workflow 較簡單,不能把今天的檢查項目倒填回 2025 年的 log。

在 preview 或 production 前至少手動驗證:

  • 長文(3000 字)→ 顯示「約 8 分鐘閱讀」 ✅
  • 滾動 → progress bar 正確填充 ✅
  • Dark mode → 顏色正確 ✅
  • /about 頁面 → 沒有 progress bar ✅
  • 手機寬度 → 3px 高度 ✅

這些項目通過,才適合往 production 走。

時間對比:只代表這一次

這次的 Agentic Workflow

步驟時間誰做的
寫 Spec8 分鐘
Context 準備3 分鐘
Agent 執行25 分鐘Agent(我去倒咖啡)
Review7 分鐘
Feedback + 修正5 分鐘我 + Agent
CI/CD + 驗證12 分鐘自動化
總計~60 分鐘

表格能看出每一步花多久,但看不出時間怎麼接在一起——畫成流程才看得出來,這一小時其實是這樣跑的:

flowchart TD
    S1["Step 1 寫 Spec<br/>8 分鐘・我"] --> S2["Step 2 Context 準備<br/>3 分鐘・我"]
    S2 --> S3["Step 3 Agent 執行<br/>25 分鐘<br/>Agent(我去倒咖啡)"]
    S3 --> S4["Step 4 Review<br/>7 分鐘・我"]
    S4 -->|"沒問題"| S5["Step 5 CI/CD 驗證<br/>12 分鐘・自動化"]
    S4 -->|"抓到問題"| FB["Feedback 修正<br/>5 分鐘<br/>我 + Agent"]
    FB -->|"回頭再跑一次"| S3
    S5 --> TOTAL["總計<br/>約 60 分鐘"]

圖裡看得出一件表格沒直接講的事:我自己動手的三段——8 分鐘 Spec、7 分鐘 Review、5 分鐘 Feedback 修正——單獨看都不到 10 分鐘,但卡在 25 分鐘 Agent 執行的前後,才是那 25 分鐘能不能一次跑對的關鍵;而 Feedback 修正繞回 Agent 執行那條線,代表這一圈也可能不只跑一次,這次的 60 分鐘只是繞了一圈就過關的結果。

如果用傳統方式

步驟時間
理解需求 + 研究做法30 分鐘
寫 ReadingProgress component45 分鐘
寫 ReadingTime component30 分鐘
整合到 BlogLayout20 分鐘
處理 View Transitions30 分鐘
寫 CSS / responsive20 分鐘
測試 + debug45 分鐘
CI/CD + 驗證12 分鐘
總計~4 小時

依我當時的估算,這類任務大約從半天縮到一小時。不過這不是 benchmark:需求熟悉度、既有 component、CI 與我對 Astro 的熟悉程度都占了便宜。它能證明這次流程有效,不能證明 coding agent 普遍快四倍。

但不是每個任務都這麼理想

公平地說,這是一個「適合 agentic workflow」的任務——需求明確、scope 有限、技術棧 agent 很熟。

以下是 agentic workflow 不太適合的情況:

場景原因建議
全新的架構設計Agent 未必掌握你的業務 constraint你主導取捨,agent 協助探索與實作
跨多個 repo 的變更Context 太分散拆成每個 repo 一個 task
Debug 未知的 production issue需要即時互動和直覺你帶頭,agent 輔助
涉及敏感權限的操作安全風險你自己做,agent 不碰
第三方 API 整合(文件不完整)Agent 可能 hallucinate API你先確認 API,agent 來寫整合

每個決策點的標注

回顧整個流程,有幾個關鍵的決策點值得標記:

決策 1:寫 Spec 還是直接叫 Agent 做?

選擇:寫 Spec。

原因:這個功能涉及 UI + 計算 + 整合,如果不寫 spec,agent 很可能做出我不想要的東西(比如用 npm library、用英文 wpm、progress bar 蓋住 nav)。8 分鐘的 spec 投資,預防了至少 1 小時的拆除工作。

決策 2:離開電腦 vs 盯著 Agent 做

選擇:離開。

原因:這是低風險、可回滾的小功能,先拿到一份完整 diff 比每幾分鐘調整細節容易 review。若 agent 開始動部署、權限、資料或不在 scope 的檔案,我會立即介入。

決策 3:怎麼給 Feedback

選擇:描述問題 + 給方向,不規定做法。

原因:我指出「目前的字數計算來源不對」,並要求它回到 Astro 實際提供的文章內容,而不是指定一個我沒確認過的 API。最後實作直接用 post.body 計算,也避開了為了修 regex 又疊一層 workaround。

決策 4:這個 PR 是合成一個還是拆兩個?

選擇:合成一個。

原因:ReadingProgress 和 ReadingTime 雖然是兩個 component,但它們服務同一個 feature,而且修改的文件有重疊(都要改 BlogLayout.astro)。拆成兩個 PR 反而增加 overhead。

流程的核心公式

把整個流程提煉成一個公式:

Agentic Workflow =
  高品質 Spec(10 分鐘)
  + 充足 Context(CLAUDE.md + codebase)
  + 有邊界的執行(低風險時讓 agent 完整跑一輪)
  + 精準 Review(focus 在 agent 特有的錯誤模式)
  + 快速 Feedback Loop(描述問題 + 給方向)

每一步都不難。難的是紀律——動手前先寫清楚驗收,執行時看住邊界,完成後別因為 diff 很工整就省略 review。至於 spec 要寫 3 分鐘還是 30 分鐘、要不要中途介入,都應由任務風險決定。

這個紀律,就是 Agentic Engineering 和 Vibe Coding 的分界線。

Takeaway

  1. Agentic workflow 的核心是「前置投資」——Spec 和 Context 的品質決定後續效率。8 分鐘的 spec + 3 分鐘的 context 準備,讓 25 分鐘的 agent 執行幾乎零障礙。

  2. 這個案例的速度提升不能直接外推——它受益於範圍小、既有架構清楚、容易回滾。把它當工作流範例,不要當四倍生產力的普遍證明。

  3. 最重要的技能不是寫 prompt,是知道什麼時候介入、什麼時候放手——低風險任務可以等完整 diff,高風險或 scope 漂移要立刻停。放手從來不等於離席不管。


上一篇:Agent 產出品質保證 下一篇:CLAUDE.md 與 Rules Files 大師班

留言討論

esc
輸入關鍵字搜尋文章...
查看收藏 →