baodan/docs/后续开发计划.md

19 KiB
Raw Blame History

保险智能客服系统 — 后续开发计划

文档版本V1.0 更新日期2026-06-25 当前状态:后端框架完成,核心功能完成 64%,产品推荐功能待实现 预计工期2-3 个工作日


一、当前项目状态

1.1 已完成功能64%

模块 功能 状态 备注
认证系统 企微 OAuth 登录 需配置真实企微
账密登录 admin/admin123456
Token 刷新
退出登录
对话功能 iframe 嵌入 BaoDan
险种筛选 7 种险种
会话管理
用户管理 用户 CRUD
角色权限 5 种内置角色
权限校验中间件
知识库 文档上传/列表/删除 调用 BaoDan API
文档状态查询
数据源 CRUD
统计报表 使用概览 占位数据
趋势数据 占位数据
知识库健康度 占位数据
Token 消耗 占位数据
系统管理 方案模板管理
通知告警配置
分组管理
Prompt 管理
登录日志
对话记录
导出功能 PDF 导出
Word 导出

1.2 未完成功能36%

模块 功能 优先级 工作量
产品推荐 BaoDan Workflow 配置 🔴 0.5 天
Workflow 调用封装 🔴 0.5 天
产品推荐 API 联调 🔴 0.5 天
用户管理 批量导入用户 🟡 0.5 天
数据权限过滤 🟡 0.5 天
知识库 文档编号自动生成 🟢 0.2 天
企微集成 XML 加解密 🟡 0.5 天
测试 功能测试 🔴 1 天

二、后续开发计划

Phase 2.5BaoDan Workflow 配置0.5 天)

目标:在 Dify 后台配置产品推荐 Workflow

任务清单

# 任务 说明 验证标准
W.1 创建 Workflow 应用 在 Dify 后台创建新的 Workflow 应用 应用创建成功
W.2 配置节点1参数校验 Code Node校验输入参数 传入合法参数通过
W.3 配置节点2检索策略生成 Code Node根据险种生成检索策略 输出检索策略 JSON
W.4 配置节点3知识库检索 Knowledge Retrieval Node 返回相关文档
W.5 配置节点4LLM 方案生成 LLM Node生成推荐方案 输出 Markdown 方案
W.6 配置节点5异常处理 Code Node处理异常情况 异常时返回友好提示
W.7 配置节点6格式化输出 Code Node格式化为 JSON 输出结构化方案
W.8 配置条件分支 根据险种类型分支处理 分支逻辑正确
W.9 测试验证 端到端测试 输入客户信息 → 输出 3 套方案

Workflow 节点设计

开始
  ↓
[节点1] 参数校验 (Code Node)
  ↓
[节点2] 检索策略生成 (Code Node)
  ↓
[节点3] 知识库检索 (Knowledge Retrieval Node)
  ↓
[节点4] LLM 方案生成 (LLM Node)
  ↓
[节点5] 异常处理 (Code Node)
  ↓
[节点6] 格式化输出 (Code Node)
  ↓
结束

输入参数

{
  "customer_name": "张三",
  "customer_age": 30,
  "customer_gender": "male",
  "health_status": "健康",
  "occupation": "工程师",
  "annual_income": 300000,
  "monthly_budget": 5000,
  "insurance_types": ["重疾险", "医疗险"],
  "coverage_amount": 500000,
  "coverage_period": "至80岁",
  "existing_policies": []
}

输出格式

{
  "status": "done",
  "proposal": {
    "customer_name": "张三",
    "plans": [
      {
        "name": "基础方案",
        "total_premium": 12000,
        "items": [
          {
            "product_name": "XX重疾险",
            "coverage_amount": 300000,
            "annual_premium": 8000,
            "recommend_reason": "性价比高,保障全面"
          }
        ],
        "summary": "适合预算有限的客户"
      },
      {
        "name": "均衡方案",
        "total_premium": 18000,
        "items": [...],
        "summary": "保障与价格平衡"
      },
      {
        "name": "全面方案",
        "total_premium": 25000,
        "items": [...],
        "summary": "保障最全面"
      }
    ],
    "disclaimer": "以上方案仅供参考,具体以保险合同为准"
  }
}

Phase 3.1:产品推荐后端 API0.5 天)

目标:实现产品推荐相关的后端 API

任务清单

