# 多租户知识空间平台运行手册 ## 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`、`backend/script/sql/update/aihr_20260722_knowledge_category_mysql8.sql`;需要从原 OSS 文件恢复历史零片段图片/视频时,还必须执行 `backend/script/sql/update/aihr_20260729_media_reprocess_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; show create table aihr_knowledge_category; show create table aihr_knowledge_upload_item; ``` ## 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 零片段图片/视频排障与重试 资料处理页把 `aihr_knowledge_attach.status in (0,3)` 且片段数为 0 的图片/视频列为“待重试”。先确认视觉模型、视频 ASR/ffmpeg 和原 OSS 对象仍可读取,再从页面点击“重试”;服务端只接受当前租户、状态为待处理/失败且仍有 OSS 原件的图片或视频,通过 `POST /api/knowledge/doc/processing-tasks/{attachmentId}/retry` 重新暂存并写入异步队列。重复点击由附件状态 CAS 拒绝,不得直接把数据库状态改成完成或手工复制片段。 只读排障可使用: ```sql select a.id, a.tenant_id, a.name, a.status, a.remark, a.doc_id, count(f.id) fragment_count from aihr_knowledge_attach a 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 where a.id = group by a.id, a.tenant_id, a.name, a.status, a.remark, a.doc_id; select id, batch_id, file_name, source_attach_id, status, error, fragment_count, update_time from aihr_knowledge_upload_item where tenant_id = '<当前租户>' and source_attach_id = order by id desc; ``` 队列状态固定为 `0=待处理、1=处理中、2=完成、3=失败`。成功条件是最新队列条目为 2、附件为 2、片段数大于 0,并按当前向量配置确认相应片段已向量化;零片段必须保持失败态,不能显示为完成。普通失败条目只有在 72 小时暂存保留期内才可调用 `POST /api/knowledge/doc/upload-items/{id}/retry`;暂存已清理时应重新上传。历史附件重试不依赖旧暂存文件,而是从 OSS 原件重新入队。 ### 5.3 RC-007 容量与存储门禁 当前资料加工 worker 固定为单实例并发 2,单文件上限 500MiB,ZIP 解压总量上限 2GiB,失败暂存保留 72 小时。默认暂存目录为 `./.data/staging`,生产必须通过 `AIHR_UPLOAD_STAGING` 或 `aihr.upload.staging` 指向独立、可监控的持久磁盘,不得依赖系统临时目录。`aihrUploadCapacity` 健康组件默认要求可用空间不少于 10GiB;可用 `AIHR_UPLOAD_MINIMUM_FREE_BYTES` 调整,但只能在完成容量测算后修改。 发布前先只读检查: ```bash curl -fsS https:///actuator/health/aihrUploadCapacity curl -fsS https:///actuator/metrics/http.server.requests ``` 健康详情必须满足 `status=UP`、`stagingWritable=true`、`capacityReady=true`,并核对 `workerConcurrency=2`、`maxFileBytes=524288000`、`maxArchiveUnpackedBytes=2147483648`。生产配置已为 `http.server.requests` 开启 P50/P95/P99 分位统计;错误率按同一指标的 `status/outcome` 标签计算。出现低磁盘健康失败时先扩容或迁移暂存盘,不得通过降低门禁值冒充恢复。 录音中的约 600 名生活管家只是用户规模,不是 600 并发。压测前由业务、实施和运维另行签认峰值在线人数、并发到达率、业务流量占比、文件大小分布、弱网条件、P95 目标、错误率目标和持续时长;未签认前只可验证健康门禁和现有并发上限,不得宣称容量验收通过。压测必须使用隔离环境和脱敏/合成数据,不对生产执行写压测。 ### 5.4 细粒度 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`,移动端“问”的规范入口是 `/api/aihr/agent/**`,仅在 Agent 识别为知识/资源意图后调用该层。知识查询可带 `conversationId/contextVersion` 启用最新 6 轮、30 分钟不活跃过期的短期会话;外部入口 `POST /api/open/knowledge/query` 始终无状态。内部原文件/视频通过 `GET /api/knowledge/resources/{attachmentId}/content` 在下载时重新鉴权。外部请求使用 `Authorization: Bearer `。查询日志只保存问题哈希、有效空间、来源类型、状态、耗时和提示版本,不保存完整问题或令牌。 `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 不可用时外部查询应失败关闭并返回服务不可用,不能绕过限流继续调用。 ### 6.1 总结卡证据绑定与排障 总结卡必须复用当前知识回答中的 `DOCUMENT` 引用,不接受客户端自行填写或历史回答残留的片段: ```json { "queryText": "厕所打扫的 SOP 是什么?", "category": "sop", "fragmentIds": [120535] } ``` `fragmentIds` 最多 5 条。`POST /api/knowledge/summary-card` 会按当前租户、应用和主体授权重新校验,只基于仍有权限的片段生成固定「问题/建议/标准」结构,不再执行第二次检索。引用为空、越权、模型不可用或输出结构不合格都应返回明确错误;前端保留当前答案并允许重试,不展示原文伪造的步骤卡。 若知识回答正常但总结卡失败,先核对请求片段确实来自同一轮响应,再检查启用的 `category='chat'` 模型。DeepSeek 旧模型名或 SOP Prompt 未兼容部分证据时,按[生产迁移 Runbook](BRD_PRODUCTION_MIGRATION_RUNBOOK.md)执行 `aihr_20260725_deepseek_v4_model_mysql8.sql` 与 `aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql`,随后通过管理端连接测试和认证态查询—总结卡链路复核;不要在日志或工单中记录密钥、手机号或完整问题正文。 ## 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,不回滚已经写入的稳定空间编码。数据库和静态资源发布仍遵循项目既有备份与发布口径。 ## 9. 引用来源定位回填 引用定位迁移为 `backend/script/sql/update/aihr_20260731_knowledge_fragment_locator_mysql8.sql`。先执行只读核对: ```bash node scripts/verify-knowledge-fragment-locators.mjs node scripts/backfill-knowledge-fragment-locators.mjs ``` 第二条命令只输出完整 `MIGRATE_DB:` 授权串,不写数据库。仅在独立获得该完整授权串后,才可设置 `AIHR_MIGRATE_AUTH` 并追加 `--apply`。回填只新增旁路 locator,不更新附件哈希、正式来源审批、fragment、embedding 或 Qdrant point;无法确定页码或时间的旧资料只保留段落级降级位置。 ## 10. 数据质量准入与索引一致性 资料上传完成只代表候选版本可供审核,不代表可检索。运营按以下顺序处理: 1. 在资料处理页查看 `REVIEW_PENDING/QUARANTINED` 资产和全部 reason code;硬问题必须修订原资料后重跑,不能勾选放行。 2. 对 `EXACT_DUPLICATE/NEAR_DUPLICATE/SEMANTIC_DUPLICATE` 对照来源、版本和适用范围;任何重复关系仅辅助人工判断,不自动删除或合并。`SEMANTIC_ANALYSIS_DEGRADED` 表示只运行了本地 hash 近似,不能当作完整语义检查。 3. 同名或精确重复上传始终创建新的附件、`docId` 和候选资产;只允许复用不可变 OSS 对象,不得把旧附件改指向新对象。同名内容变化产生 `VERSION_CONFLICT`。规范性知识发布时必须选择同租户、同来源名且仍为 `PUBLISHED/APPROVED` 的被替代资产;成功后旧版本同步变为 `DEPRECATED`。 4. 对 `EXPERT_CONFLICT` 在审核弹窗逐条查看双方来源和原文;真实冲突先确认,再依据现行制度、适用范围和版本标记已解决,误报必须写明理由。任何 `PENDING_REVIEW/CONFIRMED` claim 冲突都阻断发布。 5. 发布时填写来源权威级别、来源版本、用途、适用岗位/区域/项目和审核理由。服务端拒绝语义分析未完成、冲突未裁决、硬问题开放或软问题未逐项确认的版本,不依赖浏览器状态。 6. 发布后查询 `GET /api/knowledge/quality/index-health`。`DEAD_LETTER > 0` 或最老待处理事件持续增长时,先排查 Qdrant、维度和凭据,再由受控重放/修复流程处理;不得手工伪造索引成功。 7. 员工答案争议进入后台 SOP 的“处理争议”。`KEEP` 必须写保留依据;`WITHDRAW` 必须写撤回原因,系统先切断 MySQL 可见性,再由 DELETE outbox 最终清除向量。 8. 业务术语先创建 `DRAFT`,由人工审核为 `ACTIVE` 后才参与当前租户的召回查询扩展;项目/角色范围不匹配时不得扩展。术语 definition 只是审核说明,不能作为无引用事实直接注入模型。 9. 规则自动化先建立版本化草稿并进入 `SHADOW`,用人工或黄金集标签记录误放行/误隔离;当前接口不能进入 `CANARY/ACTIVE`,影子结果不得改变资产状态或替代人工发布。 10. 影子评估由定时任务风险抽样,也可由人工调用 `/rules/samples/schedule` 立即补充队列。差异样本必抽,其他样本按风险稳定抽样;只有登录审核人能提交复核结论。每批抽样写 `aihr_pipeline_run`,指标中的 `assetMutationCount` 必须为 0。 数据质量生命周期迁移按 `aihr_20260801` 至 `aihr_20260814` 的日期顺序执行,最后执行 `aihr_20260718_release_collation_compat_mysql8.sql`。`aihr_20260808_data_quality_monitoring_mysql8.sql` 新增 `aihr_quality_alert`,`20260809` 新增人工术语表,`20260810` 补齐 AI 案例 provenance,`20260811` 增加只观察的规则演进、影子评估和抽样复核证据,`20260812` 增加处理批次血缘和自动影子抽样,`20260813` 增加冻结黄金集、黄金评估血缘和风险验收门槛,`20260814` 增加独立隐私脱敏派生、规则版本和复扫状态;迁移可重复执行,但生产执行前仍须备份并在结构副本验证。不得用 `reset-dev-db.sh` 代替生产迁移。 日常监控入口: ```http GET /api/knowledge/quality/metrics GET /api/knowledge/quality/alerts?includeResolved=false&limit=100 GET /api/knowledge/quality/glossary?status=ACTIVE&limit=100 GET /api/knowledge/quality/rules?status=SHADOW&limit=100 GET /api/knowledge/quality/pipeline-runs?status=ALL&limit=100 GET /api/knowledge/quality/rules/{ruleId}/samples?status=PENDING&limit=100 GET /api/knowledge/quality/golden-datasets?status=FROZEN&limit=100 GET /api/knowledge/quality/rules/{ruleId}/readiness GET /api/knowledge/quality/legacy/preview?afterAttachmentId=0&limit=20 GET /actuator/health ``` 管理端“资料处理”页展示生产来源可追溯率、24 小时问答证据覆盖率、待裁决冲突、语义分析死信和开放告警。Actuator 中的 `aihrKnowledgeQuality` 只反映门禁与索引健康,不代替人工内容审批;告警扫描不会自动发布、删除、合并或裁决资料。`CRITICAL/ERROR` 告警应先定位 `evidenceJson` 对应的资产、outbox 或查询证据,再通过既有审核/撤回/重建流程处置,不得直接修改告警表伪造恢复。 只读健康核验: ```sql select status, operation, count(*) events, min(create_time) oldest from aihr_index_outbox group by status, operation order by status, operation; select lifecycle_status, index_status, count(*) assets from aihr_data_asset group by lifecycle_status, index_status order by lifecycle_status, index_status; select reason_code, gate_type, status, count(*) findings from aihr_quality_issue group by reason_code, gate_type, status order by reason_code, gate_type, status; select semantic_analysis_status, semantic_embedding_model, count(*) versions, max(semantic_retry_count) max_retries from aihr_data_version group by semantic_analysis_status, semantic_embedding_model order by semantic_analysis_status, semantic_embedding_model; select conflict_type, status, count(*) conflicts, min(create_time) oldest from aihr_claim_conflict group by conflict_type, status order by conflict_type, status; select alert_code, severity, status, occurrence_count, first_seen_time, last_seen_time from aihr_quality_alert order by status = 'OPEN' desc, severity, last_seen_time desc; select status, stage, processor_name, processor_version, count(*) runs, min(started_time) oldest, max(started_time) newest from aihr_pipeline_run group by status, stage, processor_name, processor_version order by status, stage, processor_name; ``` 生产查询必须同时满足当前租户/空间授权、资产 `PUBLISHED`、数据集成员 `ACTIVE` 和当前有效版本。历史纳管接口按 `afterAttachmentId` 游标读取附件;有当前租户可验证的 OSS 原件时重新执行解析、质量门禁和切片,无原件或原件不可读时创建 `QUARANTINED / SOURCE_UNAVAILABLE` 版本。不得通过现有 fragment 反向伪造原始来源,也不得自动批准历史资料。 新接入资料的原始 MinIO/OSS 对象、`parsed_content` 和 `normalized_content` 只作为受控审计证据保留。生产处理必须使用 `privacy-redaction-v1` 生成的独立脱敏派生版本;审核页通过 `GET /api/knowledge/quality/assets/{assetId}/privacy-preview` 只查看脱敏文件名、命中分类和脱敏正文预览。`privacy_status` 不是 `CLEAN/REDACTED`、缺少规则版本或派生正文时不得发布;`BLOCKED / PII_DETECTED` 必须修订来源并产生新版本,不能在发布时人工接受。 上线或批量纳管前先按租户核对隐私派生覆盖,不允许为历史版本直接回填一个“已通过”状态: ```sql select privacy_status, redaction_policy_version, count(*) versions from aihr_data_version group by privacy_status, redaction_policy_version order by privacy_status, redaction_policy_version; select count(*) unsafe_chunks from aihr_chunk_revision c join aihr_data_version v on v.id = c.version_id and v.tenant_id = c.tenant_id where v.privacy_status not in ('CLEAN', 'REDACTED') or v.redacted_content is null or v.redaction_policy_version is null; ``` 历史版本在迁移后保持 `NOT_PROCESSED`,必须从可验证原件重新解析、脱敏、复扫和人工审核。先用少量访谈材料验证规则,再批量纳管;不得在隐私派生完成前复制现有历史 fragment。 检索结果返回后仍必须在引用水合、引用详情、相邻片段和原件下载四个读取点分别复核当前版本、`PUBLISHED`、`HUMAN_VERIFIED`、`dataset_code=production`、成员 `ACTIVE` 和有效期。Qdrant payload、查询 filter、计数和显式重建使用同一组生产标签;没有这些标签的历史点不参与生产检索,也不计入生产向量一致性。管理端的“历史未纳管”及 `UNGOVERNED_LEGACY_FRAGMENTS` 是迁移待办,不是“一键重建”提示。 历史资料按以下批次执行,严禁全量自动批准: 1. 只读导出本批附件 manifest:租户、附件 ID、OSS ID、对象 hash、当前空间和处理状态,不导出业务正文到报告。 2. 调用 `/api/knowledge/quality/legacy/stage` 时使用 `afterAttachmentId` 和 20–50 的小批量;只从同租户 MinIO 原件重新解析。 3. `SOURCE_UNAVAILABLE`、解析损坏、PII、提示词注入、版本冲突和跨租户风险一律留在隔离区;不得从旧 fragment 补造原文。 4. 内容负责人逐份确认来源、版本、适用岗位/区域/项目、有效期和 reason code。AI 分析只能提供证据,不具有批准权限。 5. 每批批准后运行该空间标准题与无答案负例,核对引用、详情、下载和 Qdrant 生产点数,再开始下一批。 6. 旧的未标记向量点保留到批次 manifest、生产点和回归结果全部对账完成;清理必须使用独立授权和可回滚清单,不与重建动作混在一起。 推荐通过 CLI 执行。默认命令不调用写接口;提供 token 时会调用只读 `/legacy/preview` 返回本批原件可用/不可用数量,不提供 token 时只做离线参数校验。显式 `--execute` 时才会写入待审或隔离数据,token 不写 manifest。批次出现失败附件时游标保持不变,修复后可从 manifest 恢复: ```bash AIHR_LEGACY_TOKEN="$LOCAL_ADMIN_TOKEN" node scripts/stage-legacy-knowledge.mjs \ --base-url https://wygj-api.localhost \ --manifest tmp/legacy-knowledge-stage-manifest.json \ --batch-size 20 --max-batches 1 AIHR_LEGACY_TOKEN="$LOCAL_ADMIN_TOKEN" node scripts/stage-legacy-knowledge.mjs \ --execute --base-url https://wygj-api.localhost \ --manifest tmp/legacy-knowledge-stage-manifest.json \ --batch-size 20 --max-batches 1 ``` 黄金检索评测必须使用人工标注的业务数据集和本地登录令牌显式运行,脚本不会读取示例夹具作为正式验收结果,也不会输出令牌或问题正文: ```bash node scripts/evaluate-knowledge-quality.mjs \ --dataset tests/fixtures/data_quality/retrieval-golden.local.json \ --base-url https://wygj-api.localhost \ --token "$AIHR_EVAL_TOKEN" \ --k 5 \ --min-recall 0.90 \ --min-mrr 0.85 \ --min-ndcg 0.85 \ --max-leakage 0 \ --max-wrong-source 0.02 \ --max-no-answer-false-positive 0.05 ``` 验收至少核对 Recall@5、MRR、nDCG@5、禁止片段/来源泄漏率、错误来源率和无答案误召回率;任一显式门槛不通过时脚本退出码为 2。示例文件 `tests/fixtures/data_quality/retrieval-golden.example.json` 只定义格式;正式门槛必须使用 100–300 条经业务专家确认、覆盖多租户/版本/正反案例/无答案问题的黄金集标定。