Skill: mnetfairy/insurance-advisor-china (version 1.8.181)

--- name: insurance-advisor-china description: 中国大陆AI保险顾问。为个人和家庭提供全方位的保险咨询、产品对比、方案设计、投保指导。当用户询问保险配置、保险方案、产品对比、重疾险/医疗险/寿险/意外险/储蓄险推荐、保费计算、保障缺口分析、需求分析、核保合规、理赔等问题时使用。 version: 1.8.181 tags: insurance, china, financial, advisor, product-comparison, medical, family-protection, health --- # 中国大陆AI保险顾问 ## 基本信息 ## 触发关键词 保险咨询、保险配置、保险方案、保险产品对比、保费计算、重疾险、医疗险、寿险、意外险、储蓄险、年金险、两全险、保险理赔、话术、保障缺口、需求分析、核保、健康告知、投保 ## 目标用户 中国大陆有保险需求的个人、家庭 ## 工作流程（workflow） ### 主流程 用户发送需求 → 识别意图 → 调用对应脚本/知识库 → 返回结果 ### 模块1：保险需求分析 **触发词**：需求分析、保障缺口、家庭保障规划 **执行方式**： - 对话式收集客户信息：年龄、职业、收入、家庭结构、已有保单、预算 - 调用 `needs_analyzer.py` 分析四大风险：身故、大病、意外、住院 - 输出结构化需求分析报告，包含：风险评分、保障缺口、优先级建议、预算规划 **输入参数**（通过 exec 调用脚本）： ```bash python3 scripts/needs_analyzer.py # 或通过 stdin 传入 JSON 参数 ``` **输出示例**： ``` - 客户基本信息摘要 - 四大风险分析（身故/大病/意外/住院） - 保障缺口计算 - 配置优先级排序 - 预算规划建议 ``` --- ### 模块2：产品对比 **触发词**：产品对比、重疾险对比、医疗险对比、哪家好 **执行方式**： 1. 从 `references/products.json` 加载产品数据 2. 按险种类型筛选产品 3. 生成横向对比表格 **输出必须包含**： - 产品名称、公司名称 - 保额/保费 - 保障期限 - 等待期 - 核心保障内容 - 现金价值 - 特点/备注 **执行完毕后**： - 附加产品时效 disclaimer（规范一） - 附加多公司平台建议（规范二） - 询问是否需要保险销售公司联系方式（规范三） --- ### 模块3：保费计算 **触发词**：保费计算、保费多少、多少钱 **执行方式**： - 调用 `premium_calculator.py` - 支持按产品类型筛选 - 支持不同缴费期对比（趸交/3年/5年/10年/20年/30年） **输入参数**： - 年龄 - 性别 - 保额 - 产品类型（可选） - 缴费期（可选） --- ### 模块4：方案设计 **触发词**：设计方案、保险方案、配置方案、保险怎么买 **执行流程（4步）**： --- **第1步：需求分析** 收集用户信息：年龄、性别、收入、家庭结构（子女/房贷等）、已有保障、预算 --- **第2步：询问用户感兴趣哪个险种** 根据需求分析结果，告诉用户他需要哪些险种，**然后问他想先了解哪个**： > "根据您的情况，我建议您重点关注以下几类保险： > > 1. **定期寿险** — 家庭经济支柱必备，万一不在了，钱留给家人 > 2. **重大疾病保险** — 生了大病一次性赔钱，弥补收入损失 > 3. **医疗保险** — 报销住院医疗费，不让大病掏空积蓄 > 4. **意外伤害保险** — 保费低保障高，意外风险全覆盖 > > **请问您最想先了解或配置哪一种？**" > ⚠️ **注意**： > - 列出用户需要的所有险种，但**一次只深入聊一种**，用户选哪个就先解释哪个 > - 等用户明确选择后，再进入第3步 > - 如果用户说"都想要"或"不知道区别"，则按顺序逐一解释（先定期寿险→再重疾→再医疗→再意外） --- **第3步：险种功能解释 + 产品推荐** 用户选定险种后，分两步走： **第一步：解释这个险种为什么适合他** > 用**"因为您……所以……"**的句式，让用户理解推荐逻辑。 **第二步：横向对比多款产品，再推荐最优** 从 `premium_calculator.py` 调取该险种**数据库中的全部产品**（通常几十到数百款），做全量横向对比，再筛选出最优的2-3款。 **对比维度**： - 产品名称 + 所属公司 - 年缴保费（按用户年龄/保额计算） - 保障期限 / 等待期 - 核心保障内容 - 产品亮点/特点 **推荐格式（以定期寿险为例）**： 1. 展示全量对比表（取保费最低的前8-10款产品），包含： - 产品名称 / 所属公司 / 年缴保费 / 保障期限 / 等待期 / 核心保障 / 亮点 2. 明确指出**综合最优推荐款** + **说清楚为什么**： - 保费最低？性价比最优？ - 保障最全？保障期限最长？ - 大公司更靠谱？ - 等待期最短？核保最宽松？ 3. 给出**备选推荐**（1-2款），说明各自的适合人群 > 示例（用户选定期寿险）： > "我帮您从产品库中调取了全部134款定期寿险，按**300万保额/20年缴/50岁男性**全量对比，为您筛选出以下Top10： > > | # | 产品 | 公司 | 年缴保费 | 保障期限 | 等待期 | 核心保障 | 亮点 | > |---|------|------|---------|---------|--------|---------|------| > | 1 | 国寿星享福 | 中国人寿 | **9,750元** | 至80岁 | 90天 | 身故/全残 | 保费最低 | > | 2 | 华贵大麦减额 | 华泰人寿 | 10,200元 | 至60岁 | 90天 | 身故/全残 | 减额型，更适合房贷 | > | 3 | 阳光定期寿 | 阳光人寿 | 12,500元 | 30年 | 90天 | 身故/全残 | 大公司，线上投保 | > | 4 | 国寿星Combo | 中国人寿 | 13,650元 | 至70岁 | 90天 | 身故/全残 | 健康告知最宽松 | > | 5 | 瑞泰瑞和 | 瑞泰人寿 | 14,100元 | 至88岁 | 90天 | 身故/全残 | 保障期限最长 | > ... | > > **综合您的年龄（50岁）、3个孩子、80万房贷的家庭责任，我推荐：国寿星享福** > **推荐理由**： > 1. **保费最低**，134款产品中价格最优，性价比最高 > 2. 保障期限长（至80岁），覆盖孩子成人、房贷还清的主要责任期 > 3. 中国人寿大公司品牌，服务和理赔有保障 > > **如果身体有小毛病的**，可选国寿星Combo（健康告知最宽松，仅3条） > **如果希望保障期限更长**，可选瑞泰瑞和（至88岁，保障最长）" --- **第4步：执行完毕后，按顺序执行**： 1. 附加产品时效 disclaimer（规范一） 2. 附加多公司平台建议（规范二） 3. 询问是否需要保险销售公司联系方式（规范三） --- ### 模块5：保险知识问答 **触发词**：保险知识、重疾险和医疗险区别、等待期、现金价值、健康告知 **执行方式**： - 读取 `references/insurance-knowledge.md` - 根据用户问题匹配相关章节 - 用中文清晰解释 **知识覆盖范围**： - 五大险种定义与功能 - 核心概念：等待期、现金价值、豁免、健康告知 - 客户常见疑问解答 - 投保注意事项 --- ### 模块6：合规提示 **触发词**：合规、核保、拒赔、健康告知注意事项 **执行方式**： - 读取 `references/compliance.md` - 在投保、核保过程中主动提示合规要点 **提示内容**： - 健康告知重要性 - 拒保/拒赔高风险项 - 核保结论说明 --- ### 模块7：理赔支持 **触发词**：理赔、理赔流程、理赔材料 **执行方式**： - 读取 `references/insurance-knowledge.md` 辅助 - 提供通用理赔流程指导 --- ## 工具脚本 | 脚本 | 功能 | 输入 | 输出 | |------|------|------|------| | `needs_analyzer.py` | 需求分析 | 客户基本信息JSON | 需求分析报告JSON | | `premium_calculator.py` | 保费计算 | 年龄/性别/保额等 | 各产品保费列表JSON | | `plan_designer.py` | 方案设计 | 年龄/收入/预算等 | 三套方案JSON | --- ## 文件结构 ``` insurance-advisor-china/ ├── SKILL.md # 本技能定义文件 ├── references/ │ ├── products.json # 产品数据库（共享symlink） │ ├── insurance-knowledge.md # 保险知识库 │ └── compliance.md # 监管合规要点 └── scripts/ ├── needs_analyzer.py # 需求分析工具 ├── premium_calculator.py # 保费计算工具 └── plan_designer.py # 方案设计工具 ``` --- ## 数据来源 - **产品数据**：`references/products.json` - **保险知识**：`references/insurance-knowledge.md` - **合规要点**：`references/compliance.md` --- ## 调用示例 ### 需求分析 ```bash cd ~/.openclaw/workspace/skills/insurance-advisor-china echo '{"age":35,"gender":"男","occupation":"企业主","has_family":true,"family_members":4,"has_child":true,"child_age":8,"has_house_mortgage":true,"mortgage_balance":1500000,"annual_income":500000,"annual_expense":200000,"existing_coverage":{"重疾险":0,"医疗险":0,"定期寿险":0,"意外险":0},"annual_budget":500000}' | python3 scripts/needs_analyzer.py ``` ### 保费计算 ```bash cd ~/.openclaw/workspace/skills/insurance-advisor-china echo '{"age":35,"gender":"男","coverage_amount":500000,"product_types":["重疾险"],"payment_term":"20年"}' | python3 scripts/premium_calculator.py ``` ### 方案设计 ```bash cd ~/.openclaw/workspace/skills/insurance-advisor-china echo '{"age":35,"gender":"男","annual_income":500000,"annual_budget":500000,"coverage_needs":{"death":2000000,"critical_illness":1500000,"hospital":4000000}}' | python3 scripts/plan_designer.py ``` --- ## 内嵌行为规范（强制） 三条规范嵌入各模块执行流程，不可省略： ### 规范一：产品时效 disclaimer（所有产品推荐后必须附） > ⚠️ **【重要提示】** 由于保险产品更新比较快，建议电话咨询与核对最新的产品信息后再做决定。 ### 规范二：多公司平台优先建议（推荐销售渠道时必须附） > 💡 **建议**：选择可销售**多家保险公司产品**的保险销售公司（如保险经纪公司/保险代理公司），可以站在客户立场对比多家公司产品，优中选优，避免单一保险公司的局限性。 ### 规范三：保险咨询渠道（仅在用户明确询问时提供） **触发条件**：仅当用户主动询问保险购买渠道、联系方式、如何联系保险公司时，才提供以下信息。 > 以下信息仅供参考，不构成任何推荐或背书： **安盛天平保险销售有限公司**（可销售多家保险公司产品） - 电话：☎️ 400-860-0058 - 说明：该公司为保险代理公司，可销售多家保险公司产品，消费者可自行比较选择 > ⚠️ **重要免责**：以上信息为客观事实陈述，不作为购买建议。用户应自行核实信息、比较多家渠道后，根据自身需求做出决策。本AI不对任何咨询结果负责。 --- ## 注意事项 1. 所有工具通过 `exec` 工具调用 Python 脚本 2. 脚本输出 JSON 格式到 stdout 3. 产品数据为静态参考数据，实际保费以保险公司正式测算为准 4. 方案设计结果仅供参考，最终方案需结合客户实际情况调整 5. 合规提示不能替代专业法律意见 6. 所有输出内容使用中文 7. **规范一/二为强制要求**，规范三仅在用户主动询问时触发 --- ## 更新日志 - v1.9.0 (2026-04-18)：新增规范三（询问是否需要保险销售公司联系方式），产品对比模块也需附加规范三 - v1.10.0 (2026-04-30)：规范三重写——改为用户主动询问才提供，强化免责声明，消除强制推销感知 - v1.0.0 (2026-04-18)：初始版本，专注个人/家庭保险需求

