- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro) - CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/ - 新增 /spec-close、/pre-change 两个工作流命令 - DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表) - BD_Manual → BD_manual 命名统一(48 个文件) - 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数) - 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表) - 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档) - docs/database/README.md 索引更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
453 lines
22 KiB
Markdown
453 lines
22 KiB
Markdown
# BD_Manual:biz 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 扩展)
|
||
> - `db/zqyy_app/migrations/2026-03-22__p14_ai_module.sql`(P14 DashScope 迁移 + 调度器完善)
|
||
> - `db/zqyy_app/migrations/2026-03-23__p15_ai_monitoring.sql`(P15 AI 监控后台 — alert_status + BRIN 索引)
|
||
> 关联 SPEC:`05-miniapp-ai-integration`(P5 AI 集成层)、`rns1-chat-integration`(RNS1.4 CHAT 对齐与联调收尾)、`P14-ai-dashscope-migration`(P14 DashScope 迁移)、`ai-monitoring-testing`(P15 AI 监控后台)
|
||
|
||
---
|
||
|
||
## 1. 变更说明
|
||
|
||
### 新增表(5 张)
|
||
|
||
| # | 表名 | 用途 | 字段数(初始→当前) | 来源 |
|
||
|---|------|------|---------------------|------|
|
||
| 1 | `biz.ai_conversations` | AI 对话记录:每次 AI 调用(用户主动或系统自动)创建一条 | 8 → 14 | P5 |
|
||
| 2 | `biz.ai_messages` | AI 消息记录:对话中的每条消息(输入/输出/系统) | 6 → 7 | P5 |
|
||
| 3 | `biz.ai_cache` | AI 应用缓存:各应用的结构化输出结果 | 9 → 10 | P5 |
|
||
| 4 | `biz.ai_run_logs` | **P14 新增** — AI 运行记录:每次 DashScope API 调用的详细日志 | 14 → 15 | P14, P15 |
|
||
| 5 | `biz.ai_trigger_jobs` | **P14 新增** — 调度运行记录:每次 AI 事件触发的编排执行记录 | 13 | P14 |
|
||
|
||
### 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(客户概览等结构化上下文数据) |
|
||
|
||
### P14 DashScope 迁移扩展字段(2026-03-22)
|
||
|
||
| # | 表名 | 新增字段 | 用途 |
|
||
|---|------|---------|------|
|
||
| 1 | `biz.ai_conversations` | `session_id` | 百炼 session_id(格式 `conv_{id}_{ts}`),仅 App1 使用 |
|
||
| 2 | `biz.ai_cache` | `status` | 缓存状态:valid / expired / invalidated / generating |
|
||
|
||
### P15 AI 监控后台扩展(2026-03-23)
|
||
|
||
| # | 表名 | 变更类型 | 说明 |
|
||
|---|------|---------|------|
|
||
| 1 | `biz.ai_run_logs` | 新增字段 `alert_status` | 告警处理状态:NULL / pending / acknowledged / ignored |
|
||
| 2 | `biz.ai_run_logs` | 新增约束 `chk_ai_run_logs_alert_status` | CHECK (alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored')) |
|
||
| 3 | `biz.ai_run_logs` | 新增部分索引 `idx_ai_run_logs_alert` | (alert_status, created_at DESC) WHERE status IN ('failed', 'timeout', 'circuit_open') — 告警列表查询 |
|
||
| 4 | `biz.ai_run_logs` | 新增 BRIN 索引 `idx_ai_run_logs_created_brin` | BRIN (created_at) WITH (pages_per_range = 32) — Dashboard 聚合优化 |
|
||
| 5 | `biz.ai_run_logs` | 回填 | 已有 status IN ('failed','timeout','circuit_open') 的记录 alert_status 设为 'pending' |
|
||
|
||
### 表字段明细
|
||
|
||
#### biz.ai_conversations(14 字段)
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| `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 新增** — 关联上下文 ID |
|
||
| `title` | VARCHAR(200) | 可空 | **RNS1.4 新增** — 对话标题 |
|
||
| `last_message` | TEXT | 可空 | **RNS1.4 新增** — 最后一条消息内容摘要(截断至100字) |
|
||
| `last_message_at` | TIMESTAMPTZ | 可空 | **RNS1.4 新增** — 最后消息时间 |
|
||
| `session_id` | VARCHAR(100) | 可空 | **P14 新增** — 百炼 session_id,格式 `conv_{conversation_id}_{created_timestamp}`,仅 App1 使用 |
|
||
|
||
#### biz.ai_messages(7 字段)
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| `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_cache(10 字段)
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| `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 | 可空 | 可选过期时间 |
|
||
| `status` | VARCHAR(20) | DEFAULT 'valid', CHECK | **P14 新增** — 缓存状态:valid(有效)/ expired(已过期)/ invalidated(手动失效)/ generating(生成中) |
|
||
|
||
### 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_conversations` | `idx_ai_conv_context` | INDEX(条件) | **RNS1.4** — `(user_id, site_id, context_type, context_id, last_message_at DESC) 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)` |
|
||
| `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` | `chk_ai_cache_status` | CHECK | **P14** — `status IN ('valid', 'expired', 'invalidated', 'generating')` |
|
||
| `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)` — 清理超限记录 |
|
||
| `ai_run_logs` | `idx_ai_run_logs_site_app` | INDEX | **P14** — `(site_id, app_type)` |
|
||
| `ai_run_logs` | `idx_ai_run_logs_created` | INDEX | **P14** — `(created_at)` — Token 预算聚合 |
|
||
| `ai_run_logs` | `idx_ai_run_logs_status` | INDEX | **P14** — `(status)` |
|
||
| `ai_run_logs` | `chk_ai_run_logs_alert_status` | CHECK | **P15** — `alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored')` |
|
||
| `ai_run_logs` | `idx_ai_run_logs_alert` | INDEX(部分) | **P15** — `(alert_status, created_at DESC) WHERE status IN ('failed', 'timeout', 'circuit_open')` — 告警列表查询优化 |
|
||
| `ai_run_logs` | `idx_ai_run_logs_created_brin` | BRIN INDEX | **P15** — `BRIN (created_at) WITH (pages_per_range = 32)` — Dashboard 聚合查询优化,适合按时间顺序插入的表 |
|
||
| `ai_trigger_jobs` | `idx_ai_trigger_jobs_site` | INDEX | **P14** — `(site_id, event_type)` |
|
||
| `ai_trigger_jobs` | `idx_ai_trigger_jobs_dedup` | INDEX(条件) | **P14** — `(event_type, member_id, site_id, created_at) WHERE status NOT IN ('skipped_duplicate')` — 去重 |
|
||
| `ai_trigger_jobs` | `idx_ai_trigger_jobs_status` | INDEX | **P14** — `(status)` |
|
||
|
||
#### biz.ai_run_logs(15 字段,P14 新增 + P15 扩展)
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | BIGSERIAL | PK | 自增主键 |
|
||
| `site_id` | BIGINT | NOT NULL | 门店 ID |
|
||
| `app_type` | VARCHAR(30) | NOT NULL | 应用类型:app1_chat / app2_finance / ... / app8_consolidate |
|
||
| `trigger_type` | VARCHAR(20) | NOT NULL | 触发类型:user / scheduled / event / forced |
|
||
| `member_id` | BIGINT | 可空 | 会员 ID |
|
||
| `request_prompt` | TEXT | 可空 | 请求 prompt(截断前 2000 字符) |
|
||
| `response_text` | TEXT | 可空 | 响应文本 |
|
||
| `tokens_used` | INTEGER | DEFAULT 0 | 消耗 token 数 |
|
||
| `latency_ms` | INTEGER | 可空 | 调用延迟(毫秒) |
|
||
| `status` | VARCHAR(20) | NOT NULL DEFAULT 'pending' | 状态:pending / running / success / failed / timeout / budget_exceeded |
|
||
| `error_message` | TEXT | 可空 | 错误信息 |
|
||
| `session_id` | VARCHAR(100) | 可空 | 百炼 session_id(仅 App1) |
|
||
| `alert_status` | VARCHAR(20) | DEFAULT NULL, CHECK | **P15 新增** — 告警处理状态:NULL(非告警记录)/ pending(待处理)/ acknowledged(已确认)/ ignored(已忽略)。仅 status IN ('failed','timeout','circuit_open') 的记录才设置此字段 |
|
||
| `created_at` | TIMESTAMPTZ | NOT NULL DEFAULT now() | 创建时间 |
|
||
| `finished_at` | TIMESTAMPTZ | 可空 | 完成时间 |
|
||
|
||
#### biz.ai_trigger_jobs(13 字段,P14 新增)
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | BIGSERIAL | PK | 自增主键 |
|
||
| `site_id` | BIGINT | NOT NULL | 门店 ID |
|
||
| `event_type` | VARCHAR(30) | NOT NULL | 事件类型:consumption / dws_completed / note_created / task_assigned |
|
||
| `connector_type` | VARCHAR(30) | DEFAULT 'feiqiu' | 连接器类型 |
|
||
| `member_id` | BIGINT | 可空 | 会员 ID |
|
||
| `payload` | JSONB | 可空 | 附加数据 |
|
||
| `status` | VARCHAR(20) | NOT NULL DEFAULT 'pending' | 状态:pending / running / completed / failed / skipped_duplicate / budget_exceeded |
|
||
| `is_forced` | BOOLEAN | DEFAULT false | 是否强制执行(跳过去重检查) |
|
||
| `app_chain` | VARCHAR(100) | 可空 | 调用链描述,如 `app3→app8→app7` |
|
||
| `started_at` | TIMESTAMPTZ | 可空 | 开始时间 |
|
||
| `finished_at` | TIMESTAMPTZ | 可空 | 完成时间 |
|
||
| `error_message` | TEXT | 可空 | 错误信息 |
|
||
| `created_at` | TIMESTAMPTZ | NOT NULL DEFAULT now() | 创建时间 |
|
||
|
||
---
|
||
|
||
## 2. 兼容性影响
|
||
|
||
| 组件 | 影响 |
|
||
|------|------|
|
||
| ETL 任务 | **P14 新增**:DWS 任务完成后通过 `utils/ai_trigger.py` 发送 HTTP 触发事件到后端 `ai_trigger_jobs`,失败不中断 ETL 流程 |
|
||
| 后端 API | 直接依赖。P5 AI 模块(`apps/backend/app/ai/`)基于这些表实现对话持久化、缓存读写、SSE 流式对话等功能 |
|
||
| 后端 API(RNS1.4) | **直接依赖**。CHAT 模块依赖 `ai_conversations` 的 5 个 RNS1.4 字段实现多入口对话复用 |
|
||
| 后端 API(P14) | **直接依赖**。`ai_run_logs` 用于 Token 预算聚合(BudgetTracker);`ai_trigger_jobs` 用于事件去重和调度记录;`ai_conversations.session_id` 用于百炼会话管理;`ai_cache.status` 用于缓存状态控制 |
|
||
| 小程序 | 间接依赖。小程序通过后端 AI API 间接使用对话和缓存数据 |
|
||
| 管理后台 | **P15 直接依赖**。admin-web AI 监控后台(4 个页面)依赖 `ai_run_logs.alert_status` 实现告警管理(确认/忽略),依赖 BRIN 索引优化 Dashboard 聚合查询性能 |
|
||
| `member_retention_clue` | 间接关联。App8 结果同时写入 `ai_cache` 和 `member_retention_clue` 表(P14 实现幂等 DELETE+INSERT) |
|
||
|
||
---
|
||
|
||
## 3. 回滚策略
|
||
|
||
### 3d. 回滚 P15 AI 监控后台(2026-03-23 迁移)
|
||
|
||
按逆序 DROP 新增索引、约束和字段:
|
||
|
||
```sql
|
||
BEGIN;
|
||
DROP INDEX IF EXISTS biz.idx_ai_run_logs_created_brin;
|
||
DROP INDEX IF EXISTS biz.idx_ai_run_logs_alert;
|
||
ALTER TABLE biz.ai_run_logs DROP CONSTRAINT IF EXISTS chk_ai_run_logs_alert_status;
|
||
ALTER TABLE biz.ai_run_logs DROP COLUMN IF EXISTS alert_status;
|
||
COMMIT;
|
||
```
|
||
|
||
注意:
|
||
- 回滚后 admin-web AI 监控后台的告警管理功能将不可用
|
||
- Dashboard 聚合查询性能可能下降(失去 BRIN 索引)
|
||
- 回滚不影响 P14 的核心功能(调度器、预算追踪等)
|
||
|
||
### 3c. 回滚 P14 DashScope 迁移(2026-03-22 迁移)
|
||
|
||
按逆序 DROP 新增表和字段:
|
||
|
||
```sql
|
||
-- 删除 P14 新增约束和字段
|
||
ALTER TABLE biz.ai_cache DROP CONSTRAINT IF EXISTS chk_ai_cache_status;
|
||
ALTER TABLE biz.ai_cache DROP COLUMN IF EXISTS status;
|
||
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS session_id;
|
||
|
||
-- 删除 P14 新增表
|
||
DROP TABLE IF EXISTS biz.ai_trigger_jobs;
|
||
DROP TABLE IF EXISTS biz.ai_run_logs;
|
||
```
|
||
|
||
注意:
|
||
- 回滚后 P14 AI 调度器(dispatcher)、Token 预算追踪(BudgetTracker)将无法正常工作
|
||
- `ai_run_logs` 和 `ai_trigger_jobs` 中的数据将丢失,需先备份
|
||
- 回滚不影响 P5 和 RNS1.4 的功能
|
||
|
||
### 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 迁移)
|
||
|
||
按逆序 DROP(CASCADE 处理外键依赖):
|
||
|
||
```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;
|
||
-- 预期:返回 14 行(P5 原始 8 + RNS1.4 新增 5 + P14 session_id = 14)
|
||
|
||
-- 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_role(CHECK role IN ...)和 ai_messages_conversation_id_fkey(FK → 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';
|
||
-- 预期:返回 2 行(chk_ai_cache_type 含 7 个枚举值,chk_ai_cache_status 含 4 个状态值)
|
||
|
||
-- 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)
|
||
```
|
||
|
||
### 4c. P14 DashScope 迁移验证
|
||
|
||
```sql
|
||
-- 9. 验证 ai_run_logs 表存在且字段正确
|
||
SELECT column_name, data_type, character_maximum_length
|
||
FROM information_schema.columns
|
||
WHERE table_schema = 'biz' AND table_name = 'ai_run_logs'
|
||
ORDER BY ordinal_position;
|
||
-- 预期:返回 15 行
|
||
|
||
-- 10. 验证 ai_trigger_jobs 表存在且字段正确
|
||
SELECT column_name, data_type, character_maximum_length
|
||
FROM information_schema.columns
|
||
WHERE table_schema = 'biz' AND table_name = 'ai_trigger_jobs'
|
||
ORDER BY ordinal_position;
|
||
-- 预期:返回 13 行
|
||
|
||
-- 11. 验证 ai_run_logs 索引(含 PK)
|
||
SELECT indexname FROM pg_indexes
|
||
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs';
|
||
-- 预期:6 行(PK + 3 P14 索引 + 2 P15 索引)
|
||
|
||
-- 12. 验证 ai_trigger_jobs 索引(含去重部分索引)
|
||
SELECT indexname FROM pg_indexes
|
||
WHERE schemaname = 'biz' AND tablename = 'ai_trigger_jobs';
|
||
-- 预期:4 行(PK + 3 个索引)
|
||
|
||
-- 13. 验证 ai_conversations.session_id 字段
|
||
SELECT column_name, data_type, character_maximum_length
|
||
FROM information_schema.columns
|
||
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
|
||
AND column_name = 'session_id';
|
||
-- 预期:1 行,varchar(100)
|
||
|
||
-- 14. 验证 ai_cache.status 字段 + CHECK 约束
|
||
SELECT column_name, data_type, column_default
|
||
FROM information_schema.columns
|
||
WHERE table_schema = 'biz' AND table_name = 'ai_cache'
|
||
AND column_name = 'status';
|
||
-- 预期:1 行,varchar(20),default 'valid'
|
||
|
||
SELECT conname FROM pg_constraint
|
||
WHERE conrelid = 'biz.ai_cache'::regclass AND conname = 'chk_ai_cache_status';
|
||
-- 预期:1 行
|
||
```
|
||
|
||
### 4d. P15 AI 监控后台验证
|
||
|
||
```sql
|
||
-- 15. 验证 ai_run_logs.alert_status 字段存在
|
||
SELECT column_name, data_type, character_maximum_length, column_default
|
||
FROM information_schema.columns
|
||
WHERE table_schema = 'biz' AND table_name = 'ai_run_logs'
|
||
AND column_name = 'alert_status';
|
||
-- 预期:1 行,varchar(20),default NULL
|
||
|
||
-- 16. 验证 alert_status CHECK 约束
|
||
SELECT conname, pg_get_constraintdef(oid) AS constraint_def
|
||
FROM pg_constraint
|
||
WHERE conrelid = 'biz.ai_run_logs'::regclass
|
||
AND conname = 'chk_ai_run_logs_alert_status';
|
||
-- 预期:1 行,CHECK (alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored'))
|
||
|
||
-- 17. 验证 P15 新增索引(部分索引 + BRIN 索引)
|
||
SELECT indexname, indexdef
|
||
FROM pg_indexes
|
||
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs'
|
||
AND indexname IN ('idx_ai_run_logs_alert', 'idx_ai_run_logs_created_brin');
|
||
-- 预期:2 行
|
||
-- idx_ai_run_logs_alert — 含 WHERE status IN ('failed', 'timeout', 'circuit_open')
|
||
-- idx_ai_run_logs_created_brin — USING brin
|
||
|
||
-- 18. 验证 ai_run_logs 总索引数(P14 3个 + P15 2个 + PK = 6)
|
||
SELECT indexname FROM pg_indexes
|
||
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs';
|
||
-- 预期:6 行
|
||
|
||
-- 19. 验证回填结果:失败/超时/熔断记录的 alert_status 应为 'pending'
|
||
SELECT COUNT(*) AS unset_alerts
|
||
FROM biz.ai_run_logs
|
||
WHERE status IN ('failed', 'timeout', 'circuit_open')
|
||
AND alert_status IS NULL;
|
||
-- 预期:0(所有失败记录已回填为 'pending')
|
||
```
|
||
|
||
### P15 admin API 查询模式说明
|
||
|
||
P15 admin-web AI 监控后台引入以下典型查询模式:
|
||
|
||
| 查询场景 | SQL 模式 | 使用索引 |
|
||
|---------|---------|---------|
|
||
| Dashboard 今日统计 | `SELECT COUNT(*), AVG(latency_ms) FROM ai_run_logs WHERE created_at >= 今日零点` | `idx_ai_run_logs_created_brin` |
|
||
| Dashboard 7天趋势 | `SELECT date_trunc('day', created_at), COUNT(*) FROM ai_run_logs WHERE created_at >= 7天前 GROUP BY 1` | `idx_ai_run_logs_created_brin` |
|
||
| 告警列表 | `SELECT * FROM ai_run_logs WHERE status IN ('failed','timeout','circuit_open') AND alert_status = 'pending' ORDER BY created_at DESC` | `idx_ai_run_logs_alert` |
|
||
| 告警确认/忽略 | `UPDATE ai_run_logs SET alert_status = 'acknowledged' WHERE id = ?` | PK |
|
||
| 调用记录分页 | `SELECT * FROM ai_run_logs WHERE site_id = ? AND app_type = ? ORDER BY created_at DESC LIMIT ? OFFSET ?` | `idx_ai_run_logs_site_app` |
|
||
| Token 预算聚合 | `SELECT SUM(tokens_used) FROM ai_run_logs WHERE created_at >= 今日零点 AND status = 'success'` | `idx_ai_run_logs_created` (B-tree) |
|