为什么不让大模型给自己打分:CodePilot 的评分引擎与不可信输入边界
同一份代码多次审计分数会变,所以我把「找问题」和「算分数」拆开:LLM 只输出结构化 Finding,总分由确定性评分引擎按维度权重计算,并给不可信输入划出明确边界。
- AI
- LLM
- 评分
- Prompt 注入
CodePilot 是一个面向学生与初级开发者的「AI 工程能力提升平台」:导入真实代码项目后,走扫描 → 12 维度 AI 工程审计 → 改进任务 → Git 代码评审 → 模拟面试 → 能力画像这样一条闭环。
做这个平台时我给自己定了一条硬规则:评分必须可审计。下面两个决定都是从这条规则推出来的;事实与测量方式来自项目记录,超出记录的解释会标注为「分析」。
问题:同一份代码,两次审计分数不一样
最初的实现是让 LLM 直接给总分。结果是:同一份代码多次审计,分数会漂移 —— 不可复现,也无法解释「这个分数从哪来」。
方案:我把「找问题」和「算分数」拆成两层
- LLM 负责找问题:只输出结构化的 Finding(问题 + 位置 + 依据)。
- 评分引擎负责算分:12 维度总分由确定性引擎按维度权重计算,不依赖模型自报分数。
我选这条路的理由是可审计、可复现;它也有明确代价 —— 评分引擎与维度权重需要自己维护,而不是直接采用模型判断。这笔交换值得:模型擅长的是语义理解,不是给自己当裁判。
一个直接后果:能力画像也不再靠模型打分
画像由审计、任务、Review、面试产生的真实记录汇聚而成。所以「改代码 → 完成任务 → 面试」之后分数会变化,而且变化可复现 —— 它不是一次性的模型评价,而是一条可追溯的证据链。
验证一:端到端闭环(用 mock provider 走真实代码路径)
| 环节 | 结果 | 测量方式 |
|---|---|---|
| 导入 → 审计 | 132 个文件 → 审计 65.5 分(12 维度) | mock provider 走真实代码路径(注册 → 导入 → 审计 → 任务 → Review → 面试) |
| 审计产出 | 12 条 Finding → 12 个改进任务 | 同上 |
| Review → 面试 → 画像 | 完成 1 个任务 + AI Review(pass) → 面试 90.8 分 → 画像 64.6 分 | 同上(证据链完整) |
验证二:真实模型链路也跑过
Mock 只是让测试零成本,不能替代真实链路。所以我还对 Demo 项目做了一次真实的 DeepSeek 审计:评分 33.8,12 个维度共 19 条真实 Finding,例如「API 层直接包含业务逻辑和 SQL 查询」和「空 except 吞异常」。
第二个问题:我把被分析的代码当成不可信输入
平台读取并分析用户上传的代码与仓库内容,而这些内容里可能包含试图改写系统指令的文本。如果把它们当成普通上下文送进 Prompt,模型的权限边界就由被分析的代码决定了 —— 这个前提我不能接受。
- Prompt 注入边界:用户代码与仓库内容不能改写系统 Prompt 与工具权限,并补测试覆盖。
- 上传安全:ZIP 路径穿越、ZIP 炸弹、大小限制校验。
- Git 操作安全:参数白名单 —— commit hash 仅允许十六进制。
- 多租户隔离:所有资源按 owner 校验,越权统一返回 404 —— 不用错误码泄露资源是否存在。
验证三:代码评审能不能真的查出问题
安全能力不能只看「写了什么」,要看「能不能查出来」。所以我做了一次反向验证:向真实 Git 仓库引入硬编码密码与 SQL 字符串拼接 → Review 报出 2 个高危 → 修复后复检 0 问题。这条链路现在是我判断「评审是否真的有效」的基准。
长任务:状态要看得见
导入与审计耗时较长,放在请求里同步执行会阻塞接口,失败后也看不到卡在哪一步。这里的处理是 Job 表 + 线程 Worker + `request_id` / `job_id` 双追踪,前端轮询状态:请求快速返回,任务状态落库可查。
诚实边界(我自己写进结果的)
- 回归在 SQLite 上完成:本机 PostgreSQL 受安全软件限制,无法在本地完整跑通全部回归;因此做 PostgreSQL / SQLite 同构支持,同时保留 PostgreSQL 部署路径。
- 限流是进程内实现:多实例部署需要换成集中式限流。
- 演示视频待补。
我要求自己把「哪一部分没有在目标环境上验证过」写进结果,而不是含糊带过 —— 这比声称一切完备更可信,也让下一个接手的人知道风险在哪里。
复盘
- 我不让模型给自己打分:把「找问题」与「算分数」拆开后,结果才可复现,也才敢用在需要解释的场景里。
- 不可信输入要显式划边界:边界写进系统约束并用测试守住,而不是依赖模型自觉。
- 环境限制要如实记录:写清楚「什么没验证过」,比声称一切完备更有价值。
完整的平台架构(分层后端、16 张表、Job Worker、评分引擎与 Prompt 边界)与实测数据在项目页里:查看 CodePilot AI 项目详情。
韦坤计算机科学本科生 · 后端开发 / AI 应用开发方向
相关项目
导入真实代码项目后形成成长闭环:代码扫描 → 12 维度 AI 工程审计 → 改进任务 → Git 代码评审 → 模拟面试 → 能力画像。评分由确定性引擎计算,LLM 只负责找问题。
- Next.js 14(App Router)
- TypeScript
- Tailwind CSS
- 还有 23 项技术
相关文章
我为什么不相信 Agent 说「完成了」
AI / Agent约 4 分钟从分阶段实施到全项目回归检查:Agent 可以承担越来越多的执行工作,但「Agent 说完成了」不能自动等于「工程结果已经完成」。记录我如何把它的执行结果变成可验证的工程结果。
Agent 反复填同一个输入框:一个属性读取方式引起的静默循环
AI / Agent约 4 分钟WebRunner 里最难查的一个缺陷:观察层读的是 HTML 初始属性,动作改的却是运行时状态,于是模型永远看不到「已经填过」。以及它如何变成一条写进设计里的约束。