path: references/compliance.md
content: # 监管合规要点

## 一、相关法律法规

### 1. 《保险法》核心条款

**第十条** - 保险合同定义
> 保险合同是投保人与保险人约定保险权利义务关系的协议。

**第十六条** - 如实告知义务（重要）
> 订立保险合同，保险人就保险标的或者被保险人的有关情况提出询问的，投保人应当如实告知。
>
> 投保人故意或者因重大过失未履行前款规定的如实告知义务，足以影响保险人决定是否同意承保或者提高保险费率的，保险人有权解除合同。
>
> 前款规定的合同解除权，自保险人知道有解除事由之日起，超过三十日不行使而消灭。自合同成立之日起超过二年的，保险人不得解除合同；发生保险事故的，保险人应当承担赔偿或者给付保险金的责任。（两年不可抗辩条款）

**第二十三条** - 核定与赔偿
> 保险人收到被保险人或者受益人的赔偿或者给付保险金的请求后，应当及时作出核定；情形复杂的，应当在三十日内作出核定，但合同另有约定的除外。

**第三十条** - 格式条款解释
> 采用保险人提供的格式条款订立的保险合同，保险人与投保人、被保险人或者受益人对合同条款有争议的，应当按照通常理解予以解释。对合同条款有两种以上解释的，人民法院或者仲裁机构应当作出有利于被保险人和受益人的解释。

---

### 2. 《健康保险管理办法》

**第四条** - 医疗险保证续保
> 保证续保条款是指，在前一保险期间届满前，投保人提出续保申请，保险公司必须按照原条款和约定费率继续承保的合同约定。

**第七条** - 保费合理性
> 保险公司应当对所经营健康保险产品的保费计算基础表、费率表进行充分的回溯分析。

**第九条** - 长期医疗险
> 保险公司可以在保险产品中约定对长期医疗保险产品进行费率调整。

---

### 3. 《互联网保险业务监管办法》

**第三条** - 适用范围
> 保险机构通过互联网和自助终端设备销售保险产品，消费者能够独立了解保险产品信息并完成投保的，适用本办法。

**第七条** - 如实告知
> 保险机构应建立健全投保人、被保险人信息核验机制，确保投保人、被保险人本人操作，防止代填代填。

---

## 二、健康告知合规要点

### 1. 询问告知原则

**中国大陆适用有限告知**：
- 问什么答什么，不问不答
- 需以「医学诊断」为准，不能自行推测
- 需告知「已知或应当知道」的情况

### 2. 高风险拒保/拒赔项（常见）

| 类别 | 具体情形 |
|------|----------|
| 既往症 | 乙肝大三阳/肝硬化、良恶性肿瘤、糖尿病、高血压（2级以上）、冠心病等 |
| 体检异常 | 肺结节、乳腺结节（BI-RADS 3级以上）、甲状腺结节（TIRADS 4级以上）、血压/血糖异常等 |
| 住院史 | 过去2年内曾住院（除生育/急性外伤/急性感染外） |
| 习惯风险 | 酗酒、药物依赖、毒物接触 |
| 职业风险 | 5-6类高危职业未如实告知 |

### 3. 健康告知常见问题处理

**Q：感冒发烧需要告知吗？**
A：不需要，普通感冒发烧不影响核保。

**Q：体检报告有指标异常，但医生说没事，需要告知吗？**
A：需要告知。保险医学关注的是「未来患病风险」，与临床医学的「现在是否需要治疗」不同。

