AI 评审最怕的不是漏报,而是审完以后代码已经变了

你让 Agent 审一个未提交的改动。它读了十几个文件,过了一会儿给出一个看起来很完整的报告。

这时你顺手又改了两行代码。

报告还能用吗?

很多代码评审工具默认把答案当成一张静态截图:开始时拿到 diff,结束时输出 finding。可工作区不是截图。评审进行中,文件会变、分支会切、未跟踪文件会出现,甚至 HEAD 也可能移动。报告如果没有绑定它实际看过的目标,最后那句"第 8 行有问题"可能已经对应不到任何代码。

Blade Code v0.10.7 新增的 Session-native 只读 Code Review,把这个问题放到了运行时边界里处理。它的重点不是多一个 /review 命令,而是:评审先固定目标,目标变化就明确标记过期,无法证明位置对应时直接失败。

评审开始前,先给工作区做一张"指纹卡片"

packages/cli/src/services/GitReviewTargetService.ts 没有把目标简单写成一个路径。它先解析目标类型:

text 复制代码
/review uncommitted   当前 HEAD 到工作区的 staged、unstaged、untracked
/review base main     merge-base 到当前 HEAD 的变化
/review commit <sha>  某个 commit 引入的变化

然后把这些东西连续写进 SHA-256:

ts 复制代码
hash.update(`kind\0${request.kind}\0head\0${headSha}\0`);
hash.update(diff);
hash.update(`\0merge-base\0${mergeBase}`); // base review
hash.update(`\0commit\0${commitSha}`);    // commit review

未跟踪文件也不能漏掉。实现会把相对路径和文件内容写入同一个 digest,并为它们记录从第 1 行开始的 changed range。最后返回的 target 信息包含 headSha、文件数量和 digest,而不是只有一句"审当前目录"。

这张指纹卡片解决的是一个很具体的追责问题:当报告说"这个 finding 来自这次提交"时,系统至少知道它对应哪一个 commit 身份、哪一份 diff 和哪一批文件。

为什么一定要记录精确 changed line

只保存文件名还不够。一个文件里可能有 500 行,Agent 报告第 8 行的问题,必须证明第 8 行确实属于这次评审目标。

changedLinesFromDiff() 逐段解析 unified diff 的 hunk,维护旧行号和新行号,把新增、删除的行合并成连续范围。模型返回 finding 时,宿主会检查:

  • 路径属于 target;
  • 行号没有越界;
  • 行范围和真实 changed lines 有重叠;
  • priority、confidence 和结构化字段符合协议。

只要输出无法解析、引用了未改动的代码,整个 review 会 fail closed。这个选择有点严格,但它避免了一种很难排查的假精确:报告看上去指向 src/auth.ts:L8,实际上 Agent 读的是另一版文件。

Finding 不是一段自由文本,而是一个有边界的对象:

ts 复制代码
{
  title: "[P1] 命令式标题",
  body: "触发场景、影响和修复方向",
  priority: 1,
  confidenceScore: 0.99,
  codeLocation: {
    path: "src/auth.ts",
    lineStart: 8,
    lineEnd: 8
  }
}

这对读者的实际收益是,拿到报告后可以直接回到改动行处理,而不是重新猜 Agent 到底在说哪个版本。

评审跑着跑着,目标变了怎么办

最常见的现场是这样的:

sequenceDiagram participant W as 工作区 participant R as reviewer child Session participant S as 父 Session 事件流 W->>R: 固定 digest + changed lines R->>W: 只读检查 W->>W: 用户又改动文件 R->>S: review_completed(status=stale) S-->>用户: 这份报告不代表当前工作区

docs/reference/native-code-review.md 明确规定:评审运行期间 target 发生变化,结果标记为 stale。系统不把旧报告涂成绿色,也不自动把模型重新跑一遍来"补救"。

这是一条值得迁移到其他工具的判断规则:

评审结果要么绑定一个可复核的输入,要么公开承认输入已经失效。

很多工具只关注模型给出的结论,却没有把"结论对应哪一版代码"当成一等信息。实际协作中,后者往往更重要。

只读不是一句系统提示词

如果评审 Agent 可以写工作区,它就可能一边审、一边修,最后你分不清报告是针对原始改动,还是针对它自己改过的版本。

