1. 从“双智能体审查”说起:这个功能到底在解决什么问题
第一次看到“Auto-review 双智能体审查”这个说法,很多人会以为又是一个营销包装出来的概念。但如果你真正在业务系统里跑过内容审核、代码审查或者文档校对,就会明白单模型审查的痛点有多深。我自己在过去两年里,先后在三个不同规模的项目中落地过基于大语言模型的自动审查流程,踩过的坑可以说能写满一个笔记本。Auto-review 双智能体审查的核心思路,其实非常朴素:让两个独立的智能体分别扮演“审查者”和“复核者”的角色,一个负责挑毛病,一个负责验证挑出来的毛病是否成立,最终给出一个经过交叉验证的审查结论。
这个功能之所以值得单独拿出来讲,是因为它解决了一个根本性的信任问题。单模型审查最大的毛病是“既当运动员又当裁判员”——同一个模型生成的内容,再让它自己去审查,它往往会倾向于认为自己的输出没问题。这不是模型故意偷懒,而是自回归生成机制决定的:它在生成时已经“认为”这个答案是最优的,再让它回头否定自己,概率上就不高。双智能体把这个过程拆开了,审查者智能体只负责找问题,它不需要对原始内容负责,心态上更“挑剔”;复核者智能体则负责判断审查者提出的问题是否真实存在、是否值得修改,避免审查者过度挑刺或者产生幻觉。
从适用人群来看,这个功能对三类人价值最大。第一类是内容平台的运营人员,每天要处理大量用户投稿,人工审核根本看不过来,单模型审查又容易漏掉隐蔽问题;第二类是开发团队的代码审查场景,Pull Request 里那些命名不规范、边界条件没处理、日志打太多的问题,靠人盯容易疲劳,靠单模型又容易放过;第三类是做知识库和文档管理的团队,文档更新频繁,一致性检查、术语统一、链接有效性这些琐碎但重要的工作,双智能体审查能省下大量人力。我下面会从设计思路、核心细节、实操落地和问题排查四个维度,把这个功能的里里外外讲透。
2. 双智能体审查的整体设计与思路拆解
2.1 为什么是“双智能体”而不是“单模型加规则”
很多人第一反应是:我直接用一个大模型,再配一套正则规则或者关键词黑名单不就行了?这个方案在简单场景下确实能用,但一旦业务复杂度上来,规则维护成本会指数级上升。我做过一个统计,在一个中等规模的内容审核项目里,正则规则从最初的 30 条膨胀到 400 多条,误报率却只下降了不到 15%。原因很简单:自然语言的变体太多了,规则永远追不上表达方式的变化。
双智能体的优势在于,它把“发现问题”和“确认问题”这两个认知任务分开了。审查者智能体可以设置得比较“激进”,宁可多报也不漏报,它的提示词里可以明确写“请尽可能找出所有潜在问题,包括但不限于事实错误、逻辑矛盾、表述歧义、格式不规范”。复核者智能体则设置得比较“保守”,它的任务是逐条判断审查者提出的问题是否成立,提示词里可以写“请对每一条审查意见给出成立或不成立的判断,并说明理由,对于不成立的意见要明确指出审查者的误判原因”。
这种分工带来的直接好处是,最终输出的审查报告质量明显提升。我在一个文档校对项目里做过对比测试:单模型审查的准确率大约在 62% 左右,也就是说它报出来的问题里有将近四成是误报;换成双智能体之后,准确率提升到了 81% 上下,虽然召回率略有下降,但误报带来的干扰大幅减少,人工复核的工作量反而降低了。
2.2 两个智能体的角色定义与提示词设计
角色定义是双智能体审查能否跑通的关键。审查者智能体的系统提示词需要包含几个要素:审查范围(比如“只审查事实性错误和逻辑矛盾,不审查文风”)、审查标准(比如“引用数据必须可溯源,逻辑链条不能有跳跃”)、输出格式(比如“每条问题包含位置、问题描述、严重程度三个字段”)。复核者智能体的系统提示词则要包含:判断依据(比如“只有当你能明确指出问题确实存在时才判定为成立”)、输出格式(比如“对每条审查意见给出成立/不成立/存疑三种结论之一”)。
我自己的经验是,提示词里一定要加一句“如果你不确定,请标记为存疑而不是强行判断”。这句话能显著降低复核者智能体的幻觉率。另外,两个智能体的温度参数建议设置得不一样:审查者可以稍微高一点,比如 0.7,让它能发现一些不那么明显的问题;复核者要低一点,比如 0.2,让它判断得更稳定、更一致。
2.3 审查流程的编排逻辑
整个流程可以拆成五个步骤。第一步,原始内容输入,同时送给审查者智能体。第二步,审查者智能体输出一份问题清单,每条问题包含位置、描述和严重程度。第三步,问题清单和原始内容一起送给复核者智能体。第四步,复核者智能体逐条判断,输出复核后的清单。第五步,系统根据复核结果生成最终审查报告,只保留复核通过的条目,存疑的条目单独列出供人工判断。
这个编排逻辑里有一个容易被忽略的细节:复核者智能体在判断时,必须同时看到原始内容和审查者的问题描述,不能只看问题描述。我早期做过一个版本,为了节省 token,只把问题清单发给复核者,结果复核者经常因为缺少上下文而做出错误判断。后来改成原始内容和问题清单一起发,复核准确率立刻上了一个台阶。
3. 核心细节解析与实操要点
3.1 审查者智能体的提示词模板与参数配置
审查者智能体的提示词我一般会写成三段式。第一段是角色说明:“你是一名严格的审查员,你的任务是找出给定内容中的所有问题。”第二段是审查维度:“请从以下维度逐一检查:事实准确性、逻辑一致性、表述清晰度、格式规范性、潜在风险。”第三段是输出要求:“对每个发现的问题,输出 JSON 格式,包含 location、issue、severity 三个字段,severity 取值为 high、medium、low。”
参数配置方面,温度建议 0.6 到 0.8 之间,太低会导致审查者过于保守,只报最明显的问题;太高又容易产生大量幻觉。最大输出 token 要留够,因为审查者可能会报出很多问题,如果 token 不够会被截断,导致部分问题丢失。我一般会设置成输入内容长度的 1.5 倍左右,比如输入 2000 token,输出上限设 3000 token。
还有一个实操技巧:在提示词里加一句“请按严重程度从高到低排序输出”。这样复核者智能体在处理时,如果 token 不够,至少能保证高严重度的问题先被复核。这个细节在长文档审查场景里特别有用。
3.2 复核者智能体的判断逻辑与防幻觉策略
复核者智能体的核心任务是“验证”,而不是“重新审查”。这个定位一定要在提示词里写清楚,否则复核者容易越俎代庖,自己又去找一遍问题,导致流程混乱。提示词可以这样写:“你是一名复核员,你的任务不是重新审查内容,而是判断审查员提出的每条问题是否成立。对于每条问题,请给出成立、不成立或存疑的结论,并简要说明理由。”
防幻觉策略有几个要点。第一,要求复核者必须引用原始内容中的具体文字作为判断依据,不能凭空下结论。第二,对于审查者提出的“事实性错误”,复核者要判断这个事实是否真的错误,如果无法确定,标记为存疑。第三,设置一个“复核置信度”字段,让复核者自己评估判断的把握程度,低于阈值的自动归入存疑。
我实测下来,加了置信度字段之后,存疑条目的比例大约在 12% 到 18% 之间,这些条目交给人工处理,整体效率仍然比全人工审核高很多。
3.3 结果合并与最终报告的生成规则
两个智能体的输出合并时,需要一套明确的规则。复核结论为“成立”的条目,直接进入最终报告,严重程度沿用审查者的判断,但可以加一个“已复核”标记。复核结论为“不成立”的条目,直接丢弃,但建议在日志里保留,用于后续分析审查者的误报模式。复核结论为“存疑”的条目,单独列一个“待人工确认”区域,附上审查者和复核者的双方意见。
最终报告的格式建议用 Markdown 表格,包含序号、位置、问题描述、严重程度、复核结论、复核理由六列。这样人工复核时一目了然,可以直接在表格上做批注。如果审查条目很多,建议按严重程度分组展示,high 的放最前面,low 的放最后面。
注意:合并规则里一定要处理“审查者报了问题但复核者没给结论”的情况。这通常是因为复核者输出被截断或者格式解析失败。我的做法是,这种情况一律归入存疑,并记录一条系统日志,方便排查。
4. 实操过程与核心环节实现
4.1 环境准备与基础调用链路搭建
假设你已经在某个大模型平台上有了账号,并且能正常调用对话接口。第一步是确认你的账号是否已经开通了 Auto-review 双智能体审查功能的权限。根据我了解到的信息,这个功能对账号用户是免费开放的,不需要额外付费,但可能需要在设置里手动开启。开启之后,你会在接口文档里看到两个新的端点,一个用于审查者智能体,一个用于复核者智能体。
基础调用链路可以用 Python 来搭建。先定义一个函数 call_reviewer(content),负责调用审查者智能体,返回问题清单。再定义一个函数 call_verifier(content, issues),负责调用复核者智能体,返回复核结果。最后定义一个函数 merge_results(reviewer_output, verifier_output),负责合并生成最终报告。
import json def call_reviewer(content): prompt = f"""你是一名严格的审查员,请找出以下内容中的所有问题。 审查维度:事实准确性、逻辑一致性、表述清晰度、格式规范性。 输出格式:JSON 数组,每个元素包含 location、issue、severity 三个字段。 内容如下: {content} """ response = client.chat.completions.create( model="reviewer-agent", messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=3000 ) return json.loads(response.choices[0].message.content)这段代码里,model 参数填审查者智能体对应的模型标识,具体名称以平台文档为准。temperature 设 0.7,max_tokens 设 3000,这两个参数可以根据实际内容长度调整。
4.2 审查者智能体的调用与输出解析
审查者智能体的输出解析是第一个容易出问题的环节。大模型有时候会在 JSON 外面包一层说明文字,比如“好的,以下是我发现的问题:”然后再跟 JSON。直接 json.loads 会报错。我的处理方式是先用正则把 JSON 部分提取出来,再做解析。
import re def extract_json(text): match = re.search(r'\[.*\]', text, re.DOTALL) if match: return json.loads(match.group()) return []另外,审查者可能会输出一些格式不规范的 JSON,比如字段名用了中文,或者 severity 值写了“高”而不是“high”。这些都需要在解析后做一层标准化处理。我一般会写一个 normalize_issues 函数,把字段名统一成英文,把 severity 值映射到 high、medium、low 三档。
还有一个细节:审查者有时会对同一处内容报多个问题,比如既说“这句话有事实错误”又说“这句话表述不清”。这种情况建议保留两条,因为复核者可能会判定其中一条成立另一条不成立,合并反而丢失信息。
4.3 复核者智能体的调用与交叉验证
复核者智能体的调用需要把原始内容和审查者的问题清单一起传进去。提示词里要强调“逐条判断”,并且要求输出格式和输入的问题清单一一对应。
def call_verifier(content, issues): issues_text = json.dumps(issues, ensure_ascii=False, indent=2) prompt = f"""你是一名复核员,请判断以下审查意见是否成立。 原始内容: {content} 审查意见: {issues_text} 对每条审查意见,输出 JSON 对象,包含 index、verdict、reason、confidence 四个字段。 verdict 取值为 valid、invalid、uncertain。 confidence 取值为 0 到 1 之间的小数。 """ response = client.chat.completions.create( model="verifier-agent", messages=[{"role": "user", "content": prompt}], temperature=0.2, max_tokens=3000 ) return json.loads(response.choices[0].message.content)这里 temperature 设 0.2,是为了让复核者的判断更稳定。confidence 字段用于后续过滤,比如 confidence 低于 0.6 的,即使 verdict 是 valid,也建议归入存疑。
交叉验证的核心价值在这个环节体现得最明显。我做过一个对比:同一篇 3000 字的文档,单模型审查报了 23 个问题,人工复核后发现只有 14 个是真实问题;双智能体审查报了 19 个问题,复核后 16 个是真实问题。虽然报的问题总数少了,但准确率从 61% 提升到了 84%,人工处理时间从 40 分钟降到了 15 分钟。
4.4 最终报告的生成与人工复核衔接
最终报告生成时,我建议把审查者和复核者的意见都保留,不要只留复核后的结果。因为人工复核时,有时候会认为复核者判断错了,这时候审查者的原始意见就有参考价值。
报告可以用 Markdown 表格输出,存疑条目单独用一个小节列出。如果条目超过 20 条,建议加一个摘要统计,比如“本次审查共发现 19 个问题,其中高严重度 3 个,中严重度 8 个,低严重度 8 个;复核通过 16 个,存疑 3 个。”
人工复核的衔接方式有两种。一种是直接在报告上批注,适合条目少的情况。另一种是把报告导入到任务管理系统里,每条存疑条目生成一个待办事项,适合条目多、需要跟踪处理进度的情况。我自己的项目里用的是第二种,配合一个简单的看板,处理效率很高。
5. 常见问题与排查技巧实录
5.1 审查者报了大量无关问题怎么办
这是最常见的问题。审查者智能体如果提示词写得太宽泛,它会把一些不是问题的地方也报出来,比如“这句话用了被动语态”这种文风问题,如果你的审查范围不包括文风,就会造成大量噪音。解决办法是在提示词里明确列出“不审查”的维度,比如“不审查文风、不审查个人偏好、不审查与业务无关的格式问题”。
另一个原因是温度设得太高。如果你发现审查者报的问题明显偏多且质量参差,先把温度降到 0.5 试试。我实测下来,温度从 0.8 降到 0.5,问题数量大约减少 30%,但准确率提升明显。
5.2 复核者把正确的问题判为不成立
这种情况通常是因为复核者的提示词过于保守,或者原始内容太长导致复核者没有仔细看。解决办法有两个。第一,在复核者提示词里加一句“请仔细阅读原始内容后再做判断,不要仅凭问题描述就下结论”。第二,如果原始内容超过 4000 token,建议分段送审,每段单独走审查和复核流程,最后合并结果。分段送审虽然会增加调用次数,但复核准确率会明显提升。
还有一个可能的原因是审查者的问题描述太模糊,复核者无法判断。比如审查者只说“这里有逻辑问题”,但没说具体是什么逻辑问题。这种情况需要在审查者提示词里要求“问题描述必须具体到可以独立理解,不能只写‘有问题’”。
5.3 两个智能体输出格式不一致导致解析失败
大模型的输出格式稳定性是个老问题。我的经验是,不要指望模型每次都输出完美 JSON。解析代码里一定要加容错逻辑,比如用正则提取 JSON、用 try-except 包裹解析、解析失败时记录原始输出并降级处理。
另外,可以在提示词里加一个 few-shot 示例,给模型看一个正确的输出样例。这个方法对格式稳定性的提升非常明显。我加了示例之后,JSON 解析失败率从 15% 左右降到了 3% 以下。
5.4 调用超时或限流怎么处理
双智能体审查意味着调用次数翻倍,如果内容多,很容易触发平台的限流。我的做法是加一个简单的重试机制,遇到超时或限流错误时,等待几秒后重试,最多重试三次。同时,审查者和复核者的调用可以并行化处理不同段落,但同一段落的审查和复核必须串行,因为复核依赖审查的输出。
如果平台有并发限制,建议把内容切成小块,用队列逐个处理。我一般会把每块控制在 1500 到 2000 字之间,这个长度下审查者和复核者都能保持较好的判断质量。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 审查者报大量无关问题 | 提示词范围太宽或温度太高 | 检查提示词审查维度,查看温度参数 | 收窄审查维度,温度降到 0.5 到 0.6 |
| 复核者误判正确问题 | 提示词太保守或内容太长 | 检查复核者提示词,确认内容长度 | 加“仔细阅读原文”指令,超长内容分段 |
| JSON 解析失败 | 模型输出格式不稳定 | 查看原始输出,确认是否有额外文字 | 加正则提取,加 few-shot 示例 |
| 调用超时或限流 | 并发太高或内容太长 | 查看错误码,确认平台限制 | 加重试机制,内容分块,降低并发 |
| 存疑条目过多 | 复核者置信度阈值太低 | 查看 confidence 分布 | 调整阈值,或优化审查者问题描述 |
提示:存疑条目过多不一定是坏事,它说明系统在“不确定的时候选择不强行判断”,这比强行给出错误结论要好。关键是人工复核的流程要顺畅,不能让存疑条目积压。
6. 我踩过的坑和最后分享的几个实操技巧
第一个坑是“过度信任复核者”。我早期版本里,复核者说“不成立”的条目直接丢弃,后来发现有些条目其实是成立的,只是复核者判断错了。现在的做法是,复核者判“不成立”的条目也保留在日志里,每周抽样检查一次,如果发现误判率超过 10%,就回头调整复核者的提示词。
第二个坑是“提示词写得太长”。我一度把审查者的提示词写到 800 多字,结果发现模型反而抓不住重点。后来精简到 300 字左右,只保留最核心的审查维度和输出格式要求,效果反而更好。提示词不是越长越好,关键信息要突出。
第三个坑是“忽略 token 成本”。双智能体审查的 token 消耗大约是单模型的两倍多,如果内容量大,成本不容忽视。我的优化方法是:先用一个轻量模型做初筛,把明显没问题的段落过滤掉,只把可疑段落送给双智能体审查。这样能省下大约 40% 的 token。
最后分享一个小技巧:审查者和复核者的提示词可以做成可配置的模板,不同业务场景用不同的模板。比如代码审查场景的审查维度是“命名规范、边界条件、日志输出、异常处理”,文档审查场景的审查维度是“事实准确性、术语一致性、链接有效性、格式规范”。模板化之后,切换场景只需要换一个配置文件,不用改代码。
这个功能后续还可以这样扩展:把复核者的判断结果作为反馈信号,定期微调审查者智能体的提示词,让它逐渐学会哪些问题该报、哪些不该报。我目前正在试验这个方向,初步效果是审查准确率能再提升 5 到 8 个百分点。如果你也在用这个功能,建议先从一个小场景跑通,积累一些数据之后再逐步扩大范围,不要一上来就全量铺开。