# 寫出 AI 代理驗得過的驗收標準

Canonical: https://specscore.md/zh-tw/articles/acceptance-criteria/

更新於 2026年11月3日。

[驗收標準](https://specscore.md/acceptance-criteria-specification)（AC，acceptance criteria）是一項變更要算作完成之前，必須為真的條件。Given/When/Then 是 [Gherkin](https://cucumber.io/docs/gherkin/reference/) 裡的步驟寫法。[Cucumber](https://cucumber.io/docs/bdd/) 用這種語言做行為驅動開發（BDD，behaviour-driven development）：Given 是起始狀態，When 是發生一個動作，Then 是接著出現、可以觀察到的結果。產品需求文件（PRD，product requirements document）是一段散文，點出問題，也點出打算做的產品。[規範驅動開發](https://specscore.md/zh-tw/spec-driven-development/)（SDD，spec-driven development）把結構化的規範，而不只是那段散文，當成核對實作的依據。[EARS](https://alistairmavin.com/ears/)（Easy Approach to Requirements Syntax）用來約束一條需求句子，讓其中的子句維持固定順序。持續整合（CI，continuous integration）會對每一項提議中的變更自動做一次檢查；本站在 [驗證器頁面](https://specscore.md/zh-tw/validators/) 說明 SpecScore 的兩項檢查。本頁說明如何寫出人工智慧（AI）程式開發代理驗得過的驗收標準，並給出驗收標準範例，以及 SpecScore 命令列介面（CLI，command-line interface）實際檢查什麼。

## 驗收標準是什麼

一條驗收標準回答的是「什麼必須為真」。它點出審閱者、測試或代理能夠接受或拒絕的條件。它不點出要呼叫的函式，也不點出要改的檔案。那些選擇屬於實作。

需求是規則。在 SpecScore 的 [需求規範](https://github.com/specscore/specscore/blob/main/spec/features/requirement/README.md) 裡，需求是功能中的一個 `#### REQ:` 標題：一項義務，自帶識別碼。驗收標準把相關需求收成一個條件。情境是一個具體案例，用來表明該條件成立。[驗收標準規範](https://specscore.md/acceptance-criteria-specification) 是這樣說的：標準回答「什麼必須為真」，情境回答「如何證明」。

PRD 可以把同樣的意圖寫進段落。段落幫得上人。代理仍然得猜測哪一句才是通過或失敗的檢驗。把標準寫成自己的一句話，就不用再猜。

## 什麼讓驗收標準可以驗證

AI 程式開發代理能照著一條標準做，前提是事後的讀者能指出證據，並說出通過或失敗。五個習慣讓這件事變得可能。沒有一個是句子範本。它們是可以套到任何範本上的檢查，Given/When/Then 和檢查清單都算在內。

### 可觀察

結果是外人看得到的東西：頁面上的一則訊息、一筆存下來或沒存下來的紀錄、一次重新導向、一份被拒絕的表單。「系統理解購物者」無法觀察。「頁面在電子郵件欄位旁邊顯示 Enter a valid email address」可以觀察。

### 具體

點出行為者、輸入和結果。「壞的輸入會被處理」沒有說是哪一種輸入、哪一種處理。「購物者送出電子郵件 not-an-email」說了。具體不是要你把每個正式環境的值都貼上來。而是讀者能自己準備一筆測試資料，並且知道該發生什麼。

### 一個行為

一條標準，一個行為。「購物者可以登入、重設密碼，並看到鎖定訊息」是一句話裡的三條標準。實作了第一條、略過第三條的代理，仍可以說這句話做完了。把它們拆開。

### 通過或失敗

可驗證的驗收標準只有兩種結局。「表單應該感覺很快」是程度問題，不是一個結果。如果需要一條界線，就把界線寫出來：「結帳頁顯示錯誤，而且不再向伺服器送出進一步的請求。」如果說不出失敗長什麼樣子，這句話還不是標準。

### 拿掉含糊的詞

拿掉把結果藏起來的詞：優雅、直覺、穩健、好用、無縫、快、應該、適當。把每一個換成你願意接受的證據。「優雅地處理錯誤」變成「在欄位旁邊顯示 Enter a valid email address，而且不要成立訂單」。

## Given/When/Then 和檢查清單

團隊真正留得下來的驗收標準範例，大多是兩種形態。Given/When/Then 是一個情境。檢查清單是一串結果。狀態、動作、結果的順序要緊時，用情境。要列出同一個動作各自獨立的結果時，用檢查清單。

Cucumber 的 [Gherkin 參考](https://cucumber.io/docs/gherkin/reference/) 給步驟配上關鍵字 Given、When、Then、And 和 But。這份參考使用英文；Gherkin 也有這些關鍵字的譯文。關鍵字後面的文字，會在 Cucumber 執行檔案時對上稱為步驟定義（step definition）的程式碼。SpecScore 不用那一層。下面的例子是 Gherkin，好讓形態看起來眼熟。它不是 SpecScore 檔案。

### Given/When/Then

```gherkin
Scenario: Reject an email that is not a valid address
  Given the shopper is on the checkout form
  When the shopper submits the email "not-an-email"
  Then the page shows "Enter a valid email address" beside the email field
  And the order is not placed
```

### 檢查清單

```markdown
- Submitting the email "not-an-email" shows "Enter a valid email address" beside the email field.
- The order is not placed.
```

When 只留一個。第二個動作就是第二個情境。And 延續同一個關鍵字：另一個 Given，或另一個 Then。不要用 And 夾帶第二個行為。

檢查清單是同一個約定，只是沒有關鍵字。每一行仍然是一個可觀察的結果。上面的檢查清單就是情境的 Then，寫成一項項檢查。

## 這和 EARS 需求的關係

這些句式寫在[EARS 需求語法詳解與範例](https://specscore.md/zh-tw/articles/ears-requirements/)。

[Alistair Mavin 的指南](https://alistairmavin.com/ears/) 把 EARS（Easy Approach to Requirements Syntax）定義成一種溫和地約束文字需求的機制。子句維持同一個順序。指南給出的通用形態是：While <optional pre-condition>, when <optional trigger>, the <system name> shall <system response>。一條需求有零個或多個前置條件、零個或一個觸發、一個系統名稱，以及一個或多個系統回應。

那句話是義務：系統應當滿足的規則。驗收標準是這項義務要算作已滿足時必須為真的條件。一個 Given/When/Then 情境是這個條件的一個具體案例。需求可以寫成 EARS 句子，標準仍然可以不含範例輸入。

在 SpecScore 的功能裡，需求可以是 `#### REQ:` 標題下的一句 EARS 風格的話。標準維持抽象條件。情境帶著範例。EARS 兩者都不取代。它只約束需求那一句。

## 驗收標準範例：含糊的和可驗證的

### 點出證據

**含糊**

```text
The checkout form should handle bad input gracefully and feel fast.
```

**可驗證**

```text
When the shopper submits the email "not-an-email", the checkout page shows "Enter a valid email address" beside that field and does not place the order.
```

含糊的那一行藏著兩項要求（錯誤與速度），也沒有證據。可驗證的那一行有一個動作，以及人或代理都能核對的兩個結果。範例維持英文，因為格式的關鍵字是英文。

### 一個行為

**含糊**

```text
Users can sign in, reset a password, and see an error if the account is locked.
```

**可驗證**

```text
When a visitor submits a known email and the matching password, the app sets a session cookie and redirects to /dashboard.
```

登入、重設和鎖定是三個行為。可驗證的那一行只留下登入。重設和鎖定各自得到自己的標準，帶著自己的輸入和結果。

### 寫結果，不寫函式名

**含糊**

```text
The handler returns 400 from validateEmail().
```

**可驗證**

```text
When the shopper submits an email that is not a valid address, the checkout page shows "Enter a valid email address" and does not place the order.
```

函式名和狀態碼把標準綁在今天的程式碼上。檢查挪到另一個函式，結果仍然成立。當狀態碼本身就是你承諾的行為時，把它留下來，並且寫成可觀察的結果。

## SpecScore 如何儲存它們，以及 CI 檢查什麼

SpecScore 在 [specscore/specscore](https://github.com/specscore/specscore) 儲存庫發布格式，在 [specscore/specscore-cli](https://github.com/specscore/specscore-cli) 發布 CLI。兩份文件描述驗收標準時，形態並不完全一樣。兩份都還在用。這一節先說明哪一份是哪一種，然後說明 `specscore spec lint` 實際拒絕什麼。

這份[驗收標準規範](https://specscore.md/acceptance-criteria-specification)，也就是該 URL 上提供的功能 README，把標準寫在功能 README 裡面。每個功能都有一節 `## Acceptance Criteria`。每條標準是一個 `### AC: {slug}` 標題。slug 使用小寫，並用連字號連接。下一行是 `**Requirements:**`，按下面的形式列出它所收攏的需求：`{feature-id}#req:{slug}`。後面是散文，也就是合成後的條件。規範說，這段散文維持抽象。它不得包含 Given/When/Then 步驟、範例輸入或實作細節。還沒有標準時，這一節讀作「Not defined yet.」，Open Questions 一節寫「Acceptance criteria not yet defined for this feature.」。標準是可選的分組：規範說，收攏兩條或更多需求時加一條，若只會複述單條需求就省掉。

具體的證明是功能的 `_tests/` 目錄下的情境檔案。[情境規範](https://github.com/specscore/specscore/blob/main/spec/features/scenario/README.md) 要求有一個 `# Scenario:` 標題、一節 `## Steps`、大寫的 `GIVEN`、`WHEN`、`THEN` 和 `AND`，並且恰好一個 WHEN。可選的 `**Validates:**` 行把情境連到 `{feature-path}#ac:{slug}`，或連到一條需求。`## Rehearse` 一節可以在 `rehearse` 圍欄裡放一段可執行的腳本，腳本以 shebang 開頭。

CLI 也讀取精簡的標準檔案，每條標準一個，位於 `_acs/<slug>.ac.md`。[登入範例](https://specscore.md/example-login) 和 [Rehearse 指南](https://specscore.md/rehearse) 記錄了這種形態：`# AC: <slug>`，可選的 `**Status:**`、`**Verifies:**` 和 `**Applies-to:**`（這三項都可選），以及 `## Statement` 下面的條件。`specscore rehearse acs <feature-dir>` 根據這些檔案印出一張摘要表。`specscore rehearse acs --write` 用這張表，外加一則說明該節是產生出來的、不要手改的註解，替換功能 README 裡的 Acceptance Criteria 一節。沒有 `# AC:` 標題的檔案，會被該命令報為錯誤。

本儲存庫的 CI 是 [dogfood 工作流程](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)。它安裝 CLI v0.39.1，並在拉取請求上、以及推向 main 時執行 `specscore spec lint`。2026年11月3日核對過，該發行版和 CLI 的預設分支都包含下面這些規則。檢查器查的是結構。它不為英文打分。

規則 `ac-heading-format` 是一則錯誤。在功能 README（標題為 `# Feature:` 的檔案）裡，看起來像驗收標準標題的一行必須恰好是 `### AC: <id>`，冒號後一個空白，id 為 kebab-case。形如 `### AC: <id> (verifies ...)` 的標題也被接受。`--fix` 只修復空白。帶大寫字母或底線的 id 會被回報，並留給人處理。這條規則不要求有 `**Requirements:**` 行，不要求「Not defined yet.」佔位，散文裡出現 Given、When 或 Then 時也不警告。規範裡為那則警告所寫的情境，並不是這支 CLI 裡的 lint 規則。

當一份計畫點名了來源功能時，檢查器會讀取該功能 Acceptance Criteria 一節裡的 `### AC:` 標題。規則 `P-002` 回報任務的 `**Verifies:**` 值不是這些標題之一所對應的 `<feature-slug>#ac:<ac-slug>`。規則 `P-001` 回報沒有任何任務涵蓋、並且沒有列在 `## Deferred AC Coverage` 下面的標題。這兩條規則不開啟 `_acs/*.ac.md`。`rehearse acs --write` 產生的摘要表沒有 `### AC:` 標題，所以計畫規則看不到那些精簡檔案。

同一條 lint 命令不檢查情境步驟的關鍵字。`specscore rehearse` 執行情境檔案：Rehearse 指南在圍欄命令上方使用 `## Given` 或 `## When` 這樣的標題，並用 `**Use:**` 呼叫可重複使用的檢查。一個檔案裡有一個 Given 和數個 When 分支時，會作為各自獨立的案例執行。`specscore rehearse new <feature-slug>#ac:<ac-slug>` 讀取功能 README，並把該標準裡的 Given/When/Then 行抽到 `spec/features/<feature-slug>/_tests/<ac-slug>.md`。這些都不在 dogfood 工作流程裡執行。工作流程執行的是 `specscore spec lint`。

### 內嵌標準，出自驗收標準規範

```markdown
## Acceptance Criteria

### AC: invalid-email-rejected

**Requirements:** checkout#req:reject-invalid-email

An email that is not a valid address is rejected, and the order is not placed.
```

### 精簡標準檔案，rehearse acs 讀取的形態

```markdown
# AC: invalid-email-rejected

**Status:** accepted
**Verifies:** checkout#req:reject-invalid-email

## Statement

An email that is not a valid address is rejected, and the order is not placed.
```

### 情境檔案，出自情境規範

```markdown
# Scenario: Reject an invalid email

**Validates:** [checkout#ac:invalid-email-rejected](../README.md#ac-invalid-email-rejected)

## Steps

GIVEN the shopper is on the checkout form
WHEN the shopper submits the email "not-an-email"
THEN the page shows "Enter a valid email address" beside the email field
AND the order is not placed
```

### Rehearse 情境，Rehearse 指南裡的形態

~~~~markdown
# Rehearse: Reject an invalid email

## Given a submitted email that is not a valid address
```bash
printf 'email=not-an-email\n' > form.txt
```

## When the response is recorded
```bash
printf 'Enter a valid email address\n' > out.txt
```

## Then the message is the invalid-email text
```bash
grep -q 'Enter a valid email address' out.txt
```
~~~~

這四份樣品用來說明那些形態。它們不是一棵完整的功能樹，本頁也不聲稱它們單獨就能通過 `specscore spec lint`。功能 README 還需要其他必要小節，那條命令才會乾淨。

如果想要一份問題清單，用來從含糊的請求裡把標準問出來，用 [提出好問題](https://specscore.md/asking-good-questions)。登入導覽把一條精簡標準 `session-hardened` 放在其他產物之中。

## 常見問題

### 什麼是驗收標準？

驗收標準（AC）是一項變更要算作完成之前必須為真的條件。在 SpecScore 的驗收標準規範裡，它們是抽象的：說明什麼必須為真，把具體步驟留給情境。

### 什麼是 Given/When/Then？

Given/When/Then 是 Gherkin 裡的步驟寫法：Given 是起始狀態，When 是發生一個動作，Then 是接著出現、可以觀察到的結果。Cucumber 在 Gherkin 參考裡記錄這些關鍵字。SpecScore 的情境規範使用大寫關鍵字 GIVEN、WHEN、THEN 和 AND，每個情境檔案恰好一個 WHEN。

### 怎樣為 AI 程式開發代理寫驗收標準？

寫一個可觀察的行為，帶上行為者、輸入和結果，並且不要含糊的詞。範例資料放進情境，不要放進抽象標準。代理就可以對著標準實作，並核對情境。

### 驗收標準和測試案例是同一回事嗎？

不是。標準陳述條件。測試案例，或 SpecScore 情境，是帶具體輸入的一次執行，用來表明條件成立或失敗。多個情境可以支撐同一條標準。

### specscore spec lint 會評判含糊的用詞嗎？

不會。在 CLI v0.39.1，也就是本儲存庫 CI 所安裝的發行版裡，ac-heading-format 檢查 ### AC: 標題。它不為「graceful」或「fast」這類詞打分，標準裡出現 Given/When/Then 時也不警告。用詞是寫作的事。[驗證器頁面](https://specscore.md/zh-tw/validators/) 把那種決定性的 lint 和手動的 AI 審查分開。

### Given/When/Then 步驟在 SpecScore 裡放在哪裡？

放在情境裡，不放在驗收標準裡。驗收標準規範禁止在標準內部寫 Given/When/Then 步驟。情境規範把它們放在 _tests/ 下的 ## Steps 裡。Rehearse 執行一種相關形態：_tests/ 下的標題和圍欄命令，記錄在 Rehearse 指南裡。檢查器不強制這些步驟關鍵字。

## 來源

閱讀日是 2026年11月3日。第三方頁面只按它們公布的定義引用。

- [Cucumber — Gherkin 參考](https://cucumber.io/docs/gherkin/reference/)
- [Cucumber — 行為驅動開發](https://cucumber.io/docs/bdd/)
- [Alistair Mavin — EARS](https://alistairmavin.com/ears/)
- [EARS 需求語法詳解與範例](https://specscore.md/zh-tw/articles/ears-requirements/)
- [SpecScore — 驗收標準規範](https://specscore.md/acceptance-criteria-specification)
- [specscore/specscore — 驗收標準功能](https://github.com/specscore/specscore/blob/main/spec/features/acceptance-criteria/README.md)
- [specscore/specscore — 情境功能](https://github.com/specscore/specscore/blob/main/spec/features/scenario/README.md)
- [specscore/specscore — 需求功能](https://github.com/specscore/specscore/blob/main/spec/features/requirement/README.md)
- [SpecScore — 功能規範](https://specscore.md/feature-specification)
- [SpecScore — Rehearse](https://specscore.md/rehearse)
- [SpecScore — 登入範例](https://specscore.md/example-login)
- [SpecScore — 提出好問題](https://specscore.md/asking-good-questions)
- [specscore/specscore-cli](https://github.com/specscore/specscore-cli)
- [specscore/specscore](https://github.com/specscore/specscore)
- [dogfood 工作流程（CLI v0.39.1）](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)
- [specscore-cli — ac-heading-format](https://github.com/specscore/specscore-cli/blob/main/pkg/lint/ac_heading.go)
- [specscore-cli — 計畫規則 P-001 與 P-002](https://github.com/specscore/specscore-cli/blob/main/pkg/lint/plan_rules.go)

## 相關

- [給 AI 寫程式用的 Markdown PRD 範本](https://specscore.md/zh-tw/articles/feature-spec-template/)
- [在 CI 中用規格檢查器檢查規格](https://specscore.md/zh-tw/articles/lint-specs-in-ci/)
- [EARS 需求語法詳解與範例](https://specscore.md/zh-tw/articles/ears-requirements/)
- [規範驅動開發](https://specscore.md/zh-tw/spec-driven-development/)
- [規範驅動開發工具](https://specscore.md/zh-tw/spec-driven-development/tools/)
- [驗收標準規範](https://specscore.md/acceptance-criteria-specification)
- [提出好問題](https://specscore.md/asking-good-questions)
- [以範例看一個登入功能](https://specscore.md/example-login)
- [Rehearse](https://specscore.md/rehearse)
- [SpecScore 驗證什麼](https://specscore.md/zh-tw/validators/)
- [CLI](https://specscore.md/zh-tw/cli/)
