4、基于规则的初筛引擎构建:编写正则表达式与业务规则,实现第一道筛选关卡
说实话,做材料筛选这件事,最怕的就是一上来就上AI模型。我见过太多团队,数据还没洗干净就直接上BERT,结果模型训出来全是噪音。我的习惯是——先搭一道规则的筛子,把明显不合格的材料挡在外面。
这一章,我们就来聊聊怎么构建这个「第一道关卡」。说白了,就是用正则表达式和业务规则,把那些格式不对、内容不全、明显造假的数据先过滤掉。你想想看,如果连文件后缀名都不对,还谈什么内容分析?
4.1 为什么需要规则引擎?
规则引擎不是万能的,但它有几个不可替代的好处:
- 速度快——正则匹配是毫秒级的,比任何模型都快
- 可解释——每一条规则都能说清楚为什么拦截
- 零成本——不需要训练数据,不需要GPU
- 防漏网——能堵住AI模型容易忽略的「低级错误」
我在项目中遇到过一件事:有个供应商提交的材料,AI模型分析后给了85分,但规则引擎发现它的「营业执照编号」只有14位(标准是18位)。嗯,这就是典型的AI盲区——模型只看语义,不看格式规范。
4.2 正则表达式:你的第一把刀
正则表达式这东西,很多人觉得难,其实你只要掌握几个核心模式就够了。我平时用的最多的,也就下面这几种:
| 用途 | 正则表达式 | 说明 |
|---|---|---|
| 手机号 | ^1[3-9]\d{9}$ |
11位,以1开头,第二位3-9 |
| 邮箱 | ^[\w.-]+@[\w.-]+\.\w+$ |
基础邮箱格式校验 |
| 统一社会信用代码 | ^[0-9A-HJ-NPQRTUWXY]{18}$ |
18位,不含I、O、S、V、Z |
| 金额(万元) | ^\d+(\.\d{1,2})?$ |
最多两位小数 |
| 日期(YYYY-MM-DD) | ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
带月份和日期校验 |
4.3 业务规则:把经验变成代码
正则只能管格式,业务规则才是真正的「灵魂」。举个例子:
假设我们要筛选「高新技术企业认定」的材料,业务规则可以这样设计:
# 伪代码示例:业务规则引擎
def apply_business_rules(material):
violations = []
# 规则1:注册时间必须满1年
if material.register_date > (today - timedelta(days=365)):
violations.append("注册时间不足1年")
# 规则2:知识产权数量至少1项
if material.ip_count < 1:
violations.append("无自主知识产权")
# 规则3:研发费用占比不低于3%
if material.rd_ratio < 0.03:
violations.append("研发费用占比不足3%")
# 规则4:高新技术产品收入占比不低于60%
if material.high_tech_revenue_ratio < 0.6:
violations.append("高新技术产品收入占比不足60%")
return violations
你看,这些规则其实都是政策文件里白纸黑字写着的。我们做的,就是把它们翻译成计算机能理解的逻辑。
4.4 规则引擎的架构设计
下面这张图是我个人比较推荐的规则引擎架构。它把规则分成了三个层次,每一层各司其职:
这个架构的好处是:每一层只关注自己的事。格式校验层不管业务逻辑,业务规则层不管交叉验证。出了问题,定位也快——哪一层报错,就查哪一层的规则。
4.5 实战:构建一个简单的初筛引擎
好了,理论说完了,我们来写点真东西。下面是一个用Python实现的简易初筛引擎:
import re
from datetime import datetime, timedelta
class MaterialScreener:
def __init__(self):
self.rules = []
self.load_default_rules()
def load_default_rules(self):
# 注册格式校验规则
self.add_rule('phone_format', lambda m: re.match(r'^1[3-9]\d{9}$', m.get('phone', '')), '手机号格式错误')
self.add_rule('email_format', lambda m: re.match(r'^[\w.-]+@[\w.-]+\.\w+$', m.get('email', '')), '邮箱格式错误')
self.add_rule('credit_code_format', lambda m: re.match(r'^[0-9A-HJ-NPQRTUWXY]{18}$', m.get('credit_code', '')), '统一社会信用代码格式错误')
# 注册业务规则
self.add_rule('register_time', lambda m: m.get('register_date', datetime.min) <= datetime.now() - timedelta(days=365), '注册时间不足1年')
self.add_rule('ip_count', lambda m: m.get('ip_count', 0) >= 1, '知识产权数量不足')
self.add_rule('rd_ratio', lambda m: m.get('rd_ratio', 0) >= 0.03, '研发费用占比不足3%')
def add_rule(self, name, func, message):
self.rules.append({'name': name, 'func': func, 'message': message})
def screen(self, material):
results = {'passed': True, 'violations': []}
for rule in self.rules:
try:
if not rule['func'](material):
results['passed'] = False
results['violations'].append(rule['message'])
except Exception as e:
results['passed'] = False
results['violations'].append(f"{rule['name']}执行异常: {str(e)}")
return results
# 使用示例
screener = MaterialScreener()
material = {
'phone': '13800138000',
'email': 'test@company.com',
'credit_code': '91310000MA1FL1WL9A',
'register_date': datetime(2022, 6, 1),
'ip_count': 3,
'rd_ratio': 0.05
}
result = screener.screen(material)
print(result)
# 输出:{'passed': True, 'violations': []}
4.6 规则引擎的维护与迭代
规则引擎不是写完就完事了。我个人的经验是,每两周做一次规则复盘:
- 看拦截率——某条规则拦截率突然飙升?可能是数据源变了,也可能是规则太严了
- 看误杀率——人工复核时,被规则拦截但实际合格的材料占比多少?超过5%就要调整
- 看漏网率——通过了规则但最终被AI判定不合格的,是不是有新的规则需要补充?
说白了,规则引擎是一个「活」的系统。它需要随着业务变化、政策调整、数据质量变化而不断进化。别指望一次性写完就一劳永逸——我在项目里见过最夸张的情况,一套规则用了两年没动过,结果政策都改了三轮了,拦截的全是「过时」的问题。
公众号:蓝海资料掘金营,微信deep3321