928 lines
43 KiB
Markdown
928 lines
43 KiB
Markdown
# 数据库建表设计
|
||
|
||
> 版本:v3.1
|
||
> 修订日期:2026-09-09
|
||
> 演进原则:只允许新增表和新增字段,不修改已有表名、已有字段名、字段类型及既有业务含义
|
||
|
||
## 1. 文档目的
|
||
|
||
本文定义通用 Agent 平台、记忆系统和智能客服专项能力的数据库建设方案。数据库业务基线已固化为项目内的《00-新数据库基线设计.md》,本文只在该基线上补充字段、表、实施顺序和迁移规则。
|
||
|
||
## 2. 数据库范围
|
||
|
||
- 数据库:MySQL 8.0。
|
||
- 默认字符集:`utf8mb4`。
|
||
- 默认排序规则:`utf8mb4_0900_ai_ci`。
|
||
- 基础业务表:33 张。
|
||
- 智能客服专项表:6 张。
|
||
- 平台底座增量表:12 张(原设计 10 张、outbox_delivery、api_request_receipt)。
|
||
- 建成后总表数:51 张(包含会话补表及公共 HTTP 写操作幂等回执)。
|
||
- Redis、Milvus 和 Neo4j 不计入 MySQL 表数量。
|
||
|
||
当前交易范围是场内基金模拟交易。数据库不建设充值、提现、银行流水匹配或场外基金申购赎回交易表。
|
||
|
||
### 2.1 不可变基线规则
|
||
|
||
新版《00-新数据库基线设计.md》中的表名和已有字段是不可变基线。后续迁移只能创建新表、在已有表中增加新字段,或为新增字段增加索引和约束。禁止重命名表,禁止删除、重命名或复用已有字段,禁止改变已有字段的类型、可空性和既有业务含义。历史问题无法兼容解决时,新增语义明确的字段或新表,并由应用执行双读、回填和切换。
|
||
|
||
## 3. 通用建表约定
|
||
|
||
数据库实体和迁移属于 MVC+S 的 Model 层。Controller 不访问 ORM;Service 通过 Repository 读写 Model。Alembic 迁移是表结构变更的唯一入口,运行时业务代码不执行 `CREATE TABLE` 或 `ALTER TABLE`。
|
||
|
||
| 项目 | 约定 |
|
||
|---|---|
|
||
| 主键 | `BIGINT UNSIGNED AUTO_INCREMENT` |
|
||
| 业务编号 | 单独字段并建立唯一索引 |
|
||
| 时间 | 使用 `DATETIME(6)`,统一以 `_at` 结尾 |
|
||
| 金额 | `DECIMAL(18,2)` |
|
||
| 价格 | `DECIMAL(18,6)` |
|
||
| 数量 | `DECIMAL(18,4)` |
|
||
| 置信度 | `DECIMAL(5,4)`,范围 0 至 1 |
|
||
| JSON | 使用 MySQL 原生 `JSON`,禁止用逗号字符串代替数组 |
|
||
| 删除 | 交易、预警、审计、对话和通知不物理删除 |
|
||
| 审计 | 关键状态变化追加写入 `interaction_audit` |
|
||
| 外键 | MySQL 核心实体使用外键;Milvus/Neo4j 关系由应用校验 |
|
||
| 时间基准 | 应用和数据库统一使用 UTC,展示层转换时区 |
|
||
|
||
## 4. 51 张表总览
|
||
|
||
### 4.1 基础业务表
|
||
|
||
| 域 | 表 | 主要职责 | Agent 访问边界 |
|
||
|---|---|---|---|
|
||
| 身份 | `sys_user` | 客户与员工统一身份 | 按字段策略读取 |
|
||
| 权限 | `sys_role` | 角色定义 | 只读 |
|
||
| 权限 | `sys_permission` | 资源、动作、数据范围 | 只读 |
|
||
| 权限 | `sys_user_role` | 用户角色关系 | 只读 |
|
||
| 权限 | `sys_role_permission` | 角色权限关系 | 只读 |
|
||
| 归属 | `sys_customer_assignment` | 客户与投顾/运营归属 | 只读 |
|
||
| 客户 | `fin_customer_profile` | 客户金融画像 | 只读 |
|
||
| 客户 | `fin_risk_assessment` | 正式风险测评历史 | 只读、权威事实 |
|
||
| 软事实 | `user_facts` | 现有代码兼容软事实 | 只读 |
|
||
| 产品 | `fin_product` | 场内产品及适当性信息 | 只读 |
|
||
| 行情 | `fin_market_price` | 场内日线行情 | 只读 |
|
||
| 净值 | `fin_nav_history` | 基金净值兼容数据 | 只读 |
|
||
| 账户 | `fin_sim_account` | 虚拟资金账户 | 只读 |
|
||
| 资金 | `fin_cash_ledger` | 虚拟资金明细 | 只读 |
|
||
| 资金 | `fin_capital_flow` | 风控兼容标准化流水 | 只读 |
|
||
| 费用 | `fin_fee_rule` | 模拟交易费率 | 只读 |
|
||
| 委托 | `fin_sim_order` | 场内模拟委托 | 交易服务写,Agent 只读 |
|
||
| 成交 | `fin_transaction` | 模拟成交 | 交易服务写,Agent 只读 |
|
||
| 持仓 | `fin_holding` | 当前持仓汇总 | 交易服务写,Agent 只读 |
|
||
| 登录 | `sys_login_record` | 逐次登录结果 | 只读 |
|
||
| 工单 | `biz_work_order` | 风险调查和处置工单 | 风控流程读写 |
|
||
| 风控 | `fin_risk_alert` | 规则命中与人工处置 | 风控服务读写 |
|
||
| 通知 | `fin_risk_notification` | 站内和邮件通知 | 风控服务读写 |
|
||
| 会话 | `conversation_message` | 完整对话留存 | 公共基础层写 |
|
||
| 知识 | `fin_knowledge_meta` | 知识元数据及正文镜像 | 知识服务写、Agent 只读 |
|
||
| Episode | `episodes` | 会话片段摘要 | 记忆服务写 |
|
||
| 记忆 | `memory_unit` | 中期记忆单元 | 记忆服务写 |
|
||
| 证据 | `memory_evidence` | 记忆来源证据 | 记忆服务写 |
|
||
| 冲突 | `memory_conflict` | 新旧记忆冲突 | 记忆服务写 |
|
||
| 画像 | `profile_snapshots` | 长期画像版本投影 | 画像服务写 |
|
||
| 同步 | `memory_sync_outbox` | Milvus/Neo4j 同步事件 | 记忆服务写、消费者更新状态 |
|
||
| 审计 | `interaction_audit` | 全系统追加审计 | 公共基础层追加写 |
|
||
| 内容 | `client_facing_content` | 对客内容审核发布 | 投顾流程读写 |
|
||
|
||
### 4.2 智能客服专项表
|
||
|
||
| 表 | 优先级 | 主要职责 |
|
||
|---|---|---|
|
||
| `agent_negative_word` | P0 | 禁止表达与变体规则配置 |
|
||
| `svc_handover_ticket` | P0 | 客服转人工工单 |
|
||
| `agent_faq_synonym` | P1 | FAQ 同义问法和口语表达 |
|
||
| `conversation_feedback` | P1 | 用户对回复的反馈 |
|
||
| `agent_reply_template` | Phase 2 | 兜底、拒答、免责声明等模板 |
|
||
| `agent_intent_config` | Phase 2 | 意图、阈值、路由和工具配置 |
|
||
|
||
### 4.3 平台底座增量表
|
||
|
||
| 表 | 主要职责 | 写入方 |
|
||
|---|---|---|
|
||
| `svc_conversation_session` | 会话状态、澄清轮次和配置快照 | 会话服务 |
|
||
| `outbox_delivery` | 已有 Outbox 消费幂等记录 | Outbox Worker |
|
||
| `api_request_receipt` | 公共 HTTP 写操作幂等回执 | ApiTransactionService |
|
||
|
||
api_request_receipt 是独立新增表,不复用只用于 Agent 运行的 request_idempotency。
|
||
其字段为 id BIGINT UNSIGNED 自增主键、user_id BIGINT UNSIGNED 非空、scope_hash CHAR(64)
|
||
非空、idempotency_key VARCHAR(128) 非空、request_hash CHAR(64) 非空、response_json JSON
|
||
可空、created_at DATETIME(6) 非空默认 CURRENT_TIMESTAMP(6),唯一键
|
||
(user_id, scope_hash, idempotency_key)。操作结果、业务状态和审计在同一事务完成;失败整体回滚。
|
||
迁移 20260909_api_receipt 仅 CREATE TABLE;既有 49 表字段指纹比对未变化,会话表保持 §8.1。
|
||
| `domain_event_outbox` | 通用领域事件可靠投递 | 事务内事件发布器 |
|
||
| `request_idempotency` | 请求占位、结果定位和并发防重 | AgentService |
|
||
| `agent_run` | 可恢复 Agent 运行状态、租约和结果定位 | AgentRunService/Worker |
|
||
| `config_release` | 配置发布、审核、激活和回滚批次 | 配置中心 |
|
||
| `platform_config_item` | 记忆、关系及运行参数的版本化配置项 | 配置中心 |
|
||
| `model_endpoint_config` | 模型端点能力、限制和密钥引用 | 模型平台管理员 |
|
||
| `model_routing_rule` | 按 Agent 和任务类型选择模型及备用链 | 模型路由服务 |
|
||
| `model_routing_fallback` | 路由规则的有序备用端点及可重试错误 | 模型路由服务 |
|
||
| `prompt_template_version` | 分类、生成、摘要和提取 Prompt 版本 | Prompt 管理服务 |
|
||
|
||
## 5. 核心关系
|
||
|
||
```text
|
||
sys_user 1 --- 1 fin_customer_profile
|
||
sys_user 1 --- N fin_risk_assessment
|
||
sys_user 1 --- N conversation_message
|
||
sys_user 1 --- N svc_handover_ticket
|
||
sys_user 1 --- N svc_conversation_session
|
||
|
||
conversation_message N --- 1 session_id(逻辑会话)
|
||
conversation_message 1 --- N conversation_feedback
|
||
|
||
fin_knowledge_meta 1 --- N agent_faq_synonym
|
||
fin_knowledge_meta -- 正文和向量镜像 --> Milvus 知识集合
|
||
|
||
episodes 1 --- N memory_unit
|
||
memory_unit 1 --- N memory_evidence
|
||
memory_unit N --- N memory_unit(通过 memory_conflict)
|
||
memory_unit/profile_snapshots 1 --- N memory_sync_outbox
|
||
|
||
svc_conversation_session 1 --- N conversation_message
|
||
svc_conversation_session 1 --- N request_idempotency
|
||
svc_conversation_session 1 --- N agent_run
|
||
request_idempotency 1 --- 1 agent_run
|
||
conversation_message 1 --- N agent_run(用户消息)
|
||
conversation_message 1 --- N agent_run(助手结果)
|
||
conversation_message/interaction_audit 1 --- N domain_event_outbox
|
||
|
||
config_release 1 --- N platform_config_item
|
||
config_release 1 --- N model_routing_rule
|
||
config_release 1 --- N prompt_template_version
|
||
model_endpoint_config 1 --- N model_routing_rule
|
||
model_routing_rule 1 --- N model_routing_fallback
|
||
model_endpoint_config 1 --- N model_routing_fallback
|
||
|
||
fin_risk_alert 1 --- N biz_work_order
|
||
fin_risk_alert 1 --- N fin_risk_notification
|
||
|
||
svc_handover_ticket 与 biz_work_order 相互独立
|
||
```
|
||
|
||
## 6. 现有表字段增补
|
||
|
||
### 6.1 conversation_message
|
||
|
||
新版基线已经包含 `tool_calls JSON`,保持其名称和定义不变。本次只新增以下三个字段:
|
||
|
||
| 字段 | 类型 | 约束 | 用途 |
|
||
|---|---|---|---|
|
||
| `intent` | VARCHAR(32) | 可空、索引 | 助手消息的意图结果 |
|
||
| `confidence` | DECIMAL(5,4) | 可空、索引、0 至 1 | 意图置信度 |
|
||
| `source_references` | JSON | 可空 | RAG 来源集合与文档 ID |
|
||
|
||
用户原始消息的三个新增字段可以为空;助手最终消息记录实际采用的意图、置信度和来源。既有 `tool_calls` 字段继续保存脱敏后的工具调用;未使用知识或工具时对应 JSON 字段使用 `NULL`。
|
||
|
||
迁移示例:
|
||
|
||
```sql
|
||
ALTER TABLE conversation_message
|
||
ADD COLUMN intent VARCHAR(32) NULL COMMENT '识别的意图' AFTER trace_id,
|
||
ADD COLUMN confidence DECIMAL(5,4) NULL COMMENT '意图置信度' AFTER intent,
|
||
ADD COLUMN source_references JSON NULL COMMENT '检索来源' AFTER confidence,
|
||
ADD CONSTRAINT chk_conversation_confidence
|
||
CHECK (confidence IS NULL OR confidence BETWEEN 0 AND 1),
|
||
ADD INDEX idx_conversation_intent (intent),
|
||
ADD INDEX idx_conversation_confidence (confidence);
|
||
```
|
||
|
||
### 6.2 fin_knowledge_meta
|
||
|
||
最终结构以新版表定义为准,必须包含 `content_text`、`tags`、`effective_date`、`expire_date`、`version`、`reviewer_id` 和 `review_status`。
|
||
|
||
实际迁移前使用 Alembic Inspector 检查现库。若 `version`、`effective_date`、`expire_date` 已存在,只新增以下四个缺失字段:
|
||
|
||
```sql
|
||
ALTER TABLE fin_knowledge_meta
|
||
ADD COLUMN content_text MEDIUMTEXT NULL COMMENT 'Milvus知识正文MySQL镜像,保持可空兼容旧数据',
|
||
ADD COLUMN tags JSON NULL COMMENT '知识标签数组',
|
||
ADD COLUMN reviewer_id BIGINT UNSIGNED NULL COMMENT '审校人ID',
|
||
ADD COLUMN review_status VARCHAR(16) NOT NULL DEFAULT 'pending'
|
||
COMMENT 'pending/approved/published/archived',
|
||
ADD CONSTRAINT fk_knowledge_reviewer
|
||
FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
ADD INDEX idx_knowledge_review_status (review_status),
|
||
ADD INDEX idx_knowledge_reviewer (reviewer_id);
|
||
```
|
||
|
||
`content_text` 保持新增时的可空定义,后续不得更改已有字段约束。应用通过发布校验保证 `published` 知识必须存在正文。
|
||
|
||
有效知识的统一过滤条件为:
|
||
|
||
```sql
|
||
review_status = 'published'
|
||
AND status = 'active'
|
||
AND (effective_date IS NULL OR effective_date <= UTC_DATE())
|
||
AND (expire_date IS NULL OR expire_date > UTC_DATE())
|
||
```
|
||
|
||
## 7. 智能客服专项表 DDL
|
||
|
||
以下 DDL 面向全新数据库。若应用于已有数据库,必须通过 Alembic 生成版本迁移并在测试库演练。
|
||
|
||
### 7.1 agent_negative_word
|
||
|
||
禁止表达不写死在业务 Agent 中。规则变更必须经过审核并保留版本。
|
||
|
||
```sql
|
||
CREATE TABLE agent_negative_word (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
rule_code VARCHAR(64) NOT NULL,
|
||
word_pattern VARCHAR(256) NOT NULL,
|
||
match_type VARCHAR(16) NOT NULL DEFAULT 'contains',
|
||
category VARCHAR(32) NOT NULL,
|
||
severity VARCHAR(16) NOT NULL DEFAULT 'block',
|
||
applicable_agents JSON NULL,
|
||
safe_reply_template_code VARCHAR(64) NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'draft',
|
||
version INT UNSIGNED NOT NULL DEFAULT 1,
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_negative_rule_code (rule_code),
|
||
KEY idx_negative_status_category (status, category),
|
||
KEY idx_negative_reviewer (reviewer_id),
|
||
CONSTRAINT fk_negative_created_by FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_negative_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_negative_match_type
|
||
CHECK (match_type IN ('exact', 'contains', 'regex')),
|
||
CONSTRAINT chk_negative_severity
|
||
CHECK (severity IN ('warn', 'regenerate', 'block')),
|
||
CONSTRAINT chk_negative_status
|
||
CHECK (status IN ('draft', 'active', 'disabled', 'archived'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Agent禁止表达配置';
|
||
```
|
||
|
||
### 7.2 svc_handover_ticket
|
||
|
||
本表只表示客服会话向人工坐席的转接,不替代风险预警处置工单 `biz_work_order`。
|
||
|
||
```sql
|
||
CREATE TABLE svc_handover_ticket (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
ticket_no VARCHAR(32) NOT NULL,
|
||
session_id VARCHAR(64) NOT NULL,
|
||
customer_id BIGINT UNSIGNED NULL,
|
||
source_agent VARCHAR(32) NOT NULL DEFAULT 'customer_service',
|
||
source_message_id BIGINT UNSIGNED NULL,
|
||
intent VARCHAR(32) NULL,
|
||
confidence DECIMAL(5,4) NULL,
|
||
priority VARCHAR(8) NOT NULL DEFAULT 'P1',
|
||
reason_code VARCHAR(64) NOT NULL,
|
||
reason_detail VARCHAR(500) NULL,
|
||
conversation_summary MEDIUMTEXT NULL,
|
||
source_references JSON NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||
assigned_to BIGINT UNSIGNED NULL,
|
||
assigned_at DATETIME(6) NULL,
|
||
accepted_at DATETIME(6) NULL,
|
||
resolved_at DATETIME(6) NULL,
|
||
closed_at DATETIME(6) NULL,
|
||
resolution TEXT NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_handoff_ticket_no (ticket_no),
|
||
KEY idx_handoff_session (session_id, created_at),
|
||
KEY idx_handoff_customer (customer_id, created_at),
|
||
KEY idx_handoff_queue (status, priority, created_at),
|
||
KEY idx_handoff_assignee (assigned_to, status),
|
||
CONSTRAINT fk_handoff_customer FOREIGN KEY (customer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_handoff_source_message
|
||
FOREIGN KEY (source_message_id) REFERENCES conversation_message(id),
|
||
CONSTRAINT fk_handoff_assignee FOREIGN KEY (assigned_to) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_handoff_confidence
|
||
CHECK (confidence IS NULL OR confidence BETWEEN 0 AND 1),
|
||
CONSTRAINT chk_handoff_priority CHECK (priority IN ('P0', 'P1', 'P2')),
|
||
CONSTRAINT chk_handoff_status
|
||
CHECK (status IN ('pending', 'assigned', 'processing', 'resolved', 'closed', 'cancelled'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='客服转人工工单';
|
||
```
|
||
|
||
状态流转:
|
||
|
||
```text
|
||
pending -> assigned -> processing -> resolved -> closed
|
||
| | |
|
||
`----------+-------------+-> cancelled
|
||
```
|
||
|
||
`cancelled` 只允许在未解决状态进入。每次分配、接单、解决、关闭或取消都要写入 `interaction_audit`。
|
||
|
||
### 7.3 agent_faq_synonym
|
||
|
||
```sql
|
||
CREATE TABLE agent_faq_synonym (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
knowledge_id BIGINT UNSIGNED NOT NULL,
|
||
phrase VARCHAR(500) NOT NULL,
|
||
normalized_phrase VARCHAR(500) NOT NULL,
|
||
phrase_hash CHAR(64) NOT NULL,
|
||
language_code VARCHAR(16) NOT NULL DEFAULT 'zh-CN',
|
||
source_type VARCHAR(24) NOT NULL DEFAULT 'manual',
|
||
hit_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_faq_synonym (knowledge_id, phrase_hash),
|
||
KEY idx_faq_synonym_status (status),
|
||
KEY idx_faq_synonym_normalized (normalized_phrase(191)),
|
||
CONSTRAINT fk_synonym_knowledge FOREIGN KEY (knowledge_id) REFERENCES fin_knowledge_meta(id),
|
||
CONSTRAINT fk_synonym_created_by FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_synonym_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_synonym_source
|
||
CHECK (source_type IN ('manual', 'conversation', 'ticket', 'import')),
|
||
CONSTRAINT chk_synonym_status
|
||
CHECK (status IN ('pending', 'approved', 'disabled', 'archived'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='FAQ同义问法';
|
||
```
|
||
|
||
只有 `approved` 的同义问法参与意图识别和检索扩展。会话自动提取内容必须先进入 `pending`。
|
||
`phrase_hash` 由应用对完整 `normalized_phrase` 计算 SHA-256,防止仅使用索引前缀时不同长文本被误判为重复。
|
||
|
||
### 7.4 conversation_feedback
|
||
|
||
```sql
|
||
CREATE TABLE conversation_feedback (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
feedback_no VARCHAR(32) NOT NULL,
|
||
session_id VARCHAR(64) NOT NULL,
|
||
message_id BIGINT UNSIGNED NOT NULL,
|
||
customer_id BIGINT UNSIGNED NULL,
|
||
rating TINYINT NOT NULL,
|
||
feedback_type VARCHAR(32) NULL,
|
||
feedback_content VARCHAR(1000) NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'open',
|
||
handler_id BIGINT UNSIGNED NULL,
|
||
handled_at DATETIME(6) NULL,
|
||
handling_note VARCHAR(1000) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_feedback_no (feedback_no),
|
||
UNIQUE KEY uk_feedback_message_customer (message_id, customer_id),
|
||
KEY idx_feedback_session (session_id, created_at),
|
||
KEY idx_feedback_status_type (status, feedback_type),
|
||
CONSTRAINT fk_feedback_message FOREIGN KEY (message_id) REFERENCES conversation_message(id),
|
||
CONSTRAINT fk_feedback_customer FOREIGN KEY (customer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_feedback_handler FOREIGN KEY (handler_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_feedback_rating CHECK (rating IN (-1, 1)),
|
||
CONSTRAINT chk_feedback_status CHECK (status IN ('open', 'reviewed', 'resolved', 'ignored'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='对话回复反馈';
|
||
```
|
||
|
||
匿名或未登录反馈的 `customer_id` 可以为空,但必须由 API 限流并保存安全审计信息,防止重复刷票。
|
||
|
||
### 7.5 agent_reply_template
|
||
|
||
```sql
|
||
CREATE TABLE agent_reply_template (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
template_code VARCHAR(64) NOT NULL,
|
||
scene VARCHAR(32) NOT NULL,
|
||
title VARCHAR(128) NOT NULL,
|
||
content_text MEDIUMTEXT NOT NULL,
|
||
variables JSON NULL,
|
||
locale VARCHAR(16) NOT NULL DEFAULT 'zh-CN',
|
||
version INT UNSIGNED NOT NULL DEFAULT 1,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'draft',
|
||
active_key VARCHAR(128) GENERATED ALWAYS AS
|
||
(IF(status = 'active', CONCAT(template_code, ':', locale), NULL)) STORED,
|
||
effective_at DATETIME(6) NULL,
|
||
expire_at DATETIME(6) NULL,
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_reply_template_version (template_code, version),
|
||
UNIQUE KEY uk_reply_template_active_one (active_key),
|
||
KEY idx_reply_template_active (scene, status, effective_at, expire_at),
|
||
CONSTRAINT fk_template_created_by FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_template_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_template_scene
|
||
CHECK (scene IN ('disclaimer', 'low_confidence', 'compliance_block',
|
||
'transfer', 'model_failure', 'system_busy', 'clarification')),
|
||
CONSTRAINT chk_template_status
|
||
CHECK (status IN ('draft', 'approved', 'active', 'archived')),
|
||
CONSTRAINT chk_template_window
|
||
CHECK (expire_at IS NULL OR effective_at IS NULL OR expire_at > effective_at)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Agent回复模板';
|
||
```
|
||
|
||
相同 `template_code + locale` 可以有多个历史版本,但数据库通过 `active_key` 唯一索引保证同一组合最多一个 `active` 版本。发布服务仍须在事务中完成状态切换并写入审计记录。
|
||
|
||
### 7.6 agent_intent_config
|
||
|
||
```sql
|
||
CREATE TABLE agent_intent_config (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
agent_type VARCHAR(32) NOT NULL,
|
||
intent_code VARCHAR(64) NOT NULL,
|
||
intent_name VARCHAR(128) NOT NULL,
|
||
description VARCHAR(500) NULL,
|
||
examples JSON NOT NULL,
|
||
classifier_instruction TEXT NULL,
|
||
confidence_threshold DECIMAL(5,4) NOT NULL DEFAULT 0.6000,
|
||
max_clarification_rounds TINYINT UNSIGNED NOT NULL DEFAULT 2,
|
||
transfer_on_failure TINYINT(1) NOT NULL DEFAULT 1,
|
||
collection_routes JSON NULL,
|
||
allowed_tools JSON NULL,
|
||
priority INT NOT NULL DEFAULT 100,
|
||
version INT UNSIGNED NOT NULL DEFAULT 1,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'draft',
|
||
active_key VARCHAR(128) GENERATED ALWAYS AS
|
||
(IF(status = 'active', CONCAT(agent_type, ':', intent_code), NULL)) STORED,
|
||
effective_at DATETIME(6) NULL,
|
||
expire_at DATETIME(6) NULL,
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_intent_config_version (agent_type, intent_code, version),
|
||
UNIQUE KEY uk_intent_config_active_one (active_key),
|
||
KEY idx_intent_config_active (agent_type, status, priority),
|
||
CONSTRAINT fk_intent_created_by FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_intent_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_intent_confidence
|
||
CHECK (confidence_threshold BETWEEN 0 AND 1),
|
||
CONSTRAINT chk_intent_status
|
||
CHECK (status IN ('draft', 'approved', 'active', 'archived')),
|
||
CONSTRAINT chk_intent_window
|
||
CHECK (expire_at IS NULL OR effective_at IS NULL OR expire_at > effective_at)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Agent意图路由配置';
|
||
```
|
||
|
||
客服初始意图至少包含:`faq`、`product_inquiry`、`policy_explain`、`chitchat` 和 `transfer_human`。
|
||
|
||
## 8. 平台底座增量表 DDL
|
||
|
||
本节所有对象均为新增表,不替换、不重命名原有表。
|
||
|
||
### 8.1 svc_conversation_session
|
||
|
||
```sql
|
||
CREATE TABLE svc_conversation_session (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
session_id VARCHAR(64) NOT NULL,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
portal VARCHAR(32) NOT NULL,
|
||
agent_type VARCHAR(32) NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
||
clarification_round TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||
message_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||
last_intent VARCHAR(32) NULL,
|
||
config_version VARCHAR(64) NULL,
|
||
started_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
last_active_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
ended_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_session_id (session_id),
|
||
KEY idx_session_user_active (user_id, last_active_at),
|
||
KEY idx_session_status_active (status, last_active_at),
|
||
CONSTRAINT fk_session_user FOREIGN KEY (user_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_session_status
|
||
CHECK (status IN ('active', 'ended', 'transferred', 'expired')),
|
||
CONSTRAINT chk_session_clarification CHECK (clarification_round <= 10)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Agent会话状态与澄清轮次';
|
||
```
|
||
|
||
澄清次数使用带旧值条件的原子更新;Redis 只缓存该记录,MySQL 是权威来源。会话结束、转人工和过期必须写明确状态。
|
||
|
||
### 8.2 domain_event_outbox
|
||
|
||
```sql
|
||
CREATE TABLE domain_event_outbox (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
event_id CHAR(36) NOT NULL,
|
||
event_type VARCHAR(64) NOT NULL,
|
||
aggregate_type VARCHAR(32) NOT NULL,
|
||
aggregate_id VARCHAR(64) NOT NULL,
|
||
trace_id VARCHAR(64) NOT NULL,
|
||
payload JSON NOT NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||
retry_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||
next_retry_at DATETIME(6) NULL,
|
||
last_error VARCHAR(500) NULL,
|
||
occurred_at DATETIME(6) NOT NULL,
|
||
published_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_domain_event_id (event_id),
|
||
KEY idx_domain_outbox_pending (status, next_retry_at, id),
|
||
KEY idx_domain_outbox_aggregate (aggregate_type, aggregate_id),
|
||
KEY idx_domain_outbox_trace (trace_id),
|
||
CONSTRAINT chk_domain_outbox_status
|
||
CHECK (status IN ('pending', 'published', 'failed', 'dead'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='通用领域事件Outbox';
|
||
```
|
||
|
||
### 8.3 request_idempotency
|
||
|
||
```sql
|
||
CREATE TABLE request_idempotency (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
session_id VARCHAR(64) NOT NULL,
|
||
agent_type VARCHAR(32) NOT NULL,
|
||
idempotency_key VARCHAR(64) NOT NULL,
|
||
request_hash CHAR(64) NOT NULL,
|
||
trace_id VARCHAR(64) NOT NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'processing',
|
||
result_message_id BIGINT UNSIGNED NULL,
|
||
error_code VARCHAR(64) NULL,
|
||
locked_until DATETIME(6) NULL,
|
||
expire_at DATETIME(6) NOT NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_idempotency_scope (user_id, agent_type, idempotency_key),
|
||
KEY idx_idempotency_expire (expire_at),
|
||
KEY idx_idempotency_trace (trace_id),
|
||
KEY idx_idempotency_session (session_id, created_at),
|
||
CONSTRAINT fk_idempotency_user FOREIGN KEY (user_id) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_idempotency_session
|
||
FOREIGN KEY (session_id) REFERENCES svc_conversation_session(session_id),
|
||
CONSTRAINT fk_idempotency_result
|
||
FOREIGN KEY (result_message_id) REFERENCES conversation_message(id),
|
||
CONSTRAINT chk_idempotency_status
|
||
CHECK (status IN ('processing', 'completed', 'failed'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Agent请求幂等记录';
|
||
```
|
||
|
||
相同幂等键但 `request_hash` 不同必须返回冲突;`processing` 未过租约返回处理中,`completed` 返回原结果,只有租约超时后才能由新请求接管。
|
||
|
||
### 8.4 agent_run
|
||
|
||
```sql
|
||
CREATE TABLE agent_run (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
run_id CHAR(36) NOT NULL,
|
||
idempotency_id BIGINT UNSIGNED NOT NULL,
|
||
session_id VARCHAR(64) NOT NULL,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
agent_type VARCHAR(32) NOT NULL,
|
||
trace_id VARCHAR(64) NOT NULL,
|
||
request_message_id BIGINT UNSIGNED NOT NULL,
|
||
result_message_id BIGINT UNSIGNED NULL,
|
||
status VARCHAR(24) NOT NULL DEFAULT 'queued',
|
||
attempt_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||
worker_id VARCHAR(128) NULL,
|
||
locked_until DATETIME(6) NULL,
|
||
result_version INT UNSIGNED NULL,
|
||
error_code VARCHAR(64) NULL,
|
||
cancel_requested_at DATETIME(6) NULL,
|
||
started_at DATETIME(6) NULL,
|
||
completed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_agent_run_id (run_id),
|
||
UNIQUE KEY uk_agent_run_idempotency (idempotency_id),
|
||
UNIQUE KEY uk_agent_run_trace (trace_id),
|
||
KEY idx_agent_run_session (session_id, created_at),
|
||
KEY idx_agent_run_user (user_id, created_at),
|
||
KEY idx_agent_run_worker_lease (status, locked_until),
|
||
CONSTRAINT fk_agent_run_idempotency
|
||
FOREIGN KEY (idempotency_id) REFERENCES request_idempotency(id),
|
||
CONSTRAINT fk_agent_run_session
|
||
FOREIGN KEY (session_id) REFERENCES svc_conversation_session(session_id),
|
||
CONSTRAINT fk_agent_run_user FOREIGN KEY (user_id) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_agent_run_request_message
|
||
FOREIGN KEY (request_message_id) REFERENCES conversation_message(id),
|
||
CONSTRAINT fk_agent_run_result_message
|
||
FOREIGN KEY (result_message_id) REFERENCES conversation_message(id),
|
||
CONSTRAINT chk_agent_run_status CHECK
|
||
(status IN ('queued', 'running', 'succeeded', 'failed',
|
||
'cancel_requested', 'cancelled'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='可恢复Agent运行状态';
|
||
```
|
||
|
||
`run_id` 是对外运行主键,`trace_id` 只用于可观测性。Worker 通过 `locked_until` 租约接管过期运行;同一 `run_id` 安全重试,不承诺从模型中间 Token 续写。最终消息、审计、幂等完成状态和 Outbox 必须与运行成功状态同一事务提交。
|
||
|
||
### 8.5 config_release
|
||
|
||
```sql
|
||
CREATE TABLE config_release (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
release_no VARCHAR(64) NOT NULL,
|
||
title VARCHAR(128) NOT NULL,
|
||
change_summary VARCHAR(1000) NOT NULL,
|
||
status VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
activated_at DATETIME(6) NULL,
|
||
supersedes_release_id BIGINT UNSIGNED NULL,
|
||
rollback_of_release_id BIGINT UNSIGNED NULL,
|
||
active_slot TINYINT GENERATED ALWAYS AS
|
||
(IF(status = 'active', 1, NULL)) STORED,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_config_release_no (release_no),
|
||
UNIQUE KEY uk_config_release_active_one (active_slot),
|
||
KEY idx_config_release_status (status, created_at),
|
||
CONSTRAINT fk_config_release_creator FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_config_release_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_config_release_supersedes
|
||
FOREIGN KEY (supersedes_release_id) REFERENCES config_release(id),
|
||
CONSTRAINT fk_config_release_rollback
|
||
FOREIGN KEY (rollback_of_release_id) REFERENCES config_release(id),
|
||
CONSTRAINT chk_config_release_status
|
||
CHECK (status IN ('draft', 'validating', 'pending_review', 'approved',
|
||
'active', 'superseded', 'rejected', 'rolled_back'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='平台配置发布批次';
|
||
```
|
||
|
||
> **变更记录**:原 `CONSTRAINT chk_config_release_separation CHECK (reviewer_id IS NULL OR reviewer_id <> created_by)`
|
||
> (双人复核)已于迁移 `20260910_drop_review_separation` 撤下。原因是本平台为单管理员部署,
|
||
> 该约束使配置发布在数据库层永远无法完成(错误 3819)。撤下的只是"审核人必须不同于创建人"这一
|
||
> 身份限制:状态机仍要求 `pending_review` → `approved` 经审核接口并写入 `reviewer_id`/`reviewed_at`,
|
||
> `reviewer_id` 列本身的类型、可空性与业务含义均未改变。`docs/00-新数据库基线设计.md` 未修改。
|
||
> **变更记录(2026-09-11 合并说明)**:两条并行分支各自补了一次撤约束迁移——
|
||
> `20260910_drop_review_separation`(风控线)与 `20260911_drop_review_separation`(yc 线),
|
||
> 两者都先查 `information_schema` 再决定是否 `ALTER`,重复执行不会报错,因此合并后全部保留。
|
||
> `chk_config_release_status`、全部外键、唯一键与索引不变,表名与字段定义未做任何改动;
|
||
> `docs/00-新数据库基线设计.md` 未修改。
|
||
|
||
### 8.6 platform_config_item
|
||
|
||
```sql
|
||
CREATE TABLE platform_config_item (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
release_id BIGINT UNSIGNED NOT NULL,
|
||
namespace VARCHAR(64) NOT NULL,
|
||
config_key VARCHAR(128) NOT NULL,
|
||
value_json JSON NOT NULL,
|
||
schema_version VARCHAR(32) NOT NULL,
|
||
checksum CHAR(64) NOT NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_config_item_release (release_id, namespace, config_key),
|
||
KEY idx_config_item_lookup (namespace, config_key, release_id),
|
||
CONSTRAINT fk_config_item_release
|
||
FOREIGN KEY (release_id) REFERENCES config_release(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='版本化平台配置项';
|
||
```
|
||
|
||
`namespace` 首版限定为 `agent_runtime`、`memory_policy`、`relationship_view`、`compliance_policy` 和 `tool_policy`;`value_json` 必须先通过对应 Pydantic Schema 校验。
|
||
|
||
### 8.7 model_endpoint_config
|
||
|
||
```sql
|
||
CREATE TABLE model_endpoint_config (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
endpoint_code VARCHAR(64) NOT NULL,
|
||
provider VARCHAR(32) NOT NULL,
|
||
model_name VARCHAR(128) NOT NULL,
|
||
base_url VARCHAR(500) NOT NULL,
|
||
secret_ref VARCHAR(256) NOT NULL,
|
||
capabilities JSON NOT NULL,
|
||
allowed_data_levels JSON NOT NULL,
|
||
context_window INT UNSIGNED NOT NULL,
|
||
timeout_ms INT UNSIGNED NOT NULL DEFAULT 15000,
|
||
cost_input_per_1k DECIMAL(12,6) NULL,
|
||
cost_output_per_1k DECIMAL(12,6) NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'disabled',
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
reviewer_id BIGINT UNSIGNED NULL,
|
||
reviewed_at DATETIME(6) NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
|
||
ON UPDATE CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_model_endpoint_code (endpoint_code),
|
||
KEY idx_model_endpoint_status (status, provider),
|
||
CONSTRAINT fk_model_endpoint_creator FOREIGN KEY (created_by) REFERENCES sys_user(id),
|
||
CONSTRAINT fk_model_endpoint_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id),
|
||
CONSTRAINT chk_model_endpoint_status
|
||
CHECK (status IN ('draft', 'approved', 'active', 'disabled', 'archived'))
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='模型端点配置';
|
||
```
|
||
|
||
`secret_ref` 只保存环境变量名或密钥服务路径,禁止保存明文密钥。
|
||
|
||
### 8.8 model_routing_rule
|
||
|
||
```sql
|
||
CREATE TABLE model_routing_rule (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
release_id BIGINT UNSIGNED NOT NULL,
|
||
rule_code VARCHAR(64) NOT NULL,
|
||
agent_type VARCHAR(32) NOT NULL,
|
||
task_type VARCHAR(48) NOT NULL,
|
||
model_policy VARCHAR(32) NOT NULL,
|
||
primary_endpoint_id BIGINT UNSIGNED NOT NULL,
|
||
fallback_endpoint_ids JSON NULL,
|
||
condition_json JSON NULL,
|
||
max_attempts TINYINT UNSIGNED NOT NULL DEFAULT 2,
|
||
latency_budget_ms INT UNSIGNED NOT NULL DEFAULT 15000,
|
||
cost_budget DECIMAL(12,6) NULL,
|
||
priority INT NOT NULL DEFAULT 100,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_model_route_release (release_id, rule_code),
|
||
KEY idx_model_route_match
|
||
(release_id, agent_type, task_type, model_policy, priority),
|
||
CONSTRAINT fk_model_route_release FOREIGN KEY (release_id) REFERENCES config_release(id),
|
||
CONSTRAINT fk_model_route_primary
|
||
FOREIGN KEY (primary_endpoint_id) REFERENCES model_endpoint_config(id),
|
||
CONSTRAINT chk_model_route_attempts CHECK (max_attempts BETWEEN 1 AND 3)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='多模型路由规则';
|
||
```
|
||
|
||
`fallback_endpoint_ids` 是为旧版读取方保留的兼容字段,可为空;它不再作为备用链权威来源。若迁移期继续填充该字段,其端点顺序必须与 `model_routing_fallback` 按 `fallback_order` 排序后的结果完全一致,发布服务在同一配置发布事务中校验。
|
||
|
||
### 8.9 model_routing_fallback
|
||
|
||
```sql
|
||
CREATE TABLE model_routing_fallback (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
routing_rule_id BIGINT UNSIGNED NOT NULL,
|
||
endpoint_id BIGINT UNSIGNED NOT NULL,
|
||
fallback_order TINYINT UNSIGNED NOT NULL,
|
||
retryable_error_codes JSON NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_model_fallback_order (routing_rule_id, fallback_order),
|
||
UNIQUE KEY uk_model_fallback_endpoint (routing_rule_id, endpoint_id),
|
||
KEY idx_model_fallback_endpoint (endpoint_id),
|
||
CONSTRAINT fk_model_fallback_rule
|
||
FOREIGN KEY (routing_rule_id) REFERENCES model_routing_rule(id),
|
||
CONSTRAINT fk_model_fallback_endpoint
|
||
FOREIGN KEY (endpoint_id) REFERENCES model_endpoint_config(id),
|
||
CONSTRAINT chk_model_fallback_order CHECK (fallback_order BETWEEN 1 AND 2)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='模型路由有序备用端点';
|
||
```
|
||
|
||
`model_routing_fallback` 是备用链的权威关系表。发布服务必须校验主端点不出现在备用链中、每条路由的总端点数不超过 3,且 `retryable_error_codes` 只能包含平台登记的错误码。
|
||
|
||
### 8.10 prompt_template_version
|
||
|
||
```sql
|
||
CREATE TABLE prompt_template_version (
|
||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
release_id BIGINT UNSIGNED NOT NULL,
|
||
prompt_code VARCHAR(64) NOT NULL,
|
||
task_type VARCHAR(48) NOT NULL,
|
||
agent_type VARCHAR(32) NULL,
|
||
version INT UNSIGNED NOT NULL,
|
||
system_prompt MEDIUMTEXT NOT NULL,
|
||
user_prompt_template MEDIUMTEXT NOT NULL,
|
||
input_schema JSON NULL,
|
||
output_schema JSON NULL,
|
||
checksum CHAR(64) NOT NULL,
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_prompt_version (prompt_code, version),
|
||
KEY idx_prompt_release_task (release_id, task_type, agent_type),
|
||
CONSTRAINT fk_prompt_release FOREIGN KEY (release_id) REFERENCES config_release(id),
|
||
CONSTRAINT fk_prompt_creator FOREIGN KEY (created_by) REFERENCES sys_user(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='Prompt不可变版本';
|
||
```
|
||
|
||
## 9. 创建与迁移顺序
|
||
|
||
### 9.1 空库创建顺序
|
||
|
||
1. 创建数据库和 Alembic 版本表。
|
||
2. 创建 `sys_user`、角色、权限及用户角色关系。
|
||
3. 创建客户画像、风险测评和客户归属。
|
||
4. 创建产品、行情、账户、费用、委托、成交、资金和持仓。
|
||
5. 创建预警、通知、风险工单、内容和审计表。
|
||
6. 创建对话、知识、Episode 和记忆相关表。
|
||
7. 创建 `agent_negative_word` 和 `svc_handover_ticket`。
|
||
8. 创建 `agent_faq_synonym` 和 `conversation_feedback`。
|
||
9. 创建 `agent_reply_template` 和 `agent_intent_config`。
|
||
10. 创建会话、幂等、`agent_run` 和通用事件 Outbox 表。
|
||
11. 创建配置发布、平台配置、模型端点、模型路由、路由备用端点和 Prompt 表。
|
||
12. 写入初始角色、权限、意图、模板、模型路由和禁止表达。
|
||
13. 建立 Milvus 集合、Neo4j 约束和 Redis Key 规范。
|
||
|
||
### 9.2 已有库升级
|
||
|
||
1. 备份结构和关键表数据。
|
||
2. 使用 Inspector 获取真实列、索引和外键。
|
||
3. 只增加缺失字段,不重建或覆盖现有业务表。
|
||
4. 新字段先允许兼容旧代码,再部署双版本兼容应用。
|
||
5. 回填知识正文、审核状态和对话分类信息。
|
||
6. 创建专项表和平台底座增量表。
|
||
7. 发布首个完整配置快照。
|
||
8. 部署新代码并验证双版本兼容读写。
|
||
|
||
`content_text` 在已有知识数据未回填前保持可空。即使回填完成,也不修改该已有字段定义;由应用校验和发布条件保证已发布知识正文非空。
|
||
|
||
## 10. 初始数据
|
||
|
||
### 10.1 内置角色
|
||
|
||
- `customer`
|
||
- `advisor`
|
||
- `operator`
|
||
- `risk_operator`
|
||
- `admin`
|
||
- `super_admin`
|
||
|
||
### 10.2 客服初始禁止表达
|
||
|
||
至少录入:保本、稳赚、无风险、保证收益、预期收益率、年化收益率、安全,以及经合规确认的变体。初始状态必须经过审核后才可以设置为 `active`。
|
||
|
||
### 10.3 客服初始模板
|
||
|
||
- 固定免责声明。
|
||
- AI 生成标识。
|
||
- 低置信兜底。
|
||
- 合规拒答。
|
||
- 转人工提示。
|
||
- 模型故障和系统繁忙提示。
|
||
|
||
## 11. 事务和并发要求
|
||
|
||
- 模拟成交、账户余额、资金明细和持仓必须在一个事务内提交。
|
||
- 工单状态更新采用乐观锁或条件更新,禁止重复接单覆盖。
|
||
- 画像版本和 Outbox 事件在同一事务提交。
|
||
- 助手消息、执行审计和 `domain_event_outbox` 在同一短事务提交。
|
||
- 幂等记录通过唯一键抢占,完成状态与结果消息在同一事务更新。
|
||
- 配置发布批次和全部配置项校验通过后才能原子激活。
|
||
- 模板和意图新版本发布时,旧版本失效与新版本生效必须原子完成。
|
||
- 审计记录与受监管的业务状态变更应在同一事务写入。
|
||
- 外部模型、邮件、Milvus 和 Neo4j 调用不得放入 MySQL 长事务。
|
||
|
||
## 12. 数据安全
|
||
|
||
- `password_hash` 不向 Agent、风控或 NL2SQL 开放。
|
||
- 身份证、手机号、银行卡号和精确账户余额不得写入 Milvus 或 Neo4j。
|
||
- `source_references` 只保存必要的来源标识,不复制整份文档。
|
||
- SQL 查询必须应用 `data_scope` 和客户归属过滤。
|
||
- `interaction_audit` 仅追加,不允许普通业务接口更新或删除。
|
||
- 生产备份、迁移导出和错误日志均执行敏感字段保护。
|
||
- 模型端点表只保存 `secret_ref`,不得保存 API 明文密钥。
|
||
|
||
## 13. 验证清单
|
||
|
||
- 51 张业务表全部存在(另有 `alembic_version`),原 39 张表的名称和已有字段定义保持不变。
|
||
- 主键、唯一键、外键和检查约束生效;唯一键必须与 `docs/00` 声明一致,由 `tools/audit_constraints.py` 逐表比对。
|
||
- 2026-09-09 约束纠偏:`fin_market_price`、`fin_nav_history`、`fin_holding`、`sys_customer_assignment` 四张表的联合唯一键曾被基线生成器错误拆成单列唯一键,已由迁移 `20260909_constraint_fix` 修正(删 8 个错误唯一键、加 4 个联合唯一键),`docs/00` 未做修改。证据见 `docs/evidence/` 与 `docs/08`。
|
||
- `conversation_message` 三个 Agent 增量字段和既有 `tool_calls` 字段可正常读写。
|
||
- 知识检索只命中已发布且在有效期内的条目。
|
||
- Milvus 故障时 MySQL 正文降级检索可用。
|
||
- 客服转人工工单与风险工单完全独立。
|
||
- 同义问法只有审核通过后参与检索。
|
||
- 一个客户对同一回复不能重复反馈。
|
||
- 模板和意图配置可版本化发布和回滚。
|
||
- 每个模板或意图组合最多一个 `active` 版本,备用模型端点均受外键约束且顺序唯一。
|
||
- 越权客户查询被数据库访问层和服务层共同拒绝。
|
||
- Redis 丢失可以从 MySQL 恢复必要记忆。
|
||
- Milvus 或 Neo4j 单边失败不会丢失 Outbox 事件。
|
||
- 重复请求不会重复生成消息、工单或领域事件。
|
||
- 配置发布失败时旧版本继续有效,回滚不修改历史版本。
|
||
- 模型路由最多尝试三个已审核端点,并完整记录采用版本。
|
||
- 所有迁移在空库、旧版本库和回滚路径各执行一次。
|
||
|
||
## 14. 已知实施前提
|
||
|
||
6 张专项表的字段由本文补全并作为建议实施结构。若团队已有《智能客服Agent新增表详细设计.md》,合并前必须逐字段比较;业务编号、状态枚举、审核流和外键语义不一致时,由数据库负责人组织评审,不允许两个定义同时进入迁移脚本。
|