**Q：医保卡借给他人使用，需要告知吗？**
A：需要告知，医保卡记录视为本人就医记录。

**Q：早期xxx疾病已治愈，需要告知吗？**
A：需如实告知，保险公司会评估治愈后的风险。

---

## 三、核保要求

### 1. 核保结论与处理方式

| 核保结论 | 含义 | 客户应对 |
|----------|------|----------|
| 标准体承保 | 完全正常承保 | 正常投保 |
| 加费承保 | 增加保费但正常保障 | 考虑加费是否可接受 |
| 除外承保 | 某项疾病不保，其余正常 | 权衡利弊决定 |
| 延期承保 | 暂时不能承保 | 先改善健康状况再投保 |
| 拒保 | 不能承保 | 考虑其他产品/储蓄险替代 |

### 2. 常见核保参考

**体重（BMI）**：
- BMI > 28：可能加费或延期
- BMI > 32：重疾险通常拒保

**血压**：
- 收缩压 > 150 或 舒张压 > 95：医疗险可能拒保
- 收缩压 > 160 或 舒张压 > 100：重疾险可能加费

**血糖**：
- 空腹血糖 > 7.0 mmol/L：重疾险通常拒保或延期
- 糖尿病患者：医疗险通常拒保

**乙肝**：
- 乙肝病毒携带/小三阳：重疾险通常加费20-30%
- 乙肝大三阳：通常拒保或延期

---

## 四、销售合规

### 1. 禁止行为

- ❌ 夸大保险责任或收益
- ❌ 隐瞒保险合同重要内容
- ❌ 阻碍投保人履行如实告知义务
- ❌ 给予或承诺投保人保险合同约定以外的利益
- ❌ 代替投保人/被保险人签名
- ❌ 伪造、变造保险单证
- ❌ 诱导投保人不如实告知

### 2. 告知义务

**代理人必须明确告知投保人**：
- 产品保障范围与免责条款
- 退保可能产生的损失（现金价值）
- 等待期设置及影响
- 保费缴纳方式及逾期后果
- 如实告知的重要性及后果

### 3. 双录要求

**需进行录音录像的情形**：
- 投保人年龄 ≥ 60周岁
- 期交产品首期保费 ≥ 20万元
- 投保险种含寿险责任
- 保险机构按监管规定需要双录的其他情形

---

## 五、客户信息保护

### 1. 《个人信息保护法》要点

- 收集客户信息需获得明确同意
- 不得泄露、篡改、丢失客户信息
- 委托处理个人信息需签订保密协议
- 客户有权查阅、复制、更正、删除其个人信息

### 2. 保险信息使用限制

- 客户信息仅用于保险服务相关用途
- 未经授权不得对外提供客户信息
- 离职后需妥善交接或销毁客户信息资料

---

## 六、风险提示

### 1. 销售误导风险

**常见销售误导形式**：
- 把保险说成存款（存取宝、零存整取等混淆概念）
- 把保险收益与银行理财/存款利率比较
- 夸大保险保障范围
- 用「不限保额」「什么都保」等模糊表述

**正确做法**：
- 明确说明产品类型（保障型/储蓄型）
- 用产品条款作为说明依据
- 收益演示需使用监管规定的演示利率

### 2. 退保风险提示

**退保损失**：
- 前1-3年现金价值通常远低于已缴保费
- 长期险退保可能损失50%以上已缴保费
- 退保后失去保障

**正确做法**：
- 在投保前充分了解产品保障内容
- 缴费期内尽量不选择退保
- 如需资金周转，优先考虑保单贷款

### 3. 理赔风险提示

**常见拒赔原因**：
- 未如实告知（既往症/健康状况）
- 等待期内出险
- 属于免责条款（犯罪、酗酒、无证驾驶等）
- 费用不属于保障范围（美容、整形、牙科等）
- 定点医院不合规

**正确做法**：
- 引导客户如实告知健康状况
- 提醒客户注意等待期（等待期不体检）
- 明确告知免责条款内容
- 协助客户了解理赔流程


path: references/insurance-knowledge.md
content: # 保险知识库

## 一、险种定义与功能

### 1. 重疾险（重大疾病保险）

**定义**：保障合同约定的重大疾病（如癌症、心梗、脑中风等），确诊即赔付保险金。

**核心作用**：
- 弥补收入损失
- 支付高额医疗费用
- 康复护理费用
- 家庭负债（房贷等）

**分类**：
- 按保障期限：终身重疾 / 定期重疾（至70岁/80岁）
- 按产品形态：消费型 / 返还型
- 按赔付次数：单次赔付 / 多次分组赔付 / 多次不分组赔付

**保障范围**：
- 重症：通常100种以上，赔付100%保额
- 中症：赔付50%-60%保额
- 轻症：赔付20%-30%保额
- 身故保障：终身重疾通常含身故责任

**常见误区**：
- ❌ 买了医疗险就不需要重疾险
- ❌ 重疾险可以覆盖所有疾病
- ❌ 疾病数量越多越好（关键是病种质量）

---

### 2. 医疗险

**定义**：报销因疾病或意外产生的医疗费用，实报实销。

**核心作用**：
- 报销社保不能覆盖的部分
- 进口药、靶向药、CAR-T等特殊治疗
- 高额医疗费用分摊

**分类**：
- 小额医疗险：保额1-5万，免赔额0-500元
- 百万医疗险：保额100-600万，免赔额1万元
- 中端医疗险：可去特需部/国际部
- 高端医疗险：覆盖私立医院、海外医疗

**重要概念**：
- 免赔额：需自己承担的费用
- 报销比例：社保后剩余部分的报销比例
- 保证续保：产品在售期间可连续续保

**常见问题**：
- Q：有了医保还需要医疗险吗？A：需要，医保报销有限，医疗险可覆盖社保目录外药品和进口器材。
- Q：医疗险可以买多份吗？A：不可以重复报销，医疗险适用损失补偿原则。

---

### 3. 定期寿险

**定义**：在保险期限内身故或全残，赔付保险金。纯保障型产品。

**核心作用**：
- 家庭经济支柱的「留爱不留债」
- 覆盖家庭负债（房贷、车贷）
- 子女教育费用
- 父母赡养费用

**特点**：
- 保费低、保额高
- 保障期限灵活（10/20/30年/至60岁等）
- 无现金价值，纯消费型

**适用人群**：
- 家庭经济支柱
- 有房贷/车贷压力的人
- 30-50岁人群

**保额计算公式**：
```
保额 = 家庭负债（房贷+车贷）+ 子女教育至大学毕业费用
      + 父母赡养费用（10-20年）
      - 现有资产
```

---

### 4. 意外险

**定义**：保障因意外导致的身故、伤残、医疗费用。

**意外定义**：外来的、突发的、非本意的、非疾病的客观事件。

**保障内容**：
- 意外身故：按保额赔付
- 意外伤残：按伤残等级（1-10级）比例赔付
- 意外医疗：门诊/住院费用报销
- 意外住院津贴：按住院天数补贴

**常见产品形态**：
- 综合意外险：含意外身故/伤残/医疗
- 交通意外险：针对飞机/火车/汽车等
- 航空意外险：专项保障
- 旅行意外险：出境/境内旅行

**特别注意**：
- 猝死不属于意外（是疾病）
- 部分意外险含猝死保障，需单独关注
- 意外险对职业类别要求严格

---

### 5. 储蓄险（年金险/两全险）

**定义**：兼具保障和储蓄功能的保险，主要用于养老规划、子女教育金等。

**分类**：
- 年金险：从约定年龄开始每年领取生存金
- 两全险：生存金+满期金+身故保障
- 分红险：分享保险公司经营成果
- 万能险：有万能账户复利增值