# 任务 API 说明
3.1.1 数据库扩展 - 添加 share_token 等字段
3.1.2 Workflow 调用封装 - 封装 Dify Workflow API
3.1.3 生成方案 API POST /recommend/generate 调用 Workflow
3.1.4 查询状态 API GET /recommend/generate/{task_id} 轮询任务状态
3.1.5 导出方案 API POST /recommend/{id}/export PDF/Word 导出
3.1.6 分享链接 API POST /recommend/{id}/share 生成分享链接

3.1.1 数据库扩展

-- 添加分享相关字段
ALTER TABLE recommendation_records
ADD COLUMN IF NOT EXISTS share_token VARCHAR(64),
ADD COLUMN IF NOT EXISTS share_expire_at TIMESTAMP;

3.1.2 Workflow 调用封装

文件api/insurance/recommend/workflow_helper.py

"""BaoDan Workflow 调用封装。"""
import requests
from flask import current_app


class WorkflowHelper:
    """Workflow API 调用封装。"""

    def run_workflow(self, inputs: dict, user_id: str) -> dict:
        """
        执行 Workflow 获取推荐方案。

        Args:
            inputs: 客户信息和保险需求
            user_id: 用户 ID

        Returns:
            Workflow 执行结果
        """
        base_url = current_app.config.get("BAODAN_API_URL", "http://localhost:5001")
        api_key = current_app.config.get("BAODAN_WORKFLOW_API_KEY", "")

        resp = requests.post(
            f"{base_url}/v1/workflows/run",
            json={
                "inputs": inputs,
                "response_mode": "blocking",
                "user": f"recommend_{user_id}",
            },
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=120,
        )

        return resp.json()

3.1.3 生成方案 API

文件api/insurance/recommend/routes.py

@recommend_bp.route("/generate", methods=["POST"])
@jwt_required
def generate():
    """生成推荐方案。"""
    data = request.get_json()
    if not data:
        return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400

    user_id = request.user_id

    # 参数校验(见需求文档 §13.3
    errors = self._validate_params(data)
    if errors:
        return jsonify({"code": 1001, "message": "; ".join(errors), "data": None}), 400

    # 创建推荐记录
    from insurance.recommend.service import RecommendService
    service = RecommendService()
    result = service.create_proposal(user_id, data)

    if result["code"] != 0:
        return jsonify(result), 400

    task_id = result["data"]["task_id"]

    # 异步调用 Workflow
    import threading
    threading.Thread(
        target=self._run_workflow_async,
        args=(task_id, data, user_id),
        daemon=True,
    ).start()

    return jsonify({"code": 0, "data": {"task_id": task_id, "status": "processing"}})

3.1.4 查询状态 API

@recommend_bp.route("/generate/<task_id>", methods=["GET"])
@jwt_required
def get_status(task_id):
    """查询推荐任务状态。"""
    from insurance.recommend.service import RecommendService
    service = RecommendService()
    result = service.get_proposal_status(task_id)
    return jsonify(result)

3.1.5 导出方案 API

@recommend_bp.route("/<proposal_id>/export", methods=["POST"])
@jwt_required
def export_proposal(proposal_id):
    """导出推荐方案。"""
    data = request.get_json()
    format_type = data.get("format", "pdf")  # pdf / docx

    from insurance.recommend.service import RecommendService
    service = RecommendService()
    result = service.export_proposal(proposal_id, format_type)

    if result["code"] != 0:
        return jsonify(result), 400

    return jsonify(result)

3.1.6 分享链接 API

@recommend_bp.route("/<proposal_id>/share", methods=["POST"])
@jwt_required
def share_proposal(proposal_id):
    """生成分享链接。"""
    from insurance.recommend.service import RecommendService
    service = RecommendService()
    result = service.create_share_link(proposal_id)
    return jsonify(result)

Phase 3.2产品推荐前端联调0.5 天)

目标:联调前端与后端 API

已有前端文件

文件 说明 状态
RecommendPage.vue 推荐主页面 已存在
RecommendForm.vue 客户信息表单 已存在
RecommendResult.vue 方案展示组件 已存在
RecommendHistory.vue 历史方案列表 已存在
RecommendDetail.vue 方案详情页 已存在

需要修改的文件

文件 修改内容 工作量
RecommendPage.vue 联调 generate API 0.2 天
RecommendResult.vue 适配后端返回格式 0.2 天
RecommendHistory.vue 联调 list API 0.1 天
RecommendDetail.vue 联调 export/share API 0.1 天

RecommendPage.vue 联调逻辑

