系列:從鐵人賽到 Agent Orchestration — AI 自動建立 .NET 測試的完整方案(2/10)
前言
上一篇介紹了 29 個 Agent Skills 的全貌與安裝方式,看起來一切都很美好 — 安裝 Skills、啟用設定、用自然語言要求 AI 建立測試。
但實際使用之後,很快就會遇到一個根本問題:
AI 不太會主動觸發 Skill。
這篇文章要誠實面對這個痛點,分析背後的原因,以及我嘗試過的解決方案 — 從改善 Description 到設計 16 個 Custom Prompts — 每一步都有改善,但每一步也都留下新的問題。
期望 vs. 現實
理想情境
安裝完 29 個 Skills 之後,理想的使用體驗應該是這樣的:
- 使用者在 VS Code Agent Mode 輸入:「幫我為 OrderService 建立單元測試」
- AI 自動分析
OrderService的建構子依賴(IOrderRepository、IPaymentGateway、IEmailService、TimeProvider) - AI 判斷需要 NSubstitute Mock、AutoFixture 測試資料、TimeProvider 時間測試
- AI 載入對應的 Skills:
nsubstitute-mocking、autofixture-basics、datetime-testing-timeprovider - AI 依照 Skills 指引產出符合最佳實踐的測試程式碼
實際情況
實際上發生的事情往往是:
- AI 沒有主動觸發任何 Skill,直接用通用知識寫測試
- AI 觸發了 Skill,但載入的不是最需要的那幾個
- AI 載入了入口型 Skill
dotnet-testing,讀完導航文件後卻沒有繼續載入子技能 - AI 載入了某個 Skill,但只用了一部分指引就開始寫程式碼
結果就是:測試可能用了 Moq 而不是 NSubstitute、用了原生 Assert 而不是 AwesomeAssertions (或是直接使用要花錢的 FluentAssertions)、命名沒有遵循中文三段式規範。這些「不符合團隊最佳實踐」的問題,正是 Skills 要解決的,卻因為觸發不穩定而打了折扣。
入口型 Skill 的困境
29 個 Skills 中有一個特殊的「入口型 Skill」— dotnet-testing,它的作用是導航中心,告訴 AI 在不同情境下該載入哪些子技能。
但問題在於:AI 需要先讀完整份導航文件,理解 29 個 Skills 的分類與適用情境,才能做出正確的判斷。這對 AI 來說是一個不小的認知負擔,而且即使讀完了,也不保證會做出正確的選擇。
根本原因分析
觸發問題不是單一原因造成的,背後有幾個結構性的因素:
1. AI 無法自動分析被測類別需要哪些技能組合
一個真實的測試場景,通常不是只用到一個 Skill。以 OrderProcessingService 為例:
public class OrderProcessingService
{
private readonly IOrderRepository _orderRepository;
private readonly IPaymentGateway _paymentGateway;
private readonly IEmailService _emailService;
private readonly TimeProvider _timeProvider;
public OrderProcessingService(
IOrderRepository orderRepository,
IPaymentGateway paymentGateway,
IEmailService emailService,
TimeProvider timeProvider)
{
// ...
}
}要為這個類別寫出高品質的測試,AI 需要同時具備以下技能:
| 需求 | 對應 Skill |
|---|---|
| Mock 4 個介面依賴 | nsubstitute-mocking |
| 自動產生測試資料 | autofixture-basics |
| AutoFixture + NSubstitute 整合 | autofixture-nsubstitute-integration |
| TimeProvider 時間測試 | datetime-testing-timeprovider |
| AwesomeAssertions 斷言 | awesome-assertions-guide |
這需要 AI 先分析被測類別的建構子參數、方法簽章、回傳型別,才能判斷需要哪些 Skills — 但目前的 Agent Skills 機制並沒有提供這種「分析再載入」的流程。AI 只能根據使用者的對話內容和 Skill 的 Description 做模糊匹配。
2. Context Window 壓力
單一 Agent 一次載入 5 個以上的 Skills,Context Window 就會面臨壓力。
以上面的例子來說,5 個 Skills 加起來約 39K tokens。加上被測類別的程式碼、測試專案的既有程式碼、使用者的對話歷史,Context Window 很容易就被填滿。
當 Context 被大量 Skill 內容佔據時,AI 對每個 Skill 的理解深度會下降,產出品質也會受影響。
3. 缺乏智能路由機制
目前的 Agent Skills 機制是「被動」的 — AI 根據對話情境自行判斷要不要載入某個 Skill,以及載入哪個。
沒有一個「路由器」的角色來主動分析情境、決定載入哪些 Skills、以什麼順序使用它們。
Description 與版本演進的努力
意識到觸發問題後,我在每個版本中都嘗試改善 Skill 的 Description、Triggers 與內容結構,希望提高 AI 的觸發機率。
v1.0.0 → v2.0.0:全面加入 Triggers
v1.0.0 是首次發布,27 個 Skills 的 Description 相對簡短。到了 v2.0.0,做了全面優化:
- 為所有 Skills 加入 Triggers 欄位,總計 400~520 個觸發關鍵字
- 改用多行 Description 格式,更清楚地描述功能與適用情境
# v1.0.0 — 簡短描述
---
name: nsubstitute-mocking
description: NSubstitute mocking guide for .NET tests.
---
# v2.0.0 — 多行描述 + Triggers
---
name: nsubstitute-mocking
description: >-
NSubstitute mocking and dependency isolation for .NET unit tests.
Use when creating mock objects, setting up method returns, or
verifying method calls with NSubstitute in xUnit test projects.
triggers:
- mock
- NSubstitute
- dependency isolation
- Substitute.For
- Returns
- Received
---v2.1.0:符合 agentskills.io 官方規範
v2.1.0 的重點是遵循 Agent Skills 的官方規範。其中一個重要變更是:
- 移除非標準的
triggers欄位,將觸發關鍵字整合到description中 - 官方規範中並沒有
triggers這個 frontmatter 欄位,AI 實際上是靠description的內容來判斷是否相關
這個版本讓所有 29 個 Skills 完全符合官方規格。
v2.2.0:依據 Anthropic 指南重新調整
v2.2.0 是根據 Anthropic 發布的「The Complete Guide to Building Skills for Claude」所做的全面調整,引入了幾個關鍵概念:
漸進式揭露(Progressive Disclosure)
將 SKILL.md 主文件控制在 500 行以內,詳細的範例、模式、腳本移到 references/ 目錄。AI 先讀取精簡的主文件理解核心指引,需要時再載入參考資料。
nsubstitute-mocking/
├── SKILL.md # 精簡主文件(≤500 行)
└── references/
└── advanced-patterns.md # 詳細範例與進階模式具體的改善項目:
| 改善項目 | 影響範圍 |
|---|---|
SKILL.md 精簡至 ≤500 行,詳細內容移至 references/ | 21 個 Skills |
| Description 加入「when you need to...」觸發句型 | 14 個 Skills |
補充 related_skills 欄位,改善 Skill 間的導航 | 26 個 Skills |
| 統一第一個 H2 段落為「適用情境」 | 17 個 Skills |
| 統一最後一個 H2 段落為「參考資源」 | 9 個 Skills |
效果:有改善但仍無法根本解決
每一次版本優化都有帶來改善 — Description 更精準、結構更清晰、Context Window 佔用更少。
但核心問題依然存在:AI 仍然需要自己判斷要不要載入、載入哪個 Skill。即使 Description 寫得再好,AI 面對一個有 4 個介面依賴的 Service,還是無法可靠地判斷「我需要同時載入 nsubstitute-mocking + autofixture-basics + datetime-testing-timeprovider」。
Custom Prompts 補強方案
既然 AI 不會自己判斷,那就由使用者來明確告訴它 — 這就是 Custom Prompts 的設計初衷。
16 個 Custom Prompts
我設計了 16 個 Custom Prompts(Slash Commands),每個 Prompt 對應一個或多個 Skill 的組合,涵蓋 29 個 Skills 的所有功能:
16 個 Custom Prompts:https://github.com/kevintsengtw/dotnet-testing-agent-orchestration/tree/main/.github/prompts
基礎與框架(4 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-fundamentals | 基礎單元測試 | unit-test-fundamentals、test-naming-conventions、xunit-project-setup |
/dotnet-testing-advanced-xunit-upgrade | xUnit v2→v3 升級 | xunit-upgrade-guide |
/dotnet-testing-advanced-tunit | TUnit 框架 | tunit-fundamentals、tunit-advanced |
/dotnet-testing-advanced-aspire-testing | Aspire 測試 | aspire-testing |
整合測試(2 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-advanced-integration | ASP.NET 整合測試 | aspnet-integration-testing、webapi-integration-testing |
/dotnet-testing-advanced-testcontainers | 容器化測試 | testcontainers-database、testcontainers-nosql |
測試資料(2 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-autofixture-bogus | 測試資料產生 | autofixture-basics、autofixture-customization、bogus-fake-data、autofixture-bogus-integration、autodata-xunit-integration |
/dotnet-testing-test-data-builder | Test Data Builder | test-data-builder-pattern |
Mock 與斷言(3 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-nsubstitute-mocking | NSubstitute Mock | nsubstitute-mocking、autofixture-nsubstitute-integration、autodata-xunit-integration |
/dotnet-testing-assertions | 斷言與物件比較 | awesome-assertions-guide、complex-object-comparison |
/dotnet-testing-fluentvalidation-testing | FluentValidation 測試 | fluentvalidation-testing |
測試實踐(3 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-test-output-logging | 測試輸出與記錄 | test-output-logging |
/dotnet-testing-code-coverage-analysis | 程式碼覆蓋率 | code-coverage-analysis |
/dotnet-testing-private-internal-testing | Private/Internal 測試 | private-internal-testing |
特定場景(2 個)
| Custom Prompt | 用途 | 載入的 Skills |
|---|---|---|
/dotnet-testing-datetime-testing-timeprovider | 時間測試 | datetime-testing-timeprovider |
/dotnet-testing-filesystem-testing-abstractions | 檔案系統測試 | filesystem-testing-abstractions |
使用方式
在 VS Code Agent Mode 的對話中,使用者可以輸入 Slash Command 來明確觸發:
/dotnet-testing-nsubstitute-mocking為 OrderService 建立單元測試
AI 收到這個指令後,就會確定載入 nsubstitute-mocking、autofixture-nsubstitute-integration 和 autodata-xunit-integration 三個 Skills,然後依照 Skills 的指引來撰寫測試。
每個 Custom Prompt 的結構是標準的 .prompt.md 檔案,包含 YAML frontmatter 和明確的 SKILL.md 讀取指令:
---
agent: 'agent'
description: 'AwesomeAssertions 斷言與複雜物件比較完整指南'
---
## 重要指示
**在執行以下任務之前,你必須先讀取並完整理解以下技能文件的全部內容:**
**必讀資源**:
1. `.github/skills/dotnet-testing-awesome-assertions-guide/SKILL.md`
2. `.github/skills/dotnet-testing-complex-object-comparison/SKILL.md`
...透過在 Prompt 中明確列出要讀取的 SKILL.md 路徑,確保 AI 一定會載入對應的 Skills。
優點
Custom Prompts 確實解決了「觸發」的問題:
- 確定性:使用者明確指定,AI 一定會載入對應的 Skills
- 組合性:每個 Prompt 預先配好了正確的 Skill 組合,不需要使用者了解每個 Skill 的名稱
- 品質提升:因為 Skills 確實被載入和遵循,測試品質明顯優於不使用 Skills 的情況
致命缺陷
但 Custom Prompts 有一個致命的問題 — 認知負擔轉移到了使用者身上。
使用者需要從 16 個指令中選擇正確的那一個。
回到 OrderProcessingService 的例子,使用者需要:
- 先分析
OrderProcessingService有哪些依賴 - 判斷需要 Mock(因為有介面依賴)
- 判斷需要 TimeProvider 測試(因為有
TimeProvider參數) - 判斷需要 AutoFixture(因為方法有複雜的輸入參數)
- 從 16 個指令中找到最合適的那一個...
- 是
/dotnet-testing-autofixture-bogus? - 是
/dotnet-testing-nsubstitute-mocking? - 還是
/dotnet-testing-datetime-testing-timeprovider?
- 是
這就是問題所在 — 使用者要從 16 個指令中挑對的那一個,這跟原本期待 AI 自己觸發正確 Skill 一樣難。
使用者不該需要做這些判斷。使用者應該只需要說一句話:「為 OrderService 建立測試」,剩下的事情都該由 AI 來處理。
問題的本質
走過 4 個版本的 SKILL.md 內的 Description 優化和 16 個 Custom Prompts 之後,我就開始意識到:
問題不在 Skill 的數量或 Description 的寫法。
問題在於一個根本的架構缺陷:
誰來決定載入哪些 Skills?
目前的答案是「AI 自己判斷」或「使用者手動指定」。這兩個答案都不夠好。
真正的解決方案需要一個能夠:
- 自動分析被測類別的程式碼特徵
- 智能決策需要哪些技能組合
- 精準載入對應的 Skills
- 獨立運作在隔離的 Context 中深入理解每個 Skill
這不是靠改善 SKILL.md 的 Description 或設計更多 Custom Prompts 能解決的。
直到 2026 年 2 月 4 日,VS Code v1.109 更新中出現了 Agent Orchestration and Subagents 的功能支援。於是我就在我想,這或許能拿來解決前面不管是單純使用 Agent Skills 還是改用 Custom Prompts 時所遇到的問題。
下一篇就來聊 VS Code v1.109 帶來了什麼,以及我怎麼用它來設計新的架構。
參考資源
NET Testing Agent Skills
- dotnet-testing-agent-skills:https://github.com/kevintsengtw/dotnet-testing-agent-skills
- SKILLS_QUICK_REFERENCE.md:https://github.com/kevintsengtw/dotnet-testing-agent-skills/blob/main/SKILLS_QUICK_REFERENCE.md
- v2.2.0 Release Notes:https://github.com/kevintsengtw/dotnet-testing-agent-skills/releases/tag/v2.2.0
Agent Skills
- agentskills.io:https://agentskills.io
- Anthropic — The Complete Guide to Building Skills for Claude:https://claude.com/blog/complete-guide-to-building-skills-for-claude
- 指南 PDF:https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf
- 指南繁中翻譯(Ian Chen):https://github.com/iangithub/translate/blob/main/The-Complete-Guide-to-Building-Skill-for-Claude_zh-TW.md
- 指南繁中翻譯(Will 保哥):https://drive.google.com/file/d/10llQ9I1JGboNsENEvhL42jc5GnHddcZ-/view
純粹是在寫興趣的,用寫程式、寫文章來抒解工作壓力