第 6 课:实战:搭一个双 Agent 评审流水线
学习目标:
- 用 Claude API 写出一个可以真正运行的生产者-评审者双 Agent 流水线
- 让评审者返回结构化、可核查的评审结果,而不是一句笼统的「还不错」
- 给这套循环装上安全阀,避免生产者和评审者无限来回打磨
前置要求:读完第 1-5 课,能读懂基本的 JavaScript/Node.js,有可用的 Claude API key | 上一课 第 5 课 <<
先看效果:一次完整的运行
这是本课最后要跑出来的东西。终端里给一个任务,两个 Agent 轮流干活,直到评审通过或者到达轮数上限:
第一版被评审者打回,理由具体到每一条标准;生产者照着意见改出第二版,评审者再看一遍,这次通过。这就是第 4 课讲过的生产者-评审者模式落地成的代码:「一次 LLM 调用生成回复,另一次 LLM 调用提供评估和反馈,如此循环。」1
整体结构:和执行循环是同一个骨架
如果你学过本系列「Agent 工具调用基础」那门课,会发现这套流水线的骨架很眼熟:一个循环、每一轮做一次判断、判断结果决定要不要继续、外加一道防止无限循环的安全阀。区别只在于「判断」判断的是什么——那门课的工具执行循环判断的是「模型还要不要调用工具」(循环语义详见那门课第 2 课及其官方来源),这里判断的是「评审者说通过了没有」。骨架相同,循环体里装的东西不同。
整套流水线由三个函数拼起来:runProducer 负责生成或者修改正文,runReviewer 负责依据标准打分并给出具体意见,runPipeline 把两者串成循环,加上轮数上限这道安全阀。
第一步:生产者——接到任务,产出正文
生产者第一次运行时只有任务本身;如果是被评审者打回后的第二次运行,还要同时带上上一版全文和评审意见,让生产者在上一版的基础上照着意见改,而不是重新自由发挥:
生产者的提示词是自包含的——第 3 课讲过,子代理看不到编排者这边发生了什么,也看不到自己上一次是怎么被评审的2。所以每次调用都把「任务是什么」「上一版写了什么」「(如果有)上一轮的问题是什么」原样写进这次的 prompt 里。注意连生产者自己的上一稿也要显式传回去——这是自包含原则最容易被漏掉的一半:Messages API 是无状态的,每次请求都必须自带完整的所需历史,请求之间服务器什么都不保留3,「修改你上一版的内容」这句话只有在上一版真的写进了这次 prompt 时才有意义。
第二步:评审者——依据具体标准打分,不给模糊评价
评审者不是简单问模型「这段写得好不好」——第 5 课讲过,验证要落到具体、可核查的标准上,而不是凭印象打分4。这里给评审者一份明确的检查清单,并要求它按固定的 JSON 格式回复:
approved 和 issues 两个字段合起来就是一份结构化评审结果:不是一句「还可以」,而是「通过还是没通过」加上「没通过的每一条具体是什么问题」。生产者拿到 issues 之后,改的就是这几条具体问题,而不是对着一句模糊评价瞎猜该往哪改。
第三步:评审结果不能直接信——解析失败当作没通过
runReviewer 返回的是一段文本,不是真正的 JSON 对象,还需要解析。评审者虽然被要求「严格按 JSON 格式回复」,但没有结构化输出约束时,模型仍可能产出语法不合法的 JSON、漏掉字段,或者在 JSON 外面裹一层代码块、加几句解释5。这一步容易踩的坑是:解析失败了怎么办?如果图省事,解析失败就默认放行,等于把一次「评审者没干好活」的失败,悄悄当成了「评审通过」——这正是第 5 课讲过的道理:产出「看起来」处理完了,不等于真的做对了,没法验证就不该直接采用6。这里反过来处理:解析失败,一律当作没通过,而不是当作通过:
typeof parsed.approved !== "boolean" 和 !Array.isArray(parsed.issues) 这两行也是同一个道理的延伸——就算 JSON.parse 成功了,也要确认解析出来的字段形状对不对,字段类型不对同样当作没通过,不能因为「至少是个合法 JSON」就放松警惕。
顺带一提:官方提供了结构化输出功能,能从采样层面保证响应严格符合 schema5。本课故意用「裸调用 + 自行防御解析」的写法,是为了让你亲手体会「模型输出不能直接信」这件事;生产环境里可以直接用结构化输出把这一层坑消掉。
第四步:串成循环,装上安全阀
有了 runProducer、runReviewer、parseReview,runPipeline 把三者接起来,MAX_ROUNDS 是这里唯一的安全阀——生产者和评审者理论上可以无限打磨下去,必须有个上限:
到达 MAX_ROUNDS 仍未通过时,runPipeline 不会强行判它「通过」,而是老老实实交出最后一版草稿和还没解决的问题,留给人工复核——这也是第 5 课讲过的道理在收尾这一步的体现:结果整合阶段遇到判断不了的情况,不该在代码里自己拍板蒙混过去。
小结
- 生产者-评审者流水线的骨架和执行循环是同一套东西:一个循环、每一轮做一次判断、判断结果决定要不要继续,外加一道防止无限循环的安全阀。官方对这个模式的定义正是「一次调用生成回复、另一次调用提供评估和反馈、如此循环」1——这里的判断从「要不要调用工具」换成了「评审者说通过了没有」。
- 生产者的提示词是自包含的:每次调用都把任务、上一版全文和(如果有)上一轮的具体问题原样写进 prompt——Messages API 无状态,每次请求都要自带完整历史,请求之间什么都不保留3,不能指望模型自己记得上一轮发生了什么2。
- 评审者要依据具体、可核查的标准逐条打分,返回结构化的
{approved, issues},而不是一句笼统的评价4。
- 评审者返回的内容本身也不能直接信——解析失败或者字段形状不对,应该当作没通过处理,而不是悄悄放行6;这条原则不只适用于「相信子代理说的话」,也适用于「相信子代理返回的数据格式」。
- 到达最大轮数仍未通过时,流水线应该老实交出最后一版草稿和未解决的问题,留给人工复核,而不是在代码里自己拍板判定通过。
到这里,这门课的六课就学完了:从「为什么要多个 Agent」,到编排者-子代理怎么分工、委派提示词怎么写、几种协作模式各自适合什么场景、失败该怎么应对,最后自己动手搭出了一套能跑的生产者-评审者流水线。接下来最值得做的,不是再读一遍解释,而是挑一个你手头真实的小任务,套进这套流水线骨架里改一改评审标准,跑起来看看它到底会不会打回、打回几次——亲手调一次评审标准,比再读十遍原理都管用。