Files
awoooi/docs/adr/ADR-018-llm-testing-strategy.md
OG T 2f5986df5c docs: ADR 整理與新增 (021-029)
ADR 編號修正:
- ADR-023 failure-auto-repair → ADR-028
- ADR-025 cicd-ai-integration → ADR-029

新增 ADR:
- ADR-021: Playbook 更新驗證
- ADR-022: Sentry 整合架構
- ADR-027: Incident-Approval 同步
- ADR-028: 失敗自動修復閉環
- ADR-029: CI/CD AI 整合 (原 ADR-025)

更新:
- ADR-018: LLM 測試策略狀態更新

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-26 19:09:08 +08:00

197 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-018: LLM 測試策略
| 屬性 | 值 |
|------|-----|
| **狀態** | 延緩 (Deferred) - 方案 A 先行 |
| **建立日期** | 2026-03-26 |
| **決策者** | 首席架構師 + 統帥 |
| **關聯** | Phase 12.3, #68, #69 |
## 背景
現有 LLM 測試 (`test_model_regression.py`, `test_prompt_validation.py`) 存在以下問題:
1. **字串精確匹配** - 檢查 "AWOOOI" 或 "kubectl" 是否存在
2. **LLM 非確定性** - 相同 prompt 產生不同輸出
3. **CI 依賴 Live LLM** - Ollama 不穩定導致 CI 失敗
4. **無語意理解** - 無法判斷「意思相近」
## 決策
採用 **三層測試策略**
### Tier 1: 結構驗證 (CI 必跑)
```
測試目標: 輸出符合 Schema
執行時機: 每次 CI
Mock 策略: 使用錄製的 Golden Responses
```
**原則**:
- 驗證 JSON Schema不驗證內容
- 驗證 kubectl 語法有效性,不驗證具體命令
- 驗證風險等級為有效 Enum不驗證「應該是 HIGH」
**實作**:
```python
# ❌ 錯誤: 字串匹配
lambda r: "CRITICAL" in r.upper()
# ✅ 正確: Schema 驗證
class LLMProposalOutput(BaseModel):
risk_level: Literal["LOW", "MEDIUM", "HIGH", "CRITICAL"]
kubectl_command: str
reasoning: str
def validate_output(response: str) -> bool:
try:
parsed = LLMProposalOutput.model_validate_json(response)
return True
except ValidationError:
return False
```
### Tier 2: 屬性測試 (Nightly)
```
測試目標: 輸出符合不變量
執行時機: 每晚 / PR Merge
Mock 策略: Live LLM + 寬鬆閾值
```
**不變量範例**:
- kubectl 命令必須可解析 (用 shlex.split)
- 風險等級必須為有效值
- 回應長度 < 500 字
- 繁體中文比例 > 30% (用 regex 檢測)
**實作**:
```python
def test_kubectl_parseable(llm_response):
"""kubectl 命令必須可被 shell 解析"""
import shlex
cmd = extract_kubectl(llm_response)
if cmd:
tokens = shlex.split(cmd) # 若無法解析會拋 ValueError
assert tokens[0] == "kubectl"
def test_risk_level_valid(llm_response):
"""風險等級必須是有效值"""
risk = extract_risk_level(llm_response)
assert risk in {"LOW", "MEDIUM", "HIGH", "CRITICAL"}
```
### Tier 3: 語意品質 (Weekly/Manual)
```
測試目標: 輸出語意品質
執行時機: 每週 / 手動觸發
Mock 策略: Live LLM + Embedding 比對
```
**原則**:
- 使用 Embedding 計算語意相似度
- 與 Golden Response 比對,相似度 > 0.7 為通過
- 統計通過率8/10 通過 = 整體通過
**實作**:
```python
async def test_semantic_similarity(llm_response, golden_response):
"""語意相似度測試"""
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
emb1 = model.encode(llm_response)
emb2 = model.encode(golden_response)
similarity = cosine_similarity(emb1, emb2)
assert similarity > 0.7, f"相似度 {similarity:.2f} 低於閾值 0.7"
```
## 測試分層總覽
| Tier | 執行時機 | Mock | 驗證內容 | 失敗處理 |
|------|---------|------|---------|---------|
| **1** | 每次 CI | Golden Response | Schema + 語法 | 阻擋合併 |
| **2** | Nightly | Live LLM | 不變量屬性 | 告警 + Issue |
| **3** | Weekly | Live LLM + Embedding | 語意品質 | 報告 + 趨勢追蹤 |
## 實作計畫
### Phase 1: Schema 強制 (1 天)
1. 修改 OpenClaw Prompt 強制 JSON 輸出
2. 建立 `LLMProposalOutput` Pydantic Model
3. 所有 LLM 回應經過 Schema 驗證
### Phase 2: Golden Response 錄製 (1 天)
1. 執行現有測試,錄製成功回應
2. 儲存為 `tests/fixtures/golden_responses.json`
3. CI 改用 Golden Response Mock
### Phase 3: 屬性測試重構 (2 天)
1. 將 lambda validators 改為屬性測試
2. 新增 kubectl 解析驗證
3. 新增風險等級 Enum 驗證
### Phase 4: 語意測試 (2 天)
1. 整合 sentence-transformers
2. 建立語意相似度基準線
3. 設定 Weekly 排程
## 替代方案
| 方案 | 優點 | 缺點 | 決定 |
|------|------|------|------|
| **Skip 測試** | 簡單 | 無品質保證 | ❌ |
| **增加 Retry** | 簡單 | 治標不治本 | ❌ |
| **降低閾值** | 簡單 | 漏檢問題 | ❌ |
| **三層策略** | 完整 | 實作成本 | ✅ |
## 風險
1. **Embedding 模型載入時間** - 使用輕量模型 (MiniLM)
2. **Golden Response 過時** - 定期更新機制
3. **語意閾值調校** - 初期從寬,逐步收緊
## 成功指標
- Tier 1 測試 100% 通過率 (CI 不再因 LLM 波動失敗)
- Tier 2 測試 > 90% 通過率 (Nightly)
- Tier 3 測試 > 80% 通過率 (Weekly)
- 無 LLM 相關 CI 失敗導致的開發阻塞
## 參考
- [LLM Evaluation Best Practices](https://www.anthropic.com/research/evaluations)
- [Property-Based Testing](https://hypothesis.readthedocs.io/)
- [Sentence Transformers](https://www.sbert.net/)
---
## 2026-03-26 決策更新
**狀態**: 延緩 (Deferred)
**實際採用方案**: 方案 A - 最小改動優先
| 項目 | 實作內容 |
|------|---------|
| 確定性參數 | `temperature: 0.0`, `seed: 42` |
| CI 分層 | LLM 測試移至 Nightly |
| 超時調整 | 300 秒 (CPU 推理) |
| 繁體中文 | System Prompt 強制繁中 |
**原因**:
1. 三層策略實作成本高 (~1000 行代碼)
2. 方案 A 已解決 CI 不穩定問題
3. 優先確保 CI 穩定,後續再評估是否需要完整框架
**評估文件**: `docs/evaluations/2026-03-26_llm_testing_evaluation.md`
**後續**: 若方案 A 效果良好,此 ADR 維持 Deferred若仍有問題再實施三層策略