外观
AI正则质检闭环:从盲信大模型到样本自动验证
问题背景:AI 生成正则为什么不能直接上线
大模型生成正则表达式的速度很快,尤其面对“提取订单号”“校验工单号”“识别敏感手机号”等需求时,往往几秒钟就能给出一版结果。但正则的风险也恰恰藏在这种“看起来正确”里:训练数据中的写法可能过时,字符类可能漏写 Unicode 场景,贪婪匹配可能吞掉相邻字段,量词嵌套还可能触发灾难性回溯。
AI 正则质检的目标不是再请一个模型评价答案,而是建立一个可重复执行的工程闭环:先用标注样本自动验证,再把失败案例按风险和不确定性分流给人工审核,最后把审核结论沉淀为回归样本。这样,大模型负责提高规则生产效率,测试集和人工分级负责守住线上质量。
一个完整闭环包含四类输入:业务描述、候选正则、正例样本、反例样本;三类输出:通过率、失败明细、人工审核任务。
方案对比:三种 AI 正则验收方式怎么选
常见做法有三种。第一,纯 Prompt 复查,让模型解释正则并自我纠错,成本最低,但它无法证明边界样本是否通过,也容易出现“解释正确、代码错误”。第二,只做少量正例测试,能验证最常见输入,却无法发现误杀反例,例如把普通数字编号误识别为订单号。第三,样本集自动验证加人工分级,虽然前期要建设样本库,但能稳定发现漏匹配、误匹配、捕获组变化和性能退化,更适合生产环境。
建议把验收拆成三层:语法层检查是否可编译;语义层检查正例必须命中、反例必须拒绝、提取字段必须等于期望值;性能层用长文本和恶意构造文本检测回溯风险。自动验证无法判断“业务上像不像”时,再进入人工审核。
实操步骤:用 Python 搭建样本自动验证器
下面以“物流工单号提取”为例。业务规则:工单号以 SF 或 YT 开头,后接 10 到 12 位数字,允许前面出现“单号:”等文字,但不能从更长的字母数字串中截断。
候选正则如下:
python
import re
pattern = r"(?<![A-Za-z0-9])(?:SF|YT)\d{10,12}(?![A-Za-z0-9])"
rx = re.compile(pattern)逐段解析:
(?<![A-Za-z0-9])是负向后行断言,要求工单号前一位不是字母或数字,避免从XSF123...中截取出假单号。(?:SF|YT)匹配两个允许的前缀;?:表示只分组、不捕获,避免污染提取结果。\d{10,12}匹配 10 到 12 位数字。注意它会优先匹配 12 位,边界由后续断言控制。(?![A-Za-z0-9])是负向先行断言,防止 13 位以上数字或后续字母被截断。
接着构造带期望结果的样本。质检不能只存文本,还要存“应该匹配什么”,否则无法判断提取内容是否正确。
python
import time
cases = [
{
"id": "pos-1",
"text": "您的顺丰单号:SF1234567890,请注意签收。",
"expect": ["SF1234567890"],
"label": "positive",
},
{
"id": "pos-2",
"text": "YT987654321012 已揽收",
"expect": ["YT987654321012"],
"label": "positive",
},
{
"id": "neg-1",
"text": "订单编号 SF12345 太短",
"expect": [],
"label": "negative",
},
{
"id": "neg-2",
"text": "ABSF1234567890 是被污染的编号",
"expect": [],
"label": "negative",
},
{
"id": "boundary-1",
"text": "SF1234567890123 超过十二位",
"expect": [],
"label": "boundary",
},
]
def run_semantic_check(rx, cases):
failures = []
for case in cases:
got = [m.group(0) for m in rx.finditer(case["text"])]
if got != case["expect"]:
failures.append({
"id": case["id"],
"label": case["label"],
"text": case["text"],
"expect": case["expect"],
"got": got,
"reason": classify_failure(case, got),
})
return failures
def classify_failure(case, got):
if case["expect"] and not got:
return "漏匹配:正例未命中,可能前缀、位数或边界过严"
if not case["expect"] and got:
return "误匹配:反例被命中,重点检查边界断言和字符类"
return "结果不一致:检查贪婪匹配、捕获组或 findall 行为"
failures = run_semantic_check(rx, cases)
print("失败数:", len(failures))
for item in failures:
print(item["id"], item["reason"], item["got"])再加入性能检测。正则性能问题通常不在普通短句,而在重复量词、可选分组和长文本组合中暴露。
python
def run_perf_check(pattern, evil_text, timeout_seconds=0.05):
rx = re.compile(pattern)
start = time.perf_counter()
rx.search(evil_text)
cost = time.perf_counter() - start
return {
"cost_seconds": round(cost, 4),
"passed": cost <= timeout_seconds,
}
# 大量重复数字但不满足结尾边界,用来观察量词组合的回溯成本
evil_text = "SF" + "1" * 100000 + "!"
print(run_perf_check(pattern, evil_text))这里的 \d{10,12} 是有限量词,且后面紧跟边界断言,通常不会形成指数级回溯;但如果模型生成 (\d+)+$、(.*,)*X 这类嵌套重复结构,就必须在性能层阻断。
人工分级:让审核资源花在高风险样本上
自动验证的结果不应只有“通过/失败”。更实用的做法是分成四级:
- P0 阻断:反例命中,可能造成误拦截、错扣款、错误脱敏,直接禁止上线。
- P1 高风险复核:正例漏匹配,或核心字段提取错误,由规则负责人审核。
- P2 业务确认:正则行为确定,但样本标签存在歧义,例如历史单号是否算有效格式,由业务人员确认。
- P3 观察通过:全部样本通过且性能达标,先进入灰度日志,不立即全量生效。
可以用简单规则生成分级任务:
python
def triage(failures, perf_result):
if not perf_result["passed"]:
return "P0", "性能阈值超限,疑似灾难性回溯"
if any(f["label"] == "negative" and f["got"] for f in failures):
return "P0", "反例误匹配,可能扩大业务打击面"
if any(f["label"] == "positive" for f in failures):
return "P1", "正例漏匹配,影响召回"
if failures:
return "P2", "边界样本标签或期望结果需确认"
return "P3", "自动验证通过,建议灰度观察"
level, advice = triage(failures, run_perf_check(pattern, evil_text))
print(level, advice)人工确认后的样本要回流:新增反例防止规则再次放宽,新增正例防止修复时过度收紧。每次大模型生成的新版本都跑同一套回归集,才能形成真正的 AI 正则质检闭环。
避坑总结:生产环境里的具体注意事项
第一,不要用 \\d 想当然地只表示 ASCII 数字。 在 Python 3 中,默认正则下 \d 能匹配部分 Unicode 数字字符,可能把阿拉伯文数字等也算作编号。若业务只要 0-9,应改成 [0-9]{10,12};常见错误现象是测试英文数字全部通过,线上却提取出含非 ASCII 数字的“单号”。
第二,不要只测 search 是否命中,还要校验完整匹配值。 很多 AI 生成正则包含多个捕获组,使用 findall 时返回元组,代码却按字符串处理,导致下游字段为空。修正方法是统一使用 finditer 并取 group(0) 或命名组 group("order_no"),在样本里填写精确期望。
第三,不要忽略前后边界。 典型错误是 (SF|YT)\d{10,12},它会从 ABSF1234567890 中提取出看似合法的片段。应增加 (?<![A-Za-z0-9]) 和 (?![A-Za-z0-9]),并把污染编号加入反例回归集。
第四,不要把性能测试放在很短的样本文本上。 普通句子通过不代表安全,嵌套量词遇到“几乎匹配但最后失败”的长文本可能急剧变慢。应为每类规则准备超长重复串、缺失终止符文本和大量分隔符文本,并设置毫秒级阈值。
第五,不要让人工审核只看正则本身。 审核人员必须同时看到业务描述、原始样本、期望结果、实际命中片段和失败类型。只给一串正则,人工很容易被复杂表达式震慑并点头通过;给足上下文,才能把经验转化为可回归的样本资产。
最终,AI 生成的是候选规则,不是上线承诺。把样本自动验证作为硬门槛,把人工分级作为风险闸门,再把每次审核结论沉淀回测试集,正则规则才能在高频迭代中保持可信。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。