返回博客

代码评审分层路由:$0.20初筛+$5复核精度账

人工智能7391
代码评审分层路由:$0.20初筛+$5复核精度账

同样的五十个 PR,同样的提示词,一个模型花 $0.20 找出 69 个经验证的缺陷,另一个花 $5.66 找出 92 个。这不是二选一的题目,而是一道分层题:谁该做初筛,谁该做终审。

一、一组可直接引用的对比数字

一份公开的代码评审对比给出了干净的量化结论:在 50 个公开基准 PR 上用完全相同的提示词,GPT-5.6 Luna 找到 69 个经验证的 bug,总成本 $0.20,精度 74%;GPT-6 Astra 找到 92 个,总成本 $5.66,精度 96%。

把这组数字翻译成接入视角:旗舰档的边际收益是多召回 23 个缺陷,边际成本是 28 倍的账单。缺陷召回的差异是真实的,精度差距(74% 对 96%)也是真实的——便宜模型会报更多不成立的发现,评审者要花人力甄别。两头的账都要算,结论不是"谁好谁坏",而是"谁放在哪一层"。

二、评审预算的分层结构

评审管线天然是一个漏斗:入口的变更量大,真正值得深度推敲的变更少。把两种模型放进漏斗的两层:

层级模型档位单 PR 成本量级职责输出
初筛层次旗舰 / 高性价比档约 $0.004全量扫描,找明显缺陷与风险点候选缺陷清单 + 置信标记
复核层旗舰档约 $0.11验证候选缺陷、深挖高危变更确认缺陷 + 修复建议
裁决层人工处理双方分歧与高危决策最终处置

漏斗的宽度比是关键参数。如果初筛层直接把 69 个候选全推给复核层,复核成本省不下来;分层路由的收益来自初筛层的置信标记——低置信的发现直接归档为提示信息,只有高置信候选才消耗旗舰复核额度。

三、原理速览:分层评审的请求流

text
PR 变更事件
    |
    v
初筛模型(次旗舰档,全量跑)
    |
    +--> 高置信缺陷候选 ──> 复核模型(旗舰档,按需跑)
    |                             |
    +--> 低置信提示 ──> 归档,不消耗复核额度
    |                             |
    v                             v
双方一致 ──> 直接确认;分歧 ──> 人工裁决队列
    |
    v
审计日志:每条缺陷记录初筛/复核/裁决三级留痕

这张图的精髓在分支条件。分支条件不是"发现多少个缺陷",而是"初筛模型自己有多确定"。让初筛模型同时输出发现与置信度,置信度门槛成为一个可调的成本旋钮:调高,复核额度省,漏检风险升;调低,反之。

四、多阶段管线的隐性坑:指代漂移

分层评审是典型的多阶段管线,而多阶段管线有一个实测过的失效模式:指代漂移。一份公开研究用构造数据测过 draft-verify-revise 这类编排:同一句"修复上一步提到的问题",在不同阶段被解析成不同对象,结果平衡准确率能从近满分跌到 0.156——低于随机猜。

两个实测结论值得抄进评审管线。其一,推理努力的补偿是有价的:GPT-5.2 从无推理档的 0.156 提到最高档的 0.942,而另一个模型在低推理档就稳定在 0.94 以上,且以约 5% 的单次成本在多数试验中不输旗舰的最高档。其二,修法便宜:在每个阶段显式固定指代对象——不要写"上述问题",要写"issue_id=482 的空指针缺陷"——漂移就失去了生存空间。

接入方的教训是:管线里传递的不该只有文本,还要有结构化的对象引用。文本是给模型读的,ID 是给管线对齐用的,两者都要有。

五、接入教程:两级评审器

下面这段 Python 示例以 4sapi 提供的 OpenAI 兼容接口为例,实现一个最小两级评审器:初筛走次旗舰档,高置信候选升级到旗舰复核,全程结构化传递对象 ID。4sapi 上配置好多模型密钥后,换档只改模型名。

python
import json
import openai

client = openai.OpenAI(base_url="https://4sapi.com/v1", api_key="sk-xxx")

SCREEN_MODEL = "mid-tier-model"    # 初筛:次旗舰档
REVIEW_MODEL = "flagship-model"    # 复核:旗舰档
CONFIDENCE_GATE = 0.7              # 置信门槛,成本旋钮

SCREEN_PROMPT = """对以下 PR diff 做缺陷初筛。
要求:每条发现输出 JSON,字段包括 bug_id、类型、置信度(0~1)、
涉及的文件与行号。只输出 JSON 数组,不做修饰。
PR diff:
{diff}"""

REVIEW_PROMPT = """复核以下缺陷候选是否真实成立。
候选清单(JSON):{candidates}
原始 diff:{diff}
要求:对每条候选给出 verdict(确认/否决)、依据、修复建议。"""


def screen(diff: str) -> list:
    resp = client.chat.completions.create(
        model=SCREEN_MODEL,
        messages=[{"role": "user", "content": SCREEN_PROMPT.format(diff=diff)}],
        temperature=0,
    )
    findings = json.loads(resp.choices[0].message.content)
    for i, f in enumerate(findings):
        f["bug_id"] = f"B-{i:04d}"          # 显式 ID,防跨阶段指代漂移
        f["model"] = SCREEN_MODEL
    return findings


