Files
wecom_it_smart_desk/docs/02-技术文档/01-架构设计/业务路由推荐-架构设计.md
T
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

28 KiB
Raw Blame History

业务路由推荐 — 系统架构设计

版本: v1.0 日期: 2026-07-15 作者: Bob(架构师) 状态: 待评审 关联PRD: docs/01-产品文档/03-AI服务/业务路由推荐-PRD.md


目录


Part A: 系统设计

1. 实现方案

1.1 技术栈选型

沿用现有技术栈,不引入新框架

技术栈 说明
后端 FastAPI + SQLAlchemy + PostgreSQL + Redis 与现有审批/BYOD 系统完全一致
H5前端 Vue3 + Vant4 + TypeScript 名片卡片用 Vant 组件实现
坐席前端 Vue3 + Element Plus 名片卡片用 Element Plus 风格适配
AI意图识别 Dify 原生 API(扩展现有 Prompt 同一个 Dify 应用,API Key 不变

1.2 核心技术挑战与对策

挑战 对策
向后兼容:扩展 Dify Prompt 后不能破坏现有审批识别 原审批判断规则原文保留不动,仅新增非IT判断段落;原3字段(is_approval_request/confidence/approval_type)语义和取值不变,新增3字段;上线前用审批测试用例集回归
路由检测时机:在消息处理流程中何时调用 Dify process_h5_ai_reply 后台任务中新增路由检测步骤(与 BYOD 拦截模式一致),位于 BYOD 检测之后、打招呼/呼叫人工检测之前;通过关键词预过滤减少不必要的 Dify 调用
误路由防护IT问题被误识别为非IT routing_confidence < 0.7 不触发名片推荐,走正常 AI 回复流程;路由文本消息中附「仍需IT帮助」兜底引导
企微跳转可靠性openEnterpriseChat 调用失败 前端容错:userid 为空或 SDK 未就绪时 Toast 提示;上线前核对联系人 userid 数据
双通道下发:名片消息需同时到达 H5 和坐席端 复用现有 ws_manager.broadcast_to_employees()(推H5+ ws_manager.broadcast()(推坐席)双通道模式

1.3 架构模式

采用现有系统的「后台任务 + WS推送」异步架构,与 BYOD 卡片完全一致的消息处理模式:

员工发消息 → HTTP即时返回 → 后台AI任务(process_h5_ai_reply)
                                  ↓
                          ┌─ BYOD关键词拦截(现有)
                          ├─ 路由关键词预过滤 → Dify统一意图识别(新增)
                          │   └─ non_it_routing && confidence≥0.7 → 发送名片卡片
                          ├─ 打招呼/呼叫人工检测(现有)
                          └─ Dify流式回复(现有)

1.4 关键设计决策

  1. 路由检测放在后台任务而非前端调用:PRD 要求「后端自动发送」名片消息,且需经 WS 双通道下发。与 BYOD 卡片的处理模式一致,在 process_h5_ai_reply 中集成,保证服务端控制消息发送。

  2. 统一 Dify Prompt 但独立调用函数Dify 后台 Prompt 扩展为统一意图识别引擎(一次调用输出审批+路由判断),但后端 routing_service.pyapproval.py 各自维护调用函数,避免耦合。两者使用相同的 Dify 应用(同一 API Key),只是解析各自关心的字段。

  3. 关键词预过滤双层设计:路由预过滤关键词(打印机/工牌/报销等)与审批预过滤关键词可能重叠(如"办公用品")。Dify Prompt 内部的判断优先级(先审批→再IT咨询→再非IT路由)确保正确分流,预过滤只负责「是否值得调 Dify」。

  4. 名片消息三段式发送:路由文本说明 → 名片卡片 → 系统提示,三条消息分别落库 + WS推送,与 PRD 4.3 交互流程一致。


2. 文件列表

2.1 新建文件

# 文件路径 说明
1 backend/app/models/business_contact.py 业务联系人数据模型
2 backend/app/models/routing_event.py 路由命中统计模型(P1
3 backend/app/services/routing_service.py 路由服务:Dify调用、联系人查询、名片发送
4 backend/app/api/routing.py 路由API:联系人查询、坐席手动发名片(P1)
5 backend/alembic/versions/047_business_contacts.py 数据库迁移:建表 + 初始数据
6 docs/02-技术文档/实现配置/dify_unified_intent_prompt_v3.md 扩展后的统一意图识别 Dify Prompt
7 frontend-h5/src/components/chat/ContactCard.vue H5员工名片卡片组件
8 frontend-h5/src/api/routing.ts H5路由API(联系人查询,供组件使用)
9 frontend-agent/src/components/chat/ContactCardInline.vue 坐席端名片卡片组件
10 frontend-agent/src/api/routing.ts 坐席端路由API(手动发名片)

2.2 修改文件

# 文件路径 修改内容
11 backend/app/config.py 新增 routing_confidence_threshold 配置项
12 backend/app/models/__init__.py 注册 BusinessContactRoutingEvent 模型
13 backend/app/api/router.py 注册 routing 路由器
14 backend/app/api/approval.py _call_dify_approval_intent() 解析扩展字段;ApprovalDetectIntentResponse 新增 intent_type/business_category/routing_confidence 字段
15 backend/app/tasks/h5_ai_task.py 新增路由检测步骤:_handle_routing()
16 frontend-h5/src/api/conversation.ts MsgContentType 新增 'contact_card'
17 frontend-h5/src/components/chat/MessageBubble.vue 新增 msg.msg_type === 'contact_card' 渲染分支
18 frontend-agent/src/components/chat/MessageBubble.vue 新增 contact_card 渲染分支
19 frontend-agent/src/components/chat/InputBox.vue 新增「发名片」入口按钮(P1

3. 数据结构与接口

3.1 类图

完整类图见 docs/02-技术文档/技术架构/业务路由推荐-类图.mermaid

classDiagram
    class BusinessContact {
        +int id
        +str name
        +str gender
        +str department
        +str position
        +str responsibility
        +str extension
        +str service_area
        +str wecom_userid
        +str avatar_url
        +str business_category
        +bool is_active
        +datetime created_at
        +datetime updated_at
    }

    class RoutingEvent {
        +int id
        +str conversation_id
        +str employee_id
        +str message_content
        +str business_category
        +float routing_confidence
        +int contact_id
        +str contact_name
        +bool is_clicked
        +datetime created_at
    }

    class RoutingService {
        +ROUTING_PREFILTER_KEYWORDS: list~str~
        +ROUTING_KEYWORD_TO_CATEGORY: dict
        +async detect_routing_intent(text, employee_id) dict
        +async get_contact_by_category(category) BusinessContact
        +async send_contact_card(db, conversation, employee_id, contact, reason) None
        +async record_routing_event(db, conversation_id, employee_id, content, category, confidence, contact) None
    }

    class RoutingAPI {
        +GET /h5/routing/contact
        +GET /routing/contacts
        +POST /conversations/{id}/send-contact-card
    }

    class ApprovalDetectIntentResponse {
        +bool is_approval_request
        +float confidence
        +str approval_type
        +str source
        +str intent_type
        +str business_category
        +float routing_confidence
    }

    BusinessContact "1" --> RoutingEvent : contact_id
    RoutingService --> BusinessContact : 查询
    RoutingService --> RoutingEvent : 记录
    RoutingAPI --> RoutingService : 调用

3.2 数据库表结构

business_contactsP0

字段 类型 约束 说明
id Integer PK, 自增 主键
name String(50) NOT NULL 联系人姓名
gender String(10) NOT NULL, default 'male' 性别(male/female
department String(100) NOT NULL 部门名称
position String(100) NOT NULL 岗位
responsibility String(500) NOT NULL 负责业务描述
extension String(20) NULL 分机号
service_area String(200) NULL 服务区域/办公地点
wecom_userid String(100) NOT NULL 企微用户ID
avatar_url String(500) NULL 头像URL(为空用姓名首字渲染)
business_category String(50) NOT NULL 业务类别(行政/人力资源/财务/法务/行政-物业)
is_active Boolean NOT NULL, default True 是否启用
created_at DateTime NOT NULL 创建时间
updated_at DateTime NOT NULL 更新时间

索引: idx_business_contacts_category on (business_category, is_active)

routing_eventsP1 — 路由命中统计)

字段 类型 约束 说明
id Integer PK, 自增 主键
conversation_id String(36) NOT NULL, FK 会话ID
employee_id String(64) NOT NULL 员工ID
message_content String(500) NOT NULL 触发路由的员工消息(截断)
business_category String(50) NOT NULL 识别的业务类别
routing_confidence Float NOT NULL 路由置信度
contact_id Integer FK 推荐的联系人ID
contact_name String(50) NOT NULL 联系人姓名(冗余)
is_clicked Boolean default False 员工是否点击了「联系TA」
created_at DateTime NOT NULL 创建时间

索引: idx_routing_events_category on (business_category), idx_routing_events_conv on (conversation_id)

3.3 消息类型定义

新增 msg_type = 'contact_card'

与现有 approval_card / byod_card 采用相同的渲染架构:后端通过 msg_type 区分,卡片数据通过 extra_data 透传。

消息记录结构Message 表):

字段 说明
sender_type 'ai' 发送者为 AI
sender_id 'ai_bot' AI 标识
sender_name 'Duckula(达寇拉)' 与现有 AI 消息一致
msg_type 'contact_card' 新增消息类型
content 路由说明文本 如"为您推荐行政服务联系人"
extra_data JSON(见下) 联系人完整信息

extra_data 结构规范

{
  "contact": {
    "id": 1,
    "name": "王芳",
    "gender": "female",
    "department": "行政部",
    "position": "设备管理岗",
    "responsibility": "打印机/复印机/扫描仪",
    "extension": "8002",
    "service_area": "滨江园区 3-5楼",
    "wecom_userid": "WangFang",
    "avatar_url": "",
    "business_category": "行政"
  },
  "routing_reason": "打印机问题属于行政设备范畴,不在IT服务台服务范围内,为您推荐行政服务联系人",
  "business_category": "行政",
  "routing_confidence": 0.85
}

3.4 API 接口定义

H5 端 — 查询联系人(P0

GET /api/h5/routing/contact?business_category=行政

响应

{
  "code": 0,
  "data": {
    "id": 1,
    "name": "王芳",
    "gender": "female",
    "department": "行政部",
    "position": "设备管理岗",
    "responsibility": "打印机/复印机/扫描仪",
    "extension": "8002",
    "service_area": "滨江园区 3-5楼",
    "wecom_userid": "WangFang",
    "avatar_url": "",
    "business_category": "行政"
  }
}

逻辑:按 business_category + is_active=true 查询,取第一条有效联系人。

坐席端 — 获取联系人列表(P1

GET /api/routing/contacts?business_category=行政&keyword=王

响应{ "code": 0, "data": { "items": [BusinessContact, ...] } }

坐席端 — 手动发送名片(P1

POST /api/conversations/{conversation_id}/send-contact-card

请求体

{ "contact_id": 1, "reason": "员工咨询报销问题,为您推荐财务联系人" }

逻辑:坐席手动选择联系人 → 后端创建 contact_card 消息 → WS 推送双通道。

审批意图检测扩展(P0 — 向后兼容)

POST /api/approval/detect-intent

响应(扩展后)

{
  "code": 0,
  "data": {
    "is_approval_request": false,
    "confidence": 0.15,
    "approval_type": null,
    "source": "dify",
    "intent_type": "non_it_routing",
    "business_category": "行政",
    "routing_confidence": 0.85
  }
}

原 4 个字段(is_approval_request/confidence/approval_type/source)语义不变,新增 3 个字段。前端现有审批逻辑只读取原字段,不受影响。

3.5 Dify 统一意图识别 Prompt 扩展

扩展后输出格式(原3字段不变,新增3字段):

{
  "is_approval_request": true,
  "confidence": 0.95,
  "approval_type": "设备申请",
  "intent_type": "approval",
  "business_category": null,
  "routing_confidence": 0.0
}

判断优先级链Prompt 内部逻辑):

1. IT审批意图 → intent_type: "approval", is_approval_request: true
2. IT范围内咨询/报修 → intent_type: "it_consult", is_approval_request: false
3. 非IT业务路由 → intent_type: "non_it_routing", business_category: "行政"/"人力资源"/...
4. 闲聊/无关 → intent_type: "chitchat"

完整 Prompt 见 docs/02-技术文档/实现配置/dify_unified_intent_prompt_v3.md


4. 程序调用流程

4.1 核心时序图

完整时序图见 docs/02-技术文档/技术架构/业务路由推荐-时序图.mermaid

sequenceDiagram
    participant E as 员工(H5)
    participant H5 as H5前端
    participant BE as 后端API
    participant TASK as 后台AI任务
    participant DIFY as Dify API
    participant DB as PostgreSQL
    participant WS as WebSocket
    participant AG as 坐席端
    participant WECOM as 企微

    E->>H5: 发送非IT消息 "打印机坏了"
    H5->>BE: POST /h5/conversations/current/messages
    BE->>DB: 存储员工消息
    BE->>WS: broadcast(新消息→坐席)
    BE-->>H5: 即时返回(user_message)
    BE->>TASK: asyncio.create_task(process_h5_ai_reply)

    Note over TASK: BYOD关键词检查(未命中)
    
    TASK->>TASK: 路由关键词预过滤("打印机"命中)
    TASK->>DIFY: 调用统一意图识别
    DIFY-->>TASK: intent_type=non_it_routing, business_category=行政, routing_confidence=0.85
    
    TASK->>DB: 查询business_contacts(行政)
    DB-->>TASK: 返回联系人(王芳)
    
    TASK->>DB: 存路由说明文本消息(ai, text)
    TASK->>WS: broadcast_to_employees(ai_reply→H5)
    TASK->>WS: broadcast(new_message→坐席)
    
    TASK->>DB: 存contact_card消息(ai, contact_card)
    TASK->>WS: broadcast_to_employees(ai_reply→H5, 含extra_data)
    TASK->>WS: broadcast(new_message→坐席, 含extra_data)
    
    TASK->>DB: 存系统提示消息(system)
    TASK->>WS: broadcast_to_employees(ai_reply→H5)
    TASK->>WS: broadcast(new_message→坐席)
    
    TASK->>DB: 记录routing_event(P1)
    
    WS-->>H5: ai_reply(路由文本)
    H5->>E: 渲染AI文本气泡
    WS-->>H5: ai_reply(contact_card)
    H5->>E: 渲染ContactCard名片卡片
    WS-->>H5: ai_reply(系统提示)
    H5->>E: 渲染系统消息
    
    WS-->>AG: new_message x3(路由文本+名片+系统提示)
    AG->>AG: 渲染名片卡片(坐席端可见)
    
    E->>H5: 点击「联系TA」
    H5->>WECOM: wx.invoke('openEnterpriseChat', {userids: 'WangFang'})
    WECOM-->>E: 打开企微单聊
    
    Note over E,BE: 当前IT服务台会话不自动结束

4.2 路由检测在后台任务中的位置

process_h5_ai_reply(conversation_id, employee_id, content, dify_conversation_id)
│
├─ 1. BYOD 关键词拦截(现有,不变)
│     └─ 命中 → _handle_byod_query() → return
│
├─ 2. 【新增】路由关键词预过滤
│     └─ 命中非IT关键词 → _handle_routing()
│         ├─ 调用 Dify 统一意图识别
│         ├─ intent_type == "non_it_routing" && routing_confidence >= 0.7
│         │   └─ YES → 发送名片三段式消息 → return
│         │   └─ NO  → 继续往下(走正常AI流程)
│         └─ Dify调用失败 → 关键词降级兜底(按关键词映射类别)
│
├─ 3. 打招呼/呼叫人工检测(现有,不变)
│     └─ 命中 → 同步回复 → return
│
└─ 4. Dify 流式回复(现有,不变)
      └─ 流式推送 → _persist_and_push()

4.3 坐席手动发名片流程(P1

sequenceDiagram
    participant AG as 坐席端
    participant BE as 后端API
    participant DB as PostgreSQL
    participant WS as WebSocket
    participant H5 as H5前端

    AG->>BE: POST /conversations/{id}/send-contact-card {contact_id, reason}
    BE->>DB: 查询 BusinessContact by id
    DB-->>BE: 返回联系人信息
    BE->>DB: 创建 contact_card 消息(ai, extra_data=contact)
    BE->>WS: broadcast_to_employees(ai_reply→H5)
    BE->>WS: broadcast(new_message→坐席)
    BE-->>AG: 返回成功
    WS-->>H5: ai_reply(contact_card)
    H5->>H5: 渲染名片卡片

5. 待明确事项

# 问题 影响 假设/建议
1 企微 openEnterpriseChatuserids 参数格式(企微账号ID vs 工号) 数据模型 wecom_userid 字段取值 假设:使用企微通讯录同步的 userid(与现有员工 employee_id 格式一致),需上线前核对
2 非IT业务类别是否还有其他部门需覆盖 Prompt 设计 + 数据初始化 当前覆盖 5 类(行政/人力资源/财务/法务/行政-物业),建议上线后根据路由统计补充
3 一个业务类别多个联系人时的选择策略 后端查询逻辑 P0 取第一个 is_active=true 的联系人;P2 支持按服务区域匹配
4 Dify Prompt 修改后是否需要 A/B 测试 上线策略 建议灰度上线,监控审批识别准确率无下降后全量;先用 PRD 5.5 回归测试用例集验证
5 坐席手动发名片的触发入口位置 坐席端 UI 假设:在 InputBox 工具栏新增「发名片」按钮,弹出联系人选择面板
6 routing_confidence 在 0.5~0.7 之间是否推荐 路由触发策略 已确认:不推荐,走正常 AI 回复流程

Part B: 任务分解

6. 依赖包列表

无需新增第三方依赖包。所有功能基于现有技术栈实现:

已有依赖 用途
fastapi API 路由
sqlalchemy ORM 模型
alembic 数据库迁移
httpx Dify API 调用(已在 approval.py 中使用)
pydantic Schema 定义
vant@^4 H5 名片卡片 UI 组件
element-plus 坐席端名片卡片 UI 组件

7. 任务列表

T01: 后端数据层 + 配置 + Prompt 基础设施

内容
Task ID T01
Task Name 后端数据层 + 配置基础设施
Priority P0
Dependencies

源文件

  • backend/app/models/business_contact.py(新建)— BusinessContact 模型
  • backend/app/models/routing_event.py(新建)— RoutingEvent 模型(P1
  • backend/app/models/__init__.py(修改)— 注册新模型
  • backend/alembic/versions/047_business_contacts.py(新建)— 建表 + 初始数据迁移
  • backend/app/config.py(修改)— 新增 routing_confidence_threshold 配置
  • backend/app/api/router.py(修改)— 注册 routing 路由器(占位,路由实现在 T02)
  • docs/02-技术文档/实现配置/dify_unified_intent_prompt_v3.md(新建)— 扩展后的 Dify Prompt

验收标准

  • BusinessContact / RoutingEvent 模型可被 Alembic 检测到
  • alembic upgrade head 成功建表并写入初始联系人数据
  • routing_confidence_threshold 配置项默认值 0.7
  • Dify Prompt 文档包含完整的扩展后 System Prompt(原审批规则 + 新增非IT路由判断段落)

T02: 后端路由服务 + API + 后台任务集成

内容
Task ID T02
Task Name 后端路由服务与消息发送
Priority P0
Dependencies T01

源文件

  • backend/app/services/routing_service.py(新建)— 核心路由逻辑:关键词预过滤、Dify调用、联系人查询、名片三段式发送、路由事件记录
  • backend/app/api/routing.py(新建)— API 端点:GET /h5/routing/contactGET /routing/contactsPOST /conversations/{id}/send-contact-card
  • backend/app/api/approval.py(修改)— _call_dify_approval_intent() 解析扩展字段;ApprovalDetectIntentResponse 新增 intent_type/business_category/routing_confidence
  • backend/app/tasks/h5_ai_task.py(修改)— 在 BYOD 检测后新增 _handle_routing() 调用步骤

验收标准

  • 员工发送"打印机坏了" → 后台任务检测到 non_it_routing → 发送路由文本 + contact_card + 系统提示三条消息
  • 员工发送"我要申请笔记本电脑" → 审批意图正常识别(回归无影响)
  • routing_confidence < 0.7 时不触发名片推荐,走正常 AI 流程
  • Dify 调用失败时降级为关键词匹配(按 ROUTING_KEYWORD_TO_CATEGORY 映射)
  • 坐席端通过 POST /conversations/{id}/send-contact-card 可手动发送名片
  • WS 双通道推送正常(H5 收到 ai_reply,坐席收到 new_message

T03: H5 前端名片卡片组件 + 消息映射

内容
Task ID T03
Task Name H5 员工名片卡片与渲染
Priority P0
Dependencies T02

源文件

  • frontend-h5/src/components/chat/ContactCard.vue(新建)— 名片卡片组件:头像/姓名/部门岗位/负责业务(绿色高亮)/分机号/服务区域/「联系TA」按钮
  • frontend-h5/src/components/chat/MessageBubble.vue(修改)— 新增 v-else-if="msg.msg_type === 'contact_card'" 渲染分支
  • frontend-h5/src/api/conversation.ts(修改)— MsgContentType 新增 'contact_card'
  • frontend-h5/src/api/routing.ts(新建)— getContactByCategory() API 封装

验收标准

  • 名片卡片按 PRD 4.1 布局渲染:头像44px、姓名加粗、负责业务绿色高亮 #07C160、「联系TA」绿色按钮
  • 点击「联系TA」→ 调用 wx.invoke('openEnterpriseChat', {userids: contact.wecom_userid}) 打开企微单聊
  • userid 为空或企微 SDK 未就绪 → Toast 提示「暂时无法发起聊天,请联系管理员」
  • mapMessage() 无需改动(msg_typeextra_data 已透传),仅类型定义扩展
  • 历史消息中 contact_card 消息可正常渲染(从 extra_data.contact 读取数据)

T04: 坐席端名片展示 + 手动发名片功能

内容
Task ID T04
Task Name 坐席端名片可见性与手动发送
Priority P1
Dependencies T02

源文件

  • frontend-agent/src/components/chat/ContactCardInline.vue(新建)— 坐席端名片卡片(Element Plus 风格,展示联系人信息 + 推荐原因,无「联系TA」按钮)
  • frontend-agent/src/components/chat/MessageBubble.vue(修改)— 新增 contact_card 渲染分支
  • frontend-agent/src/api/routing.ts(新建)— getContacts()sendContactCard() API 封装
  • frontend-agent/src/components/chat/InputBox.vue(修改)— 工具栏新增「发名片」按钮,弹出联系人选择面板

验收标准

  • AI 发送的路由名片在坐席端消息流中可见,展示联系人信息 + 推荐原因
  • 坐席点击「发名片」→ 弹出联系人选择面板(按业务类别分组)→ 选择联系人 → 发送到当前会话
  • 坐席端名片卡片不显示「联系TA」按钮(坐席无需跳转企微单聊)
  • 名片消息在坐席端和 H5 端同时可见(双通道验证)

8. 共享知识

8.1 消息类型命名规范

msg_type 取值统一使用 snake_case
  text / image / file / voice / video / location
  system / approval_card / byod_card / contact_card(新增)

8.2 extra_data 结构规范

所有卡片类消息的 extra_data 采用 命名空间嵌套 结构:

msg_type extra_data 结构
approval_card { "approval_type": "设备申请" }
byod_card { "byod_result": { eligible, has_subsidy, ... } }
contact_card(新增) { "contact": { name, department, ... }, "routing_reason": "...", "business_category": "...", "routing_confidence": 0.85 }

8.3 WS 推送事件规范

路由名片消息复用现有 WS 事件类型:

推送目标 事件类型 data 关键字段
H5 员工 ai_reply message_id, msg_type: "contact_card", extra_data, sender_type: "ai"
坐席端 new_message message_id, msg_type: "contact_card", extra_data, sender_type: "ai"

H5 前端收到 ai_reply 事件时,根据 msg_type 决定渲染方式(文本气泡 / 名片卡片),与现有 BYOD 处理逻辑一致。

8.4 Dify 统一意图识别响应字段

字段 类型 取值范围 说明
is_approval_request bool true/false 原字段,是否为审批请求(语义不变)
confidence float 0.0~1.0 原字段,审批置信度(语义不变)
approval_type string|null 12种类型|null 原字段,审批类型(语义不变)
intent_type string approval/it_consult/non_it_routing/chitchat 新增,意图大类
business_category string|null 行政/人力资源/财务/法务/行政-物业|null 新增,非IT业务类别
routing_confidence float 0.0~1.0 新增,路由置信度,≥0.7 触发名片推荐

8.5 路由关键词预过滤列表

ROUTING_PREFILTER_KEYWORDS = [
    # 行政
    "打印机", "复印机", "扫描仪", "保洁", "名片印刷",
    # 人力资源
    "工牌", "考勤", "入职", "离职", "社保", "公积金",
    # 财务
    "报销", "发票", "借款", "工资条",
    # 法务
    "合同", "法务", "知识产权",
    # 行政-物业
    "空调", "电梯", "门禁", "停车",
]

ROUTING_KEYWORD_TO_CATEGORY = {
    "打印机": "行政", "复印机": "行政", "扫描仪": "行政", "保洁": "行政", "名片印刷": "行政",
    "工牌": "人力资源", "考勤": "人力资源", "入职": "人力资源", "离职": "人力资源",
    "社保": "人力资源", "公积金": "人力资源",
    "报销": "财务", "发票": "财务", "借款": "财务", "工资条": "财务",
    "合同": "法务", "法务": "法务", "知识产权": "法务",
    "空调": "行政-物业", "电梯": "行政-物业", "门禁": "行政-物业", "停车": "行政-物业",
}

8.6 跳转后会话不自动结束

员工点击「联系TA」跳转企微单聊后,当前 IT 服务台会话状态保持不变(ai_handling/serving),员工可返回继续咨询。不在后端触发任何会话状态变更。

8.7 向后兼容性保证

  1. Dify Prompt 扩展:原审批判断规则原文保留,仅新增非IT判断段落
  2. API 响应扩展/approval/detect-intent 响应新增字段,原字段语义不变;前端现有审批逻辑只读取原字段
  3. 消息类型扩展contact_card 是新增 msg_type,不影响现有 text/image/approval_card/byod_card 的渲染
  4. 数据库扩展:新建表,不修改现有表结构

9. 任务依赖图

graph LR
    T01[T01: 后端数据层+配置+Prompt]
    T02[T02: 后端路由服务+API+任务集成]
    T03[T03: H5名片卡片+消息映射]
    T04[T04: 坐席端名片+手动发名片]

    T01 --> T02
    T02 --> T03
    T02 --> T04

    style T01 fill:#07C160,color:#fff
    style T02 fill:#07C160,color:#fff
    style T03 fill:#1989fa,color:#fff
    style T04 fill:#ff976a,color:#fff

依赖说明

  • T01 → T02:路由服务依赖数据模型和配置
  • T02 → T03H5 前端依赖后端 API 契约和 WS 推送格式
  • T02 → T04:坐席端依赖后端 API 契约
  • T03 和 T04 互不依赖,可并行开发

:时序图 docs/02-技术文档/技术架构/业务路由推荐-时序图.mermaid :类图 docs/02-技术文档/技术架构/业务路由推荐-类图.mermaid