☰
智能核保系统毕业设计:Python规则引擎实现自动核保与风险评估
2026/10/18 16:37:00 网站建设 项目流程

简介:这份资源是重庆工商大学2023届毕业设计项目「智能核保系统」的完整源码包,面向计算机相关专业学生、Python后端初学者以及需要参考毕设实现思路的开发者。项目围绕保险核保业务场景,提供了一套可运行的系统实现,适合用于课程设计、毕业设计参考或后端开发练手。压缩包共42个文件,整体约29KB,以32个Python源码文件为核心,涵盖业务逻辑与后端服务;另含4个Shell脚本用于环境与数据库初始化,以及Dockerfile、requirements.txt、README.md、HTML模板和配置文件等,便于快速部署与二次开发。目录中可见server、apps、templates、manage.py等模块,结构清晰,体现了Django风格的项目组织方式。目前已有131人学习下载,读者可从中获取完整的项目目录结构、核保业务代码实现、依赖清单与容器化部署脚本,并参考其模块划分与配置方式,用于理解一个真实毕设项目的落地过程。

1. 从一份毕业设计压缩包说起:智能核保系统能解决什么问题

保险核保这件事,外行看是填表、体检、等通知,内行看是一堆规则引擎在打架。一个投保人提交申请后,核保员要对照健康告知、年龄、职业、既往病史、保额、险种等几十个维度逐条判断,给出标准承保、加费承保、除外承保还是拒保的结论。人工做这件事,一份单子少则几分钟,复杂件要半小时以上,而且不同核保员对同一条规则的尺度把握还不一样。这份「智能核保系统」要干的事,就是把这套判断逻辑搬到代码里,让系统自动跑规则、自动出结论,把核保员从重复劳动里解放出来。

这个项目是某高校 2023 年的毕业设计,技术栈以 Python 为主,适合两类人:一类是正在做类似选题的学生,想找一个能跑通、结构完整的参考实现;另一类是刚入行的后端开发,想看看规则引擎、决策树这类东西在真实业务场景里怎么落地。它不是一个玩具 Demo,而是把「用户提交投保单 → 系统逐条核保 → 输出核保结论 → 记录核保日志」这条链路完整走通了。下面我从项目结构、核心模块、运行方式到二次开发,一层层拆开讲。

2. 项目结构与技术选型:一个核保请求从进入到返回要经过哪些模块

2.1 目录结构总览

拿到压缩包解压后,常见的目录组织方式是这样的(不同版本可能略有差异,但核心模块不会变):

intelligent_underwriting/ ├── app/ │ ├── __init__.py │ ├── models/ # 数据模型层 │ │ ├── applicant.py # 投保人信息模型 │ │ ├── policy.py # 保单模型 │ │ └── underwriting.py # 核保记录模型 │ ├── rules/ # 核保规则引擎 │ │ ├── base_rule.py # 规则基类 │ │ ├── health_rule.py # 健康告知规则 │ │ ├── age_rule.py # 年龄规则 │ │ ├── occupation_rule.py # 职业风险规则 │ │ └── rule_engine.py # 规则调度引擎 │ ├── services/ # 业务服务层 │ │ ├── underwriting_service.py # 核保主流程 │ │ └── risk_service.py # 风险评估服务 │ ├── api/ # 接口层 │ │ └── routes.py # 路由定义 │ └── utils/ # 工具函数 │ ├── logger.py │ └── validators.py ├── config.py # 配置文件 ├── requirements.txt # 依赖清单 ├── run.py # 启动入口 └── tests/ # 测试用例 └── test_rules.py

这个结构是典型的 Flask 分层架构:models管数据,rules管规则,services管流程编排,api管对外接口。分层的好处是改规则不用动接口,改接口不用动规则,各层职责清晰。

2.2 技术选型与依赖说明

项目以 Python 为主语言,常见搭配是 Flask 做 Web 框架、SQLAlchemy 做 ORM、SQLite 做开发数据库。requirements.txt里一般会包含这些:

Flask==2.3.2 SQLAlchemy==2.0.19 Flask-SQLAlchemy==3.0.5 pydantic==2.0.3 pytest==7.4.0

选 Flask 而不是 Django,是因为核保系统本质是一个规则计算服务,不需要 Django 那套完整的 Admin 和模板体系,Flask 更轻,启动快,改起来也直接。SQLite 适合毕业设计场景,零配置,一个文件就是数据库,换到 MySQL 只需要改config.py里的连接串。

提示:如果requirements.txt里的版本号和你本地 Python 版本冲突,优先保证 Flask 和 SQLAlchemy 大版本一致,小版本可以放宽。

2.3 核保请求的完整链路

