课程大纲 › 领域 4:提示工程与结构化输出
4.6 设计多实例、多轮次的评审架构
タスクステートメント4.6:マルチインスタンスおよびマルチパスのレビューアーキテクチャを設計する
官方大纲原文(日文):知识 3 条 · 技能 3 条
需要掌握的知识
- セルフレビューの限界:モデルは生成時の推論コンテキストを保持しているため、同じセッション内では自身の判断を疑いにくくなること
- 独立したレビューインスタンス(以前の推論コンテキストを持たない)は、セルフレビューの指示や拡張思考よりも、微妙な問題を見つけるうえで効果的であること
- マルチパスレビュー:注意の分散や矛盾した指摘事項を避けるために、大規模なレビューをファイル単位の局所的な分析パスとファイル横断の統合パスに分割すること
需要能做到的事
- 生成側の推論コンテキストを持たない、別の独立したClaudeインスタンスを使用して、生成されたコードをレビューする
- 大規模な複数ファイルのレビューを、局所的な問題に焦点を絞ったファイル単位のパスと、ファイル横断のデータフロー分析のための別個の統合パスに分割する
- モデルが各指摘事項とあわせて確信度を自己申告する検証パスを実行し、キャリブレーションされたレビューのルーティングを可能にする
课程讲解 · AI 草稿,未经人工审核 以官方文档为准
这一条考什么
这一条考你知不知道"让同一个会话审查自己刚写的代码"为什么效果差,以及怎么用一个独立的、没有生成时推理上下文的 Claude 实例来做审查。你还要会把大规模的多文件审查拆成"按文件的局部分析"和"跨文件的整合分析"多个轮次,并用带置信度的验证轮次来决定发现怎么分流。
核心概念
自我审查的局限
在同一个会话里,模型的上下文里装着它生成代码时的全部推理:为什么这么设计、做了哪些假设、排除了哪些方案。让它在同一会话里"检查一下有没有问题",它会顺着原来的思路去读代码,倾向于证明自己是对的,很难怀疑当初的前提。这不是上下文满了,也不是提示词不够具体,而是推理被锚定了(anchoring)。
典型场景:开发者让 Claude Code 重构一个函数,接着在同一会话里让它自查,它说没问题;结果 CI 里另起的独立审查却找出了好几个 bug。差别就在于审查者是否独立。
独立审查实例更有效
独立的审查实例是一个全新的上下文:只拿到代码、diff、需求说明和审查标准,不带生成时的推理过程。它只能从代码本身出发判断,所以更容易发现隐含假设、边界条件和"看起来合理其实错了"的细节。
对比几种手段:
- 同一会话里加一句"请严格审查你的代码":作用很小,锚定还在。
- 同一会话里打开 extended thinking:推理更深,但仍然在原来的思路上展开。
- 独立实例:最有效,因为它根本看不到原来的推理。
实现方式可以很多样:另起一次 Messages API 调用(不带之前的 messages)、Agent SDK 里定义一个专门的 reviewer 子 Agent(子 Agent 本来就是新上下文)、在 CI 里用 claude -p 跑一次审查。
review = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
system="你是代码审查者。只依据给出的需求与代码判断,列出具体缺陷。",
messages=[{"role": "user", "content": f"需求:\n{spec}\n\n代码:\n{code}"}],
)这里的关键是 messages 里没有生成阶段的对话。
多轮次审查:局部轮次 + 整合轮次
一次性把 30 个文件塞给模型审查,常见问题有:
- 注意力被摊薄,单个文件里的细节问题被漏掉;
- 文件看到后面,前面的结论被遗忘或自相矛盾;
- 输出太长,可能撞上
max_tokens被截断。
更好的结构是:
- 按文件的局部轮次:每个文件(或一小组紧密相关的文件)单独审查,专注于局部问题,比如空指针、错误处理、资源泄漏、逻辑分支。每轮输出结构化的发现,以及这个文件的接口摘要(导出了什么、依赖什么、对数据做了什么假设)。
- 跨文件的整合轮次:输入各文件的接口摘要和局部发现,专门分析跨文件的数据流:调用方和被调用方的契约是否一致、某字段在 A 里可空但 B 里直接解引用、事务边界跨文件是否正确。顺便对局部发现去重、消解矛盾。
局部轮次可以并行跑;整合轮次只看摘要,不用重读全部源码,所以上下文压力小。
带置信度的验证轮次与分流
审查之后再加一轮验证:让模型对每条发现重新核实,并自报置信度,同时给出依据,比如具体行号和触发条件。然后按置信度分流:
- 高置信度:直接作为 PR 评论发出;
- 中置信度:标记为"建议人工确认";
- 低置信度:只记日志,不打扰开发者。
注意这里的置信度只是一个分流信号。阈值应该用历史数据(开发者采纳和驳回的记录)来校准,不能拍脑袋定"8 分以上才报"。另外,不要在生成阶段的提示词里写"只报告你确定的问题",这会压低召回率,让真 bug 被模型自己过滤掉。更好的做法是先全部报出来、附上置信度和严重度,再由下游按校准过的阈值过滤。
{"file": "billing/refund.py", "line": 88, "issue": "refund_amount 可能为 None 时直接参与比较",
"evidence": "第 72 行 get_refund() 在订单未找到时返回 None", "confidence": 0.82, "severity": "high"}正确做法与反模式
- 正确:用独立的 Claude 实例(新上下文、没有生成推理)审查生成的代码。反模式:在同一会话里让模型"再仔细检查一遍"。
- 正确:要发现微妙问题,靠审查者独立。反模式:以为打开 extended thinking 或者加一句"请严格审查"就能替代独立审查。
- 正确:大规模审查拆成按文件的局部轮次,再加一个跨文件数据流的整合轮次。反模式:把所有文件一次塞进一个请求,或者只做按文件审查、完全漏掉跨文件问题。
- 正确:让模型对每条发现自报置信度和依据,用校准过的阈值分流。反模式:在提示词里要求"只报告确定的问题",导致召回率下降。
- 正确:第二轮审查要换视角(独立实例、不同的关注点)。反模式:用同样的提示词把同一个 diff 再读一遍,指望它发现第一遍漏掉的问题。
常见陷阱
- "同会话审查失败是因为上下文满了 / 提示词不具体":根因是生成时的推理上下文造成的锚定。题干描述"同一会话自查没发现,独立 CI 审查发现了"时,选与推理上下文相关的选项。
- "开启 extended thinking 让模型逐步推理":推理更深不等于更独立。如果还是同一个上下文,偏差依然在。
- "同一提示词再跑一遍":同样的输入、同样的视角,漏掉的大概率还会漏掉。
- "一次请求审查全部文件,把 max_tokens 调到最大":没有解决注意力摊薄和输出截断。正确做法是拆分审查,再合并发现数组。
- "只报告高置信度问题"写进生成提示词:会造成漏报。应该全部报告并附上置信度,由下游过滤。
- 把模型自报置信度当成绝对可靠:它只是分流信号,阈值要用带标签的历史数据校准。
实操练习
目标:对比"同会话自查"和"独立实例审查",并实现"局部轮次 + 整合轮次"。
- 让 Claude 生成一个带隐藏边界问题的小函数(比如分页计算)。
- 在同一会话里追加"请审查上面的代码",记录它找到了哪些问题。
- 另起一个不带历史的调用审查同一段代码,对比两边的发现。
- 准备两个相互调用的文件,先分别做局部审查,再把两份摘要交给整合轮次。
import anthropic
client = anthropic.Anthropic()
M = "claude-sonnet-4-5"
def ask(messages, system=None):
kw = {"system": system} if system else {}
r = client.messages.create(model=M, max_tokens=1500, messages=messages, **kw)
return r.content[0].text
gen_msgs = [{"role": "user", "content": "写一个 Python 函数 paginate(items, page, size),page 从 1 开始。"}]
code = ask(gen_msgs)
self_review = ask(gen_msgs + [{"role": "assistant", "content": code},
{"role": "user", "content": "请审查上面的代码,列出缺陷。"}])
independent = ask([{"role": "user", "content": f"需求:paginate(items, page, size),page 从 1 开始。\n代码:\n{code}\n\n列出所有缺陷,每条附 confidence(0-1) 和触发输入。"}],
system="你是独立代码审查者,只依据需求和代码判断。")
files = {"api.py": "def handler(req):\n user = find_user(req['id'])\n return user.name\n",
"repo.py": "def find_user(uid):\n return DB.get(uid) # 找不到时返回 None\n"}
local = {f: ask([{"role": "user", "content": f"只审查本文件的局部问题,并输出接口摘要(导出函数、返回值可能为何):\n{src}"}])
for f, src in files.items()}
integration = ask([{"role": "user", "content": "以下是各文件的局部审查与接口摘要。请只分析跨文件数据流与契约不一致问题:\n" +
"\n\n".join(f"## {f}\n{s}" for f, s in local.items())}])
print("自查:\n", self_review, "\n\n独立审查:\n", independent, "\n\n整合轮次:\n", integration)要检查的结果:独立审查通常会指出更多边界问题(page ≤ 0、size ≤ 0、越界页);整合轮次应该指出"find_user 可能返回 None,而 handler 直接访问 .name"这个跨文件问题,单看任何一个文件的局部轮次都不一定能发现。
自测清单
- 为什么同一会话的自我审查容易漏掉问题?根本原因是什么?
- 独立审查实例的"独立"具体指什么?在 API、Agent SDK、CI 里分别怎么实现?
- 为什么 extended thinking 不能替代独立审查?
- 多轮次审查中,局部轮次和整合轮次分别负责什么?整合轮次的输入是什么?
- 带置信度的验证轮次怎么用于分流?阈值应该怎么定?
- 为什么不应该在生成提示词里写"只报告确定的问题"?
对应题目(3)
题目归类由 AI 判断,仅供参考。
练习这 3 道题