ユースケース2024年12月19日
使用 CCJK 进行代码审查:从代码质量到智能代理的完整工作流
深入了解如何使用 CCJK 的 ShenCha 审查引擎和 CCR 代理路由器,构建高效的代码审查工作流,提升代码质量并优化成本
CCJK 技术团队
代码审查ShenChaCCR代码质量智能代理
在现代软件开发中,代码审查是确保代码质量、安全性和可维护性的关键环节。传统的人工代码审查虽然有效,但面临着效率低下、主观性强、成本高昂等问题。今天,我们将探讨如何使用 CCJK 的 ShenCha 审查引擎和 CCR 代理路由器,构建一个智能化、自动化的代码审查系统,让团队能够在保证质量的同时提升开发效率。
使用场景:大型前端项目的代码审查挑战
项目背景
假设我们负责一个大型电商平台的前端项目,团队有 15 名开发者,日均提交 50+ 个 PR。项目包含:
- 代码规模:50,000+ 行 TypeScript/React 代码
- 技术栈:React 18 + TypeScript + Next.js + TailwindCSS
- 开发团队:前端工程师(8人)+ 全栈工程师(5人)+ 实习生(2人)
- 业务模块:用户中心、商品管理、订单系统、支付模块、营销活动
面临的挑战
- 审查效率低:资深工程师需要花费大量时间进行代码审查
- 质量不一致:不同审查者的标准不统一
- 安全隐患:支付相关代码的安全问题容易被忽视
- 成本考虑:频繁使用 Claude Opus 进行代码分析成本过高
- 知识传递:新人代码质量参差不齐,需要更多指导
完整工作流程
第一步:配置 CCR 代理路由器
首先,我们需要配置 CCR 来优化不同类型审查任务的成本和效率。
hljs bash# 安装并启动 CCR
ccjk ccr install
ccjk ccr start
# 检查服务状态
ccjk ccr status
配置多模型路由策略:
hljs yaml# .ccr/config.yaml
name: "code-review-router"
version: "1.0"
providers:
# 免费模型 - 处理简单代码检查
deepseek:
endpoint: "https://api.deepseek.com/v1"
models:
- "deepseek-coder"
cost_per_token: 0.00014
# 快速模型 - 处理常规审查
claude_haiku:
endpoint: "https://api.anthropic.com/v1"
models:
- "claude-3-haiku-20240307"
cost_per_token: 0.00025
# 高质量模型 - 处理复杂逻辑和安全审查
claude_opus:
endpoint: "https://api.anthropic.com/v1"
models:
- "claude-3-opus-20240229"
cost_per_token: 0.015
routes:
# 代码格式和基础检查 -> 免费模型
- name: "basic-check"
pattern:
keywords: ["format", "lint", "import", "export", "syntax"]
file_types: [".ts", ".tsx", ".js", ".jsx"]
max_tokens: 1000
target: "deepseek"
# 常规业务逻辑审查 -> 快速模型
- name: "business-logic"
pattern:
keywords: ["component", "hook", "util", "helper"]
file_types: [".ts", ".tsx"]
max_tokens: 3000
target: "claude_haiku"
# 安全敏感代码 -> 高质量模型
- name: "security-critical"
pattern:
keywords: ["auth", "payment", "crypto", "password", "token", "session"]
file_patterns: ["**/auth/**", "**/payment/**", "**/api/secure/**"]
target: "claude_opus"
priority: "high"
# 复杂算法和架构 -> 高质量模型
- name: "complex-logic"
pattern:
complexity_threshold: 10
file_size_threshold: 500
target: "claude_opus"
# 成本优化配置
cost_optimization:
enabled: true
daily_budget: 50.0 # 每日预算 $50
fallback_strategy: "downgrade" # 超预算时降级到便宜模型
# 监控配置
monitoring:
enabled: true
web_ui: true
port: 8080
第二步:配置 ShenCha 审查引擎
接下来配置针对电商项目特点的审查规则:
hljs yaml# .shencha.yaml
version: 1
name: "ecommerce-frontend-review"
# 审查范围
include:
- src/**/*.ts
- src/**/*.tsx
- pages/**/*.tsx
- components/**/*.tsx
exclude:
- "**/*.test.ts"
- "**/*.spec.ts"
- "**/*.stories.tsx"
- node_modules/**
- .next/**
# 针对电商项目的审查规则
rules:
# 代码质量
quality:
maxComplexity: 12 # 电商逻辑相对复杂,适当放宽
maxFileLines: 400
maxFunctionLines: 60
requireComments: true
naming:
style: "camelCase"
prefixes:
components: ["use", "with", "handle"]
types: ["I", "T"]
# 安全规则(电商项目严格要求)
security:
level: strict
checkDependencies: true
sensitivePatterns:
- password
- secret
- apiKey
- creditCard
- paymentToken
sensitiveFiles:
- "**/payment/**"
- "**/auth/**"
- "**/api/secure/**"
# 性能规则(用户体验关键)
performance:
checkNPlusOne: true
checkMemoryLeaks: true
maxBundleSize: 600kb # 电商页面允许稍大
requireLazyLoading: true
checkImageOptimization: true
# 电商特定最佳实践
bestPractices:
framework: react
typescript: strict
accessibility:
level: "AA" # 符合 WCAG 2.1 AA 标准
seo:
requireMetaTags: true
requireStructuredData: true
testing:
minCoverage: 75 # 业务逻辑要求高覆盖率
requireE2ETests: true
# 自定义电商规则
customRules:
# 价格处理规则
- id: "ecommerce/price-precision"
pattern: "price.*[*/]"
message: "价格计算必须使用精确数学库,避免浮点数精度问题"
severity: error
suggestion: "使用 decimal.js 或 big.js 进行价格计算"
# 支付安全规则
- id: "ecommerce/payment-logging"
pattern: "console\\.log.*(?:card|payment|billing)"
message: "支付相关信息禁止输出到日志"
severity: error
files: "**/payment/**"
# 用户数据保护
- id: "ecommerce/pii-exposure"
pattern: "(?:email|phone|address).*localStorage"
message: "个人敏感信息不应存储在 localStorage"
severity: warning
suggestion: "使用加密存储或会话存储"
# 商品数据验证
- id: "ecommerce/product-validation"
pattern: "product.*price.*[<>]\\s*0"
message: "商品价格验证应考虑负数和零值情况"
severity: warning
# 分级审查配置
reviewLevels:
intern: # 实习生代码 - 严格审查
rules:
security: strict
quality: strict
bestPractices: strict
aiModel: "claude-opus"
junior: # 初级工程师
rules:
security: strict
quality: moderate
bestPractices: moderate
aiModel: "claude-haiku"
senior: # 高级工程师
rules:
security: strict
quality: relaxed
bestPractices: relaxed
aiModel: "deepseek-coder"
# 报告配置
report:
format: markdown
output: ./reviews/shencha-report.md
includeCode: true
includeMetrics: true
maxIssues: 30
groupBy: ["severity", "category", "file"]
第三步:设置自动化工作流
配置 Git hooks 和 CI/CD 集成:
hljs yaml# .claude/hooks/pre-commit-review.yaml
name: automated-code-review
event: onPreCommit
stages:
- name: "快速检查"
condition: "changed_files < 5"
handler:
command: "/shencha --changed --level basic"
timeout: 30s
- name: "完整审查"
condition: "changed_files >= 5 OR contains_payment_files"
handler:
command: "/shencha --changed --level full"
timeout: 120s
- name: "安全专项审查"
condition: "touches_security_files"
handler:
command: "/shencha --changed --security --ai-model claude-opus"
timeout: 180s
onFailure:
action: block
message: |
🚫 代码审查发现问题,请修复后再提交:
📋 查看详细报告: cat .shencha/last-report.md
🔧 自动修复: /shencha --changed --fix
💬 获取帮助: /ask "如何修复 ShenCha 发现的问题?"
hljs yaml# .github/workflows/shencha-review.yml
name: Automated Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
shencha-review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Setup CCJK
run: |
npm install -g ccjk
ccjk ccr start --config .ccr/config.yaml
- name: Run ShenCha Review
id: review
run: |
ccjk shencha --ci \
--report json \
--output review-report.json \
--fail-on error
env:
CCJK_API_KEY: ${{ secrets.CCJK_API_KEY }}
- name: Generate Review Summary
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('review-report.json', 'utf8'));
// 生成审查摘要
const summary = `
## 🔍 代码审查报告
**总体评分**: ${report.overallScore}/10
**审查文件**: ${report.filesReviewed}个
**发现问题**: ${report.totalIssues}个
### 📊 问题分布
- 🔴 严重: ${report.criticalIssues}个
- 🟡 警告: ${report.warningIssues}个
- 🔵 信息: ${report.infoIssues}个
### 🏷️ 主要问题类别
${report.issueCategories.map(cat => `- ${cat.name}: ${cat.count}个`).join('\n')}
### 💰 AI 使用成本
- 本次审查成本: $${report.cost.toFixed(4)}
- 模型使用: ${report.modelUsage.map(m => `${m.model}(${m.requests}次)`).join(', ')}
${report.criticalIssues > 0 ? '⚠️ **发现严重问题,建议修复后合并**' : '✅ **代码质量良好,可以合并**'}
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
- name: Upload Review Artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: code-review-report
path: |
review-report.json
.shencha/detailed-report.md
第四步:实际使用场景演示
现在让我们看几个典型的代码审查场景:
场景1:新人提交的支付组件
假设实习生小李提交了一个支付表单组件:
hljs typescript// src/components/payment/PaymentForm.tsx
import React, { useState } from 'react';
interface PaymentFormProps {
onSubmit: (data: any) => void;
}
const PaymentForm: React.FC<PaymentFormProps> = ({ onSubmit }) => {
const [cardNumber, setCardNumber] = useState('');
const [cvv, setCvv] = useState('');
const [expiry, setExpiry] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log('Payment data:', { cardNumber, cvv, expiry }); // 问题!
// 简单验证
if (cardNumber.length === 16) { // 问题!
const total = 99.99 + 5.50; // 问题!浮点数精度
onSubmit({
cardNumber: cardNumber,
cvv: cvv,
expiry: expiry,
total: total
});
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Card Number"
value={cardNumber}
onChange={(e) => setCardNumber(e.target.value)}
/>
<input
type="text"
placeholder="CVV"
value={cvv}
onChange={(e) => setCvv(e.target.value)}
/>
<input
type="text"
placeholder="MM/YY"
value={expiry}
onChange={(e) => setExpiry(e.target.value)}
/>
<button type="submit">Pay Now</button>
</form>
);
};
export default PaymentForm;
运行审查:
hljs bash# 检测到支付相关文件,自动使用 Claude Opus 进行安全审查
/shencha src/components/payment/PaymentForm.tsx
ShenCha 审查结果:
🛡️ 支付组件安全审查报告
🔴 严重问题 (3):
1. [SECURITY-001] 支付敏感信息输出到控制台
位置: line 13
代码: console.log('Payment data:', { cardNumber, cvv, expiry });
风险: 敏感支付信息可能泄露到日志
修复: 移除日志输出或使用脱敏处理
2. [SECURITY-002] 信用卡号验证过于简单
位置: line 16
代码: if (cardNumber.length === 16)
风险: 无效的信用卡号可能通过验证
修复: 使用 Luhn 算法验证信用卡号
3. [ECOMMERCE-001] 价格计算使用浮点数
位置: line 17
代码: const total = 99.99 + 5.50;
风险: 浮点数精度问题可能导致金额错误
修复: 使用 decimal.js 进行精确计算
🟡 警告 (4):
4. [ACCESSIBILITY-001] 表单缺少标签和错误提示
5. [SECURITY-003] 输入框未限制最大长度
6. [TYPES-001] onSubmit 参数类型过于宽泛 (any)
7. [VALIDATION-001] 缺少客户端验证
💡 修复建议:
需要我帮您自动修复这些问题吗?我将:
1. 移除敏感信息的日志输出
2. 添加信用卡号 Luhn 验证
3. 使用 decimal.js 进行价格计算
4. 改进类型定义和表单验证
5. 添加无障碍支持
用户确认后,ShenCha 提供修复版本:
hljs typescript// ShenCha 修复后的版本
import React, { useState } from 'react';
import { Decimal } from 'decimal.js';
import { validateCardNumber, validateCVV, validateExpiry } from '@/utils/payment-validation';
interface PaymentData {
cardNumber: string;
cvv: string;
expiry: string;
total: string; // 使用字符串避免精度问题
}
interface PaymentFormProps {
onSubmit: (data: PaymentData) => void;
baseAmount: number;
shippingCost: number;
}
const PaymentForm: React.FC<PaymentFormProps> = ({
onSubmit,
baseAmount,
shippingCost
}) => {
const [cardNumber, setCardNumber] = useState('');
const [cvv, setCvv] = useState('');
const [expiry, setExpiry] = useState('');
const [errors, setErrors] = useState<Record<string, string>>({});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const validationErrors: Record<string, string> = {};
// 验证信用卡号(使用 Luhn 算法)
if (!validateCardNumber(cardNumber)) {
validationErrors.cardNumber = '请输入有效的信用卡号';
}
// 验证 CVV
if (!validateCVV(cvv)) {
validationErrors.cvv = '请输入有效的 CVV';
}
// 验证有效期
if (!validateExpiry(expiry)) {
validationErrors.expiry = '请输入有效的有效期 (MM/YY)';
}
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
// 使用 Decimal.js 进行精确计算
const total = new Decimal(baseAmount).plus(shippingCost).toString();
onSubmit({
cardNumber: cardNumber.replace(/\s/g, ''), // 移除空格
cvv,
expiry,
total
});
}
};
return (
<form onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="cardNumber">信用卡号 *</label>
<input
id="cardNumber"
type="text"
placeholder="1234 5678 9012 3456"
value={cardNumber}
maxLength={19} // 16位数字 + 3个空格
onChange={(e) => setCardNumber(e.target.value)}
aria-invalid={!!errors.cardNumber}
aria-describedby={errors.cardNumber ? "cardNumber-error" : undefined}
/>
{errors.cardNumber && (
<span id="cardNumber-error" role="alert" className="error">
{errors.cardNumber}
</span>
)}
</div>
<div>
<label htmlFor="cvv">CVV *</label>
<input
id="cvv"
type="text"
placeholder="123"
value={cvv}
maxLength={4}
onChange={(e) => setCvv(e.target.value)}
aria-invalid={!!errors.cvv}
aria-describedby={errors.cvv ? "cvv-error" : undefined}
/>
{errors.cvv && (
<span id="cvv-error" role="alert" className="error">
{errors.cvv}
</span>
)}
</div>
<div>
<label htmlFor="expiry">有效期 *</label>
<input
id="expiry"
type="text"
placeholder="MM/YY"
value={expiry}
maxLength={5}
onChange={(e) => setExpiry(e.target.value)}
aria-invalid={!!errors.expiry}
aria-describedby={errors.expiry ? "expiry-error" : undefined}
/>
{errors.expiry && (
<span id="expiry-error" role="alert" className="error">
{errors.expiry}
</span>
)}
</div>
<button type="submit">
立即支付 ¥{new Decimal(baseAmount).plus(shippingCost).toFixed(2)}
</button>
</form>
);
};
export default PaymentForm;
场景2:高级工程师的商品列表优化
资深工程师张三提交了商品列表性能优化:
hljs typescript// src/components/product/ProductList.tsx
import React, { useMemo } from 'react';
import { Product } from '@/types/product';
interface ProductListProps {
products: Product[];
onProductClick: (id: string) => void;
}
const ProductList: React.FC<ProductListProps> = ({ products, onProductClick }) => {
const sortedProducts = useMemo(() => {
return products.sort((a, b) => b.rating - a.rating);
}, [products]);
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{sortedProducts.map(product => (
<ProductCard
key={product.id}
product={product}
onClick={() => onProductClick(product.id)}
/>
))}
</div>
);
};
由于是资深工程师的代码,CCR 自动使用 DeepSeek 进行基础检查:
hljs bash# 自动检测到高级工程师,使用轻量级审查
/shencha src/components/product/ProductList.tsx --author senior
审查结果:
✅ 代码质量良好 (8.5/10)
优点:
• 正确使用 useMemo 优化排序性能
• 类型定义完整
• 组件职责单一
🟡 可选优化建议 (1):
1. [PERF-001] 大列表可考虑虚拟化
建议: 当 products.length > 100 时使用 react-window
💰 成本报告:
- 使用模型: DeepSeek Coder
- 审查耗时: 3.2秒
- 成本: $0.0008
场景3:批量审查整个功能模块
产品经理要求审查整个购物车模块:
hljs bash# 审查购物车相关所有文件
/shencha src/features/cart/ --deep --report html
ShenCha 生成详细的模块级审查报告:
🛒 购物车模块审查报告
📁 审查范围: src/features/cart/ (15 个文件)
⏱️ 审查时间: 2分35秒
🤖 使用模型: Claude Haiku (12个文件), Claude Opus (3个安全关键文件)
💰 总成本: $0.24
📊 总体评分: 7.8/10
模块结构分析:
├── components/ 8.5/10 ✅ 优秀
├── hooks/ 8.0/10 ✅ 良好
├── utils/ 7.2/10 ⚠️ 需改进
├── types/ 9.0/10 ✅ 优秀
└── api/ 6.5/10 ⚠️ 需关注
🔍 发现的问题:
高优先级 (2):
1. utils/price-calculator.ts: 价格计算精度问题
2. api/cart-service.ts: 缺少错误重试机制
中优先级 (5):
3. hooks/useCart.ts: 状态更新可能导致不必要重渲染
4. components/CartItem.tsx: 无障碍属性不完整
5. utils/storage.ts: localStorage 异常处理缺失
6. types/cart.ts: 部分类型定义过于宽泛
7. api/discount-service.ts: 优惠券验证逻辑复杂
低优先级 (8):
8-15. 代码风格和注释改进建议...
🎯 改进建议:
立即修复:
• price-calculator.ts 的浮点数计算问题
• cart-service.ts 添加网络异常处理
短期优化:
• 优化 useCart hook 的性能
• 完善无障碍支持
• 改进错误处理
长期规划:
• 考虑引入状态管理库(Zustand/Redux)
• 抽象通用的 API 错误处理逻辑
• 添加更多单元测试覆盖
📈 模块健康度趋势:
- 代码质量: 7.5 → 7.8 (+4%)
- 测试覆盖: 72% → 78% (+6%)
- 性能评分: 7.0 → 8.2 (+17%)
- 安全性: 8.0 → 8.5 (+6%)
实用技巧分享
1. 成本优化策略
通过 CCR 的智能路由,我们实现了显著的成本节约:
hljs bash# 查看成本分析报告
ccjk ccr metrics --period 30d
# 输出示例
CCR 成本优化报告 (最近30天)
────────────────────────────
总体节约: 62% ($450 → $171)
模型使用分布:
┌─────────────────┬────────────┬─────────────┬──────────┐
│ 模型 │ 请求次数 │ 总成本 │ 平均成本 │
├─────────────────┼────────────┼─────────────┼──────────┤
│ DeepSeek │ 2,847 │ $23.45 │ $0.008 │
│ Claude Haiku │ 1,256 │ $87.32 │ $0.069 │
│ Claude Opus │ 187 │ $134.78 │ $0.721 │
└─────────────────┴────────────┴─────────────┴──────────┘
任务类型分布:
• 基础检查 (67%): DeepSeek 处理,节约 85%
• 业务审查 (28%): Haiku 处理,节约 45%
• 安全审查 (5%): Opus 处理,保证质量
优化建议:
✅ 当前配置已优化良好
💡 可考虑增加更多基础检查规则到 DeepSeek
2. 团队协作最佳实践
建立审查等级制度
hljs yaml# .shencha/team-config.yaml
authors:
intern:
emails: ["intern1@company.com", "intern2@company.com"]
review_level: "strict"
ai_model: "claude-opus"
require_manual_approval: true
junior:
emails: ["dev1@company.com", "dev2@company.com"]
review_level: "standard"
ai