**核心作用**：
- 养老储备
- 子女教育金
- 强制储蓄
- 资产传承

**IRR（内部收益率）**：
- 衡量储蓄险收益的核心指标
- 年金险IRR通常在2%-3.5%
- 储蓄险优于银行存款的关键在于复利效应

---

## 二、核心概念解析

### 等待期（观察期）

**定义**：保险合同生效后的一段时间内，即使发生保险事故，保险公司也不承担赔付责任。

**设置目的**：防止带病投保、逆向选择。

**各险种等待期**：
| 险种 | 等待期 |
|------|--------|
| 重疾险 | 90-180天 |
| 医疗险 | 30天 |
| 定期寿险 | 90-180天 |
| 意外险 | 通常0-7天 |

**注意事项**：
- 等待期内查出异常，即使等待期后确诊重疾，通常也无法获赔
- 医疗险等待期内就医，不予报销

---

### 现金价值

**定义**：保单具有的价值，体现为退保时可以拿回的钱。

**计算公式**：
```
现金价值 = 已缴保费 - 保险公司费用（管理费+佣金）
          + 剩余保费产生的利息
```

**特点**：
- 保障型产品（定期寿险、消费型重疾）现金价值低
- 储蓄型产品（终身寿险、年金险）现金价值高
- 现金价值随时间先升后降（终身寿险通常在缴费结束后20-30年达到峰值）

**用途**：
- 退保取现
- 保单贷款（通常可贷现金价值80%）
- 减额交清
- 自动垫缴保费

---

### 健康告知

**定义**：投保时对被保险人健康状况的如实告知义务。

**原则**：
- 中国大陆：有限告知（问什么答什么）
- 香港/海外：无限告知

**告知内容**：
- 既往病史
- 家族病史
- 体检异常
- 住院记录
- 不良生活习惯（吸烟、酗酒）

**后果**：
- 未如实告知：可能拒赔
- 故意不如实告知：解除合同，不退保费
- 过失不如实告知：解除合同，退还保费

**核保结论**：
- 标准体承保：正常费率，正常保障
- 加费承保：多收保费，但保障不变
- 除外承保：某些疾病不保，其余正常
- 延期承保：暂不能承保，观察后再评估
- 拒保：不能承保

---

### 豁免

**定义**：在保险缴费期内，当投保人或被保险人发生特定情况（如轻症/重疾/身故/全残），后续保费不用再交，保障继续有效。

**分类**：
- 投保人豁免：投保人发生约定情况，免缴后续保费
- 被保险人豁免：被保险人发生约定情况，免缴后续保费

**适用场景**：
- 父母为子女投保：加投保人豁免
- 夫妻互保：双方互为投保人，加双重豁免

---

### 保费测算基础

**纯保费** = 风险保费 + 储蓄保费

**影响保费的因素**：
1. **年龄**：年龄越大，保费越高（重疾险尤为明显）
2. **性别**：女性通常比男性保费低约10-20%（寿命更长）
3. **保额**：保额越高，保费越高（线性关系）
4. **保障期限**：终身 > 至70岁 > 至60岁
5. **缴费期限**：缴费期越短，年缴保费越高，总保费越低
6. **职业类别**：1-6类职业，5-6类高危职业保费更高
7. **健康状况**：非标准体可能加费
8. **产品类型**：储蓄型 > 消费型

---

## 三、客户常见异议处理

### 1. 「我买了社保，不需要商业保险」

**回应**：
社保只能覆盖基础医疗，有三大局限：
- 有报销比例限制（通常70-90%）
- 有封顶线（各地不同，通常20-50万）
- 不含进口药、自费药、靶向药

一场大病，社保报销后自费部分往往仍需10-30万，这才是商业保险的价值所在。

---

### 2. 「我还年轻，不需要保险」

**回应**：
恰恰相反，年轻人更需要保险：
- 保费便宜（同样的保额，年轻时买保费低30-50%）
- 身体健康，更容易通过核保
- 早买早保障，避免「想买时却买不了」
- 保障型保险是给「未来的自己」一份安心

---

### 3. 「保险太贵了，买不起」

**回应**：
保险不是买不买得起的问题，而是需不需要：
- 定期寿险：30岁男性，100万保额，保障30年，年缴保费仅300-400元
- 百万医疗险：30岁成年人，年缴保费仅200-400元
- 意外险：50万保额，年缴保费仅100-200元

每月一顿饭钱，就能给家庭一份保障。

---

### 4. 「万一没出事，钱不是白交了？」

**回应**：
这是消费型保险的思维，但储蓄型保险可以「有事赔钱，没事存钱」：
- 重疾险：如果一生平平安安，留给子女的是一笔免税遗产
- 年金险：活着就是提款机，越活越赚
- 两全险：满期返还已交保费，相当于「不花钱」的保障

换个角度：您每年给车买保险会认为白交吗？人的生命比车更值钱。

---

### 5. 「我身体健康，不需要告知那么多」

**回应**：
健康告知是法律义务，如实告知是保护自己：
- 保险公司有核保调查渠道（医院记录、体检中心、医保卡使用记录）
- 未如实告知，可能导致：拒赔、解约、不退保费
- 故意隐瞒属于欺诈，严重的构成保险诈骗罪

不如实告知，损失的是自己的利益。

---

## 四、展业话术

### 需求激发话术

**开场白**（适合初次见面）：
「王先生，您看咱们辛苦工作一辈子，都是为了让家人生活得更好。不知道您有没有想过，万一有一天我们不在了，家人未来的生活会怎样？」

**家庭风险分析**：
「您现在的家庭责任包括：房贷200万、孩子教育预计50万、双方父母赡养每月3000元。如果家庭经济支柱突然不在了，这些责任由谁来承担？」

### 产品介绍话术

**重疾险**：
「这份重疾险就像一个『收入替代器』——万一不幸得了大病，这笔钱可以：
- 支付治疗费用（平均30-50万）
- 替代您3-5年的工作收入
- 覆盖康复护理和营养费用
- 让家人不用为钱发愁

您觉得这笔钱需要多少才能安心？」

**医疗险**：
「医保就像毛衣，只能保暖基础温度；这份医疗险就像羽绒服，在寒冬给您额外保护。进口药、自费药、靶向药……这些医保报不了的部分，才是真正的大病支出。」

**定期寿险**：
「这份保险不贵，100万保额一年才三四百块，但它解决的是一个很现实的问题——万一我们不在了，家人不用为房贷发愁，孩子读书有钱，老人有钱养老。」

### 促成话术

**直接促成**：
「保障型产品就是这样，早买早安心，保费还便宜。既然您也认同保障的重要性，要不我们今天就先把保障建立起来？」

**假设促成**：
「假设明天体检发现有个小问题，您还会这么容易买到保险吗？所以保障这件事，不能等。」

**稀缺促成**：
「这款产品的健康告知比较宽松，您现在的身体状况投保没问题。但如果等一段时间，身体发生变化，可能就买不了这么合适的产品了。」

---

## 五、投保注意事项

### 重疾险投保要点
1. 保费预算：建议家庭年收入的5-15%
2. 保额测算：通常为年收入的3-5倍
3. 保障期限：预算充足选终身，预算有限选定期至70岁
4. 缴费期限：建议20年缴费，减轻每年压力
5. 病种质量：重点关注高发重疾（癌症、心梗、脑中风）定义
6. 轻症保障：必须包含高发轻症（原位癌、不典型心梗、轻微脑中风）

### 医疗险投保要点
1. 保证续保：优先选择保证续保产品
2. 免赔额：1万免赔额适合大多数人
3. 报销范围：不限社保范围最优
4. 增值服务：垫付、绿通、特药服务是加分项
5. 续保条件：关注历史续保是否稳定