async function onSubmit(formData: RecommendRequest) {
  loading.value = true
  generating.value = true
  result.value = null

  try {
    // 1. 提交生成请求
    const submitRes = await api.post('/recommend/generate', formData)
    const taskId = submitRes.data.task_id

    // 2. 轮询状态
    let retries = 0
    const maxRetries = 60
    while (retries < maxRetries) {
      await new Promise(r => setTimeout(r, 2000))
      const pollRes = await api.get(`/recommend/generate/${taskId}`)
      const task = pollRes.data

      if (task.status === 'done') {
        result.value = task
        ElMessage.success('方案生成成功')
        return
      }
      if (task.status === 'failed') {
        ElMessage.error(task.error_message || '方案生成失败')
        return
      }
      retries++
    }
    ElMessage.warning('生成超时,请稍后在历史方案中查看')
  } catch {
    // 错误已由 api 拦截器处理
  } finally {
    loading.value = false
    generating.value = false
  }
}

Phase 5.1批量导入用户0.5 天)

目标:支持 Excel 批量导入用户

任务清单

# 任务 说明
5.1.1 后端 API POST /admin/users/batch-import
5.1.2 Excel 解析 使用 openpyxl 解析 Excel
5.1.3 批量插入 批量插入用户记录
5.1.4 前端上传 UsersPage 添加导入按钮

后端实现

@bp.route("/users/batch-import", methods=["POST"])
@super_admin_required
def batch_import_users():
    """批量导入用户。"""
    file = request.files.get("file")
    if not file:
        return jsonify({"code": 1001, "message": "请选择文件", "data": None}), 400

    # 解析 Excel
    import openpyxl
    wb = openpyxl.load_workbook(file)
    ws = wb.active

    users = []
    for row in ws.iter_rows(min_row=2, values_only=True):
        username, department, role = row[0], row[1], row[2]
        if username:
            users.append({
                "username": username,
                "department": department or "",
                "role": role or "sales",
            })

    # 批量插入
    from insurance.admin.service import AdminService
    service = AdminService()
    result = service.batch_create_users(users)

    return jsonify(result)

前端实现

<!-- UsersPage.vue -->
<el-upload
  :action="'/insurance/admin/users/batch-import'"
  :headers="uploadHeaders"
  :on-success="onImportSuccess"
  :on-error="onImportError"
  accept=".xlsx,.xls"
  :show-file-list="false"
>
  <el-button>批量导入</el-button>
</el-upload>

Phase 5.2数据权限过滤0.5 天)

目标:实现销售只看自己的数据,主管看本组数据

任务清单

# 任务 说明
5.2.1 数据权限中间件 get_data_scope() 已实现
5.2.2 推荐记录过滤 根据权限过滤推荐记录
5.2.3 对话记录过滤 根据权限过滤对话记录

实现逻辑

# 在查询接口中注入数据权限
def get_proposals(user_id, params):
    """获取推荐记录列表(带数据权限)。"""
    from insurance.middleware.auth_middleware import get_data_scope
    scope = get_data_scope()

    query = db.session.query(RecommendationRecord)

    if scope["scope"] == "self":
        # 销售:只看自己的
        query = query.filter(RecommendationRecord.user_id == user_id)
    elif scope["scope"] == "team":
        # 主管:看本部门的
        query = query.filter(
            RecommendationRecord.user_id.in_(
                db.session.query(WeComUserMapping.id).filter(
                    WeComUserMapping.department == scope["department"]
                )
            )
        )
    # admin/super_admin看全部

    return query.all()

Phase 7.1文档编号自动生成0.2 天)

目标:文档上传时自动生成编号

编号规则

格式:{险种代码}-{保司代码}-{序号}
示例CJ-XX-001重疾险-XX人寿-第1个文档

险种代码:
- CJ = 重疾险
- RS = 寿险
- YL = 医疗险
- YW = 意外险
- CX = 车险
- NJ = 年金险
- CX = 储蓄险

实现

def generate_doc_number(insurance_type: str, company: str) -> str:
    """生成文档编号。"""
    type_codes = {
        "重疾险": "CJ", "寿险": "RS", "医疗险": "YL",
        "意外险": "YW", "车险": "CX", "年金险": "NJ", "储蓄险": "CX",
    }
    type_code = type_codes.get(insurance_type, "XX")
    company_code = company[:2] if company else "XX"

    # 查询当前序号
    count = db.session.query(DocumentMetadata).filter(
        DocumentMetadata.insurance_type == insurance_type,
        DocumentMetadata.company == company,
    ).count()

    return f"{type_code}-{company_code}-{count + 1:03d}"