一个核保请求进来后,经过的路径是这样的:

  1. api/routes.py接收 POST 请求,解析投保人 JSON 数据
  2. services/underwriting_service.py调用rule_engine启动规则链
  3. rule_engine按优先级依次执行health_rule、age_rule、occupation_rule
  4. 每条规则返回pass、warn或reject,引擎汇总所有结果
  5. 汇总结果映射为最终核保结论,写入underwriting表
  6. 返回 JSON 响应给调用方

这条链路的关键设计是「规则链 + 结果汇总」,而不是「一条规则否决全部」。这样做的原因是核保业务里,有些规则是硬性拒保(比如确诊某类疾病),有些是软性提示(比如年龄偏大建议加费),需要区分处理。

3. 核心模块拆解:规则引擎、健康告知与风险评估怎么写的

3.1 规则基类与规则引擎

规则引擎的核心是抽象出一个基类,所有具体规则继承它,实现自己的evaluate方法。先看基类:

# app/rules/base_rule.py from abc import ABC, abstractmethod class BaseRule(ABC): """所有核保规则的基类""" def __init__(self, name, priority=0): self.name = name # 规则名称 self.priority = priority # 优先级,数字越小越先执行 @abstractmethod def evaluate(self, applicant_data): """ 执行规则判断 :param applicant_data: dict,投保人信息 :return: dict,包含 result(pass/warn/reject) 和 reason """ pass def __repr__(self): return f"<Rule: {self.name}, priority={self.priority}>"

这个基类定义了规则的统一接口:name标识规则,priority控制执行顺序,evaluate是具体判断逻辑。用ABC抽象基类而不是普通类,是为了强制子类必须实现evaluate,避免漏写导致运行时才报错。

规则引擎负责调度所有规则:

# app/rules/rule_engine.py from app.rules.health_rule import HealthRule from app.rules.age_rule import AgeRule from app.rules.occupation_rule import OccupationRule class RuleEngine: """核保规则调度引擎""" def __init__(self): # 注册规则,按优先级排序 self.rules = sorted([ HealthRule(), AgeRule(), OccupationRule(), ], key=lambda r: r.priority) def run(self, applicant_data): """ 执行所有规则,汇总结果 :param applicant_data: dict :return: dict,包含最终结论和每条规则的明细 """ results = [] final_result = "pass" # 默认通过 for rule in self.rules: result = rule.evaluate(applicant_data) results.append({ "rule": rule.name, "result": result["result"], "reason": result["reason"] }) # 一旦出现 reject,直接终止,不再执行后续规则 if result["result"] == "reject": final_result = "reject" break # warn 不终止,但会拉低最终结论 if result["result"] == "warn" and final_result == "pass": final_result = "warn" return { "final_result": final_result, "details": results }

这段代码有两个关键设计点。第一,规则按priority排序执行,健康告知优先级最高,因为它是核保里最硬的指标。第二,reject会短路终止,warn只降级不终止。这个逻辑对应真实核保场景:如果投保人确诊了拒保疾病,后面的年龄、职业规则就没必要跑了;但如果只是年龄偏大,系统应该继续检查其他维度,最后给出「加费承保」的结论。

3.2 健康告知规则的具体实现

健康告知是核保里最复杂的部分,通常用问卷形式收集,每条问题对应一个风险因子。实现上一般用字典映射:

# app/rules/health_rule.py from app.rules.base_rule import BaseRule class HealthRule(BaseRule): """健康告知规则:根据问卷结果判断风险等级""" # 拒保疾病清单 REJECT_DISEASES = { "malignant_tumor": "恶性肿瘤", "severe_heart_disease": "严重心脏病", "aids": "艾滋病", "severe_mental_illness": "严重精神疾病" } # 加费疾病清单 WARN_DISEASES = { "hypertension": "高血压", "diabetes": "糖尿病", "hepatitis_b": "乙肝" } def __init__(self): super().__init__(name="健康告知规则", priority=1) def evaluate(self, applicant_data): health_info = applicant_data.get("health_info", {}) # 检查拒保疾病 for disease_key, disease_name in self.REJECT_DISEASES.items(): if health_info.get(disease_key): return { "result": "reject", "reason": f"确诊{disease_name},不符合承保条件" } # 检查加费疾病 warn_reasons = [] for disease_key, disease_name in self.WARN_DISEASES.items(): if health_info.get(disease_key): warn_reasons.append(disease_name) if warn_reasons: return { "result": "warn", "reason": f"存在{','.join(warn_reasons)},建议加费承保" } return {"result": "pass", "reason": "健康告知无异常"}