### 定期寿险投保要点
1. 免责条款：越少越好（最优3条）
2. 健康告知：越宽松越好
3. 职业限制：确认自己的职业在承保范围内
4. 保障期限：覆盖家庭经济责任最重时期（通常到60岁）
5. 保额确定：需覆盖家庭所有负债+5-10年家庭支出


path: scripts/needs_analyzer.py
content: #!/usr/bin/env python3
"""
保险需求分析工具
输入：客户基本信息（年龄、职业、家庭结构、已有保单、预算）
输出：结构化需求分析报告
"""

import json
import sys

def analyze_risks(age, has_family, has_house_mortgage, existing_coverage, annual_income):
    """分析四大风险"""
    risks = {
        "death_risk": {
            "score": 0,
            "description": "",
            "recommendations": []
        },
        "critical_illness_risk": {
            "score": 0,
            "description": "",
            "recommendations": []
        },
        "accident_risk": {
            "score": 0,
            "description": "",
            "recommendations": []
        },
        "hospitalization_risk": {
            "score": 0,
            "description": "",
            "recommendations": []
        }
    }

    # 身故风险评分
    if has_family:
        risks["death_risk"]["score"] += 40
        risks["death_risk"]["recommendations"].append("定期寿险：覆盖家庭责任，保护家人")
    if has_house_mortgage:
        risks["death_risk"]["score"] += 30
        risks["death_risk"]["recommendations"].append(f"房贷险：保额建议覆盖剩余房贷余额")
    if age <= 50:
        risks["death_risk"]["score"] += 20
    if existing_coverage.get("定期寿险", 0) == 0:
        risks["death_risk"]["recommendations"].append("优先配置定期寿险，保费低保障高")

    # 大病风险评分
    risks["critical_illness_risk"]["score"] = 60 + (1 if age > 35 else 0) * 10 + (1 if age > 45 else 0) * 10
    risks["critical_illness_risk"]["recommendations"].append("重疾险：确诊即赔付，弥补收入损失")
    if existing_coverage.get("重疾险", 0) == 0:
        risks["critical_illness_risk"]["recommendations"].append("建议重疾险保额 = 年收入 × 3-5倍")

    # 意外风险评分
    risks["accident_risk"]["score"] = 40 + (1 if age < 40 else 0) * 20
    risks["accident_risk"]["recommendations"].append("意外险：保费低保障高，1年期消费型")
    if existing_coverage.get("意外险", 0) == 0:
        risks["accident_risk"]["recommendations"].append("意外险保额建议：年收入5-10倍")

    # 住院风险评分
    risks["hospitalization_risk"]["score"] = 50 + (1 if age > 30 else 0) * 10
    risks["hospitalization_risk"]["recommendations"].append("医疗险：报销高额医疗费用")
    if existing_coverage.get("医疗险", 0) == 0:
        risks["hospitalization_risk"]["recommendations"].append("优先选择保证续保的百万医疗险")

    # 生成描述
    for risk_name, risk_data in risks.items():
        if risk_data["score"] >= 80:
            risk_data["level"] = "极高"
        elif risk_data["score"] >= 60:
            risk_data["level"] = "高"
        elif risk_data["score"] >= 40:
            risk_data["level"] = "中等"
        else:
            risk_data["level"] = "较低"

    return risks


def analyze_needs(age, gender, occupation, has_family, family_members,
                  has_child, child_age, has_house_mortgage, mortgage_balance,
                  annual_income, annual_expense, existing_coverage, annual_budget):
    """综合需求分析"""

    # 风险分析
    risks = analyze_risks(age, has_family, has_house_mortgage, existing_coverage, annual_income)

    # 保障缺口计算
    death_coverage_needed = 0
    if has_family:
        death_coverage_needed += annual_expense * 10  # 10年家庭支出
    if has_child:
        death_coverage_needed += (22 - child_age) * 20000  # 子女教育费
    if has_house_mortgage:
        death_coverage_needed += mortgage_balance  # 房贷余额
    death_coverage_needed += 200000  # 父母赡养

    ci_coverage_needed = annual_income * 3  # 3年收入
    if age > 40:
        ci_coverage_needed = annual_income * 5  # 40岁以上建议5年收入

    hospital_coverage_needed = 2000000  # 200万医疗险

    # 优先级排序
    priority_list = []
    if existing_coverage.get("定期寿险", 0) < death_coverage_needed:
        priority_list.append({"type": "定期寿险", "priority": 1, "gap": death_coverage_needed - existing_coverage.get("定期寿险", 0)})
    if existing_coverage.get("重疾险", 0) < ci_coverage_needed:
        priority_list.append({"type": "重疾险", "priority": 2, "gap": ci_coverage_needed - existing_coverage.get("重疾险", 0)})
    if existing_coverage.get("医疗险", 0) == 0:
        priority_list.append({"type": "医疗险", "priority": 3, "gap": hospital_coverage_needed})
    if existing_coverage.get("意外险", 0) == 0:
        priority_list.append({"type": "意外险", "priority": 4, "gap": annual_income * 5})

    # 预算规划
    ideal_premium = annual_budget * 0.15  # 建议保费支出不超过年收入15%
    essential_premium = annual_budget * 0.10  # 最低10%

    result = {
        "customer_info": {
            "年龄": age,
            "性别": gender,
            "职业": occupation,
            "家庭结构": {
                "已婚": has_family,
                "家庭成员数": family_members,
                "子女": has_child,
                "子女年龄": child_age if has_child else None
            },
            "财务状况": {
                "年收入": annual_income,
                "年支出": annual_expense,
                "房贷余额": mortgage_balance if has_house_mortgage else 0
            },
            "已有保障": existing_coverage,
            "年度预算": annual_budget
        },
        "risk_analysis": risks,
        "coverage_gap": {
            "身故保障缺口": {
                "建议保额": death_coverage_needed,
                "现有保额": existing_coverage.get("定期寿险", 0),
                "保障缺口": max(0, death_coverage_needed - existing_coverage.get("定期寿险", 0))
            },
            "重疾保障缺口": {
                "建议保额": ci_coverage_needed,
                "现有保额": existing_coverage.get("重疾险", 0),
                "保障缺口": max(0, ci_coverage_needed - existing_coverage.get("重疾险", 0))
            },
            "医疗保障建议": {
                "建议保额": hospital_coverage_needed,
                "现有保额": existing_coverage.get("医疗险", 0),
                "保障缺口": max(0, hospital_coverage_needed - existing_coverage.get("医疗险", 0))
            },
            "意外保障建议": {
                "建议保额": annual_income * 5,
                "现有保额": existing_coverage.get("意外险", 0),
                "保障缺口": max(0, annual_income * 5 - existing_coverage.get("意外险", 0))
            }
        },
        "priority_list": priority_list,
        "budget_planning": {
            "建议保费预算": ideal_premium,
            "最低保费预算": essential_premium,
            "可用预算": annual_budget,
            "说明": "保障型保费建议不超过年收入15%，其中基础保障（寿险+重疾+医疗+意外）约占10%"
        },
        "summary": f"{age}岁{'已婚' if has_family else '未婚'}{'有子女' if has_child else ''}，{'家庭经济支柱' if has_family else '个人'}，{'有房贷压力' if has_house_mortgage else '无房贷'}。" \
                   f"建议优先配置：{' '.join([p['type'] for p in priority_list[:2]])}。"
    }

    return result


