包含多个会话的累积代码变更: - 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>
4.9 KiB
4.9 KiB
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. 索引支持审计查询
-- 按用户+门店查询历史对话
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):
# 创建对话记录
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):
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
);
建议
审计日志功能已完整实现,以下为可选增强方向(非必须):
- 审计查询 API:当前仅有面向用户的历史对话查询(
get_conversations),可增加面向管理员的审计查询接口(按时间范围、app_id、site_id 筛选) - 数据保留策略:当前无自动清理机制,长期运行后
ai_messages.content可能占用大量存储,建议制定保留策略