包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
4.9 KiB
Markdown
128 lines
4.9 KiB
Markdown
# P5.1→NS3 缺失项 #10:AI 生成内容的审计日志
|
||
|
||
## 简要结论
|
||
- 状态:✅ 已解决
|
||
- 风险等级:🟡 低
|
||
- `biz.ai_conversations` + `biz.ai_messages` 两张表已完整记录"谁在什么时候对哪个客户生成了什么",满足审计日志需求
|
||
|
||
## 详细审查
|
||
|
||
### 审查范围
|
||
- `apps/backend/app/ai/conversation_service.py` — 对话持久化服务
|
||
- `apps/backend/app/services/chat_service.py` — Chat 模块服务
|
||
- `docs/database/ddl/zqyy_app__biz.sql` — biz schema DDL 基线
|
||
- `db/zqyy_app/migrations/2026-03-20__rns14_chat_module_extend.sql` — Chat 模块扩展迁移
|
||
- `apps/backend/app/ai/apps/app5_tactics.py` — 典型 App 调用流程(审计写入示例)
|
||
|
||
### 发现
|
||
|
||
#### ✅ 审计信息完整记录
|
||
|
||
**1. `biz.ai_conversations` 表 — 对话级审计**
|
||
|
||
| 字段 | 类型 | 审计用途 |
|
||
|------|------|----------|
|
||
| `id` | bigint PK | 对话唯一标识 |
|
||
| `user_id` | varchar(50) NOT NULL | **谁**:操作用户 ID(系统自动调用时为 `'system'`) |
|
||
| `nickname` | varchar(100) | 用户昵称 |
|
||
| `app_id` | varchar(30) NOT NULL | **什么应用**:app1_chat / app2_finance / ... / app8_consolidation |
|
||
| `site_id` | bigint NOT NULL | **哪个门店** |
|
||
| `source_page` | varchar(100) | 触发来源页面 |
|
||
| `source_context` | jsonb | 上下文信息(含 `assistant_id`、`member_id` 等 → **对哪个客户**) |
|
||
| `context_type` | varchar(20) | 对话关联类型:task/customer/coach/general |
|
||
| `context_id` | varchar(50) | 关联 ID(taskId/customerId/coachId) |
|
||
| `title` | varchar(200) | 对话标题 |
|
||
| `created_at` | timestamptz | **什么时候** |
|
||
|
||
**2. `biz.ai_messages` 表 — 消息级审计**
|
||
|
||
| 字段 | 类型 | 审计用途 |
|
||
|------|------|----------|
|
||
| `id` | bigint PK | 消息唯一标识 |
|
||
| `conversation_id` | bigint FK | 关联对话 |
|
||
| `role` | varchar(10) | system / user / assistant |
|
||
| `content` | text NOT NULL | **生成了什么**:完整的 AI 输入和输出内容 |
|
||
| `tokens_used` | integer | Token 消耗量 |
|
||
| `reference_card` | jsonb | 引用卡片数据 |
|
||
| `created_at` | timestamptz | 消息时间戳 |
|
||
|
||
**3. 写入时机**
|
||
|
||
所有 8 个 AI 应用在每次调用时都通过 `ConversationService` 写入完整审计链:
|
||
|
||
```
|
||
create_conversation(user_id, nickname, app_id, site_id, source_context)
|
||
→ add_message(role="system", content=prompt)
|
||
→ add_message(role="user", content=user_input)
|
||
→ 调用百炼 API
|
||
→ add_message(role="assistant", content=ai_output, tokens_used=N)
|
||
```
|
||
|
||
**4. 索引支持审计查询**
|
||
|
||
```sql
|
||
-- 按用户+门店查询历史对话
|
||
CREATE INDEX idx_ai_conv_user_site ON biz.ai_conversations (user_id, site_id, created_at DESC);
|
||
-- 按应用+门店查询
|
||
CREATE INDEX idx_ai_conv_app_site ON biz.ai_conversations (app_id, site_id, created_at DESC);
|
||
-- 按上下文查询(客户/任务/助教维度)
|
||
CREATE INDEX idx_ai_conv_context ON biz.ai_conversations (user_id, site_id, context_type, context_id, ...);
|
||
-- 按对话查询消息
|
||
CREATE INDEX idx_ai_msg_conv ON biz.ai_messages (conversation_id, created_at);
|
||
```
|
||
|
||
### 证据
|
||
|
||
**App5 审计写入示例(app5_tactics.py L240-268)**:
|
||
```python
|
||
# 创建对话记录
|
||
conversation_id = conv_svc.create_conversation(
|
||
user_id=user_id, nickname=nickname,
|
||
app_id=APP_ID, site_id=site_id,
|
||
source_context={"assistant_id": assistant_id, "member_id": member_id},
|
||
)
|
||
# 写入 system + user 消息
|
||
conv_svc.add_message(conversation_id=conversation_id, role="system", content=...)
|
||
conv_svc.add_message(conversation_id=conversation_id, role="user", content=...)
|
||
# 调用 AI 后写入 assistant 消息
|
||
result, tokens_used = await bailian.chat_json(messages)
|
||
conv_svc.add_message(
|
||
conversation_id=conversation_id, role="assistant",
|
||
content=json.dumps(result, ensure_ascii=False),
|
||
tokens_used=tokens_used,
|
||
)
|
||
```
|
||
|
||
**DDL 基线确认(zqyy_app__biz.sql)**:
|
||
```sql
|
||
CREATE TABLE biz.ai_conversations (
|
||
id bigint ... NOT NULL,
|
||
user_id character varying(50) NOT NULL,
|
||
nickname character varying(100) ...,
|
||
app_id character varying(30) NOT NULL,
|
||
site_id bigint NOT NULL,
|
||
source_page character varying(100),
|
||
source_context jsonb,
|
||
context_type character varying(20),
|
||
context_id character varying(50),
|
||
...
|
||
created_at timestamp with time zone DEFAULT now() NOT NULL
|
||
);
|
||
|
||
CREATE TABLE biz.ai_messages (
|
||
id bigint ... NOT NULL,
|
||
conversation_id bigint NOT NULL,
|
||
role character varying(10) NOT NULL,
|
||
content text NOT NULL,
|
||
tokens_used integer,
|
||
reference_card jsonb,
|
||
created_at timestamp with time zone DEFAULT now() NOT NULL
|
||
);
|
||
```
|
||
|
||
### 建议
|
||
|
||
审计日志功能已完整实现,以下为可选增强方向(非必须):
|
||
1. **审计查询 API**:当前仅有面向用户的历史对话查询(`get_conversations`),可增加面向管理员的审计查询接口(按时间范围、app_id、site_id 筛选)
|
||
2. **数据保留策略**:当前无自动清理机制,长期运行后 `ai_messages.content` 可能占用大量存储,建议制定保留策略
|