def review(diff: str, candidates: list) -> list:
    resp = client.chat.completions.create(
        model=REVIEW_MODEL,
        messages=[{"role": "user",
                   "content": REVIEW_PROMPT.format(
                       candidates=json.dumps(candidates, ensure_ascii=False),
                       diff=diff)}],
        temperature=0,
    )
    verdicts = json.loads(resp.choices[0].message.content)
    for v in verdicts:
        v["model"] = REVIEW_MODEL           # 全链留痕:谁筛的、谁复核的
    return verdicts


def two_stage_review(diff: str) -> dict:
    findings = screen(diff)
    hot = [f for f in findings if f.get("置信度", 0) >= CONFIDENCE_GATE]
    cold = [f for f in findings if f.get("置信度", 0) < CONFIDENCE_GATE]
    verdicts = review(diff, hot) if hot else []
    return {"confirmed": verdicts, "archived": cold,
            "cost_note": {"screen_model": SCREEN_MODEL,
                          "review_calls": len(hot)}}

三处实现细节决定了这套管线的账单。第一,bug_id 在初筛阶段生成并贯穿复核,复核模型看到的每个候选都有 ID 可引用,指代漂移没有生存空间。第二,CONFIDENCE_GATE 是唯一的成本旋钮,按缺陷漏检的实际代价调节:内部工具库调高,支付链路调低。第三,cold 列表归档但不丢弃,每周抽样人工复查,用它反推门槛设置是否过松或过紧。

六、成本对比:三种评审策略的账本

以每 PR 平均 diff 规模、初筛 $0.004、复核 $0.11 的量级估算(示例口径,实际以牌价为准):

策略每 PR 成本(估算)缺陷召回人工甄别负担
全人工高(人力)依赖资深程度全部靠自己
全旗舰自动评审约 $5.66 / 50 PR 折合单 PR $0.11 量级的数倍最高(92 个)低,但账单高
分层评审约 $0.02~0.05,随门槛浮动高置信区接近旗舰中,需处理少量误报

分层策略省下的是复核层的全量成本,保留的是旗舰的验证深度;多出来的人力负担集中在低置信误报的甄别上,而这部分可以通过调门槛与积累误报特征逐步压缩。评审从"要不要买旗舰"变成"旗舰额度花在哪个置信区间",这就是分层路由的本质。

七、成本与风险提示

第一条风险是初筛漏检。74% 的精度意味着四分之一的发现不成立,但更有价值的数字是召回率的下限——初筛层漏掉的缺陷,复核层永远看不到。对策是把高危路径(支付、权限、数据删除)设为免分层区,直接进旗舰或人工评审,不给初筛层裁量的机会。

第二条风险是门槛漂移。模型版本更新后,置信度分布会移动,上季度调好的门槛可能失效。把每周的误报率与漏检率做成趋势图,越过警戒线就重跑门槛标定。

第三条风险是多阶段上下文膨胀。初筛发现全量塞进复核提示,复核成本会随发现数线性上涨。复核提示只带候选清单与相关 diff 片段,不带全量上下文,这一条就能把复核调用量压掉一大半。

红线照旧:评审管线直连生产代码仓库,凭证走受控注入,不把仓库 Token 写进提示词;自动评审结果只做辅助,高危变更的合并决策保留人工签核。

八、上线前的自查清单

  1. 免分层区已圈定:高危路径清单成文,绕过初筛直达旗舰或人工。
  2. 置信门槛已标定:用历史缺陷回归集标过,误报率与漏检率都在接受带内。
  3. 对象 ID 已贯通:初筛、复核、裁决三级用同一套 bug_id 对齐,日志可还原全程。
  4. 复核上下文已裁剪:复核提示只含候选与相关片段,成本不随发现数失控。
  5. 归档区有人复查:低置信发现每周抽样,作为门槛标定的反馈源。
  6. 账单按层归因:初筛与复核的调用量分列,分层收益可被财务验证。

九、什么时候该放弃分层

分层不是永恒答案。三种情况应该退回单层:一是任务量太小,分层的工程维护成本超过节省;二是初筛模型在自己的任务分布上召回率始终不达标,说明该变更类型超出当前便宜档的能力面;三是安全相关变更占比过高,免分层区大到底层初筛只剩边角料。定期用影子的办法重新验证分层假设,假设失效就大方退回,省下的是维护一套失效优化的隐形账单。

十、总结

这一期想沉淀的结论是:代码评审的成本问题本质上是个路由问题。$0.20 与 $5.66 的对比说明次旗舰档已经具备做初筛的能力面,92 对 69 的召回差说明旗舰档的深度仍然不可替代,而指代漂移的实测数据说明多阶段管线的正确性取决于工程细节而非模型价格。把置信门槛当作成本旋钮、把对象 ID 当作跨阶段契约、把高危路径划出免分层区,评审账单就可以在保住召回的前提下压到零头。我在 4sapi 维护的评审接入里,最稳定的配置从来不是最便宜的,而是每层职责最清晰的。对分层门槛或免分层区的划法有不同经验,欢迎在评论区聊聊。

标签:代码评审分层路由成本优化多阶段管线精度账

推荐阅读

探索更多前沿洞察与行业干货。