一键导入
tdd-workflow
强制测试驱动开发循环 - 先写测试(RED)→ 实现功能(GREEN)→ 重构(REFACTOR)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
强制测试驱动开发循环 - 先写测试(RED)→ 实现功能(GREEN)→ 重构(REFACTOR)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Guidelines and constraints for modifying the FastAPI api.py server, the BayesianOptimizer core logic, the physics-informed KnowledgeEngine prompting, or the VectorMemory embeddings/RAG layers. Use this skill whenever the user asks to modify python backend code under backend/optimization/ or backend/api.py.
Guidelines and constraints for modifying the React, Vite, Tailwind CSS 4.x, and Recharts frontend of BOagent. Use this skill whenever the user asks to modify App.tsx, BenchMode.tsx, OperationalMode.tsx, custom components in src/components/, or the styling theme in index.css.
Rules and protocols for running backend unit/integration tests (pytest) and frontend E2E tests (Playwright) in BOagent. Use this skill whenever the user asks to run test suites, check code coverage, add new test cases, mock API calls, or verify modifications to the codebase.
审查科学计算代码的数值稳定性、物理单位一致性和数学正确性
Specialized expert for BOagent codebase. Analyzes Bayesian Optimization logic, materials science physical constraints (Band Alignment/Defects), and verifies PVK-LLM alignment. Use when auditing backend optimization logic, benchmark consistency, or frontend-backend API contracts.
Simplifies code for clarity. Use when refactoring code for clarity without changing behavior. Use when code works but is harder to read, maintain, or extend than it should be. Use when reviewing code that has accumulated unnecessary complexity.
| name | tdd-workflow |
| description | 强制测试驱动开发循环 - 先写测试(RED)→ 实现功能(GREEN)→ 重构(REFACTOR) |
当添加新功能、修复 bug 或重构代码时,强制执行 TDD 循环。
┌─────────────────────────────────────┐
│ 1. RED: 写失败的测试 │
│ ↓ │
│ 2. GREEN: 实现最小可用代码 │
│ ↓ │
│ 3. REFACTOR: 重构并保持测试通过 │
└─────────────────────────────────────┘
测试文件位置: backend/tests/test_*.py
测试模板:
import pytest
from backend.optimization.optimizer import BayesianOptimizer
def test_ucb_acquisition_function():
"""测试 UCB 采集函数计算正确性"""
optimizer = BayesianOptimizer(
bounds=[(0, 1), (0, 1)],
acquisition="ucb",
kappa=2.0
)
# 添加初始观测点
X_init = [[0.2, 0.3], [0.7, 0.8]]
y_init = [25.0, 27.0]
optimizer.tell(X_init, y_init)
# 测试 UCB 计算
X_test = [[0.5, 0.5]]
ucb_values = optimizer._calculate_ucb(X_test)
# 断言:UCB = mean + kappa * std
assert ucb_values.shape == (1,)
assert ucb_values[0] > 0 # UCB 应为正值
assert not np.isnan(ucb_values[0]) # 不应为 NaN
运行测试:
cd backend
python -m pytest tests/test_optimizer.py::test_ucb_acquisition_function -v
预期结果: ❌ 测试失败(因为功能尚未实现)
测试文件位置: frontend/tests/e2e/*.spec.ts
测试模板:
import { test, expect } from '@playwright/test';
test('应该能够切换 LLM 模型并启动评测', async ({ page }) => {
await page.goto('http://localhost:5173');
// 切换到 DeepSeek Pro 模型
await page.selectOption('select[name="model"]', 'deepseek-v4-pro');
// 点击启动评测按钮
await page.click('button:has-text("启动评测")');
// 验证日志流开始输出
await expect(page.locator('.log-stream')).toBeVisible();
await expect(page.locator('.log-stream')).toContainText('开始评测');
// 验证图表渲染
await expect(page.locator('.recharts-wrapper')).toBeVisible();
});
运行测试:
cd frontend
npm run test:e2e -- --headed
预期结果: ❌ 测试失败(因为功能尚未实现)
# backend/optimization/optimizer.py
def _calculate_ucb(self, X):
"""计算 UCB 采集函数值"""
X = np.atleast_2d(X)
mean, std = self.gp.predict(X, return_std=True)
# 添加 epsilon 防止 std=0
std = np.maximum(std, 1e-10)
# UCB = mean + kappa * std
return mean + self.kappa * std
运行测试:
python -m pytest tests/test_optimizer.py::test_ucb_acquisition_function -v
预期结果: ✅ 测试通过
// frontend/src/App.tsx
const [selectedModel, setSelectedModel] = useState('deepseek-v4-flash');
const [isRunning, setIsRunning] = useState(false);
const handleStartBenchmark = async () => {
setIsRunning(true);
const response = await fetch('/api/benchmark/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: selectedModel })
});
// 处理 SSE 日志流
const reader = response.body.getReader();
// ... 流处理逻辑
};
运行测试:
npm run test:e2e
预期结果: ✅ 测试通过
重构前:
def calculate_acquisition(self, X, method):
if method == "ucb":
mean, std = self.gp.predict(X, return_std=True)
return mean + self.kappa * std
elif method == "ei":
mean, std = self.gp.predict(X, return_std=True)
# ... EI 计算
elif method == "pi":
mean, std = self.gp.predict(X, return_std=True)
# ... PI 计算
重构后:
def calculate_acquisition(self, X, method):
"""计算采集函数值
Args:
X: 候选点 (n_samples, n_features)
method: 采集函数类型 ("ucb", "ei", "pi")
Returns:
采集函数值 (n_samples,)
"""
mean, std = self._predict_with_uncertainty(X)
acquisition_funcs = {
"ucb": self._calculate_ucb,
"ei": self._calculate_ei,
"pi": self._calculate_pi
}
return acquisition_funcs[method](mean, std)
def _predict_with_uncertainty(self, X):
"""预测均值和标准差(添加数值稳定性保护)"""
mean, std = self.gp.predict(X, return_std=True)
std = np.maximum(std, 1e-10) # 防止 std=0
return mean, std
验证重构:
# 确保所有测试仍然通过
python -m pytest tests/ -v
预期结果: ✅ 所有测试通过,代码更清晰
检查覆盖率:
# Backend
cd backend
python -m pytest --cov=. --cov-report=term-missing
# Frontend (如果配置了 coverage)
cd frontend
npm run test:coverage
覆盖率报告示例:
Name Stmts Miss Cover Missing
---------------------------------------------------------------
backend/optimization/optimizer.py 120 8 93% 45-47, 89
backend/optimization/knowledge.py 200 15 92%
backend/optimization/memory.py 85 5 94%
---------------------------------------------------------------
TOTAL 405 28 93%
conftest.py 定义共享 fixturesStep 1: RED - 写失败的测试
# backend/tests/test_optimizer.py
def test_ei_acquisition_function():
optimizer = BayesianOptimizer(acquisition="ei")
optimizer.tell([[0.5, 0.5]], [26.0])
ei_values = optimizer._calculate_ei([[0.3, 0.7]])
assert ei_values[0] >= 0 # EI 应非负
assert not np.isnan(ei_values[0])
运行: pytest tests/test_optimizer.py::test_ei_acquisition_function
结果: ❌ AttributeError: 'BayesianOptimizer' object has no attribute '_calculate_ei'
Step 2: GREEN - 最小实现
# backend/optimization/optimizer.py
def _calculate_ei(self, mean, std):
"""计算期望改进"""
from scipy.stats import norm
# 当前最优值
y_best = np.max(self.y_observed)
# 改进量
improvement = mean - y_best
# 标准化改进
Z = improvement / std
# EI = improvement * CDF(Z) + std * PDF(Z)
ei = improvement * norm.cdf(Z) + std * norm.pdf(Z)
return ei
运行: pytest tests/test_optimizer.py::test_ei_acquisition_function
结果: ✅ 测试通过
Step 3: REFACTOR - 重构优化
def _calculate_ei(self, mean, std):
"""计算期望改进(Expected Improvement)
EI 衡量候选点相对当前最优值的期望改进量。
数值稳定的实现避免了 std=0 时的除零错误。
Args:
mean: 预测均值 (n_samples,)
std: 预测标准差 (n_samples,)
Returns:
期望改进值 (n_samples,)
"""
from scipy.stats import norm
y_best = np.max(self.y_observed)
improvement = mean - y_best
# 数值稳定性:当 std 很小时,EI ≈ 0
with np.errstate(divide='ignore', invalid='ignore'):
Z = improvement / std
ei = improvement * norm.cdf(Z) + std * norm.pdf(Z)
ei[std == 0] = 0 # std=0 时 EI=0
return ei
运行: pytest tests/ -v
结果: ✅ 所有测试通过
backend/pytest.ini 或 backend/conftest.pyfrontend/playwright.config.tsbackend/.coveragerc# Backend 快速测试
alias pytest-fast="python -m pytest -x -v"
# Backend 覆盖率报告
alias pytest-cov="python -m pytest --cov=. --cov-report=html"
# Frontend E2E 测试
alias e2e="npm run test:e2e"
# Frontend E2E 调试
alias e2e-debug="npm run test:e2e:debug"