Blade 的内置 reviewer 只允许 Read、Glob、Grep 和分类后的只读 Bash。GitReviewTargetService 还会限制目标最多 500 个文件、diff 与未跟踪内容合计最多 8 MiB。reviewer 进入 workspace-read-only sandbox,网络关闭,HOME、Blade storage、provider credentials 不可读,Git 使用隔离配置。

这里有两个不同的边界:

text 复制代码
工具白名单    防止 reviewer 主动修改或外传
target digest  防止 reviewer 的结论脱离它实际看到的输入

只做第一层,Agent 可能安全地审了一份已经过期的代码;只做第二层,Agent 仍可能在审查过程中改变代码。两层需要一起存在。

为什么 review 生命周期要写进 Session

Blade 没有把评审状态放在 Web 页面组件里。父 Session JSONL 会记录:

text 复制代码
review_started
→ review_completed
→ rendered assistant report

packages/cli/src/context/reviews.ts 会按 reviewId 投影这些事件。只有出现 review_started 且还没有完成事件的记录,才是 pending review。进程在 reviewer 完成前退出,下一次 owner 写入 interrupted;如果已经写入 review_completed,但渲染消息前崩溃,fresh Session 可以直接恢复报告,不需要重放模型。

这和"页面刷新后重新发起一次请求"差别很大。前者恢复的是已经落盘的事实,后者可能把一次只读评审变成两次不同输入的模型调用。

Fork 不复制 live review lifecycle,rewind 会移除 checkpoint 后的 review 事件和报告。它们不是 UI 细节,而是 Session 历史语义的一部分。

这次发布证明了什么,没证明什么

公开 v0.10.7 changelog 写明了三类 target、stale、abort、interrupted、crash projection、fork/rewind、finding contract 和只读 sandbox 的回归覆盖,也记录了 production Web、ACP、TUI 的真实 GPT 验证。

这些是 release notes 的交付声明,不是我在这篇文章里重新跑出的 production 结果。本文能直接核对的是公开源码和文档中的目标解析、digest、changed line、finding 校验以及 Session 投影逻辑。没有当前凭证时,不把 release note 写成自己的端到端复测。

如果你要评估自己的 AI 评审器,先问这五个问题:

  1. 评审输入有没有 commit identity、文件内容和 changed line 的摘要?
  2. 未跟踪文件是否被纳入目标,而不是默认忽略?
  3. 评审中目标变化后,结果是 stale、重跑,还是悄悄继续?
  4. finding 的路径和行号是否经过宿主校验?
  5. 进程重启后,恢复的是完成事件,还是重新调用模型?

回答不清楚之前,先别把"AI 代码评审"当成一份可以直接合并的意见。它首先是一份针对特定输入、在特定时间点生成的证据。

源码依据 :Blade Code v0.10.7(公开提交 1044d7e565fa55ba8b60ae6749d918c37dd59966),docs/reference/native-code-review.md、packages/cli/src/services/GitReviewTargetService.ts、packages/cli/src/context/reviews.ts。

相关推荐
wflynn7 小时前
GitHub 日榜趋势速报 | 2026-10-13
开源·github
m4Rk_11 小时前
【论文阅读】Agent 记忆机制(99):PrisMem——从整体分数搜索走向能力驱动的记忆自进化
论文阅读·人工智能·学习·开源·github
张洛闻Eren12 小时前
Ansible【第一课】:Ansible介绍
运维·数据库·云原生·kubernetes·github·ansible
miofly13 小时前
Meta 发布 Muse Wonder 系列模型,长上下文智能体任务表现接近主流竞品
开源·github
高频因子挖掘机13 小时前
股票分红送转后价格“断层”:前复权、后复权和不复权该怎么选?
后端·github·api
解道Jdon14 小时前
FigCraft把Figma用Rust从零重写了一遍
ide·windows·git·svn·eclipse·github·visual studio
u13013014 小时前
GitHub 热榜项目:日榜(2026-10-13)
人工智能·github
答案answer15 小时前
不用写一行Three.js代码,也能搭出复杂数字孪生场景
github·three.js
deepseek2315 小时前
Dependabot匿名私有仓库开放后仍更新失败?组织级镜像的访问边界与排查实战
python·github·devops·软件供应链·dependabot
2023自学中16 小时前
github , ubuntu 虚拟机 push file config
linux·ubuntu·github