← 返回文章列表
008 — AI · #Prompt 工程 #输出质量控制 #AI Agent · 2026-08-19 · 9 MIN READ

LLM 输出质量控制的三层防线

大模型的四种失败模式

长文档生成任务里,大模型的失败不是随机的,翻来覆去就四种:

静默丢任务。让它处理二十个功能点,输出十九个,不报错、不提示,文档看起来依然完整。合并简化。三个字段压成一行「合同信息包含编码、名称、金额等」,信息量在概括中蒸发。凭空编造。文档里出现一个代码库中不存在的字段或接口,读者无从分辨。悄悄截断。写到一半工具输出被长度限制切断,后半篇戛然而止,节号从 1.4 直接跳到 1.7。

这四种失败有个共同的恶劣性质:输出看起来都是合格的。语法正确、格式工整、语气自信。等到下游某个步骤发现少了东西,排查成本已经翻了几倍。靠「生成后人工通读」兜底不现实——一个中等项目的业务需求文档加起来几十万字。

这条流水线的答案是三层防线:生成前把红线写进 prompt,生成中设闸门,生成后用脚本验证。三层各自独立,任何一层失守,下一层还能兜住。

mermaid
flowchart TD
    A[任务输入] --> L1[第一层 预防 - 红线与反面案例写入 prompt]
    L1 --> L2[第二层 过程 - 强制清单与两阶段闸门]
    L2 --> L3[第三层 事后 - 脚本验证与数量校验]
    L3 -->|通过| O[产物落盘]
    L3 -->|不通过| R[重新生成 最多 3 次]
    R --> L2
    R -->|3 次仍失败| M[标记需人工审核]

第一层防线:把红线写进 prompt

第一层解决「模型不知道什么算错」。多数质量问题的根源是验收标准没有传达:你心里有一条线,模型不知道,它就按互联网上泛滥的文档习惯自由发挥。

写法是两条:红线用禁令清单写死,错误用反面案例演示。业务需求生成一篇展示过最典型的一例,一行合并字段:

字段类型必填说明
合同信息对象包含编码、名称、金额等

把这行原样放进 prompt,后面跟着拆好的正确写法:合同编码、合同名称、开始日期、结束日期各占一行,各有类型和业务含义。模型对具体例子的领悟远好于抽象原则,一个正反对照胜过十句「要写详细」。

禁令清单则负责封死整类错误:禁止「等、包括、多个、相关」这类模糊词,禁止方法名、控件属性、框架术语、SQL 词汇、编程概念,数据类型强制写中文。清单的长度本身就是经验值,每一条背后都是模型真实犯过的错。

这一层的成本几乎为零——不过是把验收标准提前写清楚。但它防不住执行走样:红线记得住,写到第二十页就松了。所以需要第二层。

第二层防线:过程中的闸门

第二层解决「写着写着走样」。手段有三个,都嵌在生成流程内部。

强制检查清单。输入参数提取完成后必须逐项自检:每个参数在函数体里有实际使用吗,实参和形参一一对应吗,条件分支里的变量全都提取了吗。清单不是提醒,是过不去就不许往下走的关卡。

两阶段闸门。业务需求生成把任务切成两段:阶段一只做输入参数,自检全部通过后才允许进入阶段二做输出字段。单个阶段的目标单一,走样的概率随任务复杂度上升,切小了就不容易歪。阶段间还设退回机制,主代理发现合并字段或技术词,整段打回重写。

交叉验证。同一个事实从两个来源核对:接口调用的参数和函数定义的形参对账,SQL 的 where 参数和输入参数表对账,展示层列定义和数据访问层 SELECT 别名对账。两处一致才可信,不一致就是提取漏了或错了。

这一层的共同特点是都在模型自己的工作流里执行,靠的是自我约束。模型状态好的时候非常有效,但它终究不是硬约束——于是有了第三层。

第三层防线:事后的脚本验证

第三层解决「模型说了不算」。流水线里凡是有明确数字标准的验证,全部交给确定性脚本。

模块合并这一步的配置最完整。LLM 按模板生成合并文档后,必须调用 merge_verify.py,把原始文档和输出文档都交给脚本,由脚本解析结构、比对数量、给出判定。门禁标准是三个数字:

检查项标准不通过时
功能点保留率≥ 90%重新生成
输入参数表格100% 保留重新生成
业务规则数量≥ 原始 x 90%警告但允许输出

数量校验 N=M 是另一类脚本验证。链路图生成要求 JSON 里功能点总数 N 等于输出文件里 ### 功能点X 标题数 M,数完必须相等。这是专门对付静默丢任务的:两个计数、一次比较,成本趋近于零,却能拦住最隐蔽的失败。