这里用两个字典分别管理拒保和加费疾病,好处是新增疾病只需要加一行配置,不用改判断逻辑。health_info是一个布尔字典,前端问卷的每个问题对应一个 key,用户勾选后传True。这种设计在毕业设计里很常见,简单直接,也方便答辩时演示。

3.3 年龄与职业规则的参数化配置

年龄规则和职业规则相对简单,但参数需要可配置,不能写死在代码里:

# app/rules/age_rule.py from app.rules.base_rule import BaseRule class AgeRule(BaseRule): """年龄规则:不同年龄段对应不同核保结论""" # 年龄区间配置:(最小年龄, 最大年龄, 结论, 说明) AGE_CONFIG = [ (0, 17, "warn", "未成年,需监护人投保"), (18, 50, "pass", "标准承保年龄段"), (51, 60, "warn", "年龄偏大,建议加费"), (61, 200, "reject", "超出承保年龄上限") ] def __init__(self): super().__init__(name="年龄规则", priority=2) def evaluate(self, applicant_data): age = applicant_data.get("age") if age is None: return {"result": "reject", "reason": "年龄信息缺失"} for min_age, max_age, result, reason in self.AGE_CONFIG: if min_age <= age <= max_age: return {"result": result, "reason": reason} return {"result": "reject", "reason": "年龄不在承保范围内"}

职业规则同理,用职业风险等级(1-6 类)映射核保结论。这类规则的特点是「配置驱动」,把业务参数从代码里抽出来,改规则不用改逻辑。我一般会把这类配置放到config.py或者单独的 YAML 文件里,方便非技术人员调整。

3.4 核保服务层的流程编排

服务层负责把规则引擎、数据持久化和日志串起来:

# app/services/underwriting_service.py from app.rules.rule_engine import RuleEngine from app.models.underwriting import UnderwritingRecord from app.utils.logger import logger class UnderwritingService: """核保主流程服务""" def __init__(self, db_session): self.engine = RuleEngine() self.db = db_session def process(self, applicant_data): """ 处理核保请求 :param applicant_data: dict,投保人信息 :return: dict,核保结论 """ logger.info(f"开始核保,投保人: {applicant_data.get('name')}") # 1. 执行规则引擎 result = self.engine.run(applicant_data) # 2. 持久化核保记录 record = UnderwritingRecord( applicant_name=applicant_data.get("name"), applicant_age=applicant_data.get("age"), final_result=result["final_result"], detail=result["details"] ) self.db.add(record) self.db.commit() logger.info(f"核保完成,结论: {result['final_result']}") return result

服务层不关心规则怎么判断,只负责「调用引擎 → 存记录 → 打日志」这条流水线。这种分层让单元测试变得容易:测规则就 mock 数据直接调evaluate,测服务就 mock 引擎返回固定结果。

4. 跑起来才算数:环境搭建、启动与接口验证

4.1 环境准备与依赖安装

先确认 Python 版本,建议 3.9 以上:

python --version # Python 3.9.13

然后创建虚拟环境并安装依赖:

# 创建虚拟环境 python -m venv venv # 激活(Windows) venv\Scripts\activate # 激活(Mac/Linux) source venv/bin/activate # 安装依赖 pip install -r requirements.txt

如果安装过程中SQLAlchemy编译报错,通常是缺少 C 编译环境,Windows 下装个 Visual C++ Build Tools 就能解决,Mac 下xcode-select --install即可。

4.2 数据库初始化与启动

项目一般会在run.py里做数据库初始化:

# run.py from app import create_app, db from app.models import applicant, policy, underwriting app = create_app() if __name__ == "__main__": with app.app_context(): db.create_all() # 自动建表 app.run(host="0.0.0.0", port=5000, debug=True)

启动命令:

python run.py

看到Running on http://0.0.0.0:5000就说明起来了。debug=True模式下改代码会自动重启,开发时很方便,但上线要关掉。

4.3 接口调用验证

核保接口一般是 POST/api/underwriting,用 curl 测一下:

curl -X POST http://127.0.0.1:5000/api/underwriting \ -H "Content-Type: application/json" \ -d '{ "name": "张三", "age": 35, "occupation_risk": 2, "health_info": { "hypertension": true, "diabetes": false, "malignant_tumor": false } }'

预期返回:

{ "final_result": "warn", "details": [ {"rule": "健康告知规则", "result": "warn", "reason": "存在高血压,建议加费承保"}, {"rule": "年龄规则", "result": "pass", "reason": "标准承保年龄段"}, {"rule": "职业规则", "result": "pass", "reason": "职业风险等级可承保"} ] }

