feat: govern knowledge assets and source citations

This commit is contained in:
key
2026-08-02 01:43:43 +08:00
parent cafb836cda
commit 699cc08050
144 changed files with 17205 additions and 453 deletions
+74 -3
View File
@@ -26,7 +26,7 @@
| 资料处理 `/knowledge/processing` | `GET /api/knowledge/processing/overview`、`POST /api/knowledge/doc/upload-async`、`GET /api/knowledge/doc/upload-items`、`POST /api/knowledge/doc/upload-items/{id}/retry`、`POST /api/knowledge/doc/processing-tasks/{attachmentId}/retry` | 已接入解析任务状态聚合;页面只保留“批量导入”,接口暂存+入队即秒回,后台 worker(并发 2)逐条解析/归类/向量化;ZIP 在 worker 内安全解压后把支持的子文件继续入同一批次队列,页面按批次轮询进度。零片段媒体不再记为完成或永久“等待解析”,而是保留为可重试失败;管理端可从原 OSS 文件重新入队,无需用户重复上传;不提供浏览器目录选择或服务端目录导入入口 |
| 组织人员同步 | `POST /api/aihr/org/sync` | 从开放组织同步系统的 `/api/open/v1/sync/snapshot` 拉取 `company/department/employee/employee_project_assignment` 快照,分页参数使用 `limit`;员工手机号只落 `person_phone` 用于移动端身份映射,不在组织列表响应暴露;岗位识别 `position/job_title/post/job_name/role/title` 等字段。`dryRun` 必须显式传入 `true`(预检)或 `false`(写入),省略或传 `null` 直接拒绝;默认 `replaceExisting=true`,写入前必须先运行 `{"dryRun":true}`。dry-run 不访问本地快照表、不执行 DDL/写库,返回 `phoneLinked/maskedPhone/suspectText/warnings` 且 `syncedCount=0`。非 dry-run 写入(含 `replaceExisting=false`)遇到脱敏手机号一律默认拒绝,避免空值覆盖本地登录身份;覆盖写入遇到员工被跳过、手机号不完整、疑似乱码或同项目重复关系时同样默认拒绝;`allowPartialReplace=true` 只能在身份字段契约一致且异常逐项确认后使用,不能绕过主体身份漂移或重复成员关系,此时脱敏员工的本地既有有效手机号会被保留而非清空。相同员工可由多条有效项目分配展开为多个项目成员行,唯一约束为 `tenant_id + project_code + ext_party_id`。2026-07-25 生产安全状态:既有快照 3417 行、2938 人在职、3392 个手机号映射;姓名已按稳定 `employee_id` 定向补齐,未执行全量覆盖。当前上游返回 3424 名员工、3398 个脱敏手机号和 1 条重复项目成员关系,优先字段 `employee_number` 仅匹配既有主体 `7/3417`,稳定 `employee_id` 匹配 `3417/3417`;全量覆盖仍只允许 dry-run,日常岗位变化使用下方增量接口。 |
| 组织人员增量同步 | `POST /api/aihr/org/sync-changes` | 主动拉取上游 `/sync/changes?resource_type=employee`,即使事件没有进入 outbox、`changed_fields` 为空,也会按 `resource_id` 回源 `/employees/{id}`,并结合任职快照只替换受影响员工。主体固定使用稳定 `employee.id`;上游只返回脱敏手机号时保留本地既有有效手机号,上游显式清空手机号时同步清除本地值(对应移动端登录身份失效),手机号字段整体缺失则拒绝写入;范围字段明确不一致视为迁出,写入时删除该员工本地旧记录,范围字段缺失则保守跳过不删。任职快照失败、资源 ID 不一致或项目关系重复时拒绝写入。首次调用必须传 `sinceTime`,后续可传响应的 `nextCursor`;仍须先 `dryRun=true` 再以相同起点执行 `dryRun=false`,且只处理当前租户有效组织绑定范围。 |
| 移动端手机号登录 | `GET /resource/sms/code`、`POST /auth/mobile/sms-login` | 已复用 sms4j 阿里云配置 `config1` 和 RuoYi `sms` 授权策略;移动专用接口固定服务端默认租户,客户端不传也不能选择 `tenantId`;验证码按“默认租户 + 手机号”隔离。校验在手机号粒度的分布式锁内完成:仅匹配成功才消费,输错不会作废原验证码。移动端令牌只关联 `app_user`;若同一手机号存在任何后台/系统账号(即使同时存在 `app_user`),一律拒绝登录而不复用或并置身份;手机号完全不存在时才自动注册 `app_user`。`aihr.sms.dev-fixed-code` 非空时不真发短信、验证码固定(dev 默认 `123456`)。prod 默认关闭,试点期只有同时设置 `AIHR_SMS_DEV_FIXED_CODE` 与 `AIHR_SMS_PROD_FIXED_CODE_ENABLED=true` 才启用固定码。 |
| 移动端手机号登录 | `GET /resource/sms/code`、`POST /auth/mobile/sms-login` | 已复用 sms4j 阿里云配置 `config1` 和 RuoYi `sms` 授权策略;移动专用接口固定服务端默认租户,客户端不传也不能选择 `tenantId`。dev 默认 `aihr.sms.verification-enabled=false`,移动 APP 客户端可只提交手机号,便于本地自动化;只有同时设置后端 `AIHR_SMS_VERIFICATION_ENABLED=true` 与前端 `VITE_SMS_VERIFICATION_ENABLED=true` 才恢复验证码控件和校验。启用后,验证码按“默认租户 + 手机号”隔离,并在手机号粒度的分布式锁内完成校验:仅匹配成功才消费,输错不会作废原验证码。生产默认保持验证码校验开启。移动端令牌只关联 `app_user`;若同一手机号存在任何后台/系统账号,一律拒绝登录;手机号完全不存在时才自动注册 `app_user`。固定码仍仅用于显式开启验证后的联调;生产固定码必须同时设置 `AIHR_SMS_DEV_FIXED_CODE` 与 `AIHR_SMS_PROD_FIXED_CODE_ENABLED=true`。 |
| 用户侧三端首页 `mobile-uni` hash 路由;旧 `/h5/user`、`/h5/candidate`、`/h5/supervisor` 兼容重定向 | `GET /api/aihr/mobile/home/{role}` | 未登录请求只返回不读取租户业务统计的公开首屏 seed;已登录移动端请求自动携带 `Authorization/clientid`,才返回员工/主管真实统计;移动端本地 fallback 保演示 |
| 移动端登录后角色识别 | `GET /api/aihr/mobile/me` | 认证后仅以手机号精确查询 `person_phone`(`activeByMobilePhone`,不使用组织模糊搜索);`position_level` 为“主管/项目经理”时进入主管端,否则进入员工端。响应返回去重后的 `projects[]` 供页面按项目名称选择,不要求用户输入或记忆编码;同一人员在多个项目的快照行按 `tenant_id + project_code + ext_party_id` 保留。登录身份缺失、组织查询异常或没有有效在职主体时一律明确失败关闭,不再静默回退员工端。 |
| 移动端员工训练与主管复盘闭环 | 员工复用 `POST /api/train/practice/start`、`/turn`、`/finish`,查询 `GET /api/aihr/mobile/practice/history`、`/practice/mistakes`、`/profile`;训练完成后提交 `POST /api/aihr/mobile/practice/satisfaction`;主管查询 `GET /api/aihr/mobile/practice/team`、`/practice/alerts`、`/practice/reviews`、`/practice/reviews/{id}`,标记 `POST /api/aihr/mobile/practice/reviews/{id}/reviewed`,指派 `POST /api/aihr/mobile/practice/assignments` | 员工端登录后带 `Authorization` 与 `clientid` 调用;服务端固定身份和 `mode=mobile` 后才写入 `aihr_practice_session` 并进入员工/主管统计。员工历史、错题、画像、成长进度、晋升证据和满意度均只使用当前认证手机号经服务端验证得到的受控历史别名;后台内容/任务运营只通过独立 `/api/train/practice/**` 契约,不得向 `/api/aihr/mobile/**` 传入外部 ID 读取个人或主管数据。主管 `/practice/team` 的范围只含已验证外部 ID;历史训练或任务若存的是同一员工的旧手机号,只在该手机号能无碰撞规范化到团队外部 ID 时才展示/统计,避免把另一人的外部 ID 误并入团队。管理端 `mode=preview` 仅是运营调试记录,不能伪装成员工训练、满意度、复盘、成长或试点证据。满意度接口只接受本人已完成训练的 1-5 分,意见脱敏后落库,未填写不补默认值。错题本按员工本人聚合低分/红线回合,并关联已有 `retry` assignment,不伪造错题结论。主管 `/practice/team` 在同一项目权限范围内额外返回 `mistakes` 聚合,按场景/归因统计次数、影响人数、平均分和最近发生时间;普通员工返回“无主管权限”。主管接口以后端当前登录手机号先解析为在职组织外部 ID,仅允许岗位为“主管/项目经理”的账号,并按租户和项目范围返回真实成员、全状态训练记录及非 daily 专项。复盘标记只允许首次 `待复盘 -> 已复盘` 创建后续专项,并发重复提交幂等;可带 `incentivePoint` 写入贡献度。每日三题正式只对 `hire_date` 在当前日期前三个月内的在职员工派发,且只会从已发布、已启用、风险审核完成的同岗位场景题库取题;选择时优先补最低未覆盖的成长层/能力项,仅作为训练推荐,不自动调整职级或形成硬性解锁。没有入职日期时不使用训练次数推断,开发 Demo 的旧回退只有在 `dev/local` profile 且由 `aihr.practice.allow-legacy-daily-drill-fallback` 显式开启时生效,生产 profile 强制关闭。 |
@@ -93,7 +93,7 @@ curl -fsS -X POST "$API_BASE/api/aihr/agent/actions/<draftId>/dismiss" \
当前管理端 AI 面试和案例沉淀已改为真实模型/ASR 优先;移动端首页和部分演示态数据仍保留 fallback。知识库、模型能力、文档解析、RAG、chat 按 [ruoyi-ai 能力分片迁移计划](RUOYI_AI_INCREMENTAL_MIGRATION.md) 逐片引入;知识库 DDL 与住宅类 SOP seed 在 `backend/script/sql/aihr_knowledge_mysql8.sql`,模型 DDL 在 `backend/script/sql/aihr_model_mysql8.sql`,训练记录 DDL 在 `backend/script/sql/aihr_practice_mysql8.sql`,AI 面试结果 DDL 在 `backend/script/sql/aihr_interview_result_mysql8.sql`,候选人资料 DDL 在 `backend/script/sql/aihr_candidate_material_mysql8.sql`,组织人员快照表在 `backend/script/sql/aihr_org_snapshot_mysql8.sql`,本地 reset 带 2 个住宅项目 22 人 seed;配置开放组织同步系统后用 `POST /api/aihr/org/sync` 覆盖为外部快照。
直接打后端 `/api/**` 通常需要登录后的 `Authorization: Bearer <access_token>`;浏览器内通过已登录前端和 `/dev-api` 代理访问。移动端登录接口为 `POST /auth/mobile/sms-login`,请求 `{ phonenumber, smsCode }`,内部固定使用 app 客户端 `428a8310cd442757ae699df5d894f051` 和 `sms` grant;验证码通过后若手机号不存在,会创建 `app_user`,用户名为手机号,备注为“移动端短信自动注册”。移动端首页接口 `GET /api/aihr/mobile/home/{role}` 仍保留 `@SaIgnore` 以保证真正未登录的首屏可用,匿名分支只返回不读取业务统计的公开数据;已登录请求必须是有效 `app_user`,并按认证手机号校验员工/主管身份后返回真实统计。已登录但身份缺失、后台账号误用、组织查询失败或客户端收到未知角色时均明确失败关闭,不得静默回到公开数据、默认员工端或旧岗位缓存。
直接打后端 `/api/**` 通常需要登录后的 `Authorization: Bearer <access_token>`;浏览器内通过已登录前端和 `/dev-api` 代理访问。移动端登录接口为 `POST /auth/mobile/sms-login`,dev 默认请求 `{ phonenumber }`,显式开启验证码后请求 `{ phonenumber, smsCode }`;内部固定使用 app 客户端 `428a8310cd442757ae699df5d894f051` 和 `sms` grant。手机号不存在时会创建 `app_user`,用户名为手机号,备注为“移动端短信自动注册”。移动端首页接口 `GET /api/aihr/mobile/home/{role}` 仍保留 `@SaIgnore` 以保证真正未登录的首屏可用,匿名分支只返回不读取业务统计的公开数据;已登录请求必须是有效 `app_user`,并按认证手机号校验员工/主管身份后返回真实统计。已登录但身份缺失、后台账号误用、组织查询失败或客户端收到未知角色时均明确失败关闭,不得静默回到公开数据、默认员工端或旧岗位缓存。
阿里云短信复用 RuoYi 的 `sms.blends.config1`。本地开发把真实短信参数放根目录 `.env.local` 或外部环境变量,`scripts/dev-backend.sh` 会自动加载;`application-dev.yml` / `application-prod.yml` 只保留占位,不写真实密钥。
@@ -114,6 +114,8 @@ ALIYUN_SMS_SIGN_NAME=物业AI助手
SOP 文档上传第三片已经落最小后端边界:
> 说明(2026-08-01):下表中仍保留的“直接写入 `aihr_knowledge_fragment`/机会性向量化”是历史兼容实现说明,不代表经过质量批准。批量资料和视频必须使用 `POST /api/knowledge/doc/upload-async`,先进入不可变候选 asset/version/chunk revision 和 `REVIEW_PENDING/QUARANTINED`;只有人工发布后才投影到生产 fragment、数据集成员和 Qdrant outbox。同步 `POST /api/knowledge/doc/upload` 仅供 SOP 单文件即时预览,不得作为批量生产导入入口。新代码或运维脚本不得绕过 `/api/knowledge/quality/assets/{assetId}/publish`。
| 能力 | 后端接口 | 处理 |
|---|---|---|
| 文档上传解析 | `POST /api/knowledge/doc/upload` | `multipart/form-data`,字段 `file` 和 `category`;支持 `.txt/.md/.markdown/.pdf/.doc/.docx/.xls/.xlsx/.ppt/.pptx` 及图片 `.jpg/.jpeg/.png/.gif/.webp/.bmp`、100MB 内;先写 `sys_oss`,再绑定 `aihr_knowledge_attach.oss_id` 并切分写入 `aihr_knowledge_fragment`;管理端该接口 timeout 为 180s,避免 PDF 同步解析/归类/向量化接近默认 50s 时被客户端断开 |
@@ -252,6 +254,75 @@ curl -fsS -X POST "$API_BASE/api/knowledge/doc/rebuild-vector-index" -H "Authori
浏览器验收仍按 [DEMO_ACCEPTANCE.md](DEMO_ACCEPTANCE.md) 的四条关键路径执行。
## 知识数据质量准入
文件上传、个人经验转企业知识和 AI 整理案例都先进入候选版本,不直接写入生产检索。质量审核接口仅允许当前租户的 `superadmin` 或 `hr_operator` 调用,租户上下文和审核人均从登录态取得,不接受请求体指定。
```http
GET /api/knowledge/quality/assets?status=REVIEW_PENDING&limit=50
GET /api/knowledge/quality/assets/{assetId}/issues
GET /api/knowledge/quality/assets/{assetId}/conflicts
GET /api/knowledge/quality/index-health
GET /api/knowledge/quality/metrics
GET /api/knowledge/quality/alerts?includeResolved=false&limit=100
GET /api/knowledge/quality/glossary?status=ACTIVE&limit=100
POST /api/knowledge/quality/glossary
POST /api/knowledge/quality/glossary/{id}/approve
POST /api/knowledge/quality/glossary/{id}/reject
POST /api/knowledge/quality/glossary/{id}/deprecate
GET /api/knowledge/quality/rules?status=SHADOW&limit=100
POST /api/knowledge/quality/rules
POST /api/knowledge/quality/rules/{ruleId}/status
POST /api/knowledge/quality/rules/{ruleId}/evaluations
GET /api/knowledge/quality/rules/{ruleId}/metrics
POST /api/knowledge/quality/rules/{ruleId}/samples
GET /api/knowledge/quality/rules/{ruleId}/samples?status=PENDING&limit=100
POST /api/knowledge/quality/rules/samples/{sampleId}/review
POST /api/knowledge/quality/rules/samples/schedule?limit=200
GET /api/knowledge/quality/pipeline-runs?status=ALL&limit=100
POST /api/knowledge/quality/pipeline-runs
POST /api/knowledge/quality/pipeline-runs/{runId}/finish
GET /api/knowledge/quality/golden-datasets?status=DRAFT&limit=100
POST /api/knowledge/quality/golden-datasets
GET /api/knowledge/quality/golden-datasets/{datasetId}/samples?limit=200
POST /api/knowledge/quality/golden-datasets/{datasetId}/samples
POST /api/knowledge/quality/golden-datasets/{datasetId}/freeze
GET /api/knowledge/quality/rules/{ruleId}/acceptance-profiles
POST /api/knowledge/quality/rules/{ruleId}/acceptance-profiles
POST /api/knowledge/quality/rules/{ruleId}/acceptance-profiles/{profileId}/freeze
GET /api/knowledge/quality/rules/{ruleId}/readiness
POST /api/knowledge/quality/conflicts/{conflictId}/review
GET /api/knowledge/quality/assets/{assetId}/privacy-preview
POST /api/knowledge/quality/assets/{assetId}/publish
POST /api/knowledge/quality/assets/{assetId}/withdraw
GET /api/knowledge/quality/legacy/preview?afterAttachmentId=0&limit=50
POST /api/knowledge/quality/legacy/stage?afterAttachmentId=0&limit=50
```
`publish` 必须带人工审核意见、用途、来源权威级别和来源版本。请求中的 `acceptedReasonCodes` 只能确认当前版本仍开放的软提示,服务端会再次统计开放问题,遗漏任何一项都拒绝发布;`HARD` 问题不能在发布动作中接受,必须修订原资料并生成新版本,或通过后续独立的显式纠错流程解决。规范性知识仅接受 `FORMAL_POLICY / COMPANY_POLICY / REGULATION / APPROVED_SOP` 且版本非空;同名已发布资料内容变化会产生 `VERSION_CONFLICT`,规范性知识必须再传 `supersedesAssetId`,服务端验证同租户、同来源名和旧资产仍已发布后,在同一事务内撤回旧版本并发布新版本。
规范化采用版本化的 NFKC、换行、控制字符和空白处理;解析正文和规范化正文作为不可变审计证据保留,不作为下游生产内容。`privacy-redaction-v1` 从规范化正文生成独立的 `redacted_content/redacted_source_name`,记录派生 hash、分类计数、隐私状态和规则版本,并对派生正文及全部派生 chunk 复扫。只有 `CLEAN/REDACTED` 派生版本参与结构化切片、异步语义分析、模型调用、发布和检索;重复文件复用的历史摘要、模型新生成的摘要/标签/归类理由以及上传 snippet 也必须在返回或保存前走同一脱敏规则,不能因 OSS 对象复用而绕过。残留敏感模式写入 `BLOCKED / PII_DETECTED` 并拒绝发布,已完成替换写入 `PII_REDACTED` 证据。`GET /assets/{assetId}/privacy-preview` 只返回脱敏文件名、分类计数和截断后的脱敏正文,不返回原始正文。
按标题、段落、Q&A 与 SOP 步骤切片,只有超长结构块使用 overlap。处理结果只写新版本,不覆盖 raw;`aihr_data_version` 保存 SimHash、结构画像、extractor 和规则版本。精确重复、近重复、语义重复和版本冲突只产生 reason code 与候选关系,不由算法自动删除、批准或合并。语义分析在接入事务外异步执行;PII、提示词注入或已隔离内容不发送到外部 embedding。租户未配置可用向量模型时使用本地 hash 向量,并写入 `SEMANTIC_ANALYSIS_DEGRADED`,不得冒充完整语义检测;状态未达到 `COMPLETE/NOT_REQUIRED` 时发布失败。
制度与专家材料由确定性规则提取 claim 候选,只比较同租户已发布 claim,正反约束或数值不一致写入 `EXPERT_CONFLICT` 和 `aihr_claim_conflict`。审核人通过 `/conflicts/{conflictId}/review` 明确提交 `CONFIRMED/FALSE_POSITIVE/RESOLVED` 及依据;`PENDING_REVIEW/CONFIRMED` 冲突存在时后端拒绝发布。算法和 LLM 均不能自行裁决适用范围、权威来源或替代关系。
发布后才创建 `aihr_knowledge_fragment`、生产数据集成员和向量 outbox;撤回会在同一数据库事务中先删除 MySQL 生产片段、停用数据集成员,再排队删除 Qdrant 文档。向量失败不恢复 MySQL 可检索性。outbox 最多自动尝试 8 次,之后进入 `DEAD_LETTER`;`index-health` 返回待处理、重试、死信数量和最老事件时间,运营必须处理死信而不能把数据库 `PUBLISHED/DEPRECATED` 状态改回去掩盖漂移。每次查询的召回证据写入 `aihr_query_evidence`,记录实际 rank、score、`FULLTEXT/KEYWORD/VECTOR/HYBRID_RRF` 通道和 used 标记,可反查 chunk revision、数据版本、资产、原附件和 OSS 对象。
`legacy/preview` 只读返回下一批 `discovered/sourceAvailable/sourceUnavailable/nextCursor/moreAvailable`,不读取对象正文、不写治理表或索引。`legacy/stage` 按附件 ID 游标小批次纳管历史资料:存在当前租户可验证的 OSS 原件时,服务端从 MinIO 下载到受限临时文件,重新执行解析、质量门禁和切片;没有原件或原件不可读取时,创建 `QUARANTINED / SOURCE_UNAVAILABLE` 的不可变版本。写接口返回 `discovered/staged/reparsed/quarantined/failedAttachmentIds/nextCursor/moreAvailable`。它不从既有 fragment 反向伪造原始来源、不自动批准、不覆盖 MinIO;失败 ID 必须显式复核或从该 ID 前重新运行,只有人工确认来源、版本和适用范围后才能发布。
术语表采用不可变修订:创建接口只产生 `DRAFT`,只有人工 `approve` 后的 `ACTIVE` 版本参与同租户、项目和角色范围内的召回查询扩展;批准新版本会失效同一术语的旧活动版本。当前认证上下文没有可靠区域字段,带 `applicableRegion` 的词条 fail-closed,不参与扩展。`definition` 不进入模型事实上下文,`deprecate` 后立即停止扩展。对应迁移为 `aihr_20260809_knowledge_glossary_mysql8.sql`。AI 整理案例永久保留 synthetic、生成器/模型、prompt、原始音频 OSS、摘要 hash 和人工审核信息,对应迁移为 `aihr_20260810_case_provenance_mysql8.sql`;人工通过不改变其合成身份。
员工“没解决”反馈可携带本轮知识查询 `requestId`。服务端只接受该请求实际召回且属于当前租户的 fragment,创建 `DOWNSTREAM_ANSWER_DISPUTED` 再审问题,不自动撤回资料。后台复核接口 `POST /api/knowledge/answer-feedback/{id}/review` 只接受 `{action: "KEEP"|"WITHDRAW", note: "..."}`:`KEEP` 将争议标为误报并保留资料,`WITHDRAW` 必须由已认证审核人填写理由并调用统一生命周期撤回,随后触发向量 DELETE outbox。
质量监控由 `AihrKnowledgeQualityMonitoringService` 按租户定时扫描。`metrics` 返回资产生命周期、开放问题、待裁决重复/冲突、24 小时查询证据覆盖率、生产来源可追溯率和索引一致性;`alerts` 返回稳定 reason code、严重级别、首次/最近发生时间、累计次数、证据和解决状态。监控只报警和自动关闭已恢复告警,不批准、发布、合并、替代或删除资产。Actuator 健康组件名为 `aihrKnowledgeQuality`;迁移未执行时返回 `UNKNOWN`,存在生产血缘缺口、索引漂移、死信、过期发布资产或查询证据缺口时返回 `DOWN`。对应新增表迁移为 `backend/script/sql/update/aihr_20260808_data_quality_monitoring_mysql8.sql`。
规则演进第一批接口只保存版本化规则草稿、人工/黄金集期望与影子结果的对照、误放行/误隔离指标以及风险抽样复核。规则动作只允许 `FLAG/REVIEW/QUARANTINE`,不允许批准、发布或删除;服务端只允许 `DRAFT -> SHADOW -> PAUSED/RETIRED` 及 `PAUSED -> SHADOW/RETIRED`,在独立自动执行安全门、真实黄金集和灰度回滚能力完成前拒绝进入 `CANARY/ACTIVE`。影子评估和抽样结果不修改 `aihr_data_asset`、质量问题、审核决定或索引。对应迁移为 `backend/script/sql/update/aihr_20260811_rule_evolution_mysql8.sql`。
规则演进第二批新增 `aihr_pipeline_run` 和影子评估自动抽样。`pipeline-runs` 保存同租户的阶段、处理器及版本、输入/输出版本、触发方式、指标、错误和起止时间;完成状态只允许 `SUCCEEDED/FAILED/CANCELLED`,不能把 `PUBLISHED` 伪装成处理结果。定时任务及 `/rules/samples/schedule` 只读取仍处于 `SHADOW` 的评估:误放行/误隔离 100% 进入待复核,其余按 `CRITICAL=100% / HIGH=50% / MEDIUM=20% / LOW=10%` 做稳定哈希抽样,唯一键保证重复调度幂等。自动抽样只创建 `PENDING` 样本和运行证据,`assetMutationCount` 固定为 0;它不修改资产、问题、审核、发布或索引。管理端资料处理页只开放草稿、影子、暂停、退役和人工样本复核,不提供 `CANARY/ACTIVE`。对应迁移为 `backend/script/sql/update/aihr_20260812_pipeline_run_sampling_mysql8.sql`。
规则演进第三批新增版本化黄金集和风险验收门槛。黄金集先创建 `DRAFT`,只能由登录后台人员逐条写入稳定样本键、风险、期望决定、reason code 和人工证据;冻结时生成 SHA-256 内容哈希,此后不可修改,修订必须新建版本。`expectedSource=GOLDEN` 的影子评估必须引用当前租户已冻结的 `goldenSampleId`,期望决定、样本身份和资产版本由服务端从冻结样本加载,客户端不能自称黄金标签。每个规则版本可建立并人工冻结一份风险门槛,`readiness` 分别检查总样本、黄金样本、人工复核、一致率、误放行、误隔离、复核覆盖和待复核差异,返回稳定原因码;`enforcementEnabled` 固定为 `false`,证据就绪不等于允许 `CANARY/ACTIVE`。对应迁移为 `backend/script/sql/update/aihr_20260813_golden_calibration_mysql8.sql`。
## 多租户知识空间统一问答
内部员工端、主管端和管理端统一调用:
@@ -287,7 +358,7 @@ Content-Type: application/json
成功响应包含 `requestId`、`answer`、`citations`、`usedSpaceCodes`、`noEvidence` 和兼容 `legacy` 数据。引用携带 `spaceCode/sourceType/docId/title/snippet/fragmentId`;客户端不得把无引用回答包装成有知识依据的正式答案。
空间、空间内分类、授权和应用管理接口统一位于 `/api/knowledge/admin`:`spaces`、`spaces/{id}/categories`、`spaces/{id}/documents`、`spaces/{id}/documents/{attachId}/category`、`spaces/{id}/grants`、`apps`、`apps/{id}/spaces`、`apps/{id}/rotate-token`。分类仅在当前有效租户和当前知识空间内维护;停用分类不能继续归类,删除前必须先移走其知识,分类不会扩大空间授权或调用应用的检索范围。`DELETE /spaces/{id}/documents/{attachId}` 只解绑当前空间成员;其他空间仍引用同一 OSS 时原文件不会删除。仅知识平台管理角色可调用,API_TOKEN 创建或轮换后只返回一次明文。超级管理员由“租户管理”进入知识维护时,通过 `GET /system/tenant/dynamic/{tenantId}` 设置服务端动态租户,再由 `GET /system/tenant/dynamic` 回读当前上下文;仅正常状态的已存在租户允许切换。动态租户按当前 Sa-Token 与浏览器页面生成的匿名上下文共同隔离,客户端每次请求回传页面上下文及当前展示租户;两者与服务端不一致时服务端返回 `409` 并拒绝读写,避免多标签页误写。知识平台不接受客户端传入的 `tenantId` 来选租户。完整初始化、令牌保管、legacy 迁移与回滚步骤见 [KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md)。
空间、空间内分类、授权和应用管理接口统一位于 `/api/knowledge/admin`:`spaces`、`spaces/{id}/categories`、`spaces/{id}/documents`、`spaces/{id}/documents/{attachId}/category`、`spaces/{id}/grants`、`apps`、`apps/{id}/spaces`、`apps/{id}/rotate-token`。分类仅在当前有效租户和当前知识空间内维护;停用分类不能继续归类,删除前必须先移走其知识,分类不会扩大空间授权或调用应用的检索范围。`DELETE /spaces/{id}/documents/{attachId}` 只解绑当前空间成员;若该成员对应已批准或已发布的治理资产,服务端会先以当前人工操作人执行统一 `WITHDRAW`,立即切断 MySQL 生产可见性并通过 outbox 删除向量。其他空间或治理资产仍引用同一 OSS 时原文件不会删除,引用核验失败时也必须保留原件。仅知识平台管理角色可调用,API_TOKEN 创建或轮换后只返回一次明文。超级管理员由“租户管理”进入知识维护时,通过 `GET /system/tenant/dynamic/{tenantId}` 设置服务端动态租户,再由 `GET /system/tenant/dynamic` 回读当前上下文;仅正常状态的已存在租户允许切换。动态租户按当前 Sa-Token 与浏览器页面生成的匿名上下文共同隔离,客户端每次请求回传页面上下文及当前展示租户;两者与服务端不一致时服务端返回 `409` 并拒绝读写,避免多标签页误写。知识平台不接受客户端传入的 `tenantId` 来选租户。完整初始化、令牌保管、legacy 迁移与回滚步骤见 [KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md)。
## 工作助手确认式统一采集
+19
View File
@@ -147,9 +147,28 @@ mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aih
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260725_deepseek_v4_model_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260729_media_reprocess_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260731_knowledge_fragment_locator_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260801_data_quality_lifecycle_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260802_data_quality_observability_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260803_data_quality_structure_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260804_data_quality_feedback_loop_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260805_knowledge_attachment_immutability_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260806_data_quality_extraction_evidence_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260807_data_quality_semantic_conflict_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260808_data_quality_monitoring_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260809_knowledge_glossary_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260810_case_provenance_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260811_rule_evolution_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260812_pipeline_run_sampling_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260813_golden_calibration_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260814_knowledge_privacy_derivative_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/aihr_personal_knowledge_mysql8.sql
```
七个数据质量迁移必须按 `20260801 -> 20260802 -> 20260803 -> 20260804 -> 20260805 -> 20260806 -> 20260807` 顺序执行:生命周期迁移创建不可变资产/版本/质量问题/审核/数据集/血缘/outbox;可观测性迁移增加 outbox 死信和查询证据;结构迁移增加 SimHash、结构画像、extractor 版本与近重复聚类;反馈闭环迁移把答案反馈绑定到查询请求和质量问题,并记录 `KEEP/WITHDRAW` 人工结论;附件不可变迁移取消“知识空间内文件名唯一”的覆盖语义;解析证据迁移保存页数、逐页 OCR 可读性和提取器版本;语义与冲突迁移增加异步分析状态、可审计重复关系、claim/观点及冲突关系。同名或精确重复上传可共享只读 OSS 对象,但必须创建新的附件、候选资产和审核记录,不能改写旧附件的 `oss_id/doc_id`。所有算法只创建待审证据,不能自动批准、合并、替代或删除资料;执行 schema 不等于历史资料已获批准。
随后按 `20260808 -> 20260809 -> 20260810 -> 20260811 -> 20260812 -> 20260813 -> 20260814` 执行质量监控、人工术语修订、AI 案例来源、规则演进、处理批次、黄金集校准和隐私派生迁移。`20260811` 只增加规则草稿、状态审计、影子对照和抽样复核;`20260812` 只增加 `pipeline_run` 与自动生成待人工复核样本的调度,不启用规则执法,不改变任何资产生命周期。`20260814` 只增加独立脱敏正文、脱敏文件名、派生 hash、隐私状态、规则版本和复扫摘要字段,历史版本默认保持 `NOT_PROCESSED`,不得通过 SQL 伪造脱敏完成或自动获批。完整迁移后仍须最后执行排序规则兼容迁移。
8 月 1 日受控内部试点的正式来源注册是独立的业务数据变更,不随通用 schema 自动执行。先逐一核对附件 `id + doc_id`、原文件 SHA-256、发文号/版本、生效日期和适用范围,再由已授权负责人执行 `backend/script/sql/ops/aihr_20260730_aug1_formal_source_registry_mysql8.sql`。执行后必须只读确认恰好 10 条 `FORMAL_POLICY + APPROVED` 记录;任何缺失都保持无正式依据,不得把访谈、经验萃取、AI 生成内容或草稿补进白名单。
顺序原因:场景补充依赖三张场景/Rubric 基础表;五维迁移依赖场景和 Rubric;五岗位题库之后的内容运营迁移为每个场景补齐唯一的初始 Rubric、五个稳定评分维度与训练时评分规则快照列,并只修正仍处于待训练状态的旧每日题场景编号,不重写已完成记录。紧随其后的成长目录迁移只在既有场景和会话表上增加岗位/层级/能力项/审核状态与会话快照,以及复盘会话专用的 `growth_confirmation_level/growth_confirmed_by/growth_confirmed_time`;它只允许记录主管对当前会话下一训练层级的确认,不改写原训练快照或人事结论,并补齐/修复派发请求的 `(tenant_id,request_key,ext_party_id)` 唯一键与最近内容过滤索引。它保留既有启停可用性和历史会话,不把迁移结果写成业务内容签字。生产环境不得设置 `AIHR_PRACTICE_RUNTIME_SCHEMA_BOOTSTRAP=true`:应用请求只读校验表、列和关键索引,任何缺失都必须先执行本节正式 SQL,不能由任一用户请求触发补列、补索引或状态回填。岗位/SOP/任务/资格迁移只补正式数据契约,不写业务行,也不代表岗位适用范围、任务规则或资格标准已经获得 HR 确认。住宅 SOP 和 Prompt 迁移只补内置内容,不代表内容已完成业务复核。知识会话迁移只新增短期上下文表,不生成业务对话。排序规则兼容迁移先对齐本批发布表,全量排序规则迁移再统一历史 `aihr_*` 表;两者都读取目标库 `aihr_knowledge_info.tenant_id` 的实际排序规则。服务记忆迁移创建候选、统一采集、兼容项目记录和版本留痕四张表;工作上报幂等迁移随后只补原表列与唯一索引;知识分类迁移新增空间内分类表及附件成员的可空 `category_id`,不迁移、删除或扩大任何空间授权与检索范围;正式知识来源治理迁移只创建附件级权威类型、生命周期、版本、生效期、适用范围和原文件哈希契约,不自动批准任何历史附件。移动端政策问答只使用有效的 `FORMAL_POLICY + APPROVED` 注册项,治理表缺失、来源未批准、已失效、版本或哈希为空时均按无正式依据关闭。银城大喇叭 M0 迁移创建消息、阅读和不可变 v1 快照三表,为已存在消息补一次快照,并补发布请求键/载荷哈希、撤回原因及 `(tenant_id,published_by,publish_request_key)` 唯一约束。紧接着 M1 定向迁移补充必读与目标载荷字段,以及规则快照、命中对象快照两表;它只决定提醒/必读对象,不改变全租户公开频道的可见性。直通车迁移创建点对点反馈表,并给正式租户 `000000` 幂等预置总裁、财务、人力、审计、运营五个处理角色;人员仍须由管理员按职责分配,业务匿名不抹除内部审计身份。公司文件迁移创建异步提炼表并给消息增加可空 `attachment_id`,不迁移或公开已有文件;紧随其后的多岗位解读迁移只在附件表增加生成状态、经引用校验的结构化结果和规则版本,并建立异步队列索引,不回填旧文件、不改变文件 READY 或消息发布状态。随后,消息追问迁移只给短期会话增加可空 `broadcast_message_id`;它不保存消息正文,并用于约束同一会话不能切换公司消息。历史普通会话保持 `NULL`。Agent 迁移只新增最小运行审计表,不保存问题、答案、密钥或模型推理。个人资料迁移最后创建独立 `aihr_personal_*` 表,并从当前租户既有 MinIO 配置派生私有 `personal-minio` 配置;`ruoyi-personal` bucket 必须由受控运维流程创建和验证,不能在文档或日志中输出访问密钥。它们同样对齐目标排序规则,兼容历史生产库与全新 MySQL 8 数据库。
+7 -7
View File
@@ -40,7 +40,7 @@ portless run --name wygj-api ./scripts/dev-backend.sh
Windows 10/11 + Docker Desktop 不要从 PowerShell 直接执行 `./scripts/dev.sh`:Windows 的 `bash` 可能解析到 WSL,而 WSL 的 Node、Docker 集成和检出文件换行符未必满足脚本要求。使用本文件的 [Windows 10/11 + Docker Desktop](#windows-docker-desktop) 流程。
本地启动默认关闭管理端图形验证码;需要专门验证验证码链路时设置 `AIHR_DEV_CAPTCHA_ENABLED=true`。生产启动不使用该开发开关,验证码保持开启。
本地启动默认关闭管理端图形验证码和移动端短信验证码校验;移动端开发页只需输入手机号并同意协议即可登录,无需请求验证码。需要专门验证验证码链路时,后端设置 `AIHR_DEV_CAPTCHA_ENABLED=true`、`AIHR_SMS_VERIFICATION_ENABLED=true`,移动端同时设置 `VITE_SMS_VERIFICATION_ENABLED=true`。生产不复用本地免验证码设置,短信校验默认保持开启。
重复启动或切换分支时优先使用 `./scripts/dev.sh restart`,停止使用 `./scripts/dev.sh stop`。脚本会递归终止 portless 包装进程及其 Java/Vite 子进程,避免旧后端脱离后继续占用 MySQL 连接池;进程树回归可用 `bash scripts/tests/process-tree.test.sh` 验证。
@@ -65,7 +65,7 @@ AIHR_SMS_LOGIN_TEMPLATE_ID=SMS_xxxxxx
ALIYUN_SMS_ACCESS_KEY_ID=xxx
ALIYUN_SMS_ACCESS_KEY_SECRET=xxx
ALIYUN_SMS_SIGN_NAME=物业AI助手
# 演示兜底:非空则不真发短信,验证码固定为该值;dev 默认 123456
# 仅在显式开启短信校验时使用:非空则不真发短信,验证码固定为该值
AIHR_SMS_DEV_FIXED_CODE=123456
# prod 默认 false;试点期仅在明确接受固定码风险时与上一项同时开启
AIHR_SMS_PROD_FIXED_CODE_ENABLED=false
@@ -85,7 +85,7 @@ AIHR_AI_SPEECH_ENABLED=true
全网检索访问密钥使用数据库表 `aihr_web_ai_secret` 中自动生成的主密钥加密,不依赖环境变量,也不通过通用参数接口回显。数据库迁移、备份和恢复必须同时保留该表;丢失或修改主密钥后需要重新保存提供方密钥。全网检索提供方只接受公网 HTTPS 地址,且每次修改地址或密钥后都必须重新连接测试,测试成功后才能启用。
`application-dev.yml` 只保留占位和默认值,不提交真实短信密钥。dev 环境不配阿里云短信也能登录移动端:验证码固定 `123456`。
`application-dev.yml` 只保留占位和默认值,不提交真实短信密钥。dev 默认关闭短信验证码校验;显式开启校验但不配阿里云短信时,可继续使用固定验证码 `123456`。
<a id="windows-docker-desktop"></a>
@@ -148,7 +148,7 @@ npm --prefix mobile-uni ci
docker compose -f docker-compose.dev.yml up -d mysql redis qdrant minio minio-init
```
基础开发不要求 `.env.local`:dev 短信验证码默认固定为 `123456`,模型调用失败仍保留 seed fallback。真实短信、外部组织同步或外部 AI 模型联调时,再按前文示例创建被 Git 忽略的 `.env.local`。
基础开发不要求 `.env.local`:dev 默认免短信验证码,模型调用失败仍保留 seed fallback。需要验证码、真实短信、外部组织同步或外部 AI 模型联调时,再按前文示例创建被 Git 忽略的 `.env.local`。
### 3. 启动后端
@@ -263,7 +263,7 @@ docker compose -f docker-compose.dev.yml stop
- AIHR 真跑测试必须显式关闭父 POM 的默认跳测:`mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am -DskipTests=false test`;普通 `mvn ... test` 只适合编译/打包检查。
- 前端依赖已安装,Vite 已通过 portless 暴露为 `https://wygj-admin.localhost/`
- 当前用户侧由 `./scripts/dev.sh` 通过 portless 启动 `mobile-uni`,入口 `https://wygj-mobile-uni.localhost/h5/`;旧移动端兜底仅在 `PORTLESS=0` 调试时启动到 `5174`
- 移动端手机号登录页已接 `/resource/sms/code` 与 `/auth/mobile/sms-login`;未配置真实 `ALIYUN_SMS_ACCESS_KEY_ID`、`ALIYUN_SMS_ACCESS_KEY_SECRET`、`ALIYUN_SMS_SIGN_NAME`、`AIHR_SMS_LOGIN_TEMPLATE_ID` 时不会发送阿里云短信;手机号不存在时会自动注册为 `app_user`
- 移动端手机号登录页已接 `/resource/sms/code` 与 `/auth/mobile/sms-login`;dev 默认隐藏验证码控件并跳过短信校验,手机号不存在时会自动注册为 `app_user`。显式开启验证码后,未配置真实 `ALIYUN_SMS_ACCESS_KEY_ID`、`ALIYUN_SMS_ACCESS_KEY_SECRET`、`ALIYUN_SMS_SIGN_NAME`、`AIHR_SMS_LOGIN_TEMPLATE_ID` 时不会发送阿里云短信
- 移动端员工端“开始训练”已复用 `/api/train/practice/start`、`/turn`、`/finish`;移动端请求需带登录返回的 `Authorization` 与 `clientid`,服务端会强制当前 APP 身份和 `mode=mobile`,完成后才会改变主管端完训人数、“待复盘对练”计数、复盘列表、复盘详情、员工训练历史和能力画像。管理端训练看板的同一路径只允许 `superadmin/hr_operator` 做服务端绑定的 `mode=preview` 运营预览;预览不会冒用员工身份,也不计入上述统计、复盘或试点。
- 移动端候选人端“开始面试/面试练习”已复用 `/api/recruit/interview/start`、`/answer`、`/finish`;“补充资料”需带移动端 `Authorization` 与 `clientid`,上传后写 `sys_oss` 和 `aihr_candidate_material`,管理端 `/recruit/interview` 可审核为 `已通过/已驳回`
- `/dev-api/auth/tenant/list` 与 `/dev-api/auth/code` 已通过前端代理返回 `200`
@@ -405,12 +405,12 @@ Android 人工验收每完成一个步骤,用 `.\scripts\capture-android-accep
- 案例沉淀:进入 `/knowledge/cases`,上传真实语音 → “AI 整理” → “送审” → “入库”,应看到“已完成闭环”和新增案例记录;上传必须先完成 ASR 转写。
- SOP知识库:进入 `/knowledge/sop`,可上传 txt/md/PDF/Word/Excel/PPT 文档入库;点击“检索” → “生成训练题”,应看到“已完成闭环”、命中数据库 SOP 原文片段和训练题;数据库不可用时页面回退 seed。
- 资料处理:进入 `/knowledge/processing`,应看到资料总量、解析任务表、处理链路、规则与风险;页面只保留“批量导入”和“刷新”,不应出现“选择目录”“服务端导入”或目录导入任务面板。**批量导入走异步队列**:提交即返回,页面出现“本次批量上传”进度面板(排队/加工中/完成/失败 + 单条重试),后台 worker 并发 2 逐条解析入库;支持多文件和 ZIP,暂存目录默认 `./.data/staging`(`aihr.upload.staging` 覆盖)。
- uni-app 员工端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/user/today/index`,手机号登录(dev 验证码固定 `123456`)。今日页进入问师傅、练习、案例素材和个人页;练习页应能完成开始练习、提交回应、结束评分、每日三题提交,个人页同步训练历史和成长证据包。每日三题正式按组织快照 `hire_date` 判断入职三个月窗口;本地 Demo 若快照尚无该字段,仅由 `dev/local` profile 且 `application-dev.yml` 的 `aihr.practice.allow-legacy-daily-drill-fallback=true` 启用训练次数回退,生产 profile 即使误传环境变量也强制关闭。
- uni-app 员工端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/user/today/index`,dev 默认只输入手机号登录。今日页进入问师傅、练习、案例素材和个人页;练习页应能完成开始练习、提交回应、结束评分、每日三题提交,个人页同步训练历史和成长证据包。每日三题正式按组织快照 `hire_date` 判断入职三个月窗口;本地 Demo 若快照尚无该字段,仅由 `dev/local` profile 且 `application-dev.yml` 的 `aihr.practice.allow-legacy-daily-drill-fallback=true` 启用训练次数回退,生产 profile 即使误传环境变量也强制关闭。
- 工作助手确认式统一采集:`/h5/#/pages/user/sop/index` 一级入口只保留“工作助手 / 查全网”,既有文字、ASR、媒体、数据工具和 30 分钟/最近 6 轮短会话链保持不变;显式“记一下/帮我记/保存一下”返回 `DRAFT` 确认卡,位置缺失只作可选提示。确认后写 `aihr_assistant_capture`:`PRIVATE/NOT_REQUIRED` 仅本人可见,`COMPANY/PENDING` 只表示待流转;旧项目记录继续使用 `aihr_service_memory/version`。`/h5/#/pages/user/assistant/memories` 展示待确认候选和本人已确认记录;不依赖新的 Qdrant collection,提醒默认关闭。
- 上一条只验证当前已部署的确认式采集;项目名称下拉、项目化会话、原始来源绑定、今日工作成果和主管按日汇总仍属[后续迭代](工作助手与今日工作成果迭代计划-20260721.md),不得在本地回归结果中写成已完成。
- 移动端登录后若组织快照接口返回 `401/403`,只降级为手动岗位确认,不应清除手机号登录态;岗位确认页仍需允许员工选择“生活顾问”后继续进入业务页。
- uni-app 主管端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/supervisor/index/index`,应看到团队概览、团队画像、团队预警、指派专项、待复盘和复盘详情;从团队画像派专项后,最近专项应立即回读新记录。
- uni-app 候选人端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/candidate/index/index`,手机号登录(dev 验证码固定 `123456`)→ “开始面试/面试练习”完成答题评分;“补充资料”选择 PDF/Word/图片后上传,应看到资料状态。Codex 内置浏览器不支持本地文件选择时,用真实 HTTP multipart smoke 代替浏览器文件选择。
- uni-app 候选人端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/candidate/index/index`,dev 默认只输入手机号登录 → “开始面试/面试练习”完成答题评分;“补充资料”选择 PDF/Word/图片后上传,应看到资料状态。Codex 内置浏览器不支持本地文件选择时,用真实 HTTP multipart smoke 代替浏览器文件选择。
- 真 LLM 激活:在 `/system/model` 给供应商填 api_host/api_key 并启用 `category=chat` 模型后,三角色对练的客户回复与评分即为真实 LLM 生成;再启用 `category=asr/tts` 语音路径生效。阿里云短音频 ASR 使用 `provider_code=dashscope`、`model_name=qwen3-asr-flash` 和北京工作空间的 `/compatible-mode/v1` Base URL;现有 `backend/.env` 中同一工作空间的 `AIHR_QWEN_REALTIME_ENDPOINT` / `AIHR_QWEN_REALTIME_API_KEY` 可作为本地模型管理的配置来源,但应用不会自动把私密变量导入模型表。密钥只通过模型管理或本地私密配置提供,不写入文档、SQL 或受版本控制配置。SiliconFlow SenseVoice/CosyVoice2 仍作为兼容供应商。未配置时全链路自动回退 seed。
演示前可先跑最小预检:
+850
View File
@@ -0,0 +1,850 @@
# 企业数字资产处理与治理方案
> 文档状态:目标方案与实施基线
>
> 更新时间:2026-08-02
>
> 适用范围:帮道 APP 的知识、案例、SOP、陪练、考试、评测及相关数据资产
>
> 当前实现证据:[data-quality-audit.md](data-quality-audit.md)
>
> 接口事实:[API_INTEGRATION.md](API_INTEGRATION.md)
>
> 生产运维:[KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md)
## 1. 方案结论
本项目需要建设的不是一个“上传后清洗文本”的工具,而是一条把各种数字材料转化为可用、可信、可追溯企业数字资产的生产线。核心目标有两个:
1. 任何进入生产问答、陪练、评分或评测的数据,都能证明来源、版本、适用范围、有效期、处理规则和批准责任人。
2. 人工只处理机器无法可靠决定的异常、冲突和高风险责任事项,并通过持续沉淀规则,让相同问题不再重复依赖人工。
总体采用五层架构:
1. **原始资产层**:不可变保存文件、图片、表格、录音、视频、对话和外部数据快照。
2. **规范化层**:版本化执行解析、OCR/ASR、编码修复、空白和版面噪声处理,不覆盖原件。
3. **结构化层**:拆解为制度条款、SOP 步骤、Q&A、案例、观点、术语、事实与证据等通用单元。
4. **治理审核层**:确定性规则、统计模型和 LLM 辅助检测后,自动放行低风险高置信数据、隔离硬风险、把灰区交给人工。
5. **发布消费层**:经批准的数据按用途进入生产知识、案例、陪练、考试或黄金评测集,并通过可撤回的索引投影供下游使用。
生产系统必须始终满足:
```text
未经批准的数据 != 生产知识
模型生成的数据 != 权威事实
用户交互记录 != 可自动回流的企业经验
解析成功 != 质量合格
有 embedding != 已批准发布
```
## 2. 目标、范围与非目标
### 2.1 目标
- 建立统一资产身份、不可变版本和全链路血缘。
- 让原始、候选、可信、合成、运行和评测数据明确分域。
- 用硬门禁、软规则和 reason code 取代单一 `is_clean` 或综合质量分。
- 建立自动检测、人工裁决、规则学习、影子验证、灰度执行和回滚闭环。
- 保证发布、撤回、过期和版本替代能同步影响全文检索、引用读取和向量索引。
- 让错误回答能够定位到具体 chunk、加工版本、原始文件和审核记录。
- 在不降低风险控制的前提下,持续提高自动处理率并降低人工审核量。
### 2.2 覆盖的数据来源
- 文件上传、批量导入、运维目录导入、API 导入和数据库同步。
- PDF、Word、Excel、PPT、文本、图片 OCR、录音 ASR 和视频关键帧/音轨。
- 企业制度、法规、SOP、专家经验、员工案例和业务术语。
- AI 生成的问题、答案、案例、评分、摘要和结构化草稿。
- 用户问答、陪练对话、评分结果、纠错反馈和成果投稿。
- 用于训练、验证、测试和回归评测的数据集。
### 2.3 非目标
- 不用一次性重写现有知识平台替代渐进治理。
- 不把所有历史数据一键判为可信,也不从旧片段反向伪造原始来源。
- 不让 LLM 成为唯一质量判断者、审核人或发布人。
- 不追求消灭所有人工;高风险责任确认、事实冲突和业务例外长期保留人工裁决。
- 不把提高召回率等同于提高答案可信度。HyDE、rerank 和 Prompt 优化只能在准入治理之后评估。
## 3. 不可妥协的设计原则
1. **原始不可变**:MinIO/OSS 原件、原始 hash 和采集上下文不可由清洗流程覆盖。
2. **加工即新版本**:重解析、重清洗、重切片和规则升级都产生新版本或新修订。
3. **默认不可信**:新上传、OCR/ASR、个人经验、AI 生成和运行交互默认不是生产知识。
4. **用途决定准入**:同一内容可能不适合权威知识,却可作为反例、陪练素材或仅供参考资料。
5. **硬风险不可被总分抵消**:敏感信息、跨租户、来源不明或提示词注入命中后,即使内容相关度很高也不能发布。
6. **LLM 只提供信号**:LLM 可提取、分类、提出纠错和冲突候选,无权批准、发布、撤回、删除或改变来源身份。
7. **人工决定可学习**:每次人工决定都必须形成结构化反馈,成为规则候选和黄金集样本。
8. **发布是显式动作**:只有授权人对确定内容 hash 做出批准后,系统才能建立生产数据集成员和索引投影。
9. **撤回先于异步删除**:先在 MySQL 事实源切断可见性,再通过 outbox 幂等删除向量。
10. **多租户失败关闭**:租户、知识空间、项目、岗位、区域或身份无法可靠确认时,拒绝猜测和跨域回退。
11. **可观测且可回滚**:规则、模型、索引 generation 和迁移批次均可对账、回退和追责。
12. **自动化以风险为约束**:减少人工不能通过放宽门禁实现,只能通过提高检测置信度、复用人工决策和缩小异常面实现。
## 4. 五层总体架构
```mermaid
flowchart TD
S["原始来源<br/>文件、图片、音视频、数据库、API、交互"] --> I["接入与固化<br/>身份、租户、来源、Hash、MinIO"]
I --> R["原始资产层<br/>RAW / 不可变原件"]
R --> P["规范化层<br/>解析、OCR/ASR、除噪、格式统一"]
P --> U["结构化层<br/>条款、步骤、Q&A、案例、观点、术语、证据"]
U --> G["治理审核层<br/>规则检测、质量评价、去重、隐私、冲突"]
G -->|"硬门禁"| Q["QUARANTINED<br/>隔离与修订"]
G -->|"灰区"| H["REVIEW_PENDING<br/>人工差异审核"]
G -->|"低风险高置信"| A["自动候选通过<br/>抽样复核"]
H --> A2["APPROVED<br/>人工责任确认"]
A --> A2
A2 --> D["用途路由<br/>knowledge/case/roleplay/assessment/eval"]
D --> O["发布消费层<br/>PUBLISHED + production membership"]
O --> X["全文检索 / Qdrant / RAG / 陪练 / 考试"]
X --> E["查询证据与用户反馈"]
E --> F["质量问题与人工裁决"]
F --> G
F --> L["规则演进<br/>影子运行、灰度、抽样、回滚"]
L --> G
O --> W["WITHDRAW / DEPRECATED"]
W --> Z["立即停止可见 + DELETE outbox"]
```
五层是职责分层,不要求五套完全独立的产品。现有架构应通过增量表、服务端门禁和发布投影逐步实现,避免大规模重写。
## 5. 数据域与资产身份
### 5.1 数据域
| 数据域 | 典型内容 | 默认信任 | 可否直接生产检索 | 主要去向 |
|---|---|---:|---:|---|
| `raw` | 上传原件、原始录音、视频、数据库快照 | 不可信 | 否 | 重处理与审计 |
| `candidate` | 解析、规范化、结构化后的候选版本 | 不可信 | 否 | 自动检测与审核 |
| `trusted_knowledge` | 已审批制度、法规、SOP、正式术语 | 受控可信 | 是 | 企业问答和学习 |
| `reviewed_cases` | 审核通过的正例、反例、场景案例 | 按用途可信 | 仅按用途 | 案例库与陪练 |
| `synthetic` | AI 生成问题、案例、答案、摘要、评分说明 | 不可信 | 默认否 | 草稿、测试、经审后专项使用 |
| `runtime_interactions` | 用户问题、模型回答、陪练对话、评分、反馈 | 不可信 | 否 | 运营分析与问题闭环 |
| `golden_eval` | 人工确认问题、标准答案、允许/禁止来源 | 高可信但只读 | 不参与回答 | 回归评测 |
数据域必须是服务端持久化属性,不能只靠文件夹名、前端标签或 Prompt 约定。`synthetic` 内容即使人工审核通过,也必须永久保留合成来源身份。
### 5.2 业务用途
| `usage_type` | 含义 | 关键准入要求 |
|---|---|---|
| `NORMATIVE_KNOWLEDGE` | 法规、制度、正式 SOP | 权威来源、版本、有效期、适用范围、责任人批准 |
| `POSITIVE_CASE` | 已验证的正面案例 | 场景、行动、依据、结果和专家评价完整 |
| `NEGATIVE_CASE` | 错误做法或失败案例 | 明确反例标签,禁止作为标准做法召回 |
| `ROLEPLAY_MATERIAL` | 陪练角色、对话和情境 | 去标识化、场景边界和训练目的明确 |
| `ASSESSMENT_ITEM` | 考题、标准答案、评分标准 | 来源依据、难度、适用岗位和人工签认 |
| `REFERENCE_ONLY` | 仅供辅助参考 | 不能包装成强制制度或标准答案 |
| `UNUSABLE` | 无法使用但需保留审计 | 不进入任何生产数据集 |
## 6. 生命周期状态机
```mermaid
stateDiagram-v2
[*] --> RAW
RAW --> PARSED
PARSED --> NORMALIZED
NORMALIZED --> CLASSIFIED
CLASSIFIED --> DEDUPLICATED
DEDUPLICATED --> PRIVACY_CHECKED
PRIVACY_CHECKED --> DOMAIN_VALIDATED
DOMAIN_VALIDATED --> QUALITY_EVALUATED
QUALITY_EVALUATED --> QUARANTINED: 硬门禁或来源不可用
QUALITY_EVALUATED --> REVIEW_PENDING: 软问题或需责任确认
QUARANTINED --> REVIEW_PENDING: 新版本修复并重新检测
REVIEW_PENDING --> APPROVED: 授权审核人批准
REVIEW_PENDING --> QUARANTINED: 拒绝或要求修订
APPROVED --> PUBLISHED: 创建生产投影和索引任务
PUBLISHED --> DEPRECATED: 撤回、过期或被替代
DEPRECATED --> REVIEW_PENDING: 以新版本重新进入流程
```
状态转换约束:
- 每个状态转换记录操作者、处理器版本、输入/输出 hash、时间和结果。
- `APPROVED` 绑定具体 `version_id + content_sha256`;内容变化后旧批准自动失效。
- `PUBLISHED` 不是“文件已解析”,而是已批准版本被显式路由到允许的数据集。
- `QUARANTINED` 不等于删除。隔离数据保留原件和证据,可修订后以新版本重跑。
- `DEPRECATED` 立即退出所有生产读取路径,但按保留策略保存审计链。
- 自动处理可以推进技术状态;高风险资产进入 `APPROVED` 必须有满足责任矩阵的人类决定。
## 7. 各层处理契约
### 7.1 第一层:原始资产保存
**输入**:浏览器上传、批量上传、运维导入、数据库/API 同步、录音、视频和用户提交。
**处理动作**:
- 在接入时确定 `tenant_id`、知识空间、来源类型、采集主体、时间和授权范围。
- 计算 SHA-256、探测 MIME/扩展名、记录大小,并把原件写入 MinIO/OSS。
- 生成稳定 `asset_id`,把上传任务、附件、OSS 对象和业务对象建立血缘。
- 精确重复可以复用只读 OSS 对象,但不能把两次业务接入合成同一个来源事件。
- 原件缺失、租户不明或来源无法验证时直接隔离。
**输出**:`RAW` 资产、原始对象引用、来源元数据和接入审计记录。
**不得执行**:覆盖同名文件、修改原始正文、直接切片入生产库、直接调用生产向量写入。
### 7.2 第二层:解析与规范化
规范化只处理确定性的技术噪声,不负责改写业务事实。
| 类型 | 解析 | 可自动规范化 | 必须保留的证据 |
|---|---|---|---|
| PDF | 文本层、页数、页码、图片/OCR | Unicode、换行、重复页眉页脚候选 | 页码、文本坐标、OCR 置信度、缺页判断 |
| Word/PPT | 标题、段落、表格、列表、备注 | 空白、控制字符、样式噪声 | 标题路径、页/段定位、表格结构 |
| Excel | sheet、表头、单元格、合并区 | 空行空列和类型标准化候选 | sheet/行列坐标、公式与显示值 |
| 图片 | OCR、版面区域、方向 | 旋转和确定性字符规范化 | 框坐标、置信度、原图引用 |
| 录音 | ASR、说话人分段、时间轴 | 标点和口头停顿候选 | 时间戳、声道/说话人、ASR 置信度 |
| 视频 | 音轨 ASR、关键帧、字幕、视觉结果 | 时间轴对齐 | 关键帧时间、字幕区间、视觉解析来源 |
| 文本/API | 编码、字段和 schema | NFKC、换行、控制字符、空白 | 原始 payload hash、接口版本 |
清洗结果生成新 `data_version`,至少记录:
- `parser_name/parser_version`
- `extractor_name/extractor_version`
- `cleaning_policy_version`
- `classification_policy_version`
- 页数、OCR/ASR 指标和结构画像
- 清洗前后 hash 及可查看的差异
以下行为只能生成候选,不得静默改写事实:OCR 错字纠正、表格语义重建、说话人归属、日期和金额纠正、行业黑话解释、缺失上下文补写。
#### 7.2.1 隐私脱敏派生层
解析正文和规范化正文继续作为不可变审计证据保存在受控数据版本中,不直接用于切片、语义分析、模型调用、发布或检索。系统使用版本化的确定性规则从规范化正文生成独立脱敏派生版本,并记录 `redacted_content`、`redacted_source_name`、派生内容 hash、`privacy_status`、`redaction_policy_version` 和分类计数;当前规则版本为 `privacy-redaction-v1`。
脱敏后必须再次扫描派生正文和全部派生 chunk:结果为 `CLEAN` 或 `REDACTED` 才能继续质量评估;仍命中敏感模式时标记为 `BLOCKED / PII_DETECTED` 并隔离。命中并已安全替换的类别记录 `PII_REDACTED` 软证据,不能用综合质量分覆盖残留 PII 硬门禁。审核界面默认只展示脱敏文件名、分类计数和脱敏正文预览;查看原件必须走单独鉴权、留痕的审计入口。
下游统一消费脱敏派生版本:结构化拆解和 chunk 从 `redacted_content` 生成,外部 embedding/LLM 只接收隐私状态为 `CLEAN/REDACTED` 的派生内容,生产引用标题优先使用 `redacted_source_name`。重复对象中遗留的摘要、标签和归类理由不能直接复用,必须经当前隐私规则重新脱敏;上传响应 snippet 也使用脱敏文件名。规则升级不覆盖旧派生版本,而是生成新版本、重新复扫、重新审核和重新发布。
### 7.3 第三层:结构化拆解
结构化目标不是强迫所有资料变成 Q&A,而是先保留文档结构,再映射为可复用业务单元。
统一信封建议:
```json
{
"unitId": "stable-id",
"assetId": 123,
"versionId": 2,
"tenantId": "000000",
"unitType": "SOP_STEP",
"title": "首次短信催费",
"content": "...",
"context": {
"scenario": "欠费首次提醒",
"role": ["生活顾问"],
"project": ["示例项目"],
"region": ["南京"]
},
"validity": {
"effectiveFrom": "2026-01-01",
"effectiveTo": null
},
"evidence": [
{"sourceLocator": {"page": 3, "paragraph": 7}}
],
"origin": "ENTERPRISE_SOURCE",
"synthetic": false
}
```
通用单元类型:
| 单元类型 | 关键字段 | 适用内容 |
|---|---|---|
| `POLICY_CLAUSE` | 条款号、义务/禁止、适用对象、有效期、上位依据 | 制度与法规 |
| `SOP_STEP` | 场景、前置条件、步骤号、动作、例外、完成标准 | 标准流程 |
| `QA_PAIR` | 问题、答案、依据、无答案条件 | 高频问答 |
| `CASE` | 背景、角色、诉求、行动、依据、结果、专家评价 | 正反案例 |
| `EXPERT_OPINION` | 观点、专家、适用条件、依据、冲突关系 | 经验和争议意见 |
| `GLOSSARY_TERM` | 术语、别名、定义、适用项目/岗位、版本 | 业务黑话 |
| `FACT_CLAIM` | 主体、谓词、对象、约束、证据位置 | 冲突和事实核验 |
| `ASSESSMENT_ITEM` | 题干、选项、标准答案、评分依据、难度 | 考试与评测 |
| `ROLEPLAY_SCENE` | 人设、背景、目标、红线、回合锚点 | 陪练素材 |
结构化后再进行语义切片:优先保持标题、段落、Q&A、SOP 步骤和表格行组完整;只有超长结构块才使用 overlap。不得把固定“500–800 字、重叠 100 字”当作所有文档的全局真理,参数应按文档类型在黄金集上标定。
### 7.4 第四层:治理与审核
治理阶段依次执行:
1. 技术完整性:空内容、解析失败、缺页、乱码、OCR/ASR 低置信度。
2. 结构质量:页眉页脚、水印、分页噪声、表格丢失、切片上下文断裂。
3. 来源与身份:来源、版本、租户、空间、项目、岗位和有效期。
4. 安全与隐私:PII、密钥、跨租户引用、提示词注入和外发边界。
5. 去重与版本:精确、近似和语义重复;制度替代和多版本冲突。
6. 领域与事实:领域相关性、上下文完整性、结论依据、标签和专家冲突。
7. 来源污染:未声明合成、运行数据回流、训练/评测泄漏。
8. 用途路由:确定是否可成为权威知识、案例、陪练、题目、评测或仅供参考。
每项问题单独生成 `quality_issue`,包含 reason code、严重级别、硬/软门禁、检测器和版本、证据位置、建议动作及处理状态。不得用一个总分掩盖具体风险。
### 7.5 第五层:发布与消费
发布前置条件:
- 当前版本已封存且内容 hash 未变化。
- 来源、版本、适用范围、有效期和数据用途完整。
- 无开放的硬门禁问题,所有软问题均被逐项接受、解决或判为误报。
- 语义重复/冲突分析已完成或明确不需要。
- 规范性知识的替代关系已经确认。
- 有符合责任矩阵的人工审核记录。
- 数据集路由和知识空间授权由服务端生成。
发布动作在同一事务中创建生产 fragment、`production` 数据集成员和 `UPSERT` outbox。向量索引只是 MySQL 事实源的可重建投影,不是独立事实源。
## 8. 数据模型
### 8.1 当前本地已具备的核心对象
| 对象 | 责任 |
|---|---|
| `aihr_data_asset` | 稳定资产身份、来源、租户、用途、信任、适用范围和生命周期 |
| `aihr_data_version` | 不可变解析/规范化版本、规则版本、结构画像和提取质量 |
| `aihr_chunk_revision` | 不可变候选切片、定位信息和发布 fragment 映射 |
| `aihr_quality_assessment` | 一次版本化、多维质量评估 |
| `aihr_quality_issue` | reason code、门禁、证据、检测器及解决状态 |
| `aihr_review_decision` | 只允许人工记录批准、拒绝、隔离、撤回和失效决定 |
| `aihr_dataset_membership` | 明确版本属于哪个数据集以及用途 |
| `aihr_lineage_edge` | 原件、版本、切片、发布片段之间的正反向血缘 |
| `aihr_index_outbox` | 向量 UPSERT/DELETE 的持久、幂等、可重试任务 |
| `aihr_query_evidence` | 每次检索的排名、通道、分数、使用情况和污染定位 |
| `aihr_duplicate_relation` | 精确、近似和语义重复候选关系 |
| `aihr_knowledge_claim` / `aihr_claim_conflict` | 事实/约束候选及人工冲突裁决 |
| `aihr_quality_alert` | 索引漂移、血缘缺口、开放问题和过期资产告警 |
| `aihr_knowledge_glossary_term` | 不可变术语修订、人工批准和适用范围 |
当前表结构是现有架构内的增量治理骨架。实际字段和迁移顺序以 `backend/script/sql/update/aihr_20260801...20260814` 及 [API_INTEGRATION.md](API_INTEGRATION.md) 为准。
### 8.2 建议补充的规则演进对象
现有表已保存 policy/detector version,但要系统性降低人工量,还应补充两类显式对象:
| 建议对象 | 关键字段 | 用途 |
|---|---|---|
| `aihr_processing_rule` | `rule_code, version, stage, scope_json, risk_class, action, implementation_type, config_json, status, owner, effective_at, rollback_version` | 管理规则草稿、影子、灰度、启用、停用和回滚 |
| `aihr_rule_evaluation` | `rule_version, sample_id, expected_decision, actual_decision, confidence, matched_reason_codes, false_allow, false_block, run_id, evaluated_at` | 对比人工/黄金集结论,证明规则可否自动执行 |
| `aihr_pipeline_run` | `run_id, asset_id, input_version, output_version, stage, processor_version, status, metrics_json, started_at, ended_at` | 记录重处理批次、耗时、错误和可重放性 |
| `aihr_review_sample` | `rule_version, asset_id, sampling_strategy, sampled_at, review_result` | 对已自动通过/隔离结果持续抽样复核 |
上述四类对象已在本地增量落地;它们当前只支撑影子评估、批次追溯和人工复核,不代表规则已经获得自动执法权限。
## 9. 自动化分流模型
### 9.1 三路分流
```mermaid
flowchart LR
C["候选版本"] --> D["规则与模型检测"]
D --> B["BLOCK<br/>硬门禁自动隔离"]
D --> R["REVIEW<br/>灰区人工审核"]
D --> P["PASS<br/>低风险高置信候选"]
P --> S["按风险抽样复核"]
S -->|"发现误放行"| K["撤回 + 规则降级 + 回归"]
S -->|"稳定"| T["扩大自动化覆盖"]
```
- **自动隔离**:命中确定性硬风险,系统可阻止发布,但不得物理删除原件。
- **人工审核**:规则置信度不足、存在冲突、业务适用范围不明或需要责任确认。
- **自动候选通过**:只适用于低风险、确定性且已在黄金集/影子流量中证明可靠的规则;仍须满足抽样和可撤回要求。
### 9.2 风险与置信度矩阵
| 业务风险 | 高置信安全 | 中等/冲突置信 | 高置信风险 |
|---|---|---|---|
| 低风险参考资料 | 自动进入待发布队列,按比例抽样 | 人工差异审核 | 自动隔离/修订 |
| 中风险案例/SOP | 规则通过后仍需用途责任确认,可批量审核 | 人工审核 | 自动隔离 |
| 高风险制度/法规/标准答案 | 不自动最终批准,减少到差异审核 | 双人或指定责任人审核 | 自动隔离并告警 |
| PII/密钥/跨租户/注入 | 不存在自动放行通道 | 隔离并人工安全复核 | 自动隔离并告警 |
“高置信”必须来自版本化规则在代表性标注集上的数据,而不是 LLM 自报置信度。
## 10. Reason code 与门禁策略
### 10.1 当前核心 reason code
| 类别 | reason code | 默认动作 |
|---|---|---|
| 解析 | `PARSE_EMPTY`, `PARSE_FAILED`, `PAGE_COUNT_MISMATCH`, `SOURCE_UNAVAILABLE` | 硬隔离,修复来源后新版本重跑 |
| 来源 | `SOURCE_UNKNOWN`, `SOURCE_EVIDENCE_INSUFFICIENT`, `SOURCE_VERSION_MISSING` | 硬隔离或补齐来源与事实依据责任确认 |
| 隐私安全 | `PII_DETECTED`, `SECRET_DETECTED`, `CROSS_TENANT_REFERENCE`, `PROMPT_INJECTION_SUSPECTED` | 硬隔离,不外发语义分析 |
| 时效 | `POLICY_EXPIRED`, `VERSION_CONFLICT` | 停止发布,确认有效版本和替代关系 |
| 合成数据 | `SYNTHETIC_UNDECLARED`, `SYNTHETIC_UNVERIFIED` | 强制合成身份,未经人工不得生产使用 |
| 提取质量 | `OCR_LOW_CONFIDENCE`, `ASR_LOW_CONFIDENCE` | 隔离或差异复核 |
| 版面/结构 | `HEADER_FOOTER_NOISE`, `PAGINATION_NOISE`, `CHUNK_CONTEXT_BROKEN` | 软门禁,修订或逐项接受 |
| 业务质量 | `DOMAIN_IRRELEVANT`, `CONTEXT_INCOMPLETE` | 软/硬动作取决于用途 |
| 重复 | `EXACT_DUPLICATE`, `NEAR_DUPLICATE`, `SEMANTIC_DUPLICATE` | 建立候选关系,不自动删除或合并 |
| 语义分析 | `SEMANTIC_ANALYSIS_DEGRADED`, `SEMANTIC_ANALYSIS_FAILED` | 标明降级,未完成时拒绝发布 |
| 冲突 | `EXPERT_CONFLICT` | 人工确认、误报或解决 |
| 下游反馈 | `DOWNSTREAM_ANSWER_DISPUTED` | 创建复核任务,不自动撤回 |
| 责任门禁 | `HUMAN_REVIEW_REQUIRED` | 等待符合权限的人工决定 |
### 10.2 建议扩充的 reason code
- 解析:`PARSE_TRUNCATED`, `EMBEDDED_CONTENT_SKIPPED`, `TABLE_STRUCTURE_LOST`。
- 编码:`ENCODING_REPLACEMENT_CHAR`, `UNICODE_CONTROL_CHAR`, `OCR_PARTIAL`, `ASR_SPEAKER_UNCERTAIN`。
- 清洗:`TOC_NOISE`, `WATERMARK_NOISE`, `CHUNK_TOO_SHORT`。
- 业务:`UNSUPPORTED_CLAIM`, `LABEL_CONFLICT`, `APPLICABILITY_MISSING`。
- 污染:`RUNTIME_DATA_CONTAMINATION`, `TRAIN_EVAL_LEAKAGE`。
- 索引:`INDEX_UPSERT_FAILED`, `INDEX_DELETE_FAILED`, `INDEX_DRIFT`, `INDEX_PAYLOAD_INVALID`。
扩充 reason code 时必须同时定义检测器、证据结构、严重级别、门禁类型、推荐动作、可否接受、测试夹具和负责团队,禁止只增加枚举名称。
## 11. 如何持续减少人工工作
人工不是永久流水线,而是规则的教师、例外处理者和责任承担者。减少人工的正确路径如下:
### 11.1 优先减少审核操作,而不是减少控制
- **差异审核**:只展示原文与候选修订的变化、命中问题和影响范围,不要求审核人通读整份文档。
- **聚类审核**:精确重复自动归组;近重复和同模板资料批量展示共同问题,一次决定可形成受控批处理建议。
- **建议决策**:系统预填用途、适用范围、reason code 处理建议和相似历史决定,人工确认或修改。
- **异常审核**:稳定规则覆盖的数据不进入逐份队列,只对例外、冲突、低置信和高风险项审核。
- **抽样复核**:对自动通过按风险分层抽样;样本失败立即降低规则自动化级别。
- **增量审核**:新版本只审与已批准版本的差异、规则变化和影响的结构单元。
- **批量适用范围**:同来源、同项目、同版本批次可复用已确认元数据,但每个资产仍保留独立血缘和 hash。
### 11.2 人工决定必须结构化
每次审核至少记录:
- 决定:批准、拒绝、隔离、撤回、失效、误报或接受软问题。
- 对象:具体 `asset/version/chunk` 与内容 hash。
- 原因:reason code 及自由说明。
- 修改:人工改了哪些字段或正文差异。
- 依据:原文件位置、制度、业务责任人或适用条件。
- 复用条件:这个判断在什么来源、文档类型、项目、岗位或阈值下可以规则化。
- 风险等级和是否允许作为自动化训练/评测样本。
只保存“通过/不通过”的审核记录无法形成有效自动化。
### 11.3 规则演进闭环
```mermaid
flowchart LR
H["人工决定"] --> C["聚合高频原因与修订模式"]
C --> R["规则候选 + 版本 + 适用范围"]
R --> S["影子运行<br/>不改变生产决定"]
S --> M["与人工/黄金集比较指标"]
M -->|"不达标"| C
M -->|"达标"| G["小租户/小来源灰度"]
G --> A["自动执行 + 风险抽样"]
A --> O["监控误放行、误隔离与漂移"]
O -->|"稳定"| E["扩大覆盖"]
O -->|"异常"| B["一键回退旧规则并重审受影响版本"]
B --> C
```
规则晋级条件必须按风险等级设定:
- 安全硬门禁可自动隔离,但误伤率需受控且允许修订重跑。
- 低风险技术清洗可在 diff 可见、原文保留和指标达标后自动应用。
- 权威制度、标准答案、跨租户和敏感数据不能因规则表现良好而取消最终责任确认。
- LLM 分类器升级必须视为新 detector version,重新跑影子集,不得静默替换。
### 11.4 人工角色的最终形态
随着规则成熟,人工工作应从“逐份清洗和逐条检查”转为:
- 处理系统无法决定的少数异常和冲突。
- 确认制度权威性、适用范围、有效期和替代关系。
- 维护术语、黄金集、规则阈值和误报样本。
- 对高风险发布、撤回和安全例外承担责任。
- 定期评估规则漂移,而不是持续做重复机械操作。
## 12. LLM 的允许与禁止边界
### 12.1 可以做
- OCR/ASR 错字、断句和结构恢复建议。
- 候选 Q&A、SOP、案例、术语和 claim 提取。
- 领域相关性、上下文缺失和冲突候选提示。
- 对人工修改生成规则候选说明。
- 为审核人生成差异摘要,但必须链接原始证据。
- 在黄金集上参与分类器评测和影子运行。
### 12.2 不可以做
- 覆盖原始文件或把推断写成原始事实。
- 自己决定来源权威性、制度有效期、跨项目适用范围或专家冲突结论。
- 自行批准、发布、撤回、物理删除数据或修改审核记录。
- 把生成的案例、答案、评分或总结无标记地写回可信知识区。
- 将用户回答、运行日志或历史模型回答自动转为标准答案。
- 在 PII、密钥、提示词注入或隔离内容上调用未经批准的外部模型。
LLM 输出统一标记 `synthetic=true` 或 detector signal;人工审核不能消除其合成身份,只能批准其在特定用途下使用。
## 13. 发布、检索、撤回与追溯
### 13.1 生产检索条件
所有全文、关键词、向量、引用水合、相邻片段和原件下载路径都必须独立复核以下交集:
```text
当前认证租户
AND 调用应用绑定的知识空间
AND 主体授权的知识空间
AND 当前版本
AND lifecycle_status = PUBLISHED
AND trust_level = HUMAN_VERIFIED
AND dataset_code = production
AND membership_status = ACTIVE
AND 未过期
AND 项目/岗位/区域适用
```
客户端提交的租户、角色、项目、标签或 `toolCode` 不能作为可信过滤条件。Qdrant payload filter 是第一层过滤,MySQL hydrate 是最终事实复核。
### 13.2 向量索引
- 生产 Qdrant point 使用确定性 ID 和 generation,payload 带租户、asset、version、chunk revision、生命周期、数据集、有效期和 embedding 模型。
- 所有写入/删除先在数据库事务内写 `aihr_index_outbox`,worker 幂等执行并重试。
- 超过重试阈值进入 `DEAD_LETTER` 并告警,不能通过改回业务状态掩盖索引漂移。
- 定时 reconciler 对比 MySQL 的已发布集合与 Qdrant 点,缺失发 UPSERT,多余发 DELETE,hash 不一致重建并留痕。
- 候选、隔离、合成和运行数据原则上不进生产 collection。即使未来需要语义分析,也使用隔离索引或临时分析向量。
### 13.3 撤回与替代
1. 授权人提交撤回/失效决定和原因。
2. 同一事务把版本改为 `DEPRECATED`、停用数据集成员、移除生产 fragment、写 DELETE outbox。
3. 所有 MySQL 读取立即不可见,不等待 Qdrant 删除完成。
4. outbox 删除失败重试并告警;索引对账确认点为零。
5. 原件、版本、问题、审核和查询证据继续保留。
6. 新制度通过 `supersedes_asset_id` 显式替代旧制度,不使用同名覆盖。
### 13.4 错误回答追溯
```text
用户反馈 / requestId
→ aihr_query_evidence
→ published fragment
→ chunk revision
→ data version
→ data asset
→ attachment / MinIO 原件
→ parser、cleaner、chunker、detector 版本
→ quality issues 与 review decisions
```
用户“没解决”只创建 `DOWNSTREAM_ANSWER_DISPUTED`。人工确认 `KEEP` 或 `WITHDRAW`;模型和用户反馈都不能自动撤回可信资产。
## 14. 多租户、权限与安全隔离
- 所有治理主键关联和查询同时携带并校验 `tenant_id`,不接受只凭全局 ID 查询。
- 知识空间授权取“租户 + 调用应用绑定 + 当前主体授权”的交集。
- 项目、岗位、区域和有效期由已审核服务端 metadata 生成,不信任客户端标签。
- 跨租户重复分析默认只比较 hash,不暴露正文、文件名或来源;发现相同内容也不能自动共享授权。
- 生产 collection 至少按可信与非可信隔离;高合规租户可进一步使用独立 collection 或实例。
- PII、密钥、提示词注入和隔离内容先在本地确定性扫描,未通过前不得发送外部 embedding/LLM。
- 审核、发布、撤回、规则变更和数据集导出必须记录操作者、租户、对象 hash 和审计时间。
- 评测集与训练候选按内容 hash 防泄漏;同源近重复内容不能跨 train/test split。
## 15. 历史 1,046 份附件纳管方案
当前本地基线为:
- `aihr_data_asset = 0`
- 历史附件 `1,046`
- 历史片段 `8,607`
- 业务术语总数/活动术语 `0`
这表示治理骨架已存在,但历史资料尚未进入该生命周期。不能把现有片段或 embedding 视为已审核数字资产。
### 15.1 前置条件
1. 先部署并验证新数据 fail-closed,阻止继续产生 `RAW -> INDEXED`。
2. 在生产结构副本按顺序验证 `aihr_20260801` 至 `aihr_20260814` 迁移幂等性。
3. 备份数据库,导出仅含 ID/hash/状态的附件、OSS、片段和 Qdrant manifest。
4. 准备高频业务黄金问题和来源清单,不以当前答案作为标准答案。
5. 明确每个知识空间的业务责任人、审核人和允许用途。
### 15.2 批次策略
每批 20–50 份,按以下顺序处理:
1. 现行法规、公司制度、安全、消防、财务和人事资料。
2. 高频使用的正式 SOP 和标准话术。
3. 专家访谈、员工经验和正反案例。
4. OCR 噪声较大的扫描件、录音和视频。
5. 低频参考材料和来源不足材料。
每批执行:
```text
legacy preview(只读盘点)
→ 从当前租户 MinIO 原件重新解析
→ 自动检测和结构化
→ 人工差异审核
→ 小范围批准发布
→ 标准题回归与跨租户负例
→ 索引对账
→ 批次签认
```
- 原件存在:以 MinIO 原件为唯一重解析依据,建立新 asset/version/chunk revision。
- 原件缺失或不可读:创建 `QUARANTINED / SOURCE_UNAVAILABLE`,不得用旧 fragment 伪造来源。
- 旧 fragment 和旧向量在迁移完成前只作为未治理遗留数据统计,不参与新生产集合计数。
- 每批 manifest 记录游标、输入/输出 hash、成功/失败 ID、规则版本、审核人和索引 generation,不保存正文或 token。
- 任一失败 ID 不推进恢复游标;禁止全量自动批准。
### 15.3 批次验收与回滚
- 该批生产血缘完整率 100%。
- 未批准版本生产可检索数量为 0。
- 跨租户禁止片段泄漏数量为 0。
- 撤回后 MySQL 立即不可见,Qdrant 删除最终一致率 100%。
- 黄金问题达到该批预设 Recall/MRR/nDCG 和无答案阈值。
- 回滚只切换生产可见性/索引 generation,不删除原件、版本和审核证据。
## 16. 黄金集、测试与标定
### 16.1 黄金集设计
首批由业务专家标注 100–300 条,覆盖:
- 有唯一答案、多来源答案和明确无答案问题。
- 现行/过期/冲突制度。
- 不同租户、项目、岗位和区域的同名问题。
- OCR 乱码、缺页、表格、上下文断裂和业务黑话。
- 正面案例、反面案例、个人经验和 AI 合成内容。
- PII、密钥、提示词注入和跨租户数据。
- 精确、近似、语义重复及 train/eval 泄漏。
每条样本至少标注:
```json
{
"expectedStatus": "QUARANTINED",
"expectedReasonCodes": ["PII_DETECTED", "SOURCE_UNKNOWN"],
"allowedDatasets": [],
"allowedSourceIds": [],
"forbiddenSourceIds": [9981],
"answerable": false,
"reviewer": "business-owner",
"labelVersion": "golden-v1"
}
```
仓库中的示例 fixture 只验证代码契约,不等于真实业务黄金集,也不能据此宣称业务准确率达标。
### 16.2 测试分层
| 层级 | 重点 |
|---|---|
| 单元测试 | parser、normalizer、reason code、状态转换、hash、locator、租户 filter、outbox 幂等 |
| 组件测试 | 不同文件解析、OCR/ASR 证据、结构切片、重复关系、claim 冲突、规则版本 |
| 集成测试 | 上传到待审、批准发布、撤回删除、索引死信、反馈追溯、历史 stage 游标 |
| 安全测试 | 跨租户、越权审核、客户端 metadata 伪造、Prompt 注入、PII 外发阻断 |
| E2E | 管理端差异审核、批量决定、发布、检索引用、原文定位、撤回后不可见 |
| 离线评测 | Recall@K、MRR、nDCG、错误来源率、无答案误召回、跨租户泄漏 |
| 生产 canary | 合成禁止片段、已撤回片段和跨租户片段永不被召回 |
### 16.3 规则标定流程
1. 冻结黄金集版本,确保样本来源和标注责任人可追溯。
2. 现有规则跑基线,输出每个 reason code 的 precision/recall 和混淆矩阵。
3. 新规则只影子运行,不影响生产决定。
4. 按风险分别设阈值,不使用统一 `0.8`。
5. 达标后在小范围来源或租户灰度,自动结果持续抽样复核。
6. 监控分布漂移;parser、模型、Prompt 或规则升级均重跑基线。
## 17. 质量与自动化指标
| 指标 | 定义 | 初期验收目标 |
|---|---|---:|
| 生产来源可追溯率 | 可反查原件、版本、规则和审核的生产 chunk / 全部生产 chunk | 100% |
| 未审批入生产数 | 无有效人工批准却可检索的版本数 | 0 |
| 跨租户泄漏数 | 任一查询召回越权 tenant/space/project 的片段数 | 0 |
| 索引一致率 | MySQL 应有生产点与 Qdrant 实际点一致比例 | 100%,允许短暂 outbox 延迟 |
| 撤回同步成功率 | 撤回后最终完成向量删除的比例 | 100% |
| 自动处理率 | 无逐份人工操作完成技术处理和分流的资产数 / 总资产数 | 分类型逐月提升 |
| 人工审核率 | 进入人工队列的资产数 / 总候选资产数 | 逐月下降,不以放宽门禁换取 |
| 单份审核耗时 | 审核总时长 / 审核资产数 | 按文档类型持续下降 |
| 规则覆盖率 | 被已验证规则明确处理的问题数 / 全部质量问题数 | 按 reason code 统计 |
| 自动放行误判率 | 抽样中不应放行却自动放行的比例 | 高风险为 0;低风险按批准阈值 |
| 自动隔离误伤率 | 抽样中应通过却被自动隔离的比例 | 按风险和规则分别设阈值 |
| 规则转化率 | 高频人工模式转化为已上线规则的比例 | 每月跟踪 |
| 无答案误召回率 | 黄金集中无答案问题却返回事实性来源的比例 | 按业务门槛设定并持续降低 |
| 错误定位成功率 | 错误回答能定位具体 chunk 和原件的比例 | 100% |
自动化指标必须与风险指标并列展示。只报“自动处理率提高”而不报误放行和误隔离,是无效甚至危险的优化。
## 18. 实施路线
### 18.1 P0:阻止新增污染并形成可撤回主链
**目标**:任何新数据未经明确批准不得进入生产检索。
当前本地已实现:不可变 asset/version/chunk、质量门禁、人工发布、生产标签、查询证据、撤回 DELETE outbox、历史 stage、监控骨架和首批测试。该结论仅代表本地代码,不代表生产发布或历史完成治理。
剩余动作:
1. 在生产结构副本验证 `aihr_20260801` 至 `aihr_20260812` 迁移、回滚和幂等。
2. 完成生产部署前预检和空候选、批准、撤回、跨租户负例验证。
3. 接通 `DEAD_LETTER`、索引漂移、血缘缺口和过期资产外部告警。
4. 明确知识空间责任人和人工审核权限。
5. 开始按 20–50 份执行历史高风险资料纳管,禁止自动批准。
**P0 验收**:`RAW -> INDEXED = 0`、`MODEL_OUTPUT -> TRUSTED = 0`、跨租户泄漏为 0、生产血缘完整率 100%、撤回最终索引清除率 100%。
### 18.2 P1:结构质量、业务质量和人工减负
1. 建立正式术语表并由项目/岗位责任人审核。
2. 按制度、SOP、案例、访谈和多媒体分别标定切片与噪声规则。
3. 建设 100–300 条真实业务黄金集,标定 OCR、近重复、语义重复和领域阈值。
4. 扩充 claim、制度替代、多专家意见和场景完整性模型。
5. 实现差异审核、聚类审核、增量审核、批量 metadata 和风险抽样。
6. 落地 `processing_rule/rule_evaluation/pipeline_run/review_sample` 或等价对象。当前本地已完成规则版本、状态审计、只观察的影子评估、处理批次台账、风险自动抽样与管理端观察工作台;自动抽样只生成待人工复核任务,不改变资产。
7. 新规则经过影子运行和灰度后,逐类提高自动处理覆盖。
**P1 验收**:人工审核率和单份耗时连续下降,同时误放行不超过分级门槛;所有自动决定可解释、可抽样、可撤回。
### 18.3 P2:下游反馈和质量运营闭环
1. 将错误回答、引用、投诉和纠错统一关联到查询 evidence。
2. 形成“定位污染源 -> 撤回/修订 -> 重建索引 -> 回归评测”的标准工单。
3. 建立质量仪表板:生命周期、问题分布、审核积压、规则覆盖、索引一致和错误来源。
4. 对 parser、规则、模型和业务数据分布做漂移监控。
5. 在黄金集证明收益后再 A/B 混合召回、rerank、查询扩展和 HyDE。
6. 建立训练/验证/测试 snapshot、hash 去重和时间切分,防止评测泄漏。
**P2 验收**:所有错误答案可定位;高风险告警可送达、处置和关闭;规则退化能自动降级并触发受影响资产重审。
## 19. 职责分工
| 角色 | 主要责任 | 不应承担 |
|---|---|---|
| 数据资产负责人 | 数据域、准入标准、指标和跨团队裁决 | 逐份做机械清洗 |
| 业务责任人 | 来源权威、适用范围、有效期、制度替代 | 判断系统安全实现 |
| 业务审核人 | 处理灰区、冲突、案例用途和标准答案 | 修改原始证据 |
| 数据工程 | 解析、版本、血缘、规则执行、迁移和对账 | 代替业务批准事实 |
| AI/RAG 工程 | 结构提取、检索、评测、模型版本和降级 | 让 LLM 自行发布 |
| 安全/隐私 | PII、秘密、外发、跨租户和保留策略 | 用业务总分覆盖硬风险 |
| 运维 | MinIO、MySQL、Qdrant、outbox、告警和恢复 | 手工改状态掩盖漂移 |
| 产品/运营 | 审核体验、积压、效率和规则候选管理 | 将用户反馈直接回流为知识 |
高风险制度和标准答案至少需要明确的业务责任人。是否采用双人审核应按法规、安全、财务、人事等风险分类配置,而非一刀切要求所有资料双审。
## 20. 管理端最小工作台
为了真正降低人工成本,审核界面至少提供:
- 队列筛选:租户、知识空间、来源、类型、风险、reason code、批次和处理时长。
- 原文证据:受控预览、页码/时间轴/单元格定位,不暴露原始 OSS URL。
- 差异视图:解析文本、规范化文本、结构化单元和前一批准版本之间的差异。
- 问题面板:硬/软门禁、证据位置、检测器版本和建议动作。
- 相似组:精确/近似/语义重复及版本冲突并排对比。
- 适用范围:项目名称、岗位、区域、有效期和来源版本,内部编码由服务端复核。
- 决策动作:批准、拒绝、隔离、修订、误报、接受软问题、撤回和替代。
- 批量动作:只对同规则、同风险、同来源范围的低风险项开放,并显示预计影响。
- 审核抽样:自动通过/隔离结果的风险分层样本。
- 规则候选:按高频人工修改和 reason code 聚合,提交影子规则而非直接启用。
任何批量批准都必须在服务端逐个复核版本 hash、租户、开放问题和权限,不能只由前端勾选完成。
## 21. 运行节奏
### 每日
- 查看审核积压、硬门禁、outbox 重试/死信和索引漂移。
- 处理高风险新资产和已发布资产争议。
- 对自动处理结果按风险抽样。
### 每周
- 统计人工审核原因 Top N、重复修改模式和平均处理时长。
- 选取可规则化模式,建立规则候选和回归样本。
- 复核误放行、误隔离、无答案误召回和跨租户 canary。
- 对历史资料完成一个或多个小批次纳管和签认。
### 每月
- 审查规则覆盖、自动处理率、人工审核率和风险指标是否同时改善。
- 复核即将过期制度、来源责任人变更和项目/岗位适用范围。
- 重跑完整黄金集,评估 parser、模型、embedding、rerank 和规则漂移。
- 决定规则晋级、降级、停用和历史版本重处理范围。
## 22. 失败处理与回滚
| 故障 | 系统行为 | 回滚/恢复 |
|---|---|---|
| 解析器升级质量下降 | 新版本隔离,旧批准版本继续服务 | 回退 parser version,重跑受影响资产 |
| 规则误隔离 | 不影响原件,停止新规则自动执行 | 回退规则版本,批量重评但不自动发布 |
| 规则误放行 | 立即切断受影响版本可见性 | 撤回、DELETE outbox、回归和扩大抽检 |
| Qdrant UPSERT 失败 | MySQL 不把向量成功当发布前提的替代;记录失败 | outbox 重试,死信告警和重建 |
| Qdrant DELETE 失败 | MySQL 已不可检索 | 持续重试和 reconciler 清理 |
| MinIO 原件缺失 | 创建 `SOURCE_UNAVAILABLE` 隔离版本 | 从合规备份恢复;不能用旧片段伪造 |
| 模型/embedding 不可用 | 标记降级或失败,不静默换成等价质量 | 恢复后按 detector version 重跑 |
| 跨租户校验异常 | 失败关闭 | 修复身份/授权后重试,不做模糊回退 |
| 迁移批次失败 | 停止游标推进,旧 generation 不切换 | 按 manifest 重试,切回旧可见 generation |
原件和审计链不作为普通回滚对象物理删除。回滚主要切换可见性、规则版本和索引 generation。
## 23. 当前项目落地映射
截至 2026-08-02,本地代码已具备:
- 新上传和 AI 整理先进入不可变候选生命周期,生命周期服务不可用时 fail-closed。
- NFKC、控制字符、换行和空白规范化生成新版本,不覆盖原件。
- `privacy-redaction-v1` 从规范化正文生成独立的脱敏正文和脱敏文件名;解析正文与规范化正文继续作为受控审计证据保留。结构化切片、语义分析、模型调用和发布只消费 `CLEAN/REDACTED` 派生版本,脱敏后复扫仍命中敏感模式时以 `PII_DETECTED` 阻断发布。
- 标题、段落、Q&A 和 SOP 步骤结构切片,保存定位、结构画像和规则版本。
- 精确、近似、语义重复候选;制度版本冲突和基础 claim 冲突检测。
- PII、秘密、跨租户、提示词注入、合成身份和人工审核门禁。
- 人工发布后才建立生产 fragment、数据集成员和向量 outbox。
- 查询证据、差评复核、统一撤回和向量删除闭环。
- 历史 preview/stage、质量指标、告警表、Actuator 健康和评测脚本骨架。
- 不可变术语修订与 AI 案例 provenance。
- 规则版本、状态转换、人工/黄金标签影子评估、误放行/误隔离指标和风险抽样证据;当前只允许 `DRAFT/SHADOW/PAUSED/RETIRED`,不执行自动门禁。
- `pipeline_run` 记录处理阶段、处理器版本、输入输出版本、指标和错误;影子评估按风险自动生成待人工复核样本,管理端可查看规则指标、批次并提交人工抽样结论。调度前先筛选可抽样候选,没有命中风险桶的候选时返回空结果且不创建空处理批次。
- 黄金集和门槛基础设施已在本地落地:黄金集按编码和版本维护,人工样本携带风险、期望决定、reason code 与证据,冻结后生成内容哈希且不可修改;`GOLDEN` 影子评估必须引用冻结样本。规则门槛同样先草稿、后人工冻结,`readiness` 输出分项指标和未达标原因,但 `enforcementEnabled` 固定为 `false`,不开放 `CANARY/ACTIVE`。
仍未完成或不得宣称完成:
- 1,046 份历史附件和 8,607 个旧片段尚未逐份纳管、审核和发布。
- 2026-08-01 最后一次本地隐私链路验证后,治理表保留 2 个待审测试资产,生产 fragment、生产数据集成员、索引 outbox 和 Qdrant 生产点均为 0;这 2 个测试资产不代表历史资料已经纳管。
- 缺失 MinIO 原件的历史资料无法恢复真实来源。
- 业务术语尚未由责任人录入并审核。
- 真实业务 100–300 条黄金样本尚未由责任人录入和冻结;现已具备版本、样本、内容哈希、风险门槛和就绪原因码,但空表和开发样本不得冒充业务标定完成。
- 生产 Qdrant 一致性、外部告警送达、Recall/nDCG 和无答案误召回尚未验收。
- 规则自动执行安全门、差异/聚类审核、真实黄金集标定和更完整的自动化运营指标仍需按 P1 实施;当前工作台不提供 `CANARY/ACTIVE`。
- 本方案没有连接或修改 YCWY,也没有执行历史 staging、人工批准或生产发布。
上述数量是最后一次已记录的本地验证快照,不是实时监控值。2026-08-02 收尾检查时本地后端未运行,未重新查询数据库或 Actuator;再次启动、重置数据或执行历史纳管后必须重新取证。
更细的代码与行号证据以 [data-quality-audit.md](data-quality-audit.md) 第 19 节为准;接口和生产操作不得从本方案反推,分别以 [API_INTEGRATION.md](API_INTEGRATION.md) 和 [KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md) 为准。
## 24. 决策清单
开始实施前,项目负责人需要正式确认:
- [ ] 各知识空间的数据资产负责人和业务审核人。
- [ ] 哪些资产属于高风险制度、标准答案或敏感领域,是否双审。
- [ ] 原件保留期、撤回后的审计保留期和合法删除流程。
- [ ] 各数据用途的准入条件及禁止用途。
- [ ] 第一版 100–300 条黄金集的标注责任人和冻结日期。
- [ ] 自动通过、自动隔离和抽样比例的分风险阈值。
- [ ] 历史纳管优先知识空间与每批 20–50 份的执行窗口。
- [ ] 生产告警接收人、响应时间和死信处理流程。
- [ ] 规则晋级、降级和紧急回滚权限。
- [ ] P0 生产发布、历史治理和业务准确率验收分别签认,不互相冒充。
## 25. 最终验收定义
数字资产体系达到可用状态,不是看“上传成功”或“模型回答看起来不错”,而是同时满足:
1. 新数据不存在任何未经批准进入生产索引的路径。
2. 每个生产 chunk 均可反查原件、版本、处理规则、适用范围和人工批准。
3. 原始、候选、可信、合成、运行和评测数据的用途与索引隔离可被测试证明。
4. 过期、撤回或被替代数据立即停止 MySQL 可见,并最终从向量索引清除。
5. 跨租户、敏感信息、提示词注入和来源不明数据的误放行为 0。
6. 错误回答能通过 requestId 定位污染 chunk,并完成撤回、修订和回归。
7. 自动处理率逐步提高,同时误放行、误隔离和业务准确率有独立证据。
8. 人工审核由逐份机械处理转向异常、冲突、规则和高风险责任确认。
9. 历史批次、规则版本、模型版本和索引 generation 均可回滚且不破坏原始证据。
10. 本地实现、生产部署、历史纳管和业务验收四种状态在所有报告中清晰区分。
这套体系的长期价值不是“把资料洗得更像文本”,而是把企业经验加工成有身份、有证据、有责任、有用途、可持续演进的数字资产,并让自动化在可测量、可解释和可回退的边界内不断替代重复人工工作。
+150
View File
@@ -248,3 +248,153 @@ node scripts/verify-knowledge-platform.mjs
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:<sha256>` 授权串,不写数据库。仅在独立获得该完整授权串后,才可设置 `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 条经业务专家确认、覆盖多租户/版本/正反案例/无答案问题的黄金集标定。
+2
View File
@@ -32,6 +32,8 @@
| [FIGMA需求覆盖与版本偏差审计-20260717.md](FIGMA需求覆盖与版本偏差审计-20260717.md) | 旧版功能、已确认需求、Figma 实际画板与当前实现的四方对照,以及防止遗漏旧功能和误拉后续阶段的事实源规则 |
| [DEMO_ACCEPTANCE.md](DEMO_ACCEPTANCE.md) | 一期 MVP 演示脚本、录屏兜底、MVP 演示流验收清单 |
| [API_INTEGRATION.md](API_INTEGRATION.md) | 后端 API 对接顺序、数字师傅 Agent、正式试点 CSV、移动端训练/复盘、候选资料和 SOP 接口 |
| [DIGITAL_ASSET_PROCESSING_GOVERNANCE.md](DIGITAL_ASSET_PROCESSING_GOVERNANCE.md) | 企业数字资产从原始保存、规范化、结构化、质量门禁、人工审核到发布、撤回和规则自动化演进的总体方案 |
| [data-quality-audit.md](data-quality-audit.md) | 数据质量、脏数据治理、信任边界、数据血缘与当前本地实施证据的只读审计基线 |
| [superpowers/specs/2026-07-24-digital-master-agent-design.md](superpowers/specs/2026-07-24-digital-master-agent-design.md) | “问”模块最终 Agent 产品/架构边界,以及当前已实现与后续工具范围 |
| [superpowers/plans/2026-07-24-digital-master-agent.md](superpowers/plans/2026-07-24-digital-master-agent.md) | Agent 实施、自动化/H5/浏览器验证记录和剩余专项生产/真机验收边界 |
| [superpowers/plans/2026-07-31-mobile-citation-source-viewer.md](superpowers/plans/2026-07-31-mobile-citation-source-viewer.md) | 手机端回答引用点击全文、图片和视频定位的分阶段实施计划;每阶段必须记录自动化、权限、Range、性能、生产和真机实际结果 |
+495
View File
@@ -0,0 +1,495 @@
# prop-ai-hr 数据质量与脏数据治理专项审计
> 实施状态(2026-08-02):本报告正文保留改造前的只读审计基线。当前工作树已在本地完成 P0 主门禁,并落地 P1 的版本化规范化、独立隐私脱敏派生与复扫、结构感知切片、SimHash 近重复、异步语义重复候选、同名版本冲突、确定性 claim 级冲突证据、带管理端人工审核的版本化术语表,以及 P2 的索引死信健康度、真实召回证据、答案争议回到具体 chunk/asset 的人工 `KEEP/WITHDRAW` 闭环、持久化质量告警、Actuator 健康项和可失败的黄金检索评测门禁。`dq-gate-v3` 还会以软 reason code 标记页码、重复页眉页脚、领域无关、案例上下文缺失和孤立片段,不改写原文、不自动拒绝或批准。历史附件可通过只读预览和带 manifest 的 CLI 按游标恢复纳管;任何历史数据都不能自动批准。AI 整理案例会永久保存 synthetic、模型/生成器、prompt 版本、原始音频和人工审核 provenance。100–300 条真实业务黄金集标注、复杂适用条件阈值标定、生产告警平台接入和全量历史重清洗尚未完成。该状态不代表生产部署或业务资料已获批准。
>
> 快照说明:正文中的“本地 MinIO 为空、Qdrant collection 不存在”等数据是第一阶段只读审计时的基线,不是 2026-08-01 本地 E2E 完成后的运行状态;最新实施证据见第 19 节。
> 审计日期:2026-08-01
> 审计方式:代码、SQL 迁移、测试及本地运行数据的只读审计
> 审计结论适用范围:当前工作区(包括审计时已经存在、尚未提交的引用定位器改动)与本机开发数据快照;不等同于生产数据全量结论
> 第一阶段变更边界:只生成本报告,未修改业务代码、配置、数据库、对象存储或向量索引;后续本地实施状态见第 19 节
## 1. 执行摘要
当前系统已经具备若干有价值的局部控制:知识查询以服务端计算“租户 + 调用应用 + 主体授权”的空间交集;文件接入有大小/解析失败处理和文件、文本哈希精确去重;正式制度查询有来源权威性、版本、审批、生效和失效日期门禁;个人知识有私有对象存储、所有权校验、精确哈希去重、发布审核和确定性脱敏;陪练场景有内容版本、哈希和高风险双人审核;考试发布和显式记忆也有人工或用户确认。
但这些控制没有形成统一的数据质量生命周期。普通企业资料的主路径实际是:上传或导入后,只要解析出非空文本,就直接切片写入 `aihr_knowledge_fragment`,随后向量化并可被普通检索使用。该路径没有通用的隐私检查、领域验证、上下文完整性检查、近重复/语义重复、质量原因码、隔离区或人工批准门禁。结论是:**当前存在 `RAW/PARSED -> INDEXED` 直接路径,目标生命周期并未全局落地。**
最高风险还包括:个人经验经一次发布审核后直接写入企业知识表;模型整理或兜底总结可直接把案例标成“已入库”;考试生成从租户全部片段取材,未复用文档批准/有效期门禁;向量删除失败仅尽力忽略,没有持久化重试;查询审计没有记录具体片段修订,错误答案无法从 `request_id` 稳定反查污染版本。普通企业 RAG 还把片段原文直接拼进提示词,缺少个人问答路径已有的“来源是不可信数据、不得执行其中指令”边界。
本地只读快照进一步证明风险已经落地,而不只是理论可能:1,046 个附件全部处于“已解析”,8,607 个片段中检测到 1,897 个全局精确重复余量、1,178 个疑似页码/分页噪声命中、19 个含 UTF-8 替换字符的片段、6 个找不到附件的片段;1,207 个上传任务中 94 个失败,失败率 7.79%。正式来源治理仅覆盖 10 个附件,约占附件数 0.96%。本地 Qdrant collection 不存在,本地两个 MinIO bucket 均无对象,因此本机数据库中的原文可恢复性和向量一致性无法成立。一次真实移动端请假/考勤问题还召回了招聘、垃圾站保洁、防汛等无关引用,属于已观察到的检索相关性失败。
建议按最小增量方式修复,不整体重写现有知识平台:保留 `sys_oss`、`aihr_knowledge_*` 和现有权限模型,新增不可变原始资产、版本、质量评估、问题明细、审核决策、片段修订、血缘和索引 outbox 侧表。生产检索只允许读取 `PUBLISHED` 且版本有效的片段修订;普通上传、个人发布、案例和 AI 生成内容统一先进入隔离/待审区。P0 应优先关闭新污染入口、建立可靠撤回与片段级审计,再迁移历史数据。
## 2. 审计方法与边界
### 2.1 审计方法
1. 由 HTTP Controller 反向跟踪上传、导入、检索、案例、考试、陪练、个人知识、记忆和反馈到 Service、SQL 与存储对象。
2. 检查解析器、文本规范化、切片、哈希去重、embedding、Qdrant payload/filter、删除与重建代码。
3. 检查知识、个人知识、案例、陪练、考试、记忆、反馈、组织快照相关建表和增量迁移。
4. 检查现有单元测试中对租户、所有权、审批、去重、正式制度和失败路径的断言。
5. 对本机 MySQL、Qdrant 和 MinIO 做只读计数、孤儿关系、重复、字符异常及运行状态检查;未读取或披露业务正文、姓名、手机号和密钥。
### 2.2 证据口径与限制
- 文件行号指向审计时工作区,不保证后续代码变更后仍保持相同行号。
- 本地数据库来自当前开发环境,只说明本地快照;不能外推为生产全量数据质量。
- 本地 MinIO 无对象、Qdrant collection 不存在,因此未能验证远端原文件完整性、生产向量数量和线上删除一致性。
- “有”表示所审计主路径存在明确、不可绕过的控制;“部分”表示只覆盖特定格式、来源、意图或入口;“无”表示未找到足够代码证据。
- 当前未发现独立训练流水线。本文所称“训练集/评测集泄漏”同时覆盖陪练、考试、评分、案例等可被误作训练或评测语料的业务数据。
## 3. 当前数据血缘图
```mermaid
flowchart LR
A["原始来源<br/>企业文件/ZIP/本地目录/API<br/>个人文本/文件/URL<br/>案例录音/用户对话/组织 API"]
B["接入与暂存<br/>Controller + UploadQueue<br/>sys_oss / staging_path / personal MinIO"]
C["解析<br/>Tika / OCR / 视频抽帧 / ASR / URL fetch"]
D["规范化与分类<br/>换行+trim / LLM或规则分类<br/>文件与文本哈希精确去重"]
E["切片<br/>空段落 + 字符硬切 + overlap"]
F["事实存储<br/>aihr_knowledge_attach<br/>aihr_knowledge_fragment<br/>个人/案例/陪练/考试/记忆表"]
G["向量化<br/>embedding provider<br/>Qdrant aihr_knowledge"]
H["检索<br/>MySQL FULLTEXT/LIKE + Qdrant<br/>tenant + app + principal space"]
I["模型生成<br/>RAG 答案/案例总结/考试题/评分/记忆草稿"]
J["用户交互<br/>问师傅/案例/陪练/考试/反馈"]
K["回流<br/>query log/answer feedback/review<br/>practice session/calibration/memory"]
A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K
K -. "当前无统一批准后回流" .-> F
C -. "非空即可" .-> E
F -. "普通资料无文档批准过滤" .-> H
```
### 3.1 企业知识主链路
| 节点 | 实际入口、函数与存储 | 证据 |
|---|---|---|
| 接入 | `POST /api/knowledge/doc/upload-async`;`AihrSopController.uploadAsync` 调用 `AihrUploadQueueService.enqueue`。另有同步 `/doc/upload`、本地目录 `/doc/import-local` 和 `/doc/import-local-task` 运维入口 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSopController.java:73`、`:188`、`:206`、`:212` |
| 队列 | `AihrUploadQueueService.processItem` 从 `aihr_knowledge_upload_item.staging_path` 取文件,转入 `processStagedDocument`,结果仅以片段数是否大于 0 判定完成 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrUploadQueueService.java:350`、`:388`、`:396` |
| 解析 | 普通文档走 `TikaKnowledgeDocumentParser`;图片走视觉 OCR,视频走关键帧/转写相关分支。Tika 输出全文、metadata 和按行段;嵌入文档明确不解析 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/parse/TikaKnowledgeDocumentParser.java:117`、`:132`、`:166`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4022`、`:4050`、`:4092` |
| 清洗 | `normalizeExtractedText` 只统一换行并 `trim`;没有通用页眉页脚、页码、水印、控制字符、PII 或领域规则 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4226` |
| 分类/去重 | 计算文件 SHA-256、MD5、文本 SHA-256;通过 `duplicateHit` 复用精确重复附件;分类 insight 可来自模型或兜底 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1262`、`:1263`、`:1727`、`:1755` |
| 切片 | `split` 按空段落组块,超长内容按字符硬切,并加 overlap;片段无独立修订号/规则版本 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4240`、`:4252`、`:4264` |
| 原文/附件 | 原文件通常写 `sys_oss`,文档成员写 `aihr_knowledge_attach`;其 `status=2` 仅表示解析完成,不是质量批准 | `backend/script/sql/aihr_knowledge_mysql8.sql:34`、`:43`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1279`、`:1282` |
| 片段 | 删除同文档旧片段后,直接插入 `aihr_knowledge_fragment`,随后标记附件已解析 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1296`、`:1299`、`:1308` |
| 定位 | 当前工作区新增 `aihr_knowledge_fragment_locator`;企业导入仍丢弃解析器 segments,定位回填主要以切片序号模拟段落,不能证明 PDF 页/PPT 页/Excel 行 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4091`、`:4095`;`backend/script/sql/aihr_knowledge_mysql8.sql:95` |
| 向量化 | 每个片段 embedding 后 upsert Qdrant,payload 为 `tenant_id/knowledge_id/category/doc_id/idx/embedding_model` | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:2269`、`:3737`、`:3757` |
| 检索 | `/api/knowledge/search` 进入统一查询;MySQL FULLTEXT、LIKE、向量结果都以租户和授权空间为核心条件 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSopController.java:105`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3052`、`:3103`、`:3164` |
| 权限 | 服务端计算应用空间、主体授权空间、请求空间的交集;Qdrant 过滤包含租户和空间 ID | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeAccessService.java:23`、`:57`、`:66`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3945` |
| 生成 | 检索片段拼入企业 RAG prompt,模型生成答案;引用再从片段表 hydrate | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3331`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryService.java:648` |
| 回流 | 写 `aihr_knowledge_query_log`、`aihr_sop_answer_review`、`aihr_knowledge_answer_feedback`;差评只屏蔽相同规范化问题与片段组合 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryAuditService.java:23`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:2975` |
### 3.2 特殊来源与生成链路
| 数据流 | 当前实际路径 | 是否进入企业可信区 |
|---|---|---|
| 正式制度 | 普通知识接入后,另由 `aihr_knowledge_source_governance` 登记 `APPROVED`、版本、生效/失效日期;只有识别为正式制度意图时附加过滤 | 特殊意图受控;普通检索仍可能命中相同片段。证据:`backend/script/sql/update/aihr_20260730_formal_knowledge_source_governance_mysql8.sql:5`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryService.java:662` |
| 个人知识 | `POST /api/aihr/personal-assistant/items/text|file|url` -> 私有 item/fragment;HR/超级管理员审核发布 -> 脱敏后的 fragment 直接复制到企业知识表 | 是,审批后直接写企业表,但绕过通用附件/版本/质量/重新解析链。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java:89`、`:94`、`:103`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalPublishService.java:107`、`:232` |
| 案例录音 | `/api/knowledge/case/upload` -> OSS + ASR -> `aihr_case_record`;`organize` 用模型或本地兜底总结;`curate` 直接标“已入库”;主管 `review` 只是事后点评 | 是案例库可见数据,但没有前置发布审批。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrCaseController.java:53`、`:61`、`:69`、`:108`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrCaseService.java:96`、`:107`、`:127` |
| AI 考试题 | `AihrExamService.generateDraft` 从租户片段抽取 grounding,模型/规则生成草稿;主管创建并发布考试 | 不直接自动发布,但 grounding 未要求来源批准、附件有效或授权空间。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/learning/AihrExamService.java:185`、`:482`、`:541` |
| 陪练 | 用户回答、音频、LLM/seed 评分写 session/assignment;可选 calibration 保存人工校准 | 不写企业知识表,但属于运行/评测数据,当前缺少统一 synthetic、置信度、模型版本和数据用途隔离。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java:1513`;`backend/script/sql/aihr_practice_mysql8.sql:27`、`:168` |
| 陪练场景 | 场景有草稿、待业务审核、已发布、已下线;高风险需不同用户双审并校验内容版本/哈希 | 局部强控制。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java:599`、`:675`、`:696`;`backend/script/sql/aihr_practice_mysql8.sql:184` |
| 显式记忆 | 模型/规则先给候选项,用户确认后进入 PRIVATE;COMPANY 捕获保持 `PENDING`;召回走独立记忆表 | 当前未直接写企业知识片段,控制较好。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/memory/AihrMemoryService.java:517`、`:859`、`:900` |
| 组织 API 同步 | `/api/aihr/org/sync-changes` 写组织快照;要求显式 dry-run,重复成员和异常数据可 fail closed | 影响身份/授权而非知识正文;属于重要旁路数据。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrOrgSyncController.java:24`、`:39`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java:208`、`:301` |
## 4. 当前数据对象和存储结构
| 数据域 | 主要对象/表 | 当前角色与关键缺口 |
|---|---|---|
| 原文件 | `sys_oss`、MinIO `ruoyi` | 保存对象与扩展元数据;没有独立不可变业务资产版本、采集来源可信等级和保留策略。`sys_oss.ext1` 中有文件/文本哈希和自动分类元数据,但更新失败被忽略:`AihrSopSeedService.java:1813-1826`。 |
| 企业空间 | `aihr_knowledge_info`、`aihr_knowledge_category`、`aihr_knowledge_acl` | 空间状态为 `DRAFT/ACTIVE/DISABLED`,是空间级开关,不是文档/片段质量状态:`backend/script/sql/aihr_knowledge_mysql8.sql:4`、`:11`。 |
| 企业附件 | `aihr_knowledge_attach` | 只有解析状态 `0/1/2/3`;`2=已解析` 被界面称作“可引用资料”,不代表质量批准:`backend/script/sql/aihr_knowledge_mysql8.sql:34`、`:43`;`AihrSopSeedService.java:1830-1843`。 |
| 企业片段 | `aihr_knowledge_fragment`、`aihr_knowledge_fragment_locator` | 正文、embedding、doc/idx 和定位;无来源版本、质量状态、原因码、规则版本、有效期、synthetic/runtime 标记和修订历史:`backend/script/sql/aihr_knowledge_mysql8.sql:73`、`:95`。 |
| 正式来源 | `aihr_knowledge_source_governance` | 有来源 ID、附件、版本、权威类型、生命周期、生效/失效、内容哈希;只覆盖正式制度专用路径:`backend/script/sql/update/aihr_20260730_formal_knowledge_source_governance_mysql8.sql:5-30`。 |
| 应用与授权 | `aihr_knowledge_app`、`aihr_knowledge_app_space`、`aihr_knowledge_space_grant` | 支持租户、应用、主体授权交集;这是访问控制,不替代内容质量审批:`backend/script/sql/aihr_knowledge_mysql8.sql:249`、`:266`、`:288`。 |
| 处理任务 | `aihr_knowledge_upload_item`、`aihr_knowledge_import_task` | 记录等待/处理中/完成/失败和错误文本;没有阶段级质量结果、reason code 列表、检测器版本和人工处置:`backend/script/sql/aihr_knowledge_mysql8.sql:149`、`:228`。 |
| 查询与反馈 | `aihr_knowledge_query_log`、`aihr_sop_answer_review`、`aihr_knowledge_answer_feedback`、`aihr_knowledge_gap` | 有请求、状态、来源类型、提示词版本和特定 query-fragment 差评;缺精确使用片段修订、排名、模型/embedding 版本、答案 hash 及处置闭环:`backend/script/sql/aihr_knowledge_mysql8.sql:300`;`backend/script/sql/aihr_practice_mysql8.sql:283`、`:296`、`:318`。 |
| 个人知识 | `aihr_personal_item`、`aihr_personal_fragment`、OCR job/page、cleanup job、publish request | 所有权、私有存储、精确 hash、处理和发布状态较完整;但批准发布时仍复制进通用企业片段,丢失完整个人来源版本链:`backend/script/sql/aihr_personal_knowledge_mysql8.sql:35`、`:64`、`:132`、`:190`。 |
| 案例 | `aihr_case_record` | 原转写、AI 总结、主管点评和状态同表;状态主要是流程展示,不足以区分 raw/trusted/synthetic:`backend/script/sql/aihr_practice_mysql8.sql:4-24`。 |
| 陪练与评分 | `aihr_practice_session`、`assignment`、`calibration`、`scenario`、`rubric` | 保存回答、AI 分数、规则兜底、人审校准及内容版本;运行数据和评测用途没有统一数据资产标记:`backend/script/sql/aihr_practice_mysql8.sql:27`、`:137`、`:168`、`:184`。 |
| 考试 | `aihr_onboard_exam*` | 草稿/发布、题目正确答案、员工答案和得分;AI 题来源未绑定具体已批准 chunk revision:`backend/script/sql/update/aihr_20260717_learning_closure_mysql8.sql:102`、`:161`、`:189`。 |
| 记忆 | `aihr_service_memory*`、assistant capture | 候选、确认、拒绝、过期和公司 pending 独立于知识片段,边界相对清晰:`backend/script/sql/aihr_service_memory_mysql8.sql:14`。 |
## 5. 信任边界分析
| 内容类型 | 是否存在直接进入可信/生产使用区的路径 | 现有控制 | 结论与证据 |
|---|---|---|---|
| 未审核上传文件 | 是 | 角色限制、非空、解析状态、精确重复 | 非空即写片段并 embedding,无通用审批:`AihrSopController.java:73-84`;`AihrSopSeedService.java:1243-1308`。P0。 |
| OCR 结果 | 是 | 图片/视频无结果可待处理;个人 PDF 有分页失败状态 | 企业 OCR 有文本即可进入同一片段链,未保留置信度和逐页证据:`AihrSopSeedService.java:673`、`:4050`。P0。 |
| 录音转写 | 部分是 | 案例上传需登录/项目权限 | 转写进入案例,整理/入库无前置质量审核:`AihrCaseController.java:53-74`;`AihrCaseService.java:96-124`。P1。 |
| 员工个人经验 | 是 | 个人区隔离;发布需 HR/超级管理员审核和确定性脱敏 | 一次批准后直接复制到企业知识表,不走版本/质量链:`PersonalPublishService.java:107-159`、`:232-264`。P0。 |
| 信息不完整案例 | 是 | 可由主管事后点评 | `curate` 不检查必填证据、上下文、结论依据,直接标已入库:`AihrCaseService.java:107-124`。P1。 |
| 用户回答 | 否(企业知识),是(运行/评分表) | 身份、会话和项目范围;部分人工校准 | 没有发现自动写入知识片段的路径;但评分/未来训练用途无统一 consent/purpose/split 标记:`aihr_practice_mysql8.sql:27-75`、`:168-182`。P1。 |
| 模型回答 | 否(企业知识),是(日志/评审) | 有引用和问答评审表 | 未发现自动提升为企业知识;审计却不能稳定记录用过的 chunk revision:`AihrKnowledgeQueryAuditService.java:23-37`。P1。 |
| AI 生成案例 | 是(案例库) | 操作者需有案例管理权限 | 模型失败还会用本地兜底,随后可直接已入库;没有 synthetic 标记和批准门:`AihrCaseService.java:96-124`。P0/P1 边界,按 P1 排期但必须与 P0 门禁一起封堵。 |
| AI 生成标准答案/考试题 | 否(自动发布),但来源可污染 | 生成草稿后由主管创建/发布,试卷总分等有校验 | grounding 从全部租户片段读取,未过滤批准、空间和附件有效性:`AihrExamService.java:482-568`;发布控制:`:185-251`。P1。 |
| AI 生成评分 | 是(业务结果) | `score_mode`、rubric snapshot、可选 calibration | LLM 失败退 seed,结果直接用于 session/assignment;人审不是强制,缺模型/置信度/异常 reason:`AihrPracticeSeedService.java:1513-1539`;`aihr_practice_mysql8.sql:157-177`。P1。 |
| 旧版本制度 | 是,普通检索可命中 | 正式制度意图有版本、生效/失效门禁 | 门禁只在 `formalPolicyOnly` 分支,普通检索不要求治理行:`AihrKnowledgeQueryService.java:648-713`。P0。 |
| 来源不明数据 | 是 | 文件名、OSS、remark、部分 hash | 普通片段不要求来源所有者、权威性、版本、采集时间和适用范围。P0。 |
| 跨租户数据 | 主查询未发现直接路径;索引漂移仍有残余风险 | SQL tenant 条件、空间交集、Qdrant tenant filter | 服务端隔离较强:`AihrKnowledgeAccessService.java:23-104`;`AihrSopSeedService.java:3945-3956`。但向量删除失败无可靠补偿,必须做一致性审计。P1。 |
## 6. 脏数据类型覆盖矩阵
| 脏数据类型 | 是否已处理 | 处理位置/方式 | 可绕过路径 | 风险 | 代码证据 |
|---|---|---|---|---|---|
| 空内容 | 部分 | Tika 空文本抛错;企业保存拒绝 blank;图片/视频无视觉结果保持待处理 | 仅检查整体非空,极短、只有页眉页脚或无语义文本仍可入库 | 中 | `TikaKnowledgeDocumentParser.java:117-124`;`AihrSopSeedService.java:1250-1256` |
| 乱码和解析失败 | 部分 | 解析异常、大小限制、任务失败/重试 | 未检测替换字符、控制字符、异常编码比例;本地有 19 个含 `U+FFFD` 片段 | 高 | `TikaKnowledgeDocumentParser.java:105-123`;`AihrUploadQueueService.java:410-417` |
| 文档缺页 | 无(通用) | 个人 PDF OCR 有 page/job 状态和 partial | 企业 Tika 丢失真实分页结构,也没有声明页数与解析页数比对 | 高 | `TikaKnowledgeDocumentParser.java:128-143`;`PersonalPdfOcrService.java:436-444` |
| 精确重复 | 部分 | 企业文件/文本 SHA-256;个人内容 hash | 片段级重复、不同包装/页眉差异、跨空间重复仍存在;本地全局重复余量 1,897 | 中 | `AihrSopSeedService.java:1262-1267`、`:1755-1788`;`PersonalIngestionService.java:171-203` |
| 近重复 | 无 | 未发现 MinHash/SimHash/edit distance 规则 | 改空格、页眉、格式或少量措辞即可绕过精确 hash | 高 | `AihrSopSeedService.java:1262-1267` |
| 语义重复 | 无 | 未发现聚类/相似度阻断或审核队列 | 同义改写、不同专家复述都能并存并进入召回 | 高 | `AihrSopSeedService.java:1296-1306` |
| 来源不明 | 部分 | OSS、文件名、docId、remark;正式制度有 source registry | 普通资料、个人发布生成的企业片段不要求权威来源和稳定版本 | 严重 | `aihr_knowledge_mysql8.sql:34-92`;`PersonalPublishService.java:232-254` |
| 领域无关 | 无(通用) | LLM/规则自动分类只决定空间/标签 | 分类结果不形成阻断或 reason code;已观察到跨主题错误召回 | 严重 | `AihrSopSeedService.java:1263-1269`、`:1296-1308` |
| 上下文不完整 | 无 | 切片带 overlap;回答提示要求依据片段 | 字符硬切、表格/页码结构丢失,无法验证片段是否自洽 | 高 | `AihrSopSeedService.java:4240-4269`;`aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql:7-8` |
| 结论无依据 | 部分 | RAG prompt 要求只基于片段;正式制度再做相关证据判断 | 原片段自身可能无来源/不可信;案例总结、考试题和评分可由模型/兜底直接产生 | 严重 | `AihrKnowledgeQueryService.java:704-710`;`AihrCaseService.java:96-124` |
| 错误标签 | 无(通用) | insight 保存 `classifiedBy/reason/tags` | 没有确定性校验、人工确认状态和标签版本;分类失败不阻断入库 | 高 | `AihrSopSeedService.java:1264-1269`、`:1818-1824` |
| 制度过期 | 部分 | 正式制度意图检查 `APPROVED`、生效/失效和版本 | 普通知识查询、考试 grounding 不执行该条件 | 严重 | `AihrKnowledgeQueryService.java:662-680`;`AihrExamService.java:482-538` |
| 多版本冲突 | 部分 | 正式制度 `source_id/source_version` 唯一登记;陪练场景有版本/hash | 普通资料无 supersedes/有效期;新上传不会自动下线旧版 | 严重 | `aihr_20260730_formal_knowledge_source_governance_mysql8.sql:8-27`;`aihr_knowledge_mysql8.sql:34-92` |
| 多专家意见冲突 | 无 | 未发现 claim/观点级冲突模型和仲裁状态 | 多份专家经验可同时发布/召回,无法表达适用条件和异议 | 高 | `PersonalPublishService.java:232-264` |
| 未脱敏个人信息 | 部分 | 个人发布使用确定性 sanitizer;工作投稿另有隐私警告 | 普通企业上传/OCR/ASR 无通用 PII 扫描;上传角色可信不能代替内容脱敏 | 严重 | `PersonalPublishService.java:139-151`;`PersonalPromptSanitizer.java:10-62` |
| 跨租户数据 | 有(检索主链)/部分(索引一致性) | SQL tenant、应用/主体/请求空间交集、Qdrant tenant payload/filter | 删除失败、历史错误 payload 或旁路直写需靠对账发现;当前无 outbox/reconciler | 高 | `AihrKnowledgeAccessService.java:23-104`;`AihrSopSeedService.java:3737-3748`、`:3945-3956` |
| 提示词注入 | 部分 | 个人 QA 明确把来源当不可信并 XML 隔离 | 企业 RAG 将片段原文直接拼入 prompt,未找到等价指令隔离 | 严重 | `PersonalAnswerService.java:249-274`;`AihrSopSeedService.java:3331-3381` |
| AI 合成数据污染 | 部分 | 考试先草稿后人工发布;记忆需确认 | 案例自动“已入库”;个人发布/企业片段无统一 `is_synthetic/generator`;LLM 分类无版本化门禁 | 严重 | `AihrCaseService.java:96-124`;`AihrExamService.java:185-251` |
| 运行日志回流污染 | 部分 | 当前未发现 query log、agent run 自动写入企业片段;记忆独立且需确认 | 缺统一 data purpose 和 lineage,未来离线导出/训练难以防误用;案例和陪练运行表仍可被当语料 | 高 | `aihr_knowledge_mysql8.sql:300-372`;`AihrMemoryService.java:859-942` |
| 训练集和评测集泄漏 | 无 | 未发现正式 split registry、样本 hash、时间切分或用途限制 | 考题、参考答案、员工答案、AI 评分、案例同处业务库,离线抽取无法证明隔离 | 高 | `aihr_20260717_learning_closure_mysql8.sql:151-200`;`aihr_practice_mysql8.sql:137-182` |
## 7. P0、P1、P2 问题清单
### P0:必须先阻止新增污染或越权可信化
**P0-1 普通资料非空即可进入生产片段和索引。** 解析、切片、写 MySQL、embedding 在同一保存流程连续执行,缺少 `PRIVACY_CHECKED -> DOMAIN_VALIDATED -> QUALITY_EVALUATED -> APPROVED` 门禁。证据:`AihrUploadQueueService.java:350-417`;`AihrSopSeedService.java:1243-1314`、`:2269-2312`。影响所有普通文件、OCR/视频文本、同步上传和运维导入。
**P0-2 生产检索不要求文档/片段批准与有效版本。** 普通 FULLTEXT、LIKE、向量 hydrate 仅约束租户/空间等条件;只有正式制度意图附加 governance 条件。证据:`AihrSopSeedService.java:2949-2972`、`:3052-3200`;`AihrKnowledgeQueryService.java:648-713`。旧制度、低质量和待处置片段可被正常问答使用。
**P0-3 个人发布可直接污染企业可信表。** 审核与脱敏值得保留,但发布器直接新建企业空间并写 `aihr_knowledge_fragment`,没有附件、不可变来源版本、质量评估、重切片或索引生命周期。证据:`PersonalPublishService.java:107-159`、`:232-264`。
**P0-4 撤回与向量删除不是可靠事务。** 文档解绑先删 MySQL,Qdrant 删除异常被捕获并忽略;没有 durable outbox、重试、死信和对账修复。证据:`AihrSopSeedService.java:842-881`、`:3763-3780`。结果可能是 SQL 已撤回但向量仍残留,且无法证明最终一致。
**P0-5 来源、版本和可追溯性不足。** 普通片段没有稳定 source/version、有效期、适用范围、规则版本和修订;当前 locator 也不能恢复真实 PDF 页/PPT 页/Excel 行。证据:`aihr_knowledge_mysql8.sql:34-119`;`TikaKnowledgeDocumentParser.java:117-143`;`AihrSopSeedService.java:4091-4122`。
**P0-6 企业 RAG 缺少来源指令隔离。** 个人 QA 明确声明来源不可信并转义,企业 RAG 没有等价边界,恶意文档可尝试覆盖系统指令。证据:`PersonalAnswerService.java:249-274`;`AihrSopSeedService.java:3331-3381`。
### P1:P0 门禁建立后立即治理
**P1-1 清洗和结构恢复过弱。** 目前主要是换行/trim 与字符切片,不能处理页眉页脚、目录、水印、表格、OCR 置信度、控制字符和段落重复。本地 1,178 个疑似页码噪声、19 个替换字符、195 个小于 40 字片段构成直接证据。代码:`AihrSopSeedService.java:4226-4269`。
**P1-2 只有精确文档去重,没有近重复、语义重复和冲突检测。** 本地 8,607 个片段中,全局精确重复余量 1,897,同空间 560,同文档 422。代码:`AihrSopSeedService.java:1262-1267`、`:1755-1788`。
**P1-3 AI/兜底案例可直接标“已入库”。** 主管 review 是事后评论,不是发布前审核;缺 synthetic、generator、grounding 和证据完整性。证据:`AihrCaseService.java:96-138`、`:299-333`。
**P1-4 AI 考试题的 grounding 绕过知识批准和授权范围。** 草稿发布有人审,但底层素材来自租户全部片段,可能吸收过期、跨岗位或未批准内容。证据:`AihrExamService.java:482-568`。
**P1-5 AI 评分被作为业务结果,校准非强制。** LLM 与 seed fallback 都生成实际分数,需记录模型、prompt/rubric、置信度、fallback reason 并对高风险结果抽审/强审。证据:`AihrPracticeSeedService.java:1513-1539`;`aihr_practice_mysql8.sql:168-182`。
**P1-6 查询审计无法反查确切污染修订。** 日志只存问题 hash、空间、来源类型、状态、时延和 prompt version,不存 fragment revision IDs、排名、分数、答案 hash、生成模型。证据:`AihrKnowledgeQueryAuditService.java:23-37`;`aihr_knowledge_mysql8.sql:300-317`。
**P1-7 反馈没有形成源数据隔离闭环。** downvote 只屏蔽“相同规范化问题 + fragment”组合,不会降低全局质量状态、隔离来源或触发再审。证据:`AihrSopSeedService.java:2975-3010`;`aihr_practice_mysql8.sql:318-337`。
**P1-8 数据质量监控不足。** 处理概览只有完成、处理中、失败、片段和 embedding 数,并把解析成功称为“可引用资料”;没有重复率、乱码率、PII、过期、隔离、索引漂移、审批时长和质量告警。证据:`AihrSopSeedService.java:1830-1873`。
### P2:治理能力完善与运营优化
**P2-1 缺 claim/观点级冲突模型。** 制度冲突、专家意见冲突只能靠文档级人工发现,无法让检索优先选择当前有效结论。
**P2-2 缺统一数据用途和同意记录。** 用户回答、对话、音频、评分、日志虽然没有自动进入企业知识,但没有统一的 `purpose/consent/retention/training_eligible` 控制,未来离线使用容易污染训练和评测。
**P2-3 缺独立基准数据集与回归门禁。** 现有测试覆盖若干权限和业务状态,但未发现跨格式脏数据 corpus、检索黄金集、跨租户 canary、污染注入和 train/eval 泄漏检测套件。
**P2-4 局部状态语义不统一。** 附件“已解析”、案例“已入库”、个人 item “READY”、空间“ACTIVE”、场景“已发布”分别由业务模块定义,无法回答一个资产是否已清洗、已批准、已索引、已失效。
## 8. 重点架构问题逐项结论
| # | 问题 | 结论 |
|---|---|---|
| 1 | `RAW -> INDEXED` 直接路径 | **存在。** 普通资料非空后写片段并 embedding:`AihrSopSeedService.java:1243-1308`。 |
| 2 | `MODEL_OUTPUT -> TRUSTED_KNOWLEDGE` 直接路径 | **存在于案例;个人发布存在人工批准后直写。** 案例模型/兜底总结可直接已入库:`AihrCaseService.java:96-124`。模型回答和显式记忆未发现直接写企业片段。 |
| 3 | raw/trusted/synthetic/runtime 混表或混 collection | **存在混合。** `aihr_knowledge_fragment` 没有 trust/origin 字段;个人发布片段与上传片段混用;案例 raw transcript、AI summary、review 同表。Qdrant 只有默认 collection。 |
| 4 | 单一 `is_clean`/综合分,缺原因码 | **不是“只有 is_clean”,而是通用质量状态和原因码整体缺失。** 上传 error 和反馈 reason 只覆盖局部故障/回答反馈。 |
| 5 | 无来源、版本、范围、有效期 | **普通资料存在。** 正式制度和陪练场景是局部例外。 |
| 6 | 发布后不能撤回或不能同步清索引 | **可发起解绑,但不能保证同步清除。** Qdrant 删除失败被忽略,无持久重试:`AihrSopSeedService.java:3763-3780`。 |
| 7 | 清洗覆盖原始内容 | **原文件通常保存在 OSS,未发现清洗回写覆盖对象。** 但本地 MinIO 为空,且缺不可变业务版本约束,不能证明所有历史原文可恢复。 |
| 8 | LLM 是唯一质量判断者 | **部分存在。** 自动分类/案例总结缺人工质量门;考试发布和高风险场景有人审。 |
| 9 | LLM 自行删除、批准或发布 | **未发现 LLM 直接调用删除/批准 API。** 但服务代码会把 LLM/兜底案例结果直接置为已入库,效果等价于缺前置人审。 |
| 10 | 清洗规则修改后无法识别旧规则版本 | **存在。** 片段无 parser/normalizer/chunker/rule version。locator 仅有自身 `locator_version`。 |
| 11 | 错误回答无法反查具体污染 chunk | **存在。** 引用响应含 fragment ID,但持久 query log 不保存片段修订集合:`AihrKnowledgeQueryAuditService.java:23-37`。 |
| 12 | 多租户只在前端/Prompt | **否。** SQL、应用/主体授权交集和 Qdrant filter 均在服务端;残余风险是索引漂移与旁路数据而非纯前端隔离。 |
## 9. 建议的数据状态机
目标状态机是数据资产的统一治理主状态,不替换上传任务、OCR job 等技术状态。
```mermaid
stateDiagram-v2
[*] --> RAW
RAW --> PARSED: parser 成功,保留原文与解析产物
RAW --> QUARANTINED: 空/损坏/恶意文件
PARSED --> NORMALIZED: 确定性清洗完成
NORMALIZED --> CLASSIFIED: 来源/领域/范围分类
CLASSIFIED --> DEDUPLICATED: 精确/近似/语义去重
DEDUPLICATED --> PRIVACY_CHECKED: PII 与秘密检查
PRIVACY_CHECKED --> DOMAIN_VALIDATED: 领域和适用范围验证
DOMAIN_VALIDATED --> QUALITY_EVALUATED: 结构/依据/时效/冲突评分
QUALITY_EVALUATED --> QUARANTINED: 阻断 reason code
QUALITY_EVALUATED --> REVIEW_PENDING: 需人工判断
QUALITY_EVALUATED --> APPROVED: 低风险自动规则通过
REVIEW_PENDING --> APPROVED: 授权审核人批准
REVIEW_PENDING --> QUARANTINED: 驳回/待补充
APPROVED --> PUBLISHED: outbox 索引成功并校验
PUBLISHED --> DEPRECATED: 撤回/过期/被新版本替代
QUARANTINED --> PARSED: 修复原始来源后新建版本
DEPRECATED --> REVIEW_PENDING: 新修订重新走完整检查
```
强制不变量:
1. 原始对象和原始 hash 不可覆盖;重传、重解析、重新清洗都创建新 `data_version`。
2. `PUBLISHED` 的前置条件是 `APPROVED`、无阻断 reason、来源可追溯、租户和适用范围完整、未过期、索引 upsert 成功。
3. 生产 FULLTEXT、LIKE、向量检索和所有下游 grounding 只读取 `PUBLISHED` 的 `chunk_revision`。
4. `SYNTHETIC`、`RUNTIME`、`QUARANTINE` 永不进入生产 collection;AI 生成内容默认 `REVIEW_PENDING`。
5. `DEPRECATED` 立即从检索可见集合移除,并通过 outbox 幂等删除向量;物理保留历史用于审计。
6. 状态转换由确定性规则和授权人完成;LLM 只能提出标签/风险建议,不能执行批准、发布、删除。
## 10. 建议的数据表和字段
优先采用旁路增量表,避免直接重构现有所有业务表。
| 建议表 | 关键字段 | 作用 |
|---|---|---|
| `aihr_data_asset` | `id, tenant_id, asset_type, source_type, source_owner, source_system, source_uri_redacted, raw_oss_id, raw_sha256, captured_at, retention_class, consent_scope, created_by` | 一份不可变原始资产的稳定身份;`raw_sha256` + 租户唯一,禁止 update 原始对象。 |
| `aihr_data_version` | `id, asset_id, version_no, parent_version_id, source_version, authority_type, applicability_json, effective_at, expires_at, parser_version, normalizer_version, classifier_version, dedupe_version, privacy_rule_version, quality_rule_version, lifecycle_status, origin_type, synthetic, generator_model, prompt_version, superseded_by` | 每次解析/清洗/规则升级产生版本,承载完整生命周期。 |
| `aihr_quality_assessment` | `id, version_id, stage, detector_code, detector_version, score, decision, assessed_at, run_id, metrics_json` | 一次检测运行;允许多个维度,不以一个 `quality_score` 代替原因。 |
| `aihr_quality_issue` | `id, assessment_id, version_id, chunk_revision_id, reason_code, severity, blocking, location_json, evidence_hash, status, resolved_by, resolved_at` | 结构化问题明细和定位;敏感 evidence 只存 hash/脱敏摘要。 |
| `aihr_review_decision` | `id, version_id, decision, reviewer_user_id, reviewer_role, comment, content_hash, decided_at, previous_decision_id` | 人工批准/驳回/撤回,绑定当时内容 hash,内容变化后自动失效。 |
| `aihr_chunk_revision` | `id, version_id, tenant_id, knowledge_id, doc_id, chunk_key, revision_no, content, content_sha256, locator_json, parent_chunk_id, lifecycle_status, effective_at, expires_at, created_at` | 生产片段的不可变修订;现有 fragment ID 可作为迁移映射,不再原地覆盖。 |
| `aihr_lineage_edge` | `from_type, from_id, to_type, to_id, relation, pipeline_run_id, created_at` | 表达 `raw -> parsed -> normalized -> chunk -> embedding -> answer/exam/case/score` 血缘。 |
| `aihr_index_outbox` | `id, tenant_id, chunk_revision_id, collection, operation, generation, payload_sha256, status, attempts, next_retry_at, last_error_code, created_at, completed_at` | MySQL 事务内登记 UPSERT/DELETE,worker 幂等执行、重试、死信和对账。 |
| `aihr_query_evidence` | `request_id, rank, chunk_revision_id, retrieval_mode, retrieval_score, rerank_score, payload_generation, cited, created_at` | 从错误答案反查精确污染修订和召回排名。 |
| `aihr_dataset_membership` | `dataset_id, version_id/chunk_revision_id, split, purpose, snapshot_at, content_sha256, approval_id` | 管理 TRAIN/VALIDATION/TEST/GOLDEN,防止内容 hash 跨 split 和时间穿越。 |
字段约束建议:所有业务主键关联同时携带/校验 `tenant_id`;`lifecycle_status` 用 CHECK 或受控枚举;`PUBLISHED` 需要唯一有效版本;`effective_at < expires_at`;`synthetic=true` 必须有 generator;`origin_type` 至少区分 `ENTERPRISE_SOURCE/PERSONAL_EXPERIENCE/SYNTHETIC/RUNTIME/EXTERNAL_API`。
## 11. 建议的 reason code
reason code 必须一对多记录,包含 `severity`、`blocking`、检测器版本和证据位置。首批至少支持:
| 类别 | reason code |
|---|---|
| 解析完整性 | `PARSE_EMPTY`, `PARSE_FAILED`, `PARSE_TRUNCATED`, `PAGE_COUNT_MISMATCH`, `EMBEDDED_CONTENT_SKIPPED` |
| 编码/OCR/ASR | `ENCODING_REPLACEMENT_CHAR`, `UNICODE_CONTROL_CHAR`, `OCR_LOW_CONFIDENCE`, `OCR_PARTIAL`, `ASR_LOW_CONFIDENCE`, `ASR_SPEAKER_UNCERTAIN` |
| 清洗与结构 | `HEADER_FOOTER_NOISE`, `PAGINATION_NOISE`, `TOC_NOISE`, `WATERMARK_NOISE`, `TABLE_STRUCTURE_LOST`, `CHUNK_TOO_SHORT`, `CHUNK_CONTEXT_BROKEN` |
| 重复 | `EXACT_DUPLICATE`, `NEAR_DUPLICATE`, `SEMANTIC_DUPLICATE` |
| 来源与版本 | `SOURCE_UNKNOWN`, `SOURCE_HASH_MISMATCH`, `SOURCE_VERSION_MISSING`, `SOURCE_UNAVAILABLE`, `SUPERSEDED_VERSION` |
| 业务质量 | `DOMAIN_IRRELEVANT`, `CONTEXT_INCOMPLETE`, `UNSUPPORTED_CLAIM`, `LABEL_CONFLICT`, `APPLICABILITY_MISSING` |
| 时效与冲突 | `POLICY_EXPIRED`, `VERSION_CONFLICT`, `EXPERT_CONFLICT` |
| 安全与隔离 | `PII_DETECTED`, `SECRET_DETECTED`, `CROSS_TENANT_REFERENCE`, `PROMPT_INJECTION_SUSPECTED` |
| 来源污染 | `SYNTHETIC_UNDECLARED`, `RUNTIME_DATA_CONTAMINATION`, `TRAIN_EVAL_LEAKAGE` |
| 索引一致性 | `INDEX_UPSERT_FAILED`, `INDEX_DELETE_FAILED`, `INDEX_DRIFT`, `INDEX_PAYLOAD_INVALID` |
默认阻断发布的 reason:所有 parse failure、page mismatch、source unknown/version missing、PII/secret、cross-tenant、prompt injection、undeclared synthetic、runtime contamination、train/eval leakage、expired policy、unsupported claim 和 index drift。`CHUNK_TOO_SHORT` 等可配置为告警,但不得被单一总分抵消严重问题。
## 12. 数据隔离和向量索引方案
1. MySQL 事实源分层:raw/parsed/quality/review/chunk revision 分表;现有 `aihr_knowledge_fragment` 在过渡期只作为兼容发布视图或发布投影,不再接受任意入口直写。
2. 逻辑 collection 至少分 `aihr_knowledge_prod`、`aihr_knowledge_quarantine`、`aihr_knowledge_synthetic`、`aihr_knowledge_runtime`。最小 P0 可先只建立 prod,其他状态完全不入向量库;不要用 payload flag 作为唯一隔离。
3. prod payload 必须包含 `tenant_id, knowledge_id, asset_id, data_version_id, chunk_revision_id, lifecycle_status, source_version, effective_at, expires_at, applicability_hash, index_generation, embedding_model`。
4. Qdrant 查询仍保留 tenant + allowed knowledge IDs filter,同时增加 `lifecycle_status=PUBLISHED` 和 generation;从 MySQL hydrate 时再次校验发布/有效期,防止 stale vector 绕过。
5. 所有 upsert/delete 先与状态变更同事务写 `aihr_index_outbox`;worker 使用确定性 point ID(基于 chunk revision)和 generation 幂等处理。失败指数退避,超过阈值进入 dead letter 并告警。
6. 定时 reconciler 对比 MySQL `PUBLISHED` 修订与 Qdrant point:多余点发 DELETE,缺失/哈希不一致发 UPSERT;输出 `INDEX_DRIFT`,不得静默修复后不留审计。
7. 撤回顺序:MySQL 先将版本标为 `DEPRECATED` 使 hydrate 立即不可见,再提交 DELETE outbox;物理删除原文件需满足保留期和引用计数,不与检索撤回绑定。
## 13. 历史数据迁移与重新清洗方案
1. **冻结新增污染**:先上线检索发布门和新导入 `REVIEW_PENDING` 默认值;在此之前不要批量重建向量,否则会扩大污染面。
2. **只读盘点**:按租户导出附件、片段、OSS、正式治理、空间授权和 Qdrant manifest,只记录 ID/hash/计数,不导出敏感正文到报告。
3. **建立资产映射**:以 `tenant_id + oss_id/file hash/doc_id` 回填 `aihr_data_asset/version`。能找到原文件的版本标 `RAW`;找不到原文件的 6 个孤儿片段及其他不可恢复项先 `QUARANTINED/SOURCE_UNAVAILABLE`,不得假定可信。
4. **保留旧数据**:原 `aihr_knowledge_fragment` 和 `sys_oss` 只读保留;新 parser/normalizer/chunker 输出新 version/chunk revision,不 UPDATE 覆盖旧正文。
5. **分批重处理**:优先正式制度、安全/消防/财务/人事等高风险空间,再处理高频引用和普通空间。每批记录 pipeline/rule versions、输入/输出 hash 和问题明细。
6. **去重与版本归并**:先精确 hash,再近重复,最后语义候选;自动检测只生成 duplicate group,版本冲突和专家冲突由业务审核人决定 authoritative/superseded。
7. **隐私与领域门禁**:确定性 PII/秘密/注入规则先跑,LLM 仅作为补充风险信号;命中阻断项进入隔离。
8. **人工审核**:给审核人显示原始文件、解析差异、清洗差异、重复组、适用范围、有效期和 reason codes;批准绑定 content hash。
9. **双写验证**:候选 prod collection 建新 generation,以 shadow query 与黄金集比较;不切换用户流量。
10. **原子切换与回滚**:达到验收标准后切换 active generation;旧 generation 保留约定窗口,可即时切回。切换后再按 outbox 清理旧点。
本地快照迁移基线:附件 1,046、片段 8,607、locator 0、上传任务 1,207(完成 1,113、失败 94)、embedded 3,893。重清洗后应分别对账,不得把“有 embedding”当作“已批准”。
## 14. 自动检测与人工审核边界
| 能力 | 自动化可决定 | 必须人工决定 |
|---|---|---|
| 技术完整性 | 文件 hash、MIME、大小、解析异常、页数比、乱码、OCR/ASR 置信度阈值 | 低置信度页面是否可由原件补正 |
| 清洗 | 确定性移除已验证的页眉页脚/页码副本,并保留 diff | 表格语义重构、歧义段落合并、事实改写 |
| 去重 | 精确重复可自动归组;近/语义重复生成候选 | 哪个版本权威、是否合并、是否存在适用范围差异 |
| 隐私 | 规则/NER 检测和默认阻断;自动遮罩仅生成候选版本 | 高风险 PII、商业秘密是否允许发布及适用范围 |
| 领域与依据 | 分类器/LLM 给相关度、claim-evidence 候选和 reason | 边界业务、制度解释、冲突结论、例外条款 |
| 发布 | 系统验证前置条件、角色、双审、hash 未变化 | 授权审核人批准;高风险制度至少双人或法务/业务责任人审核 |
| AI 内容 | 强制标 synthetic、绑定模型/prompt/grounding | 案例、标准答案、题目、评分用于正式业务前的责任人确认 |
| 删除/撤回 | 系统执行幂等状态变更、outbox 和对账 | 业务撤回决定;LLM 无权批准、发布或删除 |
LLM 输出永远是检测信号或草稿,不是唯一审批证据。任何自动低风险批准都必须基于可解释、版本化的确定性规则,并允许抽样复核和一键撤回。
## 15. 测试数据集设计
建立不含真实个人信息的版本化测试 corpus,每条样本有 `sample_id`、租户、来源类型、期望状态、期望 reason codes、期望 locator、期望可检索范围和 content hash。
1. 格式集:原生/扫描 PDF、缺页 PDF、含附件 PDF、DOCX 页眉页脚/批注、PPTX 多页、XLSX 多 sheet/合并单元格、TXT/CSV 编码变体、图片、长短音频、视频关键帧。
2. 噪声集:页码、水印、目录、重复页、零宽字符、`U+FFFD`、乱码、空文档、超长段、极短段、表格错序。
3. 重复集:字节相同、文本相同格式不同、页眉不同、少量改写、语义同义、同文档重复段、多版本制度。
4. 信任集:未知来源、过期制度、冲突制度、专家冲突、缺少适用范围、无依据结论、AI 合成未标记。
5. 安全集:合成手机号/证件/住址/邮箱、内部密钥样式、跨租户 canary、文档内提示词注入和工具调用诱导。
6. 检索黄金集:物业高频问题、无答案问题、正式制度问题、跨岗位/项目问题;每题标 allowed/forbidden chunk revisions 和最低 nDCG/Recall。
7. 回流集:用户回答、模型回答、差评、日志、记忆草稿、已确认 private/company pending,验证均不进入 prod knowledge。
8. 数据集隔离集:相同/近似 content hash 跨 train/validation/test,验证构建任务 fail closed。
## 16. 单元测试、集成测试和 E2E 测试方案
### 16.1 单元测试
- parser:格式、字符编码、页数、embedded exclusion、超限、空内容和 locator 准确性。
- normalizer:保留原文、确定性 diff、页眉页脚/页码规则、Unicode 控制字符和规则版本。
- dedupe:精确、近似、语义阈值边界;同内容不同适用范围不能自动合并。
- privacy/security:合成 PII、秘密、prompt injection;阻断 reason 不能被质量总分覆盖。
- state machine:非法跳转(尤其 `RAW/PARSED -> PUBLISHED`)必须失败;审批必须绑定当前 content hash。
- retrieval predicate:所有检索实现和 exam/case grounding 只能访问 `PUBLISHED`、未过期、授权范围内的 revision。
- outbox:幂等 upsert/delete、重试、generation、死信和并发状态转换。
### 16.2 集成测试
- MySQL + MinIO + Qdrant:上传后未批准时 MySQL/Qdrant 均不可检索;批准后只出现目标 revision;撤回后 SQL 立即不可见、Qdrant 最终删除。
- 模拟 Qdrant 500/超时:状态不谎报成功,outbox 可重试,reconciler 能发现并修复 drift。
- 多租户:同 docId、同 fragment text、同 point ID 场景下,用 tenant canary 验证 SQL、Qdrant、hydrate、下载全链路隔离。
- 规则升级:同一 raw 产生新 version,旧 PUBLISHED 继续可回滚;切换后查询审计只记录新 revision。
- 个人发布、案例、考试:统一进入 `REVIEW_PENDING`,不得直接写 prod;grounding 只能来自批准版本。
- 反馈闭环:达到阈值生成 quality issue/再审,不直接由模型或单个用户删除内容。
### 16.3 E2E 测试
1. 管理员上传一份包含 PII、过期版本和注入文本的文件,确认隔离页显示 reason codes、原文/清洗 diff,用户端搜不到。
2. 审核通过干净新版本,用户端在授权租户/岗位/项目能检索并看到正确页/段定位;其他租户不可见。
3. 撤回文档,在 MySQL 可见性切断后立即查询无结果;等待 outbox 后 Qdrant point 为 0,并保留完整审计。
4. 用真实业务黄金问题在 `390x844` 移动端跑问师傅主路径,验证引用相关、可打开原文定位、无无关主题结果。
5. 生成案例/考试题/评分,验证 synthetic/model/prompt/grounding 元数据存在,未人审内容不进入正式案例/试卷/生产统计。
现有测试应保留并扩展,例如正式制度过滤 `AihrSopSeedServiceTest.java:505`、个人精确去重 `PersonalIngestionServiceTest.java:134-182`、个人发布审核 `PersonalPublishServiceTest.java:58-64`、跨身份 fail closed `OrgSnapshotEnterpriseKnowledgeAccessPolicyTest.java:94-108`。它们证明局部控制,但不是全局 DQ 门禁测试。
## 17. 可量化验收标准
| 类别 | P0 上线门槛 | 稳态目标 |
|---|---|---|
| 生命周期 | 100% 新资产不能从 `RAW/PARSED` 直接到 prod;100% prod chunk revision 有批准记录 | 非法状态跳转测试 100% 拦截 |
| 血缘 | 100% prod chunk 可追溯到 tenant、raw asset/hash、version、规则版本、审核人 | 任一 `request_id` 5 分钟内反查全部 chunk revisions、排名和答案 hash |
| 来源/版本 | 高风险制度 100% 有 source/version/effective/expiry/authority | 过期或被替代版本召回率 0 |
| 隐私 | 阻断测试集 PII/secret 召回率 0;人工批准例外有审计 | PII 检测 recall >= 99%,precision >= 95%(在标注集) |
| 重复 | 新数据精确重复自动发现率 100% | 近重复 recall >= 95%;prod 同版本精确重复余量 0 |
| 解析 | 空/失败/缺页/替换字符阻断准确率 100% | `U+FFFD` prod 片段 0;page count mismatch prod 0 |
| 检索质量 | 跨租户 canary 泄漏 0;非 PUBLISHED 命中 0 | 黄金集 Recall@5 >= 90%,nDCG@5 >= 0.85;无关引用率 <= 5% |
| 索引一致性 | DELETE/UPSERT 失败均有 outbox 与告警;不静默丢失 | MySQL-Qdrant drift <= 0.1%,P0 delete 99% 在 5 分钟内收敛,最长 30 分钟 |
| 人工审核 | 高风险内容 100% 人审;高风险制度/场景双审身份不同 | 审核决定 100% 绑定 content hash,变更后旧批准自动失效 |
| AI 内容 | AI 案例/题目/答案/评分 100% 标 synthetic、model、prompt、grounding | 未批准 synthetic 进入 prod 数量 0 |
| 回流/数据集 | runtime/user interaction 自动进入 prod 数量 0 | train/eval content hash 交集 0;每次构建生成可审计 manifest |
| 可恢复性 | 100% 新资产原始对象存在且 hash 校验通过 | 原文抽检 100% 可恢复;不存在无来源 prod orphan |
上线前还应以本地当前值建立下降基线:上传失败率 7.79%、全局重复余量 1,897、页码类噪声 1,178、替换字符片段 19、孤儿片段 6。不能通过删除统计口径来“达标”,必须保留迁移前后 manifest 和 reason 分布。
## 18. 最小修改文件清单、实施风险与回滚
### 18.1 最小 P0 修改文件清单(审计建议;当前本地实施映射见第 19 节)
| 范围 | 最小改动 |
|---|---|
| SQL 迁移 | 新增一个 `backend/script/sql/update/aihr_<date>_data_quality_lifecycle_mysql8.sql`,创建 asset/version/assessment/issue/review/chunk revision/lineage/index outbox/query evidence 表和必要索引;不破坏现有表。 |
| 上传编排 | `AihrUploadQueueService.java`:完成条件改为“解析产物已进入治理状态”,不再以 fragment_count > 0 代表可引用。 |
| 解析/保存 | `AihrSopSeedService.java`:保存 immutable raw/version;停止普通入口直写生产片段/直接 embedding;发布、撤回只生成 outbox。 |
| 文档解析 | `ParsedDocument.java`、`TikaKnowledgeDocumentParser.java`:保留真实结构/页数/segment locator 和 parser version;显式记录 embedded skipped、truncated 等 reason。 |
| 查询 | `AihrKnowledgeQueryService.java` 与 `AihrSopSeedService.java`:所有 FULLTEXT/LIKE/vector/hydrate 统一要求 PUBLISHED revision 与有效期;企业 prompt 增加不可信来源隔离。 |
| 审计 | `AihrKnowledgeQueryAuditService.java`:新增 query evidence 批量写入、答案 hash、生成/检索模型版本。 |
| 向量 | 可在现有 service 内先加 `AihrIndexOutboxService/Worker/Reconciler`,后续再拆模块;所有 point 使用 revision/generation。 |
| 特殊入口 | `PersonalPublishService.java`、`AihrCaseService.java`、`AihrExamService.java`:改为创建待审版本,复用同一发布门和批准 grounding。 |
| API/管理端 | `AihrSopController.java` 及管理端资料处理页:增加质量详情、reason、审核、撤回/重处理;不恢复目录导入 UI。 |
| 测试 | 扩展 knowledge/personal/case/exam tests;新增 lifecycle、quality detector、outbox、reconciliation、cross-tenant E2E 和 corpus fixtures。 |
### 18.2 实施风险
- 加发布过滤后,历史片段默认都不满足 `PUBLISHED`,直接启用会造成检索结果骤降。必须先 inventory/backfill,并按风险分空间灰度。
- 重解析会改变 chunk ID、引用和排序;需要 `legacy_fragment_id -> chunk_revision_id` 映射与引用兼容期。
- 新旧 collection 双写会增加 embedding 成本和资源;必须按 hash 跳过未变化版本,并设置批次限流。
- 自动 PII/领域规则存在误报;默认隔离虽安全,但可能形成审核积压,需要容量、SLA 和批量归组能力。
- MinIO 原文件缺失的历史资料无法可靠重建定位与质量证据;不得从现有片段反向伪造“原始版本”。
- 对案例、考试和个人发布统一加门禁会改变运营流程,应在 API 中显式返回 `REVIEW_PENDING`,不能继续显示“已入库/已发布”。
### 18.3 回滚方案
1. 数据库采用纯新增迁移;旧表和原始对象不删除、不覆盖。应用回滚时可忽略新表。
2. 新检索以 feature flag/active generation 切换;回滚只切回旧 generation,不重新导入或覆盖数据。
3. 新旧索引并存一个约定窗口;任何质量或召回回归先停新发布 worker,再切回旧读路径。
4. outbox 操作幂等;回滚应用版本不能删除未完成事件。恢复后由兼容 worker 继续消费或人工批准重放。
5. 历史 migration batch 有 manifest、输入/输出 hash、状态和 rollback generation;只撤销“可见性/索引指针”,不物理删除审计链。
6. P0 安全不变量不得作为普通回滚项:跨租户过滤、非 PUBLISHED 隔离、PII/secret 阻断、撤回后 hydrate 校验必须保持 fail closed。
---
**最终判断:** 当前系统不是“完全没有治理”,而是存在多个质量不同、彼此不统一的局部生命周期。正式制度、个人知识、陪练场景、考试和记忆分别实现了部分正确控制,但企业通用知识主链仍把“解析成功”近似等同于“可引用”。在完成 P0 之前,不应把现有 `aihr_knowledge_fragment` 或默认 Qdrant collection 定义为经过审核的可信知识区,也不应将其直接作为训练集或评测集来源。
## 19. 审计后本地实施映射(2026-08-02)
本节只说明审计后工作树的本地实现,不改写前述审计时证据,也不代表生产部署。
| 审计问题 | 当前本地措施 | 状态 |
|---|---|---|
| `RAW -> INDEXED` | 上传、个人投稿和 AI 整理内容先创建不可变 asset/version/chunk revision;只有人工批准后创建生产 fragment 与 UPSERT outbox | 已实现并有门禁测试 |
| `MODEL_OUTPUT -> TRUSTED` | synthetic/用户交互默认不可信;模型不能自行批准、删除或发布 | 已实现 |
| 软问题可绕过 | 发布后端接受 reason code 后重新统计全部 `OPEN SOFT`,仍有遗漏即拒绝 | 已实现并有回归测试 |
| 清洗覆盖原文 | NFKC/控制字符/空白规范化只生成 `normalize-v2` 新版本;保存 extractor/cleaner/chunker 版本 | 已实现 |
| 规范化正文携带个人信息进入下游 | `privacy-redaction-v1` 生成独立 `redacted_content/redacted_source_name` 并保存派生 hash、隐私状态、规则版本和分类计数;解析/规范化正文只作受控审计证据,chunk、语义分析、模型调用、发布和引用标题只消费 `CLEAN/REDACTED` 派生内容;复扫残留以 `PII_DETECTED` 阻断 | 已实现;管理端提供脱敏预览,规则升级需生成新派生版本并重新审核 |
| 同名上传覆盖来源 | 取消附件文件名唯一约束;每次接入创建独立 attachment/doc/asset,精确重复只复用只读 OSS 对象 | 已实现并有迁移契约测试 |
| 结构与重复 | 标题、段落、Q&A、SOP 步骤切片;保存结构画像和 64 位 SimHash;异步 embedding 仅生成语义候选,本地降级显式标记 | 已实现;真实业务阈值待标定 |
| 旧制度冲突 | 同租户同名已发布资料内容不同产生 `VERSION_CONFLICT`;规范性知识必须显式 `supersedesAssetId`,同事务撤回旧资产 | 已实现并有回归测试 |
| 制度/专家 claim 冲突 | 确定性提取正反约束和数值 claim,只与同租户已发布 claim 比较;人工逐条确认、误报或解决,未裁决阻断发布 | 已实现基础规则;复杂条件与多专家关系待扩充 |
| 撤回后向量残留 | MySQL 立即切断生产可见性,DELETE outbox 最多重试 8 次后进入 `DEAD_LETTER`;提供 `index-health` | 已实现;生产告警接入待做 |
| 知识空间解绑绕过撤回 | 已批准或已发布资产解绑前必须由当前人工操作人走统一 `WITHDRAW`;OSS 孤儿清理同时检查附件与治理资产引用,核验失败时保留原件 | 已实现并有回归测试 |
| 错误答案无法定位污染 chunk | query evidence 保存实际 rank/score/channel/used;差评带 requestId 关联 fragment、chunk revision、asset/version | 已实现 |
| 用户反馈自动影响可信数据 | 反馈只创建 `DOWNSTREAM_ANSWER_DISPUTED`;人工 `KEEP` 保留,`WITHDRAW` 调统一撤回 | 已实现并有回归测试 |
| 缺测试基线 | 增加 PII、secret、提示词注入、synthetic、无来源历史数据黄金夹具及生命周期/证据/反馈单测 | 已实现首批;真实业务标注集待扩充 |
| 历史片段伪造来源 | `/quality/legacy/stage` 不复制旧 fragment 作为事实;存在同租户 OSS 原件时下载到受限临时文件并重新解析,不存在或不可读时创建 `QUARANTINED / SOURCE_UNAVAILABLE` 版本 | 已实现并有游标、隔离测试;全量迁移待人工分批执行 |
| Agent 反馈缺少真实检索血缘 | Agent run 只保存内部 `KNOWLEDGE:<requestId>` 引用,不保存问题/答案/附件;反馈在同租户内解析到真实 query evidence 和 fragment | 已实现并通过本地真实链路验证 |
| 缺生产质量告警 | `aihr_quality_alert` 保存稳定告警码、严重级别、证据、次数和打开/解决时间;定时扫描覆盖索引漂移、死信、血缘、开放问题、过期资料和查询证据,Actuator 暴露 `aihrKnowledgeQuality` | 已在本地实现并验证迁移幂等;外部告警平台接入待生产运维配置 |
| 缺可重复检索质量评测 | `scripts/evaluate-knowledge-quality.mjs` 计算 Recall@K、MRR、nDCG@K、跨租户禁止片段泄漏率和无证据率,不记录令牌或问题正文 | 工具和示例契约已实现;真实业务黄金集仍需专家标注后才能形成验收结论 |
| 上传失败时绕过生命周期 | 上传、批量上传和媒体重处理不再回退为直接写 `aihr_knowledge_fragment`/embedding/Qdrant;生命周期服务不可用时返回 503 | 已实现;必须保持 fail-closed |
| 只在初次检索检查发布状态 | 检索引用水合、引用详情、相邻片段和原件下载均独立复核当前版本、`PUBLISHED`、`HUMAN_VERIFIED`、`production/ACTIVE` 和有效期 | 已实现并有回归测试 |
| 历史向量与生产向量混算 | 新向量 payload 固定带 `dataset_code=production`、`PUBLISHED`、`HUMAN_VERIFIED`;查询、重建和健康计数只处理这些点,未纳管片段单列 `UNGOVERNED_LEGACY_FRAGMENTS` | 已实现;旧点暂不物理删除,待历史纳管完成后按 manifest 处置 |
| 页码、页眉和上下文噪声只定义未检测 | `dq-gate-v3` 以版本化确定性规则生成 `PAGINATION_NOISE/HEADER_FOOTER_NOISE/DOMAIN_IRRELEVANT/CONTEXT_INCOMPLETE/CHUNK_CONTEXT_BROKEN` 软问题 | 已实现并有门禁测试;阈值仍需真实语料标定,算法不自动清洗原文 |
| 历史纳管缺少断点恢复 | `scripts/stage-legacy-knowledge.mjs` 默认 dry-run;带 token 时先调用只读 `/legacy/preview`,显式 `--execute` 才分批写入;manifest 不保存正文/token,失败 ID 不推进恢复游标 | 已实现并有 Java/Node 测试;尚未对 1,046 份附件执行 |
| 评测不能作为发布门禁 | 评测契约区分 answerable/no-answer,统计并可分别设置 Recall/MRR/nDCG、禁止来源泄漏、错误来源和无答案误召回阈值;任一阈值失败退出码为 2 | 已实现并有 Node 测试;示例仅为模板,不能冒充人工黄金集 |
| 业务黑话缺少治理 | 新增不可变版本术语表和管理端入口,支持草稿、批准、驳回、新修订与停用;只有同租户人工 `ACTIVE` 版本按项目/角色扩展召回查询,definition 不作为事实注入 Prompt | 已实现服务端 API、管理端、检索接入和迁移;词条内容尚待业务审核录入 |
| AI 案例审核后丢失合成身份 | 案例整理记录 synthetic、generator/model、prompt version、grounding OSS、摘要 hash、reviewer/time;“已入库”仍是人工批准的合成案例 | 已实现并有迁移与单测,不等同于权威知识 |
本地真实链路已经验证:一次 Agent 查询能够从 `aihr_agent_run.result_ref` 反查知识请求、召回证据和具体 fragment,并将“未解决”反馈落为 `DOWNSTREAM_ANSWER_DISPUTED`;一次已发布资产撤回后,MySQL 生产 fragment 与 locator 被移除,数据集成员停用,DELETE outbox 成功,Qdrant 对应点为 0,同时 asset/version/chunk revision/原件审计链保留。隐私链路另以访谈类测试资料验证:原始/规范化正文保留审计内容,脱敏正文、派生 chunk、摘要、标签、归类理由和响应 snippet 不再包含已识别姓名或手机号,审核页只显示脱敏预览;`PII_REDACTED` 作为处理证据保留,残留 PII 才触发硬门禁。最后一次快照保留 2 个 `REVIEW_PENDING / UNTRUSTED` 测试资产,生产 fragment、生产成员、outbox 与 Qdrant 生产点均为 0。2026-08-02 收尾时本地后端未运行,因此这些是最后已记录快照,不是实时状态;未重置数据库,也未覆盖从 YCWY 同步的资料。
当前仍不得宣称完成的事项:历史 1,046 份附件未完成逐份来源/版本复核;缺失 MinIO 原件的历史片段无法恢复真实来源;业务术语尚未由责任人录入并审核;语义阈值、噪声阈值与复杂 claim 适用条件尚未用真实业务黄金集标定;生产 Qdrant 一致性、外部告警送达、黄金集 Recall/nDCG、无答案误召回与误隔离率尚未按真实标注集验收。
## 20. 综合改进方案与实施顺序
### 20.1 对其它 Agent 建议的取舍
| 建议 | 结论 | 在本项目中的正确用法 |
|---|---|---|
| OCR 除噪、术语表、结构化 Q&A/SOP | 采用 | 作为 `PARSED -> NORMALIZED/CLASSIFIED` 的候选产物,保留原文、规则版本和差异;仍需质量门禁与人工批准。 |
| 用 AI 把乱码整理成 JSON 后入向量库 | 不能直接采用 | AI 只能生成 `synthetic_unverified` 候选和清洗建议;不得覆盖原件,也不得自动进入生产索引。 |
| 固定使用 500–800 字、重叠 100 字 | 不作为全局规则 | 先按标题、段落、Q&A、SOP 步骤和页码结构切片,再用黄金集标定不同文档类型的长度和重叠。 |
| 标题、岗位、场景 metadata filter | 采用 | metadata 必须由服务端从已审核资产生成,并与租户、空间、项目、岗位、有效期过滤同时执行,不能信任客户端标签。 |
| HyDE | 暂不进入 P0 | 它可能提高召回,也可能放大查询假设和错误制度;只能在人工黄金集上与基线做 A/B,对无答案率和错误来源率设置回退门槛。 |
| Prompt 强制引用、资料不足时拒答 | 采用但不视为安全边界 | 服务端先完成发布状态与权限过滤并记录召回证据;Prompt 只约束表达,不能替代数据准入、权限或撤回。 |
| 覆盖旧文件做“一劳永逸”清洗 | 拒绝 | 原始对象不可变;新清洗结果生成新版本,批准后通过 `supersedesAssetId` 失效旧版本。 |
### 20.2 最合适的落地顺序
1. **P0 新污染止血(本地代码已完成,尚未生产发布)**:保持所有接入 fail-closed;生产检索、引用详情和下载只认当前人工批准版本;向量写入、查询、删除和计数只认生产标签;撤回先切断 MySQL 可见性,再由 outbox 删除向量。
2. **P0 生产前准备**:在结构副本按顺序执行 `aihr_20260801` 至 `aihr_20260814` 迁移并做幂等验证;备份生产数据库;部署后先验证空候选不可检索、隐私状态未完成或复扫残留 PII 的候选不可发布、批准后可检索、撤回后不可检索和跨租户负例。未通过时只回滚应用可见性,不删除原件和审计表。
3. **P0 历史资料分批纳管**:按租户和 `attachmentId` 游标盘点 1,046 份附件,以 MinIO 原件为唯一重解析依据;建议每批 20–50 份。每批执行“重解析 -> 自动检测 -> 人工审核 -> 小范围发布 -> 标准题回归”,禁止自动批准或把 8,607 个旧片段反向伪造成原始来源。
4. **P1 内容质量提升**:先处理现行制度和高频 SOP,再处理专家访谈、案例和 OCR 材料;建立术语表、适用范围、有效期、版本替代、结构化步骤和正反例标签。AI 只辅助提取、纠错候选和冲突发现,最终事实与适用范围由人确认。
5. **P1 检索标定**:业务专家标注 100–300 条黄金问题,覆盖有答案、无答案、旧制度、冲突制度、多租户、岗位/项目差异和 OCR 噪声。先调结构切片、metadata filter、混合召回和 rerank,再评估 HyDE;没有 Recall/nDCG、错误来源率和无证据率数据,不宣称“更准确”。
6. **P2 质量闭环**:把错误回答通过 `requestId -> evidence -> fragment -> version -> asset -> source` 定位到污染源;人工决定 `KEEP/WITHDRAW`,随后重建受影响生产点并运行回归集。告警平台接入 `DEAD_LETTER`、索引漂移、发布血缘缺口、过期资料和跨租户 canary。
### 20.3 决策原则
最优先的不是让模型“更会猜”,而是让系统能够证明每条生产内容为何可信、适用于谁、何时有效、由谁批准,并能在发现问题后立即停止检索和追溯原件。在此基础上再做 OCR 除噪、结构化、检索参数和 Prompt 优化,收益才可测量且不会形成新的自污染。
@@ -2,7 +2,7 @@
> 制定日期:2026-07-31
>
> 当前状态:阶段 0 基线冻结已完成;阶段 1—6 待实施
> 当前状态:阶段 0 基线冻结已完成;阶段 1—5 已实现部分能力但尚未满足完整技术通过门禁;阶段 6 未开始
>
> 适用范围:`mobile-uni` 员工端“问 · 数字师傅”、`/api/aihr/agent/**`、知识检索与受控原始资料接口
@@ -99,11 +99,11 @@ output/citation-source-viewer/<run-id>/
| 阶段 | 交付物 | 完成门禁 | 当前状态 |
|---|---|---|---|
| 0. 基线冻结 | 当前引用、资源、视频解析和权限链路事实 | 源码位置与缺口逐项复核 | 已完成 |
| 1. 定位数据契约 | schema、结构化解析结果、写入和替换一致性 | 迁移幂等;六类样本定位记录正确 | 未开始 |
| 2. 受控详情与媒体接口 | `detailRef`、详情解析、全文、图片和 Range 视频 | 正授权成功;跨租户/撤权/伪造全部拒绝 | 未开始 |
| 3. 手机端引用详情 | 可点击引用、全文高亮、图片预览、视频定位 | 390×844 主路径实际点击;H5 与 App 测试通过 | 未开始 |
| 4. 历史资料回填 | 安全回填、失败降级、进度报告 | 不改正式来源审批;成功/失败/降级数量可核对 | 未开始 |
| 5. 集成、安全与性能 | 全链路矩阵、并发/Range/资源释放 | 零越权;定位误差和性能达到冻结阈值 | 未开始 |
| 1. 定位数据契约 | schema、结构化解析结果、写入和替换一致性 | 迁移幂等;六类样本定位记录正确 | 实现中 |
| 2. 受控详情与媒体接口 | `detailRef`、详情解析、全文、图片和 Range 视频 | 正授权成功;跨租户/撤权/伪造全部拒绝 | 实现中 |
| 3. 手机端引用详情 | 可点击引用、全文高亮、图片预览、视频定位 | 390×844 主路径实际点击;H5 与 App 测试通过 | 实现中 |
| 4. 历史资料回填 | 安全回填、失败降级、进度报告 | 不改正式来源审批;成功/失败/降级数量可核对 | 实现中 |
| 5. 集成、安全与性能 | 全链路矩阵、并发/Range/资源释放 | 零越权;定位误差和性能达到冻结阈值 | 实现中 |
| 6. 发布与真机收口 | schema、后端、H5/Android 发布与生产验证 | 独立授权发布;正式账号和签名 APK 真机证据 | 未开始 |
依赖顺序:
@@ -262,14 +262,14 @@ mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am `
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| commit | 待填写 |
| JUnit | 待填写,例如 `18/18` |
| 迁移幂等 | 待填写 |
| 六类样本定位 | 待填写 |
| 替换/失败清理 | 待填写 |
| 证据目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 实现中 |
| commit | 工作区未提交,当前 HEAD `cafb836` |
| JUnit | 未运行:当前 PowerShell 未找到 `java`/`mvn` |
| 迁移幂等 | 本地 locator 迁移与回填已执行;未完成两次正式迁移的 JUnit 证明 |
| 六类样本定位 | 当前本地 seed 仅有 5 个文本附件、15 个 TEXT locator;PDF/DOCX/PPTX/XLSX/IMAGE/VIDEO 固定样本未完成 |
| 替换/失败清理 | 代码路径已实现,未完成后端自动化复跑 |
| 证据目录 | `output/citation-source-viewer/20260731-local/` |
| 遗留项 | 缺少 Java/Maven 运行时及六类公开合成附件样本 |
---
@@ -366,15 +366,15 @@ GET /api/knowledge/citations/{detailRef}
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| commit | 待填写 |
| JUnit | 待填写 |
| 正授权 | 待填写 |
| 越权矩阵 | 待填写,例如 `12/12 rejected` |
| Range | 待填写,例如 `bytes=... -> 206` |
| 日志敏感信息扫描 | 待填写 |
| 证据目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 实现中 |
| commit | 工作区未提交,当前 HEAD `cafb836` |
| JUnit | 未运行:当前 PowerShell 未找到 `java`/`mvn` |
| 正授权 | 未完成;本地 `aihr_knowledge_app` 为空,真实问答返回“当前登录端未启用知识问答应用” |
| 越权矩阵 | 未完成;源码保留租户、应用、主体、来源治理复验,未形成后端运行证据 |
| Range | 未完成后端运行验证;实现已加入 OSS/MinIO Range 链路 |
| 日志敏感信息扫描 | 未完成后端运行日志扫描;未在移动端脱敏证据中写入手机号、令牌或 OSS 原址 |
| 证据目录 | `output/citation-source-viewer/20260731-local/` |
| 遗留项 | 需要 Java/Maven、真实 APP 应用绑定、带 `oss_id` 的授权附件及后端正反权限矩阵 |
---
@@ -451,15 +451,17 @@ npm --prefix mobile-uni run build:app
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| commit | 待填写 |
| Node tests | 待填写 |
| typecheck | 待填写 |
| H5/App build | 待填写 |
| 390×844 文本/图片/视频 | 待填写,例如 `3/3` |
| 错误状态 | 待填写 |
| 截图目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 实现中 |
| commit | 工作区未提交,当前 HEAD `cafb836` |
| Node tests | `node --test mobile-uni/tests/*.test.mjs`:`211/211` 通过;有既有 WebSocket 端口占用告警但无失败用例 |
| typecheck | `npm --prefix mobile-uni run typecheck`:通过 |
| H5/App build | `npm --prefix mobile-uni run build:h5` 与 `build:app`:均完成;仅有既有 Sass 弃用告警 |
| 390×844 文本/图片/视频 | 真实引用 `0/3`:员工首页和问页面可加载,但本地应用未启用知识问答,未生成真实 citation;未伪造图片/视频 fixture |
| 错误状态 | 详情页无引用参数正确显示不可查看状态;点击“返回问答”回到首页;问答业务错误明确显示应用未启用 |
| 截图目录 | `output/citation-source-viewer/20260731-local/`,含首页、问答错误和详情不可查看截图 |
| 遗留项 | 未完成真实文本高亮、图片缩放、视频定位;需配置本地 APP 绑定和受控附件后复核 |
本次浏览器复核(2026-07-31,指定在职测试账号切换后):通过内置 Browser 完成退出旧会话、重新获取验证码、登录和进入员工端“问”页面;固定制度问题返回真实回答并展开 `3` 条引用。当前 3 条引用均为旧知识片段,DOM 中 `.citation-action` 与“查看出处”入口均为 `0`,因此没有可安全构造的 `detailRef`,未伪造详情 URL。已保存脱敏页面证据:`output/citation-source-viewer/20260731-local/question-citations-expanded.png`。本次验证结论为“引用展示通过,出处详情被定位数据缺失阻断”,不计入文本/图片/视频 `3/3` 详情门禁。
---
@@ -532,15 +534,15 @@ qdrant_points_unchanged
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| commit | 待填写 |
| 计划分母 | 待填写 |
| exact/coarse/ambiguous/failed | 待填写 |
| 抽检 | 待填写 |
| 正式来源未变化 | 待填写 |
| fragment/Qdrant 未变化 | 待填写 |
| 证据目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 实现中 |
| commit | 工作区未提交,当前 HEAD `cafb836` |
| 计划分母 | `attachments_total=5`,`locators_before=15` |
| exact/coarse/ambiguous/failed | `exact=15`,`coarse=0`,`ambiguous=0`,`failed=0`;`locators_created=0` |
| 抽检 | 已核对本地 5 个 seed 附件及 15 条 locator;未覆盖计划要求的 PDF/PPT/图片/视频抽检样本 |
| 正式来源未变化 | `formal_sources_unchanged=0`(本地无治理来源记录,未写入正式来源) |
| fragment/Qdrant 未变化 | fragment 与 Qdrant 未变化(只回填 locator) |
| 证据目录 | `output/citation-source-viewer/20260731-local/` |
| 遗留项 | 需要公开合成六类样本及生产正式来源状态后再完成阶段门禁 |
---
@@ -585,18 +587,18 @@ qdrant_points_unchanged
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| commit | 待填写 |
| 后端测试 | 待填写 |
| 移动端测试 | 待填写 |
| 越权矩阵 | 待填写 |
| 定位误差 | 待填写 |
| Range | 待填写 |
| p50/p95 | 待填写 |
| 资源泄漏循环 | 待填写 |
| 敏感信息扫描 | 待填写 |
| 证据目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 实现中 |
| commit | 工作区未提交,当前 HEAD `cafb836` |
| 后端测试 | 未运行:当前 PowerShell 未找到 `java`/`mvn` |
| 移动端测试 | Node `211/211` 通过;typecheck、H5/App build 通过 |
| 越权矩阵 | 未完成真实后端矩阵;仅完成源码级治理约束复核 |
| 定位误差 | 未测量;无真实视频引用数据 |
| Range | 未测量;无带 `oss_id` 的本地授权视频 fixture |
| p50/p95 | 未测量 |
| 资源泄漏循环 | Node 单元覆盖 Blob URL 释放,未完成 20 次真实页面循环 |
| 敏感信息扫描 | 移动端截图/DOM 证据未包含手机号、验证码、令牌、票据或 OSS 原址;后端日志扫描未完成 |
| 证据目录 | `output/citation-source-viewer/20260731-local/` |
| 遗留项 | 后端运行时、正式/测试授权数据、Range 样本和性能基准均待补齐 |
---
@@ -659,21 +661,21 @@ Android 真机:
| 字段 | 实际值 |
|---|---|
| 状态 | 待填写 |
| release commit | 待填写 |
| schema 版本/迁移结果 | 待填写 |
| 生产 JAR SHA-256 | 待填写 |
| H5 构建与远端哈希 | 待填写 |
| APK 版本/versionCode | 待填写 |
| APK SHA-256/签名摘要 | 待填写 |
| 生产正反权限 | 待填写 |
| 真机型号/Android | 待填写 |
| 文本/图片/视频 | 待填写,例如 `3/3` |
| 视频定位误差 | 待填写 |
| Crash/ANR | 待填写 |
| 回滚物 | 待填写 |
| 证据目录 | 待填写 |
| 遗留项 | 待填写 |
| 状态 | 未开始 |
| release commit | 未发布;工作区未提交,当前 HEAD `cafb836` |
| schema 版本/迁移结果 | 仅本地 Docker 数据库验证;未执行生产迁移 |
| 生产 JAR SHA-256 | 未生成/未部署 |
| H5 构建与远端哈希 | 本地 H5 构建完成;未生产发布、未计算远端哈希 |
| APK 版本/versionCode | App-Plus 构建输入完成;未出包、未安装真机 |
| APK SHA-256/签名摘要 | 未生成 |
| 生产正反权限 | 未验证 |
| 真机型号/Android | 未验证 |
| 文本/图片/视频 | `0/3`,未进行正式账号真机验收 |
| 视频定位误差 | 未测量 |
| Crash/ANR | 未验证 |
| 回滚物 | 未生成 |
| 证据目录 | `output/citation-source-viewer/20260731-local/`(仅本地浏览器证据) |
| 遗留项 | 未授权生产部署;未完成正式账号、Android 真机、签名 APK 和正式资源验收 |
---
@@ -0,0 +1,436 @@
# 帮道 AI 知识资产生产流水线
> 项目定位:面向企业行业知识场景的 AI 知识资产生产基础设施\
> 版本:v1.0
## 1. 项目定位
帮道 AI
知识资产生产流水线,不是简单的知识库系统,而是一套将企业分散在文档、制度、案例、访谈、员工经验中的非结构化信息,转化为可理解、可检索、可信任、可持续演进
AI 知识资产的生产体系。
核心理念:
> 企业 AI
> 的竞争力不是模型能力,而是企业经验被数字化、结构化和持续优化的能力。
------------------------------------------------------------------------
## 2. 当前问题
传统 RAG 流程:
文件上传
↓
对象存储
↓
文本解析
↓
切片
↓
Embedding
↓
向量数据库
↓
AI回答
存在问题:
- 原始资料质量不可控;
- PDF/OCR 噪声污染知识库;
- 页眉页脚、水印影响检索;
- 文档结构丢失;
- 制度、案例、经验混杂;
- 无法判断知识可信程度;
- 错误知识难以追溯和撤回。
因此企业 AI 首先需要解决:
> 如何把企业资料加工成为 AI 可以安全使用的知识资产。
------------------------------------------------------------------------
## 3. 总体架构
数据来源层
↓
原始资产层
↓
数据加工层
↓
知识结构层
↓
治理审核层
↓
发布消费层
### 数据来源层
包括:
- 文档
- 图片
- 音视频
- API数据
- 企业业务系统数据
### 原始资产层
负责:
- 原件保存
- Hash校验
- 来源记录
- 权限信息
- 数据血缘起点
原则:
> 原始数据永不修改。
------------------------------------------------------------------------
# 4. 数据加工层(核心建设重点)
数据加工层解决当前 RAG 准确率不足的核心问题。
流程:
原始文件
↓
解析
↓
去噪
↓
结构恢复
↓
知识分类
↓
智能切片
↓
向量化
------------------------------------------------------------------------
## 4.1 文档解析
支持:
- PDF
- Word
- Excel
- PPT
- 图片OCR
- 录音ASR
- 视频分析
输出:
- 文档结构
- 页面信息
- 内容定位
- 原始证据
------------------------------------------------------------------------
## 4.2 文档去噪
处理:
- 页眉页脚
- 页码
- 水印
- 重复目录
- 空白字符
- OCR错误
- 编码异常
原则:
> 清洗生成新版本,不覆盖原文。
------------------------------------------------------------------------
## 4.3 结构恢复
禁止简单固定字数切片。
根据知识类型:
### 制度
章节
↓
条款
↓
解释
### SOP
场景
↓
前置条件
↓
步骤
↓
异常处理
### 案例
背景
↓
问题
↓
处理过程
↓
结果
↓
经验
------------------------------------------------------------------------
# 5. 知识资产模型
核心对象不是 Document,而是:
> Knowledge Unit(知识单元)
类型:
类型 说明
------------ ----------
POLICY 制度规范
SOP 业务流程
CASE 真实案例
FAQ 问答
EXPERIENCE 专家经验
TERM 行业术语
ASSESSMENT 评测数据
------------------------------------------------------------------------
# 6. 知识生命周期
RAW
↓
PARSED
↓
NORMALIZED
↓
STRUCTURED
↓
REVIEW_PENDING
↓
APPROVED
↓
PUBLISHED
↓
DEPRECATED
原则:
- 每次加工产生新版本;
- 发布必须经过确认;
- 撤回必须可追踪。
------------------------------------------------------------------------
# 7. 数据可信体系
数据分类:
类型 用途
----------- ------------
RAW 原始资料
CANDIDATE 加工候选
TRUSTED 可信知识
CASE 案例资产
SYNTHETIC AI生成内容
RUNTIME 运行数据
GOLDEN 评测数据
核心原则:
AI生成 != 企业事实
用户反馈 != 标准经验
Embedding != 已发布知识
------------------------------------------------------------------------
# 8. AI 使用边界
AI 可以:
- 自动分类;
- 信息抽取;
- 标签生成;
- 候选FAQ生成;
- 相似检测;
- 案例结构化。
AI 不可以:
- 修改原始事实;
- 自动发布知识;
- 判断制度有效性;
- 替代业务责任人。
原则:
LLM = 加工助手
不是
知识管理员
------------------------------------------------------------------------
# 9. 帮道业务场景示例
原始资料:
物业经理访谈录音。
↓
AI加工:
生成案例:
场景:
业主拒缴物业费
背景:
业主认为服务不到位
处理:
1. 情绪沟通
2. 定位问题
3. 提供方案
结果:
恢复缴费
经验:
先解决情绪,再解决业务问题
↓
人工确认
↓
进入:
- AI问答
- 物业经理陪练
- 培训系统
------------------------------------------------------------------------
# 10. 实施路线
## Phase 1:知识加工链路
目标:
提升现有知识库准确率。
建设:
- 原始资产管理
- 文档解析
- 去噪
- 结构化切片
- 基础版本管理
## Phase 2:知识治理
建设:
- 审核流程
- 生命周期
- 血缘
- 撤回
- 权限
## Phase 3:智能运营
建设:
- 自动规则
- 黄金评测集
- 自动质量分析
- 持续优化
------------------------------------------------------------------------
# 11. 核心指标
## 数据指标
- 来源可追溯率
- 噪声发现率
- 结构恢复率
## AI指标
- Recall@K
- MRR
- nDCG
- 无答案误召回率
## 业务指标
- 专家经验沉淀数量
- 人工查询减少比例
- 培训效率提升
------------------------------------------------------------------------
# 12. 最终目标
帮道不是建设一个普通知识库。
而是建设:
企业经验数字化生产系统
将:
员工脑中的经验
历史文件中的知识
业务案例中的方法
转化为:
AI可以理解
AI可以调用
AI可以训练
AI可以评估
的企业数字资产。
------------------------------------------------------------------------
# 总结
未来企业 AI 的竞争:
不是单纯模型竞争。
而是:
企业独有数据
+
行业经验结构
+
持续优化机制
+
可信治理能力
帮道 AI 知识资产生产流水线,就是围绕这一核心能力建设。