没有现成脚本时,Grep 也能当验证器用:统计 ^### 的数量对功能数,统计 ^##### 的数量对详细说明数。脚本验证的妙处在于它根本不看内容——正因为不看内容,它才不会被内容的质量假象欺骗。数字对不上就是不对,没有商量。

质量指标的可量化设计

三层防线能运转的前提,是「质量好」被翻译成了脚本可判定的数字。这件事在设计产物格式时就要想好,而不是生成之后补。

翻译的方法是找结构性锚点。功能点保留率的锚点是标题层级:原始文档每个 ### 功能对应输出文档一个 ##### 详细说明,数标题就是数功能。输入参数完整性的锚点是表格:原始有输入参数表格的功能点,输出必须有相同字段的表格,查表格存在性就是查完整性。一致性的锚点是列名:输出列名必须与数据访问层 SELECT 别名严格一致,逐列比对即可。

质量诉求结构锚点脚本判定方式
功能点保留率标题层级计数比对 ≥ 90%
输入参数完整性表格存在性逐功能点查表 100%
业务规则完整性规则条目数条数比对 ≥ 90%
任务无遗漏功能点计数N = M
列名一致SELECT 别名逐列字符串比对

反过来讲,产物格式设计得越规整,可脚本化的锚点就越多。这条流水线强制所有产物用固定模板(三级标题功能点、四列输入参数表、三段式结构),一半是为了读者,另一半就是为了给验证脚本留着手的地方。自由格式的文档没有质量门禁可言。

防超时与防截断

长任务有两类工程故障,各自有对策。

超时的表现是子代理或长步骤跑着跑着没了动静,调度方不知道该继续等还是重启。对策是进度心跳:每 30 秒输出一行当前进度,比如「正在处理功能点 7/23」。有心跳,调度方就知道任务活着;心跳停了,问题定位到具体功能点。配套手段是分批处理,大任务切成小批,单批超时的损失可控。子代理还有一条启动即通知的约定,主代理发出任务后先确认子代理接上了,再撒手不管。

截断的表现是写入工具的输出被长度限制悄悄切断,文档后半段缺失。对策有三条:超长内容分批读取,不一次性读入;写入被截断时用局部编辑补齐;补齐后复查节号连续性——功能点应从 1.1 排到 1.N,跳号就是截断的铁证。跳号检查是纯机械活,Grep 标题再排序一遍就完成。

重试与优雅降级

验证不通过之后怎么办,也要预先设计,不能临场发挥。流水线的规则是:质量门禁不通过,重新生成或修正,最多 3 次;3 次仍不通过,标记为「需人工审核」,继续处理其他文档。

text
如果输出包含 "✅ 质量验证通过":
    -> 质量通过,临时文件移动到最终位置,输出完成
如果输出包含 "⚠️ 质量门禁未通过":
    -> 重新生成或修正(最多3次)
3次仍不通过:
    -> 标记为"需人工审核",继续处理其他文档

这段伪代码出自模块合并的技能文档,三个数字值得注意。重试上限是 3 次不是 10 次,因为同一 prompt 重试多次仍失败,说明问题在任务本身而不是运气,继续重试只是浪费 token。降级不是报错中止,而是标记后继续,让单点失败不阻塞整条流水线,最后人工只处理带标记的少数文档。人工审核标记落在产物里而不是日志里,翻文档的人一眼能看到。

这种「失败一定要发生时就让它失败得体面」的思路,和我在另一个项目里给 AI 聊天窗做的降级四层防线是同一套哲学:超时拉闸、保留已交付的部分、冷却后短路重试、兜底文案留出路。

重试、降级、心跳、截断补齐,这四件事没有一件提升质量上限,但它们决定了质量下限——流水线跑十次,十次都能交付。

三层防线的适用边界

三层防线不是万能的。防得住的是结构性失败:丢任务、合并简化、截断、格式漂移,这些有数字锚点,脚本能判。防不住的是语义性失败:一句业务规则翻译得微妙地不准确,一个字段的业务含义写偏了,数字门禁发现不了,只能靠评审人对着链路图抽查。

所以这套体系的合理用法是:把结构性质量全部交给机器,把人的注意力全集中在语义质量上。人不再通读全文找丢失的表格,只复核脚本标出的「需人工审核」项和抽样比对关键规则。质量工程做不到消灭人工,能做到的是把人工用在刀刃上。

回看这三层,其实是一个通用的思路:对任何批量生成任务,先问验收标准能不能翻译成数字,再问数字能不能交给脚本,最后问失败之后系统往哪退。三个问题都有答案,大模型就可以放心用在生产线上。

三层防线管住了每一步的质量,下一篇讲怎么把任务拆给一群子代理并行干活:子代理并行:大规模任务的分治实践

Comments