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 只允许 ReadGlobGrep 和分类后的只读 BashGitReviewTargetService 还会限制目标最多 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.mdpackages/cli/src/services/GitReviewTargetService.tspackages/cli/src/context/reviews.ts

相关推荐
峰向AI12 小时前
GenOffice:开源 Office 套件,字节级保留、本地转换、BYOK模式
github
其实防守也摸鱼14 小时前
权限提升与横向移动:从内网渗透到域控的完整技术图谱
运维·服务器·数据库·安全·github·copilot·渗透
m4Rk_14 小时前
【论文阅读】Agent 记忆机制(57):MemSearch-o1——从查询词元生长证据,重组 Deep Search 记忆路径
论文阅读·人工智能·学习·开源·github
其实防守也摸鱼14 小时前
免杀与持久化入门:从载荷免杀到隐蔽通道的完整指南
运维·服务器·数据库·安全·github·copilot·渗透
sec_jay15 小时前
一个面向有限本地语料库的、单智能体、工具调用型 Agentic RAG 原型--关于agent的实践调研报告
github
goplaysource17 小时前
IPTV 频道去重:用哈希解决"同一个频道出现十遍"的问题
github
liuyicenysabel18 小时前
从 0 到 1:一套 GitHub + GHCR + k3s 的全自动 CI/CD 流水线(Flask 项目实战)
ci/cd·flask·github
u13013019 小时前
GitHub 热榜项目:日榜(2026-08-31)
github
Justinsky20 小时前
DeepSeek Harness 开源一个月,我把它整个嵌进了 Electron 桌面软件
github
小宋102120 小时前
MCP 是什么:从零编写一个可供 AI 调用的工具服务
人工智能·github