小模型写的说明,怎么放心放进报告:巡检 agent 的三道输出校验

小模型写的说明,怎么放心放进报告 — 封面

上一篇《让只读 agent 真的只读》讲的是数据库巡检 agent 的输入一侧:它怎么碰数据库。这一篇讲输出一侧:本地小模型写出来的说明,怎么确定能放进报告。

分工:规则判问题,模型写说明

巡检报告里每个问题都由规则判出来:哪张表、什么检查、实际值多少、阈值多少、严重级别。这些是确定的事实,不交给模型。模型只负责两段文字:“可能原因”和“建议排查”,按问题编号输出一段 JSON。

这和我在项目顾问里用的是同一个思路。但巡检报告是给人照着去排查的,写错的代价更高,所以模型的输出在进报告之前要过三道校验。

第一道:每个问题都写到

小模型在问题多的时候常见的毛病是漏写,或者把两个问题合成一条。校验很简单:输出里的问题编号集合必须和输入完全一致,不多不少,每一项的两段文字都不能为空。

def check_coverage(issues, out):
    want = {i["id"] for i in issues}
    got = {o.get("id") for o in out}
    errs = [f"缺少 {x}" for x in sorted(want - got)]
    errs += [f"多出 {x}" for x in sorted(got - want)]
    errs += [f"{o['id']} 内容为空" for o in out
             if not o.get("cause", "").strip() or not o.get("action", "").strip()]
    return errs

第二道:不编数字

这是最容易出事的一项。模型喜欢写“数据已中断约 3 小时”“空值比例上升到 15%”这种看起来很具体的话,可输入里根本没有这两个数。读报告的人会信这些数字,然后按错误的方向去查。

做法是:把这个问题的输入事实里出现过的所有数字收集起来,模型文字里出现的每个数字都必须能在里面找到。

NUM = re.compile(r"\d+(?:\.\d+)?")

def numbers(text):
    return {float(x) for x in NUM.findall(text)}

def check_numbers(issue, text):
    allowed = numbers(json.dumps(issue, ensure_ascii=False))
    bad = [n for n in numbers(text)
           if not any(abs(n - a) <= 1e-6 * max(1, abs(a)) for a in allowed)]
    return [f"出现输入里没有的数字: {n:g}" for n in bad]

实际用起来要处理几种情况:

  • 格式不同但值相同:输入是 0.125,模型写成 12.5%。要么在输入里同时放好两种写法,要么在提示词里要求“百分比照抄输入的写法”。比较稳的是前者:事实里直接给出格式化好的字符串。
  • 日期和时间:日期里的 10、15 也是数字。把事实里的日期按模型可能用的写法展开一份,加进允许集合。
  • 序号和常识数字:“第一步”“检查 2 个方面”这类,更好的办法是在提示词里要求不用阿拉伯数字编号,而不是在校验里开白名单。白名单一开,口子就会越开越大。

这道校验宁严勿松。误杀一段本来正确的说明,代价只是退回模板;放过一个编出来的数字,代价是有人照着它去查。

第三道:不给危险建议

模型给“建议排查”时,有时会顺手写出“清理异常数据”“重启服务”“删除重复记录”。这些在某些情况下也许是对的,但不应该出现在一份自动生成的报告里:巡检只负责发现和定位,处置要由人判断。

校验用一个关键词清单,中英文都要有:删除、清空、清理数据、修改数据、重启、停止服务、DELETE、TRUNCATE、DROP、UPDATE、KILL 等。命中任何一个,这段输出就不合格。提示词里也写明了“只建议查看和核对,不建议任何修改、删除或重启”,但提示词只是降低概率,校验才是保证。

不合格怎么办:重试一次,再退回模板

  1. 重试一次,并把错误原因告诉模型。比如“K3 出现了输入里没有的数字 3”,比单纯重新生成有效得多。
  2. 还不合格,就用模板。每种检查类型都有一段规则写好的说明,比如数据新鲜度问题的模板是“查看数据写入程序是否在运行、上游是否有数据”。模板不如模型写得贴切,但永远是对的。
  3. 最好在报告里标出来源。每条说明后面注明是“模型”还是“模板”,读报告的人知道哪些是机器归纳的,心里有数。

三道校验是逐个问题做的:一个问题不合格,只有这一个退回模板,其他问题照常用模型的说明。模型完全连不上时,整份报告用模板生成,巡检本身不受影响。

怎么知道校验有用

我给它配了一个单独的评测脚本,用一批固定的问题样例反复让模型写说明,看有多少能通过校验、多少要退回模板。改提示词或换模型时跑一遍对比,和项目顾问的做法一样,看数字而不是看感觉。

评测集里值得放几条“诱导”样例:输入里只有一个数字,但问题描述很容易让人联想到具体的时长或比例。这类样例最能看出模型会不会编数字。

小结

小模型写的东西不是不能用,而是不能不检查就用。检查的标准要能用代码判定:编号齐不齐、数字有没有出处、有没有越界的建议。判定不过就退回一个保证正确的模板。这样模型写得好时报告更好读,写得不好时报告也不会出错。


上一篇
下一篇