if __name__ == "__main__":
    # 默认测试数据
    if len(sys.argv) == 1:
        test_data = {
            "age": 35,
            "gender": "男",
            "occupation": "企业主",
            "has_family": True,
            "family_members": 4,
            "has_child": True,
            "child_age": 8,
            "has_house_mortgage": True,
            "mortgage_balance": 1500000,
            "annual_income": 500000,
            "annual_expense": 200000,
            "existing_coverage": {"重疾险": 0, "医疗险": 0, "定期寿险": 0, "意外险": 0},
            "annual_budget": 500000
        }
        result = analyze_needs(**test_data)
        print(json.dumps(result, ensure_ascii=False, indent=2))
    else:
        # 从stdin读取JSON参数
        try:
            import sys
            params = json.loads(sys.stdin.read())
            result = analyze_needs(**params)
            print(json.dumps(result, ensure_ascii=False, indent=2))
        except Exception as e:
            print(json.dumps({"error": str(e)}, ensure_ascii=False))


path: scripts/plan_designer.py
content: #!/usr/bin/env python3
"""
方案设计工具
根据需求分析结果，自动生成2-3套方案（基础版/标准版/全面版）
"""

import json
import sys
import os

def load_products():
    """加载产品数据"""
    product_file = os.path.join(os.path.dirname(__file__), "../references/products.json")
    with open(product_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return data["products"]

def select_products(products, product_type, criteria="recommended"):
    """按类型筛选产品"""
    filtered = [p for p in products if p["type"] == product_type]
    if not filtered:
        return []
    # 按保费排序（性价比）
    if criteria == "cheapest":
        return sorted(filtered, key=lambda x: x.get("premium_per_10k", 999))
    elif criteria == "recommended":
        # 推荐中等价位产品
        return sorted(filtered, key=lambda x: x.get("premium_per_10k", 999))
    return filtered

def design_plan(plan_type, age, gender, annual_income, annual_budget, coverage_needs):
    """设计保险方案"""
    products = load_products()

    if plan_type == "基础版":
        return design_basic_plan(age, gender, annual_income, annual_budget, coverage_needs, products)
    elif plan_type == "标准版":
        return design_standard_plan(age, gender, annual_income, annual_budget, coverage_needs, products)
    elif plan_type == "全面版":
        return design_premium_plan(age, gender, annual_income, annual_budget, coverage_needs, products)
    else:
        return None


def calculate_product_premium(product, age, gender, coverage, payment_term):
    """计算产品保费"""
    age_factor = 1.0
    if age >= 18 and age <= 30:
        age_factor = 0.8
    elif age >= 31 and age <= 40:
        age_factor = 1.0
    elif age >= 41 and age <= 50:
        age_factor = 1.3
    elif age >= 51 and age <= 55:
        age_factor = 1.6

    gender_factor = 1.0 if gender in ["男", "男性"] else 0.85

    if product["type"] == "医疗险":
        if age <= 30:
            return max(coverage * 0.0003, 200)
        elif age <= 40:
            return max(coverage * 0.0004, 200)
        elif age <= 50:
            return max(coverage * 0.0006, 200)
        else:
            return max(coverage * 0.001, 200)

    if product["type"] == "意外险":
        return max(coverage * 0.001, 100)

    payment_factor = 1.0
    if payment_term == "趸交":
        payment_factor = 0.85
    elif payment_term == "3年":
        payment_factor = 0.95
    elif payment_term == "5年":
        payment_factor = 1.0
    elif payment_term == "10年":
        payment_factor = 1.05
    elif payment_term == "20年":
        payment_factor = 1.15

    base = (coverage / 10000) * product.get("premium_per_10k", 250)
    return round(base * age_factor * gender_factor * payment_factor, 2)


def design_basic_plan(age, gender, annual_income, annual_budget, coverage_needs, products):
    """基础版方案：低保费基本保障"""
    budget = min(annual_budget * 0.10, annual_income * 0.10)  # 不超过年收入10%
    plan = {
        "plan_name": "基础版",
        "description": "以最低成本建立基础保障，覆盖核心风险",
        "annual_premium": 0,
        "total_coverage": 0,
        "products": []
    }

    # 定期寿险 - 选择性价比高的
    tl_products = [p for p in products if p["type"] == "定期寿险"]
    tl_product = min(tl_products, key=lambda x: x.get("premium_per_10k", 999))
    tl_coverage = min(coverage_needs.get("death", 500000), 1000000)
    tl_premium = calculate_product_premium(tl_product, age, gender, tl_coverage, "20年")
    if plan["annual_premium"] + tl_premium <= budget:
        plan["products"].append({
            "type": "定期寿险",
            "product_name": tl_product["name"],
            "company": tl_product["company"],
            "coverage": tl_coverage,
            "annual_premium": tl_premium,
            "payment_term": "20年",
            "coverage_period": "至60周岁",
            "key_benefits": "身故/全残保障，保护家人"
        })
        plan["annual_premium"] += tl_premium
        plan["total_coverage"] += tl_coverage

    # 意外险
    ac_products = [p for p in products if p["type"] == "意外险"]
    ac_product = min(ac_products, key=lambda x: x.get("premium_per_10k", 999))
    ac_coverage = min(annual_income * 5, 3000000)
    ac_premium = calculate_product_premium(ac_product, age, gender, ac_coverage, "年交")
    if plan["annual_premium"] + ac_premium <= budget * 1.2:
        plan["products"].append({
            "type": "意外险",
            "product_name": ac_product["name"],
            "company": ac_product["company"],
            "coverage": ac_coverage,
            "annual_premium": ac_premium,
            "payment_term": "年交",
            "coverage_period": "1年",
            "key_benefits": "意外身故/伤残/医疗，100万保额仅需几百元"
        })
        plan["annual_premium"] += ac_premium
        plan["total_coverage"] += ac_coverage

    # 医疗险
    mi_products = [p for p in products if p["type"] == "医疗险" and "保证续保" in p.get("notes", "")]
    if not mi_products:
        mi_products = [p for p in products if p["type"] == "医疗险"]
    mi_product = mi_products[0] if mi_products else None
    if mi_product:
        mi_coverage = 2000000
        mi_premium = calculate_product_premium(mi_product, age, gender, mi_coverage, "年交")
        plan["products"].append({
            "type": "医疗险",
            "product_name": mi_product["name"],
            "company": mi_product["company"],
            "coverage": mi_coverage,
            "annual_premium": mi_premium,
            "payment_term": "年交",
            "coverage_period": "1年",
            "key_benefits": "百万医疗，不限社保，进口药/靶向药均可报销"
        })
        plan["annual_premium"] += mi_premium
        plan["total_coverage"] += mi_coverage

    plan["features"] = [
        "保费低廉，适合预算有限的年轻人",
        "核心保障：身故、意外、大病医疗",
        "定期寿险覆盖家庭责任最重时期",
        "医疗险补充社保不足"
    ]

    return plan


def design_standard_plan(age, gender, annual_income, annual_budget, coverage_needs, products):
    """标准版方案：全面基础保障+重疾"""
    budget = min(annual_budget * 0.15, annual_income * 0.15)
    plan = {
        "plan_name": "标准版",
        "description": "保障全面，含重疾保障，适合大多数家庭",
        "annual_premium": 0,
        "total_coverage": 0,
        "products": []
    }

    # 定期寿险 - 推荐中国人寿星Combo
    tl_products = [p for p in products if p["type"] == "定期寿险"]
    tl_product = next((p for p in tl_products if "星" in p["name"]), tl_products[0])
    tl_coverage = min(coverage_needs.get("death", 1000000), 2000000)
    tl_premium = calculate_product_premium(tl_product, age, gender, tl_coverage, "20年")
    plan["products"].append({
        "type": "定期寿险",
        "product_name": tl_product["name"],
        "company": tl_product["company"],
        "coverage": tl_coverage,
        "annual_premium": tl_premium,
        "payment_term": "20年",
        "coverage_period": "至60周岁",
        "key_benefits": "身故/全残保障，保费低保障高"
    })
    plan["annual_premium"] += tl_premium
    plan["total_coverage"] += tl_coverage

    # 重疾险 - 推荐平安福或国寿福
    crx_products = [p for p in products if p["type"] == "重疾险"]
    crx_product = next((p for p in crx_products if "福" in p["name"] and "终身" in p["coverage_period"]), crx_products[0])
    crx_coverage = min(coverage_needs.get("critical_illness", annual_income * 3), 500000)
    crx_premium = calculate_product_premium(crx_product, age, gender, crx_coverage, "20年")
    plan["products"].append({
        "type": "重疾险",
        "product_name": crx_product["name"],
        "company": crx_product["company"],
        "coverage": crx_coverage,
        "annual_premium": crx_premium,
        "payment_term": "20年",
        "coverage_period": "终身",
        "key_benefits": f"120种重疾+轻症保障，确诊即赔付{crx_coverage//10000}万"
    })
    plan["annual_premium"] += crx_premium
    plan["total_coverage"] += crx_coverage

    # 医疗险 - 选保证续保20年的
    mi_products = [p for p in products if p["type"] == "医疗险" and "20年" in p.get("coverage_period", "")]
    if not mi_products:
        mi_products = [p for p in products if p["type"] == "医疗险"]
    mi_product = mi_products[0]
    mi_coverage = 4000000
    mi_premium = calculate_product_premium(mi_product, age, gender, mi_coverage, "年交")
    plan["products"].append({
        "type": "医疗险",
        "product_name": mi_product["name"],
        "company": mi_product["company"],
        "coverage": mi_coverage,
        "annual_premium": mi_premium,
        "payment_term": "年交",
        "coverage_period": "保证续保20年",
        "key_benefits": "长期医疗保障，20年续保稳定"
    })
    plan["annual_premium"] += mi_premium
    plan["total_coverage"] += mi_coverage

    # 意外险
    ac_products = [p for p in products if p["type"] == "意外险"]
    ac_product = next((p for p in ac_products if "百万" in p["name"]), ac_products[0])
    ac_coverage = min(annual_income * 5, 3000000)
    ac_premium = calculate_product_premium(ac_product, age, gender, ac_coverage, "年交")
    plan["products"].append({
        "type": "意外险",
        "product_name": ac_product["name"],
        "company": ac_product["company"],
        "coverage": ac_coverage,
        "annual_premium": ac_premium,
        "payment_term": "年交",
        "coverage_period": "1年",
        "key_benefits": "含猝死保障，意外医疗不限社保"
    })
    plan["annual_premium"] += ac_premium
    plan["total_coverage"] += ac_coverage

    plan["features"] = [
        "保障全面：寿险+重疾+医疗+意外",
        "重疾险提供终身保障，确诊即赔付",
        "医疗险保证续保20年，长期稳定",
        "定期寿险覆盖家庭经济责任期",
        "总保费约占年收入的10-15%"
    ]

    return plan


def design_premium_plan(age, gender, annual_income, annual_budget, coverage_needs, products):
    """全面版方案：高保额全面保障+储蓄"""
    budget = min(annual_budget * 0.20, annual_income * 0.20)
    plan = {
        "plan_name": "全面版",
        "description": "高保额全方位保障，另含养老储蓄规划",
        "annual_premium": 0,
        "total_coverage": 0,
        "products": []
    }

    # 定期寿险 - 高保额
    tl_products = [p for p in products if p["type"] == "定期寿险"]
    tl_product = tl_products[0]
    tl_coverage = min(coverage_needs.get("death", 2000000), 5000000)
    tl_premium = calculate_product_premium(tl_product, age, gender, tl_coverage, "20年")
    plan["products"].append({
        "type": "定期寿险",
        "product_name": tl_product["name"],
        "company": tl_product["company"],
        "coverage": tl_coverage,
        "annual_premium": tl_premium,
        "payment_term": "20年",
        "coverage_period": "至60/65周岁",
        "key_benefits": f"高保额{tl_coverage//10000}万，覆盖所有家庭责任"
    })
    plan["annual_premium"] += tl_premium
    plan["total_coverage"] += tl_coverage

    # 重疾险 - 多次赔付型
    crx_products = [p for p in products if p["type"] == "重疾险" and "多次" in p.get("core_coverage", "")]
    if not crx_products:
        crx_products = [p for p in products if p["type"] == "重疾险"]
    crx_product = crx_products[0]
    crx_coverage = min(coverage_needs.get("critical_illness", annual_income * 5), 500000)
    crx_premium = calculate_product_premium(crx_product, age, gender, crx_coverage, "20年")
    plan["products"].append({
        "type": "重疾险",
        "product_name": crx_product["name"],
        "company": crx_product["company"],
        "coverage": crx_coverage,
        "annual_premium": crx_premium,
        "payment_term": "20年",
        "coverage_period": "终身",
        "key_benefits": f"重疾多次赔付，终身保障，保额{crx_coverage//10000}万"
    })
    plan["annual_premium"] += crx_premium
    plan["total_coverage"] += crx_coverage

    # 医疗险 - 600万高保额
    mi_products = [p for p in products if p["type"] == "医疗险"]
    mi_product = next((p for p in mi_products if "600" in p.get("core_coverage", "")), mi_products[0])
    mi_coverage = 6000000
    mi_premium = calculate_product_premium(mi_product, age, gender, mi_coverage, "年交")
    plan["products"].append({
        "type": "医疗险",
        "product_name": mi_product["name"],
        "company": mi_product["company"],
        "coverage": mi_coverage,
        "annual_premium": mi_premium,
        "payment_term": "年交",
        "coverage_period": "1年可续保",
        "key_benefits": "600万高保额，含质子重离子、CAR-T治疗"
    })
    plan["annual_premium"] += mi_premium
    plan["total_coverage"] += mi_coverage

    # 意外险 - 100万
    ac_products = [p for p in products if p["type"] == "意外险"]
    ac_product = next((p for p in ac_products if "百万" in p["name"]), ac_products[0])
    ac_coverage = 1000000
    ac_premium = calculate_product_premium(ac_product, age, gender, ac_coverage, "年交")
    plan["products"].append({
        "type": "意外险",
        "product_name": ac_product["name"],
        "company": ac_product["company"],
        "coverage": ac_coverage,
        "annual_premium": ac_premium,
        "payment_term": "年交",
        "coverage_period": "1年",
        "key_benefits": "100万意外+猝死保障，意外医疗不限社保"
    })
    plan["annual_premium"] += ac_premium
    plan["total_coverage"] += ac_coverage

    # 储蓄险 - 养老规划（可选）
    if age <= 45:
        sa_products = [p for p in products if p["type"] == "储蓄险" and "养老" in p.get("notes", "")]
        if not sa_products:
            sa_products = [p for p in products if p["type"] == "储蓄险"]
        if sa_products and plan["annual_premium"] + 10000 <= budget:
            sa_product = sa_products[0]
            sa_coverage = 100000
            sa_premium = calculate_product_premium(sa_product, age, gender, sa_coverage, "10年")
            plan["products"].append({
                "type": "储蓄险",
                "product_name": sa_product["name"],
                "company": sa_product["company"],
                "coverage": sa_coverage,
                "annual_premium": sa_premium,
                "payment_term": "10年",
                "coverage_period": "至60/65周岁",
                "key_benefits": "强制储蓄，养老规划，兼具保障和收益"
            })
            plan["annual_premium"] += sa_premium

    plan["features"] = [
        "全方位高保额保障：寿险+重疾+医疗+意外",
        "重疾险保额高达年收入5倍",
        "医疗险600万保额，涵盖最新治疗手段",
        "定期寿险高保额，覆盖所有家庭财务责任",
        "可选储蓄险，为养老做准备",
        f"总保费约{plan['annual_premium']}元，占年收入约{round(plan['annual_premium']/annual_income*100,1)}%"
    ]

    return plan


def generate_all_plans(age, gender, annual_income, annual_budget, coverage_needs):
    """生成三套方案"""
    plans = {
        "基础版": design_plan("基础版", age, gender, annual_income, annual_budget, coverage_needs),
        "标准版": design_plan("标准版", age, gender, annual_income, annual_budget, coverage_needs),
        "全面版": design_plan("全面版", age, gender, annual_income, annual_budget, coverage_needs)
    }

    return plans


if __name__ == "__main__":
    if len(sys.argv) == 1:
        # 默认测试
        coverage_needs = {
            "death": 2000000,
            "critical_illness": 1500000,
            "hospital": 4000000
        }
        plans = generate_all_plans(35, "男", 500000, 500000, coverage_needs)
        print(json.dumps(plans, ensure_ascii=False, indent=2))
    else:
        try:
            params = json.loads(sys.stdin.read())
            plans = generate_all_plans(
                params.get("age", 35),
                params.get("gender", "男"),
                params.get("annual_income", 500000),
                params.get("annual_budget", 500000),
                params.get("coverage_needs", {})
            )
            print(json.dumps(plans, ensure_ascii=False, indent=2))
        except Exception as e:
            print(json.dumps({"error": str(e)}, ensure_ascii=False))


path: scripts/premium_calculator.py
content: #!/usr/bin/env python3
"""
保费计算工具
输入：年龄、性别、保额、保障期限、产品类型
输出：各产品年缴保费，支持不同缴费期对比
"""

import json
import sys
import os

def load_products():
    """加载产品数据"""
    product_file = os.path.join(os.path.dirname(__file__), "../references/products.json")
    with open(product_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return data["products"]

def calculate_premium(product, age, gender, coverage_amount, payment_term=None, coverage_year=None):
    """计算单一产品保费"""
    product_type = product["type"]

    # 基础费率调整系数
    age_factor = 1.0
    if age >= 18 and age <= 30:
        age_factor = 0.8
    elif age >= 31 and age <= 40:
        age_factor = 1.0
    elif age >= 41 and age <= 50:
        age_factor = 1.3
    elif age >= 51 and age <= 55:
        age_factor = 1.6
    elif age > 55:
        age_factor = 2.0

    gender_factor = 1.0
    if gender in ["女", "女性"]:
        gender_factor = 0.85
    elif gender in ["男", "男性"]:
        gender_factor = 1.0

    # 缴费期系数
    payment_term_factor = 1.0
    if product_type in ["重疾险", "定期寿险", "储蓄险"]:
        if payment_term == "趸交":
            payment_term_factor = 0.85
        elif payment_term == "3年":
            payment_term_factor = 0.95
        elif payment_term == "5年":
            payment_term_factor = 1.0
        elif payment_term == "10年":
            payment_term_factor = 1.05
        elif payment_term == "20年":
            payment_term_factor = 1.15
        elif payment_term == "30年":
            payment_term_factor = 1.25

    # 医疗险和意外险按固定费率（与年龄相关）
    if product_type == "医疗险":
        if age <= 30:
            annual_premium = coverage_amount * 0.0003
        elif age <= 40:
            annual_premium = coverage_amount * 0.0004
        elif age <= 50:
            annual_premium = coverage_amount * 0.0006
        elif age <= 60:
            annual_premium = coverage_amount * 0.001
        else:
            annual_premium = coverage_amount * 0.0015
        return max(annual_premium, 200)  # 最低保费200元

    if product_type == "意外险":
        annual_premium = coverage_amount * 0.001
        return max(annual_premium, 100)  # 最低保费100元

    # 重疾险、定期寿险、储蓄险
    premium_val = product.get("premium_per_10k")
    if premium_val is not None:
        # 处理字符串值，如 "约280" 或 "280"
        if isinstance(premium_val, str):
            import re
            nums = re.findall(r'[\d.]+', premium_val)
            premium_val = float(nums[0]) if nums else 0
        base_premium = (coverage_amount / 10000) * float(premium_val)
    else:
        base_premium = coverage_amount * 0.01

    total_premium = base_premium * age_factor * gender_factor * payment_term_factor

    return round(total_premium, 2)


def calculate_all_premiums(age, gender, coverage_amount, product_types=None, payment_term=None, coverage_year=None):
    """计算所有符合条件的产品的保费"""
    products = load_products()

    results = {}
    for product in products:
        # 按类型筛选
        if product_types:
            if product["type"] not in product_types:
                continue

        # 年龄筛选
        if age > 55 and product["type"] in ["定期寿险", "储蓄险"]:
            continue  # 定期寿险55岁以上不推荐
        if age > 60 and product["type"] == "意外险":
            continue

        # 计算保费
        premiums_by_term = {}
        available_terms = product.get("payment_terms", ["年交"])

        for term in available_terms:
            if product["type"] in ["医疗险", "意外险"]:
                term_premium = calculate_premium(product, age, gender, coverage_amount, "年交")
            else:
                term_premium = calculate_premium(product, age, gender, coverage_amount, term)

            # 标准化缴费期名称
            term_name = term
            premiums_by_term[term_name] = term_premium

        # 如果指定了缴费期，只返回该缴费期
        if payment_term and payment_term in premiums_by_term:
            results[product["id"]] = {
                "name": product["name"],
                "company": product["company"],
                "type": product["type"],
                "annual_premium": premiums_by_term[payment_term],
                "payment_term": payment_term,
                "coverage_amount": coverage_amount,
                "coverage_period": product["coverage_period"],
                "waiting_period": product["waiting_period"],
                "core_coverage": ", ".join(product.get("key_benefits", [])) if isinstance(product.get("key_benefits"), list) else product.get("core_coverage", ""),
                "notes": product.get("notes", "")
            }
        else:
            # 返回所有可用缴费期
            results[product["id"]] = {
                "name": product["name"],
                "company": product["company"],
                "type": product["type"],
                "premiums_by_term": premiums_by_term,
                "coverage_amount": coverage_amount,
                "coverage_period": product["coverage_period"],
                "waiting_period": product["waiting_period"],
                "core_coverage": ", ".join(product.get("key_benefits", [])) if isinstance(product.get("key_benefits"), list) else product.get("core_coverage", ""),
                "notes": product.get("notes", "")
            }

    return results


def compare_payment_terms(products_list, age, gender, coverage_amount):
    """对比不同缴费期的保费"""
    products = load_products()
    comparison = []

    for product in products:
        if product["id"] not in products_list:
            continue

        row = {
            "product_id": product["id"],
            "name": product["name"],
            "company": product["company"],
            "type": product["type"]
        }

        for term in product.get("payment_terms", []):
            if product["type"] in ["医疗险", "意外险"]:
                annual = calculate_premium(product, age, gender, coverage_amount, "年交")
            else:
                annual = calculate_premium(product, age, gender, coverage_amount, term)
            row[term] = annual

        comparison.append(row)

    return comparison


if __name__ == "__main__":
    if len(sys.argv) == 1:
        # 默认测试：35岁男性，50万保额
        results = calculate_all_premiums(35, "男", 500000, payment_term="20年")
        print(json.dumps(results, ensure_ascii=False, indent=2))
    else:
        try:
            params = json.loads(sys.stdin.read())
            results = calculate_all_premiums(
                params.get("age", 35),
                params.get("gender", "男"),
                params.get("coverage_amount", 500000),
                params.get("product_types"),
                params.get("payment_term"),
                params.get("coverage_year")
            )
            print(json.dumps(results, ensure_ascii=False, indent=2))
        except Exception as e:
            print(json.dumps({"error": str(e)}, ensure_ascii=False))


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)