Phase 8.1功能测试1 天)

目标:验证所有功能正常工作

测试清单

# 测试项 测试用例 验证标准
X.1 登录 账密登录 返回 token可访问受保护页面
X.2 登录 企微 OAuth 重定向到企微授权页
X.3 对话 发送消息 返回 AI 回答
X.4 对话 险种筛选 切换险种后对话正常
X.5 推荐 生成方案 返回 3 套方案
X.6 推荐 导出 PDF 下载 PDF 文件
X.7 用户 新增用户 用户列表增加
X.8 用户 角色权限 非管理员无法访问 /admin
X.9 知识库 上传文档 文档出现在列表
X.10 统计 查看仪表盘 显示数据

三、开发时间表

第 1 天产品推荐核心1.5 天工作量)

时间 任务 产出
上午 Phase 2.5: Workflow 配置 Workflow 应用创建完成
下午 Phase 3.1: 后端 API generate/status/export/share API
晚上 Phase 3.2: 前端联调 推荐页面可正常使用

第 2 天增强功能1.5 天工作量)

时间 任务 产出
上午 Phase 5.1: 批量导入 Excel 导入功能
下午 Phase 5.2: 数据权限 销售/主管数据隔离
晚上 Phase 7.1: 文档编号 自动编号功能

第 3 天:测试 + 部署1 天工作量)

时间 任务 产出
上午 Phase 8.1: 功能测试 测试报告
下午 部署 + 文档 生产环境部署

四、文件变更清单

后端文件

文件 操作 说明
api/insurance/recommend/workflow_helper.py 修改 封装 Workflow 调用
api/insurance/recommend/routes.py 修改 完善 generate/status/export/share
api/insurance/recommend/service.py 修改 实现业务逻辑
api/insurance/admin/routes.py 修改 添加 batch-import
api/insurance/admin/service.py 修改 实现批量导入
api/insurance/kb/service.py 修改 添加编号生成

前端文件

文件 操作 说明
frontend/src/pages/RecommendPage.vue 修改 联调 generate API
frontend/src/pages/RecommendResult.vue 修改 适配返回格式
frontend/src/pages/RecommendHistory.vue 修改 联调 list API
frontend/src/pages/admin/UsersPage.vue 修改 添加导入按钮

五、配置变更

docker-compose.dify.yml

# 更新 Workflow API Key从 Dify 后台获取)
BAODAN_WORKFLOW_API_KEY: "app-real-workflow-api-key"

数据库变更

-- 添加分享字段
ALTER TABLE recommendation_records
ADD COLUMN IF NOT EXISTS share_token VARCHAR(64),
ADD COLUMN IF NOT EXISTS share_expire_at TIMESTAMP;

六、验收标准

功能验收

# 功能 验收标准
1 登录 账密/企微登录正常
2 对话 iframe 嵌入 BaoDan可对话
3 推荐 填写表单 → 生成 3 套方案
4 导出 方案可导出 PDF/Word
5 用户管理 CRUD + 角色权限正常
6 知识库 文档上传/列表正常
7 统计 仪表盘显示数据

性能验收

# 指标 标准
1 登录响应 < 2 秒
2 对话响应 < 5 秒
3 推荐生成 < 30 秒
4 页面加载 < 3 秒

七、风险与应对

风险 影响 应对措施
Workflow 配置复杂 推荐功能无法使用 参考 Dify 官方文档,逐步配置
Workflow 输出格式不稳定 方案解析失败 在 workflow_helper.py 中加容错解析
企微 XML 加解密 消息回调不通 参考企微官方 Python SDK
测试时间不足 部署后出现问题 优先测试核心功能

八、总结

工作量估算

任务 工作量 优先级
Workflow 配置 0.5 天 🔴
产品推荐 API 0.5 天 🔴
前端联调 0.5 天 🔴
批量导入 0.5 天 🟡
数据权限 0.5 天 🟡
文档编号 0.2 天 🟢
功能测试 1 天 🔴
总计 3.2 天

交付物

  1. 完整的产品推荐功能Workflow + API + 前端)
  2. 批量导入用户功能
  3. 数据权限过滤
  4. 文档编号自动生成
  5. 功能测试报告
  6. 部署文档