# AI-Review 评审系统 ## 目录 ``` ai-review/ ├── server/ # 后端 Express + TypeScript + better-sqlite3 ├── web/ # 前端 React + TypeScript + Vite ├── config/ # teams.json(14 支参赛队伍结构化数据,含 gittea 凭据与选题) ├── docs/ # 文档(评审标准模板、user-stories.md 用户故事) ├── docs/design/ # 设计书(01-系统 / 02-API / 03-后台 / 04-前端) └── AGENTS.md # 本文件 ``` ## 启动方式 ```bash # 后端(端口 3002) cd server npx tsc # 必须先编译(不能直接跑 ts) node dist/index.js # 前端(端口 14001) cd web npx vite --host 0.0.0.0 --port 14001 # 后端测试(vitest,在 server/ 下运行) cd server && npm test ``` ## 关键配置 | 项 | 值 | 位置 | |---|---|---| | 后端端口 | 3002 | `server/src/config.ts` | | 前端端口 | 14001 | `web/vite.config.ts` | | 登录密码 | `620f4c96` | `server/.env` | | DeepSeek API | `api.deepseek.com` | `server/src/services/review.service.ts` | | MAX_CONCURRENT | 3 | `review.service.ts` | | DB 文件 | `server/data/ai-review.db` | `server/src/db.ts` | ## 核心架构 ### 评审管线(3 阶段) ``` Phase 1: 概览(1 次 AI 调用) Phase 2: N 子 Agent 并行评审(按标准维度数,concurrency=3) Phase 3: 确定性校准(computeCalibration) + 硬规则引擎 ``` ### 核心文件 | 文件 | 职责 | |------|------| | `review.service.ts` (~1500行) | 评审引擎:clone→tryBuild→tryBrowse→AI→校准(computeCalibration)→硬规则→出分 | | `standards.ts` | `parseDimensions` 解析标准 MD 为维度列表 | | `l2-topics.ts` | L2考核选题元数据(11命题题+自选题,`config/l2-topics.json`):难度赋分 cap、功能完整性拆分、验收要点注入 | | `l2-participants.ts` | L2受验者注册表(`config/l2-participants.json`):员工编号↔Gitea账号↔仓库映射,自动生成拉取 URL;拉取认证走全局评审账号只读协作者权限 | | `code-inventory.ts` | 全量符号索引(评审真实性改进 2026-08-26):对所有文本文件提取 path/lines/symbols,注入实现类维度让 AI 看见 100% 文件清单(接口:`extractSignatures` + `renderInventoryText`,无 coreFiles 精读包——精读由 `filterFilesForDim` 维度过滤承担,2026-08-27 文档对齐) | | `code-signals.ts` | 代码信号检测器:TODO 密度/空壳率/硬编码返回/死导入——确定性线索注入实现类维度 prompt,定位为线索而非判据 | | `ai-log-audit.ts` | AI 日志确定性审计:占位率 / git 一致率 / 覆盖广度;占位>50%→维度≤30%、git一致<30%→≤20% 封顶 | | `measurement-audit.ts` | 测量协议检查(P2,2026-08-27):确定性检查 `data/measurement/` 齐备性(baseline/README/timing-log),注入效果类维度 prompt | | `accept-runner.ts` | 验收命令执行器(P2,2026-08-27):解析 README `## 验收` 命令块并真实执行,注入实现类维度;测试环境 dry-run 不实跑 | | `entries.ts` | 条目 CRUD + 触发评审 + PDF 导出 | | `projects.ts` | 项目 CRUD + 汇总排名 | | `db.ts` | SQLite 初始化 + migrations(ALTER TABLE try/catch) | | `config.ts` | 端口/密码/DeepSeek key | ### 关键流程 ``` cloneRepo → discoverFiles → countCodeStats → tryBuild → tryBrowse/tryStart → 概览(精简context) → N子Agent(content+fileBlock) → 校准(computeCalibration) → 硬规则 → 总分(rawScore) → 迟交扣分 → finalScore → review_snapshots ``` ## 关键事实(修改前必读) ### 编译与重启 - TS 改动后必须 `cd server && npx tsc`,不能只改 .ts 不编译 - `server/dist/` 编译输出和 `server/src/` 分离 - 启动:必须用 `node dist/index.js`(不能 `tsx watch`,那需要 dev 模式) - 服务器崩溃后启动会自动恢复卡死的 entry(状态重置为 pending) ### tryBuild - 支持 7 种构建系统:npm/pom.xml/build.gradle/makefile/cargo/go/pyproject - Python build 命令是 `python -m build --wheel --no-isolation`(不是 `pip install -e .`) - `buildRootMap[file] === undefined` 判断是否存在(不是 falsy,根目录文件 relDir="") - `canBuild` 过滤 install 步骤:`!command.startsWith('npm install')` 和 `!command.startsWith('pip install')` ### tryBrowse - 用 `puppeteer-core` + 自动检测 Chrome/Edge 路径(不自带 Chromium) - `waitUntil: 'domcontentloaded'`(不是 `networkidle0`,对 API 服务太严格) - `service_url` 提供时跳过 tryStart,直接 browse 该 URL - **看门狗**:整体 45s 硬超时(BROWSE_WATCHDOG_MS),Chrome 启动/加载/关闭任一环节挂住也会被强制 kill 并降级为"跳过浏览器测试",不会卡死评审管线 - **评审期二次 SSRF 校验**(`revalidateHost`):打开 URL 前重新 DNS 解析域名,若已变为内网地址(重绑定攻击)则拦截并跳过浏览器测试;仅 `config.ssrfDnsCheck` 开启时生效 ### 维度评审(runSubAgent) - 评审依据优先级:**标准快照 `dim.content` 优先且唯一**;内置 `dimGuidelines` 仅当 content 为空时兜底(并标注"内置兜底,仅供参考")。不要两套规则同时注入,否则 AI 会困惑 - `dimGuidelines` 是硬编码指南(key:场景价值/架构设计/工具使用/实现完整/开发范式/Agent核心/规模/代码规范/演示与文档/AI使用日志/效果与数据等),分值小计可能≠maxScore,仅兜底用 - `DIM_FILE_FILTERS` 按维度过滤文件(如代码规范只给源码,演示文档只给 .md) - `filterFilesForDim` 输出时给文档文件标注 `(文档/说明文件,非代码)`,防止 AI 把 README/CLAUDE.md 内容当作代码问题上报 - `fileBlock` 截断:普通维度 15000 字,构建维度 40000 字 - `DIM_FILE_FILTERS` 的 `'AI使用日志'` 正则需同时覆盖 `ai_log`/`ai_usage`/`usage_log`(如 `_AI_USAGE_LOG.md`),否则该文件被过滤、AI 判"未发现日志"(2026-08-18 实测修复) - `extraContext` 只对构建维度(实现完整度)附加构建步骤详情 - `projectContext` 包含服务状态行:`参赛者服务地址: xxx(可正常访问/无法访问)` ### 确定性证据(方案一 / 方案二,2026-08-07 新增) - **方案一 `evidence-detect.ts`**:Agent核心能力 4 项硬门槛由代码模式匹配做**确定性判定**(LLM调用/工具选择策略/错误重试降级/状态持久化),AI 不再判门槛、只做 5 项评分要素。检测结果(文件:行号)注入 Agent核心维度 prompt,含 `allPassed` 结论 - **方案二 `test-runner.ts`**:`tryTest` 在构建可用的前提下真跑测试。支持多框架输出解析——pytest/jest/go test -v/surefire(Maven)/Gradle tests completed/Cargo test result;覆盖率解析含 pytest-cov/jest/istanbul/go cover/jacoco。go test 自动加 `-v -cover`。**软证据**——成功才注入真实通过率/覆盖率到"效果与数据"维度;环境失败/工具缺失一律**中性不扣分**(不证明项目差) - **tryTest 与构建完全解耦**(2026-08-13):无条件跑测试,不依赖 `buildResult.canBuild`。构建失败 ≠ 测试不可跑(cobol-java 的 build-backend 写错打不了包,但 pytest 能真跑 33/42)。`runTest` 完整保留输出供解析——**汇总行在输出尾部,截断到 3000 字会丢 passed/coverage 汇总**(曾导致 testsPassed=0、覆盖率 null) - **维度独立原则**(`review.service.ts` runSubAgent 严格规则):每个维度独立评分,其他维度的判定(如 Agent核心门槛是否通过、项目是否为 Agent 应用)**不构成扣分依据**——"效果与数据"评估测试覆盖/覆盖率/可复现性,即使非 Agent 项目,测试真实存在且通过就应据实给分 - **确定性测试证据强绑定**:tryTest 真跑成功时 `testEvidenceToPrompt` 注入"确定性证据,评分必须据此",AI 不得忽略或低估真实通过率/覆盖率(实测生效:calc 项目 Agent核心 0/25 但效果与数据 15/20 正常给分;cobol-java 效果与数据 0/20→6/20,AI 引用"42个用例33通过") - **Agent核心检测置信度**:`buildAgentGateReport` 按命中数标注置信度——0/低(1)/中(2-3)/高(≥4);低置信度通过项注入提示"可能误匹配,可在评分要素中酌情下调,但不得推翻门槛判定" - 阈值常量在 `evidence-detect.ts`:MAX_HITS=5;`test-runner.ts`:TEST_TIMEOUT=180s ### 校准(Phase 3b,确定性) - `computeCalibration`(`standard-utils.ts`)由代码计算,**不信任 LLM 的 delta 数值** - LLM 只输出跨维度语义矛盾的方向(over/under),代码定调幅:L1 矛盾±2、L2 σ异常(偏离>2σ)±4、L3 最不稳定维度(Agent核心/规模·功能点/效果与数据)高估×0.8 - 调幅常量在 `review-constants.ts`:CAL_ANOMALY_STDDEV=2.0 / CAL_L2_LIMIT=4 / CAL_L1_LIMIT=2 / CAL_UNSTABLE_WEIGHT=0.8 - 每个实际改动写入 `calibrationExplanation`(格式:`校准执行:\n- 维度: 旧分→新分(L1/L2/L3)`),可审计 - 老的 `applyCalibration`(LLM-delta)已删除,不要引用 ### 代码健康度(countCodeStats) - 返回 CodeStats:fileCount/totalLines/effectiveLines/blankLines/commentLines/duplicateRatio/dirDepth/tinyFiles - `duplicateRatio` 用 MD5 哈希文件内容检测 - `dirDepth.avg` 追踪目录嵌套深度 - 结果注入 `projectContext` 供 AI 参考 ### 硬规则(Phase 3c,校准后执行) - 构建失败→实现完整度≤4/12,效果与数据≤3/10 - pytest 失败→效果与数据≤5/10 - 重复代码>50%→代码规范≤3/5 - 无根目录 README→演示与文档≤2/5 - 日志写入 calibrationExplanation ### 评分 - 校准 delta 用 `Math.round()` 取整(避免 52.400000000000006) - 总分 = `Math.round(每个维度分数)` 累加 - `finalScore` = `totalScore - 迟交扣分`,上限 `max_score_cap` - 迟交判定(2026-08-15 增强):`resolveSubmitTime` 解析提交时间——优先 git 最后 commit 时间;commit 缺失或早于条目创建时间(空仓库/提前 clone 旧代码/无 .git)→ 用条目创建时间兜底避免逃逸;两者都无效才用评审时刻。然后 `computeLateDays` 对比 `project.deadline` ### 评审可信度(2026-08-19) - **排名用多次聚合**:`aggregateScores`/`aggregateEntryScores`(standard-utils.ts)——最近 N 次(默认3)`review_snapshots.score` 中位数;N=2 平均、N=1 单次。聚合前提=各快照 `standard_snapshot` 一致。`<3 次标"初评(未达聚合样本)"`,排名区分正式/初评 - **快照分数列**:`review_snapshots.score` 存含迟交扣分的 final_score(写快照时一并存,不解析 ai_report——它只有 totalScore)。历史快照 backfill 从 totalScore best-effort - **可验证能力三档**(`classifyVerifiability`,效果/提效类维度,校准之前判档):A=基准证据(`entries.benchmark_json` status=done);B=测试通过或覆盖率非 null;C=数据缺位→封顶 maxScore*0.3 + note"数据缺位(未证明),非无效"。**构建成功≠效果可验证**。C 档 note 渲染到前端维度表 + PDF。**纯增益维度严格制(2026-08-26)**:`提效幅度/效果对比/效率提升` 类维度(isPureGainDim)测试通过**不构成**提效证据——无基线对比数据一律 C 档封顶(实测案例:六边形战队提效幅度无量化数据 raw=6,修复后同类场景 C≤3)。**定性设计维度豁免(2026-08-26)**:`提效设计合理性/XX清晰度`(isQualitativeDesignDim)考察设计思路而非量化结果,不参与 C 档封顶——避免测试环境因素跨队伍不公平(净码特攻案例) - **基准证据按 entry 落库**(`entries.benchmark_json`,非 env 变量——MAX_CONCURRENT=3 并发会串数据) - **确定性 L1**(`detectStructuralContradictions`):仅证据性矛盾触发(有测试/基准证据但效果≈0 → under;效果高分+实现全低 → over)。**效果维度 under 一律丢弃**(computeCalibration 内过滤)——效果维度只降不升,诚实由三档封顶负责。禁止"实现高分+无数据"当 under - **overall 中性边界**(`neutralizeTestEvidence`):测试 summary 含"中性"→ 标 `[中性证据]`;不含("未检测到测试框架配置"=真缺测试)→ 真实弱点。synthesizeOverall prompt 禁止把 `[中性证据]` 列为不足 - **视频 URL 弱证据**:`detectDemoVideo` 扫根目录 README + 根级 docs/*.md 的视频链接,source='url'(外部链接未核验)vs 'file'(强证据优先) - **维度级聚合**:详情/PDF 维度表用 `averageDimensions` 跨快照聚合(entries.ts GET /:entryId 返回 dimsAgg),展示"历次分差" - **决赛圈基准框架**:`benchmark.ts` `runBenchmark(dir, seeds, detect)`,检出率与基线分开呈现。seed 库赛前生成不公开(Goodhart 已知上限) - **人机标定**:`docs/design/06-人机标定方案.md`——绝对准确未验证前,分数用于排名(相对序)可信,绝对解读需标定偏差基线 ### parseDimensions - 正则在 `standards.ts`,修复后支持空内容(`content: ""`) - 从 `## 维度名(分数)` 解析,必须紧跟 `\n## ` 或字符串结束 - 过滤分区/说明性标题:`评审维度`、`合格判定`、`成果物清单`、`第X部分:` 等不进入维度列表 - group 推断:`## [Q2] xxx`(显式)或 `## 2-A. xxx` / `## 2-A:xxx`(题目追加维度前缀)→ group=Q2;其余 common - 验证:标准模板解析结果应固定为——赛道一 12维/150、赛道二 8维/100、L2考核 7维/100(全 common);人才测评已整合进 L2考核(2026-08-23),不再单独验证 ### entries 表 - `UNIQUE(project_id, repo_url)` 约束 - `service_url TEXT DEFAULT ''`(migration 添加) - `feature_inventory TEXT DEFAULT ''`(2026-08-27,migration 添加):全量功能发现轮(Map-Reduce)结果 JSON 数组,供详情页展示与跨快照复用;重评时覆盖 - `ai_report.dimensions[n].checks`:实现类维度子 Agent 返回的定向追踪核对表(feature/entry/depth/evidence/reason),由 `parseDimResponse` 解析透传(2026-08-27 修正),前端维度表展示,缺失回退现状不崩 - `build_status TEXT DEFAULT ''`(2026-08-18,migration 添加):赛道二/L2考核单阶段人工构建确认,''=未确认(自动构建) / done / failed;赛道一 B 阶段不存此列,走 /verify 请求体 - `standard_snapshot` 存标准快照(评审时标准被修改也不影响已评审结果) - `review_snapshots` 存每次评审历史 - L2考核专属字段:`selected_topic`(选题 01~11/self,决定 max_score_cap 与难度赋分)、`self_registration`(自选题登记 JSON:登记编号+功能清单快照) - force-review(测试端点)需 `ADMIN_TEST_TOKEN=true` **且** `NODE_ENV=test` 双条件才开启;生产 `node dist/index.js` 即使 flag 泄漏也打不开 - **赛道必选(2026-08-13)**:创建/编辑项目必须传 track(赛道一/赛道二/L2考核),缺省返回 400 `赛道为必选项`;前端下拉首项"请选择赛道(必选)",create() 校验 `if (!track) setError('请选择赛道')`。注意:有赛道会自动导入对应默认标准(`projects.ts` POST 里 `loadDefaultStandard`)——创建项目的测试用例必须带合法 track,否则建出的项目无赛道且后续标准解析行为不同。**e2e 陷阱**:依赖"自定义标准快照"的用例(如 `hardcode-fixes.spec.ts` 3.1/3.2)在带 track 创建项目后,自动标准会抢占 `resolveStandard` 匹配,导致条目快照不是测试上传的标准——需先调用 `apiClearStandards(request, token, pid)` 清掉自动标准再上传自定义标准 ### 本地评审样本 - `server/data/clone/_real_cobol_java/`:真实仓库(cobol-java-v3,COBOL→Java 测试生成工具)的本地副本,作真实评审冒烟对象 - 用它跑过 6 次真实 DeepSeek 评审:30(旧校准)→52(确定性门槛)→58→67(效果与数据 0→6,tryTest 解耦构建后)→55(第 5 次评审,校准 anomalies 触发的自然波动)。数据在 `data/e2e-usertest.db` 的 review_snapshots(该项目 track=赛道一,12 维标准) - **注意:评审结束会删除 clone 目录**(`executeReview` 末尾 `fs.rmSync(dir)`),只留 review_snapshots;若需现场调试 clone 内容,评审前复制一份出来 ### 管线诊断日志(`[pipe:entryId]`) - `pipeLog(entryId, phase, msg, durMs?)` 只写服务端 console(不进 progress_log,不污染前端) - 覆盖阶段:START / CLONE / ANALYZE(含 canBuild·untested)/ GATES / TEST(command·pass/fail·coverage·summary,**这是"证据静默丢失"类问题的 debug 入口**)/ BROWSE(serviceUrl·pageLoaded)/ OVERVIEW / SUBAGENT(12 个 DIM 各带耗时)/ **OVERALL**(整体评价合成,pos/hl/wk,失败打印 failed)/ DONE(score·penalty·final·总耗时)/ **FAIL**(`runReview` catch 兜底,任何阶段抛错都会有 `[pipe:xxx] FAIL [耗时ms]`,不会再静默卡 status=failed) - 实测 cobol 第 5 次评审:ANALYZE 24s(tryBuild 跑 python 构建超时)、TEST 10s(`python -m pytest` 33/42 pass、coverage null)、DIM 每维度 4.6~24.7s、全程 114s ### 整体评价合成(方案A,2026-08-19) - `synthesizeOverall`(review.service.ts):校准+硬规则之后,+1 次 LLM 调用(约 15-30s),把 overview+维度得分评语+确定性证据合成**点评式**整体评价,写入 `ai_report.overall`(JSON:highlights[{point,review}]/weaknesses[{point,review}]/verdict) - **项目总览(overview)负责中立描述,overall 只做点评**:每条亮点/不足都带判断(价值/影响/严重度),不重复定位 - 输入全是真实证据,prompt 显式"禁止编造";失败非致命(overall=null,不影响评分) - 兼容旧格式(字符串数组 → point,review 空) - 落点:赛道一 B 尾(executeReviewB)与赛道二单阶段尾(executeReview)各一次;A 阶段不合成 - 展示:前端条目详情"整体评价"段(亮点点评绿/不足点评红/总评,ProjectView.tsx)+ PDF 报告块(pdf.service.ts) - 纯函数 `parseOverallResponse` 负责 JSON 解析/代码块剥离/裁剪(overall.test.ts 单测 7 用例) ## 已知坑 1. **Chrome 崩溃导致服务器卡死(已缓解)** — tryBrowse 有整体 45s 看门狗(BROWSE_WATCHDOG_MS),挂住会强制 kill Chrome 并降级"跳过浏览器测试",但仍建议留意 browse 期间系统资源占用 2. **多人提交排队** — MAX_CONCURRENT=3,第 4 个 entry 起入队列排队等空位(`queue[]` + `processQueue`) 3. **AI 从 docs 编造代码问题(已缓解)** — fileBlock 中文档文件已标注 `(文档/说明文件,非代码)`,但 AI 仍可能把标准模板内容误当代码问题,若再出现可在 prompt 强化 4. **tryBrowse SSRF 风险(已缓解)** — service_url 保存时校验 + 评审期 `revalidateHost` 二次 DNS 解析(重绑定拦截,仅 `config.ssrfDnsCheck` 开启时生效),仍建议沙箱 5. **review.service.ts 1060 行** — 单文件过大,改动前必须理解整个 pipeline 6. **difficulty 字段已移除** — 不要搜或引用 difficulty(前端已改为"赛道"下拉) 7. **本地 file:// 仓库 URL 格式** — 必须用 `file://D:/...`(两斜杠);`file:///D:/...`(三斜杠)会被 `path.resolve` 解析成 `D:\D:\...` 导致白名单拒绝(2026-08-07 实测) 8. **测试数据会污染"真实数据"判断** — 库里大量 `选手X/小明作品/k4-entry` 是 e2e 造的假条目;判断真实评审数据要看 `repo_url`(真实 https/本地副本)而非条目名 ## 测试 ```bash # 后端单元测试(vitest) cd server && npm test # 特定测试文件 cd server && npm test -- src/__tests__/api.test.ts # 用户故事驱动验收(docs/user-stories.md,纯函数级,不调 AI,20 用例) cd server && npm test -- src/__tests__/user-stories.test.ts # E2E(需前后端都启动) # web/e2e 目录有 Playwright 测试 ## vitest 超时陷阱(2026-08-27 实测) - **vitest 默认测试超时 5000ms**,而触发完整评审(`/start` → A 阶段)的用例因功能发现轮(Map-Reduce,mock 环境 12 块串行 ×400ms)拖到 ~5s,**会撞默认 5s 超时**。凡 `waitA_done`/等待 A 阶段完成的用例必须显式加超时(`}, 30000)` 或更大),否则偶发 `Test timed out in 5000ms` - 现象:单跑通过、全量偶发失败,报错是 vitest 超时而非断言失败 ## E2E 运行陷阱(2026-08-14 实测) - **整套 full-e2e 需 15+ 分钟**,单个 describe 单独跑更快(评审标准 7、条目管理 10、批量/详情/汇总/异常/UI 27、完整流程 1 = 45 个测试)。整套跑超时是正常现象,不是 bug - **孤儿 tsx server 会卡死所有 DB 请求**:多次中断 e2e 会残留多组 `tsx src/index.ts` 进程同时打开 `data/ai-review.db`,better-sqlite3 WAL 锁冲突导致 login/beforeAll 全部挂起 90s。症状:health 慢、login 超时、beforeAll timeout。排查:`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | where CommandLine -like "*tsx*src/index.ts*"`,全杀后重跑 - **`apiClearStandards` 的 BASE 必须带 `/api`**(`http://localhost:3002/api`),漏掉会打到 `/projects/:id/standards`(无路由)返回 404 HTML,`list.json()` 抛 `SyntaxError: Unexpected token '<'` - **补 track 后项目头部和表格赛道列都会渲染 `赛道一`**,原 `.badge` 选择器断言会多命中——用 `.entry-table .badge` 限定,且状态文案是中文(`待评审` 而非 `pending`,见 `ProjectView.tsx` statusBadge) ``` ## 数据库操作 ```bash # 手动查 SQLite cd server && node -e "const D=require('better-sqlite3');const d=new D('data/ai-review.db');console.log(d.prepare('SELECT name FROM sqlite_master WHERE type=\"table\"').all())" ``` ## 评审标准格式 ```markdown ## 维度名(满分X分) 内容描述... ## 下一个维度(满分Y分) 内容描述... ``` 标准 MD 必须至少有一个 `## 维度名(分数)` 格式的标题。 ### 内置标准模板(由项目管理员上传) **赛道一(Agent开发实战赛):** 场景价值15、开发范式与架构设计25、工具使用10、实现完整度15、规模·功能点·技术难度10、演示与文档5、AI使用日志10、效果评估与数据10 **赛道二(IDE+开发范式创新赛):** 场景价值、开发范式、工具使用、实现完整度、规模·功能点、演示与文档、AI使用日志、效果评估与数据(总分100) **L2考核(AI人才育成认证,7维/100):** 功能完整性30、设计文档10、测试用例与测试结果10、AI协作过程记录15、技术选型与范式运用15、代码质量+README 10、业务场景理解与需求分析10。选题难度赋分:★★+0/★★★+5/★★★★+10,封顶选题 cap(100/105/110)。合格线≥60 且 功能完整性≥15(地板线)。 当前维度 guideline 只覆盖标准维度名(如"场景价值与合理性"),赛道一变体名(如"开发范式与架构设计")需扩展匹配关键词。L2考核 7 维标准自带分档锚点与交叉验证规则,content 优先不触发内置兜底。