这个返回说明系统正确识别了高血压这个加费因子,年龄和职业都没问题,最终结论是「加费承保」。如果返回reject,看details里哪条规则触发了拒保,就知道问题出在哪。

4.4 单元测试跑一遍

项目里一般带了tests/test_rules.py,直接跑:

pytest tests/ -v

测试用例通常覆盖这几种场景:健康告知全通过、有加费疾病、有拒保疾病、年龄超限、职业高风险。跑通测试说明规则逻辑没问题,改代码后也能快速回归。

5. 避坑与常见问题:跑不起来、结果不对、改规则翻车怎么办

5.1 启动报 ModuleNotFoundError

现象:python run.py报ModuleNotFoundError: No module named 'app'。

原因:启动时工作目录不对,或者虚拟环境没激活,Python 找不到app包。

解决:确认在项目根目录(有run.py的那层)执行命令,并且虚拟环境已激活。如果还不行,在run.py开头加import sys; sys.path.insert(0, '.')把当前目录加入路径。

5.2 数据库表不存在

现象:调用接口报no such table: underwriting_record。

原因:db.create_all()没执行,或者执行时模型没被导入。

解决:确保run.py里db.create_all()在app.app_context()内执行,并且app/models/__init__.py里导入了所有模型类。SQLAlchemy 只对已导入的模型建表,漏导入就不会建。

5.3 规则执行顺序不对导致结论异常

现象:明明有拒保疾病,返回的却是warn。

原因:规则priority设置反了,或者RuleEngine里排序逻辑写错。

解决:检查每条规则的priority,健康告知应该是 1,年龄 2,职业 3。sorted默认升序,数字小的先执行。如果想让拒保规则优先,就把它的 priority 设成最小。

5.4 修改规则后测试全挂

现象:改了一条规则的判断逻辑,跑pytest一堆失败。

原因:测试用例里硬编码了预期结果,规则一改就对不上。

解决:测试用例应该测「输入 → 输出」的映射关系,而不是测具体实现。改规则时同步更新测试预期,或者把测试数据参数化,用@pytest.mark.parametrize管理多组用例。

5.5 接口返回中文乱码

现象:curl 返回的 JSON 里中文显示为\uXXXX。

原因:Flask 默认JSON_AS_ASCII=True,会把非 ASCII 字符转义。

解决:在config.py里设置JSON_AS_ASCII = False,或者升级到 Flask 2.3 后用app.json.ensure_ascii = False。这不影响程序解析,只是可读性问题。

6. 二次开发怎么改:从规则扩展到模型替换的实操思路

拿到这个项目后,最常改的三个方向是:加规则、换数据库、接前端。下面分别说。

加一条新规则,比如「保额规则」:在app/rules/下新建amount_rule.py,继承BaseRule,实现evaluate方法,然后在RuleEngine.__init__里注册进去。注意priority要排在合适的位置,保额规则一般放在健康告知之后、年龄之前。改完后在tests/里加对应的测试用例,跑一遍pytest确认没破坏原有逻辑。

换数据库,从 SQLite 换到 MySQL:改config.py里的SQLALCHEMY_DATABASE_URI,格式是mysql+pymysql://user:password@host:port/dbname,然后pip install pymysql。注意 MySQL 下建表要用db.create_all()或者 Alembic 迁移,SQLite 的create_all在 MySQL 下同样适用,但字段类型可能有差异,比如Text和String的长度限制。

接前端,如果要做成 Web 页面:在app/api/routes.py里加一个返回 HTML 的路由,或者单独起一个前端项目通过 CORS 调接口。Flask 这边需要装flask-cors,配置CORS(app)允许跨域。前端表单字段要和applicant_data的 key 对齐,尤其是health_info里的疾病 key,拼错一个就判断不出来。

一个实用技巧:把规则配置抽到 YAML 文件里。比如年龄区间、疾病清单这些,写在rules_config.yaml里,启动时加载。这样改规则不用动 Python 代码,非技术人员也能维护。我一般会写一个load_rules_config()函数,在RuleEngine初始化时调用,把配置注入到各条规则里。

# app/utils/config_loader.py import yaml def load_rules_config(path="rules_config.yaml"): with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f) # 在 AgeRule 里使用 class AgeRule(BaseRule): def __init__(self, config=None): super().__init__(name="年龄规则", priority=2) self.age_config = config or self.AGE_CONFIG

这个改动不大,但让整个系统的可维护性上了一个台阶。从那以后我每次做规则类项目,都强制把业务参数和代码逻辑分开,哪怕初期只有两三条规则——因为规则这东西,一定会越加越多,等到二十条的时候再重构,成本就高了。

希望这个拆解能帮你把项目跑起来,也帮你在二次开发时少走点弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询