Files
prop-ai-hr/docs/KNOWLEDGE_PLATFORM_RUNBOOK.md
T

206 lines
10 KiB
Markdown

# 多租户知识空间平台运行手册
## 1. 适用范围与安全边界
本手册用于银城与美途作为两个独立 SaaS 租户的知识空间初始化、内容迁移、授权、外部应用联调和回滚。租户、调用应用和知识空间是三层独立边界:内部用户的有效查询范围取“当前租户 + 当前调用应用绑定空间 + 用户/角色授权空间”的交集;外部应用只能访问其所属租户内显式绑定的空间。
2026-07-18 平台代码、管理页和 schema 已随 `32fa376d` 发布,生产知识空间页面已打开复核。该状态不代表银城/美途正式租户、空间、授权矩阵、外部令牌和内容迁移已经业务验收;这些仍须按本手册逐项确认。生产执行知识平台迁移后,必须最后执行 `aihr_20260718_release_collation_compat_mysql8.sql`,防止历史库排序规则与新表混用。
禁止把集团账号、公司名称、客户端传入的 `tenantId/userId/extPartyId` 当作授权依据。禁止在浏览器、小程序包、日志、工单或文档中保存 API_TOKEN。回滚优先停用应用或解绑空间,不删除知识数据、附件或 OSS 对象。
## 2. 初始化前确认
### 2.1 确认生产租户 ID
先只读查询生产库,不凭公司简称猜租户 ID:
```sql
select tenant_id, company_name, status, del_flag
from sys_tenant
where del_flag = '0'
order by tenant_id;
```
由业务负责人确认银城、美途分别对应的 `tenant_id` 和公司全称,并确认二者不同。执行脚本还会再次查询并打印 `tenant_id:company_name`,操作者必须核对后才继续。
### 2.2 备份与迁移
先备份数据库,再执行 `backend/script/sql/update/aihr_20260716_knowledge_space_platform_mysql8.sql`。迁移可重复执行,但生产仍应先在结构副本验证。执行后至少核对:
```sql
show tables like 'aihr_knowledge_%';
show create table aihr_knowledge_info;
show create table aihr_knowledge_app;
show create table aihr_knowledge_space_grant;
```
## 3. 幂等初始化
先 dry-run,不连接数据库、不输出密码或令牌:
```bash
./scripts/provision-knowledge-platform.sh \
--silver-tenant-id '<银城租户ID>' \
--meitu-tenant-id '<美途租户ID>' \
--dry-run
```
确认输出恰好包含银城 3 个空间、美途 1 个空间、3 个应用及预期绑定后,再实际执行:
```bash
AIHR_DB_HOST='<数据库地址>' \
AIHR_DB_PORT='3306' \
AIHR_DB_NAME='ry-vue' \
AIHR_DB_USER='<账号>' \
AIHR_DB_PASSWORD='<从安全环境注入>' \
./scripts/provision-knowledge-platform.sh \
--silver-tenant-id '<银城租户ID>' \
--meitu-tenant-id '<美途租户ID>' \
--confirm
```
不设置 `AIHR_DB_HOST` 时,脚本使用本地 `wygj-mysql` 容器。脚本是幂等 upsert,可重复执行;它不会生成 API_TOKEN,也不会把现有细粒度知识库改名、搬迁或删除。
执行后核对:
```sql
select tenant_id, code, name, space_type, sensitivity_level, status
from aihr_knowledge_info
where code in ('yc_public_policy','yc_property_sop','yc_management_ops','mt_customer_service')
order by tenant_id, code;
select tenant_id, app_code, auth_type, internal_client_key, status, rate_limit_per_minute
from aihr_knowledge_app
where app_code in ('yc_admin','yc_mobile','mt_card_miniapp')
order by tenant_id, app_code;
```
`mt_card_miniapp` 初始化后必须是 `DISABLED` 且 `token_hash` 为空;银城与美途之间不得存在应用—空间绑定。
## 4. 空间、授权与应用管理
管理端“知识空间”页面提供空间、主体授权和调用应用管理。空间编码创建后不可修改;停用空间会让检索立即失去该空间,但不删除资料。`MANAGE` 授权可以给用户或角色,`READ` 只决定主体能否读;SESSION 应用与主体授权取交集。
外部美途应用的启用顺序固定为:
1. 核对只绑定 `mt_customer_service`。
2. 核对空间只含批准对外发布的内容。
3. 设置合理的每分钟限流和过期时间。
4. 在管理端轮换令牌;明文只显示一次。
5. 立即写入小程序云函数、API 网关或可信后端的密钥系统。
6. 确认后端联调通过,再把应用状态改为 `ACTIVE`。
轮换令牌后旧令牌立即失效。发生泄露或暂停联调时,先把应用改为 `DISABLED`;需要恢复时重新轮换,不复用曾暴露的明文。前端、小程序源码和用户设备绝不能直接持有令牌。
## 5. 内容导入与 legacy 空间迁移
### 5.1 新内容导入
在 SOP 或资料处理页显式选择一个或多个可管理空间。多空间上传只解析一次、复用同一个 OSS 对象,但为每个空间建立独立附件成员关系和检索片段。解绑或停用一个空间不得影响另一个空间的内容。
导入后核对:
```sql
select a.tenant_id, k.code, a.doc_id, a.name, a.oss_id, a.status,
count(f.id) fragment_count
from aihr_knowledge_attach a
join aihr_knowledge_info k
on k.tenant_id = a.tenant_id and k.id = a.knowledge_id
left join aihr_knowledge_fragment f
on f.tenant_id = a.tenant_id and f.knowledge_id = a.knowledge_id and f.doc_id = a.doc_id
group by a.tenant_id, k.code, a.doc_id, a.name, a.oss_id, a.status
order by a.id desc;
```
空间解绑会先删除当前成员、片段和向量点;只有跨租户附件引用计数为零时才尝试删除 OSS。对象存储删除失败不会恢复已解绑成员,而是留下可审计的孤立对象,按下列查询确认后由独立清理流程处理:
```sql
select o.oss_id, o.tenant_id, o.original_name
from sys_oss o
left join aihr_knowledge_attach a
on a.tenant_id = o.tenant_id and a.oss_id = o.oss_id
where a.id is null and o.ext1 in ('aihr-knowledge','aihr-knowledge-staging');
```
### 5.2 细粒度 SOP 迁入 `yc_property_sop`
现有“投诉处理 SOP、催缴沟通 SOP、报修跟进 SOP”等 `legacy_*` 空间不直接改名。按以下顺序执行:
1. 业务负责人导出现有空间的文件清单,逐项标记目标空间、密级、版本日期、维护人和是否允许复用。
2. 通过多空间导入或 OSS 成员复用把批准内容加入 `yc_property_sop`,保留原 legacy 成员关系。
3. 对新空间至少运行 10 个标准问题,逐题核对答案、文件标题、引用片段和空间编码。
4. 核对新应用只绑定新空间,legacy 空间不向新应用授权。
5. 业务确认后把不再使用的 legacy 空间改为 `DISABLED`,观察查询日志一个完整业务周期。
6. 若出现缺失,重新启用 legacy 空间或恢复应用绑定;不要搬回附件、删除片段或清理 OSS。
## 6. 查询、日志与限流观察
内部统一入口为 `POST /api/knowledge/query`,内部移动端可带 `conversationId/contextVersion` 启用最近 6 轮、30 分钟不活跃过期的短期会话;外部入口 `POST /api/open/knowledge/query` 始终无状态。内部原文件/视频通过 `GET /api/knowledge/resources/{attachmentId}/content` 在下载时重新鉴权。外部请求使用 `Authorization: Bearer <API_TOKEN>`。查询日志只保存问题哈希、有效空间、来源类型、状态、耗时和提示版本,不保存完整问题或令牌。
`aihr_knowledge_conversation` 只保存脱敏截断后的短期上下文,过期记录由查询流量每 5 分钟惰性清理最多 500 条。可只读观察积压:
```sql
select count(*) total, sum(expires_time <= now()) expired, min(expires_time) oldest_expiry
from aihr_knowledge_conversation;
```
```sql
select tenant_id, app_id, status, source_types, count(*) calls,
round(avg(latency_ms)) avg_latency_ms, max(create_time) last_time
from aihr_knowledge_query_log
group by tenant_id, app_id, status, source_types
order by last_time desc;
```
重点观察 `REJECTED`、`FAILED`、`NO_EVIDENCE`、连续 `429` 和异常高耗时。外部应用的限流依赖 Redis;Redis 不可用时外部查询应失败关闭并返回服务不可用,不能绕过限流继续调用。
## 7. 验证与发布闸门
自动合同测试:
```bash
bash scripts/tests/provision-knowledge-platform.test.sh
node --test scripts/tests/knowledge-platform-security.test.mjs
npm --prefix mobile-uni run test:unit
```
本地手机号登录、多轮改写、原文件下载、视频空结果和旧版本冲突可执行:
```bash
AIHR_BASE_URL='http://127.0.0.1:8080' node scripts/verify-ask-memory-local.mjs
```
真实环境验证器从环境变量读取令牌,绝不写入命令脚本或仓库:
```bash
AIHR_BASE_URL='https://wygj-api.localhost' \
AIHR_SILVER_ADMIN_TOKEN='<管理端登录令牌>' \
AIHR_SILVER_EMPLOYEE_TOKEN='<员工登录令牌>' \
AIHR_SILVER_SUPERVISOR_TOKEN='<主管登录令牌>' \
AIHR_MEITU_APP_TOKEN='<美途应用令牌>' \
AIHR_MEITU_QUERY='<已确认能命中公开内容的美途标准题>' \
node scripts/verify-knowledge-platform.mjs
```
在预先导入了同一测试文件到 `yc_public_policy` 与 `yc_property_sop` 的非生产环境,可额外执行破坏性解绑验证;它会删除公共制度空间中的测试成员,因此必须使用专用测试文件:
```bash
AIHR_VERIFY_UNBIND=true \
AIHR_SHARED_DOC_NAME='<专用测试文件名>' \
AIHR_SHARED_DOC_QUERY='<测试文件唯一标记>' \
node scripts/verify-knowledge-platform.mjs
```
只有工程回归、真实 HTTP 正反例、数据库租户归属、Qdrant tenant+knowledge 过滤和每空间标准题都通过,才可标记“联调可用”。当前生产包已发布,但在真实内容负责人/授权矩阵签字、正式空间初始化、令牌联调和标准题完成前,不得标记“知识平台业务上线”或“正式试点验收”。
## 8. 回滚
按影响最小顺序处理:
1. 停用 `mt_card_miniapp` 或对应 SESSION 应用。
2. 解绑错误空间或把有问题的新空间置为 `DISABLED`。
3. 客户端临时回到兼容 `/api/knowledge/search`,该入口仍经过统一授权服务。
4. 恢复旧应用绑定或重新启用 legacy 空间。
不要删除新表,不删除查询审计,不把附件移动回旧空间,不清理 OSS,不回滚已经写入的稳定空间编码。数据库和静态资源发布仍遵循项目既有备份与发布口径。