Files
Neo-ZQYY/docs/database/BD_Manual_ai_tables.md

247 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BD_Manualbiz Schema AI 表(对话记录 + 消息 + 缓存)
> 目标库:`test_zqyy_app`(通过 `APP_DB_DSN` 连接)
> 迁移脚本:
> - `db/zqyy_app/migrations/2026-03-08__create_ai_tables.sql`(初始建表)
> - `db/zqyy_app/migrations/2026-03-20__rns14_chat_module_extend.sql`RNS1.4 CHAT 扩展)
> 关联 SPEC`05-miniapp-ai-integration`P5 AI 集成层)、`rns1-chat-integration`RNS1.4 CHAT 对齐与联调收尾)
---
## 1. 变更说明
### 新增表3 张P5 初始建表)
| # | 表名 | 用途 | 字段数(初始→当前) |
|---|------|------|---------------------|
| 1 | `biz.ai_conversations` | AI 对话记录:每次 AI 调用(用户主动或系统自动)创建一条 | 8 → 13 |
| 2 | `biz.ai_messages` | AI 消息记录:对话中的每条消息(输入/输出/系统) | 6 → 7 |
| 3 | `biz.ai_cache` | AI 应用缓存:各应用的结构化输出结果 | 9 |
### RNS1.4 CHAT 模块扩展字段2026-03-20
| # | 表名 | 新增字段 | 用途 |
|---|------|---------|------|
| 1 | `biz.ai_conversations` | `context_type`, `context_id`, `title`, `last_message`, `last_message_at` | 多入口对话复用 + 历史列表展示与排序 |
| 2 | `biz.ai_messages` | `reference_card` | 引用卡片 JSON客户概览等结构化上下文数据 |
### 表字段明细
#### biz.ai_conversations13 字段)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | BIGSERIAL | PK | 自增主键 |
| `user_id` | VARCHAR(50) | NOT NULL | 用户 ID系统自动调用时为 `system` |
| `nickname` | VARCHAR(100) | NOT NULL DEFAULT '' | 用户昵称 |
| `app_id` | VARCHAR(30) | NOT NULL | 应用标识app1_chat / app2_finance / app3_clue / app4_analysis / app5_tactics / app6_note / app7_customer / app8_consolidation |
| `site_id` | BIGINT | NOT NULL | 门店 ID多门店隔离 |
| `source_page` | VARCHAR(100) | 可空 | 来源页面标识 |
| `source_context` | JSONB | 可空 | 页面上下文 JSON |
| `created_at` | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| `context_type` | VARCHAR(20) | 可空 | **RNS1.4 新增** — 对话关联上下文类型task任务/ customer客户/ coach助教/ general通用 |
| `context_id` | VARCHAR(50) | 可空 | **RNS1.4 新增** — 关联上下文 IDtask 入口为 taskIdcustomer 入口为 customerIdcoach 入口为 coachIdgeneral 为 NULL |
| `title` | VARCHAR(200) | 可空 | **RNS1.4 新增** — 对话标题:自定义 > 上下文名称 > 首条消息前20字 |
| `last_message` | TEXT | 可空 | **RNS1.4 新增** — 最后一条消息内容摘要截断至100字 |
| `last_message_at` | TIMESTAMPTZ | 可空 | **RNS1.4 新增** — 最后消息时间,用于历史列表排序和对话复用时限判断 |
#### biz.ai_messages7 字段)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | BIGSERIAL | PK | 自增主键 |
| `conversation_id` | BIGINT | NOT NULL, FK → `biz.ai_conversations(id)` ON DELETE CASCADE | 关联对话 |
| `role` | VARCHAR(10) | NOT NULL, CHECK IN ('user', 'assistant', 'system') | 消息角色 |
| `content` | TEXT | NOT NULL | 消息内容 |
| `tokens_used` | INTEGER | 可空 | 本条消息消耗的 token 数 |
| `created_at` | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| `reference_card` | JSONB | 可空 | **RNS1.4 新增** — 引用卡片 JSON`{type, title, summary, data}`,用于展示客户概览等结构化上下文数据 |
#### biz.ai_cache9 字段)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | BIGSERIAL | PK | 自增主键 |
| `cache_type` | VARCHAR(30) | NOT NULL, CHECK 7 个枚举值 | 缓存类型(见下方枚举) |
| `site_id` | BIGINT | NOT NULL | 门店 ID多门店隔离 |
| `target_id` | VARCHAR(100) | NOT NULL | 目标 ID含义因 cache_type 而异 |
| `result_json` | JSONB | NOT NULL | 结构化输出结果 |
| `score` | INTEGER | 可空 | 评分:仅应用 6 使用1-10 分) |
| `triggered_by` | VARCHAR(100) | 可空 | 触发来源标识 |
| `created_at` | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| `expires_at` | TIMESTAMPTZ | 可空 | 可选过期时间 |
### cache_type 枚举值与 target_id 约定
| cache_type | target_id 格式 | 示例 |
|---|---|---|
| `app2_finance` | 时间维度编码 | `this_month`, `last_week` |
| `app3_clue` | member_id | `12345` |
| `app4_analysis` | `{assistant_id}_{member_id}` | `100_12345` |
| `app5_tactics` | `{assistant_id}_{member_id}` | `100_12345` |
| `app6_note_analysis` | member_id | `12345` |
| `app7_customer_analysis` | member_id | `12345` |
| `app8_clue_consolidated` | member_id | `12345` |
### 约束与索引
| 表 | 约束/索引名 | 类型 | 说明 |
|----|-----------|------|------|
| `ai_conversations` | `idx_ai_conv_user_site` | INDEX | `(user_id, site_id, created_at DESC)` — 用户历史对话列表查询 |
| `ai_conversations` | `idx_ai_conv_app_site` | INDEX | `(app_id, site_id, created_at DESC)` — 按应用查询对话 |
| `ai_messages` | FK `conversation_id` | FK | → `biz.ai_conversations(id)` ON DELETE CASCADE |
| `ai_messages` | `chk_ai_msg_role` | CHECK | `role IN ('user', 'assistant', 'system')` |
| `ai_messages` | `idx_ai_msg_conv` | INDEX | `(conversation_id, created_at)` — 对话消息列表 |
| `ai_cache` | `chk_ai_cache_type` | CHECK | 7 个枚举值 |
| `ai_cache` | `idx_ai_cache_lookup` | INDEX | `(cache_type, site_id, target_id, created_at DESC)` — 查询最新缓存 |
| `ai_cache` | `idx_ai_cache_cleanup` | INDEX | `(cache_type, site_id, target_id, created_at)` — 清理超限记录ASC 排序便于删除最旧) |
| `ai_conversations` | `idx_ai_conv_context` | INDEX条件 | **RNS1.4 新增**`(user_id, site_id, context_type, context_id, last_message_at DESC NULLS LAST) WHERE context_type IS NOT NULL` — 上下文对话查找(多入口复用) |
| `ai_conversations` | `idx_ai_conv_last_msg` | INDEX | **RNS1.4 新增**`(user_id, site_id, last_message_at DESC NULLS LAST)` — 历史列表排序优化CHAT-1 倒序) |
---
## 2. 兼容性影响
| 组件 | 影响 |
|------|------|
| ETL 任务 | 无影响。AI 表属于 `biz` Schema不参与 ETL 流程 |
| 后端 API | 直接依赖。P5 AI 模块(`apps/backend/app/ai/`将基于这三张表实现对话持久化、缓存读写、SSE 流式对话等功能 |
| 后端 APIRNS1.4 | **直接依赖**。CHAT 模块(`apps/backend/app/routers/xcx_chat.py``apps/backend/app/services/chat_service.py`)依赖 `ai_conversations` 的 5 个新字段(`context_type`/`context_id`/`title`/`last_message`/`last_message_at`)实现多入口对话复用、历史列表展示与排序;依赖 `ai_messages.reference_card` 存储引用卡片 JSON |
| 小程序 | 间接依赖。小程序通过后端 AI API 间接使用对话和缓存数据 |
| 小程序RNS1.4 | **间接依赖**`pages/chat/chat.ts``pages/chat-history/chat-history.ts` 通过 CHAT-1/2/3/4 端点间接依赖新字段(`title`→对话标题、`lastMessage`→摘要、`timestamp`→排序、`referenceCard`→引用卡片渲染) |
| 管理后台 | 暂无影响。后续可能增加 AI 调用统计和缓存管理界面 |
| `member_retention_clue` | 间接关联。App8维客线索整理的结果同时写入 `ai_cache``member_retention_clue` 表 |
| 现有 `biz` Schema | 兼容。P5 新增 3 张表RNS1.4 仅在已有表上 ADD COLUMN / CREATE INDEX不修改已有字段或约束 |
---
## 3. 回滚策略
### 3a. 回滚 RNS1.4 CHAT 扩展2026-03-20 迁移)
按逆序 DROP 新增索引和字段:
```sql
-- 删除 RNS1.4 新增索引
DROP INDEX IF EXISTS biz.idx_ai_conv_context;
DROP INDEX IF EXISTS biz.idx_ai_conv_last_msg;
-- 回退 ai_messages 新增字段
ALTER TABLE biz.ai_messages DROP COLUMN IF EXISTS reference_card;
-- 回退 ai_conversations 新增字段(逆序)
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS last_message_at;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS last_message;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS title;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS context_id;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS context_type;
```
注意:
- 回滚后 CHAT 模块xcx_chat 路由、chat_service将无法正常工作
- 如果新字段中已有数据,需先备份再执行回滚
- 回滚不影响 P5 初始建表的 8 个原始字段
### 3b. 回滚 P5 初始建表2026-03-08 迁移)
按逆序 DROPCASCADE 处理外键依赖):
```sql
-- 删除索引
DROP INDEX IF EXISTS biz.idx_ai_cache_cleanup;
DROP INDEX IF EXISTS biz.idx_ai_cache_lookup;
DROP INDEX IF EXISTS biz.idx_ai_msg_conv;
DROP INDEX IF EXISTS biz.idx_ai_conv_app_site;
DROP INDEX IF EXISTS biz.idx_ai_conv_user_site;
-- 删除表ai_messages 依赖 ai_conversations需先删或用 CASCADE
DROP TABLE IF EXISTS biz.ai_cache CASCADE;
DROP TABLE IF EXISTS biz.ai_messages CASCADE;
DROP TABLE IF EXISTS biz.ai_conversations CASCADE;
```
注意:
- `ai_messages` 通过 FK 依赖 `ai_conversations`CASCADE 会级联删除消息
- 如果表中已有数据,需先备份再执行回滚
- 回滚不会删除 `biz` Schema 本身
---
## 4. 验证 SQL
### 4a. P5 初始建表验证
```sql
-- 1. 验证 3 张 AI 表全部存在
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'biz'
AND table_name IN ('ai_conversations', 'ai_messages', 'ai_cache')
ORDER BY table_name;
-- 预期:返回 3 行ai_cache, ai_conversations, ai_messages
-- 2. 验证 ai_conversations 字段数量和关键字段
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
ORDER BY ordinal_position;
-- 预期:返回 13 行P5 原始 8 字段 + RNS1.4 新增 5 字段)
-- 3. 验证 ai_messages 的外键和 CHECK 约束
SELECT conname, contype, pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'biz.ai_messages'::regclass
ORDER BY conname;
-- 预期:包含 chk_ai_msg_roleCHECK role IN ...)和 ai_messages_conversation_id_fkeyFK → ai_conversations
-- 4. 验证 ai_cache 的 CHECK 约束7 个枚举值)
SELECT conname, pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'biz.ai_cache'::regclass AND contype = 'c';
-- 预期:返回 1 行 chk_ai_cache_type包含 7 个枚举值
-- 5. 验证 P5 初始索引全部存在5 个)
SELECT indexname
FROM pg_indexes
WHERE schemaname = 'biz'
AND indexname IN (
'idx_ai_conv_user_site', 'idx_ai_conv_app_site',
'idx_ai_msg_conv',
'idx_ai_cache_lookup', 'idx_ai_cache_cleanup'
)
ORDER BY indexname;
-- 预期:返回 5 行
```
### 4b. RNS1.4 CHAT 扩展验证
```sql
-- 6. 验证 ai_conversations 新增 5 个字段存在
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
AND column_name IN ('context_type', 'context_id', 'title', 'last_message', 'last_message_at');
-- 预期:返回 5 行
-- context_type | character varying | 20
-- context_id | character varying | 50
-- title | character varying | 200
-- last_message | text | NULL
-- last_message_at | timestamp with time zone | NULL
-- 7. 验证 ai_messages 新增 reference_card 字段存在
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_messages'
AND column_name = 'reference_card';
-- 预期:返回 1 行data_type = 'jsonb'
-- 8. 验证 RNS1.4 新增 2 个索引存在
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_conversations'
AND indexname IN ('idx_ai_conv_context', 'idx_ai_conv_last_msg');
-- 预期:返回 2 行
-- idx_ai_conv_context — 含 WHERE context_type IS NOT NULL 条件
-- idx_ai_conv_last_msg — (user_id, site_id, last_message_at DESC NULLS LAST)
```