256 lines
11 KiB
JavaScript
256 lines
11 KiB
JavaScript
const Database = require('better-sqlite3');
|
||
const db = new Database('data/ai-review.db');
|
||
|
||
const dims = [
|
||
{
|
||
name: '场景价值与技术合理性',
|
||
maxScore: 10,
|
||
content: `AI读取参赛者的方案文档(DESIGN.md / docs/ 等),判断场景论述的质量。
|
||
|
||
评分要素:
|
||
1) 真实需求(3分)— 解决的是真实业务需求还是虚构场景
|
||
2) Agent不可替代性(3分)— 为什么非用Agent不可,不是传统脚本/工具能解决的
|
||
3) ROI可量化(2分)— 效率提升/成本降低等有数据支撑
|
||
4) 场景文档完整性(2分)— 业务背景、痛点分析、方案对比齐全
|
||
|
||
无场景文档 → 0分`
|
||
},
|
||
{
|
||
name: '开发范式应用',
|
||
maxScore: 5,
|
||
content: `通过分析已有文件的内容推断参赛者是否遵循了合理的开发范式。
|
||
|
||
评分要素:
|
||
1) 开发流程覆盖(2分)— AI日志是否覆盖需求分析→设计→编码→测试的完整流程
|
||
2) 设计文档质量(2分)— 是否有需求分析、架构设计、接口设计文档
|
||
3) 测试文档质量(1分)— 是否有测试用例、测试计划、测试报告
|
||
|
||
没有任何一个维度的证据 → 0分`
|
||
},
|
||
{
|
||
name: '架构设计',
|
||
maxScore: 10,
|
||
content: `架构文档存在性 + 允许代码反向推断。
|
||
discoverFiles 扩大匹配:**/architecture*、**/design*、含"架构"/"模块"/"数据流"关键词的文件。
|
||
|
||
评分要素:
|
||
1) 架构文档存在且质量高(3分)— 有 DESIGN.md / docs/design.md 等完整文档
|
||
2) 模块化与分层(3分)— 代码是否按职责分层、模块间依赖是否合理
|
||
3) 数据流清晰度(2分)— 数据流转路径是否可追溯
|
||
4) 可扩展性(2分)— 是否有接口抽象、插件机制等便于扩展的设计
|
||
|
||
文档规则:
|
||
- 有完整架构文档:可评至满分10分
|
||
- 无文档但有代码证据:封顶5分(允许根据代码结构反向推断模块化/分层/数据流)
|
||
- 无文档且代码混乱:0-3分`
|
||
},
|
||
{
|
||
name: '工具使用与Skill集成深度',
|
||
maxScore: 5,
|
||
content: `AI框架集成深度 + 开发工具链。
|
||
|
||
AI框架集成(3分):是否深度使用了LangChain/LangGraph/AutoGen等Agent框架。
|
||
- 无框架使用 → 0分
|
||
- 使用框架基本功能(chain/pipeline)→ 1分
|
||
- 实现了MCP/Function Calling协议 → 2分
|
||
- 自定义Agent工具链、有深度框架定制 → 3分
|
||
|
||
开发工具链(2分):非AI框架的开发工具/基础设施集成。
|
||
- IDE集成(VSCode插件/LSP/Webview面板等)→ 1分
|
||
- CI/CD配置(GitHub Actions/Jenkins等)、监控/可观测性 → 1分
|
||
|
||
两项可叠加,上限5分。不再要求必须IDE集成。`
|
||
},
|
||
{
|
||
name: 'Agent核心能力',
|
||
maxScore: 25,
|
||
content: `4项硬性门槛条件 + 5项评分要素。
|
||
|
||
门槛条件(二进制判定,缺任意1个→整个维度0分):
|
||
所有条件必须从代码中提取具体证据,不接受AI感觉判断:
|
||
1) 调用了外部LLM/推理引擎 — 代码中存在对LLM API的调用(openai/deepseek/fetch LLM endpoint),或通过框架抽象调用(LangChain ChatOpenAI / AutoGen LLM config)
|
||
2) 有明确的工具选择策略 — 存在if-else/switch/map路由逻辑,根据条件选择不同工具执行。无条件分支的直接调用→不通过
|
||
3) 存在错误→重试→切换路径 — 存在try-catch+retry loop/fallback handler/降级路径
|
||
4) 有跨步骤的状态持久化 — 存在上下文对象传递、DB写状态、session存储、消息历史维护中的至少一种
|
||
|
||
评分要素:
|
||
- Agent存在性(4分):满足4个门槛条件→4分,缺任意1个→整个维度0分
|
||
- 工具调用能力(6分):静态if-else工具选择→3分;动态prompt决策/多工具编排→6分
|
||
- 自主规划能力(6分):有任务分解(script/model/Agent call)→3分;递归/动态重规划→6分
|
||
- 协作机制(5分):多Agent通信(消息总线/共享memory)→3分;自主任务分配/协商→5分
|
||
- 可靠性(4分):retry+timeout→2分;fallback+降级策略→4分
|
||
|
||
所有评分必须引用具体代码文件+行号`
|
||
},
|
||
{
|
||
name: '实现完整度与稳定性',
|
||
maxScore: 20,
|
||
content: `构建测试 + 启动验证 + 运行时测试 + 异常耐受。
|
||
|
||
可构建(5分):
|
||
- 构建配置完整(package.json/pom.xml/Makefile等)
|
||
- tryBuild()实际构建成功(跨平台工具链检测)
|
||
- 依赖声明完整(含lockfile加分)
|
||
|
||
可启动(6分):
|
||
- tryStart() HTTP探测成功启动
|
||
- 启动配置(scripts.start/Dockerfile等)完善
|
||
- 服务在合理时间内就绪(超时30秒)
|
||
|
||
核心机能(6分):
|
||
- Web项目:tryBrowse() Puppeteer自动测试主要页面
|
||
- CLI项目:execSync运行并验证输出
|
||
- 页面可加载、无JS报错、无网络失败
|
||
- 核心交互可操作
|
||
|
||
异常耐受(3分):
|
||
- 错误处理机制(try-catch/错误中间件)
|
||
- 边界输入处理
|
||
- 降级/熔断机制
|
||
|
||
tryBuild失败或缺少构建配置→5分以下`
|
||
},
|
||
{
|
||
name: '规模与功能点',
|
||
maxScore: 20,
|
||
content: `3因子加权,功能点从代码提取,必须有测试托底。
|
||
|
||
A. 代码规模×功能密度(10分)
|
||
规模分档:<500行→基础3分 | 500-2000行→基础6分 | 2000-5000行→基础8分 | >5000行→基础10分
|
||
density系数:density<0.01→×0.5(样板代码多) | 0.01-0.03→×0.8(正常范围) | >0.03→×1.0(精悍)
|
||
density=函数定义数/总行数(从代码grep提取function/def/=>/fn等)
|
||
|
||
举例:5000行样板→10×0.5=5分。500行精悍→3×1.0=3分。2000行高密度→8×1.0=8分。
|
||
|
||
B. 功能点质量与可追溯性(5分)
|
||
核心规则:功能点必须由AI从代码提取(路由注册/API端点/事件处理/CLI命令),不接受申报式清单。
|
||
- 功能点必须有test/test case对应(无测试托底不计入)
|
||
- 0个可追溯功能点→0分 | 1-3个→2分 | 4-6个→3分 | 7+个→5分
|
||
|
||
C. 业务复杂度(5分)
|
||
- 单模块/单功能→1分
|
||
- 多模块协作→3分
|
||
- 跨系统/跨语言/复杂数据流→5分`
|
||
},
|
||
{
|
||
name: '代码规范性',
|
||
maxScore: 10,
|
||
content: `4层递进检测。
|
||
|
||
L0—工具实证(3分):
|
||
- 存在Linter配置(.eslintrc/ruff.toml/.pylintrc等)且实际启用→2分
|
||
- 运行Linter后零错误→再加1分(工具链不可用时跳过不扣分)
|
||
|
||
L1—一致性分析(3分):
|
||
- 跨文件命名风格统一(camelCase/PascalCase/snake_case一致性)
|
||
- 导入/导出模式一致
|
||
- 错误处理模式统一
|
||
|
||
L2—代码Review证据(2分):
|
||
- AI日志/PR记录中有代码评审环节
|
||
- 前后端/模块间有互审证据
|
||
|
||
L3—LLM特有检查(2分):
|
||
- 无提示注入回传风险
|
||
- 无幻觉API调用(调用了不存在的库/函数)
|
||
- 无AI同模式重复代码(大量结构相同仅参数不同的重复代码)
|
||
|
||
无Linter配置且命名不一致→0分`
|
||
},
|
||
{
|
||
name: '演示与文档',
|
||
maxScore: 10,
|
||
content: `存在性+闭环验证。每个文档类别2个子检查。
|
||
|
||
README:存在(0.5分)+ 启动方式描述与实际构建配置一致(0.5分)
|
||
设计书/架构:存在(0.5分)+ 提及的模块/目录在代码库中存在(0.5分)
|
||
测试用例:存在(0.5分)+ 列出的测试场景与实际测试代码对得上(0.5分)
|
||
测试报告:存在(0.5分)+ 报告数据(通过数/覆盖率)可追溯(0.5分)
|
||
需求分析:存在(0.5分)+ 需求点与实现功能对应(0.5分)
|
||
|
||
特殊情况:
|
||
- 有启动脚本但README说没启动方式→不扣分
|
||
- README说用Docker启动但无Dockerfile→闭环不通过,该类扣0.5分
|
||
- 五大类全部缺失→0分
|
||
- 含演示视频/录屏→加1分(上限10分)`
|
||
},
|
||
{
|
||
name: 'AI使用日志',
|
||
maxScore: 5,
|
||
content: `文件发现+AI真实性判断。
|
||
|
||
discoverFiles扩展匹配:包含agent/ai-log/claude/日志/開発記録的文件,不限路径。
|
||
|
||
评分:
|
||
- 无任何AI日志→0分
|
||
- 有日志但覆盖不完整(缺阶段/缺提示词记录)→1-3分
|
||
- 日志覆盖需求→设计→编码→测试各阶段,且带有工具和提示词记录→4分
|
||
- 多份日志交叉验证无矛盾,真实反映开发过程→5分
|
||
|
||
多份日志自动交叉验证:日志必须引用git commit hash或PR number,AI自动交叉验证git log与日志时间线。时间点匹配率<70%降分。`
|
||
},
|
||
{
|
||
name: '效果与数据',
|
||
maxScore: 20,
|
||
content: `3项核心检查+测试覆盖补充。
|
||
|
||
核心检查(15分,各5分):
|
||
①覆盖广度(5分):所有核心功能点都有对应测试。测试类型跟项目特性匹配(CLI项目不需要UI测试,不扣分)。交叉验证:功能点清单↔测试文件名/test case名
|
||
②断言实质性(5分):是真断言(assertEqual/expect/assertThat),不是空壳。过滤expect(true).toBe(true)、空test→无效测试。测试独立,不依赖其他测试执行顺序
|
||
③边界覆盖(5分):异常/空值/边界条件测试存在,不只是happy path
|
||
|
||
补充(5分):
|
||
④测试体系完整性(3分):单元测试+集成测试+功能/E2E等多个层次覆盖。AI生成测试的代码风格与手写不一致→合理,不扣分
|
||
⑤结果真实性(2分):测试通过率数据可复现(与tryBuild中npm test结果对比)。无伪造测试数据
|
||
|
||
完全无测试→0分`
|
||
},
|
||
{
|
||
name: '安全性',
|
||
maxScore: 10,
|
||
content: `源代码扫描。根据项目实际安全需求评估,存在明确安全风险但无对应防护才扣分。
|
||
|
||
Prompt注入防护(3分):用户输入是否sanitize、system prompt是否隔离、边界检查
|
||
密钥/凭据管理(3分):API Key/token是否硬编码、是否用环境变量/密钥管理服务
|
||
工具调用安全(2分):Agent命令执行是否有沙箱、文件读写路径校验、网络请求白名单
|
||
数据安全(2分):数据脱敏、日志是否泄露敏感信息、权限控制
|
||
|
||
无风险场景(纯CLI无网络/无输入)→标注N/A,该维度不纳入总分基数,总分相应调整为140。`
|
||
}
|
||
];
|
||
|
||
// Build the markdown content
|
||
const content = dims.map(d =>
|
||
`## ${d.name}(${d.maxScore}分)\n${d.content}`
|
||
).join('\n\n');
|
||
|
||
// Update 赛道一 and 默认标准
|
||
const ids = [
|
||
'996fa0b9-13d3-4f2f-ab32-7ce1aba14723', // 赛道一
|
||
'48e1344e-9ae5-4a74-b7c9-f22cd0a4c1d4', // 默认标准
|
||
];
|
||
|
||
for (const id of ids) {
|
||
const old = db.prepare('SELECT name, content FROM standards WHERE id = ?').get(id);
|
||
if (!old) { console.log('Not found:', id); continue; }
|
||
|
||
db.prepare(`UPDATE standards SET content = ?, updated_at = datetime('now') WHERE id = ?`).run(content, id);
|
||
console.log(`Updated: ${old.name}`);
|
||
}
|
||
|
||
// Verify
|
||
const results = db.prepare('SELECT id, name, substr(content, 1, 50) as preview FROM standards WHERE id IN (?, ?)').all(...ids);
|
||
for (const r of results) {
|
||
const parsed = require('./src/routes/standards').parseDimensions(
|
||
db.prepare('SELECT content FROM standards WHERE id = ?').get(r.id).content
|
||
);
|
||
console.log(`\n${r.name}: ${parsed.length} dimensions`);
|
||
parsed.forEach(d => console.log(` ${d.name} (${d.maxScore}分)`));
|
||
|
||
const total = parsed.reduce((s, d) => s + d.maxScore, 0);
|
||
if (total !== 150) console.log(` ⚠️ 总分${total},不等于150`);
|
||
else console.log(' ✅ 总分150');
|
||
}
|
||
|
||
db.close();
|